hashtable.h revision 259405
1// Hashtable implementation used by containers -*- C++ -*- 2 3// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 4// Free Software Foundation, Inc. 5// 6// This file is part of the GNU ISO C++ Library. This library is free 7// software; you can redistribute it and/or modify it under the 8// terms of the GNU General Public License as published by the 9// Free Software Foundation; either version 2, or (at your option) 10// any later version. 11 12// This library is distributed in the hope that it will be useful, 13// but WITHOUT ANY WARRANTY; without even the implied warranty of 14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15// GNU General Public License for more details. 16 17// You should have received a copy of the GNU General Public License along 18// with this library; see the file COPYING. If not, write to the Free 19// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 20// USA. 21 22// As a special exception, you may use this file as part of a free software 23// library without restriction. Specifically, if other files instantiate 24// templates or use macros or inline functions from this file, or you compile 25// this file and link it with other files to produce an executable, this 26// file does not by itself cause the resulting executable to be covered by 27// the GNU General Public License. This exception does not however 28// invalidate any other reasons why the executable file might be covered by 29// the GNU General Public License. 30 31/* 32 * Copyright (c) 1996,1997 33 * Silicon Graphics Computer Systems, Inc. 34 * 35 * Permission to use, copy, modify, distribute and sell this software 36 * and its documentation for any purpose is hereby granted without fee, 37 * provided that the above copyright notice appear in all copies and 38 * that both that copyright notice and this permission notice appear 39 * in supporting documentation. Silicon Graphics makes no 40 * representations about the suitability of this software for any 41 * purpose. It is provided "as is" without express or implied warranty. 42 * 43 * 44 * Copyright (c) 1994 45 * Hewlett-Packard Company 46 * 47 * Permission to use, copy, modify, distribute and sell this software 48 * and its documentation for any purpose is hereby granted without fee, 49 * provided that the above copyright notice appear in all copies and 50 * that both that copyright notice and this permission notice appear 51 * in supporting documentation. Hewlett-Packard Company makes no 52 * representations about the suitability of this software for any 53 * purpose. It is provided "as is" without express or implied warranty. 54 * 55 */ 56 57/** @file ext/hashtable.h 58 * This file is a GNU extension to the Standard C++ Library (possibly 59 * containing extensions from the HP/SGI STL subset). 60 */ 61 62#ifndef _HASHTABLE_H 63#define _HASHTABLE_H 1 64 65// Hashtable class, used to implement the hashed associative containers 66// hash_set, hash_map, hash_multiset, and hash_multimap. 67 68#include <vector> 69#include <iterator> 70#include <bits/stl_algo.h> 71#include <bits/stl_function.h> 72#include <ext/hash_fun.h> 73 74_GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) 75 76 using std::size_t; 77 using std::ptrdiff_t; 78 using std::forward_iterator_tag; 79 using std::input_iterator_tag; 80 using std::_Construct; 81 using std::_Destroy; 82 using std::distance; 83 using std::vector; 84 using std::pair; 85 using std::__iterator_category; 86 87 template<class _Val> 88 struct _Hashtable_node 89 { 90 _Hashtable_node* _M_next; 91 _Val _M_val; 92 }; 93 94 template<class _Val, class _Key, class _HashFcn, class _ExtractKey, 95 class _EqualKey, class _Alloc = std::allocator<_Val> > 96 class hashtable; 97 98 template<class _Val, class _Key, class _HashFcn, 99 class _ExtractKey, class _EqualKey, class _Alloc> 100 struct _Hashtable_iterator; 101 102 template<class _Val, class _Key, class _HashFcn, 103 class _ExtractKey, class _EqualKey, class _Alloc> 104 struct _Hashtable_const_iterator; 105 106 template<class _Val, class _Key, class _HashFcn, 107 class _ExtractKey, class _EqualKey, class _Alloc> 108 struct _Hashtable_iterator 109 { 110 typedef hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc> 111 _Hashtable; 112 typedef _Hashtable_iterator<_Val, _Key, _HashFcn, 113 _ExtractKey, _EqualKey, _Alloc> 114 iterator; 115 typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn, 116 _ExtractKey, _EqualKey, _Alloc> 117 const_iterator; 118 typedef _Hashtable_node<_Val> _Node; 119 typedef forward_iterator_tag iterator_category; 120 typedef _Val value_type; 121 typedef ptrdiff_t difference_type; 122 typedef size_t size_type; 123 typedef _Val& reference; 124 typedef _Val* pointer; 125 126 _Node* _M_cur; 127 _Hashtable* _M_ht; 128 129 _Hashtable_iterator(_Node* __n, _Hashtable* __tab) 130 : _M_cur(__n), _M_ht(__tab) { } 131 132 _Hashtable_iterator() { } 133 134 reference 135 operator*() const 136 { return _M_cur->_M_val; } 137 138 pointer 139 operator->() const 140 { return &(operator*()); } 141 142 iterator& 143 operator++(); 144 145 iterator 146 operator++(int); 147 148 bool 149 operator==(const iterator& __it) const 150 { return _M_cur == __it._M_cur; } 151 152 bool 153 operator!=(const iterator& __it) const 154 { return _M_cur != __it._M_cur; } 155 }; 156 157 template<class _Val, class _Key, class _HashFcn, 158 class _ExtractKey, class _EqualKey, class _Alloc> 159 struct _Hashtable_const_iterator 160 { 161 typedef hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc> 162 _Hashtable; 163 typedef _Hashtable_iterator<_Val,_Key,_HashFcn, 164 _ExtractKey,_EqualKey,_Alloc> 165 iterator; 166 typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn, 167 _ExtractKey, _EqualKey, _Alloc> 168 const_iterator; 169 typedef _Hashtable_node<_Val> _Node; 170 171 typedef forward_iterator_tag iterator_category; 172 typedef _Val value_type; 173 typedef ptrdiff_t difference_type; 174 typedef size_t size_type; 175 typedef const _Val& reference; 176 typedef const _Val* pointer; 177 178 const _Node* _M_cur; 179 const _Hashtable* _M_ht; 180 181 _Hashtable_const_iterator(const _Node* __n, const _Hashtable* __tab) 182 : _M_cur(__n), _M_ht(__tab) { } 183 184 _Hashtable_const_iterator() { } 185 186 _Hashtable_const_iterator(const iterator& __it) 187 : _M_cur(__it._M_cur), _M_ht(__it._M_ht) { } 188 189 reference 190 operator*() const 191 { return _M_cur->_M_val; } 192 193 pointer 194 operator->() const 195 { return &(operator*()); } 196 197 const_iterator& 198 operator++(); 199 200 const_iterator 201 operator++(int); 202 203 bool 204 operator==(const const_iterator& __it) const 205 { return _M_cur == __it._M_cur; } 206 207 bool 208 operator!=(const const_iterator& __it) const 209 { return _M_cur != __it._M_cur; } 210 }; 211 212 // Note: assumes long is at least 32 bits. 213 enum { _S_num_primes = 29 }; 214 215 static const unsigned long __stl_prime_list[_S_num_primes] = 216 { 217 5ul, // 5ul mini size is a Google addition 218 53ul, 97ul, 193ul, 389ul, 769ul, 219 1543ul, 3079ul, 6151ul, 12289ul, 24593ul, 220 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, 221 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, 222 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul, 223 1610612741ul, 3221225473ul, 4294967291ul 224 }; 225 226 inline unsigned long 227 __stl_next_prime(unsigned long __n) 228 { 229 const unsigned long* __first = __stl_prime_list; 230 const unsigned long* __last = __stl_prime_list + (int)_S_num_primes; 231 const unsigned long* pos = std::lower_bound(__first, __last, __n); 232 return pos == __last ? *(__last - 1) : *pos; 233 } 234 235 // Forward declaration of operator==. 236 template<class _Val, class _Key, class _HF, class _Ex, 237 class _Eq, class _All> 238 class hashtable; 239 240 template<class _Val, class _Key, class _HF, class _Ex, 241 class _Eq, class _All> 242 bool 243 operator==(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1, 244 const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2); 245 246 // Hashtables handle allocators a bit differently than other 247 // containers do. If we're using standard-conforming allocators, then 248 // a hashtable unconditionally has a member variable to hold its 249 // allocator, even if it so happens that all instances of the 250 // allocator type are identical. This is because, for hashtables, 251 // this extra storage is negligible. Additionally, a base class 252 // wouldn't serve any other purposes; it wouldn't, for example, 253 // simplify the exception-handling code. 254 template<class _Val, class _Key, class _HashFcn, 255 class _ExtractKey, class _EqualKey, class _Alloc> 256 class hashtable 257 { 258 public: 259 typedef _Key key_type; 260 typedef _Val value_type; 261 typedef _HashFcn hasher; 262 typedef _EqualKey key_equal; 263 264 typedef size_t size_type; 265 typedef ptrdiff_t difference_type; 266 typedef value_type* pointer; 267 typedef const value_type* const_pointer; 268 typedef value_type& reference; 269 typedef const value_type& const_reference; 270 271 hasher 272 hash_funct() const 273 { return _M_hash; } 274 275 key_equal 276 key_eq() const 277 { return _M_equals; } 278 279 private: 280 typedef _Hashtable_node<_Val> _Node; 281 282 public: 283 typedef typename _Alloc::template rebind<value_type>::other allocator_type; 284 allocator_type 285 get_allocator() const 286 { return _M_node_allocator; } 287 288 private: 289 typedef typename _Alloc::template rebind<_Node>::other _Node_Alloc; 290 typedef typename _Alloc::template rebind<_Node*>::other _Nodeptr_Alloc; 291 typedef vector<_Node*, _Nodeptr_Alloc> _Vector_type; 292 293 _Node_Alloc _M_node_allocator; 294 295 _Node* 296 _M_get_node() 297 { return _M_node_allocator.allocate(1); } 298 299 void 300 _M_put_node(_Node* __p) 301 { _M_node_allocator.deallocate(__p, 1); } 302 303 private: 304 hasher _M_hash; 305 key_equal _M_equals; 306 _ExtractKey _M_get_key; 307 _Vector_type _M_buckets; 308 size_type _M_num_elements; 309 310 public: 311 typedef _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, 312 _EqualKey, _Alloc> 313 iterator; 314 typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey, 315 _EqualKey, _Alloc> 316 const_iterator; 317 318 friend struct 319 _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>; 320 321 friend struct 322 _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey, 323 _EqualKey, _Alloc>; 324 325 public: 326 hashtable(size_type __n, const _HashFcn& __hf, 327 const _EqualKey& __eql, const _ExtractKey& __ext, 328 const allocator_type& __a = allocator_type()) 329 : _M_node_allocator(__a), _M_hash(__hf), _M_equals(__eql), 330 _M_get_key(__ext), _M_buckets(__a), _M_num_elements(0) 331 { _M_initialize_buckets(__n); } 332 333 hashtable(size_type __n, const _HashFcn& __hf, 334 const _EqualKey& __eql, 335 const allocator_type& __a = allocator_type()) 336 : _M_node_allocator(__a), _M_hash(__hf), _M_equals(__eql), 337 _M_get_key(_ExtractKey()), _M_buckets(__a), _M_num_elements(0) 338 { _M_initialize_buckets(__n); } 339 340 hashtable(const hashtable& __ht) 341 : _M_node_allocator(__ht.get_allocator()), _M_hash(__ht._M_hash), 342 _M_equals(__ht._M_equals), _M_get_key(__ht._M_get_key), 343 _M_buckets(__ht.get_allocator()), _M_num_elements(0) 344 { _M_copy_from(__ht); } 345 346 hashtable& 347 operator= (const hashtable& __ht) 348 { 349 if (&__ht != this) 350 { 351 clear(); 352 _M_hash = __ht._M_hash; 353 _M_equals = __ht._M_equals; 354 _M_get_key = __ht._M_get_key; 355 _M_copy_from(__ht); 356 } 357 return *this; 358 } 359 360 ~hashtable() 361 { clear(); } 362 363 size_type 364 size() const 365 { return _M_num_elements; } 366 367 size_type 368 max_size() const 369 { return size_type(-1); } 370 371 bool 372 empty() const 373 { return size() == 0; } 374 375 void 376 swap(hashtable& __ht) 377 { 378 std::swap(_M_hash, __ht._M_hash); 379 std::swap(_M_equals, __ht._M_equals); 380 std::swap(_M_get_key, __ht._M_get_key); 381 _M_buckets.swap(__ht._M_buckets); 382 std::swap(_M_num_elements, __ht._M_num_elements); 383 } 384 385 iterator 386 begin() 387 { 388 for (size_type __n = 0; __n < _M_buckets.size(); ++__n) 389 if (_M_buckets[__n]) 390 return iterator(_M_buckets[__n], this); 391 return end(); 392 } 393 394 iterator 395 end() 396 { return iterator(0, this); } 397 398 const_iterator 399 begin() const 400 { 401 for (size_type __n = 0; __n < _M_buckets.size(); ++__n) 402 if (_M_buckets[__n]) 403 return const_iterator(_M_buckets[__n], this); 404 return end(); 405 } 406 407 const_iterator 408 end() const 409 { return const_iterator(0, this); } 410 411 template<class _Vl, class _Ky, class _HF, class _Ex, class _Eq, 412 class _Al> 413 friend bool 414 operator==(const hashtable<_Vl, _Ky, _HF, _Ex, _Eq, _Al>&, 415 const hashtable<_Vl, _Ky, _HF, _Ex, _Eq, _Al>&); 416 417 public: 418 size_type 419 bucket_count() const 420 { return _M_buckets.size(); } 421 422 size_type 423 max_bucket_count() const 424 { return __stl_prime_list[(int)_S_num_primes - 1]; } 425 426 size_type 427 elems_in_bucket(size_type __bucket) const 428 { 429 size_type __result = 0; 430 for (_Node* __n = _M_buckets[__bucket]; __n; __n = __n->_M_next) 431 __result += 1; 432 return __result; 433 } 434 435 pair<iterator, bool> 436 insert_unique(const value_type& __obj) 437 { 438 resize(_M_num_elements + 1); 439 return insert_unique_noresize(__obj); 440 } 441 442 iterator 443 insert_equal(const value_type& __obj) 444 { 445 resize(_M_num_elements + 1); 446 return insert_equal_noresize(__obj); 447 } 448 449 pair<iterator, bool> 450 insert_unique_noresize(const value_type& __obj); 451 452 iterator 453 insert_equal_noresize(const value_type& __obj); 454 455 template<class _InputIterator> 456 void 457 insert_unique(_InputIterator __f, _InputIterator __l) 458 { insert_unique(__f, __l, __iterator_category(__f)); } 459 460 template<class _InputIterator> 461 void 462 insert_equal(_InputIterator __f, _InputIterator __l) 463 { insert_equal(__f, __l, __iterator_category(__f)); } 464 465 template<class _InputIterator> 466 void 467 insert_unique(_InputIterator __f, _InputIterator __l, 468 input_iterator_tag) 469 { 470 for ( ; __f != __l; ++__f) 471 insert_unique(*__f); 472 } 473 474 template<class _InputIterator> 475 void 476 insert_equal(_InputIterator __f, _InputIterator __l, 477 input_iterator_tag) 478 { 479 for ( ; __f != __l; ++__f) 480 insert_equal(*__f); 481 } 482 483 template<class _ForwardIterator> 484 void 485 insert_unique(_ForwardIterator __f, _ForwardIterator __l, 486 forward_iterator_tag) 487 { 488 size_type __n = distance(__f, __l); 489 resize(_M_num_elements + __n); 490 for ( ; __n > 0; --__n, ++__f) 491 insert_unique_noresize(*__f); 492 } 493 494 template<class _ForwardIterator> 495 void 496 insert_equal(_ForwardIterator __f, _ForwardIterator __l, 497 forward_iterator_tag) 498 { 499 size_type __n = distance(__f, __l); 500 resize(_M_num_elements + __n); 501 for ( ; __n > 0; --__n, ++__f) 502 insert_equal_noresize(*__f); 503 } 504 505 reference 506 find_or_insert(const value_type& __obj); 507 508 iterator 509 find(const key_type& __key) 510 { 511 size_type __n = _M_bkt_num_key(__key); 512 _Node* __first; 513 for (__first = _M_buckets[__n]; 514 __first && !_M_equals(_M_get_key(__first->_M_val), __key); 515 __first = __first->_M_next) 516 { } 517 return iterator(__first, this); 518 } 519 520 const_iterator 521 find(const key_type& __key) const 522 { 523 size_type __n = _M_bkt_num_key(__key); 524 const _Node* __first; 525 for (__first = _M_buckets[__n]; 526 __first && !_M_equals(_M_get_key(__first->_M_val), __key); 527 __first = __first->_M_next) 528 { } 529 return const_iterator(__first, this); 530 } 531 532 size_type 533 count(const key_type& __key) const 534 { 535 const size_type __n = _M_bkt_num_key(__key); 536 size_type __result = 0; 537 538 for (const _Node* __cur = _M_buckets[__n]; __cur; 539 __cur = __cur->_M_next) 540 if (_M_equals(_M_get_key(__cur->_M_val), __key)) 541 ++__result; 542 return __result; 543 } 544 545 pair<iterator, iterator> 546 equal_range(const key_type& __key); 547 548 pair<const_iterator, const_iterator> 549 equal_range(const key_type& __key) const; 550 551 size_type 552 erase(const key_type& __key); 553 554 void 555 erase(const iterator& __it); 556 557 void 558 erase(iterator __first, iterator __last); 559 560 void 561 erase(const const_iterator& __it); 562 563 void 564 erase(const_iterator __first, const_iterator __last); 565 566 void 567 resize(size_type __num_elements_hint); 568 569 void 570 clear(); 571 572 private: 573 size_type 574 _M_next_size(size_type __n) const 575 { return __stl_next_prime(__n); } 576 577 void 578 _M_initialize_buckets(size_type __n) 579 { 580 const size_type __n_buckets = _M_next_size(__n); 581 _M_buckets.reserve(__n_buckets); 582 _M_buckets.insert(_M_buckets.end(), __n_buckets, (_Node*) 0); 583 _M_num_elements = 0; 584 } 585 586 size_type 587 _M_bkt_num_key(const key_type& __key) const 588 { return _M_bkt_num_key(__key, _M_buckets.size()); } 589 590 size_type 591 _M_bkt_num(const value_type& __obj) const 592 { return _M_bkt_num_key(_M_get_key(__obj)); } 593 594 size_type 595 _M_bkt_num_key(const key_type& __key, size_t __n) const 596 { return _M_hash(__key) % __n; } 597 598 size_type 599 _M_bkt_num(const value_type& __obj, size_t __n) const 600 { return _M_bkt_num_key(_M_get_key(__obj), __n); } 601 602 _Node* 603 _M_new_node(const value_type& __obj) 604 { 605 _Node* __n = _M_get_node(); 606 __n->_M_next = 0; 607 try 608 { 609 this->get_allocator().construct(&__n->_M_val, __obj); 610 return __n; 611 } 612 catch(...) 613 { 614 _M_put_node(__n); 615 __throw_exception_again; 616 } 617 } 618 619 void 620 _M_delete_node(_Node* __n) 621 { 622 this->get_allocator().destroy(&__n->_M_val); 623 _M_put_node(__n); 624 } 625 626 void 627 _M_erase_bucket(const size_type __n, _Node* __first, _Node* __last); 628 629 void 630 _M_erase_bucket(const size_type __n, _Node* __last); 631 632 void 633 _M_copy_from(const hashtable& __ht); 634 }; 635 636 template<class _Val, class _Key, class _HF, class _ExK, class _EqK, 637 class _All> 638 _Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>& 639 _Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>:: 640 operator++() 641 { 642 const _Node* __old = _M_cur; 643 _M_cur = _M_cur->_M_next; 644 if (!_M_cur) 645 { 646 size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val); 647 while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size()) 648 _M_cur = _M_ht->_M_buckets[__bucket]; 649 } 650 return *this; 651 } 652 653 template<class _Val, class _Key, class _HF, class _ExK, class _EqK, 654 class _All> 655 inline _Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All> 656 _Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>:: 657 operator++(int) 658 { 659 iterator __tmp = *this; 660 ++*this; 661 return __tmp; 662 } 663 664 template<class _Val, class _Key, class _HF, class _ExK, class _EqK, 665 class _All> 666 _Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>& 667 _Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>:: 668 operator++() 669 { 670 const _Node* __old = _M_cur; 671 _M_cur = _M_cur->_M_next; 672 if (!_M_cur) 673 { 674 size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val); 675 while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size()) 676 _M_cur = _M_ht->_M_buckets[__bucket]; 677 } 678 return *this; 679 } 680 681 template<class _Val, class _Key, class _HF, class _ExK, class _EqK, 682 class _All> 683 inline _Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All> 684 _Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>:: 685 operator++(int) 686 { 687 const_iterator __tmp = *this; 688 ++*this; 689 return __tmp; 690 } 691 692 template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> 693 bool 694 operator==(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1, 695 const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2) 696 { 697 typedef typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_Node _Node; 698 699 if (__ht1._M_buckets.size() != __ht2._M_buckets.size()) 700 return false; 701 702 for (size_t __n = 0; __n < __ht1._M_buckets.size(); ++__n) 703 { 704 _Node* __cur1 = __ht1._M_buckets[__n]; 705 _Node* __cur2 = __ht2._M_buckets[__n]; 706 // Check same length of lists 707 for (; __cur1 && __cur2; 708 __cur1 = __cur1->_M_next, __cur2 = __cur2->_M_next) 709 { } 710 if (__cur1 || __cur2) 711 return false; 712 // Now check one's elements are in the other 713 for (__cur1 = __ht1._M_buckets[__n] ; __cur1; 714 __cur1 = __cur1->_M_next) 715 { 716 bool _found__cur1 = false; 717 for (__cur2 = __ht2._M_buckets[__n]; 718 __cur2; __cur2 = __cur2->_M_next) 719 { 720 if (__cur1->_M_val == __cur2->_M_val) 721 { 722 _found__cur1 = true; 723 break; 724 } 725 } 726 if (!_found__cur1) 727 return false; 728 } 729 } 730 return true; 731 } 732 733 template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> 734 inline bool 735 operator!=(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1, 736 const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2) 737 { return !(__ht1 == __ht2); } 738 739 template<class _Val, class _Key, class _HF, class _Extract, class _EqKey, 740 class _All> 741 inline void 742 swap(hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht1, 743 hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht2) 744 { __ht1.swap(__ht2); } 745 746 template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> 747 pair<typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator, bool> 748 hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>:: 749 insert_unique_noresize(const value_type& __obj) 750 { 751 const size_type __n = _M_bkt_num(__obj); 752 _Node* __first = _M_buckets[__n]; 753 754 for (_Node* __cur = __first; __cur; __cur = __cur->_M_next) 755 if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj))) 756 return pair<iterator, bool>(iterator(__cur, this), false); 757 758 _Node* __tmp = _M_new_node(__obj); 759 __tmp->_M_next = __first; 760 _M_buckets[__n] = __tmp; 761 ++_M_num_elements; 762 return pair<iterator, bool>(iterator(__tmp, this), true); 763 } 764 765 template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> 766 typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator 767 hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>:: 768 insert_equal_noresize(const value_type& __obj) 769 { 770 const size_type __n = _M_bkt_num(__obj); 771 _Node* __first = _M_buckets[__n]; 772 773 for (_Node* __cur = __first; __cur; __cur = __cur->_M_next) 774 if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj))) 775 { 776 _Node* __tmp = _M_new_node(__obj); 777 __tmp->_M_next = __cur->_M_next; 778 __cur->_M_next = __tmp; 779 ++_M_num_elements; 780 return iterator(__tmp, this); 781 } 782 783 _Node* __tmp = _M_new_node(__obj); 784 __tmp->_M_next = __first; 785 _M_buckets[__n] = __tmp; 786 ++_M_num_elements; 787 return iterator(__tmp, this); 788 } 789 790 template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> 791 typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::reference 792 hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>:: 793 find_or_insert(const value_type& __obj) 794 { 795 resize(_M_num_elements + 1); 796 797 size_type __n = _M_bkt_num(__obj); 798 _Node* __first = _M_buckets[__n]; 799 800 for (_Node* __cur = __first; __cur; __cur = __cur->_M_next) 801 if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj))) 802 return __cur->_M_val; 803 804 _Node* __tmp = _M_new_node(__obj); 805 __tmp->_M_next = __first; 806 _M_buckets[__n] = __tmp; 807 ++_M_num_elements; 808 return __tmp->_M_val; 809 } 810 811 template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> 812 pair<typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator, 813 typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator> 814 hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>:: 815 equal_range(const key_type& __key) 816 { 817 typedef pair<iterator, iterator> _Pii; 818 const size_type __n = _M_bkt_num_key(__key); 819 820 for (_Node* __first = _M_buckets[__n]; __first; 821 __first = __first->_M_next) 822 if (_M_equals(_M_get_key(__first->_M_val), __key)) 823 { 824 for (_Node* __cur = __first->_M_next; __cur; 825 __cur = __cur->_M_next) 826 if (!_M_equals(_M_get_key(__cur->_M_val), __key)) 827 return _Pii(iterator(__first, this), iterator(__cur, this)); 828 for (size_type __m = __n + 1; __m < _M_buckets.size(); ++__m) 829 if (_M_buckets[__m]) 830 return _Pii(iterator(__first, this), 831 iterator(_M_buckets[__m], this)); 832 return _Pii(iterator(__first, this), end()); 833 } 834 return _Pii(end(), end()); 835 } 836 837 template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> 838 pair<typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::const_iterator, 839 typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::const_iterator> 840 hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>:: 841 equal_range(const key_type& __key) const 842 { 843 typedef pair<const_iterator, const_iterator> _Pii; 844 const size_type __n = _M_bkt_num_key(__key); 845 846 for (const _Node* __first = _M_buckets[__n]; __first; 847 __first = __first->_M_next) 848 { 849 if (_M_equals(_M_get_key(__first->_M_val), __key)) 850 { 851 for (const _Node* __cur = __first->_M_next; __cur; 852 __cur = __cur->_M_next) 853 if (!_M_equals(_M_get_key(__cur->_M_val), __key)) 854 return _Pii(const_iterator(__first, this), 855 const_iterator(__cur, this)); 856 for (size_type __m = __n + 1; __m < _M_buckets.size(); ++__m) 857 if (_M_buckets[__m]) 858 return _Pii(const_iterator(__first, this), 859 const_iterator(_M_buckets[__m], this)); 860 return _Pii(const_iterator(__first, this), end()); 861 } 862 } 863 return _Pii(end(), end()); 864 } 865 866 template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> 867 typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::size_type 868 hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>:: 869 erase(const key_type& __key) 870 { 871 const size_type __n = _M_bkt_num_key(__key); 872 _Node* __first = _M_buckets[__n]; 873 size_type __erased = 0; 874 875 if (__first) 876 { 877 _Node* __cur = __first; 878 _Node* __next = __cur->_M_next; 879 while (__next) 880 { 881 if (_M_equals(_M_get_key(__next->_M_val), __key)) 882 { 883 __cur->_M_next = __next->_M_next; 884 _M_delete_node(__next); 885 __next = __cur->_M_next; 886 ++__erased; 887 --_M_num_elements; 888 } 889 else 890 { 891 __cur = __next; 892 __next = __cur->_M_next; 893 } 894 } 895 if (_M_equals(_M_get_key(__first->_M_val), __key)) 896 { 897 _M_buckets[__n] = __first->_M_next; 898 _M_delete_node(__first); 899 ++__erased; 900 --_M_num_elements; 901 } 902 } 903 return __erased; 904 } 905 906 template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> 907 void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>:: 908 erase(const iterator& __it) 909 { 910 _Node* __p = __it._M_cur; 911 if (__p) 912 { 913 const size_type __n = _M_bkt_num(__p->_M_val); 914 _Node* __cur = _M_buckets[__n]; 915 916 if (__cur == __p) 917 { 918 _M_buckets[__n] = __cur->_M_next; 919 _M_delete_node(__cur); 920 --_M_num_elements; 921 } 922 else 923 { 924 _Node* __next = __cur->_M_next; 925 while (__next) 926 { 927 if (__next == __p) 928 { 929 __cur->_M_next = __next->_M_next; 930 _M_delete_node(__next); 931 --_M_num_elements; 932 break; 933 } 934 else 935 { 936 __cur = __next; 937 __next = __cur->_M_next; 938 } 939 } 940 } 941 } 942 } 943 944 template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> 945 void 946 hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>:: 947 erase(iterator __first, iterator __last) 948 { 949 size_type __f_bucket = __first._M_cur ? _M_bkt_num(__first._M_cur->_M_val) 950 : _M_buckets.size(); 951 952 size_type __l_bucket = __last._M_cur ? _M_bkt_num(__last._M_cur->_M_val) 953 : _M_buckets.size(); 954 955 if (__first._M_cur == __last._M_cur) 956 return; 957 else if (__f_bucket == __l_bucket) 958 _M_erase_bucket(__f_bucket, __first._M_cur, __last._M_cur); 959 else 960 { 961 _M_erase_bucket(__f_bucket, __first._M_cur, 0); 962 for (size_type __n = __f_bucket + 1; __n < __l_bucket; ++__n) 963 _M_erase_bucket(__n, 0); 964 if (__l_bucket != _M_buckets.size()) 965 _M_erase_bucket(__l_bucket, __last._M_cur); 966 } 967 } 968 969 template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> 970 inline void 971 hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>:: 972 erase(const_iterator __first, const_iterator __last) 973 { 974 erase(iterator(const_cast<_Node*>(__first._M_cur), 975 const_cast<hashtable*>(__first._M_ht)), 976 iterator(const_cast<_Node*>(__last._M_cur), 977 const_cast<hashtable*>(__last._M_ht))); 978 } 979 980 template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> 981 inline void 982 hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>:: 983 erase(const const_iterator& __it) 984 { erase(iterator(const_cast<_Node*>(__it._M_cur), 985 const_cast<hashtable*>(__it._M_ht))); } 986 987 template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> 988 void 989 hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>:: 990 resize(size_type __num_elements_hint) 991 { 992 const size_type __old_n = _M_buckets.size(); 993 if (__num_elements_hint > __old_n) 994 { 995 const size_type __n = _M_next_size(__num_elements_hint); 996 if (__n > __old_n) 997 { 998 _Vector_type __tmp(__n, (_Node*)(0), _M_buckets.get_allocator()); 999 try 1000 { 1001 for (size_type __bucket = 0; __bucket < __old_n; ++__bucket) 1002 { 1003 _Node* __first = _M_buckets[__bucket]; 1004 while (__first) 1005 { 1006 size_type __new_bucket = _M_bkt_num(__first->_M_val, 1007 __n); 1008 _M_buckets[__bucket] = __first->_M_next; 1009 __first->_M_next = __tmp[__new_bucket]; 1010 __tmp[__new_bucket] = __first; 1011 __first = _M_buckets[__bucket]; 1012 } 1013 } 1014 _M_buckets.swap(__tmp); 1015 } 1016 catch(...) 1017 { 1018 for (size_type __bucket = 0; __bucket < __tmp.size(); 1019 ++__bucket) 1020 { 1021 while (__tmp[__bucket]) 1022 { 1023 _Node* __next = __tmp[__bucket]->_M_next; 1024 _M_delete_node(__tmp[__bucket]); 1025 __tmp[__bucket] = __next; 1026 } 1027 } 1028 __throw_exception_again; 1029 } 1030 } 1031 } 1032 } 1033 1034 template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> 1035 void 1036 hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>:: 1037 _M_erase_bucket(const size_type __n, _Node* __first, _Node* __last) 1038 { 1039 _Node* __cur = _M_buckets[__n]; 1040 if (__cur == __first) 1041 _M_erase_bucket(__n, __last); 1042 else 1043 { 1044 _Node* __next; 1045 for (__next = __cur->_M_next; 1046 __next != __first; 1047 __cur = __next, __next = __cur->_M_next) 1048 ; 1049 while (__next != __last) 1050 { 1051 __cur->_M_next = __next->_M_next; 1052 _M_delete_node(__next); 1053 __next = __cur->_M_next; 1054 --_M_num_elements; 1055 } 1056 } 1057 } 1058 1059 template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> 1060 void 1061 hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>:: 1062 _M_erase_bucket(const size_type __n, _Node* __last) 1063 { 1064 _Node* __cur = _M_buckets[__n]; 1065 while (__cur != __last) 1066 { 1067 _Node* __next = __cur->_M_next; 1068 _M_delete_node(__cur); 1069 __cur = __next; 1070 _M_buckets[__n] = __cur; 1071 --_M_num_elements; 1072 } 1073 } 1074 1075 template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> 1076 void 1077 hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>:: 1078 clear() 1079 { 1080 // Google addition: do not iterate over buckets when empty 1081 if (_M_num_elements == 0) 1082 return; 1083 1084 for (size_type __i = 0; __i < _M_buckets.size(); ++__i) 1085 { 1086 _Node* __cur = _M_buckets[__i]; 1087 while (__cur != 0) 1088 { 1089 _Node* __next = __cur->_M_next; 1090 _M_delete_node(__cur); 1091 __cur = __next; 1092 } 1093 _M_buckets[__i] = 0; 1094 } 1095 _M_num_elements = 0; 1096 } 1097 1098 template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All> 1099 void 1100 hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>:: 1101 _M_copy_from(const hashtable& __ht) 1102 { 1103 _M_buckets.clear(); 1104 _M_buckets.reserve(__ht._M_buckets.size()); 1105 _M_buckets.insert(_M_buckets.end(), __ht._M_buckets.size(), (_Node*) 0); 1106 try 1107 { 1108 for (size_type __i = 0; __i < __ht._M_buckets.size(); ++__i) { 1109 const _Node* __cur = __ht._M_buckets[__i]; 1110 if (__cur) 1111 { 1112 _Node* __local_copy = _M_new_node(__cur->_M_val); 1113 _M_buckets[__i] = __local_copy; 1114 1115 for (_Node* __next = __cur->_M_next; 1116 __next; 1117 __cur = __next, __next = __cur->_M_next) 1118 { 1119 __local_copy->_M_next = _M_new_node(__next->_M_val); 1120 __local_copy = __local_copy->_M_next; 1121 } 1122 } 1123 } 1124 _M_num_elements = __ht._M_num_elements; 1125 } 1126 catch(...) 1127 { 1128 clear(); 1129 __throw_exception_again; 1130 } 1131 } 1132 1133_GLIBCXX_END_NAMESPACE 1134 1135#endif 1136