OutputMapping implementation complete, pending unit test
This commit is contained in:
parent
fc051dfcba
commit
5ba7468f41
5 changed files with 192 additions and 36 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 <boost/functional/hash.hpp>
|
||||
|
||||
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<asset::Pipe> 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<asset::Pipe> const& query4pipe)
|
||||
{
|
||||
PPipe res;
|
||||
QueryHandler<asset::Pipe>& typeHandler = ConfigRules::instance();
|
||||
typeHandler.resolve (res, query4pipe);
|
||||
HashVal resulting_targetPipeID (res? (HashVal)res->getID() : 0 );
|
||||
return resulting_targetPipeID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ namespace mobject {
|
|||
class PlacementRef;
|
||||
|
||||
typedef PlacementRef<MObject> 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<asset::Pipe> 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:
|
||||
|
|
|
|||
|
|
@ -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<Pipe>.
|
||||
** 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 <boost/noncopyable.hpp>
|
||||
#include <boost/operators.hpp>
|
||||
#include <map>
|
||||
|
||||
|
|
@ -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>
|
||||
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<OutputMappingMemberFunc> Rebinder;
|
||||
|
||||
public:
|
||||
typedef typename Rebinder::Res Target;
|
||||
typedef function<Target(PId)> 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<HashVal,HashVal> 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<Resolver
|
||||
, boost::equality_comparable<Resolver, Target,
|
||||
boost::equality_comparable<Resolver>
|
||||
> >
|
||||
: public lib::BoolCheckable<Resolver // bool conversion to signal "unconnected"...
|
||||
, boost::equality_comparable<Resolver, Target, // final mapping result can be compared to Target...
|
||||
boost::equality_comparable<Resolver> // 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<asset::Pipe> const& query4pipe)
|
||||
{
|
||||
UNIMPLEMENTED ("lookup by extended query");
|
||||
HashVal hash4query;
|
||||
HashVal resulting_targetPipeID;
|
||||
table_[hash4query] = resulting_targetPipeID;
|
||||
return buildResolutionWrapper (hash4query);
|
||||
}
|
||||
operator[] (Query<asset::Pipe> 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<asset::Pipe> const&);
|
||||
|
||||
/** delegate target pipe resolution to the rules system */
|
||||
HashVal resolveQuery (Query<asset::Pipe> 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<class DEF>
|
||||
typename OutputMapping<DEF>::Resolver
|
||||
OutputMapping<DEF>::operator[] (Query<asset::Pipe> 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
|
||||
|
|
|
|||
Loading…
Reference in a new issue