implement the RAII-style collection ctor. test pass

This commit is contained in:
Fischlurch 2012-01-05 03:40:04 +01:00
parent 434a371c33
commit 72e8d22454
2 changed files with 93 additions and 63 deletions

View file

@ -64,7 +64,7 @@ namespace lib {
/**
* A fixed collection of noncopyable polymorphic objects.
*
* All child objects reside in a common chunk of storage
* and are owned and managed by this collection holder.
* Array style access and iteration.
@ -77,6 +77,7 @@ namespace lib {
: boost::noncopyable
{
public:
/**
* Storage Frame to hold one Child object.
* The storage will be an heap allocated
@ -103,11 +104,6 @@ namespace lib {
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 ()
{
@ -219,10 +202,19 @@ namespace lib {
: level_(0)
, capacity_(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
@ -366,8 +358,9 @@ namespace lib {
typedef IterType iterator;
typedef ConstIterType const_iterator;
typedef IterAdapter< I *, const ScopedCollection *> iterator;
typedef IterAdapter<const I *, const ScopedCollection *> const_iterator;
iterator begin() { return 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_; }
private:
/* ==== Storage: heap allocated array of element buffers ==== */
typedef boost::scoped_array<ElementHolder> ElementStorage;
size_t level_;
size_t capacity_;
ElementStorage elements_;
void
__ensureSufficientCapacity()
{

View file

@ -75,7 +75,6 @@ namespace test{
using util::isnil;
//using std::tr1::placeholders::_1; /////////////////////////////TODO
using lumiera::error::LUMIERA_ERROR_ITER_EXHAUST;
typedef ScopedCollection<Dummy> CollD;
@ -115,7 +114,7 @@ namespace test{
CHECK (!isnil (container));
CHECK (5 == container.size());
CHECK (0 != Dummy::checksum());
container.clear();
CHECK (isnil (container));
CHECK (0 == container.size());
@ -179,46 +178,64 @@ namespace test{
}
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
building_RAII_Style()
{
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 trigger = 101;
CollD coll (6, Populator(rr), trigger, _1 );
CollD coll (6, Populator(rr, trigger));
CHECK (!isnil (coll));
CHECK (6 == coll.size());
@ -237,16 +254,25 @@ namespace test{
// 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, _1 ) );
VERIFY_ERROR (SUBVERSIVE, CollD(10, Populator(0, 7)) );
// any already created object was properly destroyed
CHECK (0 == Dummy::checksum());
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #877
}
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
building_StackStyle()
{
@ -258,15 +284,15 @@ namespace test{
CollD coll(3);
CHECK (0 == coll.size());
CHECK (0 == Dummy::checksum());
Dummy& d0 = coll.appendNewElement();
CHECK (1 == coll.size());
Dummy& d1 = coll.appendNew<Dummy> (rr);
CHECK (2 == coll.size());
int sum = Dummy::checksum();
// trigger the bomb
VERIFY_ERROR (SUBVERSIVE, coll.appendNew<SubDummy>(rr,rr) );