فهرست منبع

Added handle alloc LRU.

Branimir Karadžić 10 سال پیش
والد
کامیت
d9f164c7d4
3فایلهای تغییر یافته به همراه367 افزوده شده و 78 حذف شده
  1. 282 72
      include/bx/handlealloc.h
  2. 6 6
      include/bx/ringbuffer.h
  3. 79 0
      tests/handle.cpp

+ 282 - 72
include/bx/handlealloc.h

@@ -11,33 +11,34 @@
 
 namespace bx
 {
-	template <uint16_t MaxHandlesT>
-	class HandleAllocT
+	class HandleAlloc
 	{
 	public:
-		static const uint16_t invalid = 0xffff;
+		static const uint16_t invalid = UINT16_MAX;
 
-		HandleAllocT()
+		HandleAlloc(uint16_t _maxHandles)
 			: m_numHandles(0)
+			, m_maxHandles(_maxHandles)
 		{
-			for (uint16_t ii = 0; ii < MaxHandlesT; ++ii)
+			uint16_t* dense = getDensePtr();
+			for (uint16_t ii = 0; ii < _maxHandles; ++ii)
 			{
-				m_handles[ii] = ii;
+				dense[ii] = ii;
 			}
 		}
 
-		~HandleAllocT()
+		~HandleAlloc()
 		{
 		}
 
 		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
@@ -47,18 +48,19 @@ namespace bx
 
 		uint16_t getMaxHandles() const
 		{
-			return MaxHandlesT;
+			return m_maxHandles;
 		}
 
 		uint16_t alloc()
 		{
-			if (m_numHandles < MaxHandlesT)
+			if (m_numHandles < m_maxHandles)
 			{
 				uint16_t index = m_numHandles;
 				++m_numHandles;
 
-				uint16_t handle = m_handles[index];
-				uint16_t* sparse = &m_handles[MaxHandlesT];
+				uint16_t* dense  = getDensePtr();
+				uint16_t  handle = dense[index];
+				uint16_t* sparse = getSparsePtr();
 				sparse[handle] = index;
 				return handle;
 			}
@@ -66,125 +68,333 @@ namespace bx
 			return invalid;
 		}
 
-		bool isValid(uint16_t _handle)
+		bool isValid(uint16_t _handle) const
 		{
-			uint16_t* sparse = &m_handles[MaxHandlesT];
-			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
+				&& dense[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* 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[MaxHandlesT*2];
+		HandleAlloc();
+
+		uint16_t* getDensePtr() const
+		{
+			uint8_t* ptr = (uint8_t*)reinterpret_cast<const uint8_t*>(this);
+			return (uint16_t*)&ptr[sizeof(HandleAlloc)];
+		}
+
+		uint16_t* getSparsePtr() const
+		{
+			return &getDensePtr()[m_maxHandles];
+		}
+
 		uint16_t m_numHandles;
+		uint16_t m_maxHandles;
 	};
 
-	class HandleAlloc
+	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);
+	}
+
+	inline void destroyHandleAlloc(AllocatorI* _allocator, HandleAlloc* _handleAlloc)
+	{
+		_handleAlloc->~HandleAlloc();
+		BX_FREE(_allocator, _handleAlloc);
+	}
+
+	template <uint16_t MaxHandlesT>
+	class HandleAllocT : public HandleAlloc
 	{
 	public:
-		static const uint16_t invalid = 0xffff;
+		HandleAllocT()
+			: HandleAlloc(MaxHandlesT)
+		{
+		}
 
-		HandleAlloc(uint16_t _maxHandles, void* _handles)
-			: m_handles( (uint16_t*)_handles)
-			, m_numHandles(0)
-			, m_maxHandles(_maxHandles)
+		~HandleAllocT()
 		{
-			for (uint16_t ii = 0; ii < _maxHandles; ++ii)
+		}
+
+	private:
+		uint16_t m_padding[2*MaxHandlesT];
+	};
+
+	template <uint16_t MaxHandlesT>
+	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)
 			{
-				m_handles[ii] = ii;
+				remove(last);
 			}
+
+			return last;
 		}
 
-		~HandleAlloc()
+		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 <uint16_t MaxHandlesT>
+	class HandleAllocLruT
+	{
+	public:
+		static const uint16_t invalid = UINT16_MAX;
+
 		const uint16_t* getHandles() const
 		{
-			return m_handles;
+			return m_alloc.getHandles();
 		}
 
 		uint16_t getHandleAt(uint16_t _at) const
 		{
-			return m_handles[_at];
+			return m_alloc.getHandleAt(_at);
 		}
 
 		uint16_t getNumHandles() const
 		{
-			return m_numHandles;
+			return m_alloc.getNumHandles();
 		}
 
 		uint16_t getMaxHandles() const
 		{
-			return m_maxHandles;
+			return m_alloc.getMaxHandles();
 		}
 
 		uint16_t alloc()
 		{
-			if (m_numHandles < m_maxHandles)
+			uint16_t handle = m_alloc.alloc();
+			if (invalid != handle)
 			{
-				uint16_t index = m_numHandles;
-				++m_numHandles;
-
-				uint16_t handle = m_handles[index];
-				uint16_t* sparse = &m_handles[m_maxHandles];
-				sparse[handle] = index;
-				return handle;
+				m_list.pushFront(handle);
 			}
+			return handle;
+		}
 
-			return invalid;
+		bool isValid(uint16_t _handle) const
+		{
+			return m_alloc.isValid(_handle);
 		}
 
-		bool isValid(uint16_t _handle)
+		void free(uint16_t _handle)
 		{
-			uint16_t* sparse = &m_handles[m_maxHandles];
-			uint16_t index = sparse[_handle];
+			BX_CHECK(isValid(_handle), "Invalid handle %d!", _handle);
+			m_list.remove(_handle);
+			m_alloc.free(_handle);
+		}
 
-			return (index < m_numHandles && m_handles[index] == _handle);
+		void touch(uint16_t _handle)
+		{
+			BX_CHECK(isValid(_handle), "Invalid handle %d!", _handle);
+			m_list.remove(_handle);
+			m_list.pushFront(_handle);
 		}
 
-		void free(uint16_t _handle)
+		uint16_t getFront() const
 		{
-			uint16_t* sparse = &m_handles[m_maxHandles];
-			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;
+			return m_list.getFront();
 		}
 
-	private:
-		uint16_t* m_handles;
-		uint16_t m_numHandles;
-		uint16_t m_maxHandles;
-	};
+		uint16_t getBack() const
+		{
+			return m_list.getBack();
+		}
 
-	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)]);
-	}
+		uint16_t getNext(uint16_t _handle) const
+		{
+			return m_list.getNext(_handle);
+		}
 
-	inline void destroyHandleAlloc(AllocatorI* _allocator, HandleAlloc* _handleAlloc)
-	{
-		_handleAlloc->~HandleAlloc();
-		BX_FREE(_allocator, _handleAlloc);
-	}
+		uint16_t getPrev(uint16_t _handle) const
+		{
+			return m_list.getPrev(_handle);
+		}
+
+	private:
+		HandleListT<MaxHandlesT>  m_list;
+		HandleAllocT<MaxHandlesT> m_alloc;
+	};
 
 } // namespace bx
 

+ 6 - 6
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);

+ 79 - 0
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 <bx/handlealloc.h>
+
+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]);
+	}
+}