From 6c267d6388ff0cc4c4f75fcdebdc85a1bcd5f4c7 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Wed, 4 Sep 2013 07:25:23 -0700 Subject: [PATCH] Add HashMap unit test --- .../Builds/VisualStudio2012/beast.vcxproj | 6 + .../VisualStudio2012/beast.vcxproj.filters | 3 + .../beast/modules/beast_core/beast_core.cpp | 1 + .../modules/beast_core/containers/HashMap.cpp | 149 ++++++++++++++++++ .../modules/beast_core/containers/HashMap.h | 77 +++++---- .../modules/beast_core/containers/List.h | 3 +- .../beast_core/containers/detail/copyconst.h | 8 +- .../diagnostic/beast_UnitTestUtilities.h | 12 +- 8 files changed, 220 insertions(+), 39 deletions(-) create mode 100644 Subtrees/beast/modules/beast_core/containers/HashMap.cpp diff --git a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj index c047fa6711..a43e84be8e 100644 --- a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj +++ b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj @@ -478,6 +478,12 @@ true true + + true + true + true + true + true true diff --git a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters index 5973783fcd..ba2e38a656 100644 --- a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters +++ b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters @@ -1465,6 +1465,9 @@ beast_core\containers + + beast_core\containers + diff --git a/Subtrees/beast/modules/beast_core/beast_core.cpp b/Subtrees/beast/modules/beast_core/beast_core.cpp index 82944cfda2..aae18a2485 100644 --- a/Subtrees/beast/modules/beast_core/beast_core.cpp +++ b/Subtrees/beast/modules/beast_core/beast_core.cpp @@ -145,6 +145,7 @@ namespace beast #include "containers/beast_Variant.cpp" #include "containers/DynamicArray.cpp" #include "containers/DynamicList.cpp" +#include "containers/HashMap.cpp" #include "diagnostic/beast_Debug.cpp" #include "diagnostic/beast_Error.cpp" diff --git a/Subtrees/beast/modules/beast_core/containers/HashMap.cpp b/Subtrees/beast/modules/beast_core/containers/HashMap.cpp new file mode 100644 index 0000000000..b4e4b629be --- /dev/null +++ b/Subtrees/beast/modules/beast_core/containers/HashMap.cpp @@ -0,0 +1,149 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +class HashMapTests : public UnitTest +{ +public: + enum + { + numberOfItems = 100 * 1000 + }; + + template + class TestTraits + { + public: + struct Value + { + int unused; + }; + + struct Key + { + class Equal + { + public: + bool operator() (Key const& lhs, Key const& rhs) const noexcept + { + return memcmp (lhs.data, rhs.data, keyBytes) == 0; + } + }; + + // stateful hardened hash + class Hash + { + public: + explicit Hash (HashValue seedToUse = Random::getSystemRandom ().nextInt ()) + : m_seed (seedToUse) + { + } + + HashValue generateHash (Key const& key) const noexcept + { + HashValue hash; + Murmur::Hash (key.data, keyBytes, m_seed, &hash); + return hash; + } + + private: + HashValue m_seed; + }; + + /* + Key () + : std::memset (data, 0, keyBytes) + { + } + */ + + uint8 data [keyBytes]; + }; + + typedef Key key_type; + typedef Value value_type; + typedef typename Key::Hash hasher; + typedef typename Key::Equal key_equal; + typedef std::size_t size_type; + + TestTraits (size_type const numberOfKeys, Random& random) + { + // need to static_bassert keyBytes can represent numberOfKeys. Log base 256 or something? + + m_keys.reserve (numberOfKeys); + m_shuffled_keys.reserve (numberOfKeys); + for (size_type i = 0; i < numberOfKeys; ++i) + { + // VFALCO NOTE std::vector is garbage..want to emplace_back() here + Key key; + memset (key.data, 0, sizeof (key.data)); + memcpy (& key.data [0], &i, std::min (sizeof (key.data), sizeof (i))); + m_keys.push_back (key); + m_shuffled_keys.push_back (&m_keys [i]); + } + + UnitTestUtilities::repeatableShuffle (numberOfKeys, m_shuffled_keys, random); + } + + Key const& getKey (size_type index) const noexcept + { + return *m_shuffled_keys [index]; + } + + private: + std::vector m_keys; + std::vector m_shuffled_keys; + }; + + template + void testInsert (std::size_t numberOfKeys, Random& random) + { + beginTestCase (String + ("insertion, numberOfKeys = ") + String::fromNumber (numberOfKeys) + + ", keyBytes = " + String::fromNumber (keyBytes)); + + typedef TestTraits Traits; + Traits traits (numberOfKeys, random); + + typedef HashMap < + typename Traits::key_type, + typename Traits::value_type, + typename Traits::hasher, + typename Traits::key_equal> Map; + Map map; + + for (std::size_t i = 0; i < numberOfKeys; ++i) + map.insert (traits.getKey (i)); + + this->logMessage ("load_factor = " + String::fromNumber (map.load_factor ())); + } + + void runTest () + { + int64 const seedValue = 072472; + Random random (seedValue); + testInsert <4> (numberOfItems, random); + testInsert <20> (numberOfItems, random); + } + + HashMapTests () : UnitTest ("HashMap", "beast") + { + } +}; + +static HashMapTests hashMapTests; diff --git a/Subtrees/beast/modules/beast_core/containers/HashMap.h b/Subtrees/beast/modules/beast_core/containers/HashMap.h index 3cfb17fcbc..95dd1f4dcf 100644 --- a/Subtrees/beast/modules/beast_core/containers/HashMap.h +++ b/Subtrees/beast/modules/beast_core/containers/HashMap.h @@ -100,6 +100,8 @@ private: namespace detail { +struct BucketTag { }; + template class HashMapLocalIterator : public std::iterator @@ -194,7 +196,7 @@ private: typedef detail::ListIterator ::Node>::type> bucket_iterator; typedef detail::ListIterator ::Node>::type> item_iterator; + typename List ::Node>::type> item_iterator; public: typedef typename M::Pair value_type; @@ -202,15 +204,36 @@ public: typedef value_type& reference; typedef typename M::size_type size_type; - HashMapIterator (M* map = nullptr, - bucket_iterator bucket = bucket_iterator (), - item_iterator local = item_iterator ()) + HashMapIterator () + : m_map (nullptr) + , m_bucket (bucket_iterator ()) + , m_local (item_iterator ()) + { + } + + // represents end() + explicit HashMapIterator (M* map) + : m_map (map) + , m_bucket (bucket_iterator ()) + , m_local (item_iterator ()) + { + } + + HashMapIterator (M* map, bucket_iterator const& bucket, item_iterator const& local) : m_map (map) , m_bucket (bucket) , m_local (local) { } +#if 0 + HashMapIterator (HashMapIterator const& other) noexcept + : m_map (other.m_map) + , m_bucket (other.m_bucket) + , m_local (other.m_local) + { + } + template HashMapIterator (HashMapIterator const& other) noexcept : m_map (other.m_map) @@ -218,7 +241,7 @@ public: , m_local (other.m_local) { } - +#endif template HashMapIterator& operator= (HashMapIterator const& other) noexcept { @@ -359,7 +382,7 @@ private: return items.empty (); } - List items; + List items; private: Bucket& operator= (Bucket const&); @@ -369,7 +392,7 @@ private: // Every item in the map is in one linked list struct Item : List ::Node - , List ::Node + , List ::Node { Item (Pair const& pair_) : m_pair (pair_) @@ -403,17 +426,17 @@ public: typedef value_type& reference; typedef value_type const* const_pointer; typedef value_type const& const_reference; + + typedef HashMap container_type; - typedef detail::HashMapIterator > iterator; - typedef detail::HashMapIterator const> const_iterator; + typedef detail::HashMapIterator iterator; + typedef detail::HashMapIterator const_iterator; - typedef detail::HashMapLocalIterator < - HashMap , - typename List ::iterator> local_iterator; + typedef detail::HashMapLocalIterator ::iterator> local_iterator; - typedef detail::HashMapLocalIterator < - HashMap const, - typename List ::const_iterator> const_local_iterator; + typedef detail::HashMapLocalIterator ::const_iterator> const_local_iterator; //-------------------------------------------------------------------------- @@ -514,17 +537,17 @@ public: iterator end () noexcept { - return iterator (this, m_bucketlist.end ()); + return iterator (static_cast (this)); } const_iterator end () const noexcept { - return const_iterator (this, m_bucketlist.end ()); + return const_iterator (this); } const_iterator cend () const noexcept { - return const_iterator (this, m_bucketlist.cend ()); + return const_iterator (this); } //-------------------------------------------------------------------------- @@ -601,10 +624,10 @@ public: { size_type found (0); Bucket& b (m_buckets [bucket (key)]); - for (typename List ::iterator iter (b.items.begin ()); + for (typename List ::iterator iter (b.items.begin ()); iter != b.items.end ();) { - typename List ::iterator cur (iter++); + typename List ::iterator cur (iter++); if (m_equal (cur->pair ().key (), key)) { erase (b, cur); @@ -641,7 +664,7 @@ public: { size_type n = 0; Bucket const& b (m_buckets [bucket (key)]); - for (typename List ::iterator iter = b.items.begin (); + for (typename List ::iterator iter = b.items.begin (); iter != b.items.end (); ++iter) if (m_equal (iter->key (), key)) ++n; @@ -765,16 +788,16 @@ private: void grow_buckets () { - float const scale = 1.f + (float (percentageIncrease) / 100.f); - size_type const count (std::ceil ( - (size () / max_load_factor ()) * scale)); + double const scale = 1. + (double (percentageIncrease) / 100.); + size_type const count (size_type (std::ceil ( + (double (size ()) / double (max_load_factor ())) * scale))); rehash (count); } iterator find (KeyParam key, size_type n) noexcept { Bucket& b (m_buckets [n]); - for (typename List ::iterator iter = + for (typename List ::iterator iter = b.items.begin (); iter != b.items.end (); ++iter) if (m_equal (iter->pair ().key (), key)) return iterator (this, m_bucketlist.iterator_to (b), iter); @@ -784,7 +807,7 @@ private: const_iterator find (KeyParam key, size_type n) const noexcept { Bucket const& b (m_buckets [n]); - for (typename List ::const_iterator iter = + for (typename List ::const_iterator iter = b.items.begin (); iter != b.items.end (); ++iter) if (m_equal (iter->pair ().key (), key)) return const_iterator (this, @@ -805,7 +828,7 @@ private: b.items.begin ()); } - void erase (Bucket& b, typename List ::iterator pos) + void erase (Bucket& b, typename List ::iterator pos) { Item& item (*pos); b.items.erase (b.items.iterator_to (item)); diff --git a/Subtrees/beast/modules/beast_core/containers/List.h b/Subtrees/beast/modules/beast_core/containers/List.h index 0d96e61d44..2a125ff7da 100644 --- a/Subtrees/beast/modules/beast_core/containers/List.h +++ b/Subtrees/beast/modules/beast_core/containers/List.h @@ -236,13 +236,14 @@ public: : m_node (node) { } -#if 0 + template ListIterator (ListIterator const& other) noexcept : m_node (other.m_node) { } +#if 0 template ListIterator& operator= (ListIterator const& other) noexcept { diff --git a/Subtrees/beast/modules/beast_core/containers/detail/copyconst.h b/Subtrees/beast/modules/beast_core/containers/detail/copyconst.h index 6b8fc502d2..ac8d74d5c0 100644 --- a/Subtrees/beast/modules/beast_core/containers/detail/copyconst.h +++ b/Subtrees/beast/modules/beast_core/containers/detail/copyconst.h @@ -33,13 +33,7 @@ struct copyconst template struct copyconst { - typedef U const type; -}; - -template -struct copyconst -{ - typedef U type; + typedef typename removecv ::type const type; }; } diff --git a/Subtrees/beast/modules/beast_core/diagnostic/beast_UnitTestUtilities.h b/Subtrees/beast/modules/beast_core/diagnostic/beast_UnitTestUtilities.h index 6f8234b483..2e2df5d962 100644 --- a/Subtrees/beast/modules/beast_core/diagnostic/beast_UnitTestUtilities.h +++ b/Subtrees/beast/modules/beast_core/diagnostic/beast_UnitTestUtilities.h @@ -26,18 +26,22 @@ namespace UnitTestUtilities /** Fairly shuffle an array pseudo-randomly. */ template -void repeatableShuffle (int const numberOfItems, T& arrayOfItems, int64 seedValue) +void repeatableShuffle (int const numberOfItems, T& arrayOfItems, Random& r) { - Random r (seedValue); - for (int i = numberOfItems - 1; i > 0; --i) { int const choice = r.nextInt (i + 1); - std::swap (arrayOfItems [i], arrayOfItems [choice]); } } +template +void repeatableShuffle (int const numberOfItems, T& arrayOfItems, int64 seedValue) +{ + Random r (seedValue); + repeatableShuffle (numberOfItems, arrayOfItems, r); +} + //------------------------------------------------------------------------------ /** A block of memory used for test data.