xo-alloc / xo-ordinaltree: work on dual-alloc-policy trees
This commit is contained in:
parent
b03f0be2f2
commit
c7816416c5
7 changed files with 65 additions and 19 deletions
|
|
@ -318,7 +318,8 @@ namespace xo {
|
||||||
* @param rhs. new target for @p *lhs
|
* @param rhs. new target for @p *lhs
|
||||||
**/
|
**/
|
||||||
virtual void assign_member(IObject * parent, IObject ** lhs, IObject* rhs) final override;
|
virtual void assign_member(IObject * parent, IObject ** lhs, IObject* rhs) final override;
|
||||||
|
/** evacuate @p *lhs and replace with forwarding pointer **/
|
||||||
|
virtual void forward_inplace(IObject ** lhs) final override;
|
||||||
/** during GC check for source objects owned by GC.
|
/** during GC check for source objects owned by GC.
|
||||||
* See Object::_shallow_move.
|
* See Object::_shallow_move.
|
||||||
**/
|
**/
|
||||||
|
|
|
||||||
|
|
@ -568,6 +568,12 @@ namespace xo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GC::forward_inplace(IObject ** lhs)
|
||||||
|
{
|
||||||
|
Object::_forward_inplace(lhs, this);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
GC::check_owned(IObject * src) const
|
GC::check_owned(IObject * src) const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,8 @@ namespace xo {
|
||||||
Object::mm = nullptr;
|
Object::mm = nullptr;
|
||||||
|
|
||||||
IObject *
|
IObject *
|
||||||
Object::_forward(IObject * src, gc::IAlloc * gc)
|
Object::_forward(IObject * src,
|
||||||
|
gc::IAlloc * gc)
|
||||||
{
|
{
|
||||||
if (!src)
|
if (!src)
|
||||||
return src;
|
return src;
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ namespace xo {
|
||||||
std::byte * allocate(std::size_t n) {
|
std::byte * allocate(std::size_t n) {
|
||||||
return this->alloc(n);
|
return this->alloc(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** std::allocator locality hint. Not used for now **/
|
/** std::allocator locality hint. Not used for now **/
|
||||||
std::byte * allocate(std::size_t n, const void * hint) {
|
std::byte * allocate(std::size_t n, const void * hint) {
|
||||||
(void)hint;
|
(void)hint;
|
||||||
|
|
@ -147,6 +147,8 @@ namespace xo {
|
||||||
virtual void assign_member(IObject * /*parent*/,
|
virtual void assign_member(IObject * /*parent*/,
|
||||||
IObject ** lhs,
|
IObject ** lhs,
|
||||||
IObject * rhs) { *lhs = rhs; }
|
IObject * rhs) { *lhs = rhs; }
|
||||||
|
/** if GC: evacuate @p *lhs and replace with forwarding pointer **/
|
||||||
|
virtual void forward_inplace(IObject ** lhs) { (void)lhs; }
|
||||||
/** allocate @p z bytes for copy of object at @p src.
|
/** allocate @p z bytes for copy of object at @p src.
|
||||||
* Only used in @ref GC. Default implementation asserts and returns nullptr
|
* Only used in @ref GC. Default implementation asserts and returns nullptr
|
||||||
**/
|
**/
|
||||||
|
|
@ -170,7 +172,7 @@ namespace xo {
|
||||||
using const_reference = const T &;
|
using const_reference = const T &;
|
||||||
using size_type = IAlloc::size_type;
|
using size_type = IAlloc::size_type;
|
||||||
using difference_type = std::ptrdiff_t;
|
using difference_type = std::ptrdiff_t;
|
||||||
|
|
||||||
using gc_object_interface = IAlloc::gc_object_interface;
|
using gc_object_interface = IAlloc::gc_object_interface;
|
||||||
using has_incremental_gc_interface = IAlloc::has_incremental_gc_interface;
|
using has_incremental_gc_interface = IAlloc::has_incremental_gc_interface;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,9 @@ namespace xo {
|
||||||
**/
|
**/
|
||||||
class IObject {
|
class IObject {
|
||||||
public:
|
public:
|
||||||
|
/** impl inheriting this class must provide gc hooks **/
|
||||||
|
static constexpr bool _requires_gc_hooks = true;
|
||||||
|
|
||||||
/** true iff this object represents a forwarding pointer.
|
/** true iff this object represents a forwarding pointer.
|
||||||
* Forwarding pointers are exclusively created by the garbage collector;
|
* Forwarding pointers are exclusively created by the garbage collector;
|
||||||
* forwarding pointers (and only forwarding pointers) return true here.
|
* forwarding pointers (and only forwarding pointers) return true here.
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ namespace xo {
|
||||||
* provide garbage collection
|
* provide garbage collection
|
||||||
* - xo::gc::GC has a collection API and also provides
|
* - xo::gc::GC has a collection API and also provides
|
||||||
* garbage collection
|
* garbage collection
|
||||||
*
|
*
|
||||||
* GC-allocated objects must:
|
* GC-allocated objects must:
|
||||||
* 2a. inherit A::object_interface
|
* 2a. inherit A::object_interface
|
||||||
* 2b. implement A::object_interface::_shallow_size()
|
* 2b. implement A::object_interface::_shallow_size()
|
||||||
|
|
@ -40,7 +40,7 @@ namespace xo {
|
||||||
* 2d. implement A::object_interface::_forward_children(alloc)
|
* 2d. implement A::object_interface::_forward_children(alloc)
|
||||||
* in multiple inheritance scenarios
|
* in multiple inheritance scenarios
|
||||||
* 2e. implement A::object_interface::_offset_destination(src)
|
* 2e. implement A::object_interface::_offset_destination(src)
|
||||||
*
|
*
|
||||||
* Design Notes:
|
* Design Notes:
|
||||||
* - virtual-method choice requires vtable pointer per object;
|
* - virtual-method choice requires vtable pointer per object;
|
||||||
* but zero *marginal* space cost for types that would have
|
* but zero *marginal* space cost for types that would have
|
||||||
|
|
@ -82,12 +82,16 @@ namespace xo {
|
||||||
// gc_allocator_traits<Allocator>::template object_interface<Allocator>
|
// gc_allocator_traits<Allocator>::template object_interface<Allocator>
|
||||||
//
|
//
|
||||||
template <typename A, typename = void>
|
template <typename A, typename = void>
|
||||||
struct object_interface {};
|
struct object_interface {
|
||||||
|
/** see also IObject::_requires_gc_hooks **/
|
||||||
|
static constexpr bool _requires_gc_hooks = false;
|
||||||
|
};
|
||||||
|
|
||||||
// specialization when A provides gc_object_interface
|
// specialization when A provides gc_object_interface
|
||||||
template <typename A>
|
template <typename A>
|
||||||
struct object_interface<A, std::void_t<typename A::gc_object_interface>>
|
struct object_interface<A, std::void_t<typename A::gc_object_interface>>
|
||||||
: A::gc_object_interface {};
|
: public A::gc_object_interface {
|
||||||
|
};
|
||||||
|
|
||||||
/** true iff this allocator advertises itself as an incremental collector
|
/** true iff this allocator advertises itself as an incremental collector
|
||||||
* allocator will include:
|
* allocator will include:
|
||||||
|
|
@ -97,7 +101,6 @@ namespace xo {
|
||||||
* };
|
* };
|
||||||
**/
|
**/
|
||||||
static inline constexpr bool has_incremental_gc_interface_v = has_incremental_gc_interface<Allocator>::value;
|
static inline constexpr bool has_incremental_gc_interface_v = has_incremental_gc_interface<Allocator>::value;
|
||||||
|
|
||||||
};
|
};
|
||||||
} /*namespace gc*/
|
} /*namespace gc*/
|
||||||
} /*namespace xo*/
|
} /*namespace xo*/
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#include "RbTypes.hpp"
|
#include "RbTypes.hpp"
|
||||||
#include "xo/reflect/Reflect.hpp"
|
#include "xo/reflect/Reflect.hpp"
|
||||||
#include "xo/indentlog/scope.hpp"
|
#include "xo/indentlog/scope.hpp"
|
||||||
|
#include "xo/allocutil/IAlloc.hpp"
|
||||||
#include "xo/allocutil/IObject.hpp"
|
#include "xo/allocutil/IObject.hpp"
|
||||||
#include "xo/allocutil/gc_allocator_traits.hpp"
|
#include "xo/allocutil/gc_allocator_traits.hpp"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
@ -301,7 +302,7 @@ namespace xo {
|
||||||
xtag("r2", this->reduced2()));
|
xtag("r2", this->reduced2()));
|
||||||
} /*local_recalc_size*/
|
} /*local_recalc_size*/
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void assign_color(Color x) { this->color_ = x; }
|
void assign_color(Color x) { this->color_ = x; }
|
||||||
void assign_size(size_t z) { this->size_ = z; }
|
void assign_size(size_t z) { this->size_ = z; }
|
||||||
|
|
||||||
|
|
@ -344,20 +345,49 @@ namespace xo {
|
||||||
} /*replace_child_reparent*/
|
} /*replace_child_reparent*/
|
||||||
|
|
||||||
// ----- (possibly) inherited from GcObjectInterface -----
|
// ----- (possibly) inherited from GcObjectInterface -----
|
||||||
virtual TaggedPtr self_tp() const { return Reflect::make_tp(const_cast<Node*>(this)); }
|
|
||||||
virtual void display(std::ostream & os) const { os << "<Node>"; }
|
|
||||||
virtual std::size_t _shallow_size() const { return sizeof(*this); }
|
|
||||||
/* note: only relevant when GcObjectInterface is xo::IObject */
|
|
||||||
|
|
||||||
template <typename T = GcObjectInterface>
|
virtual TaggedPtr self_tp() const {
|
||||||
virtual IObject * _shallow_copy(gc::IAlloc * gc) const
|
return Reflect::make_tp(const_cast<Node *>(this));
|
||||||
-> std::enable_if_t<std::is_base_of_v<xo::IObject:
|
}
|
||||||
{
|
virtual void display(std::ostream & os) const {
|
||||||
/* assert appropriate here. code will be present but dead when assert fails */
|
os << "<Node>";
|
||||||
xo::Cpof cpof(gc, this);
|
|
||||||
return new (cpof) Node(*this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual std::size_t _shallow_size() const { return sizeof(*this); }
|
||||||
|
/* note: only relevant when GcObjectInterface is xo::IObject */
|
||||||
|
virtual IObject * _shallow_copy(gc::IAlloc * gc) const {
|
||||||
|
if constexpr (GcObjectInterface::_requires_gc_hooks) {
|
||||||
|
xo::Cpof cpof(gc, this);
|
||||||
|
return new (cpof) Node(*this);
|
||||||
|
} else {
|
||||||
|
assert(false && "_shallow_copy assumes gc enabled");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::size_t _forward_children(gc::IAlloc * gc) {
|
||||||
|
if constexpr (GcObjectInterface::_requires_gc_hooks) {
|
||||||
|
static_assert(std::is_convertible_v<decltype(parent_), IObject *>,
|
||||||
|
"parent_ must be convertible to IObject*");
|
||||||
|
static_assert(std::is_convertible_v<decltype(child_v_[0]), IObject *>,
|
||||||
|
"child_v_[0] must be convertible to IObject*");
|
||||||
|
|
||||||
|
gc->forward_inplace(reinterpret_cast<IObject **>(&parent_));
|
||||||
|
gc->forward_inplace(reinterpret_cast<IObject **>(&child_v_[0]));
|
||||||
|
gc->forward_inplace(reinterpret_cast<IObject **>(&child_v_[1]));
|
||||||
|
|
||||||
|
// how do we tell if any of
|
||||||
|
// {value_type, ReducedValue}
|
||||||
|
// also contain pointers that need forwarding?
|
||||||
|
|
||||||
|
return Node::_shallow_size();
|
||||||
|
} else {
|
||||||
|
assert(false && "_forward_children assumes gc enabled");
|
||||||
|
return 0ul;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
friend class RbTreeUtil<Key, Value, Reduce, GcObjectInterface>;
|
friend class RbTreeUtil<Key, Value, Reduce, GcObjectInterface>;
|
||||||
template <typename Key1, typename Value1, typename Reduce1, typename Allocator>
|
template <typename Key1, typename Value1, typename Reduce1, typename Allocator>
|
||||||
friend class xo::tree::RedBlackTree;
|
friend class xo::tree::RedBlackTree;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue