From 5ba7468f41371334e72d46dcbbb036b97ab3a601 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 28 Nov 2010 01:43:55 +0100 Subject: [PATCH] OutputMapping implementation complete, pending unit test --- src/lib/error.hpp | 2 + src/lib/exception.cpp | 1 + src/proc/mobject/output-designation.cpp | 55 +++++++++- src/proc/mobject/output-designation.hpp | 32 ++++-- src/proc/mobject/output-mapping.hpp | 138 +++++++++++++++++++----- 5 files changed, 192 insertions(+), 36 deletions(-) diff --git a/src/lib/error.hpp b/src/lib/error.hpp index 8b22775c1..4a841c629 100644 --- a/src/lib/error.hpp +++ b/src/lib/error.hpp @@ -125,6 +125,8 @@ namespace lumiera { LUMIERA_ERROR_DECLARE (WRONG_TYPE); ///< runtime type mismatch LUMIERA_ERROR_DECLARE (ITER_EXHAUST); ///< end of sequence reached LUMIERA_ERROR_DECLARE (BOTTOM_VALUE); ///< invalid or NIL value + LUMIERA_ERROR_DECLARE (UNCONNECTED); ///< missing connection + /** Macro for creating derived exception classes properly diff --git a/src/lib/exception.cpp b/src/lib/exception.cpp index 2e07447ad..8d11c8580 100644 --- a/src/lib/exception.cpp +++ b/src/lib/exception.cpp @@ -82,6 +82,7 @@ namespace lumiera { LUMIERA_ERROR_DEFINE (WRONG_TYPE, "runtime type mismatch"); LUMIERA_ERROR_DEFINE (ITER_EXHAUST, "end of sequence reached"); LUMIERA_ERROR_DEFINE (BOTTOM_VALUE, "invalid or NIL value"); + LUMIERA_ERROR_DEFINE (UNCONNECTED, "missing connection"); } // namespace error diff --git a/src/proc/mobject/output-designation.cpp b/src/proc/mobject/output-designation.cpp index b35c5799e..137d515bc 100644 --- a/src/proc/mobject/output-designation.cpp +++ b/src/proc/mobject/output-designation.cpp @@ -21,10 +21,33 @@ * *****************************************************/ +/** @file output-designation.cpp + ** Implementation details of OutputDesignation and OutputMapping. + ** Both of these are mostly intended as interface elements to represent + ** the intention to connect to another MObject, or a translation and mapping + ** of such connection intentions. But parts of the implementation are kept + ** here in a translation unit separate of the usage site: The implementation + ** of the various kinds of OutputDesignation spec (absolute, indirect, relative) + ** and the connection between OutputMapping and the rules based system. + ** + ** @see OutputDesignation + ** @see OutputMapping + ** @see OutputMapping_test + ** + */ + + #include "lib/error.hpp" #include "proc/mobject/mobject.hpp" #include "proc/mobject/placement-ref.hpp" #include "proc/mobject/output-designation.hpp" +#include "proc/mobject/output-mapping.hpp" +#include "common/configrules.hpp" + +#include + +using lumiera::query::QueryHandler; +using lumiera::ConfigRules; namespace mobject { @@ -116,10 +139,34 @@ namespace mobject { - PID - OutputDesignation::resolve (PPipe origin) - { - UNIMPLEMENTED ("Forward output designation resolution request to the embedded spec object"); + + + + namespace _mapping { + + /** @internal to allow for the use of queries mixed with normal Pipe-IDs + * in a single table, we rely on the \c hash_value() function, to be + * picked up by ADL */ + HashVal + slot (Query const& query) + { + return hash_value (query); + } + + /** @param Query for pipe, which is handed over as-is to the rules engine. + * @return key for a table slot to hold the associated mapping. This slot + * is assumed to contain the mapped Pipe-ID for the given + * query -- including the possibility of a zero hash + * to signal an \em unconnected mapping. */ + HashVal + resolveQuery (Query const& query4pipe) + { + PPipe res; + QueryHandler& typeHandler = ConfigRules::instance(); + typeHandler.resolve (res, query4pipe); + HashVal resulting_targetPipeID (res? (HashVal)res->getID() : 0 ); + return resulting_targetPipeID; + } } diff --git a/src/proc/mobject/output-designation.hpp b/src/proc/mobject/output-designation.hpp index 1635b3810..61a7b1c1a 100644 --- a/src/proc/mobject/output-designation.hpp +++ b/src/proc/mobject/output-designation.hpp @@ -40,7 +40,7 @@ namespace mobject { class PlacementRef; typedef PlacementRef RefPlacement; - + /** @@ -53,6 +53,10 @@ namespace mobject { * encounters a pair of (OutputDesignation, OutputClaim), * an actual stream connection will be wired in the * processing node network. + * + * @todo couldn't the inline buffer be "downgraded" to InPlaceBuffer ?? + * Seemingly we never-ever need to re-discover the erased type of the embedded spec. + * Thus for this to work, we'd just need to add an "empty" spec ///////////////////TICKET #723 */ class OutputDesignation { @@ -60,11 +64,6 @@ namespace mobject { typedef asset::ID PID; typedef asset::PPipe PPipe; - PID resolve (PPipe origin); - - //TODO: API to retrieve target stream type - - explicit OutputDesignation (PID explicitTarget); explicit OutputDesignation (RefPlacement const& indirectTarget); explicit OutputDesignation (uint relative_busNr =0); @@ -72,11 +71,30 @@ namespace mobject { // using default copying + /** retrieve the direct destination + * this descriptor is actually pointing to. + * In case of a target pipe not explicitly specified + * this might involve a resolution step and take the + * current context into account. + * @param origin starting point for figuring out connections + * @return a pipe-ID, which should be used as next connection. + * This might not be the final designation, but the + * directly visible next pipe to connect to + */ + PID + resolve (PPipe origin) + { + return spec_->resolve (origin); + } + + //TODO: API to retrieve target stream type + + class TargetSpec { public: virtual ~TargetSpec(); - PID resolve (PPipe origin); + virtual PID resolve (PPipe origin) =0; }; private: diff --git a/src/proc/mobject/output-mapping.hpp b/src/proc/mobject/output-mapping.hpp index 13f52b77c..871698e36 100644 --- a/src/proc/mobject/output-mapping.hpp +++ b/src/proc/mobject/output-mapping.hpp @@ -21,16 +21,42 @@ */ +/** @file output-mapping.hpp + ** Translating and wiring output designations. + ** OutputMapping is a complement to the OutputDesignation handles + ** used at various places in the high-level model. It is used when + ** translating a given output spec into another connection target + ** - when connecting an model port to a concrete external output + ** - when connecting a timeline to a viewer element + ** - for implementing the viewer input selection "switchbord" + ** - for translating output designation of virtual clips + ** OutputMapping is to be used as value object, holding concrete + ** connections and wiring. For each of the mentioned usage situations, + ** it needs to be adapted specifically, which is achieved by template + ** (generic) programming: The usage situation provides a definition + ** context DEF to fill in the variable parts of the implementation. + ** This definition context is actually instantiated (as base class). + ** The mapping table actually just stores an association of hash + ** values, which typically are interpreted as asset::ID. + ** But the actual mapping result is retrieved on each acces + ** by invoking a functor on the stored hash value, + ** thus the final resolution is done \em late. + ** + ** @see OutputDesignation + ** @see OutputMapping_test + ** + */ + + + #ifndef PROC_MOBJECT_OUTPUT_MAPPING_H #define PROC_MOBJECT_OUTPUT_MAPPING_H -#include "proc/mobject/output-designation.hpp" -#include "lib/meta/function.hpp" +#include "lib/error.hpp" #include "lib/bool-checkable.hpp" #include "lib/query.hpp" #include "lib/util.hpp" -#include #include #include @@ -40,9 +66,12 @@ namespace mobject { namespace { // Helper to extract and rebind definition types - using std::tr1::function; using util::contains; + /** + * @internal used by OutputMapping + * to figure out the mapping target type + */ template class _def { @@ -57,21 +86,22 @@ namespace mobject { typedef RET Res; }; - typedef typeof(&DEF::output) OutputMappingMemberFunc; // GCC extension: "typeof" + typedef typeof(&DEF::output) OutputMappingMemberFunc; // GCC extension: "typeof" typedef Rebind Rebinder; public: typedef typename Rebinder::Res Target; - typedef function OutputMappingFunc; }; - - } + }//(End) type rebinding helper + namespace error = lumiera::error; using lumiera::Query; using asset::HashVal; + + /** * OutputMapping is a facility to resolve output designations. * For a given specification, resolution to the desired @@ -104,7 +134,7 @@ namespace mobject { std::map table_; public: - typedef typename Setup::Target Target; + typedef typename Setup::Target Target; // using default ctor and copy operations @@ -121,12 +151,13 @@ namespace mobject { * Actually retrieving the result value by the client code triggers invocation * of the specific resolution functor, embedded in the definition context DEF, * which was given when instantiating the OutputMapping template. + * @note depends on the template parameter of the enclosing OutputMapping type! */ class Resolver - : public lib::BoolCheckable - > > + : public lib::BoolCheckable // mapping values can be compared. + > > // { OutputMapping& thisMapping_; HashVal& pID_; @@ -147,10 +178,14 @@ namespace mobject { { REQUIRE (pID_); PId targetPipeID (pID_); - return thisMapping_.resolve (targetPipeID); + return thisMapping_.resolveTarget (targetPipeID); } public: + /** explicitly define a new target ID for this individual mapping + * @note the actually returned result depends on what the configured + * \c DEF::output functor will yield when invoked on this ID + */ void operator= (PId newId2map) { @@ -164,13 +199,28 @@ namespace mobject { pID_ = newPipe2map->getID(); } + void + disconnect() ///< switch this individual mapping into \em unconnected state + { + pID_ = 0; + } + + /** actually retrieve the target object of the mapping. + * This operation is invoked when client code accesses + * the result of an OutputMapping query. + * @return result of invoking the configured \c DEF::output functor + * @throw error::Logic when resoving an \em unconnected mapping + */ operator Target() { + if (!isValid()) + throw error::Logic ("attempt to resolve an unconnected output mapping" + , error::LUMIERA_ERROR_UNCONNECTED); return resolve(); } bool - isValid() const + isValid() const ///< is this a valid \em connected mapping? { return bool(pID_); } @@ -191,6 +241,10 @@ namespace mobject { } }; + + + /* === Map-style access for clients === */ + Resolver operator[] (PId sourcePipeID) { @@ -209,21 +263,15 @@ namespace mobject { } Resolver - operator[] (Query const& query4pipe) - { - UNIMPLEMENTED ("lookup by extended query"); - HashVal hash4query; - HashVal resulting_targetPipeID; - table_[hash4query] = resulting_targetPipeID; - return buildResolutionWrapper (hash4query); - } + operator[] (Query const& query4pipe); + private: Target - resolve (PId resultingPipeID) + resolveTarget (PId mappedPipeID) { - return DEF::output(resultingPipeID); + return DEF::output (mappedPipeID); } Resolver @@ -235,6 +283,46 @@ namespace mobject { }; + namespace _mapping { + + /** yield a suitable table slot for this query */ + HashVal slot (Query const&); + + /** delegate target pipe resolution to the rules system */ + HashVal resolveQuery (Query const&); + } + + + + /** determine an OutputMapping by resolving a complex query, + * instead of just picking a mapped pipe (which is the default usage). + * Accessing the OutputMapping this way by query enables all kinds of + * extended usages: It suffices that the given query somehow yields a Pipe, + * which then is considered the mapped result and handed over to the \c DEF::output + * functor for resolution to a result object to be returned. + * @note the mapped result is remembered within this mapping. Further invocations + * with the \em same query will just fetch this stored pipe-ID and hand it + * to the functor, without resolving the query again. You might want to + * \link Resolver::disconnect remove \endlink this specific mapping + * in order to force re-evaluation of the query. + * @param Query for a pipe, which is handed over as-is to the rules engine. + * @warning depending on the actual query, there might be no solution, + * in which case an \em unconnected marker is retrieved and + * stored. Thus the yielded Resolver should be checked, + * if in doubt. + */ + template + typename OutputMapping::Resolver + OutputMapping::operator[] (Query const& query4pipe) + { + HashVal hash4query = _mapping::slot (query4pipe); + if (!contains (table_, hash4query)) + // need to resolve this query first + table_[hash4query] = _mapping::resolveQuery (query4pipe); + + ENSURE (contains (table_, hash4query)); + return buildResolutionWrapper (hash4query); + } } // namespace mobject