1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
11 // Test that `ranges::to` can be used to convert between arbitrary standard containers.
18 #include <forward_list>
25 #include <unordered_map>
26 #include <unordered_set>
29 #include "test_iterators.h"
30 #include "test_range.h"
31 #include "type_algorithms.h"
32 #include "unwrap_container_adaptor.h"
34 std::vector
<std::vector
<int>> ints
= {
40 std::vector
<std::vector
<char>> chars
= {
46 std::vector
<std::vector
<std::pair
<const int, int>>> pairs
= {
47 {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 0}},
52 template <class From
, class To
>
53 void test_is_equal(std::vector
<std::vector
<typename
From::value_type
>> inputs
) {
54 for (const auto& in
: inputs
) {
55 From
from(in
.begin(), in
.end());
56 std::same_as
<To
> decltype(auto) result
= std::ranges::to
<To
>(from
);
57 assert(std::ranges::equal(in
, result
));
61 template <class From
, class To
>
62 void test_is_permutation(std::vector
<std::vector
<typename
From::value_type
>> inputs
) {
63 for (const auto& in
: inputs
) {
64 From
from(in
.begin(), in
.end());
65 std::same_as
<To
> decltype(auto) result
= std::ranges::to
<To
>(in
);
66 assert(std::ranges::is_permutation(in
, result
));
70 template <class From
, class To
>
71 void test_is_equal_for_adaptors(std::vector
<std::vector
<typename
From::value_type
>> inputs
) {
72 for (const auto& in
: inputs
) {
73 From
from(in
.begin(), in
.end());
74 std::same_as
<To
> decltype(auto) result
= std::ranges::to
<To
>(in
);
76 UnwrapAdaptor
<From
> unwrap_from(std::move(from
));
77 UnwrapAdaptor
<To
> unwrap_to(std::move(result
));
78 assert(std::ranges::is_permutation(unwrap_from
.get_container(), unwrap_to
.get_container()));
83 using sequence_containers
= types::type_list
<
91 using associative_sets
= types::type_list
<
96 template <class K
, class V
>
97 using associative_maps
= types::type_list
<
103 using unordered_sets
= types::type_list
<
104 std::unordered_set
<T
>,
105 std::unordered_multiset
<T
>
108 template <class K
, class V
>
109 using unordered_maps
= types::type_list
<
110 std::unordered_map
<K
, V
>,
111 std::unordered_multimap
<K
, V
>
115 using container_adaptors
= types::type_list
<
118 std::priority_queue
<T
>
122 using sequences_and_sets
= types::concatenate_t
<sequence_containers
<T
>, associative_sets
<T
>, unordered_sets
<T
>>;
124 template <class K
, class V
>
125 using all_containers
= types::concatenate_t
<
126 sequence_containers
<std::pair
<const K
, V
>>,
127 associative_sets
<std::pair
<const K
, V
>>,
128 associative_maps
<K
, V
>,
129 unordered_sets
<std::pair
<const K
, V
>>,
130 unordered_maps
<K
, V
>>;
132 // This is necessary to be able to use `pair`s with unordered sets.
133 template <class K
, class V
>
134 struct std::hash
<std::pair
<const K
, V
>> {
135 std::size_t operator()(const std::pair
<const K
, V
>& p
) const {
136 std::size_t h1
= std::hash
<K
>{}(p
.first
);
137 std::size_t h2
= std::hash
<V
>{}(p
.second
);
138 return h1
^ (h2
<< 1);
143 { // Conversions always preserving equality.
144 { // sequences <-> sequences
145 types::for_each(sequence_containers
<int>{}, []<class From
>() {
146 types::for_each(sequence_containers
<int>{}, []<class To
>() {
147 test_is_equal
<From
, To
>(ints
);
151 types::for_each(sequence_containers
<int>{}, []<class From
>() {
152 types::for_each(sequence_containers
<double>{}, []<class To
>() {
153 test_is_equal
<From
, To
>(ints
);
158 { // sequences <-> string
159 types::for_each(sequence_containers
<char>{}, []<class Seq
>() {
160 test_is_equal
<Seq
, std::basic_string
<char>>(chars
);
161 test_is_equal
<std::basic_string
<char>, Seq
>(chars
);
166 { // sequences/sets <-> sequences/sets
167 types::for_each(sequences_and_sets
<int>{}, []<class From
>() {
168 types::for_each(sequences_and_sets
<int>{}, []<class To
>() {
169 test_is_permutation
<From
, To
>(ints
);
173 types::for_each(sequences_and_sets
<int>{}, []<class From
>() {
174 types::for_each(sequences_and_sets
<double>{}, []<class To
>() {
175 test_is_permutation
<From
, To
>(ints
);
180 { // sequences/sets/maps <-> sequences/sets/maps. Uses `pair` for non-map containers to allow mutual conversion with
182 types::for_each(all_containers
<int, int>{}, []<class From
>() {
183 types::for_each(all_containers
<int, int>{}, []<class To
>() {
184 test_is_permutation
<From
, To
>(pairs
);
188 types::for_each(all_containers
<int, int>{}, []<class From
>() {
189 types::for_each(all_containers
<long, double>{}, []<class To
>() {
190 test_is_permutation
<From
, To
>(pairs
);
195 { // adaptors <-> adaptors
196 types::for_each(container_adaptors
<int>{}, []<class From
>() {
197 types::for_each(container_adaptors
<int>{}, []<class To
>() {
198 test_is_equal_for_adaptors
<From
, To
>(ints
);
202 types::for_each(container_adaptors
<int>{}, []<class From
>() {
203 types::for_each(container_adaptors
<double>{}, []<class To
>() {
204 test_is_equal_for_adaptors
<From
, To
>(ints
);
210 int main(int, char**) {