mirror of
https://github.com/bkaradzic/bx.git
synced 2026-02-20 13:53:15 +01:00
Added HandleHashMap.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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) );
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user