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... Args>
14// pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
15// template<class... Args>
16// pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
17// template<class... Args>
18// iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args);
19// template<class... Args>
20// iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);
21
22#include <flat_map>
23#include <cassert>
24#include <functional>
25#include <deque>
26
27#include "MinSequenceContainer.h"
28#include "test_macros.h"
29#include "../helpers.h"
30#include "min_allocator.h"
31#include "../../../Emplaceable.h"
32
33// Constraints: is_constructible_v<mapped_type, Args...> is true.
34template <class M, class... Args>
35concept CanTryEmplace = requires(M m, Args&&... args) { m.try_emplace(std::forward<Args>(args)...); };
36
37using Map = std::flat_map<Emplaceable, Emplaceable>;
38using Iter = typename Map::const_iterator;
39static_assert(!CanTryEmplace<Map>);
40
41static_assert(CanTryEmplace<Map, const Emplaceable&>);
42static_assert(CanTryEmplace<Map, const Emplaceable&, Emplaceable>);
43static_assert(CanTryEmplace<Map, const Emplaceable&, int, double>);
44static_assert(!CanTryEmplace<Map, const Emplaceable&, const Emplaceable&>);
45static_assert(!CanTryEmplace<Map, const Emplaceable&, int>);
46
47static_assert(CanTryEmplace<Map, Emplaceable>);
48static_assert(CanTryEmplace<Map, Emplaceable, Emplaceable>);
49static_assert(CanTryEmplace<Map, Emplaceable, int, double>);
50static_assert(!CanTryEmplace<Map, Emplaceable, const Emplaceable&>);
51static_assert(!CanTryEmplace<Map, Emplaceable, int>);
52
53static_assert(CanTryEmplace<Map, Iter, const Emplaceable&>);
54static_assert(CanTryEmplace<Map, Iter, const Emplaceable&, Emplaceable>);
55static_assert(CanTryEmplace<Map, Iter, const Emplaceable&, int, double>);
56static_assert(!CanTryEmplace<Map, Iter, const Emplaceable&, const Emplaceable&>);
57static_assert(!CanTryEmplace<Map, Iter, const Emplaceable&, int>);
58
59static_assert(CanTryEmplace<Map, Iter, Emplaceable>);
60static_assert(CanTryEmplace<Map, Iter, Emplaceable, Emplaceable>);
61static_assert(CanTryEmplace<Map, Iter, Emplaceable, int, double>);
62static_assert(!CanTryEmplace<Map, Iter, Emplaceable, const Emplaceable&>);
63static_assert(!CanTryEmplace<Map, Iter, Emplaceable, int>);
64
65template <class KeyContainer, class ValueContainer>
66void test_ck() {
67 using Key = typename KeyContainer::value_type;
68 using Value = typename ValueContainer::value_type;
69 using M = std::flat_map<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
70
71 { // pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
72 using R = std::pair<typename M::iterator, bool>;
73 M m;
74 for (int i = 0; i < 20; i += 2)
75 m.emplace(i, Moveable(i, (double)i));
76
77 assert(m.size() == 10);
78
79 Moveable mv1(3, 3.0);
80 for (int i = 0; i < 20; i += 2) {
81 std::same_as<R> decltype(auto) r = m.try_emplace(i, std::move(mv1));
82 assert(m.size() == 10);
83 assert(!r.second); // was not inserted
84 assert(!mv1.moved()); // was not moved from
85 assert(r.first->first == i); // key
86 }
87
88 std::same_as<R> decltype(auto) r2 = m.try_emplace(-1, std::move(mv1));
89 assert(m.size() == 11);
90 assert(r2.second); // was inserted
91 assert(mv1.moved()); // was moved from
92 assert(r2.first->first == -1); // key
93 assert(r2.first->second.get() == 3); // value
94
95 Moveable mv2(5, 3.0);
96 std::same_as<R> decltype(auto) r3 = m.try_emplace(5, std::move(mv2));
97 assert(m.size() == 12);
98 assert(r3.second); // was inserted
99 assert(mv2.moved()); // was moved from
100 assert(r3.first->first == 5); // key
101 assert(r3.first->second.get() == 5); // value
102
103 Moveable mv3(-1, 3.0);
104 std::same_as<R> decltype(auto) r4 = m.try_emplace(117, std::move(mv2));
105 assert(m.size() == 13);
106 assert(r4.second); // was inserted
107 assert(mv2.moved()); // was moved from
108 assert(r4.first->first == 117); // key
109 assert(r4.first->second.get() == -1); // value
110 }
111
112 { // iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args);
113 using R = typename M::iterator;
114 M m;
115 for (int i = 0; i < 20; i += 2)
116 m.try_emplace(i, Moveable(i, (double)i));
117 assert(m.size() == 10);
118 typename M::const_iterator it = m.find(2);
119
120 Moveable mv1(3, 3.0);
121 for (int i = 0; i < 20; i += 2) {
122 std::same_as<R> decltype(auto) r1 = m.try_emplace(it, i, std::move(mv1));
123 assert(m.size() == 10);
124 assert(!mv1.moved()); // was not moved from
125 assert(r1->first == i); // key
126 assert(r1->second.get() == i); // value
127 }
128
129 std::same_as<R> decltype(auto) r2 = m.try_emplace(it, 3, std::move(mv1));
130 assert(m.size() == 11);
131 assert(mv1.moved()); // was moved from
132 assert(r2->first == 3); // key
133 assert(r2->second.get() == 3); // value
134 }
135}
136
137template <class KeyContainer, class ValueContainer>
138void test_rk() {
139 using Key = typename KeyContainer::value_type;
140 using Value = typename ValueContainer::value_type;
141 using M = std::flat_map<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
142
143 { // pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
144 using R = std::pair<typename M::iterator, bool>;
145 M m;
146 for (int i = 0; i < 20; i += 2) {
147 m.emplace(Moveable(i, (double)i), Moveable(i + 1, (double)i + 1));
148 }
149 assert(m.size() == 10);
150
151 Moveable mvkey1(2, 2.0);
152 Moveable mv1(4, 4.0);
153 std::same_as<R> decltype(auto) r1 = m.try_emplace(std::move(mvkey1), std::move(mv1));
154 assert(m.size() == 10);
155 assert(!r1.second); // was not inserted
156 assert(!mv1.moved()); // was not moved from
157 assert(!mvkey1.moved()); // was not moved from
158 assert(r1.first->first == mvkey1); // key
159
160 Moveable mvkey2(3, 3.0);
161 std::same_as<R> decltype(auto) r2 = m.try_emplace(std::move(mvkey2), std::move(mv1));
162 assert(m.size() == 11);
163 assert(r2.second); // was inserted
164 assert(mv1.moved()); // was moved from
165 assert(mvkey2.moved()); // was moved from
166 assert(r2.first->first.get() == 3); // key
167 assert(r2.first->second.get() == 4); // value
168 }
169
170 { // iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);
171 using R = typename M::iterator;
172 M m;
173 for (int i = 0; i < 20; i += 2)
174 m.emplace(Moveable(i, (double)i), Moveable(i + 1, (double)i + 1));
175 assert(m.size() == 10);
176 typename M::const_iterator it = std::next(m.cbegin());
177
178 Moveable mvkey1(2, 2.0);
179 Moveable mv1(4, 4.0);
180 std::same_as<R> decltype(auto) r1 = m.try_emplace(it, std::move(mvkey1), std::move(mv1));
181 assert(m.size() == 10);
182 assert(!mv1.moved()); // was not moved from
183 assert(!mvkey1.moved()); // was not moved from
184 assert(r1->first == mvkey1); // key
185
186 Moveable mvkey2(3, 3.0);
187 std::same_as<R> decltype(auto) r2 = m.try_emplace(it, std::move(mvkey2), std::move(mv1));
188 assert(m.size() == 11);
189 assert(mv1.moved()); // was moved from
190 assert(mvkey2.moved()); // was moved from
191 assert(r2->first.get() == 3); // key
192 assert(r2->second.get() == 4); // value
193 }
194}
195
196int main(int, char**) {
197 test_ck<std::vector<int>, std::vector<Moveable>>();
198 test_ck<std::deque<int>, std::vector<Moveable>>();
199 test_ck<MinSequenceContainer<int>, MinSequenceContainer<Moveable>>();
200 test_ck<std::vector<int, min_allocator<int>>, std::vector<Moveable, min_allocator<Moveable>>>();
201
202 test_rk<std::vector<Moveable>, std::vector<Moveable>>();
203 test_rk<std::deque<Moveable>, std::vector<Moveable>>();
204 test_rk<MinSequenceContainer<Moveable>, MinSequenceContainer<Moveable>>();
205 test_rk<std::vector<Moveable, min_allocator<Moveable>>, std::vector<Moveable, min_allocator<Moveable>>>();
206
207 {
208 auto try_emplace_ck = [](auto& m, auto key_arg, auto value_arg) {
209 using M = std::decay_t<decltype(m)>;
210 using Key = typename M::key_type;
211 const Key key{key_arg};
212 m.try_emplace(key, value_arg);
213 };
214 test_emplace_exception_guarantee(emplace_function&: try_emplace_ck);
215 }
216
217 {
218 auto try_emplace_rk = [](auto& m, auto key_arg, auto value_arg) {
219 using M = std::decay_t<decltype(m)>;
220 using Key = typename M::key_type;
221 m.try_emplace(Key{key_arg}, value_arg);
222 };
223 test_emplace_exception_guarantee(emplace_function&: try_emplace_rk);
224 }
225
226 {
227 auto try_emplace_iter_ck = [](auto& m, auto key_arg, auto value_arg) {
228 using M = std::decay_t<decltype(m)>;
229 using Key = typename M::key_type;
230 const Key key{key_arg};
231 m.try_emplace(m.begin(), key, value_arg);
232 };
233 test_emplace_exception_guarantee(emplace_function&: try_emplace_iter_ck);
234 }
235
236 {
237 auto try_emplace_iter_rk = [](auto& m, auto key_arg, auto value_arg) {
238 using M = std::decay_t<decltype(m)>;
239 using Key = typename M::key_type;
240 m.try_emplace(m.begin(), Key{key_arg}, value_arg);
241 };
242 test_emplace_exception_guarantee(emplace_function&: try_emplace_iter_rk);
243 }
244
245 return 0;
246}
247

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