source: mainline/uspace/lib/cpp/include/impl/unordered_set.hpp@ 2d46556

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2d46556 was 2d46556, checked in by Dzejrou <dzejrou@…>, 7 years ago

cpp: moved logic to the underlying table

  • Property mode set to 100644
File size: 16.8 KB
Line 
1/*
2 * Copyright (c) 2018 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_UNORDERED_SET
30#define LIBCPP_UNORDERED_SET
31
32#include <initializer_list>
33#include <internal/hash_table.hpp>
34#include <functional>
35#include <memory>
36#include <utility>
37
38namespace std
39{
40 /**
41 * 23.5.6, class template unordered_set:
42 */
43
44 template<
45 class Key,
46 class Hash = hash<Key>,
47 class Pred = equal_to<Key>,
48 class Alloc = allocator<Key>
49 >
50 class unordered_set
51 {
52 public:
53 using key_type = Key;
54 using value_type = Key;
55 using hasher = Hash;
56 using key_equal = Pred;
57 using allocator_type = Alloc;
58 using pointer = typename allocator_traits<allocator_type>::pointer;
59 using const_pointer = typename allocator_traits<allocator_type>::const_pointer;
60 using reference = value_type&;
61 using const_reference = const value_type&;
62 using size_type = size_t;
63 using difference_type = ptrdiff_t;
64
65 /**
66 * Note: Both the iterator and const_iterator (and their local variants)
67 * types are constant iterators, the standard does not require them
68 * to be the same type, but why not? :)
69 */
70 using iterator = aux::hash_table_const_iterator<
71 value_type, const_reference, const_pointer, size_type
72 >;
73 using const_iterator = iterator;
74 using local_iterator = aux::hash_table_const_local_iterator<
75 value_type, const_reference, const_pointer
76 >;
77 using const_local_iterator = local_iterator;
78
79 /**
80 * Note: We need () to delegate the constructor,
81 * otherwise it could be deduced as the initializer
82 * list constructor when size_type is convertible
83 * to value_type.
84 */
85 unordered_set()
86 : unordered_set(default_bucket_count_)
87 { /* DUMMY BODY */ }
88
89 explicit unordered_set(size_type bucket_count,
90 const hasher& hf = hasher{},
91 const key_equal& eql = key_equal{},
92 const allocator_type& alloc = allocator_type{})
93 : table_{bucket_count, hf, eql}, allocator_{alloc}
94 { /* DUMMY BODY */ }
95
96 template<class InputIterator>
97 unordered_set(InputIterator first, InputIterator last,
98 size_type bucket_count = default_bucket_count_,
99 const hasher& hf = hasher{},
100 const key_equal& eql = key_equal{},
101 const allocator_type& alloc = allocator_type{})
102 : unordered_set{bucket_count, hf, eql, alloc}
103 {
104 insert(first, last);
105 }
106
107 unordered_set(const unordered_set& other)
108 : unordered_set{other, other.allocator_}
109 { /* DUMMY BODY */ }
110
111 unordered_set(unordered_set&& other)
112 : table_{move(other.table_)}, allocator_{move(other.allocator_)}
113 { /* DUMMY BODY */ }
114
115 explicit unordered_set(const allocator_type& alloc)
116 : table_{default_bucket_count_}, allocator_{alloc}
117 { /* DUMMY BODY */ }
118
119 unordered_set(const unordered_set& other, const allocator_type& alloc)
120 : table_{other.table_}, allocator_{alloc}
121 { /* DUMMY BODY */ }
122
123 unordered_set(unordered_set&& other, const allocator_type& alloc)
124 : table_{move(other.table_)}, allocator_{alloc}
125 { /* DUMMY BODY */ }
126
127 unordered_set(initializer_list<value_type> init,
128 size_type bucket_count = default_bucket_count_,
129 const hasher& hf = hasher{},
130 const key_equal& eql = key_equal{},
131 const allocator_type& alloc = allocator_type{})
132 : unordered_set{bucket_count, hf, eql, alloc}
133 {
134 insert(init.begin(), init.end());
135 }
136
137 unordered_set(size_type bucket_count, const allocator_type& alloc)
138 : unordered_set{bucket_count, hasher{}, key_equal{}, alloc}
139 { /* DUMMY BODY */ }
140
141 unordered_set(size_type bucket_count, const hasher& hf, const allocator_type& alloc)
142 : unordered_set{bucket_count, hf, key_equal{}, alloc}
143 { /* DUMMY BODY */ }
144
145 template<class InputIterator>
146 unordered_set(InputIterator first, InputIterator last,
147 size_type bucket_count, const allocator_type& alloc)
148 : unordered_set{first, last, bucket_count, hasher{}, key_equal{}, alloc}
149 { /* DUMMY BODY */ }
150
151 template<class InputIterator>
152 unordered_set(InputIterator first, InputIterator last,
153 size_type bucket_count, const hasher& hf, const allocator_type& alloc)
154 : unordered_set{first, last, bucket_count, hf, key_equal{}, alloc}
155 { /* DUMMY BODY */ }
156
157 unordered_set(initializer_list<value_type> init, size_type bucket_count,
158 const allocator_type& alloc)
159 : unordered_set{init, bucket_count, hasher{}, key_equal{}, alloc}
160 { /* DUMMY BODY */ }
161
162 unordered_set(initializer_list<value_type> init, size_type bucket_count,
163 const hasher& hf, const allocator_type& alloc)
164 : unordered_set{init, bucket_count, hf, key_equal{}, alloc}
165 { /* DUMMY BODY */ }
166
167 ~unordered_set()
168 { /* DUMMY BODY */ }
169
170 unordered_set& operator=(const unordered_set& other)
171 {
172 table_ = other.table_;
173 allocator_ = other.allocator_;
174
175 return *this;
176 }
177
178 unordered_set& operator=(unordered_set&& other)
179 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
180 is_nothrow_move_assignable<hasher>::value &&
181 is_nothrow_move_assignable<key_equal>::value)
182 {
183 table_ = move(other.table_);
184 allocator_ = move(other.allocator_);
185
186 return *this;
187 }
188
189 unordered_set& operator=(initializer_list<value_type>& init)
190 {
191 table_.clear();
192 table_.reserve(init.size());
193
194 insert(init.begin(), init.end());
195
196 return *this;
197 }
198
199 allocator_type get_allocator() const noexcept
200 {
201 return allocator_;
202 }
203
204 bool empty() const noexcept
205 {
206 return table_.empty();
207 }
208
209 size_type size() const noexcept
210 {
211 return table_.size();
212 }
213
214 size_type max_size() const noexcept
215 {
216 return table_.max_size(allocator_);
217 }
218
219 iterator begin() noexcept
220 {
221 return table_.begin();
222 }
223
224 const_iterator begin() const noexcept
225 {
226 return table_.begin();
227 }
228
229 iterator end() noexcept
230 {
231 return table_.end();
232 }
233
234 const_iterator end() const noexcept
235 {
236 return table_.end();
237 }
238
239 const_iterator cbegin() const noexcept
240 {
241 return table_.cbegin();
242 }
243
244 const_iterator cend() const noexcept
245 {
246 return table_.cend();
247 }
248
249 template<class... Args>
250 pair<iterator, bool> emplace(Args&&... args)
251 {
252 return table_.emplace(forward<Args>(args)...);
253 }
254
255 template<class... Args>
256 iterator emplace_hint(const_iterator, Args&&... args)
257 {
258 return emplace(forward<Args>(args)...).first;
259 }
260
261 pair<iterator, bool> insert(const value_type& val)
262 {
263 return table_.insert(val);
264 }
265
266 pair<iterator, bool> insert(value_type&& val)
267 {
268 return table_.insert(forward<value_type>(val));
269 }
270
271 iterator insert(const_iterator, const value_type& val)
272 {
273 return insert(val).first;
274 }
275
276 iterator insert(const_iterator, value_type&& val)
277 {
278 return insert(forward<value_type>(val)).first;
279 }
280
281 template<class InputIterator>
282 void insert(InputIterator first, InputIterator last)
283 {
284 while (first != last)
285 insert(*first++);
286 }
287
288 void insert(initializer_list<value_type> init)
289 {
290 insert(init.begin(), init.end());
291 }
292
293 iterator erase(const_iterator position)
294 {
295 return table_.erase(position);
296 }
297
298 size_type erase(const key_type& key)
299 {
300 return table_.erase(key);
301 }
302
303 iterator erase(const_iterator first, const_iterator last)
304 {
305 while (first != last)
306 first = erase(first);
307
308 return iterator{
309 table_.table(), first.idx(),
310 table_.bucket_count(), table_.head(first.idx())
311 }; // TODO: why do we pass table_.head(first.idx()) here?
312 }
313
314 void clear() noexcept
315 {
316 table_.clear();
317 }
318
319 void swap(unordered_set& other)
320 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
321 noexcept(std::swap(declval<hasher>(), declval<hasher>())) &&
322 noexcept(std::swap(declval<key_equal>(), declval<key_equal>())))
323 {
324 table_.swap(other.table_);
325 std::swap(allocator_, other.allocator_);
326 }
327
328 hasher hash_function() const
329 {
330 return table_.hash_function();
331 }
332
333 key_equal key_eq() const
334 {
335 return table_.key_eq();
336 }
337
338 iterator find(const key_type& key)
339 {
340 return table_.find(key);
341 }
342
343 const_iterator find(const key_type& key) const
344 {
345 return table_.find(key);
346 }
347
348 size_type count(const key_type& key) const
349 {
350 return table_.count(key);
351 }
352
353 pair<iterator, iterator> equal_range(const key_type& key)
354 {
355 return table_.equal_range(key);
356 }
357
358 pair<const_iterator, const_iterator> equal_range(const key_type& key) const
359 {
360 return table_.equal_range(key);
361 }
362
363 size_type bucket_count() const noexcept
364 {
365 return table_.bucket_count();
366 }
367
368 size_type max_bucket_count() const noexcept
369 {
370 return table_.max_bucket_count();
371 }
372
373 size_type bucket_size(size_type idx) const
374 {
375 return table_.bucket_size(idx);
376 }
377
378 size_type bucket(const key_type& key) const
379 {
380 return table_.bucket(key);
381 }
382
383 local_iterator begin(size_type idx)
384 {
385 return table_.begin(idx);
386 }
387
388 const_local_iterator begin(size_type idx) const
389 {
390 return table_.begin(idx);
391 }
392
393 local_iterator end(size_type idx)
394 {
395 return table_.end(idx);
396 }
397
398 const_local_iterator end(size_type idx) const
399 {
400 return table_.end(idx);
401 }
402
403 const_local_iterator cbegin(size_type idx) const
404 {
405 return table_.cbegin(idx);
406 }
407
408 const_local_iterator cend(size_type idx) const
409 {
410 return table_.cend(idx);
411 }
412
413 float load_factor() const noexcept
414 {
415 return table_.load_factor();
416 }
417
418 float max_load_factor() const noexcept
419 {
420 return table_.max_load_factor();
421 }
422
423 void max_load_factor(float factor)
424 {
425 table_.max_load_factor(factor);
426 }
427
428 void rehash(size_type bucket_count)
429 {
430 table_.rehash(bucket_count);
431 }
432
433 void reserve(size_type count)
434 {
435 table_.reserve(count);
436 }
437
438 private:
439 using table_type = aux::hash_table<
440 key_type, key_type, aux::key_no_value_key_extractor<key_type>,
441 hasher, key_equal, allocator_type, size_type,
442 iterator, const_iterator, local_iterator, const_local_iterator,
443 aux::hash_single_policy
444 >;
445 using node_type = typename table_type::node_type;
446
447 table_type table_;
448 allocator_type allocator_;
449
450 static constexpr size_type default_bucket_count_{16};
451
452 template<class K, class H, class P, class A>
453 friend bool operator==(unordered_set<K, H, P, A>&,
454 unordered_set<K, H, P, A>&);
455 };
456
457 /**
458 * 23.5.7, class template unordered_multiset:
459 */
460
461 template<
462 class Key,
463 class Hash = hash<Key>,
464 class Pred = equal_to<Key>,
465 class Alloc = allocator<Key>
466 >
467 class unordered_multiset;
468
469 template<class Key, class Hash, class Pred, class Alloc>
470 void swap(unordered_set<Key, Hash, Pred, Alloc>& lhs,
471 unordered_set<Key, Hash, Pred, Alloc>& rhs)
472 noexcept(noexcept(lhs.swap(rhs)))
473 {
474 lhs.swap(rhs);
475 }
476
477 template<class Key, class Hash, class Pred, class Alloc>
478 void swap(unordered_multiset<Key, Hash, Pred, Alloc>& lhs,
479 unordered_multiset<Key, Hash, Pred, Alloc>& rhs)
480 noexcept(noexcept(lhs.swap(rhs)))
481 {
482 lhs.swap(rhs);
483 }
484
485 template<class Key, class Hash, class Pred, class Alloc>
486 bool operator==(unordered_set<Key, Hash, Pred, Alloc>& lhs,
487 unordered_set<Key, Hash, Pred, Alloc>& rhs)
488 {
489 return lhs.table_.is_eq_to(rhs.table_);
490 }
491
492 template<class Key, class Hash, class Pred, class Alloc>
493 bool operator!=(unordered_set<Key, Hash, Pred, Alloc>& lhs,
494 unordered_set<Key, Hash, Pred, Alloc>& rhs)
495 {
496 return !(lhs == rhs);
497 }
498
499 template<class Key, class Hash, class Pred, class Alloc>
500 bool operator==(unordered_multiset<Key, Hash, Pred, Alloc>& lhs,
501 unordered_multiset<Key, Hash, Pred, Alloc>& rhs)
502 {
503 return lhs.table_.is_eq_to(rhs.table_);
504 }
505
506 template<class Key, class Value, class Hash, class Pred, class Alloc>
507 bool operator!=(unordered_multiset<Key, Hash, Pred, Alloc>& lhs,
508 unordered_multiset<Key, Hash, Pred, Alloc>& rhs)
509 {
510 return !(lhs == rhs);
511 }
512}
513
514#endif
Note: See TracBrowser for help on using the repository browser.