some naming cleanup and namespace indentation fixes

This commit is contained in:
Fischlurch 2010-12-18 00:58:19 +01:00
parent 3f1b7651e9
commit 7fc462209e
39 changed files with 1732 additions and 1741 deletions

View file

@ -35,7 +35,7 @@ liblumiera_la_LIBADD = \
liblumiera_la_SOURCES = \ liblumiera_la_SOURCES = \
$(liblumiera_la_srcdir)/advice/advice.cpp \ $(liblumiera_la_srcdir)/advice/advice.cpp \
$(liblumiera_la_srcdir)/advice/binding.cpp \ $(liblumiera_la_srcdir)/advice/binding.cpp \
$(liblumiera_la_srcdir)/allocationcluster.cpp \ $(liblumiera_la_srcdir)/allocation-cluster.cpp \
$(liblumiera_la_srcdir)/cmdline.cpp \ $(liblumiera_la_srcdir)/cmdline.cpp \
$(liblumiera_la_srcdir)/condition.c \ $(liblumiera_la_srcdir)/condition.c \
$(liblumiera_la_srcdir)/error.c \ $(liblumiera_la_srcdir)/error.c \
@ -69,8 +69,8 @@ noinst_HEADERS += \
$(liblumiera_la_srcdir)/advice.hpp \ $(liblumiera_la_srcdir)/advice.hpp \
$(liblumiera_la_srcdir)/advice/binding.hpp \ $(liblumiera_la_srcdir)/advice/binding.hpp \
$(liblumiera_la_srcdir)/advice/index.hpp \ $(liblumiera_la_srcdir)/advice/index.hpp \
$(liblumiera_la_srcdir)/allocationcluster.hpp \ $(liblumiera_la_srcdir)/allocation-cluster.hpp \
$(liblumiera_la_srcdir)/allocationcluster.hpp \ $(liblumiera_la_srcdir)/allocation-cluster.hpp \
$(liblumiera_la_srcdir)/condition.h \ $(liblumiera_la_srcdir)/condition.h \
$(liblumiera_la_srcdir)/error.h \ $(liblumiera_la_srcdir)/error.h \
$(liblumiera_la_srcdir)/error.hpp \ $(liblumiera_la_srcdir)/error.hpp \
@ -103,9 +103,9 @@ noinst_HEADERS += \
$(liblumiera_la_srcdir)/scoped-holder.hpp \ $(liblumiera_la_srcdir)/scoped-holder.hpp \
$(liblumiera_la_srcdir)/singleton-subclass.hpp \ $(liblumiera_la_srcdir)/singleton-subclass.hpp \
$(liblumiera_la_srcdir)/singleton.hpp \ $(liblumiera_la_srcdir)/singleton.hpp \
$(liblumiera_la_srcdir)/singletonfactory.hpp \ $(liblumiera_la_srcdir)/singleton-factory.hpp \
$(liblumiera_la_srcdir)/singletonpolicies.hpp \ $(liblumiera_la_srcdir)/singleton-policies.hpp \
$(liblumiera_la_srcdir)/singletonpreconfigure.hpp \ $(liblumiera_la_srcdir)/singleton-preconfigure.hpp \
$(liblumiera_la_srcdir)/sync-classlock.hpp \ $(liblumiera_la_srcdir)/sync-classlock.hpp \
$(liblumiera_la_srcdir)/sync.hpp \ $(liblumiera_la_srcdir)/sync.hpp \
$(liblumiera_la_srcdir)/sync.hpp \ $(liblumiera_la_srcdir)/sync.hpp \

View file

@ -21,7 +21,7 @@
* *****************************************************/ * *****************************************************/
#include "lib/allocationcluster.hpp" #include "lib/allocation-cluster.hpp"
#include "lib/error.hpp" #include "lib/error.hpp"
#include "lib/util.hpp" #include "lib/util.hpp"
#include "lib/sync.hpp" #include "lib/sync.hpp"

View file

@ -1,5 +1,5 @@
/* /*
ALLOCATIONCLUSTER.hpp - allocating and owning a pile of objects ALLOCATION-CLUSTER.hpp - allocating and owning a pile of objects
Copyright (C) Lumiera.org Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de> 2008, Hermann Vosseler <Ichthyostega@web.de>
@ -20,7 +20,7 @@
*/ */
/** @file allocationcluster.hpp /** @file allocation-cluster.hpp
** Memory management for the low-level model (render nodes network). ** Memory management for the low-level model (render nodes network).
** The model is organised into temporal segments, which are considered ** The model is organised into temporal segments, which are considered
** to be structurally constant and uniform. The objects within each ** to be structurally constant and uniform. The objects within each
@ -35,17 +35,17 @@
** templates, and thus need to be in the header. This way they can ** templates, and thus need to be in the header. This way they can
** exploit the type information available in call context. This ** exploit the type information available in call context. This
** information is passed to generic implementation functions ** information is passed to generic implementation functions
** defined in allocationcluster.cpp . In a similar vein, the ** defined in allocation-cluster.cpp . In a similar vein, the
** AllocationCluster::MemoryManger is just forward declared. ** AllocationCluster::MemoryManger is just forward declared.
** **
** @see allocationclustertest.cpp ** @see allocation-cluster-test.cpp
** @see builder::ToolFactory ** @see builder::ToolFactory
** @see frameid.hpp ** @see frameid.hpp
*/ */
#ifndef LIB_ALLOCATIONCLUSTER_H #ifndef LIB_ALLOCATION_CLUSTER_H
#define LIB_ALLOCATIONCLUSTER_H #define LIB_ALLOCATION_CLUSTER_H
#include <vector> #include <vector>
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>

View file

@ -1,5 +1,5 @@
/* /*
SINGLETONFACTORY.hpp - template for implementing the singleton pattern SINGLETON-FACTORY.hpp - template for implementing the singleton pattern
Copyright (C) Lumiera.org Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de> 2008, Hermann Vosseler <Ichthyostega@web.de>
@ -31,11 +31,11 @@ This code is heavily inspired by
#ifndef LIB_SINGLETONFACTORY_H #ifndef LIB_SINGLETON_FACTORY_H
#define LIB_SINGLETONFACTORY_H #define LIB_SINGLETON_FACTORY_H
#include "lib/singletonpolicies.hpp" // several Policies usable together with SingletonFactory #include "lib/singleton-policies.hpp" // several Policies usable together with SingletonFactory
#include "lib/nobug-init.hpp" #include "lib/nobug-init.hpp"
#include "include/logging.h" #include "include/logging.h"
@ -45,9 +45,9 @@ This code is heavily inspired by
namespace lib { namespace lib {
/** /**
* A configurable Template for implementing Singletons. * A configurable Template for implementing Singletons.
* Actually this is a Factory object, which could be placed into a static field * Actually this is a Factory object, which could be placed into a static field
* of the Singleton (target) class or used directly. * of the Singleton (target) class or used directly.
* @note internally uses static fields, so all factory instances share pInstance_ * @note internally uses static fields, so all factory instances share pInstance_
* @note there is an ongoing discussion regarding Double Checked Locking pattern, * @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 * which in this case boils down to the question: does \c pthread_mutex_lock/unlock
@ -71,7 +71,7 @@ namespace lib {
static PType pInstance_; static PType pInstance_;
static bool isDead_; static bool isDead_;
public: public:
/** Interface to be used by SingletonFactory's clients. /** Interface to be used by SingletonFactory's clients.
@ -84,7 +84,7 @@ namespace lib {
if (!pInstance_) if (!pInstance_)
{ {
ThreadLock guard SIDEEFFECT; ThreadLock guard SIDEEFFECT;
if (!pInstance_) if (!pInstance_)
{ {
if (isDead_) if (isDead_)
@ -114,15 +114,15 @@ namespace lib {
isDead_ = true; isDead_ = true;
} }
}; };
// Storage for SingletonFactory's static fields...
// Storage for SingletonFactory's static fields...
template template
< class SI, < class SI,
template <class> class C, template <class> class C,
template <class> class L template <class> class L
> >
typename SingletonFactory<SI,C,L>::PType typename SingletonFactory<SI,C,L>::PType
SingletonFactory<SI,C,L>::pInstance_; SingletonFactory<SI,C,L>::pInstance_;
template template

View file

@ -0,0 +1,138 @@
/*
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
This Loki code accompanies the book:
Alexandrescu, Andrei. "Modern C++ Design: Generic Programming
and Design Patterns Applied".
Copyright (c) 2001. Addison-Wesley. ISBN 0201704315
*/
#ifndef 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 placing the Singleton instance into a statically allocated buffer
*/
template<class S>
struct StaticCreate
{
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>
struct HeapCreate
{
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>
struct AutoDestroy
{
/** implements the Singleton removal by calling
* the provided deleter function(s) at application shutdown,
* relying on the runtime system calling 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)
{
class DeleteTrigger
{
vector<DelFunc> dels_;
public:
void schedule (DelFunc del)
{
dels_.push_back(del);
}
~DeleteTrigger()
{
vector<DelFunc>::iterator i = dels_.begin();
for ( ; i != dels_.end(); ++i )
(*i)(); // invoke deleter function
}
};
REQUIRE (kill_the_singleton);
static DeleteTrigger finally;
finally.schedule (kill_the_singleton);
}
static void
onDeadReference ()
{
throw lumiera::error::Logic ("Trying to access the a Singleton instance that has "
"already been released or finished its lifecycle.");
}
};
}} // namespace lib::singleton
#endif

View file

@ -1,5 +1,5 @@
/* /*
SINGLETONPRECONFIGURE - declare the configuration of some Singleton types in advance SINGLETON-PRECONFIGURE - declare the configuration of some Singleton types in advance
Copyright (C) Lumiera.org Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de> 2008, Hermann Vosseler <Ichthyostega@web.de>
@ -20,7 +20,7 @@
*/ */
/** @file singletonpreconfigure.hpp /** @file singleton-preconfigure.hpp
** Pre-configuration of some Singleton types, done by template specialisation. ** Pre-configuration of some Singleton types, done by template specialisation.
** Typically the client code just includes singleton.h and uses the Singleton ** Typically the client code just includes singleton.h and uses the Singleton
** type. But in some cases, we want to configure specific (dependency injection) ** type. But in some cases, we want to configure specific (dependency injection)
@ -37,12 +37,12 @@
** @note we declare the specialisations into the target namespace ** @note we declare the specialisations into the target namespace
** **
** @see SingletonFactory ** @see SingletonFactory
** @see singletontestmocktest.hpp ** @see SingletonTestMock_test
*/ */
#ifndef LIB_SINGLETONPRECONFIGURE_H #ifndef LIB_SINGLETON_PRECONFIGURE_H
#define LIB_SINGLETONPRECONFIGURE_H #define LIB_SINGLETON_PRECONFIGURE_H
#include "lib/test/mockinjector.hpp" #include "lib/test/mockinjector.hpp"

View file

@ -24,19 +24,19 @@
** Factory for creating Singleton instances. ** Factory for creating Singleton instances.
** This configuration header just pulls in some other implementation headers in ** This configuration header just pulls in some other implementation headers in
** the right order. The basic class template for creating singletons resides in ** the right order. The basic class template for creating singletons resides in
** singletonfactory.hpp, besides we need policy classes defining how to create ** singleton-factory.hpp, besides we need policy classes defining how to create
** the singleton objects and how to manage singleton lifecycle. Finally, ** the singleton objects and how to manage singleton lifecycle. Finally,
** we want to preconfigure singleton factories for some important facilities; ** we want to preconfigure singleton factories for some important facilities;
** e.g. sometimes we want to include a hook for injecting Test Mock instances. ** e.g. sometimes we want to include a hook for injecting Test Mock instances.
** **
** You'll find the default Policies in singletonfactory.hpp and the default ** You'll find the default Policies in singleton-factory.hpp and the default
** definition of type lumiera::singleton in singletonpreconfigure.hpp ** definition of type lumiera::singleton in singleton-preconfigure.hpp
** **
** @see SingletonFactory ** @see SingletonFactory
** @see singleton::StaticCreate ** @see singleton::StaticCreate
** @see singleton::AutoDestroy ** @see singleton::AutoDestroy
** @see singletontest.hpp ** @see singletontest.hpp
** @see singletontestmocktest.hpp ** @see SingletonTestMock_test
*/ */
@ -44,9 +44,9 @@
#define LIB_SINGLETON_H #define LIB_SINGLETON_H
#include "lib/singletonpolicies.hpp" #include "lib/singleton-policies.hpp"
#include "lib/singletonfactory.hpp" #include "lib/singleton-factory.hpp"
#include "lib/singletonpreconfigure.hpp" #include "lib/singleton-preconfigure.hpp"
#endif #endif

View file

@ -1,138 +0,0 @@
/*
SINGLETONPOLICIES.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
This Loki code accompanies the book:
Alexandrescu, Andrei. "Modern C++ Design: Generic Programming
and Design Patterns Applied".
Copyright (c) 2001. Addison-Wesley. ISBN 0201704315
*/
#ifndef LIB_SINGLETONPOLICIES_H
#define LIB_SINGLETONPOLICIES_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 placing the Singleton instance into a statically allocated buffer
*/
template<class S>
struct StaticCreate
{
static S* create ()
{
#ifdef DEBUG
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>
struct HeapCreate
{
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>
struct AutoDestroy
{
/** implements the Singleton removal by calling
* the provided deleter function(s) at application shutdown,
* relying on the runtime system calling 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)
{
class DeleteTrigger
{
vector<DelFunc> dels_;
public:
void schedule (DelFunc del)
{
dels_.push_back(del);
}
~DeleteTrigger()
{
vector<DelFunc>::iterator i = dels_.begin();
for ( ; i != dels_.end(); ++i )
(*i)(); // invoke deleter func
}
};
REQUIRE (kill_the_singleton);
static DeleteTrigger finally;
finally.schedule (kill_the_singleton);
}
static void
onDeadReference ()
{
throw lumiera::error::Logic ("Trying to access the a Singleton instance that has "
"already been released or finished its lifecycle.");
}
};
}} // namespace lib::singleton
#endif

View file

@ -29,7 +29,7 @@
** **
** @note simply using the ClassLock may cause a Monitor object (with a mutex) to be ** @note simply using the ClassLock may cause a Monitor object (with a mutex) to be
** created at static initialisation and destroyed on application shutdown. ** created at static initialisation and destroyed on application shutdown.
** @see singletonfactory.hpp usage example ** @see singleton-factory.hpp usage example
*/ */

View file

@ -26,7 +26,7 @@
#define LUMIERA_TEST_MOCKINJECTOR_H #define LUMIERA_TEST_MOCKINJECTOR_H
#include "lib/singletonfactory.hpp" #include "lib/singleton-factory.hpp"
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>

View file

@ -155,7 +155,7 @@ liblumiprocmobjectsession_la_SOURCES = \
$(liblumiprocmobjectsession_la_srcdir)/clip.cpp \ $(liblumiprocmobjectsession_la_srcdir)/clip.cpp \
$(liblumiprocmobjectsession_la_srcdir)/compoundclip.cpp \ $(liblumiprocmobjectsession_la_srcdir)/compoundclip.cpp \
$(liblumiprocmobjectsession_la_srcdir)/constraint.cpp \ $(liblumiprocmobjectsession_la_srcdir)/constraint.cpp \
$(liblumiprocmobjectsession_la_srcdir)/defsmanager.cpp \ $(liblumiprocmobjectsession_la_srcdir)/defs-manager.cpp \
$(liblumiprocmobjectsession_la_srcdir)/effect.cpp \ $(liblumiprocmobjectsession_la_srcdir)/effect.cpp \
$(liblumiprocmobjectsession_la_srcdir)/fixedlocation.cpp \ $(liblumiprocmobjectsession_la_srcdir)/fixedlocation.cpp \
$(liblumiprocmobjectsession_la_srcdir)/fixture.cpp \ $(liblumiprocmobjectsession_la_srcdir)/fixture.cpp \
@ -237,8 +237,8 @@ noinst_HEADERS += \
$(liblumiproc_la_srcdir)/mobject/session/clip.hpp \ $(liblumiproc_la_srcdir)/mobject/session/clip.hpp \
$(liblumiproc_la_srcdir)/mobject/session/compoundclip.hpp \ $(liblumiproc_la_srcdir)/mobject/session/compoundclip.hpp \
$(liblumiproc_la_srcdir)/mobject/session/constraint.hpp \ $(liblumiproc_la_srcdir)/mobject/session/constraint.hpp \
$(liblumiproc_la_srcdir)/mobject/session/defsmanager.hpp \ $(liblumiproc_la_srcdir)/mobject/session/defs-manager.hpp \
$(liblumiproc_la_srcdir)/mobject/session/defsregistry.hpp \ $(liblumiproc_la_srcdir)/mobject/session/defs-registry.hpp \
$(liblumiproc_la_srcdir)/mobject/session/effect.hpp \ $(liblumiproc_la_srcdir)/mobject/session/effect.hpp \
$(liblumiproc_la_srcdir)/mobject/session/fixedlocation.hpp \ $(liblumiproc_la_srcdir)/mobject/session/fixedlocation.hpp \
$(liblumiproc_la_srcdir)/mobject/session/fixture.hpp \ $(liblumiproc_la_srcdir)/mobject/session/fixture.hpp \

View file

@ -23,7 +23,7 @@
#include "proc/engine/nodefactory.hpp" #include "proc/engine/nodefactory.hpp"
#include "proc/mobject/session/effect.hpp" #include "proc/mobject/session/effect.hpp"
#include "lib/allocationcluster.hpp" #include "lib/allocation-cluster.hpp"
#include "proc/engine/nodewiring.hpp" #include "proc/engine/nodewiring.hpp"

View file

@ -26,7 +26,7 @@
#include "proc/engine/procnode.hpp" #include "proc/engine/procnode.hpp"
#include "lib/allocationcluster.hpp" #include "lib/allocation-cluster.hpp"
#include "proc/engine/nodewiring-def.hpp" #include "proc/engine/nodewiring-def.hpp"
//#include <boost/noncopyable.hpp> //#include <boost/noncopyable.hpp>

View file

@ -51,7 +51,7 @@
#include "proc/mobject/placement.hpp" #include "proc/mobject/placement.hpp"
#include "proc/mobject/mobject-ref.hpp" #include "proc/mobject/mobject-ref.hpp"
#include "proc/mobject/session/defsmanager.hpp" ////////////////////////////TICKET #643 forward declare this? #include "proc/mobject/session/defs-manager.hpp" ////////////////////////////TICKET #643 forward declare this?
#include "lib/ref-array.hpp" #include "lib/ref-array.hpp"
#include "lib/singleton.hpp" #include "lib/singleton.hpp"
#include "lib/symbol.hpp" #include "lib/symbol.hpp"

View file

@ -21,8 +21,8 @@
* *****************************************************/ * *****************************************************/
#include "proc/mobject/session/defsmanager.hpp" #include "proc/mobject/session/defs-manager.hpp"
#include "proc/mobject/session/defsregistry.hpp" #include "proc/mobject/session/defs-registry.hpp"
#include "common/configrules.hpp" #include "common/configrules.hpp"
#include "lib/error.hpp" #include "lib/error.hpp"

View file

@ -0,0 +1,128 @@
/*
DEFS-MANAGER.hpp - access to preconfigured default objects and definitions
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.
*/
#ifndef MOBJECT_SESSION_DEFS_MANAGER_H
#define MOBJECT_SESSION_DEFS_MANAGER_H
#include "lib/p.hpp"
#include "lib/query.hpp"
#include <boost/scoped_ptr.hpp>
#include <boost/noncopyable.hpp>
namespace mobject {
namespace session {
using lumiera::P;
using boost::scoped_ptr;
namespace impl { class DefsRegistry; }
/**
* Organise a collection of preconfigured default objects.
* For various kinds of objects we can tweak the default parametrisation
* as part of the general session configuration. A ref to an instance of
* this class is accessible through the current session and can be used
* to fill in parts of the configuration of new objects, if the user
* code didn't give more specific parameters. Necessary sub-objects
* will be created on demand, and any default configuration, once
* found, will be remembered and stored with the current session.
*
* @note while the logic of defaults handling can be considered
* roughly final, as of 12/09 most of the actual object
* handling is placeholder code.
*/
class DefsManager : private boost::noncopyable
{
scoped_ptr<impl::DefsRegistry> defsRegistry;
public:
DefsManager () throw();
~DefsManager ();
/** common access point: retrieve the default object fulfilling
* some given conditions. May silently trigger object creation.
* @throw error::Config in case no solution is possible, which
* is considered \e misconfiguration.
*/
template<class TAR>
P<TAR> operator() (lumiera::Query<TAR> const&);
/** search through the registered defaults, never create anything.
* @return object fulfilling the query, \c empty ptr if not found.
*/
template<class TAR>
P<TAR> search (lumiera::Query<TAR> const&);
/** retrieve an object fulfilling the query and register it as default.
* The resolution is delegated to the ConfigQuery system (which may cause
* creation of new object instances)
* @return object fulfilling the query, \c empty ptr if no solution.
*/
template<class TAR>
P<TAR> create (lumiera::Query<TAR> const&);
/** register the given object as default, after ensuring it fulfils the
* query. The latter may cause some properties of the object to be set,
* trigger creation of additional objects, and may fail altogether.
* @return true if query was successful and object is registered as default
* @note only a weak ref to the object is stored
*/
template<class TAR>
bool define (P<TAR> const&, lumiera::Query<TAR> const& =lumiera::Query<TAR>());
/** remove the defaults registration of the given object, if there was such
* @return false if nothing has been changed because the object wasn't registered
*/
template<class TAR>
bool forget (P<TAR> const&);
// Q: can we have something along the line of...?
//
// template
// < class TAR, ///< the target to query for
// template <class> class SMP ///< smart pointer class to wrap the result
// >
// SMP<TAR> operator() (const lumiera::Query<TAR>&);
// 12/09: according to my current knowledge of template metaprogramming, the answer is "no",
// but we could use a traits template to set up a fixed association of smart pointers
// and kinds of target object. This would allow to define a templated operator() returning
// the result wrapped into the right holder. But currently I don't see how to build a sensible
// implementation infrastructure backing such an interface.
//////////TICKET #452
};
}} // namespace mobject::session
#endif

View file

@ -1,5 +1,5 @@
/* /*
DEFSREGISTRY.hpp - implementation of the default object store DEFS-REGISTRY.hpp - implementation of the default object store
Copyright (C) Lumiera.org Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de> 2008, Hermann Vosseler <Ichthyostega@web.de>
@ -21,23 +21,23 @@
*/ */
/** @file defsregistry.hpp /** @file defs-registry.hpp
** A piece of implementation code factored out into a separate header (include). ** A piece of implementation code factored out into a separate header (include).
** Only used in defsmanager.cpp and for the unit tests. We can't place it into ** Only used in defs-manager.cpp and for the unit tests. We can't place it into
** a separate compilation unit, because defsmanager.cpp defines some explicit ** a separate compilation unit, because defs-manager.cpp defines some explicit
** template instantiation, which cause the different Slots of the DefsrRegistry#table_ ** template instantiation, which cause the different Slots of the DefsrRegistry#table_
** to be filled with data and defaults for the specific Types. ** to be filled with data and defaults for the specific Types.
** **
** @see mobject::session::DefsManager ** @see mobject::session::DefsManager
** @see defsregistryimpltest.cpp ** @see DefsRegistryImpl_test
** **
*/ */
#ifndef MOBJECT_SESSION_DEFSREGISTRY_H #ifndef MOBJECT_SESSION_DEFS_REGISTRY_H
#define MOBJECT_SESSION_DEFSREGISTRY_H #define MOBJECT_SESSION_DEFS_REGISTRY_H
#include "lib/sync-classlock.hpp" #include "lib/sync-classlock.hpp"
@ -55,131 +55,131 @@
namespace mobject { namespace mobject {
namespace session { namespace session {
using lumiera::P;
using lumiera::Query;
using lib::ClassLock;
using std::tr1::weak_ptr;
using std::string;
using boost::format;
using boost::lambda::_1;
using boost::lambda::var;
namespace impl {
using lumiera::P; namespace {
using lumiera::Query; uint maxSlots (0); ///< number of different registered Types
using lib::ClassLock; format dumpRecord ("%2i| %64s --> %s\n");
using std::tr1::weak_ptr; }
using std::string;
using boost::format;
using boost::lambda::_1;
using boost::lambda::var;
namespace impl { struct TableEntry
{
namespace { virtual ~TableEntry() {};
uint maxSlots (0); ///< number of different registered Types };
format dumpRecord ("%2i| %64s --> %s\n");
} /** we maintain an independent defaults registry
* for every participating kind of object. */
typedef std::vector< P<TableEntry> > Table;
struct TableEntry
{
virtual ~TableEntry() {}; /**
}; * holding a single "default object" entry
*/
/** we maintain an independent defaults registry template<class TAR>
* for every participating kind of object. */ struct Record
typedef std::vector< P<TableEntry> > Table; {
uint degree;
Query<TAR> query;
/** weak_ptr<TAR> objRef;
* holding a single "default object" entry
*/ Record (const Query<TAR>& q, const P<TAR>& obj)
template<class TAR> : degree (lumiera::query::countPred (q)),
struct Record query (q),
{ objRef (obj)
uint degree; { }
Query<TAR> query;
weak_ptr<TAR> objRef;
struct Search ///< Functor searching for a specific object
Record (const Query<TAR>& q, const P<TAR>& obj) {
: degree (lumiera::query::countPred (q)), Search (const P<TAR>& obj)
query (q), : obj_(obj) { }
objRef (obj)
{ }
struct Search ///< Functor searching for a specific object
{
Search (const P<TAR>& obj)
: obj_(obj) { }
const P<TAR>& obj_;
bool
operator() (const Record& rec)
{
P<TAR> storedObj (rec.objRef.lock());
return storedObj && (storedObj == obj_);
}
};
struct OrderRelation
{
inline bool
operator() (Record one, Record two) ///< @note doesn't touch the objRef
{
return ( one.degree < two.degree
||(one.degree == two.degree && one.query < two.query)
);
}
};
operator string () const { return str (dumpRecord % degree % query % dumpObj()); } const P<TAR>& obj_;
string dumpObj () const { P<TAR> o (objRef.lock()); return o? string(*o):"dead"; }
}; bool
operator() (const Record& rec)
/** every new kind of object (Type) creates a new
* slot in the main Table holding all registered
* default objects. Each slot actually holds a
* separate tree (set) of registry entries
*/
template<class TAR>
struct Slot : public TableEntry
{
typedef typename Record<TAR>::OrderRelation Ordering;
typedef std::set<Record<TAR>, Ordering> Registry;
Registry registry;
static size_t index; ///< where to find this Slot in every Table
static Registry&
access (Table& table)
{ {
if ( !index P<TAR> storedObj (rec.objRef.lock());
|| index > table.size() return storedObj && (storedObj == obj_);
||!table[index-1])
createSlot (table);
ASSERT (0 < index && index<=table.size() && table[index-1]);
Slot* item = static_cast<Slot*> (table[index-1].get());
return item->registry;
} }
};
private:
static void
createSlot (Table& table)
{
ClassLock<TableEntry> guard();
if (!index)
index = ++maxSlots;
if (index > table.size())
table.resize (index);
table[index-1].reset(new Slot);
}
};
struct OrderRelation
{
inline bool
operator() (Record one, Record two) ///< @note doesn't touch the objRef
{
return ( one.degree < two.degree
||(one.degree == two.degree && one.query < two.query)
);
}
};
// static vars to organise one Table Slot per type.... operator string () const { return str (dumpRecord % degree % query % dumpObj()); }
template<class TAR> string dumpObj () const { P<TAR> o (objRef.lock()); return o? string(*o):"dead"; }
size_t Slot<TAR>::index (0); };
/** every new kind of object (Type) creates a new
* slot in the main Table holding all registered
* default objects. Each slot actually holds a
* separate tree (set) of registry entries
*/
template<class TAR>
struct Slot : public TableEntry
{
typedef typename Record<TAR>::OrderRelation Ordering;
typedef std::set<Record<TAR>, Ordering> Registry;
Registry registry;
static size_t index; ///< where to find this Slot in every Table
static Registry&
access (Table& table)
{
if ( !index
|| index > table.size()
||!table[index-1])
createSlot (table);
ASSERT (0 < index && index<=table.size() && table[index-1]);
Slot* item = static_cast<Slot*> (table[index-1].get());
return item->registry;
}
private:
static void
createSlot (Table& table)
{
ClassLock<TableEntry> guard();
if (!index)
index = ++maxSlots;
if (index > table.size())
table.resize (index);
table[index-1].reset(new Slot);
}
};
// static vars to organise one Table Slot per type....
template<class TAR>
size_t Slot<TAR>::index (0);
/** /**
* @internal Helper for organising preconfigured default objects. * @internal Helper for organising preconfigured default objects.
* Maintains a collection of objects known or encountered as "default" * Maintains a collection of objects known or encountered as "default"
@ -235,8 +235,8 @@ namespace mobject {
public: public:
P<TAR> operator* () { return ptr; } P<TAR> operator* () { return ptr; }
bool hasNext () { return next || findNext(); } bool hasNext () { return next || findNext(); }
Iter operator++ (int) { Iter tmp=*this; operator++(); return tmp; } Iter operator++ (int) { Iter tmp=*this; operator++(); return tmp; }
Iter& operator++ () Iter& operator++ ()
{ {
ptr=findNext(); ptr=findNext();
next.reset(); next.reset();
@ -332,16 +332,13 @@ namespace mobject {
return res; return res;
} }
}; };
} // (End) impl namespace
using impl::DefsRegistry;
} // namespace mobject::session
} // (End) impl namespace
} // namespace mobject
using impl::DefsRegistry;
}} // namespace mobject::session
#endif #endif

View file

@ -1,130 +0,0 @@
/*
DEFSMANAGER.hpp - access to preconfigured default objects and definitions
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.
*/
#ifndef MOBJECT_SESSION_DEFSMANAGER_H
#define MOBJECT_SESSION_DEFSMANAGER_H
#include "lib/p.hpp"
#include "lib/query.hpp"
#include <boost/scoped_ptr.hpp>
#include <boost/noncopyable.hpp>
namespace mobject {
namespace session {
using lumiera::P;
using boost::scoped_ptr;
namespace impl { class DefsRegistry; }
/**
* Organise a collection of preconfigured default objects.
* For various kinds of objects we can tweak the default parametrisation
* as part of the general session configuration. A ref to an instance of
* this class is accessible through the current session and can be used
* to fill in parts of the configuration of new objects, if the user
* code didn't give more specific parameters. Necessary sub-objects
* will be created on demand, and any default configuration, once
* found, will be remembered and stored with the current session.
*
* @note while the logic of defaults handling can be considered
* roughly final, as of 12/09 most of the actual object
* handling is placeholder code.
*/
class DefsManager : private boost::noncopyable
{
scoped_ptr<impl::DefsRegistry> defsRegistry;
public:
DefsManager () throw();
~DefsManager ();
/** common access point: retrieve the default object fulfilling
* some given conditions. May silently trigger object creation.
* @throw error::Config in case no solution is possible, which
* is considered \e misconfiguration.
*/
template<class TAR>
P<TAR> operator() (lumiera::Query<TAR> const&);
/** search through the registered defaults, never create anything.
* @return object fulfilling the query, \c empty ptr if not found.
*/
template<class TAR>
P<TAR> search (lumiera::Query<TAR> const&);
/** retrieve an object fulfilling the query and register it as default.
* The resolution is delegated to the ConfigQuery system (which may cause
* creation of new object instances)
* @return object fulfilling the query, \c empty ptr if no solution.
*/
template<class TAR>
P<TAR> create (lumiera::Query<TAR> const&);
/** register the given object as default, after ensuring it fulfils the
* query. The latter may cause some properties of the object to be set,
* trigger creation of additional objects, and may fail altogether.
* @return true if query was successful and object is registered as default
* @note only a weak ref to the object is stored
*/
template<class TAR>
bool define (P<TAR> const&, lumiera::Query<TAR> const& =lumiera::Query<TAR>());
/** remove the defaults registration of the given object, if there was such
* @return false if nothing has been changed because the object wasn't registered
*/
template<class TAR>
bool forget (P<TAR> const&);
// Q: can we have something along the line of...?
//
// template
// < class TAR, ///< the target to query for
// template <class> class SMP ///< smart pointer class to wrap the result
// >
// SMP<TAR> operator() (const lumiera::Query<TAR>&);
// 12/09: according to my current knowledge of template metaprogramming, the answer is "no",
// but we could use a traits template to set up a fixed association of smart pointers
// and kinds of target object. This would allow to define a templated operator() returning
// the result wrapped into the right holder. But currently I don't see how to build a sensible
// implementation infrastructure backing such an interface.
//////////TICKET #452
};
} // namespace mobject::session
} // namespace mobject
#endif

View file

@ -22,7 +22,7 @@
#include "proc/mobject/session/root.hpp" #include "proc/mobject/session/root.hpp"
#include "proc/mobject/session/defsmanager.hpp" #include "proc/mobject/session/defs-manager.hpp"
namespace mobject { namespace mobject {

View file

@ -40,7 +40,7 @@
#include "proc/mobject/session.hpp" #include "proc/mobject/session.hpp"
#include "proc/mobject/session/sess-manager-impl.hpp" #include "proc/mobject/session/sess-manager-impl.hpp"
#include "proc/mobject/session/defsmanager.hpp" #include "proc/mobject/session/defs-manager.hpp"
#include "proc/mobject/session/lifecycle-advisor.hpp" #include "proc/mobject/session/lifecycle-advisor.hpp"
#include "proc/asset/timeline.hpp" #include "proc/asset/timeline.hpp"
#include "lib/error.hpp" #include "lib/error.hpp"

View file

@ -73,7 +73,7 @@
#include "lib/element-tracker.hpp" #include "lib/element-tracker.hpp"
#include "proc/asset/timeline.hpp" #include "proc/asset/timeline.hpp"
#include "proc/asset/sequence.hpp" #include "proc/asset/sequence.hpp"
#include "proc/mobject/session/defsmanager.hpp" #include "proc/mobject/session/defs-manager.hpp"
#include "proc/mobject/session/element-query.hpp" #include "proc/mobject/session/element-query.hpp"

View file

@ -32,7 +32,7 @@
#include "proc/mobject/session.hpp" #include "proc/mobject/session.hpp"
#include "proc/mobject/session/defsmanager.hpp" #include "proc/mobject/session/defs-manager.hpp"
#include "proc/mobject/session/session-impl.hpp" #include "proc/mobject/session/session-impl.hpp"
#include "proc/mobject/session/sess-manager-impl.hpp" #include "proc/mobject/session/sess-manager-impl.hpp"

View file

@ -85,9 +85,9 @@ test_components_SOURCES = \
$(testcomponents_srcdir)/proc/mobject/placement-object-identity-test.cpp \ $(testcomponents_srcdir)/proc/mobject/placement-object-identity-test.cpp \
$(testcomponents_srcdir)/proc/mobject/placement-ref-test.cpp \ $(testcomponents_srcdir)/proc/mobject/placement-ref-test.cpp \
$(testcomponents_srcdir)/proc/mobject/session/addcliptest.cpp \ $(testcomponents_srcdir)/proc/mobject/session/addcliptest.cpp \
$(testcomponents_srcdir)/proc/mobject/session/defsmanagerimpltest.cpp \ $(testcomponents_srcdir)/proc/mobject/session/defs-manager-impl-test.cpp \
$(testcomponents_srcdir)/proc/mobject/session/defsmanagertest.cpp \ $(testcomponents_srcdir)/proc/mobject/session/defs-manager-test.cpp \
$(testcomponents_srcdir)/proc/mobject/session/defsregistryimpltest.cpp \ $(testcomponents_srcdir)/proc/mobject/session/defs-registry-impl-test.cpp \
$(testcomponents_srcdir)/proc/mobject/session/deletecliptest.cpp \ $(testcomponents_srcdir)/proc/mobject/session/deletecliptest.cpp \
$(testcomponents_srcdir)/proc/mobject/session/placement-index-query-test.cpp \ $(testcomponents_srcdir)/proc/mobject/session/placement-index-query-test.cpp \
$(testcomponents_srcdir)/proc/mobject/session/placement-index-test.cpp \ $(testcomponents_srcdir)/proc/mobject/session/placement-index-test.cpp \

View file

@ -127,7 +127,7 @@ namespace test {
CHECK ( 0 == command1::check_); CHECK ( 0 == command1::check_);
VERIFY_ERROR (INVALID_ARGUMENTS, com.bind ("foo") ); VERIFY_ERROR (INVALID_ARGUMENTS, com.bind ("foo") );
com.bind (random()); // note: run-time type check only com.bind (random()); // note: run-time type check only
CHECK ( com.canExec()); CHECK ( com.canExec());
CHECK (!com.canUndo()); CHECK (!com.canUndo());
com(); com();
@ -159,7 +159,7 @@ namespace test {
def.operation (command1::operate) def.operation (command1::operate)
.captureUndo (command1::capture); .captureUndo (command1::capture);
CHECK (!def); // undo functor still missing CHECK (!def); // undo functor still missing
VERIFY_ERROR (INVALID_COMMAND, Command::get("test.command1.2") ); VERIFY_ERROR (INVALID_COMMAND, Command::get("test.command1.2") );
def.operation (command1::operate) def.operation (command1::operate)

View file

@ -28,7 +28,7 @@
#include "proc/engine/stateproxy.hpp" #include "proc/engine/stateproxy.hpp"
#include "proc/engine/buffhandle.hpp" #include "proc/engine/buffhandle.hpp"
#include "proc/mobject/session/effect.hpp" #include "proc/mobject/session/effect.hpp"
#include "lib/allocationcluster.hpp" #include "lib/allocation-cluster.hpp"
//#include <boost/format.hpp> //#include <boost/format.hpp>
//#include <iostream> //#include <iostream>

View file

@ -30,10 +30,8 @@
#include "lib/util.hpp" #include "lib/util.hpp"
#include "proc/mobject/session/mobjectfactory.hpp" ////TODO: avoidable? #include "proc/mobject/session/mobjectfactory.hpp" ////TODO: avoidable?
//#include <boost/format.hpp>
#include <iostream> #include <iostream>
//using boost::format;
using lumiera::Time; using lumiera::Time;
using util::contains; using util::contains;
using std::string; using std::string;
@ -41,61 +39,57 @@ using std::cout;
namespace mobject { namespace mobject {
namespace session { namespace session {
namespace test { namespace test {
using asset::VIDEO; using asset::VIDEO;
/******************************************************************* /*******************************************************************
* @test basic behaviour of Placements and access to MObjects. * @test basic behaviour of Placements and access to MObjects.
* @see mobject::Placement * @see mobject::Placement
* @see mobject::MObject#create * @see mobject::MObject#create
* @see mobject::Placement#addPlacement * @see mobject::Placement#addPlacement
* @see mobject::Placement#resolve * @see mobject::Placement#resolve
*/ */
class PlacementBasic_test : public Test class PlacementBasic_test : public Test
{
typedef shared_ptr<asset::Media> PM;
typedef shared_ptr<asset::Clip> PCA;
virtual void
run (Arg)
{ {
typedef shared_ptr<asset::Media> PM; // create Clip-MObject, which is wrapped into a placement (smart ptr)
typedef shared_ptr<asset::Clip> PCA; PM media = asset::Media::create("test-1", VIDEO);
PCA clipAsset = Media::create(*media);
virtual void Placement<Clip> pc = MObject::create (*clipAsset, *media);
run (Arg)
{ // use of the Clip-MObject interface by dereferencing the placement
// create Clip-MObject, which is wrapped into a placement (smart ptr) PM clip_media = pc->getMedia();
PM media = asset::Media::create("test-1", VIDEO); CHECK (clip_media->ident.category.hasKind (VIDEO));
PCA clipAsset = Media::create(*media);
Placement<Clip> pc = MObject::create (*clipAsset, *media); // using the Placement interface
// TODO: how to handle insufficiently determinated Placement? Throw?
// use of the Clip-MObject interface by dereferencing the placement FixedLocation & fixloc = pc.chain(Time(1)); // TODO: the track??
PM clip_media = pc->getMedia(); ExplicitPlacement expla = pc.resolve();
CHECK (clip_media->ident.category.hasKind (VIDEO)); CHECK (expla.time == Time(1));
CHECK (!expla.chain.isOverdetermined());
// using the Placement interface
// TODO: how to handle insufficiently determinated Placement? Throw?
FixedLocation & fixloc = pc.chain(Time(1)); // TODO: the track??
ExplicitPlacement expla = pc.resolve();
CHECK (expla.time == Time(1));
CHECK (!expla.chain.isOverdetermined());
// CHECK (*expla == *pc); ////////////////////////////////////////////TICKET #511 define equivalence of locating chains and solutions // CHECK (*expla == *pc); ////////////////////////////////////////////TICKET #511 define equivalence of locating chains and solutions
// now overconstraining with another Placement // now overconstraining with another Placement
pc.chain(Time(2)); pc.chain(Time(2));
ExplicitPlacement expla2 = pc.resolve(); ExplicitPlacement expla2 = pc.resolve();
CHECK (expla2.time == Time(2)); // the latest addition wins CHECK (expla2.time == Time(2)); // the latest addition wins
CHECK (expla2.chain.isOverdetermined()); CHECK (expla2.chain.isOverdetermined());
} }
}; };
/** Register this test class... */ /** Register this test class... */
LAUNCHER (PlacementBasic_test, "unit session"); LAUNCHER (PlacementBasic_test, "unit session");
} // namespace test }}} // namespace mobject::session::test
} // namespace session
} // namespace mobject

View file

@ -0,0 +1,176 @@
/*
DefsManagerImpl(Test) - checking implementation details of the defaults manager
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.
* *****************************************************/
#include "pre_a.hpp"
#include "lib/test/run.hpp"
#include "lib/util.hpp"
#include "proc/asset.hpp"
#include "proc/asset/pipe.hpp"
#include "proc/asset/struct.hpp"
#include "common/configrules.hpp"
#include "proc/assetmanager.hpp"
#include "proc/mobject/session.hpp"
#include "lib/streamtype.hpp"
#include <boost/format.hpp>
using boost::format;
using util::isnil;
using std::string;
namespace mobject {
namespace session {
namespace test {
using lib::Symbol;
using asset::Asset;
using asset::AssetManager;
using asset::Pipe;
using asset::PPipe;
using asset::Struct;
using lumiera::Query;
using lumiera::query::normaliseID;
using lumiera::ConfigRules;
using lumiera::query::QueryHandler;
using lumiera::StreamType;
/** shortcut: query for given Pipe-ID */
bool
find (const string& pID)
{
return Session::current->defaults.search (Query<Pipe> ("pipe("+pID+")"));
}
format pattern ("dummy_%s_%i");
/** create a random new ID */
string
newID (Symbol prefix)
{
return str (pattern % prefix % std::rand());
}
/************************************************************************
* @test verify some general assumptions regarding implementation details
* of the the defaults manager.
* @see DefsManager_test for the "big picture"
*/
class DefsManagerImpl_test : public Test
{
virtual void
run(Arg)
{
define_and_search();
string pipeID = create();
forget(pipeID);
}
void
define_and_search ()
{
string sID = newID ("stream");
StreamType::ID stID (sID);
// create Pipes explicitly
// (without utilising default queries)
PPipe pipe1 = Struct::retrieve.newPipe (newID("pipe"), newID("stream"));
PPipe pipe2 = Struct::retrieve.newPipe (newID("pipe"), sID );
CHECK (pipe1 != pipe2);
CHECK (stID == pipe2->getStreamID());
CHECK (!find (pipe1->getPipeID()), "accidental clash of random test-IDs");
CHECK (!find (pipe2->getPipeID()), "accidental clash of random test-IDs");
// now declare that these objects should be considered "default"
lumiera::query::setFakeBypass(""); /////////////////////////////////////////////////TODO mock resolution
CHECK (Session::current->defaults.define (pipe1, Query<Pipe> (""))); // unrestricted default
lumiera::query::setFakeBypass("stream("+sID+")"); ///////////////////////////////////TODO mock resolution
CHECK (Session::current->defaults.define (pipe2, Query<Pipe> ("stream("+sID+")")));
CHECK ( find (pipe1->getPipeID()), "failure declaring object as default");
CHECK ( find (pipe2->getPipeID()), "failure declaring object as default");
CHECK (stID != pipe1->getStreamID(), "accidental clash");
CHECK (!Session::current->defaults.define (pipe1, Query<Pipe> ("stream("+sID+")")));
// can't be registered with this query, due to failure caused by wrong stream-ID
}
const string&
create()
{
string sID = newID ("stream");
Query<Pipe> query_for_streamID ("stream("+sID+")");
// issue a ConfigQuery directly, without involving the DefaultsManager
QueryHandler<Pipe>& typeHandler = ConfigRules::instance();
PPipe pipe1;
typeHandler.resolve (pipe1, query_for_streamID);
CHECK (pipe1);
CHECK (!find (pipe1->getPipeID()));
PPipe pipe2 = Session::current->defaults.create (query_for_streamID);
CHECK (pipe2);
CHECK (pipe2 == pipe1);
CHECK ( find (pipe1->getPipeID())); // now declared as "default Pipe" for this stream-ID
return pipe1->getPipeID();
}
void
forget (string pID)
{
PPipe pipe = Pipe::query ("pipe("+pID+")");
REQUIRE (find (pipe->getPipeID()), "need an object registered as default");
long cnt = pipe.use_count();
// now de-register the pipe as "default Pipe"
CHECK (Session::current->defaults.forget (pipe));
CHECK (!find (pipe->getPipeID()));
CHECK (cnt == pipe.use_count()); // indicates DefaultsManager holding only a weak ref.
}
};
/** Register this test class... */
LAUNCHER (DefsManagerImpl_test, "function session");
}}} // namespace mobject::session::test

View file

@ -0,0 +1,204 @@
/*
DefsManager(Test) - checking basic behaviour of the defaults manager
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.
* *****************************************************/
#include "pre_a.hpp"
#include "lib/test/run.hpp"
#include "lib/symbol.hpp"
#include "lib/query.hpp"
#include "lib/util.hpp"
#include "proc/asset.hpp"
#include "proc/asset/pipe.hpp"
#include "proc/asset/struct.hpp"
#include "proc/assetmanager.hpp"
#include "proc/mobject/session.hpp"
#include "lib/streamtype.hpp"
#include <boost/format.hpp>
using boost::format;
using util::isnil;
using std::string;
namespace mobject {
namespace session {
namespace test {
using util::cStr;
using lib::Symbol;
using asset::ID;
using asset::Asset;
using asset::AssetManager;
using asset::Pipe;
using asset::PPipe;
using asset::Struct;
using lumiera::Query;
using lumiera::query::normaliseID;
using lumiera::StreamType;
/** shortcut: run just a query
* without creating new instances
*/
bool
find (Query<Pipe>& q)
{
return Session::current->defaults.search (q);
}
/***********************************************************************
* @test basic behaviour of the defaults manager ("the big picture")
* - retrieving a "default" object repeatedly
* - retrieving a more constrained "default" object
* - failure registers a new "default"
* - instance management
*
* Using pipe assets as an example. The defaults manager shouldn't
* interfere with memory management (it holds weak refs).
*/
class DefsManager_test : public Test
{
virtual void
run (Arg arg)
{
string pipeID = isnil(arg)? "Black Hole" : arg[1];
string streamID = 2>arg.size()? "teststream" : arg[2];
normaliseID (pipeID);
normaliseID (streamID);
retrieveSimpleDefault (pipeID);
retrieveConstrainedDefault (pipeID, streamID);
failureCreatesNewDefault();
verifyRemoval();
}
void
retrieveSimpleDefault (string)
{
PPipe pipe1 = Pipe::query (""); // "the default pipe"
PPipe pipe2;
// several variants to query for "the default pipe"
pipe2 = Pipe::query ("");
CHECK (pipe2 == pipe1);
pipe2 = Pipe::query ("default(X)");
CHECK (pipe2 == pipe1);
pipe2 = Session::current->defaults(Query<Pipe> ());
CHECK (pipe2 == pipe1);
pipe2 = asset::Struct::retrieve (Query<Pipe> ());
CHECK (pipe2 == pipe1);
pipe2 = asset::Struct::retrieve (Query<Pipe> ("default(P)"));
CHECK (pipe2 == pipe1);
}
void
retrieveConstrainedDefault (string pID, string sID)
{
PPipe pipe1 = Pipe::query (""); // "the default pipe"
CHECK ( pipe1->getStreamID() != StreamType::ID(sID),
"stream-ID \"%s\" not suitable for test, because "
"the default-pipe \"%s\" happens to have the same "
"stream-ID. We need it to be different",
sID.c_str(), pID.c_str()
);
string query_for_sID ("stream("+sID+")");
PPipe pipe2 = Pipe::query (query_for_sID);
CHECK (pipe2->getStreamID() == StreamType::ID(sID));
CHECK (pipe2 != pipe1);
CHECK (pipe2 == Pipe::query (query_for_sID)); // reproducible
}
void
failureCreatesNewDefault()
{
PPipe pipe1 = Session::current->defaults(Query<Pipe> ()); // "the default pipe"
string new_pID (str (format ("dummy_%s_%i")
% pipe1->getPipeID()
% std::rand()
)); // make random new pipeID
Query<Pipe> query_for_new ("pipe("+new_pID+")");
CHECK (!find (query_for_new)); // check it doesn't exist
PPipe pipe2 = Session::current->defaults (query_for_new); // triggers creation
CHECK ( find (query_for_new)); // check it exists now
CHECK (pipe1 != pipe2);
CHECK (pipe2 == Session::current->defaults (query_for_new));
}
/** verify the defaults manager holds only weak refs,
* so if an object goes out of scope, any defaults entries
* are purged silently
*/
void
verifyRemoval()
{
Symbol pID ("some_pipe");
Query<Pipe> query_for_pID ("pipe("+pID+")");
size_t hash;
{
// create new pipe and declare it to be a default
PPipe pipe1 = Struct::retrieve.newInstance<Pipe> (pID);
Session::current->defaults.define(pipe1);
CHECK (2 == pipe1.use_count()); // the pipe1 smart-ptr and the AssetManager
hash = pipe1->getID();
}
// pipe1 out of scope....
// AssetManager now should hold the only ref
ID<Asset> assetID (hash);
AssetManager& aMang (AssetManager::instance());
CHECK ( aMang.known (assetID));
aMang.remove (assetID);
CHECK (!aMang.known (assetID));
CHECK (!find(query_for_pID)); // bare default-query should fail...
PPipe pipe2 = Session::current->defaults (query_for_pID); // triggers re-creation
CHECK ( find(query_for_pID)); // should succeed again
}
};
/** Register this test class... */
LAUNCHER (DefsManager_test, "function session");
}}} // namespace mobject::session::test

View file

@ -0,0 +1,292 @@
/*
DefsRegistryImpl(Test) - verifying correct behaviour of the defaults registry
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.
* *****************************************************/
#include "lib/test/run.hpp"
#include "lib/util.hpp"
#include "proc/mobject/session/defs-registry.hpp"
#include "lib/factory.hpp"
#include "lib/query.hpp"
#include "lib/p.hpp"
#include "../lib/query/querydiagnostics.hpp"
#include <boost/scoped_ptr.hpp>
#include <boost/format.hpp>
#include <map>
using lumiera::P;
using lumiera::Query;
using lumiera::query::test::garbage_query;
using util::isnil;
using boost::scoped_ptr;
using boost::format;
using std::string;
using std::rand;
using std::map;
namespace mobject {
namespace session {
namespace test {
format typePatt ("Dummy<%2i>");
format instancePatt ("obj_%s_%i");
format predicatePatt ("%s_%2i( %s )");
/** create a random new ID */
string
newID (string prefix)
{
return str (instancePatt % prefix % rand());
}
/** template for generating some different test types */
template<int I>
struct Dummy
{
static string name;
string instanceID;
operator string () const { return instanceID; }
bool operator== (const Dummy& odu) const { return this == &odu; }
Dummy () : instanceID (newID (name)) {}
};
template<int I>
string Dummy<I>::name = str (typePatt % I);
/************************************************************************
* @test build an registry table (just for this test) configured for
* some artificial test Types. Register some entries and verify
* the intended behaviour of the storage structure.
* @see DefsManagerImpl_test for checking the implementation details
* in the actual context used in Lumiera.
*/
class DefsRegistryImpl_test : public Test
{
scoped_ptr<DefsRegistry> reg_;
typedef lumiera::P<Dummy<13> > O;
typedef lumiera::P<Dummy<23> > P;
typedef Query<Dummy<13> > Q13;
typedef Query<Dummy<23> > Q23;
typedef DefsRegistry::Iter<Dummy<13> > Iter13;
typedef DefsRegistry::Iter<Dummy<23> > Iter23;
// fabricating Objects wrapped into smart-ptrs
lib::factory::RefcountFac<Dummy<13> > oFac;
lib::factory::RefcountFac<Dummy<23> > pFac;
O o1, o2, o3;
Q13 q1, q2, q3, q4, q5;
map<Q23, P> ps;
public:
DefsRegistryImpl_test ()
: o1 (oFac()), o2 (oFac()), o3 (oFac()),
q1 (garbage_query (1)),
q2 (garbage_query (2)),
q3 (garbage_query (3)),
q4 (garbage_query (4)),
q5 (garbage_query (5))
{ }
virtual void
run (Arg)
{
this->reg_.reset (new DefsRegistry);
fill_table ();
check_query ();
check_remove ();
}
void
fill_table ()
{
// at start the registry is indeed empty
// thus a query doesn't yield any results....
CHECK ( ! *(reg_->candidates(Q13 ("something"))) );
reg_->put (o1, q5);
reg_->put (o2, q4);
reg_->put (o3, q3);
reg_->put (o3, q2);
reg_->put (o2, q1);
reg_->put (o1, Q13()); // the empty query
ps.clear();
for (int i=0; i<100; ++i)
{
P px (pFac());
Q23 qx (garbage_query());
ps[qx] = px;
reg_->put (px, qx);
px->instanceID = qx;
}
}
void
check_query ()
{
Iter13 i (reg_->candidates(Q13 ("irrelevant query")));
CHECK ( i.hasNext());
CHECK ( *i++ == o1); // ordered according to the degree of the queries
CHECK ( *i++ == o2);
CHECK ( *i++ == o3);
CHECK ( *i++ == o3);
CHECK ( *i++ == o2);
CHECK ( *i == o1);
CHECK (!i.hasNext());
CHECK (! *++i ); // null after end
i = reg_->candidates(q3);
CHECK ( *i++ == o3); // found by direct match
CHECK ( *i++ == o1); // followed by the ordered enumeration
CHECK ( *i++ == o2);
CHECK ( *i++ == o3);
CHECK ( *i++ == o3);
CHECK ( *i++ == o2);
CHECK ( *i++ == o1);
CHECK (!i.hasNext());
i = reg_->candidates(Q13());
CHECK ( *i++ == o1); // found by direct match to the empty query
CHECK ( *i++ == o1);
CHECK ( *i++ == o2);
CHECK ( *i++ == o3);
CHECK ( *i++ == o3);
CHECK ( *i++ == o2);
CHECK ( *i++ == o1);
CHECK (!i.hasNext());
uint d=0;
uint d_prev=0;
Iter23 j = reg_->candidates(Q23 ("some crap"));
for ( ; *j ; ++j )
{
CHECK ( *j );
Q23 qx ((*j)->instanceID);
CHECK ( ps[qx] == (*j));
d = lumiera::query::countPred (qx);
CHECK ( d_prev <= d );
d_prev = d;
}
CHECK (!j.hasNext());
// calling with an arbitrary (registered) query
// yields the corresponding object at start of the enumeration
j = reg_->candidates(ps.begin()->first);
CHECK ( *j == ps.begin()->second);
}
void
check_remove ()
{
reg_->forget (o2);
Iter13 i (reg_->candidates(q4));
CHECK ( i.hasNext());
CHECK ( *i++ == o1); // ordered according to the degree of the queries
// but the o2 entries are missing
CHECK ( *i++ == o3);
CHECK ( *i++ == o3);
// missing
CHECK ( *i == o1);
CHECK (!i.hasNext());
o3.reset(); // killing the only reference....
// expires the weak ref in the registry
i = reg_->candidates(Q13 ("something"));
CHECK ( i.hasNext());
CHECK ( *i++ == o1); // ordered according to the degree of the queries
// but now also the o3 entries are missing...
CHECK ( *i == o1);
CHECK (!i.hasNext());
CHECK ( reg_->put (o1, q5)); // trying to register the same object at the same place
// doesn't change anything (but counts as "success")
i = reg_->candidates(q5);
CHECK ( *i++ == o1); // direct match
CHECK ( *i++ == o1);
CHECK ( *i++ == o1);
CHECK (!i.hasNext());
CHECK (!reg_->put (o2, q5)); // trying to (re)register o2 with a existing query
// counts as failure (nothing changes)
i = reg_->candidates(q5);
CHECK ( *i++ == o1); // direct match
CHECK ( *i++ == o1);
CHECK ( *i++ == o1);
CHECK (!i.hasNext());
CHECK ( reg_->put (o2, q2)); // trying to (re)register o2 with another query succeeds
i = reg_->candidates(q2);
CHECK ( *i++ == o2); // direct match
CHECK ( *i++ == o1);
CHECK ( *i++ == o2); // inserted here in the dataset
CHECK ( *i++ == o1);
CHECK (!i.hasNext());
CHECK ( reg_->forget (o1));
CHECK (!reg_->forget (o1)); // failure, because it's already removed
CHECK ( reg_->forget (o2));
o3 = oFac(); // another object is another object (it's irrelevant...)
i = reg_->candidates(q2);
CHECK (! (*i)); // empty
}
};
/** Register this test class... */
LAUNCHER (DefsRegistryImpl_test, "function session");
}}} // namespace mobject::session::test

View file

@ -1,172 +0,0 @@
/*
DefsManagerImpl(Test) - checking implementation details of the defaults manager
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.
* *****************************************************/
#include "pre_a.hpp"
#include "lib/test/run.hpp"
#include "lib/util.hpp"
#include "proc/asset.hpp"
#include "proc/asset/pipe.hpp"
#include "common/configrules.hpp"
#include "proc/assetmanager.hpp"
#include "proc/mobject/session.hpp"
#include "lib/streamtype.hpp"
#include <boost/format.hpp>
using boost::format;
using util::isnil;
using std::string;
namespace asset {
namespace test {
using mobject::Session;
using lib::Symbol;
using lumiera::Query;
using lumiera::query::normaliseID;
using lumiera::ConfigRules;
using lumiera::query::QueryHandler;
using lumiera::StreamType;
/** shortcut: query for given Pipe-ID */
bool
find (const string& pID)
{
return Session::current->defaults.search (Query<Pipe> ("pipe("+pID+")"));
}
format pattern ("dummy_%s_%i");
/** create a random new ID */
string
newID (Symbol prefix)
{
return str (pattern % prefix % std::rand());
}
/************************************************************************
* @test verify some general assumptions regarding implementation details
* of the the defaults manager.
* @see DefsManager_test for the "big picture"
*/
class DefsManagerImpl_test : public Test
{
virtual void
run(Arg)
{
define_and_search();
string pipeID = create();
forget(pipeID);
}
void
define_and_search ()
{
string sID = newID ("stream");
StreamType::ID stID (sID);
// create Pipes explicitly
// (without utilising default queries)
PPipe pipe1 = Struct::retrieve.newPipe (newID("pipe"), newID("stream"));
PPipe pipe2 = Struct::retrieve.newPipe (newID("pipe"), sID );
CHECK (pipe1 != pipe2);
CHECK (stID == pipe2->getStreamID());
CHECK (!find (pipe1->getPipeID()), "accidental clash of random test-IDs");
CHECK (!find (pipe2->getPipeID()), "accidental clash of random test-IDs");
// now declare that these objects should be considered "default"
lumiera::query::setFakeBypass(""); /////////////////////////////////////////////////TODO mock resolution
CHECK (Session::current->defaults.define (pipe1, Query<Pipe> (""))); // unrestricted default
lumiera::query::setFakeBypass("stream("+sID+")"); ///////////////////////////////////TODO mock resolution
CHECK (Session::current->defaults.define (pipe2, Query<Pipe> ("stream("+sID+")")));
CHECK ( find (pipe1->getPipeID()), "failure declaring object as default");
CHECK ( find (pipe2->getPipeID()), "failure declaring object as default");
CHECK (stID != pipe1->getStreamID(), "accidental clash");
CHECK (!Session::current->defaults.define (pipe1, Query<Pipe> ("stream("+sID+")")));
// can't be registered with this query, due to failure caused by wrong stream-ID
}
const string&
create()
{
string sID = newID ("stream");
Query<Pipe> query_for_streamID ("stream("+sID+")");
// issue a ConfigQuery directly, without involving the DefaultsManager
QueryHandler<Pipe>& typeHandler = ConfigRules::instance();
PPipe pipe1;
typeHandler.resolve (pipe1, query_for_streamID);
CHECK (pipe1);
CHECK (!find (pipe1->getPipeID()));
PPipe pipe2 = Session::current->defaults.create (query_for_streamID);
CHECK (pipe2);
CHECK (pipe2 == pipe1);
CHECK ( find (pipe1->getPipeID())); // now declared as "default Pipe" for this stream-ID
return pipe1->getPipeID();
}
void
forget (string pID)
{
PPipe pipe = Pipe::query ("pipe("+pID+")");
REQUIRE (find (pipe->getPipeID()), "need an object registered as default");
long cnt = pipe.use_count();
// now de-register the pipe as "default Pipe"
CHECK (Session::current->defaults.forget (pipe));
CHECK (!find (pipe->getPipeID()));
CHECK (cnt == pipe.use_count()); // indicates DefaultsManager holding only a weak ref.
}
};
/** Register this test class... */
LAUNCHER (DefsManagerImpl_test, "function session");
} // namespace test
} // namespace asset

View file

@ -1,197 +0,0 @@
/*
DefsManager(Test) - checking basic behaviour of the defaults manager
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.
* *****************************************************/
#include "pre_a.hpp"
#include "lib/test/run.hpp"
#include "lib/symbol.hpp"
#include "lib/query.hpp"
#include "lib/util.hpp"
#include "proc/asset.hpp"
#include "proc/asset/pipe.hpp"
#include "proc/assetmanager.hpp"
#include "proc/mobject/session.hpp"
#include "lib/streamtype.hpp"
#include <boost/format.hpp>
using boost::format;
using util::isnil;
using std::string;
namespace asset {
namespace test {
using util::cStr;
using lib::Symbol;
using mobject::Session;
using lumiera::Query;
using lumiera::query::normaliseID;
using lumiera::StreamType;
/** shortcut: run just a query
* without creating new instances
*/
bool
find (Query<Pipe>& q)
{
return Session::current->defaults.search (q);
}
/***********************************************************************
* @test basic behaviour of the defaults manager ("the big picture")
* - retrieving a "default" object repeatedly
* - retrieving a more constrained "default" object
* - failure registers a new "default"
* - instance management
*
* Using pipe assets as an example. The defaults manager shouldn't
* interfere with memory management (it holds weak refs).
*/
class DefsManager_test : public Test
{
virtual void
run (Arg arg)
{
string pipeID = isnil(arg)? "Black Hole" : arg[1];
string streamID = 2>arg.size()? "teststream" : arg[2] ;
normaliseID (pipeID);
normaliseID (streamID);
retrieveSimpleDefault (pipeID);
retrieveConstrainedDefault (pipeID, streamID);
failureCreatesNewDefault();
verifyRemoval();
}
void
retrieveSimpleDefault (string)
{
PPipe pipe1 = Pipe::query (""); // "the default pipe"
PPipe pipe2;
// several variants to query for "the default pipe"
pipe2 = Pipe::query ("");
CHECK (pipe2 == pipe1);
pipe2 = Pipe::query ("default(X)");
CHECK (pipe2 == pipe1);
pipe2 = Session::current->defaults(Query<Pipe> ());
CHECK (pipe2 == pipe1);
pipe2 = asset::Struct::retrieve (Query<Pipe> ());
CHECK (pipe2 == pipe1);
pipe2 = asset::Struct::retrieve (Query<Pipe> ("default(P)"));
CHECK (pipe2 == pipe1);
}
void
retrieveConstrainedDefault (string pID, string sID)
{
PPipe pipe1 = Pipe::query (""); // "the default pipe"
CHECK ( pipe1->getStreamID() != StreamType::ID(sID),
"stream-ID \"%s\" not suitable for test, because "
"the default-pipe \"%s\" happens to have the same "
"stream-ID. We need it to be different",
sID.c_str(), pID.c_str()
);
string query_for_sID ("stream("+sID+")");
PPipe pipe2 = Pipe::query (query_for_sID);
CHECK (pipe2->getStreamID() == StreamType::ID(sID));
CHECK (pipe2 != pipe1);
CHECK (pipe2 == Pipe::query (query_for_sID)); // reproducible
}
void
failureCreatesNewDefault()
{
PPipe pipe1 = Session::current->defaults(Query<Pipe> ()); // "the default pipe"
string new_pID (str (format ("dummy_%s_%i")
% pipe1->getPipeID()
% std::rand()
)); // make random new pipeID
Query<Pipe> query_for_new ("pipe("+new_pID+")");
CHECK (!find (query_for_new)); // check it doesn't exist
PPipe pipe2 = Session::current->defaults (query_for_new); // triggers creation
CHECK ( find (query_for_new)); // check it exists now
CHECK (pipe1 != pipe2);
CHECK (pipe2 == Session::current->defaults (query_for_new));
}
/** verify the defaults manager holds only weak refs,
* so if an object goes out of scope, any defaults entries
* are purged silently
*/
void
verifyRemoval()
{
Symbol pID ("some_pipe");
Query<Pipe> query_for_pID ("pipe("+pID+")");
size_t hash;
{
// create new pipe and declare it to be a default
PPipe pipe1 = Struct::retrieve.newInstance<Pipe> (pID);
Session::current->defaults.define(pipe1);
CHECK (2 == pipe1.use_count()); // the pipe1 smart-ptr and the AssetManager
hash = pipe1->getID();
}
// pipe1 out of scope....
// AssetManager now should hold the only ref
ID<Asset> assetID (hash);
AssetManager& aMang (AssetManager::instance());
CHECK ( aMang.known (assetID));
aMang.remove (assetID);
CHECK (!aMang.known (assetID));
CHECK (!find(query_for_pID)); // bare default-query should fail...
PPipe pipe2 = Session::current->defaults (query_for_pID); // triggers re-creation
CHECK ( find(query_for_pID)); // should succeed again
}
};
/** Register this test class... */
LAUNCHER (DefsManager_test, "function session");
}} // namespace asset::test

View file

@ -1,296 +0,0 @@
/*
DefsRegistryImpl(Test) - verifying correct behaviour of the defaults registry
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.
* *****************************************************/
#include "lib/test/run.hpp"
#include "lib/util.hpp"
#include "proc/mobject/session/defsregistry.hpp"
#include "lib/factory.hpp"
#include "lib/query.hpp"
#include "lib/p.hpp"
#include "../lib/query/querydiagnostics.hpp"
#include <boost/scoped_ptr.hpp>
#include <boost/format.hpp>
#include <map>
using lumiera::P;
using lumiera::Query;
using lumiera::query::test::garbage_query;
using util::isnil;
using boost::scoped_ptr;
using boost::format;
using std::string;
using std::rand;
using std::map;
namespace mobject {
namespace session {
namespace test {
format typePatt ("Dummy<%2i>");
format instancePatt ("obj_%s_%i");
format predicatePatt ("%s_%2i( %s )");
/** create a random new ID */
string
newID (string prefix)
{
return str (instancePatt % prefix % rand());
}
/** template for generating some different test types */
template<int I>
struct Dummy
{
static string name;
string instanceID;
operator string () const { return instanceID; }
bool operator== (const Dummy& odu) const { return this == &odu; }
Dummy () : instanceID (newID (name)) {}
};
template<int I>
string Dummy<I>::name = str (typePatt % I);
/************************************************************************
* @test build an registry table (just for this test) configured for
* some artificial test Types. Register some entries and verify
* the intended behaviour of the storage structure.
* @see DefsManagerImpl_test for checking the implementation details
* in the actual context used in Lumiera.
*/
class DefsRegistryImpl_test : public Test
{
scoped_ptr<DefsRegistry> reg_;
typedef lumiera::P<Dummy<13> > O;
typedef lumiera::P<Dummy<23> > P;
typedef Query<Dummy<13> > Q13;
typedef Query<Dummy<23> > Q23;
typedef DefsRegistry::Iter<Dummy<13> > Iter13;
typedef DefsRegistry::Iter<Dummy<23> > Iter23;
// fabricating Objects wrapped into smart-ptrs
lib::factory::RefcountFac<Dummy<13> > oFac;
lib::factory::RefcountFac<Dummy<23> > pFac;
O o1, o2, o3;
Q13 q1, q2, q3, q4, q5;
map<Q23, P> ps;
public:
DefsRegistryImpl_test ()
: o1 (oFac()), o2 (oFac()), o3 (oFac()),
q1 (garbage_query (1)),
q2 (garbage_query (2)),
q3 (garbage_query (3)),
q4 (garbage_query (4)),
q5 (garbage_query (5))
{ }
virtual void
run (Arg)
{
this->reg_.reset (new DefsRegistry);
fill_table ();
check_query ();
check_remove ();
}
void
fill_table ()
{
// at start the registry is indeed empty
// thus a query doesn't yield any results....
CHECK ( ! *(reg_->candidates(Q13 ("something"))) );
reg_->put (o1, q5);
reg_->put (o2, q4);
reg_->put (o3, q3);
reg_->put (o3, q2);
reg_->put (o2, q1);
reg_->put (o1, Q13()); // the empty query
ps.clear();
for (int i=0; i<100; ++i)
{
P px (pFac());
Q23 qx (garbage_query());
ps[qx] = px;
reg_->put (px, qx);
px->instanceID = qx;
}
}
void
check_query ()
{
Iter13 i (reg_->candidates(Q13 ("irrelevant query")));
CHECK ( i.hasNext());
CHECK ( *i++ == o1); // ordered according to the degree of the queries
CHECK ( *i++ == o2);
CHECK ( *i++ == o3);
CHECK ( *i++ == o3);
CHECK ( *i++ == o2);
CHECK ( *i == o1);
CHECK (!i.hasNext());
CHECK (! *++i ); // null after end
i = reg_->candidates(q3);
CHECK ( *i++ == o3); // found by direct match
CHECK ( *i++ == o1); // followed by the ordered enumeration
CHECK ( *i++ == o2);
CHECK ( *i++ == o3);
CHECK ( *i++ == o3);
CHECK ( *i++ == o2);
CHECK ( *i++ == o1);
CHECK (!i.hasNext());
i = reg_->candidates(Q13());
CHECK ( *i++ == o1); // found by direct match to the empty query
CHECK ( *i++ == o1);
CHECK ( *i++ == o2);
CHECK ( *i++ == o3);
CHECK ( *i++ == o3);
CHECK ( *i++ == o2);
CHECK ( *i++ == o1);
CHECK (!i.hasNext());
uint d=0;
uint d_prev=0;
Iter23 j = reg_->candidates(Q23 ("some crap"));
for ( ; *j ; ++j )
{
CHECK ( *j );
Q23 qx ((*j)->instanceID);
CHECK ( ps[qx] == (*j));
d = lumiera::query::countPred (qx);
CHECK ( d_prev <= d );
d_prev = d;
}
CHECK (!j.hasNext());
// calling with an arbitrary (registered) query
// yields the corresponding object at start of the enumeration
j = reg_->candidates(ps.begin()->first);
CHECK ( *j == ps.begin()->second);
}
void
check_remove ()
{
reg_->forget (o2);
Iter13 i (reg_->candidates(q4));
CHECK ( i.hasNext());
CHECK ( *i++ == o1); // ordered according to the degree of the queries
// but the o2 entries are missing
CHECK ( *i++ == o3);
CHECK ( *i++ == o3);
// missing
CHECK ( *i == o1);
CHECK (!i.hasNext());
o3.reset(); // killing the only reference....
// expires the weak ref in the registry
i = reg_->candidates(Q13 ("something"));
CHECK ( i.hasNext());
CHECK ( *i++ == o1); // ordered according to the degree of the queries
// but now also the o3 entries are missing...
CHECK ( *i == o1);
CHECK (!i.hasNext());
CHECK ( reg_->put (o1, q5)); // trying to register the same object at the same place
// doesn't change anything (but counts as "success")
i = reg_->candidates(q5);
CHECK ( *i++ == o1); // direct match
CHECK ( *i++ == o1);
CHECK ( *i++ == o1);
CHECK (!i.hasNext());
CHECK (!reg_->put (o2, q5)); // trying to (re)register o2 with a existing query
// counts as failure (nothing changes)
i = reg_->candidates(q5);
CHECK ( *i++ == o1); // direct match
CHECK ( *i++ == o1);
CHECK ( *i++ == o1);
CHECK (!i.hasNext());
CHECK ( reg_->put (o2, q2)); // trying to (re)register o2 with another query succeeds
i = reg_->candidates(q2);
CHECK ( *i++ == o2); // direct match
CHECK ( *i++ == o1);
CHECK ( *i++ == o2); // inserted here in the dataset
CHECK ( *i++ == o1);
CHECK (!i.hasNext());
CHECK ( reg_->forget (o1));
CHECK (!reg_->forget (o1)); // failure, because it's already removed
CHECK ( reg_->forget (o2));
o3 = oFac(); // another object is another object (it's irrelevant...)
i = reg_->candidates(q2);
CHECK (! (*i)); // empty
}
};
/** Register this test class... */
LAUNCHER (DefsRegistryImpl_test, "function session");
} // namespace test
} // namespace mobject
} // namespace mobject

View file

@ -43,7 +43,7 @@ test_lib_SOURCES = \
$(testlib_srcdir)/advice/advice-index-test.cpp \ $(testlib_srcdir)/advice/advice-index-test.cpp \
$(testlib_srcdir)/advice/advice-multiplicity-test.cpp \ $(testlib_srcdir)/advice/advice-multiplicity-test.cpp \
$(testlib_srcdir)/advice/advice-situations-test.cpp \ $(testlib_srcdir)/advice/advice-situations-test.cpp \
$(testlib_srcdir)/allocationclustertest.cpp \ $(testlib_srcdir)/allocation-cluster-test.cpp \
$(testlib_srcdir)/appconfigtest.cpp \ $(testlib_srcdir)/appconfigtest.cpp \
$(testlib_srcdir)/bool-checkable-test.cpp \ $(testlib_srcdir)/bool-checkable-test.cpp \
$(testlib_srcdir)/custom-shared-ptr-test.cpp \ $(testlib_srcdir)/custom-shared-ptr-test.cpp \
@ -87,7 +87,7 @@ test_lib_SOURCES = \
$(testlib_srcdir)/scoped-holder-transfer-test.cpp \ $(testlib_srcdir)/scoped-holder-transfer-test.cpp \
$(testlib_srcdir)/singleton-subclass-test.cpp \ $(testlib_srcdir)/singleton-subclass-test.cpp \
$(testlib_srcdir)/singleton-test.cpp \ $(testlib_srcdir)/singleton-test.cpp \
$(testlib_srcdir)/singletontestmocktest.cpp \ $(testlib_srcdir)/singleton-testmock-test.cpp \
$(testlib_srcdir)/streamtypebasicstest.cpp \ $(testlib_srcdir)/streamtypebasicstest.cpp \
$(testlib_srcdir)/streamtypelifecycletest.cpp \ $(testlib_srcdir)/streamtypelifecycletest.cpp \
$(testlib_srcdir)/sub-id-test.cpp \ $(testlib_srcdir)/sub-id-test.cpp \

View file

@ -0,0 +1,234 @@
/*
AllocationCluster(Test) - verify bulk (de)allocating a family of 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.
* *****************************************************/
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
#include "lib/util.hpp"
#include "lib/util-foreach.hpp"
#include "lib/allocation-cluster.hpp"
#include "lib/scoped-holder.hpp"
#include <vector>
#include <limits>
#include <boost/lexical_cast.hpp>
using boost::lexical_cast;
using lib::test::showSizeof;
using util::for_each;
using util::isnil;
using ::Test;
using std::numeric_limits;
using std::vector;
namespace lib {
namespace test {
namespace { // a family of test dummy classes
uint NUM_CLUSTERS = 5;
uint NUM_OBJECTS = 500;
uint NUM_FAMILIES = 5;
long checksum = 0; // validate proper pairing of ctor/dtor calls
bool randomFailures = false;
template<uint i>
class Dummy
{
char content[i];
public:
Dummy (char id=1)
{
content[0] = id;
checksum += id;
}
Dummy (char i1, char i2, char i3=0)
{
char id = i1 + i2 + i3;
content[0] = id;
checksum += id;
if (randomFailures && 0 == (rand() % 20))
throw id;
}
~Dummy()
{
checksum -= content[0];
}
char getID() { return content[0]; }
};
typedef ScopedHolder<AllocationCluster> PCluster;
typedef vector<PCluster> ClusterList;
inline char
truncChar (uint x)
{
return x % numeric_limits<char>::max();
}
template<uint i>
void
place_object (AllocationCluster& clu, uint id)
{
clu.create<Dummy<i> > (id);
}
typedef void (Invoker)(AllocationCluster&, uint);
Invoker* invoke[20] = { &place_object<1>
, &place_object<2>
, &place_object<3>
, &place_object<5>
, &place_object<10>
, &place_object<13>
, &place_object<14>
, &place_object<15>
, &place_object<16>
, &place_object<17>
, &place_object<18>
, &place_object<19>
, &place_object<20>
, &place_object<25>
, &place_object<30>
, &place_object<35>
, &place_object<40>
, &place_object<50>
, &place_object<100>
, &place_object<200>
};
void
fillIt (PCluster& clu)
{
clu.create();
if (20<NUM_FAMILIES)
NUM_FAMILIES = 20;
for (uint i=0; i<NUM_OBJECTS; ++i)
{
char id = truncChar(i);
(*(invoke[rand() % NUM_FAMILIES])) (*clu,id);
}
}
}
/*************************************************************************
* @test verify the proper workings of our custom allocation scheme
* managing families of interconnected objects for the segments
* of the low-level model.
*/
class AllocationCluster_test : public Test
{
virtual void
run (Arg arg)
{
if (0 < arg.size()) NUM_CLUSTERS = lexical_cast<uint> (arg[0]);
if (1 < arg.size()) NUM_OBJECTS = lexical_cast<uint> (arg[1]);
if (2 < arg.size()) NUM_FAMILIES = lexical_cast<uint> (arg[2]);
simpleUsage();
checkAllocation();
checkErrorHandling();
}
void
simpleUsage()
{
AllocationCluster clu;
char c1(123), c2(56), c3(3), c4(4), c5(5);
Dummy<44>& ref1 = clu.create<Dummy<44> > ();
Dummy<37>& ref2 = clu.create<Dummy<37> > (c1);
Dummy<37>& ref3 = clu.create<Dummy<37> > (c2);
Dummy<1234>& rX = clu.create<Dummy<1234> > (c3,c4,c5);
CHECK (&ref1);
CHECK (&ref2);
CHECK (&ref3);
CHECK (&rX);
TRACE (test, "%s", showSizeof(rX).c_str());
CHECK (123==ref2.getID());
CHECK (3+4+5==rX.getID());
// shows that the returned references actually
// point at the objects we created. Just use them
// and let them go. When clu goes out of scope,
// all created object's dtors will be invoked.
}
void
checkAllocation()
{
CHECK (0==checksum);
{
ClusterList clusters (NUM_CLUSTERS);
for_each (clusters, fillIt);
CHECK (0!=checksum);
}
CHECK (0==checksum);
}
void
checkErrorHandling()
{
CHECK (0==checksum);
{
randomFailures = true;
AllocationCluster clu;
for (uint i=0; i<NUM_OBJECTS; ++i)
try
{
char i1 = truncChar(i);
char i2 = truncChar(rand() % 5);
clu.create<Dummy<1> > (i1,i2);
}
catch (char id)
{
checksum -= id; // exception thrown from within constructor,
} // thus dtor won't be called. Repair the checksum!
}
randomFailures = false;
CHECK (0==checksum);
}
};
LAUNCHER (AllocationCluster_test, "unit common");
}} // namespace lib::test

View file

@ -1,236 +0,0 @@
/*
AllocationCluster(Test) - verify bulk (de)allocating a family of 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.
* *****************************************************/
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
#include "lib/util.hpp"
#include "lib/util-foreach.hpp"
#include "lib/allocationcluster.hpp"
#include "lib/scoped-holder.hpp"
#include <vector>
#include <limits>
#include <boost/lexical_cast.hpp>
using boost::lexical_cast;
using lib::test::showSizeof;
using util::for_each;
using util::isnil;
using ::Test;
using std::numeric_limits;
using std::vector;
namespace lib {
namespace test {
namespace { // a family of test dummy classes
uint NUM_CLUSTERS = 5;
uint NUM_OBJECTS = 500;
uint NUM_FAMILIES = 5;
long checksum = 0; // validate proper pairing of ctor/dtor calls
bool randomFailures = false;
template<uint i>
class Dummy
{
char content[i];
public:
Dummy (char id=1)
{
content[0] = id;
checksum += id;
}
Dummy (char i1, char i2, char i3=0)
{
char id = i1 + i2 + i3;
content[0] = id;
checksum += id;
if (randomFailures && 0 == (rand() % 20))
throw id;
}
~Dummy()
{
checksum -= content[0];
}
char getID() { return content[0]; }
};
typedef ScopedHolder<AllocationCluster> PCluster;
typedef vector<PCluster> ClusterList;
inline char
truncChar (uint x)
{
return x % numeric_limits<char>::max();
}
template<uint i>
void
place_object (AllocationCluster& clu, uint id)
{
clu.create<Dummy<i> > (id);
}
typedef void (Invoker)(AllocationCluster&, uint);
Invoker* invoke[20] = { &place_object<1>
, &place_object<2>
, &place_object<3>
, &place_object<5>
, &place_object<10>
, &place_object<13>
, &place_object<14>
, &place_object<15>
, &place_object<16>
, &place_object<17>
, &place_object<18>
, &place_object<19>
, &place_object<20>
, &place_object<25>
, &place_object<30>
, &place_object<35>
, &place_object<40>
, &place_object<50>
, &place_object<100>
, &place_object<200>
};
void
fillIt (PCluster& clu)
{
clu.create();
if (20<NUM_FAMILIES)
NUM_FAMILIES = 20;
for (uint i=0; i<NUM_OBJECTS; ++i)
{
char id = truncChar(i);
(*(invoke[rand() % NUM_FAMILIES])) (*clu,id);
}
}
}
/*************************************************************************
* @test verify the proper workings of our custom allocation scheme
* managing families of interconnected objects for the segments
* of the low-level model.
*/
class AllocationCluster_test : public Test
{
virtual void
run (Arg arg)
{
if (0 < arg.size()) NUM_CLUSTERS = lexical_cast<uint> (arg[0]);
if (1 < arg.size()) NUM_OBJECTS = lexical_cast<uint> (arg[1]);
if (2 < arg.size()) NUM_FAMILIES = lexical_cast<uint> (arg[2]);
simpleUsage();
checkAllocation();
checkErrorHandling();
}
void
simpleUsage()
{
AllocationCluster clu;
char c1(123), c2(56), c3(3), c4(4), c5(5);
Dummy<44>& ref1 = clu.create<Dummy<44> > ();
Dummy<37>& ref2 = clu.create<Dummy<37> > (c1);
Dummy<37>& ref3 = clu.create<Dummy<37> > (c2);
Dummy<1234>& rX = clu.create<Dummy<1234> > (c3,c4,c5);
CHECK (&ref1);
CHECK (&ref2);
CHECK (&ref3);
CHECK (&rX);
TRACE (test, "%s", showSizeof(rX).c_str());
CHECK (123==ref2.getID());
CHECK (3+4+5==rX.getID());
// shows that the returned references actually
// point at the objects we created. Just use them
// and let them go. When clu goes out of scope,
// all created object's dtors will be invoked.
}
void
checkAllocation()
{
CHECK (0==checksum);
{
ClusterList clusters (NUM_CLUSTERS);
for_each (clusters, fillIt);
CHECK (0!=checksum);
}
CHECK (0==checksum);
}
void
checkErrorHandling()
{
CHECK (0==checksum);
{
randomFailures = true;
AllocationCluster clu;
for (uint i=0; i<NUM_OBJECTS; ++i)
try
{
char i1 = truncChar(i);
char i2 = truncChar(rand() % 5);
clu.create<Dummy<1> > (i1,i2);
}
catch (char id)
{
checksum -= id; // exception thrown from within constructor,
} // thus dtor won't be called. Repair the checksum!
}
randomFailures = false;
CHECK (0==checksum);
}
};
LAUNCHER (AllocationCluster_test, "unit common");
}// namespace test
} // namespace lib

View file

@ -34,205 +34,204 @@
namespace lib { namespace lib {
namespace test { namespace test {
using ::Test; using ::Test;
using util::isnil; using util::isnil;
using std::vector; using std::vector;
using std::cout; using std::cout;
namespace { // extending the Dummy for our special purpose.... namespace { // extending the Dummy for our special purpose....
bool throw_in_transfer = false; bool throw_in_transfer = false;
class FixedDummy class FixedDummy
: public Dummy : public Dummy
{
public:
FixedDummy()
{
TRACE (test, "CTOR FixedDummy() --> this=%p val=%d", this, getVal());
}
~FixedDummy()
{
TRACE (test, "DTOR ~FixedDummy() this=%p val=%d", this, getVal());
}
friend void
transfer_control (FixedDummy& from, FixedDummy& to)
{
TRACE (test, "TRANSFER target=%p <-- source=%p (%d,%d)", &to,&from, to.getVal(),from.getVal());
if (throw_in_transfer)
throw to.getVal();
swap (from,to);
from.setVal(0); // remove the old Dummy from accounting (checksum)
}
};
typedef ScopedHolder<FixedDummy> HolderD;
typedef ScopedPtrHolder<FixedDummy> PtrHolderD;
template<class HOL>
struct Table
{
typedef Allocator_TransferNoncopyable<HOL> Allo;
typedef typename std::vector<HOL,Allo> Type;
};
}
/**********************************************************************************
* @test growing a vector containing noncopyable objects wrapped into ScopedHolder
* instances. This requires the use of a custom allocator, invoking a
* \c transfer_control() function to be provided for the concrete
* noncopyable class type, being invoked when the vector
* needs to reallocate.
*/
class ScopedHolderTransfer_test : public Test
{ {
public:
virtual void FixedDummy()
run (Arg)
{ {
TRACE (test, "CTOR FixedDummy() --> this=%p val=%d", this, getVal());
cout << "checking ScopedHolder<Dummy>...\n";
buildVector<HolderD>();
growVector<HolderD>();
checkErrorHandling<HolderD>();
cout << "checking ScopedPtrHolder<Dummy>...\n";
buildVector<PtrHolderD>();
growVector<PtrHolderD>();
checkErrorHandling<PtrHolderD>();
} }
void create_contained_object (HolderD& holder) { holder.create(); } ~FixedDummy()
void create_contained_object (PtrHolderD& holder) { holder.reset(new FixedDummy()); }
template<class HO>
void
buildVector()
{ {
CHECK (0==checksum); TRACE (test, "DTOR ~FixedDummy() this=%p val=%d", this, getVal());
{
typedef typename Table<HO>::Type Vect;
Vect table(50);
CHECK (0==checksum);
for (uint i=0; i<10; ++i)
create_contained_object (table[i]);
CHECK (0 < checksum);
CHECK ( table[9]);
CHECK (!table[10]);
Dummy *rawP = table[5].get();
CHECK (rawP);
CHECK (table[5]);
CHECK (rawP == &(*table[5]));
CHECK (rawP->add(-555) == table[5]->add(-555));
}
CHECK (0==checksum);
} }
friend void
template<class HO> transfer_control (FixedDummy& from, FixedDummy& to)
void {
growVector() TRACE (test, "TRANSFER target=%p <-- source=%p (%d,%d)", &to,&from, to.getVal(),from.getVal());
{
CHECK (0==checksum); if (throw_in_transfer)
{ throw to.getVal();
typedef typename Table<HO>::Type Vect;
swap (from,to);
Vect table; from.setVal(0); // remove the old Dummy from accounting (checksum)
table.reserve(2); }
CHECK (0==checksum);
cout << ".\n..install one element at index[0]\n";
table.push_back(HO());
CHECK (0==checksum);
create_contained_object (table[0]); // switches into "managed" state
CHECK (0 < checksum);
int theSum = checksum;
cout << ".\n..*** resize table to 16 elements\n";
for (uint i=0; i<15; ++i)
table.push_back(HO());
CHECK (theSum==checksum);
}
CHECK (0==checksum);
}
template<class HO>
void
checkErrorHandling()
{
CHECK (0==checksum);
{
typedef typename Table<HO>::Type Vect;
Vect table(5);
table.reserve(5);
CHECK (0==checksum);
create_contained_object (table[2]);
create_contained_object (table[4]);
CHECK (0 < checksum);
int theSum = checksum;
cout << ".\n.throw some exceptions...\n";
throw_in_ctor = true;
try
{
create_contained_object (table[3]);
NOTREACHED ();
}
catch (int val)
{
CHECK (theSum < checksum);
checksum -= val;
CHECK (theSum==checksum);
}
CHECK ( table[2]);
CHECK (!table[3]); // not created because of exception
CHECK ( table[4]);
throw_in_ctor = false;
throw_in_transfer=true; // can do this only when using ScopedHolder
try
{
table.resize(10);
}
catch (int val)
{
CHECK ( table.size() < 10);
}
CHECK (theSum == checksum);
throw_in_transfer=false;
}
CHECK (0==checksum);
}
}; };
LAUNCHER (ScopedHolderTransfer_test, "unit common");
typedef ScopedHolder<FixedDummy> HolderD;
typedef ScopedPtrHolder<FixedDummy> PtrHolderD;
}// namespace test
template<class HOL>
} // namespace lib struct Table
{
typedef Allocator_TransferNoncopyable<HOL> Allo;
typedef typename std::vector<HOL,Allo> Type;
};
}//(End) test helpers
/**********************************************************************************
* @test growing a vector containing noncopyable objects wrapped into ScopedHolder
* instances. This requires the use of a custom allocator, invoking a
* \c transfer_control() function to be provided for the concrete
* noncopyable class type, being invoked when the vector
* needs to reallocate.
*/
class ScopedHolderTransfer_test : public Test
{
virtual void
run (Arg)
{
cout << "checking ScopedHolder<Dummy>...\n";
buildVector<HolderD>();
growVector<HolderD>();
checkErrorHandling<HolderD>();
cout << "checking ScopedPtrHolder<Dummy>...\n";
buildVector<PtrHolderD>();
growVector<PtrHolderD>();
checkErrorHandling<PtrHolderD>();
}
void create_contained_object (HolderD& holder) { holder.create(); }
void create_contained_object (PtrHolderD& holder) { holder.reset(new FixedDummy()); }
template<class HO>
void
buildVector()
{
CHECK (0==checksum);
{
typedef typename Table<HO>::Type Vect;
Vect table(50);
CHECK (0==checksum);
for (uint i=0; i<10; ++i)
create_contained_object (table[i]);
CHECK (0 < checksum);
CHECK ( table[9]);
CHECK (!table[10]);
Dummy *rawP = table[5].get();
CHECK (rawP);
CHECK (table[5]);
CHECK (rawP == &(*table[5]));
CHECK (rawP->add(-555) == table[5]->add(-555));
}
CHECK (0==checksum);
}
template<class HO>
void
growVector()
{
CHECK (0==checksum);
{
typedef typename Table<HO>::Type Vect;
Vect table;
table.reserve(2);
CHECK (0==checksum);
cout << ".\n..install one element at index[0]\n";
table.push_back(HO());
CHECK (0==checksum);
create_contained_object (table[0]); // switches into "managed" state
CHECK (0 < checksum);
int theSum = checksum;
cout << ".\n..*** resize table to 16 elements\n";
for (uint i=0; i<15; ++i)
table.push_back(HO());
CHECK (theSum==checksum);
}
CHECK (0==checksum);
}
template<class HO>
void
checkErrorHandling()
{
CHECK (0==checksum);
{
typedef typename Table<HO>::Type Vect;
Vect table(5);
table.reserve(5);
CHECK (0==checksum);
create_contained_object (table[2]);
create_contained_object (table[4]);
CHECK (0 < checksum);
int theSum = checksum;
cout << ".\n.throw some exceptions...\n";
throw_in_ctor = true;
try
{
create_contained_object (table[3]);
NOTREACHED ();
}
catch (int val)
{
CHECK (theSum < checksum);
checksum -= val;
CHECK (theSum==checksum);
}
CHECK ( table[2]);
CHECK (!table[3]); // not created because of exception
CHECK ( table[4]);
throw_in_ctor = false;
throw_in_transfer=true; // can do this only when using ScopedHolder
try
{
table.resize(10);
}
catch (int val)
{
CHECK ( table.size() < 10);
}
CHECK (theSum == checksum);
throw_in_transfer=false;
}
CHECK (0==checksum);
}
};
LAUNCHER (ScopedHolderTransfer_test, "unit common");
}} // namespace lib::test

View file

@ -78,7 +78,7 @@ namespace test{
* *
* @see CommandRegistry * @see CommandRegistry
* @see command-registry-test.cpp * @see command-registry-test.cpp
* @see allocationclustertest.cpp * @see allocation-cluster-test.cpp
*/ */
class TypedAllocationManager_test : public Test class TypedAllocationManager_test : public Test
{ {

View file

@ -32,132 +32,130 @@
namespace lib { namespace lib {
namespace test { namespace test {
using ::Test; using ::Test;
using std::vector; using std::vector;
using std::cout; using std::cout;
namespace { // extending the Dummy for our special purpose.... namespace { // extending the Dummy for our special purpose....
class TransDummy class TransDummy
: public Dummy : public Dummy
{
public:
TransDummy()
{
TRACE (test, "CTOR TransDummy() --> this=%p", this);
setVal(0); // we use val_==0 to mark the "empty" state
}
~TransDummy()
{
TRACE (test, "DTOR ~TransDummy() this=%p", this);
}
/* to make Dummy usable within vector, we need to provide
* \em special copy operations, an operator bool() and
* a transfer_control friend function to be used by
* our special allocator.
*/
TransDummy (const TransDummy& o)
: Dummy()
{
TRACE (test, "COPY-ctor TransDummy( ref=%p ) --> this=%p", &o,this);
CHECK (!o, "protocol violation: real copy operations inhibited");
}
TransDummy&
operator= (TransDummy const& ref)
{
TRACE (test, "COPY target=%p <-- source=%p", this,&ref);
CHECK (!(*this));
CHECK (!ref, "protocol violation: real copy operations inhibited");
return *this;
}
void
setup (int x=0)
{
setVal (x? x : (rand() % 10000));
TRACE (test, "CREATE val=%d ---> this=%p", getVal(),this);
}
// define implicit conversion to "bool" the naive way...
operator bool() const
{
return 0!=getVal();
}
friend void transfer_control (TransDummy& from, TransDummy& to);
};
void
transfer_control (TransDummy& from, TransDummy& to)
{ {
TRACE (test, "TRANSFER target=%p <-- source=%p", &to,&from); public:
CHECK (!to, "protocol violation: target already manages another object"); TransDummy()
to.setVal (from.getVal());
from.setVal(0);
}
typedef Allocator_TransferNoncopyable<TransDummy> Allo;
typedef vector<TransDummy, Allo> TransDummyVector;
}
/**********************************************************************************
* @test growing (re-allocating) a vector with noncopyable objects, with the
* help of a special Allocator and a custom \c transfer_control operation
* provided by the contained objects. The idea is to allow some special
* copy-operations for the purpose of re-allocations within the vector,
* without requiring the object to be really copyable.
*/
class VectorTransfer_test : public Test
{
virtual void
run (Arg)
{ {
cout << "\n..setup table space for 2 elements\n"; TRACE (test, "CTOR TransDummy() --> this=%p", this);
TransDummyVector table; setVal(0); // we use val_==0 to mark the "empty" state
table.reserve(2);
CHECK (0==checksum);
cout << "\n..install one element at index[0]\n";
table.push_back(TransDummy());
CHECK (0==checksum);
table[0].setup(); // switches into "managed" state
CHECK (0 < checksum);
int theSum = checksum;
cout << "\n..*** resize table to 5 elements\n";
table.resize(5);
CHECK (theSum==checksum);
cout << "\n..install another element\n";
table[3].setup(375);
CHECK (theSum+375==checksum);
cout << "\n..kill all elements....\n";
table.clear();
CHECK (0==checksum);
} }
~TransDummy()
{
TRACE (test, "DTOR ~TransDummy() this=%p", this);
}
/* to make Dummy usable within vector, we need to provide
* \em special copy operations, an operator bool() and
* a transfer_control friend function to be used by
* our special allocator.
*/
TransDummy (const TransDummy& o)
: Dummy()
{
TRACE (test, "COPY-ctor TransDummy( ref=%p ) --> this=%p", &o,this);
CHECK (!o, "protocol violation: real copy operations inhibited");
}
TransDummy&
operator= (TransDummy const& ref)
{
TRACE (test, "COPY target=%p <-- source=%p", this,&ref);
CHECK (!(*this));
CHECK (!ref, "protocol violation: real copy operations inhibited");
return *this;
}
void
setup (int x=0)
{
setVal (x? x : (rand() % 10000));
TRACE (test, "CREATE val=%d ---> this=%p", getVal(),this);
}
// define implicit conversion to "bool" the naive way...
operator bool() const
{
return 0!=getVal();
}
friend void transfer_control (TransDummy& from, TransDummy& to);
}; };
LAUNCHER (VectorTransfer_test, "unit common");
void
}// namespace test transfer_control (TransDummy& from, TransDummy& to)
{
} // namespace lib TRACE (test, "TRANSFER target=%p <-- source=%p", &to,&from);
CHECK (!to, "protocol violation: target already manages another object");
to.setVal (from.getVal());
from.setVal(0);
}
typedef Allocator_TransferNoncopyable<TransDummy> Allo;
typedef vector<TransDummy, Allo> TransDummyVector;
}
/**********************************************************************************
* @test growing (re-allocating) a vector with noncopyable objects, with the
* help of a special Allocator and a custom \c transfer_control operation
* provided by the contained objects. The idea is to allow some special
* copy-operations for the purpose of re-allocations within the vector,
* without requiring the object to be really copyable.
*/
class VectorTransfer_test : public Test
{
virtual void
run (Arg)
{
cout << "\n..setup table space for 2 elements\n";
TransDummyVector table;
table.reserve(2);
CHECK (0==checksum);
cout << "\n..install one element at index[0]\n";
table.push_back(TransDummy());
CHECK (0==checksum);
table[0].setup(); // switches into "managed" state
CHECK (0 < checksum);
int theSum = checksum;
cout << "\n..*** resize table to 5 elements\n";
table.resize(5);
CHECK (theSum==checksum);
cout << "\n..install another element\n";
table[3].setup(375);
CHECK (theSum+375==checksum);
cout << "\n..kill all elements....\n";
table.clear();
CHECK (0==checksum);
}
};
LAUNCHER (VectorTransfer_test, "unit common");
}} // namespace lib::test