Skip to content

Commit

Permalink
Added: Stack allocator
Browse files Browse the repository at this point in the history
  • Loading branch information
richardbiely committed Mar 13, 2024
1 parent fba1e58 commit fcdb1ea
Show file tree
Hide file tree
Showing 9 changed files with 301 additions and 77 deletions.
1 change: 1 addition & 0 deletions include/gaia.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "gaia/mem/data_layout_policy.h"
#include "gaia/mem/mem_alloc.h"
#include "gaia/mem/mem_utils.h"
#include "gaia/mem/raw_data_holder.h"

#include "gaia/meta/reflection.h"
#include "gaia/meta/type_info.h"
Expand Down
2 changes: 1 addition & 1 deletion include/gaia/cnt/impl/darray_ext_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

#include "../../core/iterator.h"
#include "../../core/utility.h"
#include "../../mem/data_layout_policy.h"
#include "../../mem/raw_data_holder.h"
#include "../../mem/mem_utils.h"

namespace gaia {
Expand Down
2 changes: 1 addition & 1 deletion include/gaia/cnt/impl/sarray_ext_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@

#include "../../core/iterator.h"
#include "../../core/utility.h"
#include "../../mem/data_layout_policy.h"
#include "../../mem/mem_utils.h"
#include "../../mem/raw_data_holder.h"

namespace gaia {
namespace cnt {
Expand Down
2 changes: 1 addition & 1 deletion include/gaia/cnt/impl/sarray_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

#include "../../core/iterator.h"
#include "../../core/utility.h"
#include "../../mem/data_layout_policy.h"
#include "../../mem/mem_utils.h"
#include "../../mem/raw_data_holder.h"

namespace gaia {
namespace cnt {
Expand Down
37 changes: 0 additions & 37 deletions include/gaia/mem/data_layout_policy.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,40 +53,6 @@ namespace gaia {
address += padding + itemSize * cnt;
return address;
}

//----------------------------------------------------------------------
// Data storage
//----------------------------------------------------------------------

template <uint32_t Size, uint32_t Alignment>
struct raw_data_holder {
static_assert(Size > 0);

GAIA_ALIGNAS(Alignment) uint8_t data[Size];

constexpr operator uint8_t*() noexcept {
return &data[0];
}

constexpr operator const uint8_t*() const noexcept {
return &data[0];
}
};

template <uint32_t Size>
struct raw_data_holder<Size, 0> {
static_assert(Size > 0);

uint8_t data[Size];

constexpr operator uint8_t*() noexcept {
return &data[0];
}

constexpr operator const uint8_t*() const noexcept {
return &data[0];
}
};
} // namespace detail

template <DataLayout TDataLayout, typename TItem>
Expand Down Expand Up @@ -542,8 +508,5 @@ namespace gaia {
template <typename T>
inline constexpr bool is_soa_layout_v = detail::is_soa_layout<T>::value;

template <typename T, uint32_t N>
using raw_data_holder = detail::raw_data_holder<N, auto_view_policy<T>::Alignment>;

} // namespace mem
} // namespace gaia
45 changes: 45 additions & 0 deletions include/gaia/mem/raw_data_holder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#pragma once
#include "../config/config.h"

#include <cinttypes>

#include "data_layout_policy.h"

namespace gaia {
namespace mem {
namespace detail {
template <uint32_t Size, uint32_t Alignment>
struct raw_data_holder {
static_assert(Size > 0);

GAIA_ALIGNAS(Alignment) uint8_t data[Size];

constexpr operator uint8_t*() noexcept {
return &data[0];
}

constexpr operator const uint8_t*() const noexcept {
return &data[0];
}
};

template <uint32_t Size>
struct raw_data_holder<Size, 0> {
static_assert(Size > 0);

uint8_t data[Size];

constexpr operator uint8_t*() noexcept {
return &data[0];
}

constexpr operator const uint8_t*() const noexcept {
return &data[0];
}
};
} // namespace detail

template <typename T, uint32_t N>
using raw_data_holder = detail::raw_data_holder<N, auto_view_policy<T>::Alignment>;
} // namespace mem
} // namespace gaia
146 changes: 146 additions & 0 deletions include/gaia/mem/stack_allocator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#pragma once
#include "../config/config.h"

#include <cinttypes>

#include "raw_data_holder.h"

namespace gaia {
namespace mem {
namespace detail {
struct AllocationInfo {
//! Byte offset of the previous allocation
uint32_t prev;
//! Offset of data area from info area in bytes
uint32_t off : 8;
//! The number of requested bytes to allocate
uint32_t cnt : 24;
void (*dtor)(void*, uint32_t);
};
} // namespace detail

//! Stack allocator capable of instantiating any default-constructible object on stack.
//! Every allocation comes with a 16-bytes long sentinel object.
template <uint32_t CapacityInBytes = 1024>
class StackAllocator {
using alloc_info = detail::AllocationInfo;

//! Internal stack buffer aligned to 16B boundary
detail::raw_data_holder<CapacityInBytes, 16> m_buffer;
//! Current byte offset
uint32_t m_pos = 0;
//! Byte offset of the previous allocatoin
uint32_t m_posPrev = 0;
//! Number of allocations made
uint32_t m_allocs = 0;

public:
StackAllocator() {
// Aligned used so the sentinel object can be stored properly
const auto bufferMemAddr = (uintptr_t)((uint8_t*)m_buffer);
m_posPrev = m_pos = padding<alignof(alloc_info)>(bufferMemAddr);
}

~StackAllocator() {
reset();
}

StackAllocator(const StackAllocator&) = delete;
StackAllocator(StackAllocator&&) = delete;
StackAllocator& operator=(const StackAllocator&) = delete;
StackAllocator& operator=(StackAllocator&&) = delete;

//! Allocates \param cnt objects of type \tparam T inside the buffer.
//! No default initialization is done so the object is returned in a non-initialized
//! state unless a custom constructor is provided.
//! \return Pointer to the first allocated object
template <typename T>
GAIA_NODISCARD T* alloc(uint32_t cnt) {
constexpr auto sizeT = (uint32_t)sizeof(T);
const auto addrBuff = (uintptr_t)((uint8_t*)m_buffer);
const auto addrAllocInfo = align<alignof(alloc_info)>(addrBuff + m_pos);
const auto addrAllocData = align<alignof(T)>(addrAllocInfo + sizeof(alloc_info));
const auto off = (uint32_t)(addrAllocData - addrAllocInfo);

// There has to be some space left in the buffer
const bool isFull = (uint32_t)(addrAllocData - addrBuff) + sizeT * cnt >= CapacityInBytes;
if GAIA_UNLIKELY (isFull) {
GAIA_ASSERT(!isFull && "Allocation space exceeded on StackAllocator");
return nullptr;
}

// Memory sentinel
auto* pInfo = (alloc_info*)addrAllocInfo;
pInfo->prev = m_posPrev;
pInfo->off = off;
pInfo->cnt = cnt;
pInfo->dtor = [](void* ptr, uint32_t cnt) {
core::call_dtor_n((T*)ptr, cnt);
};

// Constuction the object is necessary
auto* pData = (T*)addrAllocData;
core::call_ctor_raw_n(pData, cnt);

// Allocation start offset
m_posPrev = addrAllocInfo - addrBuff;
// Point to the next free space (not necessary alligned yet)
m_pos = m_posPrev + pInfo->off + sizeT * cnt;

++m_allocs;
return pData;
}

//! Frees the last allocated object from the stack.
//! \param pData Pointer to the last allocated object on the stack
//! \param cnt Number of objects that were allocated on the given memory address
void free([[maybe_unused]] void* pData, [[maybe_unused]] uint32_t cnt) {
GAIA_ASSERT(pData != nullptr);
GAIA_ASSERT(cnt > 0);
GAIA_ASSERT(m_allocs > 0);

const auto addrBuff = (uintptr_t)((uint8_t*)m_buffer);

// Destroy the last allocated object
const auto addrAllocInfo = addrBuff + m_posPrev;
auto* pInfo = (alloc_info*)addrAllocInfo;
const auto addrAllocData = addrAllocInfo + pInfo->off;
void* pInfoData = (void*)addrAllocData;
GAIA_ASSERT(pData == pInfoData);
GAIA_ASSERT(pInfo->cnt == cnt);
pInfo->dtor(pInfoData, pInfo->cnt);

m_pos = m_posPrev;
m_posPrev = pInfo->prev;
--m_allocs;
}

//! Frees all allocated objects from the buffer
void reset() {
const auto addrBuff = (uintptr_t)((uint8_t*)m_buffer);

// Destroy allocated objects back-to-front
auto pos = m_posPrev;
while (m_allocs > 0) {
const auto addrAllocInfo = addrBuff + pos;
auto* pInfo = (alloc_info*)addrAllocInfo;
const auto addrAllocData = addrAllocInfo + pInfo->off;
pInfo->dtor((void*)addrAllocData, pInfo->cnt);
pos = pInfo->prev;

--m_allocs;
}

GAIA_ASSERT(m_allocs == 0);

m_pos = 0;
m_posPrev = 0;
m_allocs = 0;
}

GAIA_NODISCARD constexpr uint32_t capacity() {
return CapacityInBytes;
}
};
} // namespace mem
} // namespace gaia
78 changes: 41 additions & 37 deletions single_include/gaia.h
Original file line number Diff line number Diff line change
Expand Up @@ -3744,40 +3744,6 @@ namespace gaia {
address += padding + itemSize * cnt;
return address;
}

//----------------------------------------------------------------------
// Data storage
//----------------------------------------------------------------------

template <uint32_t Size, uint32_t Alignment>
struct raw_data_holder {
static_assert(Size > 0);

GAIA_ALIGNAS(Alignment) uint8_t data[Size];

constexpr operator uint8_t*() noexcept {
return &data[0];
}

constexpr operator const uint8_t*() const noexcept {
return &data[0];
}
};

template <uint32_t Size>
struct raw_data_holder<Size, 0> {
static_assert(Size > 0);

uint8_t data[Size];

constexpr operator uint8_t*() noexcept {
return &data[0];
}

constexpr operator const uint8_t*() const noexcept {
return &data[0];
}
};
} // namespace detail

template <DataLayout TDataLayout, typename TItem>
Expand Down Expand Up @@ -4233,9 +4199,6 @@ namespace gaia {
template <typename T>
inline constexpr bool is_soa_layout_v = detail::is_soa_layout<T>::value;

template <typename T, uint32_t N>
using raw_data_holder = detail::raw_data_holder<N, auto_view_policy<T>::Alignment>;

} // namespace mem
} // namespace gaia

Expand Down Expand Up @@ -4650,6 +4613,47 @@ namespace gaia {
} // namespace mem
} // namespace gaia

#include <cinttypes>

namespace gaia {
namespace mem {
namespace detail {
template <uint32_t Size, uint32_t Alignment>
struct raw_data_holder {
static_assert(Size > 0);

GAIA_ALIGNAS(Alignment) uint8_t data[Size];

constexpr operator uint8_t*() noexcept {
return &data[0];
}

constexpr operator const uint8_t*() const noexcept {
return &data[0];
}
};

template <uint32_t Size>
struct raw_data_holder<Size, 0> {
static_assert(Size > 0);

uint8_t data[Size];

constexpr operator uint8_t*() noexcept {
return &data[0];
}

constexpr operator const uint8_t*() const noexcept {
return &data[0];
}
};
} // namespace detail

template <typename T, uint32_t N>
using raw_data_holder = detail::raw_data_holder<N, auto_view_policy<T>::Alignment>;
} // namespace mem
} // namespace gaia

namespace gaia {
namespace meta {

Expand Down
Loading

0 comments on commit fcdb1ea

Please sign in to comment.