diff --git a/docs/AAllocIterator-reference.rst b/docs/AAllocIterator-reference.rst new file mode 100644 index 0000000..a576ef2 --- /dev/null +++ b/docs/AAllocIterator-reference.rst @@ -0,0 +1,67 @@ +.. _AAllocIterator-reference: + +AAllocIterator Reference +======================== + +Abstract interface facet for an alloc iterator. + +Base class for runtime polymorphism over alloc-iterator implementations, +using faceted object model. + +* runtime size consists of vtable pointer only. + +* per FOMO principles, runtime state is stored separately. + Classes that inherit AAllocIterator will not add state. + +Context +------- + +.. ditaa:: + :--scale: 0.99 + + +----------------------+-------------------------+-----------------------------------+ + | RAllocator | RAllocIterator | IAllocator_DArena | + | | | IAllocIterator_DArenaIterator | + +----------------------+-------------------------+-----------------------------------+ + | IAllocator_Xfer | IAllocIterator_Xfer | DArena | + | IAllocator_Any | IAllocIterator_Any | DArenaIterator | + | IAllocator_Impltype | IAllocIterator_Impltype | | + | | | | + +----------------------+-------------------------+-----------------------------------+ + | AAllocator | AAllocIterator cBLU| ArenaConfig | + +----------------------+-------------------------+-----------------------------------+ + +-----------------+----------------------------------------------+-------------------+ + | | AllocInfo | | + | +----------------------------------------------+ | + | AllocError | AllocHeaderConfig | cmpresult | + | +----------------------------------------------+ | + | | AllocHeader | | + +-----------------+----------------------------------------------+-------------------+ + +Application code will likely use: + +.. code-block:: cpp + + #include + +to get definitions for cooperating AllocIterator classes +:cpp:class:`xo::mm::AAllocIterator`, +:cpp:class:`xo::mm::IAllocIterator_Any`, +:cpp:class:`xo::mm::IAllocIterator_Xfer`, +:cpp:class:`xo::mm::RAllocator` + +Instead, to get just :cpp:class:`xo::mm::AAllocIterator` definition: + +.. code-block:: cpp + + #include + +Class +----- + +.. doxygenclass:: xo::mm::AAllocIterator + +Methods +------- + +.. doxygengroup:: mm-allociterator-methods diff --git a/docs/ArenaConfig-reference.rst b/docs/ArenaConfig-reference.rst index 37932f4..20dbabb 100644 --- a/docs/ArenaConfig-reference.rst +++ b/docs/ArenaConfig-reference.rst @@ -11,25 +11,50 @@ Context .. ditaa:: :--scale: 0.99 - +--------------------------------+ - | IAllocator_DArena | - +--------------------------------+ - | IAllocator_Xfer | - +--------------------------------+ - | IAllocator_ImplType | - +--------------+-----------------+ - | | DArena | - | AAllocator +-----------------+ - | | ArenaConfig cBLU| - +--------------+-----------------+ + +----------------------+-------------------------+-----------------------------------+ + | RAllocator | RAllocIterator | IAllocator_DArena | + | | | IAllocIterator_DArenaIterator | + +----------------------+-------------------------+-----------------------------------+ + | IAllocator_Xfer | IAllocIterator_Xfer | DArena | + | IAllocator_Any | IAllocIterator_Any | DArenaIterator | + | IAllocator_Impltype | IAllocIterator_Impltype | | + | | | | + +----------------------+-------------------------+-----------------------------------+ + | AAllocator | AAllocIterator | ArenaConfig cBLU| + +----------------------+-------------------------+-----------------------------------+ + +-----------------+----------------------------------------------+-------------------+ + | | AllocInfo | | + | +----------------------------------------------+ | + | AllocError | AllocHeaderConfig | cmpresult | + | +----------------------------------------------+ | + | | AllocHeader | | + +-----------------+----------------------------------------------+-------------------+ + +.. uml:: + :caption: example arena config + :scale: 99% + :align: center + + object cfg<> + cfg : name = "tmp" + cfg : size = 128MB + cfg : hugepage_z = 2MB + cfg : guard_z = 8 + cfg : guard_byte = 0xfd + cfg : store_header_flag = true + cfg : header_size_mask = 0xffffffff + cfg : debug_flag = false .. code-block:: cpp - #include + #include Class ----- .. doxygenclass:: xo::mm::ArenaConfig -.. doxygenclass:: mm-arenaconfig-instance-vars +Instance Variables +------------------ + +.. doxygengroup:: mm-arenaconfig-instance-vars diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index d5d24f2..54c28e5 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -8,9 +8,12 @@ xo_docdir_sphinx_config( examples.rst implementation.rst AAllocator-reference.rst + IAllocator_Xfer-reference.rst + AAllocIterator-reference.rst ArenaConfig-reference.rst DArena-reference.rst AllocInfo-reference.rst + cmpresult-reference.rst #install.rst #introduction.rst #implementation.rst diff --git a/docs/DArena-reference.rst b/docs/DArena-reference.rst index 35d65fe..11037fc 100644 --- a/docs/DArena-reference.rst +++ b/docs/DArena-reference.rst @@ -1,9 +1,9 @@ .. _DArena-reference: -DArena Reference -================ +DArena +====== -Native representation for arena allocator +Native arena allocator Context ------- @@ -34,7 +34,6 @@ Context #include - Arena memory layout ~~~~~~~~~~~~~~~~~~~ diff --git a/docs/DArenaIterator-reference.rst b/docs/DArenaIterator-reference.rst new file mode 100644 index 0000000..4ef4c19 --- /dev/null +++ b/docs/DArenaIterator-reference.rst @@ -0,0 +1,55 @@ +.. _DArenaIterator-reference: + +DArenaIterator +============== + +Iterator for allocs obtained from a :cpp:class:`DArena`. + +Context +------- + +.. ditaa:: + :--scale: 0.99 + + +----------------------+-------------------------+-----------------------------------+ + | RAllocator | RAllocIterator | IAllocator_DArena | + | | | IAllocIterator_DArenaIterator | + +----------------------+-------------------------+-----------------------------------+ + | IAllocator_Xfer | IAllocIterator_Xfer | DArena | + | IAllocator_Any | IAllocIterator_Any +-----------------------------------+ + | IAllocator_Impltype | IAllocIterator_Impltype | DArenaIterator | + | | | cBLU| + +----------------------+-------------------------+-----------------------------------+ + | AAllocator | AAllocIterator | ArenaConfig | + +----------------------+-------------------------+-----------------------------------+ + +-----------------+----------------------------------------------+-------------------+ + | | AllocInfo | | + | +----------------------------------------------+ | + | AllocError | AllocHeaderConfig | cmpresult | + | +----------------------------------------------+ | + | | AllocHeader | | + +-----------------+----------------------------------------------+-------------------+ + +.. code-block:: cpp + + #include + +Class +----- + +.. doxygenclass:: xo::mm::DArenaIterator + +Member Variables +---------------- + +.. doxygengroup:: mm-arenaiterator-instance-vars + +Constructors +------------ + +.. doxygengroup:: mm-arenaiterator-ctors + +Methods +------- + +.. doxygengroup:: mm-arenaiterator-methods diff --git a/docs/IAllocator_Xfer-reference.rst b/docs/IAllocator_Xfer-reference.rst new file mode 100644 index 0000000..9ca9056 --- /dev/null +++ b/docs/IAllocator_Xfer-reference.rst @@ -0,0 +1,73 @@ +.. _IAllocator_Xfer-reference: + +IAllocator_Xfer +=============== + +IAllocator_Xfer provides a type-erased interface to a specific native allocator +implementation. + +Context +------- + +.. ditaa:: + :--scale: 0.99 + + +----------------------+-------------------------+-----------------------------------+ + | RAllocator | RAllocIterator | IAllocator_DArena | + | | | IAllocIterator_DArenaIterator | + +----------------------+-------------------------+-----------------------------------+ + |cBLU IAllocator_Xfer | IAllocIterator_Xfer | DArena | + +----------------------+ IAllocIterator_Any | DArenaIterator | + | IAllocator_Any | IAllocIterator_Impltype | | + | IAllocator_Impltype | | | + +----------------------+-------------------------+-----------------------------------+ + | AAllocator | AAllocIterator | ArenaConfig | + +----------------------+-------------------------+-----------------------------------+ + +-----------------+----------------------------------------------+-------------------+ + | | AllocInfo | | + | +----------------------------------------------+ | + | AllocError | AllocHeaderConfig | cmpresult | + | +----------------------------------------------+ | + | | AllocHeader | | + +-----------------+----------------------------------------------+-------------------+ + +Each method operates by downcasting its first argument to the known target +native interface type, and delegating to native interface method with the same name. + +For example (paraphrasing): + +.. code-block:: cpp + + template + bool IAllocator_Xfer::contains(Copaque d, + const void * p) const ... + { + return IAllocator_DRepr::contains(*(DRepr*)(d), p); + }; + +Code for other methods follows the same pattern; +in fact expect to be able to generate class definition mechanically at some point. + +Application code will not normally interact with :cpp:class:`IAllocator_Xfer`. +It will be used once for each specific allocator implementation +(e.g. with :cpp:class:`xo::mm::IAllocator_DArena`). +In any case, can include the transfer template with: + +.. code-block:: cpp + + #include + +Class +----- + +.. doxygenclass:: xo::mm::IAllocator_Xfer + +Types +----- + +.. doxygengroup:: mm-allocator-xfer-types + +Methods +------- + +.. doxygengroup:: mm-allocator-xfer-methods diff --git a/docs/cmpresult-reference.rst b/docs/cmpresult-reference.rst new file mode 100644 index 0000000..00c27ae --- /dev/null +++ b/docs/cmpresult-reference.rst @@ -0,0 +1,55 @@ +.. _cmpresult-reference: + +cmpresult +========= + +Represent the result of a partially ordered comparison + +Context +------- + +.. ditaa:: + :--scale: 0.99 + + +----------------------+-------------------------+-----------------------------------+ + | RAllocator | RAllocIterator | IAllocator_DArena | + | | | IAllocIterator_DArenaIterator | + +----------------------+-------------------------+-----------------------------------+ + | IAllocator_Xfer | IAllocIterator_Xfer | DArena | + | IAllocator_Any | IAllocIterator_Any | DArenaIterator | + | IAllocator_Impltype | IAllocIterator_Impltype | | + | | | | + +----------------------+-------------------------+-----------------------------------+ + | AAllocator | AAllocIterator | ArenaConfig | + +----------------------+-------------------------+-----------------------------------+ + +-----------------+----------------------------------------------+-------------------+ + | | AllocInfo | | + | +----------------------------------------------+ | + | AllocError | AllocHeaderConfig | cmpresult | + | +----------------------------------------------+ | + | | AllocHeader | cBLU | + +-----------------+----------------------------------------------+-------------------+ + +.. code-block:: cpp + + #include + +Class +----- + +.. doxygenclass:: xo::mm::cmpresult + +Constructors +------------ + +.. doxgyengroup:: mm-cmpresult-ctors + +Methods +------- + +.. doxygengroup:: mm-cmpresult-methods + +Member Variables +---------------- + +.. doxygengroup:: mm-cmpresult-instance-vars diff --git a/docs/examples.rst b/docs/examples.rst index 89c4939..5e78bbb 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -84,6 +84,17 @@ Given a successful allocation: info.guard_lo(); // guard bytes preceding alloc info.guard_hi(); // guard bytes following alloc +Can alternatively scan all live allocs in arena: + +.. code-block:: cpp + + for (AllocInfo info : arena) { + info.payload(); // allocated memory range + info.is_valid(); // true + info.guard_lo(); // guard bytes preceding alloc + info.guard_hi(); // guard bytes following alloc + } + Recycling memory ---------------- @@ -102,8 +113,10 @@ Recycling memory arena.allocated(); // 0k arena.available(); // 8k -Memory released by @ref Darena::clear is still committed. -It's in use as far as operating system is concerned. +Memory recycled by :cpp:func:`DArena::clear()` +is available for reuse by application; it's still owned by arena. +We're just resetting the free pointer back to the beginning of arena +memory. To release memory to the operating system, destroy arena: diff --git a/docs/index.rst b/docs/index.rst index 325985b..a93873d 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -24,9 +24,13 @@ Implemented using FOMO (faceted rust-like object model) from xo-facet examples implementation AAllocator-reference + IAllocator_Xfer-reference + AAllocIterator-reference ArenaConfig-reference DArena-reference + DArenaIterator-reference AllocInfo-reference + cmpresult-reference glossary genindex search diff --git a/include/xo/alloc2/ArenaConfig.hpp b/include/xo/alloc2/ArenaConfig.hpp new file mode 100644 index 0000000..7d3f347 --- /dev/null +++ b/include/xo/alloc2/ArenaConfig.hpp @@ -0,0 +1,70 @@ +/** @file ArenaConfig.hpp + * + * @author Roland Conybeare, Dec 2025 + **/ + +#pragma once + +#include +#include + +namespace xo { + namespace mm { + + /** @class ArenaConfig + * @brief configuration for a @ref DArena instance + **/ + struct ArenaConfig { + /** @defgroup mm-arenaconfig-ctors ArenaConfig ctors **/ + ///@{ + + /** create anonymous arena with size @p z **/ + static ArenaConfig simple(std::size_t z); + + ///@} + + /** @defgroup mm-arenaconfig-instance-vars ArenaConfig members **/ + ///@{ + + /** optional name, for diagnostics **/ + std::string name_; + /** desired arena size -- hard max = reserved virtual memory **/ + std::size_t size_; + /** hugepage size -- using huge pages relieves some TLB pressure + * (provided you use their full extent :) + **/ + std::size_t hugepage_z_ = 2 * 1024 * 1024; + /** if non-zero, allocate extra space between allocs, and fill + * with fixed test-pattern contents. Allows for simple + * runtime arena sanitizing checks. + * Will be rounded up to multiple of @ref padding::c_alloc_alignment + **/ + std::size_t guard_z_ = 0; + /** if guard_z_ > 0, write at least that many copies + * of this guard byte following each complete allocation + **/ + std::uint8_t guard_byte_ = 0xfd; + /** if store_header_flag_ is true: mask bits for allocation size. + * remaining bits can be stolen for other purposes + * otherwise ignored + **/ + /** true to store header (8 bytes) at the beginning of each allocation. + * necessary and sufficient to allows iterating over allocs + * present in arena + **/ + bool store_header_flag_ = false; + /** mask applied to 8-byte alloc header. + * bits set to 1 store alloc size; remaining + * bits in alloc header can be used for other purposes. + **/ + std::uint64_t header_size_mask_ = 0xffffffff; + /** true to enable debug logging **/ + bool debug_flag_ = false; + + ///@} + }; + + } /*namespace mm*/ +} /*namespace xo*/ + +/* end ArenaConfig.hpp */ diff --git a/include/xo/alloc2/alloc/AAllocIterator.hpp b/include/xo/alloc2/alloc/AAllocIterator.hpp index 29be0a3..af308b6 100644 --- a/include/xo/alloc2/alloc/AAllocIterator.hpp +++ b/include/xo/alloc2/alloc/AAllocIterator.hpp @@ -23,6 +23,8 @@ namespace xo { struct AAllocIterator { using obj_AAllocIterator = xo::facet::obj; + /** @defgroup mm-allociterator-methods AllocIterator methods **/ + ///@{ /** RTTI: unique id# for actual runtime *data* representation **/ virtual int32_t _typeseq() const noexcept = 0; /** retrieve AllocInfo for current iterator position @@ -33,6 +35,7 @@ namespace xo { const obj_AAllocIterator & other) const noexcept = 0; /** advance iterator to next position **/ virtual void next(Opaque d) const noexcept = 0; + ///@} }; } /*namespace mm*/ } /*namespace xo*/ diff --git a/include/xo/alloc2/alloc/IAllocator_Xfer.hpp b/include/xo/alloc2/alloc/IAllocator_Xfer.hpp index 61c9adb..4f92ff0 100644 --- a/include/xo/alloc2/alloc/IAllocator_Xfer.hpp +++ b/include/xo/alloc2/alloc/IAllocator_Xfer.hpp @@ -11,15 +11,24 @@ namespace xo { namespace mm { /** @class IAllocator_Xfer * - * Adapts typed allocator implementation @tparam IAllocator_DRepr + * @tparam DRepr target representation + * @tparam IAllocator_DRepr typed interface for @p DRepr + * + * Adapts typed allocator implementation @p IAllocator_DRepr * to type-erased @ref AAllocator interface **/ template struct IAllocator_Xfer : public AAllocator { + /** @defgroup mm-allocator-xfer-types **/ + ///@{ // parallel interface to AAllocator, with specific data type using Impl = IAllocator_DRepr; using size_type = AAllocator::size_type; using value_type = AAllocator::value_type; + ///@} + + /** @defgroup mm-allocator-xfer-methods IAllocator_Xfer methods **/ + ///@{ static const DRepr & _dcast(Copaque d) { return *(const DRepr *)d; } static DRepr & _dcast(Opaque d) { return *(DRepr *)d; } @@ -28,6 +37,7 @@ namespace xo { // const methods + /** return typeseq for @tparam DRepr **/ int32_t _typeseq() const noexcept override { return s_typeseq; } std::string_view name(Copaque d) const noexcept override { return I::name(_dcast(d)); } size_type reserved(Copaque d) const noexcept override { return I::reserved(_dcast(d)); } @@ -59,6 +69,7 @@ namespace xo { } void clear(Opaque d) const override { return I::clear(_dcast(d)); } void destruct_data(Opaque d) const override { return I::destruct_data(_dcast(d)); } + ///@} private: using I = Impl; diff --git a/include/xo/alloc2/arena/DArena.hpp b/include/xo/alloc2/arena/DArena.hpp index 1b03aaa..696dbae 100644 --- a/include/xo/alloc2/arena/DArena.hpp +++ b/include/xo/alloc2/arena/DArena.hpp @@ -200,6 +200,9 @@ namespace xo { **/ bool expand(size_type z) noexcept; + /** create initial guard **/ + void establish_initial_guard() noexcept; + /** discard all allocated memory, return to empty state * Promise: * - committed memory unchanged diff --git a/include/xo/alloc2/arena/DArenaIterator.hpp b/include/xo/alloc2/arena/DArenaIterator.hpp index e25fbb8..cb277d6 100644 --- a/include/xo/alloc2/arena/DArenaIterator.hpp +++ b/include/xo/alloc2/arena/DArenaIterator.hpp @@ -18,7 +18,7 @@ namespace xo { * * Map showing an arena allocation: * - * @pre + * @verbatim * * <-------------z1---------------> * < guard >< hz >< req_z >< dz >< guard > @@ -37,9 +37,11 @@ namespace xo { * dz [p] padding (to uintptr_t alignment. req_z+dz recorded in header) * free_ DArena::free_ just after guard bytes for last allocation * - * @endpre + * @endverbatim **/ struct DArenaIterator { + /** @defgroup mm-arenaiterator-ctors DArenaIterator instance vars **/ + ///@{ DArenaIterator() = default; DArenaIterator(const DArena * arena, AllocHeader * pos) : arena_{arena}, @@ -58,7 +60,10 @@ namespace xo { * an iterator error in @p *arena **/ static DArenaIterator end(const DArena * arena); + ///@} + /** @defgroup mm-arenaiterator-methods DArenaIterator methods **/ + ///@{ /** Address of allocation header for beginning of alloc range in @p arena **/ static AllocHeader * begin_header(const DArena * arena); /** Address of allocation header for end of alloc range. @@ -71,6 +76,9 @@ namespace xo { * It can be dereferenced if is also non-empty **/ bool is_valid() const noexcept { return (arena_ != nullptr) && (pos_ != nullptr); } + /** An invalid (or sentinel) iterator is incomparable with all + * iterators including itself + **/ bool is_invalid() const noexcept { return !is_valid(); } /** fetch contents at current iterator position **/ @@ -82,26 +90,35 @@ namespace xo { /** advance iterator to next allocation **/ void next() noexcept; + /** cast iterator position to byte* */ std::byte * pos_as_byte() const { return (std::byte *)pos_; } /** *ix synonym for ix.deref() **/ AllocInfo operator*() const noexcept { return this->deref(); } /** ++ix synonym for ix.next() **/ DArenaIterator & operator++() noexcept { this->next(); return *this; } + ///@} + /** @defgroup mm-arenaiterator-instance-vars **/ + ///@{ /** iterator visits allocations from this arena **/ const DArena * arena_ = nullptr; /** current iterator position **/ AllocHeader * pos_ = nullptr; + ///@} }; inline bool - operator==(const DArenaIterator & x, const DArenaIterator & y) { + operator==(const DArenaIterator & x, + const DArenaIterator & y) + { return x.compare(y).is_equal(); } inline bool - operator!=(const DArenaIterator & x, const DArenaIterator & y) { + operator!=(const DArenaIterator & x, + const DArenaIterator & y) + { return !x.compare(y).is_equal(); } } /*namespace mm*/ diff --git a/include/xo/alloc2/cmpresult.hpp b/include/xo/alloc2/cmpresult.hpp index 477e1dc..0a9a911 100644 --- a/include/xo/alloc2/cmpresult.hpp +++ b/include/xo/alloc2/cmpresult.hpp @@ -24,7 +24,11 @@ namespace xo { return os; } + /** Result of a generic comparison operation + **/ struct cmpresult { + /** @defgroup mm-cmpresult-ctors cmpresult ctors **/ + ///@{ cmpresult() : err_{comparison::invalid}, cmp_{0} {} cmpresult(comparison err, std::int16_t cmp) : err_{err}, cmp_{cmp} {} @@ -32,7 +36,6 @@ namespace xo { static cmpresult lesser() { return cmpresult(comparison::comparable, -1); } static cmpresult equal() { return cmpresult(comparison::comparable, 0); } static cmpresult greater() { return cmpresult(comparison::comparable, +1); } - template static cmpresult from_cmp(T && x, T && y) { if (x < y) @@ -43,6 +46,11 @@ namespace xo { return cmpresult::greater(); } + ///@} + + /** @defgroup mm-cmpresult-methods cmpresult methods **/ + ///@{ + /** print to stream **/ void display(std::ostream & os) const; @@ -52,14 +60,18 @@ namespace xo { bool is_equal() const { return (err_ == comparison::comparable) && (cmp_ == 0); } + ///@} - /* -1 -> invalid (sentinel) - * 0 -> comparable - * +1 -> incomparable (e.g. iterators from different arenas) - */ + /** @defgroup mm-cmpresult-instance-vars cmpresult instance vars **/ + ///@{ + /** -1 -> invalid (sentinel) + * 0 -> comparable + * +1 -> incomparable (e.g. iterators from different arenas) + **/ comparison err_ = comparison::invalid; - /* <0 -> lesser; 0 -> equal, >0 -> greater */ + /** <0 -> lesser; 0 -> equal, >0 -> greater **/ std::int16_t cmp_ = 0; + ///@} }; inline std::ostream & operator<<(std::ostream & os, diff --git a/src/alloc2/ArenaConfig.cpp b/src/alloc2/ArenaConfig.cpp new file mode 100644 index 0000000..942a7e9 --- /dev/null +++ b/src/alloc2/ArenaConfig.cpp @@ -0,0 +1,17 @@ +/** @file ArenaConfig.cpp + * + * @author Roland Conybeare, Dec 2025 + **/ + +#include "ArenaConfig.hpp" +namespace xo { + namespace mm { + ArenaConfig + ArenaConfig::simple(std::size_t z) + { + return ArenaConfig { .size_ = z }; + } + } +} + +/* end ArenaConfig.cpp */ diff --git a/src/alloc2/CMakeLists.txt b/src/alloc2/CMakeLists.txt index 79aea85..1d66ead 100644 --- a/src/alloc2/CMakeLists.txt +++ b/src/alloc2/CMakeLists.txt @@ -8,6 +8,7 @@ set(SELF_SRCS cmpresult.cpp AAllocator.cpp + ArenaConfig.cpp DArena.cpp IAllocator_Any.cpp IAllocator_DArena.cpp diff --git a/src/alloc2/DArena.cpp b/src/alloc2/DArena.cpp index b353462..095349e 100644 --- a/src/alloc2/DArena.cpp +++ b/src/alloc2/DArena.cpp @@ -81,8 +81,8 @@ namespace xo { ::munmap(aligned_hi, suffix); } -#ifdef __linux__ if (enable_hugepage_flag) { +#ifdef __linux__ /** linux: * opt-in to transparent huge pages (THP) * provided OS configured to support them. @@ -100,8 +100,8 @@ namespace xo { * Page table has a handful of levels **/ ::madvise(aligned_base, target_z, MADV_HUGEPAGE); // 8. - } #endif + } return std::make_pair(aligned_base, aligned_hi); } @@ -483,6 +483,18 @@ namespace xo { return mem; } + void + DArena::establish_initial_guard() noexcept + { + assert(free_ == lo_); + + ::memset(this->free_, + config_.header_.guard_byte_, + config_.header_.guard_z_); + + this->free_ += config_.header_.guard_z_; + } + bool DArena::expand(size_t target_z) noexcept { @@ -551,11 +563,7 @@ namespace xo { if (commit_start == lo_) [[unlikely]] { /* first expand() for this allocator - start with guard_z_ bytes */ - ::memset(free_, - config_.header_.guard_byte_, - config_.header_.guard_z_); - - free_ += config_.header_.guard_z_; + this->establish_initial_guard(); } assert(committed_z_ % arena_align_z_ == 0); @@ -568,6 +576,7 @@ namespace xo { DArena::clear() noexcept { this->free_ = lo_; + this->establish_initial_guard(); } } } /*namespace xo*/