| 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 | // <flat_map> |
| 12 | |
| 13 | // flat_map(key_container_type key_cont, mapped_container_type mapped_cont, |
| 14 | // const key_compare& comp = key_compare()); |
| 15 | // template<class Allocator> |
| 16 | // flat_map(const key_container_type& key_cont, const mapped_container_type& mapped_cont, |
| 17 | // const Allocator& a); |
| 18 | // template<class Alloc> |
| 19 | // flat_map(const key_container_type& key_cont, const mapped_container_type& mapped_cont, |
| 20 | // const key_compare& comp, const Alloc& a); |
| 21 | |
| 22 | #include <algorithm> |
| 23 | #include <deque> |
| 24 | #include <flat_map> |
| 25 | #include <functional> |
| 26 | #include <vector> |
| 27 | |
| 28 | #include "min_allocator.h" |
| 29 | #include "MoveOnly.h" |
| 30 | #include "test_allocator.h" |
| 31 | #include "test_iterators.h" |
| 32 | #include "test_macros.h" |
| 33 | #include "../../../test_compare.h" |
| 34 | |
| 35 | struct P { |
| 36 | int first; |
| 37 | int second; |
| 38 | template <class T, class U> |
| 39 | bool operator==(const std::pair<T, U>& rhs) const { |
| 40 | return MoveOnly(first) == rhs.first && MoveOnly(second) == rhs.second; |
| 41 | } |
| 42 | }; |
| 43 | |
| 44 | int main(int, char**) { |
| 45 | { |
| 46 | // The constructors in this subclause shall not participate in overload |
| 47 | // resolution unless uses_allocator_v<key_container_type, Alloc> is true |
| 48 | // and uses_allocator_v<mapped_container_type, Alloc> is true. |
| 49 | |
| 50 | using C = test_less<int>; |
| 51 | using A1 = test_allocator<int>; |
| 52 | using A2 = other_allocator<int>; |
| 53 | using V1 = std::vector<int, A1>; |
| 54 | using V2 = std::vector<int, A2>; |
| 55 | using M1 = std::flat_map<int, int, C, V1, V1>; |
| 56 | using M2 = std::flat_map<int, int, C, V1, V2>; |
| 57 | using M3 = std::flat_map<int, int, C, V2, V1>; |
| 58 | static_assert(std::is_constructible_v<M1, const V1&, const V1&, const A1&>); |
| 59 | static_assert(!std::is_constructible_v<M1, const V1&, const V1&, const A2&>); |
| 60 | static_assert(!std::is_constructible_v<M2, const V1&, const V2&, const A2&>); |
| 61 | static_assert(!std::is_constructible_v<M3, const V2&, const V1&, const A2&>); |
| 62 | |
| 63 | static_assert(std::is_constructible_v<M1, const V1&, const V1&, const C&, const A1&>); |
| 64 | static_assert(!std::is_constructible_v<M1, const V1&, const V1&, const C&, const A2&>); |
| 65 | static_assert(!std::is_constructible_v<M2, const V1&, const V2&, const C&, const A2&>); |
| 66 | static_assert(!std::is_constructible_v<M3, const V2&, const V1&, const C&, const A2&>); |
| 67 | } |
| 68 | { |
| 69 | // flat_map(key_container_type , mapped_container_type) |
| 70 | using M = std::flat_map<int, char>; |
| 71 | std::vector<int> ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; |
| 72 | std::vector<char> vs = {1, 2, 3, 4, 5, 6, 7, 8, 9}; |
| 73 | auto m = M(ks, vs); |
| 74 | assert((m.keys() == std::vector<int>{1, 2, 3})); |
| 75 | LIBCPP_ASSERT((m.values() == std::vector<char>{1, 4, 6})); |
| 76 | |
| 77 | // explicit(false) |
| 78 | M m2 = {ks, vs}; |
| 79 | assert(m2 == m); |
| 80 | |
| 81 | m = M(std::move(ks), std::move(vs)); |
| 82 | assert(ks.empty()); // it was moved-from |
| 83 | assert(vs.empty()); // it was moved-from |
| 84 | assert((m.keys() == std::vector<int>{1, 2, 3})); |
| 85 | LIBCPP_ASSERT((m.values() == std::vector<char>{1, 4, 6})); |
| 86 | } |
| 87 | { |
| 88 | // flat_map(key_container_type , mapped_container_type) |
| 89 | // move-only |
| 90 | P expected[] = {{.first: 3, .second: 2}, {.first: 2, .second: 1}, {.first: 1, .second: 3}}; |
| 91 | using Ks = std::deque<int, min_allocator<int>>; |
| 92 | using Vs = std::vector<MoveOnly, min_allocator<MoveOnly>>; |
| 93 | using M = std::flat_map<int, MoveOnly, std::greater<int>, Ks, Vs>; |
| 94 | Ks ks = {1, 3, 2}; |
| 95 | Vs vs; |
| 96 | vs.push_back(3); |
| 97 | vs.push_back(2); |
| 98 | vs.push_back(1); |
| 99 | auto m = M(std::move(ks), std::move(vs)); |
| 100 | assert(ks.empty()); // it was moved-from |
| 101 | assert(vs.empty()); // it was moved-from |
| 102 | assert(std::ranges::equal(m, expected, std::equal_to<>())); |
| 103 | } |
| 104 | { |
| 105 | // flat_map(key_container_type , mapped_container_type) |
| 106 | // container's allocators are used |
| 107 | using A = test_allocator<int>; |
| 108 | using M = std::flat_map<int, int, std::less<int>, std::vector<int, A>, std::deque<int, A>>; |
| 109 | auto ks = std::vector<int, A>({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); |
| 110 | auto vs = std::deque<int, A>({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(6)); |
| 111 | auto m = M(std::move(ks), std::move(vs)); |
| 112 | assert(ks.empty()); // it was moved-from |
| 113 | assert(vs.empty()); // it was moved-from |
| 114 | assert((m == M{{1, 1}, {2, 2}, {3, 3}})); |
| 115 | assert(m.keys().get_allocator() == A(5)); |
| 116 | assert(m.values().get_allocator() == A(6)); |
| 117 | } |
| 118 | { |
| 119 | // flat_map(key_container_type , mapped_container_type, key_compare) |
| 120 | using C = test_less<int>; |
| 121 | using M = std::flat_map<int, char, C>; |
| 122 | std::vector<int> ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; |
| 123 | std::vector<char> vs = {1, 2, 3, 4, 5, 6, 7, 8, 9}; |
| 124 | auto m = M(ks, vs, C(4)); |
| 125 | assert((m.keys() == std::vector<int>{1, 2, 3})); |
| 126 | LIBCPP_ASSERT((m.values() == std::vector<char>{1, 4, 6})); |
| 127 | assert(m.key_comp() == C(4)); |
| 128 | |
| 129 | // explicit(false) |
| 130 | M m2 = {ks, vs, C(4)}; |
| 131 | assert(m2 == m); |
| 132 | assert(m2.key_comp() == C(4)); |
| 133 | } |
| 134 | { |
| 135 | // flat_map(key_container_type , mapped_container_type, const Allocator&) |
| 136 | using A = test_allocator<int>; |
| 137 | using M = std::flat_map<int, int, std::less<int>, std::vector<int, A>, std::deque<int, A>>; |
| 138 | auto ks = std::vector<int, A>({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); |
| 139 | auto vs = std::deque<int, A>({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(6)); |
| 140 | auto m = M(ks, vs, A(4)); // replaces the allocators |
| 141 | assert(!ks.empty()); // it was an lvalue above |
| 142 | assert(!vs.empty()); // it was an lvalue above |
| 143 | assert((m == M{{1, 1}, {2, 2}, {3, 3}})); |
| 144 | assert(m.keys().get_allocator() == A(4)); |
| 145 | assert(m.values().get_allocator() == A(4)); |
| 146 | } |
| 147 | { |
| 148 | // flat_map(key_container_type , mapped_container_type, const Allocator&) |
| 149 | // explicit(false) |
| 150 | using A = test_allocator<int>; |
| 151 | using M = std::flat_map<int, int, std::less<int>, std::vector<int, A>, std::deque<int, A>>; |
| 152 | auto ks = std::vector<int, A>({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5)); |
| 153 | auto vs = std::deque<int, A>({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(6)); |
| 154 | M m = {ks, vs, A(4)}; // implicit ctor |
| 155 | assert(!ks.empty()); // it was an lvalue above |
| 156 | assert(!vs.empty()); // it was an lvalue above |
| 157 | assert((m == M{{1, 1}, {2, 2}, {3, 3}})); |
| 158 | assert(m.keys().get_allocator() == A(4)); |
| 159 | assert(m.values().get_allocator() == A(4)); |
| 160 | } |
| 161 | { |
| 162 | // flat_map(key_container_type , mapped_container_type, key_compare, const Allocator&) |
| 163 | using C = test_less<int>; |
| 164 | using A = test_allocator<int>; |
| 165 | using M = std::flat_map<int, int, C, std::vector<int, A>, std::vector<int, A>>; |
| 166 | std::vector<int, A> ks = {1, 1, 1, 2, 2, 3, 2, 3, 3}; |
| 167 | std::vector<int, A> vs = {1, 2, 3, 4, 5, 6, 7, 8, 9}; |
| 168 | auto m = M(ks, vs, C(4), A(5)); |
| 169 | assert((m.keys() == std::vector<int, A>{1, 2, 3})); |
| 170 | LIBCPP_ASSERT((m.values() == std::vector<int, A>{1, 4, 6})); |
| 171 | assert(m.key_comp() == C(4)); |
| 172 | assert(m.keys().get_allocator() == A(5)); |
| 173 | assert(m.values().get_allocator() == A(5)); |
| 174 | |
| 175 | // explicit(false) |
| 176 | M m2 = {ks, vs, C(4), A(5)}; |
| 177 | assert(m2 == m); |
| 178 | assert(m2.key_comp() == C(4)); |
| 179 | assert(m2.keys().get_allocator() == A(5)); |
| 180 | assert(m2.values().get_allocator() == A(5)); |
| 181 | } |
| 182 | |
| 183 | return 0; |
| 184 | } |
| 185 | |