/* ScopedHolderTransfer(Test) - managing noncopyable objects within a growing vector Copyright (C) Lumiera.org 2008, Hermann Vosseler This program 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *****************************************************/ #include "lib/test/run.hpp" #include "lib/util.hpp" #include "lib/scoped-holder.hpp" #include "lib/scoped-holder-transfer.hpp" #include "testdummy.hpp" #include #include namespace lib { namespace test { using ::Test; using util::isnil; using std::vector; using std::cout; namespace { // extending the Dummy for our special purpose.... bool throw_in_transfer = false; class FixedDummy : public Dummy { public: FixedDummy() { TRACE (test, "CTOR FixedDummy() --> this=%p val=%d", this, getVal()); } ~FixedDummy() { TRACE (test, "DTOR ~FixedDummy() this=%p val=%d", this, getVal()); } friend void transfer_control (FixedDummy& from, FixedDummy& to) { TRACE (test, "TRANSFER target=%p <-- source=%p (%d,%d)", &to,&from, to.getVal(),from.getVal()); if (throw_in_transfer) throw to.getVal(); swap (from,to); from.setVal(0); // remove the old Dummy from accounting (checksum) } }; typedef ScopedHolder HolderD; typedef ScopedPtrHolder PtrHolderD; template struct Table { typedef Allocator_TransferNoncopyable Allo; typedef typename std::vector Type; }; }//(End) test helpers /********************************************************************************** * @test growing a vector containing noncopyable objects wrapped into ScopedHolder * instances. This requires the use of a custom allocator, invoking a * \c transfer_control() function to be provided for the concrete * noncopyable class type, being invoked when the vector * needs to reallocate. */ class ScopedHolderTransfer_test : public Test { virtual void run (Arg) { cout << "checking ScopedHolder...\n"; buildVector(); growVector(); checkErrorHandling(); cout << "checking ScopedPtrHolder...\n"; buildVector(); growVector(); checkErrorHandling(); } void create_contained_object (HolderD& holder) { holder.create(); } void create_contained_object (PtrHolderD& holder) { holder.reset(new FixedDummy()); } template void buildVector() { CHECK (0==checksum); { typedef typename Table::Type Vect; Vect table(50); CHECK (0==checksum); for (uint i=0; i<10; ++i) create_contained_object (table[i]); CHECK (0 < checksum); CHECK ( table[9]); CHECK (!table[10]); Dummy *rawP = table[5].get(); CHECK (rawP); CHECK (table[5]); CHECK (rawP == &(*table[5])); CHECK (rawP->add(-555) == table[5]->add(-555)); } CHECK (0==checksum); } template void growVector() { CHECK (0==checksum); { typedef typename Table::Type Vect; Vect table; table.reserve(2); CHECK (0==checksum); cout << ".\n..install one element at index[0]\n"; table.push_back(HO()); CHECK (0==checksum); create_contained_object (table[0]); // switches into "managed" state CHECK (0 < checksum); int theSum = checksum; cout << ".\n..*** resize table to 16 elements\n"; for (uint i=0; i<15; ++i) table.push_back(HO()); CHECK (theSum==checksum); } CHECK (0==checksum); } template void checkErrorHandling() { CHECK (0==checksum); { typedef typename Table::Type Vect; Vect table(5); table.reserve(5); CHECK (0==checksum); create_contained_object (table[2]); create_contained_object (table[4]); CHECK (0 < checksum); int theSum = checksum; cout << ".\n.throw some exceptions...\n"; throw_in_ctor = true; try { create_contained_object (table[3]); NOTREACHED (); } catch (int val) { CHECK (theSum < checksum); checksum -= val; CHECK (theSum==checksum); } CHECK ( table[2]); CHECK (!table[3]); // not created because of exception CHECK ( table[4]); throw_in_ctor = false; throw_in_transfer=true; // can do this only when using ScopedHolder try { table.resize(10); } catch (int val) { CHECK ( table.size() < 10); } CHECK (theSum == checksum); throw_in_transfer=false; } CHECK (0==checksum); } }; LAUNCHER (ScopedHolderTransfer_test, "unit common"); }} // namespace lib::test