From b1562b1ee6d0c6af74b1832436e73760dc6fa38a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 1 Dec 2025 22:25:41 -0500 Subject: [PATCH] xo-ordinaltree: GC test [wip] --- include/xo/allocutil/IAlloc.hpp | 70 +++++++++++++++++++- include/xo/allocutil/IObject.hpp | 14 ++++ include/xo/allocutil/gc_allocator_traits.hpp | 4 ++ 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/include/xo/allocutil/IAlloc.hpp b/include/xo/allocutil/IAlloc.hpp index 5c18a2a..4f9097f 100644 --- a/include/xo/allocutil/IAlloc.hpp +++ b/include/xo/allocutil/IAlloc.hpp @@ -14,6 +14,7 @@ namespace xo { using up = std::unique_ptr; class IObject; + class Object; namespace gc { /** @class IAllocator @@ -31,10 +32,15 @@ namespace xo { **/ class IAlloc { public: + /** type-erased allocator **/ + using value_type = std::byte; using pointer_type = std::byte *; using size_type = std::size_t; - /** traits: see gc_allocator_traits **/ - using gc_object_interface = xo::IObject; + /** traits: see gc_allocator_traits + * + * want Object here (not IObject) to get Object::_forward_to() + **/ + using gc_object_interface = xo::Object; using has_incremental_gc_interface = std::true_type; public: @@ -151,6 +157,66 @@ namespace xo { // LCOV_EXCL_STOP } }; + + /** allocator wrapper (in the style of std::allocator) + **/ + template + struct allocator { + public: + using value_type = T; + using pointer = T *; + using const_pointer = const T *; + using reference = T &; + using const_reference = const T &; + using size_type = IAlloc::size_type; + using difference_type = std::ptrdiff_t; + + using gc_object_interface = IAlloc::gc_object_interface; + using has_incremental_gc_interface = IAlloc::has_incremental_gc_interface; + + /** rebind is for typed allocators. since IAlloc is untyped, + * we want degenerate version + **/ + template + struct rebind { + using other = allocator; + }; + + public: + explicit allocator(IAlloc * mm) : mm_{mm} {} + + allocator(const allocator &) = default; + allocator & operator=(const allocator &) = default; + + template + allocator(const allocator & other) : mm_{other.mm_} {} + + pointer allocate(size_type n) { + std::byte * raw = mm_->allocate(n * sizeof(T)); + + return reinterpret_cast(raw); + } + + void deallocate(pointer p, size_type n) { + std::byte * raw = reinterpret_cast(p); + + mm_->deallocate(raw, n * sizeof(T)); + } + + // optional construct, destroy (but allocator_traits provides defaults) + + /** required! otherwise allocator, allocator with the same IAlloc* + * would be considered to own disjoin memory addresses + **/ + template + bool operator==(const allocator & other) const noexcept { + return mm_ == other.mm_; + } + + public: + IAlloc * mm_ = nullptr; + }; + } /*namespace gc*/ class MMPtr { diff --git a/include/xo/allocutil/IObject.hpp b/include/xo/allocutil/IObject.hpp index c4b1580..87c6013 100644 --- a/include/xo/allocutil/IObject.hpp +++ b/include/xo/allocutil/IObject.hpp @@ -92,6 +92,20 @@ namespace xo { **/ virtual std::size_t _forward_children(gc::IAlloc * gc) = 0; }; + + /** @class Cpof + * @brief argument to operator new used for garbage collector evacuation phase + * + * Tag overloaded operator new to activate allocation policy based on location + * in memory of source object. + **/ + class Cpof { + public: + explicit Cpof(gc::IAlloc * mm, const IObject * src) : mm_{mm}, src_{src} {} + + gc::IAlloc * mm_ = nullptr; + const void * src_ = nullptr; + }; } /* end IObject.hpp */ diff --git a/include/xo/allocutil/gc_allocator_traits.hpp b/include/xo/allocutil/gc_allocator_traits.hpp index e183471..dd1a632 100644 --- a/include/xo/allocutil/gc_allocator_traits.hpp +++ b/include/xo/allocutil/gc_allocator_traits.hpp @@ -57,6 +57,10 @@ namespace xo { using super = std::allocator_traits; using pointer = typename super::pointer; using value_type = typename super::value_type; + using super::construct; + using super::destroy; + using super::allocate; + using super::deallocate; // default: allocator A fallback to standard non-gc allocator behavior template