From d9f164c7d4d2d6b8a21c6deede14041bfac58564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Thu, 13 Aug 2015 20:13:30 -0700 Subject: [PATCH] Added handle alloc LRU. --- include/bx/handlealloc.h | 412 +++++++++++++++++++++++++++++---------- include/bx/ringbuffer.h | 12 +- tests/handle.cpp | 79 ++++++++ 3 files changed, 396 insertions(+), 107 deletions(-) create mode 100644 tests/handle.cpp diff --git a/include/bx/handlealloc.h b/include/bx/handlealloc.h index 41dbd4f..d0ebf88 100644 --- a/include/bx/handlealloc.h +++ b/include/bx/handlealloc.h @@ -11,101 +11,19 @@ namespace bx { - template - class HandleAllocT - { - public: - static const uint16_t invalid = 0xffff; - - HandleAllocT() - : m_numHandles(0) - { - for (uint16_t ii = 0; ii < MaxHandlesT; ++ii) - { - m_handles[ii] = ii; - } - } - - ~HandleAllocT() - { - } - - const uint16_t* getHandles() const - { - return m_handles; - } - - uint16_t getHandleAt(uint16_t _at) const - { - return m_handles[_at]; - } - - uint16_t getNumHandles() const - { - return m_numHandles; - } - - uint16_t getMaxHandles() const - { - return MaxHandlesT; - } - - uint16_t alloc() - { - if (m_numHandles < MaxHandlesT) - { - uint16_t index = m_numHandles; - ++m_numHandles; - - uint16_t handle = m_handles[index]; - uint16_t* sparse = &m_handles[MaxHandlesT]; - sparse[handle] = index; - return handle; - } - - return invalid; - } - - bool isValid(uint16_t _handle) - { - uint16_t* sparse = &m_handles[MaxHandlesT]; - uint16_t index = sparse[_handle]; - - return index < m_numHandles - && m_handles[index] == _handle - ; - } - - void free(uint16_t _handle) - { - BX_CHECK(0 < m_numHandles, "Freeing invalid handle %d.", _handle); - uint16_t* sparse = &m_handles[MaxHandlesT]; - uint16_t index = sparse[_handle]; - --m_numHandles; - uint16_t temp = m_handles[m_numHandles]; - m_handles[m_numHandles] = _handle; - sparse[temp] = index; - m_handles[index] = temp; - } - - private: - uint16_t m_handles[MaxHandlesT*2]; - uint16_t m_numHandles; - }; - class HandleAlloc { public: - static const uint16_t invalid = 0xffff; + static const uint16_t invalid = UINT16_MAX; - HandleAlloc(uint16_t _maxHandles, void* _handles) - : m_handles( (uint16_t*)_handles) - , m_numHandles(0) + HandleAlloc(uint16_t _maxHandles) + : m_numHandles(0) , m_maxHandles(_maxHandles) { + uint16_t* dense = getDensePtr(); for (uint16_t ii = 0; ii < _maxHandles; ++ii) { - m_handles[ii] = ii; + dense[ii] = ii; } } @@ -115,12 +33,12 @@ namespace bx const uint16_t* getHandles() const { - return m_handles; + return getDensePtr(); } uint16_t getHandleAt(uint16_t _at) const { - return m_handles[_at]; + return getDensePtr()[_at]; } uint16_t getNumHandles() const @@ -140,8 +58,9 @@ namespace bx uint16_t index = m_numHandles; ++m_numHandles; - uint16_t handle = m_handles[index]; - uint16_t* sparse = &m_handles[m_maxHandles]; + uint16_t* dense = getDensePtr(); + uint16_t handle = dense[index]; + uint16_t* sparse = getSparsePtr(); sparse[handle] = index; return handle; } @@ -149,27 +68,43 @@ namespace bx return invalid; } - bool isValid(uint16_t _handle) + bool isValid(uint16_t _handle) const { - uint16_t* sparse = &m_handles[m_maxHandles]; - uint16_t index = sparse[_handle]; + uint16_t* dense = getDensePtr(); + uint16_t* sparse = getSparsePtr(); + uint16_t index = sparse[_handle]; - return (index < m_numHandles && m_handles[index] == _handle); + return index < m_numHandles + && dense[index] == _handle + ; } void free(uint16_t _handle) { - uint16_t* sparse = &m_handles[m_maxHandles]; + uint16_t* dense = getDensePtr(); + uint16_t* sparse = getSparsePtr(); uint16_t index = sparse[_handle]; --m_numHandles; - uint16_t temp = m_handles[m_numHandles]; - m_handles[m_numHandles] = _handle; + uint16_t temp = dense[m_numHandles]; + dense[m_numHandles] = _handle; sparse[temp] = index; - m_handles[index] = temp; + dense[index] = temp; } private: - uint16_t* m_handles; + HandleAlloc(); + + uint16_t* getDensePtr() const + { + uint8_t* ptr = (uint8_t*)reinterpret_cast(this); + return (uint16_t*)&ptr[sizeof(HandleAlloc)]; + } + + uint16_t* getSparsePtr() const + { + return &getDensePtr()[m_maxHandles]; + } + uint16_t m_numHandles; uint16_t m_maxHandles; }; @@ -177,7 +112,7 @@ namespace bx inline HandleAlloc* createHandleAlloc(AllocatorI* _allocator, uint16_t _maxHandles) { uint8_t* ptr = (uint8_t*)BX_ALLOC(_allocator, sizeof(HandleAlloc) + 2*_maxHandles*sizeof(uint16_t) ); - return ::new (ptr) HandleAlloc(_maxHandles, &ptr[sizeof(HandleAlloc)]); + return ::new (ptr) HandleAlloc(_maxHandles); } inline void destroyHandleAlloc(AllocatorI* _allocator, HandleAlloc* _handleAlloc) @@ -186,6 +121,281 @@ namespace bx BX_FREE(_allocator, _handleAlloc); } + template + class HandleAllocT : public HandleAlloc + { + public: + HandleAllocT() + : HandleAlloc(MaxHandlesT) + { + } + + ~HandleAllocT() + { + } + + private: + uint16_t m_padding[2*MaxHandlesT]; + }; + + template + class HandleListT + { + public: + static const uint16_t invalid = UINT16_MAX; + + HandleListT() + : m_front(invalid) + , m_back(invalid) + { + memset(m_links, 0xff, sizeof(m_links) ); + } + + void pushBack(uint16_t _handle) + { + insertAfter(m_back, _handle); + } + + uint16_t popBack() + { + uint16_t last = invalid != m_back + ? m_back + : m_front + ; + + if (invalid != last) + { + remove(last); + } + + return last; + } + + void pushFront(uint16_t _handle) + { + insertBefore(m_front, _handle); + } + + uint16_t popFront() + { + uint16_t front = m_front; + + if (invalid != front) + { + remove(front); + } + + return front; + } + + uint16_t getFront() const + { + return m_front; + } + + uint16_t getBack() const + { + return m_back; + } + + uint16_t getNext(uint16_t _handle) const + { + const Link& curr = m_links[_handle]; + BX_CHECK(!isValid(_handle), "Invalid handle %d!", _handle); + return curr.m_next; + } + + uint16_t getPrev(uint16_t _handle) const + { + const Link& curr = m_links[_handle]; + BX_CHECK(!isValid(_handle), "Invalid handle %d!", _handle); + return curr.m_prev; + } + + void remove(uint16_t _handle) + { + Link& curr = m_links[_handle]; + BX_CHECK(!isValid(_handle), "Invalid handle %d!", _handle); + + if (invalid != curr.m_prev) + { + Link& prev = m_links[curr.m_prev]; + prev.m_next = curr.m_next; + } + else + { + m_front = curr.m_next; + } + + if (invalid != curr.m_next) + { + Link& next = m_links[curr.m_next]; + next.m_prev = curr.m_prev; + } + else + { + m_back = curr.m_prev; + } + + curr.m_prev = invalid; + curr.m_next = invalid; + } + + private: + void insertBefore(int16_t _before, uint16_t _handle) + { + Link& curr = m_links[_handle]; + curr.m_next = _before; + + if (invalid != _before) + { + Link& link = m_links[_before]; + if (invalid != link.m_prev) + { + Link& prev = m_links[link.m_prev]; + prev.m_next = _handle; + } + + curr.m_prev = link.m_prev; + link.m_prev = _handle; + } + + updateFirstLast(_handle); + } + + void insertAfter(uint16_t _after, uint16_t _handle) + { + Link& curr = m_links[_handle]; + curr.m_prev = _after; + + if (invalid != _after) + { + Link& link = m_links[_after]; + if (invalid != link.m_next) + { + Link& next = m_links[link.m_next]; + next.m_prev = _handle; + } + + curr.m_next = link.m_next; + link.m_next = _handle; + } + + updateFirstLast(_handle); + } + + bool isValid(uint16_t _handle) const + { + return _handle < MaxHandlesT; + } + + void updateFirstLast(uint16_t _handle) + { + Link& curr = m_links[_handle]; + + if (invalid == curr.m_prev) + { + m_front = _handle; + } + + if (invalid == curr.m_next) + { + m_back = _handle; + } + } + + uint16_t m_front; + uint16_t m_back; + + struct Link + { + uint16_t m_prev; + uint16_t m_next; + }; + + Link m_links[MaxHandlesT]; + }; + + template + class HandleAllocLruT + { + public: + static const uint16_t invalid = UINT16_MAX; + + 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(); + } + + uint16_t alloc() + { + uint16_t handle = m_alloc.alloc(); + if (invalid != handle) + { + m_list.pushFront(handle); + } + return handle; + } + + bool isValid(uint16_t _handle) const + { + return m_alloc.isValid(_handle); + } + + void free(uint16_t _handle) + { + BX_CHECK(isValid(_handle), "Invalid handle %d!", _handle); + m_list.remove(_handle); + m_alloc.free(_handle); + } + + void touch(uint16_t _handle) + { + BX_CHECK(isValid(_handle), "Invalid handle %d!", _handle); + m_list.remove(_handle); + m_list.pushFront(_handle); + } + + uint16_t getFront() const + { + return m_list.getFront(); + } + + uint16_t getBack() const + { + return m_list.getBack(); + } + + uint16_t getNext(uint16_t _handle) const + { + return m_list.getNext(_handle); + } + + uint16_t getPrev(uint16_t _handle) const + { + return m_list.getPrev(_handle); + } + + private: + HandleListT m_list; + HandleAllocT m_alloc; + }; + } // namespace bx #endif // BX_HANDLE_ALLOC_H_HEADER_GUARD diff --git a/include/bx/ringbuffer.h b/include/bx/ringbuffer.h index 6dff4f2..8b24e0e 100644 --- a/include/bx/ringbuffer.h +++ b/include/bx/ringbuffer.h @@ -40,7 +40,7 @@ namespace bx uint32_t consume(uint32_t _size) // consumer only { const uint32_t maxSize = distance(m_read, m_current); - const uint32_t sizeNoSign = uint32_and(_size, 0x7FFFFFFF); + const uint32_t sizeNoSign = uint32_and(_size, 0x7fffffff); const uint32_t test = uint32_sub(sizeNoSign, maxSize); const uint32_t size = uint32_sels(test, _size, maxSize); const uint32_t advance = uint32_add(m_read, size); @@ -53,7 +53,7 @@ namespace bx { const uint32_t dist = distance(m_write, m_read)-1; const uint32_t maxSize = uint32_sels(dist, m_size-1, dist); - const uint32_t sizeNoSign = uint32_and(_size, 0x7FFFFFFF); + const uint32_t sizeNoSign = uint32_and(_size, 0x7fffffff); const uint32_t test = uint32_sub(sizeNoSign, maxSize); const uint32_t size = uint32_sels(test, _size, maxSize); const uint32_t advance = uint32_add(m_write, size); @@ -65,7 +65,7 @@ namespace bx uint32_t commit(uint32_t _size) // producer only { const uint32_t maxSize = distance(m_current, m_write); - const uint32_t sizeNoSign = uint32_and(_size, 0x7FFFFFFF); + const uint32_t sizeNoSign = uint32_and(_size, 0x7fffffff); const uint32_t test = uint32_sub(sizeNoSign, maxSize); const uint32_t size = uint32_sels(test, _size, maxSize); const uint32_t advance = uint32_add(m_current, size); @@ -124,7 +124,7 @@ namespace bx uint32_t consume(uint32_t _size) // consumer only { const uint32_t maxSize = distance(m_read, m_current); - const uint32_t sizeNoSign = uint32_and(_size, 0x7FFFFFFF); + const uint32_t sizeNoSign = uint32_and(_size, 0x7fffffff); const uint32_t test = uint32_sub(sizeNoSign, maxSize); const uint32_t size = uint32_sels(test, _size, maxSize); const uint32_t advance = uint32_add(m_read, size); @@ -137,7 +137,7 @@ namespace bx { const uint32_t dist = distance(m_write, m_read)-1; const uint32_t maxSize = uint32_sels(dist, m_size-1, dist); - const uint32_t sizeNoSign = uint32_and(_size, 0x7FFFFFFF); + const uint32_t sizeNoSign = uint32_and(_size, 0x7fffffff); const uint32_t test = uint32_sub(sizeNoSign, maxSize); const uint32_t size = uint32_sels(test, _size, maxSize); const uint32_t advance = uint32_add(m_write, size); @@ -149,7 +149,7 @@ namespace bx uint32_t commit(uint32_t _size) // producer only { const uint32_t maxSize = distance(m_current, m_write); - const uint32_t sizeNoSign = uint32_and(_size, 0x7FFFFFFF); + const uint32_t sizeNoSign = uint32_and(_size, 0x7fffffff); const uint32_t test = uint32_sub(sizeNoSign, maxSize); const uint32_t size = uint32_sels(test, _size, maxSize); const uint32_t advance = uint32_add(m_current, size); diff --git a/tests/handle.cpp b/tests/handle.cpp new file mode 100644 index 0000000..887d21f --- /dev/null +++ b/tests/handle.cpp @@ -0,0 +1,79 @@ +/* + * Copyright 2010-2015 Branimir Karadzic. All rights reserved. + * License: http://www.opensource.org/licenses/BSD-2-Clause + */ + +#include "test.h" +#include + +TEST(HandleListT) +{ + bx::HandleListT<32> list; + + list.pushBack(16); + CHECK(list.getFront() == 16); + CHECK(list.getBack() == 16); + + list.pushFront(7); + CHECK(list.getFront() == 7); + CHECK(list.getBack() == 16); + + uint16_t expected0[] = { 15, 31, 7, 16, 17, 11, 13 }; + list.pushBack(17); + list.pushBack(11); + list.pushBack(13); + list.pushFront(31); + list.pushFront(15); + uint16_t count = 0; + for (uint16_t it = list.getFront(); it != UINT16_MAX; it = list.getNext(it), ++count) + { + CHECK(it == expected0[count]); + } + CHECK(count == BX_COUNTOF(expected0) ); + + list.remove(17); + list.remove(31); + list.remove(16); + list.pushBack(16); + uint16_t expected1[] = { 15, 7, 11, 13, 16 }; + count = 0; + for (uint16_t it = list.getFront(); it != UINT16_MAX; it = list.getNext(it), ++count) + { + CHECK(it == expected1[count]); + } + CHECK(count == BX_COUNTOF(expected1) ); + + list.popBack(); + list.popFront(); + list.popBack(); + list.popBack(); + + CHECK(list.getFront() == 7); + CHECK(list.getBack() == 7); + + list.popBack(); + CHECK(list.getFront() == UINT16_MAX); + CHECK(list.getBack() == UINT16_MAX); +} + +TEST(HandleAllocLruT) +{ + bx::HandleAllocLruT<16> lru; + + uint16_t handle[4] = + { + lru.alloc(), + lru.alloc(), + lru.alloc(), + lru.alloc(), + }; + + lru.touch(handle[3]); + + uint16_t expected0[] = { handle[3], handle[0], handle[1], handle[2] }; + uint16_t count = 0; + for (uint16_t it = lru.getFront(); it != UINT16_MAX; it = lru.getNext(it), ++count) + { + CHECK(it == expected0[count]); + } +}