2008-01-04 15:10:18 +01:00
|
|
|
/*
|
|
|
|
|
VISITORDISPATCHER.hpp - visitor implementation details
|
|
|
|
|
|
2008-03-10 04:25:03 +01:00
|
|
|
Copyright (C) Lumiera.org
|
|
|
|
|
2008, Hermann Vosseler <Ichthyostega@web.de>
|
2008-01-04 15:10:18 +01:00
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-04-09 00:27:21 +02:00
|
|
|
#ifndef LUMIERA_VISITORDISPATCHER_H
|
|
|
|
|
#define LUMIERA_VISITORDISPATCHER_H
|
2008-01-04 15:10:18 +01:00
|
|
|
|
2008-12-27 00:53:35 +01:00
|
|
|
#include "lib/error.hpp"
|
2008-12-17 17:53:32 +01:00
|
|
|
#include "lib/util.hpp"
|
|
|
|
|
#include "lib/singleton.hpp"
|
|
|
|
|
#include "lib/multithread.hpp"
|
2008-01-04 15:10:18 +01:00
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
|
2008-04-09 00:27:21 +02:00
|
|
|
namespace lumiera
|
2008-01-04 15:10:18 +01:00
|
|
|
{
|
|
|
|
|
namespace visitor
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
2008-01-05 19:42:43 +01:00
|
|
|
private:
|
|
|
|
|
static void
|
|
|
|
|
generateID (size_t& id)
|
|
|
|
|
{
|
|
|
|
|
Thread::Lock<Tag> guard SIDEEFFECT;
|
|
|
|
|
if (!id)
|
|
|
|
|
id = ++lastRegisteredID;
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-04 15:10:18 +01:00
|
|
|
public:
|
|
|
|
|
Tag() : tagID(0) { }
|
|
|
|
|
operator size_t() const { return tagID; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<class TOOLImpl>
|
|
|
|
|
static Tag&
|
2008-12-26 23:17:51 +01:00
|
|
|
get (TOOLImpl* const =0)
|
2008-01-04 15:10:18 +01:00
|
|
|
{
|
|
|
|
|
Tag& t = TagTypeRegistry<TOOL,TOOLImpl>::tag;
|
2008-01-05 19:42:43 +01:00
|
|
|
if (!t) generateID (t.tagID);
|
2008-01-04 15:10:18 +01:00
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2008-10-20 03:13:02 +02:00
|
|
|
* For each possible call entry point via some subclass of the visitable hierarchy,
|
2008-01-04 15:10:18 +01:00
|
|
|
* we maintain a dispatcher table to keep track of all concrete tool implementations
|
2008-10-20 03:13:02 +02:00
|
|
|
* able to receive and process calls on objects of this subclass.
|
2008-01-04 15:10:18 +01:00
|
|
|
*/
|
|
|
|
|
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_;
|
|
|
|
|
|
|
|
|
|
|
2008-01-05 19:42:43 +01:00
|
|
|
void
|
|
|
|
|
accomodate (size_t index)
|
|
|
|
|
{
|
|
|
|
|
Thread::Lock<Dispatcher> guard SIDEEFFECT;
|
|
|
|
|
if (index > table_.size())
|
|
|
|
|
table_.resize (index); // performance bottleneck?? TODO: measure the real impact!
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-04 15:10:18 +01:00
|
|
|
inline bool
|
|
|
|
|
is_known (size_t id)
|
|
|
|
|
{
|
|
|
|
|
return id<=table_.size() && table_[id-1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void
|
|
|
|
|
storePtr (size_t id, Trampoline func)
|
|
|
|
|
{
|
2008-01-05 19:42:43 +01:00
|
|
|
REQUIRE (func);
|
|
|
|
|
REQUIRE (0 < id);
|
2008-01-04 15:10:18 +01:00
|
|
|
if (id>table_.size())
|
2008-01-05 19:42:43 +01:00
|
|
|
accomodate (id);
|
2008-01-04 15:10:18 +01:00
|
|
|
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)
|
|
|
|
|
{
|
2008-01-05 01:38:32 +01:00
|
|
|
return tool.onUnknown (target);
|
2008-01-04 15:10:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
2008-04-09 00:27:21 +02:00
|
|
|
} // namespace lumiera
|
2008-01-04 15:10:18 +01:00
|
|
|
#endif
|