xo-alloc: explicit typeseq arg to alloc

This commit is contained in:
Roland Conybeare 2026-01-02 10:20:19 -05:00
commit 6bd33bd900
22 changed files with 99 additions and 48 deletions

View file

@ -117,20 +117,22 @@ namespace xo {
**/
virtual bool expand(Opaque d, std::size_t z) const noexcept = 0;
/** attempt to allocate @p z bytes of memory from allocator @p d.
* for object with type @p t.
* (DX1collector cares about @p t, DArena does not)
* If allocation fails returns nullptr. In this case error details may be retrieved
* using last error
**/
virtual value_type alloc(Opaque d, size_type z) const = 0;
virtual value_type alloc(Opaque d, typeseq t, size_type z) const = 0;
/** like @ref alloc, but follow with one or more consecutive
* @ref sub_alloc() calls. This sequence of allocs will share
* the initial allocation header.
**/
virtual value_type super_alloc(Opaque d, size_type z) const = 0;
virtual value_type super_alloc(Opaque d, typeseq t, size_type z) const = 0;
/** follow a preceding @ref super_alloc call with additional
* subsidiary allocs that share the same object header.
* Must finish sequence with exactly one sub_alloc call
* with @p complete_flag set. This sub_alloc call may have
* zero @p z
* zero @p z.
**/
virtual value_type sub_alloc(Opaque d, size_type z, bool complete_flag) const = 0;
/** reset allocator @p d to empty state. **/

View file

@ -26,6 +26,7 @@ namespace xo {
**/
struct IAllocator_Any : public AAllocator {
//using Impl = IAllocator_ImplType<xo::facet::DVariantPlaceholder>;
using typeseq = xo::facet::typeseq;
using size_type = std::size_t;
const AAllocator * iface() const { return std::launder(this); }
@ -49,8 +50,8 @@ namespace xo {
// 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 alloc(Opaque, typeseq, std::size_t) const override { _fatal(); }
[[noreturn]] value_type super_alloc(Opaque, typeseq, 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(); }

View file

@ -60,9 +60,11 @@ namespace xo {
bool expand(Opaque d,
std::size_t z) const noexcept override { return I::expand(_dcast(d), z); }
value_type alloc(Opaque d,
std::size_t z) const override { return I::alloc(_dcast(d), z); }
typeseq t,
std::size_t z) const override { return I::alloc(_dcast(d), t, z); }
value_type super_alloc(Opaque d,
std::size_t z) const override { return I::super_alloc(_dcast(d), z); }
typeseq t,
std::size_t z) const override { return I::super_alloc(_dcast(d), t, z); }
value_type sub_alloc(Opaque d,
std::size_t z,
bool complete_flag) const override {

View file

@ -40,8 +40,8 @@ namespace xo {
AllocInfo alloc_info(value_type mem) const noexcept { return O::iface()->alloc_info(O::data(), mem); }
range_type alloc_range(DArena & mm) const noexcept { return O::iface()->alloc_range(O::data(), mm); }
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 alloc(typeseq t, size_type z) noexcept { return O::iface()->alloc(O::data(), t, z); }
value_type super_alloc(typeseq t, size_type z) noexcept { return O::iface()->super_alloc(O::data(), t, z); }
value_type sub_alloc(size_type z,
bool complete_flag) noexcept { return O::iface()->sub_alloc(O::data(),
z, complete_flag); }

View file

@ -8,6 +8,7 @@
#include "ArenaConfig.hpp"
#include "AllocError.hpp"
#include "AllocInfo.hpp"
#include <xo/facet/typeseq.hpp>
namespace xo {
namespace mm {
@ -43,7 +44,9 @@ namespace xo {
/** @brief a contiguous memory range **/
using range_type = std::pair<value_type, value_type>;
/** @brief type for allocation header (if enabled) **/
using header_type = AllocHeader; //std::uint64_t;
using header_type = AllocHeader;
/** integer identifying a type (see xo::facet::typeid<T>()) **/
using typeseq = xo::facet::typeseq;
/** @brief mode argument for @ref _alloc **/
enum class alloc_mode : uint8_t {
@ -169,14 +172,14 @@ namespace xo {
* May expand committed memory, as long as resulting committed size
* is no larger than reserved size
**/
value_type alloc(size_type z);
value_type alloc(typeseq t, size_type z);
/** when store_header_flag enabled:
* like alloc(), but combine memory consumed by this alloc
* plus following consecutive sub_alloc()'s into a single header.
* otherwise equivalent to alloc()
**/
value_type super_alloc(size_type z);
value_type super_alloc(typeseq t, size_type z);
/** when store_header_flag enabled:
* follow preceding super_alloc() by one or more sub_allocs().
@ -271,7 +274,10 @@ namespace xo {
static T *
construct_with(DArena & ialloc, Args&&... args)
{
std::byte * mem = ialloc.alloc(sizeof(T));
using xo::facet::typeseq;
typeseq t = typeseq::id<T>();
std::byte * mem = ialloc.alloc(t, sizeof(T));
if (mem)
return new (mem) T(std::forward<Args>(args)...);

View file

@ -29,6 +29,7 @@ namespace xo {
* IAllocator_Xfer IAllocator_Xfer.hpp
* RAllocator RAllocator.hpp
*/
using typeseq = xo::facet::typeseq;
using size_type = std::size_t;
using value_type = std::byte *;
using range_type = AAllocator::range_type;
@ -54,13 +55,13 @@ namespace xo {
**/
static bool expand(DArena & d, size_type z) noexcept;
static value_type alloc(DArena &, size_type z);
static value_type alloc(DArena &, typeseq t, size_type z);
/** when store_header_flag enabled:
* like alloc(), but combine memory consumed by this alloc
* plus following consecutive sub_alloc()'s into a single header.
* otherwise equivalent to alloc()
**/
static value_type super_alloc(DArena &, size_type z);
static value_type super_alloc(DArena &, typeseq t, size_type z);
/** when store_header_flag enabled:
* follow preceding super_alloc() by one or more sub_allocs().
* accumulate total allocated size (including padding) into

View file

@ -15,6 +15,7 @@
#include <string.h> // for ::memset()
namespace xo {
using xo::facet::typeseq;
using std::byte;
using std::size_t;
@ -313,18 +314,20 @@ namespace xo {
}
std::byte *
DArena::alloc(std::size_t req_z)
DArena::alloc(typeseq t, std::size_t req_z)
{
/* - primary allocation path:
* exactly 1 header per alloc() call.
* - store_header_flag follows configuration
*/
(void)t;
return _alloc(req_z, alloc_mode::standard);
}
std::byte *
DArena::super_alloc(std::size_t req_z)
DArena::super_alloc(typeseq t, std::size_t req_z)
{
/* - (uncommon) pattern for parent alloc immediately followed by
* zero-or-more susidiary allocs, all sharing a single header.
@ -332,6 +335,8 @@ namespace xo {
* ArenaConfig.store_header_flag_ disabled
*/
(void)t;
return _alloc(req_z,
alloc_mode::super);
}

View file

@ -111,16 +111,18 @@ namespace xo {
std::byte *
IAllocator_DArena::alloc(DArena & s,
typeseq t,
std::size_t req_z)
{
return s.alloc(req_z);
return s.alloc(t, req_z);
}
std::byte *
IAllocator_DArena::super_alloc(DArena & s,
typeseq t,
std::size_t req_z)
{
return s.super_alloc(req_z);
return s.super_alloc(t, req_z);
}
std::byte *

View file

@ -169,7 +169,7 @@ namespace xo {
/* arbitrary alloc size */
size_t req_z = 13;
byte * mem = a1o.alloc(req_z);
byte * mem = a1o.alloc(typeseq::anon(), req_z);
REQUIRE(arena.error_count_ == 0);
REQUIRE(mem != nullptr);

View file

@ -26,6 +26,7 @@ namespace xo {
using xo::mm::padding;
using xo::mm::error;
using xo::facet::obj;
using xo::facet::typeseq;
using xo::scope;
using std::byte;
using std::size_t;
@ -199,7 +200,7 @@ namespace xo {
REQUIRE(a1o.allocated() == 0);
size_t z0 = 1;
byte * m0 = a1o.alloc(1);
byte * m0 = a1o.alloc(typeseq::anon(), 1);
REQUIRE(m0);
REQUIRE(a1o.last_error().error_ == error::ok);
@ -211,7 +212,7 @@ namespace xo {
REQUIRE(a1o.committed() <= a1o.reserved());
size_t z1 = 16;
byte * m1 = a1o.alloc(z1);
byte * m1 = a1o.alloc(typeseq::anon(), z1);
REQUIRE(m1);
REQUIRE(a1o.last_error().error_ == error::ok);
@ -248,7 +249,7 @@ namespace xo {
REQUIRE(a1o.allocated() == 0);
size_t z0 = 1;
byte * m0 = a1o.alloc(1);
byte * m0 = a1o.alloc(typeseq::anon(), 1);
REQUIRE(m0);
@ -291,7 +292,7 @@ namespace xo {
REQUIRE(a1o.allocated() == 0);
size_t z0 = 1;
byte * m0 = a1o.alloc(1);
byte * m0 = a1o.alloc(typeseq::anon(), 1);
REQUIRE(m0);
@ -343,7 +344,7 @@ namespace xo {
REQUIRE(a1o.allocated() == 0);
size_t z0 = cfg.hugepage_z_ + 1;
byte * m0 = a1o.alloc(z0);
byte * m0 = a1o.alloc(typeseq::anon(), z0);
REQUIRE(!m0);

View file

@ -43,6 +43,8 @@ namespace utest {
xoshiro256ss * p_rgen,
obj<AAllocator> mm)
{
using xo::facet::typeseq;
scope log(XO_DEBUG(catch_flag), xtag("n-alloc", n_alloc));
/* track allocs. verify:
@ -65,7 +67,7 @@ namespace utest {
bool ok_flag = true;
std::byte * mem = mm.alloc(z);
std::byte * mem = mm.alloc(typeseq::anon(), z);
log && log(xtag("i_alloc", i_alloc),
xtag("si", si),

View file

@ -44,6 +44,13 @@ namespace xo {
}
/** 'anonymous' sentinel type.
* Niche uses for this, e.g. untyped allocator
**/
static typeseq_impl<Tag> anon() {
return typeseq_impl(-1);
}
int32_t seqno() const { return seqno_; }
private:

View file

@ -155,6 +155,7 @@ namespace xo {
// ----- DX1Collector -----
struct DX1Collector {
using typeseq = xo::facet::typeseq;
using size_type = DArena::size_type;
using value_type = DArena::value_type;
using header_type = DArena::header_type;
@ -216,9 +217,14 @@ namespace xo {
// ----- allocation -----
/** simple allocation. new allocs always in gen0 to-space **/
value_type alloc(size_type z) noexcept;
/** compound allocation. To be followed immediately by:
/** simple allocation. allocate @p z bytes of memory
* for an object of type @p t.
* New allocs always in gen0 to-space
**/
value_type alloc(typeseq t, size_type z) noexcept;
/** compound allocation. Allocate @p z bytes of memory
* for an object of type @p t.
* To be followed immediately by:
* 1. zero or more calls to sub_alloc(zi, complete=false), then
* 2. exactly one call to sub_alloc(zi, complete=true)
* all the allocs in a compound allocation share the same
@ -226,7 +232,7 @@ namespace xo {
* allocation with size z + sum(zi).
* New allocs always in gen0 to-space
**/
value_type super_alloc(size_type z) noexcept;
value_type super_alloc(typeseq t, size_type z) noexcept;
/** sub-allocation with preceding compound allocation.
* New allocs always in gen0 to-space
**/

View file

@ -29,6 +29,7 @@ namespace xo {
* RAllocator RCollector.hpp
*/
struct IAllocator_DX1Collector {
using typeseq = xo::facet::typeseq;
using size_type = std::size_t;
using value_type = std::byte *;
using range_type = AAllocator::range_type;
@ -58,8 +59,8 @@ namespace xo {
static range_type alloc_range(const DX1Collector & d, DArena & ialloc) noexcept;
/** always alloc in gen0 to-space **/
static value_type alloc(DX1Collector & d, size_type z) noexcept;
static value_type super_alloc(DX1Collector & d, size_type z) noexcept;
static value_type alloc(DX1Collector & d, typeseq t, size_type z) noexcept;
static value_type super_alloc(DX1Collector & d, typeseq t, size_type z) noexcept;
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;

View file

@ -216,14 +216,14 @@ namespace xo {
}
auto
DX1Collector::alloc(size_type z) noexcept -> value_type
DX1Collector::alloc(typeseq t, size_type z) noexcept -> value_type
{
return with_facet<AAllocator>::mkobj(new_space()).alloc(z);
return with_facet<AAllocator>::mkobj(new_space()).alloc(t, z);
}
auto
DX1Collector::super_alloc(size_type z) noexcept -> value_type {
return with_facet<AAllocator>::mkobj(new_space()).super_alloc(z);
DX1Collector::super_alloc(typeseq t, size_type z) noexcept -> value_type {
return with_facet<AAllocator>::mkobj(new_space()).super_alloc(t, z);
}
auto

View file

@ -12,6 +12,7 @@
namespace xo {
using xo::facet::with_facet;
using xo::facet::typeseq;
using std::size_t;
using std::byte;
@ -80,15 +81,19 @@ namespace xo {
}
auto
IAllocator_DX1Collector::alloc(DX1Collector & d, size_type z) noexcept -> value_type
IAllocator_DX1Collector::alloc(DX1Collector & d,
typeseq t,
size_type z) noexcept -> value_type
{
return d.alloc(z);
return d.alloc(t, z);
}
auto
IAllocator_DX1Collector::super_alloc(DX1Collector & d, size_type z) noexcept -> value_type
IAllocator_DX1Collector::super_alloc(DX1Collector & d,
typeseq t,
size_type z) noexcept -> value_type
{
return d.super_alloc(z);
return d.super_alloc(t, z);
}
auto

View file

@ -30,6 +30,7 @@ namespace xo {
using xo::mm::cmpresult;
using xo::mm::padding;
using xo::facet::with_facet;
using xo::facet::typeseq;
using std::byte;
namespace ut {
@ -109,7 +110,7 @@ namespace xo {
REQUIRE(a1o.allocated() == 0);
size_t req_z = 13;
byte * mem = gc.alloc(req_z);
byte * mem = gc.alloc(typeseq::anon(), req_z);
REQUIRE(mem != nullptr);

View file

@ -43,6 +43,8 @@ namespace utest {
xoshiro256ss * p_rgen,
obj<AAllocator> mm)
{
using xo::facet::typeseq;
scope log(XO_DEBUG(catch_flag), xtag("n-alloc", n_alloc));
/* track allocs. verify:
@ -65,7 +67,7 @@ namespace utest {
bool ok_flag = true;
std::byte * mem = mm.alloc(z);
std::byte * mem = mm.alloc(typeseq::anon(), z);
log && log(xtag("i_alloc", i_alloc),
xtag("si", si),

View file

@ -8,6 +8,7 @@
namespace xo {
using xo::mm::AGCObject;
using xo::facet::typeseq;
namespace scm {
static DList s_null(obj<AGCObject>(), nullptr);
@ -22,7 +23,7 @@ namespace xo {
DList::list(obj<AAllocator> mm,
obj<AGCObject> h1)
{
void * mem = mm.alloc(sizeof(DList));
void * mem = mm.alloc(typeseq::id<DList>(), sizeof(DList));
return new (mem) DList(h1, DList::null());
}
@ -32,7 +33,7 @@ namespace xo {
obj<AGCObject> h1,
obj<AGCObject> h2)
{
void * mem = mm.alloc(sizeof(DList));
void * mem = mm.alloc(typeseq::id<DList>(), sizeof(DList));
return new (mem) DList(h1, DList::list(mm, h2));
}

View file

@ -11,6 +11,7 @@
namespace xo {
using xo::mm::AAllocator;
using xo::facet::obj;
using xo::facet::typeseq;
using std::size_t;
namespace scm {
@ -24,7 +25,8 @@ namespace xo {
IGCObject_DFloat::shallow_copy(const DFloat & src,
obj<AAllocator> mm) noexcept
{
DFloat * copy = (DFloat *)mm.alloc(sizeof(DFloat));
DFloat * copy = (DFloat *)mm.alloc(typeseq::id<DFloat>(),
sizeof(DFloat));
if (copy)
*copy = src;

View file

@ -11,6 +11,7 @@
namespace xo {
using xo::mm::AAllocator;
using xo::facet::obj;
using xo::facet::typeseq;
using std::size_t;
namespace scm {
@ -24,7 +25,8 @@ namespace xo {
IGCObject_DInteger::shallow_copy(const DInteger & src,
obj<AAllocator> mm) noexcept
{
DInteger * copy = (DInteger *)mm.alloc(sizeof(DInteger));
DInteger * copy = (DInteger *)mm.alloc(typeseq::id<DInteger>(),
sizeof(DInteger));
if (copy)
*copy = src;

View file

@ -8,8 +8,9 @@
namespace xo {
using xo::mm::AGCObject;
using xo::mm::AAllocator;
using xo::facet::with_facet;
//using xo::facet::with_facet;
using xo::facet::obj;
using xo::facet::typeseq;
using std::size_t;
namespace scm {
@ -23,7 +24,8 @@ namespace xo {
IGCObject_DList::shallow_copy(const DList & src,
obj<AAllocator> mm) noexcept
{
DList * copy = (DList *)mm.alloc(sizeof(DList));
/* FIXME: need to supply object age here */
DList * copy = (DList *)mm.alloc(typeseq::id<DList>(), sizeof(DList));
if (copy)
*copy = src;