-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Emerson Knapp <eknapp@amazon.com>
- Loading branch information
Emerson Knapp
committed
May 13, 2019
1 parent
ca1eb86
commit 305400e
Showing
2 changed files
with
223 additions
and
3 deletions.
There are no files selected for viewing
220 changes: 220 additions & 0 deletions
220
osrf_testing_tools_cpp/src/memory_tools/impl/arena_allocator.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,220 @@ | ||
#pragma once | ||
|
||
#include <cassert> | ||
|
||
namespace osrf_testing_tools_cpp | ||
{ | ||
namespace memory_tools | ||
{ | ||
namespace impl | ||
{ | ||
|
||
template <std::size_t MemoryPoolSize, std::size_t Align> | ||
class ArenaAllocator; | ||
|
||
template <std::size_t PoolSize, std::size_t Alignment = alignof(std::max_align_t)> | ||
class MemoryPool | ||
{ | ||
alignas(Alignment) char buf_[PoolSize]; | ||
char* ptr_; | ||
|
||
public: | ||
~MemoryPool() | ||
{ | ||
ptr_ = nullptr; | ||
} | ||
|
||
MemoryPool() noexcept | ||
: ptr_(buf_) | ||
{} | ||
|
||
MemoryPool(const MemoryPool&) = delete; | ||
|
||
MemoryPool& operator=(const MemoryPool&) = delete; | ||
|
||
template <std::size_t ReqAlign> char* allocate(std::size_t n); | ||
|
||
bool deallocate(char* p, std::size_t n) noexcept; | ||
|
||
static constexpr std::size_t size() noexcept | ||
{ | ||
return PoolSize; | ||
} | ||
|
||
std::size_t used() const noexcept | ||
{ | ||
return static_cast<std::size_t>(ptr_ - buf_); | ||
} | ||
|
||
void reset() noexcept | ||
{ | ||
ptr_ = buf_; | ||
} | ||
|
||
private: | ||
static std::size_t | ||
align_up(std::size_t n) noexcept | ||
{ | ||
return (n + (Alignment-1)) & ~(Alignment-1); | ||
} | ||
|
||
bool | ||
pointer_in_buffer(char* p) noexcept | ||
{ | ||
return buf_ <= p && p <= buf_ + PoolSize; | ||
} | ||
|
||
friend class ArenaAllocator<PoolSize, Alignment>; | ||
}; | ||
|
||
template <std::size_t PoolSize, std::size_t Alignment> | ||
template <std::size_t ReqAlign> | ||
char* | ||
MemoryPool<PoolSize, Alignment>::allocate(std::size_t n) | ||
{ | ||
static_assert(ReqAlign <= Alignment, "alignment is too small for this arena"); | ||
assert(pointer_in_buffer(ptr_) && "Allocator has outlived MemoryPool"); | ||
auto const aligned_n = align_up(n); | ||
if (static_cast<decltype(aligned_n)>(buf_ + PoolSize - ptr_) >= aligned_n) | ||
{ | ||
char* r = ptr_; | ||
ptr_ += aligned_n; | ||
return r; | ||
} | ||
|
||
static_assert(Alignment <= alignof(std::max_align_t), "you've chosen an " | ||
"alignment that is larger than alignof(std::max_align_t), and " | ||
"cannot be guaranteed by normal operator new"); | ||
return static_cast<char*>(::operator new(n)); | ||
} | ||
|
||
template <std::size_t PoolSize, std::size_t Alignment> | ||
bool | ||
MemoryPool<PoolSize, Alignment>::deallocate(char* p, std::size_t n) noexcept | ||
{ | ||
assert(pointer_in_buffer(ptr_) && "Allocator has outlived MemoryPool"); | ||
if (pointer_in_buffer(p)) { | ||
n = align_up(n); | ||
if (p + n == ptr_) { | ||
ptr_ = p; | ||
} | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
template <std::size_t MemoryPoolSize, std::size_t Align = alignof(std::max_align_t)> | ||
class ArenaAllocator | ||
{ | ||
public: | ||
using value_type = uint8_t; | ||
static auto constexpr alignment = Align; | ||
static auto constexpr size = MemoryPoolSize; | ||
using pool_type = MemoryPool<size, alignment>; | ||
|
||
private: | ||
pool_type& pool_; | ||
|
||
public: | ||
ArenaAllocator(const ArenaAllocator&) = default; | ||
ArenaAllocator& operator=(const ArenaAllocator&) = delete; | ||
|
||
ArenaAllocator(pool_type& p) noexcept : pool_(p) | ||
{ | ||
static_assert(size % alignment == 0, | ||
"size MemoryPoolSize needs to be a multiple of alignment Align"); | ||
} | ||
|
||
void* allocate(std::size_t n) | ||
{ | ||
return reinterpret_cast<void*>(pool_.template allocate<alignof(void*)>(n*sizeof(void*))); | ||
} | ||
|
||
bool deallocate(void * ptr) noexcept | ||
{ | ||
// NOTE never deallocating, we have created a pool large enough for all memory needed | ||
return pool_.pointer_in_buffer(reinterpret_cast<char*>(ptr)); | ||
} | ||
|
||
void* reallocate(void*, std::size_t n) | ||
{ | ||
return this->allocate(n); | ||
} | ||
|
||
void* zero_allocate(size_t count, size_t size) | ||
{ | ||
size_t total_size = count * size; | ||
void* memory = this->allocate(total_size); | ||
if (nullptr != memory) { | ||
memset(memory, 0x0, total_size); | ||
} | ||
return memory; | ||
} | ||
}; | ||
|
||
|
||
template <std::size_t N> | ||
class ArenaAlloc | ||
{ | ||
using value_type = uint8_t; | ||
static auto constexpr alignment = alignof(std::max_align_t); | ||
static auto constexpr size = N; | ||
alignas(alignment) char buf_[N]; | ||
char * ptr_; | ||
public: | ||
ArenaAlloc() noexcept : ptr_(buf_) { | ||
static_assert(size % alignment == 0, "size N needs to be a multiple of std::max_align_t"); | ||
} | ||
~ArenaAlloc() { ptr_ = nullptr; } | ||
|
||
void * allocate(std::size_t n) | ||
{ | ||
assert(pointer_in_buffer(ptr_)); | ||
auto const aligned_n = align_up(n); | ||
if (static_cast<decltype(aligned_n)>(buf_ + N - ptr_) >= aligned_n) { | ||
char * r = ptr_; | ||
ptr_ += aligned_n; | ||
return r; | ||
} | ||
return nullptr; | ||
} | ||
|
||
bool deallocate(void * ptr) noexcept | ||
{ | ||
// NOTE never deallocating | ||
return pointer_in_buffer(reinterpret_cast<char *>(ptr)); | ||
} | ||
|
||
void * reallocate(void *, std::size_t n) | ||
{ | ||
// TODO(eknapp) actually reallocate? | ||
return allocate(n); | ||
} | ||
|
||
void * zero_allocate(size_t count, size_t size) | ||
{ | ||
size_t total_size = count * size; | ||
void * memory = allocate(total_size); | ||
if (nullptr != memory) { | ||
memset(memory, 0x0, total_size); | ||
} | ||
return memory; | ||
} | ||
|
||
private: | ||
static std::size_t | ||
align_up(std::size_t n) noexcept | ||
{ | ||
return (n + (alignment-1)) & ~(alignment-1); | ||
} | ||
|
||
bool pointer_in_buffer(char * p) | ||
{ | ||
return buf_ <= p && p <= (buf_ + N); | ||
} | ||
}; | ||
|
||
|
||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters