xo-alloc2 xo-object: bugfix + refactor -> IGCObject_DList builds

This commit is contained in:
Roland Conybeare 2025-12-14 13:52:29 -05:00
commit 9b74d749a3
19 changed files with 421 additions and 19 deletions

View file

@ -4,9 +4,12 @@ Glossary
--------
.. glossary::
b/c
b/c
| abbreviation for ``because``
dwim
| abbreviation for ``do what I mean``
iff
| abbreviation for ``if, and only if``

View file

@ -3,6 +3,14 @@
* @author Roland Conybeare, Dec 2025
**/
#pragma once
#include "IGCObject_Any.hpp"
#include <xo/facet/facet_implementation.hpp>
#include <xo/facet/typeseq.hpp>
#include <xo/facet/obj.hpp>
#include "gc/generation.hpp"
#include "gc/role.hpp"
@ -14,6 +22,8 @@ namespace xo {
using Copaque = const void *;
using Opaque = void *;
struct IGCObject_Any; // see IGCObject_Any.hpp
/** @class ACollector
* @brief Abstract facet for the XO garbage collector
*
@ -37,8 +47,13 @@ namespace xo {
* in which case calls through @c std::launder(&iface)
* will properly act on @c DFoo.
**/
virtual void install_type(Opaque d, int32_t tseq, AGCObject_Any & iface);
virtual void add_gc_root(Opaque d, int32_t tid, Opaque * root) = 0;
virtual void install_type(Opaque d, int32_t tseq, IGCObject_Any & iface);
virtual void add_gc_root(Opaque d, int32_t tseq, Opaque * root) = 0;
/** evacuate @p *lhs to to-space and replace with forwarding pointer
* Require: gc in progress
**/
virtual void forward_inplace(Opaque d, obj<AGCObject> * lhs) = 0;
};
}

View file

@ -9,7 +9,7 @@
#include "RAllocator.hpp"
#include "xo/facet/facet_implementation.hpp"
#include "xo/facet/typeseq.hpp"
#include "xo/facet/obj.hpp"
#include "xo/facet/obj.hpp" // for obj<AAllocator> in shallow_copy
#include <cstdint>
#include <cstddef>

View file

@ -31,6 +31,7 @@ namespace xo {
// from AAllocator
int32_t _typeseq() const noexcept override { return s_typeseq; }
// const methods
[[noreturn]] std::string_view name(Copaque) const noexcept override { _fatal(); }
[[noreturn]] size_type reserved(Copaque) const noexcept override { _fatal(); }
[[noreturn]] size_type size(Copaque) const noexcept override { _fatal(); }
@ -40,6 +41,7 @@ namespace xo {
[[noreturn]] bool contains(Copaque, const void *) const noexcept override { _fatal(); }
[[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(); }

View file

@ -0,0 +1,51 @@
/** @file ICollector_Any.hpp
*
* @author Roland Conybeare, Dec 2025
**/
#pragma once
#include "ACollector.hpp"
//#include <cassert>
namespace xo {
namespace mm { struct ICollector_Any; }
namespace facet {
template <>
struct FacetImplementation<xo::mm::ACollector, DVariantPlaceholder> {
using ImplType = xo::mm::ICollector_Any;
};
}
namespace mm {
/** @class ICollector_Any
* @brief Stub Collector Implementation for empty variant instance
**/
struct ICollector_Any : public ACollector {
using size_type = std::size_t;
// from ACollector
int32_t _typeseq() const noexcept override { return s_typeseq; }
// const methods
[[noreturn]] size_type allocated(Copaque, generation, role) const noexcept { _fatal(); }
[[noreturn]] size_type reserved(Copaque, generation, role) const noexcept { _fatal(); }
[[noreturn]] size_type committed(Copaque, generation, role) const noexcept { _fatal(); }
// non-const methods
[[noreturn]] void install_type(Opaque, int32_t, IGCObject_Any &) noexcept { _fatal(); }
[[noreturn]] void add_gc_root(Opaque, int32_t, Opaque *) { _fatal(); }
[[noreturn]] void forward_inplace(Opaque, obj<AGCObject> *) { _fatal(); }
private:
[[noreturn]] static void _fatal();
public:
static int32_t s_typeseq;
static bool _valid;
};
} /*namespace mm*/
} /*namespace xo*/
/* end ICollector_Any.hpp */

View file

@ -6,7 +6,7 @@
#pragma once
#include "AAllocator.hpp"
#include "xo/facet/RRouter.hpp"
#include <xo/facet/RRouter.hpp>
#include <string>
namespace xo {
@ -18,28 +18,29 @@ namespace xo {
using O = Object;
public:
using ObjectType = Object;
using DataPtr = Object::DataPtr;
using size_type = std::size_t;
using value_type = std::byte *;
RAllocator() {}
RAllocator(Object::DataPtr data) : Object{std::move(data)} {}
int32_t _typeseq() const { return O::iface()->_typeseq(); }
std::string_view name() const { return O::iface()->name(O::data()); }
size_type reserved() const { return O::iface()->reserved(O::data()); }
size_type size() const { return O::iface()->size(O::data()); }
size_type committed() const { return O::iface()->committed(O::data()); }
size_type available() const { return O::iface()->available(O::data()); }
size_type allocated() const { return O::iface()->allocated(O::data()); }
bool contains(const void * p) const { return O::iface()->contains(O::data(), p); }
AllocatorError last_error() const { return O::iface()->last_error(O::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); }
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) { return O::iface()->alloc(O::data(), z); }
value_type super_alloc(size_type z) { return O::iface()->super_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) { return O::iface()->sub_alloc(O::data(),
z, complete_flag); }
bool complete_flag) noexcept { return O::iface()->sub_alloc(O::data(),
z, complete_flag); }
static bool _valid;
};

View file

@ -0,0 +1,51 @@
/** @file RCollector.hpp
*
* @author Roland Conybeare, Dec 2025
**/
#include "ACollector.hpp"
#include <xo/facet/RRouter.hpp>
namespace xo {
namespace mm {
/** @class RCollector **/
template <typename Object>
struct RCollector : public Object {
private:
using O = Object;
public:
using ObjectType = Object;
using DataPtr = Object::DataPtr;
using size_type = std::size_t;
//using value_type = std::byte *;
RCollector() = default;
RCollector(DataPtr data) : Object{std::move(data)} {}
int32_t _typeseq() const noexcept { return O::iface()->_typeseq(); }
size_type allocated(generation g, role r) const noexcept { return O::iface()->allocated(O::data()); }
size_type reserved(generation g, role r) const noexcept { return O::iface()->reserved(O::data()); }
size_type committed(generation g, role r) const noexcept { return O::iface()->committed(O::data()); }
void install_type(int32_t tseq, IGCObject_Any & iface) { return O::iface()->install_type(O::data()); }
void add_gc_root(int32_t tseq, Opaque * root) { O::iface()->add_gc_root(O::data()); }
void forward_inplace(obj<AGCObject> * lhs) { O::iface()->forward_inplace(O::data(), lhs); }
static bool _valid;
};
template <typename Object>
bool
RCollector<Object>::_valid = facet::valid_object_router<Object>();
} /*namespace mm*/
namespace facet {
template <typename Object>
struct RoutingFor<xo::mm::ACollector, Object> {
using RoutingType = xo::mm::RCollector<Object>;
};
}
} /*namespace xo*/
/* end RCollector.hpp */

View file

@ -0,0 +1,51 @@
/** @file RCollector_Any.hpp
*
* @author Roland Conybeare, Dec 2025
**/
#pragma once
#include "ACollector.hpp"
//#include <cassert>
namespace xo {
namespace mm { struct ICollector_Any; }
namespace facet {
template <>
struct FacetImplementation<xo::mm::ACollector, DVariantPlaceholder> {
using ImplType = xo::mm::ICollector_Any;
};
}
namespace mm {
/** @class ICollector_Any
* @brief Stub Collector Implementation for empty variant instance
**/
struct ICollector_Any : public ACollector {
using size_type = std::size_t;
// from ACollector
int32_t _typeseq() const noexcept override { return s_typeseq; }
// const methods
[[noreturn]] size_type allocated(Copaque, generation, role) const noexcept { _fatal(); }
[[noreturn]] size_type reserved(Copaque, generation, role) const noexcept { _fatal(); }
[[noreturn]] size_type committed(Copaque, generation, role) const noexcept { _fatal(); }
// non-const methods
[[noreturn]] void install_type(Opaque, int32_t, IGCObject_Any &) noexcept { _fatal(); }
[[noreturn]] void add_gc_root(Opaque, int32_t, Opaque *) { _fatal(); }
[[noreturn]] void forward_inplace(Opaque, Opaque **) { _fatail(); }
private:
[[noreturn]] static void _fatal();
public:
static int32_t s_typeseq;
static bool _valid;
};
} /*namespace mm*/
} /*namespace xo*/
/* end RCollector_Any.hpp */

View file

@ -0,0 +1,47 @@
/** @file RGCObject.hpp
*
* @author Roland Conybeare, Dec 2025
**/
#pragma once
#include "AGCObject.hpp"
#include <xo/facet/RRouter.hpp>
namespace xo {
namespace mm {
/** @class RGCObject **/
template <typename Object>
struct RGCObject : public Object {
private:
using O = Object;
public:
using ObjectType = Object;
using DataPtr = Object::DataPtr;
using size_type = std::size_t;
RGCObject() = default;
RGCObject(Object::DataPtr data) : Object{std::move(data)} {}
int32_t _typeseq() const noexcept { return O::iface()->_typeseq(); }
size_type shallow_size() const noexcept { O::iface()->shallow_size(O::data()); }
Opaque * shallow_copy(obj<AAllocator> mm) const noexcept { O::iface()->shallow_copy(O::data(), mm); }
size_type forward_children() noexcept { O::iface()->forward_children(O::data()); }
static bool _valid;
};
template <typename Object>
bool
RGCObject<Object>::_valid = facet::valid_object_router<RGCObject>();
} /*namespace mm*/
namespace facet {
template <typename Object>
struct RoutingFor<xo::mm::AGCObject, Object> {
using RoutingType = xo::mm::RGCObject<Object>;
};
}
} /*namespace xo*/
/* end RGCObject.hpp */

View file

@ -3,6 +3,8 @@
* @author Roland Conybeare, Dec 2025
**/
#pragma once
#include <cstddef>
#include <cstdint>

View file

@ -8,6 +8,8 @@ set(SELF_SRCS
IAllocator_Any.cpp
IAllocator_DArena.cpp
ICollector_Any.cpp
IGCObject_Any.cpp
)

View file

@ -0,0 +1,39 @@
/** @file ICollector_Any.cpp
*
* @author Roland Conybeare, Dec 2025
**/
#include "ICollector_Any.hpp"
#include <iostream>
namespace xo {
using xo::facet::DVariantPlaceholder;
using xo::facet::typeseq;
using xo::facet::valid_facet_implementation;
namespace mm {
void
ICollector_Any::_fatal() {
/* control here on uninitialized ICollector_Any.
* Initialized instance will have specific implementation type
* e.g. ICollector_Xfer<DCollector>
*/
std::cerr << "fatal"
<< ": attempt to call uninitialized"
<< " ICollector_Any method"
<< std::endl;
std::terminate();
}
int32_t
ICollector_Any::s_typeseq = typeseq::id<DVariantPlaceholder>();
bool
ICollector_Any::_valid = valid_facet_implementation<ACollector, ICollector_Any>();
} /*namespace mm*/
} /*namespace xo*/
/** end ICollector_Any.cpp */

View file

@ -72,6 +72,8 @@ namespace xo {
/** OObject is truthy **/
operator bool() const { return data_ != nullptr; }
// ----- iface() for variant fat pointer -----
/** interface pointer for variant OObject instances.
* These instance support runtime polymorphism.
**/
@ -88,6 +90,18 @@ namespace xo {
return std::launder(&iface_);
}
/** non-const verison. Technically all interface methods are const.
* But counterintuitive to have to mark interface methods const
* that are dedicated to mutable data.
**/
FacetType * iface()
requires std::is_same_v<DataType, DVariantPlaceholder>
{
return std::launder(&iface_);
}
// ----- iface() for typed fat pointer -----
/** interface pointer for OObject instance with representation
* known at compile time.
*
@ -102,6 +116,16 @@ namespace xo {
return &iface_;
}
/** non-const verison. Technically all interface methods are const.
* But counterintuitive to have to mark interface methods const
* that are dedicated to mutable data.
**/
FacetType * iface()
requires(!std::is_same_v<DataType, DVariantPlaceholder>)
{
return &iface_;
}
DataPtr data() const { return data_; }
void reset() { data_ = nullptr; }

View file

@ -12,6 +12,10 @@ namespace xo {
template <typename RRouter>
consteval bool valid_object_router()
{
static_assert(sizeof(RRouter) >= sizeof(RRouter::ObjectType),
"Router type must inherit Router::ObjectType");
static_assert(std::is_convertible_v<RRouter, typename RRouter::ObjectType>,
"Router type must inherit Router::ObjectType");
static_assert(requires { typename RRouter::ObjectType; },
"Router type must provide typename Router::ObjectType");
static_assert(valid_object_traits<RRouter::ObjectType>,

View file

@ -5,9 +5,11 @@
#pragma once
#include <cstdint>
namespace xo {
namespace scm {
using DInteger = double;
using DInteger = std::int64_t;
} /*nmaespace obj*/
} /*namespace xo*/

View file

@ -0,0 +1,26 @@
/** @file DList.hpp
*
* @author Roland Conybeare, Dec 2025
**/
#include "xo/alloc2/RGCObject.hpp"
#include "xo/alloc2/IGCObject_Any.hpp"
#include "xo/facet/obj.hpp"
namespace xo {
namespace scm {
struct DList {
using AGCObject = xo::mm::AGCObject;
DList(xo::obj<AGCObject> h,
xo::obj<AGCObject> r) : head_{h}, rest_{r} {}
obj<AGCObject> head_;
obj<AGCObject> rest_;
};
} /*namespace scm*/
} /*namespace xo*/
/* end DList.hpp */

View file

@ -0,0 +1,36 @@
/** @file IGCObject_DList.hpp
*
* @author Roland Conybeare, Dec 2025
**/
#pragma once
#include <xo/alloc2/AAllocator.hpp>
#include <xo/alloc2/RAllocator.hpp>
#include <xo/alloc2/ACollector.hpp>
#include <xo/alloc2/ICollector_Any.hpp>
#include <xo/alloc2/RCollector.hpp>
#include <xo/alloc2/AGCObject.hpp>
#include <xo/alloc2/IGCObject_Xfer.hpp>
#include "DList.hpp"
namespace xo {
namespace scm {
/* changes here coordinate with:
* IGCObject_XFer
*/
struct IGCObject_DList {
public:
using AAllocator = xo::mm::AAllocator;
using ACollector = xo::mm::ACollector;
using size_type = std::size_t;
static size_type shallow_size(const DList & d) noexcept;
static DList * shallow_copy(const DList & d, obj<AAllocator> mm) noexcept;
static size_type forward_children(DList & d, obj<ACollector> gc) noexcept;
};
} /*namespace scm*/
} /*namespace xo*/
/* end IGCObject_DList.hpp */

View file

@ -4,6 +4,7 @@ set(SELF_LIB xo_object2)
set(SELF_SRCS
IGCObject_DFloat.cpp
IGCObject_DInteger.cpp
IGCObject_DList.cpp
)
xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS})

View file

@ -0,0 +1,45 @@
/** @file IGCObject_DList.cpp
*
* @author Roland Conybeare, Dec 2025
**/
#include "IGCObject_DList.hpp"
namespace xo {
using xo::mm::AAllocator;
using xo::facet::obj;
using std::size_t;
namespace scm {
size_t
IGCObject_DList::shallow_size(const DList &) noexcept
{
return sizeof(DList);
}
DList *
IGCObject_DList::shallow_copy(const DList & src,
obj<AAllocator> mm) noexcept
{
DList * copy = (DList *)mm.alloc(sizeof(DList));
if (copy)
*copy = src;
return copy;
}
size_t
IGCObject_DList::forward_children(DList & src,
obj<ACollector> gc) noexcept
{
gc.forward_inplace(&src.head_);
gc.forward_inplace(&src.rest_);
return shallow_size(src);
}
} /*namespace scm*/
} /*namespace xo*/
/* end IGCObject_DList.cpp */