1// -*- C++ -*- 2 3// Copyright (C) 2005, 2006 Free Software Foundation, Inc. 4// 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 terms 7// of the GNU General Public License as published by the Free Software 8// Foundation; either version 2, or (at your option) any later 9// version. 10 11// This library is distributed in the hope that it will be useful, but 12// WITHOUT ANY WARRANTY; without even the implied warranty of 13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14// General Public License for more details. 15 16// You should have received a copy of the GNU General Public License 17// along with this library; see the file COPYING. If not, write to 18// the Free Software Foundation, 59 Temple Place - Suite 330, Boston, 19// MA 02111-1307, USA. 20 21// As a special exception, you may use this file as part of a free 22// software library without restriction. Specifically, if other files 23// instantiate templates or use macros or inline functions from this 24// file, or you compile this file and link it with other files to 25// produce an executable, this file does not by itself cause the 26// resulting executable to be covered by the GNU General Public 27// License. This exception does not however invalidate any other 28// reasons why the executable file might be covered by the GNU General 29// Public License. 30 31// Copyright (C) 2004 Ami Tavory and Vladimir Dreizin, IBM-HRL. 32 33// Permission to use, copy, modify, sell, and distribute this software 34// is hereby granted without fee, provided that the above copyright 35// notice appears in all copies, and that both that copyright notice 36// and this permission notice appear in supporting documentation. None 37// of the above authors, nor IBM Haifa Research Laboratories, make any 38// representation about the suitability of this software for any 39// purpose. It is provided "as is" without express or implied 40// warranty. 41 42/** 43 * @file hash_policy.hpp 44 * Contains hash-related policies. 45 */ 46 47#ifndef PB_DS_HASH_POLICY_HPP 48#define PB_DS_HASH_POLICY_HPP 49 50#include <algorithm> 51#include <vector> 52#include <cmath> 53#include <ext/pb_ds/exception.hpp> 54#include <ext/pb_ds/detail/type_utils.hpp> 55#include <ext/pb_ds/detail/hash_fn/mask_based_range_hashing.hpp> 56#include <ext/pb_ds/detail/hash_fn/mod_based_range_hashing.hpp> 57#include <ext/pb_ds/detail/resize_policy/hash_load_check_resize_trigger_size_base.hpp> 58 59namespace pb_ds 60{ 61 // A null hash function, indicating that the combining hash function 62 // is actually a ranged hash function. 63 struct null_hash_fn 64 { }; 65 66 // A null probe function, indicating that the combining probe 67 // function is actually a ranged probe function. 68 struct null_probe_fn 69 { }; 70 71#define PB_DS_CLASS_T_DEC template<typename Size_Type> 72#define PB_DS_CLASS_C_DEC linear_probe_fn<Size_Type> 73 74 // A probe sequence policy using fixed increments. 75 template<typename Size_Type = size_t> 76 class linear_probe_fn 77 { 78 public: 79 typedef Size_Type size_type; 80 81 void 82 swap(PB_DS_CLASS_C_DEC& other); 83 84 protected: 85 // Returns the i-th offset from the hash value. 86 inline size_type 87 operator()(size_type i) const; 88 }; 89 90#include <ext/pb_ds/detail/hash_fn/linear_probe_fn_imp.hpp> 91 92#undef PB_DS_CLASS_T_DEC 93#undef PB_DS_CLASS_C_DEC 94 95#define PB_DS_CLASS_T_DEC template<typename Size_Type> 96#define PB_DS_CLASS_C_DEC quadratic_probe_fn<Size_Type> 97 98 // A probe sequence policy using square increments. 99 template<typename Size_Type = size_t> 100 class quadratic_probe_fn 101 { 102 public: 103 typedef Size_Type size_type; 104 105 void 106 swap(PB_DS_CLASS_C_DEC& other); 107 108 protected: 109 // Returns the i-th offset from the hash value. 110 inline size_type 111 operator()(size_type i) const; 112 }; 113 114#include <ext/pb_ds/detail/hash_fn/quadratic_probe_fn_imp.hpp> 115 116#undef PB_DS_CLASS_T_DEC 117#undef PB_DS_CLASS_C_DEC 118 119#define PB_DS_CLASS_T_DEC template<typename Size_Type> 120#define PB_DS_CLASS_C_DEC direct_mask_range_hashing<Size_Type> 121 122 // A mask range-hashing class (uses a bit-mask). 123 template<typename Size_Type = size_t> 124 class direct_mask_range_hashing 125 : public detail::mask_based_range_hashing<Size_Type> 126 { 127 private: 128 typedef detail::mask_based_range_hashing<Size_Type> mask_based_base; 129 130 public: 131 typedef Size_Type size_type; 132 133 void 134 swap(PB_DS_CLASS_C_DEC& other); 135 136 protected: 137 void 138 notify_resized(size_type size); 139 140 // Transforms the __hash value hash into a ranged-hash value 141 // (using a bit-mask). 142 inline size_type 143 operator()(size_type hash) const; 144 }; 145 146#include <ext/pb_ds/detail/hash_fn/direct_mask_range_hashing_imp.hpp> 147 148#undef PB_DS_CLASS_T_DEC 149#undef PB_DS_CLASS_C_DEC 150 151#define PB_DS_CLASS_T_DEC template<typename Size_Type> 152#define PB_DS_CLASS_C_DEC direct_mod_range_hashing<Size_Type> 153 154 // A mod range-hashing class (uses the modulo function). 155 template<typename Size_Type = size_t> 156 class direct_mod_range_hashing 157 : public detail::mod_based_range_hashing<Size_Type> 158 { 159 public: 160 typedef Size_Type size_type; 161 162 void 163 swap(PB_DS_CLASS_C_DEC& other); 164 165 protected: 166 void 167 notify_resized(size_type size); 168 169 // Transforms the __hash value hash into a ranged-hash value 170 // (using a modulo operation). 171 inline size_type 172 operator()(size_type hash) const; 173 174 private: 175 typedef detail::mod_based_range_hashing<size_type> mod_based_base; 176 }; 177 178#include <ext/pb_ds/detail/hash_fn/direct_mod_range_hashing_imp.hpp> 179 180#undef PB_DS_CLASS_T_DEC 181#undef PB_DS_CLASS_C_DEC 182 183#define PB_DS_CLASS_T_DEC template<bool External_Load_Access, typename Size_Type> 184#define PB_DS_CLASS_C_DEC hash_load_check_resize_trigger<External_Load_Access, Size_Type> 185#define PB_DS_SIZE_BASE_C_DEC detail::hash_load_check_resize_trigger_size_base<Size_Type, External_Load_Access> 186 187 // A resize trigger policy based on a load check. It keeps the 188 // load factor between some load factors load_min and load_max. 189 template<bool External_Load_Access = false, typename Size_Type = size_t> 190 class hash_load_check_resize_trigger : private PB_DS_SIZE_BASE_C_DEC 191 { 192 public: 193 typedef Size_Type size_type; 194 195 enum 196 { 197 external_load_access = External_Load_Access 198 }; 199 200 // Default constructor, or constructor taking load_min and 201 // load_max load factors between which this policy will keep the 202 // actual load. 203 hash_load_check_resize_trigger(float load_min = 0.125, 204 float load_max = 0.5); 205 206 void 207 swap(hash_load_check_resize_trigger& other); 208 209 virtual 210 ~hash_load_check_resize_trigger(); 211 212 // Returns a pair of the minimal and maximal loads, respectively. 213 inline std::pair<float, float> 214 get_loads() const; 215 216 // Sets the loads through a pair of the minimal and maximal 217 // loads, respectively. 218 void 219 set_loads(std::pair<float, float> load_pair); 220 221 protected: 222 inline void 223 notify_insert_search_start(); 224 225 inline void 226 notify_insert_search_collision(); 227 228 inline void 229 notify_insert_search_end(); 230 231 inline void 232 notify_find_search_start(); 233 234 inline void 235 notify_find_search_collision(); 236 237 inline void 238 notify_find_search_end(); 239 240 inline void 241 notify_erase_search_start(); 242 243 inline void 244 notify_erase_search_collision(); 245 246 inline void 247 notify_erase_search_end(); 248 249 // Notifies an element was inserted. The total number of entries 250 // in the table is num_entries. 251 inline void 252 notify_inserted(size_type num_entries); 253 254 inline void 255 notify_erased(size_type num_entries); 256 257 // Notifies the table was cleared. 258 void 259 notify_cleared(); 260 261 // Notifies the table was resized as a result of this object's 262 // signifying that a resize is needed. 263 void 264 notify_resized(size_type new_size); 265 266 void 267 notify_externally_resized(size_type new_size); 268 269 inline bool 270 is_resize_needed() const; 271 272 inline bool 273 is_grow_needed(size_type size, size_type num_entries) const; 274 275 private: 276 virtual void 277 do_resize(size_type new_size); 278 279 typedef PB_DS_SIZE_BASE_C_DEC size_base; 280 281#ifdef _GLIBCXX_DEBUG 282 void 283 assert_valid() const; 284#endif 285 286 float m_load_min; 287 float m_load_max; 288 size_type m_next_shrink_size; 289 size_type m_next_grow_size; 290 bool m_resize_needed; 291 }; 292 293#include <ext/pb_ds/detail/resize_policy/hash_load_check_resize_trigger_imp.hpp> 294 295#undef PB_DS_CLASS_T_DEC 296#undef PB_DS_CLASS_C_DEC 297#undef PB_DS_SIZE_BASE_C_DEC 298 299#define PB_DS_CLASS_T_DEC template<bool External_Load_Access, typename Size_Type> 300#define PB_DS_CLASS_C_DEC cc_hash_max_collision_check_resize_trigger<External_Load_Access, Size_Type> 301 302 // A resize trigger policy based on collision checks. It keeps the 303 // simulated load factor lower than some given load factor. 304 template<bool External_Load_Access = false, typename Size_Type = size_t> 305 class cc_hash_max_collision_check_resize_trigger 306 { 307 public: 308 typedef Size_Type size_type; 309 310 enum 311 { 312 external_load_access = External_Load_Access 313 }; 314 315 // Default constructor, or constructor taking load, a __load 316 // factor which it will attempt to maintain. 317 cc_hash_max_collision_check_resize_trigger(float load = 0.5); 318 319 void 320 swap(PB_DS_CLASS_C_DEC& other); 321 322 // Returns the current load. 323 inline float 324 get_load() const; 325 326 // Sets the load; does not resize the container. 327 void 328 set_load(float load); 329 330 protected: 331 inline void 332 notify_insert_search_start(); 333 334 inline void 335 notify_insert_search_collision(); 336 337 inline void 338 notify_insert_search_end(); 339 340 inline void 341 notify_find_search_start(); 342 343 inline void 344 notify_find_search_collision(); 345 346 inline void 347 notify_find_search_end(); 348 349 inline void 350 notify_erase_search_start(); 351 352 inline void 353 notify_erase_search_collision(); 354 355 inline void 356 notify_erase_search_end(); 357 358 inline void 359 notify_inserted(size_type num_entries); 360 361 inline void 362 notify_erased(size_type num_entries); 363 364 void 365 notify_cleared(); 366 367 // Notifies the table was resized as a result of this object's 368 // signifying that a resize is needed. 369 void 370 notify_resized(size_type new_size); 371 372 void 373 notify_externally_resized(size_type new_size); 374 375 inline bool 376 is_resize_needed() const; 377 378 inline bool 379 is_grow_needed(size_type size, size_type num_entries) const; 380 381 private: 382 void 383 calc_max_num_coll(); 384 385 inline void 386 calc_resize_needed(); 387 388 float m_load; 389 size_type m_size; 390 size_type m_num_col; 391 size_type m_max_col; 392 bool m_resize_needed; 393 }; 394 395#include <ext/pb_ds/detail/resize_policy/cc_hash_max_collision_check_resize_trigger_imp.hpp> 396 397#undef PB_DS_CLASS_T_DEC 398#undef PB_DS_CLASS_C_DEC 399 400#define PB_DS_CLASS_T_DEC template<typename Size_Type> 401#define PB_DS_CLASS_C_DEC hash_exponential_size_policy<Size_Type> 402 403 // A size policy whose sequence of sizes form an exponential 404 // sequence (typically powers of 2. 405 template<typename Size_Type = size_t> 406 class hash_exponential_size_policy 407 { 408 public: 409 typedef Size_Type size_type; 410 411 // Default constructor, or onstructor taking a start_size, or 412 // constructor taking a start size and grow_factor. The policy 413 // will use the sequence of sizes start_size, start_size* 414 // grow_factor, start_size* grow_factor^2, ... 415 hash_exponential_size_policy(size_type start_size = 8, 416 size_type grow_factor = 2); 417 418 void 419 swap(PB_DS_CLASS_C_DEC& other); 420 421 protected: 422 size_type 423 get_nearest_larger_size(size_type size) const; 424 425 size_type 426 get_nearest_smaller_size(size_type size) const; 427 428 private: 429 size_type m_start_size; 430 size_type m_grow_factor; 431 }; 432 433#include <ext/pb_ds/detail/resize_policy/hash_exponential_size_policy_imp.hpp> 434 435#undef PB_DS_CLASS_T_DEC 436#undef PB_DS_CLASS_C_DEC 437 438#define PB_DS_CLASS_T_DEC 439#define PB_DS_CLASS_C_DEC hash_prime_size_policy 440 441 // A size policy whose sequence of sizes form a nearly-exponential 442 // sequence of primes. 443 class hash_prime_size_policy 444 { 445 public: 446 // Size type. 447 typedef size_t size_type; 448 449 // Default constructor, or onstructor taking a start_size The 450 // policy will use the sequence of sizes approximately 451 // start_size, start_size* 2, start_size* 2^2, ... 452 hash_prime_size_policy(size_type start_size = 8); 453 454 inline void 455 swap(PB_DS_CLASS_C_DEC& other); 456 457 protected: 458 size_type 459 get_nearest_larger_size(size_type size) const; 460 461 size_type 462 get_nearest_smaller_size(size_type size) const; 463 464 private: 465 size_type m_start_size; 466 }; 467 468#include <ext/pb_ds/detail/resize_policy/hash_prime_size_policy_imp.hpp> 469 470#undef PB_DS_CLASS_T_DEC 471#undef PB_DS_CLASS_C_DEC 472 473#define PB_DS_CLASS_T_DEC template<typename Size_Policy, typename Trigger_Policy, bool External_Size_Access, typename Size_Type> 474 475#define PB_DS_CLASS_C_DEC hash_standard_resize_policy<Size_Policy, Trigger_Policy, External_Size_Access, Size_Type> 476 477 // A resize policy which delegates operations to size and trigger policies. 478 template<typename Size_Policy = hash_exponential_size_policy<>, 479 typename Trigger_Policy = hash_load_check_resize_trigger<>, 480 bool External_Size_Access = false, 481 typename Size_Type = size_t> 482 class hash_standard_resize_policy 483 : public Size_Policy, public Trigger_Policy 484 { 485 public: 486 typedef Size_Type size_type; 487 typedef Trigger_Policy trigger_policy; 488 typedef Size_Policy size_policy; 489 490 enum 491 { 492 external_size_access = External_Size_Access 493 }; 494 495 // Default constructor. 496 hash_standard_resize_policy(); 497 498 // constructor taking some policies r_size_policy will be copied 499 // by the Size_Policy object of this object. 500 hash_standard_resize_policy(const Size_Policy& r_size_policy); 501 502 // constructor taking some policies. r_size_policy will be 503 // copied by the Size_Policy object of this 504 // object. r_trigger_policy will be copied by the Trigger_Policy 505 // object of this object. 506 hash_standard_resize_policy(const Size_Policy& r_size_policy, 507 const Trigger_Policy& r_trigger_policy); 508 509 virtual 510 ~hash_standard_resize_policy(); 511 512 inline void 513 swap(PB_DS_CLASS_C_DEC& other); 514 515 // Access to the Size_Policy object used. 516 Size_Policy& 517 get_size_policy(); 518 519 // Const access to the Size_Policy object used. 520 const Size_Policy& 521 get_size_policy() const; 522 523 // Access to the Trigger_Policy object used. 524 Trigger_Policy& 525 get_trigger_policy(); 526 527 // Access to the Trigger_Policy object used. 528 const Trigger_Policy& 529 get_trigger_policy() const; 530 531 // Returns the actual size of the container. 532 inline size_type 533 get_actual_size() const; 534 535 // Resizes the container to suggested_new_size, a suggested size 536 // (the actual size will be determined by the Size_Policy 537 // object). 538 void 539 resize(size_type suggested_new_size); 540 541 protected: 542 inline void 543 notify_insert_search_start(); 544 545 inline void 546 notify_insert_search_collision(); 547 548 inline void 549 notify_insert_search_end(); 550 551 inline void 552 notify_find_search_start(); 553 554 inline void 555 notify_find_search_collision(); 556 557 inline void 558 notify_find_search_end(); 559 560 inline void 561 notify_erase_search_start(); 562 563 inline void 564 notify_erase_search_collision(); 565 566 inline void 567 notify_erase_search_end(); 568 569 inline void 570 notify_inserted(size_type num_e); 571 572 inline void 573 notify_erased(size_type num_e); 574 575 void 576 notify_cleared(); 577 578 void 579 notify_resized(size_type new_size); 580 581 inline bool 582 is_resize_needed() const; 583 584 // Queries what the new size should be, when the container is 585 // resized naturally. The current __size of the container is 586 // size, and the number of used entries within the container is 587 // num_used_e. 588 size_type 589 get_new_size(size_type size, size_type num_used_e) const; 590 591 private: 592 // Resizes to new_size. 593 virtual void 594 do_resize(size_type new_size); 595 596 typedef Trigger_Policy trigger_policy_base; 597 598 typedef Size_Policy size_policy_base; 599 600 size_type m_size; 601 }; 602 603#include <ext/pb_ds/detail/resize_policy/hash_standard_resize_policy_imp.hpp> 604 605#undef PB_DS_CLASS_T_DEC 606#undef PB_DS_CLASS_C_DEC 607 608} // namespace pb_ds 609 610#endif 611