зеркало из https://github.com/microsoft/STL.git
Split `tests/P1206R7_ranges_to` into four parts (#3026)
Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
This commit is contained in:
Родитель
fea2b8cfee
Коммит
a3f2956bd2
|
@ -495,7 +495,10 @@ tests\P1206R7_priority_queue_from_range
|
|||
tests\P1206R7_priority_queue_push_range
|
||||
tests\P1206R7_queue_from_range
|
||||
tests\P1206R7_queue_push_range
|
||||
tests\P1206R7_ranges_to
|
||||
tests\P1206R7_ranges_to_mappish
|
||||
tests\P1206R7_ranges_to_misc
|
||||
tests\P1206R7_ranges_to_sequence
|
||||
tests\P1206R7_ranges_to_settish
|
||||
tests\P1206R7_set_from_range
|
||||
tests\P1206R7_set_insert_range
|
||||
tests\P1206R7_stack_from_range
|
||||
|
|
|
@ -1,606 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <cassert>
|
||||
#include <deque>
|
||||
#include <format>
|
||||
#include <forward_list>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <ranges>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <range_algorithm_support.hpp>
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
template <class T>
|
||||
struct myalloc {
|
||||
using value_type = T;
|
||||
|
||||
int state = 42;
|
||||
|
||||
myalloc() = default;
|
||||
constexpr explicit myalloc(int i) noexcept : state{i} {}
|
||||
template <class U>
|
||||
constexpr myalloc(const myalloc<U>& that) noexcept : state{that.state} {}
|
||||
|
||||
[[nodiscard]] constexpr T* allocate(std::size_t n) const {
|
||||
return std::allocator<T>{}.allocate(n);
|
||||
}
|
||||
|
||||
constexpr void deallocate(T* const p, const std::size_t n) const noexcept {
|
||||
std::allocator<T>{}.deallocate(p, n);
|
||||
}
|
||||
|
||||
template <class U>
|
||||
constexpr bool operator==(const myalloc<U>& that) const noexcept {
|
||||
return state == that.state;
|
||||
}
|
||||
};
|
||||
|
||||
struct sequence_instantiator {
|
||||
template <template <class...> class C>
|
||||
struct deduce_container_impl {
|
||||
template <class... Args>
|
||||
using apply = C<Args...>;
|
||||
};
|
||||
template <>
|
||||
struct deduce_container_impl<std::basic_string> {
|
||||
template <class T, class... Args>
|
||||
using apply = std::basic_string<T, std::char_traits<T>, Args...>;
|
||||
};
|
||||
|
||||
template <template <class...> class C, class T, class... Args>
|
||||
using deduce_container = typename deduce_container_impl<C>::template apply<T, Args...>;
|
||||
|
||||
static constexpr auto meow = "meow"sv;
|
||||
|
||||
template <template <class...> class C>
|
||||
static constexpr bool test_copy_move() {
|
||||
const auto c = ranges::to<C<char>>(meow);
|
||||
|
||||
// validate the "direct" construction path with some copies and moves
|
||||
{
|
||||
std::same_as<C<char>> auto c0 = ranges::to<C<char>>(ranges::to<C<char>>(meow));
|
||||
assert(c0 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<C<char>> auto c1 = ranges::to<C<char>>(c);
|
||||
assert(c1 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<C<char>> auto c2 = ranges::to<C>(ranges::to<C<char>>(meow));
|
||||
assert(c2 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<C<char>> auto c3 = ranges::to<C>(c);
|
||||
assert(c3 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<C<char>> auto c4 = ranges::to<C<char>>(meow) | ranges::to<C<char>>();
|
||||
assert(c4 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<C<char>> auto c5 = c | ranges::to<C<char>>();
|
||||
assert(c5 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<C<char>> auto c6 = ranges::to<C<char>>(meow) | ranges::to<C>();
|
||||
assert(c6 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<C<char>> auto c7 = c | ranges::to<C>();
|
||||
assert(c7 == c);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <ranges::input_range R, template <class...> class C>
|
||||
static constexpr bool test_sequence() {
|
||||
// validate from_range construction and deduction guides
|
||||
{
|
||||
std::same_as<C<char>> auto c0 = ranges::to<C<char>>(R{meow});
|
||||
assert(ranges::equal(c0, meow));
|
||||
}
|
||||
{
|
||||
std::same_as<C<char>> auto c1 = ranges::to<C>(R{meow});
|
||||
assert(ranges::equal(c1, meow));
|
||||
}
|
||||
{
|
||||
std::same_as<C<char>> auto c2 = R{meow} | ranges::to<C<char>>();
|
||||
assert(ranges::equal(c2, meow));
|
||||
}
|
||||
{
|
||||
std::same_as<C<char>> auto c3 = R{meow} | ranges::to<C>();
|
||||
assert(ranges::equal(c3, meow));
|
||||
}
|
||||
|
||||
// validate from_range construction and deduction guides with an extra argument
|
||||
using Alloc = myalloc<char>;
|
||||
using T = deduce_container<C, char, Alloc>;
|
||||
|
||||
{
|
||||
std::same_as<T> auto c4 = ranges::to<T>(R{meow}, Alloc{13});
|
||||
assert(c4.get_allocator().state == 13);
|
||||
assert(ranges::equal(c4, meow));
|
||||
}
|
||||
{
|
||||
std::same_as<T> auto c5 = ranges::to<C>(R{meow}, Alloc{13});
|
||||
assert(c5.get_allocator().state == 13);
|
||||
assert(ranges::equal(c5, meow));
|
||||
}
|
||||
{
|
||||
std::same_as<T> auto c6 = R{meow} | ranges::to<T>(Alloc{13});
|
||||
assert(c6.get_allocator().state == 13);
|
||||
assert(ranges::equal(c6, meow));
|
||||
}
|
||||
{
|
||||
std::same_as<T> auto c7 = R{meow} | ranges::to<C>(Alloc{13});
|
||||
assert(c7.get_allocator().state == 13);
|
||||
assert(ranges::equal(c7, meow));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <ranges::input_range R>
|
||||
static void call() {
|
||||
test_sequence<R, std::basic_string>();
|
||||
test_sequence<R, std::deque>();
|
||||
test_sequence<R, std::forward_list>();
|
||||
test_sequence<R, std::list>();
|
||||
test_sequence<R, std::vector>();
|
||||
|
||||
static_assert(test_sequence<R, std::basic_string>());
|
||||
static_assert(test_sequence<R, std::vector>());
|
||||
}
|
||||
};
|
||||
|
||||
struct mappish_instantiator {
|
||||
static constexpr std::pair<int, std::string_view> some_pairs[] = {{0, "0"}, {1, "1a"}, {1, "1b"}, {1, "1c"},
|
||||
{2, "2"}, {3, "3"}, {4, "4"}, {5, "5a"}, {5, "5b"}, {6, "6"}, {7, "7"}};
|
||||
static constexpr std::pair<int, std::string_view> unique_pairs[] = {
|
||||
{0, "0"}, {1, "1a"}, {2, "2"}, {3, "3"}, {4, "4"}, {5, "5a"}, {6, "6"}, {7, "7"}};
|
||||
|
||||
enum class is_multi : bool { no, yes };
|
||||
|
||||
static constexpr auto any_pair_eq = [](auto x, auto y) { return x.first == y.first && x.second == y.second; };
|
||||
|
||||
template <template <class...> class C>
|
||||
struct deduce_container_impl; // not defined
|
||||
template <>
|
||||
struct deduce_container_impl<std::map> {
|
||||
template <class Key, class Val, class... Args>
|
||||
using apply = std::map<Key, Val, std::less<Key>, Args...>;
|
||||
};
|
||||
template <>
|
||||
struct deduce_container_impl<std::multimap> {
|
||||
template <class Key, class Val, class... Args>
|
||||
using apply = std::multimap<Key, Val, std::less<Key>, Args...>;
|
||||
};
|
||||
template <>
|
||||
struct deduce_container_impl<std::unordered_map> {
|
||||
template <class Key, class Val, class... Args>
|
||||
using apply = std::unordered_map<Key, Val, std::hash<Key>, std::equal_to<Key>, Args...>;
|
||||
};
|
||||
template <>
|
||||
struct deduce_container_impl<std::unordered_multimap> {
|
||||
template <class Key, class Val, class... Args>
|
||||
using apply = std::unordered_multimap<Key, Val, std::hash<Key>, std::equal_to<Key>, Args...>;
|
||||
};
|
||||
|
||||
template <template <class...> class C, class Key, class Val, class... Args>
|
||||
using deduce_container = typename deduce_container_impl<C>::template apply<Key, Val, Args...>;
|
||||
|
||||
template <template <class...> class C>
|
||||
static void test_copy_move() {
|
||||
using Container = C<int, std::string_view>;
|
||||
const auto c = ranges::to<Container>(some_pairs);
|
||||
|
||||
// validate the "direct" construction path with some copies and moves
|
||||
{
|
||||
std::same_as<Container> auto c0 = ranges::to<Container>(ranges::to<Container>(some_pairs));
|
||||
assert(c0 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c1 = ranges::to<Container>(c);
|
||||
assert(c1 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c2 = ranges::to<C>(ranges::to<Container>(some_pairs));
|
||||
assert(c2 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c3 = ranges::to<C>(c);
|
||||
assert(c3 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c4 = ranges::to<Container>(some_pairs) | ranges::to<Container>();
|
||||
assert(c4 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c5 = c | ranges::to<Container>();
|
||||
assert(c5 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c6 = ranges::to<Container>(some_pairs) | ranges::to<C>();
|
||||
assert(c6 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c7 = c | ranges::to<C>();
|
||||
assert(c7 == c);
|
||||
}
|
||||
}
|
||||
|
||||
template <ranges::input_range R, template <class...> class C, is_multi Multi>
|
||||
static void test_mappish() {
|
||||
auto& expected = []() -> auto& {
|
||||
if constexpr (Multi == is_multi::yes) {
|
||||
return some_pairs;
|
||||
} else {
|
||||
return unique_pairs;
|
||||
}
|
||||
}
|
||||
();
|
||||
|
||||
using Container = C<int, std::string_view>;
|
||||
{
|
||||
std::same_as<Container> auto c0 = ranges::to<Container>(R{some_pairs});
|
||||
assert(ranges::is_permutation(c0, expected, any_pair_eq));
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c1 = ranges::to<C>(R{some_pairs});
|
||||
assert(ranges::is_permutation(c1, expected, any_pair_eq));
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c2 = R{some_pairs} | ranges::to<Container>();
|
||||
assert(ranges::is_permutation(c2, expected, any_pair_eq));
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c3 = R{some_pairs} | ranges::to<C>();
|
||||
assert(ranges::is_permutation(c3, expected, any_pair_eq));
|
||||
}
|
||||
|
||||
using Alloc = myalloc<std::pair<const int, std::string_view>>;
|
||||
using T = deduce_container<C, int, std::string_view, Alloc>;
|
||||
|
||||
{
|
||||
std::same_as<T> auto c4 = ranges::to<T>(R{some_pairs}, Alloc{13});
|
||||
assert(c4.get_allocator().state == 13);
|
||||
assert(ranges::is_permutation(c4, expected, any_pair_eq));
|
||||
}
|
||||
{
|
||||
std::same_as<T> auto c5 = ranges::to<C>(R{some_pairs}, Alloc{13});
|
||||
assert(c5.get_allocator().state == 13);
|
||||
assert(ranges::is_permutation(c5, expected, any_pair_eq));
|
||||
}
|
||||
{
|
||||
std::same_as<T> auto c6 = R{some_pairs} | ranges::to<T>(Alloc{13});
|
||||
assert(c6.get_allocator().state == 13);
|
||||
assert(ranges::is_permutation(c6, expected, any_pair_eq));
|
||||
}
|
||||
{
|
||||
std::same_as<T> auto c7 = R{some_pairs} | ranges::to<C>(Alloc{13});
|
||||
assert(c7.get_allocator().state == 13);
|
||||
assert(ranges::is_permutation(c7, expected, any_pair_eq));
|
||||
}
|
||||
}
|
||||
|
||||
template <ranges::input_range R>
|
||||
static void call() {
|
||||
if constexpr (std::same_as<std::remove_cvref_t<ranges::range_reference_t<R>>,
|
||||
std::pair<int, std::string_view>>) {
|
||||
test_mappish<R, std::map, is_multi::no>();
|
||||
test_mappish<R, std::multimap, is_multi::yes>();
|
||||
test_mappish<R, std::unordered_map, is_multi::no>();
|
||||
test_mappish<R, std::unordered_multimap, is_multi::yes>();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct settish_instantiator {
|
||||
static constexpr int some_ints[] = {0, 1, 1, 1, 2, 3, 4, 5, 5, 6, 7};
|
||||
static constexpr int unique_ints[] = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
|
||||
enum class is_multi : bool { no, yes };
|
||||
|
||||
template <template <class...> class C>
|
||||
struct deduce_container_impl; // not defined
|
||||
template <>
|
||||
struct deduce_container_impl<std::set> {
|
||||
template <class Key, class... Args>
|
||||
using apply = std::set<Key, std::less<Key>, Args...>;
|
||||
};
|
||||
template <>
|
||||
struct deduce_container_impl<std::multiset> {
|
||||
template <class Key, class... Args>
|
||||
using apply = std::multiset<Key, std::less<Key>, Args...>;
|
||||
};
|
||||
template <>
|
||||
struct deduce_container_impl<std::unordered_set> {
|
||||
template <class Key, class... Args>
|
||||
using apply = std::unordered_set<Key, std::hash<Key>, std::equal_to<Key>, Args...>;
|
||||
};
|
||||
template <>
|
||||
struct deduce_container_impl<std::unordered_multiset> {
|
||||
template <class Key, class... Args>
|
||||
using apply = std::unordered_multiset<Key, std::hash<Key>, std::equal_to<Key>, Args...>;
|
||||
};
|
||||
|
||||
template <template <class...> class C, class Key, class... Args>
|
||||
using deduce_container = typename deduce_container_impl<C>::template apply<Key, Args...>;
|
||||
|
||||
template <template <class...> class C>
|
||||
static void test_copy_move() {
|
||||
using Container = C<int>;
|
||||
const auto c = ranges::to<Container>(some_ints);
|
||||
|
||||
// validate the "direct" construction path with some copies and moves
|
||||
{
|
||||
std::same_as<Container> auto c0 = ranges::to<Container>(ranges::to<Container>(some_ints));
|
||||
assert(c0 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c1 = ranges::to<Container>(c);
|
||||
assert(c1 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c2 = ranges::to<C>(ranges::to<Container>(some_ints));
|
||||
assert(c2 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c3 = ranges::to<C>(c);
|
||||
assert(c3 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c4 = ranges::to<Container>(some_ints) | ranges::to<Container>();
|
||||
assert(c4 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c5 = c | ranges::to<Container>();
|
||||
assert(c5 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c6 = ranges::to<Container>(some_ints) | ranges::to<C>();
|
||||
assert(c6 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c7 = c | ranges::to<C>();
|
||||
assert(c7 == c);
|
||||
}
|
||||
}
|
||||
|
||||
template <ranges::input_range R, template <class...> class C, is_multi Multi>
|
||||
static void test_settish() {
|
||||
auto& expected = []() -> auto& {
|
||||
if constexpr (Multi == is_multi::yes) {
|
||||
return some_ints;
|
||||
} else {
|
||||
return unique_ints;
|
||||
}
|
||||
}
|
||||
();
|
||||
|
||||
using Container = C<int>;
|
||||
{
|
||||
std::same_as<Container> auto c0 = ranges::to<Container>(R{some_ints});
|
||||
assert(ranges::is_permutation(c0, expected));
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c1 = ranges::to<C>(R{some_ints});
|
||||
assert(ranges::is_permutation(c1, expected));
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c2 = R{some_ints} | ranges::to<Container>();
|
||||
assert(ranges::is_permutation(c2, expected));
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c3 = R{some_ints} | ranges::to<C>();
|
||||
assert(ranges::is_permutation(c3, expected));
|
||||
}
|
||||
|
||||
using Alloc = myalloc<int>;
|
||||
using T = deduce_container<C, int, Alloc>;
|
||||
|
||||
{
|
||||
std::same_as<T> auto c4 = ranges::to<T>(R{some_ints}, Alloc{13});
|
||||
assert(c4.get_allocator().state == 13);
|
||||
assert(ranges::is_permutation(c4, expected));
|
||||
}
|
||||
{
|
||||
std::same_as<T> auto c5 = ranges::to<C>(R{some_ints}, Alloc{13});
|
||||
assert(c5.get_allocator().state == 13);
|
||||
assert(ranges::is_permutation(c5, expected));
|
||||
}
|
||||
{
|
||||
std::same_as<T> auto c6 = R{some_ints} | ranges::to<T>(Alloc{13});
|
||||
assert(c6.get_allocator().state == 13);
|
||||
assert(ranges::is_permutation(c6, expected));
|
||||
}
|
||||
{
|
||||
std::same_as<T> auto c7 = R{some_ints} | ranges::to<C>(Alloc{13});
|
||||
assert(c7.get_allocator().state == 13);
|
||||
assert(ranges::is_permutation(c7, expected));
|
||||
}
|
||||
}
|
||||
|
||||
template <ranges::input_range R>
|
||||
static void call() {
|
||||
test_settish<R, std::set, is_multi::no>();
|
||||
test_settish<R, std::multiset, is_multi::yes>();
|
||||
test_settish<R, std::unordered_set, is_multi::no>();
|
||||
test_settish<R, std::unordered_multiset, is_multi::yes>();
|
||||
}
|
||||
};
|
||||
|
||||
struct secret_key_t {
|
||||
explicit secret_key_t() = default;
|
||||
};
|
||||
inline constexpr secret_key_t secret_key;
|
||||
|
||||
struct reservable {
|
||||
using value_type = int;
|
||||
|
||||
std::size_t cap_ = 0;
|
||||
std::size_t reserved_ = 0;
|
||||
std::size_t size_ = 0;
|
||||
|
||||
constexpr reservable(secret_key_t) {}
|
||||
|
||||
constexpr std::size_t capacity() const {
|
||||
return cap_;
|
||||
}
|
||||
constexpr std::size_t max_size() const {
|
||||
return ~std::size_t{};
|
||||
}
|
||||
constexpr std::size_t size() const {
|
||||
return size_;
|
||||
}
|
||||
constexpr void reserve(const std::size_t n) {
|
||||
if (n > cap_) {
|
||||
assert(reserved_ == 0);
|
||||
reserved_ = n;
|
||||
cap_ = n;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void push_back(int) {
|
||||
if (++size_ > cap_) {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
int* begin(); // not defined
|
||||
int* end(); // not defined
|
||||
};
|
||||
|
||||
constexpr bool test_reservable() {
|
||||
int some_ints[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
{
|
||||
std::same_as<reservable> auto r = some_ints | ranges::to<reservable>(secret_key);
|
||||
assert(r.size_ == ranges::size(some_ints));
|
||||
assert(r.cap_ == ranges::size(some_ints));
|
||||
assert(r.reserved_ == ranges::size(some_ints));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool test_common_constructible() {
|
||||
struct common_constructible {
|
||||
using value_type = int;
|
||||
|
||||
constexpr common_constructible(const int* const first, const int* const last, secret_key_t)
|
||||
: first_{first}, last_{last} {}
|
||||
|
||||
const int* begin() const; // not defined
|
||||
const int* end() const; // not defined
|
||||
|
||||
const int* first_;
|
||||
const int* last_;
|
||||
};
|
||||
|
||||
int some_ints[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
|
||||
{
|
||||
std::same_as<common_constructible> auto c0 = ranges::to<common_constructible>(some_ints, secret_key);
|
||||
assert(c0.first_ == ranges::begin(some_ints));
|
||||
assert(c0.last_ == ranges::end(some_ints));
|
||||
}
|
||||
{
|
||||
std::same_as<common_constructible> auto c1 = some_ints | ranges::to<common_constructible>(secret_key);
|
||||
assert(c1.first_ == ranges::begin(some_ints));
|
||||
assert(c1.last_ == ranges::end(some_ints));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool test_nested_range() {
|
||||
int some_int_ervals[3][2][2] = {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}, {{8, 9}, {10, 11}}};
|
||||
|
||||
using C = std::vector<std::vector<std::vector<int>>>;
|
||||
|
||||
{
|
||||
std::same_as<C> auto c0 = ranges::to<C>(some_int_ervals);
|
||||
assert(c0.size() == 3);
|
||||
assert(c0[0].size() == 2);
|
||||
assert(c0[0][0].size() == 2);
|
||||
assert(c0[0][0][0] == 0);
|
||||
assert(c0[0][0][1] == 1);
|
||||
assert(c0[0][1][0] == 2);
|
||||
assert(c0[0][1][1] == 3);
|
||||
assert(c0[1][0][0] == 4);
|
||||
assert(c0[1][0][1] == 5);
|
||||
assert(c0[1][1][0] == 6);
|
||||
assert(c0[1][1][1] == 7);
|
||||
assert(c0[2][0][0] == 8);
|
||||
assert(c0[2][0][1] == 9);
|
||||
assert(c0[2][1][0] == 10);
|
||||
assert(c0[2][1][1] == 11);
|
||||
}
|
||||
{
|
||||
std::same_as<C> auto c0 = some_int_ervals | ranges::to<C>();
|
||||
assert(c0.size() == 3);
|
||||
assert(c0[0].size() == 2);
|
||||
assert(c0[0][0].size() == 2);
|
||||
assert(c0[0][0][0] == 0);
|
||||
assert(c0[0][0][1] == 1);
|
||||
assert(c0[0][1][0] == 2);
|
||||
assert(c0[0][1][1] == 3);
|
||||
assert(c0[1][0][0] == 4);
|
||||
assert(c0[1][0][1] == 5);
|
||||
assert(c0[1][1][0] == 6);
|
||||
assert(c0[1][1][1] == 7);
|
||||
assert(c0[2][0][0] == 8);
|
||||
assert(c0[2][0][1] == 9);
|
||||
assert(c0[2][1][0] == 10);
|
||||
assert(c0[2][1][1] == 11);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_in<sequence_instantiator, const char>();
|
||||
test_in<mappish_instantiator, const std::pair<int, std::string_view>>();
|
||||
test_in<settish_instantiator, const int>();
|
||||
|
||||
sequence_instantiator::test_copy_move<std::basic_string>();
|
||||
sequence_instantiator::test_copy_move<std::deque>();
|
||||
sequence_instantiator::test_copy_move<std::forward_list>();
|
||||
sequence_instantiator::test_copy_move<std::list>();
|
||||
sequence_instantiator::test_copy_move<std::vector>();
|
||||
static_assert(sequence_instantiator::test_copy_move<std::basic_string>());
|
||||
static_assert(sequence_instantiator::test_copy_move<std::vector>());
|
||||
|
||||
mappish_instantiator::test_copy_move<std::map>();
|
||||
mappish_instantiator::test_copy_move<std::multimap>();
|
||||
mappish_instantiator::test_copy_move<std::unordered_map>();
|
||||
mappish_instantiator::test_copy_move<std::unordered_multimap>();
|
||||
|
||||
settish_instantiator::test_copy_move<std::set>();
|
||||
settish_instantiator::test_copy_move<std::multiset>();
|
||||
settish_instantiator::test_copy_move<std::unordered_set>();
|
||||
settish_instantiator::test_copy_move<std::unordered_multiset>();
|
||||
|
||||
test_reservable();
|
||||
static_assert(test_reservable());
|
||||
|
||||
test_common_constructible();
|
||||
static_assert(test_common_constructible());
|
||||
|
||||
test_nested_range();
|
||||
#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1588614
|
||||
static_assert(test_nested_range());
|
||||
#endif // defined(__clang__) || defined(__EDG__)
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
#include <ranges>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include <range_algorithm_support.hpp>
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
template <class T>
|
||||
struct myalloc {
|
||||
using value_type = T;
|
||||
|
||||
int state = 42;
|
||||
|
||||
myalloc() = default;
|
||||
constexpr explicit myalloc(int i) noexcept : state{i} {}
|
||||
template <class U>
|
||||
constexpr myalloc(const myalloc<U>& that) noexcept : state{that.state} {}
|
||||
|
||||
[[nodiscard]] constexpr T* allocate(std::size_t n) const {
|
||||
return std::allocator<T>{}.allocate(n);
|
||||
}
|
||||
|
||||
constexpr void deallocate(T* const p, const std::size_t n) const noexcept {
|
||||
std::allocator<T>{}.deallocate(p, n);
|
||||
}
|
||||
|
||||
template <class U>
|
||||
constexpr bool operator==(const myalloc<U>& that) const noexcept {
|
||||
return state == that.state;
|
||||
}
|
||||
};
|
||||
|
||||
struct mappish_instantiator {
|
||||
static constexpr std::pair<int, std::string_view> some_pairs[] = {{0, "0"}, {1, "1a"}, {1, "1b"}, {1, "1c"},
|
||||
{2, "2"}, {3, "3"}, {4, "4"}, {5, "5a"}, {5, "5b"}, {6, "6"}, {7, "7"}};
|
||||
static constexpr std::pair<int, std::string_view> unique_pairs[] = {
|
||||
{0, "0"}, {1, "1a"}, {2, "2"}, {3, "3"}, {4, "4"}, {5, "5a"}, {6, "6"}, {7, "7"}};
|
||||
|
||||
enum class is_multi : bool { no, yes };
|
||||
|
||||
static constexpr auto any_pair_eq = [](auto x, auto y) { return x.first == y.first && x.second == y.second; };
|
||||
|
||||
template <template <class...> class C>
|
||||
struct deduce_container_impl; // not defined
|
||||
template <>
|
||||
struct deduce_container_impl<std::map> {
|
||||
template <class Key, class Val, class... Args>
|
||||
using apply = std::map<Key, Val, std::less<Key>, Args...>;
|
||||
};
|
||||
template <>
|
||||
struct deduce_container_impl<std::multimap> {
|
||||
template <class Key, class Val, class... Args>
|
||||
using apply = std::multimap<Key, Val, std::less<Key>, Args...>;
|
||||
};
|
||||
template <>
|
||||
struct deduce_container_impl<std::unordered_map> {
|
||||
template <class Key, class Val, class... Args>
|
||||
using apply = std::unordered_map<Key, Val, std::hash<Key>, std::equal_to<Key>, Args...>;
|
||||
};
|
||||
template <>
|
||||
struct deduce_container_impl<std::unordered_multimap> {
|
||||
template <class Key, class Val, class... Args>
|
||||
using apply = std::unordered_multimap<Key, Val, std::hash<Key>, std::equal_to<Key>, Args...>;
|
||||
};
|
||||
|
||||
template <template <class...> class C, class Key, class Val, class... Args>
|
||||
using deduce_container = typename deduce_container_impl<C>::template apply<Key, Val, Args...>;
|
||||
|
||||
template <template <class...> class C>
|
||||
static void test_copy_move() {
|
||||
using Container = C<int, std::string_view>;
|
||||
const auto c = ranges::to<Container>(some_pairs);
|
||||
|
||||
// validate the "direct" construction path with some copies and moves
|
||||
{
|
||||
std::same_as<Container> auto c0 = ranges::to<Container>(ranges::to<Container>(some_pairs));
|
||||
assert(c0 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c1 = ranges::to<Container>(c);
|
||||
assert(c1 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c2 = ranges::to<C>(ranges::to<Container>(some_pairs));
|
||||
assert(c2 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c3 = ranges::to<C>(c);
|
||||
assert(c3 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c4 = ranges::to<Container>(some_pairs) | ranges::to<Container>();
|
||||
assert(c4 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c5 = c | ranges::to<Container>();
|
||||
assert(c5 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c6 = ranges::to<Container>(some_pairs) | ranges::to<C>();
|
||||
assert(c6 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c7 = c | ranges::to<C>();
|
||||
assert(c7 == c);
|
||||
}
|
||||
}
|
||||
|
||||
template <ranges::input_range R, template <class...> class C, is_multi Multi>
|
||||
static void test_mappish() {
|
||||
auto& expected = []() -> auto& {
|
||||
if constexpr (Multi == is_multi::yes) {
|
||||
return some_pairs;
|
||||
} else {
|
||||
return unique_pairs;
|
||||
}
|
||||
}
|
||||
();
|
||||
|
||||
using Container = C<int, std::string_view>;
|
||||
{
|
||||
std::same_as<Container> auto c0 = ranges::to<Container>(R{some_pairs});
|
||||
assert(ranges::is_permutation(c0, expected, any_pair_eq));
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c1 = ranges::to<C>(R{some_pairs});
|
||||
assert(ranges::is_permutation(c1, expected, any_pair_eq));
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c2 = R{some_pairs} | ranges::to<Container>();
|
||||
assert(ranges::is_permutation(c2, expected, any_pair_eq));
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c3 = R{some_pairs} | ranges::to<C>();
|
||||
assert(ranges::is_permutation(c3, expected, any_pair_eq));
|
||||
}
|
||||
|
||||
using Alloc = myalloc<std::pair<const int, std::string_view>>;
|
||||
using T = deduce_container<C, int, std::string_view, Alloc>;
|
||||
|
||||
{
|
||||
std::same_as<T> auto c4 = ranges::to<T>(R{some_pairs}, Alloc{13});
|
||||
assert(c4.get_allocator().state == 13);
|
||||
assert(ranges::is_permutation(c4, expected, any_pair_eq));
|
||||
}
|
||||
{
|
||||
std::same_as<T> auto c5 = ranges::to<C>(R{some_pairs}, Alloc{13});
|
||||
assert(c5.get_allocator().state == 13);
|
||||
assert(ranges::is_permutation(c5, expected, any_pair_eq));
|
||||
}
|
||||
{
|
||||
std::same_as<T> auto c6 = R{some_pairs} | ranges::to<T>(Alloc{13});
|
||||
assert(c6.get_allocator().state == 13);
|
||||
assert(ranges::is_permutation(c6, expected, any_pair_eq));
|
||||
}
|
||||
{
|
||||
std::same_as<T> auto c7 = R{some_pairs} | ranges::to<C>(Alloc{13});
|
||||
assert(c7.get_allocator().state == 13);
|
||||
assert(ranges::is_permutation(c7, expected, any_pair_eq));
|
||||
}
|
||||
}
|
||||
|
||||
template <ranges::input_range R>
|
||||
static void call() {
|
||||
if constexpr (std::same_as<std::remove_cvref_t<ranges::range_reference_t<R>>,
|
||||
std::pair<int, std::string_view>>) {
|
||||
test_mappish<R, std::map, is_multi::no>();
|
||||
test_mappish<R, std::multimap, is_multi::yes>();
|
||||
test_mappish<R, std::unordered_map, is_multi::no>();
|
||||
test_mappish<R, std::unordered_multimap, is_multi::yes>();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
test_in<mappish_instantiator, const std::pair<int, std::string_view>>();
|
||||
mappish_instantiator::test_copy_move<std::map>();
|
||||
mappish_instantiator::test_copy_move<std::multimap>();
|
||||
mappish_instantiator::test_copy_move<std::unordered_map>();
|
||||
mappish_instantiator::test_copy_move<std::unordered_multimap>();
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_latest_matrix.lst
|
|
@ -0,0 +1,150 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <ranges>
|
||||
#include <vector>
|
||||
|
||||
namespace ranges = std::ranges;
|
||||
|
||||
struct secret_key_t {
|
||||
explicit secret_key_t() = default;
|
||||
};
|
||||
inline constexpr secret_key_t secret_key;
|
||||
|
||||
struct reservable {
|
||||
using value_type = int;
|
||||
|
||||
std::size_t cap_ = 0;
|
||||
std::size_t reserved_ = 0;
|
||||
std::size_t size_ = 0;
|
||||
|
||||
constexpr reservable(secret_key_t) {}
|
||||
|
||||
constexpr std::size_t capacity() const {
|
||||
return cap_;
|
||||
}
|
||||
constexpr std::size_t max_size() const {
|
||||
return ~std::size_t{};
|
||||
}
|
||||
constexpr std::size_t size() const {
|
||||
return size_;
|
||||
}
|
||||
constexpr void reserve(const std::size_t n) {
|
||||
if (n > cap_) {
|
||||
assert(reserved_ == 0);
|
||||
reserved_ = n;
|
||||
cap_ = n;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void push_back(int) {
|
||||
if (++size_ > cap_) {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
int* begin(); // not defined
|
||||
int* end(); // not defined
|
||||
};
|
||||
|
||||
constexpr bool test_reservable() {
|
||||
int some_ints[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
{
|
||||
std::same_as<reservable> auto r = some_ints | ranges::to<reservable>(secret_key);
|
||||
assert(r.size_ == ranges::size(some_ints));
|
||||
assert(r.cap_ == ranges::size(some_ints));
|
||||
assert(r.reserved_ == ranges::size(some_ints));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool test_common_constructible() {
|
||||
struct common_constructible {
|
||||
using value_type = int;
|
||||
|
||||
constexpr common_constructible(const int* const first, const int* const last, secret_key_t)
|
||||
: first_{first}, last_{last} {}
|
||||
|
||||
const int* begin() const; // not defined
|
||||
const int* end() const; // not defined
|
||||
|
||||
const int* first_;
|
||||
const int* last_;
|
||||
};
|
||||
|
||||
int some_ints[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
|
||||
{
|
||||
std::same_as<common_constructible> auto c0 = ranges::to<common_constructible>(some_ints, secret_key);
|
||||
assert(c0.first_ == ranges::begin(some_ints));
|
||||
assert(c0.last_ == ranges::end(some_ints));
|
||||
}
|
||||
{
|
||||
std::same_as<common_constructible> auto c1 = some_ints | ranges::to<common_constructible>(secret_key);
|
||||
assert(c1.first_ == ranges::begin(some_ints));
|
||||
assert(c1.last_ == ranges::end(some_ints));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool test_nested_range() {
|
||||
int some_int_ervals[3][2][2] = {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}, {{8, 9}, {10, 11}}};
|
||||
|
||||
using C = std::vector<std::vector<std::vector<int>>>;
|
||||
|
||||
{
|
||||
std::same_as<C> auto c0 = ranges::to<C>(some_int_ervals);
|
||||
assert(c0.size() == 3);
|
||||
assert(c0[0].size() == 2);
|
||||
assert(c0[0][0].size() == 2);
|
||||
assert(c0[0][0][0] == 0);
|
||||
assert(c0[0][0][1] == 1);
|
||||
assert(c0[0][1][0] == 2);
|
||||
assert(c0[0][1][1] == 3);
|
||||
assert(c0[1][0][0] == 4);
|
||||
assert(c0[1][0][1] == 5);
|
||||
assert(c0[1][1][0] == 6);
|
||||
assert(c0[1][1][1] == 7);
|
||||
assert(c0[2][0][0] == 8);
|
||||
assert(c0[2][0][1] == 9);
|
||||
assert(c0[2][1][0] == 10);
|
||||
assert(c0[2][1][1] == 11);
|
||||
}
|
||||
{
|
||||
std::same_as<C> auto c0 = some_int_ervals | ranges::to<C>();
|
||||
assert(c0.size() == 3);
|
||||
assert(c0[0].size() == 2);
|
||||
assert(c0[0][0].size() == 2);
|
||||
assert(c0[0][0][0] == 0);
|
||||
assert(c0[0][0][1] == 1);
|
||||
assert(c0[0][1][0] == 2);
|
||||
assert(c0[0][1][1] == 3);
|
||||
assert(c0[1][0][0] == 4);
|
||||
assert(c0[1][0][1] == 5);
|
||||
assert(c0[1][1][0] == 6);
|
||||
assert(c0[1][1][1] == 7);
|
||||
assert(c0[2][0][0] == 8);
|
||||
assert(c0[2][0][1] == 9);
|
||||
assert(c0[2][1][0] == 10);
|
||||
assert(c0[2][1][1] == 11);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_reservable();
|
||||
static_assert(test_reservable());
|
||||
|
||||
test_common_constructible();
|
||||
static_assert(test_common_constructible());
|
||||
|
||||
test_nested_range();
|
||||
#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1588614
|
||||
static_assert(test_nested_range());
|
||||
#endif // defined(__clang__) || defined(__EDG__)
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_latest_matrix.lst
|
|
@ -0,0 +1,174 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <deque>
|
||||
#include <forward_list>
|
||||
#include <list>
|
||||
#include <ranges>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <range_algorithm_support.hpp>
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
template <class T>
|
||||
struct myalloc {
|
||||
using value_type = T;
|
||||
|
||||
int state = 42;
|
||||
|
||||
myalloc() = default;
|
||||
constexpr explicit myalloc(int i) noexcept : state{i} {}
|
||||
template <class U>
|
||||
constexpr myalloc(const myalloc<U>& that) noexcept : state{that.state} {}
|
||||
|
||||
[[nodiscard]] constexpr T* allocate(std::size_t n) const {
|
||||
return std::allocator<T>{}.allocate(n);
|
||||
}
|
||||
|
||||
constexpr void deallocate(T* const p, const std::size_t n) const noexcept {
|
||||
std::allocator<T>{}.deallocate(p, n);
|
||||
}
|
||||
|
||||
template <class U>
|
||||
constexpr bool operator==(const myalloc<U>& that) const noexcept {
|
||||
return state == that.state;
|
||||
}
|
||||
};
|
||||
|
||||
struct sequence_instantiator {
|
||||
template <template <class...> class C>
|
||||
struct deduce_container_impl {
|
||||
template <class... Args>
|
||||
using apply = C<Args...>;
|
||||
};
|
||||
template <>
|
||||
struct deduce_container_impl<std::basic_string> {
|
||||
template <class T, class... Args>
|
||||
using apply = std::basic_string<T, std::char_traits<T>, Args...>;
|
||||
};
|
||||
|
||||
template <template <class...> class C, class T, class... Args>
|
||||
using deduce_container = typename deduce_container_impl<C>::template apply<T, Args...>;
|
||||
|
||||
static constexpr auto meow = "meow"sv;
|
||||
|
||||
template <template <class...> class C>
|
||||
static constexpr bool test_copy_move() {
|
||||
const auto c = ranges::to<C<char>>(meow);
|
||||
|
||||
// validate the "direct" construction path with some copies and moves
|
||||
{
|
||||
std::same_as<C<char>> auto c0 = ranges::to<C<char>>(ranges::to<C<char>>(meow));
|
||||
assert(c0 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<C<char>> auto c1 = ranges::to<C<char>>(c);
|
||||
assert(c1 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<C<char>> auto c2 = ranges::to<C>(ranges::to<C<char>>(meow));
|
||||
assert(c2 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<C<char>> auto c3 = ranges::to<C>(c);
|
||||
assert(c3 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<C<char>> auto c4 = ranges::to<C<char>>(meow) | ranges::to<C<char>>();
|
||||
assert(c4 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<C<char>> auto c5 = c | ranges::to<C<char>>();
|
||||
assert(c5 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<C<char>> auto c6 = ranges::to<C<char>>(meow) | ranges::to<C>();
|
||||
assert(c6 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<C<char>> auto c7 = c | ranges::to<C>();
|
||||
assert(c7 == c);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <ranges::input_range R, template <class...> class C>
|
||||
static constexpr bool test_sequence() {
|
||||
// validate from_range construction and deduction guides
|
||||
{
|
||||
std::same_as<C<char>> auto c0 = ranges::to<C<char>>(R{meow});
|
||||
assert(ranges::equal(c0, meow));
|
||||
}
|
||||
{
|
||||
std::same_as<C<char>> auto c1 = ranges::to<C>(R{meow});
|
||||
assert(ranges::equal(c1, meow));
|
||||
}
|
||||
{
|
||||
std::same_as<C<char>> auto c2 = R{meow} | ranges::to<C<char>>();
|
||||
assert(ranges::equal(c2, meow));
|
||||
}
|
||||
{
|
||||
std::same_as<C<char>> auto c3 = R{meow} | ranges::to<C>();
|
||||
assert(ranges::equal(c3, meow));
|
||||
}
|
||||
|
||||
// validate from_range construction and deduction guides with an extra argument
|
||||
using Alloc = myalloc<char>;
|
||||
using T = deduce_container<C, char, Alloc>;
|
||||
|
||||
{
|
||||
std::same_as<T> auto c4 = ranges::to<T>(R{meow}, Alloc{13});
|
||||
assert(c4.get_allocator().state == 13);
|
||||
assert(ranges::equal(c4, meow));
|
||||
}
|
||||
{
|
||||
std::same_as<T> auto c5 = ranges::to<C>(R{meow}, Alloc{13});
|
||||
assert(c5.get_allocator().state == 13);
|
||||
assert(ranges::equal(c5, meow));
|
||||
}
|
||||
{
|
||||
std::same_as<T> auto c6 = R{meow} | ranges::to<T>(Alloc{13});
|
||||
assert(c6.get_allocator().state == 13);
|
||||
assert(ranges::equal(c6, meow));
|
||||
}
|
||||
{
|
||||
std::same_as<T> auto c7 = R{meow} | ranges::to<C>(Alloc{13});
|
||||
assert(c7.get_allocator().state == 13);
|
||||
assert(ranges::equal(c7, meow));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <ranges::input_range R>
|
||||
static void call() {
|
||||
test_sequence<R, std::basic_string>();
|
||||
test_sequence<R, std::deque>();
|
||||
test_sequence<R, std::forward_list>();
|
||||
test_sequence<R, std::list>();
|
||||
test_sequence<R, std::vector>();
|
||||
|
||||
static_assert(test_sequence<R, std::basic_string>());
|
||||
static_assert(test_sequence<R, std::vector>());
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
test_in<sequence_instantiator, const char>();
|
||||
|
||||
sequence_instantiator::test_copy_move<std::basic_string>();
|
||||
sequence_instantiator::test_copy_move<std::deque>();
|
||||
sequence_instantiator::test_copy_move<std::forward_list>();
|
||||
sequence_instantiator::test_copy_move<std::list>();
|
||||
sequence_instantiator::test_copy_move<std::vector>();
|
||||
static_assert(sequence_instantiator::test_copy_move<std::basic_string>());
|
||||
static_assert(sequence_instantiator::test_copy_move<std::vector>());
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_latest_matrix.lst
|
|
@ -0,0 +1,181 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <ranges>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <range_algorithm_support.hpp>
|
||||
|
||||
template <class T>
|
||||
struct myalloc {
|
||||
using value_type = T;
|
||||
|
||||
int state = 42;
|
||||
|
||||
myalloc() = default;
|
||||
constexpr explicit myalloc(int i) noexcept : state{i} {}
|
||||
template <class U>
|
||||
constexpr myalloc(const myalloc<U>& that) noexcept : state{that.state} {}
|
||||
|
||||
[[nodiscard]] constexpr T* allocate(std::size_t n) const {
|
||||
return std::allocator<T>{}.allocate(n);
|
||||
}
|
||||
|
||||
constexpr void deallocate(T* const p, const std::size_t n) const noexcept {
|
||||
std::allocator<T>{}.deallocate(p, n);
|
||||
}
|
||||
|
||||
template <class U>
|
||||
constexpr bool operator==(const myalloc<U>& that) const noexcept {
|
||||
return state == that.state;
|
||||
}
|
||||
};
|
||||
|
||||
struct settish_instantiator {
|
||||
static constexpr int some_ints[] = {0, 1, 1, 1, 2, 3, 4, 5, 5, 6, 7};
|
||||
static constexpr int unique_ints[] = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
|
||||
enum class is_multi : bool { no, yes };
|
||||
|
||||
template <template <class...> class C>
|
||||
struct deduce_container_impl; // not defined
|
||||
template <>
|
||||
struct deduce_container_impl<std::set> {
|
||||
template <class Key, class... Args>
|
||||
using apply = std::set<Key, std::less<Key>, Args...>;
|
||||
};
|
||||
template <>
|
||||
struct deduce_container_impl<std::multiset> {
|
||||
template <class Key, class... Args>
|
||||
using apply = std::multiset<Key, std::less<Key>, Args...>;
|
||||
};
|
||||
template <>
|
||||
struct deduce_container_impl<std::unordered_set> {
|
||||
template <class Key, class... Args>
|
||||
using apply = std::unordered_set<Key, std::hash<Key>, std::equal_to<Key>, Args...>;
|
||||
};
|
||||
template <>
|
||||
struct deduce_container_impl<std::unordered_multiset> {
|
||||
template <class Key, class... Args>
|
||||
using apply = std::unordered_multiset<Key, std::hash<Key>, std::equal_to<Key>, Args...>;
|
||||
};
|
||||
|
||||
template <template <class...> class C, class Key, class... Args>
|
||||
using deduce_container = typename deduce_container_impl<C>::template apply<Key, Args...>;
|
||||
|
||||
template <template <class...> class C>
|
||||
static void test_copy_move() {
|
||||
using Container = C<int>;
|
||||
const auto c = ranges::to<Container>(some_ints);
|
||||
|
||||
// validate the "direct" construction path with some copies and moves
|
||||
{
|
||||
std::same_as<Container> auto c0 = ranges::to<Container>(ranges::to<Container>(some_ints));
|
||||
assert(c0 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c1 = ranges::to<Container>(c);
|
||||
assert(c1 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c2 = ranges::to<C>(ranges::to<Container>(some_ints));
|
||||
assert(c2 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c3 = ranges::to<C>(c);
|
||||
assert(c3 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c4 = ranges::to<Container>(some_ints) | ranges::to<Container>();
|
||||
assert(c4 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c5 = c | ranges::to<Container>();
|
||||
assert(c5 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c6 = ranges::to<Container>(some_ints) | ranges::to<C>();
|
||||
assert(c6 == c);
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c7 = c | ranges::to<C>();
|
||||
assert(c7 == c);
|
||||
}
|
||||
}
|
||||
|
||||
template <ranges::input_range R, template <class...> class C, is_multi Multi>
|
||||
static void test_settish() {
|
||||
auto& expected = []() -> auto& {
|
||||
if constexpr (Multi == is_multi::yes) {
|
||||
return some_ints;
|
||||
} else {
|
||||
return unique_ints;
|
||||
}
|
||||
}
|
||||
();
|
||||
|
||||
using Container = C<int>;
|
||||
{
|
||||
std::same_as<Container> auto c0 = ranges::to<Container>(R{some_ints});
|
||||
assert(ranges::is_permutation(c0, expected));
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c1 = ranges::to<C>(R{some_ints});
|
||||
assert(ranges::is_permutation(c1, expected));
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c2 = R{some_ints} | ranges::to<Container>();
|
||||
assert(ranges::is_permutation(c2, expected));
|
||||
}
|
||||
{
|
||||
std::same_as<Container> auto c3 = R{some_ints} | ranges::to<C>();
|
||||
assert(ranges::is_permutation(c3, expected));
|
||||
}
|
||||
|
||||
using Alloc = myalloc<int>;
|
||||
using T = deduce_container<C, int, Alloc>;
|
||||
|
||||
{
|
||||
std::same_as<T> auto c4 = ranges::to<T>(R{some_ints}, Alloc{13});
|
||||
assert(c4.get_allocator().state == 13);
|
||||
assert(ranges::is_permutation(c4, expected));
|
||||
}
|
||||
{
|
||||
std::same_as<T> auto c5 = ranges::to<C>(R{some_ints}, Alloc{13});
|
||||
assert(c5.get_allocator().state == 13);
|
||||
assert(ranges::is_permutation(c5, expected));
|
||||
}
|
||||
{
|
||||
std::same_as<T> auto c6 = R{some_ints} | ranges::to<T>(Alloc{13});
|
||||
assert(c6.get_allocator().state == 13);
|
||||
assert(ranges::is_permutation(c6, expected));
|
||||
}
|
||||
{
|
||||
std::same_as<T> auto c7 = R{some_ints} | ranges::to<C>(Alloc{13});
|
||||
assert(c7.get_allocator().state == 13);
|
||||
assert(ranges::is_permutation(c7, expected));
|
||||
}
|
||||
}
|
||||
|
||||
template <ranges::input_range R>
|
||||
static void call() {
|
||||
test_settish<R, std::set, is_multi::no>();
|
||||
test_settish<R, std::multiset, is_multi::yes>();
|
||||
test_settish<R, std::unordered_set, is_multi::no>();
|
||||
test_settish<R, std::unordered_multiset, is_multi::yes>();
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
test_in<settish_instantiator, const int>();
|
||||
settish_instantiator::test_copy_move<std::set>();
|
||||
settish_instantiator::test_copy_move<std::multiset>();
|
||||
settish_instantiator::test_copy_move<std::unordered_set>();
|
||||
settish_instantiator::test_copy_move<std::unordered_multiset>();
|
||||
}
|
Загрузка…
Ссылка в новой задаче