Ticket #934: switch entire code-base to use the new Singleton factory

lib::Depend<TY>  works as drop-in replacement for lib::Singleton<TY>

This changeset removes the convoluted special cases like
SingletonSub and MockInjector.
This commit is contained in:
Fischlurch 2013-10-20 03:19:36 +02:00
parent 7b3c68898a
commit 0ea37402d2
63 changed files with 217 additions and 1198 deletions

View file

@ -50,7 +50,7 @@ namespace engine {
/** storage for the Singleton accessor */
lib::Singleton<EngineConfig> EngineConfig::get;
lib::Depend<EngineConfig> EngineConfig::get;
/** build up a new engine configuration set,

View file

@ -32,7 +32,7 @@
#ifdef __cplusplus /* ============== C++ Interface ================= */
#include "lib/time/timevalue.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
namespace backend{
@ -64,14 +64,14 @@ namespace engine {
EngineConfig();
~EngineConfig();
friend class lib::singleton::StaticCreate<EngineConfig>;
friend class lib::DependencyFactory::InstanceHolder<EngineConfig>;
public:
/** access point to the Engine Interface.
* @internal this is an facade interface for internal use
* by the player. Client code should use the Player.
*/
static lib::Singleton<EngineConfig> get;
static lib::Depend<EngineConfig> get;
//////////////////////////////////////////////////////////////////// TODO: find out about required configuration and tweaking values

View file

@ -29,7 +29,7 @@ namespace engine {
/** storage for the (singleton) scheduler access frontend */
lib::Singleton<SchedulerFrontend> SchedulerFrontend::instance;
lib::Depend<SchedulerFrontend> SchedulerFrontend::instance;

View file

@ -26,7 +26,7 @@
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include "lib/time/timevalue.hpp"
#include "backend/engine/job.h"
@ -59,7 +59,7 @@ namespace engine {
* @internal this is an facade interface for internal use
* by the player. Client code should use the Player.
*/
static lib::Singleton<SchedulerFrontend> instance;
static lib::Depend<SchedulerFrontend> instance;
/**

View file

@ -22,7 +22,7 @@
#include "backend/enginefacade.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include <string>
@ -67,7 +67,7 @@ namespace backend {
};
namespace {
lib::Singleton<EngineSubsysDescriptor> theDescriptor;
lib::Depend<EngineSubsysDescriptor> theDescriptor;
}

View file

@ -32,7 +32,7 @@ namespace backend {
/** storage for the SingletonFactory
* (actually a lumiera::test::MockInjector) */
Singleton<MediaAccessFacade> MediaAccessFacade::instance;
lib::Depend<MediaAccessFacade> MediaAccessFacade::instance;

View file

@ -26,7 +26,7 @@
#include "lib/error.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include "lib/time/timevalue.hpp"
#include <string>
@ -57,7 +57,7 @@ namespace backend {
public:
typedef void* ChanHandle;
static Singleton<MediaAccessFacade> instance;
static lib::Depend<MediaAccessFacade> instance;
/** request for testing the denoted files accessibility
* @param name path and filename of the media file.

View file

@ -22,7 +22,7 @@
#include "backend/netnodefacade.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include <string>
@ -66,7 +66,7 @@ namespace backend {
};
namespace {
lib::Singleton<NetNodeSubsysDescriptor> theDescriptor;
lib::Depend<NetNodeSubsysDescriptor> theDescriptor;
}

View file

@ -44,7 +44,7 @@
#include "lib/error.hpp"
//#include "lib/handle.hpp"
#include "lib/time/timevalue.hpp"
//#include "lib/singleton.hpp"
//#include "lib/depend.hpp"
//#include "proc/engine/buffer-provider.hpp"
//#include "lib/iter-source.hpp"
//#include "lib/sync.hpp"

View file

@ -22,7 +22,7 @@
#include "backend/scriptrunnerfacade.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include <string>
@ -67,7 +67,7 @@ namespace backend {
};
namespace {
lib::Singleton<ScriptRunnerSubsysDescriptor> theDescriptor;
lib::Depend<ScriptRunnerSubsysDescriptor> theDescriptor;
}

View file

@ -91,7 +91,7 @@
#include "lib/error.hpp"
#include "lib/del-stash.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include "lib/symbol.hpp"
#include "lib/sync.hpp"
#include "lib/util.hpp"
@ -102,7 +102,6 @@
#include <boost/noncopyable.hpp>
using lib::Symbol;
using lib::Singleton;
using lib::DelStash;
using util::unConst;
@ -254,7 +253,7 @@ namespace advice {
/** hidden implementation-level access to the AdviceSystem */
Singleton<AdviceSystem> aSys;
lib::Depend<AdviceSystem> aSys;
} //(End) AdviceSystem implementation

View file

@ -73,7 +73,7 @@ namespace lumiera {
/** storage for the single system-wide config facade instance */
lib::Singleton<Config> Config::instance;
lib::Depend<Config> Config::instance;
Config::Config ()

View file

@ -25,7 +25,7 @@
#include "include/guinotification-facade.h"
#include "lib/sync.hpp"
#include "lib/error.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include "lib/functor-util.hpp"
#include "common/instancehandle.hpp"
@ -164,7 +164,7 @@ namespace gui {
}
};
lib::Singleton<GuiSubsysDescriptor> theDescriptor;
lib::Depend<GuiSubsysDescriptor> theDescriptor;
} // (End) impl details

View file

@ -26,7 +26,7 @@
#include "gui/workspace/workspace-window.hpp"
#include "gui/controller/controller.hpp"
#include "gui/model/project.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include "lib/symbol.hpp"
#include "include/config-facade.h"
@ -56,7 +56,7 @@ typedef std::vector<uString> UVector;
namespace {
/** storage for the Main Application object */
lib::Singleton<GtkLumiera> theApplicationInstance;
lib::Depend<GtkLumiera> theApplicationInstance;
Literal KEY_TITLE = "Lumiera.title";
Literal KEY_VERSION = "Lumiera.version";

View file

@ -55,7 +55,7 @@
#include "gui/display-service.hpp"
#include "common/subsys.hpp"
#include "backend/thread-wrapper.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
extern "C" {
#include "common/interface.h"

View file

@ -22,7 +22,7 @@
#include "gui/notification-service.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include "include/logging.h"
#include "lib/util.hpp"

View file

@ -44,7 +44,7 @@
#ifdef __cplusplus /* ============== C++ Interface ================= */
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include "lib/symbol.hpp"
#include <string>
@ -67,13 +67,13 @@ namespace lumiera {
public:
static string get (lib::Literal key);
static lib::Singleton<Config> instance;
static lib::Depend<Config> instance;
private:
Config();
~Config();
friend class lib::singleton::StaticCreate<Config>;
friend class lib::DependencyFactory::InstanceHolder<Config>;
};

View file

@ -31,6 +31,49 @@ This code is heavily inspired by
/** @file depend.hpp
** Singleton services and Dependency Injection.
** The <b>Singleton Pattern</b> provides a single access point to a class or
** service and exploits this ubiquitous access point to limit the number of objects
** of this type to a single shared instance. Within Lumiera, we mostly employ a
** factory template for this purpose; the intention is to use on-demand initialisation
** and a standardised lifecycle. In the default configuration, this \c Depend<TY> factory
** maintains a singleton instance of type TY. The possibility to install other factory
** functions allows for subclass creation and various other kinds of service management.
**
**
** \par Why Singletons? Inversion-of-Control and Dependency Injection
**
** Singletons are frequently over-used, and often they serve as disguised
** global variables to support a procedural programming style. As a remedy, typically
** the use of a »Dependency Injection Container« is promoted. And -- again typically --
** these DI containers tend to evolve into heavyweight universal tools and substitute
** the original problem by metadata hell.
**
** Thus, for Lumiera, the choice to use Singletons was deliberate: we understand the
** Inversion-of-Control principle, yet we want to stay just below the level of building
** a central application manager core. At the usage site, we access a factory for some
** service <i>by name</i>, where the »name« is actually the type name of an interface
** or facade. Singleton is used as an implementation of this factory, when the service
** is self-contained and can be brought up lazily.
**
** \par Conventions, Lifecycle and Unit Testing
**
** Usually we place an instance of the singleton factory (or some other kind of factory)
** as a static variable within the interface class describing the service or facade.
** As a rule, everything accessible as Singleton is sufficiently self-contained to come
** up any time -- even prior to \c main(). But at shutdown, any deregistration must be
** done explicitly using a lifecycle hook. Destructors aren't allowed to do any significant
** work besides releasing references, and we acknowledge that singletons can be released
** in \em arbitrary order.
**
** @see Depend
** @see DependencyFactory
** @see singleton-test.cpp
** @see dependency-factory-test.cpp
*/
#ifndef LIB_DEPEND_H
#define LIB_DEPEND_H
@ -49,8 +92,8 @@ namespace lib {
/**
* Access point to singletons and other kinds of dependencies.
* Actually this is a Factory object, which is typically placed into a static field
* of the Singleton (target) class or some otherwise suitable interface.
* Actually this is a Factory object, which is typically placed into a
* static field of the Singleton (target) class or some otherwise suitable interface.
* @note uses static fields internally, so all factory instances share pInstance_
* @remark there is an ongoing discussion regarding the viability of the
* Double Checked Locking pattern, which requires either the context of a clearly defined

View file

@ -59,7 +59,7 @@
#include "lib/error.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include "util.hpp"
#include <tr1/functional>
@ -223,9 +223,9 @@ namespace lib {
*/
template<class IMP>
class Singleton
: lib::Singleton<IMP>
: lib::Depend<IMP>
{
typedef lib::Singleton<IMP> SingFac;
typedef lib::Depend<IMP> SingFac;
Creator
createSingleton_accessFunction()

View file

@ -1,143 +0,0 @@
/*
SINGLETON-FACTORY.hpp - template for implementing the singleton pattern
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
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
Loki code accompanies the book:
Alexandrescu, Andrei. "Modern C++ Design: Generic Programming
and Design Patterns Applied".
Copyright (c) 2001. Addison-Wesley. ISBN 0201704315
*/
#ifndef LIB_SINGLETON_FACTORY_H
#define LIB_SINGLETON_FACTORY_H
#include "lib/singleton-policies.hpp" // several Policies usable together with SingletonFactory
#include "lib/nobug-init.hpp"
#include "lib/sync-classlock.hpp"
namespace lib {
/**
* A configurable Template for implementing Singletons.
* Actually this is a Factory object, which could be placed into a static field
* of the Singleton (target) class or used directly.
* @note internally uses static fields, so all factory instances share pInstance_
* @note there is an ongoing discussion regarding Double Checked Locking pattern,
* which in this case boils down to the question: does \c pthread_mutex_lock/unlock
* constitute a memory barrier, such as to force any memory writes done within
* the singleton ctor to be flushed and visible to other threads when releasing
* the lock? To my understanding, the answer is yes. See
* http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap04.html#tag_04_10
* @param SI the class of the Singleton instance
* @param Create policy defining how to create/destroy the instance
* @param Life policy defining how to manage Singleton Lifecycle
*/
template
< class SI
, template <class> class Create = singleton::StaticCreate
, template <class> class Life = singleton::AutoDestroy
>
class SingletonFactory
{
typedef lib::ClassLock<SI> ThreadLock;
static SI* volatile pInstance_;
static bool isDead_;
public:
/** Interface to be used by SingletonFactory's clients.
* Manages internally the instance creation, lifecycle
* and access handling in a multithreaded context.
* @return "the" single instance of class S
*/
SI& operator() ()
{
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_;
}
private:
/** @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 occurs.
*/
static void destroy()
{
REQUIRE (!isDead_);
Create<SI>::destroy (pInstance_);
pInstance_ = 0;
isDead_ = true;
}
};
// Storage for SingletonFactory's static fields...
template
< class SI,
template <class> class C,
template <class> class L
>
SI* volatile SingletonFactory<SI,C,L>::pInstance_;
template
< class SI,
template <class> class C,
template <class> class L
>
bool SingletonFactory<SI,C,L>::isDead_;
///// Question: can we get rid of the static fields?
///// this is tricky because of invoking the destructors. If we rely on instance vars,
///// the object may already have been released when the runtime system calls the
///// destructors of static objects at shutdown.
///// It seems this would either cost us much of the flexibility or get complicated
///// to a point where we could as well implement our own Dependency Injection Manager.
///// But the whole point of my pervasive use of this singleton template is to remain
///// below this borderline of integration ("IoC yes, but avoid DI").
} // namespace lib
#endif

View file

@ -1,141 +0,0 @@
/*
SINGLETON-POLICIES.hpp - how to manage creation, lifecycle and multithreading
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
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
Loki code accompanies the book:
Alexandrescu, Andrei. "Modern C++ Design: Generic Programming
and Design Patterns Applied".
Copyright (c) 2001. Addison-Wesley. ISBN 0201704315
*/
#ifndef LIB_SINGLETON_POLICIES_H
#define LIB_SINGLETON_POLICIES_H
#include "lib/nobug-init.hpp"
#include "lib/error.hpp"
#include <vector>
namespace lib {
namespace singleton {
/* === several Policies usable in conjunction with lib::Singleton === */
/**
* Policy to place the Singleton instance into a statically allocated buffer
*/
template<class S>
class StaticCreate
{
public:
static S* create ()
{
#if NOBUG_MODE_ALPHA
static uint callCount = 0;
ASSERT ( 0 == callCount++ );
#endif
static char buff[sizeof(S)];
return new(buff) S();
}
static void destroy (S* pSi)
{
pSi-> ~S();
}
};
/**
* Policy for creating the Singleton instance heap allocated
*/
template<class S>
class HeapCreate
{
public:
static S* create () { return new S; }
static void destroy (S* pS) { delete pS; }
};
typedef void (*DelFunc)(void);
using std::vector;
/**
* Policy relying on the compiler/runtime system for Singleton Lifecycle
*/
template<class S>
class AutoDestroy
{
class DeleteTrigger
{
vector<DelFunc> dels_;
public:
void schedule (DelFunc del)
{
dels_.push_back(del);
}
~DeleteTrigger()
{
vector<DelFunc>::iterator del = dels_.begin();
for ( ; del != dels_.end(); ++del )
(*del)(); // invoke deleter function
}
};
public:
/** implements the Singleton removal by calling
* the provided deleter function(s) at application shutdown,
* relying on the runtime system to call destructors of static
* objects. Because this Policy class can be shared between
* several Singletons, we need to memorise all registered
* deleter functions for calling them at shutdown.
*/
static void
scheduleDelete (DelFunc kill_the_singleton)
{
REQUIRE (kill_the_singleton);
static DeleteTrigger finally;
finally.schedule (kill_the_singleton);
}
static void
onDeadReference ()
{
throw lumiera::error::Logic ("Trying to access a Singleton instance that has "
"already been released or finished its lifecycle.");
}
};
}} // namespace lib::singleton
#endif

View file

@ -1,121 +0,0 @@
/*
SINGLETON-PRECONFIGURE - declare the configuration of some Singleton types in advance
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
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 singleton-preconfigure.hpp
** Pre-configuration of some Singleton types, done by template specialisation.
** Typically the client code just includes singleton.h and uses the Singleton
** type. But in some cases, we want to configure specific (dependency injection)
** behaviour at a central location. At some point, we may well have a full blown
** Dependency Manager, but for the moment using just some specialised Singleton
** type for some instances seems sufficient.
**
** One reason why one wants special Singleton behaviour is testing: Without
** altering the executable, for running some tests we need to inject a Test Mock
** in place of some service object, so we can verify the behaviour of the code
** <i>using</i> this service. For this, we mix lumiera::test::MockInjector
** into the actual Singleton type.
**
** @note we declare the specialisations into the target namespace
**
** @see SingletonFactory
** @see SingletonTestMock_test
*/
#ifndef LIB_SINGLETON_PRECONFIGURE_H
#define LIB_SINGLETON_PRECONFIGURE_H
#include "lib/test/mock-injector.hpp"
namespace lib {
/**
* Default Singleton configuration
* @note all Policy template parameters taking default values
*/
template <class SI>
class Singleton
: public SingletonFactory<SI>
{ }
;
/* ********************************************************************** */
/* Forward declarations of all Classes we want to specialise the template */
/* ********************************************************************** */
namespace test {
class TestSingletonO;
using lib::Singleton;
} // namespace test
} // namespace lumiera
namespace backend {
class MediaAccessFacade;
using lib::Singleton;
} // namespace backend
namespace proc {
namespace engine {
class EngineService;
using lib::Singleton;
}}
/* ************************** */
/* Specialisation Definitions */
/* ************************** */
namespace lib {
using test::MockInjector;
template<>
class Singleton<test::TestSingletonO>
: public MockInjector<test::TestSingletonO>
{ };
template<>
class Singleton<backend::MediaAccessFacade>
: public MockInjector<backend::MediaAccessFacade>
{ };
template<>
class Singleton<proc::engine::EngineService>
: public MockInjector<proc::engine::EngineService>
{ };
} // namespace lib
#endif

View file

@ -1,177 +0,0 @@
/*
SINGLETON-SUBCLASS.hpp - variant of the singleton (factory) creating a subclass
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
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 singleton-subclass.hpp
** Specialised SingletonFactory creating subclasses of the nominal type.
** The rationale is to be able to defer the decision what type to create
** down to the point where the singleton factory is actually created.
** Thus the code using the singleton need not know the implementation
** class, but nevertheless gets an non-virtual access function to the
** singleton instance (which can be inlined), and the compiler is
** still able to spot type errors. Maybe someone knows a less
** contrived solution fulfilling the same criteria....?
**
** @see configrules.cpp usage example
** @see SingletonSubclass_test
*/
#ifndef LIB_SINGLETON_SUBCLASS_H
#define LIB_SINGLETON_SUBCLASS_H
#include "lib/singleton.hpp"
#include <boost/scoped_ptr.hpp>
#include <typeinfo>
namespace lib {
using boost::scoped_ptr;
namespace singleton {
/**
* Helper template to use the general policy classes of the lib::Singleton,
* but change the way they are parametrised on-the-fly.
*/
template<template<class> class POL, class I>
struct Adapter
{
struct Link
{
virtual ~Link() {}
virtual I* create () = 0; ///< @note compiler will check if the actual type is assignable...
virtual void destroy (I* pSi) = 0;
};
template<class S>
struct TypedLink : Link
{
virtual S* create () { return POL<S>::create (); } // covariance checked!
virtual void destroy (I* pSi) { POL<S>::destroy (static_cast<S*> (pSi)); }
};
struct My_scoped_ptr : scoped_ptr<Link> ///< implementation detail: defeat static initialisation
{
using scoped_ptr<Link>::get;
My_scoped_ptr() : scoped_ptr<Link> (get()? get() : 0) {} ///< bypass if already configured
};
/** we configure this link \e later, when the singleton factory
* is actually created, to point at the desired implementation subclass.
*/
static My_scoped_ptr link;
/** Forwarding Template used to configure the basic SingletonFactory */
template<class II>
struct Adapted
{
static II* create () { return link->create (); }
static void destroy (II* pSi) { link->destroy (pSi); }
};
};
template<template<class> class A, class I>
typename Adapter<A,I>::My_scoped_ptr Adapter<A,I>::link; // note: use special ctor (due to static init order!)
/** type-information used to configure the factory instance
* with the concrete implementation type to be created. */
template<class SU>
struct UseSubclass
{ };
} // namespace singleton
/**
* Special variant of the SingletonFactory with the option of actually creating
* a subclass or wrap the product in some way. For the user code, it should behave
* exactly like the standard SingletonFactory. The configuration of the product
* actually to be created is delayed until the ctor call, so it can be hidden
* away to the implementation of a class using the SingletonFactory.
*
* @see configrules.cpp usage example
*/
template
< class SI // the class to use as Interface for the Singleton
, template <class> class Create = singleton::StaticCreate // how to create/destroy the instance
, template <class> class Life = singleton::AutoDestroy // how to manage Singleton Lifecycle
>
class SingletonSubclassFactory
: public SingletonFactory< SI
, singleton::Adapter<Create,SI>::template Adapted
, Life
>
{
public:
/** The singleton-factory ctor configures what concrete type to create.
* It takes type information passed as dummy parameter and installs
* a trampoline object in the static field of class Adapter to perform
* the necessary up/downcasts. This allows to use whatever policy
* class is desired, but parametrises this policy template with
* the concrete type to be created. (only the "create" policy
* needs to know the actual class, because it allocates storage)
*/
template<class SU>
SingletonSubclassFactory (singleton::UseSubclass<SU>&)
{
typedef typename singleton::Adapter<Create,SI> Adapter;
typedef typename Adapter::template TypedLink<SU> TypedLink;
if (!Adapter::link)
Adapter::link.reset (new TypedLink);
#ifdef DEBUG
else
REQUIRE ( typeid(*Adapter::link) == typeid(new TypedLink),
"If using several instances of the sub-class-creating "
"singleton factory, all *must* be configured to create "
"objects of exactly the same implementation type!");
#endif
}
};
/**
* Default Singleton configuration (subclass creating factory)
* @note all Policy template parameters taking default values
*/
template <class SI>
struct SingletonSub
: public SingletonSubclassFactory<SI>
{
template<typename TY>
SingletonSub (TY ref) : SingletonSubclassFactory<SI>(ref) {}
};
} // namespace lib
#endif

View file

@ -1,83 +0,0 @@
/*
SINGLETON.hpp - configuration header for singleton factory
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
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 singleton.hpp
** Factory for creating Singleton instances.
** The <b>Singleton Pattern</b> provides a single access point to a class or
** service and exploits this ubiquitous access point to limit the number of objects
** of this type to a single shared instance. Within Lumiera, we mostly employ a
** factory template; the intention is to use on-demand initialisation and a
** standardised lifecycle.
**
** This configuration header just pulls in some other implementation headers in
** the right order. The basic class template for creating singletons resides in
** singleton-factory.hpp, besides we need policy classes defining how to create
** the singleton objects and how to manage singleton lifecycle. Finally,
** we want to preconfigure singleton factories for some important facilities;
** e.g. sometimes we want to include a hook for injecting Test Mock instances.
**
** You'll find the default Policies in singleton-factory.hpp and the default
** definition of type lumiera::singleton in singleton-preconfigure.hpp
**
** \par Why Singletons? Inversion-of-Control and Dependency Injection
**
** Singletons are frequently over-used, and often they serve as disguised
** global variables to support a procedural programming style. As a remedy, typically
** the use of a »Dependency Injection Container« is promoted. And -- again typically --
** these DI containers tend to evolve into heavyweight universal tools and substitute
** the original problem by metadata hell.
**
** Thus, for Lumiera, the choice to use Singletons was deliberate: we understand the
** Inversion-of-Control principle, yet we want to stay just below the level of building
** a central application manager core. At the usage site, we access a factory for some
** service <i>by name</i>, where the »name« is actually the type name of an interface
** or facade. Singleton is used as an implementation of this factory, when the service
** is self-contained and can be brought up lazily.
**
** \par Conventions, Lifecycle and Unit Testing
**
** Usually we place an instance of the singleton factory (or some other kind of factory)
** as a static variable within the interface class describing the service or facade.
** As a rule, everything accessible as Singleton is sufficiently self-contained to come
** up any time -- even prior to \c main(). But at shutdown, any deregistration must be
** done explicitly using a lifecycle hook. Destructors aren't allowed to do any significant
** work besides releasing references, and we acknowledge that singletons can be released
** in \em arbitrary order.
**
** @see SingletonFactory
** @see singleton::StaticCreate
** @see singleton::AutoDestroy
** @see singletontest.hpp
** @see SingletonTestMock_test
*/
#ifndef LIB_SINGLETON_H
#define LIB_SINGLETON_H
#include "lib/singleton-policies.hpp"
#include "lib/singleton-factory.hpp"
#include "lib/singleton-preconfigure.hpp"
#endif

View file

@ -1,248 +0,0 @@
/*
MOCK-INJECTOR.hpp - replacement singleton factory for injecting Test-Mock objects
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
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 mock-injector.hpp
** Support for unit-testing with a mock implementation of some singleton service.
** Using a Singleton to access a global service (instead of using a dependency injection
** framework) has the downside of making unit-tests hard to write. When the code to be
** tested accesses the global service, usually, several further services must be available.
** Usually this (and the lack of flexibility) counts as the main arguments against using
** Singletons. Yet still our current analysis (as of 2011) for Lumiera is that this
** drawback doesn't justify all the overhead of writing our own dependency-injection
** container (given the lack of pre-existing suitable C++ implementations).
**
** lib::test::MockInjector provides a mechanism to overcome this problem. Given
** a Singleton service, it allows to install a subclass of the service interface
** temporarily as a mock implementation. As an additional convenience shortcut,
** the Use4Test template can be used as a scoped variable to automate this process
** of installing and removing the mock service within the call scope of a single test
** method or test object.
**
** \par prerequisites
** The Singleton needs to be managed and accessed through Lumiera's lib::Singleton
** factory. Moreover, an explicit template specialisation to use MockInjector instead
** of the plain lib::SingletonFactory needs to be given globally, for the service interface
** to use. For this template specialisation, a forward declaration of the service is
** sufficient. See singleton-preconfigure.hpp for examples.
**
** The Mock implementation of the service needs to be default constructible and
** assignment compatible to the service interface. Moreover, the mock implementation class
** must expose a typedef \c ServiceInterface pointing to this interface. The instance of
** the mock service implementation will be created in heap memory and managed by a static
** smart-ptr variable; it will be destroyed when leaving the scope marked by Use4Test.
**
** @see SingletonFactory
** @see SingletonTestMock_test
** @see MediaAccessMock_test usage example
*/
#ifndef LUMIERA_TEST_MOCK_INJECTOR_H
#define LUMIERA_TEST_MOCK_INJECTOR_H
#include "lib/singleton-factory.hpp"
#include "lib/meta/duck-detector.hpp"
#include <boost/scoped_ptr.hpp>
#include <boost/noncopyable.hpp>
#include <boost/static_assert.hpp>
#include <boost/utility/enable_if.hpp>
namespace lib {
template <class SI>
class Singleton; // forward decl; see singleton-preconfigure
namespace test{
using boost::scoped_ptr;
/**
* Special SingletonFactory allowing to inject some instance of the Singleton
* class, thus shadowing "the" (default) Singleton instance temporarily.
* This allows installing a Mock Subclass of the Singleton for running tests,
* while the Singleton can be used as usual in production code.
* @note we use the default policies or SingletonFactory
*/
template<class SI>
class MockInjector : public SingletonFactory<SI>
{
static scoped_ptr<SI> mock_;
public:
/** Overwriting the normal Singleton creation Interface
* to return some mock if defined, falling back to the
* default Singleton creation behaviour else.
*/
SI& operator() ()
{
if (mock_)
return *mock_;
else
return SingletonFactory<SI>::operator() ();
}
void injectSubclass (SI* mockobj)
{
TRACE_IF (mockobj, test, "Singleton: installing Mock object");
TRACE_IF (!mockobj, test, "Singleton: removing Mock object");
mock_.reset (mockobj);
}
MockInjector () {};
// MockInjector objects may be copied freely (no object fields)
};
/** embedded static var to hold onto a configured mock implementation */
template<class SI>
scoped_ptr<SI> MockInjector<SI>::mock_;
/** Details of creating and accessing mock instances, *
* especially for services implemented as Singleton. */
namespace mock {
using boost::enable_if;
using lib::meta::Yes_t;
using lib::meta::No_t;
/**
* Metafunction: does the Type in question
* give us a clue about what service interface to use?
*/
template<class MOCK>
class defines_ServiceInterface
{
META_DETECT_NESTED (ServiceInterface);
public:
enum{ value = HasNested_ServiceInterface<MOCK>::value
};
};
/**
* Trait template: getting the types of the
* Service interface and SingletonFactory
*/
template<class IMP, class YES =void>
struct SingletonAccess
{
typedef No_t ServiceInterface;
typedef No_t Factory;
};
template<class IMP>
struct SingletonAccess<IMP, typename enable_if< defines_ServiceInterface<IMP> >::type>
{
typedef typename IMP::ServiceInterface ServiceInterface;
typedef lib::Singleton<ServiceInterface> Factory;
};
/**
* A Metafunction to find out, if a type in question
* is used as Singleton and especially has been configured
* to inject Mock implementations defined as Subclasses.
*/
template<class MOCK>
class is_Singleton_with_MockInjector
{
typedef typename SingletonAccess<MOCK>::ServiceInterface Interface;
typedef typename SingletonAccess<MOCK>::Factory SingletonFactory;
META_DETECT_MEMBER (injectSubclass);
public:
enum{ value = defines_ServiceInterface<MOCK>::value
&& HasMember_injectSubclass<SingletonFactory>::value
};
};
/**
* Policy-Trait: How to access and inject
* a mock service implementation?
*/
template<class MOCK, class YES =void>
struct AccessPoint
{
BOOST_STATIC_ASSERT (is_Singleton_with_MockInjector<MOCK>::value );
}; // Hint: (1) the mock needs a typedef pointing to the ServiceInterface
// (2) prepare the Singleton-Factory for injecting a Mock implementation...
// look into singleton-preconfigure.hpp for examples!
template<class MOCK>
struct AccessPoint<MOCK, typename enable_if< is_Singleton_with_MockInjector<MOCK> >::type>
{
typedef typename SingletonAccess<MOCK>::Factory ServiceAccessPoint;
static void
activateMock()
{
ServiceAccessPoint().injectSubclass (new MOCK());
}
static void
deactivateMock()
{
ServiceAccessPoint().injectSubclass (0);
}
};
}//(End) details of injecting the mock implementation
/**
* Scoped object for installing/deinstalling a mocked service automatically.
* Placing a suitably specialised instance of this template into a local scope
* will inject the corresponding mock installation and remove it when the
* control flow leaves this scope.
* @param MOCK the concrete mock implementation to inject. It needs to
* subclass the service interface and expose a typedef \c ServiceInterace
*/
template<class MOCK>
struct Use4Test
: boost::noncopyable
{
Use4Test()
{
mock::AccessPoint<MOCK>::activateMock();
}
~Use4Test()
{
mock::AccessPoint<MOCK>::deactivateMock();
}
};
}} // namespace lib::test
#endif

View file

@ -28,7 +28,7 @@
#include "lib/error.hpp"
#include "lib/util.hpp"
#include "lib/sync-classlock.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include "lib/util.hpp"
#include <vector>
@ -38,7 +38,7 @@ namespace lib {
namespace visitor {
using lib::ClassLock;
using lib::Singleton;
using lib::Depend;
template<class TOOL> class Tag;
@ -180,7 +180,7 @@ namespace visitor {
public:
static Singleton<Dispatcher<TAR,TOOL> > instance;
static Depend<Dispatcher<TAR,TOOL> > instance;
inline ReturnType
forwardCall (TAR& target, TOOL& tool)
@ -208,7 +208,7 @@ namespace visitor {
/** storage for the dispatcher table(s) */
template<class TAR, class TOOL>
Singleton<Dispatcher<TAR,TOOL> > Dispatcher<TAR,TOOL>::instance;
Depend<Dispatcher<TAR,TOOL> > Dispatcher<TAR,TOOL>::instance;

View file

@ -102,7 +102,7 @@ namespace asset {
clear();
}
friend class lib::singleton::StaticCreate<DB>;
friend class lib::DependencyFactory::InstanceHolder<DB>;
public:

View file

@ -36,7 +36,7 @@ using std::tr1::placeholders::_1;
using boost::format;
using util::for_each;
using lib::Singleton;
using lib::Depend;
using lib::Sync;
@ -84,10 +84,10 @@ namespace asset {
/** get at the system-wide asset manager instance.
* Implemented as singleton.
*/
Singleton<AssetManager> AssetManager::instance;
Depend<AssetManager> AssetManager::instance;
AssetManager::AssetManager ()
: registry (Singleton<asset::DB>() ())
: registry (Depend<asset::DB>() ())
{ }

View file

@ -46,7 +46,7 @@
#include "proc/asset.hpp"
#include "lib/error.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include <cstddef>
@ -74,7 +74,7 @@ namespace asset {
public:
static lib::Singleton<AssetManager> instance;
static lib::Depend<AssetManager> instance;
/** provide the unique ID for given Asset::Ident tuple */
static ID<Asset> getID (const Asset::Ident&);
@ -126,7 +126,7 @@ namespace asset {
AssetManager ();
friend class lib::singleton::StaticCreate<AssetManager>;
friend class lib::DependencyFactory::InstanceHolder<AssetManager>;
};

View file

@ -30,16 +30,10 @@
namespace proc {
namespace {
/** type of the actual ConfigRules implementation to use */
lib::singleton::UseSubclass<proc::mobject::session::query::MockConfigRules> typeinfo;
}
/** Singleton factory instance, parametrised to actual impl. type. */
lib::SingletonSub<ConfigResolver> ConfigResolver::instance (typeinfo);
using lib::buildSingleton;
/** Singleton factory instance, configured with the actual implementation type. */
lib::Depend<ConfigResolver> ConfigResolver::instance (buildSingleton<proc::mobject::session::query::MockConfigRules>());
} // namespace proc

View file

@ -48,7 +48,7 @@
#include "common/query.hpp"
#include "common/config-rules.hpp"
#include "lib/singleton-subclass.hpp"
#include "lib/depend.hpp"
// types for explicit specialisations....
#include "proc/mobject/session/track.hpp"
@ -87,7 +87,7 @@ namespace proc {
{
public:
static lib::SingletonSub<ConfigResolver> instance;
static lib::Depend<ConfigResolver> instance;
};

View file

@ -58,7 +58,7 @@
#define CONTROL_COMMAND_REGISTRY_H
#include "lib/error.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include "lib/sync.hpp"
#include "include/logging.h"
#include "lib/util.hpp"
@ -129,7 +129,7 @@ namespace control {
public:
static lib::Singleton<CommandRegistry> instance;
static lib::Depend<CommandRegistry> instance;
~CommandRegistry()

View file

@ -98,7 +98,7 @@ namespace control {
/** storage for the singleton factory used to access CommandRegistry */
lib::Singleton<CommandRegistry> CommandRegistry::instance;
lib::Depend<CommandRegistry> CommandRegistry::instance;
Command::~Command() { }

View file

@ -53,7 +53,7 @@ namespace control {
}
/** storage for Singleton access */
lib::Singleton<ProcDispatcher> ProcDispatcher::instance;
lib::Depend<ProcDispatcher> ProcDispatcher::instance;

View file

@ -37,7 +37,7 @@
//#include "lib/symbol.hpp"
#include "proc/control/command.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
//#include <tr1/memory>
@ -57,7 +57,7 @@ namespace control {
{
public:
static lib::Singleton<ProcDispatcher> instance;
static lib::Depend<ProcDispatcher> instance;
void activate();
void deactivate();

View file

@ -46,7 +46,7 @@ namespace control {
/** access the system-wide stream type manager instance.
* Implemented as singleton. */
lib::Singleton<STypeManager> STypeManager::instance;
lib::Depend<STypeManager> STypeManager::instance;
void

View file

@ -26,7 +26,7 @@
#include "proc/streamtype.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include <boost/scoped_ptr.hpp>
@ -44,7 +44,7 @@ namespace control {
boost::scoped_ptr<Registry> reg_;
public:
static lib::Singleton<STypeManager> instance;
static lib::Depend<STypeManager> instance;
typedef StreamType::ImplFacade ImplFacade;
@ -79,7 +79,7 @@ namespace control {
STypeManager() ;
~STypeManager();
friend class lib::singleton::StaticCreate<STypeManager>;
friend class lib::DependencyFactory::InstanceHolder<STypeManager>;
/** Lifecycle: reset all type registration information
* to the <i>generic pristine default</i> state. This includes

View file

@ -33,7 +33,7 @@ namespace engine {
/** Storage for the diagnostics frontend */
lib::Singleton<DiagnosticBufferProvider> DiagnosticBufferProvider::diagnostics;
lib::Depend<DiagnosticBufferProvider> DiagnosticBufferProvider::diagnostics;

View file

@ -31,7 +31,7 @@
#include "lib/error.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include "lib/util.hpp"
#include "proc/engine/type-handler.hpp"
#include "proc/engine/buffer-provider.hpp"
@ -63,7 +63,7 @@ namespace engine {
{
boost::scoped_ptr<TrackingHeapBlockProvider> pImpl_;
static lib::Singleton<DiagnosticBufferProvider> diagnostics;
static lib::Depend<DiagnosticBufferProvider> diagnostics;
TrackingHeapBlockProvider& reset();
@ -73,7 +73,7 @@ namespace engine {
DiagnosticBufferProvider();
~DiagnosticBufferProvider();
friend class lib::singleton::StaticCreate<DiagnosticBufferProvider>;
friend class lib::DependencyFactory::InstanceHolder<DiagnosticBufferProvider>;
public:
/** build a new Diagnostic Buffer Provider instance,

View file

@ -48,7 +48,7 @@
//#include "common/instancehandle.hpp"
//#include "lib/singleton-ref.hpp"
//#include "lib/polymorphic-value.hpp"
//#include "lib/singleton.hpp"
//#include "lib/depend.hpp"
//
#include <boost/noncopyable.hpp>
//#include <boost/scoped_ptr.hpp>

View file

@ -54,7 +54,7 @@ namespace engine{
/** storage for the EngineService interface object */
lib::Singleton<EngineService> EngineService::instance;
lib::Depend<EngineService> EngineService::instance;

View file

@ -60,7 +60,7 @@
//#include "common/instancehandle.hpp"
//#include "lib/singleton-ref.hpp"
#include "lib/polymorphic-value.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
//
#include <boost/noncopyable.hpp>
//#include <boost/scoped_ptr.hpp>
@ -136,7 +136,7 @@ namespace engine{
* @internal this is an facade interface for internal use
* by the player. Client code should use the Player.
*/
static lib::Singleton<EngineService> instance;
static lib::Depend<EngineService> instance;
virtual ~EngineService() { }

View file

@ -22,7 +22,7 @@
#include "proc/facade.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include "proc/play/output-director.hpp"
#include <string>
@ -151,9 +151,9 @@ namespace proc {
};
namespace {
lib::Singleton<BuilderSubsysDescriptor> theBuilderDescriptor;
lib::Singleton<SessionSubsysDescriptor> theSessionDescriptor;
lib::Singleton<PlayOutSubsysDescriptor> thePlayOutDescriptor;
lib::Depend<BuilderSubsysDescriptor> theBuilderDescriptor;
lib::Depend<SessionSubsysDescriptor> theSessionDescriptor;
lib::Depend<PlayOutSubsysDescriptor> thePlayOutDescriptor;
}

View file

@ -53,7 +53,7 @@
#include "proc/mobject/mobject-ref.hpp"
#include "common/query/defs-manager.hpp" ////////////////////////////TICKET #643 forward declare this?
#include "lib/ref-array.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include "lib/symbol.hpp"
#include "lib/p.hpp"

View file

@ -283,7 +283,7 @@ namespace session {
{
protected:
MockConfigRules (); ///< to be used only by the singleton factory
friend class lib::singleton::StaticCreate<MockConfigRules>;
friend class lib::DependencyFactory::InstanceHolder<MockConfigRules>;
virtual ~MockConfigRules() {}

View file

@ -28,7 +28,7 @@
#include "proc/mobject/session/scope-query.hpp"
#include "proc/mobject/placement.hpp"
#include "lib/iter-source.hpp" ////////////////////TICKET #493 : the bare interface would be sufficient here
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include <boost/scoped_ptr.hpp>
@ -63,7 +63,7 @@ namespace session {
scoped_ptr<QueryFocusStack> focusStack_;
public:
static lib::Singleton<ScopeLocator> instance;
static lib::Depend<ScopeLocator> instance;
ScopePath& currPath();
ScopePath& pushPath();
@ -94,7 +94,7 @@ namespace session {
protected:
ScopeLocator();
friend class lib::singleton::StaticCreate<ScopeLocator>;
friend class lib::DependencyFactory::InstanceHolder<ScopeLocator>;
private:
lumiera::QueryResolver const& theResolver();

View file

@ -111,7 +111,7 @@ namespace session {
/** Storage holding the single ScopeLocator instance */
lib::Singleton<ScopeLocator> ScopeLocator::instance;
lib::Depend<ScopeLocator> ScopeLocator::instance;
/** @internal the one (and only) access point

View file

@ -47,7 +47,7 @@ namespace session {
scoped_ptr<LifecycleAdvisor> lifecycle_;
SessManagerImpl() throw();
friend class lib::singleton::StaticCreate<SessManagerImpl>;
friend class lib::DependencyFactory::InstanceHolder<SessManagerImpl>;
~SessManagerImpl() ;

View file

@ -37,7 +37,7 @@
//#include "common/query/defs-manager.hpp"
#include "lib/symbol.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
@ -45,7 +45,6 @@ namespace proc {
namespace mobject {
using lib::Symbol;
using lib::Singleton;
using session::SessManager;
using session::SessManagerImpl;
using session::SessionImplAPI;
@ -67,7 +66,7 @@ namespace mobject {
* you use dot-notation, while you access the <i>session object</i>
* via arrow notation (e.g. \code Session::current->getFixture() )
*/
SessManager& Session::current = Singleton<SessManagerImpl>()();
SessManager& Session::current = lib::Depend<SessManagerImpl>()();
/** special access point allowing Proc-Layer internals

View file

@ -24,7 +24,7 @@
#include "proc/play/dummy-play-connection.hpp"
//#include "proc/play/dummy-image-generator.hpp"
//#include "proc/play/tick-service.hpp"
//#include "lib/singleton.hpp"
//#include "lib/depend.hpp"
//#include <string>
//#include <memory>

View file

@ -24,7 +24,7 @@
#include "proc/play/dummy-player-service.hpp"
#include "proc/engine/worker/dummy-image-generator.hpp"
#include "proc/engine/worker/tick-service.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
extern "C" {
#include "common/interfacedescriptor.h"
@ -92,7 +92,7 @@ namespace proc {
}
};
lib::Singleton<DummyPlayerSubsysDescriptor> theDummyPlayerDescriptor;
lib::Depend<DummyPlayerSubsysDescriptor> theDummyPlayerDescriptor;

View file

@ -41,7 +41,7 @@ namespace play {
/** storage for the single application wide OutputDirector instance */
lib::Singleton<OutputDirector> OutputDirector::instance;
lib::Depend<OutputDirector> OutputDirector::instance;
/** bring up the framework for handling input/output connections.

View file

@ -36,7 +36,7 @@
#include "lib/error.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include "proc/play/output-manager.hpp"
#include "common/subsys.hpp"
#include "lib/sync.hpp"
@ -78,7 +78,7 @@ namespace play {
scoped_ptr<PlayService> player_;
public:
static lib::Singleton<OutputDirector> instance;
static lib::Depend<OutputDirector> instance;
bool connectUp() ;
void triggerDisconnect(SigTerm) throw();
@ -88,7 +88,7 @@ namespace play {
private:
OutputDirector() ;
~OutputDirector() ;
friend class lib::singleton::StaticCreate<OutputDirector>;
friend class lib::DependencyFactory::InstanceHolder<OutputDirector>;
void bringDown (SigTerm completedSignal);

View file

@ -594,28 +594,6 @@ out: '§&Ω%€' --> ''
END
TEST "SingletonSubclass_test" SingletonSubclass_test 13 <<END
out: using the Singleton should create TargetObj\(13\)...
out: ctor TargetObj\(13\) successful
out: calling a non-static method on the Singleton-Implementation
out: .....TargetObj\(13\): data="\*\*\*\*\*\*\*\*\*\*\*\*\*", array\[13\]=\{0,1,2,3,4,5,6,7,8,9,10,11,12,\}
out: dtor ~TargetObj\(13\) successful
END
TEST "SingletonTestMock_test" SingletonTestMock_test <<END
out: TestSingletonO::doIt\(\) call=1
out: TestSingletonO::doIt\(\) call=2
out: Mock_1::doIt\(\) call=1
out: Mock_1::doIt\(\) call=2
out: Mock_1::doIt\(\) call=3
out: Mock_1::doIt\(\) call=4
out: Mock_1::doIt\(\) call=5
out: Mock_2::doIt\(\) call=1
out: TestSingletonO::doIt\(\) call=3
END
TEST "ScopedHolder_test" ScopedHolder_test <<END
out: checking ScopedHolder<Dummy>...
out: checking ScopedPtrHolder<Dummy>...
@ -666,16 +644,33 @@ END
TEST "Singleton_test" Singleton_test 23 <<END
out: testing TargetObj\(23\) as Singleton\(statically allocated\)
out: ctor TargetObj\(23\) successful
out: calling a non-static method on the Singleton instance
out: .....TargetObj\(23\): data="\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*", array\[23\]=\{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,\}
out: testing TargetObj\(24\) as Singleton\(heap allocated\)
out: ctor TargetObj\(24\) successful
out: calling a non-static method on the Singleton instance
out: .....TargetObj\(24\): data="\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*", array\[24\]=\{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,\}
out: dtor ~TargetObj\(23\) successful
out: dtor ~TargetObj\(24\) successful
out-lit: testing TargetObj(23) as Singleton
out-lit: ctor TargetObj(23) successful
out-lit: calling a non-static method on the Singleton instance
out-lit: .....TargetObj(23): data="***********************", array[23]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,}
out-lit: dtor ~TargetObj(23) successful
END
TEST "SingletonSubclass_test" SingletonSubclass_test 13 <<END
out-lit: using the Singleton should create TargetObj(13)...
out-lit: ctor TargetObj(13) successful
out-lit: calling a non-static method on the Singleton-Implementation
out-lit: .....TargetObj(13): data="*************", array[13]={0,1,2,3,4,5,6,7,8,9,10,11,12,}
out-lit: dtor ~TargetObj(13) successful
END
TEST "SingletonTestMock_test" SingletonTestMock_test <<END
out-lit: TestSingletonO::doIt() call=1
out-lit: TestSingletonO::doIt() call=2
out-lit: Mock_1::doIt() call=1
out-lit: Mock_1::doIt() call=2
out-lit: Mock_1::doIt() call=3
out-lit: Mock_1::doIt() call=4
out-lit: Mock_1::doIt() call=5
out-lit: Mock_2::doIt() call=1
out-lit: TestSingletonO::doIt() call=3
END

View file

@ -37,7 +37,7 @@
#include "proc/mobject/session/testclip.hpp"
#include "lib/util.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include "lib/time/mutation.hpp"
#include "lib/symbol.hpp"
@ -119,7 +119,7 @@ namespace test {
};
// instantiate TestCasses table
lib::Singleton<TestCases> testCases;
lib::Depend<TestCases> testCases;
} // (end) implementation namespace

View file

@ -31,7 +31,7 @@
#include "proc/play/timings.hpp"
#include "lib/time/timevalue.hpp"
//#include "lib/time/timequant.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include "lib/itertools.hpp"
#include "lib/util-coll.hpp"
#include "lib/util.hpp"
@ -117,7 +117,7 @@ namespace test {
}
};
lib::Singleton<MockDispatcherTable> mockDispatcher;
lib::Depend<MockDispatcherTable> mockDispatcher;
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #880
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #890

View file

@ -23,7 +23,7 @@
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include "common/query/query-resolver.hpp"
@ -167,7 +167,7 @@ namespace test{
};
lib::Singleton<DummyTypedSolutionProducer> testResolver;
lib::Depend<DummyTypedSolutionProducer> testResolver;
QueryResolver&
buildTestQueryResolver ()

View file

@ -24,7 +24,7 @@
#include "lib/test/run.hpp"
#include "proc/mobject/session.hpp"
#include "lib/meta/generator.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
@ -35,7 +35,7 @@ namespace mobject {
namespace session {
namespace test {
using lib::Singleton;
using lib::Depend;
using boost::lexical_cast;
using std::ostream;
using std::string;
@ -202,7 +202,7 @@ namespace test {
uint TSessionImpl::magic_;
TSessManager& TSession::current = Singleton<TSessManagerImpl>()();
TSessManager& TSession::current = Depend<TSessManagerImpl>()();
//note: already during static initialisation
template<>

View file

@ -26,7 +26,7 @@
#include "backend/media-access-mock.hpp"
#include "proc/asset/media.hpp"
#include "proc/asset/clip.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include "lib/time/timevalue.hpp"
namespace proc {
@ -72,7 +72,7 @@ namespace test {
{ }
};
lib::Singleton<Testbed> testbed_1; // invoke ctor when creating first TestClip...
lib::Depend<Testbed> testbed_1; // invoke ctor when creating first TestClip...

View file

@ -27,12 +27,13 @@
#include "lib/util.hpp"
#include "test-target-obj.hpp"
#include "lib/singleton-subclass.hpp"
#include "lib/depend.hpp"
#include <boost/lexical_cast.hpp>
#include <iostream>
using boost::lexical_cast;
using util::isSameObject;
using util::_Fmt;
using util::isnil;
using std::string;
@ -42,7 +43,7 @@ using std::cout;
namespace lib {
namespace test{
using lumiera::error::LUMIERA_ERROR_ASSERTION;
using lumiera::error::LUMIERA_ERROR_LIFECYCLE;
/**
* Target object to be instantiated as Singleton
@ -61,8 +62,7 @@ namespace test{
Interface () : TestTargetObj(cnt) {}
virtual ~Interface() {}
friend class singleton::StaticCreate<Interface>;
friend class singleton::HeapCreate<Interface>;
friend class DependencyFactory::InstanceHolder<Interface>;
};
int Interface::cnt = 0;
@ -87,9 +87,9 @@ namespace test{
* subclasses (implementation classes) without coupling the
* caller to the concrete class type.
* Expected results: an instance of the subclass is created.
* @see lib::Singleton
* @see lib::SingletonSubclassFactory
* @see lib::singleton::Adapter
* @see lib::Depend
* @see lib::buildSingleton()
* @see lib/dependency-factory.hpp
*/
class SingletonSubclass_test : public Test
{
@ -104,29 +104,24 @@ namespace test{
Interface::setCountParam(num);
// marker to declare the concrete type to be created
singleton::UseSubclass<Impl> typeinfo;
DependencyFactory::InstanceConstructor factoryFunction = buildSingleton<Impl>();
// define an instance of the Singleton factory,
// specialised to create the concrete Type passed in
SingletonSubclassFactory<Interface> instance (typeinfo);
Depend<Interface> instance (factoryFunction);
// Now use the Singleton factory...
// Note: we get the Base type
Interface& t1 = instance();
Interface& t2 = instance();
CHECK ( &t1 == &t2, "not a Singleton, got two different instances." );
CHECK (isSameObject (t1, t2), "not a Singleton, got two different instances." );
cout << "calling a non-static method on the Singleton-"
<< t1.identify() << "\n"
<< string (t1) << "\n";
///////////////////////////////////////////////////////////////////////////////TODO: find a way to configure NoBug to throw in case of assertion
///////////////////////////////////////////////////////////////////////////////TODO: just for the proc tests. Also find a better way to configure
///////////////////////////////////////////////////////////////////////////////TODO: the non-release check. Then re-enable these checks...
//#ifdef DEBUG
// verify_error_detection ();
//#endif
verify_error_detection ();
}
@ -134,19 +129,11 @@ namespace test{
void
verify_error_detection ()
{
VERIFY_ERROR (LIFECYCLE, Depend<Interface> instance (buildSingleton<Impl_XXX>()) );
VERIFY_ERROR (LIFECYCLE, Depend<Interface> instance (buildSingleton<Unrelated>()) );
singleton::UseSubclass<Impl_XXX> more_special_type;
VERIFY_ERROR (ASSERTION, SingletonSubclassFactory<Interface> instance (more_special_type) );
/* in debug mode, an attempt to re-configure an already
* configured SingletonSubclassFactory with another type
* should be detected and spotted by assertion failure */
// Note: the following won't compile, because the "subclass" isn't a subclass...
//
// singleton::UseSubclass<Unrelated> yet_another_type;
// SingletonSubclassFactory<Interface> instance (yet_another_type);
Depend<Interface> newFactory;
CHECK ( INSTANCEOF (Impl, &newFactory() )); // works as before
}
};

View file

@ -26,7 +26,7 @@
#include "lib/util.hpp"
#include "test-target-obj.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include <tr1/functional>
#include <boost/lexical_cast.hpp>
@ -58,8 +58,7 @@ namespace test{
protected:
TargetObj () : TestTargetObj(cnt) {}
friend class singleton::StaticCreate<TargetObj>;
friend class singleton::HeapCreate<TargetObj>;
friend class DependencyFactory::InstanceHolder<TargetObj>;
};
int TargetObj::cnt = 0;
@ -72,54 +71,25 @@ namespace test{
/*******************************************************************
* @test implement a Singleton class using our Singleton Template.
* Expected results: no memory leaks.
* @see lib::Singleton
* @see lib::singleton::StaticCreate
* @see lib::singleton::HeapCreate
* Expected results: single instance created in static memory,
* single instance properly destroyed, no memory leaks.
* @see lib::Depend
* @see lib::DependencyFactory::InstanceHolder
*/
class Singleton_test : public Test
{
typedef function<TargetObj& ()> InstanceAccessFunc;
InstanceAccessFunc instance;
virtual void run(Arg arg)
virtual void
run (Arg arg)
{
uint num= isnil(arg)? 1 : lexical_cast<uint>(arg[1]);
testStaticallyAllocatedSingleton (num++);
testHeapAllocatedSingleton (num++);
}
/** @test parametrise the Singleton creation such as to create
* the single TargetObj instance as a static variable.
*/
void testStaticallyAllocatedSingleton (uint num)
{
SingletonFactory<TargetObj> single;
instance = single;
useInstance (num, "statically allocated");
}
/** @test parametrise the Singleton creation such as to create
* the single TargetObj instance allocated on the Heap
* and deleted automatically at application shutdown.
*/
void testHeapAllocatedSingleton (uint num)
{
SingletonFactory<TargetObj,singleton::HeapCreate> single;
instance = single;
useInstance (num, "heap allocated");
}
void useInstance (uint num, string kind)
{
cout << _Fmt("testing TargetObj(%d) as Singleton(%s)\n") % num % kind;
Depend<TargetObj> singleton;
cout << _Fmt("testing TargetObj(%d) as Singleton\n") % num;
TargetObj::setCountParam(num);
TargetObj& t1 = instance();
TargetObj& t2 = instance();
TargetObj& t1 = singleton();
TargetObj& t2 = singleton();
CHECK (isSameObject(t1, t2), "not a Singleton, got two different instances." );

View file

@ -23,7 +23,7 @@
#include "lib/test/run.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include "lib/util.hpp"
#include <boost/lexical_cast.hpp>
@ -108,46 +108,28 @@ namespace test{
/*******************************************************************
* @test inject a Mock object into the Singleton Factory,
* to be returned and used in place of the original object.
* Expected results: Mock(s) called, no memory leaks.
* @see lib::Singleton
* @see lib::singleton::Static
* This test covers the full usage cycle: first access the
* Client Object, then replace it by two different mocks,
* and finally restore the original Client Object.
* @see lib::Depend
* @see lib::test::Depend4Test
* @see DependencyFactory_test
*/
class SingletonTestMock_test : public Test
{
Singleton<TestSingletonO> sing;
void
run (Arg arg)
{
string scenario = isnil(arg)? "default" : arg[1];
Depend<TestSingletonO> sing;
if (scenario == "default")
injectBoth();
else
if (scenario == "noMock")
noMock();
else
if (scenario == "onlyMock")
onlyMock();
else
if (scenario == "firstMock")
firstMock();
}
/** @test complete use sequence: first access the Client Object,
* then replace it by two different mocks, and finally
* restore the original Client Object
*/
void
injectBoth ()
{
sing().doIt();
sing().doIt();
CHECK (sing().getCnt() == 2);
sing.injectSubclass (new Mock_1);
Mock_1 mock_1;
TestSingletonO* original =
sing.injectReplacement (&mock_1);
sing().doIt();
sing().doIt();
sing().doIt();
@ -155,51 +137,16 @@ namespace test{
sing().doIt();
CHECK (sing().getCnt() == 5);
sing.injectSubclass (new Mock_2);
Mock_2 mock_2;
sing.injectReplacement (&mock_2);
sing().doIt();
CHECK (sing().getCnt() == 1);
sing.injectSubclass (0); // un-shadowing original instance
sing.injectReplacement (original); // un-shadowing original instance
CHECK (sing().getCnt() == 2);
sing().doIt();
CHECK (sing().getCnt() == 3);
}
/** @test just use Singleton Factory normally without any Mock. */
void
noMock ()
{
sing().doIt();
}
/** @test inject the Mock prior to using the Singleton Factory,
* thus the original Client Object shouldn't be created.*/
void
onlyMock ()
{
sing.injectSubclass (new Mock_1);
sing().doIt();
}
/** @test inject the Mock prior to using the Singleton Factory,
* but then reset the Mock, so following calls should
* create the original Client Object.
*/
void
firstMock ()
{
sing.injectSubclass (new Mock_1);
sing().doIt();
sing().doIt();
CHECK (sing().getCnt() == 2);
sing.injectSubclass (0);
sing().doIt();
CHECK (sing().getCnt() == 1);
}
};

View file

@ -54,22 +54,20 @@
#include "lib/test/run.hpp"
#include "lib/singleton.hpp"
#include "lib/depend.hpp"
#include <boost/format.hpp>
#include <iostream>
#include <vector>
using lib::Singleton;
using boost::format;
using std::string;
using std::cout;
namespace lumiera
{
namespace visitor_concept_draft
{
namespace lumiera {
namespace visitor_concept_draft {
// ================================================================== Library ====
@ -223,7 +221,7 @@ namespace lumiera
public:
static Singleton<Dispatcher<TAR,TOOL> > instance;
static lib::Depend<Dispatcher<TAR,TOOL> > instance;
inline ReturnType
forwardCall (TAR& target, TOOL& tool)
@ -251,7 +249,7 @@ namespace lumiera
/** storage for the dispatcher table(s) */
template<class TAR, class TOOL>
Singleton<Dispatcher<TAR,TOOL> > Dispatcher<TAR,TOOL>::instance;
lib::Depend<Dispatcher<TAR,TOOL> > Dispatcher<TAR,TOOL>::instance;