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 |
10 | |
11 | // <unordered_map> |
12 | |
13 | // class unordered_map |
14 | |
15 | // template <class... Args> |
16 | // pair<iterator, bool> try_emplace(const key_type& k, Args&&... args); // C++17 |
17 | // template <class... Args> |
18 | // pair<iterator, bool> try_emplace(key_type&& k, Args&&... args); // C++17 |
19 | // template <class... Args> |
20 | // iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); // C++17 |
21 | // template <class... Args> |
22 | // iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); // C++17 |
23 | |
24 | #include <unordered_map> |
25 | #include <cassert> |
26 | #include <iterator> |
27 | #include <tuple> |
28 | |
29 | #include "test_macros.h" |
30 | |
31 | class Moveable |
32 | { |
33 | Moveable(const Moveable&); |
34 | Moveable& operator=(const Moveable&); |
35 | |
36 | int int_; |
37 | double double_; |
38 | public: |
39 | Moveable() : int_(0), double_(0) {} |
40 | Moveable(int i, double d) : int_(i), double_(d) {} |
41 | Moveable(Moveable&& x) |
42 | : int_(x.int_), double_(x.double_) |
43 | {x.int_ = -1; x.double_ = -1;} |
44 | Moveable& operator=(Moveable&& x) |
45 | {int_ = x.int_; x.int_ = -1; |
46 | double_ = x.double_; x.double_ = -1; |
47 | return *this; |
48 | } |
49 | |
50 | bool operator==(const Moveable& x) const |
51 | {return int_ == x.int_ && double_ == x.double_;} |
52 | bool operator<(const Moveable& x) const |
53 | {return int_ < x.int_ || (int_ == x.int_ && double_ < x.double_);} |
54 | std::size_t hash () const { return std::hash<int>()(int_) + std::hash<double>()(double_); } |
55 | |
56 | int get() const {return int_;} |
57 | bool moved() const {return int_ == -1;} |
58 | }; |
59 | |
60 | namespace std { |
61 | template <> struct hash<Moveable> { |
62 | std::size_t operator () (const Moveable &m) const { return m.hash(); } |
63 | }; |
64 | } |
65 | |
66 | int main(int, char**) |
67 | { |
68 | |
69 | { // pair<iterator, bool> try_emplace(const key_type& k, Args&&... args); |
70 | typedef std::unordered_map<int, Moveable> M; |
71 | typedef std::pair<M::iterator, bool> R; |
72 | M m; |
73 | R r; |
74 | for (int i = 0; i < 20; i += 2) |
75 | m.emplace (args&: i, args: Moveable(i, (double) i)); |
76 | assert(m.size() == 10); |
77 | |
78 | Moveable mv1(3, 3.0); |
79 | for (int i=0; i < 20; i += 2) |
80 | { |
81 | r = m.try_emplace(k: i, args: 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 | r = m.try_emplace(k: -1, args: std::move(mv1)); |
89 | assert(m.size() == 11); |
90 | assert(r.second); // was inserted |
91 | assert(mv1.moved()); // was moved from |
92 | assert(r.first->first == -1); // key |
93 | assert(r.first->second.get() == 3); // value |
94 | |
95 | Moveable mv2(5, 3.0); |
96 | r = m.try_emplace(k: 5, args: std::move(mv2)); |
97 | assert(m.size() == 12); |
98 | assert(r.second); // was inserted |
99 | assert(mv2.moved()); // was moved from |
100 | assert(r.first->first == 5); // key |
101 | assert(r.first->second.get() == 5); // value |
102 | |
103 | Moveable mv3(-1, 3.0); |
104 | r = m.try_emplace(k: 117, args: std::move(mv2)); |
105 | assert(m.size() == 13); |
106 | assert(r.second); // was inserted |
107 | assert(mv2.moved()); // was moved from |
108 | assert(r.first->first == 117); // key |
109 | assert(r.first->second.get() == -1); // value |
110 | } |
111 | |
112 | { // pair<iterator, bool> try_emplace(key_type&& k, Args&&... args); |
113 | typedef std::unordered_map<Moveable, Moveable> M; |
114 | typedef std::pair<M::iterator, bool> R; |
115 | M m; |
116 | R r; |
117 | for (int i = 0; i < 20; i += 2) |
118 | m.emplace ( args: Moveable(i, (double) i), args: Moveable(i+1, (double) i+1)); |
119 | assert(m.size() == 10); |
120 | |
121 | Moveable mvkey1(2, 2.0); |
122 | Moveable mv1(4, 4.0); |
123 | r = m.try_emplace(k: std::move(mvkey1), args: std::move(mv1)); |
124 | assert(m.size() == 10); |
125 | assert(!r.second); // was not inserted |
126 | assert(!mv1.moved()); // was not moved from |
127 | assert(!mvkey1.moved()); // was not moved from |
128 | assert(r.first->first == mvkey1); // key |
129 | |
130 | Moveable mvkey2(3, 3.0); |
131 | r = m.try_emplace(k: std::move(mvkey2), args: std::move(mv1)); |
132 | assert(m.size() == 11); |
133 | assert(r.second); // was inserted |
134 | assert(mv1.moved()); // was moved from |
135 | assert(mvkey2.moved()); // was moved from |
136 | assert(r.first->first.get() == 3); // key |
137 | assert(r.first->second.get() == 4); // value |
138 | } |
139 | |
140 | { // iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); |
141 | typedef std::unordered_map<int, Moveable> M; |
142 | M m; |
143 | M::iterator r; |
144 | for (int i = 0; i < 20; i += 2) |
145 | m.try_emplace ( k: i, args: Moveable(i, (double) i)); |
146 | assert(m.size() == 10); |
147 | M::const_iterator it = m.find(x: 2); |
148 | |
149 | Moveable mv1(3, 3.0); |
150 | for (int i=0; i < 20; i += 2) |
151 | { |
152 | r = m.try_emplace(hint: it, k: i, args: std::move(mv1)); |
153 | assert(m.size() == 10); |
154 | assert(!mv1.moved()); // was not moved from |
155 | assert(r->first == i); // key |
156 | assert(r->second.get() == i); // value |
157 | } |
158 | |
159 | r = m.try_emplace(hint: it, k: 3, args: std::move(mv1)); |
160 | assert(m.size() == 11); |
161 | assert(mv1.moved()); // was moved from |
162 | assert(r->first == 3); // key |
163 | assert(r->second.get() == 3); // value |
164 | } |
165 | |
166 | { // iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); |
167 | typedef std::unordered_map<Moveable, Moveable> M; |
168 | M m; |
169 | M::iterator r; |
170 | for ( int i = 0; i < 20; i += 2 ) |
171 | m.emplace ( args: Moveable(i, (double) i), args: Moveable(i+1, (double) i+1)); |
172 | assert(m.size() == 10); |
173 | M::const_iterator it = std::next(x: m.cbegin()); |
174 | |
175 | Moveable mvkey1(2, 2.0); |
176 | Moveable mv1(4, 4.0); |
177 | r = m.try_emplace(hint: it, k: std::move(mvkey1), args: std::move(mv1)); |
178 | assert(m.size() == 10); |
179 | assert(!mv1.moved()); // was not moved from |
180 | assert(!mvkey1.moved()); // was not moved from |
181 | assert(r->first == mvkey1); // key |
182 | |
183 | Moveable mvkey2(3, 3.0); |
184 | r = m.try_emplace(hint: it, k: std::move(mvkey2), args: std::move(mv1)); |
185 | assert(m.size() == 11); |
186 | assert(mv1.moved()); // was moved from |
187 | assert(mvkey2.moved()); // was moved from |
188 | assert(r->first.get() == 3); // key |
189 | assert(r->second.get() == 4); // value |
190 | } |
191 | |
192 | return 0; |
193 | } |
194 | |