Program Listing for File allocator.hpp¶
↰ Return to documentation for file (include/ripple/allocation/allocator.hpp
)
#ifndef RIPPLE_ALLOCATION_ALLOCATOR_HPP
#define RIPPLE_ALLOCATION_ALLOCATOR_HPP
#include "aligned_heap_allocator.hpp"
#include "arena.hpp"
#include "pool_allocator.hpp"
#include <mutex>
namespace ripple {
struct VoidLock {
auto lock() noexcept -> void {}
auto unlock() noexcept -> void {}
};
/*==--- [forward declarations & aliases] -----------------------------------==*/
template <
typename PrimaryAllocator,
typename Arena = HeapArena,
typename FallbackAllocator = AlignedHeapAllocator,
typename LockingPolicy = VoidLock>
class Allocator;
template <
typename T,
typename LockingPolicy = VoidLock,
typename Arena = HeapArena>
using ObjectPoolAllocator = Allocator<
PoolAllocator<sizeof(T), std::max(alignof(T), alignof(Freelist)), Freelist>,
Arena,
AlignedHeapAllocator,
LockingPolicy>;
template <typename T, typename Arena = HeapArena>
using ThreadSafeObjectPoolAllocator = Allocator<
PoolAllocator<
sizeof(T),
std::max(alignof(T), alignof(ThreadSafeFreelist)),
ThreadSafeFreelist>,
Arena,
AlignedHeapAllocator,
VoidLock>;
/*==--- [implementation] ---------------------------------------------------==*/
template <
typename PrimaryAllocator,
typename Arena,
typename FallbackAllocator,
typename LockingPolicy>
class Allocator {
static_assert(
std::is_trivially_constructible_v<FallbackAllocator>,
"Fallback allocator must be trivially constructible!");
public:
static constexpr bool contexpr_arena_size = Arena::constexpr_size;
using Guard = std::lock_guard<LockingPolicy>;
/*==--- [construction] ---------------------------------------------------==*/
template <typename... Args>
Allocator(size_t size, Args&&... args)
: arena_(size), primary_(arena_, ripple_forward(args)...) {}
~Allocator() noexcept = default;
// clang-format off
Allocator(Allocator&& other) noexcept = default;
auto operator=(Allocator&& other) noexcept -> Allocator& = default;
/*==--- [deleted] --------------------------------------------------------==*/
Allocator(const Allocator&) = delete;
auto operator=(const Allocator&) = delete;
// clang-format on
/*==--- [alloc/free interface] -------------------------------------------==*/
auto alloc(size_t size, size_t alignment = alignof(std::max_align_t)) noexcept
-> void* {
Guard g(lock_);
void* ptr = primary_.alloc(size, alignment);
if (!ptr) {
ptr = fallback_.alloc(size, alignment);
}
return ptr;
}
auto free(void* ptr) noexcept -> void {
if (!ptr) {
return;
}
Guard g(lock_);
if (primary_.owns(ptr)) {
primary_.free(ptr);
return;
}
fallback_.free(ptr);
}
auto free(void* ptr, size_t size) noexcept -> void {
if (!ptr) {
return;
}
Guard g(lock_);
if (primary_.owns(ptr)) {
primary_.free(ptr, size);
return;
}
fallback_.free(ptr, size);
}
auto reset() noexcept -> void {
Guard g(lock_);
primary_.reset();
}
/*==--- [create/destroy interface] ---------------------------------------==*/
template <typename T, typename... Args>
auto create(Args&&... args) noexcept -> T* {
constexpr size_t size = sizeof(T);
constexpr size_t alignment = alignof(T);
void* const ptr = alloc(size, alignment);
return ptr ? new (ptr) T(ripple_forward(args)...) : nullptr;
}
template <typename T>
auto recycle(T* ptr) noexcept -> void {
if (!ptr) {
return;
}
constexpr size_t size = sizeof(T);
ptr->~T();
free(static_cast<void*>(ptr), size);
}
private:
Arena arena_;
PrimaryAllocator primary_;
FallbackAllocator fallback_;
LockingPolicy lock_;
};
} // namespace ripple
#endif // RIPPLE_ALLOCATION_ALLOCATOR_HP