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:
parent
3ecd8047df
commit
5f0c9e209e
45 changed files with 854 additions and 883 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 ); };
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
217
src/lib/visitor-dispatcher.hpp
Normal file
217
src/lib/visitor-dispatcher.hpp
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 "";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
162
tests/lib/singleton-subclass-test.cpp
Normal file
162
tests/lib/singleton-subclass-test.cpp
Normal 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
|
||||
137
tests/lib/singleton-test.cpp
Normal file
137
tests/lib/singleton-test.cpp
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 () {}
|
||||
|
|
|
|||
Loading…
Reference in a new issue