diff --git a/src/lib/iter-adapter.hpp b/src/lib/iter-adapter.hpp
index 581613611..069d57fcd 100644
--- a/src/lib/iter-adapter.hpp
+++ b/src/lib/iter-adapter.hpp
@@ -135,7 +135,7 @@ namespace lib {
* - it is not just a disguised pointer (meaning, it's more expensive)
* - it checks validity on every operation and may throw
* - it has a distinct back-link to the source container
- * - the source container needs to provide hasNext() and iterNext() free functions.
+ * - the source container needs to support `checkPoint()` and `iterNext()` free functions.
* - we may need friendship to implement those extension points on the container
* - the end-of-iteration can be detected by bool check
* @note it is possible to "hide" a smart-ptr within the CON template parameter.
@@ -303,7 +303,7 @@ namespace lib {
inline bool operator== (IterAdapter const& il, IterAdapter const& ir) { return il.pos_ == ir.pos_; }
template
- inline bool operator!= (IterAdapter const& il, IterAdapter const& ir) { return !(il == ir); }
+ inline bool operator!= (IterAdapter const& il, IterAdapter const& ir) { return not (il == ir); }
diff --git a/src/vault/gear/activity.hpp b/src/vault/gear/activity.hpp
index dd12beb44..1f8ad14a3 100644
--- a/src/vault/gear/activity.hpp
+++ b/src/vault/gear/activity.hpp
@@ -181,7 +181,7 @@ namespace gear {
explicit
- Activity (Verb verb)
+ Activity (Verb verb) noexcept
: verb_{verb}
, next{nullptr}
{
@@ -193,7 +193,7 @@ namespace gear {
/* ==== special case initialisation ==== */
- Activity (size_t o1, size_t o2)
+ Activity (size_t o1, size_t o2) noexcept
: Activity{FEED}
{
data_.feed.one = o1;
@@ -201,42 +201,42 @@ namespace gear {
}
explicit
- Activity (Activity* target)
+ Activity (Activity* target) noexcept
: Activity{NOTIFY}
{
data_.notification.target = target;
}
explicit
- Activity (int expectNotifications, Time deadline = Time::NEVER)
+ Activity (int expectNotifications, Time deadline = Time::NEVER) noexcept
: Activity{GATE}
{
data_.condition.rest = expectNotifications;
data_.condition.dead = deadline;
}
- Activity (Time when, Activity* followUp)
+ Activity (Time when, Activity* followUp) noexcept
: verb_{POST}
, next{followUp}
{
data_.timeWindow = {when,when};
}
- Activity (Time start, Time after, Activity* followUp)
+ Activity (Time start, Time after, Activity* followUp) noexcept
: verb_{POST}
, next{followUp}
{
data_.timeWindow = {start,after};
}
- Activity()
+ Activity() noexcept
: Activity{TICK}
{ }
private:
void
- setDefaultArg (Verb verb)
+ setDefaultArg (Verb verb) noexcept
{
data_ = {0,0};
switch (verb) {
diff --git a/src/vault/gear/block-flow.hpp b/src/vault/gear/block-flow.hpp
index 4fabda044..7cfd17229 100644
--- a/src/vault/gear/block-flow.hpp
+++ b/src/vault/gear/block-flow.hpp
@@ -34,7 +34,7 @@
** activities, necessitating timely clean-up of obsolete descriptors.
** Used memory should be recycled, calling for an arrangement of
** pooled allocation tiles, extending the underlying block
- ** allocation on increased throughput.
+ ** allocation on increased throughput.
**
** @note currently this rather marks the intended memory management pattern,
** while the actual allocations are still performed on the heap.
@@ -60,6 +60,7 @@
//#include "lib/util.hpp"
//#include
+#include
namespace vault{
@@ -75,30 +76,66 @@ namespace gear {
const size_t INITIAL_FRAMES = 50;
const size_t INITIAL_ALLOC = 1 + (INITIAL_FRAMES * ACTIVITIES_PER_FRAME) / EPOCH_SIZ;
+ /** raw allocator to provide a sequence of Extents to place Activity records */
using Allocator = mem::ExtentFamily;
}
+
/**
- *
+ * Allocation Extent holding _scheduler Activities_ to be performed altogether
+ * before a common _deadline._ Other than the underlying raw Extent, the Epoch
+ * 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.
*/
class Epoch
: public Allocator::Extent
{
-
+
/// @warning will be faked, not constructed
Epoch() = delete;
public:
+ /**
+ * specifically rigged GATE Activity,
+ * used for managing Epoch metadata
+ * - the Condition::rest tracks pending async IO operations
+ * - the Condition::deadline is the nominal deadline of this Epoch
+ * - the field `next` points to the next free allocation Slot to use
+ */
struct EpochGate
: Activity
{
+ /** @note initially by default there is...
+ * - effectively no deadline
+ * - no IO operations pending (i.e. we can just discard the Epoch)
+ * - the `next` usable Slot is the last Storage slot, and will be
+ * decremented until there is only one slot left (EpochGate itself)
+ * @warning EpochGate is assumed to sit in the Epoch's first slot
+ */
EpochGate()
: Activity{int(0), Time::ANYTIME}
{
- UNIMPLEMENTED ("initialise allocation usage marker to zero");
+ // initialise allocation usage marker: start at last usable slot
+ next = this + (Epoch::SIZ() - 1);
+ ENSURE (next != this);
}
// default copyable
+
+ bool
+ hasFreeSlot()
+ { // see C++ § 5.9 : comparison of pointers within same array
+ return next > this;
+ }
+
+ Activity*
+ claimNextSlot()
+ {
+ REQUIRE (hasFreeSlot());
+ return next--;
+ }
};
static Epoch&
@@ -116,8 +153,12 @@ namespace gear {
}
};
+
+
/**
- * Basic (abstracted) view of...
+ * Allocation scheme for the Scheduler, based on Epoch(s).
+ * Scheduling entails to provide a chain of Activity definitions,
+ * which will then »flow« through the priority queue until invocation.
*
* @see SchedulerCommutator
* @see BlockFlow_test
@@ -132,10 +173,51 @@ namespace gear {
: alloc_{INITIAL_ALLOC}
{ }
- Activity&
- createActivity (Activity::Verb verb, Time deadline)
+ /**
+ * Local handle to allow allocating a collection of Activities,
+ * all sharing a common deadline. Internally, these records are
+ * maintained in fixed-sized _extents_ and thus allocations may
+ * _overflow_ — leading to allocation of further extents. However,
+ * this extension is handled transparently by the embedded iterator.
+ */
+ class AllocatorHandle
{
- UNIMPLEMENTED ("place new allocation");
+ Allocator::iterator extent;
+
+ public:
+ template
+ Activity&
+ create (ARGS&& ...args)
+ {
+ return *new(claimSlot()) Activity {std::forward (args)...};
+ }
+
+ private:
+ Epoch&
+ currEpoch()
+ {
+ REQUIRE (bool(extent));
+ return static_cast (extent->access()); ////////////////////////////OOO is it possible to adapt the iterator, so that dereferentiation directly yields the Extent?
+ }
+
+ void*
+ claimSlot() ///< EX_SANE
+ {
+ if (currEpoch().gate().hasFreeSlot())
+ {
+ return currEpoch().gate().claimNextSlot();
+ }
+ else // Epoch overflow
+ { // use following Epoch; possibly allocate
+ UNIMPLEMENTED ("advance to next epoch");
+ }
+ }
+ };
+
+ AllocatorHandle
+ until (Time deadline)
+ {
+ UNIMPLEMENTED ("search through existing Epochs to locate the latest one to support given deadline");
}
void
diff --git a/src/vault/mem/extent-family.hpp b/src/vault/mem/extent-family.hpp
index d7e156327..7746e0f0d 100644
--- a/src/vault/mem/extent-family.hpp
+++ b/src/vault/mem/extent-family.hpp
@@ -46,7 +46,8 @@
#include "vault/common.hpp"
//#include "lib/symbol.hpp"
-#include "lib/nocopy.hpp"
+#include "lib/iter-adapter.hpp"
+#include "lib/nocopy.hpp"
//#include "lib/util.hpp"
//#include
@@ -76,6 +77,7 @@ namespace mem {
: std::array
{
using Payload = T;
+ using SIZ = std::integral_constant;
};
private:
@@ -101,6 +103,7 @@ namespace mem {
}
};
using Extents = std::vector;
+ using RawIter = typename Extents::iterator;
Extents extents_;
@@ -119,6 +122,23 @@ namespace mem {
{
extents_.reserve (expectedMaxExtents);
}
+
+ /** allow transparent iteration of Extents, expanding storage on demand */
+ using iterator = lib::IterAdapter; ////////////////////OOO consider to use a Extent* instead of the RawIter??
+
+ /* == Iteration control API (used by IterAdapter via ADL) == */
+
+ friend bool
+ checkPoint (ExtentFamily* exFam, RawIter& pos)
+ {
+ UNIMPLEMENTED ("ExtentFamily iteration control: check and adapt position");
+ }
+
+ friend void
+ iterNext (ExtentFamily* exFam, RawIter& pos)
+ {
+ UNIMPLEMENTED ("ExtentFamily iteration control: access next Extent, possibly expand allocation");
+ }
};
diff --git a/tests/library/iter-adapter-test.cpp b/tests/library/iter-adapter-test.cpp
index 89b20101e..c29bbb0a0 100644
--- a/tests/library/iter-adapter-test.cpp
+++ b/tests/library/iter-adapter-test.cpp
@@ -144,9 +144,9 @@ namespace test{
template
friend void
iterNext (const TestContainer*, ITER& pos)
- {
- ++pos;
- }
+ {
+ ++pos;
+ }
/** Implementation of Iteration-logic: detect iteration end.
* @note the problem here is that this implementation chooses to use
@@ -161,15 +161,15 @@ namespace test{
template
friend bool
checkPoint (const TestContainer* src, ITER& pos)
- {
- REQUIRE (src);
- if ((pos != ITER()) && (pos != src->numberz_.end()))
- return true;
- else
- {
- pos = ITER();
- return false;
- } }
+ {
+ REQUIRE (src);
+ if ((pos != ITER()) && (pos != src->numberz_.end()))
+ return true;
+ else
+ {
+ pos = ITER();
+ return false;
+ } }
};
} // (END) impl test dummy container
diff --git a/tests/vault/gear/block-flow-test.cpp b/tests/vault/gear/block-flow-test.cpp
index 4354925bf..f73ac460e 100644
--- a/tests/vault/gear/block-flow-test.cpp
+++ b/tests/vault/gear/block-flow-test.cpp
@@ -76,7 +76,7 @@ namespace test {
{
BlockFlow bFlow;
Time deadline = randTime();
- Activity tick = bFlow.createActivity(Activity::TICK, deadline);
+ Activity tick = bFlow.until(deadline).create();
///////////////////////////////////////////////////////////////////////////////OOO diagnostic function to check allocation
bFlow.discardBefore (deadline + Time{0,5});
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index 63e58c4a9..df3f23932 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -78646,7 +78646,15 @@ Date: Thu Apr 20 18:53:17 2023 +0200
-
+
+
+
+
+
+
+
+
+
@@ -78741,6 +78749,7 @@ Date: Thu Apr 20 18:53:17 2023 +0200
+
@@ -78879,11 +78888,38 @@ Date: Thu Apr 20 18:53:17 2023 +0200