blob: f1327d54d3bc5cdec8c6e5376c61a1e07770707b [file] [log] [blame]
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊThe LLVM Compiler Infrastructure
5//
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
349#ifdef _LIBCPP_MOVE
350
351 __bucket_list_deallocator(__bucket_list_deallocator&& __x)
352 : __data_(_STD::move(__x.__data_))
353 {
354 __x.size() = 0;
355 }
356
357#endif
358
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);
489#ifdef _LIBCPP_MOVE
490 __hash_table(__hash_table&& __u);
491 __hash_table(__hash_table&& __u, const allocator_type& __a);
492#endif
493 ~__hash_table();
494
495 __hash_table& operator=(const __hash_table& __u);
496#ifdef _LIBCPP_MOVE
497 __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
515#ifdef _LIBCPP_MOVE
516 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);
522#endif
523
524 pair<iterator, bool> __insert_unique(const value_type& __x);
525
526#ifdef _LIBCPP_MOVE
527 template <class _P>
528 pair<iterator, bool> __insert_unique(_P&& __x);
529#endif
530
531#ifdef _LIBCPP_MOVE
532 template <class _P>
533 iterator __insert_multi(_P&& __x);
534 template <class _P>
535 iterator __insert_multi(const_iterator __p, _P&& __x);
536#else
537 iterator __insert_multi(const value_type& __x);
538 iterator __insert_multi(const_iterator __p, const value_type& __x);
539#endif
540
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
618#ifdef _LIBCPP_MOVE
619 template <class ..._Args>
620 __node_holder __construct_node(_Args&& ...__args);
621 __node_holder __construct_node(value_type&& __v, size_t __hash);
622#else
623 __node_holder __construct_node(const value_type& __v);
624#endif
625 __node_holder __construct_node(const value_type& __v, size_t __hash);
626
627 void __copy_assign_alloc(const __hash_table& __u)
628 {__copy_assign_alloc(__u, integral_constant<bool,
629 __node_traits::propagate_on_container_copy_assignment::value>());}
630 void __copy_assign_alloc(const __hash_table& __u, true_type);
631 void __copy_assign_alloc(const __hash_table& __u, false_type) {}
632
633 void __move_assign(__hash_table& __u, false_type);
634 void __move_assign(__hash_table& __u, true_type);
635 void __move_assign_alloc(__hash_table& __u)
636 {__move_assign_alloc(__u, integral_constant<bool,
637 __node_traits::propagate_on_container_move_assignment::value>());}
638 void __move_assign_alloc(__hash_table& __u, true_type)
639 {
640 __bucket_list_.get_deleter().__alloc() =
641 _STD::move(__u.__bucket_list_.get_deleter().__alloc());
642 __node_alloc() = _STD::move(__u.__node_alloc());
643 }
644 void __move_assign_alloc(__hash_table&, false_type) {}
645
646 template <class _A>
647 static
648 void
649 __swap_alloc(_A& __x, _A& __y)
650 {
651 __swap_alloc(__x, __y,
652 integral_constant<bool,
653 allocator_traits<_A>::propagate_on_container_swap::value
654 >());
655 }
656
657 template <class _A>
658 static
659 void
660 __swap_alloc(_A& __x, _A& __y, true_type)
661 {
662 using _STD::swap;
663 swap(__x, __y);
664 }
665
666 template <class _A>
667 static
668 void
669 __swap_alloc(_A& __x, _A& __y, false_type) {}
670
671 void __deallocate(__node_pointer __np);
672 __node_pointer __detach();
673};
674
675template <class _Tp, class _Hash, class _Equal, class _Alloc>
676inline
677__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table()
678 : __p2_(0),
679 __p3_(1.0f)
680{
681}
682
683template <class _Tp, class _Hash, class _Equal, class _Alloc>
684inline
685__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const hasher& __hf,
686 const key_equal& __eql)
687 : __bucket_list_(nullptr, __bucket_list_deleter()),
688 __p1_(),
689 __p2_(0, __hf),
690 __p3_(1.0f, __eql)
691{
692}
693
694template <class _Tp, class _Hash, class _Equal, class _Alloc>
695__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const hasher& __hf,
696 const key_equal& __eql,
697 const allocator_type& __a)
698 : __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
699 __p1_(__node_allocator(__a)),
700 __p2_(0, __hf),
701 __p3_(1.0f, __eql)
702{
703}
704
705template <class _Tp, class _Hash, class _Equal, class _Alloc>
706__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const allocator_type& __a)
707 : __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
708 __p1_(__node_allocator(__a)),
709 __p2_(0),
710 __p3_(1.0f)
711{
712}
713
714template <class _Tp, class _Hash, class _Equal, class _Alloc>
715__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const __hash_table& __u)
716 : __bucket_list_(nullptr,
717 __bucket_list_deleter(allocator_traits<__pointer_allocator>::
718 select_on_container_copy_construction(
719 __u.__bucket_list_.get_deleter().__alloc()), 0)),
720 __p1_(allocator_traits<__node_allocator>::
721 select_on_container_copy_construction(__u.__node_alloc())),
722 __p2_(0, __u.hash_function()),
723 __p3_(__u.__p3_)
724{
725}
726
727template <class _Tp, class _Hash, class _Equal, class _Alloc>
728__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const __hash_table& __u,
729 const allocator_type& __a)
730 : __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
731 __p1_(__node_allocator(__a)),
732 __p2_(0, __u.hash_function()),
733 __p3_(__u.__p3_)
734{
735}
736
737#ifdef _LIBCPP_MOVE
738
739template <class _Tp, class _Hash, class _Equal, class _Alloc>
740__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(__hash_table&& __u)
741 : __bucket_list_(_STD::move(__u.__bucket_list_)),
742 __p1_(_STD::move(__u.__p1_)),
743 __p2_(_STD::move(__u.__p2_)),
744 __p3_(_STD::move(__u.__p3_))
745{
746 if (size() > 0)
747 {
748 __bucket_list_[__p1_.first().__next_->__hash_ % bucket_count()] =
749 static_cast<__node_pointer>(addressof(__p1_.first()));
750 __u.__p1_.first().__next_ = nullptr;
751 __u.size() = 0;
752 }
753}
754
755template <class _Tp, class _Hash, class _Equal, class _Alloc>
756__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(__hash_table&& __u,
757 const allocator_type& __a)
758 : __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
759 __p1_(__node_allocator(__a)),
760 __p2_(0, _STD::move(__u.hash_function())),
761 __p3_(_STD::move(__u.__p3_))
762{
763 if (__a == allocator_type(__u.__node_alloc()))
764 {
765 __bucket_list_.reset(__u.__bucket_list_.release());
766 __bucket_list_.get_deleter().size() = __u.__bucket_list_.get_deleter().size();
767 __u.__bucket_list_.get_deleter().size() = 0;
768 if (__u.size() > 0)
769 {
770 __p1_.first().__next_ = __u.__p1_.first().__next_;
771 __u.__p1_.first().__next_ = nullptr;
772 __bucket_list_[__p1_.first().__next_->__hash_ % bucket_count()] =
773 static_cast<__node_pointer>(addressof(__p1_.first()));
774 size() = __u.size();
775 __u.size() = 0;
776 }
777 }
778}
779
780#endif
781
782template <class _Tp, class _Hash, class _Equal, class _Alloc>
783__hash_table<_Tp, _Hash, _Equal, _Alloc>::~__hash_table()
784{
785 __deallocate(__p1_.first().__next_);
786}
787
788template <class _Tp, class _Hash, class _Equal, class _Alloc>
789void
790__hash_table<_Tp, _Hash, _Equal, _Alloc>::__copy_assign_alloc(
791 const __hash_table& __u, true_type)
792{
793 if (__node_alloc() != __u.__node_alloc())
794 {
795 clear();
796 __bucket_list_.reset();
797 __bucket_list_.get_deleter().size() = 0;
798 }
799 __bucket_list_.get_deleter().__alloc() = __u.__bucket_list_.get_deleter().__alloc();
800 __node_alloc() = __u.__node_alloc();
801}
802
803template <class _Tp, class _Hash, class _Equal, class _Alloc>
804__hash_table<_Tp, _Hash, _Equal, _Alloc>&
805__hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(const __hash_table& __u)
806{
807 if (this != &__u)
808 {
809 __copy_assign_alloc(__u);
810 hash_function() = __u.hash_function();
811 key_eq() = __u.key_eq();
812 max_load_factor() = __u.max_load_factor();
813 __assign_multi(__u.begin(), __u.end());
814 }
815 return *this;
816}
817
818template <class _Tp, class _Hash, class _Equal, class _Alloc>
819void
820__hash_table<_Tp, _Hash, _Equal, _Alloc>::__deallocate(__node_pointer __np)
821{
822 __node_allocator& __na = __node_alloc();
823 while (__np != nullptr)
824 {
825 __node_pointer __next = __np->__next_;
826 __node_traits::destroy(__na, addressof(__np->__value_));
827 __node_traits::deallocate(__na, __np, 1);
828 __np = __next;
829 }
830}
831
832template <class _Tp, class _Hash, class _Equal, class _Alloc>
833typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_pointer
834__hash_table<_Tp, _Hash, _Equal, _Alloc>::__detach()
835{
836 size_type __bc = bucket_count();
837 for (size_type __i = 0; __i < __bc; ++__i)
838 __bucket_list_[__i] = nullptr;
839 size() = 0;
840 __node_pointer __cache = __p1_.first().__next_;
841 __p1_.first().__next_ = nullptr;
842 return __cache;
843}
844
845#ifdef _LIBCPP_MOVE
846
847template <class _Tp, class _Hash, class _Equal, class _Alloc>
848void
849__hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(
850 __hash_table& __u, true_type)
851{
852 clear();
853 __bucket_list_.reset(__u.__bucket_list_.release());
854 __bucket_list_.get_deleter().size() = __u.__bucket_list_.get_deleter().size();
855 __u.__bucket_list_.get_deleter().size() = 0;
856 __move_assign_alloc(__u);
857 size() = __u.size();
858 hash_function() = _STD::move(__u.hash_function());
859 max_load_factor() = __u.max_load_factor();
860 key_eq() = _STD::move(__u.key_eq());
861 __p1_.first().__next_ = __u.__p1_.first().__next_;
862 if (size() > 0)
863 {
864 __bucket_list_[__p1_.first().__next_->__hash_ % bucket_count()] =
865 static_cast<__node_pointer>(addressof(__p1_.first()));
866 __u.__p1_.first().__next_ = nullptr;
867 __u.size() = 0;
868 }
869}
870
871template <class _Tp, class _Hash, class _Equal, class _Alloc>
872void
873__hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(
874 __hash_table& __u, false_type)
875{
876 if (__node_alloc() == __u.__node_alloc())
877 __move_assign(__u, true_type());
878 else
879 {
880 hash_function() = _STD::move(__u.hash_function());
881 key_eq() = _STD::move(__u.key_eq());
882 max_load_factor() = __u.max_load_factor();
883 if (bucket_count() != 0)
884 {
885 __node_pointer __cache = __detach();
886#ifndef _LIBCPP_NO_EXCEPTIONS
887 try
888 {
889#endif
890 const_iterator __i = __u.begin();
891 while (__cache != nullptr && __u.size() != 0)
892 {
893 __cache->__value_ = _STD::move(__u.remove(__i++)->__value_);
894 __node_pointer __next = __cache->__next_;
895 __node_insert_multi(__cache);
896 __cache = __next;
897 }
898#ifndef _LIBCPP_NO_EXCEPTIONS
899 }
900 catch (...)
901 {
902 __deallocate(__cache);
903 throw;
904 }
905#endif
906 __deallocate(__cache);
907 }
908 const_iterator __i = __u.begin();
909 while (__u.size() != 0)
910 {
911 __node_holder __h =
912 __construct_node(_STD::move(__u.remove(__i++)->__value_));
913 __node_insert_multi(__h.get());
914 __h.release();
915 }
916 }
917}
918
919template <class _Tp, class _Hash, class _Equal, class _Alloc>
920inline
921__hash_table<_Tp, _Hash, _Equal, _Alloc>&
922__hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(__hash_table&& __u)
923{
924 __move_assign(__u, integral_constant<bool,
925 __node_traits::propagate_on_container_move_assignment::value>());
926 return *this;
927}
928
929#endif
930
931template <class _Tp, class _Hash, class _Equal, class _Alloc>
932template <class _InputIterator>
933void
934__hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_unique(_InputIterator __first,
935 _InputIterator __last)
936{
937 if (bucket_count() != 0)
938 {
939 __node_pointer __cache = __detach();
940#ifndef _LIBCPP_NO_EXCEPTIONS
941 try
942 {
943#endif
944 for (; __cache != nullptr && __first != __last; ++__first)
945 {
946 __cache->__value_ = *__first;
947 __node_pointer __next = __cache->__next_;
948 __node_insert_unique(__cache);
949 __cache = __next;
950 }
951#ifndef _LIBCPP_NO_EXCEPTIONS
952 }
953 catch (...)
954 {
955 __deallocate(__cache);
956 throw;
957 }
958#endif
959 __deallocate(__cache);
960 }
961 for (; __first != __last; ++__first)
962 __insert_unique(*__first);
963}
964
965template <class _Tp, class _Hash, class _Equal, class _Alloc>
966template <class _InputIterator>
967void
968__hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_multi(_InputIterator __first,
969 _InputIterator __last)
970{
971 if (bucket_count() != 0)
972 {
973 __node_pointer __cache = __detach();
974#ifndef _LIBCPP_NO_EXCEPTIONS
975 try
976 {
977#endif
978 for (; __cache != nullptr && __first != __last; ++__first)
979 {
980 __cache->__value_ = *__first;
981 __node_pointer __next = __cache->__next_;
982 __node_insert_multi(__cache);
983 __cache = __next;
984 }
985#ifndef _LIBCPP_NO_EXCEPTIONS
986 }
987 catch (...)
988 {
989 __deallocate(__cache);
990 throw;
991 }
992#endif
993 __deallocate(__cache);
994 }
995 for (; __first != __last; ++__first)
996 __insert_multi(*__first);
997}
998
999template <class _Tp, class _Hash, class _Equal, class _Alloc>
1000inline
1001typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1002__hash_table<_Tp, _Hash, _Equal, _Alloc>::begin()
1003{
1004 return iterator(__p1_.first().__next_);
1005}
1006
1007template <class _Tp, class _Hash, class _Equal, class _Alloc>
1008inline
1009typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1010__hash_table<_Tp, _Hash, _Equal, _Alloc>::end()
1011{
1012 return iterator(nullptr);
1013}
1014
1015template <class _Tp, class _Hash, class _Equal, class _Alloc>
1016inline
1017typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator
1018__hash_table<_Tp, _Hash, _Equal, _Alloc>::begin() const
1019{
1020 return const_iterator(__p1_.first().__next_);
1021}
1022
1023template <class _Tp, class _Hash, class _Equal, class _Alloc>
1024inline
1025typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator
1026__hash_table<_Tp, _Hash, _Equal, _Alloc>::end() const
1027{
1028 return const_iterator(nullptr);
1029}
1030
1031template <class _Tp, class _Hash, class _Equal, class _Alloc>
1032void
1033__hash_table<_Tp, _Hash, _Equal, _Alloc>::clear()
1034{
1035 if (size() > 0)
1036 {
1037 __deallocate(__p1_.first().__next_);
1038 __p1_.first().__next_ = nullptr;
1039 size_type __bc = bucket_count();
1040 for (size_type __i; __i < __bc; ++__i)
1041 __bucket_list_[__i] = nullptr;
1042 size() = 0;
1043 }
1044}
1045
1046template <class _Tp, class _Hash, class _Equal, class _Alloc>
1047pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool>
1048__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_unique(__node_pointer __nd)
1049{
1050 __nd->__hash_ = hash_function()(__nd->__value_);
1051 size_type __bc = bucket_count();
1052 bool __inserted = false;
1053 __node_pointer __ndptr;
1054 size_t __chash;
1055 if (__bc != 0)
1056 {
1057 __chash = __nd->__hash_ % __bc;
1058 __ndptr = __bucket_list_[__chash];
1059 if (__ndptr != nullptr)
1060 {
1061 for (__ndptr = __ndptr->__next_; __ndptr != nullptr &&
1062 __ndptr->__hash_ % __bc == __chash;
1063 __ndptr = __ndptr->__next_)
1064 {
1065 if (key_eq()(__ndptr->__value_, __nd->__value_))
1066 goto __done;
1067 }
1068 }
1069 }
1070 {
1071 if (size()+1 > __bc * max_load_factor() || __bc == 0)
1072 {
1073 rehash(_STD::max<size_type>(2 * __bc + 1,
1074 size_type(ceil(float(size() + 1) / max_load_factor()))));
1075 __bc = bucket_count();
1076 __chash = __nd->__hash_ % __bc;
1077 }
1078 // insert_after __bucket_list_[__chash], or __first_node if bucket is null
1079 __node_pointer __pn = __bucket_list_[__chash];
1080 if (__pn == nullptr)
1081 {
1082 __pn = static_cast<__node_pointer>(addressof(__p1_.first()));
1083 __nd->__next_ = __pn->__next_;
1084 __pn->__next_ = __nd;
1085 // fix up __bucket_list_
1086 __bucket_list_[__chash] = __pn;
1087 if (__nd->__next_ != nullptr)
1088 __bucket_list_[__nd->__next_->__hash_ % __bc] = __nd;
1089 }
1090 else
1091 {
1092 __nd->__next_ = __pn->__next_;
1093 __pn->__next_ = __nd;
1094 }
1095 __ndptr = __nd;
1096 // increment size
1097 ++size();
1098 __inserted = true;
1099 }
1100__done:
1101 return pair<iterator, bool>(iterator(__ndptr), __inserted);
1102}
1103
1104template <class _Tp, class _Hash, class _Equal, class _Alloc>
1105typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1106__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi(__node_pointer __cp)
1107{
1108 __cp->__hash_ = hash_function()(__cp->__value_);
1109 size_type __bc = bucket_count();
1110 if (size()+1 > __bc * max_load_factor() || __bc == 0)
1111 {
1112 rehash(_STD::max<size_type>(2 * __bc + 1,
1113 size_type(ceil(float(size() + 1) / max_load_factor()))));
1114 __bc = bucket_count();
1115 }
1116 size_t __chash = __cp->__hash_ % __bc;
1117 __node_pointer __pn = __bucket_list_[__chash];
1118 if (__pn == nullptr)
1119 {
1120 __pn = static_cast<__node_pointer>(addressof(__p1_.first()));
1121 __cp->__next_ = __pn->__next_;
1122 __pn->__next_ = __cp;
1123 // fix up __bucket_list_
1124 __bucket_list_[__chash] = __pn;
1125 if (__cp->__next_ != nullptr)
1126 __bucket_list_[__cp->__next_->__hash_ % __bc] = __cp;
1127 }
1128 else
1129 {
1130 for (bool __found = false; __pn->__next_ != nullptr &&
1131 __pn->__next_->__hash_ % __bc == __chash;
1132 __pn = __pn->__next_)
1133 {
1134 // __found key_eq() action
1135 // false false loop
1136 // true true loop
1137 // false true set __found to true
1138 // true false break
1139 if (__found != (__pn->__next_->__hash_ == __cp->__hash_ &&
1140 key_eq()(__pn->__next_->__value_, __cp->__value_)))
1141 {
1142 if (!__found)
1143 __found = true;
1144 else
1145 break;
1146 }
1147 }
1148 __cp->__next_ = __pn->__next_;
1149 __pn->__next_ = __cp;
1150 if (__cp->__next_ != nullptr)
1151 {
1152 size_t __nhash = __cp->__next_->__hash_ % __bc;
1153 if (__nhash != __chash)
1154 __bucket_list_[__nhash] = __cp;
1155 }
1156 }
1157 ++size();
1158 return iterator(__cp);
1159}
1160
1161template <class _Tp, class _Hash, class _Equal, class _Alloc>
1162typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1163__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi(
1164 const_iterator __p, __node_pointer __cp)
1165{
1166 if (__p != end() && key_eq()(*__p, __cp->__value_))
1167 {
1168 __node_pointer __np = const_cast<__node_pointer>(__p.__node_);
1169 __cp->__hash_ = __np->__hash_;
1170 size_type __bc = bucket_count();
1171 if (size()+1 > __bc * max_load_factor() || __bc == 0)
1172 {
1173 rehash(_STD::max<size_type>(2 * __bc + 1,
1174 size_type(ceil(float(size() + 1) / max_load_factor()))));
1175 __bc = bucket_count();
1176 }
1177 size_t __chash = __cp->__hash_ % __bc;
1178 __node_pointer __pp = __bucket_list_[__chash];
1179 while (__pp->__next_ != __np)
1180 __pp = __pp->__next_;
1181 __cp->__next_ = __np;
1182 __pp->__next_ = __cp;
1183 ++size();
1184 return iterator(__cp);
1185 }
1186 return __node_insert_multi(__cp);
1187}
1188
1189template <class _Tp, class _Hash, class _Equal, class _Alloc>
1190pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool>
1191__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_unique(const value_type& __x)
1192{
1193 size_t __hash = hash_function()(__x);
1194 size_type __bc = bucket_count();
1195 bool __inserted = false;
1196 __node_pointer __nd;
1197 size_t __chash;
1198 if (__bc != 0)
1199 {
1200 __chash = __hash % __bc;
1201 __nd = __bucket_list_[__chash];
1202 if (__nd != nullptr)
1203 {
1204 for (__nd = __nd->__next_; __nd != nullptr &&
1205 __nd->__hash_ % __bc == __chash;
1206 __nd = __nd->__next_)
1207 {
1208 if (key_eq()(__nd->__value_, __x))
1209 goto __done;
1210 }
1211 }
1212 }
1213 {
1214 __node_holder __h = __construct_node(__x, __hash);
1215 if (size()+1 > __bc * max_load_factor() || __bc == 0)
1216 {
1217 rehash(_STD::max<size_type>(2 * __bc + 1,
1218 size_type(ceil(float(size() + 1) / max_load_factor()))));
1219 __bc = bucket_count();
1220 __chash = __hash % __bc;
1221 }
1222 // insert_after __bucket_list_[__chash], or __first_node if bucket is null
1223 __node_pointer __pn = __bucket_list_[__chash];
1224 if (__pn == nullptr)
1225 {
1226 __pn = static_cast<__node_pointer>(addressof(__p1_.first()));
1227 __h->__next_ = __pn->__next_;
1228 __pn->__next_ = __h.get();
1229 // fix up __bucket_list_
1230 __bucket_list_[__chash] = __pn;
1231 if (__h->__next_ != nullptr)
1232 __bucket_list_[__h->__next_->__hash_ % __bc] = __h.get();
1233 }
1234 else
1235 {
1236 __h->__next_ = __pn->__next_;
1237 __pn->__next_ = __h.get();
1238 }
1239 __nd = __h.release();
1240 // increment size
1241 ++size();
1242 __inserted = true;
1243 }
1244__done:
1245 return pair<iterator, bool>(iterator(__nd), __inserted);
1246}
1247
1248#ifdef _LIBCPP_MOVE
1249
1250template <class _Tp, class _Hash, class _Equal, class _Alloc>
1251template <class... _Args>
1252pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool>
1253__hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_unique(_Args&&... __args)
1254{
1255 __node_holder __h = __construct_node(_STD::forward<_Args>(__args)...);
1256 pair<iterator, bool> __r = __node_insert_unique(__h.get());
1257 if (__r.second)
1258 __h.release();
1259 return __r;
1260}
1261
1262template <class _Tp, class _Hash, class _Equal, class _Alloc>
1263template <class... _Args>
1264typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1265__hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_multi(_Args&&... __args)
1266{
1267 __node_holder __h = __construct_node(_STD::forward<_Args>(__args)...);
1268 iterator __r = __node_insert_multi(__h.get());
1269 __h.release();
1270 return __r;
1271}
1272
1273template <class _Tp, class _Hash, class _Equal, class _Alloc>
1274template <class... _Args>
1275typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1276__hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_hint_multi(
1277 const_iterator __p, _Args&&... __args)
1278{
1279 __node_holder __h = __construct_node(_STD::forward<_Args>(__args)...);
1280 iterator __r = __node_insert_multi(__p, __h.get());
1281 __h.release();
1282 return __r;
1283}
1284
1285template <class _Tp, class _Hash, class _Equal, class _Alloc>
1286template <class _P>
1287pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool>
1288__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_unique(_P&& __x)
1289{
1290 __node_holder __h = __construct_node(_STD::forward<_P>(__x));
1291 pair<iterator, bool> __r = __node_insert_unique(__h.get());
1292 if (__r.second)
1293 __h.release();
1294 return __r;
1295}
1296
1297#endif
1298
1299#ifdef _LIBCPP_MOVE
1300
1301template <class _Tp, class _Hash, class _Equal, class _Alloc>
1302template <class _P>
1303typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1304__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_multi(_P&& __x)
1305{
1306 __node_holder __h = __construct_node(_STD::forward<_P>(__x));
1307 iterator __r = __node_insert_multi(__h.get());
1308 __h.release();
1309 return __r;
1310}
1311
1312template <class _Tp, class _Hash, class _Equal, class _Alloc>
1313template <class _P>
1314typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1315__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_multi(const_iterator __p,
1316 _P&& __x)
1317{
1318 __node_holder __h = __construct_node(_STD::forward<_P>(__x));
1319 iterator __r = __node_insert_multi(__p, __h.get());
1320 __h.release();
1321 return __r;
1322}
1323
1324#else
1325
1326template <class _Tp, class _Hash, class _Equal, class _Alloc>
1327typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1328__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_multi(const value_type& __x)
1329{
1330 __node_holder __h = __construct_node(__x);
1331 iterator __r = __node_insert_multi(__h.get());
1332 __h.release();
1333 return __r;
1334}
1335
1336template <class _Tp, class _Hash, class _Equal, class _Alloc>
1337typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1338__hash_table<_Tp, _Hash, _Equal, _Alloc>::__insert_multi(const_iterator __p,
1339 const value_type& __x)
1340{
1341 __node_holder __h = __construct_node(__x);
1342 iterator __r = __node_insert_multi(__p, __h.get());
1343 __h.release();
1344 return __r;
1345}
1346
1347#endif
1348
1349template <class _Tp, class _Hash, class _Equal, class _Alloc>
1350void
1351__hash_table<_Tp, _Hash, _Equal, _Alloc>::rehash(size_type __n)
1352{
1353 __n = __next_prime(_STD::max<size_type>(__n, size() > 0));
1354 size_type __bc = bucket_count();
1355 if (__n > __bc)
1356 __rehash(__n);
1357 else
1358 {
1359 __n = _STD::max<size_type>
1360 (
1361 __n,
1362 __next_prime(size_t(ceil(float(size()) / max_load_factor())))
1363 );
1364 if (__n < __bc)
1365 __rehash(__n);
1366 }
1367}
1368
1369template <class _Tp, class _Hash, class _Equal, class _Alloc>
1370void
1371__hash_table<_Tp, _Hash, _Equal, _Alloc>::__rehash(size_type __nbc)
1372{
1373 __pointer_allocator& __npa = __bucket_list_.get_deleter().__alloc();
1374 __bucket_list_.reset(__nbc > 0 ?
1375 __pointer_alloc_traits::allocate(__npa, __nbc) : nullptr);
1376 __bucket_list_.get_deleter().size() = __nbc;
1377 if (__nbc > 0)
1378 {
1379 for (size_type __i = 0; __i < __nbc; ++__i)
1380 __bucket_list_[__i] = nullptr;
1381 __node_pointer __pp(static_cast<__node_pointer>(addressof(__p1_.first())));
1382 __node_pointer __cp = __pp->__next_;
1383 if (__cp != nullptr)
1384 {
1385 size_type __chash = __cp->__hash_ % __nbc;
1386 __bucket_list_[__chash] = __pp;
1387 size_type __phash = __chash;
1388 for (__pp = __cp, __cp = __cp->__next_; __cp != nullptr;
1389 __cp = __pp->__next_)
1390 {
1391 __chash = __cp->__hash_ % __nbc;
1392 if (__chash == __phash)
1393 __pp = __cp;
1394 else
1395 {
1396 if (__bucket_list_[__chash] == nullptr)
1397 {
1398 __bucket_list_[__chash] = __pp;
1399 __pp = __cp;
1400 __phash = __chash;
1401 }
1402 else
1403 {
1404 __node_pointer __np = __cp;
1405 for (; __np->__next_ != nullptr &&
1406 key_eq()(__cp->__value_, __np->__next_->__value_);
1407 __np = __np->__next_)
1408 ;
1409 __pp->__next_ = __np->__next_;
1410 __np->__next_ = __bucket_list_[__chash]->__next_;
1411 __bucket_list_[__chash]->__next_ = __cp;
1412
1413 }
1414 }
1415 }
1416 }
1417 }
1418}
1419
1420template <class _Tp, class _Hash, class _Equal, class _Alloc>
1421template <class _Key>
1422typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1423__hash_table<_Tp, _Hash, _Equal, _Alloc>::find(const _Key& __k)
1424{
1425 size_t __hash = hash_function()(__k);
1426 size_type __bc = bucket_count();
1427 if (__bc != 0)
1428 {
1429 size_t __chash = __hash % __bc;
1430 __node_pointer __nd = __bucket_list_[__chash];
1431 if (__nd != nullptr)
1432 {
1433 for (__nd = __nd->__next_; __nd != nullptr &&
1434 __nd->__hash_ % __bc == __chash;
1435 __nd = __nd->__next_)
1436 {
1437 if (key_eq()(__nd->__value_, __k))
1438 return iterator(__nd);
1439 }
1440 }
1441 }
1442 return end();
1443}
1444
1445template <class _Tp, class _Hash, class _Equal, class _Alloc>
1446template <class _Key>
1447typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator
1448__hash_table<_Tp, _Hash, _Equal, _Alloc>::find(const _Key& __k) const
1449{
1450 size_t __hash = hash_function()(__k);
1451 size_type __bc = bucket_count();
1452 if (__bc != 0)
1453 {
1454 size_t __chash = __hash % __bc;
1455 __node_const_pointer __nd = __bucket_list_[__chash];
1456 if (__nd != nullptr)
1457 {
1458 for (__nd = __nd->__next_; __nd != nullptr &&
1459 __nd->__hash_ % __bc == __chash;
1460 __nd = __nd->__next_)
1461 {
1462 if (key_eq()(__nd->__value_, __k))
1463 return const_iterator(__nd);
1464 }
1465 }
1466
1467 }
1468 return end();
1469}
1470
1471#ifdef _LIBCPP_MOVE
1472
1473template <class _Tp, class _Hash, class _Equal, class _Alloc>
1474template <class ..._Args>
1475typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder
1476__hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node(_Args&& ...__args)
1477{
1478 __node_allocator& __na = __node_alloc();
1479 __node_holder __h(__node_traits::allocate(__na, 1), _D(__na));
1480 __node_traits::construct(__na, addressof(__h->__value_), _STD::forward<_Args>(__args)...);
1481 __h.get_deleter().__value_constructed = true;
1482 __h->__hash_ = hash_function()(__h->__value_);
1483 __h->__next_ = nullptr;
1484 return __h;
1485}
1486
1487template <class _Tp, class _Hash, class _Equal, class _Alloc>
1488typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder
1489__hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node(value_type&& __v,
1490 size_t __hash)
1491{
1492 __node_allocator& __na = __node_alloc();
1493 __node_holder __h(__node_traits::allocate(__na, 1), _D(__na));
1494 __node_traits::construct(__na, addressof(__h->__value_), _STD::move(__v));
1495 __h.get_deleter().__value_constructed = true;
1496 __h->__hash_ = __hash;
1497 __h->__next_ = nullptr;
1498 return _STD::move(__h);
1499}
1500
1501#else
1502
1503template <class _Tp, class _Hash, class _Equal, class _Alloc>
1504typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder
1505__hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node(const value_type& __v)
1506{
1507 __node_allocator& __na = __node_alloc();
1508 __node_holder __h(__node_traits::allocate(__na, 1), _D(__na));
1509 __node_traits::construct(__na, addressof(__h->__value_), __v);
1510 __h.get_deleter().__value_constructed = true;
1511 __h->__hash_ = hash_function()(__h->__value_);
1512 __h->__next_ = nullptr;
1513 return _STD::move(__h);
1514}
1515
1516#endif
1517
1518template <class _Tp, class _Hash, class _Equal, class _Alloc>
1519typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder
1520__hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node(const value_type& __v,
1521 size_t __hash)
1522{
1523 __node_allocator& __na = __node_alloc();
1524 __node_holder __h(__node_traits::allocate(__na, 1), _D(__na));
1525 __node_traits::construct(__na, addressof(__h->__value_), __v);
1526 __h.get_deleter().__value_constructed = true;
1527 __h->__hash_ = __hash;
1528 __h->__next_ = nullptr;
1529 return _STD::move(__h);
1530}
1531
1532template <class _Tp, class _Hash, class _Equal, class _Alloc>
1533typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1534__hash_table<_Tp, _Hash, _Equal, _Alloc>::erase(const_iterator __p)
1535{
1536 __node_pointer __np = const_cast<__node_pointer>(__p.__node_);
1537 iterator __r(__np);
1538 ++__r;
1539 remove(__p);
1540 return __r;
1541}
1542
1543template <class _Tp, class _Hash, class _Equal, class _Alloc>
1544typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1545__hash_table<_Tp, _Hash, _Equal, _Alloc>::erase(const_iterator __first,
1546 const_iterator __last)
1547{
1548 for (const_iterator __p = __first; __first != __last; __p = __first)
1549 {
1550 ++__first;
1551 erase(__p);
1552 }
1553 __node_pointer __np = const_cast<__node_pointer>(__last.__node_);
1554 return iterator (__np);
1555}
1556
1557template <class _Tp, class _Hash, class _Equal, class _Alloc>
1558template <class _Key>
1559typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::size_type
1560__hash_table<_Tp, _Hash, _Equal, _Alloc>::__erase_unique(const _Key& __k)
1561{
1562 iterator __i = find(__k);
1563 if (__i == end())
1564 return 0;
1565 erase(__i);
1566 return 1;
1567}
1568
1569template <class _Tp, class _Hash, class _Equal, class _Alloc>
1570template <class _Key>
1571typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::size_type
1572__hash_table<_Tp, _Hash, _Equal, _Alloc>::__erase_multi(const _Key& __k)
1573{
1574 size_type __r = 0;
1575 iterator __i = find(__k);
1576 if (__i != end())
1577 {
1578 iterator __e = end();
1579 do
1580 {
1581 erase(__i++);
1582 ++__r;
1583 } while (__i != __e && key_eq()(*__i, __k));
1584 }
1585 return __r;
1586}
1587
1588template <class _Tp, class _Hash, class _Equal, class _Alloc>
1589typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder
1590__hash_table<_Tp, _Hash, _Equal, _Alloc>::remove(const_iterator __p)
1591{
1592 // current node
1593 __node_pointer __cn = const_cast<__node_pointer>(__p.__node_);
1594 size_type __bc = bucket_count();
1595 size_t __chash = __cn->__hash_ % __bc;
1596 // find previous node
1597 __node_pointer __pn = __bucket_list_[__chash];
1598 for (; __pn->__next_ != __cn; __pn = __pn->__next_)
1599 ;
1600 // Fix up __bucket_list_
1601 // if __pn is not in same bucket (before begin is not in same bucket) &&
1602 // if __cn->__next_ is not in same bucket (nullptr is not in same bucket)
1603 if (__pn == addressof(__p1_.first()) || __pn->__hash_ % __bc != __chash)
1604 {
1605 if (__cn->__next_ == nullptr || __cn->__next_->__hash_ % __bc != __chash)
1606 __bucket_list_[__chash] = nullptr;
1607 }
1608 // if __cn->__next_ is not in same bucket (nullptr is in same bucket)
1609 if (__cn->__next_ != nullptr)
1610 {
1611 size_t __nhash = __cn->__next_->__hash_ % __bc;
1612 if (__nhash != __chash)
1613 __bucket_list_[__nhash] = __pn;
1614 }
1615 // remove __cn
1616 __pn->__next_ = __cn->__next_;
1617 __cn->__next_ = nullptr;
1618 --size();
1619 return __node_holder(__cn, _D(__node_alloc()));
1620}
1621
1622template <class _Tp, class _Hash, class _Equal, class _Alloc>
1623template <class _Key>
1624inline
1625typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::size_type
1626__hash_table<_Tp, _Hash, _Equal, _Alloc>::__count_unique(const _Key& __k) const
1627{
1628 return static_cast<size_type>(find(__k) != end());
1629}
1630
1631template <class _Tp, class _Hash, class _Equal, class _Alloc>
1632template <class _Key>
1633typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::size_type
1634__hash_table<_Tp, _Hash, _Equal, _Alloc>::__count_multi(const _Key& __k) const
1635{
1636 size_type __r = 0;
1637 const_iterator __i = find(__k);
1638 if (__i != end())
1639 {
1640 const_iterator __e = end();
1641 do
1642 {
1643 ++__i;
1644 ++__r;
1645 } while (__i != __e && key_eq()(*__i, __k));
1646 }
1647 return __r;
1648}
1649
1650template <class _Tp, class _Hash, class _Equal, class _Alloc>
1651template <class _Key>
1652pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator,
1653 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator>
1654__hash_table<_Tp, _Hash, _Equal, _Alloc>::__equal_range_unique(
1655 const _Key& __k)
1656{
1657 iterator __i = find(__k);
1658 iterator __j = __i;
1659 if (__i != end())
1660 ++__j;
1661 return pair<iterator, iterator>(__i, __j);
1662}
1663
1664template <class _Tp, class _Hash, class _Equal, class _Alloc>
1665template <class _Key>
1666pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator,
1667 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator>
1668__hash_table<_Tp, _Hash, _Equal, _Alloc>::__equal_range_unique(
1669 const _Key& __k) const
1670{
1671 const_iterator __i = find(__k);
1672 const_iterator __j = __i;
1673 if (__i != end())
1674 ++__j;
1675 return pair<const_iterator, const_iterator>(__i, __j);
1676}
1677
1678template <class _Tp, class _Hash, class _Equal, class _Alloc>
1679template <class _Key>
1680pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator,
1681 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator>
1682__hash_table<_Tp, _Hash, _Equal, _Alloc>::__equal_range_multi(
1683 const _Key& __k)
1684{
1685 iterator __i = find(__k);
1686 iterator __j = __i;
1687 if (__i != end())
1688 {
1689 iterator __e = end();
1690 do
1691 {
1692 ++__j;
1693 } while (__j != __e && key_eq()(*__j, __k));
1694 }
1695 return pair<iterator, iterator>(__i, __j);
1696}
1697
1698template <class _Tp, class _Hash, class _Equal, class _Alloc>
1699template <class _Key>
1700pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator,
1701 typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator>
1702__hash_table<_Tp, _Hash, _Equal, _Alloc>::__equal_range_multi(
1703 const _Key& __k) const
1704{
1705 const_iterator __i = find(__k);
1706 const_iterator __j = __i;
1707 if (__i != end())
1708 {
1709 const_iterator __e = end();
1710 do
1711 {
1712 ++__j;
1713 } while (__j != __e && key_eq()(*__j, __k));
1714 }
1715 return pair<const_iterator, const_iterator>(__i, __j);
1716}
1717
1718template <class _Tp, class _Hash, class _Equal, class _Alloc>
1719void
1720__hash_table<_Tp, _Hash, _Equal, _Alloc>::swap(__hash_table& __u)
1721{
1722 {
1723 __node_pointer_pointer __npp = __bucket_list_.release();
1724 __bucket_list_.reset(__u.__bucket_list_.release());
1725 __u.__bucket_list_.reset(__npp);
1726 }
1727 _STD::swap(__bucket_list_.get_deleter().size(), __u.__bucket_list_.get_deleter().size());
1728 __swap_alloc(__bucket_list_.get_deleter().__alloc(),
1729 __u.__bucket_list_.get_deleter().__alloc());
1730 __swap_alloc(__node_alloc(), __u.__node_alloc());
1731 _STD::swap(__p1_.first().__next_, __u.__p1_.first().__next_);
1732 __p2_.swap(__u.__p2_);
1733 __p3_.swap(__u.__p3_);
1734 if (size() > 0)
1735 __bucket_list_[__p1_.first().__next_->__hash_ % bucket_count()] =
1736 static_cast<__node_pointer>(addressof(__p1_.first()));
1737 if (__u.size() > 0)
1738 __u.__bucket_list_[__u.__p1_.first().__next_->__hash_ % __u.bucket_count()] =
1739 static_cast<__node_pointer>(addressof(__u.__p1_.first()));
1740}
1741
1742template <class _Tp, class _Hash, class _Equal, class _Alloc>
1743typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::size_type
1744__hash_table<_Tp, _Hash, _Equal, _Alloc>::bucket_size(size_type __n) const
1745{
1746 __node_const_pointer __np = __bucket_list_[__n];
1747 size_type __bc = bucket_count();
1748 size_type __r = 0;
1749 if (__np != nullptr)
1750 {
1751 for (__np = __np->__next_; __np != nullptr &&
1752 __np->__hash_ % __bc == __n;
1753 __np = __np->__next_, ++__r)
1754 ;
1755 }
1756 return __r;
1757}
1758
1759_LIBCPP_END_NAMESPACE_STD
1760
1761#endif // _LIBCPP__HASH_TABLE