xo-alloc2: + Allocator.alloc_range() with DArena input

This commit is contained in:
Roland Conybeare 2025-12-18 18:34:54 -05:00
commit 181ae9f12b
13 changed files with 158 additions and 59 deletions

View file

@ -37,4 +37,4 @@ namespace xo {
} /*namespace mm*/ } /*namespace mm*/
} /*namespace xo*/ } /*namespace xo*/
/* end AllocIterator.hpp */ /* end AAllocIterator.hpp */

View file

@ -7,8 +7,10 @@
#include "AllocError.hpp" #include "AllocError.hpp"
#include "AllocInfo.hpp" #include "AllocInfo.hpp"
#include "xo/facet/facet_implementation.hpp" #include "AllocIterator.hpp"
#include "xo/facet/typeseq.hpp" #include <xo/facet/obj.hpp>
#include <xo/facet/facet_implementation.hpp>
#include <xo/facet/typeseq.hpp>
#include <string> #include <string>
namespace xo { namespace xo {
@ -32,6 +34,8 @@ namespace xo {
using value_type = std::byte *; using value_type = std::byte *;
/** object header, if configured **/ /** object header, if configured **/
using header_type = std::uint64_t; using header_type = std::uint64_t;
/** iterator range. These are forward iterators over allocs **/
using range_type = std::pair<obj<AAllocIterator>, obj<AAllocIterator>>;
///@} ///@}
/* /*
@ -85,20 +89,21 @@ namespace xo {
* Non-const @p d because may stash error details * Non-const @p d because may stash error details
**/ **/
virtual AllocInfo alloc_info(Copaque d, value_type mem) const noexcept = 0; virtual AllocInfo alloc_info(Copaque d, value_type mem) const noexcept = 0;
/** Ideally we want to control allocation for iterator here. /** Ideally we want to control allocator for iterator here.
* Awkward to describe to compiler since we don't have vt<AAllocator> yet. * Awkward to supply to compiler since we don't have obj<AAllocator> yet.
* OTOH iteration over allocs is a niche feature. * OTOH iteration over allocs is a super-niche feature.
* Consider alternatives: *
* Rejected alternatives:
* - put begin/end in separate interface. e.g. extend AAllocator * - put begin/end in separate interface. e.g. extend AAllocator
* - layer of indirection: begin/end return iterator factory. * - layer of indirection: begin/end return iterator factory.
* Then allocator can be passed to iterator factory separately. * Then allocator can be passed to iterator factory separately.
* Helps because factory can be static * Helps because factory can be static
* - abandon allocator support in this case. Instead will need to * - abandon allocator support in this case. Instead will need to
* reinstate uvt<AAllocIterator> (unique variant), use heap * reinstate uvt<AAllocIterator> (unique variant), use heap
* - just pass DArena& for alloc-iterator-allocation *
* @p mm is allocator for resulting iterator range
**/ **/
//virtual facet::vt<AAllocIterator> begin(Copaque d, DArena & ialloc) const noexcept; virtual range_type alloc_range(Copaque d, DArena & mm) const noexcept = 0;
// virtual obj<AAllocIterator> end() const noexcept = 0;
/** expand committed space in arena @p d /** expand committed space in arena @p d
* to size at least @p z * to size at least @p z

View file

@ -1,24 +0,0 @@
/** @file AllocIterator.hpp
*
* @author Roland Conybeare, Dec 2025
**/
#pragma once
namespace xo {
namespace mm {
/** @class AllocIterator
* @brief iterator over arena allocations.
*
* Intended for instrumentation/diagnostics.
* Not needed for normal operator
**/
struct AllocIterator {
};
} /*namespace mm*/
} /*namespace xo*/
/* end AllocIterator.hpp */

View file

@ -45,6 +45,7 @@ namespace xo {
[[noreturn]] AllocInfo alloc_info(Copaque, value_type) const noexcept override { _fatal(); } [[noreturn]] AllocInfo alloc_info(Copaque, value_type) const noexcept override { _fatal(); }
// defn in .cpp - problematic to require compiler know vt<AAllocIterator> defn here // defn in .cpp - problematic to require compiler know vt<AAllocIterator> defn here
//[[noreturn]] facet::vt<AAllocIterator> begin(Copaque, DArena &) const noexcept override; // { _fatal(); } //[[noreturn]] facet::vt<AAllocIterator> begin(Copaque, DArena &) const noexcept override; // { _fatal(); }
[[noreturn]] range_type alloc_range(Copaque, DArena &) const noexcept override { _fatal(); }
// non-const methods // non-const methods
[[noreturn]] bool expand(Opaque, std::size_t) const noexcept override { _fatal(); } [[noreturn]] bool expand(Opaque, std::size_t) const noexcept override { _fatal(); }

View file

@ -39,12 +39,13 @@ namespace xo {
return I::contains(_dcast(d), p); return I::contains(_dcast(d), p);
} }
AllocError last_error(Copaque d) const noexcept override { return I::last_error(_dcast(d)); } AllocError last_error(Copaque d) const noexcept override { return I::last_error(_dcast(d)); }
// non-const methods
AllocInfo alloc_info(Copaque d, value_type mem) const noexcept override { AllocInfo alloc_info(Copaque d, value_type mem) const noexcept override {
return I::alloc_info(_dcast(d), mem); return I::alloc_info(_dcast(d), mem);
} }
range_type alloc_range(Copaque d, DArena & mm) const noexcept override { return I::alloc_range(_dcast(d), mm); }
// non-const methods
bool expand(Opaque d, bool expand(Opaque d,
std::size_t z) const noexcept override { return I::expand(_dcast(d), z); } std::size_t z) const noexcept override { return I::expand(_dcast(d), z); }
value_type alloc(Opaque d, value_type alloc(Opaque d,

View file

@ -59,6 +59,14 @@ namespace xo {
**/ **/
static DArenaIterator end(const DArena * arena); static DArenaIterator end(const DArena * arena);
/** 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.
* This is the address of header for _next_ allocation in @p arena
* i.e. free pointer
**/
static AllocHeader * end_header(const DArena * arena);
/** A valid iterator can be compared, at least with itself /** A valid iterator can be compared, at least with itself
* It can be dereferenced if is also non-empty * It can be dereferenced if is also non-empty
**/ **/

View file

@ -19,15 +19,20 @@ namespace xo {
} }
namespace mm { namespace mm {
/* changes here coordinate with: /** @class IAllocator_DArena
* AAllocator AAllocator.hpp * @brief Provide AAllocator interface for DArena state
* IAllocator_Any IAllocator_Any.hpp **/
* IAllocator_Xfer IAllocator_Xfer.hpp
* RAllocator RAllocator.hpp
*/
struct IAllocator_DArena { struct IAllocator_DArena {
/* changes here coordinate with:
* AAllocator AAllocator.hpp
* IAllocator_Any IAllocator_Any.hpp
* IAllocator_Xfer IAllocator_Xfer.hpp
* RAllocator RAllocator.hpp
*/
using size_type = std::size_t; using size_type = std::size_t;
using value_type = std::byte *; using value_type = std::byte *;
using range_type = std::pair<obj<AAllocIterator>,
obj<AAllocIterator>>;
enum class alloc_mode : uint8_t { enum class alloc_mode : uint8_t {
standard, standard,
@ -44,9 +49,13 @@ namespace xo {
static size_type allocated(const DArena &) noexcept; static size_type allocated(const DArena &) noexcept;
static bool contains(const DArena &, const void * p) noexcept; static bool contains(const DArena &, const void * p) noexcept;
static AllocError last_error(const DArena &) noexcept; static AllocError last_error(const DArena &) noexcept;
/** retrieve allocation bookkeeping info for @p mem from arena @p d **/ /** retrieve allocation bookkeeping info for @p mem from arena @p d **/
static AllocInfo alloc_info(const DArena &, value_type mem) noexcept; static AllocInfo alloc_info(const DArena &, value_type mem) noexcept;
/** create alloc-iterator range over allocs on @d,
* Iterators themselves allocated from @p ialloc.
**/
static range_type alloc_range(const DArena & d, DArena & ialloc) noexcept;
/** expand committed space in arena @p d /** expand committed space in arena @p d
* to size at least @p z * to size at least @p z
* In practice will round up to a multiple of @ref page_z_. * In practice will round up to a multiple of @ref page_z_.

View file

@ -31,6 +31,8 @@ namespace xo {
struct IAllocator_DX1Collector { struct IAllocator_DX1Collector {
using size_type = std::size_t; using size_type = std::size_t;
using value_type = std::byte *; using value_type = std::byte *;
using range_type = std::pair<obj<AAllocIterator>,
obj<AAllocIterator>>;
// todo: available() // todo: available()
@ -51,6 +53,10 @@ namespace xo {
static AllocError last_error(const DX1Collector &) noexcept; static AllocError last_error(const DX1Collector &) noexcept;
/** fetch allocation bookkeeping info **/ /** fetch allocation bookkeeping info **/
static AllocInfo alloc_info(const DX1Collector & d, value_type mem) noexcept; static AllocInfo alloc_info(const DX1Collector & d, value_type mem) noexcept;
/** create alloc-iterator range over allocs in @d,
* with iterator working storage obtained from @p ialloc
**/
static range_type alloc_range(const DX1Collector & d, DArena & ialloc) noexcept;
/** always alloc in gen0 to-space **/ /** always alloc in gen0 to-space **/
static value_type alloc(DX1Collector & d, size_type z) noexcept; static value_type alloc(DX1Collector & d, size_type z) noexcept;

View file

@ -19,16 +19,10 @@ namespace xo {
constexpr bool c_debug_flag = false; constexpr bool c_debug_flag = false;
scope log(XO_DEBUG(c_debug_flag)); scope log(XO_DEBUG(c_debug_flag));
assert(arena); AllocHeader * begin_hdr = begin_header(arena);
if (arena->config_.store_header_flag_ == false) {
arena->capture_error(error::alloc_iterator_not_supported);
if (!begin_hdr)
return DArenaIterator::invalid(); return DArenaIterator::invalid();
}
byte * begin_byte = arena->lo_;
AllocHeader * begin_hdr = (AllocHeader *)begin_byte;
log && log(xtag("begin_hdr", begin_hdr)); log && log(xtag("begin_hdr", begin_hdr));
@ -41,20 +35,48 @@ namespace xo {
constexpr bool c_debug_flag = false; constexpr bool c_debug_flag = false;
scope log(XO_DEBUG(c_debug_flag)); scope log(XO_DEBUG(c_debug_flag));
AllocHeader * end_hdr = end_header(arena);
if (!end_hdr)
return DArenaIterator::invalid();
log && log(xtag("end_hdr", end_hdr));
return DArenaIterator(arena, end_hdr);
}
AllocHeader *
DArenaIterator::begin_header(const DArena * arena)
{
assert(arena); assert(arena);
if (arena->config_.store_header_flag_ == false) { if (arena->config_.store_header_flag_ == false) {
arena->capture_error(error::alloc_iterator_not_supported); arena->capture_error(error::alloc_iterator_not_supported);
return DArenaIterator::invalid(); return nullptr;
}
byte * begin_byte = arena->lo_;
AllocHeader * begin_hdr = (AllocHeader *)begin_byte;
return begin_hdr;
}
AllocHeader *
DArenaIterator::end_header(const DArena * arena)
{
assert(arena);
if (arena->config_.store_header_flag_ == false) {
arena->capture_error(error::alloc_iterator_not_supported);
return nullptr;
} }
byte * end_byte = arena->free_; byte * end_byte = arena->free_;
AllocHeader * end_hdr = (AllocHeader *)end_byte; AllocHeader * end_hdr = (AllocHeader *)end_byte;
log && log(xtag("end_hdr", end_hdr)); return end_hdr;
return DArenaIterator(arena, end_hdr);
} }
AllocInfo AllocInfo

View file

@ -3,15 +3,20 @@
* @author Roland Conybeare, Dec 2025 * @author Roland Conybeare, Dec 2025
**/ **/
#include "AllocIterator.hpp"
#include "arena/IAllocator_DArena.hpp" #include "arena/IAllocator_DArena.hpp"
#include "arena/IAllocIterator_DArenaIterator.hpp" // for alloc_range
#include "arena/DArenaIterator.hpp"
#include "padding.hpp" #include "padding.hpp"
#include "xo/indentlog/scope.hpp" #include <xo/facet/obj.hpp>
#include <xo/indentlog/scope.hpp>
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <cstring> #include <cstring>
#include <sys/mman.h> #include <sys/mman.h>
namespace xo { namespace xo {
using xo::facet::with_facet;
using std::size_t; using std::size_t;
using std::byte; using std::byte;
@ -65,6 +70,35 @@ namespace xo {
return s.alloc_info(mem); return s.alloc_info(mem);
} }
void dummy(const DArena & s) {
byte * begin_mem = nullptr;
DArenaIterator * ix = new (begin_mem) DArenaIterator(&s, DArenaIterator::begin_header(&s));
obj<AAllocIterator,DArenaIterator> ix_vt{ix};
}
auto
IAllocator_DArena::alloc_range(const DArena & s,
DArena & ialloc) noexcept -> range_type
{
byte * begin_mem = IAllocator_DArena::alloc(ialloc,
sizeof(DArenaIterator));
byte * end_mem = IAllocator_DArena::alloc(ialloc,
sizeof(DArenaIterator));
assert(begin_mem);
assert(end_mem);
DArenaIterator * begin_ix = new (begin_mem) DArenaIterator(&s, DArenaIterator::begin_header(&s));
DArenaIterator * end_ix = new ( end_mem) DArenaIterator(&s, DArenaIterator::end_header(&s));
obj<AAllocIterator> begin_obj = with_facet<AAllocIterator>::mkobj(begin_ix);
obj<AAllocIterator> end_obj = with_facet<AAllocIterator>::mkobj( end_ix);
return std::make_pair(begin_obj, end_obj);
}
bool bool
IAllocator_DArena::expand(DArena & s, size_t target_z) noexcept IAllocator_DArena::expand(DArena & s, size_t target_z) noexcept
{ {

View file

@ -6,9 +6,14 @@
**/ **/
#include "gc/IAllocator_DX1Collector.hpp" #include "gc/IAllocator_DX1Collector.hpp"
#include "gc/IAllocIterator_DX1CollectorIterator.hpp"
#include "gc/DX1CollectorIterator.hpp"
#include "arena/IAllocator_DArena.hpp"
namespace xo { namespace xo {
using xo::facet::with_facet;
using std::size_t; using std::size_t;
using std::byte;
namespace mm { namespace mm {
using value_type = IAllocator_DX1Collector::value_type; using value_type = IAllocator_DX1Collector::value_type;
@ -61,6 +66,29 @@ namespace xo {
return d.last_error(); return d.last_error();
} }
auto
IAllocator_DX1Collector::alloc_range(const DX1Collector & d,
DArena & ialloc) noexcept -> range_type
{
byte * begin_mem = IAllocator_DArena::alloc(ialloc,
sizeof(DX1CollectorIterator));
byte * end_mem = IAllocator_DArena::alloc(ialloc,
sizeof(DX1CollectorIterator));
assert(begin_mem);
assert(end_mem);
DX1CollectorIterator * begin_ix
= new (begin_mem) DX1CollectorIterator(d.begin());
DX1CollectorIterator * end_ix
= new ( end_mem) DX1CollectorIterator(d.end());
obj<AAllocIterator> begin_obj = with_facet<AAllocIterator>::mkobj(begin_ix);
obj<AAllocIterator> end_obj = with_facet<AAllocIterator>::mkobj( end_ix);
return std::make_pair(begin_obj, end_obj);
}
auto auto
IAllocator_DX1Collector::alloc(DX1Collector & d, size_type z) noexcept -> value_type IAllocator_DX1Collector::alloc(DX1Collector & d, size_type z) noexcept -> value_type
{ {

View file

@ -14,12 +14,14 @@ namespace xo {
{ {
switch (x) { switch (x) {
case comparison::invalid: case comparison::invalid:
return "?comparison"; break;
case comparison::comparable: case comparison::comparable:
return "cmp"; return "cmp";
case comparison::incomparable: case comparison::incomparable:
return "!cmp"; return "!cmp";
} }
return "?comparison";
} }
void void

View file

@ -110,7 +110,14 @@ namespace xo {
REQUIRE(ix.is_valid()); REQUIRE(ix.is_valid());
REQUIRE(end_ix.is_valid()); REQUIRE(end_ix.is_valid());
/* iteration not supported since we did not set */ /* verify obj 'fat pointer' packaging */
obj<AAllocIterator,DArenaIterator> ix_vt{&ix};
obj<AAllocIterator,DArenaIterator> end_ix_vt{&end_ix};
REQUIRE(ix_vt.iface());
REQUIRE(ix_vt.data());
REQUIRE(end_ix_vt.iface());
REQUIRE(end_ix_vt.data());
/* arena is empty, so begin==end */ /* arena is empty, so begin==end */
REQUIRE(ix == end_ix); REQUIRE(ix == end_ix);