diff --git a/src/lib/scoped-collection.hpp b/src/lib/scoped-collection.hpp index d240a39ee..52f272c06 100644 --- a/src/lib/scoped-collection.hpp +++ b/src/lib/scoped-collection.hpp @@ -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 ElementStorage; - - size_t level_; - size_t capacity_; - ElementStorage elements_; - typedef IterAdapter< I *, const ScopedCollection *> IterType; - typedef IterAdapter 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_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 ElementStorage; + + size_t level_; + size_t capacity_; + ElementStorage elements_; + + + void __ensureSufficientCapacity() { diff --git a/tests/lib/scoped-collection-test.cpp b/tests/lib/scoped-collection-test.cpp index f4ea3db91..acfdf99e0 100644 --- a/tests/lib/scoped-collection-test.cpp +++ b/tests/lib/scoped-collection-test.cpp @@ -75,7 +75,6 @@ namespace test{ using util::isnil; -//using std::tr1::placeholders::_1; /////////////////////////////TODO using lumiera::error::LUMIERA_ERROR_ITER_EXHAUST; typedef ScopedCollection 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 (i_+off_); + break; + + case 1: + storage.create (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 (rr); CHECK (2 == coll.size()); - + int sum = Dummy::checksum(); - + // trigger the bomb VERIFY_ERROR (SUBVERSIVE, coll.appendNew(rr,rr) );