Block-Flow: rationalise iterator usage
...with the preceding IterableDecorator refactoring, the navigation and access to the storage extents can now be organised into a clear progression Allocator::iterator -> EpochIter -> Epoch& Convenience management and support functions can then be pushed down into Epoch, while iteration control can be done high-level in BlockFlow, based on the helpers in Epoch
This commit is contained in:
parent
5a8463acce
commit
5055ba7144
4 changed files with 125 additions and 67 deletions
|
|
@ -54,12 +54,10 @@
|
|||
#include "vault/common.hpp"
|
||||
#include "vault/gear/activity.hpp"
|
||||
#include "vault/mem/extent-family.hpp"
|
||||
//#include "lib/symbol.hpp"
|
||||
#include "lib/time/timevalue.hpp"
|
||||
#include "lib/nocopy.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
//#include <string>
|
||||
#include <utility>
|
||||
|
||||
|
||||
|
|
@ -67,12 +65,12 @@ namespace vault{
|
|||
namespace gear {
|
||||
|
||||
using util::isnil;
|
||||
// using std::string;
|
||||
using lib::time::Time;
|
||||
using lib::time::TimeVar;
|
||||
using lib::time::Duration;
|
||||
using lib::time::FrameRate;
|
||||
|
||||
|
||||
namespace {// hard-wired parametrisation
|
||||
const size_t EPOCH_SIZ = 100;
|
||||
const size_t ACTIVITIES_PER_FRAME = 10;
|
||||
|
|
@ -94,13 +92,13 @@ namespace gear {
|
|||
* maintains a deadline time and keeps track of storage slots already claimed.
|
||||
* This is achieved by using the Activity record in the first slot as a GATE term
|
||||
* to maintain those administrative information.
|
||||
* @remark rationale is to discard the Extent as a whole, once the deadline passed.
|
||||
* @remark rationale is to discard the Extent as a whole, once deadline passed.
|
||||
*/
|
||||
class Epoch
|
||||
: public Allocator::Extent
|
||||
{
|
||||
|
||||
/// @warning will be faked, not constructed
|
||||
/// @warning will be faked, never constructed
|
||||
Epoch() = delete;
|
||||
|
||||
public:
|
||||
|
|
@ -150,19 +148,27 @@ namespace gear {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
EpochGate& gate() { return static_cast<EpochGate&> ((*this)[0]); }
|
||||
Time deadline() { return Time{gate().deadline()}; }
|
||||
|
||||
|
||||
static Epoch&
|
||||
implantInto (Allocator::Extent& rawStorage)
|
||||
implantInto (Allocator::iterator storageSlot)
|
||||
{
|
||||
Epoch& target = static_cast<Epoch&> (rawStorage);
|
||||
Epoch& target = static_cast<Epoch&> (*storageSlot);
|
||||
new(&target[0]) EpochGate{};
|
||||
return target;
|
||||
}
|
||||
|
||||
EpochGate&
|
||||
gate()
|
||||
static Epoch&
|
||||
setup (Allocator::iterator storageSlot, Time deadline)
|
||||
{
|
||||
return static_cast<EpochGate&> ((*this)[0]);
|
||||
Epoch& newEpoch{implantInto (storageSlot)};
|
||||
newEpoch.gate().deadline() = deadline;
|
||||
return newEpoch;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -181,6 +187,22 @@ namespace gear {
|
|||
Allocator alloc_;
|
||||
TimeVar epochStep_;
|
||||
|
||||
|
||||
/** @internal use a raw storage Extent as Epoch (unchecked cast) */
|
||||
static Epoch&
|
||||
asEpoch (Allocator::Extent& extent)
|
||||
{
|
||||
return static_cast<Epoch&> (extent);
|
||||
}
|
||||
|
||||
struct StorageAdaptor : Allocator::iterator
|
||||
{
|
||||
StorageAdaptor(Allocator::iterator it) : Allocator::iterator{it} { }
|
||||
Epoch& yield() const { return asEpoch (Allocator::iterator::yield()); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
public:
|
||||
BlockFlow()
|
||||
: alloc_{INITIAL_ALLOC}
|
||||
|
|
@ -194,6 +216,10 @@ namespace gear {
|
|||
}
|
||||
|
||||
|
||||
/** Adapted storage-extent iterator, directly exposing Extent& */
|
||||
using EpochIter = lib::IterableDecorator<Epoch, StorageAdaptor>;
|
||||
|
||||
|
||||
/**
|
||||
* Local handle to allow allocating a collection of Activities,
|
||||
* all sharing a common deadline. Internally, these records are
|
||||
|
|
@ -203,13 +229,16 @@ namespace gear {
|
|||
*/
|
||||
class AllocatorHandle
|
||||
{
|
||||
Allocator::iterator extent;
|
||||
EpochIter epoch_;
|
||||
|
||||
public:
|
||||
AllocatorHandle(Allocator::iterator slot)
|
||||
: extent{slot}
|
||||
: epoch_{slot}
|
||||
{ }
|
||||
|
||||
/*************************************************//**
|
||||
* Main API operation: allocate a new Activity record
|
||||
*/
|
||||
template<typename...ARGS>
|
||||
Activity&
|
||||
create (ARGS&& ...args)
|
||||
|
|
@ -218,18 +247,12 @@ namespace gear {
|
|||
}
|
||||
|
||||
private:
|
||||
Epoch&
|
||||
currEpoch()
|
||||
{
|
||||
return asEpoch(extent);
|
||||
}
|
||||
|
||||
void*
|
||||
claimSlot() ///< EX_SANE
|
||||
{
|
||||
if (currEpoch().gate().hasFreeSlot())
|
||||
if (epoch_->gate().hasFreeSlot())
|
||||
{
|
||||
return currEpoch().gate().claimNextSlot();
|
||||
return epoch_->gate().claimNextSlot();
|
||||
}
|
||||
else // Epoch overflow
|
||||
{ // use following Epoch; possibly allocate
|
||||
|
|
@ -238,14 +261,16 @@ namespace gear {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
/* ===== public BlockFlow API ===== */
|
||||
|
||||
AllocatorHandle
|
||||
until (Time deadline)
|
||||
{
|
||||
if (isnil (alloc_))
|
||||
{//just create new Epoch one epochStep ahead
|
||||
alloc_.openNew();
|
||||
Epoch& newEpoch = Epoch::implantInto (alloc_.first());
|
||||
newEpoch.gate().deadline() = deadline + Time{epochStep_};
|
||||
Epoch::setup (alloc_.begin(), deadline + Time{epochStep_});
|
||||
return AllocatorHandle{alloc_.begin()};
|
||||
}
|
||||
else
|
||||
|
|
@ -258,23 +283,24 @@ namespace gear {
|
|||
discardBefore (Time deadline)
|
||||
{
|
||||
if (isnil (alloc_)
|
||||
or asEpoch(alloc_.first()).gate().deadline() > deadline)
|
||||
or firstEpoch().deadline() > deadline)
|
||||
return;
|
||||
}
|
||||
|
||||
private:
|
||||
/** @internal use a raw allocator Extent as Epoch (unchecked cast) */
|
||||
static Epoch&
|
||||
asEpoch (Allocator::iterator slot)
|
||||
{
|
||||
REQUIRE (bool(slot));
|
||||
return asEpoch (*slot);
|
||||
}
|
||||
|
||||
static Epoch&
|
||||
asEpoch (Allocator::Extent& extent)
|
||||
|
||||
private:
|
||||
Epoch&
|
||||
firstEpoch()
|
||||
{
|
||||
return static_cast<Epoch&> (extent);
|
||||
REQUIRE (not isnil (alloc_));
|
||||
return asEpoch(*alloc_.begin());
|
||||
}
|
||||
Epoch&
|
||||
lastEpoch()
|
||||
{
|
||||
REQUIRE (not isnil (alloc_));
|
||||
return asEpoch(*alloc_.last());
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -300,10 +326,10 @@ namespace gear {
|
|||
: flow_{theFlow}
|
||||
{ }
|
||||
|
||||
Time first() { return Time{BlockFlow::asEpoch(flow_.alloc_.first()).gate().deadline()}; }
|
||||
Time last() { return Time{BlockFlow::asEpoch(flow_.alloc_.last() ).gate().deadline()}; }
|
||||
Time first() { return flow_.firstEpoch().deadline();}
|
||||
Time last() { return flow_.lastEpoch().deadline(); }
|
||||
size_t cntEpochs() { return watch(flow_.alloc_).active(); }
|
||||
size_t poolSize() { return watch(flow_.alloc_).size(); }
|
||||
size_t poolSize() { return watch(flow_.alloc_).size(); }
|
||||
};
|
||||
|
||||
inline FlowDiagnostic
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ namespace mem {
|
|||
void
|
||||
iterNext()
|
||||
{
|
||||
exFam->incWrap (index);
|
||||
index = exFam->incWrap (index);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -150,6 +150,12 @@ namespace mem {
|
|||
return exFam == oi.exFam
|
||||
and index == oi.index;
|
||||
}
|
||||
|
||||
|
||||
/* === pass-through extended functionality === */
|
||||
|
||||
size_t getIndex() { return index; }
|
||||
void expandAlloc(){ exFam->openNew();}
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -184,7 +190,7 @@ namespace mem {
|
|||
{
|
||||
if (not canAccomodate (cnt))
|
||||
{//insufficient reserve => allocate
|
||||
size_t oldSiz = extents_.size();
|
||||
size_t oldSiz = slotCnt();
|
||||
size_t addSiz = cnt - freeSlotCnt()
|
||||
+ EXCESS_ALLOC;
|
||||
// add a strike of new extents at the end
|
||||
|
|
@ -202,7 +208,7 @@ namespace mem {
|
|||
}
|
||||
// now sufficient reserve extents are available
|
||||
ENSURE (canAccomodate (cnt));
|
||||
incWrap (after_, cnt);
|
||||
after_ = incWrap (after_, cnt);
|
||||
}
|
||||
|
||||
/** discard oldest \a cnt extents */
|
||||
|
|
@ -210,18 +216,13 @@ namespace mem {
|
|||
dropOld (size_t cnt)
|
||||
{
|
||||
REQUIRE (cnt <= activeSlotCnt());
|
||||
incWrap (start_, cnt);
|
||||
start_ = incWrap (start_, cnt);
|
||||
} ////////////////////////////////////////////////////////////////////////////TICKET #1316 : should reduce excess allocation (with appropriate damping to avoid oscillations)
|
||||
|
||||
|
||||
/** allow transparent iteration of Extents,
|
||||
* with the ability to expand storage */
|
||||
struct iterator
|
||||
: lib::IterStateWrapper<Extent, IdxLink>
|
||||
{
|
||||
size_t getIndex() { return this->stateCore().index; }
|
||||
void expandAlloc(){ this->stateCore().exFam->openNew();}
|
||||
};
|
||||
using iterator = lib::IterableDecorator<Extent, IdxLink>;
|
||||
|
||||
/** iterate over all the currently active Extents */
|
||||
iterator begin() { return iterator{IdxLink{this, start_}}; }
|
||||
|
|
@ -232,8 +233,17 @@ namespace mem {
|
|||
|
||||
|
||||
bool empty() const { return start_ == after_; }
|
||||
Extent& last() const { return access((after_+extents_.size()-1) % extents_.size()); } ///< @warning undefined behaviour when empty
|
||||
Extent& first() const { return access(start_); } ///< @warning undefined behaviour when empty
|
||||
|
||||
/** positioned to the last / latest storage extent opened
|
||||
* @warning undefined behaviour when empty
|
||||
*/
|
||||
iterator
|
||||
last()
|
||||
{
|
||||
REQUIRE (not empty()); // trick to safely decrement by one
|
||||
size_t penultimate = incWrap (after_, slotCnt()-1);
|
||||
return iterator{IdxLink{this, penultimate}};
|
||||
}
|
||||
|
||||
|
||||
private: /* ====== storage management implementation ====== */
|
||||
|
|
@ -243,24 +253,30 @@ namespace mem {
|
|||
return after_ < start_;
|
||||
} // note: both are equal only when empty
|
||||
|
||||
size_t
|
||||
slotCnt() const
|
||||
{
|
||||
return extents_.size();
|
||||
}
|
||||
|
||||
/** @return number of allocated slots actually used */
|
||||
size_t
|
||||
activeSlotCnt() const
|
||||
{
|
||||
REQUIRE (start_ < extents_.size());
|
||||
REQUIRE (after_ <= extents_.size());
|
||||
REQUIRE (start_ < slotCnt());
|
||||
REQUIRE (after_ <= slotCnt());
|
||||
|
||||
return not isWrapped()? after_ - start_
|
||||
: (after_ - 0)
|
||||
+(extents_.size() - start_);
|
||||
+(slotCnt() - start_);
|
||||
}
|
||||
|
||||
size_t
|
||||
freeSlotCnt() const
|
||||
{ // always keep one in reserve...
|
||||
REQUIRE (activeSlotCnt() < extents_.size());
|
||||
REQUIRE (activeSlotCnt() < slotCnt());
|
||||
|
||||
return extents_.size() - activeSlotCnt();
|
||||
return slotCnt() - activeSlotCnt();
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -273,19 +289,19 @@ namespace mem {
|
|||
/** increment index, but wrap at array end.
|
||||
* @remark using the array cyclically
|
||||
*/
|
||||
void
|
||||
incWrap (size_t& idx, size_t inc =1)
|
||||
size_t
|
||||
incWrap (size_t idx, size_t inc =1)
|
||||
{
|
||||
idx = (idx+inc) % extents_.size();
|
||||
return (idx+inc) % slotCnt();
|
||||
}
|
||||
|
||||
bool
|
||||
isValidPos (size_t idx) const
|
||||
{
|
||||
REQUIRE (idx < extents_.size());
|
||||
REQUIRE (idx < slotCnt());
|
||||
REQUIRE (activeSlotCnt() > 0);
|
||||
|
||||
return isWrapped()? (start_ <= idx and idx < extents_.size())
|
||||
return isWrapped()? (start_ <= idx and idx < slotCnt())
|
||||
or idx < after_
|
||||
: (start_ <= idx and idx < after_);
|
||||
}
|
||||
|
|
@ -319,7 +335,7 @@ namespace mem {
|
|||
|
||||
size_t first() { return exFam_.start_; }
|
||||
size_t last() { return exFam_.after_; }
|
||||
size_t size() { return exFam_.extents_.size(); }
|
||||
size_t size() { return exFam_.slotCnt(); }
|
||||
size_t active() { return exFam_.activeSlotCnt(); }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ namespace test {
|
|||
extents.openNew(2); // allot two extents for active use
|
||||
CHECK (it);
|
||||
CHECK (0 == it.getIndex());
|
||||
CHECK (isSameObject(*it, extents.first()));
|
||||
CHECK (isSameObject(*it, *extents.begin()));
|
||||
|
||||
Extent& extent{*it};
|
||||
CHECK (10 == extent.size());
|
||||
|
|
@ -141,7 +141,7 @@ namespace test {
|
|||
CHECK (1 == it.getIndex());
|
||||
Extent& nextEx{*it};
|
||||
CHECK (not isSameObject(extent, nextEx));
|
||||
CHECK (isSameObject(nextEx, extents.last()));
|
||||
CHECK (isSameObject(nextEx, *extents.last()));
|
||||
nextEx[5] = extent[2] + 1;
|
||||
CHECK (num == extent[2]);
|
||||
CHECK (num+1 == nextEx[5]);
|
||||
|
|
|
|||
|
|
@ -79815,8 +79815,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1689246500734" ID="ID_1611070672" MODIFIED="1689246508365" TEXT="Zugriff / Navigation">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1689246500734" ID="ID_1611070672" MODIFIED="1689265537668" TEXT="Zugriff / Navigation">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1689246852684" ID="ID_1894820075" MODIFIED="1689246867447" TEXT="Problemlage">
|
||||
<icon BUILTIN="info"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1689246509452" ID="ID_1697713434" MODIFIED="1689246780008">
|
||||
|
|
@ -79837,7 +79837,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1689247882172" ID="ID_1363520850" MODIFIED="1689247914843" TEXT="mögliche Ansätze">
|
||||
<node COLOR="#435e98" CREATED="1689247882172" ID="ID_1363520850" MODIFIED="1689265724651" TEXT="mögliche Ansätze">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node COLOR="#5b280f" CREATED="1689247931732" ID="ID_1905005266" MODIFIED="1689248098163" TEXT="einen Epochen-Iterator zum universellen Agens ausbauen">
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
|
|
@ -79867,14 +79867,14 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1689248121694" ID="ID_1139194353" MODIFIED="1689248191851" TEXT="Zugriffs-Hierarchie: Allocator::iterator ⧐ EpochIter ⧐ Epoch&">
|
||||
<icon BUILTIN="forward"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1689248200483" ID="ID_1272289829" MODIFIED="1689248241810" TEXT="⟹ Konsequenz: Extent& nicht eigenständig verwenden"/>
|
||||
<node COLOR="#435e98" CREATED="1689248200483" ID="ID_1272289829" MODIFIED="1689265563074" TEXT="⟹ Konsequenz: Extent& nicht eigenständig verwenden"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1689248250300" ID="ID_652125369" MODIFIED="1689248275834" TEXT="Epoch wird dann alle Abkürzungen und Hilfsfunktionen tragen">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1689248380839" ID="ID_215002237" MODIFIED="1689248398479" TEXT="BlockFlow stellt dann nur die grundlegenden Konverter bereit">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1689248522225" ID="ID_1824695865" MODIFIED="1689248543003" TEXT="problematisches Layering der Iteratoren">
|
||||
<node COLOR="#435e98" CREATED="1689248522225" ID="ID_1824695865" MODIFIED="1689265504640" TEXT="problematisches Layering der Iteratoren">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1689248585384" ID="ID_1368624985" MODIFIED="1689248594457" TEXT="IterStateWrapper hat eine private Core"/>
|
||||
<node CREATED="1689248595565" ID="ID_1453930677" MODIFIED="1689248612015" TEXT="in IterExplorer gäbe es eine Variante mit Vererbung"/>
|
||||
|
|
@ -79916,6 +79916,22 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1689265603545" ID="ID_791858650" MODIFIED="1689265662325" TEXT="BlockFlow stellt einen EpochIter bereit">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1689265613521" ID="ID_1391121959" MODIFIED="1689265629139" TEXT="das ist noch einmal ein kompletter IterableDecorator"/>
|
||||
<node CREATED="1689265630439" ID="ID_1230547158" MODIFIED="1689265658063" TEXT="aber setzt auf der »state core« von ExtentFamily::iterator auf">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1689265676041" ID="ID_129160018" MODIFIED="1689265714844" TEXT="BlockFlow::AllocatorHandle wrappt nun diesen EpochIter">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1689265693878" ID="ID_391870028" MODIFIED="1689265713540" TEXT="alle weiteren Iterator-basierten Funktionen dereferenzieren damit auf Epoch&">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1689265754039" ID="ID_199514628" MODIFIED="1689265769886" TEXT="Epoch::setup (rawStorageIter) extrahiert">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1688516187452" ID="ID_843039397" MODIFIED="1688516195292" TEXT="Zusatz-Infos zu verwalten">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue