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// template<class K, class... Args>
14// pair<iterator, bool> try_emplace(K&& k, Args&&... args);
15// template<class K, class... Args>
16// iterator try_emplace(const_iterator hint, K&& k, Args&&... args);
17
18#include <flat_map>
19#include <cassert>
20#include <functional>
21#include <deque>
22#include <vector>
23
24#include "MinSequenceContainer.h"
25#include "test_macros.h"
26#include "../helpers.h"
27#include "min_allocator.h"
28#include "../../../Emplaceable.h"
29
30// Constraints:
31// The qualified-id Compare::is_transparent is valid and denotes a type.
32// is_constructible_v<key_type, K> is true.
33// is_constructible_v<mapped_type, Args...> is true.
34// For the first overload, is_convertible_v<K&&, const_iterator> and is_convertible_v<K&&, iterator> are both false
35template <class M, class... Args>
36concept CanTryEmplace = requires(M m, Args&&... args) { m.try_emplace(std::forward<Args>(args)...); };
37
38using TransparentMap = std::flat_map<int, Emplaceable, TransparentComparator>;
39using NonTransparentMap = std::flat_map<int, Emplaceable, NonTransparentComparator>;
40
41using TransparentMapIter = typename TransparentMap::iterator;
42using TransparentMapConstIter = typename TransparentMap::const_iterator;
43
44static_assert(!CanTryEmplace<TransparentMap>);
45static_assert(!CanTryEmplace<NonTransparentMap>);
46
47static_assert(CanTryEmplace<TransparentMap, ConvertibleTransparent<int>>);
48static_assert(CanTryEmplace<TransparentMap, ConvertibleTransparent<int>, Emplaceable>);
49static_assert(CanTryEmplace<TransparentMap, ConvertibleTransparent<int>, int, double>);
50static_assert(!CanTryEmplace<TransparentMap, ConvertibleTransparent<int>, const Emplaceable&>);
51static_assert(!CanTryEmplace<TransparentMap, ConvertibleTransparent<int>, int>);
52static_assert(!CanTryEmplace<TransparentMap, NonConvertibleTransparent<int>, Emplaceable>);
53static_assert(!CanTryEmplace<NonTransparentMap, NonConvertibleTransparent<int>, Emplaceable>);
54static_assert(!CanTryEmplace<TransparentMap, ConvertibleTransparent<int>, int>);
55static_assert(!CanTryEmplace<TransparentMap, TransparentMapIter, Emplaceable>);
56static_assert(!CanTryEmplace<TransparentMap, TransparentMapConstIter, Emplaceable>);
57
58static_assert(CanTryEmplace<TransparentMap, TransparentMapConstIter, ConvertibleTransparent<int>>);
59static_assert(CanTryEmplace<TransparentMap, TransparentMapConstIter, ConvertibleTransparent<int>, Emplaceable>);
60static_assert(CanTryEmplace<TransparentMap, TransparentMapConstIter, ConvertibleTransparent<int>, int, double>);
61static_assert(!CanTryEmplace<TransparentMap, TransparentMapConstIter, ConvertibleTransparent<int>, const Emplaceable&>);
62static_assert(!CanTryEmplace<TransparentMap, TransparentMapConstIter, ConvertibleTransparent<int>, int>);
63static_assert(!CanTryEmplace<TransparentMap, TransparentMapConstIter, NonConvertibleTransparent<int>, Emplaceable>);
64static_assert(!CanTryEmplace<NonTransparentMap, TransparentMapConstIter, NonConvertibleTransparent<int>, Emplaceable>);
65static_assert(!CanTryEmplace<TransparentMap, TransparentMapConstIter, ConvertibleTransparent<int>, int>);
66
67template <class KeyContainer, class ValueContainer>
68void test() {
69 using Key = typename KeyContainer::value_type;
70 using Value = typename ValueContainer::value_type;
71 using M = std::flat_map<Key, Value, TransparentComparator, KeyContainer, ValueContainer>;
72
73 { // pair<iterator, bool> try_emplace(K&& k, Args&&... args);
74 using R = std::pair<typename M::iterator, bool>;
75 M m;
76 for (int i = 0; i < 20; i += 2)
77 m.emplace(i, Moveable(i, (double)i));
78
79 assert(m.size() == 10);
80
81 Moveable mv1(3, 3.0);
82 for (int i = 0; i < 20; i += 2) {
83 std::same_as<R> decltype(auto) r = m.try_emplace(ConvertibleTransparent<int>{i}, std::move(mv1));
84 assert(m.size() == 10);
85 assert(!r.second); // was not inserted
86 assert(!mv1.moved()); // was not moved from
87 assert(r.first->first == i); // key
88 }
89
90 std::same_as<R> decltype(auto) r2 = m.try_emplace(ConvertibleTransparent<int>{-1}, std::move(mv1));
91 assert(m.size() == 11);
92 assert(r2.second); // was inserted
93 assert(mv1.moved()); // was moved from
94 assert(r2.first->first == -1); // key
95 assert(r2.first->second.get() == 3); // value
96
97 Moveable mv2(5, 3.0);
98 std::same_as<R> decltype(auto) r3 = m.try_emplace(ConvertibleTransparent<int>{5}, std::move(mv2));
99 assert(m.size() == 12);
100 assert(r3.second); // was inserted
101 assert(mv2.moved()); // was moved from
102 assert(r3.first->first == 5); // key
103 assert(r3.first->second.get() == 5); // value
104
105 Moveable mv3(-1, 3.0);
106 std::same_as<R> decltype(auto) r4 = m.try_emplace(ConvertibleTransparent<int>{117}, std::move(mv2));
107 assert(m.size() == 13);
108 assert(r4.second); // was inserted
109 assert(mv2.moved()); // was moved from
110 assert(r4.first->first == 117); // key
111 assert(r4.first->second.get() == -1); // value
112 }
113
114 { // iterator try_emplace(const_iterator hint, K&& k, Args&&... args);
115 using R = typename M::iterator;
116 M m;
117 for (int i = 0; i < 20; i += 2)
118 m.try_emplace(i, Moveable(i, (double)i));
119 assert(m.size() == 10);
120 typename M::const_iterator it = m.find(2);
121
122 Moveable mv1(3, 3.0);
123 for (int i = 0; i < 20; i += 2) {
124 std::same_as<R> decltype(auto) r1 = m.try_emplace(it, ConvertibleTransparent<int>{i}, std::move(mv1));
125 assert(m.size() == 10);
126 assert(!mv1.moved()); // was not moved from
127 assert(r1->first == i); // key
128 assert(r1->second.get() == i); // value
129 }
130
131 std::same_as<R> decltype(auto) r2 = m.try_emplace(it, ConvertibleTransparent<int>{3}, std::move(mv1));
132 assert(m.size() == 11);
133 assert(mv1.moved()); // was moved from
134 assert(r2->first == 3); // key
135 assert(r2->second.get() == 3); // value
136 }
137}
138
139int main(int, char**) {
140 test<std::vector<int>, std::vector<Moveable>>();
141 test<std::deque<int>, std::vector<Moveable>>();
142 test<MinSequenceContainer<int>, MinSequenceContainer<Moveable>>();
143 test<std::vector<int, min_allocator<int>>, std::vector<Moveable, min_allocator<Moveable>>>();
144
145 {
146 bool transparent_used = false;
147 TransparentComparator c(transparent_used);
148 std::flat_map<int, int, TransparentComparator> m(std::sorted_unique, {{1, 1}, {2, 2}, {3, 3}}, c);
149 assert(!transparent_used);
150 auto p = m.try_emplace(ConvertibleTransparent<int>{3}, 3);
151 assert(!p.second);
152 assert(transparent_used);
153 }
154 {
155 bool transparent_used = false;
156 TransparentComparator c(transparent_used);
157 std::flat_map<int, int, TransparentComparator> m(std::sorted_unique, {{1, 1}, {2, 2}, {3, 3}}, c);
158 assert(!transparent_used);
159 auto p = m.try_emplace(m.begin(), ConvertibleTransparent<int>{3}, 3);
160 assert(p->second == 3);
161 assert(transparent_used);
162 }
163 {
164 // LWG4239 std::string and C string literal
165 using M = std::flat_map<std::string, int, std::less<>>;
166 M m{{"alpha", 1}, {"beta", 2}, {"epsilon", 1}, {"eta", 3}, {"gamma", 3}};
167 auto [it1, inserted] = m.try_emplace("charlie", 4);
168 assert(it1 == m.begin() + 2);
169 assert(inserted);
170
171 auto it2 = m.try_emplace(m.begin(), "beta2", 2);
172 assert(it2 == m.begin() + 2);
173 }
174 {
175 auto try_emplace = [](auto& m, auto key_arg, auto value_arg) {
176 using M = std::decay_t<decltype(m)>;
177 using Key = typename M::key_type;
178 m.try_emplace(ConvertibleTransparent<Key>{key_arg}, value_arg);
179 };
180 test_emplace_exception_guarantee(emplace_function&: try_emplace);
181 }
182
183 {
184 auto try_emplace_iter = [](auto& m, auto key_arg, auto value_arg) {
185 using M = std::decay_t<decltype(m)>;
186 using Key = typename M::key_type;
187 m.try_emplace(m.begin(), ConvertibleTransparent<Key>{key_arg}, value_arg);
188 };
189 test_emplace_exception_guarantee(emplace_function&: try_emplace_iter);
190 }
191
192 return 0;
193}
194

source code of libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/try_emplace_transparent.pass.cpp