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
This commit is contained in:
parent
39cd8bb121
commit
45ed4b4264
7 changed files with 468 additions and 2 deletions
|
|
@ -82,4 +82,4 @@ namespace util
|
|||
|
||||
|
||||
|
||||
} // namespace cinelerra
|
||||
} // namespace util
|
||||
|
|
|
|||
102
src/common/singleton.cpp
Normal file
102
src/common/singleton.cpp
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
Singleton - template for implementing the singleton pattern
|
||||
|
||||
Copyright (C) CinelerraCV
|
||||
2007, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
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> class Create, // how to create/destroy the instance
|
||||
template <class> class Life, // how to manage Singleton Lifecycle
|
||||
template <class> class Threading
|
||||
>
|
||||
SI&
|
||||
Singleton<SI,Create,Life,Threading>::instance()
|
||||
{
|
||||
if (!pInstance_)
|
||||
{
|
||||
ThreadLock guard;
|
||||
if (!pInstance_)
|
||||
{
|
||||
if (isDead_)
|
||||
{
|
||||
Life<SI>::onDeadReference();
|
||||
isDead_ = false;
|
||||
}
|
||||
pInstance_ = Create<SI>::create();
|
||||
Life<SI>::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> class Create,
|
||||
template <class> class Life,
|
||||
template <class> class Threading
|
||||
>
|
||||
void
|
||||
Singleton<SI,Create,Life,Threading>::destroy()
|
||||
{
|
||||
REQUIRE (!isDead_);
|
||||
Create<SI>::destroy (pInstance_);
|
||||
pInstance_ = 0;
|
||||
isDead_ = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
namespace singleton
|
||||
{
|
||||
|
||||
} // namespace singleton
|
||||
|
||||
} // namespace cinelerra
|
||||
76
src/common/singleton.hpp
Normal file
76
src/common/singleton.hpp
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
SINGLETON.hpp - template for implementing the singleton pattern
|
||||
|
||||
Copyright (C) CinelerraCV
|
||||
2007, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
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> class Create = singleton::Static, // how to create/destroy the instance
|
||||
template <class> class Life = singleton::Automatic, // how to manage Singleton Lifecycle
|
||||
template <class> class Threading = singleton::IgnoreThreadsafety //TODO use Multithreaded!!!
|
||||
>
|
||||
class Singleton
|
||||
{
|
||||
public:
|
||||
static S& instance();
|
||||
|
||||
private:
|
||||
typedef Threading<S>::VolatileType SType;
|
||||
typedef Threading<S>::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
|
||||
141
src/common/singletonpolicies.hpp
Normal file
141
src/common/singletonpolicies.hpp
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
SINGLETONPOLICIES.hpp - how to manage creation, lifecycle and multithreading
|
||||
|
||||
Copyright (C) CinelerraCV
|
||||
2007, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
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<class S>
|
||||
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<class S>
|
||||
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<class S>
|
||||
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<class S>
|
||||
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<class S>
|
||||
struct IgnoreThreadsafety
|
||||
{
|
||||
typedef S VolatileType;
|
||||
struct Lock {};
|
||||
};
|
||||
|
||||
|
||||
} // namespace singleton
|
||||
|
||||
} // namespace cinelerra
|
||||
#endif
|
||||
|
|
@ -27,6 +27,8 @@
|
|||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
#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 */
|
||||
|
|
|
|||
133
tests/components/common/singletontest.cpp
Normal file
133
tests/components/common/singletontest.cpp
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
Singleton(Test) - unittest for our Singleton template
|
||||
|
||||
Copyright (C) CinelerraCV
|
||||
2007, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
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 <boost/lexical_cast.hpp>
|
||||
#include <iostream>
|
||||
|
||||
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<uint>(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<TargetObj>::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<TargetObj,singleton::Heap>::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
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in a new issue