diff --git a/src/vault/mem/extent-family.hpp b/src/vault/mem/extent-family.hpp index 76819f6ec..bde17ca4d 100644 --- a/src/vault/mem/extent-family.hpp +++ b/src/vault/mem/extent-family.hpp @@ -32,7 +32,7 @@ ** and down to avoid holding larger amounts of unused memory, while the availability ** of a baseline amount of memory can be enforced. ** - ** @see ////TODO_test usage example + ** @see ExtentFamily_test ** @see gear::BlockFlow usage example ** ** @todo WIP-WIP-WIP 7/2023 »Playback Vertical Slice« @@ -51,6 +51,7 @@ //#include "lib/util.hpp" //#include +#include #include #include #include @@ -68,12 +69,17 @@ namespace mem { /** * Memory manager to provide a sequence of Extents for cyclic usage. * @todo WIP-WIP 7/2023 - * @see NA_test + * @see ExtentFamily_test */ template class ExtentFamily : util::NonCopyable { + /** number of excess new extents + * to add whenever new storage is required + */ + static const size_t EXCESS_ALLOC{5}; + public: struct Extent : std::array @@ -108,6 +114,8 @@ namespace mem { using RawIter = typename Extents::iterator; + /* ==== Management Data ==== */ + Extents extents_; size_t start_,after_; @@ -125,17 +133,42 @@ namespace mem { extents_.reserve (expectedMaxExtents); } + /** claim next \a cnt extents, possibly allocate. + * @note always allocating slightly in excess + */ void openNew (size_t cnt) { - UNIMPLEMENTED ("claim next cnt extents, possibly allocate"); + if (not canAccomodate (cnt)) + {//insufficient reserve -> allocate + size_t oldSiz = extents_.size(); + size_t addSiz = cnt - freeSlotCnt() + + EXCESS_ALLOC; + // add a strike of new extents at the end + extents_.resize (oldSiz + addSiz); + if (isWrapped()) + {// need the new elements in the middle, before the existing start_ + auto p = extents_.begin(); + auto first = p + start_; + auto mid = p + oldSiz; + auto last = p + oldSiz + addSiz; + // relocate [fist..mid) after [mid..last) + std::rotate (first, mid, last); + start_ += addSiz; + } + } + // now sufficient reserve extents are available + ENSURE (canAccomodate (cnt)); + incWrap (after_, cnt); } + /** discard oldest \a cnt extents */ void dropOld (size_t cnt) { - UNIMPLEMENTED ("discard oldest cnt extents"); - } + REQUIRE (cnt <= activeSlotCnt()); + incWrap (start_, cnt); + } ////////////////////////////////////////////////////////////////////////////TICKET #1316 : should reduce excess allocation (with apropriate damping to avoid oscillations) /** allow transparent iteration of Extents, expanding storage on demand */ @@ -149,6 +182,49 @@ namespace mem { } + private: + bool + isWrapped() const + { + return after_ < start_; + } // note: both are equal only when empty + + /** @return number of allocated slots actually used */ + size_t + activeSlotCnt() const + { + REQUIRE (start_ <= extents_.size()); + REQUIRE (after_ <= extents_.size()); + + return not isWrapped()? after_ - start_ + : (after_ - 0) + +(extents_.size() - start_); + } + + size_t + freeSlotCnt() const + { // always keep one in reserve... + REQUIRE (activeSlotCnt() < extents_.size()); + + return extents_.size() - activeSlotCnt(); + } + + bool + canAccomodate (size_t addCnt) const + { + return addCnt < freeSlotCnt(); // keep one in reserve + } + + /** increment index, but wrap at array end. + * @remark using the array cyclically + */ + void + incWrap (size_t& idx, size_t inc) + { + idx = (idx+inc) % extents_.size(); + } + + /* == Iteration control API (used by IterAdapter via ADL) == */ friend bool @@ -163,11 +239,19 @@ namespace mem { UNIMPLEMENTED ("ExtentFamily iteration control: access next Extent, possibly expand allocation"); } + + /// „backdoor“ to watch internals from tests friend class ExtentDiagnostic; }; + + + + + /* ===== Test / Diagnostic ===== */ + template struct ExtentDiagnostic { @@ -178,7 +262,7 @@ namespace mem { size_t first() { return exFam_.start_; } size_t last() { return exFam_.after_; } size_t size() { return exFam_.extents_.size(); } - size_t active() { UNIMPLEMENTED ("count active"); } + size_t active() { return exFam_.activeSlotCnt(); } }; template diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 6c4ce26c5..4acafbedc 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -78517,8 +78517,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + @@ -78783,8 +78783,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + @@ -78808,9 +78808,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + - + @@ -78949,18 +78949,49 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - - + + + + - - - - + + - - + + + + + + + + + + + + + + + +

+ ...dieser tauscht per std::swap aus; und zwar rekursiv inkrementell: erst das Segment vom Ende an den Anfang und dann rekursiv wieder std::rotate für den Rest. Komplexität: linear +

+ +
+
+
+
+ + + + + + + + + + + +