diff --git a/tests/nlalloc_test.cpp b/tests/nlalloc_test.cpp new file mode 100644 index 0000000..d216136 --- /dev/null +++ b/tests/nlalloc_test.cpp @@ -0,0 +1,217 @@ +/* + * Copyright 2010-2018 Branimir Karadzic. All rights reserved. + * License: https://github.com/bkaradzic/bx#license-bsd-2-clause + */ + +#include "test.h" +#include +#include + +bx::DefaultAllocator g_allocator0; + +struct TinyStlAllocator +{ + static void* static_allocate(size_t _bytes) + { + return BX_ALLOC(&g_allocator0, _bytes); + } + + static void static_deallocate(void* _ptr, size_t /*_bytes*/) + { + if (NULL != _ptr) + { + BX_FREE(&g_allocator0, _ptr); + } + } +}; + +#define TINYSTL_ALLOCATOR ::TinyStlAllocator +#include + +namespace tinystl +{ + template + class list : public vector + { + public: + void push_front(const T& _value) + { + this->insert(this->begin(), _value); + } + + void pop_front() + { + this->erase(this->begin() ); + } + + void sort() + { + bx::quickSort( + this->begin() + , uint32_t(this->end() - this->begin() ) + , sizeof(T) + , [](const void* _a, const void* _b) -> int32_t { + const T& lhs = *(const T*)(_a); + const T& rhs = *(const T*)(_b); + return lhs < rhs ? -1 : 1; + }); + } + }; + +} // namespace tinystl + +namespace stl = tinystl; + +namespace bx +{ + struct Blk + { + static const uint64_t kInvalid = UINT64_MAX; + + Blk() + : ptr(kInvalid) + , size(0) + { + } + + Blk(uint64_t _ptr, uint32_t _size) + : ptr(_ptr) + , size(_size) + { + } + + uint64_t ptr; + uint32_t size; + }; + + inline bool operator<(const Blk& _lhs, const Blk& _rhs) + { + return _lhs.ptr < _rhs.ptr; + } + + inline bool isValid(const Blk& _blk) + { + return Blk::kInvalid != _blk.ptr; + } + + // First-fit non-local allocator. + class NonLocalAllocator + { + public: + NonLocalAllocator() + { + } + + ~NonLocalAllocator() + { + } + + void reset() + { + m_free.clear(); + m_used = 0; + } + + void add(const Blk& _blk) + { + m_free.push_back(_blk); + } + + Blk remove() + { + BX_CHECK(0 == m_used, ""); + + if (0 < m_free.size() ) + { + Blk freeBlock = m_free.front(); + m_free.pop_front(); + return freeBlock; + } + + return Blk{}; + } + + Blk alloc(uint32_t _size) + { + _size = max(_size, 16u); + + for (FreeList::iterator it = m_free.begin(), itEnd = m_free.end(); it != itEnd; ++it) + { + if (it->size >= _size) + { + uint64_t ptr = it->ptr; + + if (it->size != _size) + { + it->size -= _size; + it->ptr += _size; + } + else + { + m_free.erase(it); + } + + m_used += _size; + return Blk{ ptr, _size }; + } + } + + // there is no block large enough. + return Blk{}; + } + + void free(const Blk& _blk) + { + m_used -= _blk.size; + m_free.push_front(_blk); + } + + bool compact() + { + m_free.sort(); + + for (FreeList::iterator it = m_free.begin(), next = it, itEnd = m_free.end(); next != itEnd;) + { + if ( (it->ptr + it->size) == next->ptr) + { + it->size += next->size; + next = m_free.erase(next); + } + else + { + it = next; + ++next; + } + } + + return 0 == m_used; + } + + uint32_t getUsed() const + { + return m_used; + } + + private: + typedef stl::list FreeList; + FreeList m_free; + uint32_t m_used; + }; +} // namespace bx + +TEST_CASE("nlalloc") +{ + bx::NonLocalAllocator nla; + + bx::Blk blk; + + blk = nla.alloc(100); + REQUIRE(!isValid(blk) ); + nla.add(bx::Blk{0x1000, 100}); + + blk = nla.alloc(100); + REQUIRE(isValid(blk) ); + + nla.free(blk); + REQUIRE(0 == nla.getUsed() ); +}