lean cpp library
A lean C++ library providing efficient utility classes for high-performance C++ applications.
|
00001 /*****************************************************/ 00002 /* lean Containers (c) Tobias Zirr 2011 */ 00003 /*****************************************************/ 00004 00005 #ifndef LEAN_CONTAINERS_SIMPLE_HASH_MAP 00006 #define LEAN_CONTAINERS_SIMPLE_HASH_MAP 00007 00008 #include "../lean.h" 00009 #include "../limits.h" 00010 #include "../smart/terminate_guard.h" 00011 #include "../tags/noncopyable.h" 00012 #include "../functional/hashing.h" 00013 #include "../meta/type_traits.h" 00014 #include <memory> 00015 #include <utility> 00016 #include <cmath> 00017 #include <functional> 00018 #include <string> 00019 #include <iterator> 00020 00021 namespace lean 00022 { 00023 namespace containers 00024 { 00025 00027 namespace simple_hash_map_policies 00028 { 00030 template <bool RawMove = false, bool NoDestruct = false, bool RawKeyMove = RawMove, bool NoKeyDestruct = NoDestruct> 00031 struct policy 00032 { 00034 static const bool raw_move = RawMove; 00036 static const bool no_destruct = NoDestruct; 00038 static const bool raw_key_move = RawKeyMove; 00040 static const bool no_key_destruct = NoKeyDestruct; 00041 }; 00042 00044 typedef policy<> nonpod; 00046 typedef policy<false, false, true> semipodkey; 00048 typedef policy<true> semipod; 00050 typedef policy<false, false, true, true> podkey; 00052 typedef policy<true, false, true, true> podkey_semipod; 00054 typedef policy<true, true> pod; 00055 } 00056 00058 template <class Key> 00059 struct default_keys 00060 { 00062 static const Key invalid_key; 00064 static const Key end_key; 00066 LEAN_INLINE static bool is_valid(const Key &key) 00067 { 00068 return (key != invalid_key); 00069 } 00070 }; 00071 00072 // Numeric (generic) defaults 00073 template <class Key> 00074 const Key default_keys<Key>::invalid_key = 00075 (numeric_limits<Key>::has_infinity) 00076 ? numeric_limits<Key>::infinity 00077 : (numeric_limits<Key>::is_unsigned) 00078 ? numeric_limits<Key>::max 00079 : numeric_limits<Key>::min; 00080 template <class Key> 00081 const Key default_keys<Key>::end_key = Key(); 00082 00083 // Pointer defaults 00084 template <class Value> 00085 struct default_keys<Value*> 00086 { 00087 static Value* const invalid_key; 00088 static Value* const end_key; 00089 00090 LEAN_INLINE static bool is_valid(Value *ptr) 00091 { 00092 return (ptr != nullptr); 00093 } 00094 }; 00095 00096 template <class Value> 00097 Value* const default_keys<Value*>::invalid_key = nullptr; 00098 template <class Value> 00099 Value* const default_keys<Value*>::end_key = reinterpret_cast<Value*>( static_cast<uintptr_t>(-1) ); 00100 00101 // String defaults 00102 template <class Char, class Traits, class Allocator> 00103 struct default_keys< std::basic_string<Char, Traits, Allocator> > 00104 { 00105 typedef std::basic_string<Char, Traits, Allocator> key_type; 00106 00107 static const key_type invalid_key; 00108 static const key_type end_key; 00109 00110 LEAN_INLINE static bool is_valid(const key_type &key) 00111 { 00112 return !key.empty(); 00113 } 00114 }; 00115 00116 template <class Char, class Traits, class Allocator> 00117 const std::basic_string<Char, Traits, Allocator> 00118 default_keys< std::basic_string<Char, Traits, Allocator> >::invalid_key = std::basic_string<Char, Traits, Allocator>(); 00119 template <class Char, class Traits, class Allocator> 00120 const std::basic_string<Char, Traits, Allocator> 00121 default_keys< std::basic_string<Char, Traits, Allocator> >::end_key = std::basic_string<Char, Traits, Allocator>(1, Char()); 00122 00123 namespace impl 00124 { 00125 00129 LEAN_MAYBE_EXPORT size_t next_prime_capacity(size_t capacity, size_t max); 00130 00132 template < class Key, class Element, 00133 class Policy, 00134 class KeyValues, 00135 class Allocator > 00136 class simple_hash_map_base 00137 { 00138 protected: 00139 typedef std::pair<const Key, Element> value_type_; 00140 00141 typedef typename Allocator::template rebind<value_type_>::other allocator_type_; 00142 allocator_type_ m_allocator; 00143 00144 value_type_ *m_elements; 00145 value_type_ *m_elementsEnd; 00146 00147 typedef typename allocator_type_::size_type size_type_; 00148 size_type_ m_count; 00149 size_type_ m_capacity; 00150 00151 float m_maxLoadFactor; 00152 00153 static const size_type_ s_maxElementCount = static_cast<size_type_>(-1) / sizeof(value_type_); 00154 // Make sure size_type is unsigned 00155 LEAN_STATIC_ASSERT(is_unsigned<size_type_>::value); 00156 // Reserve end element to allow for proper iteration termination 00157 static const size_type_ s_maxBucketCount = s_maxElementCount - 1U; 00158 // Keep one slot open at all times to simplify wrapped find loop termination 00159 static const size_type_ s_maxSize = s_maxBucketCount - 1U; 00160 static const size_type_ s_minSize = (32U < s_maxSize) ? 32U : s_maxSize; 00161 00163 LEAN_INLINE size_type_ buckets_from_capacity(size_type_ capacity) 00164 { 00165 LEAN_ASSERT(capacity <= s_maxSize); 00166 00167 float bucketHint = ceil(capacity / m_maxLoadFactor); 00168 00169 size_type_ bucketCount = (bucketHint >= s_maxBucketCount) 00170 ? s_maxBucketCount 00171 : static_cast<size_type_>(bucketHint); 00172 00173 // Keep one slot open at all times to simplify wrapped find loop termination conditions 00174 return max(bucketCount, capacity + 1U); 00175 } 00177 LEAN_INLINE size_type_ capacity_from_buckets(size_type_ buckets, size_type_ minCapacity) 00178 { 00179 LEAN_ASSERT(buckets <= s_maxBucketCount); 00180 LEAN_ASSERT(minCapacity <= s_maxSize); 00181 00182 // Keep one slot open at all times to simplify wrapped find loop termination conditions 00183 LEAN_ASSERT(minCapacity < buckets); 00184 00185 return max( 00186 // Keep one slot open at all times to simplify wrapped find loop termination conditions 00187 // -> Unsigned overflow handles buckets == 0 00188 min(static_cast<size_type_>(buckets * m_maxLoadFactor), buckets - 1U), 00189 // Guarantee minimum capacity 00190 minCapacity); 00191 } 00192 00194 LEAN_INLINE bool contains_element(const value_type_ *element) const 00195 { 00196 return (m_elements <= element) && (element < m_elementsEnd); 00197 } 00199 LEAN_INLINE bool contains_element(const value_type_ &element) const 00200 { 00201 return contains_element(lean::addressof(element)); 00202 } 00203 00205 static LEAN_INLINE void mark_end(value_type_ *dest) 00206 { 00207 new( const_cast<void*>(static_cast<const void*>(lean::addressof(dest->first))) ) Key(KeyValues::end_key); 00208 } 00210 static LEAN_INLINE void invalidate(value_type_ *dest) 00211 { 00212 new( const_cast<void*>(static_cast<const void*>(lean::addressof(dest->first))) ) Key(KeyValues::invalid_key); 00213 } 00215 static void invalidate(value_type_ *dest, value_type_ *destEnd) 00216 { 00217 value_type_ *destr = dest; 00218 00219 try 00220 { 00221 for (; dest != destEnd; ++dest) 00222 invalidate(dest); 00223 } 00224 catch (...) 00225 { 00226 destruct_keys(destr, dest); 00227 throw; 00228 } 00229 } 00231 static LEAN_INLINE void revalidate(value_type_ *dest) 00232 { 00233 destruct_key(dest); 00234 } 00235 00237 static LEAN_INLINE void destruct_key(value_type_ *destr) 00238 { 00239 if (!Policy::no_key_destruct) 00240 destr->first.~Key(); 00241 } 00243 static void destruct_keys(value_type_ *destr, value_type_ *destrEnd) 00244 { 00245 if (!Policy::no_key_destruct) 00246 for (; destr != destrEnd; ++destr) 00247 destruct_key(destr); 00248 } 00249 00253 class invalidate_guard : public noncopyable 00254 { 00255 private: 00256 value_type_ *m_dest; 00257 bool m_armed; 00258 00259 public: 00261 LEAN_INLINE explicit invalidate_guard(value_type_ *dest, bool armed = true) 00262 : m_dest(dest), 00263 m_armed(armed) { } 00265 LEAN_INLINE ~invalidate_guard() 00266 { 00267 if (m_armed) 00268 invalidate(m_dest); 00269 } 00271 LEAN_INLINE void disarm() { m_armed = false; } 00272 }; 00273 00277 class invalidate_n_guard : public noncopyable 00278 { 00279 private: 00280 value_type_ *m_dest; 00281 value_type_ *m_destEnd; 00282 bool m_armed; 00283 00284 public: 00286 LEAN_INLINE explicit invalidate_n_guard(value_type_ *dest, value_type_ *destEnd, bool armed = true) 00287 : m_dest(dest), 00288 m_destEnd(destEnd), 00289 m_armed(armed) { } 00291 LEAN_INLINE ~invalidate_n_guard() 00292 { 00293 if (m_armed) 00294 invalidate(m_dest, m_destEnd); 00295 } 00297 LEAN_INLINE void disarm() { m_armed = false; } 00298 }; 00299 00301 LEAN_INLINE void default_construct(value_type_ *dest, const Key &key) 00302 { 00303 invalidate_guard guard(dest); 00304 00305 revalidate(dest); 00306 m_allocator.construct(dest, value_type_(key, Element())); 00307 00308 guard.disarm(); 00309 } 00310 #ifndef LEAN0X_NO_RVALUE_REFERENCES 00311 00312 LEAN_INLINE void default_construct(value_type_ *dest, Key &&key) 00313 { 00314 invalidate_guard guard(dest); 00315 00316 revalidate(dest); 00317 m_allocator.construct(dest, value_type_(std::move(key), Element())); 00318 00319 guard.disarm(); 00320 } 00321 #endif 00322 00323 LEAN_INLINE void copy_construct(value_type_ *dest, const value_type_ &source) 00324 { 00325 invalidate_guard guard(dest); 00326 00327 revalidate(dest); 00328 m_allocator.construct(dest, source); 00329 00330 guard.disarm(); 00331 } 00333 LEAN_INLINE void move_construct(value_type_ *dest, value_type_ &source) 00334 { 00335 #ifndef LEAN0X_NO_RVALUE_REFERENCES 00336 invalidate_guard guard(dest); 00337 00338 revalidate(dest); 00339 m_allocator.construct(dest, std::move(source)); 00340 00341 guard.disarm(); 00342 #else 00343 copy_construct(dest, source); 00344 #endif 00345 } 00347 LEAN_INLINE void move(value_type_ *dest, value_type_ &source) 00348 { 00349 #ifndef LEAN0X_NO_RVALUE_REFERENCES 00350 const_cast<Key&>(dest->first) = std::move(const_cast<Key&>(source.first)); 00351 dest->second = std::move(source.second); 00352 #else 00353 const_cast<Key&>(dest->first) = const_cast<Key&>(source.first); 00354 dest->second = source.second; 00355 #endif 00356 } 00357 00359 LEAN_INLINE void destruct_element(value_type_ *destr) 00360 { 00361 if (!Policy::no_destruct) 00362 m_allocator.destroy(destr); 00363 } 00364 00366 void destruct(value_type_ *destr, value_type_ *destrEnd) 00367 { 00368 if (!Policy::no_destruct || !Policy::no_key_destruct) 00369 for (; destr != destrEnd; ++destr) 00370 if (key_valid(destr->first)) 00371 destruct_element(destr); 00372 else 00373 destruct_key(destr); 00374 } 00375 00377 void destruct_and_invalidate(value_type_ *destr, value_type_ *destrEnd) 00378 { 00379 // Elements invalidated (overwritten) by guard on exception 00380 invalidate_n_guard invalidateGuard(destr, destrEnd); 00381 00382 for (; destr != destrEnd; ++destr) 00383 if (key_valid(destr->first)) 00384 { 00385 // Don't handle exceptions explicitly, resources leaking anyways 00386 destruct_element(destr); 00387 invalidate(destr); 00388 } 00389 00390 // Everything has been invalidated correctly 00391 invalidateGuard.disarm(); 00392 } 00393 00395 LEAN_NOINLINE static void length_exceeded() 00396 { 00397 throw std::length_error("simple_hash_map<K, E> too long"); 00398 } 00400 LEAN_INLINE static void check_length(size_type_ count) 00401 { 00402 if (count > s_maxSize) 00403 length_exceeded(); 00404 } 00405 00407 LEAN_INLINE explicit simple_hash_map_base(float maxLoadFactor) 00408 : m_elements(nullptr), 00409 m_elementsEnd(nullptr), 00410 m_count(0), 00411 m_capacity(0), 00412 m_maxLoadFactor(maxLoadFactor) { } 00414 LEAN_INLINE simple_hash_map_base(float maxLoadFactor, const allocator_type_ &allocator) 00415 : m_allocator(allocator), 00416 m_elements(nullptr), 00417 m_elementsEnd(nullptr), 00418 m_count(0), 00419 m_capacity(0), 00420 m_maxLoadFactor(maxLoadFactor) { } 00422 LEAN_INLINE simple_hash_map_base(const simple_hash_map_base &right) 00423 : m_allocator(right.m_allocator), 00424 m_elements(nullptr), 00425 m_elementsEnd(nullptr), 00426 m_count(0), 00427 m_capacity(0), 00428 m_maxLoadFactor(right.m_maxLoadFactor) { } 00429 #ifndef LEAN0X_NO_RVALUE_REFERENCES 00430 00431 LEAN_INLINE simple_hash_map_base(simple_hash_map_base &&right) 00432 : m_allocator(std::move(right.m_allocator)), 00433 m_elements(std::move(right.m_elements)), 00434 m_elementsEnd(std::move(right.m_elementsEnd)), 00435 m_count(std::move(right.m_count)), 00436 m_capacity(std::move(right.m_capacity)), 00437 m_maxLoadFactor(std::move(right.m_maxLoadFactor)) { } 00438 #endif 00439 00441 LEAN_INLINE simple_hash_map_base& operator =(const simple_hash_map_base&) { return *this; } 00442 #ifndef LEAN0X_NO_RVALUE_REFERENCES 00443 00444 LEAN_INLINE simple_hash_map_base& operator =(simple_hash_map_base&&) { return *this; } 00445 #endif 00446 00448 LEAN_INLINE static bool key_valid(const Key &key) { return KeyValues::is_valid(key); } 00449 00451 LEAN_INLINE void swap(simple_hash_map_base &right) throw() 00452 { 00453 using std::swap; 00454 00455 swap(m_allocator, right.m_allocator); 00456 swap(m_elements, right.m_elements); 00457 swap(m_elementsEnd, right.m_elementsEnd); 00458 swap(m_count, right.m_count); 00459 swap(m_capacity, right.m_capacity); 00460 swap(m_maxLoadFactor, right.m_maxLoadFactor); 00461 } 00462 }; 00463 00464 } 00465 00467 template < class Key, class Element, 00468 class Policy = simple_hash_map_policies::nonpod, 00469 class Hash = hash<Key>, 00470 class KeyValues = default_keys<Key>, 00471 class Pred = std::equal_to<Key>, 00472 class Allocator = std::allocator<Element> > 00473 class simple_hash_map : private impl::simple_hash_map_base<Key, Element, Policy, KeyValues, Allocator> 00474 { 00475 private: 00476 typedef impl::simple_hash_map_base<Key, Element, Policy, KeyValues, Allocator> base_type; 00477 00478 typedef Hash hasher_; 00479 hasher_ m_hasher; 00480 typedef Pred key_equal_; 00481 key_equal_ m_keyEqual; 00482 00484 void reallocate(size_type_ newBucketCount, size_type_ minCapacity = 0U) 00485 { 00486 // Make prime (required for universal modulo hashing) 00487 newBucketCount = impl::next_prime_capacity(newBucketCount, s_maxBucketCount); 00488 00489 // Guarantee minimum capacity 00490 // ASSERT: One slot always remains open, automatically terminating find loops 00491 if (newBucketCount <= minCapacity) 00492 length_exceeded(); 00493 00494 // Use end element to allow for proper iteration termination 00495 const size_type_ newElementCount = newBucketCount + 1U; 00496 00497 value_type_ *newElements = m_allocator.allocate(newElementCount); 00498 value_type_ *newElementsEnd = newElements + newBucketCount; 00499 00500 try 00501 { 00502 // ASSERT: End element key always valid to allow for proper iteration termination 00503 mark_end(newElementsEnd); 00504 00505 try 00506 { 00507 invalidate(newElements, newElementsEnd); 00508 } 00509 catch(...) 00510 { 00511 destruct_key(newElementsEnd); 00512 throw; 00513 } 00514 00515 if (!empty()) 00516 try 00517 { 00518 // ASSERT: One slot always remains open, automatically terminating find loops 00519 LEAN_ASSERT(size() < newBucketCount); 00520 00521 for (value_type_ *element = m_elements; element != m_elementsEnd; ++element) 00522 if (base_type::key_valid(element->first)) 00523 move_construct( 00524 locate_element(element->first, newElements, newElementsEnd, newBucketCount).second, 00525 *element ); 00526 } 00527 catch(...) 00528 { 00529 destruct(newElements, newElementsEnd); 00530 destruct_key(newElementsEnd); 00531 throw; 00532 } 00533 } 00534 catch(...) 00535 { 00536 m_allocator.deallocate(newElements, newElementCount); 00537 throw; 00538 } 00539 00540 value_type_ *oldElements = m_elements; 00541 value_type_ *oldElementsEnd = m_elementsEnd; 00542 const size_type_ oldBucketCount = bucket_count(); 00543 00544 m_elements = newElements; 00545 m_elementsEnd = newElementsEnd; 00546 m_capacity = capacity_from_buckets(newBucketCount, minCapacity); 00547 00548 if (oldElements) 00549 free(oldElements, oldElementsEnd, oldBucketCount + 1U); 00550 } 00551 00553 LEAN_INLINE void free() 00554 { 00555 if (m_elements) 00556 free(m_elements, m_elementsEnd, bucket_count() + 1U); 00557 } 00559 LEAN_INLINE void free(value_type_ *elements, value_type_ *elementsEnd, size_type_ elementCount) 00560 { 00561 // ASSERT: End element key always valid to allow for proper iteration termination 00562 00563 // Do nothing on exception, resources leaking anyways! 00564 destruct(elements, elementsEnd); 00565 destruct_key(elementsEnd); 00566 m_allocator.deallocate(elements, elementCount); 00567 } 00568 00570 LEAN_INLINE value_type_* first_element(const Key &key) const 00571 { 00572 return first_element(key, m_elements, bucket_count()); 00573 } 00575 LEAN_INLINE value_type_* first_element(const Key &key, value_type_ *elements, size_type_ bucketCount) const 00576 { 00577 return elements + m_hasher(key) % bucketCount; 00578 } 00580 LEAN_INLINE std::pair<bool, value_type_*> locate_element(const Key &key) const 00581 { 00582 return locate_element(key, m_elements, m_elementsEnd, bucket_count()); 00583 } 00585 LEAN_INLINE std::pair<bool, value_type_*> locate_element(const Key &key, value_type_ *elements, value_type_ *elementsEnd, size_type_ bucketCount) const 00586 { 00587 LEAN_ASSERT(base_type::key_valid(key)); 00588 00589 value_type_ *element = first_element(key, elements, bucketCount); 00590 00591 while (base_type::key_valid(element->first)) 00592 { 00593 if (m_keyEqual(element->first, key)) 00594 return std::make_pair(false, element); 00595 00596 // Wrap around 00597 if (++element == elementsEnd) 00598 element = elements; 00599 00600 // ASSERT: One slot always remains open, automatically terminating this loop 00601 } 00602 00603 return std::make_pair(true, element); 00604 } 00606 LEAN_INLINE value_type_* find_element(const Key &key) const 00607 { 00608 value_type_ *element = first_element(key); 00609 00610 while (base_type::key_valid(element->first)) 00611 { 00612 if (m_keyEqual(element->first, key)) 00613 return element; 00614 00615 // Wrap around 00616 if (++element == m_elementsEnd) 00617 element = m_elements; 00618 00619 // ASSERT: One slot always remains open, automatically terminating this loop 00620 } 00621 00622 return m_elementsEnd; 00623 } 00625 LEAN_INLINE void remove_element(value_type_ *element) 00626 { 00627 // If anything goes wrong, we won't be able to fix it 00628 terminate_guard terminateGuard; 00629 00630 value_type_ *hole = element; 00631 00632 // Wrap around 00633 if (++element == m_elementsEnd) 00634 element = m_elements; 00635 00636 // Find next empty position 00637 while (base_type::key_valid(element->first)) 00638 { 00639 value_type_ *auxElement = first_element(element->first); 00640 00641 bool tooLate = (auxElement <= hole); 00642 bool tooEarly = (element < auxElement); 00643 bool wrong = (hole <= element) ? (tooLate || tooEarly) : (tooLate && tooEarly); 00644 00645 // Move wrongly positioned elements into hole 00646 if (wrong) 00647 { 00648 move(hole, *element); 00649 hole = element; 00650 } 00651 00652 // Wrap around 00653 if (++element == m_elementsEnd) 00654 element = m_elements; 00655 00656 // ASSERT: One slot always remains open, automatically terminating this loop 00657 } 00658 00659 destruct_element(hole); 00660 invalidate(hole); 00661 --m_count; 00662 00663 terminateGuard.disarm(); 00664 } 00666 LEAN_INLINE void copy_elements_to_empty(const value_type_ *elements, const value_type_ *elementsEnd) 00667 { 00668 LEAN_ASSERT(empty()); 00669 00670 for (const value_type *element = elements; element != elementsEnd; ++element) 00671 if (base_type::key_valid(element->first)) 00672 { 00673 copy_construct( 00674 locate_element(element->first).second, 00675 *element ); 00676 ++m_count; 00677 } 00678 } 00679 00681 LEAN_INLINE void growTo(size_type_ newCount, bool checkLength = true) 00682 { 00683 // Mind overflow 00684 if (checkLength) 00685 check_length(newCount); 00686 00687 reallocate(buckets_from_capacity(next_capacity_hint(newCount)), newCount); 00688 } 00690 LEAN_INLINE void grow(size_type_ count) 00691 { 00692 size_type_ oldSize = size(); 00693 00694 // Mind overflow 00695 if (count > s_maxSize || s_maxSize - count < oldSize) 00696 length_exceeded(); 00697 00698 growTo(oldSize + count, false); 00699 } 00701 LEAN_NOINLINE void growToHL(size_type_ newCount) 00702 { 00703 growTo(newCount); 00704 } 00706 LEAN_NOINLINE void growHL(size_type_ count) 00707 { 00708 grow(count); 00709 } 00710 00711 public: 00713 typedef Policy construction_policy; 00714 00716 typedef allocator_type_ allocator_type; 00718 typedef size_type_ size_type; 00720 typedef typename allocator_type::difference_type difference_type; 00721 00723 typedef typename allocator_type::pointer pointer; 00725 typedef typename allocator_type::const_pointer const_pointer; 00727 typedef typename allocator_type::reference reference; 00729 typedef typename allocator_type::const_reference const_reference; 00731 typedef typename allocator_type::value_type value_type; 00733 typedef Key key_type; 00735 typedef Element mapped_type; 00736 00738 template <class Element> 00739 class basic_iterator 00740 { 00741 friend class simple_hash_map; 00742 00743 private: 00744 Element *m_element; 00745 00747 enum search_first_valid_t 00748 { 00750 search_first_valid 00751 }; 00752 00754 LEAN_INLINE basic_iterator(Element *element) 00755 : m_element(element) { } 00757 LEAN_INLINE basic_iterator(Element *element, search_first_valid_t) 00758 : m_element( 00759 (element && !base_type::key_valid(element->first)) 00760 ? (++basic_iterator(element)).m_element 00761 : element 00762 ) { } 00763 00764 public: 00766 typedef std::forward_iterator_tag iterator_category; 00768 typedef typename simple_hash_map::difference_type difference_type; 00770 typedef Element value_type; 00772 typedef value_type& reference; 00774 typedef value_type* pointer; 00775 00777 LEAN_INLINE reference operator *() const 00778 { 00779 return *m_element; 00780 } 00782 LEAN_INLINE pointer operator ->() const 00783 { 00784 return m_element; 00785 } 00786 00788 LEAN_INLINE basic_iterator& operator ++() 00789 { 00790 do 00791 { 00792 ++m_element; 00793 } 00794 // ASSERT: End element key is always valid 00795 while (!base_type::key_valid(m_element->first)); 00796 00797 return *this; 00798 } 00800 LEAN_INLINE basic_iterator operator ++(int) 00801 { 00802 return ++basic_iterator(*this); 00803 } 00804 00806 LEAN_INLINE bool operator ==(const basic_iterator &right) const 00807 { 00808 return (m_element == right.m_element); 00809 } 00811 LEAN_INLINE bool operator !=(const basic_iterator &right) const 00812 { 00813 return (m_element != right.m_element); 00814 } 00815 }; 00816 00818 typedef basic_iterator<value_type> iterator; 00820 typedef basic_iterator<const value_type> const_iterator; 00822 typedef iterator local_iterator; 00824 typedef const_iterator const_local_iterator; 00825 00827 typedef hasher_ hasher; 00829 typedef key_equal_ key_equal; 00830 00832 simple_hash_map() 00833 : base_type(0.75f) 00834 { 00835 LEAN_ASSERT(key_valid(KeyValues::end_key)); 00836 } 00838 explicit simple_hash_map(size_type capacity, float maxLoadFactor = 0.75f) 00839 : base_type(maxLoadFactor) 00840 { 00841 LEAN_ASSERT(key_valid(KeyValues::end_key)); 00842 growTo(capacity); 00843 } 00845 simple_hash_map(size_type capacity, float maxLoadFactor, const hasher& hash) 00846 : base_type(maxLoadFactor), 00847 m_hasher(hash) 00848 { 00849 LEAN_ASSERT(key_valid(KeyValues::end_key)); 00850 growTo(capacity); 00851 } 00853 simple_hash_map(size_type capacity, float maxLoadFactor, const hasher& hash, const key_equal& keyComp) 00854 : base_type(maxLoadFactor), 00855 m_hasher(hash), 00856 m_keyEqual(keyComp) 00857 { 00858 LEAN_ASSERT(key_valid(KeyValues::end_key)); 00859 growTo(capacity); 00860 } 00862 simple_hash_map(size_type capacity, float maxLoadFactor, const hasher& hash, const key_equal& keyComp, const allocator_type &allocator) 00863 : base_type(maxLoadFactor, allocator), 00864 m_hasher(hash), 00865 m_keyEqual(keyComp) 00866 { 00867 LEAN_ASSERT(key_valid(KeyValues::end_key)); 00868 growTo(capacity); 00869 } 00871 simple_hash_map(const simple_hash_map &right) 00872 : base_type(right), 00873 m_hasher(right.m_hasher), 00874 m_keyEqual(right.m_keyEqual) 00875 { 00876 if (!right.empty()) 00877 { 00878 growTo(right.size()); 00879 copy_elements_to_empty(right.m_elements, right.m_elementsEnd); 00880 } 00881 } 00882 #ifndef LEAN0X_NO_RVALUE_REFERENCES 00883 00884 simple_hash_map(simple_hash_map &&right) 00885 : base_type(std::move(right)), 00886 m_hasher(std::move(right.m_hasher)), 00887 m_keyEqual(std::move(right.m_keyEqual)) 00888 { 00889 right.m_elements = nullptr; 00890 right.m_elementsEnd = nullptr; 00891 right.m_count = 0; 00892 right.m_capacity = 0; 00893 } 00894 #endif 00895 00896 ~simple_hash_map() 00897 { 00898 free(); 00899 } 00900 00902 simple_hash_map& operator =(const simple_hash_map &right) 00903 { 00904 if (&right != this) 00905 { 00906 // Clear before reallocation to prevent full-range moves 00907 clear(); 00908 00909 if (!right.empty()) 00910 { 00911 if (right.size() > capacity()) 00912 growToHL(right.size()); 00913 00914 copy_elements_to_empty(right.m_elements, right.m_elementsEnd); 00915 } 00916 } 00917 return *this; 00918 } 00919 #ifndef LEAN0X_NO_RVALUE_REFERENCES 00920 00921 simple_hash_map& operator =(simple_hash_map &&right) 00922 { 00923 if (&right != this) 00924 { 00925 free(); 00926 00927 m_elements = std::move(right.m_elements); 00928 m_elementsEnd = std::move(right.m_elementsEnd); 00929 00930 right.m_elements = nullptr; 00931 right.m_elementsEnd = nullptr; 00932 00933 m_allocator = std::move(right.m_allocator); 00934 } 00935 return *this; 00936 } 00937 #endif 00938 00941 LEAN_INLINE reference insert(const key_type &key) 00942 { 00943 LEAN_ASSERT(base_type::key_valid(key)); 00944 00945 if (m_count == capacity()) 00946 growHL(1); 00947 00948 std::pair<bool, value_type*> element = locate_element(key); 00949 00950 if (element.first) 00951 { 00952 default_construct(element.second, key); 00953 ++m_count; 00954 } 00955 return *element.second; 00956 } 00957 #ifndef LEAN0X_NO_RVALUE_REFERENCES 00958 00959 00960 LEAN_INLINE reference insert(key_type &&key) 00961 { 00962 LEAN_ASSERT(base_type::key_valid(key)); 00963 00964 if (m_count == capacity()) 00965 growHL(1); 00966 00967 std::pair<bool, value_type*> element = locate_element(key); 00968 00969 if (element.first) 00970 { 00971 default_construct(element.second, std::move(key)); 00972 ++m_count; 00973 } 00974 return *element.second; 00975 } 00976 #endif 00977 00978 LEAN_INLINE std::pair<iterator, bool> insert(const value_type &value) 00979 { 00980 LEAN_ASSERT(base_type::key_valid(value.first)); 00981 00982 if (m_count == capacity()) 00983 { 00984 if (contains_element(value)) 00985 return std::make_pair(iterator(const_cast<value_type*>(lean::addressof(value))), false); 00986 00987 growHL(1); 00988 } 00989 00990 std::pair<bool, value_type*> element = locate_element(value.first); 00991 00992 if (element.first) 00993 { 00994 copy_construct(element.second, value); 00995 ++m_count; 00996 } 00997 return std::make_pair(iterator(element.second), element.first); 00998 } 00999 #ifndef LEAN0X_NO_RVALUE_REFERENCES 01000 01001 LEAN_INLINE std::pair<iterator, bool> insert(value_type &&value) // wrong way round 01002 { 01003 LEAN_ASSERT(base_type::key_valid(value.first)); 01004 01005 if (m_count == capacity()) 01006 { 01007 if (contains_element(value)) 01008 return std::make_pair(iterator(lean::addressof(value)), false); 01009 01010 growHL(1); 01011 } 01012 01013 std::pair<bool, value_type*> element = locate_element(value.first); 01014 01015 if (element.first) 01016 { 01017 move_construct(element.second, value); 01018 ++m_count; 01019 } 01020 return std::make_pair(iterator(element.second), element.first); 01021 } 01022 #endif 01023 01024 LEAN_INLINE size_type erase(const key_type &key) 01025 { 01026 // Explicitly handle unallocated state 01027 value_type* element = (!empty()) 01028 ? find_element(key) 01029 : m_elementsEnd; 01030 01031 if (element != m_elementsEnd) 01032 { 01033 remove_element(element); 01034 return 1; 01035 } 01036 else 01037 return 0; 01038 } 01040 LEAN_INLINE iterator erase(iterator where) 01041 { 01042 LEAN_ASSERT(contains_element(where.m_element)); 01043 01044 remove_element(where.m_element); 01045 return iterator(where.m_element, iterator::search_first_valid); 01046 } 01047 01049 LEAN_INLINE void clear() 01050 { 01051 m_count = 0; 01052 destruct_and_invalidate(m_elements, m_elementsEnd); 01053 } 01054 01056 LEAN_INLINE void reserve(size_type newCapacity) 01057 { 01058 // Mind overflow 01059 check_length(newCapacity); 01060 01061 if (newCapacity > capacity()) 01062 reallocate(buckets_from_capacity(newCapacity), newCapacity); 01063 } 01066 LEAN_INLINE void rehash(size_type newCapacity) 01067 { 01068 newCapacity = max(size(), newCapacity); 01069 01070 // Mind overflow 01071 check_length(newCapacity); 01072 01073 if (newCapacity != capacity()) 01074 reallocate(buckets_from_capacity(newCapacity), newCapacity); 01075 } 01076 01078 LEAN_INLINE iterator find(const key_type &key) { return (!empty()) ? iterator(find_element(key)) : end(); } 01080 LEAN_INLINE const_iterator find(const key_type &key) const { return (!empty()) ? const_iterator(find_element(key)) : end(); } 01081 01083 LEAN_INLINE mapped_type& operator [](const key_type &key) { return insert(key).second; } 01084 #ifndef LEAN0X_NO_RVALUE_REFERENCES 01085 01086 LEAN_INLINE mapped_type& operator [](key_type &&key) { return insert(std::move(key)).second; } 01087 #endif 01088 01090 LEAN_INLINE iterator begin(void) { return iterator(m_elements, iterator::search_first_valid); } 01092 LEAN_INLINE const_iterator begin(void) const { return const_iterator(m_elements, const_iterator::search_first_valid); } 01094 LEAN_INLINE iterator end(void) { return iterator(m_elementsEnd); } 01096 LEAN_INLINE const_iterator end(void) const { return const_iterator(m_elementsEnd); } 01097 01099 LEAN_INLINE allocator_type get_allocator() const { return m_allocator; }; 01100 01102 LEAN_INLINE bool key_valid(const key_type &key) const { return base_type::key_valid(key); } 01103 01105 LEAN_INLINE bool empty(void) const { return (m_count == 0); }; 01107 LEAN_INLINE size_type size(void) const { return m_count; }; 01109 LEAN_INLINE size_type capacity(void) const { return m_capacity; }; 01111 LEAN_INLINE size_type bucket_count() const { return m_elementsEnd - m_elements; } 01112 01114 LEAN_INLINE float max_load_factor() const { return m_maxLoadFactor; } 01116 void max_load_factor(float factor) 01117 { 01118 m_maxLoadFactor = factor; 01119 01120 // Make sure capacity never goes below the number of elements currently stored 01121 // -> Capacity equal count will result in reallocation on next element insertion 01122 m_capacity = capacity_from_buckets(bucket_count(), size()); 01123 } 01124 01126 LEAN_INLINE float load_factor() const { return static_cast<float>(m_count) / static_cast<float>(m_capacity); }; 01127 01129 size_type next_capacity_hint(size_type count) const 01130 { 01131 size_type oldCapacity = capacity(); 01132 LEAN_ASSERT(oldCapacity <= s_maxSize); 01133 01134 // Try to double capacity (mind overflow) 01135 size_type newCapacity = (s_maxSize - oldCapacity < oldCapacity) 01136 ? 0 01137 : oldCapacity + oldCapacity; 01138 01139 if (newCapacity < count) 01140 newCapacity = count; 01141 01142 if (newCapacity < s_minSize) 01143 newCapacity = s_minSize; 01144 01145 return newCapacity; 01146 } 01147 01149 LEAN_INLINE void swap(simple_hash_map &right) throw() 01150 { 01151 using std::swap; 01152 01153 swap(m_keyEqual, right.m_keyEqual); 01154 swap(m_hasher, right.m_hasher); 01155 base_type::swap(right); 01156 } 01158 LEAN_INLINE size_type max_size() const 01159 { 01160 return s_maxSize; 01161 } 01162 }; 01163 01165 template <class Element, class Policy, class Allocator> 01166 LEAN_INLINE void swap(simple_hash_map<Element, Policy, Allocator> &left, simple_hash_map<Element, Policy, Allocator> &right) 01167 { 01168 left.swap(right); 01169 } 01170 01171 } // namespace 01172 01173 namespace simple_hash_map_policies = containers::simple_hash_map_policies; 01174 using containers::simple_hash_map; 01175 01176 } // namespace 01177 01178 #ifdef LEAN_INCLUDE_LINKED 01179 #include "source/simple_hash_map.cpp" 01180 #endif 01181 01182 #endif