diff --git a/src/lib/several-builder.hpp b/src/lib/several-builder.hpp index 5c0f6cbd6..c7c65ca15 100644 --- a/src/lib/several-builder.hpp +++ b/src/lib/several-builder.hpp @@ -299,10 +299,15 @@ namespace lib { /* ===== Builder API ===== */ + template SeveralBuilder&& - reserve (size_t cntElm) + reserve (size_t cntElm =1 + ,size_t elmSiz =reqSiz()) { - adjustStorage (cntElm, reqSiz()); + ensureElementCapacity (elmSiz); + ensureStorageCapacity (elmSiz,cntElm); + elmSiz = max (elmSiz, Coll::spread()); + adjustStorage (cntElm, elmSiz); return move(*this); } @@ -365,8 +370,10 @@ namespace lib { return move (*this); } - size_t size() const { return Coll::size(); } - bool empty() const { return Coll::empty();} + size_t size() const { return Coll::size(); } + bool empty() const { return Coll::empty();} + size_t capacity() const { return Coll::storageBuffSiz() / Coll::spread(); } + size_t capReserve() const { return capacity() - size(); } private: @@ -384,23 +391,9 @@ namespace lib { { static_assert (is_object_v and not (is_const_v or is_volatile_v)); - // mark when target type is not trivially movable - probeMoveCapability(); - - // ensure sufficient element capacity or the ability to adapt element spread - if (Coll::spread() < reqSiz() and not (Coll::empty() or canWildMove())) - throw err::Invalid{_Fmt{"Unable to place element of type %s (size=%d)" - "into Several-container for element size %d."} - % util::typeStr() % reqSiz() % Coll::spread()}; - - // ensure sufficient storage or verify the ability to re-allocate - if (not (Coll::empty() or Coll::hasReserve(reqSiz()) - or POL::canExpand(reqSiz()) - or canDynGrow())) - throw err::Invalid{_Fmt{"Several-container is unable to accommodate further element of type %s; " - "storage reserve (%s bytes) exhausted and unable to move elements " - "of mixed unknown detail type, which are not trivially movable." } - % util::typeStr() % Coll::storageBuffSiz()}; + probeMoveCapability(); // mark when target type is not (trivially) movable + ensureElementCapacity(); // sufficient or able to adapt spread + ensureStorageCapacity(); // sufficient or able to grow buffer size_t elmSiz = reqSiz(); size_t newPos = Coll::size(); @@ -424,6 +417,34 @@ namespace lib { Coll::data_->deleter = deleterFunctor; } + /** ensure sufficient element capacity or the ability to adapt element spread */ + template + void + ensureElementCapacity (size_t requiredSiz =reqSiz()) + { + if (Coll::spread() < requiredSiz and not (Coll::empty() or canWildMove())) + throw err::Invalid{_Fmt{"Unable to place element of type %s (size=%d)" + "into Several-container for element size %d."} + % util::typeStr() % requiredSiz % Coll::spread()}; + } + + /** ensure sufficient storage reserve or verify the ability to re-allocate */ + template + void + ensureStorageCapacity (size_t requiredSiz =reqSiz(), size_t newElms =1) + { + if (not (Coll::empty() + or Coll::hasReserve (requiredSiz, newElms) + or POL::canExpand (requiredSiz*newElms) + or canDynGrow())) + throw err::Invalid{_Fmt{"Several-container is unable to accommodate further element of type %s; " + "storage reserve (%d bytes ≙ %d elms) exhausted and unable to move " + "elements of mixed unknown detail type, which are not trivially movable." } + % util::typeStr() % Coll::storageBuffSiz() % capacity()}; + } + + + /** possibly grow storage and re-arrange elements to accommodate desired capacity */ void adjustStorage (size_t cnt, size_t spread) { @@ -433,9 +454,11 @@ namespace lib { return; if (demand > buffSiz) {// grow into exponentially expanded new allocation + if (spread > Coll::spread()) + cnt = max (cnt, buffSiz / Coll::spread()); // retain reserve size_t safetyLim = LUMIERA_MAX_ORDINAL_NUMBER * Coll::spread(); size_t expandAlloc = min (safetyLim - ,max (2*buffSiz, demand)); + ,max (2*buffSiz, cnt*spread)); if (expandAlloc < demand) throw err::State{_Fmt{"Storage expansion for Several-collection " "exceeds safety limit of %d bytes"} % safetyLim diff --git a/src/lib/several.hpp b/src/lib/several.hpp index b770b5642..833395aa9 100644 --- a/src/lib/several.hpp +++ b/src/lib/several.hpp @@ -217,10 +217,13 @@ namespace lib { } bool - hasReserve (size_t extraSize) const + hasReserve (size_t requiredSize, size_t newElms =1) const { - if (extraSize > spread()) - extraSize += (extraSize - spread())*size(); + if (requiredSize < spread()) + requiredSize = spread(); + size_t extraSize{requiredSize * newElms}; + if (requiredSize > spread()) + extraSize += (requiredSize - spread())*size(); return data_ and data_->buffSiz >= size()*spread() + extraSize; } diff --git a/tests/library/several-builder-test.cpp b/tests/library/several-builder-test.cpp index 51db58478..cbd563c3d 100644 --- a/tests/library/several-builder-test.cpp +++ b/tests/library/several-builder-test.cpp @@ -321,6 +321,8 @@ namespace test{ // but we aren't able to move elements safely any more, since we don't capture the type. builder.emplace>(); CHECK (20 == builder.size()); + CHECK (20 == builder.capacity()); + CHECK ( 0 == builder.capReserve()); // But here comes the catch: since we choose to accept arbitrary sub-types not identified in detail, // the container has lost its ability of move-reallocation; with 20 elements the current reserve @@ -336,6 +338,23 @@ namespace test{ CHECK (elms[i].calc(i) == 5 + i + (5+5+5+5+5)); CHECK (elms.back().calc(0) == 1 + 0 + (1)); } + + { // Scenario-3 : arbitrary elements of trivial type + SeveralBuilder builder; + + string BFR{"starship is cool"}; + builder.appendAll (BFR); + CHECK (16 == builder.size()); + CHECK ( 4 == builder.capReserve()); + + builder.append(int64_t(33)); + CHECK (17 == builder.size()); + CHECK ( 3 == builder.capReserve()); + + auto elms = builder.build(); +SHOW_EXPR(elms.size()) +SHOW_EXPR(join(elms, "·")) + } } diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index ecf404960..b28a0d622 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -82828,6 +82828,59 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + +

+ sonst würde eine Spread-Vergrößerung +

+

+ tatsächlich die Reserve verkleinern... +

+ + +
+ + + + + +
    +
  • + Beispiel: +
  • +
  • + Buffer hat Kapazität für 10 Elemente bei Spread ≡ 1 und 3 Elemente sind belegt +
  • +
  • + es wird ein 4.Element der Größe 8 bytes verlangt +
  • +
  • + 4*8 = 32 > 10 ⟹ realloc() +
  • +
  • + naiver weise würde man jetzt auf 32 Bytes vergrößern, aber danach wäre der Buffer bei Spread ≡ 8 sofort wieder ganz voll +
  • +
  • + daher ist es sinnvoll, die bisherige Reserve von 7 freien Slots zu beachten; d.h. man vergrößert auf 10*8 = 80 bytes +
  • +
  • + danach paßt das 4. Element rein und es ist nach-wie-vor Platz für 6 weitere Elemente +
  • +
+

+ Begründung: das ganze Thema »spread« ist extrem technisch und für den Nutzer normalerweise nicht nachvollziehbar, aber die Kapazität in Anzahl der freien Slots ist sehr wohl verständlich für den User; es wäre also ziemlich überraschend wenn — scheinbar ohne ersichtlichen Grund — plötzlich die Reserve-Kapazität verschwunden wäre. +

+ + +
+
+
@@ -83111,16 +83164,37 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - @@ -83553,9 +83627,15 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - + + + + + + + + +