xo-alloc2: work on alloc_range + operator++ for alloc iterators [WIP]
This commit is contained in:
parent
d09c18eb19
commit
5c7a2e1ad5
9 changed files with 165 additions and 48 deletions
|
|
@ -27,6 +27,9 @@ namespace xo {
|
|||
return O::iface()->compare(O::data(), other); }
|
||||
void next() noexcept { O::iface()->next(O::data()); }
|
||||
|
||||
/** triggers operator++ in obj<RAllocIterator<Object>> **/
|
||||
void _preincrement() noexcept { this->next(); }
|
||||
|
||||
static bool _valid;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ namespace xo {
|
|||
using DataPtr = Object::DataPtr;
|
||||
using size_type = std::size_t;
|
||||
using value_type = std::byte *;
|
||||
using range_type = AAllocator::range_type;
|
||||
|
||||
RAllocator() {}
|
||||
RAllocator(Object::DataPtr data) : Object{std::move(data)} {}
|
||||
|
|
@ -36,7 +37,7 @@ namespace xo {
|
|||
bool contains(const void * p) const noexcept { return O::iface()->contains(O::data(), p); }
|
||||
AllocError last_error() const noexcept { return O::iface()->last_error(O::data()); }
|
||||
AllocInfo alloc_info(value_type mem) const noexcept { return O::iface()->alloc_info(O::data(), mem); }
|
||||
//range_type alloc_range(DArena & mm)
|
||||
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); }
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ namespace xo {
|
|||
cmpresult
|
||||
DArenaIterator::compare(const DArenaIterator & other_ix) const noexcept
|
||||
{
|
||||
scope log(XO_DEBUG(false),
|
||||
scope log(XO_DEBUG(true),
|
||||
xtag("arena", arena_),
|
||||
xtag("pos", pos_),
|
||||
xtag("other.arena", other_ix.arena_),
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "arena/IAllocIterator_DArenaIterator.hpp"
|
||||
#include "AllocIterator.hpp"
|
||||
#include <xo/indentlog/scope.hpp>
|
||||
#include <cassert>
|
||||
|
||||
namespace xo {
|
||||
|
|
@ -21,6 +22,10 @@ namespace xo {
|
|||
IAllocIterator_DArenaIterator::compare(const DArenaIterator & ix,
|
||||
const obj<AAllocIterator> & other_arg) noexcept
|
||||
{
|
||||
scope log(XO_DEBUG(true),
|
||||
xtag("&ix", &ix),
|
||||
xtag("ix.arena", ix.arena_), xtag("ix.pos", ix.pos_));
|
||||
|
||||
/* downcast from variant */
|
||||
auto other = obj<AAllocIterator, DArenaIterator>::from(other_arg);
|
||||
|
||||
|
|
@ -29,6 +34,10 @@ namespace xo {
|
|||
|
||||
DArenaIterator & other_ix = *other;
|
||||
|
||||
log && log(xtag("&other_ix", &other_ix),
|
||||
xtag("other_ix.arena", other_ix.arena_),
|
||||
xtag("other_ix.pos", other_ix.pos_));
|
||||
|
||||
return ix.compare(other_ix);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,13 +74,46 @@ namespace xo {
|
|||
IAllocator_DArena::alloc_range(const DArena & s,
|
||||
DArena & ialloc) noexcept -> range_type
|
||||
{
|
||||
scope log(XO_DEBUG(true));
|
||||
|
||||
DArenaIterator * begin_ix = construct_with<DArenaIterator>(ialloc, &s, s.begin_header());
|
||||
DArenaIterator * end_ix = construct_with<DArenaIterator>(ialloc, &s, s.end_header());
|
||||
|
||||
obj<AAllocIterator> begin_obj = with_facet<AAllocIterator>::mkobj(begin_ix);
|
||||
obj<AAllocIterator> end_obj = with_facet<AAllocIterator>::mkobj( end_ix);
|
||||
obj<AAllocIterator,DArenaIterator> begin_obj = with_facet<AAllocIterator>::mkobj(begin_ix);
|
||||
obj<AAllocIterator,DArenaIterator> end_obj = with_facet<AAllocIterator>::mkobj( end_ix);
|
||||
|
||||
return std::make_pair(begin_obj, end_obj);
|
||||
log && log(xtag("begin_obj.typeseq", begin_obj._typeseq()));
|
||||
|
||||
obj<AAllocIterator> begin_vt = begin_obj;
|
||||
obj<AAllocIterator> end_vt = end_obj;
|
||||
|
||||
log && log(xtag("begin_vt.typeseq", begin_vt._typeseq()));
|
||||
|
||||
log && log(xtag("begin_ix", begin_ix),
|
||||
xtag("begin_ix.arena", begin_ix->arena_),
|
||||
xtag("begin_ix.pos", begin_ix->pos_));
|
||||
|
||||
range_type retval = std::make_pair(begin_vt, end_vt);
|
||||
|
||||
log && log(xtag("1.retval.first.typeseq", retval.first._typeseq()));
|
||||
|
||||
retval.first.from_obj(begin_vt);
|
||||
retval.second.from_obj(end_vt);
|
||||
|
||||
// this gets correct typeseq. so first.from_obj() works
|
||||
log && log(xtag("2.retval.first.typeseq", retval.first._typeseq()));
|
||||
|
||||
obj<AAllocIterator> begin_vt2;
|
||||
|
||||
begin_vt2 = retval.first;
|
||||
|
||||
log && log(xtag("3.begin_vt2.typeseq", begin_vt2._typeseq()));
|
||||
|
||||
retval = std::make_pair(begin_vt2, begin_vt2);
|
||||
|
||||
log && log(xtag("4.retval.first.typeseq", retval.first._typeseq()));
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
#include "arena/IAllocator_DArena.hpp"
|
||||
#include "arena/IAllocIterator_DArenaIterator.hpp"
|
||||
#include "padding.hpp"
|
||||
#include <xo/indentlog/scope.hpp>
|
||||
#include <xo/indentlog/print/tag.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
namespace xo {
|
||||
|
|
@ -27,6 +29,10 @@ namespace xo {
|
|||
using xo::mm::padding;
|
||||
using xo::mm::error;
|
||||
|
||||
using xo::facet::DVariantPlaceholder;
|
||||
using xo::facet::obj;
|
||||
using xo::facet::typeseq;
|
||||
|
||||
using std::byte;
|
||||
|
||||
namespace ut {
|
||||
|
|
@ -146,6 +152,8 @@ namespace xo {
|
|||
|
||||
TEST_CASE("IAllocIterator-singlearena", "[alloc2]")
|
||||
{
|
||||
scope log(XO_DEBUG(true));
|
||||
|
||||
ArenaConfig cfg { .name_ = "testarena",
|
||||
.size_ = 64*1024,
|
||||
.store_header_flag_ = true,
|
||||
|
|
@ -166,37 +174,80 @@ namespace xo {
|
|||
REQUIRE(arena.error_count_ == 0);
|
||||
REQUIRE(mem != nullptr);
|
||||
|
||||
DArenaIterator ix = arena.begin();
|
||||
DArenaIterator end_ix = arena.end();
|
||||
|
||||
REQUIRE(ix.is_valid());
|
||||
REQUIRE(end_ix.is_valid());
|
||||
|
||||
/* arena is non-empty, so begin!=end */
|
||||
REQUIRE (ix != end_ix);
|
||||
|
||||
REQUIRE(arena.error_count_ == 0);
|
||||
|
||||
/* valid iterator can be dereferenced */
|
||||
{
|
||||
AllocInfo info = *ix;
|
||||
DArenaIterator ix = arena.begin();
|
||||
DArenaIterator end_ix = arena.end();
|
||||
|
||||
REQUIRE(ix.is_valid());
|
||||
REQUIRE(end_ix.is_valid());
|
||||
|
||||
/* arena is non-empty, so begin!=end */
|
||||
REQUIRE (ix != end_ix);
|
||||
|
||||
REQUIRE(arena.error_count_ == 0);
|
||||
REQUIRE(info.is_valid());
|
||||
REQUIRE(info.size() == padding::with_padding(req_z));
|
||||
|
||||
auto [payload_lo, payload_hi] = info.payload();
|
||||
/* valid iterator can be dereferenced */
|
||||
{
|
||||
AllocInfo info = *ix;
|
||||
|
||||
REQUIRE(payload_lo == mem);
|
||||
REQUIRE(payload_hi == mem + info.size());
|
||||
REQUIRE(arena.error_count_ == 0);
|
||||
REQUIRE(info.is_valid());
|
||||
REQUIRE(info.size() == padding::with_padding(req_z));
|
||||
|
||||
auto [payload_lo, payload_hi] = info.payload();
|
||||
|
||||
REQUIRE(payload_lo == mem);
|
||||
REQUIRE(payload_hi == mem + info.size());
|
||||
}
|
||||
|
||||
/* valid iterator can be advanced */
|
||||
{
|
||||
ix.next();
|
||||
|
||||
REQUIRE(arena.error_count_ == 0);
|
||||
REQUIRE(ix == end_ix);
|
||||
}
|
||||
}
|
||||
|
||||
/* valid iterator can be advanced */
|
||||
// repeat, this time with generic iterators
|
||||
{
|
||||
ix.next();
|
||||
log && log(xtag("section", "obj<AAllocIterator>"),
|
||||
xtag("arena", &arena),
|
||||
xtag("arena.lo", arena.lo_),
|
||||
xtag("arena.free", arena.free_));
|
||||
|
||||
REQUIRE(arena.error_count_ == 0);
|
||||
REQUIRE(ix == end_ix);
|
||||
DArena scratch_mm
|
||||
= DArena::map(
|
||||
ArenaConfig{
|
||||
.size_ = 4*1024,
|
||||
.hugepage_z_ = 4*1024});
|
||||
|
||||
auto range = a1o.alloc_range(scratch_mm);
|
||||
|
||||
obj<AAllocIterator> ix = range.first;
|
||||
obj<AAllocIterator> end_ix = range.second;
|
||||
|
||||
REQUIRE(ix.iface());
|
||||
REQUIRE(ix.data());
|
||||
REQUIRE(end_ix.iface());
|
||||
REQUIRE(end_ix.data());
|
||||
|
||||
REQUIRE(scratch_mm.allocated() >= 2*sizeof(DArenaIterator));
|
||||
REQUIRE(scratch_mm.available() > 0);
|
||||
|
||||
log && log(xtag("ix._typeseq", ix._typeseq()),
|
||||
xtag("ix.data", ix.data()));
|
||||
|
||||
log && log(xtag("typeseq<DArena>",
|
||||
typeseq::id<DArena>()));
|
||||
log && log(xtag("typeseq<DArenaIterator>",
|
||||
typeseq::id<DArenaIterator>()));
|
||||
log && log(xtag("typeseq<DVariantPlaceholder>",
|
||||
typeseq::id<DVariantPlaceholder>()));
|
||||
|
||||
REQUIRE(ix.compare(ix).is_equal());
|
||||
|
||||
//REQUIRE(ix.compare(end_ix).is_equal());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ namespace utest {
|
|||
DArena scratch_mm = DArena::map(ArenaConfig{.name_ = "scratch",
|
||||
.size_ = 4*1024,
|
||||
.hugepage_z_ = 4*1024 });
|
||||
|
||||
auto range = mm.alloc_range(scratch_mm);
|
||||
|
||||
#ifdef NOT_YET // to verify iteration here, need iterator support in AAllocator
|
||||
|
||||
|
|
|
|||
|
|
@ -133,6 +133,28 @@ namespace xo {
|
|||
void reset() { data_ = nullptr; }
|
||||
void reset_opaque(Opaque data) { data_ = (DataPtr)data; }
|
||||
|
||||
template <typename DOther>
|
||||
OObject & from_obj(const OObject<AFacet, DOther> & other) {
|
||||
if constexpr (std::is_same_v<DRepr, DVariantPlaceholder>) {
|
||||
/* Actual runtime type of other encoded in other.iface()
|
||||
* (whether or not DOther says other is variant).
|
||||
* Either way need to force vtable replacement, hence memcpy here
|
||||
*/
|
||||
::memcpy((void*)this, (void*)&other, sizeof(*this));
|
||||
} else if constexpr (std::is_convertible_v<DRepr, DOther>) {
|
||||
/* other is typed, consistently with *this */
|
||||
this->from_data(other.data());
|
||||
} else
|
||||
{
|
||||
// downcast from variant must be explicit
|
||||
// + may fail at runtime
|
||||
|
||||
static_assert(std::is_same_v<DRepr, DVariantPlaceholder>
|
||||
|| std::is_convertible_v<DRepr, DOther>);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* We're either:
|
||||
* - assigning from pointer with compatible representation
|
||||
|
|
@ -144,8 +166,10 @@ namespace xo {
|
|||
static_assert(std::is_same_v<DRepr, DVariantPlaceholder>
|
||||
|| std::is_convertible_v<DOther*, DRepr*>);
|
||||
|
||||
if constexpr (std::is_convertible_v<DOther*, DRepr*>) {
|
||||
/* assigning from data with same representation,
|
||||
if constexpr (!std::is_same_v<DRepr, DVariantPlaceholder>
|
||||
&& std::is_convertible_v<DOther*, DRepr*>)
|
||||
{
|
||||
/* assigning typed data with consistent representation
|
||||
* keep .iface_ pointer
|
||||
*/
|
||||
this->data_ = other;
|
||||
|
|
|
|||
|
|
@ -49,10 +49,14 @@ namespace xo {
|
|||
struct obj : public RoutingType<AFacet, OObject<AFacet, DRepr>> {
|
||||
using Super = RoutingType<AFacet, OObject<AFacet, DRepr>>;
|
||||
|
||||
obj() {}
|
||||
obj() : Super() {}
|
||||
explicit obj(Super::DataPtr d) : Super(d) {}
|
||||
|
||||
/** copy constructor
|
||||
obj(const obj & rhs) : Super() {
|
||||
this->from_data(rhs.data_);
|
||||
}
|
||||
|
||||
/** pseudo copy constructor
|
||||
*
|
||||
* Intended for use cases:
|
||||
* obj<AFoo, DRepr> lhs = obj<AFoo, DRepr> // same type on rhs
|
||||
|
|
@ -65,16 +69,7 @@ namespace xo {
|
|||
|| std::is_convertible_v<DRepr, DOther>)
|
||||
: Super()
|
||||
{
|
||||
if constexpr (std::is_convertible_v<DRepr, DOther>) {
|
||||
/* preserving .iface */
|
||||
this->data_ = other.data_;
|
||||
} else {
|
||||
/* replacing .iface_
|
||||
*
|
||||
* WARNING: only works if .data_ is POD
|
||||
*/
|
||||
this->from_data(other.data_);
|
||||
}
|
||||
this->from_obj(other);
|
||||
}
|
||||
|
||||
/** move constructor from a different representation.
|
||||
|
|
@ -88,21 +83,22 @@ namespace xo {
|
|||
|| std::is_convertible_v<DRepr, DOther>)
|
||||
: Super()
|
||||
{
|
||||
if constexpr (std::is_convertible_v<DRepr, DOther>) {
|
||||
/* move .data_, keeping .iface_ */
|
||||
this->data_ = std::move(other.data_);
|
||||
} else {
|
||||
// TODO: instead, have other move itself,
|
||||
/* replacing .iface_ along w/ .data_ */
|
||||
this->from_obj(other);
|
||||
}
|
||||
|
||||
/* replacing .iface_ + .data_ */
|
||||
this->from_data(other.data_);
|
||||
}
|
||||
obj & operator=(const obj & rhs) {
|
||||
/* ensure we replace .iface_ along w/ .ata_ */
|
||||
this->from_obj(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** safe downcast from variant. null if downcast fails **/
|
||||
static obj from(const OObject<AFacet> & other) {
|
||||
return obj(other.template downcast<DRepr>());
|
||||
}
|
||||
|
||||
obj & operator++() noexcept { this->_preincrement(); return *this; }
|
||||
};
|
||||
|
||||
template <typename AFacet>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue