comparison libstdc++-v3/include/bits/hashtable.h @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children dafe684d005c
comparison
equal deleted inserted replaced
131:84e7813d76e9 145:1830386684a0
1 // hashtable.h header -*- C++ -*- 1 // hashtable.h header -*- C++ -*-
2 2
3 // Copyright (C) 2007-2018 Free Software Foundation, Inc. 3 // Copyright (C) 2007-2020 Free Software Foundation, Inc.
4 // 4 //
5 // This file is part of the GNU ISO C++ Library. This library is free 5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the 6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the 7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option) 8 // Free Software Foundation; either version 3, or (at your option)
186 __detail::_Hash_node<_Value, 186 __detail::_Hash_node<_Value,
187 _Traits::__hash_cached::value>>> 187 _Traits::__hash_cached::value>>>
188 { 188 {
189 static_assert(is_same<typename remove_cv<_Value>::type, _Value>::value, 189 static_assert(is_same<typename remove_cv<_Value>::type, _Value>::value,
190 "unordered container must have a non-const, non-volatile value_type"); 190 "unordered container must have a non-const, non-volatile value_type");
191 #ifdef __STRICT_ANSI__ 191 #if __cplusplus > 201703L || defined __STRICT_ANSI__
192 static_assert(is_same<typename _Alloc::value_type, _Value>{}, 192 static_assert(is_same<typename _Alloc::value_type, _Value>{},
193 "unordered container must have the same value_type as its allocator"); 193 "unordered container must have the same value_type as its allocator");
194 #endif 194 #endif
195 static_assert(__is_invocable<const _H1&, const _Key&>{},
196 "hash function must be invocable with an argument of key type");
197 static_assert(__is_invocable<const _Equal&, const _Key&, const _Key&>{},
198 "key equality predicate must be invocable with two arguments of "
199 "key type");
200 195
201 using __traits_type = _Traits; 196 using __traits_type = _Traits;
202 using __hash_cached = typename __traits_type::__hash_cached; 197 using __hash_cached = typename __traits_type::__hash_cached;
203 using __node_type = __detail::_Hash_node<_Value, __hash_cached::value>; 198 using __node_type = __detail::_Hash_node<_Value, __hash_cached::value>;
204 using __node_alloc_type = __alloc_rebind<_Alloc, __node_type>; 199 using __node_alloc_type = __alloc_rebind<_Alloc, __node_type>;
256 251
257 using __eq_base = __detail::_Equality<_Key, _Value, _Alloc, _ExtractKey, 252 using __eq_base = __detail::_Equality<_Key, _Value, _Alloc, _ExtractKey,
258 _Equal, _H1, _H2, _Hash, 253 _Equal, _H1, _H2, _Hash,
259 _RehashPolicy, _Traits>; 254 _RehashPolicy, _Traits>;
260 255
261 using __reuse_or_alloc_node_type = 256 using __reuse_or_alloc_node_gen_t =
262 __detail::_ReuseOrAllocNode<__node_alloc_type>; 257 __detail::_ReuseOrAllocNode<__node_alloc_type>;
258 using __alloc_node_gen_t =
259 __detail::_AllocNode<__node_alloc_type>;
260
261 // Simple RAII type for managing a node containing an element
262 struct _Scoped_node
263 {
264 // Take ownership of a node with a constructed element.
265 _Scoped_node(__node_type* __n, __hashtable_alloc* __h)
266 : _M_h(__h), _M_node(__n) { }
267
268 // Allocate a node and construct an element within it.
269 template<typename... _Args>
270 _Scoped_node(__hashtable_alloc* __h, _Args&&... __args)
271 : _M_h(__h),
272 _M_node(__h->_M_allocate_node(std::forward<_Args>(__args)...))
273 { }
274
275 // Destroy element and deallocate node.
276 ~_Scoped_node() { if (_M_node) _M_h->_M_deallocate_node(_M_node); };
277
278 _Scoped_node(const _Scoped_node&) = delete;
279 _Scoped_node& operator=(const _Scoped_node&) = delete;
280
281 __hashtable_alloc* _M_h;
282 __node_type* _M_node;
283 };
284
285 template<typename _Ht>
286 static constexpr
287 typename conditional<std::is_lvalue_reference<_Ht>::value,
288 const value_type&, value_type&&>::type
289 __fwd_value_for(value_type& __val) noexcept
290 { return std::move(__val); }
263 291
264 // Metaprogramming for picking apart hash caching. 292 // Metaprogramming for picking apart hash caching.
265 template<typename _Cond> 293 template<typename _Cond>
266 using __if_hash_cached = __or_<__not_<__hash_cached>, _Cond>; 294 using __if_hash_cached = __or_<__not_<__hash_cached>, _Cond>;
267 295
281 ._M_bucket_index((const __node_type*)nullptr, 309 ._M_bucket_index((const __node_type*)nullptr,
282 (std::size_t)0)), 310 (std::size_t)0)),
283 "Cache the hash code or qualify your functors involved" 311 "Cache the hash code or qualify your functors involved"
284 " in hash code and bucket index computation with noexcept"); 312 " in hash code and bucket index computation with noexcept");
285 313
286 // Following two static assertions are necessary to guarantee
287 // that local_iterator will be default constructible.
288
289 // When hash codes are cached local iterator inherits from H2 functor 314 // When hash codes are cached local iterator inherits from H2 functor
290 // which must then be default constructible. 315 // which must then be default constructible.
291 static_assert(__if_hash_cached<is_default_constructible<_H2>>::value, 316 static_assert(__if_hash_cached<is_default_constructible<_H2>>::value,
292 "Functor used to map hash code to bucket index" 317 "Functor used to map hash code to bucket index"
293 " must be default constructible"); 318 " must be default constructible");
310 typename _H1a, typename _H2a, typename _Hasha, 335 typename _H1a, typename _H2a, typename _Hasha,
311 typename _RehashPolicya, typename _Traitsa, 336 typename _RehashPolicya, typename _Traitsa,
312 bool _Constant_iteratorsa> 337 bool _Constant_iteratorsa>
313 friend struct __detail::_Insert; 338 friend struct __detail::_Insert;
314 339
340 template<typename _Keya, typename _Valuea, typename _Alloca,
341 typename _ExtractKeya, typename _Equala,
342 typename _H1a, typename _H2a, typename _Hasha,
343 typename _RehashPolicya, typename _Traitsa,
344 bool _Unique_keysa>
345 friend struct __detail::_Equality;
346
315 public: 347 public:
316 using size_type = typename __hashtable_base::size_type; 348 using size_type = typename __hashtable_base::size_type;
317 using difference_type = typename __hashtable_base::difference_type; 349 using difference_type = typename __hashtable_base::difference_type;
318 350
319 using iterator = typename __hashtable_base::iterator; 351 using iterator = typename __hashtable_base::iterator;
334 __node_base _M_before_begin; 366 __node_base _M_before_begin;
335 size_type _M_element_count = 0; 367 size_type _M_element_count = 0;
336 _RehashPolicy _M_rehash_policy; 368 _RehashPolicy _M_rehash_policy;
337 369
338 // A single bucket used when only need for 1 bucket. Especially 370 // A single bucket used when only need for 1 bucket. Especially
339 // interesting in move semantic to leave hashtable with only 1 buckets 371 // interesting in move semantic to leave hashtable with only 1 bucket
340 // which is not allocated so that we can have those operations noexcept 372 // which is not allocated so that we can have those operations noexcept
341 // qualified. 373 // qualified.
342 // Note that we can't leave hashtable with 0 bucket without adding 374 // Note that we can't leave hashtable with 0 bucket without adding
343 // numerous checks in the code to avoid 0 modulus. 375 // numerous checks in the code to avoid 0 modulus.
344 __bucket_type _M_single_bucket = nullptr; 376 __bucket_type _M_single_bucket = nullptr;
353 385
354 __hashtable_alloc& 386 __hashtable_alloc&
355 _M_base_alloc() { return *this; } 387 _M_base_alloc() { return *this; }
356 388
357 __bucket_type* 389 __bucket_type*
358 _M_allocate_buckets(size_type __n) 390 _M_allocate_buckets(size_type __bkt_count)
359 { 391 {
360 if (__builtin_expect(__n == 1, false)) 392 if (__builtin_expect(__bkt_count == 1, false))
361 { 393 {
362 _M_single_bucket = nullptr; 394 _M_single_bucket = nullptr;
363 return &_M_single_bucket; 395 return &_M_single_bucket;
364 } 396 }
365 397
366 return __hashtable_alloc::_M_allocate_buckets(__n); 398 return __hashtable_alloc::_M_allocate_buckets(__bkt_count);
367 } 399 }
368 400
369 void 401 void
370 _M_deallocate_buckets(__bucket_type* __bkts, size_type __n) 402 _M_deallocate_buckets(__bucket_type* __bkts, size_type __bkt_count)
371 { 403 {
372 if (_M_uses_single_bucket(__bkts)) 404 if (_M_uses_single_bucket(__bkts))
373 return; 405 return;
374 406
375 __hashtable_alloc::_M_deallocate_buckets(__bkts, __n); 407 __hashtable_alloc::_M_deallocate_buckets(__bkts, __bkt_count);
376 } 408 }
377 409
378 void 410 void
379 _M_deallocate_buckets() 411 _M_deallocate_buckets()
380 { _M_deallocate_buckets(_M_buckets, _M_bucket_count); } 412 { _M_deallocate_buckets(_M_buckets, _M_bucket_count); }
386 418
387 __node_type* 419 __node_type*
388 _M_begin() const 420 _M_begin() const
389 { return static_cast<__node_type*>(_M_before_begin._M_nxt); } 421 { return static_cast<__node_type*>(_M_before_begin._M_nxt); }
390 422
391 template<typename _NodeGenerator> 423 // Assign *this using another _Hashtable instance. Whether elements
424 // are copied or moved depends on the _Ht reference.
425 template<typename _Ht>
392 void 426 void
393 _M_assign(const _Hashtable&, const _NodeGenerator&); 427 _M_assign_elements(_Ht&&);
428
429 template<typename _Ht, typename _NodeGenerator>
430 void
431 _M_assign(_Ht&&, const _NodeGenerator&);
394 432
395 void 433 void
396 _M_move_assign(_Hashtable&&, std::true_type); 434 _M_move_assign(_Hashtable&&, true_type);
397 435
398 void 436 void
399 _M_move_assign(_Hashtable&&, std::false_type); 437 _M_move_assign(_Hashtable&&, false_type);
400 438
401 void 439 void
402 _M_reset() noexcept; 440 _M_reset() noexcept;
403 441
404 _Hashtable(const _H1& __h1, const _H2& __h2, const _Hash& __h, 442 _Hashtable(const _H1& __h1, const _H2& __h2, const _Hash& __h,
405 const _Equal& __eq, const _ExtractKey& __exk, 443 const _Equal& __eq, const _ExtractKey& __exk,
406 const allocator_type& __a) 444 const allocator_type& __a)
407 : __hashtable_base(__exk, __h1, __h2, __h, __eq), 445 : __hashtable_base(__exk, __h1, __h2, __h, __eq),
408 __hashtable_alloc(__node_alloc_type(__a)) 446 __hashtable_alloc(__node_alloc_type(__a))
409 { } 447 { }
410 448
411 public: 449 public:
412 // Constructor, destructor, assignment, swap 450 // Constructor, destructor, assignment, swap
413 _Hashtable() = default; 451 _Hashtable() = default;
414 _Hashtable(size_type __bucket_hint, 452 _Hashtable(size_type __bkt_count_hint,
415 const _H1&, const _H2&, const _Hash&, 453 const _H1&, const _H2&, const _Hash&,
416 const _Equal&, const _ExtractKey&, 454 const _Equal&, const _ExtractKey&,
417 const allocator_type&); 455 const allocator_type&);
418 456
419 template<typename _InputIterator> 457 template<typename _InputIterator>
420 _Hashtable(_InputIterator __first, _InputIterator __last, 458 _Hashtable(_InputIterator __first, _InputIterator __last,
421 size_type __bucket_hint, 459 size_type __bkt_count_hint,
422 const _H1&, const _H2&, const _Hash&, 460 const _H1&, const _H2&, const _Hash&,
423 const _Equal&, const _ExtractKey&, 461 const _Equal&, const _ExtractKey&,
424 const allocator_type&); 462 const allocator_type&);
425 463
426 _Hashtable(const _Hashtable&); 464 _Hashtable(const _Hashtable&);
432 _Hashtable(_Hashtable&&, const allocator_type&); 470 _Hashtable(_Hashtable&&, const allocator_type&);
433 471
434 // Use delegating constructors. 472 // Use delegating constructors.
435 explicit 473 explicit
436 _Hashtable(const allocator_type& __a) 474 _Hashtable(const allocator_type& __a)
437 : __hashtable_alloc(__node_alloc_type(__a)) 475 : __hashtable_alloc(__node_alloc_type(__a))
438 { } 476 { }
439 477
440 explicit 478 explicit
441 _Hashtable(size_type __n, 479 _Hashtable(size_type __bkt_count_hint,
442 const _H1& __hf = _H1(), 480 const _H1& __hf = _H1(),
443 const key_equal& __eql = key_equal(), 481 const key_equal& __eql = key_equal(),
444 const allocator_type& __a = allocator_type()) 482 const allocator_type& __a = allocator_type())
445 : _Hashtable(__n, __hf, _H2(), _Hash(), __eql, 483 : _Hashtable(__bkt_count_hint, __hf, _H2(), _Hash(), __eql,
446 __key_extract(), __a) 484 __key_extract(), __a)
447 { } 485 { }
448 486
449 template<typename _InputIterator> 487 template<typename _InputIterator>
450 _Hashtable(_InputIterator __f, _InputIterator __l, 488 _Hashtable(_InputIterator __f, _InputIterator __l,
451 size_type __n = 0, 489 size_type __bkt_count_hint = 0,
452 const _H1& __hf = _H1(), 490 const _H1& __hf = _H1(),
453 const key_equal& __eql = key_equal(), 491 const key_equal& __eql = key_equal(),
454 const allocator_type& __a = allocator_type()) 492 const allocator_type& __a = allocator_type())
455 : _Hashtable(__f, __l, __n, __hf, _H2(), _Hash(), __eql, 493 : _Hashtable(__f, __l, __bkt_count_hint, __hf, _H2(), _Hash(), __eql,
456 __key_extract(), __a) 494 __key_extract(), __a)
457 { } 495 { }
458 496
459 _Hashtable(initializer_list<value_type> __l, 497 _Hashtable(initializer_list<value_type> __l,
460 size_type __n = 0, 498 size_type __bkt_count_hint = 0,
461 const _H1& __hf = _H1(), 499 const _H1& __hf = _H1(),
462 const key_equal& __eql = key_equal(), 500 const key_equal& __eql = key_equal(),
463 const allocator_type& __a = allocator_type()) 501 const allocator_type& __a = allocator_type())
464 : _Hashtable(__l.begin(), __l.end(), __n, __hf, _H2(), _Hash(), __eql, 502 : _Hashtable(__l.begin(), __l.end(), __bkt_count_hint,
503 __hf, _H2(), _Hash(), __eql,
465 __key_extract(), __a) 504 __key_extract(), __a)
466 { } 505 { }
467 506
468 _Hashtable& 507 _Hashtable&
469 operator=(const _Hashtable& __ht); 508 operator=(const _Hashtable& __ht);
482 } 521 }
483 522
484 _Hashtable& 523 _Hashtable&
485 operator=(initializer_list<value_type> __l) 524 operator=(initializer_list<value_type> __l)
486 { 525 {
487 __reuse_or_alloc_node_type __roan(_M_begin(), *this); 526 __reuse_or_alloc_node_gen_t __roan(_M_begin(), *this);
488 _M_before_begin._M_nxt = nullptr; 527 _M_before_begin._M_nxt = nullptr;
489 clear(); 528 clear();
490 this->_M_insert_range(__l.begin(), __l.end(), __roan, __unique_keys()); 529 this->_M_insert_range(__l.begin(), __l.end(), __roan, __unique_keys());
491 return *this; 530 return *this;
492 } 531 }
525 564
526 size_type 565 size_type
527 size() const noexcept 566 size() const noexcept
528 { return _M_element_count; } 567 { return _M_element_count; }
529 568
530 bool 569 _GLIBCXX_NODISCARD bool
531 empty() const noexcept 570 empty() const noexcept
532 { return size() == 0; } 571 { return size() == 0; }
533 572
534 allocator_type 573 allocator_type
535 get_allocator() const noexcept 574 get_allocator() const noexcept
554 size_type 593 size_type
555 max_bucket_count() const noexcept 594 max_bucket_count() const noexcept
556 { return max_size(); } 595 { return max_size(); }
557 596
558 size_type 597 size_type
559 bucket_size(size_type __n) const 598 bucket_size(size_type __bkt) const
560 { return std::distance(begin(__n), end(__n)); } 599 { return std::distance(begin(__bkt), end(__bkt)); }
561 600
562 size_type 601 size_type
563 bucket(const key_type& __k) const 602 bucket(const key_type& __k) const
564 { return _M_bucket_index(__k, this->_M_hash_code(__k)); } 603 { return _M_bucket_index(__k, this->_M_hash_code(__k)); }
565 604
566 local_iterator 605 local_iterator
567 begin(size_type __n) 606 begin(size_type __bkt)
568 { 607 {
569 return local_iterator(*this, _M_bucket_begin(__n), 608 return local_iterator(*this, _M_bucket_begin(__bkt),
570 __n, _M_bucket_count); 609 __bkt, _M_bucket_count);
571 } 610 }
572 611
573 local_iterator 612 local_iterator
574 end(size_type __n) 613 end(size_type __bkt)
575 { return local_iterator(*this, nullptr, __n, _M_bucket_count); } 614 { return local_iterator(*this, nullptr, __bkt, _M_bucket_count); }
576 615
577 const_local_iterator 616 const_local_iterator
578 begin(size_type __n) const 617 begin(size_type __bkt) const
579 { 618 {
580 return const_local_iterator(*this, _M_bucket_begin(__n), 619 return const_local_iterator(*this, _M_bucket_begin(__bkt),
581 __n, _M_bucket_count); 620 __bkt, _M_bucket_count);
582 } 621 }
583 622
584 const_local_iterator 623 const_local_iterator
585 end(size_type __n) const 624 end(size_type __bkt) const
586 { return const_local_iterator(*this, nullptr, __n, _M_bucket_count); } 625 { return const_local_iterator(*this, nullptr, __bkt, _M_bucket_count); }
587 626
588 // DR 691. 627 // DR 691.
589 const_local_iterator 628 const_local_iterator
590 cbegin(size_type __n) const 629 cbegin(size_type __bkt) const
591 { 630 {
592 return const_local_iterator(*this, _M_bucket_begin(__n), 631 return const_local_iterator(*this, _M_bucket_begin(__bkt),
593 __n, _M_bucket_count); 632 __bkt, _M_bucket_count);
594 } 633 }
595 634
596 const_local_iterator 635 const_local_iterator
597 cend(size_type __n) const 636 cend(size_type __bkt) const
598 { return const_local_iterator(*this, nullptr, __n, _M_bucket_count); } 637 { return const_local_iterator(*this, nullptr, __bkt, _M_bucket_count); }
599 638
600 float 639 float
601 load_factor() const noexcept 640 load_factor() const noexcept
602 { 641 {
603 return static_cast<float>(size()) / static_cast<float>(bucket_count()); 642 return static_cast<float>(size()) / static_cast<float>(bucket_count());
668 707
669 // Get the node before __n in the bucket __bkt 708 // Get the node before __n in the bucket __bkt
670 __node_base* 709 __node_base*
671 _M_get_previous_node(size_type __bkt, __node_base* __n); 710 _M_get_previous_node(size_type __bkt, __node_base* __n);
672 711
673 // Insert node with hash code __code, in bucket bkt if no rehash (assumes 712 // Insert node __n with key __k and hash code __code, in bucket __bkt
674 // no element with its key already present). Take ownership of the node, 713 // if no rehash (assumes no element with same key already present).
675 // deallocate it on exception. 714 // Takes ownership of __n if insertion succeeds, throws otherwise.
676 iterator 715 iterator
677 _M_insert_unique_node(size_type __bkt, __hash_code __code, 716 _M_insert_unique_node(const key_type& __k, size_type __bkt,
678 __node_type* __n, size_type __n_elt = 1); 717 __hash_code __code, __node_type* __n,
679 718 size_type __n_elt = 1);
680 // Insert node with hash code __code. Take ownership of the node, 719
681 // deallocate it on exception. 720 // Insert node __n with key __k and hash code __code.
721 // Takes ownership of __n if insertion succeeds, throws otherwise.
682 iterator 722 iterator
683 _M_insert_multi_node(__node_type* __hint, 723 _M_insert_multi_node(__node_type* __hint, const key_type& __k,
684 __hash_code __code, __node_type* __n); 724 __hash_code __code, __node_type* __n);
685 725
686 template<typename... _Args> 726 template<typename... _Args>
687 std::pair<iterator, bool> 727 std::pair<iterator, bool>
688 _M_emplace(std::true_type, _Args&&... __args); 728 _M_emplace(true_type, _Args&&... __args);
689 729
690 template<typename... _Args> 730 template<typename... _Args>
691 iterator 731 iterator
692 _M_emplace(std::false_type __uk, _Args&&... __args) 732 _M_emplace(false_type __uk, _Args&&... __args)
693 { return _M_emplace(cend(), __uk, std::forward<_Args>(__args)...); } 733 { return _M_emplace(cend(), __uk, std::forward<_Args>(__args)...); }
694 734
695 // Emplace with hint, useless when keys are unique. 735 // Emplace with hint, useless when keys are unique.
696 template<typename... _Args> 736 template<typename... _Args>
697 iterator 737 iterator
698 _M_emplace(const_iterator, std::true_type __uk, _Args&&... __args) 738 _M_emplace(const_iterator, true_type __uk, _Args&&... __args)
699 { return _M_emplace(__uk, std::forward<_Args>(__args)...).first; } 739 { return _M_emplace(__uk, std::forward<_Args>(__args)...).first; }
700 740
701 template<typename... _Args> 741 template<typename... _Args>
702 iterator 742 iterator
703 _M_emplace(const_iterator, std::false_type, _Args&&... __args); 743 _M_emplace(const_iterator, false_type, _Args&&... __args);
704 744
705 template<typename _Arg, typename _NodeGenerator> 745 template<typename _Arg, typename _NodeGenerator>
706 std::pair<iterator, bool> 746 std::pair<iterator, bool>
707 _M_insert(_Arg&&, const _NodeGenerator&, true_type, size_type = 1); 747 _M_insert(_Arg&&, const _NodeGenerator&, true_type, size_type = 1);
708 748
730 iterator 770 iterator
731 _M_insert(const_iterator, _Arg&&, 771 _M_insert(const_iterator, _Arg&&,
732 const _NodeGenerator&, false_type); 772 const _NodeGenerator&, false_type);
733 773
734 size_type 774 size_type
735 _M_erase(std::true_type, const key_type&); 775 _M_erase(true_type, const key_type&);
736 776
737 size_type 777 size_type
738 _M_erase(std::false_type, const key_type&); 778 _M_erase(false_type, const key_type&);
739 779
740 iterator 780 iterator
741 _M_erase(size_type __bkt, __node_base* __prev_n, __node_type* __n); 781 _M_erase(size_type __bkt, __node_base* __prev_n, __node_type* __n);
742 782
743 public: 783 public:
774 erase(const_iterator, const_iterator); 814 erase(const_iterator, const_iterator);
775 815
776 void 816 void
777 clear() noexcept; 817 clear() noexcept;
778 818
779 // Set number of buckets to be appropriate for container of n element. 819 // Set number of buckets keeping it appropriate for container's number
780 void rehash(size_type __n); 820 // of elements.
821 void rehash(size_type __bkt_count);
781 822
782 // DR 1189. 823 // DR 1189.
783 // reserve, if present, comes from _Rehash_base. 824 // reserve, if present, comes from _Rehash_base.
784 825
785 #if __cplusplus > 201402L 826 #if __cplusplus > 201402L
804 __ret.inserted = false; 845 __ret.inserted = false;
805 } 846 }
806 else 847 else
807 { 848 {
808 __ret.position 849 __ret.position
809 = _M_insert_unique_node(__bkt, __code, __nh._M_ptr); 850 = _M_insert_unique_node(__k, __bkt, __code, __nh._M_ptr);
810 __nh._M_ptr = nullptr; 851 __nh._M_ptr = nullptr;
811 __ret.inserted = true; 852 __ret.inserted = true;
812 } 853 }
813 } 854 }
814 return __ret; 855 return __ret;
816 857
817 /// Re-insert an extracted node into a container with equivalent keys. 858 /// Re-insert an extracted node into a container with equivalent keys.
818 iterator 859 iterator
819 _M_reinsert_node_multi(const_iterator __hint, node_type&& __nh) 860 _M_reinsert_node_multi(const_iterator __hint, node_type&& __nh)
820 { 861 {
821 iterator __ret;
822 if (__nh.empty()) 862 if (__nh.empty())
823 __ret = end(); 863 return end();
824 else 864
825 { 865 __glibcxx_assert(get_allocator() == __nh.get_allocator());
826 __glibcxx_assert(get_allocator() == __nh.get_allocator()); 866
827 867 const key_type& __k = __nh._M_key();
828 auto __code = this->_M_hash_code(__nh._M_key()); 868 auto __code = this->_M_hash_code(__k);
829 auto __node = std::exchange(__nh._M_ptr, nullptr); 869 auto __ret
830 // FIXME: this deallocates the node on exception. 870 = _M_insert_multi_node(__hint._M_cur, __k, __code, __nh._M_ptr);
831 __ret = _M_insert_multi_node(__hint._M_cur, __code, __node); 871 __nh._M_ptr = nullptr;
832 }
833 return __ret; 872 return __ret;
834 } 873 }
835 874
836 /// Extract a node. 875 private:
837 node_type 876 node_type
838 extract(const_iterator __pos) 877 _M_extract_node(size_t __bkt, __node_base* __prev_n)
839 { 878 {
840 __node_type* __n = __pos._M_cur; 879 __node_type* __n = static_cast<__node_type*>(__prev_n->_M_nxt);
841 size_t __bkt = _M_bucket_index(__n);
842
843 // Look for previous node to unlink it from the erased one, this
844 // is why we need buckets to contain the before begin to make
845 // this search fast.
846 __node_base* __prev_n = _M_get_previous_node(__bkt, __n);
847
848 if (__prev_n == _M_buckets[__bkt]) 880 if (__prev_n == _M_buckets[__bkt])
849 _M_remove_bucket_begin(__bkt, __n->_M_next(), 881 _M_remove_bucket_begin(__bkt, __n->_M_next(),
850 __n->_M_nxt ? _M_bucket_index(__n->_M_next()) : 0); 882 __n->_M_nxt ? _M_bucket_index(__n->_M_next()) : 0);
851 else if (__n->_M_nxt) 883 else if (__n->_M_nxt)
852 { 884 {
859 __n->_M_nxt = nullptr; 891 __n->_M_nxt = nullptr;
860 --_M_element_count; 892 --_M_element_count;
861 return { __n, this->_M_node_allocator() }; 893 return { __n, this->_M_node_allocator() };
862 } 894 }
863 895
896 public:
897 // Extract a node.
898 node_type
899 extract(const_iterator __pos)
900 {
901 size_t __bkt = _M_bucket_index(__pos._M_cur);
902 return _M_extract_node(__bkt,
903 _M_get_previous_node(__bkt, __pos._M_cur));
904 }
905
864 /// Extract a node. 906 /// Extract a node.
865 node_type 907 node_type
866 extract(const _Key& __k) 908 extract(const _Key& __k)
867 { 909 {
868 node_type __nh; 910 node_type __nh;
869 auto __pos = find(__k); 911 __hash_code __code = this->_M_hash_code(__k);
870 if (__pos != end()) 912 std::size_t __bkt = _M_bucket_index(__k, __code);
871 __nh = extract(const_iterator(__pos)); 913 if (__node_base* __prev_node = _M_find_before_node(__bkt, __k, __code))
914 __nh = _M_extract_node(__bkt, __prev_node);
872 return __nh; 915 return __nh;
873 } 916 }
874 917
875 /// Merge from a compatible container into one with unique keys. 918 /// Merge from a compatible container into one with unique keys.
876 template<typename _Compatible_Hashtable> 919 template<typename _Compatible_Hashtable>
883 926
884 auto __n_elt = __src.size(); 927 auto __n_elt = __src.size();
885 for (auto __i = __src.begin(), __end = __src.end(); __i != __end;) 928 for (auto __i = __src.begin(), __end = __src.end(); __i != __end;)
886 { 929 {
887 auto __pos = __i++; 930 auto __pos = __i++;
888 const key_type& __k = this->_M_extract()(__pos._M_cur->_M_v()); 931 const key_type& __k = this->_M_extract()(*__pos);
889 __hash_code __code = this->_M_hash_code(__k); 932 __hash_code __code = this->_M_hash_code(__k);
890 size_type __bkt = _M_bucket_index(__k, __code); 933 size_type __bkt = _M_bucket_index(__k, __code);
891 if (_M_find_node(__bkt, __k, __code) == nullptr) 934 if (_M_find_node(__bkt, __k, __code) == nullptr)
892 { 935 {
893 auto __nh = __src.extract(__pos); 936 auto __nh = __src.extract(__pos);
894 _M_insert_unique_node(__bkt, __code, __nh._M_ptr, __n_elt); 937 _M_insert_unique_node(__k, __bkt, __code, __nh._M_ptr,
938 __n_elt);
895 __nh._M_ptr = nullptr; 939 __nh._M_ptr = nullptr;
896 __n_elt = 1; 940 __n_elt = 1;
897 } 941 }
898 else if (__n_elt != 1) 942 else if (__n_elt != 1)
899 --__n_elt; 943 --__n_elt;
915 } 959 }
916 #endif // C++17 960 #endif // C++17
917 961
918 private: 962 private:
919 // Helper rehash method used when keys are unique. 963 // Helper rehash method used when keys are unique.
920 void _M_rehash_aux(size_type __n, std::true_type); 964 void _M_rehash_aux(size_type __bkt_count, true_type);
921 965
922 // Helper rehash method used when keys can be non-unique. 966 // Helper rehash method used when keys can be non-unique.
923 void _M_rehash_aux(size_type __n, std::false_type); 967 void _M_rehash_aux(size_type __bkt_count, false_type);
924 968
925 // Unconditionally change size of bucket array to n, restore 969 // Unconditionally change size of bucket array to n, restore
926 // hash policy state to __state on exception. 970 // hash policy state to __state on exception.
927 void _M_rehash(size_type __n, const __rehash_state& __state); 971 void _M_rehash(size_type __bkt_count, const __rehash_state& __state);
928 }; 972 };
929 973
930 974
931 // Definitions of class template _Hashtable's out-of-line member functions. 975 // Definitions of class template _Hashtable's out-of-line member functions.
932 template<typename _Key, typename _Value, 976 template<typename _Key, typename _Value,
947 typename _Alloc, typename _ExtractKey, typename _Equal, 991 typename _Alloc, typename _ExtractKey, typename _Equal,
948 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 992 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
949 typename _Traits> 993 typename _Traits>
950 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 994 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
951 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 995 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
952 _Hashtable(size_type __bucket_hint, 996 _Hashtable(size_type __bkt_count_hint,
953 const _H1& __h1, const _H2& __h2, const _Hash& __h, 997 const _H1& __h1, const _H2& __h2, const _Hash& __h,
954 const _Equal& __eq, const _ExtractKey& __exk, 998 const _Equal& __eq, const _ExtractKey& __exk,
955 const allocator_type& __a) 999 const allocator_type& __a)
956 : _Hashtable(__h1, __h2, __h, __eq, __exk, __a) 1000 : _Hashtable(__h1, __h2, __h, __eq, __exk, __a)
957 { 1001 {
958 auto __bkt = _M_rehash_policy._M_next_bkt(__bucket_hint); 1002 auto __bkt_count = _M_rehash_policy._M_next_bkt(__bkt_count_hint);
959 if (__bkt > _M_bucket_count) 1003 if (__bkt_count > _M_bucket_count)
960 { 1004 {
961 _M_buckets = _M_allocate_buckets(__bkt); 1005 _M_buckets = _M_allocate_buckets(__bkt_count);
962 _M_bucket_count = __bkt; 1006 _M_bucket_count = __bkt_count;
963 } 1007 }
964 } 1008 }
965 1009
966 template<typename _Key, typename _Value, 1010 template<typename _Key, typename _Value,
967 typename _Alloc, typename _ExtractKey, typename _Equal, 1011 typename _Alloc, typename _ExtractKey, typename _Equal,
969 typename _Traits> 1013 typename _Traits>
970 template<typename _InputIterator> 1014 template<typename _InputIterator>
971 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1015 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
972 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1016 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
973 _Hashtable(_InputIterator __f, _InputIterator __l, 1017 _Hashtable(_InputIterator __f, _InputIterator __l,
974 size_type __bucket_hint, 1018 size_type __bkt_count_hint,
975 const _H1& __h1, const _H2& __h2, const _Hash& __h, 1019 const _H1& __h1, const _H2& __h2, const _Hash& __h,
976 const _Equal& __eq, const _ExtractKey& __exk, 1020 const _Equal& __eq, const _ExtractKey& __exk,
977 const allocator_type& __a) 1021 const allocator_type& __a)
978 : _Hashtable(__h1, __h2, __h, __eq, __exk, __a) 1022 : _Hashtable(__h1, __h2, __h, __eq, __exk, __a)
979 { 1023 {
980 auto __nb_elems = __detail::__distance_fw(__f, __l); 1024 auto __nb_elems = __detail::__distance_fw(__f, __l);
981 auto __bkt_count = 1025 auto __bkt_count =
982 _M_rehash_policy._M_next_bkt( 1026 _M_rehash_policy._M_next_bkt(
983 std::max(_M_rehash_policy._M_bkt_for_elements(__nb_elems), 1027 std::max(_M_rehash_policy._M_bkt_for_elements(__nb_elems),
984 __bucket_hint)); 1028 __bkt_count_hint));
985 1029
986 if (__bkt_count > _M_bucket_count) 1030 if (__bkt_count > _M_bucket_count)
987 { 1031 {
988 _M_buckets = _M_allocate_buckets(__bkt_count); 1032 _M_buckets = _M_allocate_buckets(__bkt_count);
989 _M_bucket_count = __bkt_count; 1033 _M_bucket_count = __bkt_count;
1021 std::__alloc_on_copy(__this_alloc, __that_alloc); 1065 std::__alloc_on_copy(__this_alloc, __that_alloc);
1022 __hashtable_base::operator=(__ht); 1066 __hashtable_base::operator=(__ht);
1023 _M_bucket_count = __ht._M_bucket_count; 1067 _M_bucket_count = __ht._M_bucket_count;
1024 _M_element_count = __ht._M_element_count; 1068 _M_element_count = __ht._M_element_count;
1025 _M_rehash_policy = __ht._M_rehash_policy; 1069 _M_rehash_policy = __ht._M_rehash_policy;
1070 __alloc_node_gen_t __alloc_node_gen(*this);
1026 __try 1071 __try
1027 { 1072 {
1028 _M_assign(__ht, 1073 _M_assign(__ht, __alloc_node_gen);
1029 [this](const __node_type* __n)
1030 { return this->_M_allocate_node(__n->_M_v()); });
1031 } 1074 }
1032 __catch(...) 1075 __catch(...)
1033 { 1076 {
1034 // _M_assign took care of deallocating all memory. Now we 1077 // _M_assign took care of deallocating all memory. Now we
1035 // must make sure this instance remains in a usable state. 1078 // must make sure this instance remains in a usable state.
1040 } 1083 }
1041 std::__alloc_on_copy(__this_alloc, __that_alloc); 1084 std::__alloc_on_copy(__this_alloc, __that_alloc);
1042 } 1085 }
1043 1086
1044 // Reuse allocated buckets and nodes. 1087 // Reuse allocated buckets and nodes.
1045 __bucket_type* __former_buckets = nullptr; 1088 _M_assign_elements(__ht);
1046 std::size_t __former_bucket_count = _M_bucket_count;
1047 const __rehash_state& __former_state = _M_rehash_policy._M_state();
1048
1049 if (_M_bucket_count != __ht._M_bucket_count)
1050 {
1051 __former_buckets = _M_buckets;
1052 _M_buckets = _M_allocate_buckets(__ht._M_bucket_count);
1053 _M_bucket_count = __ht._M_bucket_count;
1054 }
1055 else
1056 __builtin_memset(_M_buckets, 0,
1057 _M_bucket_count * sizeof(__bucket_type));
1058
1059 __try
1060 {
1061 __hashtable_base::operator=(__ht);
1062 _M_element_count = __ht._M_element_count;
1063 _M_rehash_policy = __ht._M_rehash_policy;
1064 __reuse_or_alloc_node_type __roan(_M_begin(), *this);
1065 _M_before_begin._M_nxt = nullptr;
1066 _M_assign(__ht,
1067 [&__roan](const __node_type* __n)
1068 { return __roan(__n->_M_v()); });
1069 if (__former_buckets)
1070 _M_deallocate_buckets(__former_buckets, __former_bucket_count);
1071 }
1072 __catch(...)
1073 {
1074 if (__former_buckets)
1075 {
1076 // Restore previous buckets.
1077 _M_deallocate_buckets();
1078 _M_rehash_policy._M_reset(__former_state);
1079 _M_buckets = __former_buckets;
1080 _M_bucket_count = __former_bucket_count;
1081 }
1082 __builtin_memset(_M_buckets, 0,
1083 _M_bucket_count * sizeof(__bucket_type));
1084 __throw_exception_again;
1085 }
1086 return *this; 1089 return *this;
1087 } 1090 }
1088 1091
1089 template<typename _Key, typename _Value, 1092 template<typename _Key, typename _Value,
1090 typename _Alloc, typename _ExtractKey, typename _Equal, 1093 typename _Alloc, typename _ExtractKey, typename _Equal,
1091 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1094 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1092 typename _Traits> 1095 typename _Traits>
1093 template<typename _NodeGenerator> 1096 template<typename _Ht>
1094 void 1097 void
1095 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1098 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1096 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1099 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
1097 _M_assign(const _Hashtable& __ht, const _NodeGenerator& __node_gen) 1100 _M_assign_elements(_Ht&& __ht)
1101 {
1102 __bucket_type* __former_buckets = nullptr;
1103 std::size_t __former_bucket_count = _M_bucket_count;
1104 const __rehash_state& __former_state = _M_rehash_policy._M_state();
1105
1106 if (_M_bucket_count != __ht._M_bucket_count)
1107 {
1108 __former_buckets = _M_buckets;
1109 _M_buckets = _M_allocate_buckets(__ht._M_bucket_count);
1110 _M_bucket_count = __ht._M_bucket_count;
1111 }
1112 else
1113 __builtin_memset(_M_buckets, 0,
1114 _M_bucket_count * sizeof(__bucket_type));
1115
1116 __try
1117 {
1118 __hashtable_base::operator=(std::forward<_Ht>(__ht));
1119 _M_element_count = __ht._M_element_count;
1120 _M_rehash_policy = __ht._M_rehash_policy;
1121 __reuse_or_alloc_node_gen_t __roan(_M_begin(), *this);
1122 _M_before_begin._M_nxt = nullptr;
1123 _M_assign(std::forward<_Ht>(__ht), __roan);
1124 if (__former_buckets)
1125 _M_deallocate_buckets(__former_buckets, __former_bucket_count);
1126 }
1127 __catch(...)
1128 {
1129 if (__former_buckets)
1130 {
1131 // Restore previous buckets.
1132 _M_deallocate_buckets();
1133 _M_rehash_policy._M_reset(__former_state);
1134 _M_buckets = __former_buckets;
1135 _M_bucket_count = __former_bucket_count;
1136 }
1137 __builtin_memset(_M_buckets, 0,
1138 _M_bucket_count * sizeof(__bucket_type));
1139 __throw_exception_again;
1140 }
1141 }
1142
1143 template<typename _Key, typename _Value,
1144 typename _Alloc, typename _ExtractKey, typename _Equal,
1145 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1146 typename _Traits>
1147 template<typename _Ht, typename _NodeGenerator>
1148 void
1149 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1150 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
1151 _M_assign(_Ht&& __ht, const _NodeGenerator& __node_gen)
1098 { 1152 {
1099 __bucket_type* __buckets = nullptr; 1153 __bucket_type* __buckets = nullptr;
1100 if (!_M_buckets) 1154 if (!_M_buckets)
1101 _M_buckets = __buckets = _M_allocate_buckets(_M_bucket_count); 1155 _M_buckets = __buckets = _M_allocate_buckets(_M_bucket_count);
1102 1156
1106 return; 1160 return;
1107 1161
1108 // First deal with the special first node pointed to by 1162 // First deal with the special first node pointed to by
1109 // _M_before_begin. 1163 // _M_before_begin.
1110 __node_type* __ht_n = __ht._M_begin(); 1164 __node_type* __ht_n = __ht._M_begin();
1111 __node_type* __this_n = __node_gen(__ht_n); 1165 __node_type* __this_n
1166 = __node_gen(__fwd_value_for<_Ht>(__ht_n->_M_v()));
1112 this->_M_copy_code(__this_n, __ht_n); 1167 this->_M_copy_code(__this_n, __ht_n);
1113 _M_before_begin._M_nxt = __this_n; 1168 _M_before_begin._M_nxt = __this_n;
1114 _M_buckets[_M_bucket_index(__this_n)] = &_M_before_begin; 1169 _M_buckets[_M_bucket_index(__this_n)] = &_M_before_begin;
1115 1170
1116 // Then deal with other nodes. 1171 // Then deal with other nodes.
1117 __node_base* __prev_n = __this_n; 1172 __node_base* __prev_n = __this_n;
1118 for (__ht_n = __ht_n->_M_next(); __ht_n; __ht_n = __ht_n->_M_next()) 1173 for (__ht_n = __ht_n->_M_next(); __ht_n; __ht_n = __ht_n->_M_next())
1119 { 1174 {
1120 __this_n = __node_gen(__ht_n); 1175 __this_n = __node_gen(__fwd_value_for<_Ht>(__ht_n->_M_v()));
1121 __prev_n->_M_nxt = __this_n; 1176 __prev_n->_M_nxt = __this_n;
1122 this->_M_copy_code(__this_n, __ht_n); 1177 this->_M_copy_code(__this_n, __ht_n);
1123 size_type __bkt = _M_bucket_index(__this_n); 1178 size_type __bkt = _M_bucket_index(__this_n);
1124 if (!_M_buckets[__bkt]) 1179 if (!_M_buckets[__bkt])
1125 _M_buckets[__bkt] = __prev_n; 1180 _M_buckets[__bkt] = __prev_n;
1157 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1212 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1158 typename _Traits> 1213 typename _Traits>
1159 void 1214 void
1160 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1215 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1161 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1216 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
1162 _M_move_assign(_Hashtable&& __ht, std::true_type) 1217 _M_move_assign(_Hashtable&& __ht, true_type)
1163 { 1218 {
1164 this->_M_deallocate_nodes(_M_begin()); 1219 this->_M_deallocate_nodes(_M_begin());
1165 _M_deallocate_buckets(); 1220 _M_deallocate_buckets();
1166 __hashtable_base::operator=(std::move(__ht)); 1221 __hashtable_base::operator=(std::move(__ht));
1167 _M_rehash_policy = __ht._M_rehash_policy; 1222 _M_rehash_policy = __ht._M_rehash_policy;
1189 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1244 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1190 typename _Traits> 1245 typename _Traits>
1191 void 1246 void
1192 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1247 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1193 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1248 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
1194 _M_move_assign(_Hashtable&& __ht, std::false_type) 1249 _M_move_assign(_Hashtable&& __ht, false_type)
1195 { 1250 {
1196 if (__ht._M_node_allocator() == this->_M_node_allocator()) 1251 if (__ht._M_node_allocator() == this->_M_node_allocator())
1197 _M_move_assign(std::move(__ht), std::true_type()); 1252 _M_move_assign(std::move(__ht), true_type());
1198 else 1253 else
1199 { 1254 {
1200 // Can't move memory, move elements then. 1255 // Can't move memory, move elements then.
1201 __bucket_type* __former_buckets = nullptr; 1256 _M_assign_elements(std::move(__ht));
1202 size_type __former_bucket_count = _M_bucket_count; 1257 __ht.clear();
1203 const __rehash_state& __former_state = _M_rehash_policy._M_state();
1204
1205 if (_M_bucket_count != __ht._M_bucket_count)
1206 {
1207 __former_buckets = _M_buckets;
1208 _M_buckets = _M_allocate_buckets(__ht._M_bucket_count);
1209 _M_bucket_count = __ht._M_bucket_count;
1210 }
1211 else
1212 __builtin_memset(_M_buckets, 0,
1213 _M_bucket_count * sizeof(__bucket_type));
1214
1215 __try
1216 {
1217 __hashtable_base::operator=(std::move(__ht));
1218 _M_element_count = __ht._M_element_count;
1219 _M_rehash_policy = __ht._M_rehash_policy;
1220 __reuse_or_alloc_node_type __roan(_M_begin(), *this);
1221 _M_before_begin._M_nxt = nullptr;
1222 _M_assign(__ht,
1223 [&__roan](__node_type* __n)
1224 { return __roan(std::move_if_noexcept(__n->_M_v())); });
1225 __ht.clear();
1226 }
1227 __catch(...)
1228 {
1229 if (__former_buckets)
1230 {
1231 _M_deallocate_buckets();
1232 _M_rehash_policy._M_reset(__former_state);
1233 _M_buckets = __former_buckets;
1234 _M_bucket_count = __former_bucket_count;
1235 }
1236 __builtin_memset(_M_buckets, 0,
1237 _M_bucket_count * sizeof(__bucket_type));
1238 __throw_exception_again;
1239 }
1240 } 1258 }
1241 } 1259 }
1242 1260
1243 template<typename _Key, typename _Value, 1261 template<typename _Key, typename _Value,
1244 typename _Alloc, typename _ExtractKey, typename _Equal, 1262 typename _Alloc, typename _ExtractKey, typename _Equal,
1255 _M_buckets(nullptr), 1273 _M_buckets(nullptr),
1256 _M_bucket_count(__ht._M_bucket_count), 1274 _M_bucket_count(__ht._M_bucket_count),
1257 _M_element_count(__ht._M_element_count), 1275 _M_element_count(__ht._M_element_count),
1258 _M_rehash_policy(__ht._M_rehash_policy) 1276 _M_rehash_policy(__ht._M_rehash_policy)
1259 { 1277 {
1260 _M_assign(__ht, 1278 __alloc_node_gen_t __alloc_node_gen(*this);
1261 [this](const __node_type* __n) 1279 _M_assign(__ht, __alloc_node_gen);
1262 { return this->_M_allocate_node(__n->_M_v()); });
1263 } 1280 }
1264 1281
1265 template<typename _Key, typename _Value, 1282 template<typename _Key, typename _Value,
1266 typename _Alloc, typename _ExtractKey, typename _Equal, 1283 typename _Alloc, typename _ExtractKey, typename _Equal,
1267 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1284 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1308 _M_buckets(), 1325 _M_buckets(),
1309 _M_bucket_count(__ht._M_bucket_count), 1326 _M_bucket_count(__ht._M_bucket_count),
1310 _M_element_count(__ht._M_element_count), 1327 _M_element_count(__ht._M_element_count),
1311 _M_rehash_policy(__ht._M_rehash_policy) 1328 _M_rehash_policy(__ht._M_rehash_policy)
1312 { 1329 {
1313 _M_assign(__ht, 1330 __alloc_node_gen_t __alloc_node_gen(*this);
1314 [this](const __node_type* __n) 1331 _M_assign(__ht, __alloc_node_gen);
1315 { return this->_M_allocate_node(__n->_M_v()); });
1316 } 1332 }
1317 1333
1318 template<typename _Key, typename _Value, 1334 template<typename _Key, typename _Value,
1319 typename _Alloc, typename _ExtractKey, typename _Equal, 1335 typename _Alloc, typename _ExtractKey, typename _Equal,
1320 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1336 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1348 _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin; 1364 _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin;
1349 __ht._M_reset(); 1365 __ht._M_reset();
1350 } 1366 }
1351 else 1367 else
1352 { 1368 {
1353 _M_assign(__ht, 1369 __alloc_node_gen_t __alloc_gen(*this);
1354 [this](__node_type* __n) 1370
1355 { 1371 using _Fwd_Ht = typename
1356 return this->_M_allocate_node( 1372 conditional<__move_if_noexcept_cond<value_type>::value,
1357 std::move_if_noexcept(__n->_M_v())); 1373 const _Hashtable&, _Hashtable&&>::type;
1358 }); 1374 _M_assign(std::forward<_Fwd_Ht>(__ht), __alloc_gen);
1359 __ht.clear(); 1375 __ht.clear();
1360 } 1376 }
1361 } 1377 }
1362 1378
1363 template<typename _Key, typename _Value, 1379 template<typename _Key, typename _Value,
1432 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1448 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
1433 find(const key_type& __k) 1449 find(const key_type& __k)
1434 -> iterator 1450 -> iterator
1435 { 1451 {
1436 __hash_code __code = this->_M_hash_code(__k); 1452 __hash_code __code = this->_M_hash_code(__k);
1437 std::size_t __n = _M_bucket_index(__k, __code); 1453 std::size_t __bkt = _M_bucket_index(__k, __code);
1438 __node_type* __p = _M_find_node(__n, __k, __code); 1454 __node_type* __p = _M_find_node(__bkt, __k, __code);
1439 return __p ? iterator(__p) : end(); 1455 return __p ? iterator(__p) : end();
1440 } 1456 }
1441 1457
1442 template<typename _Key, typename _Value, 1458 template<typename _Key, typename _Value,
1443 typename _Alloc, typename _ExtractKey, typename _Equal, 1459 typename _Alloc, typename _ExtractKey, typename _Equal,
1448 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1464 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
1449 find(const key_type& __k) const 1465 find(const key_type& __k) const
1450 -> const_iterator 1466 -> const_iterator
1451 { 1467 {
1452 __hash_code __code = this->_M_hash_code(__k); 1468 __hash_code __code = this->_M_hash_code(__k);
1453 std::size_t __n = _M_bucket_index(__k, __code); 1469 std::size_t __bkt = _M_bucket_index(__k, __code);
1454 __node_type* __p = _M_find_node(__n, __k, __code); 1470 __node_type* __p = _M_find_node(__bkt, __k, __code);
1455 return __p ? const_iterator(__p) : end(); 1471 return __p ? const_iterator(__p) : end();
1456 } 1472 }
1457 1473
1458 template<typename _Key, typename _Value, 1474 template<typename _Key, typename _Value,
1459 typename _Alloc, typename _ExtractKey, typename _Equal, 1475 typename _Alloc, typename _ExtractKey, typename _Equal,
1464 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1480 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
1465 count(const key_type& __k) const 1481 count(const key_type& __k) const
1466 -> size_type 1482 -> size_type
1467 { 1483 {
1468 __hash_code __code = this->_M_hash_code(__k); 1484 __hash_code __code = this->_M_hash_code(__k);
1469 std::size_t __n = _M_bucket_index(__k, __code); 1485 std::size_t __bkt = _M_bucket_index(__k, __code);
1470 __node_type* __p = _M_bucket_begin(__n); 1486 __node_type* __p = _M_bucket_begin(__bkt);
1471 if (!__p) 1487 if (!__p)
1472 return 0; 1488 return 0;
1473 1489
1474 std::size_t __result = 0; 1490 std::size_t __result = 0;
1475 for (;; __p = __p->_M_next()) 1491 for (;; __p = __p->_M_next())
1479 else if (__result) 1495 else if (__result)
1480 // All equivalent values are next to each other, if we 1496 // All equivalent values are next to each other, if we
1481 // found a non-equivalent value after an equivalent one it 1497 // found a non-equivalent value after an equivalent one it
1482 // means that we won't find any new equivalent value. 1498 // means that we won't find any new equivalent value.
1483 break; 1499 break;
1484 if (!__p->_M_nxt || _M_bucket_index(__p->_M_next()) != __n) 1500 if (!__p->_M_nxt || _M_bucket_index(__p->_M_next()) != __bkt)
1485 break; 1501 break;
1486 } 1502 }
1487 return __result; 1503 return __result;
1488 } 1504 }
1489 1505
1496 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1512 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
1497 equal_range(const key_type& __k) 1513 equal_range(const key_type& __k)
1498 -> pair<iterator, iterator> 1514 -> pair<iterator, iterator>
1499 { 1515 {
1500 __hash_code __code = this->_M_hash_code(__k); 1516 __hash_code __code = this->_M_hash_code(__k);
1501 std::size_t __n = _M_bucket_index(__k, __code); 1517 std::size_t __bkt = _M_bucket_index(__k, __code);
1502 __node_type* __p = _M_find_node(__n, __k, __code); 1518 __node_type* __p = _M_find_node(__bkt, __k, __code);
1503 1519
1504 if (__p) 1520 if (__p)
1505 { 1521 {
1506 __node_type* __p1 = __p->_M_next(); 1522 __node_type* __p1 = __p->_M_next();
1507 while (__p1 && _M_bucket_index(__p1) == __n 1523 while (__p1 && _M_bucket_index(__p1) == __bkt
1508 && this->_M_equals(__k, __code, __p1)) 1524 && this->_M_equals(__k, __code, __p1))
1509 __p1 = __p1->_M_next(); 1525 __p1 = __p1->_M_next();
1510 1526
1511 return std::make_pair(iterator(__p), iterator(__p1)); 1527 return std::make_pair(iterator(__p), iterator(__p1));
1512 } 1528 }
1523 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1539 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
1524 equal_range(const key_type& __k) const 1540 equal_range(const key_type& __k) const
1525 -> pair<const_iterator, const_iterator> 1541 -> pair<const_iterator, const_iterator>
1526 { 1542 {
1527 __hash_code __code = this->_M_hash_code(__k); 1543 __hash_code __code = this->_M_hash_code(__k);
1528 std::size_t __n = _M_bucket_index(__k, __code); 1544 std::size_t __bkt = _M_bucket_index(__k, __code);
1529 __node_type* __p = _M_find_node(__n, __k, __code); 1545 __node_type* __p = _M_find_node(__bkt, __k, __code);
1530 1546
1531 if (__p) 1547 if (__p)
1532 { 1548 {
1533 __node_type* __p1 = __p->_M_next(); 1549 __node_type* __p1 = __p->_M_next();
1534 while (__p1 && _M_bucket_index(__p1) == __n 1550 while (__p1 && _M_bucket_index(__p1) == __bkt
1535 && this->_M_equals(__k, __code, __p1)) 1551 && this->_M_equals(__k, __code, __p1))
1536 __p1 = __p1->_M_next(); 1552 __p1 = __p1->_M_next();
1537 1553
1538 return std::make_pair(const_iterator(__p), const_iterator(__p1)); 1554 return std::make_pair(const_iterator(__p), const_iterator(__p1));
1539 } 1555 }
1540 else 1556 else
1541 return std::make_pair(end(), end()); 1557 return std::make_pair(end(), end());
1542 } 1558 }
1543 1559
1544 // Find the node whose key compares equal to k in the bucket n. 1560 // Find the node whose key compares equal to k in the bucket bkt.
1545 // Return nullptr if no node is found. 1561 // Return nullptr if no node is found.
1546 template<typename _Key, typename _Value, 1562 template<typename _Key, typename _Value,
1547 typename _Alloc, typename _ExtractKey, typename _Equal, 1563 typename _Alloc, typename _ExtractKey, typename _Equal,
1548 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1564 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1549 typename _Traits> 1565 typename _Traits>
1550 auto 1566 auto
1551 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1567 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1552 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1568 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
1553 _M_find_before_node(size_type __n, const key_type& __k, 1569 _M_find_before_node(size_type __bkt, const key_type& __k,
1554 __hash_code __code) const 1570 __hash_code __code) const
1555 -> __node_base* 1571 -> __node_base*
1556 { 1572 {
1557 __node_base* __prev_p = _M_buckets[__n]; 1573 __node_base* __prev_p = _M_buckets[__bkt];
1558 if (!__prev_p) 1574 if (!__prev_p)
1559 return nullptr; 1575 return nullptr;
1560 1576
1561 for (__node_type* __p = static_cast<__node_type*>(__prev_p->_M_nxt);; 1577 for (__node_type* __p = static_cast<__node_type*>(__prev_p->_M_nxt);;
1562 __p = __p->_M_next()) 1578 __p = __p->_M_next())
1563 { 1579 {
1564 if (this->_M_equals(__k, __code, __p)) 1580 if (this->_M_equals(__k, __code, __p))
1565 return __prev_p; 1581 return __prev_p;
1566 1582
1567 if (!__p->_M_nxt || _M_bucket_index(__p->_M_next()) != __n) 1583 if (!__p->_M_nxt || _M_bucket_index(__p->_M_next()) != __bkt)
1568 break; 1584 break;
1569 __prev_p = __p; 1585 __prev_p = __p;
1570 } 1586 }
1571 return nullptr; 1587 return nullptr;
1572 } 1588 }
1648 typename _Traits> 1664 typename _Traits>
1649 template<typename... _Args> 1665 template<typename... _Args>
1650 auto 1666 auto
1651 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1667 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1652 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1668 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
1653 _M_emplace(std::true_type, _Args&&... __args) 1669 _M_emplace(true_type, _Args&&... __args)
1654 -> pair<iterator, bool> 1670 -> pair<iterator, bool>
1655 { 1671 {
1656 // First build the node to get access to the hash code 1672 // First build the node to get access to the hash code
1657 __node_type* __node = this->_M_allocate_node(std::forward<_Args>(__args)...); 1673 _Scoped_node __node { this, std::forward<_Args>(__args)... };
1658 const key_type& __k = this->_M_extract()(__node->_M_v()); 1674 const key_type& __k = this->_M_extract()(__node._M_node->_M_v());
1659 __hash_code __code; 1675 __hash_code __code = this->_M_hash_code(__k);
1660 __try
1661 {
1662 __code = this->_M_hash_code(__k);
1663 }
1664 __catch(...)
1665 {
1666 this->_M_deallocate_node(__node);
1667 __throw_exception_again;
1668 }
1669
1670 size_type __bkt = _M_bucket_index(__k, __code); 1676 size_type __bkt = _M_bucket_index(__k, __code);
1671 if (__node_type* __p = _M_find_node(__bkt, __k, __code)) 1677 if (__node_type* __p = _M_find_node(__bkt, __k, __code))
1672 { 1678 // There is already an equivalent node, no insertion
1673 // There is already an equivalent node, no insertion 1679 return std::make_pair(iterator(__p), false);
1674 this->_M_deallocate_node(__node);
1675 return std::make_pair(iterator(__p), false);
1676 }
1677 1680
1678 // Insert the node 1681 // Insert the node
1679 return std::make_pair(_M_insert_unique_node(__bkt, __code, __node), 1682 auto __pos = _M_insert_unique_node(__k, __bkt, __code, __node._M_node);
1680 true); 1683 __node._M_node = nullptr;
1684 return { __pos, true };
1681 } 1685 }
1682 1686
1683 template<typename _Key, typename _Value, 1687 template<typename _Key, typename _Value,
1684 typename _Alloc, typename _ExtractKey, typename _Equal, 1688 typename _Alloc, typename _ExtractKey, typename _Equal,
1685 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1689 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1686 typename _Traits> 1690 typename _Traits>
1687 template<typename... _Args> 1691 template<typename... _Args>
1688 auto 1692 auto
1689 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1693 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1690 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1694 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
1691 _M_emplace(const_iterator __hint, std::false_type, _Args&&... __args) 1695 _M_emplace(const_iterator __hint, false_type, _Args&&... __args)
1692 -> iterator 1696 -> iterator
1693 { 1697 {
1694 // First build the node to get its hash code. 1698 // First build the node to get its hash code.
1695 __node_type* __node = 1699 _Scoped_node __node { this, std::forward<_Args>(__args)... };
1696 this->_M_allocate_node(std::forward<_Args>(__args)...); 1700 const key_type& __k = this->_M_extract()(__node._M_node->_M_v());
1697 1701
1698 __hash_code __code; 1702 __hash_code __code = this->_M_hash_code(__k);
1699 __try 1703 auto __pos
1700 { 1704 = _M_insert_multi_node(__hint._M_cur, __k, __code, __node._M_node);
1701 __code = this->_M_hash_code(this->_M_extract()(__node->_M_v())); 1705 __node._M_node = nullptr;
1702 } 1706 return __pos;
1703 __catch(...)
1704 {
1705 this->_M_deallocate_node(__node);
1706 __throw_exception_again;
1707 }
1708
1709 return _M_insert_multi_node(__hint._M_cur, __code, __node);
1710 } 1707 }
1711 1708
1712 template<typename _Key, typename _Value, 1709 template<typename _Key, typename _Value,
1713 typename _Alloc, typename _ExtractKey, typename _Equal, 1710 typename _Alloc, typename _ExtractKey, typename _Equal,
1714 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1711 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1715 typename _Traits> 1712 typename _Traits>
1716 auto 1713 auto
1717 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1714 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1718 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1715 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
1719 _M_insert_unique_node(size_type __bkt, __hash_code __code, 1716 _M_insert_unique_node(const key_type& __k, size_type __bkt,
1720 __node_type* __node, size_type __n_elt) 1717 __hash_code __code, __node_type* __node,
1718 size_type __n_elt)
1721 -> iterator 1719 -> iterator
1722 { 1720 {
1723 const __rehash_state& __saved_state = _M_rehash_policy._M_state(); 1721 const __rehash_state& __saved_state = _M_rehash_policy._M_state();
1724 std::pair<bool, std::size_t> __do_rehash 1722 std::pair<bool, std::size_t> __do_rehash
1725 = _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count, 1723 = _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count,
1726 __n_elt); 1724 __n_elt);
1727 1725
1728 __try 1726 if (__do_rehash.first)
1729 { 1727 {
1730 if (__do_rehash.first) 1728 _M_rehash(__do_rehash.second, __saved_state);
1731 { 1729 __bkt = _M_bucket_index(__k, __code);
1732 _M_rehash(__do_rehash.second, __saved_state); 1730 }
1733 __bkt = _M_bucket_index(this->_M_extract()(__node->_M_v()), __code); 1731
1734 } 1732 this->_M_store_code(__node, __code);
1735 1733
1736 this->_M_store_code(__node, __code); 1734 // Always insert at the beginning of the bucket.
1737 1735 _M_insert_bucket_begin(__bkt, __node);
1738 // Always insert at the beginning of the bucket. 1736 ++_M_element_count;
1739 _M_insert_bucket_begin(__bkt, __node); 1737 return iterator(__node);
1740 ++_M_element_count; 1738 }
1741 return iterator(__node); 1739
1742 }
1743 __catch(...)
1744 {
1745 this->_M_deallocate_node(__node);
1746 __throw_exception_again;
1747 }
1748 }
1749
1750 // Insert node, in bucket bkt if no rehash (assumes no element with its key
1751 // already present). Take ownership of the node, deallocate it on exception.
1752 template<typename _Key, typename _Value, 1740 template<typename _Key, typename _Value,
1753 typename _Alloc, typename _ExtractKey, typename _Equal, 1741 typename _Alloc, typename _ExtractKey, typename _Equal,
1754 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1742 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1755 typename _Traits> 1743 typename _Traits>
1756 auto 1744 auto
1757 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1745 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1758 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1746 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
1759 _M_insert_multi_node(__node_type* __hint, __hash_code __code, 1747 _M_insert_multi_node(__node_type* __hint, const key_type& __k,
1760 __node_type* __node) 1748 __hash_code __code, __node_type* __node)
1761 -> iterator 1749 -> iterator
1762 { 1750 {
1763 const __rehash_state& __saved_state = _M_rehash_policy._M_state(); 1751 const __rehash_state& __saved_state = _M_rehash_policy._M_state();
1764 std::pair<bool, std::size_t> __do_rehash 1752 std::pair<bool, std::size_t> __do_rehash
1765 = _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count, 1); 1753 = _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count, 1);
1766 1754
1767 __try 1755 if (__do_rehash.first)
1768 { 1756 _M_rehash(__do_rehash.second, __saved_state);
1769 if (__do_rehash.first) 1757
1770 _M_rehash(__do_rehash.second, __saved_state); 1758 this->_M_store_code(__node, __code);
1771 1759 size_type __bkt = _M_bucket_index(__k, __code);
1772 this->_M_store_code(__node, __code); 1760
1773 const key_type& __k = this->_M_extract()(__node->_M_v()); 1761 // Find the node before an equivalent one or use hint if it exists and
1774 size_type __bkt = _M_bucket_index(__k, __code); 1762 // if it is equivalent.
1775 1763 __node_base* __prev
1776 // Find the node before an equivalent one or use hint if it exists and 1764 = __builtin_expect(__hint != nullptr, false)
1777 // if it is equivalent. 1765 && this->_M_equals(__k, __code, __hint)
1778 __node_base* __prev 1766 ? __hint
1779 = __builtin_expect(__hint != nullptr, false) 1767 : _M_find_before_node(__bkt, __k, __code);
1780 && this->_M_equals(__k, __code, __hint) 1768 if (__prev)
1781 ? __hint 1769 {
1782 : _M_find_before_node(__bkt, __k, __code); 1770 // Insert after the node before the equivalent one.
1783 if (__prev) 1771 __node->_M_nxt = __prev->_M_nxt;
1784 { 1772 __prev->_M_nxt = __node;
1785 // Insert after the node before the equivalent one. 1773 if (__builtin_expect(__prev == __hint, false))
1786 __node->_M_nxt = __prev->_M_nxt; 1774 // hint might be the last bucket node, in this case we need to
1787 __prev->_M_nxt = __node; 1775 // update next bucket.
1788 if (__builtin_expect(__prev == __hint, false)) 1776 if (__node->_M_nxt
1789 // hint might be the last bucket node, in this case we need to 1777 && !this->_M_equals(__k, __code, __node->_M_next()))
1790 // update next bucket. 1778 {
1791 if (__node->_M_nxt 1779 size_type __next_bkt = _M_bucket_index(__node->_M_next());
1792 && !this->_M_equals(__k, __code, __node->_M_next())) 1780 if (__next_bkt != __bkt)
1793 { 1781 _M_buckets[__next_bkt] = __node;
1794 size_type __next_bkt = _M_bucket_index(__node->_M_next()); 1782 }
1795 if (__next_bkt != __bkt) 1783 }
1796 _M_buckets[__next_bkt] = __node; 1784 else
1797 } 1785 // The inserted node has no equivalent in the hashtable. We must
1798 } 1786 // insert the new node at the beginning of the bucket to preserve
1799 else 1787 // equivalent elements' relative positions.
1800 // The inserted node has no equivalent in the 1788 _M_insert_bucket_begin(__bkt, __node);
1801 // hashtable. We must insert the new node at the 1789 ++_M_element_count;
1802 // beginning of the bucket to preserve equivalent 1790 return iterator(__node);
1803 // elements' relative positions.
1804 _M_insert_bucket_begin(__bkt, __node);
1805 ++_M_element_count;
1806 return iterator(__node);
1807 }
1808 __catch(...)
1809 {
1810 this->_M_deallocate_node(__node);
1811 __throw_exception_again;
1812 }
1813 } 1791 }
1814 1792
1815 // Insert v if no element with its key is already present. 1793 // Insert v if no element with its key is already present.
1816 template<typename _Key, typename _Value, 1794 template<typename _Key, typename _Value,
1817 typename _Alloc, typename _ExtractKey, typename _Equal, 1795 typename _Alloc, typename _ExtractKey, typename _Equal,
1827 { 1805 {
1828 const key_type& __k = this->_M_extract()(__v); 1806 const key_type& __k = this->_M_extract()(__v);
1829 __hash_code __code = this->_M_hash_code(__k); 1807 __hash_code __code = this->_M_hash_code(__k);
1830 size_type __bkt = _M_bucket_index(__k, __code); 1808 size_type __bkt = _M_bucket_index(__k, __code);
1831 1809
1832 __node_type* __n = _M_find_node(__bkt, __k, __code); 1810 if (__node_type* __node = _M_find_node(__bkt, __k, __code))
1833 if (__n) 1811 return { iterator(__node), false };
1834 return std::make_pair(iterator(__n), false); 1812
1835 1813 _Scoped_node __node{ __node_gen(std::forward<_Arg>(__v)), this };
1836 __n = __node_gen(std::forward<_Arg>(__v)); 1814 auto __pos
1837 return { _M_insert_unique_node(__bkt, __code, __n, __n_elt), true }; 1815 = _M_insert_unique_node(__k, __bkt, __code, __node._M_node, __n_elt);
1816 __node._M_node = nullptr;
1817 return { __pos, true };
1838 } 1818 }
1839 1819
1840 // Insert v unconditionally. 1820 // Insert v unconditionally.
1841 template<typename _Key, typename _Value, 1821 template<typename _Key, typename _Value,
1842 typename _Alloc, typename _ExtractKey, typename _Equal, 1822 typename _Alloc, typename _ExtractKey, typename _Equal,
1853 // First compute the hash code so that we don't do anything if it 1833 // First compute the hash code so that we don't do anything if it
1854 // throws. 1834 // throws.
1855 __hash_code __code = this->_M_hash_code(this->_M_extract()(__v)); 1835 __hash_code __code = this->_M_hash_code(this->_M_extract()(__v));
1856 1836
1857 // Second allocate new node so that we don't rehash if it throws. 1837 // Second allocate new node so that we don't rehash if it throws.
1858 __node_type* __node = __node_gen(std::forward<_Arg>(__v)); 1838 _Scoped_node __node{ __node_gen(std::forward<_Arg>(__v)), this };
1859 1839 const key_type& __k = this->_M_extract()(__node._M_node->_M_v());
1860 return _M_insert_multi_node(__hint._M_cur, __code, __node); 1840 auto __pos
1841 = _M_insert_multi_node(__hint._M_cur, __k, __code, __node._M_node);
1842 __node._M_node = nullptr;
1843 return __pos;
1861 } 1844 }
1862 1845
1863 template<typename _Key, typename _Value, 1846 template<typename _Key, typename _Value,
1864 typename _Alloc, typename _ExtractKey, typename _Equal, 1847 typename _Alloc, typename _ExtractKey, typename _Equal,
1865 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1848 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1913 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1896 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1914 typename _Traits> 1897 typename _Traits>
1915 auto 1898 auto
1916 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1899 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1917 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1900 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
1918 _M_erase(std::true_type, const key_type& __k) 1901 _M_erase(true_type, const key_type& __k)
1919 -> size_type 1902 -> size_type
1920 { 1903 {
1921 __hash_code __code = this->_M_hash_code(__k); 1904 __hash_code __code = this->_M_hash_code(__k);
1922 std::size_t __bkt = _M_bucket_index(__k, __code); 1905 std::size_t __bkt = _M_bucket_index(__k, __code);
1923 1906
1937 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1920 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1938 typename _Traits> 1921 typename _Traits>
1939 auto 1922 auto
1940 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1923 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1941 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1924 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
1942 _M_erase(std::false_type, const key_type& __k) 1925 _M_erase(false_type, const key_type& __k)
1943 -> size_type 1926 -> size_type
1944 { 1927 {
1945 __hash_code __code = this->_M_hash_code(__k); 1928 __hash_code __code = this->_M_hash_code(__k);
1946 std::size_t __bkt = _M_bucket_index(__k, __code); 1929 std::size_t __bkt = _M_bucket_index(__k, __code);
1947 1930
2055 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 2038 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
2056 typename _Traits> 2039 typename _Traits>
2057 void 2040 void
2058 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 2041 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2059 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 2042 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
2060 rehash(size_type __n) 2043 rehash(size_type __bkt_count)
2061 { 2044 {
2062 const __rehash_state& __saved_state = _M_rehash_policy._M_state(); 2045 const __rehash_state& __saved_state = _M_rehash_policy._M_state();
2063 std::size_t __buckets 2046 __bkt_count
2064 = std::max(_M_rehash_policy._M_bkt_for_elements(_M_element_count + 1), 2047 = std::max(_M_rehash_policy._M_bkt_for_elements(_M_element_count + 1),
2065 __n); 2048 __bkt_count);
2066 __buckets = _M_rehash_policy._M_next_bkt(__buckets); 2049 __bkt_count = _M_rehash_policy._M_next_bkt(__bkt_count);
2067 2050
2068 if (__buckets != _M_bucket_count) 2051 if (__bkt_count != _M_bucket_count)
2069 _M_rehash(__buckets, __saved_state); 2052 _M_rehash(__bkt_count, __saved_state);
2070 else 2053 else
2071 // No rehash, restore previous state to keep a consistent state. 2054 // No rehash, restore previous state to keep it consistent with
2055 // container state.
2072 _M_rehash_policy._M_reset(__saved_state); 2056 _M_rehash_policy._M_reset(__saved_state);
2073 } 2057 }
2074 2058
2075 template<typename _Key, typename _Value, 2059 template<typename _Key, typename _Value,
2076 typename _Alloc, typename _ExtractKey, typename _Equal, 2060 typename _Alloc, typename _ExtractKey, typename _Equal,
2077 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 2061 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
2078 typename _Traits> 2062 typename _Traits>
2079 void 2063 void
2080 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 2064 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2081 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 2065 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
2082 _M_rehash(size_type __n, const __rehash_state& __state) 2066 _M_rehash(size_type __bkt_count, const __rehash_state& __state)
2083 { 2067 {
2084 __try 2068 __try
2085 { 2069 {
2086 _M_rehash_aux(__n, __unique_keys()); 2070 _M_rehash_aux(__bkt_count, __unique_keys());
2087 } 2071 }
2088 __catch(...) 2072 __catch(...)
2089 { 2073 {
2090 // A failure here means that buckets allocation failed. We only 2074 // A failure here means that buckets allocation failed. We only
2091 // have to restore hash policy previous state. 2075 // have to restore hash policy previous state.
2100 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 2084 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
2101 typename _Traits> 2085 typename _Traits>
2102 void 2086 void
2103 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 2087 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2104 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 2088 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
2105 _M_rehash_aux(size_type __n, std::true_type) 2089 _M_rehash_aux(size_type __bkt_count, true_type)
2106 { 2090 {
2107 __bucket_type* __new_buckets = _M_allocate_buckets(__n); 2091 __bucket_type* __new_buckets = _M_allocate_buckets(__bkt_count);
2108 __node_type* __p = _M_begin(); 2092 __node_type* __p = _M_begin();
2109 _M_before_begin._M_nxt = nullptr; 2093 _M_before_begin._M_nxt = nullptr;
2110 std::size_t __bbegin_bkt = 0; 2094 std::size_t __bbegin_bkt = 0;
2111 while (__p) 2095 while (__p)
2112 { 2096 {
2113 __node_type* __next = __p->_M_next(); 2097 __node_type* __next = __p->_M_next();
2114 std::size_t __bkt = __hash_code_base::_M_bucket_index(__p, __n); 2098 std::size_t __bkt
2099 = __hash_code_base::_M_bucket_index(__p, __bkt_count);
2115 if (!__new_buckets[__bkt]) 2100 if (!__new_buckets[__bkt])
2116 { 2101 {
2117 __p->_M_nxt = _M_before_begin._M_nxt; 2102 __p->_M_nxt = _M_before_begin._M_nxt;
2118 _M_before_begin._M_nxt = __p; 2103 _M_before_begin._M_nxt = __p;
2119 __new_buckets[__bkt] = &_M_before_begin; 2104 __new_buckets[__bkt] = &_M_before_begin;
2128 } 2113 }
2129 __p = __next; 2114 __p = __next;
2130 } 2115 }
2131 2116
2132 _M_deallocate_buckets(); 2117 _M_deallocate_buckets();
2133 _M_bucket_count = __n; 2118 _M_bucket_count = __bkt_count;
2134 _M_buckets = __new_buckets; 2119 _M_buckets = __new_buckets;
2135 } 2120 }
2136 2121
2137 // Rehash when there can be equivalent elements, preserve their relative 2122 // Rehash when there can be equivalent elements, preserve their relative
2138 // order. 2123 // order.
2141 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 2126 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
2142 typename _Traits> 2127 typename _Traits>
2143 void 2128 void
2144 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 2129 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2145 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 2130 _H1, _H2, _Hash, _RehashPolicy, _Traits>::
2146 _M_rehash_aux(size_type __n, std::false_type) 2131 _M_rehash_aux(size_type __bkt_count, false_type)
2147 { 2132 {
2148 __bucket_type* __new_buckets = _M_allocate_buckets(__n); 2133 __bucket_type* __new_buckets = _M_allocate_buckets(__bkt_count);
2149 2134
2150 __node_type* __p = _M_begin(); 2135 __node_type* __p = _M_begin();
2151 _M_before_begin._M_nxt = nullptr; 2136 _M_before_begin._M_nxt = nullptr;
2152 std::size_t __bbegin_bkt = 0; 2137 std::size_t __bbegin_bkt = 0;
2153 std::size_t __prev_bkt = 0; 2138 std::size_t __prev_bkt = 0;
2155 bool __check_bucket = false; 2140 bool __check_bucket = false;
2156 2141
2157 while (__p) 2142 while (__p)
2158 { 2143 {
2159 __node_type* __next = __p->_M_next(); 2144 __node_type* __next = __p->_M_next();
2160 std::size_t __bkt = __hash_code_base::_M_bucket_index(__p, __n); 2145 std::size_t __bkt
2146 = __hash_code_base::_M_bucket_index(__p, __bkt_count);
2161 2147
2162 if (__prev_p && __prev_bkt == __bkt) 2148 if (__prev_p && __prev_bkt == __bkt)
2163 { 2149 {
2164 // Previous insert was already in this bucket, we insert after 2150 // Previous insert was already in this bucket, we insert after
2165 // the previously inserted one to preserve equivalent elements 2151 // the previously inserted one to preserve equivalent elements
2182 // insertions into __prev_bkt bucket. 2168 // insertions into __prev_bkt bucket.
2183 if (__prev_p->_M_nxt) 2169 if (__prev_p->_M_nxt)
2184 { 2170 {
2185 std::size_t __next_bkt 2171 std::size_t __next_bkt
2186 = __hash_code_base::_M_bucket_index(__prev_p->_M_next(), 2172 = __hash_code_base::_M_bucket_index(__prev_p->_M_next(),
2187 __n); 2173 __bkt_count);
2188 if (__next_bkt != __prev_bkt) 2174 if (__next_bkt != __prev_bkt)
2189 __new_buckets[__next_bkt] = __prev_p; 2175 __new_buckets[__next_bkt] = __prev_p;
2190 } 2176 }
2191 __check_bucket = false; 2177 __check_bucket = false;
2192 } 2178 }
2212 } 2198 }
2213 2199
2214 if (__check_bucket && __prev_p->_M_nxt) 2200 if (__check_bucket && __prev_p->_M_nxt)
2215 { 2201 {
2216 std::size_t __next_bkt 2202 std::size_t __next_bkt
2217 = __hash_code_base::_M_bucket_index(__prev_p->_M_next(), __n); 2203 = __hash_code_base::_M_bucket_index(__prev_p->_M_next(),
2204 __bkt_count);
2218 if (__next_bkt != __prev_bkt) 2205 if (__next_bkt != __prev_bkt)
2219 __new_buckets[__next_bkt] = __prev_p; 2206 __new_buckets[__next_bkt] = __prev_p;
2220 } 2207 }
2221 2208
2222 _M_deallocate_buckets(); 2209 _M_deallocate_buckets();
2223 _M_bucket_count = __n; 2210 _M_bucket_count = __bkt_count;
2224 _M_buckets = __new_buckets; 2211 _M_buckets = __new_buckets;
2225 } 2212 }
2226 2213
2227 #if __cplusplus > 201402L 2214 #if __cplusplus > 201402L
2228 template<typename, typename, typename> class _Hash_merge_helper { }; 2215 template<typename, typename, typename> class _Hash_merge_helper { };
2229 #endif // C++17 2216 #endif // C++17
2230 2217
2218 #if __cpp_deduction_guides >= 201606
2219 // Used to constrain deduction guides
2220 template<typename _Hash>
2221 using _RequireNotAllocatorOrIntegral
2222 = __enable_if_t<!__or_<is_integral<_Hash>, __is_allocator<_Hash>>::value>;
2223 #endif
2224
2231 _GLIBCXX_END_NAMESPACE_VERSION 2225 _GLIBCXX_END_NAMESPACE_VERSION
2232 } // namespace std 2226 } // namespace std
2233 2227
2234 #endif // _HASHTABLE_H 2228 #endif // _HASHTABLE_H