215 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++17, c++2010 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 <-> sequences145 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 <-> string159 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/sets167 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 with181 // 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 <-> adaptors196 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