215 lines
5.9 KiB
C++
215 lines
5.9 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
|
|
|
// Test that `ranges::to` can be used to convert between arbitrary standard containers.
|
|
|
|
#include <ranges>
|
|
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <deque>
|
|
#include <forward_list>
|
|
#include <list>
|
|
#include <map>
|
|
#include <queue>
|
|
#include <set>
|
|
#include <stack>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <unordered_set>
|
|
#include <vector>
|
|
|
|
#include "test_iterators.h"
|
|
#include "test_range.h"
|
|
#include "type_algorithms.h"
|
|
#include "unwrap_container_adaptor.h"
|
|
|
|
std::vector<std::vector<int>> ints = {
|
|
{5, 1, 3, 4, 2},
|
|
{3},
|
|
{}
|
|
};
|
|
|
|
std::vector<std::vector<char>> chars = {
|
|
{'a', 'b', 'c'},
|
|
{'a'},
|
|
{}
|
|
};
|
|
|
|
std::vector<std::vector<std::pair<const int, int>>> pairs = {
|
|
{{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 0}},
|
|
{{1, 2}},
|
|
{}
|
|
};
|
|
|
|
template <class From, class To>
|
|
void test_is_equal(std::vector<std::vector<typename From::value_type>> inputs) {
|
|
for (const auto& in : inputs) {
|
|
From from(in.begin(), in.end());
|
|
std::same_as<To> decltype(auto) result = std::ranges::to<To>(from);
|
|
assert(std::ranges::equal(in, result));
|
|
}
|
|
}
|
|
|
|
template <class From, class To>
|
|
void test_is_permutation(std::vector<std::vector<typename From::value_type>> inputs) {
|
|
for (const auto& in : inputs) {
|
|
From from(in.begin(), in.end());
|
|
std::same_as<To> decltype(auto) result = std::ranges::to<To>(in);
|
|
assert(std::ranges::is_permutation(in, result));
|
|
}
|
|
}
|
|
|
|
template <class From, class To>
|
|
void test_is_equal_for_adaptors(std::vector<std::vector<typename From::value_type>> inputs) {
|
|
for (const auto& in : inputs) {
|
|
From from(in.begin(), in.end());
|
|
std::same_as<To> decltype(auto) result = std::ranges::to<To>(in);
|
|
|
|
UnwrapAdaptor<From> unwrap_from(std::move(from));
|
|
UnwrapAdaptor<To> unwrap_to(std::move(result));
|
|
assert(std::ranges::is_permutation(unwrap_from.get_container(), unwrap_to.get_container()));
|
|
}
|
|
}
|
|
|
|
template <class T>
|
|
using sequence_containers = types::type_list<
|
|
std::vector<T>,
|
|
std::deque<T>,
|
|
std::list<T>,
|
|
std::forward_list<T>
|
|
>;
|
|
|
|
template <class T>
|
|
using associative_sets = types::type_list<
|
|
std::set<T>,
|
|
std::multiset<T>
|
|
>;
|
|
|
|
template <class K, class V>
|
|
using associative_maps = types::type_list<
|
|
std::map<K, V>,
|
|
std::multimap<K, V>
|
|
>;
|
|
|
|
template <class T>
|
|
using unordered_sets = types::type_list<
|
|
std::unordered_set<T>,
|
|
std::unordered_multiset<T>
|
|
>;
|
|
|
|
template <class K, class V>
|
|
using unordered_maps = types::type_list<
|
|
std::unordered_map<K, V>,
|
|
std::unordered_multimap<K, V>
|
|
>;
|
|
|
|
template <class T>
|
|
using container_adaptors = types::type_list<
|
|
std::stack<T>,
|
|
std::queue<T>,
|
|
std::priority_queue<T>
|
|
>;
|
|
|
|
template <class T>
|
|
using sequences_and_sets = types::concatenate_t<sequence_containers<T>, associative_sets<T>, unordered_sets<T>>;
|
|
|
|
template <class K, class V>
|
|
using all_containers = types::concatenate_t<
|
|
sequence_containers<std::pair<const K, V>>,
|
|
associative_sets<std::pair<const K, V>>,
|
|
associative_maps<K, V>,
|
|
unordered_sets<std::pair<const K, V>>,
|
|
unordered_maps<K, V>>;
|
|
|
|
// This is necessary to be able to use `pair`s with unordered sets.
|
|
template <class K, class V>
|
|
struct std::hash<std::pair<const K, V>> {
|
|
std::size_t operator()(const std::pair<const K, V>& p) const {
|
|
std::size_t h1 = std::hash<K>{}(p.first);
|
|
std::size_t h2 = std::hash<V>{}(p.second);
|
|
return h1 ^ (h2 << 1);
|
|
}
|
|
};
|
|
|
|
void test() {
|
|
{ // Conversions always preserving equality.
|
|
{ // sequences <-> sequences
|
|
types::for_each(sequence_containers<int>{}, []<class From>() {
|
|
types::for_each(sequence_containers<int>{}, []<class To>() {
|
|
test_is_equal<From, To>(ints);
|
|
});
|
|
});
|
|
|
|
types::for_each(sequence_containers<int>{}, []<class From>() {
|
|
types::for_each(sequence_containers<double>{}, []<class To>() {
|
|
test_is_equal<From, To>(ints);
|
|
});
|
|
});
|
|
}
|
|
|
|
{ // sequences <-> string
|
|
types::for_each(sequence_containers<char>{}, []<class Seq>() {
|
|
test_is_equal<Seq, std::basic_string<char>>(chars);
|
|
test_is_equal<std::basic_string<char>, Seq>(chars);
|
|
});
|
|
}
|
|
}
|
|
|
|
{ // sequences/sets <-> sequences/sets
|
|
types::for_each(sequences_and_sets<int>{}, []<class From>() {
|
|
types::for_each(sequences_and_sets<int>{}, []<class To>() {
|
|
test_is_permutation<From, To>(ints);
|
|
});
|
|
});
|
|
|
|
types::for_each(sequences_and_sets<int>{}, []<class From>() {
|
|
types::for_each(sequences_and_sets<double>{}, []<class To>() {
|
|
test_is_permutation<From, To>(ints);
|
|
});
|
|
});
|
|
}
|
|
|
|
{ // sequences/sets/maps <-> sequences/sets/maps. Uses `pair` for non-map containers to allow mutual conversion with
|
|
// map types.
|
|
types::for_each(all_containers<int, int>{}, []<class From>() {
|
|
types::for_each(all_containers<int, int>{}, []<class To>() {
|
|
test_is_permutation<From, To>(pairs);
|
|
});
|
|
});
|
|
|
|
types::for_each(all_containers<int, int>{}, []<class From>() {
|
|
types::for_each(all_containers<long, double>{}, []<class To>() {
|
|
test_is_permutation<From, To>(pairs);
|
|
});
|
|
});
|
|
}
|
|
|
|
{ // adaptors <-> adaptors
|
|
types::for_each(container_adaptors<int>{}, []<class From>() {
|
|
types::for_each(container_adaptors<int>{}, []<class To>() {
|
|
test_is_equal_for_adaptors<From, To>(ints);
|
|
});
|
|
});
|
|
|
|
types::for_each(container_adaptors<int>{}, []<class From>() {
|
|
types::for_each(container_adaptors<double>{}, []<class To>() {
|
|
test_is_equal_for_adaptors<From, To>(ints);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
int main(int, char**) {
|
|
test();
|
|
|
|
return 0;
|
|
}
|