xo-alloc2: + Allocator::alloc_info()

Also extend unit test
This commit is contained in:
Roland Conybeare 2025-12-16 16:44:44 -05:00
commit ef8ec32a2d
15 changed files with 156 additions and 40 deletions

View file

@ -6,6 +6,7 @@
#pragma once
#include "AllocatorError.hpp"
#include "AllocInfo.hpp"
#include "xo/facet/facet_implementation.hpp"
#include "xo/facet/typeseq.hpp"
#include <string>
@ -72,9 +73,15 @@ namespace xo {
/** true iff allocator @p d is responsible for memory at address @p p.
**/
virtual bool contains(Copaque d, const void * p) const noexcept = 0;
/** report last error **/
virtual AllocatorError last_error(Copaque d) const noexcept = 0;
/** fetch alloc info: given memory @p mem previously obtained
* from {@ref alloc, @ref super_alloc}, get {tseq, age, size} details
* for that allocation.
*
* Non-const @p d because may stash error details
**/
virtual AllocInfo alloc_info(Opaque d, value_type mem) const noexcept = 0;
/** expand committed space in arena @p d
* to size at least @p z

View file

@ -148,19 +148,6 @@ namespace xo {
std::uint8_t size_bits_ = 32;
};
struct AllocInfo {
using size_type = AllocHeader::size_type;
AllocInfo(const AllocHeaderConfig * p_cfg, const AllocHeader * p_hdr)
: p_config_{p_cfg}, p_header_{p_hdr} {}
std::uint32_t tseq() const noexcept { return p_config_->tseq(*p_header_); }
std::uint32_t age() const noexcept { return p_config_->age (*p_header_); }
size_type size() const noexcept { return p_config_->size(*p_header_); }
const AllocHeaderConfig * p_config_ = nullptr;
const AllocHeader * p_header_ = nullptr;
};
}
}

View file

@ -23,6 +23,12 @@ namespace xo {
header_size_mask,
/** sub_alloc not preceded by super alloc (or another sub_alloc) **/
orphan_sub_alloc,
/** attempt to call alloc_info for allocator with alloc header feature disabled
* (e.g. @ref see ArenaConfig::store_header_flag_)
**/
alloc_info_disabled,
/** attempt to call alloc_info for address not owned by allocator **/
alloc_info_address,
};
struct AllocatorError {

View file

@ -42,12 +42,13 @@ namespace xo {
[[noreturn]] AllocatorError last_error(Copaque) const noexcept override { _fatal(); }
// non-const methods
[[noreturn]] bool expand(Opaque, std::size_t) const noexcept override { _fatal(); }
[[noreturn]] value_type alloc(Opaque, std::size_t) const override { _fatal(); }
[[noreturn]] value_type super_alloc(Opaque, std::size_t) const override { _fatal(); }
[[noreturn]] value_type sub_alloc(Opaque, std::size_t, bool) const override { _fatal(); }
[[noreturn]] void clear(Opaque) const override { _fatal(); }
[[noreturn]] void destruct_data(Opaque) const override { _fatal(); }
[[noreturn]] AllocInfo alloc_info(Opaque, value_type) const noexcept override { _fatal(); }
[[noreturn]] bool expand(Opaque, std::size_t) const noexcept override { _fatal(); }
[[noreturn]] value_type alloc(Opaque, std::size_t) const override { _fatal(); }
[[noreturn]] value_type super_alloc(Opaque, std::size_t) const override { _fatal(); }
[[noreturn]] value_type sub_alloc(Opaque, std::size_t, bool) const override { _fatal(); }
[[noreturn]] void clear(Opaque) const override { _fatal(); }
[[noreturn]] void destruct_data(Opaque) const override { _fatal(); }
private:
[[noreturn]] static void _fatal();

View file

@ -42,6 +42,9 @@ namespace xo {
// non-const methods
AllocInfo alloc_info(Opaque d, value_type mem) const noexcept override {
return I::alloc_info(_dcast(d), mem);
}
bool expand(Opaque d,
std::size_t z) const noexcept override { return I::expand(_dcast(d), z); }
value_type alloc(Opaque d,

View file

@ -25,22 +25,23 @@ namespace xo {
RAllocator() {}
RAllocator(Object::DataPtr data) : Object{std::move(data)} {}
int32_t _typeseq() const noexcept { return O::iface()->_typeseq(); }
std::string_view name() const noexcept { return O::iface()->name(O::data()); }
size_type reserved() const noexcept { return O::iface()->reserved(O::data()); }
size_type size() const noexcept { return O::iface()->size(O::data()); }
size_type committed() const noexcept { return O::iface()->committed(O::data()); }
size_type available() const noexcept { return O::iface()->available(O::data()); }
size_type allocated() const noexcept { return O::iface()->allocated(O::data()); }
bool contains(const void * p) const noexcept { return O::iface()->contains(O::data(), p); }
int32_t _typeseq() const noexcept { return O::iface()->_typeseq(); }
std::string_view name() const noexcept { return O::iface()->name(O::data()); }
size_type reserved() const noexcept { return O::iface()->reserved(O::data()); }
size_type size() const noexcept { return O::iface()->size(O::data()); }
size_type committed() const noexcept { return O::iface()->committed(O::data()); }
size_type available() const noexcept { return O::iface()->available(O::data()); }
size_type allocated() const noexcept { return O::iface()->allocated(O::data()); }
bool contains(const void * p) const noexcept { return O::iface()->contains(O::data(), p); }
AllocatorError last_error() const noexcept { return O::iface()->last_error(O::data()); }
bool expand(size_type z) { return O::iface()->expand(O::data(), z); }
value_type alloc(size_type z) noexcept { return O::iface()->alloc(O::data(), z); }
value_type alloc(size_type z) noexcept { return O::iface()->alloc(O::data(), z); }
value_type super_alloc(size_type z) noexcept { return O::iface()->super_alloc(O::data(), z); }
value_type sub_alloc(size_type z,
bool complete_flag) noexcept { return O::iface()->sub_alloc(O::data(),
value_type sub_alloc(size_type z,
bool complete_flag) noexcept { return O::iface()->sub_alloc(O::data(),
z, complete_flag); }
bool expand(size_type z) { return O::iface()->expand(O::data(), z); }
AllocInfo alloc_info(value_type mem) { return O::iface()->alloc_info(O::data(), mem); }
static bool _valid;
};

View file

@ -88,6 +88,18 @@ namespace xo {
/** get header from allocated object address **/
header_type * obj2hdr(void * obj) noexcept;
/** report alloc book-keeping info for allocation at @p mem
*
* Require:
* 1. @p mem is address returned by allocation on this arena
* i.e. by @ref IAllocator_DArena::alloc() or @ref IAllocator_DArena::alloc_super()
* 2. @p mem has not been invalidated since it was allocated
* i.e. by call to @ref DArena::clear
*
* Note: non-const, may stash error details
**/
AllocInfo alloc_info(value_type mem) noexcept;
/** discard all allocated memory, return to empty state
* Promise:
* - committed memory unchanged

View file

@ -45,6 +45,8 @@ namespace xo {
static bool contains(const DArena &, const void * p) noexcept;
static AllocatorError last_error(const DArena &) noexcept;
/** retrieve allocation bookkeeping info for @p mem from arena @p d **/
static AllocInfo alloc_info(DArena &, value_type mem) noexcept;
/** expand committed space in arena @p d
* to size at least @p z
* In practice will round up to a multiple of @ref page_z_.

View file

@ -209,6 +209,8 @@ namespace xo {
/** expand gen0 committed size to at least @p z.
**/
bool expand(size_type z) noexcept;
/** Retreive bookkeeping info for allocation at @p mem. **/
AllocInfo alloc_info(value_type mem) noexcept;
// ----- book-keeping -----

View file

@ -56,6 +56,8 @@ namespace xo {
static value_type sub_alloc(DX1Collector & d, size_type z, bool complete) noexcept;
/** expand gen0 spaces (both from-space and to-space) **/
static bool expand(DX1Collector & d, size_type z) noexcept;
/** fetch allocation bookkeeping info **/
static AllocInfo alloc_info(DX1Collector & d, value_type mem) noexcept;
/** reset to empty state; clears all generations **/
static void clear(DX1Collector & d);