From de2c4cc7b841467eb8b3a35677f5edbaa544b3cd Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Sun, 1 Sep 2013 16:09:07 -0700 Subject: [PATCH] Added DynamicArray, DynamicList, and HashMap --- Builds/VisualStudio2012/beast.vcxproj | 21 +- Builds/VisualStudio2012/beast.vcxproj.filters | 33 +- modules/beast_core/beast_core.cpp | 2 + modules/beast_core/beast_core.h | 9 +- .../beast_core/containers/DynamicArray.cpp | 171 ++++ modules/beast_core/containers/DynamicArray.h | 728 +++++++++++++++ modules/beast_core/containers/DynamicList.cpp | 70 ++ modules/beast_core/containers/DynamicList.h | 452 ++++++++++ modules/beast_core/containers/HashMap.h | 833 ++++++++++++++++++ .../containers/{beast_List.h => List.h} | 480 +++++----- modules/beast_core/containers/beast_HashMap.h | 487 ---------- .../beast_core/containers/detail/copyconst.h | 47 + .../beast_core/containers/detail/removecv.h | 73 ++ modules/beast_core/memory/beast_HeapBlock.h | 9 +- .../beast_core/thread/detail/TrackedMutex.h | 4 - .../beast_crypto/math/beast_UnsignedInteger.h | 64 +- 16 files changed, 2661 insertions(+), 822 deletions(-) create mode 100644 modules/beast_core/containers/DynamicArray.cpp create mode 100644 modules/beast_core/containers/DynamicArray.h create mode 100644 modules/beast_core/containers/DynamicList.cpp create mode 100644 modules/beast_core/containers/DynamicList.h create mode 100644 modules/beast_core/containers/HashMap.h rename modules/beast_core/containers/{beast_List.h => List.h} (70%) delete mode 100644 modules/beast_core/containers/beast_HashMap.h create mode 100644 modules/beast_core/containers/detail/copyconst.h create mode 100644 modules/beast_core/containers/detail/removecv.h diff --git a/Builds/VisualStudio2012/beast.vcxproj b/Builds/VisualStudio2012/beast.vcxproj index 987fad04bc..9082fd54f7 100644 --- a/Builds/VisualStudio2012/beast.vcxproj +++ b/Builds/VisualStudio2012/beast.vcxproj @@ -110,9 +110,12 @@ - + + + + - + @@ -124,7 +127,9 @@ + + @@ -450,6 +455,18 @@ true true + + true + true + true + true + + + true + true + true + true + true true diff --git a/Builds/VisualStudio2012/beast.vcxproj.filters b/Builds/VisualStudio2012/beast.vcxproj.filters index edf760bb11..2a04302ff2 100644 --- a/Builds/VisualStudio2012/beast.vcxproj.filters +++ b/Builds/VisualStudio2012/beast.vcxproj.filters @@ -161,6 +161,9 @@ {bf498396-2e1f-4903-be68-3053ba439af5} + + {08ec13ba-4058-4ad7-afbb-cbb1c6e2fc4a} + @@ -181,9 +184,6 @@ beast_core\containers - - beast_core\containers - beast_core\containers @@ -485,9 +485,6 @@ beast_core\zip\zlib - - beast_core\containers - beast_core\memory @@ -920,6 +917,24 @@ beast_core\system + + beast_core\containers + + + beast_core\containers + + + beast_core\containers + + + beast_core\containers + + + beast_core\containers\detail + + + beast_core\containers\detail + @@ -1399,6 +1414,12 @@ beast_core\system + + beast_core\containers + + + beast_core\containers + diff --git a/modules/beast_core/beast_core.cpp b/modules/beast_core/beast_core.cpp index 2aa4a0c9e8..82944cfda2 100644 --- a/modules/beast_core/beast_core.cpp +++ b/modules/beast_core/beast_core.cpp @@ -143,6 +143,8 @@ namespace beast #include "containers/beast_NamedValueSet.cpp" #include "containers/beast_PropertySet.cpp" #include "containers/beast_Variant.cpp" +#include "containers/DynamicArray.cpp" +#include "containers/DynamicList.cpp" #include "diagnostic/beast_Debug.cpp" #include "diagnostic/beast_Error.cpp" diff --git a/modules/beast_core/beast_core.h b/modules/beast_core/beast_core.h index 895ae4cc1f..2ac12c9fd7 100644 --- a/modules/beast_core/beast_core.h +++ b/modules/beast_core/beast_core.h @@ -256,6 +256,9 @@ extern BEAST_API void BEAST_CALLTYPE logAssertion (char const* file, int line) n # pragma warning (pop) #endif +# include "containers/detail/removecv.h" +#include "containers/detail/copyconst.h" + #include "system/PlatformDefs.h" #include "system/TargetPlatform.h" #include "diagnostic/beast_Throw.h" @@ -264,7 +267,7 @@ extern BEAST_API void BEAST_CALLTYPE logAssertion (char const* file, int line) n #include "memory/beast_AtomicFlag.h" #include "memory/beast_AtomicPointer.h" #include "memory/beast_AtomicState.h" -#include "containers/beast_List.h" +#include "containers/List.h" #include "containers/beast_LockFreeStack.h" #include "threads/beast_SpinDelay.h" #include "memory/beast_StaticObject.h" @@ -301,7 +304,6 @@ extern BEAST_API void BEAST_CALLTYPE logAssertion (char const* file, int line) n #include "containers/beast_DynamicObject.h" #include "containers/beast_ElementComparator.h" #include "maths/beast_Random.h" -#include "containers/beast_HashMap.h" #include "containers/beast_LinkedListPointer.h" #include "containers/beast_LockFreeQueue.h" #include "containers/beast_NamedValueSet.h" @@ -315,6 +317,9 @@ extern BEAST_API void BEAST_CALLTYPE logAssertion (char const* file, int line) n #include "maths/beast_Range.h" #include "containers/beast_SparseSet.h" #include "containers/beast_Variant.h" +# include "containers/DynamicList.h" +# include "containers/DynamicArray.h" +#include "containers/HashMap.h" #include "files/beast_DirectoryIterator.h" #include "files/beast_File.h" #include "files/beast_FileInputStream.h" diff --git a/modules/beast_core/containers/DynamicArray.cpp b/modules/beast_core/containers/DynamicArray.cpp new file mode 100644 index 0000000000..1221e5084f --- /dev/null +++ b/modules/beast_core/containers/DynamicArray.cpp @@ -0,0 +1,171 @@ +//------------------------------------------------------------------------------ +/* + 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 DynamicArrayTests : public UnitTest +{ +public: + struct T + { + T () + { + } + + explicit T (String what) + : msg (what) + { + } + + T& operator= (T const& other) + { + msg = other.msg; + return *this; + } + + String msg; + }; + + enum + { + numberToAssign = 1000 * 1000, + numberToReserve = 1000 * 1000, + numberToMutate = 12139 + + }; + + void testAssign () + { + String s; + s << "assign (" << String::fromNumber (numberToAssign) << ")"; + beginTestCase (s); + + DynamicArray v; + v.assign (numberToAssign); + + pass (); + } + + void testReserve () + { + String s; + s << "reserve (" << String::fromNumber (numberToReserve) << ")"; + beginTestCase (s); + + DynamicArray v; + v.reserve (numberToReserve); + + v.assign (numberToReserve); + + pass (); + } + + void testMutate () + { + String s; + DynamicArray v; + + s = "push_back (" + String::fromNumber (numberToMutate) + ")"; + beginTestCase (s); + for (std::size_t i = 0; i < numberToMutate; ++i) + v.push_back (T (String::fromNumber (i))); + + s = "read [] (" + String::fromNumber (numberToMutate) + ")"; + beginTestCase (s); + for (std::size_t i = 0; i < numberToMutate; ++i) + expect (v [i].msg == String::fromNumber (i)); + + s = "write [] (" + String::fromNumber (numberToMutate) + ")"; + beginTestCase (s); + for (std::size_t i = 0; i < numberToMutate; ++i) + v [i].msg = "+" + String::fromNumber (i); + + s = "verify [] (" + String::fromNumber (numberToMutate) + ")"; + beginTestCase (s); + for (std::size_t i = 0; i < numberToMutate; ++i) + expect (v [i].msg == String ("+") + String::fromNumber (i)); + } + + void testIterate () + { + typedef DynamicArray V; + + V v; + for (std::size_t i = 0; i < numberToMutate; ++i) + v.push_back (T (String::fromNumber (i))); + + { + int step = 1; + beginTestCase ("iterator"); + V::iterator iter; + for (iter = v.begin (); iter + step < v.end (); iter += step) + { + step ++; + V::difference_type d = iter - v.begin (); + expect (iter->msg == String::fromNumber (d)); + } + } + + { + int step = 1; + beginTestCase ("const_iterator"); + V::const_iterator iter; + for (iter = v.begin (); iter + step < v.end (); iter += step) + { + step ++; + V::difference_type d = iter - v.begin (); + expect (iter->msg == String::fromNumber (d)); + } + } + + { + int step = 1; + beginTestCase ("reverse_iterator"); + V::reverse_iterator iter; + for (iter = v.rbegin (); iter + step < v.rend (); iter += step) + { + step ++; + iter - v.rend (); + } + } + + { + int step = 1; + beginTestCase ("const_reverse_iterator"); + V::const_reverse_iterator iter; + for (iter = v.crbegin (); iter + step < v.crend (); iter += step) + { + step ++; + iter - v.crend (); + } + } + } + + void runTest () + { + testAssign (); + testReserve (); + testMutate (); + testIterate (); + } + + DynamicArrayTests () : UnitTest ("DynamicArray", "beast") + { + } +}; + +static DynamicArrayTests dynamicArrayTests; diff --git a/modules/beast_core/containers/DynamicArray.h b/modules/beast_core/containers/DynamicArray.h new file mode 100644 index 0000000000..70a079cae1 --- /dev/null +++ b/modules/beast_core/containers/DynamicArray.h @@ -0,0 +1,728 @@ +//------------------------------------------------------------------------------ +/* + 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. +*/ +//============================================================================== + +#ifndef BEAST_CORE_CONTAINERS_DYNAMICARRAY_H_INCLUDED +#define BEAST_CORE_CONTAINERS_DYNAMICARRAY_H_INCLUDED + +template +class DynamicArray; + +namespace detail +{ + +template +class DynamicArrayIterator + : public std::iterator +{ +public: + typedef typename copyconst ::type + + value_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef std::ptrdiff_t difference_type; + typedef typename V::size_type size_type; + + DynamicArrayIterator (V* v = nullptr, size_type pos = 0) noexcept + : m_v (v) + , m_pos (pos) + { + } + + template + DynamicArrayIterator (DynamicArrayIterator const& u) noexcept + : m_v (u.m_v) + , m_pos (u.m_pos) + { + } + + template + DynamicArrayIterator& operator= (DynamicArrayIterator const& u) noexcept + { + m_v = u.m_v; + m_pos = u.m_pos; + return *this; + } + + template + bool operator== (DynamicArrayIterator const& u) const noexcept + { + return (m_v == u.m_v) && (m_pos == u.m_pos); + } + + template + bool operator!= (DynamicArrayIterator const& u) const noexcept + { + return ! ((*this) == u); + } + + reference operator* () const noexcept + { + return dereference (); + } + + pointer operator-> () const noexcept + { + return &dereference (); + } + + DynamicArrayIterator& operator++ () noexcept + { + increment (1); + return *this; + } + + DynamicArrayIterator operator++ (int) noexcept + { + DynamicArrayIterator const result (*this); + increment (1); + return result; + } + + DynamicArrayIterator& operator-- () noexcept + { + decrement (1); + return *this; + } + + DynamicArrayIterator operator-- (int) noexcept + { + DynamicArrayIterator const result (*this); + decrement (1); + return result; + } + + DynamicArrayIterator& operator+= (difference_type n) noexcept + { + increment (n); + return *this; + } + + DynamicArrayIterator& operator-= (difference_type n) noexcept + { + decrement (n); + return *this; + } + + DynamicArrayIterator operator+ (difference_type n) noexcept + { + return DynamicArrayIterator (m_v, m_pos + n); + } + + DynamicArrayIterator operator- (difference_type n) noexcept + { + return DynamicArrayIterator (m_v, m_pos - n); + } + + template + difference_type operator- (DynamicArrayIterator const& rhs) const noexcept + { + return m_pos - rhs.m_pos; + } + + template + bool operator< (DynamicArrayIterator const& rhs) const noexcept + { + return m_pos < rhs.m_pos; + } + + template + bool operator> (DynamicArrayIterator const& rhs) const noexcept + { + return m_pos > rhs.m_pos; + } + + template + bool operator<= (DynamicArrayIterator const& rhs) const noexcept + { + return m_pos <= rhs.m_pos; + } + + template + bool operator>= (DynamicArrayIterator const& rhs) const noexcept + { + return m_pos >= rhs.m_pos; + } + + reference operator[] (difference_type n) noexcept + { + return (*m_v)[m_pos + n]; + } + +private: + reference dereference () const noexcept + { + return (*m_v) [m_pos]; + } + + void increment (difference_type n) noexcept + { + m_pos += n; + } + + void decrement (difference_type n) noexcept + { + m_pos -= n; + } + +private: + template + friend class DynamicArrayIterator; + + V* m_v; + size_type m_pos; +}; + +//------------------------------------------------------------------------------ + +template +DynamicArrayIterator operator+ ( + typename DynamicArrayIterator ::difference_type n, + DynamicArrayIterator iter) noexcept +{ + return iter + n; +} + +template +DynamicArrayIterator operator- ( + typename DynamicArrayIterator ::difference_type n, + DynamicArrayIterator iter) noexcept +{ + return iter - n; +} + +//------------------------------------------------------------------------------ + +template +class DynamicArrayReverseIterator + : public std::iterator +{ +public: + typedef typename copyconst ::type + + value_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef std::ptrdiff_t difference_type; + typedef typename V::size_type size_type; + + DynamicArrayReverseIterator (V* v = nullptr, difference_type pos = 0) noexcept + : m_v (v) + , m_pos (pos) + { + } + + template + DynamicArrayReverseIterator (DynamicArrayReverseIterator const& u) noexcept + : m_v (u.m_v) + , m_pos (u.m_pos) + { + } + + template + DynamicArrayReverseIterator& operator= (DynamicArrayReverseIterator const& u) noexcept + { + m_v = u.m_v; + m_pos = u.m_pos; + return *this; + } + + template + bool operator== (DynamicArrayReverseIterator const& u) const noexcept + { + return (m_v == u.m_v) && (m_pos == u.m_pos); + } + + template + bool operator!= (DynamicArrayReverseIterator const& u) const noexcept + { + return ! ((*this) == u); + } + + reference operator* () const noexcept + { + return dereference (); + } + + pointer operator-> () const noexcept + { + return &dereference (); + } + + DynamicArrayReverseIterator& operator++ () noexcept + { + increment (1); + return *this; + } + + DynamicArrayReverseIterator operator++ (int) noexcept + { + DynamicArrayReverseIterator const result (*this); + increment (1); + return result; + } + + DynamicArrayReverseIterator& operator-- () noexcept + { + decrement (1); + return *this; + } + + DynamicArrayReverseIterator operator-- (int) noexcept + { + DynamicArrayReverseIterator const result (*this); + decrement (1); + return result; + } + + DynamicArrayReverseIterator& operator+= (difference_type n) noexcept + { + increment (n); + return *this; + } + + DynamicArrayReverseIterator& operator-= (difference_type n) noexcept + { + decrement (n); + return *this; + } + + DynamicArrayReverseIterator operator+ (difference_type n) noexcept + { + return DynamicArrayReverseIterator (m_v, m_pos - n); + } + + DynamicArrayReverseIterator operator- (difference_type n) noexcept + { + return DynamicArrayReverseIterator (m_v, m_pos + n); + } + + template + difference_type operator- (DynamicArrayReverseIterator const& rhs) const noexcept + { + return rhs.m_pos - m_pos; + } + + template + bool operator< (DynamicArrayReverseIterator const& rhs) const noexcept + { + return m_pos > rhs.m_pos; + } + + template + bool operator> (DynamicArrayReverseIterator const& rhs) const noexcept + { + return m_pos < rhs.m_pos; + } + + template + bool operator<= (DynamicArrayReverseIterator const& rhs) const noexcept + { + return m_pos >= rhs.m_pos; + } + + template + bool operator>= (DynamicArrayReverseIterator const& rhs) const noexcept + { + return m_pos <= rhs.m_pos; + } + + reference operator[] (difference_type n) noexcept + { + return (*m_v)[(m_pos - 1) - n]; + } + +private: + template + friend class DynamicArrayReverseIterator; + + reference dereference () const noexcept + { + return (*m_v) [m_pos - 1]; + } + + void increment (difference_type n) noexcept + { + m_pos -= n; + } + + void decrement (difference_type n) noexcept + { + m_pos += n; + } + + V* m_v; + difference_type m_pos; +}; + +//------------------------------------------------------------------------------ + +template +DynamicArrayReverseIterator operator+ ( + typename DynamicArrayReverseIterator ::difference_type n, + DynamicArrayReverseIterator iter) noexcept +{ + return iter + n; +} + +template +DynamicArrayReverseIterator operator- ( + typename DynamicArrayReverseIterator ::difference_type n, + DynamicArrayReverseIterator iter) noexcept +{ + return iter - n; +} + +} + +//------------------------------------------------------------------------------ + +template > +class DynamicArray +{ +private: + typedef PARAMETER_TYPE (T) TParam; + + typedef std::vector handles_t; + +public: + enum + { + defaultBlocksize = 1000, + growthPercentage = 10 + }; + + typedef T value_type; + typedef Allocator allocator_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef value_type const* const_pointer; + typedef value_type const& const_reference; + + typedef detail::DynamicArrayIterator > iterator; + + typedef detail::DynamicArrayIterator const> const_iterator; + + typedef detail::DynamicArrayReverseIterator > reverse_iterator; + + typedef detail::DynamicArrayReverseIterator const> const_reverse_iterator; + + //-------------------------------------------------------------------------- + + explicit DynamicArray (size_type blocksize = defaultBlocksize) noexcept + : m_blocksize (blocksize) + , m_capacity (0) + , m_size (0) + { + } + + ~DynamicArray() + { + clear (); + shrink_to_fit (); + } + + /** Replace the array with 'count' copies of a default-constructed T. + */ + void assign (size_type count) + { + clear (); + resize (count); + } + + //-------------------------------------------------------------------------- + + reference at (size_type pos) + { + if (pos >= size ()) + Throw (std::out_of_range ("bad pos"), __FILE__, __LINE__); + return get (pos); + } + + const_reference at (size_type pos) const + { + if (pos >= size ()) + Throw (std::out_of_range ("bad pos"), __FILE__, __LINE__); + return get (pos); + } + + reference operator[] (size_type pos) noexcept + { + return get (pos); + } + + const_reference operator[] (size_type pos) const noexcept + { + return get (pos); + } + + reference front () noexcept + { + return get (0); + } + + const_reference front () const noexcept + { + return get (0); + } + + reference back () noexcept + { + return get (size () - 1); + } + + const_reference back () const noexcept + { + return get (size () - 1); + } + + //-------------------------------------------------------------------------- + + iterator begin () noexcept + { + return iterator (this, 0); + } + + const_iterator begin () const noexcept + { + return const_iterator (this, 0); + } + + const_iterator cbegin () const noexcept + { + return const_iterator (this, 0); + } + + iterator end () noexcept + { + return iterator (this, size ()); + } + + const_iterator end () const noexcept + { + return const_iterator (this, size ()); + } + + const_iterator cend () const noexcept + { + return const_iterator (this, size ()); + } + + reverse_iterator rbegin () noexcept + { + return reverse_iterator (this, size ()); + } + + const_reverse_iterator rbegin () const noexcept + { + return const_reverse_iterator (this, size ()); + } + + const_reverse_iterator crbegin () const noexcept + { + return const_reverse_iterator (this, size ()); + } + + reverse_iterator rend () noexcept + { + return reverse_iterator (this, 0); + } + + const_reverse_iterator rend () const noexcept + { + return const_reverse_iterator (this, 0); + } + + const_reverse_iterator crend () const noexcept + { + return const_reverse_iterator (this, 0); + } + + //-------------------------------------------------------------------------- + + bool empty () const noexcept + { + return m_size == 0; + } + + size_type size () const noexcept + { + return m_size; + } + + size_type max_size () const noexcept + { + return std::numeric_limits ::max (); + } + + void reserve (size_type new_cap) + { + new_cap = m_blocksize * ( + (new_cap + m_blocksize - 1) / m_blocksize); + if (new_cap > max_size ()) + Throw (std::length_error ("new_cap > max_size"), __FILE__, __LINE__); + if (new_cap <= m_capacity) + return; + size_type const n (new_cap / m_blocksize); + m_handles.reserve (n); + for (size_type i = m_handles.size (); i < n; ++i) + m_handles.push_back (static_cast (std::malloc ( + m_blocksize * sizeof (T)))); + m_capacity = new_cap; + } + + size_type capacity () const noexcept + { + return m_capacity; + } + + void shrink_to_fit () + { + size_type const handles ( + (size () + m_blocksize - 1) / m_blocksize); + m_capacity = handles * m_blocksize; + for (size_type i = m_handles.size (); i-- > handles;) + { + std::free (m_handles [i]); + m_handles.erase (m_handles.begin () + i); + } + } + + //-------------------------------------------------------------------------- + + void clear () + { + resize (0); + } + + iterator push_back (TParam value) + { + ::new (alloc ()) T (value); + return iterator (this, size () - 1); + } + + iterator emplace_back () + { + ::new (alloc ()) T (); + return iterator (this, size () - 1); + } + + template + iterator emplace_back (A1 a1) + { + ::new (alloc ()) T (a1); + return iterator (this, size () - 1); + } + + template + iterator emplace_back (A1 a1, A2 a2) + { + ::new (alloc ()) T (a1, a2); + return iterator (this, size () - 1); + } + + template + iterator emplace_back (A1 a1, A2 a2, A3 a3) + { + ::new (alloc ()) T (a1, a2, a3); + return iterator (this, size () - 1); + } + + template + iterator emplace_back (A1 a1, A2 a2, A3 a3, A4 a4) + { + ::new (alloc ()) T (a1, a2, a3, a4); + return iterator (this, size () - 1); + } + + template + iterator emplace_back (A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) + { + ::new (alloc ()) T (a1, a2, a3, a4, a5); + return iterator (this, size () - 1); + } + + void pop_back () + { + resize (size () - 1); + } + + void resize (size_type count) + { + while (count > size ()) + ::new (alloc ()) T; + + while (count < size ()) + get (--m_size).~T (); + } + + void resize (size_type count, TParam value) + { + while (count > size ()) + ::new (alloc ()) T (value); + + while (count < size ()) + get (--m_size).~T (); + } + + void swap (DynamicArray& other) + { + std::swap (m_blocksize, other.m_blocksize); + std::swap (m_size, other.m_size); + std::swap (m_capacity, other.m_capacity); + std::swap (m_handles, other.m_handles); + } + +private: + reference get (size_type pos) noexcept + { + size_type const index (pos / m_blocksize); + size_type const offset (pos % m_blocksize); + return m_handles [index] [offset]; + } + + const_reference get (size_type pos) const noexcept + { + size_type const index (pos / m_blocksize); + size_type const offset (pos % m_blocksize); + return m_handles [index] [offset]; + } + + T* alloc () noexcept + { + size_type const needed (size () + 1); + if (capacity () < needed) + reserve ((needed * (100 + growthPercentage) + 99) / 100); + return &get (m_size++); + } + +private: + Allocator m_allocator; + size_type m_blocksize; + size_type m_capacity; + size_type m_size; + handles_t m_handles; +}; + +#endif diff --git a/modules/beast_core/containers/DynamicList.cpp b/modules/beast_core/containers/DynamicList.cpp new file mode 100644 index 0000000000..e32a065f42 --- /dev/null +++ b/modules/beast_core/containers/DynamicList.cpp @@ -0,0 +1,70 @@ +//------------------------------------------------------------------------------ +/* + 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 DynamicListTests : public UnitTest +{ +public: + struct T + { + T () + { + } + + explicit T (String what) + : msg (what) + { + } + + T& operator= (T const& other) + { + msg = other.msg; + return *this; + } + + String msg; + }; + + enum + { + numberToAssign = 1000 * 1000, + numberToReserve = 1000 * 1000, + numberToMutate = 12139 + + }; + + void testAssign () + { + String s; + s << "assign (" << String::fromNumber (numberToAssign) << ")"; + beginTestCase (s); + + pass (); + } + + void runTest () + { + testAssign (); + } + + DynamicListTests () : UnitTest ("DynamicList", "beast") + { + } +}; + +static DynamicListTests DynamicListTests; diff --git a/modules/beast_core/containers/DynamicList.h b/modules/beast_core/containers/DynamicList.h new file mode 100644 index 0000000000..9ccbda4dd6 --- /dev/null +++ b/modules/beast_core/containers/DynamicList.h @@ -0,0 +1,452 @@ +//------------------------------------------------------------------------------ +/* + 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. +*/ +//============================================================================== + +#ifndef BEAST_CORE_CONTAINERS_DYNAMICLIST_H_INCLUDED +#define BEAST_CORE_CONTAINERS_DYNAMICLIST_H_INCLUDED + +template +class DynamicList; + +namespace detail +{ + +template +class DynamicListIterator + : public std::iterator +{ +public: + typedef typename I::value_type ItemType; // this will be + typedef typename ItemType::value_type T; // this is the original T + + typedef typename copyconst ::type + + value_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef typename I::size_type size_type; + + DynamicListIterator (I iter = I ()) noexcept + : m_iter (iter) + { + } + +#if 1 + template + DynamicListIterator (DynamicListIterator const& other) noexcept + : m_iter (other.m_iter) + { + } + + template + DynamicListIterator& operator= (DynamicListIterator const& other) noexcept + { + m_iter = other.m_iter; + return *this; + } +#endif + + template + bool operator== (DynamicListIterator const& other) const noexcept + { + return m_iter == other.m_iter; + } + + template + bool operator != (DynamicListIterator const& other) const noexcept + { + return ! this->operator== (other); + } + + reference operator* () const noexcept + { + return dereference (); + } + + pointer operator-> () const noexcept + { + return &dereference (); + } + + DynamicListIterator& operator++ () noexcept + { + increment (); + return *this; + } + + DynamicListIterator operator++ (int) noexcept + { + DynamicListIterator const result (*this); + increment (); + return result; + } + + DynamicListIterator& operator-- () noexcept + { + decrement (); + return *this; + } + + DynamicListIterator operator-- (int) noexcept + { + DynamicListIterator const result (*this); + decrement (); + return result; + } + +private: + template + friend class DynamicList; + + typedef typename I::value_type Item; + + reference dereference () const noexcept + { + return *(m_iter->get ()); + } + + void increment () noexcept + { + ++m_iter; + } + + void decrement () noexcept + { + --m_iter; + } + + I m_iter; +}; + +} + +//------------------------------------------------------------------------------ + +/** A list that uses a very small number of dynamic allocations. + + Once an element is allocated, its address does not change. Elements + can be erased, and they are placed onto a deleted list for re-use. + Allocations occur in configurable batches. + + Iterators to elements never become invalid, they can be safely + stored elsewhere, as long as the underlying element is not erased. + + T may support these concepts: + DefaultConstructible + MoveConstructible (C++11) + + T must support these concepts: + Destructible +*/ +template > +class DynamicList +{ +private: + typedef PARAMETER_TYPE (T) TParam; + +public: + enum + { + defaultBlocksize = 1000 + }; + + typedef T value_type; + typedef Allocator allocator_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef T* pointer; + typedef T& reference; + typedef T const* const_pointer; + typedef T const& const_reference; + +private: + struct Item : List ::Node + { + typedef T value_type; + + T* get () noexcept + { + return reinterpret_cast (&storage [0]); + } + + T const* get () const noexcept + { + return reinterpret_cast (&storage [0]); + } + + private: + // Lets hope this is padded correctly + uint8 storage [sizeof (T)]; + }; + +public: + typedef detail::DynamicListIterator < + typename List ::iterator> iterator; + + typedef detail::DynamicListIterator < + typename List ::const_iterator> const_iterator; + + explicit DynamicList ( + size_type blocksize = defaultBlocksize, + Allocator const& allocator = Allocator ()) + : m_allocator (allocator) + , m_blocksize (blocksize) + , m_capacity (0) + { + } + + ~DynamicList () + { + clear (); + shrink_to_fit (); + } + + allocator_type get_allocator () const noexcept + { + return m_allocator; + } + + //-------------------------------------------------------------------------- + + reference front () noexcept + { + return *m_items.front ().get (); + } + + const_reference front () const noexcept + { + return *m_items.front ().get (); + } + + reference back () noexcept + { + return *m_items.back ().get (); + } + + const_reference back () const noexcept + { + return *m_items.back ().get (); + } + + //-------------------------------------------------------------------------- + + iterator begin () noexcept + { + return iterator (m_items.begin ()); + } + + const_iterator begin () const noexcept + { + return const_iterator (m_items.begin ()); + } + + const_iterator cbegin () const noexcept + { + return const_iterator (m_items.cbegin ()); + } + + iterator end () noexcept + { + return iterator (m_items.end ()); + } + + const_iterator end () const noexcept + { + return const_iterator (m_items.end ()); + } + + const_iterator cend () const noexcept + { + return const_iterator (m_items.cend ()); + } + + iterator iterator_to (T& value) noexcept + { + std::ptrdiff_t const offset ( + (std::ptrdiff_t)(((Item const*)0)->get ())); + Item& item (*addBytesToPointer (((Item*)&value), -offset)); + return iterator (m_items.iterator_to (item)); + } + + const_iterator const_iterator_to (T const& value) const noexcept + { + std::ptrdiff_t const offset ( + (std::ptrdiff_t)(((Item const*)0)->get ())); + Item const& item (*addBytesToPointer (((Item const*)&value), -offset)); + return const_iterator (m_items.const_iterator_to (item)); + } + + //-------------------------------------------------------------------------- + + bool empty () const noexcept + { + return m_items.empty (); + } + + size_type size () const noexcept + { + return m_items.size (); + } + + size_type max_size () const noexcept + { + return std::numeric_limits ::max (); + } + + void reserve (size_type new_cap) noexcept + { + new_cap = m_blocksize * ( + (new_cap + m_blocksize - 1) / m_blocksize); + if (new_cap > max_size ()) + Throw (std::length_error ("new_cap > max_size"), __FILE__, __LINE__); + if (new_cap <= m_capacity) + return; + size_type const n (new_cap / m_blocksize); + m_handles.reserve (n); + for (size_type i = m_handles.size (); i < n; ++i) + m_handles.push_back (static_cast (std::malloc ( + m_blocksize * sizeof (Item)))); + m_capacity = new_cap; + } + + size_type capacity () const noexcept + { + return m_capacity; + } + + void shrink_to_fit () + { + // Special case when all allocated + // items are part of the free list. + if (m_items.empty ()) + m_free.clear (); + + size_type const used (m_items.size () + m_free.size ()); + size_type const handles ((used + m_blocksize - 1) / m_blocksize); + m_capacity = handles * m_blocksize; + for (size_type i = m_handles.size (); i-- > handles;) + { + std::free (m_handles [i]); + m_handles.erase (m_handles.begin () + i); + } + } + + //-------------------------------------------------------------------------- + + void clear () + { + // Might want to skip this if is_pod is true + for (typename List ::iterator iter = m_items.begin (); + iter != m_items.end ();) + { + Item& item (*iter++); + item.get ()->~T (); + m_free.push_back (item); + } + } + + /** Allocate a new default-constructed element and return the iterator. + If there are deleted elements in the free list, the new element + may not be created at the end of the storage area. + */ + iterator emplace_back () + { + return iterator_to (*::new (alloc ()->get ()) T ()); + } + + template + iterator emplace_back (A1 a1) + { + return iterator_to (*::new (alloc ()->get ()) T (a1)); + } + + template + iterator emplace_back (A1 a1, A2 a2) + { + return iterator_to (*::new (alloc ()->get ()) T (a1, a2)); + } + + template + iterator emplace_back (A1 a1, A2 a2, A3 a3) + { + return iterator_to (*::new (alloc ()->get ()) T (a1, a2, a3)); + } + + template + iterator emplace_back (A1 a1, A2 a2, A3 a3, A4 a4) + { + return iterator_to (*::new (alloc ()->get ()) T (a1, a2, a3, a4)); + } + + template + iterator emplace_back (A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) + { + return iterator_to (*::new (alloc ()->get ()) T (a1, a2, a3, a4, a5)); + } + + /** Allocate a new copy-constructed element and return the index. */ + iterator push_back (TParam value) noexcept + { + return iterator_to (*::new (alloc ()->get ()) T (value)); + } + + /** Erase the element at the specified position. */ + iterator erase (iterator pos) + { + Item& item (*pos.m_iter); + item.get ()->~T (); + pos = m_items.erase (m_items.iterator_to (item)); + m_free.push_front (item); + return pos; + } + +private: + Item* alloc () noexcept + { + Item* item; + if (m_free.empty ()) + { + if (m_capacity <= m_items.size ()) + reserve (m_items.size () + 1); + + size_type const index (m_items.size () / m_blocksize); + size_type const offset (m_items.size () - index * m_blocksize); + item = m_handles [index] + offset; + } + else + { + item = &m_free.pop_front (); + } + + m_items.push_back (*item); + return item; + } + + typedef std::vector blocks_t; + + Allocator m_allocator; + size_type m_blocksize; + size_type m_capacity; + std::vector m_handles; + List m_items; + List m_free; +}; + +#endif diff --git a/modules/beast_core/containers/HashMap.h b/modules/beast_core/containers/HashMap.h new file mode 100644 index 0000000000..3cfb17fcbc --- /dev/null +++ b/modules/beast_core/containers/HashMap.h @@ -0,0 +1,833 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Portions of this file are from JUCE. + Copyright (c) 2013 - Raw Material Software Ltd. + Please visit http://www.juce.com + + 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. +*/ +//============================================================================== + +#ifndef BEAST_HASHMAP_H_INCLUDED +#define BEAST_HASHMAP_H_INCLUDED + +/** The integral type for holding a non cryptographic hash. + HashValue is used for fast comparisons, bloom filters, and hash maps. +*/ +typedef uint32 HashValue; + +//------------------------------------------------------------------------------ + +/** Simple hash functions for use with HashMap. + + @see HashMap +*/ +// VFALCO TODO Rewrite the hash functions to return a uint32, and not +// take the upperLimit parameter. Just do the mod in the +// calling function for simplicity. +class DefaultHashFunctions +{ +public: + /** Generates a simple hash from an integer. */ + HashValue generateHash (const int key) const noexcept + { + return HashValue (std::abs (key)); + } + + /** Generates a simple hash from an int64. */ + HashValue generateHash (const int64 key) const noexcept + { + return HashValue (key); + } + + /** Generates a simple hash from a string. */ + HashValue generateHash (const String& key) const noexcept + { + return HashValue (key.hashCode ()); + } + + /** Generates a simple hash from a variant. */ + HashValue generateHash (const var& key) const noexcept + { + return generateHash (key.toString ()); + } +}; + +#if 0 +/** Hardened hash functions for use with HashMap. + + The seed is used to make the hash unpredictable. This prevents + attackers from exploiting crafted inputs to produce degenerate + containers. +*/ +class HardenedHashFunctions +{ +public: + /** Construct a hash function. + + If a seed is specified it will be used, else a random seed + will be generated from the system. + + @param seedToUse An optional seed to use. + */ + explicit HardenedHashFunctions (int seedToUse = Random::getSystemRandom ().nextInt ()) + : m_seed (seedToUse) + { + } + + // VFALCO TODO Need hardened versions of these functions which use the seed! + +private: + int m_seed; +}; +#endif + +//------------------------------------------------------------------------------ + +namespace detail +{ + +template +class HashMapLocalIterator + : public std::iterator +{ +public: + typedef typename M::Pair value_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef typename M::size_type size_type; + + HashMapLocalIterator (M* map = nullptr, I iter = I ()) + : m_map (map) + , m_iter (iter) + { + } + + template + HashMapLocalIterator (HashMapLocalIterator const& other) + : m_map (other.m_map) + , m_iter (other.m_iter) + { + } + + template + HashMapLocalIterator& operator= (HashMapLocalIterator const& other) + { + m_map = other.m_map; + m_iter = other.m_iter; + return *this; + } + + template + bool operator== (HashMapLocalIterator const& other) + { + return m_map == other.m_map && m_iter == other.m_iter; + } + + template + bool operator!= (HashMapLocalIterator const& other) + { + return ! ((*this)==other); + } + + reference operator* () const noexcept + { + return dereference (); + } + + pointer operator-> () const noexcept + { + return &dereference (); + } + + HashMapLocalIterator& operator++ () noexcept + { + increment (); + return *this; + } + + HashMapLocalIterator operator++ (int) noexcept + { + HashMapLocalIterator const result (*this); + increment (); + return result; + } + +private: + reference dereference () const noexcept + { + return m_iter->pair (); + } + + void increment () noexcept + { + ++m_iter; + } + + M* m_map; + I m_iter; +}; + +//------------------------------------------------------------------------------ + + +template +class HashMapIterator + : public std::iterator +{ +private: + typedef typename M::Item Item; + typedef typename M::Bucket Bucket; + typedef detail::ListIterator ::Node>::type> bucket_iterator; + typedef detail::ListIterator ::Node>::type> item_iterator; + +public: + typedef typename M::Pair value_type; + typedef value_type* pointer; + 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 ()) + : m_map (map) + , m_bucket (bucket) + , m_local (local) + { + } + + template + HashMapIterator (HashMapIterator const& other) noexcept + : m_map (other.m_map) + , m_bucket (other.m_bucket) + , m_local (other.m_local) + { + } + + template + HashMapIterator& operator= (HashMapIterator const& other) noexcept + { + m_map = other.m_map; + m_bucket = other.m_bucket; + m_local = other.m_local; + return *this; + } + + template + bool operator== (HashMapIterator const& other) noexcept + { + return m_map == other.m_map && + m_bucket == other.m_bucket && + m_local == other.m_local; + } + + template + bool operator!= (HashMapIterator const& other) noexcept + { + return ! ((*this) == other); + } + + reference operator* () const noexcept + { + return dereference (); + } + + pointer operator-> () const noexcept + { + return &dereference (); + } + + HashMapIterator& operator++ () noexcept + { + increment (); + return *this; + } + + HashMapIterator operator++ (int) noexcept + { + HashMapIterator const result (*this); + increment (); + return result; + } + +private: + template + friend class HashMap; + + reference dereference () const noexcept + { + return m_local->pair (); + } + + void increment () noexcept + { + ++m_local; + if (m_local == m_bucket->items.end ()) + { + ++m_bucket; + if (m_bucket != m_map->m_bucketlist.end ()) + m_local = m_bucket->items.begin (); + } + } + + M* m_map; + bucket_iterator m_bucket; + item_iterator m_local; +}; + +} + +//------------------------------------------------------------------------------ + +/** Associative container mapping Key to T pairs. +*/ +template , + typename Allocator = std::allocator > +class HashMap +{ +private: + typedef PARAMETER_TYPE (Key) KeyParam; + typedef PARAMETER_TYPE (T) TParam; + +public: + struct Pair + { + explicit Pair (Key key) + : m_key (key) + { + } + + Pair (Key key, T t) + : m_key (key) + , m_t (t) + { + } + + Key const& key () const noexcept + { + return m_key; + } + + T& value () noexcept + { + return m_t; + } + + T const& value () const noexcept + { + return m_t; + } + + private: + Key m_key; + T m_t; + }; + +private: + template + friend class detail::HashMapLocalIterator; + + class Item; + + // Each non-empty bucket is in the linked list. + struct Bucket : List ::Node + { + Bucket () + { + } + + inline bool empty () const noexcept + { + return items.empty (); + } + + List items; + + private: + Bucket& operator= (Bucket const&); + Bucket (Bucket const&); + }; + + // Every item in the map is in one linked list + struct Item + : List ::Node + , List ::Node + { + Item (Pair const& pair_) + : m_pair (pair_) + { + } + + Pair& pair () noexcept + { + return m_pair; + } + + Pair const& pair () const noexcept + { + return m_pair; + } + + private: + Pair m_pair; + }; + +public: + typedef Key key_type; + typedef T mapped_type; + typedef Pair value_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef Hash hasher; + typedef KeyEqual key_equal; + typedef Allocator allocator_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef value_type const* const_pointer; + typedef value_type const& const_reference; + + typedef detail::HashMapIterator > iterator; + typedef detail::HashMapIterator const> const_iterator; + + typedef detail::HashMapLocalIterator < + HashMap , + typename List ::iterator> local_iterator; + + typedef detail::HashMapLocalIterator < + HashMap const, + typename List ::const_iterator> const_local_iterator; + + //-------------------------------------------------------------------------- + + enum + { + initialBucketCount = 101, + percentageIncrease = 75 + }; + + static float getDefaultLoadFactor () noexcept + { + return 1.2f; + } + + explicit HashMap ( + size_type bucket_count = initialBucketCount, + KeyEqual const& equal = KeyEqual (), + Hash const& hash = Hash (), + Allocator const& allocator = Allocator ()) + : m_hash (hash) + , m_equal (equal) + , m_allocator (allocator) + , m_max_load_factor (getDefaultLoadFactor ()) + { + rehash (bucket_count); + } + + HashMap ( + size_type bucket_count, + Allocator const& allocator = Allocator ()) + : m_allocator (allocator) + , m_max_load_factor (getDefaultLoadFactor ()) + { + rehash (bucket_count); + } + + HashMap ( + size_type bucket_count, + Hash const& hash = Hash (), + Allocator const& allocator = Allocator ()) + : m_hash (hash) + , m_allocator (allocator) + , m_max_load_factor (getDefaultLoadFactor ()) + { + rehash (bucket_count); + } + + explicit HashMap (Allocator const& allocator) + : m_allocator (allocator) + , m_max_load_factor (getDefaultLoadFactor ()) + { + rehash (initialBucketCount); + } + + ~HashMap() + { + clear (); + } + + HashMap& operator= (HashMap const& other) + { + clear (); + for (iterator iter = other.begin (); iter != other.end (); ++iter) + (*this)[iter->key ()] = iter->value (); + return *this; + } + + allocator_type get_allocator () const noexcept + { + return m_allocator; + } + + //-------------------------------------------------------------------------- + + iterator begin () noexcept + { + if (m_bucketlist.size () > 0) + return iterator (this, m_bucketlist.begin (), + m_bucketlist.front ().items.begin ()); + return end (); + } + + const_iterator begin () const noexcept + { + if (m_bucketlist.size () > 0) + return const_iterator (this, m_bucketlist.begin (), + m_bucketlist.front ().items.begin ()); + return end (); + } + + const_iterator cbegin () const noexcept + { + if (m_bucketlist.size () > 0) + return const_iterator (this, m_bucketlist.begin (), + m_bucketlist.front ().items.begin ()); + return end (); + } + + iterator end () noexcept + { + return iterator (this, m_bucketlist.end ()); + } + + const_iterator end () const noexcept + { + return const_iterator (this, m_bucketlist.end ()); + } + + const_iterator cend () const noexcept + { + return const_iterator (this, m_bucketlist.cend ()); + } + + //-------------------------------------------------------------------------- + + bool empty () const noexcept + { + return size () == 0; + } + + size_type size () const noexcept + { + return m_itemlist.size (); + } + + size_type max_size () const noexcept + { + return std::numeric_limits ::max (); + } + + //-------------------------------------------------------------------------- + + void clear() + { + for (typename DynamicList ::iterator iter = m_items.begin (); + iter != m_items.end ();) + { + typename DynamicList ::iterator const cur (iter++); + m_items.erase (cur); + } + + m_itemlist.clear (); + m_bucketlist.clear (); + size_type const count (m_buckets.size ()); + m_buckets.assign (count); + } + + struct Result + { + Result (iterator iter_ = iterator (), bool inserted_ = false) + : iter (iter_) + , inserted (inserted_) + { + } + + iterator iter; + bool inserted; + }; + + Result insert (Pair const& p) + { + size_type const n (bucket (p.key ())); + iterator iter (find (p.key (), n)); + if (iter != end ()) + return Result (iter, false); + check_load (); + return Result (store (*m_items.emplace_back (p), n), true); + } + + Result insert (KeyParam key) + { + return insert (Pair (key)); + } + + iterator erase (const_iterator pos) + { + iterator iter = pos; + ++iter; + Bucket& b (*pos.m_iter); + erase (b, pos->m_local); + return iter; + } + + size_type erase (KeyParam key) + { + size_type found (0); + Bucket& b (m_buckets [bucket (key)]); + for (typename List ::iterator iter (b.items.begin ()); + iter != b.items.end ();) + { + typename List ::iterator cur (iter++); + if (m_equal (cur->pair ().key (), key)) + { + erase (b, cur); + ++found; + } + } + return found; + } + + //-------------------------------------------------------------------------- + + T& at (KeyParam key) + { + iterator const iter (find (key)); + if (iter == end ()) + Throw (std::out_of_range ("key not found"), __FILE__, __LINE__); + return iter->value (); + } + + T const& at (KeyParam key) const + { + const_iterator const iter (find (key)); + if (iter == end ()) + Throw (std::out_of_range ("key not found"), __FILE__, __LINE__); + return iter->value (); + } + + T& operator[] (KeyParam key) noexcept + { + return insert (key).iter->value (); + } + + size_type count (KeyParam key) const noexcept + { + size_type n = 0; + Bucket const& b (m_buckets [bucket (key)]); + for (typename List ::iterator iter = b.items.begin (); + iter != b.items.end (); ++iter) + if (m_equal (iter->key (), key)) + ++n; + return n; + } + + iterator find (KeyParam key) noexcept + { + return find (key, bucket (key)); + } + + const_iterator find (KeyParam key) const noexcept + { + return find (key, bucket (key)); + } + + //-------------------------------------------------------------------------- + + local_iterator begin (size_type n) noexcept + { + return local_iterator (this, m_buckets [n].items.begin ()); + } + + const_local_iterator begin (size_type n) const noexcept + { + return const_local_iterator (this, m_buckets [n].items.begin ()); + } + + const_local_iterator cbegin (size_type n) const noexcept + { + return const_local_iterator (this, m_buckets [n].items.cbegin ()); + } + + local_iterator end (size_type n) noexcept + { + return local_iterator (this, m_buckets [n].items.end ()); + } + + const_local_iterator end (size_type n) const noexcept + { + return const_local_iterator (this, m_buckets [n].items.end ()); + } + + const_local_iterator cend (size_type n) const noexcept + { + return const_local_iterator (this, m_buckets [n].items.cend ()); + } + + size_type bucket_count () const noexcept + { + return m_buckets.size (); + } + + size_type max_bucket_count () const noexcept + { + return std::numeric_limits ::max (); + } + + size_type bucket_size (size_type n) const noexcept + { + return m_buckets [n].items.size (); + } + + size_type bucket (KeyParam key) const noexcept + { + HashValue const hash (m_hash.generateHash (key)); + return hash % bucket_count (); + } + + //-------------------------------------------------------------------------- + + float load_factor () const noexcept + { + return float (m_items.size ()) / float (m_buckets.size ()); + } + + float max_load_factor () const noexcept + { + return m_max_load_factor; + } + + void max_load_factor (float ml) noexcept + { + m_max_load_factor = ml; + check_load (); + } + + void rehash (size_type const count) + { + m_bucketlist.clear (); + m_buckets.assign (count); + for (typename List ::iterator iter = m_itemlist.begin (); + iter != m_itemlist.end (); ++iter) + { + Item& item (*iter); + size_type const n (bucket (item.pair ().key ())); + Bucket& b (m_buckets [n]); + if (b.empty ()) + m_bucketlist.push_front (b); + b.items.push_front (item); + } + } + + void reserve (size_type count) + { + m_items.reserve (count); + rehash (std::ceil (count / max_load_factor ())); + } + +private: + // rehashes if adding one more item would put us over + void check_load () noexcept + { + if ( (float (m_items.size () + 1) / + float (m_buckets.size ())) >= + max_load_factor ()) + { + grow_buckets (); + } + } + + void grow_buckets () + { + float const scale = 1.f + (float (percentageIncrease) / 100.f); + size_type const count (std::ceil ( + (size () / max_load_factor ()) * scale)); + rehash (count); + } + + iterator find (KeyParam key, size_type n) noexcept + { + Bucket& b (m_buckets [n]); + 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); + return end (); + } + + const_iterator find (KeyParam key, size_type n) const noexcept + { + Bucket const& b (m_buckets [n]); + 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, + m_bucketlist.const_iterator_to (b), iter); + return end (); + } + + iterator store (Item& item, size_type n) + { + check_load (); + Bucket& b (m_buckets [n]); + if (b.empty ()) + m_bucketlist.push_front (b); + b.items.push_front (item); + m_itemlist.push_front (item); + return iterator (this, + m_bucketlist.iterator_to (b), + b.items.begin ()); + } + + void erase (Bucket& b, typename List ::iterator pos) + { + Item& item (*pos); + b.items.erase (b.items.iterator_to (item)); + if (b.empty ()) + m_bucketlist.erase (m_bucketlist.iterator_to (b)); + m_itemlist.erase (m_itemlist.iterator_to (item)); + m_items.erase (m_items.iterator_to (item)); + } + +private: + template + friend class detail::HashMapIterator; + + Hash m_hash; + KeyEqual m_equal; + Allocator m_allocator; + DynamicList m_items; + DynamicArray m_buckets; + List m_itemlist; + List m_bucketlist; + float m_max_load_factor; +}; + +#endif + diff --git a/modules/beast_core/containers/beast_List.h b/modules/beast_core/containers/List.h similarity index 70% rename from modules/beast_core/containers/beast_List.h rename to modules/beast_core/containers/List.h index c187579b96..0d96e61d44 100644 --- a/modules/beast_core/containers/beast_List.h +++ b/modules/beast_core/containers/List.h @@ -17,8 +17,8 @@ */ //============================================================================== -#ifndef BEAST_LIST_H_INCLUDED -#define BEAST_LIST_H_INCLUDED +#ifndef BEAST_CORE_CONTAINERS_LIST_H_INCLUDED +#define BEAST_CORE_CONTAINERS_LIST_H_INCLUDED /** Intrusive Containers @@ -189,14 +189,138 @@ @defgroup intrusive intrusive @ingroup beast_core */ + +//------------------------------------------------------------------------------ + +template +class List; + +namespace detail +{ + +// This is the intrusive portion of the doubly linked list. +// One derivation per list that the object may appear on +// concurrently is required. +// +template +class ListNode : public Uncopyable +{ +private: + typedef T value_type; + + template + friend class List; + + template + friend class ListIterator; + + ListNode* m_next; + ListNode* m_prev; +}; //------------------------------------------------------------------------------ -/** Default tag for List. +template +class ListIterator : public std::iterator < + std::bidirectional_iterator_tag, std::size_t> +{ +public: + typedef typename copyconst ::type + + value_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef std::size_t size_type; - @ingroup beast_core intrusive -*/ -struct ListDefaultTag; + ListIterator (N* node = nullptr) noexcept + : m_node (node) + { + } +#if 0 + template + ListIterator (ListIterator const& other) noexcept + : m_node (other.m_node) + { + } + + template + ListIterator& operator= (ListIterator const& other) noexcept + { + m_node = other.m_node; + return *this; + } +#endif + template + bool operator== (ListIterator const& other) const noexcept + { + return m_node == other.m_node; + } + + template + bool operator!= (ListIterator const& other) const noexcept + { + return ! ((*this) == other); + } + + reference operator* () const noexcept + { + return dereference (); + } + + pointer operator-> () const noexcept + { + return &dereference (); + } + + ListIterator& operator++ () noexcept + { + increment (); + return *this; + } + + ListIterator operator++ (int) noexcept + { + ListIterator result (*this); + increment (); + return result; + } + + ListIterator& operator-- () noexcept + { + decrement (); + return *this; + } + + ListIterator operator-- (int) noexcept + { + ListIterator result (*this); + decrement (); + return result; + } + +private: + reference dereference () const noexcept + { + return static_cast (*m_node); + } + + void increment () noexcept + { + bassert (m_node->m_next); + m_node = m_node->m_next; + } + + void decrement () noexcept + { + bassert (m_node->m_prev && + m_node->m_prev->m_prev != nullptr); + m_node = m_node->m_prev; + } + + N* m_node; +}; + +} /** Intrusive doubly linked list. @@ -295,7 +419,7 @@ struct ListDefaultTag; @endcode - @tparam Element The base type of element which the list will store + @tparam T The base type of element which the list will store pointers to. @tparam Tag An optional unique type name used to distinguish lists and nodes, @@ -303,300 +427,133 @@ struct ListDefaultTag; @ingroup beast_core intrusive */ -template +template class List : public Uncopyable { public: - typedef int size_type; + typedef typename detail::ListNode Node; - typedef Element value_type; - typedef Element& reference; - typedef Element const& const_reference; - typedef Element* pointer; - typedef Element const* const_pointer; + typedef T value_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef value_type const* const_pointer; + typedef value_type const& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; - /** Thrown when some members are called with an empty list. */ - struct empty_list_error : std::logic_error - { - empty_list_error () : std::logic_error ("empty list") - { - } - }; + typedef detail::ListIterator iterator; + typedef detail::ListIterator const_iterator; - class Node : public Uncopyable - { - public: - Node () { } - - private: - friend class List; - Node* m_next; - Node* m_prev; - }; - -private: - template - class iterator_base : public std::iterator < - std::bidirectional_iterator_tag, int > - { - public: - typedef ElemType value_type; - typedef ElemType* pointer; - typedef ElemType& reference; - - iterator_base (NodeType* node = nullptr) : m_node (node) - { - } - - template - iterator_base (iterator_base const& other) - : m_node (other.m_node) - { - } - - template - iterator_base& operator= (iterator_base const& other) - { - m_node = other.m_node; - return *this; - } - - template - bool operator == (iterator_base const& other) const - { - return m_node == other.m_node; - } - - template - bool operator != (iterator_base const& other) const - { - return ! this->operator== (other); - } - - reference operator* () const - { - return dereference (); - } - - pointer operator-> () const - { - return &dereference (); - } - - iterator_base& operator++ () - { - increment (); - return *this; - } - - iterator_base operator++ (int) - { - iterator_base result (*this); - increment (); - return result; - } - - iterator_base& operator-- () - { - decrement (); - return *this; - } - - iterator_base operator-- (int) - { - iterator_base result (*this); - decrement (); - return result; - } - - private: - friend class List; - - NodeType* get_node () - { - return m_node; - } - - NodeType const* get_node () const - { - return m_node; - } - - reference dereference () const - { - return *static_cast (m_node); - } - - bool equal (NodeType* const* node) const - { - return m_node == node; - } - - void increment () - { - bassert (m_node->m_next); - m_node = m_node->m_next; - } - - void decrement () - { - bassert (m_node->m_prev && m_node->m_prev->m_prev != 0); - m_node = m_node->m_prev; - } - - private: - NodeType* m_node; - }; - -public: - /** A read/write List iterator. */ - typedef iterator_base iterator; - - /** A read-only List iterator. */ - typedef iterator_base const_iterator; - -public: /** Create an empty list. */ - List () : m_size (0) + List () { m_head.m_prev = nullptr; // identifies the head m_tail.m_next = nullptr; // identifies the tail clear (); } - /** Returns the number of elements in the list - - @return The number of elements in the list. + /** Determine if the list is empty. + @return `true` if the list is empty. */ - size_type size () const + bool empty () const noexcept + { + return size () == 0; + } + + /** Returns the number of elements in the list. */ + size_type size () const noexcept { return m_size; } /** Obtain a reference to the first element. - @invariant The list may not be empty. - @return A reference to the first element. */ - reference front () + reference front () noexcept { - if (empty ()) - Throw (empty_list_error (), __FILE__, __LINE__); - return element_from (m_head.m_next); } /** Obtain a const reference to the first element. - @invariant The list may not be empty. - @return A const reference to the first element. */ - const_reference front () const + const_reference front () const noexcept { - if (empty ()) - Throw (empty_list_error (), __FILE__, __LINE__); - return element_from (m_head.m_next); } /** Obtain a reference to the last element. - @invariant The list may not be empty. - @return A reference to the last element. */ - reference back () + reference back () noexcept { - if (empty ()) - Throw (empty_list_error (), __FILE__, __LINE__); - return element_from (m_tail.m_prev); } /** Obtain a const reference to the last element. - @invariant The list may not be empty. - @return A const reference to the last element. */ - const_reference back () const + const_reference back () const noexcept { - if (empty ()) - Throw (empty_list_error (), __FILE__, __LINE__); - return element_from (m_tail.m_prev); } /** Obtain an iterator to the beginning of the list. - @return An iterator pointing to the beginning of the list. */ - iterator begin () + iterator begin () noexcept { return iterator (m_head.m_next); } /** Obtain a const iterator to the beginning of the list. - @return A const iterator pointing to the beginning of the list. */ - const_iterator begin () const + const_iterator begin () const noexcept { return const_iterator (m_head.m_next); } /** Obtain a const iterator to the beginning of the list. - @return A const iterator pointing to the beginning of the list. */ - const_iterator cbegin () const + const_iterator cbegin () const noexcept { return const_iterator (m_head.m_next); } /** Obtain a iterator to the end of the list. - @return An iterator pointing to the end of the list. */ - iterator end () + iterator end () noexcept { return iterator (&m_tail); } /** Obtain a const iterator to the end of the list. - @return A constiterator pointing to the end of the list. */ - const_iterator end () const + const_iterator end () const noexcept { return const_iterator (&m_tail); } - /** Obtain a const iterator to the end of the list. - + /** Obtain a const iterator to the end of the list @return A constiterator pointing to the end of the list. */ - const_iterator cend () const + const_iterator cend () const noexcept { return const_iterator (&m_tail); } - /** Determine if the list is empty. - - @return `true` if the list is empty. - */ - bool empty () const - { - return m_head.m_next == &m_tail; - } - /** Clear the list. - @note This does not free the elements. */ - void clear () + void clear () noexcept { m_head.m_next = &m_tail; m_tail.m_prev = &m_head; @@ -604,19 +561,15 @@ public: } /** Insert an element. - @invariant The element must not already be in the list. - @param pos The location to insert after. - - @param elem The element to insert. - + @param element The element to insert. @return An iterator pointing to the newly inserted element. */ - iterator insert (iterator pos, Element& elem) + iterator insert (iterator pos, T& element) noexcept { - Node* node = node_from (elem); - node->m_next = pos.get_node (); + Node* node = static_cast (&element); + node->m_next = &*pos; node->m_prev = node->m_next->m_prev; node->m_next->m_prev = node; node->m_prev->m_next = node; @@ -625,19 +578,16 @@ public: } /** Insert another list into this one. - The other list is cleared. - @param pos The location to insert after. - @param other The list to insert. */ - void insert (iterator pos, List& other) + void insert (iterator pos, List& other) noexcept { if (!other.empty ()) { - Node* before = pos.get_node (); + Node* before = &*pos; other.m_head.m_next->m_prev = before->m_prev; before->m_prev->m_next = other.m_head.m_next; other.m_tail.m_prev->m_next = before; @@ -648,16 +598,13 @@ public: } /** Remove an element. - @invariant The element must exist in the list. - @param pos An iterator pointing to the element to remove. - @return An iterator pointing to the next element after the one removed. */ - iterator erase (iterator pos) + iterator erase (iterator pos) noexcept { - Node* node = pos.get_node (); + Node* node = &*pos; ++pos; node->m_next->m_prev = node->m_prev; node->m_prev->m_next = node->m_next; @@ -666,54 +613,47 @@ public: } /** Insert an element at the beginning of the list. - @invariant The element must not exist in the list. - - @param elem The element to insert. + @param element The element to insert. */ - void push_front (Element& elem) + iterator push_front (T& element) noexcept { - insert (begin (), elem); + return insert (begin (), element); } /** Remove the element at the beginning of the list. - @invariant The list must not be empty. @return A reference to the popped element. */ - Element& pop_front () + T& pop_front () noexcept { - Element& elem (front ()); + T& element (front ()); erase (begin ()); - return elem; + return element; } /** Append an element at the end of the list. - @invariant The element must not exist in the list. - - @param elem The element to append. + @param element The element to append. */ - void push_back (Element& elem) + iterator push_back (T& element) noexcept { - insert (end (), elem); + return insert (end (), element); } /** Remove the element at the end of the list. - @invariant The list must not be empty. @return A reference to the popped element. */ - Element& pop_back () + T& pop_back () noexcept { - Element& elem (back ()); + T& element (back ()); erase (--end ()); - return elem; + return element; } - /** Swap contents with another list. - */ - void swap (List& other) + /** Swap contents with another list. */ + void swap (List& other) noexcept { List temp; temp.append (other); @@ -722,72 +662,52 @@ public: } /** Insert another list at the beginning of this list. - The other list is cleared. - @param list The other list to insert. */ - void prepend (List& list) + iterator prepend (List& list) noexcept { - insert (begin (), list); + return insert (begin (), list); } /** Append another list at the end of this list. - The other list is cleared. - @param list the other list to append. */ - void append (List& list) + iterator append (List& list) noexcept { - insert (end (), list); + return insert (end (), list); } /** Obtain an iterator from an element. - @invariant The element must exist in the list. - - @param elem The element to obtain an iterator for. - + @param element The element to obtain an iterator for. @return An iterator to the element. */ - iterator iterator_to (Element& elem) const + iterator iterator_to (T& element) const noexcept { - return iterator (static_cast (&elem)); + return iterator (static_cast (&element)); } /** Obtain a const iterator from an element. - @invariant The element must exist in the list. - - @param elem The element to obtain an iterator for. - + @param element The element to obtain an iterator for. @return A const iterator to the element. */ - const_iterator const_iterator_to (Element const& elem) const + const_iterator const_iterator_to (T const& element) const noexcept { - return const_iterator (static_cast (&elem)); + return const_iterator (static_cast (&element)); } private: - inline reference element_from (Node* node) + reference element_from (Node* node) noexcept { - return * (static_cast (node)); + return *(static_cast (node)); } - inline const_reference element_from (Node const* node) const + const_reference element_from (Node const* node) const noexcept { - return * (static_cast (node)); - } - - inline Node* node_from (Element& elem) - { - return static_cast (&elem); - } - - inline Node const* node_from (Element const& elem) const - { - return static_cast (&elem); + return *(static_cast (node)); } private: diff --git a/modules/beast_core/containers/beast_HashMap.h b/modules/beast_core/containers/beast_HashMap.h deleted file mode 100644 index 75eebdbfa4..0000000000 --- a/modules/beast_core/containers/beast_HashMap.h +++ /dev/null @@ -1,487 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Portions of this file are from JUCE. - Copyright (c) 2013 - Raw Material Software Ltd. - Please visit http://www.juce.com - - 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. -*/ -//============================================================================== - -#ifndef BEAST_HASHMAP_H_INCLUDED -#define BEAST_HASHMAP_H_INCLUDED - -#include "beast_OwnedArray.h" -#include "beast_LinkedListPointer.h" -#include "../memory/beast_ScopedPointer.h" - -/** Simple hash functions for use with HashMap. - - @see HashMap -*/ -// VFALCO TODO Rewrite the hash functions to return a uint32, and not -// take the upperLimit parameter. Just do the mod in the -// calling function for simplicity. -class DefaultHashFunctions -{ -public: - /** Generates a simple hash from an integer. */ - int generateHash (const int key, const int upperLimit) const noexcept { return std::abs (key) % upperLimit; } - /** Generates a simple hash from an int64. */ - int generateHash (const int64 key, const int upperLimit) const noexcept { return std::abs ((int) key) % upperLimit; } - /** Generates a simple hash from a string. */ - int generateHash (const String& key, const int upperLimit) const noexcept { return (int) (((uint32) key.hashCode()) % (uint32) upperLimit); } - /** Generates a simple hash from a variant. */ - int generateHash (const var& key, const int upperLimit) const noexcept { return generateHash (key.toString(), upperLimit); } -}; - -#if 0 -/** Hardened hash functions for use with HashMap. - - The seed is used to make the hash unpredictable. This prevents - attackers from exploiting crafted inputs to produce degenerate - containers. -*/ -class HardenedHashFunctions -{ -public: - /** Construct a hash function. - - If a seed is specified it will be used, else a random seed - will be generated from the system. - - @param seedToUse An optional seed to use. - */ - explicit HardenedHashFunctions (int seedToUse = Random::getSystemRandom ().nextInt ()) - : m_seed (seedToUse) - { - } - - // VFALCO TODO Need hardened versions of these functions which use the seed! - -private: - int m_seed; -}; -#endif - -//============================================================================== -/** - Holds a set of mappings between some key/value pairs. - - The types of the key and value objects are set as template parameters. - You can also specify a class to supply a hash function that converts a key value - into an hashed integer. This class must have the form: - - @code - struct MyHashGenerator - { - int generateHash (MyKeyType key, int upperLimit) - { - // The function must return a value 0 <= x < upperLimit - return someFunctionOfMyKeyType (key) % upperLimit; - } - }; - @endcode - - Like the Array class, the key and value types are expected to be copy-by-value - types, so if you define them to be pointer types, this class won't delete the - objects that they point to. - - If you don't supply a class for the HashFunctionToUse template parameter, the - default one provides some simple mappings for strings and ints. - - @code - HashMap hash; - hash.set (1, "item1"); - hash.set (2, "item2"); - - DBG (hash [1]); // prints "item1" - DBG (hash [2]); // prints "item2" - - // This iterates the map, printing all of its key -> value pairs.. - for (HashMap::Iterator i (hash); i.next();) - DBG (i.getKey() << " -> " << i.getValue()); - @endcode - - @tparam HashFunctionToUse The type of hash functions, which must be copy - constructible. - - @see CriticalSection, DefaultHashFunctions, NamedValueSet, SortedSet -*/ -template -class HashMap - : public Uncopyable - , LeakChecked > -{ -private: - typedef PARAMETER_TYPE (KeyType) KeyTypeParameter; - typedef PARAMETER_TYPE (ValueType) ValueTypeParameter; - -public: - //============================================================================== - /** Creates an empty hash-map. - - The numberOfSlots parameter specifies the number of hash entries the map will - use. This will be the "upperLimit" parameter that is passed to your generateHash() - function. The number of hash slots will grow automatically if necessary, or - it can be remapped manually using remapTable(). - - @param hashFunctionToUse An instance of HashFunctionToUse, which will be - copied and stored to use with the HashMap. This - can be left out if HashFunctionToUse has a default - constructor. - */ - explicit HashMap (const int numberOfSlots = defaultHashTableSize, - HashFunctionToUse hashFunctionToUse_ = HashFunctionToUse ()) - : hashFunctionToUse (hashFunctionToUse_) - , totalNumItems (0) - { - slots.insertMultiple (0, nullptr, numberOfSlots); - } - - /** Destructor. */ - ~HashMap() - { - clear(); - } - - //============================================================================== - /** Removes all values from the map. - Note that this will clear the content, but won't affect the number of slots (see - remapTable and getNumSlots). - */ - void clear() - { - const ScopedLockType sl (getLock()); - - for (int i = slots.size(); --i >= 0;) - { - HashEntry* h = slots.getUnchecked(i); - - while (h != nullptr) - { - const ScopedPointer deleter (h); - h = h->nextEntry; - } - - slots.set (i, nullptr); - } - - totalNumItems = 0; - } - - //============================================================================== - /** Returns the current number of items in the map. */ - inline int size() const noexcept - { - return totalNumItems; - } - - /** Returns the value corresponding to a given key. - If the map doesn't contain the key, a default instance of the value type is returned. - @param keyToLookFor the key of the item being requested - */ - inline ValueType operator[] (KeyTypeParameter keyToLookFor) const - { - const ScopedLockType sl (getLock()); - - for (const HashEntry* entry = slots.getUnchecked (generateHashFor (keyToLookFor)); entry != nullptr; entry = entry->nextEntry) - if (entry->key == keyToLookFor) - return entry->value; - - return ValueType(); - } - - //============================================================================== - /** Returns true if the map contains an item with the specied key. */ - bool contains (KeyTypeParameter keyToLookFor) const - { - const ScopedLockType sl (getLock()); - - for (const HashEntry* entry = slots.getUnchecked (generateHashFor (keyToLookFor)); entry != nullptr; entry = entry->nextEntry) - if (entry->key == keyToLookFor) - return true; - - return false; - } - - /** Returns true if the hash contains at least one occurrence of a given value. */ - bool containsValue (ValueTypeParameter valueToLookFor) const - { - const ScopedLockType sl (getLock()); - - for (int i = getNumSlots(); --i >= 0;) - for (const HashEntry* entry = slots.getUnchecked(i); entry != nullptr; entry = entry->nextEntry) - if (entry->value == valueToLookFor) - return true; - - return false; - } - - //============================================================================== - /** Adds or replaces an element in the hash-map. - If there's already an item with the given key, this will replace its value. Otherwise, a new item - will be added to the map. - */ - void set (KeyTypeParameter newKey, ValueTypeParameter newValue) - { - const ScopedLockType sl (getLock()); - const int hashIndex = generateHashFor (newKey); - - HashEntry* const firstEntry = slots.getUnchecked (hashIndex); - - for (HashEntry* entry = firstEntry; entry != nullptr; entry = entry->nextEntry) - { - if (entry->key == newKey) - { - entry->value = newValue; - return; - } - } - - slots.set (hashIndex, new HashEntry (newKey, newValue, firstEntry)); - ++totalNumItems; - - if (totalNumItems > (getNumSlots() * 3) / 2) - remapTable (getNumSlots() * 2); - } - - /** Removes an item with the given key. */ - void remove (KeyTypeParameter keyToRemove) - { - const ScopedLockType sl (getLock()); - const int hashIndex = generateHashFor (keyToRemove); - HashEntry* entry = slots.getUnchecked (hashIndex); - HashEntry* previous = nullptr; - - while (entry != nullptr) - { - if (entry->key == keyToRemove) - { - const ScopedPointer deleter (entry); - - entry = entry->nextEntry; - - if (previous != nullptr) - previous->nextEntry = entry; - else - slots.set (hashIndex, entry); - - --totalNumItems; - } - else - { - previous = entry; - entry = entry->nextEntry; - } - } - } - - /** Removes all items with the given value. */ - void removeValue (ValueTypeParameter valueToRemove) - { - const ScopedLockType sl (getLock()); - - for (int i = getNumSlots(); --i >= 0;) - { - HashEntry* entry = slots.getUnchecked(i); - HashEntry* previous = nullptr; - - while (entry != nullptr) - { - if (entry->value == valueToRemove) - { - const ScopedPointer deleter (entry); - - entry = entry->nextEntry; - - if (previous != nullptr) - previous->nextEntry = entry; - else - slots.set (i, entry); - - --totalNumItems; - } - else - { - previous = entry; - entry = entry->nextEntry; - } - } - } - } - - /** Remaps the hash-map to use a different number of slots for its hash function. - Each slot corresponds to a single hash-code, and each one can contain multiple items. - @see getNumSlots() - */ - void remapTable (int newNumberOfSlots) - { - HashMap newTable (newNumberOfSlots); - - for (int i = getNumSlots(); --i >= 0;) - for (const HashEntry* entry = slots.getUnchecked(i); entry != nullptr; entry = entry->nextEntry) - newTable.set (entry->key, entry->value); - - swapWith (newTable); - } - - /** Returns the number of slots which are available for hashing. - Each slot corresponds to a single hash-code, and each one can contain multiple items. - @see getNumSlots() - */ - inline int getNumSlots() const noexcept - { - return slots.size(); - } - - //============================================================================== - /** Efficiently swaps the contents of two hash-maps. */ - template - void swapWith (OtherHashMapType& otherHashMap) noexcept - { - const ScopedLockType lock1 (getLock()); - const typename OtherHashMapType::ScopedLockType lock2 (otherHashMap.getLock()); - - slots.swapWith (otherHashMap.slots); - std::swap (totalNumItems, otherHashMap.totalNumItems); - } - - //============================================================================== - /** Returns the CriticalSection that locks this structure. - To lock, you can call getLock().enter() and getLock().exit(), or preferably use - an object of ScopedLockType as an RAII lock for it. - */ - inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return lock; } - - /** Returns the type of scoped lock to use for locking this array */ - typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType; - -private: - //============================================================================== - class HashEntry : public Uncopyable - { - public: - HashEntry (KeyTypeParameter k, ValueTypeParameter val, HashEntry* const next) - : key (k), value (val), nextEntry (next) - {} - - const KeyType key; - ValueType value; - HashEntry* nextEntry; - }; - -public: - //============================================================================== - /** Iterates over the items in a HashMap. - - To use it, repeatedly call next() until it returns false, e.g. - @code - HashMap myMap; - - HashMap::Iterator i (myMap); - - while (i.next()) - { - DBG (i.getKey() << " -> " << i.getValue()); - } - @endcode - - The order in which items are iterated bears no resemblence to the order in which - they were originally added! - - Obviously as soon as you call any non-const methods on the original hash-map, any - iterators that were created beforehand will cease to be valid, and should not be used. - - @see HashMap - */ - class Iterator : LeakChecked , public Uncopyable - { - public: - //============================================================================== - Iterator (const HashMap& hashMapToIterate) - : hashMap (hashMapToIterate), entry (nullptr), index (0) - {} - - /** Moves to the next item, if one is available. - When this returns true, you can get the item's key and value using getKey() and - getValue(). If it returns false, the iteration has finished and you should stop. - */ - bool next() - { - if (entry != nullptr) - entry = entry->nextEntry; - - while (entry == nullptr) - { - if (index >= hashMap.getNumSlots()) - return false; - - entry = hashMap.slots.getUnchecked (index++); - } - - return true; - } - - /** Returns the current item's key. - This should only be called when a call to next() has just returned true. - */ - KeyType getKey() const - { - return entry != nullptr ? entry->key : KeyType(); - } - - /** Returns the current item's value. - This should only be called when a call to next() has just returned true. - */ - ValueType getValue() const - { - return entry != nullptr ? entry->value : ValueType(); - } - - private: - //============================================================================== - const HashMap& hashMap; - HashEntry* entry; - int index; - }; - -private: - //============================================================================== - enum { defaultHashTableSize = 101 }; - friend class Iterator; - - HashFunctionToUse const hashFunctionToUse; - Array slots; - int totalNumItems; - TypeOfCriticalSectionToUse lock; - - int generateHashFor (KeyTypeParameter key) const - { - const int hash = hashFunctionToUse.generateHash (key, getNumSlots()); - bassert (isPositiveAndBelow (hash, getNumSlots())); // your hash function is generating out-of-range numbers! - return hash; - } -}; - - -#endif // BEAST_HASHMAP_H_INCLUDED diff --git a/modules/beast_core/containers/detail/copyconst.h b/modules/beast_core/containers/detail/copyconst.h new file mode 100644 index 0000000000..6b8fc502d2 --- /dev/null +++ b/modules/beast_core/containers/detail/copyconst.h @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +/* + 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. +*/ +//============================================================================== + +#ifndef BEAST_CORE_CONTAINERS_DETAIL_COPYCONST_H_INCLUDED +#define BEAST_CORE_CONTAINERS_DETAIL_COPYCONST_H_INCLUDED + +namespace detail +{ + +// Copy const attribute from T to U if present +template +struct copyconst +{ + typedef typename removecv ::type type; +}; + +template +struct copyconst +{ + typedef U const type; +}; + +template +struct copyconst +{ + typedef U type; +}; + +} + +#endif diff --git a/modules/beast_core/containers/detail/removecv.h b/modules/beast_core/containers/detail/removecv.h new file mode 100644 index 0000000000..19b3d3bc45 --- /dev/null +++ b/modules/beast_core/containers/detail/removecv.h @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +/* + 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. +*/ +//============================================================================== + +#ifndef BEAST_CORE_CONTAINERS_DETAIL_REMOVECV_H_INCLUDED +#define BEAST_CORE_CONTAINERS_DETAIL_REMOVECV_H_INCLUDED + +namespace detail +{ + +// Strip all cv qualifiers from T +template +struct removecv +{ + typedef T type; +}; + +template +struct removecv +{ + typedef typename removecv ::type type; +}; + +template +struct removecv +{ + typedef typename removecv ::type type; +}; + +template +struct removecv +{ + typedef typename removecv ::type type; +}; + +template +struct removecv +{ + typedef typename removecv ::type type; +}; + +template +struct removecv +{ + typedef typename removecv ::type type; +}; + +#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS +template +struct removecv +{ + typedef typename removecv ::type type; +}; +#endif + +} + +#endif diff --git a/modules/beast_core/memory/beast_HeapBlock.h b/modules/beast_core/memory/beast_HeapBlock.h index 935e1e0172..8d4dfc92f8 100644 --- a/modules/beast_core/memory/beast_HeapBlock.h +++ b/modules/beast_core/memory/beast_HeapBlock.h @@ -91,10 +91,17 @@ public: After creation, you can resize the array using the malloc(), calloc(), or realloc() methods. */ - HeapBlock() noexcept : data (nullptr) + HeapBlock() noexcept + : data (nullptr) { } + HeapBlock (HeapBlock& other) + { + data = other.data; + other.data = nullptr; + } + /** Creates a HeapBlock containing a number of elements. The contents of the block are undefined, as it will have been created by a diff --git a/modules/beast_core/thread/detail/TrackedMutex.h b/modules/beast_core/thread/detail/TrackedMutex.h index e291749776..cb835c20b9 100644 --- a/modules/beast_core/thread/detail/TrackedMutex.h +++ b/modules/beast_core/thread/detail/TrackedMutex.h @@ -20,10 +20,6 @@ #ifndef BEAST_CORE_THREAD_DETAIL_TRACKEDMUTEX_H_INCLUDED #define BEAST_CORE_THREAD_DETAIL_TRACKEDMUTEX_H_INCLUDED -#include "../../containers/beast_List.h" -#include "../../memory/beast_Atomic.h" -#include "../../threads/beast_ThreadLocalValue.h" - class TrackedMutex; namespace detail diff --git a/modules/beast_crypto/math/beast_UnsignedInteger.h b/modules/beast_crypto/math/beast_UnsignedInteger.h index f8b5204a2a..4413511b96 100644 --- a/modules/beast_crypto/math/beast_UnsignedInteger.h +++ b/modules/beast_crypto/math/beast_UnsignedInteger.h @@ -21,11 +21,8 @@ #define BEAST_UNSIGNEDINTEGER_H_INCLUDED /** Represents a set of bits of fixed size. - - Integer representations are stored as big endian. - + Integer representations are stored in network / big endian byte order. @note The number of bits represented can only be a multiple of 8. - @tparam Bytes The number of bytes of storage. */ template @@ -44,81 +41,65 @@ public: typedef unsigned char const* const_iterator; /** Hardened hash function for use with HashMap. - The seed is used to make the hash unpredictable. This prevents attackers from exploiting crafted inputs to produce degenerate containers. - @see HashMap */ class HashFunction { public: - /** Construct a hash function. - + /** Construct a hash function If a seed is specified it will be used, else a random seed - will be generated from the system. - + will be generated from the system @param seedToUse An optional seed to use. */ - explicit HashFunction (int seedToUse = Random::getSystemRandom ().nextInt ()) + explicit HashFunction (HashValue seedToUse = Random::getSystemRandom ().nextInt ()) : m_seed (seedToUse) { } - + /** Generates a simple hash from an UnsignedInteger. */ - int generateHash (UnsignedInteger const& key, const int upperLimit) const noexcept + HashValue generateHash (UnsignedInteger const& key) const noexcept { - uint32 hashCode; - Murmur::Hash (key.cbegin (), key.sizeInBytes, m_seed, &hashCode); - // Shouldn't produce negative numbers since upperLimit is an int? - return static_cast (hashCode % upperLimit); + HashValue hash; + Murmur::Hash (key.cbegin (), key.sizeInBytes, m_seed, &hash); + return hash; } private: - int m_seed; + HashValue m_seed; }; /** Construct the object. - The values are uninitialized. */ UnsignedInteger () noexcept { } - /** Copy construction. - */ + /** Construct a copy. */ UnsignedInteger (UnsignedInteger const& other) noexcept { this->operator= (other); } - /** Assignment. + /** Construct from raw memory. + The area pointed to by buffer must be at least Bytes in size, + or else undefined behavior will result. */ + explicit UnsignedInteger (void const* buffer) + { + memcpy (m_byte, buffer, Bytes); + } + + /** Assign from another value. */ UnsignedInteger & operator= (UnsignedInteger const& other) noexcept { memcpy (m_byte, other.m_byte, Bytes); return *this; } - /** Assignment from an integer type. - - @invariant IntegerType must be an unsigned integer type. - */ - // If you get ambiguous calls to overloaded function errors it - // means you're trying to pass a signed integer, which doesn't work here! - // - template - UnsignedInteger & operator= (IntegerType value) - { - static_bassert (Bytes >= sizeof (IntegerType)); - clear (); - value = ByteOrder::swapIfLittleEndian (value); - memcpy (end () - sizeof (value), &value, bmin (Bytes, sizeof (value))); - return *this; - } - /** Create from an integer type. @invariant IntegerType must be an unsigned integer type. @@ -126,8 +107,11 @@ public: template static UnsignedInteger createFromInteger (IntegerType value) { + static_bassert (Bytes >= sizeof (IntegerType)); UnsignedInteger result; - result.operator= (value); + value = toNetworkByteOrder (value); + result.clear (); + memcpy (result.end () - sizeof (value), &value, bmin (Bytes, sizeof (value))); return result; }