lean cpp library
A lean C++ library providing efficient utility classes for high-performance C++ applications.
simple_hash_map.h
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