2012-01-01 06:20:42 +01:00
|
|
|
|
/*
|
|
|
|
|
|
ScopedCollection(Test) - holding and owning a fixed collection of noncopyable objects
|
|
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
Copyright (C)
|
|
|
|
|
|
2012, Hermann Vosseler <Ichthyostega@web.de>
|
2012-01-01 06:20:42 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
**Lumiera** is free software; you can redistribute it and/or modify it
|
|
|
|
|
|
under the terms of the GNU General Public License as published by the
|
|
|
|
|
|
Free Software Foundation; either version 2 of the License, or (at your
|
|
|
|
|
|
option) any later version. See the file COPYING for further details.
|
2012-01-01 06:20:42 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
* *****************************************************************/
|
2012-01-01 06:20:42 +01:00
|
|
|
|
|
2017-02-22 01:54:20 +01:00
|
|
|
|
/** @file scoped-collection-test.cpp
|
2017-02-22 03:17:18 +01:00
|
|
|
|
** unit test \ref ScopedCollection_test
|
2016-11-03 18:20:10 +01:00
|
|
|
|
*/
|
|
|
|
|
|
|
2012-01-01 06:20:42 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "lib/test/run.hpp"
|
|
|
|
|
|
#include "lib/test/test-helper.hpp"
|
|
|
|
|
|
#include "lib/util.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
#include "lib/scoped-collection.hpp"
|
2024-06-15 18:14:00 +02:00
|
|
|
|
#include "lib/test/tracking-dummy.hpp"
|
2012-01-01 06:20:42 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace lib {
|
|
|
|
|
|
namespace test{
|
|
|
|
|
|
|
|
|
|
|
|
namespace error = lumiera::error;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace { // our explosive special Dummy
|
|
|
|
|
|
|
|
|
|
|
|
LUMIERA_ERROR_DEFINE(SUBVERSIVE, "undercover action");
|
|
|
|
|
|
|
|
|
|
|
|
class SubDummy
|
|
|
|
|
|
: public Dummy
|
|
|
|
|
|
{
|
|
|
|
|
|
int trigger_;
|
|
|
|
|
|
|
|
|
|
|
|
/** special variant of the dummy API operation:
|
|
|
|
|
|
* @param i when zero, the trigger value will be revealed
|
|
|
|
|
|
*/
|
|
|
|
|
|
virtual long
|
2024-06-11 18:23:48 +02:00
|
|
|
|
calc (int i)
|
2012-01-01 06:20:42 +01:00
|
|
|
|
{
|
|
|
|
|
|
if (!i)
|
|
|
|
|
|
return getVal() + trigger_;
|
|
|
|
|
|
else
|
2024-06-11 18:23:48 +02:00
|
|
|
|
return Dummy::calc(i);
|
2012-01-01 06:20:42 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
SubDummy (int id, int trigger)
|
|
|
|
|
|
: Dummy(id)
|
|
|
|
|
|
, trigger_(trigger)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (trigger == getVal())
|
2016-01-08 00:10:43 +01:00
|
|
|
|
throw error::Fatal ("Subversive Bomb", LUMIERA_ERROR_SUBVERSIVE);
|
2012-01-01 06:20:42 +01:00
|
|
|
|
}
|
2012-01-05 23:17:16 +01:00
|
|
|
|
|
|
|
|
|
|
SubDummy()
|
|
|
|
|
|
: Dummy()
|
|
|
|
|
|
, trigger_(-1)
|
|
|
|
|
|
{ }
|
2012-01-01 06:20:42 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
2012-01-05 23:17:16 +01:00
|
|
|
|
|
|
|
|
|
|
inline uint
|
|
|
|
|
|
sum (uint n)
|
|
|
|
|
|
{
|
2012-02-19 00:41:45 +01:00
|
|
|
|
return n*(n+1) / 2;
|
2012-01-05 23:17:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-01-01 06:20:42 +01:00
|
|
|
|
}//(End) subversive test data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
using util::isnil;
|
2024-03-16 02:04:47 +01:00
|
|
|
|
using LERR_(ITER_EXHAUST);
|
2012-01-01 06:20:42 +01:00
|
|
|
|
|
2012-02-19 00:41:45 +01:00
|
|
|
|
typedef ScopedCollection<Dummy, sizeof(SubDummy)> CollD;
|
2012-01-01 06:20:42 +01:00
|
|
|
|
|
|
|
|
|
|
|
2013-10-24 23:06:36 +02:00
|
|
|
|
/****************************************************************//**
|
2012-01-01 06:20:42 +01:00
|
|
|
|
* @test ScopedCollection manages a fixed set of objects, but these
|
|
|
|
|
|
* child objects are noncopyable, may be polymorphic, an can
|
|
|
|
|
|
* be created either all at once or chunk wise. The API is
|
|
|
|
|
|
* similar to a vector and allows for element access
|
|
|
|
|
|
* and iteration.
|
|
|
|
|
|
*/
|
|
|
|
|
|
class ScopedCollection_test : public Test
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
virtual void
|
|
|
|
|
|
run (Arg)
|
|
|
|
|
|
{
|
2024-11-13 02:23:23 +01:00
|
|
|
|
seedRand();
|
2012-01-01 06:20:42 +01:00
|
|
|
|
simpleUsage();
|
|
|
|
|
|
building_RAII_Style();
|
|
|
|
|
|
building_StackStyle();
|
|
|
|
|
|
iterating();
|
2012-01-05 23:17:16 +01:00
|
|
|
|
verify_defaultPopulator();
|
|
|
|
|
|
verify_iteratorPopulator();
|
2012-01-07 04:11:39 +01:00
|
|
|
|
verify_embeddedCollection();
|
2012-01-01 06:20:42 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
simpleUsage()
|
|
|
|
|
|
{
|
|
|
|
|
|
CHECK (0 == Dummy::checksum());
|
|
|
|
|
|
{
|
|
|
|
|
|
CollD container(5);
|
|
|
|
|
|
CHECK (isnil (container));
|
|
|
|
|
|
CHECK (0 == container.size());
|
|
|
|
|
|
CHECK (0 == Dummy::checksum());
|
|
|
|
|
|
|
|
|
|
|
|
container.populate();
|
|
|
|
|
|
CHECK (!isnil (container));
|
|
|
|
|
|
CHECK (5 == container.size());
|
|
|
|
|
|
CHECK (0 != Dummy::checksum());
|
2012-01-05 03:40:04 +01:00
|
|
|
|
|
2012-01-02 06:11:27 +01:00
|
|
|
|
container.clear();
|
2012-01-01 06:20:42 +01:00
|
|
|
|
CHECK (isnil (container));
|
|
|
|
|
|
CHECK (0 == container.size());
|
|
|
|
|
|
CHECK (0 == Dummy::checksum());
|
|
|
|
|
|
|
|
|
|
|
|
container.populate();
|
|
|
|
|
|
CHECK (Dummy::checksum() == container[0].getVal()
|
|
|
|
|
|
+ container[1].getVal()
|
|
|
|
|
|
+ container[2].getVal()
|
|
|
|
|
|
+ container[3].getVal()
|
|
|
|
|
|
+ container[4].getVal());
|
|
|
|
|
|
}
|
|
|
|
|
|
CHECK (0 == Dummy::checksum());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
iterating()
|
|
|
|
|
|
{
|
|
|
|
|
|
CHECK (0 == Dummy::checksum());
|
|
|
|
|
|
{
|
|
|
|
|
|
CollD coll(50);
|
2012-01-04 04:05:03 +01:00
|
|
|
|
for (uint i=0; i<coll.capacity(); ++i)
|
2017-08-06 18:21:25 +02:00
|
|
|
|
coll.emplace<Dummy>(i);
|
2012-01-01 06:20:42 +01:00
|
|
|
|
|
|
|
|
|
|
int check=0;
|
|
|
|
|
|
CollD::iterator ii = coll.begin();
|
|
|
|
|
|
while (ii)
|
|
|
|
|
|
{
|
|
|
|
|
|
CHECK (check == ii->getVal());
|
2024-06-11 18:23:48 +02:00
|
|
|
|
CHECK (check == ii->calc(+5) - 5);
|
2012-01-01 06:20:42 +01:00
|
|
|
|
++check;
|
|
|
|
|
|
++ii;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Test the const iterator
|
2012-01-04 04:05:03 +01:00
|
|
|
|
CollD const& const_coll (coll);
|
2012-01-01 06:20:42 +01:00
|
|
|
|
check = 0;
|
2012-01-04 04:05:03 +01:00
|
|
|
|
CollD::const_iterator cii = const_coll.begin();
|
2012-01-01 06:20:42 +01:00
|
|
|
|
while (cii)
|
|
|
|
|
|
{
|
|
|
|
|
|
CHECK (check == cii->getVal());
|
|
|
|
|
|
++check;
|
|
|
|
|
|
++cii;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-08-06 16:58:22 +02:00
|
|
|
|
// Test c++11 foreach iteration
|
|
|
|
|
|
check = 0;
|
|
|
|
|
|
for (auto& entry : coll)
|
|
|
|
|
|
{
|
|
|
|
|
|
CHECK (check == entry.getVal());
|
|
|
|
|
|
++check;
|
|
|
|
|
|
}
|
|
|
|
|
|
check = 0;
|
|
|
|
|
|
for (auto const& entry : const_coll)
|
|
|
|
|
|
{
|
|
|
|
|
|
CHECK (check == entry.getVal());
|
|
|
|
|
|
++check;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-01-01 06:20:42 +01:00
|
|
|
|
// Verify correct behaviour of iteration end
|
|
|
|
|
|
CHECK (! (coll.end()));
|
|
|
|
|
|
CHECK (isnil (coll.end()));
|
|
|
|
|
|
|
|
|
|
|
|
VERIFY_ERROR (ITER_EXHAUST, *coll.end() );
|
|
|
|
|
|
VERIFY_ERROR (ITER_EXHAUST, ++coll.end() );
|
|
|
|
|
|
|
|
|
|
|
|
CHECK (ii == coll.end());
|
|
|
|
|
|
CHECK (cii == coll.end());
|
|
|
|
|
|
VERIFY_ERROR (ITER_EXHAUST, ++ii );
|
|
|
|
|
|
VERIFY_ERROR (ITER_EXHAUST, ++cii );
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
CHECK (0 == Dummy::checksum());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-01-05 03:40:04 +01:00
|
|
|
|
/** @test using the ScopedCollection to hold a variable
|
|
|
|
|
|
* and possibly increasing number of elements, within the
|
|
|
|
|
|
* fixed limits of the maximum capacity defined by the
|
|
|
|
|
|
* ctor parameter. Any new elements will be created
|
|
|
|
|
|
* behind the already existing objects. In case
|
|
|
|
|
|
* of failure while creating an element, only
|
|
|
|
|
|
* this element gets destroyed, the rest of
|
|
|
|
|
|
* the container remains intact.
|
|
|
|
|
|
*/
|
2012-01-01 06:20:42 +01:00
|
|
|
|
void
|
|
|
|
|
|
building_StackStyle()
|
|
|
|
|
|
{
|
|
|
|
|
|
CHECK (0 == Dummy::checksum());
|
|
|
|
|
|
{
|
|
|
|
|
|
|
2024-11-13 02:23:23 +01:00
|
|
|
|
int rr = rani(100);
|
2012-01-01 06:20:42 +01:00
|
|
|
|
|
|
|
|
|
|
CollD coll(3);
|
|
|
|
|
|
CHECK (0 == coll.size());
|
|
|
|
|
|
CHECK (0 == Dummy::checksum());
|
2012-01-05 03:40:04 +01:00
|
|
|
|
|
2017-08-06 18:21:25 +02:00
|
|
|
|
Dummy& d0 = coll.emplaceElement();
|
2012-01-01 06:20:42 +01:00
|
|
|
|
CHECK (1 == coll.size());
|
|
|
|
|
|
|
2017-08-06 18:21:25 +02:00
|
|
|
|
Dummy& d1 = coll.emplace<Dummy> (rr);
|
2012-01-01 06:20:42 +01:00
|
|
|
|
CHECK (2 == coll.size());
|
2012-01-05 03:40:04 +01:00
|
|
|
|
|
2012-01-01 06:20:42 +01:00
|
|
|
|
int sum = Dummy::checksum();
|
2012-01-05 03:40:04 +01:00
|
|
|
|
|
2012-01-01 06:20:42 +01:00
|
|
|
|
// trigger the bomb
|
2017-08-06 18:21:25 +02:00
|
|
|
|
VERIFY_ERROR (SUBVERSIVE, coll.emplace<SubDummy>(rr,rr) );
|
2012-01-01 06:20:42 +01:00
|
|
|
|
|
|
|
|
|
|
CHECK ( 2 == coll.size()); // the other objects survived
|
|
|
|
|
|
CHECK (sum == Dummy::checksum());
|
|
|
|
|
|
|
2017-08-06 18:21:25 +02:00
|
|
|
|
Dummy& d2 = coll.emplace<SubDummy> (rr, rr+1);
|
2012-01-01 06:20:42 +01:00
|
|
|
|
CHECK (3 == coll.size());
|
|
|
|
|
|
|
2012-01-04 04:28:14 +01:00
|
|
|
|
CHECK (sum + rr == Dummy::checksum());
|
2012-01-01 06:20:42 +01:00
|
|
|
|
|
2017-08-06 18:21:25 +02:00
|
|
|
|
VERIFY_ERROR (CAPACITY, coll.emplaceElement());
|
|
|
|
|
|
VERIFY_ERROR (CAPACITY, coll.emplaceElement());
|
|
|
|
|
|
VERIFY_ERROR (CAPACITY, coll.emplaceElement());
|
2012-01-01 06:20:42 +01:00
|
|
|
|
|
|
|
|
|
|
CHECK (3 == coll.size());
|
2012-01-04 04:28:14 +01:00
|
|
|
|
CHECK (sum + rr == Dummy::checksum());
|
2012-01-01 06:20:42 +01:00
|
|
|
|
|
|
|
|
|
|
|
2024-06-11 18:23:48 +02:00
|
|
|
|
CHECK (d0.calc(11) == coll[0].getVal() + 11 );
|
|
|
|
|
|
CHECK (d1.calc(22) == rr + 22);
|
|
|
|
|
|
CHECK (d2.calc(33) == rr + 33);
|
|
|
|
|
|
CHECK (d2.calc(0) == rr + (rr+1) ); // SubDummy's special implementation of the acc()-function
|
|
|
|
|
|
// returns the trigger value, when the argument is zero
|
2012-01-01 06:20:42 +01:00
|
|
|
|
|
|
|
|
|
|
coll.clear();
|
2017-08-06 18:21:25 +02:00
|
|
|
|
coll.emplace<SubDummy> (11,22);
|
2012-01-01 06:20:42 +01:00
|
|
|
|
|
2012-01-04 04:28:14 +01:00
|
|
|
|
CHECK ( 1 == coll.size());
|
2012-01-01 06:20:42 +01:00
|
|
|
|
CHECK (11 == Dummy::checksum());
|
|
|
|
|
|
|
|
|
|
|
|
// NOTE DANGEROUS:
|
|
|
|
|
|
// The previously obtained references just point into the object storage.
|
|
|
|
|
|
// Thus we're now accessing a different object, even a different type!
|
2024-06-11 18:23:48 +02:00
|
|
|
|
CHECK (d0.calc(0) == 11 + 22);
|
2012-01-01 06:20:42 +01:00
|
|
|
|
|
|
|
|
|
|
// The others even point into obsoleted storage holding zombie objects
|
2025-02-16 21:10:06 +01:00
|
|
|
|
CHECK (d1.getVal() == Dummy::DEAD);
|
2012-01-01 06:20:42 +01:00
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
CHECK (0 == Dummy::checksum());
|
|
|
|
|
|
}
|
2012-01-05 23:17:16 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @test using the ScopedCollection according to the RAII pattern.
|
|
|
|
|
|
* For this usage style, the collection is filled right away, during
|
|
|
|
|
|
* construction. If anything goes wrong, the whole collection is
|
|
|
|
|
|
* cleared and invalidated. Consequently there is no tangible "lifecycle"
|
|
|
|
|
|
* at the usage site. Either the collection is fully usable, or not at all.
|
|
|
|
|
|
* This requires the client to provide a functor (callback) to define
|
|
|
|
|
|
* the actual objects to be created within the ScopedCollection. These
|
|
|
|
|
|
* may as well be subclasses of the base type I, provided the general
|
|
|
|
|
|
* element storage size #siz was chosen sufficiently large to hold
|
|
|
|
|
|
* those subclass instances.
|
|
|
|
|
|
*
|
|
|
|
|
|
* This test demonstrates the most elaborate usage pattern, where
|
|
|
|
|
|
* the client provides a full blown functor object #Populator,
|
|
|
|
|
|
* which even has embedded state. Generally speaking, anything
|
|
|
|
|
|
* exposing a suitable function call operator is acceptable.
|
|
|
|
|
|
*/
|
|
|
|
|
|
void
|
|
|
|
|
|
building_RAII_Style()
|
|
|
|
|
|
{
|
|
|
|
|
|
CHECK (0 == Dummy::checksum());
|
|
|
|
|
|
{
|
2024-11-13 02:23:23 +01:00
|
|
|
|
int rr = rani(100);
|
2025-06-07 23:59:57 +02:00
|
|
|
|
int trigger = 100 + 5 + 1; // prevents the bomb from exploding (since rr < 100)
|
2012-01-05 23:17:16 +01:00
|
|
|
|
|
|
|
|
|
|
CollD coll (6, Populator(rr, trigger));
|
|
|
|
|
|
|
|
|
|
|
|
CHECK (!isnil (coll));
|
|
|
|
|
|
CHECK (6 == coll.size());
|
|
|
|
|
|
CHECK (0 != Dummy::checksum());
|
|
|
|
|
|
|
2024-06-11 18:23:48 +02:00
|
|
|
|
CHECK (coll[0].calc(0) == 0 + rr);
|
|
|
|
|
|
CHECK (coll[1].calc(0) == 1 + rr + trigger);
|
|
|
|
|
|
CHECK (coll[2].calc(0) == 2 + rr);
|
|
|
|
|
|
CHECK (coll[3].calc(0) == 3 + rr + trigger);
|
|
|
|
|
|
CHECK (coll[4].calc(0) == 4 + rr);
|
|
|
|
|
|
CHECK (coll[5].calc(0) == 5 + rr + trigger);
|
2016-01-08 00:10:43 +01:00
|
|
|
|
// what does this check prove?
|
|
|
|
|
|
// - the container was indeed populated with DubDummy objects
|
|
|
|
|
|
// since the overridden version of Dummy::acc() did run and
|
|
|
|
|
|
// reveal the trigger value
|
|
|
|
|
|
// - the population was indeed done with the anonymous Populator
|
|
|
|
|
|
// instance fed to the ctor, since this object was "marked" with
|
|
|
|
|
|
// the random value rr, and adds this mark to the built values.
|
2012-01-05 23:17:16 +01:00
|
|
|
|
|
|
|
|
|
|
coll.clear();
|
|
|
|
|
|
CHECK (0 == Dummy::checksum());
|
|
|
|
|
|
|
|
|
|
|
|
// Verify Error handling while in creation:
|
|
|
|
|
|
// SubDummy explodes on equal ctor parameters
|
|
|
|
|
|
// which here happens for i==7
|
|
|
|
|
|
VERIFY_ERROR (SUBVERSIVE, CollD(10, Populator(0, 7)) );
|
|
|
|
|
|
|
|
|
|
|
|
// any already created object was properly destroyed
|
|
|
|
|
|
CHECK (0 == Dummy::checksum());
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
CHECK (0 == Dummy::checksum());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Functor to populate the Collection */
|
|
|
|
|
|
class Populator
|
|
|
|
|
|
{
|
|
|
|
|
|
uint i_;
|
|
|
|
|
|
int off_;
|
|
|
|
|
|
int trigg_;
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
Populator (int baseOffset, int triggerCode)
|
|
|
|
|
|
: i_(0)
|
|
|
|
|
|
, off_(baseOffset)
|
|
|
|
|
|
, trigg_(triggerCode)
|
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
operator() (CollD::ElementHolder& storage)
|
|
|
|
|
|
{
|
2025-06-07 23:59:57 +02:00
|
|
|
|
switch (i_ % 2)
|
2012-01-05 23:17:16 +01:00
|
|
|
|
{
|
|
|
|
|
|
case 0:
|
|
|
|
|
|
storage.create<Dummy> (i_+off_);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
|
|
storage.create<SubDummy> (i_+off_, trigg_);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
++i_;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @test for using ScopedCollection in RAII style,
|
|
|
|
|
|
* several pre-defined "populators" are provided.
|
|
|
|
|
|
* The most obvious one being just to fill the
|
|
|
|
|
|
* collection with default constructed objects.
|
|
|
|
|
|
*/
|
|
|
|
|
|
void
|
|
|
|
|
|
verify_defaultPopulator()
|
|
|
|
|
|
{
|
|
|
|
|
|
CHECK (0 == Dummy::checksum());
|
|
|
|
|
|
|
|
|
|
|
|
CollD coll (25, CollD::FillAll() );
|
|
|
|
|
|
|
|
|
|
|
|
CHECK (!isnil (coll));
|
|
|
|
|
|
CHECK (25 == coll.size());
|
|
|
|
|
|
CHECK (0 != Dummy::checksum());
|
|
|
|
|
|
|
|
|
|
|
|
for (CollD::iterator ii = coll.begin(); ii; ++ii)
|
|
|
|
|
|
{
|
|
|
|
|
|
CHECK ( INSTANCEOF (Dummy, & (*ii)));
|
|
|
|
|
|
CHECK (!INSTANCEOF (SubDummy, & (*ii)));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
verify_subclassPopulator()
|
|
|
|
|
|
{
|
|
|
|
|
|
CHECK (0 == Dummy::checksum());
|
|
|
|
|
|
|
|
|
|
|
|
CollD coll (25, CollD::FillWith<SubDummy>() );
|
|
|
|
|
|
|
|
|
|
|
|
CHECK (!isnil (coll));
|
|
|
|
|
|
CHECK (25 == coll.size());
|
|
|
|
|
|
CHECK (0 != Dummy::checksum());
|
|
|
|
|
|
|
|
|
|
|
|
for (CollD::iterator ii = coll.begin(); ii; ++ii)
|
|
|
|
|
|
CHECK (INSTANCEOF (SubDummy, & (*ii)));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
verify_iteratorPopulator()
|
|
|
|
|
|
{
|
|
|
|
|
|
typedef ScopedCollection<uint> CollI;
|
|
|
|
|
|
|
|
|
|
|
|
CollI source (25);
|
|
|
|
|
|
for (uint i=0; i < source.capacity(); ++i)
|
2017-08-06 18:21:25 +02:00
|
|
|
|
source.emplace<uint>(i); // holding the numbers 0..24
|
2012-01-05 23:17:16 +01:00
|
|
|
|
|
|
|
|
|
|
CollI coll (20, CollI::pull(source.begin()));
|
2025-06-07 23:59:57 +02:00
|
|
|
|
// this immediately pulls in the first 20 elements
|
2012-01-05 23:17:16 +01:00
|
|
|
|
CHECK (!isnil (coll));
|
|
|
|
|
|
CHECK (20 == coll.size());
|
|
|
|
|
|
CHECK (25 == source.size());
|
|
|
|
|
|
|
|
|
|
|
|
for (uint i=0; i < coll.size(); ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
CHECK (coll[i] == i );
|
|
|
|
|
|
CHECK (coll[i] == source[i]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// note: the iterator is assumed to deliver a sufficient amount of elements
|
|
|
|
|
|
VERIFY_ERROR (ITER_EXHAUST, CollI (50, CollI::pull (source.begin())));
|
|
|
|
|
|
}
|
2012-01-07 04:11:39 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @test simulate the typical situation of a manager
|
|
|
|
|
|
* owning some embedded components. Here, our ManagerDemo
|
|
|
|
|
|
* instance owns a collection of numbers 50..1. They are
|
|
|
|
|
|
* created right while initialising the manager, and this
|
|
|
|
|
|
* initialisation is done by invoking a member function
|
|
|
|
|
|
* of the manager
|
|
|
|
|
|
*/
|
|
|
|
|
|
void
|
|
|
|
|
|
verify_embeddedCollection()
|
|
|
|
|
|
{
|
|
|
|
|
|
ManagerDemo object_with_embedded_Collection(50);
|
|
|
|
|
|
CHECK (sum(50) == object_with_embedded_Collection.useMyNumbers());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class ManagerDemo
|
|
|
|
|
|
{
|
|
|
|
|
|
typedef ScopedCollection<uint> CollI;
|
|
|
|
|
|
|
|
|
|
|
|
uint memberVar_;
|
|
|
|
|
|
const CollI my_own_Numbers_;
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
buildNumbers (CollI::ElementHolder& storage)
|
|
|
|
|
|
{
|
|
|
|
|
|
storage.create<uint>(memberVar_);
|
|
|
|
|
|
--memberVar_;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
ManagerDemo(uint cnt)
|
|
|
|
|
|
: memberVar_(cnt)
|
|
|
|
|
|
, my_own_Numbers_(cnt, &ManagerDemo::buildNumbers, this)
|
2025-06-07 23:59:57 +02:00
|
|
|
|
{
|
2012-01-07 04:11:39 +01:00
|
|
|
|
CHECK (0 == memberVar_);
|
|
|
|
|
|
CHECK (cnt == my_own_Numbers_.size());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint
|
|
|
|
|
|
useMyNumbers()
|
|
|
|
|
|
{
|
|
|
|
|
|
uint sum(0);
|
|
|
|
|
|
for (CollI::const_iterator ii = my_own_Numbers_.begin(); ii; ++ii)
|
|
|
|
|
|
sum += *ii;
|
|
|
|
|
|
return sum;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2012-01-01 06:20:42 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-01-05 23:17:16 +01:00
|
|
|
|
|
2012-01-01 06:20:42 +01:00
|
|
|
|
LAUNCHER (ScopedCollection_test, "unit common");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}} // namespace lib::test
|
|
|
|
|
|
|