diff --git a/src/lib/del-stash.hpp b/src/lib/del-stash.hpp new file mode 100644 index 000000000..da26c13f0 --- /dev/null +++ b/src/lib/del-stash.hpp @@ -0,0 +1,146 @@ +/* + DEL-STASH.hpp - collect and execute deleter functions + + Copyright (C) Lumiera.org + 2010, 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. + +*/ + + +/** @file del-stash.hpp + ** Collecting and finally triggering deleter functions. + ** This building block for custom memory management allows memorising how to kill an object. + ** Frequently, custom allocation schemes have to deal with type erased elements, where the + ** full typed context is only available during construction. When implementing these objects + ** without vtable, we need a reliable way of recalling the correct destructor to invoke. + ** Typically, such entry objects are to be de-allocated in bulk during shutdown, with + ** the possibility to deallocate some objects beforehand explicitly. + ** + ** The implementation is based on using a vector in a stack-like fashion, thus the + ** deallocation of individual objects might degenerate in performance. + ** + ** @see DelStash_test + ** @see AdviceSystem usage example + ** + */ + + + +#ifndef LIB_DEL_STASH_H +#define LIB_DEL_STASH_H + + +#include "lib/error.hpp" + +//#include +//#include /////TODO better push the hash implementation into a cpp file (and btw, do it more seriously!) + +//#include +//#include +#include + + +namespace lib { + +// using boost::hash_value; + + + /** + * Manage a collection of deleter functions. + * This component can memorise addresses and deleter functions + * and trigger deletion of single objects, or delete all objects + * on demand or automatically on shutdown. + */ + class DelStash + : boost::noncopyable + { + + public: + DelStash (size_t elms_to_reserve =0) + { + if (elms_to_reserve) + { + // + } + } + + ~DelStash () + { + try { killAll(); } + + catch(...) + { + Symbol errID = lumiera_error(); + WARN (memory, "Problems on de-allocation: %s", errID.c()); + } + } + + size_t + size () const + { + UNIMPLEMENTED ("killer size"); + } + + + template + void + manage (TY* obj) + { + UNIMPLEMENTED ("accept typed ptr for later killing"); + } + + template + void + manage (TY& obj) + { + UNIMPLEMENTED ("accept typed obj ref for later killing"); + } + + template + void + manage (void *obj) + { + UNIMPLEMENTED ("accept object by void* and type information"); + } + + + template + void + kill (TY* obj) + { + UNIMPLEMENTED ("pick and kill object denoted by address"); + } + + template + void + kill (TY& obj) + { + UNIMPLEMENTED ("pick and kill object denoted by reference"); + } + + void + killAll () + { + UNIMPLEMENTED ("mass kill"); + } + }; + + + + +} // namespace lib +#endif diff --git a/tests/40components.tests b/tests/40components.tests index 174fc20d2..d729cc964 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -226,6 +226,11 @@ return: 0 END +PLANNED "Deleter function collection" DelStash_test < : Yes out: HasNested_Core : No diff --git a/tests/lib/del-stash-test.cpp b/tests/lib/del-stash-test.cpp new file mode 100644 index 000000000..3fb9002cf --- /dev/null +++ b/tests/lib/del-stash-test.cpp @@ -0,0 +1,207 @@ +/* + DelStash(Test) - verify a facility to memorise and trigger deleter functions + + Copyright (C) Lumiera.org + 2010, 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/del-stash.hpp" + +#include +#include + + + +namespace lib { +namespace test{ + + using std::tr1::function; + using std::rand; + + + + namespace { // probe victims + + ulong MAX_MASS = 200; // number of victims for mass kill + + ulong checksum = 0; + + + template + class Probe + { + uint mySiz_; + char myCrap_[siz]; + + public: + Probe() + : mySiz_(siz) + { + REQUIRE (siz); + for (uint i=0; i + Probe* + makeViktim () + { + return new Probe(); + } + + }//(End) test data + + + + + /**************************************************************************** + * @test create a bunch of objects with varying type and size, memorising + * how to kill them properly. Verify everyone is dead after mass-kill. + * + * @see lib::DelStash + */ + class DelStash_test : public Test + { + + virtual void + run (Arg) + { + checksum = 0; + checkSingleKill(); + checkMassKill(); + checkAutoKill(); + } + + + void + checkSingleKill () + { + DelStash killer; + CHECK (0 == killer.size()); + + killer.manage (NULL); + CHECK (0 == killer.size()); + + Probe<5> *p = makeViktim<5>(); + Probe<7> &r = *makeViktim<7>(); + void *v = makeViktim<9>(); + CHECK (0 < checksum); + + killer.manage (p); + killer.manage (r); + killer.manage > (v); + + CHECK (3 == killer.size()); + + killer.kill (r); + CHECK (2 == killer.size()); + + killer.kill (p); + CHECK (1 == killer.size()); + + killer.kill (p); // ignores spurious kill requests + CHECK (1 == killer.size()); + + killer.kill (v); + CHECK (0 == killer.size()); + CHECK (0 == checksum); + } + + + void + feedViktims (DelStash& killer) + { + function builder[5]; + builder[0] = makeViktim<12>; + builder[1] = makeViktim<23>; + builder[2] = makeViktim<34>; + builder[3] = makeViktim<45>; + builder[4] = makeViktim<56>; + + for (uint i=1; i <= MAX_MASS; ++i) + killer.manage (builder[i % 5]()); + } + + + void + checkMassKill () + { + DelStash killer; + CHECK (0 == killer.size()); + + CHECK (0 == checksum); + CHECK (0 == killer.size()); + + feedViktims (killer); + CHECK (MAX_MASS == killer.size()); + + killer.killAll(); + CHECK (0 == killer.size()); + CHECK (0 == checksum); + } + + + void + checkAutoKill() + { + { + DelStash killer; + CHECK (0 == killer.size()); + CHECK (0 == checksum); + + feedViktims (killer); + void * individuum = makeViktim<444>(); + killer.manage (individuum); + feedViktims (killer); + killer.manage (makeViktim<5555>()); + feedViktims (killer); + + CHECK (3*MAX_MASS + 2 == killer.size()); + + killer.kill(individuum); + CHECK (3*MAX_MASS + 1 == killer.size()); + + CHECK (0 < checksum); + }// killer going out of scope... + + CHECK (0 == checksum); + } + }; + + + /** Register this test class... */ + LAUNCHER (DelStash_test, "unit common"); + + +}} // namespace lib::test