blob: 95ecd3496f3df110f637ec7858f53a6822f24097 [file] [log] [blame]
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
Howard Hinnantf5256e12010-05-11 21:36:01 +00004// The LLVM Compiler Infrastructure
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00005//
6// This file is distributed under the University of Illinois Open Source
7// License. See LICENSE.TXT for details.
8//
9//===----------------------------------------------------------------------===//
10
11#ifndef _LIBCPP__HASH_TABLE
12#define _LIBCPP__HASH_TABLE
13
14#include <__config>
15#include <initializer_list>
16#include <memory>
17#include <iterator>
18#include <algorithm>
19#include <cmath>
20
21#pragma GCC system_header
22
23_LIBCPP_BEGIN_NAMESPACE_STD
24
25size_t __next_prime(size_t);
26
27template <class _NodePtr>
28struct __hash_node_base
29{
30 typedef __hash_node_base __first_node;
31 typedef _NodePtr pointer;
32
33 pointer __next_;
34
35 __hash_node_base() : __next_(nullptr) {}
36};
37
38template <class _Tp, class _VoidPtr>
39struct __hash_node
40 : public __hash_node_base
41 <
42 typename pointer_traits<_VoidPtr>::template
43#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
44 rebind<__hash_node<_Tp, _VoidPtr> >
45#else
46 rebind<__hash_node<_Tp, _VoidPtr> >::other
47#endif
48 >
49{
50 typedef _Tp value_type;
51
52 size_t __hash_;
53 value_type __value_;
54};
55
56template <class, class, class, class> class __hash_table;
57template <class> class __hash_const_iterator;
58template <class> class __hash_map_iterator;
59template <class> class __hash_map_const_iterator;
60template <class, class, class, class, class> class unordered_map;
61
62template <class _NodePtr>
63class __hash_iterator
64{
65 typedef _NodePtr __node_pointer;
66
67 __node_pointer __node_;
68
69public:
70 typedef forward_iterator_tag iterator_category;
71 typedef typename pointer_traits<__node_pointer>::element_type::value_type value_type;
72 typedef typename pointer_traits<__node_pointer>::difference_type difference_type;
73 typedef value_type& reference;
74 typedef typename pointer_traits<__node_pointer>::template
75#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
76 rebind<value_type>
77#else
78 rebind<value_type>::other
79#endif
80 pointer;
81
82 __hash_iterator() {}
83
84 reference operator*() const {return __node_->__value_;}
85 pointer operator->() const {return addressof(__node_->__value_);}
86
87 __hash_iterator& operator++()
88 {
89 __node_ = __node_->__next_;
90 return *this;
91 }
92
93 __hash_iterator operator++(int)
94 {
95 __hash_iterator __t(*this);
96 ++(*this);
97 return __t;
98 }
99
100 friend bool operator==(const __hash_iterator& __x, const __hash_iterator& __y)
101 {return __x.__node_ == __y.__node_;}
102 friend bool operator!=(const __hash_iterator& __x, const __hash_iterator& __y)
103 {return __x.__node_ != __y.__node_;}
104
105private:
106 __hash_iterator(__node_pointer __node)
107 : __node_(__node)
108 {}
109
110 template <class, class, class, class> friend class __hash_table;
111 template <class> friend class __hash_const_iterator;
112 template <class> friend class __hash_map_iterator;
113 template <class, class, class, class, class> friend class unordered_map;
114 template <class, class, class, class, class> friend class unordered_multimap;
115};
116
117template <class _ConstNodePtr>
118class __hash_const_iterator
119{
120 typedef _ConstNodePtr __node_pointer;
121
122 __node_pointer __node_;
123
124 typedef typename remove_const<
125 typename pointer_traits<__node_pointer>::element_type
126 >::type __node;
127
128public:
129 typedef forward_iterator_tag iterator_category;
130 typedef typename __node::value_type value_type;
131 typedef typename pointer_traits<__node_pointer>::difference_type difference_type;
132 typedef const value_type& reference;
133 typedef typename pointer_traits<__node_pointer>::template
134#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
135 rebind<const value_type>
136#else
137 rebind<const value_type>::other
138#endif
139 pointer;
140 typedef typename pointer_traits<__node_pointer>::template
141#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
142 rebind<__node>
143#else
144 rebind<__node>::other
145#endif
146 __non_const_node_pointer;
147 typedef __hash_iterator<__non_const_node_pointer> __non_const_iterator;
148
149 __hash_const_iterator() {}
150 __hash_const_iterator(const __non_const_iterator& __x)
151 : __node_(__x.__node_)
152 {}
153
154 reference operator*() const {return __node_->__value_;}
155 pointer operator->() const {return addressof(__node_->__value_);}
156
157 __hash_const_iterator& operator++()
158 {
159 __node_ = __node_->__next_;
160 return *this;
161 }
162
163 __hash_const_iterator operator++(int)
164 {
165 __hash_const_iterator __t(*this);
166 ++(*this);
167 return __t;
168 }
169
170 friend bool operator==(const __hash_const_iterator& __x, const __hash_const_iterator& __y)
171 {return __x.__node_ == __y.__node_;}
172 friend bool operator!=(const __hash_const_iterator& __x, const __hash_const_iterator& __y)
173 {return __x.__node_ != __y.__node_;}
174
175private:
176 __hash_const_iterator(__node_pointer __node)
177 : __node_(__node)
178 {}
179
180 template <class, class, class, class> friend class __hash_table;
181 template <class> friend class __hash_map_const_iterator;
182 template <class, class, class, class, class> friend class unordered_map;
183 template <class, class, class, class, class> friend class unordered_multimap;
184};
185
186template <class> class __hash_const_local_iterator;
187
188template <class _NodePtr>
189class __hash_local_iterator
190{
191 typedef _NodePtr __node_pointer;
192
193 __node_pointer __node_;
194 size_t __bucket_;
195 size_t __bucket_count_;
196
197 typedef pointer_traits<__node_pointer> __pointer_traits;
198public:
199 typedef forward_iterator_tag iterator_category;
200 typedef typename __pointer_traits::element_type::value_type value_type;
201 typedef typename __pointer_traits::difference_type difference_type;
202 typedef value_type& reference;
203 typedef typename __pointer_traits::template
204#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
205 rebind<value_type>
206#else
207 rebind<value_type>::other
208#endif
209 pointer;
210
211 __hash_local_iterator() {}
212
213 reference operator*() const {return __node_->__value_;}
214 pointer operator->() const {return &__node_->__value_;}
215
216 __hash_local_iterator& operator++()
217 {
218 __node_ = __node_->__next_;
219 if (__node_ != nullptr && __node_->__hash_ % __bucket_count_ != __bucket_)
220 __node_ = nullptr;
221 return *this;
222 }
223
224 __hash_local_iterator operator++(int)
225 {
226 __hash_local_iterator __t(*this);
227 ++(*this);
228 return __t;
229 }
230
231 friend bool operator==(const __hash_local_iterator& __x, const __hash_local_iterator& __y)
232 {return __x.__node_ == __y.__node_;}
233 friend bool operator!=(const __hash_local_iterator& __x, const __hash_local_iterator& __y)
234 {return __x.__node_ != __y.__node_;}
235
236private:
237 __hash_local_iterator(__node_pointer __node, size_t __bucket,
238 size_t __bucket_count)
239 : __node_(__node),
240 __bucket_(__bucket),
241 __bucket_count_(__bucket_count)
242 {
243 if (__node_ != nullptr)
244 __node_ = __node_->__next_;
245 }
246
247 template <class, class, class, class> friend class __hash_table;
248 template <class> friend class __hash_const_local_iterator;
249 template <class> friend class __hash_map_iterator;
250};
251
252template <class _ConstNodePtr>
253class __hash_const_local_iterator
254{
255 typedef _ConstNodePtr __node_pointer;
256
257 __node_pointer __node_;
258 size_t __bucket_;
259 size_t __bucket_count_;
260
261 typedef pointer_traits<__node_pointer> __pointer_traits;
262 typedef typename __pointer_traits::element_type __node;
263 typedef typename remove_const<__node>::type __non_const_node;
264 typedef typename pointer_traits<__node_pointer>::template
265#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
266 rebind<__non_const_node>
267#else
268 rebind<__non_const_node>::other
269#endif
270 __non_const_node_pointer;
271 typedef __hash_local_iterator<__non_const_node_pointer>
272 __non_const_iterator;
273public:
274 typedef forward_iterator_tag iterator_category;
275 typedef typename remove_const<
276 typename __pointer_traits::element_type::value_type
277 >::type value_type;
278 typedef typename __pointer_traits::difference_type difference_type;
279 typedef const value_type& reference;
280 typedef typename __pointer_traits::template
281#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
282 rebind<const value_type>
283#else
284 rebind<const value_type>::other
285#endif
286 pointer;
287
288 __hash_const_local_iterator() {}
289 __hash_const_local_iterator(const __non_const_iterator& __x)
290 : __node_(__x.__node_),
291 __bucket_(__x.__bucket_),
292 __bucket_count_(__x.__bucket_count_)
293 {}
294
295 reference operator*() const {return __node_->__value_;}
296 pointer operator->() const {return &__node_->__value_;}
297
298 __hash_const_local_iterator& operator++()
299 {
300 __node_ = __node_->__next_;
301 if (__node_ != nullptr && __node_->__hash_ % __bucket_count_ != __bucket_)
302 __node_ = nullptr;
303 return *this;
304 }
305
306 __hash_const_local_iterator operator++(int)
307 {
308 __hash_const_local_iterator __t(*this);
309 ++(*this);
310 return __t;
311 }
312
313 friend bool operator==(const __hash_const_local_iterator& __x, const __hash_const_local_iterator& __y)
314 {return __x.__node_ == __y.__node_;}
315 friend bool operator!=(const __hash_const_local_iterator& __x, const __hash_const_local_iterator& __y)
316 {return __x.__node_ != __y.__node_;}
317
318private:
319 __hash_const_local_iterator(__node_pointer __node, size_t __bucket,
320 size_t __bucket_count)
321 : __node_(__node),
322 __bucket_(__bucket),
323 __bucket_count_(__bucket_count)
324 {
325 if (__node_ != nullptr)
326 __node_ = __node_->__next_;
327 }
328
329 template <class, class, class, class> friend class __hash_table;
330 template <class> friend class __hash_map_const_iterator;
331};
332
333template <class _Alloc>
334class __bucket_list_deallocator
335{
336 typedef _Alloc allocator_type;
337 typedef allocator_traits<allocator_type> __alloc_traits;
338 typedef typename __alloc_traits::size_type size_type;
339
340 __compressed_pair<size_type, allocator_type> __data_;
341public:
342 typedef typename __alloc_traits::pointer pointer;
343
344 __bucket_list_deallocator()
345 : __data_(0) {}
346 __bucket_list_deallocator(const allocator_type& __a, size_type __size)
347 : __data_(__size, __a) {}
348
Howard Hinnant73d21a42010-09-04 23:28:19 +0000349#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000350
351 __bucket_list_deallocator(__bucket_list_deallocator&& __x)
352 : __data_(_STD::move(__x.__data_))
353 {
354 __x.size() = 0;
355 }
356
Howard Hinnant73d21a42010-09-04 23:28:19 +0000357#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000358
359 size_type& size() {return __data_.first();}
360 size_type size() const {return __data_.first();}
361
362 allocator_type& __alloc() {return __data_.second();}
363 const allocator_type& __alloc() const {return __data_.second();}
364
365 void operator()(pointer __p)
366 {
367 __alloc_traits::deallocate(__alloc(), __p, size());
368 }
369};
370
371template <class> class __hash_map_node_destructor;
372
373template <class _Alloc>
374class __hash_node_destructor
375{
376 typedef _Alloc allocator_type;
377 typedef allocator_traits<allocator_type> __alloc_traits;
378 typedef typename __alloc_traits::value_type::value_type value_type;
379public:
380 typedef typename __alloc_traits::pointer pointer;
381private:
382
383 allocator_type& __na_;
384
385 __hash_node_destructor& operator=(const __hash_node_destructor&);
386
387public:
388 bool __value_constructed;
389
390 explicit __hash_node_destructor(allocator_type& __na)
391 : __na_(__na),
392 __value_constructed(false)
393 {}
394
395 void operator()(pointer __p)
396 {
397 if (__value_constructed)
398 __alloc_traits::destroy(__na_, addressof(__p->__value_));
399 if (__p)
400 __alloc_traits::deallocate(__na_, __p, 1);
401 }
402
403 template <class> friend class __hash_map_node_destructor;
404};
405
406template <class _Tp, class _Hash, class _Equal, class _Alloc>
407class __hash_table
408{
409public:
410 typedef _Tp value_type;
411 typedef _Hash hasher;
412 typedef _Equal key_equal;
413 typedef _Alloc allocator_type;
414
415private:
416 typedef allocator_traits<allocator_type> __alloc_traits;
417public:
418 typedef value_type& reference;
419 typedef const value_type& const_reference;
420 typedef typename __alloc_traits::pointer pointer;
421 typedef typename __alloc_traits::const_pointer const_pointer;
422 typedef typename __alloc_traits::size_type size_type;
423 typedef typename __alloc_traits::difference_type difference_type;
424public:
425 // Create __node
426 typedef __hash_node<value_type, typename __alloc_traits::void_pointer> __node;
427 typedef typename __node::__first_node __first_node;
428 typedef typename __alloc_traits::template
429#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
430 rebind_alloc<__node>
431#else
432 rebind_alloc<__node>::other
433#endif
434 __node_allocator;
435 typedef allocator_traits<__node_allocator> __node_traits;
436 typedef typename __node_traits::pointer __node_pointer;
437 typedef typename __node_traits::const_pointer __node_const_pointer;
438
439private:
440
441 typedef typename __node_traits::template
442#ifndef _LIBCPP_HAS_NO_TEMPLATE_ALIASES
443 rebind_alloc<__node_pointer>
444#else
445 rebind_alloc<__node_pointer>::other
446#endif
447 __pointer_allocator;
448 typedef __bucket_list_deallocator<__pointer_allocator> __bucket_list_deleter;
449 typedef unique_ptr<__node_pointer[], __bucket_list_deleter> __bucket_list;
450 typedef allocator_traits<__pointer_allocator> __pointer_alloc_traits;
451 typedef typename __bucket_list_deleter::pointer __node_pointer_pointer;
452
453 // --- Member data begin ---
454 __bucket_list __bucket_list_;
455 __compressed_pair<__first_node, __node_allocator> __p1_;
456 __compressed_pair<size_type, hasher> __p2_;
457 __compressed_pair<float, key_equal> __p3_;
458 // --- Member data end ---
459
460 size_type& size() {return __p2_.first();}
461public:
462 size_type size() const {return __p2_.first();}
463
464 hasher& hash_function() {return __p2_.second();}
465 const hasher& hash_function() const {return __p2_.second();}
466
467 float& max_load_factor() {return __p3_.first();}
468 float max_load_factor() const {return __p3_.first();}
469
470 key_equal& key_eq() {return __p3_.second();}
471 const key_equal& key_eq() const {return __p3_.second();}
472
473 __node_allocator& __node_alloc() {return __p1_.second();}
474 const __node_allocator& __node_alloc() const {return __p1_.second();}
475
476public:
477 typedef __hash_iterator<__node_pointer> iterator;
478 typedef __hash_const_iterator<__node_const_pointer> const_iterator;
479 typedef __hash_local_iterator<__node_pointer> local_iterator;
480 typedef __hash_const_local_iterator<__node_const_pointer> const_local_iterator;
481
482 __hash_table();
483 __hash_table(const hasher& __hf, const key_equal& __eql);
484 __hash_table(const hasher& __hf, const key_equal& __eql,
485 const allocator_type& __a);
486 explicit __hash_table(const allocator_type& __a);
487 __hash_table(const __hash_table& __u);
488 __hash_table(const __hash_table& __u, const allocator_type& __a);
Howard Hinnant73d21a42010-09-04 23:28:19 +0000489#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000490 __hash_table(__hash_table&& __u);
491 __hash_table(__hash_table&& __u, const allocator_type& __a);
Howard Hinnant73d21a42010-09-04 23:28:19 +0000492#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000493 ~__hash_table();
494
495 __hash_table& operator=(const __hash_table& __u);
Howard Hinnant73d21a42010-09-04 23:28:19 +0000496#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000497 __hash_table& operator=(__hash_table&& __u);
498#endif
499 template <class _InputIterator>
500 void __assign_unique(_InputIterator __first, _InputIterator __last);
501 template <class _InputIterator>
502 void __assign_multi(_InputIterator __first, _InputIterator __last);
503
504 size_type max_size() const
505 {
506 return allocator_traits<__pointer_allocator>::max_size(
507 __bucket_list_.get_deleter().__alloc());
508 }
509
510 pair<iterator, bool> __node_insert_unique(__node_pointer __nd);
511 iterator __node_insert_multi(__node_pointer __nd);
512 iterator __node_insert_multi(const_iterator __p,
513 __node_pointer __nd);
514
Howard Hinnant73d21a42010-09-04 23:28:19 +0000515#if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS)
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000516 template <class... _Args>
517 pair<iterator, bool> __emplace_unique(_Args&&... __args);
518 template <class... _Args>
519 iterator __emplace_multi(_Args&&... __args);
520 template <class... _Args>
521 iterator __emplace_hint_multi(const_iterator __p, _Args&&... __args);
Howard Hinnant73d21a42010-09-04 23:28:19 +0000522#endif // !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS)
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000523
524 pair<iterator, bool> __insert_unique(const value_type& __x);
525
Howard Hinnant73d21a42010-09-04 23:28:19 +0000526#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000527 template <class _P>
528 pair<iterator, bool> __insert_unique(_P&& __x);
Howard Hinnant73d21a42010-09-04 23:28:19 +0000529#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000530
Howard Hinnant73d21a42010-09-04 23:28:19 +0000531#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000532 template <class _P>
533 iterator __insert_multi(_P&& __x);
534 template <class _P>
535 iterator __insert_multi(const_iterator __p, _P&& __x);
Howard Hinnant73d21a42010-09-04 23:28:19 +0000536#else // _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000537 iterator __insert_multi(const value_type& __x);
538 iterator __insert_multi(const_iterator __p, const value_type& __x);
Howard Hinnant73d21a42010-09-04 23:28:19 +0000539#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000540
541 void clear();
542 void rehash(size_type __n);
543 void reserve(size_type __n)
544 {rehash(static_cast<size_type>(ceil(__n / max_load_factor())));}
545 size_type bucket_count() const
546 {
547 return __bucket_list_.get_deleter().size();
548 }
549
550 iterator begin();
551 iterator end();
552 const_iterator begin() const;
553 const_iterator end() const;
554
555 template <class _Key>
556 size_type bucket(const _Key& __k) const
557 {return hash_function()(__k) % bucket_count();}
558
559 template <class _Key>
560 iterator find(const _Key& __x);
561 template <class _Key>
562 const_iterator find(const _Key& __x) const;
563
564 typedef __hash_node_destructor<__node_allocator> _D;
565 typedef unique_ptr<__node, _D> __node_holder;
566
567 iterator erase(const_iterator __p);
568 iterator erase(const_iterator __first, const_iterator __last);
569 template <class _Key>
570 size_type __erase_unique(const _Key& __k);
571 template <class _Key>
572 size_type __erase_multi(const _Key& __k);
573 __node_holder remove(const_iterator __p);
574
575 template <class _Key>
576 size_type __count_unique(const _Key& __k) const;
577 template <class _Key>
578 size_type __count_multi(const _Key& __k) const;
579
580 template <class _Key>
581 pair<iterator, iterator>
582 __equal_range_unique(const _Key& __k);
583 template <class _Key>
584 pair<const_iterator, const_iterator>
585 __equal_range_unique(const _Key& __k) const;
586
587 template <class _Key>
588 pair<iterator, iterator>
589 __equal_range_multi(const _Key& __k);
590 template <class _Key>
591 pair<const_iterator, const_iterator>
592 __equal_range_multi(const _Key& __k) const;
593
594 void swap(__hash_table& __u);
595
596 size_type max_bucket_count() const
597 {return __bucket_list_.get_deleter().__alloc().max_size();}
598 size_type bucket_size(size_type __n) const;
599 float load_factor() const
600 {
601 size_type __bc = bucket_count();
602 return __bc != 0 ? (float)size() / __bc : 0.f;
603 }
604 void max_load_factor(float __mlf)
605 {max_load_factor() = _STD::max(__mlf, load_factor());}
606
607 local_iterator begin(size_type __n)
608 {return local_iterator(__bucket_list_[__n], __n, bucket_count());}
609 local_iterator end(size_type __n)
610 {return local_iterator(nullptr, __n, bucket_count());}
611 const_local_iterator cbegin(size_type __n) const
612 {return const_local_iterator(__bucket_list_[__n], __n, bucket_count());}
613 const_local_iterator cend(size_type __n) const
614 {return const_local_iterator(nullptr, __n, bucket_count());}
615private:
616 void __rehash(size_type __n);
617
Howard Hinnant73d21a42010-09-04 23:28:19 +0000618#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
619#ifndef _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000620 template <class ..._Args>
621 __node_holder __construct_node(_Args&& ...__args);
Howard Hinnant73d21a42010-09-04 23:28:19 +0000622#endif
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000623 __node_holder __construct_node(value_type&& __v, size_t __hash);
Howard Hinnant73d21a42010-09-04 23:28:19 +0000624#else // _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000625 __node_holder __construct_node(const value_type& __v);
626#endif
627 __node_holder __construct_node(const value_type& __v, size_t __hash);
628
629 void __copy_assign_alloc(const __hash_table& __u)
630 {__copy_assign_alloc(__u, integral_constant<bool,
631 __node_traits::propagate_on_container_copy_assignment::value>());}
632 void __copy_assign_alloc(const __hash_table& __u, true_type);
633 void __copy_assign_alloc(const __hash_table& __u, false_type) {}
634
635 void __move_assign(__hash_table& __u, false_type);
636 void __move_assign(__hash_table& __u, true_type);
637 void __move_assign_alloc(__hash_table& __u)
638 {__move_assign_alloc(__u, integral_constant<bool,
639 __node_traits::propagate_on_container_move_assignment::value>());}
640 void __move_assign_alloc(__hash_table& __u, true_type)
641 {
642 __bucket_list_.get_deleter().__alloc() =
643 _STD::move(__u.__bucket_list_.get_deleter().__alloc());
644 __node_alloc() = _STD::move(__u.__node_alloc());
645 }
646 void __move_assign_alloc(__hash_table&, false_type) {}
647
648 template <class _A>
649 static
650 void
651 __swap_alloc(_A& __x, _A& __y)
652 {
653 __swap_alloc(__x, __y,
654 integral_constant<bool,
655 allocator_traits<_A>::propagate_on_container_swap::value
656 >());
657 }
658
659 template <class _A>
660 static
661 void
662 __swap_alloc(_A& __x, _A& __y, true_type)
663 {
664 using _STD::swap;
665 swap(__x, __y);
666 }
667
668 template <class _A>
669 static
670 void
671 __swap_alloc(_A& __x, _A& __y, false_type) {}
672
673 void __deallocate(__node_pointer __np);
674 __node_pointer __detach();
675};
676
677template <class _Tp, class _Hash, class _Equal, class _Alloc>
678inline
679__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table()
680 : __p2_(0),
681 __p3_(1.0f)
682{
683}
684
685template <class _Tp, class _Hash, class _Equal, class _Alloc>
686inline
687__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const hasher& __hf,
688 const key_equal& __eql)
689 : __bucket_list_(nullptr, __bucket_list_deleter()),
690 __p1_(),
691 __p2_(0, __hf),
692 __p3_(1.0f, __eql)
693{
694}
695
696template <class _Tp, class _Hash, class _Equal, class _Alloc>
697__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const hasher& __hf,
698 const key_equal& __eql,
699 const allocator_type& __a)
700 : __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
701 __p1_(__node_allocator(__a)),
702 __p2_(0, __hf),
703 __p3_(1.0f, __eql)
704{
705}
706
707template <class _Tp, class _Hash, class _Equal, class _Alloc>
708__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const allocator_type& __a)
709 : __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
710 __p1_(__node_allocator(__a)),
711 __p2_(0),
712 __p3_(1.0f)
713{
714}
715
716template <class _Tp, class _Hash, class _Equal, class _Alloc>
717__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const __hash_table& __u)
718 : __bucket_list_(nullptr,
719 __bucket_list_deleter(allocator_traits<__pointer_allocator>::
720 select_on_container_copy_construction(
721 __u.__bucket_list_.get_deleter().__alloc()), 0)),
722 __p1_(allocator_traits<__node_allocator>::
723 select_on_container_copy_construction(__u.__node_alloc())),
724 __p2_(0, __u.hash_function()),
725 __p3_(__u.__p3_)
726{
727}
728
729template <class _Tp, class _Hash, class _Equal, class _Alloc>
730__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const __hash_table& __u,
731 const allocator_type& __a)
732 : __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
733 __p1_(__node_allocator(__a)),
734 __p2_(0, __u.hash_function()),
735 __p3_(__u.__p3_)
736{
737}
738
Howard Hinnant73d21a42010-09-04 23:28:19 +0000739#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000740
741template <class _Tp, class _Hash, class _Equal, class _Alloc>
742__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(__hash_table&& __u)
743 : __bucket_list_(_STD::move(__u.__bucket_list_)),
744 __p1_(_STD::move(__u.__p1_)),
745 __p2_(_STD::move(__u.__p2_)),
746 __p3_(_STD::move(__u.__p3_))
747{
748 if (size() > 0)
749 {
750 __bucket_list_[__p1_.first().__next_->__hash_ % bucket_count()] =
751 static_cast<__node_pointer>(addressof(__p1_.first()));
752 __u.__p1_.first().__next_ = nullptr;
753 __u.size() = 0;
754 }
755}
756
757template <class _Tp, class _Hash, class _Equal, class _Alloc>
758__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(__hash_table&& __u,
759 const allocator_type& __a)
760 : __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
761 __p1_(__node_allocator(__a)),
762 __p2_(0, _STD::move(__u.hash_function())),
763 __p3_(_STD::move(__u.__p3_))
764{
765 if (__a == allocator_type(__u.__node_alloc()))
766 {
767 __bucket_list_.reset(__u.__bucket_list_.release());
768 __bucket_list_.get_deleter().size() = __u.__bucket_list_.get_deleter().size();
769 __u.__bucket_list_.get_deleter().size() = 0;
770 if (__u.size() > 0)
771 {
772 __p1_.first().__next_ = __u.__p1_.first().__next_;
773 __u.__p1_.first().__next_ = nullptr;
774 __bucket_list_[__p1_.first().__next_->__hash_ % bucket_count()] =
775 static_cast<__node_pointer>(addressof(__p1_.first()));
776 size() = __u.size();
777 __u.size() = 0;
778 }
779 }
780}
781
Howard Hinnant73d21a42010-09-04 23:28:19 +0000782#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000783
784template <class _Tp, class _Hash, class _Equal, class _Alloc>
785__hash_table<_Tp, _Hash, _Equal, _Alloc>::~__hash_table()
786{
787 __deallocate(__p1_.first().__next_);
788}
789
790template <class _Tp, class _Hash, class _Equal, class _Alloc>
791void
792__hash_table<_Tp, _Hash, _Equal, _Alloc>::__copy_assign_alloc(
793 const __hash_table& __u, true_type)
794{
795 if (__node_alloc() != __u.__node_alloc())
796 {
797 clear();
798 __bucket_list_.reset();
799 __bucket_list_.get_deleter().size() = 0;
800 }
801 __bucket_list_.get_deleter().__alloc() = __u.__bucket_list_.get_deleter().__alloc();
802 __node_alloc() = __u.__node_alloc();
803}
804
805template <class _Tp, class _Hash, class _Equal, class _Alloc>
806__hash_table<_Tp, _Hash, _Equal, _Alloc>&
807__hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(const __hash_table& __u)
808{
809 if (this != &__u)
810 {
811 __copy_assign_alloc(__u);
812 hash_function() = __u.hash_function();
813 key_eq() = __u.key_eq();
814 max_load_factor() = __u.max_load_factor();
815 __assign_multi(__u.begin(), __u.end());
816 }
817 return *this;
818}
819
820template <class _Tp, class _Hash, class _Equal, class _Alloc>
821void
822__hash_table<_Tp, _Hash, _Equal, _Alloc>::__deallocate(__node_pointer __np)
823{
824 __node_allocator& __na = __node_alloc();
825 while (__np != nullptr)
826 {
827 __node_pointer __next = __np->__next_;
828 __node_traits::destroy(__na, addressof(__np->__value_));
829 __node_traits::deallocate(__na, __np, 1);
830 __np = __next;
831 }
832}
833
834template <class _Tp, class _Hash, class _Equal, class _Alloc>
835typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_pointer
836__hash_table<_Tp, _Hash, _Equal, _Alloc>::__detach()
837{
838 size_type __bc = bucket_count();
839 for (size_type __i = 0; __i < __bc; ++__i)
840 __bucket_list_[__i] = nullptr;
841 size() = 0;
842 __node_pointer __cache = __p1_.first().__next_;
843 __p1_.first().__next_ = nullptr;
844 return __cache;
845}
846
Howard Hinnant73d21a42010-09-04 23:28:19 +0000847#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000848
849template <class _Tp, class _Hash, class _Equal, class _Alloc>
850void
851__hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(
852 __hash_table& __u, true_type)
853{
854 clear();
855 __bucket_list_.reset(__u.__bucket_list_.release());
856 __bucket_list_.get_deleter().size() = __u.__bucket_list_.get_deleter().size();
857 __u.__bucket_list_.get_deleter().size() = 0;
858 __move_assign_alloc(__u);
859 size() = __u.size();
860 hash_function() = _STD::move(__u.hash_function());
861 max_load_factor() = __u.max_load_factor();
862 key_eq() = _STD::move(__u.key_eq());
863 __p1_.first().__next_ = __u.__p1_.first().__next_;
864 if (size() > 0)
865 {
866 __bucket_list_[__p1_.first().__next_->__hash_ % bucket_count()] =
867 static_cast<__node_pointer>(addressof(__p1_.first()));
868 __u.__p1_.first().__next_ = nullptr;
869 __u.size() = 0;
870 }
871}
872
873template <class _Tp, class _Hash, class _Equal, class _Alloc>
874void
875__hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(
876 __hash_table& __u, false_type)
877{
878 if (__node_alloc() == __u.__node_alloc())
879 __move_assign(__u, true_type());
880 else
881 {
882 hash_function() = _STD::move(__u.hash_function());
883 key_eq() = _STD::move(__u.key_eq());
884 max_load_factor() = __u.max_load_factor();
885 if (bucket_count() != 0)
886 {
887 __node_pointer __cache = __detach();
888#ifndef _LIBCPP_NO_EXCEPTIONS
889 try
890 {
Howard Hinnant324bb032010-08-22 00:02:43 +0000891#endif // _LIBCPP_NO_EXCEPTIONS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000892 const_iterator __i = __u.begin();
893 while (__cache != nullptr && __u.size() != 0)
894 {
895 __cache->__value_ = _STD::move(__u.remove(__i++)->__value_);
896 __node_pointer __next = __cache->__next_;
897 __node_insert_multi(__cache);
898 __cache = __next;
899 }
900#ifndef _LIBCPP_NO_EXCEPTIONS
901 }
902 catch (...)
903 {
904 __deallocate(__cache);
905 throw;
906 }
Howard Hinnant324bb032010-08-22 00:02:43 +0000907#endif // _LIBCPP_NO_EXCEPTIONS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000908 __deallocate(__cache);
909 }
910 const_iterator __i = __u.begin();
911 while (__u.size() != 0)
912 {
913 __node_holder __h =
914 __construct_node(_STD::move(__u.remove(__i++)->__value_));
915 __node_insert_multi(__h.get());
916 __h.release();
917 }
918 }
919}
920
921template <class _Tp, class _Hash, class _Equal, class _Alloc>
922inline
923__hash_table<_Tp, _Hash, _Equal, _Alloc>&
924__hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(__hash_table&& __u)
925{
926 __move_assign(__u, integral_constant<bool,
927 __node_traits::propagate_on_container_move_assignment::value>());
928 return *this;
929}
930
Howard Hinnant73d21a42010-09-04 23:28:19 +0000931#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000932
933template <class _Tp, class _Hash, class _Equal, class _Alloc>
934template <class _InputIterator>
935void
936__hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_unique(_InputIterator __first,
937 _InputIterator __last)
938{
939 if (bucket_count() != 0)
940 {
941 __node_pointer __cache = __detach();
942#ifndef _LIBCPP_NO_EXCEPTIONS
943 try
944 {
Howard Hinnant324bb032010-08-22 00:02:43 +0000945#endif // _LIBCPP_NO_EXCEPTIONS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000946 for (; __cache != nullptr && __first != __last; ++__first)
947 {
948 __cache->__value_ = *__first;
949 __node_pointer __next = __cache->__next_;
950 __node_insert_unique(__cache);
951 __cache = __next;
952 }
953#ifndef _LIBCPP_NO_EXCEPTIONS
954 }
955 catch (...)
956 {
957 __deallocate(__cache);
958 throw;
959 }
Howard Hinnant324bb032010-08-22 00:02:43 +0000960#endif // _LIBCPP_NO_EXCEPTIONS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000961 __deallocate(__cache);
962 }
963 for (; __first != __last; ++__first)
964 __insert_unique(*__first);
965}
966
967template <class _Tp, class _Hash, class _Equal, class _Alloc>
968template <class _InputIterator>
969void
970__hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_multi(_InputIterator __first,
971 _InputIterator __last)
972{
973 if (bucket_count() != 0)
974 {
975 __node_pointer __cache = __detach();
976#ifndef _LIBCPP_NO_EXCEPTIONS
977 try
978 {
Howard Hinnant324bb032010-08-22 00:02:43 +0000979#endif // _LIBCPP_NO_EXCEPTIONS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000980 for (; __cache != nullptr && __first != __last; ++__first)
981 {
982 __cache->__value_ = *__first;
983 __node_pointer __next = __cache->__next_;
984 __node_insert_multi(__cache);
985 __cache = __next;
986 }
987#ifndef _LIBCPP_NO_EXCEPTIONS
988 }
989 catch (...)
990 {
991 __deallocate(__cache);
992 throw;
993 }
Howard Hinnant324bb032010-08-22 00:02:43 +0000994#endif // _LIBCPP_NO_EXCEPTIONS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000995 __deallocate(__cache);
996 }
997 for (; __first != __last; ++__first)
998 __insert_multi(*__first);
999}
1000
1001template <class _Tp, class _Hash, class _Equal, class _Alloc>
1002inline
1003typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1004__hash_table<_Tp, _Hash, _Equal, _Alloc>::begin()
1005{
1006 return iterator(__p1_.first().__next_);
1007}
1008
1009template <class _Tp, class _Hash, class _Equal, class _Alloc>
1010inline
1011typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1012__hash_table<_Tp, _Hash, _Equal, _Alloc>::end()
1013{
1014 return iterator(nullptr);
1015}
1016
1017template <class _Tp, class _Hash, class _Equal, class _Alloc>
1018inline
1019typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator
1020__hash_table<_Tp, _Hash, _Equal, _Alloc>::begin() const
1021{
1022 return const_iterator(__p1_.first().__next_);
1023}
1024
1025template <class _Tp, class _Hash, class _Equal, class _Alloc>
1026inline
1027typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator
1028__hash_table<_Tp, _Hash, _Equal, _Alloc>::end() const
1029{
1030 return const_iterator(nullptr);
1031}
1032
1033template <class _Tp, class _Hash, class _Equal, class _Alloc>
1034void
1035__hash_table<_Tp, _Hash, _Equal, _Alloc>::clear()
1036{
1037 if (size() > 0)
1038 {
1039 __deallocate(__p1_.first().__next_);
1040 __p1_.first().__next_ = nullptr;
1041 size_type __bc = bucket_count();
1042 for (size_type __i; __i < __bc; ++__i)
1043 __bucket_list_[__i] = nullptr;
1044 size() = 0;
1045 }
1046}
1047
1048template <class _Tp, class _Hash, class _Equal, class _Alloc>
1049pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool>
1050__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_unique(__node_pointer __nd)
1051{
1052 __nd->__hash_ = hash_function()(__nd->__value_);
1053 size_type __bc = bucket_count();
1054 bool __inserted = false;
1055 __node_pointer __ndptr;
1056 size_t __chash;
1057 if (__bc != 0)
1058 {
1059 __chash = __nd->__hash_ % __bc;
1060 __ndptr = __bucket_list_[__chash];
1061 if (__ndptr != nullptr)
1062 {
1063 for (__ndptr = __ndptr->__next_; __ndptr != nullptr &&
1064 __ndptr->__hash_ % __bc == __chash;
1065 __ndptr = __ndptr->__next_)
1066 {
1067 if (key_eq()(__ndptr->__value_, __nd->__value_))
1068 goto __done;
1069 }
1070 }
1071 }
1072 {
1073 if (size()+1 > __bc * max_load_factor() || __bc == 0)
1074 {
1075 rehash(_STD::max<size_type>(2 * __bc + 1,
1076 size_type(ceil(float(size() + 1) / max_load_factor()))));
1077 __bc = bucket_count();
1078 __chash = __nd->__hash_ % __bc;
1079 }
1080 // insert_after __bucket_list_[__chash], or __first_node if bucket is null
1081 __node_pointer __pn = __bucket_list_[__chash];
1082 if (__pn == nullptr)
1083 {
1084 __pn = static_cast<__node_pointer>(addressof(__p1_.first()));
1085 __nd->__next_ = __pn->__next_;
1086 __pn->__next_ = __nd;
1087 // fix up __bucket_list_
1088 __bucket_list_[__chash] = __pn;
1089 if (__nd->__next_ != nullptr)
1090 __bucket_list_[__nd->__next_->__hash_ % __bc] = __nd;
1091 }
1092 else
1093 {
1094 __nd->__next_ = __pn->__next_;
1095 __pn->__next_ = __nd;
1096 }
1097 __ndptr = __nd;
1098 // increment size
1099 ++size();
1100 __inserted = true;
1101 }
1102__done:
1103 return pair<iterator, bool>(iterator(__ndptr), __inserted);
1104}
1105
1106template <class _Tp, class _Hash, class _Equal, class _Alloc>
1107typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1108__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi(__node_pointer __cp)
1109{
1110 __cp->__hash_ = hash_function()(__cp->__value_);
1111 size_type __bc = bucket_count();
1112 if (size()+1 > __bc * max_load_factor() || __bc == 0)
1113 {
1114 rehash(_STD::max<size_type>(2 * __bc + 1,
1115 size_type(ceil(float(size() + 1) / max_load_factor()))));
1116 __bc = bucket_count();
1117 }
1118 size_t __chash = __cp->__hash_ % __bc;
1119 __node_pointer __pn = __bucket_list_[__chash];
1120 if (__pn == nullptr)
1121 {
1122 __pn = static_cast<__node_pointer>(addressof(__p1_.first()));
1123 __cp->__next_ = __pn->__next_;
1124 __pn->__next_ = __cp;
1125 // fix up __bucket_list_
1126 __bucket_list_[__chash] = __pn;
1127 if (__cp->__next_ != nullptr)
1128 __bucket_list_[__cp->__next_->__hash_ % __bc] = __cp;
1129 }
1130 else
1131 {
1132 for (bool __found = false; __pn->__next_ != nullptr &&
1133 __pn->__next_->__hash_ % __bc == __chash;
1134 __pn = __pn->__next_)
Howard Hinnant324bb032010-08-22 00:02:43 +00001135 {
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001136 // __found key_eq() action
1137 // false false loop
1138 // true true loop
1139 // false true set __found to true
1140 // true false break
1141 if (__found != (__pn->__next_->__hash_ == __cp->__hash_ &&
1142 key_eq()(__pn->__next_->__value_, __cp->__value_)))
1143 {
1144 if (!__found)
1145 __found = true;
1146 else
1147 break;
1148 }
1149 }
1150 __cp->__next_ = __pn->__next_;
1151 __pn->__next_ = __cp;
1152 if (__cp->__next_ != nullptr)
1153 {
1154 size_t __nhash = __cp->__next_->__hash_ % __bc;
1155 if (__nhash != __chash)
1156 __bucket_list_[__nhash] = __cp;
1157 }
1158 }
1159 ++size();
1160 return iterator(__cp);
1161}
1162
1163template <class _Tp, class _Hash, class _Equal, class _Alloc>
1164typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1165__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi(
1166 const_iterator __p, __node_pointer __cp)
1167{
1168 if (__p != end() && key_eq()(*__p, __cp->__value_))
1169 {
1170 __node_pointer __np = const_cast<__node_pointer>(__p.__node_);
1171 __cp->__hash_ = __np->__hash_;
1172 size_type __bc = bucket_count();
1173 if (size()+1 > __bc * max_load_factor() || __bc == 0)
1174 {
1175 rehash(_STD::max<size_type>(2 * __bc + 1,
1176 size_type(ceil(float(size() + 1) / max_load_factor()))));
1177 __bc = bucket_count();
1178 }
1179 size_t __chash = __cp->__hash_ % __bc;
1180 __node_pointer __pp = __bucket_list_[__chash];
1181 while (__pp->__next_ != __np)
1182 __pp = __pp->__next_;
1183 __cp->__next_ = __np;
1184 __pp->__next_ = __cp;
1185 ++size();
1186 return iterator(__cp);
1187 }
1188 return __node_insert_multi(__cp);
1189}
1190
1191template <class _Tp, class _Hash, class _Equal, class _Alloc>
1192pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool>
1193__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_unique(const value_type& __x)
1194{
1195 size_t __hash = hash_function()(__x);
1196 size_type __bc = bucket_count();
1197 bool __inserted = false;
1198 __node_pointer __nd;
1199 size_t __chash;
1200 if (__bc != 0)
1201 {
1202 __chash = __hash % __bc;
1203 __nd = __bucket_list_[__chash];
1204 if (__nd != nullptr)
1205 {
1206 for (__nd = __nd->__next_; __nd != nullptr &&
1207 __nd->__hash_ % __bc == __chash;
1208 __nd = __nd->__next_)
1209 {
1210 if (key_eq()(__nd->__value_, __x))
1211 goto __done;
1212 }
1213 }
1214 }
1215 {
1216 __node_holder __h = __construct_node(__x, __hash);
1217 if (size()+1 > __bc * max_load_factor() || __bc == 0)
1218 {
1219 rehash(_STD::max<size_type>(2 * __bc + 1,
1220 size_type(ceil(float(size() + 1) / max_load_factor()))));
1221 __bc = bucket_count();
1222 __chash = __hash % __bc;
1223 }
1224 // insert_after __bucket_list_[__chash], or __first_node if bucket is null
1225 __node_pointer __pn = __bucket_list_[__chash];
1226 if (__pn == nullptr)
1227 {
1228 __pn = static_cast<__node_pointer>(addressof(__p1_.first()));
1229 __h->__next_ = __pn->__next_;
1230 __pn->__next_ = __h.get();
1231 // fix up __bucket_list_
1232 __bucket_list_[__chash] = __pn;
1233 if (__h->__next_ != nullptr)
1234 __bucket_list_[__h->__next_->__hash_ % __bc] = __h.get();
1235 }
1236 else
1237 {
1238 __h->__next_ = __pn->__next_;
1239 __pn->__next_ = __h.get();
1240 }
1241 __nd = __h.release();
1242 // increment size
1243 ++size();
1244 __inserted = true;
1245 }
1246__done:
1247 return pair<iterator, bool>(iterator(__nd), __inserted);
1248}
1249
Howard Hinnant73d21a42010-09-04 23:28:19 +00001250#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
1251#ifndef _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001252
1253template <class _Tp, class _Hash, class _Equal, class _Alloc>
1254template <class... _Args>
1255pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool>
1256__hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_unique(_Args&&... __args)
1257{
1258 __node_holder __h = __construct_node(_STD::forward<_Args>(__args)...);
1259 pair<iterator, bool> __r = __node_insert_unique(__h.get());
1260 if (__r.second)
1261 __h.release();
1262 return __r;
1263}
1264
1265template <class _Tp, class _Hash, class _Equal, class _Alloc>
1266template <class... _Args>
1267typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1268__hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_multi(_Args&&... __args)
1269{
1270 __node_holder __h = __construct_node(_STD::forward<_Args>(__args)...);
1271 iterator __r = __node_insert_multi(__h.get());
1272 __h.release();
1273 return __r;
1274}
1275
1276template <class _Tp, class _Hash, class _Equal, class _Alloc>
1277template <class... _Args>
1278typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1279__hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_hint_multi(
1280 const_iterator __p, _Args&&... __args)
1281{
1282 __node_holder __h = __construct_node(_STD::forward<_Args>(__args)...);
1283 iterator __r = __node_insert_multi(__p, __h.get());
1284 __h.release();
1285 return __r;
1286}
1287
Howard Hinnant73d21a42010-09-04 23:28:19 +00001288#endif // _LIBCPP_HAS_NO_VARIADICS
1289
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001290template <class _Tp, class _Hash, class _Equal, class _Alloc>
1291template <class _P>
1292pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool>
1293__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_unique(_P&& __x)
1294{
1295 __node_holder __h = __construct_node(_STD::forward<_P>(__x));
1296 pair<iterator, bool> __r = __node_insert_unique(__h.get());
1297 if (__r.second)
1298 __h.release();
1299 return __r;
1300}
1301
Howard Hinnant73d21a42010-09-04 23:28:19 +00001302#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001303
Howard Hinnant73d21a42010-09-04 23:28:19 +00001304#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001305
1306template <class _Tp, class _Hash, class _Equal, class _Alloc>
1307template <class _P>
1308typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1309__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_multi(_P&& __x)
1310{
1311 __node_holder __h = __construct_node(_STD::forward<_P>(__x));
1312 iterator __r = __node_insert_multi(__h.get());
1313 __h.release();
1314 return __r;
1315}
1316
1317template <class _Tp, class _Hash, class _Equal, class _Alloc>
1318template <class _P>
1319typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1320__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_multi(const_iterator __p,
1321 _P&& __x)
1322{
1323 __node_holder __h = __construct_node(_STD::forward<_P>(__x));
1324 iterator __r = __node_insert_multi(__p, __h.get());
1325 __h.release();
1326 return __r;
1327}
1328
Howard Hinnant73d21a42010-09-04 23:28:19 +00001329#else // _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001330
1331template <class _Tp, class _Hash, class _Equal, class _Alloc>
1332typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1333__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_multi(const value_type& __x)
1334{
1335 __node_holder __h = __construct_node(__x);
1336 iterator __r = __node_insert_multi(__h.get());
1337 __h.release();
1338 return __r;
1339}
1340
1341template <class _Tp, class _Hash, class _Equal, class _Alloc>
1342typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1343__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_multi(const_iterator __p,
1344 const value_type& __x)
1345{
1346 __node_holder __h = __construct_node(__x);
1347 iterator __r = __node_insert_multi(__p, __h.get());
1348 __h.release();
1349 return __r;
1350}
1351
Howard Hinnant73d21a42010-09-04 23:28:19 +00001352#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001353
1354template <class _Tp, class _Hash, class _Equal, class _Alloc>
1355void
1356__hash_table<_Tp, _Hash, _Equal, _Alloc>::rehash(size_type __n)
1357{
1358 __n = __next_prime(_STD::max<size_type>(__n, size() > 0));
1359 size_type __bc = bucket_count();
1360 if (__n > __bc)
1361 __rehash(__n);
1362 else
1363 {
1364 __n = _STD::max<size_type>
1365 (
1366 __n,
1367 __next_prime(size_t(ceil(float(size()) / max_load_factor())))
1368 );
1369 if (__n < __bc)
1370 __rehash(__n);
1371 }
1372}
1373
1374template <class _Tp, class _Hash, class _Equal, class _Alloc>
1375void
1376__hash_table<_Tp, _Hash, _Equal, _Alloc>::__rehash(size_type __nbc)
1377{
1378 __pointer_allocator& __npa = __bucket_list_.get_deleter().__alloc();
1379 __bucket_list_.reset(__nbc > 0 ?
1380 __pointer_alloc_traits::allocate(__npa, __nbc) : nullptr);
1381 __bucket_list_.get_deleter().size() = __nbc;
1382 if (__nbc > 0)
1383 {
1384 for (size_type __i = 0; __i < __nbc; ++__i)
1385 __bucket_list_[__i] = nullptr;
1386 __node_pointer __pp(static_cast<__node_pointer>(addressof(__p1_.first())));
1387 __node_pointer __cp = __pp->__next_;
1388 if (__cp != nullptr)
1389 {
1390 size_type __chash = __cp->__hash_ % __nbc;
1391 __bucket_list_[__chash] = __pp;
1392 size_type __phash = __chash;
1393 for (__pp = __cp, __cp = __cp->__next_; __cp != nullptr;
1394 __cp = __pp->__next_)
1395 {
1396 __chash = __cp->__hash_ % __nbc;
1397 if (__chash == __phash)
1398 __pp = __cp;
1399 else
1400 {
1401 if (__bucket_list_[__chash] == nullptr)
1402 {
1403 __bucket_list_[__chash] = __pp;
1404 __pp = __cp;
1405 __phash = __chash;
1406 }
1407 else
1408 {
1409 __node_pointer __np = __cp;
1410 for (; __np->__next_ != nullptr &&
1411 key_eq()(__cp->__value_, __np->__next_->__value_);
1412 __np = __np->__next_)
1413 ;
1414 __pp->__next_ = __np->__next_;
1415 __np->__next_ = __bucket_list_[__chash]->__next_;
1416 __bucket_list_[__chash]->__next_ = __cp;
Howard Hinnant324bb032010-08-22 00:02:43 +00001417
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001418 }
1419 }
1420 }
1421 }
1422 }
1423}
1424
1425template <class _Tp, class _Hash, class _Equal, class _Alloc>
1426template <class _Key>
1427typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1428__hash_table<_Tp, _Hash, _Equal, _Alloc>::find(const _Key& __k)
1429{
1430 size_t __hash = hash_function()(__k);
1431 size_type __bc = bucket_count();
1432 if (__bc != 0)
1433 {
1434 size_t __chash = __hash % __bc;
1435 __node_pointer __nd = __bucket_list_[__chash];
1436 if (__nd != nullptr)
1437 {
1438 for (__nd = __nd->__next_; __nd != nullptr &&
1439 __nd->__hash_ % __bc == __chash;
1440 __nd = __nd->__next_)
1441 {
1442 if (key_eq()(__nd->__value_, __k))
1443 return iterator(__nd);
1444 }
1445 }
1446 }
1447 return end();
1448}
1449
1450template <class _Tp, class _Hash, class _Equal, class _Alloc>
1451template <class _Key>
1452typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator
1453__hash_table<_Tp, _Hash, _Equal, _Alloc>::find(const _Key& __k) const
1454{
1455 size_t __hash = hash_function()(__k);
1456 size_type __bc = bucket_count();
1457 if (__bc != 0)
1458 {
1459 size_t __chash = __hash % __bc;
1460 __node_const_pointer __nd = __bucket_list_[__chash];
1461 if (__nd != nullptr)
1462 {
1463 for (__nd = __nd->__next_; __nd != nullptr &&
1464 __nd->__hash_ % __bc == __chash;
1465 __nd = __nd->__next_)
1466 {
1467 if (key_eq()(__nd->__value_, __k))
1468 return const_iterator(__nd);
1469 }
1470 }
Howard Hinnant324bb032010-08-22 00:02:43 +00001471
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001472 }
1473 return end();
1474}
1475
Howard Hinnant73d21a42010-09-04 23:28:19 +00001476#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
1477#ifndef _LIBCPP_HAS_NO_VARIADICS
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001478
1479template <class _Tp, class _Hash, class _Equal, class _Alloc>
1480template <class ..._Args>
1481typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder
1482__hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node(_Args&& ...__args)
1483{
1484 __node_allocator& __na = __node_alloc();
1485 __node_holder __h(__node_traits::allocate(__na, 1), _D(__na));
1486 __node_traits::construct(__na, addressof(__h->__value_), _STD::forward<_Args>(__args)...);
1487 __h.get_deleter().__value_constructed = true;
1488 __h->__hash_ = hash_function()(__h->__value_);
1489 __h->__next_ = nullptr;
1490 return __h;
1491}
1492
Howard Hinnant73d21a42010-09-04 23:28:19 +00001493#endif // _LIBCPP_HAS_NO_VARIADICS
1494
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001495template <class _Tp, class _Hash, class _Equal, class _Alloc>
1496typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder
1497__hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node(value_type&& __v,
1498 size_t __hash)
1499{
1500 __node_allocator& __na = __node_alloc();
1501 __node_holder __h(__node_traits::allocate(__na, 1), _D(__na));
1502 __node_traits::construct(__na, addressof(__h->__value_), _STD::move(__v));
1503 __h.get_deleter().__value_constructed = true;
1504 __h->__hash_ = __hash;
1505 __h->__next_ = nullptr;
1506 return _STD::move(__h);
1507}
1508
Howard Hinnant73d21a42010-09-04 23:28:19 +00001509#else // _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001510
1511template <class _Tp, class _Hash, class _Equal, class _Alloc>
1512typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder
1513__hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node(const value_type& __v)
1514{
1515 __node_allocator& __na = __node_alloc();
1516 __node_holder __h(__node_traits::allocate(__na, 1), _D(__na));
1517 __node_traits::construct(__na, addressof(__h->__value_), __v);
1518 __h.get_deleter().__value_constructed = true;
1519 __h->__hash_ = hash_function()(__h->__value_);
1520 __h->__next_ = nullptr;
1521 return _STD::move(__h);
1522}
1523
Howard Hinnant73d21a42010-09-04 23:28:19 +00001524#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001525
1526template <class _Tp, class _Hash, class _Equal, class _Alloc>
1527typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder
1528__hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node(const value_type& __v,
1529 size_t __hash)
1530{
1531 __node_allocator& __na = __node_alloc();
1532 __node_holder __h(__node_traits::allocate(__na, 1), _D(__na));
1533 __node_traits::construct(__na, addressof(__h->__value_), __v);
1534 __h.get_deleter().__value_constructed = true;
1535 __h->__hash_ = __hash;
1536 __h->__next_ = nullptr;
1537 return _STD::move(__h);
1538}
1539
1540template <class _Tp, class _Hash, class _Equal, class _Alloc>
1541typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1542__hash_table<_Tp, _Hash, _Equal, _Alloc>::erase(const_iterator __p)
1543{
1544 __node_pointer __np = const_cast<__node_pointer>(__p.__node_);
1545 iterator __r(__np);
1546 ++__r;
1547 remove(__p);
1548 return __r;
1549}
1550
1551template <class _Tp, class _Hash, class _Equal, class _Alloc>
1552typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1553__hash_table<_Tp, _Hash, _Equal, _Alloc>::erase(const_iterator __first,
1554 const_iterator __last)
1555{
1556 for (const_iterator __p = __first; __first != __last; __p = __first)
1557 {
1558 ++__first;
1559 erase(__p);
1560 }
1561 __node_pointer __np = const_cast<__node_pointer>(__last.__node_);
1562 return iterator (__np);
1563}
1564
1565template <class _Tp, class _Hash, class _Equal, class _Alloc>
1566template <class _Key>
1567typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::size_type
1568__hash_table<_Tp, _Hash, _Equal, _Alloc>::__erase_unique(const _Key& __k)
1569{
1570 iterator __i = find(__k);
1571 if (__i == end())
1572 return 0;
1573 erase(__i);
1574 return 1;
1575}
1576
1577template <class _Tp, class _Hash, class _Equal, class _Alloc>
1578template <class _Key>
1579typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::size_type
1580__hash_table<_Tp, _Hash, _Equal, _Alloc>::__erase_multi(const _Key& __k)
1581{
1582 size_type __r = 0;
1583 iterator __i = find(__k);
1584 if (__i != end())
1585 {
1586 iterator __e = end();
1587 do
1588 {
1589 erase(__i++);
1590 ++__r;
1591 } while (__i != __e && key_eq()(*__i, __k));
1592 }
1593 return __r;
1594}
1595
1596template <class _Tp, class _Hash, class _Equal, class _Alloc>
1597typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder
1598__hash_table<_Tp, _Hash, _Equal, _Alloc>::remove(const_iterator __p)
1599{
1600 // current node
1601 __node_pointer __cn = const_cast<__node_pointer>(__p.__node_);
1602 size_type __bc = bucket_count();
1603 size_t __chash = __cn->__hash_ % __bc;
1604 // find previous node
1605 __node_pointer __pn = __bucket_list_[__chash];
1606 for (; __pn->__next_ != __cn; __pn = __pn->__next_)
1607 ;
1608 // Fix up __bucket_list_
1609 // if __pn is not in same bucket (before begin is not in same bucket) &&
1610 // if __cn->__next_ is not in same bucket (nullptr is not in same bucket)
1611 if (__pn == addressof(__p1_.first()) || __pn->__hash_ % __bc != __chash)
1612 {
1613 if (__cn->__next_ == nullptr || __cn->__next_->__hash_ % __bc != __chash)
1614 __bucket_list_[__chash] = nullptr;
1615 }
1616 // if __cn->__next_ is not in same bucket (nullptr is in same bucket)
1617 if (__cn->__next_ != nullptr)
1618 {
1619 size_t __nhash = __cn->__next_->__hash_ % __bc;
1620 if (__nhash != __chash)
1621 __bucket_list_[__nhash] = __pn;
1622 }
1623 // remove __cn
1624 __pn->__next_ = __cn->__next_;
1625 __cn->__next_ = nullptr;
1626 --size();
1627 return __node_holder(__cn, _D(__node_alloc()));
1628}
1629
1630template <class _Tp, class _Hash, class _Equal, class _Alloc>
1631template <class _Key>
1632inline
1633typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::size_type
1634__hash_table<_Tp, _Hash, _Equal, _Alloc>::__count_unique(const _Key& __k) const
1635{
1636 return static_cast<size_type>(find(__k) != end());
1637}
1638
1639template <class _Tp, class _Hash, class _Equal, class _Alloc>
1640template <class _Key>
1641typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::size_type
1642__hash_table<_Tp, _Hash, _Equal, _Alloc>::__count_multi(const _Key& __k) const
1643{
1644 size_type __r = 0;
1645 const_iterator __i = find(__k);
1646 if (__i != end())
1647 {
1648 const_iterator __e = end();
1649 do
1650 {
1651 ++__i;
1652 ++__r;
1653 } while (__i != __e && key_eq()(*__i, __k));
1654 }
1655 return __r;
1656}
1657
1658template <class _Tp, class _Hash, class _Equal, class _Alloc>
1659template <class _Key>
1660pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator,
1661 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator>
1662__hash_table<_Tp, _Hash, _Equal, _Alloc>::__equal_range_unique(
1663 const _Key& __k)
1664{
1665 iterator __i = find(__k);
1666 iterator __j = __i;
1667 if (__i != end())
1668 ++__j;
1669 return pair<iterator, iterator>(__i, __j);
1670}
1671
1672template <class _Tp, class _Hash, class _Equal, class _Alloc>
1673template <class _Key>
1674pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator,
1675 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator>
1676__hash_table<_Tp, _Hash, _Equal, _Alloc>::__equal_range_unique(
1677 const _Key& __k) const
1678{
1679 const_iterator __i = find(__k);
1680 const_iterator __j = __i;
1681 if (__i != end())
1682 ++__j;
1683 return pair<const_iterator, const_iterator>(__i, __j);
1684}
1685
1686template <class _Tp, class _Hash, class _Equal, class _Alloc>
1687template <class _Key>
1688pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator,
1689 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator>
1690__hash_table<_Tp, _Hash, _Equal, _Alloc>::__equal_range_multi(
1691 const _Key& __k)
1692{
1693 iterator __i = find(__k);
1694 iterator __j = __i;
1695 if (__i != end())
1696 {
1697 iterator __e = end();
1698 do
1699 {
1700 ++__j;
1701 } while (__j != __e && key_eq()(*__j, __k));
1702 }
1703 return pair<iterator, iterator>(__i, __j);
1704}
1705
1706template <class _Tp, class _Hash, class _Equal, class _Alloc>
1707template <class _Key>
1708pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator,
1709 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator>
1710__hash_table<_Tp, _Hash, _Equal, _Alloc>::__equal_range_multi(
1711 const _Key& __k) const
1712{
1713 const_iterator __i = find(__k);
1714 const_iterator __j = __i;
1715 if (__i != end())
1716 {
1717 const_iterator __e = end();
1718 do
1719 {
1720 ++__j;
1721 } while (__j != __e && key_eq()(*__j, __k));
1722 }
1723 return pair<const_iterator, const_iterator>(__i, __j);
1724}
1725
1726template <class _Tp, class _Hash, class _Equal, class _Alloc>
1727void
1728__hash_table<_Tp, _Hash, _Equal, _Alloc>::swap(__hash_table& __u)
1729{
1730 {
1731 __node_pointer_pointer __npp = __bucket_list_.release();
1732 __bucket_list_.reset(__u.__bucket_list_.release());
1733 __u.__bucket_list_.reset(__npp);
1734 }
1735 _STD::swap(__bucket_list_.get_deleter().size(), __u.__bucket_list_.get_deleter().size());
1736 __swap_alloc(__bucket_list_.get_deleter().__alloc(),
1737 __u.__bucket_list_.get_deleter().__alloc());
1738 __swap_alloc(__node_alloc(), __u.__node_alloc());
1739 _STD::swap(__p1_.first().__next_, __u.__p1_.first().__next_);
1740 __p2_.swap(__u.__p2_);
1741 __p3_.swap(__u.__p3_);
1742 if (size() > 0)
1743 __bucket_list_[__p1_.first().__next_->__hash_ % bucket_count()] =
1744 static_cast<__node_pointer>(addressof(__p1_.first()));
1745 if (__u.size() > 0)
1746 __u.__bucket_list_[__u.__p1_.first().__next_->__hash_ % __u.bucket_count()] =
1747 static_cast<__node_pointer>(addressof(__u.__p1_.first()));
1748}
1749
1750template <class _Tp, class _Hash, class _Equal, class _Alloc>
1751typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::size_type
1752__hash_table<_Tp, _Hash, _Equal, _Alloc>::bucket_size(size_type __n) const
1753{
1754 __node_const_pointer __np = __bucket_list_[__n];
1755 size_type __bc = bucket_count();
1756 size_type __r = 0;
1757 if (__np != nullptr)
1758 {
1759 for (__np = __np->__next_; __np != nullptr &&
1760 __np->__hash_ % __bc == __n;
1761 __np = __np->__next_, ++__r)
1762 ;
1763 }
1764 return __r;
1765}
1766
1767_LIBCPP_END_NAMESPACE_STD
1768
1769#endif // _LIBCPP__HASH_TABLE