1 // { dg-do run { target c++17 } }
2 // { dg-require-effective-target std_allocator_new }
3 
4 // Copyright (C) 2021 Free Software Foundation, Inc.
5 //
6 // This file is part of the GNU ISO C++ Library.  This library is free
7 // software; you can redistribute it and/or modify it under the
8 // terms of the GNU General Public License as published by the
9 // Free Software Foundation; either version 3, or (at your option)
10 // any later version.
11 
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU General Public License for more details.
16 
17 // You should have received a copy of the GNU General Public License along
18 // with this library; see the file COPYING3.  If not see
19 // <http://www.gnu.org/licenses/>.
20 
21 // libstdc++/96088
22 
23 #include <string_view>
24 #include <string>
25 #include <unordered_set>
26 #include <vector>
27 
28 #include <testsuite_hooks.h>
29 #include <replacement_memory_operators.h>
30 
31 static constexpr std::initializer_list<const char*> lst = {
32   "long_str_for_dynamic_allocating"
33 };
34 
35 void
test01()36 test01()
37 {
38   __gnu_test::counter::reset();
39   std::unordered_set<std::string> us;
40   us.insert(lst.begin(), lst.end());
41   VERIFY( us.size() == 1 );
42 
43   VERIFY( __gnu_test::counter::count() == 3 );
44   VERIFY( __gnu_test::counter::get()._M_increments == 3 );
45 
46   us.insert(lst.begin(), lst.end());
47   VERIFY( us.size() == 1 );
48 
49   VERIFY( __gnu_test::counter::count() == 3 );
50   VERIFY( __gnu_test::counter::get()._M_increments == 4 );
51 }
52 
53 void
test02()54 test02()
55 {
56   __gnu_test::counter::reset();
57   std::unordered_set<std::string,
58 		     std::hash<std::string_view>,
59 		     std::equal_to<std::string_view>> us;
60   us.insert(lst.begin(), lst.end());
61   VERIFY( us.size() == 1 );
62 
63   VERIFY( __gnu_test::counter::count() == 3 );
64   VERIFY( __gnu_test::counter::get()._M_increments == 3 );
65 
66   us.insert(lst.begin(), lst.end());
67   VERIFY( us.size() == 1 );
68 
69   VERIFY( __gnu_test::counter::count() == 3 );
70   VERIFY( __gnu_test::counter::get()._M_increments == 3 );
71 }
72 
73 std::size_t
hash_string_f(const std::string & str)74 hash_string_f(const std::string& str) noexcept
75 {
76   std::hash<std::string> h;
77   return h(str);
78 }
79 
80 void
test11()81 test11()
82 {
83   typedef std::size_t (*hash_string_t)(const std::string&) noexcept;
84   __gnu_test::counter::reset();
85   hash_string_t hasher = &hash_string_f;
86   std::unordered_set<std::string,
87 		     hash_string_t,
88 		     std::equal_to<std::string>> us(0, hasher);
89   us.insert(lst.begin(), lst.end());
90   VERIFY( us.size() == 1 );
91 
92   VERIFY( __gnu_test::counter::count() == 3 );
93   VERIFY( __gnu_test::counter::get()._M_increments == 3 );
94 
95   us.insert(lst.begin(), lst.end());
96   VERIFY( us.size() == 1 );
97 
98   VERIFY( __gnu_test::counter::count() == 3 );
99   VERIFY( __gnu_test::counter::get()._M_increments == 4 );
100 }
101 
102 std::size_t
hash_string_view_f(const std::string_view & str)103 hash_string_view_f(const std::string_view& str) noexcept
104 {
105   std::hash<std::string_view> h;
106   return h(str);
107 }
108 
109 void
test12()110 test12()
111 {
112   typedef std::size_t (*hash_stringview_t)(const std::string_view&) noexcept;
113   __gnu_test::counter::reset();
114   hash_stringview_t hasher = &hash_string_view_f;
115   std::unordered_set<std::string,
116 		     hash_stringview_t,
117 		     std::equal_to<std::string_view>> us(0, hasher);
118   us.insert(lst.begin(), lst.end());
119   VERIFY( us.size() == 1 );
120 
121   VERIFY( __gnu_test::counter::count() == 3 );
122   VERIFY( __gnu_test::counter::get()._M_increments == 3 );
123 
124   us.insert(lst.begin(), lst.end());
125   VERIFY( us.size() == 1 );
126 
127   VERIFY( __gnu_test::counter::count() == 3 );
128   VERIFY( __gnu_test::counter::get()._M_increments == 3 );
129 }
130 
131 struct hash_string_functor
132 {
133   std::size_t
operator ()hash_string_functor134   operator()(const std::string& str) const noexcept
135   {
136     std::hash<std::string> h;
137     return h(str);
138   }
139 };
140 
141 void
test21()142 test21()
143 {
144   __gnu_test::counter::reset();
145   std::unordered_set<std::string,
146 		     hash_string_functor,
147 		     std::equal_to<std::string>> us;
148   us.insert(lst.begin(), lst.end());
149   VERIFY( us.size() == 1 );
150 
151   VERIFY( __gnu_test::counter::count() == 3 );
152   VERIFY( __gnu_test::counter::get()._M_increments == 3 );
153 
154   us.insert(lst.begin(), lst.end());
155   VERIFY( us.size() == 1 );
156 
157   VERIFY( __gnu_test::counter::count() == 3 );
158   VERIFY( __gnu_test::counter::get()._M_increments == 4 );
159 }
160 
161 struct hash_string_view_noexcept_functor
162 {
163   std::size_t
operator ()hash_string_view_noexcept_functor164   operator()(const std::string_view& str) const noexcept
165   {
166     std::hash<std::string_view> h;
167     return h(str);
168   }
169 };
170 
171 void
test22()172 test22()
173 {
174   __gnu_test::counter::reset();
175   std::unordered_set<std::string,
176 		     hash_string_view_noexcept_functor,
177 		     std::equal_to<std::string_view>> us;
178   us.insert(lst.begin(), lst.end());
179   VERIFY( us.size() == 1 );
180 
181   VERIFY( __gnu_test::counter::count() == 3 );
182   VERIFY( __gnu_test::counter::get()._M_increments == 3 );
183 
184   us.insert(lst.begin(), lst.end());
185   VERIFY( us.size() == 1 );
186 
187   VERIFY( __gnu_test::counter::count() == 3 );
188   VERIFY( __gnu_test::counter::get()._M_increments == 3 );
189 }
190 
191 struct hash_string_view_functor
192 {
193   std::size_t
operator ()hash_string_view_functor194   operator()(const std::string_view& str) const
195   {
196     std::hash<std::string_view> h;
197     return h(str);
198   }
199 };
200 
201 void
test23()202 test23()
203 {
204   __gnu_test::counter::reset();
205   std::unordered_set<std::string,
206 		     hash_string_view_functor,
207 		     std::equal_to<std::string_view>> us;
208   us.insert(lst.begin(), lst.end());
209   VERIFY( us.size() == 1 );
210 
211   VERIFY( __gnu_test::counter::count() == 3 );
212   VERIFY( __gnu_test::counter::get()._M_increments == 3 );
213 
214   us.insert(lst.begin(), lst.end());
215   VERIFY( us.size() == 1 );
216 
217   VERIFY( __gnu_test::counter::count() == 3 );
218   VERIFY( __gnu_test::counter::get()._M_increments == 3 );
219 }
220 
221 void
test03()222 test03()
223 {
224   std::vector<std::string> v;
225   v.insert(v.end(), lst.begin(), lst.end());
226 
227   const auto origin = __gnu_test::counter::count();
228 
229   {
230     __gnu_test::counter::reset();
231     std::unordered_set<std::string,
232 		       std::hash<std::string_view>,
233 		       std::equal_to<std::string_view>> us;
234     us.insert(v.begin(), v.end());
235     VERIFY( us.size() == 1 );
236 
237     // Allocate array of buckets, a node, and the std::string (unless COW).
238     constexpr std::size_t increments = _GLIBCXX_USE_CXX11_ABI ? 3 : 2;
239 
240     VERIFY( __gnu_test::counter::count() == origin + increments );
241     VERIFY( __gnu_test::counter::get()._M_increments == increments );
242 
243     us.insert(v.begin(), v.end());
244     VERIFY( us.size() == 1 );
245 
246     VERIFY( __gnu_test::counter::count() == origin + increments );
247     VERIFY( __gnu_test::counter::get()._M_increments == increments );
248   }
249   VERIFY( __gnu_test::counter::count() == origin );
250 
251   {
252     __gnu_test::counter::reset();
253     std::unordered_set<std::string,
254 		       std::hash<std::string_view>,
255 		       std::equal_to<std::string_view>> us;
256     us.insert(std::make_move_iterator(v.begin()),
257 	      std::make_move_iterator(v.end()));
258     VERIFY( us.size() == 1 );
259 
260     // Allocate array of buckets and a node. String is moved.
261     constexpr std::size_t increments = 2;
262 
263     VERIFY( __gnu_test::counter::count() == origin + increments );
264     VERIFY( __gnu_test::counter::get()._M_increments == increments );
265   }
266 }
267 
268 int
main()269 main()
270 {
271   test01();
272   test02();
273   test11();
274   test12();
275   test21();
276   test22();
277   test23();
278   test03();
279   return 0;
280 }
281