Program Listing for File stack_alloc.hpp
↰ Return to documentation for file (/tmp/ws/src/proxsuite/include/proxsuite/linalg/veg/memory/stack_alloc.hpp
)
#ifndef VEG_STACK_ALLOC_HPP_UTBYR4Y5S
#define VEG_STACK_ALLOC_HPP_UTBYR4Y5S
#include "proxsuite/linalg/veg/slice.hpp"
#include "proxsuite/linalg/veg/type_traits/alloc.hpp"
#include "proxsuite/linalg/veg/internal/prologue.hpp"
namespace proxsuite {
namespace linalg {
namespace veg {
namespace _detail {
namespace _mem {
template<usize MaxAlign>
struct BumpAllocLayout
{
mem::byte* current_ptr;
mem::byte* start_ptr;
mem::byte* end_ptr;
static auto _align(usize byte_size) noexcept -> usize
{
usize const actual_max_align =
#if VEG_HAS_ASAN
MaxAlign > 8 ? MaxAlign : 8
#else
MaxAlign
#endif
;
usize const mask = (actual_max_align - 1);
return (byte_size + mask) & ~mask;
}
auto _is_last(void* ptr, usize byte_size) noexcept -> bool
{
return ptr == (current_ptr - _align(byte_size));
}
void _assert_last(void* ptr, usize byte_size) noexcept
{
VEG_ASSERT(ptr == (current_ptr - _align(byte_size)));
}
void _dealloc_last_unchecked(void* ptr, mem::Layout layout)
{
VEG_DEBUG_ASSERT(ptr == (current_ptr - _align(layout.byte_size)));
(void)layout;
current_ptr = static_cast<mem::byte*>(ptr);
}
void _dealloc_any(void* ptr, mem::Layout layout) noexcept
{
if (_is_last(ptr, layout.byte_size)) {
_dealloc_last_unchecked(ptr, layout);
}
}
void _dealloc_last(void* ptr, mem::Layout layout)
{
_assert_last(ptr, layout.byte_size);
_dealloc_last_unchecked(ptr, layout);
}
auto _alloc(mem::Layout layout) noexcept -> mem::AllocBlock
{
auto given_bytes = _align(layout.byte_size);
auto rem_bytes = usize(end_ptr - current_ptr);
VEG_ASSERT_ALL_OF( //
(layout.align <= MaxAlign),
(given_bytes < rem_bytes));
mem::AllocBlock blk = { current_ptr, given_bytes };
current_ptr += given_bytes;
return blk;
}
auto _grow_last_unchecked(void* ptr, usize new_byte_size) noexcept
-> mem::AllocBlock
{
auto rem_bytes = usize(end_ptr - static_cast<mem::byte*>(ptr));
auto given_bytes = _align(new_byte_size);
(void)rem_bytes;
VEG_DEBUG_ASSERT(given_bytes < rem_bytes);
current_ptr = static_cast<mem::byte*>(ptr) + given_bytes;
return { ptr, given_bytes };
}
auto _grow_last(void* ptr,
mem::Layout old_layout,
usize new_byte_size,
mem::RelocFn /*reloc*/) noexcept -> mem::AllocBlock
{
if (ptr == nullptr) {
mem::AllocBlock blk =
_alloc(mem::Layout{ new_byte_size, old_layout.align });
return blk;
}
_assert_last(ptr, old_layout.byte_size);
return _grow_last_unchecked(ptr, new_byte_size);
}
auto _grow_any(void* ptr,
mem::Layout old_layout,
usize new_byte_size,
mem::RelocFn reloc) noexcept -> mem::AllocBlock
{
if (_is_last(ptr, old_layout.byte_size)) {
return _grow_last_unchecked(ptr, new_byte_size);
} else {
mem::AllocBlock blk =
_alloc(mem::Layout{ new_byte_size, old_layout.align });
reloc(blk.data, ptr, old_layout.byte_size);
return blk;
}
}
};
} // namespace _mem
} // namespace _detail
namespace mem {
template<usize MaxAlign>
struct BumpAlloc : private _detail::_mem::BumpAllocLayout<MaxAlign>
{
#if VEG_HAS_ASAN
static_assert(MaxAlign >= 8, ".");
#endif
BumpAlloc(FromSliceMut /*tag*/, SliceMut<byte> s) noexcept
: _detail::_mem::BumpAllocLayout<MaxAlign>{
s.ptr_mut(),
s.ptr_mut(),
s.ptr_mut() + s.len(),
}
{
VEG_ASSERT_ALL_OF(
((std::uintptr_t(s.ptr()) % MaxAlign) == std::uintptr_t(0)),
((usize(s.len()) % usize(MaxAlign)) == usize(0)));
}
};
template<usize MaxAlign>
struct StackAlloc : private BumpAlloc<MaxAlign>
{
using BumpAlloc<MaxAlign>::BumpAlloc;
};
template<usize MaxAlign>
struct MonotonicAlloc : private BumpAlloc<MaxAlign>
{
using BumpAlloc<MaxAlign>::BumpAlloc;
};
template<usize MaxAlign>
struct Alloc<BumpAlloc<MaxAlign>>
{
using ImplMut = _detail::_mem::BumpAllocLayout<MaxAlign>&;
using RefMut = proxsuite::linalg::veg::RefMut<BumpAlloc<MaxAlign>>;
VEG_INLINE static auto alloc(RefMut ref, mem::Layout layout) noexcept
-> AllocBlock
{
return ImplMut(ref.get())._alloc(layout);
}
VEG_INLINE static void dealloc(RefMut ref,
void* ptr,
mem::Layout layout) noexcept
{
ImplMut(ref.get())._dealloc_any(ptr, layout);
}
VEG_INLINE static auto grow(RefMut ref,
void* ptr,
mem::Layout old_layout,
usize new_byte_size,
RelocFn reloc) noexcept -> mem::AllocBlock
{
return ImplMut(ref.get())._grow_any(ptr, old_layout, new_byte_size, reloc);
}
};
template<usize MaxAlign>
struct Alloc<StackAlloc<MaxAlign>>
{
using ImplMut = _detail::_mem::BumpAllocLayout<MaxAlign>&;
using RefMut = proxsuite::linalg::veg::RefMut<StackAlloc<MaxAlign>>;
VEG_INLINE static auto alloc(RefMut ref, mem::Layout layout) noexcept
-> AllocBlock
{
return ImplMut(ref.get())._alloc(layout);
}
VEG_INLINE static void dealloc(RefMut ref,
void* ptr,
mem::Layout layout) noexcept
{
ImplMut(ref.get())._dealloc_last(ptr, layout);
}
VEG_INLINE static auto grow(RefMut ref,
void* ptr,
mem::Layout old_layout,
usize new_byte_size,
RelocFn reloc) noexcept -> mem::AllocBlock
{
return ImplMut(ref.get())._grow_last(ptr, old_layout, new_byte_size, reloc);
}
};
template<usize MaxAlign>
struct Alloc<MonotonicAlloc<MaxAlign>>
{
using ImplMut = _detail::_mem::BumpAllocLayout<MaxAlign>&;
using RefMut = proxsuite::linalg::veg::RefMut<MonotonicAlloc<MaxAlign>>;
VEG_INLINE static auto alloc(RefMut ref, mem::Layout layout) noexcept
-> AllocBlock
{
return ImplMut(ref.get())._alloc(layout);
}
VEG_INLINE static void dealloc(RefMut /*ref*/,
void* /*ptr*/,
mem::Layout /*layout*/) noexcept
{
}
VEG_INLINE static auto grow(RefMut ref,
void* ptr,
mem::Layout old_layout,
usize new_byte_size,
RelocFn reloc) noexcept -> mem::AllocBlock
{
return ImplMut(ref.get())._grow_last(ptr, old_layout, new_byte_size, reloc);
}
};
} // namespace mem
} // namespace veg
} // namespace linalg
} // namespace proxsuite
#include "proxsuite/linalg/veg/internal/epilogue.hpp"
#endif /* end of include guard VEG_STACK_ALLOC_HPP_UTBYR4Y5S */