From 45ed4b426407d78bc0aaccee4e1eab113859a0a0 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 6 Sep 2007 22:13:26 +0200 Subject: [PATCH] extracted Singleton pattern into a separate Template. I prefer this approach, so I can ignore threadsafety for the moment and add it later just by switching policy --- src/common/cmdline.cpp | 2 +- src/common/singleton.cpp | 102 ++++++++++++++++ src/common/singleton.hpp | 76 ++++++++++++ src/common/singletonpolicies.hpp | 141 ++++++++++++++++++++++ src/common/util.hpp | 14 +++ tests/components/common/singletontest.cpp | 133 ++++++++++++++++++++ tests/components/common/testtargetobj.hpp | 2 +- 7 files changed, 468 insertions(+), 2 deletions(-) create mode 100644 src/common/singleton.cpp create mode 100644 src/common/singleton.hpp create mode 100644 src/common/singletonpolicies.hpp create mode 100644 tests/components/common/singletontest.cpp diff --git a/src/common/cmdline.cpp b/src/common/cmdline.cpp index 4ab1b5131..49b3585ac 100644 --- a/src/common/cmdline.cpp +++ b/src/common/cmdline.cpp @@ -82,4 +82,4 @@ namespace util -} // namespace cinelerra +} // namespace util diff --git a/src/common/singleton.cpp b/src/common/singleton.cpp new file mode 100644 index 000000000..8046504ed --- /dev/null +++ b/src/common/singleton.cpp @@ -0,0 +1,102 @@ +/* + Singleton - template for implementing the singleton pattern + + Copyright (C) CinelerraCV + 2007, Christian Thaeter + + 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. + +==================================================================== +This code is heavily inspired by + The Loki Library (loki-lib/trunk/include/loki/Singleton.h) + Copyright (c) 2001 by Andrei Alexandrescu + This Loki code accompanies the book: + Alexandrescu, Andrei. "Modern C++ Design: + Generic Programming and Design Patterns Applied". + Copyright (c) 2001. Addison-Wesley. ISBN 0201704315 + +* *****************************************************/ + + + +#include "common/singleton.hpp" +#include "common/util.hpp" +#include "nobugcfg.h" + +namespace cinelerra + { + + /** Interface to be used by Singleton's clients. + * Manages internally the instance creation, lifecycle + * and access handling in a multithreaded context. + * @return "the" single instance of class S + */ + template + < class SI, // the class to make Singleton + template class Create, // how to create/destroy the instance + template class Life, // how to manage Singleton Lifecycle + template class Threading + > + SI& + Singleton::instance() + { + if (!pInstance_) + { + ThreadLock guard; + if (!pInstance_) + { + if (isDead_) + { + Life::onDeadReference(); + isDead_ = false; + } + pInstance_ = Create::create(); + Life::scheduleDelete (&destroy); + } } + ENSURE (pInstance_); + ENSURE (!isDead_); + return *pInstance_; + } + + + /** @internal helper used to delegate destroying the single instance + * to the Create policy, at the same time allowing the Life policy + * to control the point in the Application lifecycle when the + * destruction of this instance occures. + */ + template + < class SI, + template class Create, + template class Life, + template class Threading + > + void + Singleton::destroy() + { + REQUIRE (!isDead_); + Create::destroy (pInstance_); + pInstance_ = 0; + isDead_ = true; + } + + + + + namespace singleton + { + + } // namespace singleton + +} // namespace cinelerra diff --git a/src/common/singleton.hpp b/src/common/singleton.hpp new file mode 100644 index 000000000..ce9af67e1 --- /dev/null +++ b/src/common/singleton.hpp @@ -0,0 +1,76 @@ +/* + SINGLETON.hpp - template for implementing the singleton pattern + + Copyright (C) CinelerraCV + 2007, Christian Thaeter + + 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. + +==================================================================== +This code is heavily inspired by + The Loki Library (loki-lib/trunk/include/loki/Singleton.h) + Copyright (c) 2001 by Andrei Alexandrescu + This Loki code accompanies the book: + Alexandrescu, Andrei. "Modern C++ Design: Generic Programming + and Design Patterns Applied". + Copyright (c) 2001. Addison-Wesley. ISBN 0201704315 + +*/ + + + +#ifndef CINELERRA_SINGLETON_H +#define CINELERRA_SINGLETON_H + + +#include "common/singletonpolicies.hpp" ///< several Policies usable together with singleton + + + +namespace cinelerra + { + + /** + * A configurable Template for implementing Singletons + */ + template + < class S, // the class to make Singleton + template class Create = singleton::Static, // how to create/destroy the instance + template class Life = singleton::Automatic, // how to manage Singleton Lifecycle + template class Threading = singleton::IgnoreThreadsafety //TODO use Multithreaded!!! + > + class Singleton + { + public: + static S& instance(); + + private: + typedef Threading::VolatileType SType; + typedef Threading::Lock ThreadLock; + static SType* pInstance_; + static bool isDead_; + + protected: + Singleton () { } + Singleton (const Singleton&) { } + Singleton& operator= (const Singleton&) { return *this; } + + private: + static void destroy(); + }; + + +} // namespace cinelerra +#endif diff --git a/src/common/singletonpolicies.hpp b/src/common/singletonpolicies.hpp new file mode 100644 index 000000000..d4b414b38 --- /dev/null +++ b/src/common/singletonpolicies.hpp @@ -0,0 +1,141 @@ +/* + SINGLETONPOLICIES.hpp - how to manage creation, lifecycle and multithreading + + Copyright (C) CinelerraCV + 2007, Christian Thaeter + + 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. + +==================================================================== +This code is heavily inspired by + The Loki Library (loki-lib/trunk/include/loki/Singleton.h) + Copyright (c) 2001 by Andrei Alexandrescu + This Loki code accompanies the book: + Alexandrescu, Andrei. "Modern C++ Design: Generic Programming + and Design Patterns Applied". + Copyright (c) 2001. Addison-Wesley. ISBN 0201704315 + +*/ + + + +#ifndef CINELERRA_SINGLETON_H +#define CINELERRA_SINGLETON_H + +#include "common/error.hpp" + + + +namespace cinelerra + { + namespace singleton + { + /* == several Policies usable in conjunction with cinelerra::Singleton == */ + + /** + * Policy for creating the Singleton instance statically + */ + template + struct Static + { + static S* create () + { +#ifdef DEBUG + static uint callCount (0); + ASSERT ( 0 == callCount++ ); +#endif + static S _theSingle_; + return &_theSingle_; + } + static void destroy (S*) + { + S->~S(); + } + }; + + + /** + * Policy for creating the Singleton instance heap allocated + */ + template + struct Heap + { + static S* create () { return new S; } + static void destroy (S* pS) { delete pS; } + }; + + + /** + * Policy relying on the compiler/runtime system for Singleton Lifecycle + */ + template + struct Automatic + { + /** implements the Singleton removal by calling + * the provided deleter function at application shutdown, + * relying on the runtime system calling destructors of + * static objects + */ + static void scheduleDelete (void (*deleter) (void)) + { + struct DeleteTrigger + { + ~DeleteTrigger() { *deleter (); } + }; + static DeleteTrigger trigger; + REQUIRE (deleter); + } + + static void onDeadReference () + { + throw error::Logic ("Trying to access the a Singleton instance that has " + "already been released or finished its lifecycle."); + } + }; + + + + /** + * Policy for handling multithreaded access to the singleton instance + * @todo actually implement this policy using the cinelerra databackend. + */ + template + struct Multithreaded + { + typedef volatile S* VolatileType; + class Lock + { + public: + Lock() { UNIMPLEMENTED ("aquire Thread Lock"); } + ~Lock() { UNIMPLEMENTED ("release Thread Lock"); } + }; + }; + + + /** + * Policy just ignoring thread safety + */ + template + struct IgnoreThreadsafety + { + typedef S VolatileType; + struct Lock {}; + }; + + + } // namespace singleton + +} // namespace cinelerra +#endif diff --git a/src/common/util.hpp b/src/common/util.hpp index a9a90e9b0..d66222002 100644 --- a/src/common/util.hpp +++ b/src/common/util.hpp @@ -27,6 +27,8 @@ #include #include +#include "nobugcfg.h" ///////////////////TODO: just temporarily!!!! + namespace util { @@ -80,6 +82,18 @@ namespace util } + + /** produce an identifier based on the given string. + * remove non-standard-chars, reduce punctuation to underscores + */ + string + sanitize (const string& org) + { + UNIMPLEMENTED ("sanitize String"); + return org; ///////////////////////////TODO + } + + } // namespace util /* some common macro definitions */ diff --git a/tests/components/common/singletontest.cpp b/tests/components/common/singletontest.cpp new file mode 100644 index 000000000..a146c9398 --- /dev/null +++ b/tests/components/common/singletontest.cpp @@ -0,0 +1,133 @@ +/* + Singleton(Test) - unittest for our Singleton template + + Copyright (C) CinelerraCV + 2007, Christian Thaeter + + 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 "common/testtargetobj.hpp" + +#include "common/test/run.hpp" +#include "common/singleton.hpp" +#include "common/util.hpp" +#include "nobugcfg.h" + +#include +#include + +using boost::lexical_cast; +using util::isnil; +using std::string; +using std::cout; + + +namespace cinelerra + { + namespace test + { + + class ObjFactory; + + + /** + * Target object to be instantiated as Singleton + * Allocates a variable amount of additional heap memory + * and prints diagnostic messages. + */ + class TargetObj : public TestTargetObj + { + public: + static int cnt = 0; + static void setCountParam (uint c) { TargetObj::cnt = c; } + protected: + TargetObj () : TestTargetObj(cnt) {} + }; + + + + + + + + + /******************************************************************* + * @test implement a Singleton class using our Singleton Template. + * Expected results: no memory leaks. + * @see cinelerra::Singleton + * @see cinelerra::singleton::Static + * @see cinelerra::singleton::Heap + */ + class Singleton_test : public Test + { + typedef TargetObj& (*InstanceAccessFunc) (void); + InstanceAccessFunc instance; + + virtual void run(Arg arg) + { + uint num= isnil(arg)? 1 : lexical_cast(arg[1]); + TargetObj::setCountParam(num); + + testStaticallyAllocatedSingleton (); + testHeapAllocatedSingleton (); + } + + + /** @test parametrize the Singleton creation such as to create + * the single TargetObj instance as a static variable. + */ + void testStaticallyAllocatedSingleton () + { + instance = &Singleton::instance; + useInstance (); + } + + /** @test parametrize the Singleton creation such as to create + * the single TargetObj instance allocated on the Heap + * and deleted automatically at application shutdown. + */ + void testHeapAllocatedSingleton () + { + instance = &Singleton::instance; + useInstance (); + } + + + + void useInstance () + { + TargetObj& t1 = instance(); + TargetObj& t2 = instance(); + + ASSERT ( &t1 == &t2, "not a Singleton, got two different instances." ); + + cout << "calling a non-static method on the Singleton instance\n" + << string (t1) << "\n"; + } + }; + + + + /** Register this test class... */ + LAUNCHER (Singleton_test, "unit common"); + + + + } // namespace test + +} // namespace cinelerra diff --git a/tests/components/common/testtargetobj.hpp b/tests/components/common/testtargetobj.hpp index 20667cf92..a51ab1ceb 100644 --- a/tests/components/common/testtargetobj.hpp +++ b/tests/components/common/testtargetobj.hpp @@ -46,7 +46,7 @@ namespace cinelerra namespace test { /** - * Target object to be created by the Test-Factory. + * Target object to be created by Test-Factories or as Singleton. * Allocates a variable amount of additional heap memory * and prints diagnostic messages. */