some naming cleanup and namespace indentation fixes
This commit is contained in:
parent
3f1b7651e9
commit
7fc462209e
39 changed files with 1732 additions and 1741 deletions
|
|
@ -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 \
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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
|
||||||
138
src/lib/singleton-policies.hpp
Normal file
138
src/lib/singleton-policies.hpp
Normal 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
|
||||||
|
|
@ -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"
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 \
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
||||||
128
src/proc/mobject/session/defs-manager.hpp
Normal file
128
src/proc/mobject/session/defs-manager.hpp
Normal 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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 \
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
|
||||||
176
tests/components/proc/mobject/session/defs-manager-impl-test.cpp
Normal file
176
tests/components/proc/mobject/session/defs-manager-impl-test.cpp
Normal 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
|
||||||
204
tests/components/proc/mobject/session/defs-manager-test.cpp
Normal file
204
tests/components/proc/mobject/session/defs-manager-test.cpp
Normal 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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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 \
|
||||||
|
|
|
||||||
234
tests/lib/allocation-cluster-test.cpp
Normal file
234
tests/lib/allocation-cluster-test.cpp
Normal 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
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue