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:
Fischlurch 2007-09-06 22:13:26 +02:00
parent 39cd8bb121
commit 45ed4b4264
7 changed files with 468 additions and 2 deletions

View file

@ -82,4 +82,4 @@ namespace util
} // namespace cinelerra
} // namespace util

102
src/common/singleton.cpp Normal file
View 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
View 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

View 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

View file

@ -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 */

View 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

View file

@ -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.
*/