xo-ordinaltree: expand unittest + debug logging
This commit is contained in:
parent
b4d12edc00
commit
39a9dc725c
3 changed files with 92 additions and 30 deletions
|
|
@ -143,8 +143,8 @@ namespace xo {
|
|||
/** check write barrier (if impl has write barrier)
|
||||
* given an object @p parent that contains object pointer @p lhs.
|
||||
**/
|
||||
virtual bool check_write_barrier(IObject * /*parent*/,
|
||||
IObject ** /*lhs*/,
|
||||
virtual bool check_write_barrier(const void * /*parent*/,
|
||||
const void * const * /*lhs*/,
|
||||
bool /*may_throw*/) const { return true; };
|
||||
/** write barrier for collector. perform assignment
|
||||
* @code
|
||||
|
|
@ -169,6 +169,16 @@ namespace xo {
|
|||
}
|
||||
};
|
||||
|
||||
/** for gc_allocator_traits, want an allocator pointer we can inherit from **/
|
||||
struct IAllocPtr {
|
||||
public:
|
||||
inline bool check_write_barrier(const void * parent, const void * const * lhs, bool may_throw) const {
|
||||
return mm_->check_write_barrier(parent, lhs, may_throw);
|
||||
}
|
||||
|
||||
IAlloc * mm_ = nullptr;
|
||||
};
|
||||
|
||||
/** allocator wrapper (in the style of std::allocator)
|
||||
**/
|
||||
template <typename T>
|
||||
|
|
@ -183,10 +193,11 @@ namespace xo {
|
|||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
using gc_object_interface = IAlloc::gc_object_interface;
|
||||
using gc_interface = IAllocPtr;
|
||||
using has_incremental_gc_interface = IAlloc::has_incremental_gc_interface;
|
||||
|
||||
/** rebind is for typed allocators. since IAlloc is untyped,
|
||||
* we want degenerate version
|
||||
* rebind is almost trivial
|
||||
**/
|
||||
template <typename U>
|
||||
struct rebind {
|
||||
|
|
@ -194,16 +205,16 @@ namespace xo {
|
|||
};
|
||||
|
||||
public:
|
||||
explicit allocator(IAlloc * mm) : mm_{mm} {}
|
||||
explicit allocator(IAlloc * mm) : impl_{mm} {}
|
||||
|
||||
allocator(const allocator &) = default;
|
||||
allocator & operator=(const allocator &) = default;
|
||||
|
||||
template <typename U>
|
||||
allocator(const allocator<U> & other) : mm_{other.mm_} {}
|
||||
allocator(const allocator<U> & other) : impl_{other.impl_.mm_} {}
|
||||
|
||||
pointer allocate(size_type n) {
|
||||
std::byte * raw = mm_->allocate(n * sizeof(T));
|
||||
std::byte * raw = impl_.mm_->allocate(n * sizeof(T));
|
||||
|
||||
return reinterpret_cast<pointer>(raw);
|
||||
}
|
||||
|
|
@ -211,7 +222,7 @@ namespace xo {
|
|||
void deallocate(pointer p, size_type n) {
|
||||
std::byte * raw = reinterpret_cast<std::byte *>(p);
|
||||
|
||||
mm_->deallocate(raw, n * sizeof(T));
|
||||
impl_.mm_->deallocate(raw, n * sizeof(T));
|
||||
}
|
||||
|
||||
// optional construct, destroy (but allocator_traits provides defaults)
|
||||
|
|
@ -221,11 +232,14 @@ namespace xo {
|
|||
**/
|
||||
template <typename U>
|
||||
bool operator==(const allocator<U> & other) const noexcept {
|
||||
return mm_ == other.mm_;
|
||||
return impl_.mm_ == other.impl_.mm_;
|
||||
}
|
||||
|
||||
/** gc_interface=IAlloc **/
|
||||
operator gc_interface () const { return impl_; }
|
||||
|
||||
public:
|
||||
IAlloc * mm_ = nullptr;
|
||||
IAllocPtr impl_;
|
||||
};
|
||||
|
||||
} /*namespace gc*/
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ namespace xo {
|
|||
/** GC write barrier:
|
||||
* assign value @p rhs to member @p *lhs of @p parent.
|
||||
* Identifiy and remember cross-generational pointers.
|
||||
*
|
||||
* Expect Allocator is xo::gc::allocator<T> (see IAlloc.hpp)
|
||||
**/
|
||||
template <typename T, typename Allocator>
|
||||
void _gc_assign_member(T ** lhs,
|
||||
|
|
@ -37,7 +39,7 @@ namespace xo {
|
|||
{
|
||||
static_assert(std::is_convertible_v<decltype(*lhs), IObject*>);
|
||||
|
||||
alloc.mm_->assign_member(this, reinterpret_cast<IObject **>(lhs), rhs);
|
||||
alloc.impl_.mm_->assign_member(this, reinterpret_cast<IObject **>(lhs), rhs);
|
||||
}
|
||||
|
||||
/** true iff this object represents a forwarding pointer.
|
||||
|
|
|
|||
|
|
@ -40,6 +40,19 @@ namespace xo {
|
|||
virtual std::size_t _forward_children(gc::IAlloc *) { assert(false); return 0; }
|
||||
};
|
||||
|
||||
/** dummy GC interface.
|
||||
* non-empty intersection with IAlloc
|
||||
**/
|
||||
template <typename GcObjectInterface>
|
||||
struct FallbackGcInterface {
|
||||
template <typename Allocator>
|
||||
FallbackGcInterface(Allocator & alloc) {}
|
||||
|
||||
bool check_write_barrier(const void * parent,
|
||||
const void * const * lhs,
|
||||
bool may_throw) { return true; };
|
||||
};
|
||||
|
||||
/** Extended version of
|
||||
* std::allocator_traits<Allocator>
|
||||
* Introduces additional i/face methods
|
||||
|
|
@ -136,6 +149,8 @@ namespace xo {
|
|||
using super::allocate;
|
||||
using super::deallocate;
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
// default: allocator A fallback to standard non-gc allocator behavior
|
||||
template <typename A, typename = void>
|
||||
struct has_incremental_gc_interface : std::false_type {};
|
||||
|
|
@ -148,6 +163,19 @@ namespace xo {
|
|||
struct has_incremental_gc_interface<A, std::void_t<typename A::has_incremental_gc_interface>> :
|
||||
A::has_incremental_gc_interface {};
|
||||
|
||||
/** true iff this allocator advertises itself as an incremental collector.
|
||||
* Allocator will include:
|
||||
*
|
||||
* struct IAlloc {
|
||||
* using has_incremental_gc_interface = std::true_type;
|
||||
* };
|
||||
**/
|
||||
static inline constexpr
|
||||
bool
|
||||
has_incremental_gc_interface_v = has_incremental_gc_interface<Allocator>::value;
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
// default: allocate A fallback to standard non-GC allocator behavior
|
||||
template <typename A, typename = void>
|
||||
struct has_trivial_deallocate : std::false_type {};
|
||||
|
|
@ -160,6 +188,19 @@ namespace xo {
|
|||
struct has_trivial_deallocate<A, std::void_t<typename A::has_trivial_deallocate>> :
|
||||
A::has_trivial_deallocate {};
|
||||
|
||||
/** true iff this allocator advertises trivial deallocate
|
||||
* Allocate will include:
|
||||
*
|
||||
* struct IAlloc {
|
||||
* using has_trivial_deallocate = std::true_type;
|
||||
* };
|
||||
**/
|
||||
static inline constexpr
|
||||
bool
|
||||
has_trivial_deallocate_v = has_trivial_deallocate<Allocator>::value;
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
// default: empty object interface.
|
||||
//
|
||||
// classes that want to conditionally support GC
|
||||
|
|
@ -187,27 +228,32 @@ namespace xo {
|
|||
//
|
||||
using object_interface_type = object_interface<Allocator>;
|
||||
|
||||
/** true iff this allocator advertises itself as an incremental collector.
|
||||
* Allocator will include:
|
||||
*
|
||||
* struct IAlloc {
|
||||
* using has_incremental_gc_interface = std::true_type;
|
||||
* };
|
||||
**/
|
||||
static inline constexpr
|
||||
bool
|
||||
has_incremental_gc_interface_v = has_incremental_gc_interface<Allocator>::value;
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
// default: minimal garbage collector interface.
|
||||
//
|
||||
// Use in allocator-aware components that need conditionally
|
||||
// to engage with GC functionality.
|
||||
// For example in RedBlackTree::verify_ok() want to check
|
||||
// cross-generational pointers.
|
||||
//
|
||||
// gc_interface gc
|
||||
// - gc_interface(A & alloc)
|
||||
// - gc.check_write_barrier(const object_interface_type * p,
|
||||
// const object_interface_type * const * lhs,
|
||||
// bool may_throw)
|
||||
//
|
||||
template <typename A, typename = void>
|
||||
struct gc_interface : public FallbackGcInterface<object_interface_type> {};
|
||||
|
||||
// allocator opt-in by providing a gc_interface type
|
||||
template <typename A>
|
||||
struct gc_interface<A, std::void_t<typename A::gc_interface>> : public A::gc_interface {};
|
||||
|
||||
// interface for (narrow) GC interaction.
|
||||
// Construct from allocator
|
||||
using gc_interface_type = gc_interface<Allocator>;
|
||||
|
||||
/** true iff this allocator advertises trivial deallocate
|
||||
* Allocate will include:
|
||||
*
|
||||
* struct IAlloc {
|
||||
* using has_trivial_deallocate = std::true_type;
|
||||
* };
|
||||
**/
|
||||
static inline constexpr
|
||||
bool
|
||||
has_trivial_deallocate_v = has_trivial_deallocate<Allocator>::value;
|
||||
};
|
||||
} /*namespace gc*/
|
||||
} /*namespace xo*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue