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:
parent
7b3c68898a
commit
0ea37402d2
63 changed files with 217 additions and 1198 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ namespace engine {
|
|||
|
||||
|
||||
/** storage for the (singleton) scheduler access frontend */
|
||||
lib::Singleton<SchedulerFrontend> SchedulerFrontend::instance;
|
||||
lib::Depend<SchedulerFrontend> SchedulerFrontend::instance;
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ namespace backend {
|
|||
|
||||
/** storage for the SingletonFactory
|
||||
* (actually a lumiera::test::MockInjector) */
|
||||
Singleton<MediaAccessFacade> MediaAccessFacade::instance;
|
||||
lib::Depend<MediaAccessFacade> MediaAccessFacade::instance;
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ namespace asset {
|
|||
clear();
|
||||
}
|
||||
|
||||
friend class lib::singleton::StaticCreate<DB>;
|
||||
friend class lib::DependencyFactory::InstanceHolder<DB>;
|
||||
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -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>() ())
|
||||
{ }
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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() { }
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ namespace control {
|
|||
}
|
||||
|
||||
/** storage for Singleton access */
|
||||
lib::Singleton<ProcDispatcher> ProcDispatcher::instance;
|
||||
lib::Depend<ProcDispatcher> ProcDispatcher::instance;
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ namespace engine {
|
|||
|
||||
|
||||
/** Storage for the diagnostics frontend */
|
||||
lib::Singleton<DiagnosticBufferProvider> DiagnosticBufferProvider::diagnostics;
|
||||
lib::Depend<DiagnosticBufferProvider> DiagnosticBufferProvider::diagnostics;
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ namespace engine{
|
|||
|
||||
|
||||
/** storage for the EngineService interface object */
|
||||
lib::Singleton<EngineService> EngineService::instance;
|
||||
lib::Depend<EngineService> EngineService::instance;
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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() { }
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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() ;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ()
|
||||
|
|
|
|||
|
|
@ -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<>
|
||||
|
|
|
|||
|
|
@ -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...
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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." );
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue