remove any use of boost::function in favour of <tr1/functional>

this resolves some long standing problems with ambiguous placeholders
closes Ticket #161
This commit is contained in:
Fischlurch 2009-07-19 05:47:36 +02:00
parent 3ecd8047df
commit 5f0c9e209e
45 changed files with 854 additions and 883 deletions

View file

@ -61,7 +61,7 @@ namespace lumiera {
* define and register a callback for a specific lifecycle event.
* The purpose of this class is to be defined as a static variable in the implementation
* of some subsystem (i.e. in the cpp file), providing the ctor with the pointer to a
* callback function. Thus the callback gets enrolled when the corresponding object file
* callback function. Thus the callback gets enroled when the corresponding object file
* is loaded. The event ON_BASIC_INIT is handled specifically, firing off the referred
* callback function as soon as possible. All other labels are just arbitrary (string)
* constants and it is necessary that "someone" cares to fire off the lifecycle events

View file

@ -41,7 +41,6 @@ liblumiera_la_SOURCES = \
$(liblumiera_la_srcdir)/lifecycle.cpp \
$(liblumiera_la_srcdir)/nobug-init.cpp \
$(liblumiera_la_srcdir)/util.cpp \
$(liblumiera_la_srcdir)/visitor.cpp \
$(liblumiera_la_srcdir)/query.cpp \
$(liblumiera_la_srcdir)/streamtype.cpp \
$(liblumiera_la_srcdir)/test/testoption.cpp \

View file

@ -46,7 +46,7 @@ namespace lumiera {
void
LifecycleHook::add (Symbol eventLabel, Callback callbackFun)
{
bool isNew = LifecycleRegistry::instance().enroll (eventLabel,callbackFun);
bool isNew = LifecycleRegistry::instance().enrol (eventLabel,callbackFun);
if (isNew && !strcmp(ON_BASIC_INIT, eventLabel))
callbackFun(); // when this code executes,

View file

@ -74,7 +74,7 @@ namespace lumiera {
/** @note only one copy of each distinct callback remembered */
bool enroll (const string label, Hook toCall)
bool enrol (const string label, Hook toCall)
{
return table_[label]
.insert(toCall)

View file

@ -54,7 +54,7 @@ namespace lumiera {
void
normaliseID (string& id)
{
id = util::sanitize(id);
id = util::sanitise(id);
if (isnil(id) || !is_alpha (id[0]))
id.insert(0, "o");

View file

@ -66,7 +66,7 @@ namespace lumiera {
{
/** ensure standard format for a given id string.
* Trim, sanitize and ensure the first letter is lower case.
* Trim, sanitise and ensure the first letter is lower case.
* @note modifies the given string ref in place
*/
void normaliseID (string& id);

View file

@ -84,7 +84,7 @@ namespace test
class Launch : public Launcher
{
public:
Launch (string testID, string groups) { Suite::enroll (this,testID,groups); };
Launch (string testID, string groups) { Suite::enrol (this,testID,groups); };
virtual auto_ptr<Test> operator() () { return auto_ptr<Test> (new TEST ); };
};

View file

@ -39,30 +39,30 @@
namespace test
{
namespace test {
using std::map;
using std::vector;
using std::auto_ptr;
using std::tr1::shared_ptr;
using boost::algorithm::trim;
using util::isnil;
using util::contains;
typedef map<string, Launcher*> TestMap;
typedef shared_ptr<TestMap> PTestMap;
typedef map<string,PTestMap> GroupMap;
/** helper to collect and manage the test cases.
* Every testcase class should create a Launch instance
* which causes a call to Suite::enroll(), so we can add a
* which causes a call to Suite::enrol(), so we can add a
* pointer to this Launcher into a map indexed by the
* provided testIDs and groupIDs.
* This enables us to build a Suite instance for any
* requested group and then instantiiate and invoke
* requested group and then instantiate and invoke
* individual testcases accordingly.
*/
class Registry
@ -93,16 +93,16 @@ namespace test
/** register the given test-launcher, so it can be later accessed
* either as a member of one of the specified groups, or direcly
* either as a member of one of the specified groups, or directly
* by its testID. Any test is automatically added to the groupID
* #ALLGROUP
* @param test the Launcher object used to run this test
* @param testID unique ID to refere to this test (will be used as std::map key)
* @param testID unique ID to refer to this test (will be used as std::map key)
* @param groups List of group-IDs selected by whitespace
*
*/
void
Suite::enroll (Launcher* test, string testID, string groups)
Suite::enrol (Launcher* test, string testID, string groups)
{
REQUIRE( test );
REQUIRE( !isnil(testID) );
@ -112,7 +112,7 @@ namespace test
while (ss >> group )
testcases.add2group(test, testID, group);
// Magic: allways add any testcas to groupID="ALL"
// Magic: always add any testcase to groupID="ALL"
testcases.add2group(test,testID, ALLGROUP);
}
@ -122,7 +122,7 @@ namespace test
/** create a suite comprised of all the testcases
* previously @link #enroll() registered @endlink with this
* previously @link #enrol() registered @endlink with this
* this group.
* @see #run() running tests in a Suite
*/
@ -138,14 +138,14 @@ namespace test
}
#define VALID(test,testID) \
ASSERT ((test), "NULL testcase laucher for test '%s' found in testsuite '%s'", groupID_.c_str(),testID.c_str());
ASSERT ((test), "NULL testcase launcher for test '%s' found in testsuite '%s'", groupID_.c_str(),testID.c_str());
/** run all testcases contained in this Suite.
* The first argument in the commandline, if present,
* will select one single testcase with a matching ID.
* In case of invoking a single testcase, the given cmdline
* will be forwarded to the testcase, after removind the
* will be forwarded to the testcase, after removing the
* testcaseID from cmdline[0]. Otherwise, every testcase
* in this suite is invoked with a empty cmdline vector.
* @param cmdline ref to the vector of commandline tokens
@ -173,7 +173,7 @@ namespace test
} }
// no test-ID was specified.
// instantiiate all tests cases and execute them.
// Instantiate all tests cases and execute them.
for ( TestMap::iterator i=tests->begin(); i!=tests->end(); ++i )
{
std::cout << "\n ----------"<< i->first<< "----------\n";
@ -184,7 +184,7 @@ namespace test
}
/** print to stdout an ennumeration of all testcases in this suite,
/** print to stdout an enumeration of all testcases in this suite,
* in a format suitable for use with Cehteh's ./test.sh
*/
void
@ -195,7 +195,7 @@ namespace test
ASSERT (tests);
std::cout << "TESTING \"Component Test Suite: " << groupID_ << "\" ./test-components\n\n";
for ( TestMap::iterator i=tests->begin(); i!=tests->end(); ++i )
{
string key (i->first);
@ -214,7 +214,7 @@ namespace test
std::cout << "END\n";
}
}
} // namespace test

View file

@ -42,7 +42,7 @@ namespace test
/**
* Enables running a collection of tests.
* An internal registration service #enroll() is provided
* An internal registration service #enrol() is provided
* for the individual Test - inscances to be recognized as
* testcases. The groupID passed to the constructor selects
* all testcases declared as belonging to this Group.
@ -55,7 +55,7 @@ namespace test
Suite (string groupID);
void run (Arg cmdline);
void describe ();
static void enroll (Launcher *test, string testID, string groups);
static void enrol (Launcher *test, string testID, string groups);
static const string ALLGROUP;
};

View file

@ -24,8 +24,7 @@
#include "lib/util.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <tr1/functional>
using boost::algorithm::trim_right_copy_if;
using boost::algorithm::is_any_of;
@ -33,19 +32,21 @@ using boost::algorithm::is_alnum;
using boost::algorithm::is_space;
namespace util
{
namespace util {
typedef boost::function<bool(string::value_type)> ChPredicate;
ChPredicate operator! (ChPredicate p) { return ! boost::bind(p,_1); }
using std::tr1::function;
using std::tr1::placeholders::_1;
typedef function<bool(string::value_type)> ChPredicate;
ChPredicate operator! (ChPredicate p) { return ! bind(p,_1); }
// character classes used for sanitizing a string
// character classes used for sanitising a string
ChPredicate isValid (is_alnum() || is_any_of("-_.:+$'()@")); ///< characters to be retained
ChPredicate isPunct (is_space() || is_any_of(",;#*~´`?\\=/&%![]{}")); ///< punctuation to be replaced by '_'
string
sanitize (const string& org)
sanitise (const string& org)
{
string res (trim_right_copy_if(org, !isValid ));
string::iterator j = res.begin();

View file

@ -245,8 +245,9 @@ namespace util {
"mixed Ω garbage" --> 'mixed_garbage'
"Bääääh!!" --> 'Bh'
\endverbatim
* @see sanitised-identifier-test.cpp
*/
string sanitize (const string& org);
string sanitise (const string& org);

View file

@ -0,0 +1,217 @@
/*
VISITOR-DISPATCHER.hpp - visitor implementation details
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 LUMIERA_VISITOR_DISPATCHER_H
#define LUMIERA_VISITOR_DISPATCHER_H
#include "lib/error.hpp"
#include "lib/util.hpp"
#include "lib/sync-classlock.hpp"
#include "lib/singleton.hpp"
#include "lib/util.hpp"
#include <vector>
namespace lumiera {
namespace visitor {
using lib::ClassLock;
template<class TOOL> class Tag;
template<class TOOL, class TOOLImpl>
struct TagTypeRegistry
{
static Tag<TOOL> tag;
};
/**
* Type tag for concrete visiting tool classes.
* Used to access the previously registered dispatcher
* trampoline function when handling a visitor invocation.
*/
template<class TOOL>
class Tag
{
size_t tagID; ///< tag value
static size_t lastRegisteredID;
private:
static void
generateID (size_t& id)
{
ClassLock<Tag> guard();
if (!id)
id = ++lastRegisteredID;
}
public:
Tag() : tagID(0) { }
operator size_t() const { return tagID; }
template<class TOOLImpl>
static Tag&
get (TOOLImpl* const =0)
{
Tag& t = TagTypeRegistry<TOOL,TOOLImpl>::tag;
if (!t) generateID (t.tagID);
return t;
}
};
/** storage for the Tag registry for each concrete tool */
template<class TOOL, class TOOLImpl>
Tag<TOOL> TagTypeRegistry<TOOL,TOOLImpl>::tag;
template<class TOOL>
size_t Tag<TOOL>::lastRegisteredID (0);
/**
* For each possible call entry point via some subclass of the visitable hierarchy,
* we maintain a dispatcher table to keep track of all concrete tool implementations
* able to receive and process calls on objects of this subclass.
* @param TAR the concrete target (subclass) type within the visitable hierarchy
* @param TOOL the overall tool family (base class of all concrete tools)
*/
template<class TAR, class TOOL>
class Dispatcher
{
typedef typename TOOL::ReturnType ReturnType;
/** generator for Trampoline functions,
* used to dispatch calls down to the
* right "treat"-Function on the correct
* concrete tool implementation class
*/
template<class TOOLImpl>
static ReturnType
callTrampoline (TAR& obj, TOOL& tool)
{
// cast down to real implementation type
REQUIRE (INSTANCEOF (TOOLImpl, &tool));
TOOLImpl& toolObj = static_cast<TOOLImpl&> (tool);
// trigger (compile time) overload resolution
// based on concrete type, then dispatch the call.
// Note this may cause obj to be upcasted.
return toolObj.treat (obj);
}
typedef ReturnType (*Trampoline) (TAR&, TOOL& );
/** VTable for storing the Trampoline pointers */
std::vector<Trampoline> table_;
void
accomodate (size_t index)
{
ClassLock<Dispatcher> guard(); // note: this lock is also used for the singleton!
if (index > table_.size())
table_.resize (index); // performance bottleneck?? TODO: measure the real impact!
}
inline bool
is_known (size_t id)
{
return id<=table_.size() && table_[id-1];
}
inline void
storePtr (size_t id, Trampoline func)
{
REQUIRE (func);
REQUIRE (0 < id);
if (id>table_.size())
accomodate (id);
table_[id-1] = func;
}
inline Trampoline
storedTrampoline (size_t id)
{
if (id<=table_.size() && table_[id-1])
return table_[id-1];
else
return &errorHandler;
}
static ReturnType
errorHandler (TAR& target, TOOL& tool)
{
return tool.onUnknown (target);
}
public:
static Singleton<Dispatcher<TAR,TOOL> > instance;
inline ReturnType
forwardCall (TAR& target, TOOL& tool)
{
// get concrete type via tool's VTable
Tag<TOOL> index = tool.getTag();
return (*storedTrampoline(index)) (target, tool);
}
template<class TOOLImpl>
inline void
enrol(TOOLImpl* typeref)
{
Tag<TOOL>& index = Tag<TOOL>::get (typeref);
if (is_known (index))
return;
else
{
Trampoline func = &callTrampoline<TOOLImpl>;
storePtr (index, func);
}
}
};
/** storage for the dispatcher table(s) */
template<class TAR, class TOOL>
Singleton<Dispatcher<TAR,TOOL> > Dispatcher<TAR,TOOL>::instance;
}} // namespace lumiera::visitor
#endif

View file

@ -1,5 +1,5 @@
/*
VISITOR.hpp - Acyclic Visitor library
VISITOR-POLICIES.hpp - Acyclic Visitor library
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
@ -21,7 +21,7 @@
*/
/** @file visitorpolicies.hpp
/** @file visitor-policies.hpp
** Policies usable for configuring the lumiera::visitor::Tool for different kinds of error handling.
** @see buildertool.hpp for another flavour (calling an catch-all-function there)
**
@ -29,49 +29,46 @@
#ifndef LUMIERA_VISITORPOLICIES_H
#define LUMIERA_VISITORPOLICIES_H
#ifndef LUMIERA_VISITOR_POLICIES_H
#define LUMIERA_VISITOR_POLICIES_H
#include "lib/error.hpp"
namespace lumiera
{
namespace visitor
namespace lumiera {
namespace visitor {
/**
* Policy returning just the default return value in case
* of encountering an unknown Visitor (typically caused by
* adding a new class to the visitable hierarchy)
*/
template<class RET>
struct UseDefault
{
/**
* Policy returning just the default return value in case
* of encountering an unknown Visitor (typically caused by
* adding a new class to the visitable hierarchy)
*/
template<class RET>
struct UseDefault
{
template<class TAR>
RET
onUnknown (TAR&)
{
return RET();
}
};
/**
* Policy to throw when encountering an unknown visiting tool
*/
template<class RET>
struct ThrowException
{
template<class TAR>
RET
onUnknown (TAR&)
{
throw lumiera::error::Config("unable to decide what tool operation to call");
}
};
} // namespace visitor
} // namespace lumiera
template<class TAR>
RET
onUnknown (TAR&)
{
return RET();
}
};
/**
* Policy to throw when encountering an unknown visiting tool
*/
template<class RET>
struct ThrowException
{
template<class TAR>
RET
onUnknown (TAR&)
{
throw lumiera::error::Config("unable to decide what tool operation to call");
}
};
}} // namespace lumiera::visitor
#endif

View file

@ -1,35 +0,0 @@
/*
Vistitable,Tool,Applicable - Acyclic Visitor library
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/visitor.hpp"
namespace lumiera
{
namespace visitor
{
} // namespace visitor
} // namespace lumiera

View file

@ -36,11 +36,11 @@ Credits for many further implementation ideas go to
/** @file visitor.hpp
** A library implementation of the <b>Visitor Pattern</b> taylored specifically
** A library implementation of the <b>Visitor Pattern</b> tailored specifically
** to Lumiera's needs within the Proc Layer. Visitor enables <b>double dispatch</b>
** calls, based both on the concrete type of some target object and the concrete type of
** a tool object being applied to this target. The code carrying out this tool application
** (and thus triggering the double dispatch) need not know any of these concret types and is
** (and thus triggering the double dispatch) need not know any of these concrete types and is
** thus completely decoupled form implementation details encapsulated within the visiting tool.
** The visiting tool implementation class provides specific "treat(ConcreteVisitable&)" functions,
** and this visitor lib will dispatch the call to the* correct "treat"-function based on the
@ -60,13 +60,13 @@ Credits for many further implementation ideas go to
** <li>any concrete Visitable subclass wanting to be treated by some concrete tool
** needs to use the DECLARE_PROCESSABLE_BY(TOOLBASE) macro. By this, it gets an
** virtual \code apply(TOOLBASE&) function. Otherwise, it will be treated by the
** interface of the next base clas using this macro.</li>
** interface of the next base class using this macro.</li>
** </ul>
** For design questions and more detailed implementation notes, see the Proc Layer Tiddly Wiki.
**
** @see visitingtooltest.cpp test cases using our lib implementation
** @see BuilderTool one especially important instantiiation
** @see visitordispatcher.hpp
** @see BuilderTool one especially important instantiation
** @see visitor-dispatcher.hpp
** @see typelist.hpp
**
*/
@ -76,158 +76,154 @@ Credits for many further implementation ideas go to
#ifndef LUMIERA_VISITOR_H
#define LUMIERA_VISITOR_H
#include "lib/visitorpolicies.hpp"
#include "lib/visitordispatcher.hpp"
#include "lib/visitor-policies.hpp"
#include "lib/visitor-dispatcher.hpp"
#include "lib/meta/typelist.hpp"
namespace lumiera
{
namespace visitor
namespace lumiera {
namespace visitor {
/**
* Marker interface / base class for all "visiting tools".
* When applying such a tool to some concrete instance
* derived from Visitable, a special function treating
* this concrete subclass will be selected on the
* concrete visiting tool instance.
*/
template
< typename RET = void
, template <class> class ERR = UseDefault
>
class Tool : public ERR<RET>
{
public:
typedef RET ReturnType; ///< Tool function invocation return type
typedef Tool ToolBase; ///< for templating the Tag and Dispatcher
virtual ~Tool () { }; ///< use RTTI for all visiting tools
/** allows discovery of the concrete Tool type when dispatching a
* visitor call. Can be implemented by inheriting from ToolTag */
virtual Tag<ToolBase> getTag() = 0;
};
/**
* Marker interface / base class for all "visiting tools".
* When applying such a tool to some concrete instance
* derived from Visitable, a special function treating
* this concrete subclass will be selected on the
* concrete visiting tool instance.
*/
template
< typename RET = void,
template <class> class ERR = UseDefault
>
class Tool : public ERR<RET>
{
public:
typedef RET ReturnType; ///< Tool function invocation return type
typedef Tool ToolBase; ///< for templating the Tag and Dispatcher
virtual ~Tool () { }; ///< use RTTI for all visiting tools
/** allows discovery of the concrete Tool type when dispatching a
* visitor call. Can be implemented by inheriting from ToolTag */
virtual Tag<ToolBase> getTag() = 0;
};
/**
* Marker template to declare that some "visiting tool"
* wants to treat a set of concrete Visitable classes.
*
* Each "first class" concrete visiting tool implementation has
* to inherit from an instance of this template parametrized with
* the desired types; for each of the mentioned types, calls will
* be dispatched to the tool implementation. (To make it clear:
* Calls to all other types not marked by such an "Applicable"
* won't ever be dispatched to this tool class.).
* A Sideeffect of inheriting from such an "Applicable" is that
* the tool gets an unique Tag entry, which is used internally
* as index in the dispatcher tables. And the automatic ctor call
* allows us to record the type information and preregister the
* dispatcher entry.
*/
template
< class TOOLImpl, // concrete tool implementation type
class TYPES, // List of applicable Types goes here...
class BASE=Tool<> // "visiting tool" base class
>
class Applicable;
template // recursion end: inherit from BASE
< class TOOLImpl,
class BASE
>
class Applicable<TOOLImpl, typelist::NullType, BASE>
: public BASE
{ }
;
template
< class TOOLImpl,
class TAR, class TYPES,
class BASE
>
class Applicable<TOOLImpl, typelist::Node<TAR, TYPES>, BASE>
: public Applicable<TOOLImpl, TYPES, BASE>
{
typedef typename BASE::ToolBase ToolBase;
protected:
virtual ~Applicable () {}
Applicable ()
{
TOOLImpl* typeref = 0;
Dispatcher<TAR,ToolBase>::instance().enroll (typeref);
}
public:
virtual Tag<ToolBase>
getTag ()
{
TOOLImpl* typeref = 0;
return Tag<ToolBase>::get (typeref);
}
};
using typelist::Types; // convienience for the user of "Applicable"
/**
* Marker template to declare that some "visiting tool"
* wants to treat a set of concrete Visitable classes.
*
* Each "first class" concrete visiting tool implementation has
* to inherit from an instance of this template parametrised with
* the desired types; for each of the mentioned types, calls will
* be dispatched to the tool implementation. (To make it clear:
* Calls to all other types not marked by such an "Applicable"
* won't ever be dispatched to this tool class.).
* A Sideeffect of inheriting from such an "Applicable" is that
* the tool gets an unique Tag entry, which is used internally
* as index in the dispatcher tables. And the automatic ctor call
* allows us to record the type information and pre-register the
* dispatcher entry.
*/
template
< class TOOLImpl, // concrete tool implementation type
class TYPES, // List of applicable Types goes here...
class BASE=Tool<> // "visiting tool" base class
>
class Applicable;
template // recursion end: inherit from BASE
< class TOOLImpl,
class BASE
>
class Applicable<TOOLImpl, typelist::NullType, BASE>
: public BASE
{ }
;
template
< class TOOLImpl,
class TAR, class TYPES,
class BASE
>
class Applicable<TOOLImpl, typelist::Node<TAR, TYPES>, BASE>
: public Applicable<TOOLImpl, TYPES, BASE>
{
/**
* Marker interface or base class for all "Visitables".
* Concrete types to be treated by a "visiting tool" derive from
* this interface and need to implement an #apply(Tool&), forwarding
* to the (internal, static, templated) #dispatchOp. This is done
* best by using the #DEFINE_PROCESSABLE_BY macro.
*/
template
< class TOOL = Tool<>
>
class Visitable
{
protected:
virtual ~Visitable () { };
/// @note may differ from TOOL
typedef typename TOOL::ToolBase ToolBase;
typedef typename TOOL::ReturnType ReturnType;
/** @internal used by the #DEFINE_PROCESSABLE_BY macro.
* Dispatches to the actual operation on the
* "visiting tool" (visitor implementation)
* Note: creates a context templated on concrete TAR.
*/
template <class TAR>
static inline ReturnType
dispatchOp (TAR& target, TOOL& tool)
{
return Dispatcher<TAR,ToolBase>::instance().forwardCall (target,tool);
}
public:
/** to be defined by the DEFINE_PROCESSABLE_BY macro
* in all classes wanting to be treated by some tool */
virtual ReturnType apply (TOOL&) = 0;
};
typedef typename BASE::ToolBase ToolBase;
protected:
virtual ~Applicable () {}
Applicable ()
{
TOOLImpl* typeref = 0;
Dispatcher<TAR,ToolBase>::instance().enrol (typeref);
}
public:
virtual Tag<ToolBase>
getTag ()
{
TOOLImpl* typeref = 0;
return Tag<ToolBase>::get (typeref);
}
};
using typelist::Types; // convenience for the user of "Applicable"
/**
* Marker interface or base class for all "Visitables".
* Concrete types to be treated by a "visiting tool" derive from
* this interface and need to implement an #apply(Tool&), forwarding
* to the (internal, static, templated) #dispatchOp. This is done
* best by using the #DEFINE_PROCESSABLE_BY macro.
*/
template
< class TOOL = Tool<>
>
class Visitable
{
protected:
virtual ~Visitable () { };
/// @note may differ from TOOL
typedef typename TOOL::ToolBase ToolBase;
typedef typename TOOL::ReturnType ReturnType;
/** @internal used by the #DEFINE_PROCESSABLE_BY macro.
* Dispatches to the actual operation on the
* "visiting tool" (visitor implementation)
* Note: creates a context templated on concrete TAR.
*/
template <class TAR>
static inline ReturnType
dispatchOp (TAR& target, TOOL& tool)
{
return Dispatcher<TAR,ToolBase>::instance().forwardCall (target,tool);
}
public:
/** to be defined by the DEFINE_PROCESSABLE_BY macro
* in all classes wanting to be treated by some tool */
virtual ReturnType apply (TOOL&) = 0;
};
/** mark a Visitable subclass as actually treatable by some
/** mark a Visitable subclass as actually treat-able by some
* "visiting tool" base interface. Defines the apply-function,
* which is the actual access point to invoke the visiting
*/
#define DEFINE_PROCESSABLE_BY(TOOL) \
virtual ReturnType apply (TOOL& tool) \
{ return dispatchOp (*this, tool); }
} // namespace visitor
} // namespace lumiera
}} // namespace lumiera::visitor
#endif

View file

@ -1,219 +0,0 @@
/*
VISITORDISPATCHER.hpp - visitor implementation details
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 LUMIERA_VISITORDISPATCHER_H
#define LUMIERA_VISITORDISPATCHER_H
#include "lib/error.hpp"
#include "lib/util.hpp"
#include "lib/sync-classlock.hpp"
#include "lib/singleton.hpp"
#include "lib/util.hpp"
#include <vector>
namespace lumiera {
namespace visitor {
using lib::ClassLock;
template<class TOOL> class Tag;
template<class TOOL, class TOOLImpl>
struct TagTypeRegistry
{
static Tag<TOOL> tag;
};
/**
* Type tag for concrete visiting tool classes.
* Used to access the previously registered dispatcher
* trampoline function when handling a visitor invocation.
*/
template<class TOOL>
class Tag
{
size_t tagID; ///< tag value
static size_t lastRegisteredID;
private:
static void
generateID (size_t& id)
{
ClassLock<Tag> guard();
if (!id)
id = ++lastRegisteredID;
}
public:
Tag() : tagID(0) { }
operator size_t() const { return tagID; }
template<class TOOLImpl>
static Tag&
get (TOOLImpl* const =0)
{
Tag& t = TagTypeRegistry<TOOL,TOOLImpl>::tag;
if (!t) generateID (t.tagID);
return t;
}
};
/** storage for the Tag registry for each concrete tool */
template<class TOOL, class TOOLImpl>
Tag<TOOL> TagTypeRegistry<TOOL,TOOLImpl>::tag;
template<class TOOL>
size_t Tag<TOOL>::lastRegisteredID (0);
/**
* For each possible call entry point via some subclass of the visitable hierarchy,
* we maintain a dispatcher table to keep track of all concrete tool implementations
* able to receive and process calls on objects of this subclass.
* @param TAR the concrete target (subclass) type within the visitable hierarchy
* @param TOOL the overall tool family (base class of all concrete tools)
*/
template<class TAR, class TOOL>
class Dispatcher
{
typedef typename TOOL::ReturnType ReturnType;
/** generator for Trampoline functions,
* used to dispatch calls down to the
* right "treat"-Function on the correct
* concrete tool implementation class
*/
template<class TOOLImpl>
static ReturnType
callTrampoline (TAR& obj, TOOL& tool)
{
// cast down to real implementation type
REQUIRE (INSTANCEOF (TOOLImpl, &tool));
TOOLImpl& toolObj = static_cast<TOOLImpl&> (tool);
// trigger (compile time) overload resolution
// based on concrete type, then dispatch the call.
// Note this may cause obj to be upcasted.
return toolObj.treat (obj);
}
typedef ReturnType (*Trampoline) (TAR&, TOOL& );
/** VTable for storing the Trampoline pointers */
std::vector<Trampoline> table_;
void
accomodate (size_t index)
{
ClassLock<Dispatcher> guard(); // note: this lock is also used for the singleton!
if (index > table_.size())
table_.resize (index); // performance bottleneck?? TODO: measure the real impact!
}
inline bool
is_known (size_t id)
{
return id<=table_.size() && table_[id-1];
}
inline void
storePtr (size_t id, Trampoline func)
{
REQUIRE (func);
REQUIRE (0 < id);
if (id>table_.size())
accomodate (id);
table_[id-1] = func;
}
inline Trampoline
storedTrampoline (size_t id)
{
if (id<=table_.size() && table_[id-1])
return table_[id-1];
else
return &errorHandler;
}
static ReturnType
errorHandler (TAR& target, TOOL& tool)
{
return tool.onUnknown (target);
}
public:
static Singleton<Dispatcher<TAR,TOOL> > instance;
inline ReturnType
forwardCall (TAR& target, TOOL& tool)
{
// get concrete type via tool's VTable
Tag<TOOL> index = tool.getTag();
return (*storedTrampoline(index)) (target, tool);
}
template<class TOOLImpl>
inline void
enroll(TOOLImpl* typeref)
{
Tag<TOOL>& index = Tag<TOOL>::get (typeref);
if (is_known (index))
return;
else
{
Trampoline func = &callTrampoline<TOOLImpl>;
storePtr (index, func);
}
}
};
/** storage for the dispatcher table(s) */
template<class TAR, class TOOL>
Singleton<Dispatcher<TAR,TOOL> > Dispatcher<TAR,TOOL>::instance;
} // namespace visitor
} // namespace lumiera
#endif

View file

@ -41,9 +41,8 @@
#include <vector>
#include <map>
#include <tr1/memory>
#include <boost/function.hpp>
#include <tr1/functional>
#include <boost/format.hpp>
#include <boost/bind.hpp>
#include "proc/common.hpp"

View file

@ -38,9 +38,8 @@
#include <vector>
#include <map>
#include <tr1/memory>
#include <boost/function.hpp>
#include <tr1/functional>
#include <boost/format.hpp>
#include <boost/bind.hpp>
#include "proc/common.hpp"
#include "proc/asset.hpp"

View file

@ -25,14 +25,14 @@
#include "proc/assetmanager.hpp"
#include "lib/util.hpp"
#include <boost/function.hpp>
#include <boost/format.hpp>
#include <boost/bind.hpp>
#include <tr1/functional>
using boost::bind;
using std::tr1::function;
using std::tr1::placeholders::_1;
using std::tr1::bind;
using boost::format;
using boost::function;
using util::contains;
using util::removeall;
using util::for_each;
@ -44,13 +44,13 @@ namespace asset {
using ::NOBUG_FLAG(memory);
NOBUG_CPP_DEFINE_FLAG_PARENT(assetmem, memory);
Asset::Ident::Ident(const string& n, const Category& cat, const string& o, const uint ver)
: name(util::sanitize (n)),
: name(util::sanitise (n)),
category(cat), org(o), version(ver)
{ }
/** Asset is a Interface class; usually, objects of
* concrete subclasses are created via specialized Factories
@ -147,7 +147,7 @@ namespace asset {
void
Asset::unlink ()
{
function<void(PAsset&)> forget_me = bind(&Asset::unregister, this,_1);
function<void(PAsset&)> forget_me = bind(&Asset::unregister, this, _1);
for_each (parents, forget_me);
dependants.clear();

View file

@ -41,7 +41,7 @@ namespace asset
const Asset::Ident
createClipIdent (const Media& mediaref)
{
string name (mediaref.ident.name + "-clip"); // TODO something sensible here; append number, sanitize etc.
string name (mediaref.ident.name + "-clip"); // TODO something sensible here; append number, sanitise etc.
Category category (mediaref.ident.category);
category.setPath(CLIP_SUBFOLDER);
return Asset::Ident (name, category,

View file

@ -50,7 +50,7 @@ namespace asset
namespace // Implementation details
{
/** helper: extract a name token out of a given path/filename
* @return sanitized token based on the name (minus extension),
* @return sanitised token based on the name (minus extension),
* empty string if not the common filename pattern.
*/
string extractName (const string& path)
@ -59,7 +59,7 @@ namespace asset
smatch match;
if (regex_search (path, match, pathname_pattern))
return util::sanitize (string (match[1]));
return util::sanitise (string (match[1]));
else
return "";
}

View file

@ -37,7 +37,7 @@ namespace asset
const Asset::Ident
createProxyIdent (const Asset::Ident& mediaref)
{
string name (mediaref.name + "-proxy"); // TODO something sensible here; append number, sanitize etc.
string name (mediaref.name + "-proxy"); // TODO something sensible here; append number, sanitise etc.
Category category (mediaref.category);
TODO ("put it in another subfolder within the same category??");
return Asset::Ident (name, category,

View file

@ -27,15 +27,13 @@
#include "lib/sync.hpp"
#include "lib/util.hpp"
#include <boost/function.hpp>
#include <tr1/functional>
#include <boost/format.hpp>
#include <boost/bind.hpp>
using std::tr1::static_pointer_cast;
using boost::function;
using std::tr1::function;
using std::tr1::placeholders::_1;
using boost::format;
using boost::bind;
using util::for_each;
using lumiera::Singleton;

View file

@ -48,6 +48,7 @@
#include "proc/control/argument-tuple-accept.hpp"
#include "proc/control/command-closure.hpp"
#include "proc/control/memento-tie.hpp"
#include "lib/opaque-holder.hpp"
//#include <tr1/memory>
//#include <boost/scoped_ptr.hpp>
@ -67,6 +68,8 @@ namespace control {
// using std::ostream;
using boost::noncopyable;
using std::string;
using lib::InPlaceBuffer;
namespace { // empty state marker objects for ArgumentHolder
@ -118,38 +121,49 @@ namespace control {
, ArgumentHolder<SIG,MEM> // target class providing the implementation
, CmdClosure // base class to inherit from
>
, noncopyable
, private noncopyable
{
Closure<SIG> arguments_;
MementoTie<SIG,MEM> memento_;
typedef typename Closure<SIG>::ArgTuple ArgTuple;
typedef Closure<SIG> ArgHolder;
typedef MementoTie<SIG,MEM> MemHolder;
typedef InPlaceBuffer<ArgHolder, sizeof(ArgHolder), MissingArguments<SIG> > ArgumentBuff;
typedef InPlaceBuffer<MemHolder, sizeof(MemHolder), UntiedMemento<SIG,MEM> > MementoBuff;
typedef typename ArgHolder::ArgTuple ArgTuple;
/* === proxied CmdClosure interface === */
/* ====== in-place storage buffers ====== */
ArgumentBuff arguments_;
MementoBuff memento_;
/* ==== proxied CmdClosure interface ==== */
virtual bool isValid () const
{
return bool(arguments_);
return arguments_->isValid();
}
virtual CmdFunctor bindArguments (CmdFunctor& func)
{
if (!arguments_)
if (!isValid())
throw lumiera::error::State ("Lifecycle error: can't bind functor, "
"command arguments not yet provided",
LUMIERA_ERROR_UNBOUND_ARGUMENTS);
return arguments_.bindArguments(func);
return arguments_->bindArguments(func);
}
virtual operator string() const
{
return "Command-State{ arguments="
+ (arguments_? string(arguments_) : "unbound")
+ (memento_ ? ", <memento> }" : "<no undo> }")
+ (*arguments_? string(*arguments_) : "unbound")
+ (*memento_ ? ", <memento> }" : "·noUNDO·}")
;
}
@ -161,13 +175,13 @@ namespace control {
* whereas the undo functions will be wired by #tie
*/
ArgumentHolder ()
: arguments_(MissingArguments<SIG>() )
, memento_(UntiedMemento<SIG,MEM>() )
: arguments_()
, memento_()
{ }
/** has undo state capturing been invoked? */
bool canUndo () const { return bool(memento_); }
bool empty () const { return !arguments_; }
bool canUndo () const { return memento_->isValid(); }
bool empty () const { return !arguments_->isValid(); }
/** store a new argument tuple within this ArgumentHolder,
@ -175,7 +189,7 @@ namespace control {
void
bindArg (ArgTuple argTup)
{
this->arguments_ = Closure<SIG> (argTup);
arguments_.template create<ArgHolder> (argTup);
}
@ -186,11 +200,21 @@ namespace control {
* @note any bound undo/capture functions based on the previously held MementoTie
* are silently invalidated; using them will likely cause memory corruption! */
MementoTie<SIG,MEM>&
tie (function<SIG_undo> const& undoFunc,
tiesi (function<SIG_undo> const& undoFunc,
function<SIG_cap> const& captureFunc)
{
return this->memento_ = MementoTie<SIG,MEM> (undoFunc,captureFunc);
return memento_.template create<MemHolder> (undoFunc,captureFunc);
}
/** @may be called directly referencing an function */
MementoTie<SIG,MEM>&
tie (SIG_undo& undoFunc, SIG_cap& captureFunc)
{
return tiesi ( function<SIG_undo>(undoFunc)
, function<SIG_cap>(captureFunc)
);
}
/** direct "backdoor" access to stored memento value.
@ -198,7 +222,7 @@ namespace control {
MEM&
memento ()
{
return memento_.getState();
return memento_->getState();
}
};

View file

@ -21,7 +21,7 @@
*/
/** @file nodewiringconfig.hpp
** Sometimes we need to coose a different implementation for dealing with
** Sometimes we need to choose a different implementation for dealing with
** some special cases. While for simple cases, just testing a flag or using a
** switch statement will do the job, matters get more difficult when we have to
** employ a completely different execution path for each of the different cases,
@ -29,14 +29,14 @@
** \par
** In the Lumiera render engine, right on the critical path, we need some glue code
** for invoking the predecessor nodes when pulling a given processing node. The actual
** sequence is quite dependant on the specific situation each node is wired up, regarding
** sequence is quite dependent on the specific situation each node is wired up, regarding
** buffer allocation, cache querying and the possible support for GPU processing and
** render farms. The solution is to define specialisations of a Strategy template
** using the specific configuration as template argument. Based on these, we can
** create a collection of factories, which in turn will build the internal wiring
** for the individual ProcNode instances in accordance to the situation determined
** for this node, expressed as a set of flags. As a net result, each node has an
** indivudual configuration (as opposed to creating a lot of hand-written individual
** individual configuration (as opposed to creating a lot of hand-written individual
** ProcNode subclasses), but parts of this configuration assembly is done already at
** compile time, allowing for additional checks by typing and for possible optimisation.
**
@ -54,7 +54,7 @@
#include "lib/util.hpp"
#include "lib/meta/configflags.hpp"
#include <boost/function.hpp>
#include <tr1/functional>
#include <bitset>
#include <map>
@ -95,9 +95,9 @@ namespace engine {
* configuration. The intention is to to drive this selection by
* the use of template metaprogramming for extracting all
* currently defined StateProxy object configurations.
* @todo as the facories live only within the enclosed table (map)
* @todo as the factories live only within the enclosed table (map)
* we could allocate them in-place. Unfortunately this is
* non-trivial, because the stl containers employ
* non-trivial, because the STL containers employ
* value semantics and thus do a copy even on insert.
* Thus, for now we use a shared_ptr to hold the factory
* heap allocated.
@ -108,7 +108,7 @@ namespace engine {
>
class ConfigSelector
{
typedef boost::function<FUNC> FacFunction;
typedef std::tr1::function<FUNC> FacFunction;
template<class FAC>
struct FactoryHolder

View file

@ -1,5 +1,5 @@
/*
ASSETDIAGNOSTICS.hpp - collection of test and debug helpers
ASSET-DIAGNOSTICS.hpp - collection of test and debug helpers
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
@ -20,8 +20,8 @@
*/
/** @file assetdiagnostics.hpp
** Small helper and diagnosic functions related to Asset and AssetManager
/** @file asset-diagnostics.hpp
** Small helper and diagnostic functions related to Asset and AssetManager
**
** @see assetmanager.hpp
** @see CreateAsset_test
@ -29,21 +29,22 @@
*/
#ifndef ASSET_ASSETDIAGNOSTICS_H
#define ASSET_ASSETDIAGNOSTICS_H
#ifndef ASSET_ASSET_DIAGNOSTICS_H
#define ASSET_ASSET_DIAGNOSTICS_H
#include "proc/assetmanager.hpp"
#include "lib/util.hpp"
#include <boost/format.hpp>
#include <boost/bind.hpp>
#include <tr1/functional>
#include <iostream>
using util::contains;
using util::for_each;
using std::tr1::placeholders::_1;
using std::tr1::bind;
using boost::format;
using boost::bind;
using std::string;
using std::cout;

View file

@ -30,7 +30,7 @@
#include "lib/query.hpp"
#include "proc/assetmanager.hpp"
#include "proc/mobject/session.hpp"
#include "proc/asset/assetdiagnostics.hpp"
#include "proc/asset/asset-diagnostics.hpp"
#include <boost/format.hpp>
#include <iostream>

View file

@ -29,7 +29,7 @@
#include "proc/asset/media.hpp"
#include "proc/asset/proc.hpp"
#include "proc/asset/assetdiagnostics.hpp"
#include "proc/asset/asset-diagnostics.hpp"
using util::isnil;
using std::string;

View file

@ -29,7 +29,7 @@
#include "proc/asset/media.hpp"
#include "proc/asset/proc.hpp"
#include "proc/asset/assetdiagnostics.hpp"
#include "proc/asset/asset-diagnostics.hpp"
using util::isnil;
using std::string;

View file

@ -23,7 +23,7 @@
#include "lib/test/run.hpp"
#include "proc/asset/testasset.hpp"
#include "proc/asset/assetdiagnostics.hpp"
#include "proc/asset/asset-diagnostics.hpp"
#include "proc/asset/media.hpp"
#include "proc/asset/clip.hpp"
#include "lib/util.hpp"

View file

@ -29,7 +29,7 @@
#include "proc/asset/media.hpp"
#include "proc/asset/proc.hpp"
#include "proc/asset/assetdiagnostics.hpp"
#include "proc/asset/asset-diagnostics.hpp"
using util::isnil;
using std::string;

View file

@ -28,7 +28,7 @@
#include "proc/assetmanager.hpp"
#include "proc/asset/media.hpp"
#include "proc/mobject/session/clip.hpp"
#include "proc/asset/assetdiagnostics.hpp"
#include "proc/asset/asset-diagnostics.hpp"
using util::contains;
using util::isnil;

View file

@ -28,7 +28,7 @@
#include "proc/asset/media.hpp"
#include "proc/asset/proc.hpp"
#include "proc/asset/assetdiagnostics.hpp"
#include "proc/asset/asset-diagnostics.hpp"
using util::isnil;
using std::string;

View file

@ -28,7 +28,7 @@
#include "proc/asset/media.hpp"
#include "proc/asset/proc.hpp"
#include "proc/asset/assetdiagnostics.hpp"
#include "proc/asset/asset-diagnostics.hpp"
using util::isnil;
using std::string;

View file

@ -28,11 +28,11 @@
#include "lib/util.hpp"
//#include <boost/format.hpp>
#include <boost/bind.hpp>
#include <tr1/functional>
#include <iostream>
//using boost::format;
using boost::bind;
using std::tr1::bind;
using util::contains;
using util::for_each;
using std::string;

View file

@ -59,14 +59,14 @@ test_lib_SOURCES = \
$(testlib_srcdir)/meta/config-flags-test.cpp \
$(testlib_srcdir)/query/queryutilstest.cpp \
$(testlib_srcdir)/removefromsettest.cpp \
$(testlib_srcdir)/sanitizedidentifiertest.cpp \
$(testlib_srcdir)/sanitised-identifier-test.cpp \
$(testlib_srcdir)/opaque-unchecked-buffer-test.cpp \
$(testlib_srcdir)/opaque-holder-test.cpp \
$(testlib_srcdir)/scoped-holder-test.cpp \
$(testlib_srcdir)/scopedholdertransfertest.cpp \
$(testlib_srcdir)/scoped-ptrvect-test.cpp \
$(testlib_srcdir)/singletonsubclasstest.cpp \
$(testlib_srcdir)/singletontest.cpp \
$(testlib_srcdir)/singleton-subclass-test.cpp \
$(testlib_srcdir)/singleton-test.cpp \
$(testlib_srcdir)/singletontestmocktest.cpp \
$(testlib_srcdir)/streamtypebasicstest.cpp \
$(testlib_srcdir)/streamtypelifecycletest.cpp \

View file

@ -39,6 +39,8 @@ namespace typelist{
namespace test {
using std::tr1::function;
using std::tr1::placeholders::_1;
using std::tr1::placeholders::_2;
using std::tr1::bind;

View file

@ -28,7 +28,7 @@
#include "lib/query.hpp"
#include "query/querydiagnostics.hpp"
#include <boost/bind.hpp>
#include <tr1/functional>
#include <iostream>
#include <cstdlib>
@ -38,7 +38,8 @@ using util::isnil;
using util::contains;
using util::for_each;
using boost::bind;
using std::tr1::placeholders::_1;
using std::tr1::bind;
using std::string;
using std::cout;

View file

@ -30,38 +30,34 @@ using std::cout;
namespace util
{
namespace test
{
namespace util {
namespace test {
class SanitizedIdentifier_test : public Test
{
virtual void run (Arg)
{
print_clean ("Word");
print_clean ("a Sentence");
print_clean ("trailing Withespace\n \t");
print_clean ("with a \t lot\n of Whitespace");
print_clean ("with\"much (punctuation)[]!");
print_clean ("§&Ω%€ leading garbage");
print_clean ("mixed Ω garbage");
print_clean ("Bääääh!!");
print_clean ("§&Ω%€");
}
/** @test print the original and the sanitized string */
void print_clean (const string org)
class SanitizedIdentifier_test : public Test
{
virtual void run (Arg)
{
cout << "'" << org << "' --> '" << sanitize(org) << "'\n";
print_clean ("Word");
print_clean ("a Sentence");
print_clean ("trailing Withespace\n \t");
print_clean ("with a \t lot\n of Whitespace");
print_clean ("with\"much (punctuation)[]!");
print_clean ("§&Ω%€ leading garbage");
print_clean ("mixed Ω garbage");
print_clean ("Bääääh!!");
print_clean ("§&Ω%€");
}
};
LAUNCHER (SanitizedIdentifier_test, "unit common");
} // namespace test
} // namespace util
/** @test print the original and the sanitised string */
void print_clean (const string org)
{
cout << "'" << org << "' --> '" << sanitise(org) << "'\n";
}
};
LAUNCHER (SanitizedIdentifier_test, "unit common");
}} // namespace util::test

View file

@ -0,0 +1,162 @@
/*
SingletonSubclass(Test) - actually creating a subclass of the Singleton Type
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 "testtargetobj.hpp"
#include "lib/singletonsubclass.hpp"
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>
#include <iostream>
using boost::lexical_cast;
using boost::format;
using util::isnil;
using std::string;
using std::cout;
namespace lumiera {
namespace test {
/**
* Target object to be instantiated as Singleton
* Allocates a variable amount of additional heap memory
* and prints diagnostic messages.
*/
class Interface : public TestTargetObj
{
public:
static int cnt;
static void setCountParam (uint c) { Interface::cnt = c; }
virtual string identify() { return "Interface"; }
protected:
Interface () : TestTargetObj(cnt) {}
virtual ~Interface() {}
friend class singleton::StaticCreate<Interface>;
friend class singleton::HeapCreate<Interface>;
};
int Interface::cnt = 0;
class Impl : public Interface
{
public:
virtual string identify() { return "Implementation"; }
};
// for checking the safety.....
class Impl_XXX : public Impl { };
class Unrelated { };
/*******************************************************************
* @test specialised variant of the Singleton Factory, for creating
* subclasses (implementation classes) without coupling the
* caller to the concrete class type.
* Expected results: an instance of the subclass is created.
* @see lumiera::Singleton
* @see lumiera::SingletonSubclassFactory
* @see lumiera::singleton::Adapter
*/
class SingletonSubclass_test : public Test
{
virtual void run(Arg arg)
{
uint num= isnil(arg)? 1 : lexical_cast<uint>(arg[1]);
cout << format("using the Singleton should create TargetObj(%d)...\n") % num;
Interface::setCountParam(num);
// marker to declare the concrete type to be created
singleton::UseSubclass<Impl> typeinfo;
// define an instance of the Singleton factory,
// Specialised to create the concrete Type passed in
SingletonSubclassFactory<Interface> instance (typeinfo);
// Now use the Singleton factory...
// Note: we get the Base type
Interface& t1 = instance();
Interface& t2 = instance();
ASSERT ( &t1 == &t2, "not a Singleton, got two different instances." );
cout << "calling a non-static method on the Singleton-"
<< t1.identify() << "\n"
<< string (t1) << "\n";
///////////////////////////////////////////////////////////////////////////////TODO: find a way to configure NoBug to throw in case of assertion
///////////////////////////////////////////////////////////////////////////////TODO: just for the proc tests. Also find a better way to configure
///////////////////////////////////////////////////////////////////////////////TODO: the non-release check. Then re-enable these checks...
//#ifdef DEBUG
// verify_error_detection ();
//#endif
}
void verify_error_detection ()
{
singleton::UseSubclass<Impl_XXX> more_special_type;
try
{
SingletonSubclassFactory<Interface> instance (more_special_type);
cout << "was able to re-configure the SingletonSubclassFactory "
"with another type. This should be detected in debug mode\n";
}
catch (...)
{
ASSERT (lumiera_error () == error::LUMIERA_ERROR_ASSERTION);
}
// Note: the following won't compile, because the "subclass" isn't a subclass...
//
// singleton::UseSubclass<Unrelated> yet_another_type;
// SingletonSubclassFactory<Interface> instance (yet_another_type);
}
};
/** Register this test class... */
LAUNCHER (SingletonSubclass_test, "unit common");
}} // namespace lumiera::test

View file

@ -0,0 +1,137 @@
/*
Singleton(Test) - unittest for our Singleton template
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 "testtargetobj.hpp"
#include "lib/singleton.hpp"
#include <tr1/functional>
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>
#include <iostream>
using std::tr1::function;
using boost::lexical_cast;
using boost::format;
using util::isnil;
using std::string;
using std::cout;
namespace lumiera {
namespace test {
/**
* Target object to be instantiated as Singleton
* Allocates a variable amount of additional heap memory
* and prints diagnostic messages.
*/
class TargetObj : public TestTargetObj
{
public:
static int cnt;
static void setCountParam (uint c) { TargetObj::cnt = c; }
protected:
TargetObj () : TestTargetObj(cnt) {}
friend class singleton::StaticCreate<TargetObj>;
friend class singleton::HeapCreate<TargetObj>;
};
int TargetObj::cnt = 0;
/*******************************************************************
* @test implement a Singleton class using our Singleton Template.
* Expected results: no memory leaks.
* @see lumiera::Singleton
* @see lumiera::singleton::StaticCreate
* @see lumiera::singleton::HeapCreate
*/
class Singleton_test : public Test
{
typedef function<TargetObj& ()> InstanceAccessFunc;
InstanceAccessFunc instance;
virtual void run(Arg arg)
{
uint num= isnil(arg)? 1 : lexical_cast<uint>(arg[1]);
testStaticallyAllocatedSingleton (num++);
testHeapAllocatedSingleton (num++);
}
/** @test parametrize the Singleton creation such as to create
* the single TargetObj instance as a static variable.
*/
void testStaticallyAllocatedSingleton (uint num)
{
SingletonFactory<TargetObj> single;
instance = single;
useInstance (num, "statically allocated");
}
/** @test parametrize the Singleton creation such as to create
* the single TargetObj instance allocated on the Heap
* and deleted automatically at application shutdown.
*/
void testHeapAllocatedSingleton (uint num)
{
SingletonFactory<TargetObj,singleton::HeapCreate> single;
instance = single;
useInstance (num, "heap allocated");
}
void useInstance (uint num, string kind)
{
cout << format("testing TargetObj(%d) as Singleton(%s)\n") % num % kind;
TargetObj::setCountParam(num);
TargetObj& t1 = instance();
TargetObj& t2 = instance();
ASSERT ( &t1 == &t2, "not a Singleton, got two different instances." );
cout << "calling a non-static method on the Singleton instance\n"
<< string (t1) << "\n";
}
};
/** Register this test class... */
LAUNCHER (Singleton_test, "unit common");
}} // namespace lumiera::test

View file

@ -1,166 +0,0 @@
/*
SingletonSubclass(Test) - actually creating a subclass of the Singleton Type
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 "testtargetobj.hpp"
#include "lib/singletonsubclass.hpp"
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>
#include <iostream>
using boost::lexical_cast;
using boost::format;
using util::isnil;
using std::string;
using std::cout;
namespace lumiera
{
namespace test
{
/**
* Target object to be instantiated as Singleton
* Allocates a variable amount of additional heap memory
* and prints diagnostic messages.
*/
class Interface : public TestTargetObj
{
public:
static int cnt;
static void setCountParam (uint c) { Interface::cnt = c; }
virtual string identify() { return "Interface"; }
protected:
Interface () : TestTargetObj(cnt) {}
virtual ~Interface() {}
friend class singleton::StaticCreate<Interface>;
friend class singleton::HeapCreate<Interface>;
};
int Interface::cnt = 0;
class Impl : public Interface
{
public:
virtual string identify() { return "Implementation"; }
};
// for checking the safety.....
class Impl_XXX : public Impl { };
class Unrelated { };
/*******************************************************************
* @test specialised variant of the Singleton Factory, for creating
* subclasses (implementation classes) without coupling the
* caller to the concrete class type.
* Expected results: an instance of the subclass is created.
* @see lumiera::Singleton
* @see lumiera::SingletonSubclassFactory
* @see lumiera::singleton::Adapter
*/
class SingletonSubclass_test : public Test
{
virtual void run(Arg arg)
{
uint num= isnil(arg)? 1 : lexical_cast<uint>(arg[1]);
cout << format("using the Singleton should create TargetObj(%d)...\n") % num;
Interface::setCountParam(num);
// marker to declare the concrete type to be created
singleton::UseSubclass<Impl> typeinfo;
// define an instance of the Singleton factory,
// Specialised to create the concrete Type passed in
SingletonSubclassFactory<Interface> instance (typeinfo);
// Now use the Singleton factory...
// Note: we get the Base type
Interface& t1 = instance();
Interface& t2 = instance();
ASSERT ( &t1 == &t2, "not a Singleton, got two different instances." );
cout << "calling a non-static method on the Singleton-"
<< t1.identify() << "\n"
<< string (t1) << "\n";
///////////////////////////////////////////////////////////////////////////////TODO: find a way to configure NoBug to throw in case of assertion
///////////////////////////////////////////////////////////////////////////////TODO: just for the proc tests. Also find a better way to configure
///////////////////////////////////////////////////////////////////////////////TODO: the non-release check. Then re-enable these checks...
//#ifdef DEBUG
// verify_error_detection ();
//#endif
}
void verify_error_detection ()
{
singleton::UseSubclass<Impl_XXX> more_special_type;
try
{
SingletonSubclassFactory<Interface> instance (more_special_type);
cout << "was able to re-configure the SingletonSubclassFactory "
"with another type. This should be detected in debug mode\n";
}
catch (...)
{
ASSERT (lumiera_error () == error::LUMIERA_ERROR_ASSERTION);
}
// Note: the following won't compile, because the "subclass" isn't a subclass...
//
// singleton::UseSubclass<Unrelated> yet_another_type;
// SingletonSubclassFactory<Interface> instance (yet_another_type);
}
};
/** Register this test class... */
LAUNCHER (SingletonSubclass_test, "unit common");
} // namespace test
} // namespace lumiera

View file

@ -1,139 +0,0 @@
/*
Singleton(Test) - unittest for our Singleton template
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 "testtargetobj.hpp"
#include "lib/singleton.hpp"
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>
#include <iostream>
using boost::lexical_cast;
using boost::format;
using util::isnil;
using std::string;
using std::cout;
namespace lumiera
{
namespace test
{
/**
* Target object to be instantiated as Singleton
* Allocates a variable amount of additional heap memory
* and prints diagnostic messages.
*/
class TargetObj : public TestTargetObj
{
public:
static int cnt;
static void setCountParam (uint c) { TargetObj::cnt = c; }
protected:
TargetObj () : TestTargetObj(cnt) {}
friend class singleton::StaticCreate<TargetObj>;
friend class singleton::HeapCreate<TargetObj>;
};
int TargetObj::cnt = 0;
/*******************************************************************
* @test implement a Singleton class using our Singleton Template.
* Expected results: no memory leaks.
* @see lumiera::Singleton
* @see lumiera::singleton::StaticCreate
* @see lumiera::singleton::HeapCreate
*/
class Singleton_test : public Test
{
typedef boost::function<TargetObj& ()> InstanceAccessFunc;
InstanceAccessFunc instance;
virtual void run(Arg arg)
{
uint num= isnil(arg)? 1 : lexical_cast<uint>(arg[1]);
testStaticallyAllocatedSingleton (num++);
testHeapAllocatedSingleton (num++);
}
/** @test parametrize the Singleton creation such as to create
* the single TargetObj instance as a static variable.
*/
void testStaticallyAllocatedSingleton (uint num)
{
SingletonFactory<TargetObj> single;
instance = single;
useInstance (num, "statically allocated");
}
/** @test parametrize the Singleton creation such as to create
* the single TargetObj instance allocated on the Heap
* and deleted automatically at application shutdown.
*/
void testHeapAllocatedSingleton (uint num)
{
SingletonFactory<TargetObj,singleton::HeapCreate> single;
instance = single;
useInstance (num, "heap allocated");
}
void useInstance (uint num, string kind)
{
cout << format("testing TargetObj(%d) as Singleton(%s)\n") % num % kind;
TargetObj::setCountParam(num);
TargetObj& t1 = instance();
TargetObj& t2 = instance();
ASSERT ( &t1 == &t2, "not a Singleton, got two different instances." );
cout << "calling a non-static method on the Singleton instance\n"
<< string (t1) << "\n";
}
};
/** Register this test class... */
LAUNCHER (Singleton_test, "unit common");
} // namespace test
} // namespace lumiera

View file

@ -50,7 +50,7 @@ namespace lumiera {
UNIMPLEMENTED ("setup basic dummy-type-info");
}
namespace // enroll this basic setup to be triggered when the type system is reset
namespace // enrol this basic setup to be triggered when the type system is reset
{
LifecycleHook _schedule_at_reset (ON_STREAMTYPES_RESET, &setup_basicDummyTypeInfo);
}

View file

@ -235,7 +235,7 @@ namespace lumiera
template<class TOOLImpl>
inline void
enroll(TOOLImpl* typeref)
enrol(TOOLImpl* typeref)
{
Tag<TOOL>& index = Tag<TOOL>::get (typeref);
if (is_known (index))
@ -272,7 +272,7 @@ namespace lumiera
Applicable ()
{
TOOLImpl* typeref = 0;
Dispatcher<TAR,ToolBase>::instance().enroll (typeref);
Dispatcher<TAR,ToolBase>::instance().enrol (typeref);
}
virtual ~Applicable () {}