Added DynamicArray, DynamicList, and HashMap

This commit is contained in:
Vinnie Falco
2013-09-01 16:09:07 -07:00
parent 81e5b59060
commit de2c4cc7b8
16 changed files with 2661 additions and 822 deletions

View File

@@ -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>

View File

@@ -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" />

View File

@@ -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"

View File

@@ -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"

View 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;

View 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

View 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;

View 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

View 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

View File

@@ -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:

View File

@@ -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

View 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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}