diff --git a/include/xo/alloc2/alloc/AAllocator.hpp b/include/xo/alloc2/alloc/AAllocator.hpp index 6b83c50..809c31b 100644 --- a/include/xo/alloc2/alloc/AAllocator.hpp +++ b/include/xo/alloc2/alloc/AAllocator.hpp @@ -7,7 +7,8 @@ #include "AllocError.hpp" #include "AllocInfo.hpp" -#include "AllocIterator.hpp" +//#include "AllocIterator.hpp" +#include "AllocRange.hpp" #include #include #include @@ -35,7 +36,7 @@ namespace xo { /** object header, if configured **/ using header_type = std::uint64_t; /** iterator range. These are forward iterators over allocs **/ - using range_type = std::pair, obj>; + using range_type = AllocRange; ///@} /* diff --git a/include/xo/alloc2/alloc/AllocRange.hpp b/include/xo/alloc2/alloc/AllocRange.hpp new file mode 100644 index 0000000..74656ab --- /dev/null +++ b/include/xo/alloc2/alloc/AllocRange.hpp @@ -0,0 +1,34 @@ +/** @file AllocRange.hpp + * + * @author Roland Conybeare, Dec 2025 + **/ + +#pragma once + +#include "AllocIterator.hpp" + +namespace xo { + namespace mm { + /** @class AllocRange + * @brief Provide range iteration over an @ref AAllcator + * + * Return value type for @ref AAllocator::alloc_range + **/ + struct AllocRange { + public: + using repr_type = std::pair, obj>; + + public: + AllocRange() = default; + explicit AllocRange(repr_type range) : range_{std::move(range)} {} + + obj begin() const { return range_.first; } + obj end() const { return range_.second; } + + /** state: {begin,end} pair of alloc iterators **/ + repr_type range_; + }; + } /*namsepace mm*/ +} /*namespace xo*/ + +/* end AllocRange.hpp */ diff --git a/include/xo/alloc2/arena/IAllocator_DArena.hpp b/include/xo/alloc2/arena/IAllocator_DArena.hpp index fab8565..85ef412 100644 --- a/include/xo/alloc2/arena/IAllocator_DArena.hpp +++ b/include/xo/alloc2/arena/IAllocator_DArena.hpp @@ -31,8 +31,7 @@ namespace xo { */ using size_type = std::size_t; using value_type = std::byte *; - using range_type = std::pair, - obj>; + using range_type = AAllocator::range_type; static std::string_view name(const DArena &) noexcept; static size_type reserved(const DArena &) noexcept; diff --git a/include/xo/alloc2/gc/IAllocator_DX1Collector.hpp b/include/xo/alloc2/gc/IAllocator_DX1Collector.hpp index 1fb48b0..c525dad 100644 --- a/include/xo/alloc2/gc/IAllocator_DX1Collector.hpp +++ b/include/xo/alloc2/gc/IAllocator_DX1Collector.hpp @@ -31,8 +31,7 @@ namespace xo { struct IAllocator_DX1Collector { using size_type = std::size_t; using value_type = std::byte *; - using range_type = std::pair, - obj>; + using range_type = AAllocator::range_type; // todo: available() diff --git a/src/alloc2/IAllocator_DArena.cpp b/src/alloc2/IAllocator_DArena.cpp index 4580bb3..b536227 100644 --- a/src/alloc2/IAllocator_DArena.cpp +++ b/src/alloc2/IAllocator_DArena.cpp @@ -74,13 +74,15 @@ namespace xo { IAllocator_DArena::alloc_range(const DArena & s, DArena & ialloc) noexcept -> range_type { - scope log(XO_DEBUG(true)); + scope log(XO_DEBUG(false)); DArenaIterator * begin_ix = construct_with(ialloc, &s, s.begin_header()); DArenaIterator * end_ix = construct_with(ialloc, &s, s.end_header()); - obj begin_obj = with_facet::mkobj(begin_ix); - obj end_obj = with_facet::mkobj( end_ix); + obj begin_obj + = with_facet::mkobj(begin_ix); + obj end_obj + = with_facet::mkobj( end_ix); log && log(xtag("begin_obj.typeseq", begin_obj._typeseq())); @@ -93,25 +95,10 @@ namespace xo { xtag("begin_ix.arena", begin_ix->arena_), xtag("begin_ix.pos", begin_ix->pos_)); - range_type retval = std::make_pair(begin_vt, end_vt); + range_type retval = range_type(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 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())); + log && log(xtag("1.retval.first.typeseq", + retval.begin()._typeseq())); return retval; } diff --git a/src/alloc2/IAllocator_DX1Collector.cpp b/src/alloc2/IAllocator_DX1Collector.cpp index f91f1d3..5ab1b00 100644 --- a/src/alloc2/IAllocator_DX1Collector.cpp +++ b/src/alloc2/IAllocator_DX1Collector.cpp @@ -76,7 +76,7 @@ namespace xo { obj begin_obj = with_facet::mkobj(begin_ix); obj end_obj = with_facet::mkobj( end_ix); - return std::make_pair(begin_obj, end_obj); + return AllocRange(std::make_pair(begin_obj, end_obj)); } auto diff --git a/utest/AllocIterator.test.cpp b/utest/AllocIterator.test.cpp index 9dc4d74..150c8dd 100644 --- a/utest/AllocIterator.test.cpp +++ b/utest/AllocIterator.test.cpp @@ -169,8 +169,8 @@ namespace xo { /* arbitrary alloc size */ size_t req_z = 13; - byte * mem = a1o.alloc(req_z); + REQUIRE(arena.error_count_ == 0); REQUIRE(mem != nullptr); @@ -180,7 +180,6 @@ namespace xo { REQUIRE(ix.is_valid()); REQUIRE(end_ix.is_valid()); - /* arena is non-empty, so begin!=end */ REQUIRE (ix != end_ix); @@ -224,8 +223,8 @@ namespace xo { auto range = a1o.alloc_range(scratch_mm); - obj ix = range.first; - obj end_ix = range.second; + obj ix = range.begin(); + obj end_ix = range.end(); REQUIRE(ix.iface()); REQUIRE(ix.data()); @@ -248,6 +247,27 @@ namespace xo { REQUIRE(ix.compare(ix).is_equal()); //REQUIRE(ix.compare(end_ix).is_equal()); + + REQUIRE(ix != end_ix); + + { + REQUIRE(arena.error_count_ == 0); + REQUIRE(ix.deref().is_valid()); + REQUIRE(ix.deref().size() == padding::with_padding(req_z)); + + auto [payload_lo, payload_hi] = ix.deref().payload(); + + REQUIRE(payload_lo == mem); + REQUIRE(payload_hi == mem + ix.deref().size()); + } + + /* valid iterator can be advanced + reaches end */ + { + ix.next(); + + REQUIRE(arena.error_count_ == 0); + REQUIRE(ix == end_ix); + } } } diff --git a/utest/DX1CollectorIterator.test.cpp b/utest/DX1CollectorIterator.test.cpp index b1c3241..159986a 100644 --- a/utest/DX1CollectorIterator.test.cpp +++ b/utest/DX1CollectorIterator.test.cpp @@ -15,12 +15,15 @@ #include namespace xo { + using xo::mm::AAllocator; using xo::mm::AAllocIterator; using xo::mm::IAllocIterator_Any; using xo::mm::IAllocIterator_Xfer; using xo::mm::IAllocIterator_DX1CollectorIterator; using xo::mm::DX1Collector; using xo::mm::DX1CollectorIterator; + using xo::mm::DArena; + using xo::mm::DArenaIterator; using xo::mm::CollectorConfig; using xo::mm::ArenaConfig; using xo::mm::AllocHeaderConfig; @@ -98,52 +101,103 @@ namespace xo { 0, 0, 0, 0}} }; DX1Collector gc = DX1Collector{cfg}; + obj a1o{&gc}; - size_t z = 13; - byte * mem = gc.alloc(z); + REQUIRE(a1o.reserved() >= arena_cfg.size_); + REQUIRE(a1o.committed() == 0); + REQUIRE(a1o.available() == 0); + REQUIRE(a1o.allocated() == 0); + + size_t req_z = 13; + byte * mem = gc.alloc(req_z); REQUIRE(mem != nullptr); log && log("should have iterators separated by one alloc"); - auto ix = gc.begin(); - auto end_ix = gc.end(); + { + auto ix = gc.begin(); + auto end_ix = gc.end(); - REQUIRE(ix.is_valid()); - REQUIRE(end_ix.is_valid()); - REQUIRE(ix != end_ix); + REQUIRE(ix.is_valid()); + REQUIRE(end_ix.is_valid()); + REQUIRE(ix != end_ix); - /* verify obj 'fat pointer' packaging */ - auto ix_vt = with_facet::mkobj(&ix); - auto end_ix_vt = with_facet::mkobj(&end_ix); + /* verify obj 'fat pointer' packaging */ + auto ix_vt = with_facet::mkobj(&ix); + auto end_ix_vt = with_facet::mkobj(&end_ix); - REQUIRE(ix_vt.iface()); - REQUIRE(ix_vt.data()); - REQUIRE(end_ix_vt.iface()); - REQUIRE(end_ix_vt.data()); + REQUIRE(ix_vt.iface()); + REQUIRE(ix_vt.data()); + REQUIRE(end_ix_vt.iface()); + REQUIRE(end_ix_vt.data()); - cmpresult cmp = ix_vt.compare(end_ix_vt); + cmpresult cmp = ix_vt.compare(end_ix_vt); - REQUIRE(cmp.is_lesser()); - REQUIRE(ix_vt != end_ix_vt); + REQUIRE(cmp.is_lesser()); + REQUIRE(ix_vt != end_ix_vt); - /* we only did one alloc, should be able - * to visit it - */ - auto info = ix_vt.deref(); + /* we only did one alloc, should be able + * to visit it + */ + auto info = ix_vt.deref(); - REQUIRE(info.is_valid()); - REQUIRE(info.payload().first == mem); - REQUIRE(info.size() == padding::with_padding(z)); + REQUIRE(info.is_valid()); + REQUIRE(info.payload().first == mem); + REQUIRE(info.size() == padding::with_padding(req_z)); - ix_vt.next(); + ix_vt.next(); - log && log(xtag("ix.gen", ix.gen_ix()), - xtag("ix.arena_ix.arena", ix.arena_ix().arena_)); - log && log(xtag("end_ix.gen", end_ix.gen_ix()), - xtag("end_ix.arena_ix.arena", end_ix.arena_ix().arena_)); + log && log(xtag("ix.gen", ix.gen_ix()), + xtag("ix.arena_ix.arena", ix.arena_ix().arena_)); + log && log(xtag("end_ix.gen", end_ix.gen_ix()), + xtag("end_ix.arena_ix.arena", end_ix.arena_ix().arena_)); - REQUIRE(ix_vt == end_ix_vt); + REQUIRE(ix_vt == end_ix_vt); + } + + { + //auto range = gc.alloc_range + + DArena scratch_mm + = DArena::map( + ArenaConfig{ + .size_ = 4*1024, + .hugepage_z_ = 4*1024}); + + auto range = a1o.alloc_range(scratch_mm); + + obj ix = range.begin(); + obj end_ix = range.end(); + + 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); + + REQUIRE(ix.compare(ix).is_equal()); + + REQUIRE(ix != end_ix); + + { + REQUIRE(ix.deref().is_valid()); + REQUIRE(ix.deref().size() == padding::with_padding(req_z)); + + auto [payload_lo, payload_hi] = ix.deref().payload(); + + REQUIRE(payload_lo == mem); + REQUIRE(payload_hi == mem + ix.deref().size()); + } + + { + ix.next(); + + REQUIRE(ix == end_ix); + } + } } } /*namespace ut*/ } /*namespace xo*/