Added HandleHashMap.

This commit is contained in:
Branimir Karadžić
2016-09-05 20:55:30 -07:00
parent ef5a01f0ea
commit 5fe975a39b
26 changed files with 752 additions and 81 deletions

View File

@@ -8,9 +8,11 @@
#include "bx.h"
#include "allocator.h"
#include "uint32_t.h"
namespace bx
{
///
class HandleAlloc
{
public:
@@ -127,6 +129,7 @@ namespace bx
BX_FREE(_allocator, _handleAlloc);
}
///
template <uint16_t MaxHandlesT>
class HandleAllocT : public HandleAlloc
{
@@ -144,6 +147,7 @@ namespace bx
uint16_t m_padding[2*MaxHandlesT];
};
///
template <uint16_t MaxHandlesT>
class HandleListT
{
@@ -327,6 +331,7 @@ namespace bx
Link m_links[MaxHandlesT];
};
///
template <uint16_t MaxHandlesT>
class HandleAllocLruT
{
@@ -422,6 +427,293 @@ namespace bx
HandleAllocT<MaxHandlesT> m_alloc;
};
///
template <uint32_t MaxCapacityT, typename KeyT = uint32_t>
class HandleHashMapT
{
public:
static const uint16_t invalid = UINT16_MAX;
HandleHashMapT()
: m_maxCapacity(MaxCapacityT)
{
reset();
}
~HandleHashMapT()
{
}
bool insert(KeyT _key, uint16_t _handle)
{
if (invalid == _handle)
{
return false;
}
const KeyT hash = mix(_key);
const uint32_t first = hash % MaxCapacityT;
uint32_t idx = first;
do
{
if (m_handle[idx] == invalid)
{
m_key[idx] = _key;
m_handle[idx] = _handle;
++m_numElements;
return true;
}
if (m_key[idx] == _key)
{
return false;
}
idx = (idx + 1) % MaxCapacityT;
} while (idx != first);
return false;
}
void removeByKey(KeyT _key)
{
uint32_t idx = findIndex(_key);
if (UINT32_MAX != idx)
{
m_handle[idx] = invalid;
--m_numElements;
}
}
void removeByHandle(uint16_t _handle)
{
if (invalid != _handle)
{
for (uint32_t idx = 0; idx < MaxCapacityT; ++idx)
{
if (m_handle[idx] == _handle)
{
m_handle[idx] = invalid;
--m_numElements;
}
}
}
}
uint16_t find(KeyT _key) const
{
uint32_t idx = findIndex(_key);
if (UINT32_MAX != idx)
{
return m_handle[idx];
}
return invalid;
}
void reset()
{
memset(m_handle, 0xff, sizeof(m_handle) );
m_numElements = 0;
}
uint32_t getNumElements() const
{
return m_numElements;
}
uint32_t getMaxCapacity() const
{
return m_maxCapacity;
}
struct Iterator
{
uint16_t handle;
private:
friend class HandleHashMapT<MaxCapacityT, KeyT>;
uint32_t pos;
uint32_t num;
};
Iterator first() const
{
Iterator it;
it.handle = invalid;
it.pos = 0;
it.num = m_numElements;
if (0 == it.num)
{
return it;
}
++it.num;
next(it);
return it;
}
bool next(Iterator& _it) const
{
if (0 == _it.num)
{
return false;
}
for (
;_it.pos < MaxCapacityT && invalid == m_handle[_it.pos]
; ++_it.pos
);
_it.handle = m_handle[_it.pos];
++_it.pos;
--_it.num;
return true;
}
private:
uint32_t findIndex(KeyT _key) const
{
const KeyT hash = mix(_key);
const uint32_t first = hash % MaxCapacityT;
uint32_t idx = first;
do
{
if (m_handle[idx] == invalid)
{
return UINT32_MAX;
}
if (m_key[idx] == _key)
{
return idx;
}
idx = (idx + 1) % MaxCapacityT;
} while (idx != first);
return UINT32_MAX;
}
uint32_t mix(uint32_t _x) const
{
const uint32_t tmp0 = uint32_mul(_x, UINT32_C(2246822519) );
const uint32_t tmp1 = uint32_rol(tmp0, 13);
const uint32_t result = uint32_mul(tmp1, UINT32_C(2654435761) );
return result;
}
uint64_t mix(uint64_t _x) const
{
const uint64_t tmp0 = uint64_mul(_x, UINT64_C(14029467366897019727) );
const uint64_t tmp1 = uint64_rol(tmp0, 31);
const uint64_t result = uint64_mul(tmp1, UINT64_C(11400714785074694791) );
return result;
}
uint32_t m_maxCapacity;
uint32_t m_numElements;
KeyT m_key[MaxCapacityT];
uint16_t m_handle[MaxCapacityT];
};
///
template <uint16_t MaxHandlesT, typename KeyT = uint32_t>
class HandleHashMapAllocT
{
public:
static const uint16_t invalid = UINT16_MAX;
HandleHashMapAllocT()
{
reset();
}
~HandleHashMapAllocT()
{
}
uint16_t alloc(KeyT _key)
{
uint16_t handle = m_alloc.alloc();
if (invalid == handle)
{
return invalid;
}
bool ok = m_table.insert(_key, handle);
if (!ok)
{
m_alloc.free(handle);
return invalid;
}
return handle;
}
void free(KeyT _key)
{
uint16_t handle = m_table.find(_key);
if (invalid == handle)
{
return;
}
m_table.removeByKey(_key);
m_alloc.free(handle);
}
void free(uint16_t _handle)
{
m_table.removeByHandle(_handle);
m_alloc.free(_handle);
}
uint16_t find(KeyT _key) const
{
return m_table.find(_key);
}
const uint16_t* getHandles() const
{
return m_alloc.getHandles();
}
uint16_t getHandleAt(uint16_t _at) const
{
return m_alloc.getHandleAt(_at);
}
uint16_t getNumHandles() const
{
return m_alloc.getNumHandles();
}
uint16_t getMaxHandles() const
{
return m_alloc.getMaxHandles();
}
bool isValid(uint16_t _handle) const
{
return m_alloc.isValid(_handle);
}
void reset()
{
m_table.reset();
m_alloc.reset();
}
private:
HandleHashMapT<MaxHandlesT+MaxHandlesT/2, KeyT> m_table;
HandleAllocT<MaxHandlesT> m_alloc;
};
} // namespace bx
#endif // BX_HANDLE_ALLOC_H_HEADER_GUARD

View File

@@ -162,6 +162,7 @@ namespace bx
template <typename Ty>
inline uint32_t hashMurmur2A(const Ty& _data)
{
BX_STATIC_ASSERT(BX_TYPE_IS_POD(Ty) );
return hashMurmur2A(&_data, sizeof(Ty) );
}

View File

@@ -14,12 +14,146 @@
#include <string.h>
#include <wchar.h> // wchar_t
#include <bx/allocator.h>
#include <bx/hash.h>
#ifndef va_copy
# define va_copy(_a, _b) (_a) = (_b)
#endif // va_copy
namespace bx
{
/// Non-zero-terminated string view.
class StringView
{
public:
StringView()
{
clear();
}
StringView(const char* _ptr, uint32_t _len = UINT32_MAX)
{
clear();
if (NULL != _ptr)
{
uint32_t len = UINT32_MAX == _len ? strlen(_ptr) : _len;
if (0 != len)
{
m_len = len;
m_ptr = _ptr;
}
}
}
void clear()
{
m_ptr = "";
m_len = 0;
}
const char* getPtr() const
{
return m_ptr;
}
const char* getTerm() const
{
return m_ptr + m_len;
}
bool isEmpty() const
{
return 0 == m_len;
}
uint32_t getLength() const
{
return m_len;
}
protected:
friend uint32_t hashMurmur2A(const StringView& _data);
const char* m_ptr;
uint32_t m_len;
};
inline uint32_t hashMurmur2A(const StringView& _data)
{
return hashMurmur2A(_data.m_ptr, _data.m_len);
}
inline uint32_t hashMurmur2A(const char* _data)
{
return hashMurmur2A(StringView(_data) );
}
/// ASCII string
template<bx::AllocatorI** allocator>
class StringT : public StringView
{
public:
StringT()
: StringView("", 0)
{
}
StringT(const char* _rhs)
{
clear();
if (NULL != _rhs)
{
uint32_t len = strlen(_rhs);
m_len = len;
if (0 != len)
{
++len;
char* ptr = (char*)BX_ALLOC(*allocator, len);
memcpy(ptr, _rhs, len);
*const_cast<char**>(&m_ptr) = ptr;
}
}
}
StringT(const StringView& _str)
{
uint32_t len = _str.getLength();
m_len = len;
if (0 != len)
{
++len;
char* ptr = (char*)BX_ALLOC(*allocator, len);
memcpy(ptr, _str.getPtr(), len-1);
ptr[len] = '\0';
*const_cast<char**>(&m_ptr) = ptr;
}
}
~StringT()
{
clear();
}
void clear()
{
if (0 != m_len)
{
BX_FREE(*allocator, const_cast<char*>(m_ptr) );
StringView::clear();
}
}
};
///
inline bool toBool(const char* _str)
{

View File

@@ -692,6 +692,46 @@ namespace bx
#endif // BX_COMPILER_
}
inline uint64_t uint64_sll(uint64_t _a, int _sa)
{
return _a << _sa;
}
inline uint64_t uint64_srl(uint64_t _a, int _sa)
{
return _a >> _sa;
}
inline uint64_t uint64_sra(uint64_t _a, int _sa)
{
return ( (int64_t)_a) >> _sa;
}
inline uint64_t uint64_rol(uint64_t _a, int _sa)
{
return ( _a << _sa) | (_a >> (32-_sa) );
}
inline uint64_t uint64_ror(uint64_t _a, int _sa)
{
return ( _a >> _sa) | (_a << (32-_sa) );
}
inline uint64_t uint64_add(uint64_t _a, uint64_t _b)
{
return _a + _b;
}
inline uint64_t uint64_sub(uint64_t _a, uint64_t _b)
{
return _a - _b;
}
inline uint64_t uint64_mul(uint64_t _a, uint64_t _b)
{
return _a * _b;
}
/// Greatest common divisor.
inline uint32_t uint32_gcd(uint32_t _a, uint32_t _b)
{