/* VISITORDISPATCHER.hpp - visitor implementation details Copyright (C) Lumiera.org 2008, Hermann Vosseler 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 "include/error.hpp" #include "lib/sync.hpp" #include "lib/singleton.hpp" #include "lib/util.hpp" #include namespace lumiera { namespace visitor { using lib::Sync; template class Tag; template struct TagTypeRegistry { static Tag tag; }; /** * Type tag for concrete visiting tool classes. * Used to access the previously registered dispatcher * trampoline function when handling a visitor invocation. */ template class Tag { size_t tagID; ///< tag value static size_t lastRegisteredID; private: static void generateID (size_t& id) { Sync<>::ClassLock guard(); if (!id) id = ++lastRegisteredID; } public: Tag() : tagID(0) { } operator size_t() const { return tagID; } template static Tag& get (TOOLImpl* const concreteTool=0) { Tag& t = TagTypeRegistry::tag; if (!t) generateID (t.tagID); return t; } }; /** storage for the Tag registry for each concrete tool */ template Tag TagTypeRegistry::tag; template size_t Tag::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. */ template 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 static ReturnType callTrampoline (TAR& obj, TOOL& tool) { // cast down to real implementation type REQUIRE (INSTANCEOF (TOOLImpl, &tool)); TOOLImpl& toolObj = static_cast (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 table_; void accomodate (size_t index) { Sync<>::ClassLock guard(); 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 > instance; inline ReturnType forwardCall (TAR& target, TOOL& tool) { // get concrete type via tool's VTable Tag index = tool.getTag(); return (*storedTrampoline(index)) (target, tool); } template inline void enroll(TOOLImpl* typeref) { Tag& index = Tag::get (typeref); if (is_known (index)) return; else { Trampoline func = &callTrampoline; storePtr (index, func); } } }; /** storage for the dispatcher table(s) */ template Singleton > Dispatcher::instance; } // namespace visitor } // namespace lumiera #endif