diff --git a/src/lib/several-builder.hpp b/src/lib/several-builder.hpp
index 30e962de9..5c0f6cbd6 100644
--- a/src/lib/several-builder.hpp
+++ b/src/lib/several-builder.hpp
@@ -277,7 +277,7 @@ namespace lib {
,class POL =HeapOwn ///< Allocator policy
>
class SeveralBuilder
- : Several
+ : private Several
, util::MoveOnly
, POL
{
@@ -390,15 +390,17 @@ namespace lib {
// 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 container for element 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{"Unable to accommodate further element of type %s "}
- % util::typeStr()};
+ 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()};
size_t elmSiz = reqSiz();
size_t newPos = Coll::size();
@@ -410,11 +412,13 @@ namespace lib {
Coll::data_->cnt = newPos+1;
}
+ /** ensure clean-up can be handled properly.
+ * @throw err::Invalid when \a TY requires a different style
+ * of deleter than was established for this instance */
template
void
ensureDeleter()
{
- // ensure clean-up can be handled properly
Deleter deleterFunctor = selectDestructor();
if (Coll::data_->deleter) return;
Coll::data_->deleter = deleterFunctor;
@@ -424,7 +428,7 @@ namespace lib {
adjustStorage (size_t cnt, size_t spread)
{
size_t demand{cnt*spread};
- size_t buffSiz{Coll::data_? Coll::data_->buffSiz : 0};
+ size_t buffSiz{Coll::storageBuffSiz()};
if (demand == buffSiz)
return;
if (demand > buffSiz)
@@ -462,7 +466,7 @@ namespace lib {
adjustSpread (size_t newSpread)
{
REQUIRE (Coll::data_);
- REQUIRE (newSpread * Coll::size() <= Coll::data_->buffSiz);
+ REQUIRE (newSpread * Coll::size() <= Coll::storageBuffSiz());
size_t oldSpread = Coll::spread();
if (newSpread > oldSpread)
// need to spread out
diff --git a/src/lib/several.hpp b/src/lib/several.hpp
index 4446d6cca..b770b5642 100644
--- a/src/lib/several.hpp
+++ b/src/lib/several.hpp
@@ -210,6 +210,12 @@ namespace lib {
return data_? data_->spread : sizeof(I);
}
+ size_t
+ storageBuffSiz() const
+ {
+ return data_? data_->buffSiz : 0;
+ }
+
bool
hasReserve (size_t extraSize) const
{
diff --git a/tests/library/several-builder-test.cpp b/tests/library/several-builder-test.cpp
index 3ce7d42f5..51db58478 100644
--- a/tests/library/several-builder-test.cpp
+++ b/tests/library/several-builder-test.cpp
@@ -111,6 +111,18 @@ namespace test{
}
};
+
+ /**
+ * A non-copyable struct with 16bit alignment
+ * - not trivially default constructible
+ * - but trivially destructible
+ */
+ struct ShortBlocker
+ : util::NonCopyable
+ {
+ int16_t val{short(1 + (rand() % 1'000))};
+ };
+
} // (END) test types
@@ -164,7 +176,7 @@ namespace test{
* *unchecked wild cast* will happen on access; while certainly dangerous,
* this behaviour allows for special low-level data layout tricks.
* - the results from an iterator can be used to populate by copy
- * @todo WIP 6/24 🔁 define ⟶ ✔ implement
+ * @todo WIP 6/24 ✔ define ⟶ ✔ implement
*/
void
check_Builder()
@@ -228,7 +240,17 @@ namespace test{
/** @test TODO proper handling of exceptions during population
- * @todo WIP 6/24 🔁 define ⟶ implement
+ * - when the container is filled with arbitrary subclasses
+ * of a base interface with virtual destructor, the first element is used
+ * to accommodate the storage spread; larger elements or elements of a completely
+ * different type can not be accommodated and the container can not grow beyond
+ * the initially allocated reserve (defined to be 10 elements by default).
+ * - when the container is defined to hold elements of a specific fixed subclass,
+ * it can be filled with default-constructed instances, and the initial allocation
+ * can be expanded by move-relocation. Yet totally unrelated elements can not be
+ * accepted (due to unknown destructor); and when accepting another unspecific
+ * subclass instance, the ability to grow by move-relocation is lost.
+ * @todo WIP 6/24 🔁 define ⟶ ✔ implement
*/
void
check_ErrorHandling()
@@ -266,7 +288,7 @@ namespace test{
// a re-allocation of a larger buffer, followed by copying the elements;
// but since the established scheme allows for _arbitrary_ subclasses,
// the builder does not know the exact type for safe element relocation.
- VERIFY_FAIL ("Unable to accommodate further element of type Dummy"
+ VERIFY_FAIL ("Several-container is unable to accommodate further element of type Dummy"
, builder.fillElm (20) );
CHECK (10 == builder.size());
}
@@ -274,27 +296,45 @@ namespace test{
{ // Scenario-2 : Baseclass and elements of a single fixed subclass
SeveralBuilder> builder;
- Dummy dum;
-SHOW_EXPR(dum.getVal())
- Dummy nem{move(dum)};
-SHOW_EXPR(dum.getVal())
-SHOW_EXPR(nem.getVal())
- Num<5> no5;
-SHOW_EXPR(no5.getVal())
- Num<5> ne5{move(no5)};
-SHOW_EXPR(no5.getVal())
-SHOW_EXPR(ne5.getVal())
-
builder.fillElm(5);
CHECK (5 == builder.size());
// trigger re-alloc by moving into larger memory block
builder.fillElm(14);
CHECK (19 == builder.size());
+ CHECK (builder.size() > INITIAL_ELM_CNT);
- builder.emplace();
+ // with the elements added thus far, this instance has been primed to
+ // rely on a fixed well known element type for move-growth and to use
+ // the virtual base class destructor for clean-up. It is thus not possible
+ // to add another element that is not related to this baseclass...
+ VERIFY_FAIL ("Unable to handle (trivial-)destructor for element type ShortBlocker, "
+ "since this container has been primed to use virtual-baseclass-destructors."
+ , builder.emplace() );
+ CHECK (19 == builder.size());
- builder.emplace>(); ///////////////////////////////////OOO this should trigger an exception -> need to code an explicit check right at the start of emplaceNewElm()
+ CHECK (sizeof(ShortBlocker) < sizeof(Num<5>)); // it was not rejected due to size...
+
+ // However, a subclass /different than the defined element type/ is acceptable,
+ // but only to the condition to lock any further container growth by move-reallocation.
+ // The rationale is that we can still destroy through the virtual base destructor,
+ // but we aren't able to move elements safely any more, since we don't capture the type.
+ builder.emplace>();
+ CHECK (20 == builder.size());
+
+ // 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
+ // is exhausted and we are now unable to add any further elements beyond that point.
+ VERIFY_FAIL ("unable to move elements of mixed unknown detail type, which are not trivially movable"
+ , builder.fillElm(5); );
+
+ // the container is still sound however
+ auto elms = builder.build();
+ CHECK (20 == elms.size());
+ // verify that member fields were not corrupted
+ for (uint i=0; i<=18; ++i)
+ CHECK (elms[i].calc(i) == 5 + i + (5+5+5+5+5));
+ CHECK (elms.back().calc(0) == 1 + 0 + (1));
}
}
@@ -302,7 +342,7 @@ SHOW_EXPR(ne5.getVal())
/** @test TODO verify correct placement of instances within storage
* @todo WIP 6/24 🔁 define ⟶ implement
*/
- void
+ void
check_ElementStorage()
{
}
@@ -311,7 +351,7 @@ SHOW_EXPR(ne5.getVal())
/** @test TODO demonstrate integration with a custom allocator
* @todo WIP 6/24 🔁 define ⟶ implement
*/
- void
+ void
check_CustomAllocator()
{
}
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index 3337fbb83..ecf404960 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -82728,9 +82728,9 @@ Date: Thu Apr 20 18:53:17 2023 +0200
-
+
-
+
@@ -82741,9 +82741,9 @@ Date: Thu Apr 20 18:53:17 2023 +0200
-
+
-
+
@@ -82757,10 +82757,10 @@ Date: Thu Apr 20 18:53:17 2023 +0200
-
+
-
+
@@ -82770,8 +82770,8 @@ Date: Thu Apr 20 18:53:17 2023 +0200
-
-
+
+
@@ -82790,8 +82790,7 @@ Date: Thu Apr 20 18:53:17 2023 +0200
Soweit die Theorie... in der Praxis aber scheitert das, weil der Compiler versucht, den realloc-Code zu instantiieren und dafür keinen Copy/Move-Konstruktor findet
-
-
+
@@ -82809,11 +82808,10 @@ Date: Thu Apr 20 18:53:17 2023 +0200
-
-
+