1//===----------------------------------------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
10
11// Test that `ranges::to` can be used to convert between arbitrary standard containers.
12
13#include <ranges>
14
15#include <algorithm>
16#include <cassert>
17#include <deque>
18#include <forward_list>
19#include <list>
20#include <map>
21#include <queue>
22#include <set>
23#include <stack>
24#include <string>
25#include <unordered_map>
26#include <unordered_set>
27#include <vector>
28
29#include "test_iterators.h"
30#include "test_range.h"
31#include "type_algorithms.h"
32#include "unwrap_container_adaptor.h"
33
34std::vector<std::vector<int>> ints = {
35 {5, 1, 3, 4, 2},
36 {3},
37 {}
38};
39
40std::vector<std::vector<char>> chars = {
41 {'a', 'b', 'c'},
42 {'a'},
43 {}
44};
45
46std::vector<std::vector<std::pair<const int, int>>> pairs = {
47 {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 0}},
48 {{1, 2}},
49 {}
50};
51
52template <class From, class To>
53void 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));
58 }
59}
60
61template <class From, class To>
62void 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));
67 }
68}
69
70template <class From, class To>
71void 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);
75
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()));
79 }
80}
81
82template <class T>
83using sequence_containers = types::type_list<
84 std::vector<T>,
85 std::deque<T>,
86 std::list<T>,
87 std::forward_list<T>
88>;
89
90template <class T>
91using associative_sets = types::type_list<
92 std::set<T>,
93 std::multiset<T>
94>;
95
96template <class K, class V>
97using associative_maps = types::type_list<
98 std::map<K, V>,
99 std::multimap<K, V>
100>;
101
102template <class T>
103using unordered_sets = types::type_list<
104 std::unordered_set<T>,
105 std::unordered_multiset<T>
106>;
107
108template <class K, class V>
109using unordered_maps = types::type_list<
110 std::unordered_map<K, V>,
111 std::unordered_multimap<K, V>
112>;
113
114template <class T>
115using container_adaptors = types::type_list<
116 std::stack<T>,
117 std::queue<T>,
118 std::priority_queue<T>
119>;
120
121template <class T>
122using sequences_and_sets = types::concatenate_t<sequence_containers<T>, associative_sets<T>, unordered_sets<T>>;
123
124template <class K, class V>
125using 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>>;
131
132// This is necessary to be able to use `pair`s with unordered sets.
133template <class K, class V>
134struct 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);
139 }
140};
141
142void test() {
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);
148 });
149 });
150
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);
154 });
155 });
156 }
157
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);
162 });
163 }
164 }
165
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);
170 });
171 });
172
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);
176 });
177 });
178 }
179
180 { // sequences/sets/maps <-> sequences/sets/maps. Uses `pair` for non-map containers to allow mutual conversion with
181 // map types.
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);
185 });
186 });
187
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);
191 });
192 });
193 }
194
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);
199 });
200 });
201
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);
205 });
206 });
207 }
208}
209
210int main(int, char**) {
211 test();
212
213 return 0;
214}
215

source code of libcxx/test/std/ranges/range.utility/range.utility.conv/to_std_containers.pass.cpp