xo-alloc2: ++ documentation
This commit is contained in:
parent
289751d3fd
commit
0136044ba2
18 changed files with 474 additions and 37 deletions
70
include/xo/alloc2/ArenaConfig.hpp
Normal file
70
include/xo/alloc2/ArenaConfig.hpp
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/** @file ArenaConfig.hpp
|
||||
*
|
||||
* @author Roland Conybeare, Dec 2025
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
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 */
|
||||
|
|
@ -23,6 +23,8 @@ namespace xo {
|
|||
struct AAllocIterator {
|
||||
using obj_AAllocIterator = xo::facet::obj<AAllocIterator>;
|
||||
|
||||
/** @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*/
|
||||
|
|
|
|||
|
|
@ -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 <typename DRepr, typename IAllocator_DRepr>
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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*/
|
||||
|
|
|
|||
|
|
@ -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<typename T>
|
||||
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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue