implement the RAII-style collection ctor. test pass
This commit is contained in:
parent
434a371c33
commit
72e8d22454
2 changed files with 93 additions and 63 deletions
|
|
@ -64,7 +64,7 @@ namespace lib {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A fixed collection of noncopyable polymorphic objects.
|
* A fixed collection of noncopyable polymorphic objects.
|
||||||
|
*
|
||||||
* All child objects reside in a common chunk of storage
|
* All child objects reside in a common chunk of storage
|
||||||
* and are owned and managed by this collection holder.
|
* and are owned and managed by this collection holder.
|
||||||
* Array style access and iteration.
|
* Array style access and iteration.
|
||||||
|
|
@ -77,6 +77,7 @@ namespace lib {
|
||||||
: boost::noncopyable
|
: boost::noncopyable
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
/**
|
/**
|
||||||
* Storage Frame to hold one Child object.
|
* Storage Frame to hold one Child object.
|
||||||
* The storage will be an heap allocated
|
* The storage will be an heap allocated
|
||||||
|
|
@ -103,11 +104,6 @@ namespace lib {
|
||||||
accessObj().~I();
|
accessObj().~I();
|
||||||
}
|
}
|
||||||
|
|
||||||
I&
|
|
||||||
operator* () const
|
|
||||||
{
|
|
||||||
return accessObj();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -186,21 +182,8 @@ namespace lib {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ==== Storage: heap allocated array of element buffers ==== */
|
|
||||||
|
|
||||||
typedef boost::scoped_array<ElementHolder> ElementStorage;
|
|
||||||
|
|
||||||
size_t level_;
|
|
||||||
size_t capacity_;
|
|
||||||
ElementStorage elements_;
|
|
||||||
|
|
||||||
|
|
||||||
typedef IterAdapter< I *, const ScopedCollection *> IterType;
|
|
||||||
typedef IterAdapter<const I *, const ScopedCollection *> ConstIterType;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
~ScopedCollection ()
|
~ScopedCollection ()
|
||||||
{
|
{
|
||||||
|
|
@ -219,10 +202,19 @@ namespace lib {
|
||||||
: level_(0)
|
: level_(0)
|
||||||
, capacity_(maxElements)
|
, capacity_(maxElements)
|
||||||
, elements_(new ElementHolder[maxElements])
|
, elements_(new ElementHolder[maxElements])
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED ("use the builder to populate the elements right away");
|
try {
|
||||||
}
|
while (level_ < capacity_)
|
||||||
|
{
|
||||||
|
ElementHolder& storageFrame (elements_[level_]);
|
||||||
|
builder (storageFrame);
|
||||||
|
++level_;
|
||||||
|
}}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
throw;
|
||||||
|
} }
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -366,8 +358,9 @@ namespace lib {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef IterType iterator;
|
typedef IterAdapter< I *, const ScopedCollection *> iterator;
|
||||||
typedef ConstIterType const_iterator;
|
typedef IterAdapter<const I *, const ScopedCollection *> const_iterator;
|
||||||
|
|
||||||
|
|
||||||
iterator begin() { return iterator (this, _access_begin()); }
|
iterator begin() { return iterator (this, _access_begin()); }
|
||||||
const_iterator begin() const { return const_iterator (this, _access_begin()); }
|
const_iterator begin() const { return const_iterator (this, _access_begin()); }
|
||||||
|
|
@ -380,7 +373,18 @@ namespace lib {
|
||||||
bool empty () const { return 0 == level_; }
|
bool empty () const { return 0 == level_; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/* ==== Storage: heap allocated array of element buffers ==== */
|
||||||
|
|
||||||
|
typedef boost::scoped_array<ElementHolder> ElementStorage;
|
||||||
|
|
||||||
|
size_t level_;
|
||||||
|
size_t capacity_;
|
||||||
|
ElementStorage elements_;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
__ensureSufficientCapacity()
|
__ensureSufficientCapacity()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,6 @@ namespace test{
|
||||||
|
|
||||||
|
|
||||||
using util::isnil;
|
using util::isnil;
|
||||||
//using std::tr1::placeholders::_1; /////////////////////////////TODO
|
|
||||||
using lumiera::error::LUMIERA_ERROR_ITER_EXHAUST;
|
using lumiera::error::LUMIERA_ERROR_ITER_EXHAUST;
|
||||||
|
|
||||||
typedef ScopedCollection<Dummy> CollD;
|
typedef ScopedCollection<Dummy> CollD;
|
||||||
|
|
@ -115,7 +114,7 @@ namespace test{
|
||||||
CHECK (!isnil (container));
|
CHECK (!isnil (container));
|
||||||
CHECK (5 == container.size());
|
CHECK (5 == container.size());
|
||||||
CHECK (0 != Dummy::checksum());
|
CHECK (0 != Dummy::checksum());
|
||||||
|
|
||||||
container.clear();
|
container.clear();
|
||||||
CHECK (isnil (container));
|
CHECK (isnil (container));
|
||||||
CHECK (0 == container.size());
|
CHECK (0 == container.size());
|
||||||
|
|
@ -179,46 +178,64 @@ namespace test{
|
||||||
}
|
}
|
||||||
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)
|
||||||
|
{
|
||||||
|
switch (i_ % 2)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
storage.create<Dummy> (i_+off_);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
storage.create<SubDummy> (i_+off_, trigg_);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++i_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @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, which even
|
||||||
|
* has embedded state. But, generally speaking, anything
|
||||||
|
* exposing a suitable function call operator is acceptable.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
building_RAII_Style()
|
building_RAII_Style()
|
||||||
{
|
{
|
||||||
CHECK (0 == Dummy::checksum());
|
CHECK (0 == Dummy::checksum());
|
||||||
{
|
{
|
||||||
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #877
|
|
||||||
/** Functor to populate the Collection */
|
|
||||||
class Populator
|
|
||||||
{
|
|
||||||
uint i_;
|
|
||||||
int off_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Populator (int baseOffset)
|
|
||||||
: i_(0)
|
|
||||||
, off_(baseOffset)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void
|
|
||||||
operator() (int specialOffset, void* storage)
|
|
||||||
{
|
|
||||||
switch (i_ % 2)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
new(storage) Dummy(i_+off_);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
new(storage) SubDummy(i_+off_, specialOffset);
|
|
||||||
break;
|
|
||||||
} }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
int rr = rand() % 100;
|
int rr = rand() % 100;
|
||||||
int trigger = 101;
|
int trigger = 101;
|
||||||
|
|
||||||
CollD coll (6, Populator(rr), trigger, _1 );
|
CollD coll (6, Populator(rr, trigger));
|
||||||
|
|
||||||
CHECK (!isnil (coll));
|
CHECK (!isnil (coll));
|
||||||
CHECK (6 == coll.size());
|
CHECK (6 == coll.size());
|
||||||
|
|
@ -237,16 +254,25 @@ namespace test{
|
||||||
// Verify Error handling while in creation:
|
// Verify Error handling while in creation:
|
||||||
// SubDummy explodes on equal ctor parameters
|
// SubDummy explodes on equal ctor parameters
|
||||||
// which here happens for i==7
|
// which here happens for i==7
|
||||||
VERIFY_ERROR (SUBVERSIVE, CollD(10, Populator(0), 7, _1 ) );
|
VERIFY_ERROR (SUBVERSIVE, CollD(10, Populator(0, 7)) );
|
||||||
|
|
||||||
// any already created object was properly destroyed
|
// any already created object was properly destroyed
|
||||||
CHECK (0 == Dummy::checksum());
|
CHECK (0 == Dummy::checksum());
|
||||||
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #877
|
|
||||||
}
|
}
|
||||||
CHECK (0 == Dummy::checksum());
|
CHECK (0 == Dummy::checksum());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** @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.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
building_StackStyle()
|
building_StackStyle()
|
||||||
{
|
{
|
||||||
|
|
@ -258,15 +284,15 @@ namespace test{
|
||||||
CollD coll(3);
|
CollD coll(3);
|
||||||
CHECK (0 == coll.size());
|
CHECK (0 == coll.size());
|
||||||
CHECK (0 == Dummy::checksum());
|
CHECK (0 == Dummy::checksum());
|
||||||
|
|
||||||
Dummy& d0 = coll.appendNewElement();
|
Dummy& d0 = coll.appendNewElement();
|
||||||
CHECK (1 == coll.size());
|
CHECK (1 == coll.size());
|
||||||
|
|
||||||
Dummy& d1 = coll.appendNew<Dummy> (rr);
|
Dummy& d1 = coll.appendNew<Dummy> (rr);
|
||||||
CHECK (2 == coll.size());
|
CHECK (2 == coll.size());
|
||||||
|
|
||||||
int sum = Dummy::checksum();
|
int sum = Dummy::checksum();
|
||||||
|
|
||||||
// trigger the bomb
|
// trigger the bomb
|
||||||
VERIFY_ERROR (SUBVERSIVE, coll.appendNew<SubDummy>(rr,rr) );
|
VERIFY_ERROR (SUBVERSIVE, coll.appendNew<SubDummy>(rr,rr) );
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue