mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-04 11:15:56 +00:00
Added DynamicArray, DynamicList, and HashMap
This commit is contained in:
@@ -110,9 +110,12 @@
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_ArrayAllocationBase.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_DynamicObject.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_ElementComparator.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_HashMap.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\detail\copyconst.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\detail\removecv.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\DynamicArray.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\HashMap.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_LinkedListPointer.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_List.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\List.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_LockFreeQueue.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_LockFreeStack.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_NamedValueSet.h" />
|
||||
@@ -124,7 +127,9 @@
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_SortedLookupTable.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_SortedSet.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_SparseSet.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\DynamicList.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_Variant.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\lashMap.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\diagnostic\beast_Debug.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\diagnostic\beast_Error.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\diagnostic\beast_FatalError.h" />
|
||||
@@ -450,6 +455,18 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\containers\DynamicArray.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\containers\DynamicList.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\diagnostic\beast_Debug.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
|
||||
@@ -161,6 +161,9 @@
|
||||
<Filter Include="beast_extras\traits">
|
||||
<UniqueIdentifier>{bf498396-2e1f-4903-be68-3053ba439af5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_core\containers\detail">
|
||||
<UniqueIdentifier>{08ec13ba-4058-4ad7-afbb-cbb1c6e2fc4a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\modules\beast_core\beast_core.h">
|
||||
@@ -181,9 +184,6 @@
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_ElementComparator.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_HashMap.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_LinkedListPointer.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
@@ -485,9 +485,6 @@
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BeastConfig.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_List.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_CacheLine.h">
|
||||
<Filter>beast_core\memory</Filter>
|
||||
</ClInclude>
|
||||
@@ -920,6 +917,24 @@
|
||||
<ClInclude Include="..\..\modules\beast_core\system\TargetPlatform.h">
|
||||
<Filter>beast_core\system</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\DynamicList.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\DynamicArray.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\HashMap.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\List.h">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\detail\copyconst.h">
|
||||
<Filter>beast_core\containers\detail</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\detail\removecv.h">
|
||||
<Filter>beast_core\containers\detail</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\modules\beast_core\beast_core.cpp">
|
||||
@@ -1399,6 +1414,12 @@
|
||||
<ClCompile Include="..\..\modules\beast_core\system\SystemStats.cpp">
|
||||
<Filter>beast_core\system</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\containers\DynamicArray.cpp">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\containers\DynamicList.cpp">
|
||||
<Filter>beast_core\containers</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="..\..\TODO.txt" />
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
171
modules/beast_core/containers/DynamicArray.cpp
Normal file
171
modules/beast_core/containers/DynamicArray.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
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 <int> (numberToAssign) << ")";
|
||||
beginTestCase (s);
|
||||
|
||||
DynamicArray <T> v;
|
||||
v.assign (numberToAssign);
|
||||
|
||||
pass ();
|
||||
}
|
||||
|
||||
void testReserve ()
|
||||
{
|
||||
String s;
|
||||
s << "reserve (" << String::fromNumber <int> (numberToReserve) << ")";
|
||||
beginTestCase (s);
|
||||
|
||||
DynamicArray <T> v;
|
||||
v.reserve (numberToReserve);
|
||||
|
||||
v.assign (numberToReserve);
|
||||
|
||||
pass ();
|
||||
}
|
||||
|
||||
void testMutate ()
|
||||
{
|
||||
String s;
|
||||
DynamicArray <T> v;
|
||||
|
||||
s = "push_back (" + String::fromNumber <int> (numberToMutate) + ")";
|
||||
beginTestCase (s);
|
||||
for (std::size_t i = 0; i < numberToMutate; ++i)
|
||||
v.push_back (T (String::fromNumber (i)));
|
||||
|
||||
s = "read [] (" + String::fromNumber <int> (numberToMutate) + ")";
|
||||
beginTestCase (s);
|
||||
for (std::size_t i = 0; i < numberToMutate; ++i)
|
||||
expect (v [i].msg == String::fromNumber (i));
|
||||
|
||||
s = "write [] (" + String::fromNumber <int> (numberToMutate) + ")";
|
||||
beginTestCase (s);
|
||||
for (std::size_t i = 0; i < numberToMutate; ++i)
|
||||
v [i].msg = "+" + String::fromNumber (i);
|
||||
|
||||
s = "verify [] (" + String::fromNumber <int> (numberToMutate) + ")";
|
||||
beginTestCase (s);
|
||||
for (std::size_t i = 0; i < numberToMutate; ++i)
|
||||
expect (v [i].msg == String ("+") + String::fromNumber (i));
|
||||
}
|
||||
|
||||
void testIterate ()
|
||||
{
|
||||
typedef DynamicArray <T> 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;
|
||||
728
modules/beast_core/containers/DynamicArray.h
Normal file
728
modules/beast_core/containers/DynamicArray.h
Normal file
@@ -0,0 +1,728 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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_CORE_CONTAINERS_DYNAMICARRAY_H_INCLUDED
|
||||
#define BEAST_CORE_CONTAINERS_DYNAMICARRAY_H_INCLUDED
|
||||
|
||||
template <typename, typename>
|
||||
class DynamicArray;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename V>
|
||||
class DynamicArrayIterator
|
||||
: public std::iterator <std::random_access_iterator_tag,
|
||||
typename V::size_type>
|
||||
{
|
||||
public:
|
||||
typedef typename copyconst <V, typename V::value_type>::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 <typename W>
|
||||
DynamicArrayIterator (DynamicArrayIterator <W> const& u) noexcept
|
||||
: m_v (u.m_v)
|
||||
, m_pos (u.m_pos)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
DynamicArrayIterator& operator= (DynamicArrayIterator <W> const& u) noexcept
|
||||
{
|
||||
m_v = u.m_v;
|
||||
m_pos = u.m_pos;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator== (DynamicArrayIterator <W> const& u) const noexcept
|
||||
{
|
||||
return (m_v == u.m_v) && (m_pos == u.m_pos);
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator!= (DynamicArrayIterator <W> 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 <typename W>
|
||||
difference_type operator- (DynamicArrayIterator <W> const& rhs) const noexcept
|
||||
{
|
||||
return m_pos - rhs.m_pos;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator< (DynamicArrayIterator <W> const& rhs) const noexcept
|
||||
{
|
||||
return m_pos < rhs.m_pos;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator> (DynamicArrayIterator <W> const& rhs) const noexcept
|
||||
{
|
||||
return m_pos > rhs.m_pos;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator<= (DynamicArrayIterator <W> const& rhs) const noexcept
|
||||
{
|
||||
return m_pos <= rhs.m_pos;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator>= (DynamicArrayIterator <W> 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 <typename>
|
||||
friend class DynamicArrayIterator;
|
||||
|
||||
V* m_v;
|
||||
size_type m_pos;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename V>
|
||||
DynamicArrayIterator <V> operator+ (
|
||||
typename DynamicArrayIterator <V>::difference_type n,
|
||||
DynamicArrayIterator <V> iter) noexcept
|
||||
{
|
||||
return iter + n;
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
DynamicArrayIterator <V> operator- (
|
||||
typename DynamicArrayIterator <V>::difference_type n,
|
||||
DynamicArrayIterator <V> iter) noexcept
|
||||
{
|
||||
return iter - n;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename V>
|
||||
class DynamicArrayReverseIterator
|
||||
: public std::iterator <std::random_access_iterator_tag,
|
||||
typename V::size_type>
|
||||
{
|
||||
public:
|
||||
typedef typename copyconst <V, typename V::value_type>::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 <typename W>
|
||||
DynamicArrayReverseIterator (DynamicArrayReverseIterator <W> const& u) noexcept
|
||||
: m_v (u.m_v)
|
||||
, m_pos (u.m_pos)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
DynamicArrayReverseIterator& operator= (DynamicArrayReverseIterator <W> const& u) noexcept
|
||||
{
|
||||
m_v = u.m_v;
|
||||
m_pos = u.m_pos;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator== (DynamicArrayReverseIterator <W> const& u) const noexcept
|
||||
{
|
||||
return (m_v == u.m_v) && (m_pos == u.m_pos);
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator!= (DynamicArrayReverseIterator <W> 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 <typename W>
|
||||
difference_type operator- (DynamicArrayReverseIterator <W> const& rhs) const noexcept
|
||||
{
|
||||
return rhs.m_pos - m_pos;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator< (DynamicArrayReverseIterator <W> const& rhs) const noexcept
|
||||
{
|
||||
return m_pos > rhs.m_pos;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator> (DynamicArrayReverseIterator <W> const& rhs) const noexcept
|
||||
{
|
||||
return m_pos < rhs.m_pos;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator<= (DynamicArrayReverseIterator <W> const& rhs) const noexcept
|
||||
{
|
||||
return m_pos >= rhs.m_pos;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator>= (DynamicArrayReverseIterator <W> 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 <typename>
|
||||
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 <typename V>
|
||||
DynamicArrayReverseIterator <V> operator+ (
|
||||
typename DynamicArrayReverseIterator <V>::difference_type n,
|
||||
DynamicArrayReverseIterator <V> iter) noexcept
|
||||
{
|
||||
return iter + n;
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
DynamicArrayReverseIterator <V> operator- (
|
||||
typename DynamicArrayReverseIterator <V>::difference_type n,
|
||||
DynamicArrayReverseIterator <V> iter) noexcept
|
||||
{
|
||||
return iter - n;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename T,
|
||||
typename Allocator = std::allocator <char> >
|
||||
class DynamicArray
|
||||
{
|
||||
private:
|
||||
typedef PARAMETER_TYPE (T) TParam;
|
||||
|
||||
typedef std::vector <T*> 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 <DynamicArray <T> > iterator;
|
||||
|
||||
typedef detail::DynamicArrayIterator <DynamicArray <T> const> const_iterator;
|
||||
|
||||
typedef detail::DynamicArrayReverseIterator <DynamicArray <T> > reverse_iterator;
|
||||
|
||||
typedef detail::DynamicArrayReverseIterator <DynamicArray <T> 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 <size_type>::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 <T*> (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 <class A1>
|
||||
iterator emplace_back (A1 a1)
|
||||
{
|
||||
::new (alloc ()) T (a1);
|
||||
return iterator (this, size () - 1);
|
||||
}
|
||||
|
||||
template <class A1, class A2>
|
||||
iterator emplace_back (A1 a1, A2 a2)
|
||||
{
|
||||
::new (alloc ()) T (a1, a2);
|
||||
return iterator (this, size () - 1);
|
||||
}
|
||||
|
||||
template <class A1, class A2, class A3>
|
||||
iterator emplace_back (A1 a1, A2 a2, A3 a3)
|
||||
{
|
||||
::new (alloc ()) T (a1, a2, a3);
|
||||
return iterator (this, size () - 1);
|
||||
}
|
||||
|
||||
template <class A1, class A2, class A3, class A4>
|
||||
iterator emplace_back (A1 a1, A2 a2, A3 a3, A4 a4)
|
||||
{
|
||||
::new (alloc ()) T (a1, a2, a3, a4);
|
||||
return iterator (this, size () - 1);
|
||||
}
|
||||
|
||||
template <class A1, class A2, class A3, class A4, class A5>
|
||||
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
|
||||
70
modules/beast_core/containers/DynamicList.cpp
Normal file
70
modules/beast_core/containers/DynamicList.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
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 <int> (numberToAssign) << ")";
|
||||
beginTestCase (s);
|
||||
|
||||
pass ();
|
||||
}
|
||||
|
||||
void runTest ()
|
||||
{
|
||||
testAssign ();
|
||||
}
|
||||
|
||||
DynamicListTests () : UnitTest ("DynamicList", "beast")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static DynamicListTests DynamicListTests;
|
||||
452
modules/beast_core/containers/DynamicList.h
Normal file
452
modules/beast_core/containers/DynamicList.h
Normal file
@@ -0,0 +1,452 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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_CORE_CONTAINERS_DYNAMICLIST_H_INCLUDED
|
||||
#define BEAST_CORE_CONTAINERS_DYNAMICLIST_H_INCLUDED
|
||||
|
||||
template <typename, typename>
|
||||
class DynamicList;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename I>
|
||||
class DynamicListIterator
|
||||
: public std::iterator <std::bidirectional_iterator_tag,
|
||||
typename I::size_type>
|
||||
{
|
||||
public:
|
||||
typedef typename I::value_type ItemType; // this will be <Item>
|
||||
typedef typename ItemType::value_type T; // this is the original T
|
||||
|
||||
typedef typename copyconst <ItemType, T>::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 <typename J>
|
||||
DynamicListIterator (DynamicListIterator <J> const& other) noexcept
|
||||
: m_iter (other.m_iter)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename J>
|
||||
DynamicListIterator& operator= (DynamicListIterator <J> const& other) noexcept
|
||||
{
|
||||
m_iter = other.m_iter;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename J>
|
||||
bool operator== (DynamicListIterator <J> const& other) const noexcept
|
||||
{
|
||||
return m_iter == other.m_iter;
|
||||
}
|
||||
|
||||
template <typename J>
|
||||
bool operator != (DynamicListIterator <J> 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 <typename, typename>
|
||||
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 <typename T,
|
||||
typename Allocator = std::allocator <char> >
|
||||
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 <Item>::Node
|
||||
{
|
||||
typedef T value_type;
|
||||
|
||||
T* get () noexcept
|
||||
{
|
||||
return reinterpret_cast <T*> (&storage [0]);
|
||||
}
|
||||
|
||||
T const* get () const noexcept
|
||||
{
|
||||
return reinterpret_cast <T const*> (&storage [0]);
|
||||
}
|
||||
|
||||
private:
|
||||
// Lets hope this is padded correctly
|
||||
uint8 storage [sizeof (T)];
|
||||
};
|
||||
|
||||
public:
|
||||
typedef detail::DynamicListIterator <
|
||||
typename List <Item>::iterator> iterator;
|
||||
|
||||
typedef detail::DynamicListIterator <
|
||||
typename List <Item>::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 <size_type>::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 <Item*> (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<T> is true
|
||||
for (typename List <Item>::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 <class A1>
|
||||
iterator emplace_back (A1 a1)
|
||||
{
|
||||
return iterator_to (*::new (alloc ()->get ()) T (a1));
|
||||
}
|
||||
|
||||
template <class A1, class A2>
|
||||
iterator emplace_back (A1 a1, A2 a2)
|
||||
{
|
||||
return iterator_to (*::new (alloc ()->get ()) T (a1, a2));
|
||||
}
|
||||
|
||||
template <class A1, class A2, class A3>
|
||||
iterator emplace_back (A1 a1, A2 a2, A3 a3)
|
||||
{
|
||||
return iterator_to (*::new (alloc ()->get ()) T (a1, a2, a3));
|
||||
}
|
||||
|
||||
template <class A1, class A2, class A3, class A4>
|
||||
iterator emplace_back (A1 a1, A2 a2, A3 a3, A4 a4)
|
||||
{
|
||||
return iterator_to (*::new (alloc ()->get ()) T (a1, a2, a3, a4));
|
||||
}
|
||||
|
||||
template <class A1, class A2, class A3, class A4, class A5>
|
||||
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 <Item*> blocks_t;
|
||||
|
||||
Allocator m_allocator;
|
||||
size_type m_blocksize;
|
||||
size_type m_capacity;
|
||||
std::vector <Item*> m_handles;
|
||||
List <Item> m_items;
|
||||
List <Item> m_free;
|
||||
};
|
||||
|
||||
#endif
|
||||
833
modules/beast_core/containers/HashMap.h
Normal file
833
modules/beast_core/containers/HashMap.h
Normal file
@@ -0,0 +1,833 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <typename M, typename I>
|
||||
class HashMapLocalIterator
|
||||
: public std::iterator <std::forward_iterator_tag, typename M::size_type>
|
||||
{
|
||||
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 <typename N, typename J>
|
||||
HashMapLocalIterator (HashMapLocalIterator <N, J> const& other)
|
||||
: m_map (other.m_map)
|
||||
, m_iter (other.m_iter)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename N, typename J>
|
||||
HashMapLocalIterator& operator= (HashMapLocalIterator <N, J> const& other)
|
||||
{
|
||||
m_map = other.m_map;
|
||||
m_iter = other.m_iter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename N, typename J>
|
||||
bool operator== (HashMapLocalIterator <N, J> const& other)
|
||||
{
|
||||
return m_map == other.m_map && m_iter == other.m_iter;
|
||||
}
|
||||
|
||||
template <typename N, typename J>
|
||||
bool operator!= (HashMapLocalIterator <N, J> 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 <typename M>
|
||||
class HashMapIterator
|
||||
: public std::iterator <std::forward_iterator_tag, typename M::size_type>
|
||||
{
|
||||
private:
|
||||
typedef typename M::Item Item;
|
||||
typedef typename M::Bucket Bucket;
|
||||
typedef detail::ListIterator <typename detail::copyconst <M,
|
||||
typename List <Bucket>::Node>::type> bucket_iterator;
|
||||
typedef detail::ListIterator <typename detail::copyconst <M,
|
||||
typename List <Item, Bucket>::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 <typename N>
|
||||
HashMapIterator (HashMapIterator <N> const& other) noexcept
|
||||
: m_map (other.m_map)
|
||||
, m_bucket (other.m_bucket)
|
||||
, m_local (other.m_local)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename N>
|
||||
HashMapIterator& operator= (HashMapIterator <N> const& other) noexcept
|
||||
{
|
||||
m_map = other.m_map;
|
||||
m_bucket = other.m_bucket;
|
||||
m_local = other.m_local;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename N>
|
||||
bool operator== (HashMapIterator <N> const& other) noexcept
|
||||
{
|
||||
return m_map == other.m_map &&
|
||||
m_bucket == other.m_bucket &&
|
||||
m_local == other.m_local;
|
||||
}
|
||||
|
||||
template <typename N>
|
||||
bool operator!= (HashMapIterator <N> 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 <typename, typename, typename, typename, typename>
|
||||
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 Key,
|
||||
typename T,
|
||||
typename Hash = DefaultHashFunctions,
|
||||
typename KeyEqual = std::equal_to <Key>,
|
||||
typename Allocator = std::allocator <char> >
|
||||
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 <typename M, typename I>
|
||||
friend class detail::HashMapLocalIterator;
|
||||
|
||||
class Item;
|
||||
|
||||
// Each non-empty bucket is in the linked list.
|
||||
struct Bucket : List <Bucket>::Node
|
||||
{
|
||||
Bucket ()
|
||||
{
|
||||
}
|
||||
|
||||
inline bool empty () const noexcept
|
||||
{
|
||||
return items.empty ();
|
||||
}
|
||||
|
||||
List <Item, Bucket> items;
|
||||
|
||||
private:
|
||||
Bucket& operator= (Bucket const&);
|
||||
Bucket (Bucket const&);
|
||||
};
|
||||
|
||||
// Every item in the map is in one linked list
|
||||
struct Item
|
||||
: List <Item>::Node
|
||||
, List <Item, Bucket>::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 <HashMap <Key, T, Hash> > iterator;
|
||||
typedef detail::HashMapIterator <HashMap <Key, T, Hash> const> const_iterator;
|
||||
|
||||
typedef detail::HashMapLocalIterator <
|
||||
HashMap <Key, T, Hash>,
|
||||
typename List <Item, Bucket>::iterator> local_iterator;
|
||||
|
||||
typedef detail::HashMapLocalIterator <
|
||||
HashMap <Key, T, Hash> const,
|
||||
typename List <Item, Bucket>::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 <size_type>::max ();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (typename DynamicList <Item>::iterator iter = m_items.begin ();
|
||||
iter != m_items.end ();)
|
||||
{
|
||||
typename DynamicList <Item>::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 <Item, Bucket>::iterator iter (b.items.begin ());
|
||||
iter != b.items.end ();)
|
||||
{
|
||||
typename List <Item, Bucket>::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 <Item, Bucket>::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 <size_type>::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 <Item>::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 <Item, Bucket>::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 <Item, Bucket>::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 <Item, Bucket>::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 <typename M>
|
||||
friend class detail::HashMapIterator;
|
||||
|
||||
Hash m_hash;
|
||||
KeyEqual m_equal;
|
||||
Allocator m_allocator;
|
||||
DynamicList <Item> m_items;
|
||||
DynamicArray <Bucket> m_buckets;
|
||||
List <Item> m_itemlist;
|
||||
List <Bucket> m_bucketlist;
|
||||
float m_max_load_factor;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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 <typename, typename>
|
||||
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 <typename T, typename Tag>
|
||||
class ListNode : public Uncopyable
|
||||
{
|
||||
private:
|
||||
typedef T value_type;
|
||||
|
||||
template <typename, typename>
|
||||
friend class List;
|
||||
|
||||
template <typename>
|
||||
friend class ListIterator;
|
||||
|
||||
ListNode* m_next;
|
||||
ListNode* m_prev;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Default tag for List.
|
||||
template <typename N>
|
||||
class ListIterator : public std::iterator <
|
||||
std::bidirectional_iterator_tag, std::size_t>
|
||||
{
|
||||
public:
|
||||
typedef typename copyconst <N, typename N::value_type>::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 <typename M>
|
||||
ListIterator (ListIterator <M> const& other) noexcept
|
||||
: m_node (other.m_node)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
ListIterator& operator= (ListIterator <M> const& other) noexcept
|
||||
{
|
||||
m_node = other.m_node;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
template <typename M>
|
||||
bool operator== (ListIterator <M> const& other) const noexcept
|
||||
{
|
||||
return m_node == other.m_node;
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
bool operator!= (ListIterator <M> 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 <reference> (*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 <class Element, class Tag = ListDefaultTag>
|
||||
template <typename T, typename Tag = void>
|
||||
class List : public Uncopyable
|
||||
{
|
||||
public:
|
||||
typedef int size_type;
|
||||
typedef typename detail::ListNode <T, Tag> 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 <Node> iterator;
|
||||
typedef detail::ListIterator <Node const> const_iterator;
|
||||
|
||||
class Node : public Uncopyable
|
||||
{
|
||||
public:
|
||||
Node () { }
|
||||
|
||||
private:
|
||||
friend class List;
|
||||
Node* m_next;
|
||||
Node* m_prev;
|
||||
};
|
||||
|
||||
private:
|
||||
template <class ElemType, class NodeType>
|
||||
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 <class OtherElemType, class OtherNodeType>
|
||||
iterator_base (iterator_base <OtherElemType, OtherNodeType> const& other)
|
||||
: m_node (other.m_node)
|
||||
{
|
||||
}
|
||||
|
||||
template <class OtherElemType, class OtherNodeType>
|
||||
iterator_base& operator= (iterator_base <OtherElemType, OtherNodeType> const& other)
|
||||
{
|
||||
m_node = other.m_node;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class OtherElemType, class OtherNodeType>
|
||||
bool operator == (iterator_base <OtherElemType, OtherNodeType> const& other) const
|
||||
{
|
||||
return m_node == other.m_node;
|
||||
}
|
||||
|
||||
template <class OtherElemType, class OtherNodeType>
|
||||
bool operator != (iterator_base <OtherElemType, OtherNodeType> 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 <ElemType*> (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 <Element, Node> iterator;
|
||||
|
||||
/** A read-only List iterator. */
|
||||
typedef iterator_base <Element const, Node const> 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 <Node*> (&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 <Node*> (&elem));
|
||||
return iterator (static_cast <Node*> (&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 <Node const*> (&elem));
|
||||
return const_iterator (static_cast <Node const*> (&element));
|
||||
}
|
||||
|
||||
private:
|
||||
inline reference element_from (Node* node)
|
||||
reference element_from (Node* node) noexcept
|
||||
{
|
||||
return * (static_cast <pointer> (node));
|
||||
return *(static_cast <pointer> (node));
|
||||
}
|
||||
|
||||
inline const_reference element_from (Node const* node) const
|
||||
const_reference element_from (Node const* node) const noexcept
|
||||
{
|
||||
return * (static_cast <const_pointer> (node));
|
||||
}
|
||||
|
||||
inline Node* node_from (Element& elem)
|
||||
{
|
||||
return static_cast <Node*> (&elem);
|
||||
}
|
||||
|
||||
inline Node const* node_from (Element const& elem) const
|
||||
{
|
||||
return static_cast <Node const*> (&elem);
|
||||
return *(static_cast <const_pointer> (node));
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1,487 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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<int, String> 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<int, String>::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 <typename KeyType,
|
||||
typename ValueType,
|
||||
class HashFunctionToUse = DefaultHashFunctions,
|
||||
class TypeOfCriticalSectionToUse = DummyCriticalSection>
|
||||
class HashMap
|
||||
: public Uncopyable
|
||||
, LeakChecked <HashMap <KeyType,
|
||||
ValueType,
|
||||
HashFunctionToUse,
|
||||
TypeOfCriticalSectionToUse> >
|
||||
{
|
||||
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<HashEntry> 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<HashEntry> 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<HashEntry> 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 <class OtherHashMapType>
|
||||
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 <String, String> myMap;
|
||||
|
||||
HashMap<String, String>::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 <Iterator>, 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 <HashEntry*> 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
|
||||
47
modules/beast_core/containers/detail/copyconst.h
Normal file
47
modules/beast_core/containers/detail/copyconst.h
Normal file
@@ -0,0 +1,47 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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_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 <typename T, typename U>
|
||||
struct copyconst
|
||||
{
|
||||
typedef typename removecv <U>::type type;
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
struct copyconst <T const, U>
|
||||
{
|
||||
typedef U const type;
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
struct copyconst <T const, U const>
|
||||
{
|
||||
typedef U type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
73
modules/beast_core/containers/detail/removecv.h
Normal file
73
modules/beast_core/containers/detail/removecv.h
Normal file
@@ -0,0 +1,73 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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_CORE_CONTAINERS_DETAIL_REMOVECV_H_INCLUDED
|
||||
#define BEAST_CORE_CONTAINERS_DETAIL_REMOVECV_H_INCLUDED
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// Strip all cv qualifiers from T
|
||||
template <typename T>
|
||||
struct removecv
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct removecv <const T>
|
||||
{
|
||||
typedef typename removecv <T>::type type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct removecv <volatile T>
|
||||
{
|
||||
typedef typename removecv <T>::type type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct removecv <const volatile T>
|
||||
{
|
||||
typedef typename removecv <T>::type type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct removecv <T*>
|
||||
{
|
||||
typedef typename removecv <T>::type type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct removecv <T&>
|
||||
{
|
||||
typedef typename removecv <T>::type type;
|
||||
};
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
template <typename T>
|
||||
struct removecv <T&&>
|
||||
{
|
||||
typedef typename removecv <T>::type type;
|
||||
};
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <size_t Bytes>
|
||||
@@ -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 <Bytes> const& key, const int upperLimit) const noexcept
|
||||
HashValue generateHash (UnsignedInteger <Bytes> 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 <int> (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 <Bytes> 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 <Bytes>& 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 <class IntegerType>
|
||||
UnsignedInteger <Bytes>& 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 <class IntegerType>
|
||||
static UnsignedInteger <Bytes> createFromInteger (IntegerType value)
|
||||
{
|
||||
static_bassert (Bytes >= sizeof (IntegerType));
|
||||
UnsignedInteger <Bytes> result;
|
||||
result.operator= (value);
|
||||
value = toNetworkByteOrder <IntegerType> (value);
|
||||
result.clear ();
|
||||
memcpy (result.end () - sizeof (value), &value, bmin (Bytes, sizeof (value)));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user