ModelPort registry unit test pass (closes #727)

This commit is contained in:
Fischlurch 2010-12-11 23:40:12 +01:00
parent be6f555e04
commit 8a54e00b6b
7 changed files with 92 additions and 97 deletions

View file

@ -21,13 +21,13 @@
* *****************************************************/ * *****************************************************/
/** @file model-port-registry.cpp /** @file model-port-registry.cpp
** Implementation details of model port descriptors and references. ** Implementation details of model port descriptors and references.
** Especially, the handling of the ModelPortTable datastructure is ** Essentially the handling of the ModelPortRegistry datastructure is
** kept an opaque implementation detail and confined entirely within ** kept an opaque implementation detail and confined entirely within
** this translation unit. ** this translation unit. Both the client interface (ModelPort) and
** ** the management interface (ModelPortRegistry) are backed by this
** TODO: comment necessary? ** common translation unit.
** **
** @see OutputDesignation ** @see OutputDesignation
** @see OutputMapping ** @see OutputMapping
@ -39,22 +39,10 @@
#include "lib/error.hpp" #include "lib/error.hpp"
#include "include/logging.h" #include "include/logging.h"
#include "lib/sync-classlock.hpp" #include "lib/sync-classlock.hpp"
//#include "lib/symbol.hpp"//
#include "proc/mobject/builderfacade.hpp" #include "proc/mobject/builderfacade.hpp"
#include "proc/mobject/model-port.hpp" #include "proc/mobject/model-port.hpp"
#include "proc/mobject/builder/model-port-registry.hpp" #include "proc/mobject/builder/model-port-registry.hpp"
//#include <boost/functional/hash.hpp>
//#include <cstdlib>
#include <boost/noncopyable.hpp>
//using lumiera::query::QueryHandler;
//using lumiera::query::removeTerm;
//using lumiera::query::extractID;
//using lumiera::ConfigRules;
//using lumiera::Symbol;
namespace mobject { namespace mobject {
namespace builder { namespace builder {
@ -65,8 +53,8 @@ namespace mobject {
typedef lib::ClassLock<ModelPortRegistry> LockRegistry; typedef lib::ClassLock<ModelPortRegistry> LockRegistry;
/** storage for the link to the /** storage for the link to the global
global Registry instance currently in charge */ Registry instance currently in charge */
lib::OptionalRef<ModelPortRegistry> ModelPortRegistry::theGlobalRegistry; lib::OptionalRef<ModelPortRegistry> ModelPortRegistry::theGlobalRegistry;
@ -82,18 +70,19 @@ namespace mobject {
/** switch the implicit link to \em the global ModelPort registry /** switch the implicit link to \em the global ModelPort registry
* to point to the given implementation instance. Typically used within * to point to the given implementation instance. Typically used
* the Builder subsystem lifecycle methods, or for unit tests to use * within the Builder subsystem lifecycle methods, or for
* a test instance of the registry temporarily * temporarily exchanging the registry for unit tests
* @return the registry instance previously in use or \c NULL * @return the registry instance previously in use or \c NULL
*/ */
ModelPortRegistry* ModelPortRegistry*
ModelPortRegistry::setActiveInstance (ModelPortRegistry& newRegistry) ModelPortRegistry::setActiveInstance (ModelPortRegistry& newRegistry)
{ {
INFO (builder, "activating new ModelPort registry.");
LockRegistry global_lock; LockRegistry global_lock;
ModelPortRegistry *previous = theGlobalRegistry.isValid()? ModelPortRegistry *previous = theGlobalRegistry.isValid()?
&(theGlobalRegistry()) : 0; &( theGlobalRegistry()) : 0;
INFO_IF (!previous, builder, "activating new ModelPort registry.");
WARN_IF ( previous, builder, "switching ModelPort registry instance.");
theGlobalRegistry.link_to (newRegistry); theGlobalRegistry.link_to (newRegistry);
return previous; return previous;
} }
@ -112,7 +101,7 @@ namespace mobject {
throw error::State ("global model port registry is not accessible" throw error::State ("global model port registry is not accessible"
, LUMIERA_ERROR_BUILDER_LIFECYCLE); , LUMIERA_ERROR_BUILDER_LIFECYCLE);
} }
/** does the <i>transaction currently being built</i> /** does the <i>transaction currently being built</i>
@ -128,8 +117,8 @@ namespace mobject {
/** @return true if the given pipe-ID actually denotes an /** @return true if the given pipe-ID actually denotes an
* existing, connected and usable model port. * existing, connected and usable model port.
* @note reflects the state of the publicly visible * @note reflects the state of the publicly visible
* model port registry, \em not any model ports * model port registry, \em not any model ports
* being registered within a pending transaction * being registered within a pending transaction
* (ongoing build process). */ * (ongoing build process). */
@ -240,22 +229,22 @@ namespace mobject {
{ {
LockRegistry global_lock; LockRegistry global_lock;
TRACE (builder, "discarding changes to ModelPort list (rollback)...."); TRACE (builder, "discarding changes to ModelPort list (rollback)....");
MPTable newTransaction(transaction_); MPTable newTransaction(currentReg_);
swap (transaction_, newTransaction); swap (transaction_, newTransaction);
} }
LUMIERA_ERROR_DEFINE (DUPLICATE_MODEL_PORT, "Attempt to define a new model port with an pipe-ID already denoting an existing port"); LUMIERA_ERROR_DEFINE (DUPLICATE_MODEL_PORT, "Attempt to define a new model port with an pipe-ID already denoting an existing port");
} // namespace builder }// namespace builder
LUMIERA_ERROR_DEFINE (INVALID_MODEL_PORT, "Referral to unknown model port"); LUMIERA_ERROR_DEFINE (INVALID_MODEL_PORT, "Referral to unknown model port");
LUMIERA_ERROR_DEFINE (UNCONNECTED_MODEL_PORT, "Attempt to operate on an existing but unconnected model port"); LUMIERA_ERROR_DEFINE (UNCONNECTED_MODEL_PORT, "Attempt to operate on an existing but unconnected model port");
ModelPort::ModelPort (ID<asset::Pipe> refID) ModelPort::ModelPort (ID<asset::Pipe> refID)
: id_(refID) : id_(refID)
@ -307,8 +296,7 @@ namespace mobject {
{ {
return this->id_.streamType(); return this->id_.streamType();
} }
} // namespace mobject } // namespace mobject

View file

@ -57,19 +57,11 @@
#include <map> #include <map>
//#include "lib/opaque-holder.hpp"
//#include "lib/meta/typelist-util.hpp"
//extern "C" {
//#include "lib/luid.h"
//}
namespace mobject { namespace mobject {
namespace builder { namespace builder {
using asset::ID; using asset::ID;
using asset::Pipe; using asset::Pipe;
//using asset::PPipe;
using asset::Struct; using asset::Struct;
LUMIERA_ERROR_DECLARE (DUPLICATE_MODEL_PORT); ///< Attempt to define a new model port with an pipe-ID already denoting an existing port LUMIERA_ERROR_DECLARE (DUPLICATE_MODEL_PORT); ///< Attempt to define a new model port with an pipe-ID already denoting an existing port
@ -92,18 +84,19 @@ namespace builder {
typedef ID<Struct> StID; typedef ID<Struct> StID;
public: public:
/** @internal record to describe a model port */ /** @internal record to describe a model port */
struct ModelPortDescriptor; struct ModelPortDescriptor;
static void shutdown (); static void shutdown ();
static ModelPortRegistry* static ModelPortRegistry*
setActiveInstance (ModelPortRegistry& newRegistry); setActiveInstance (ModelPortRegistry& newRegistry);
static ModelPortRegistry& static ModelPortRegistry&
globalInstance(); globalInstance();
static ModelPortDescriptor const& static ModelPortDescriptor const&
accessDescriptor (PID); accessDescriptor (PID);
@ -134,6 +127,7 @@ namespace builder {
*/ */
void rollback(); void rollback();
private: private:
static lib::OptionalRef<ModelPortRegistry> theGlobalRegistry; static lib::OptionalRef<ModelPortRegistry> theGlobalRegistry;
@ -145,6 +139,7 @@ namespace builder {
/** ModelPortDescriptor records are used as actual storage /** ModelPortDescriptor records are used as actual storage
* within the model port registration table; they are immutable * within the model port registration table; they are immutable
* value objects and never exposed to client code directly. * value objects and never exposed to client code directly.
@ -179,7 +174,7 @@ namespace builder {
const PID id() const { return id_; } const PID id() const { return id_; }
const StID holder() const { return holder_; } const StID holder() const { return holder_; }
}; };
}} // namespace mobject::builder }} // namespace mobject::builder

View file

@ -24,7 +24,7 @@
** Organising the output data calculation possibilities. ** Organising the output data calculation possibilities.
** Model ports are conceptual entities, denoting the points where output might ** Model ports are conceptual entities, denoting the points where output might
** possibly be produced. There is an actual representation, a collection of small ** possibly be produced. There is an actual representation, a collection of small
** descriptor objects managed by the Fixture and organised within the ModelPortTable ** descriptor objects managed by the Fixture and organised within the registry
** datastructure. Thus, while the actual ModelPort descriptor entities are located ** datastructure. Thus, while the actual ModelPort descriptor entities are located
** within and managed by the Fixture -- model port as a concept spans the high-level ** within and managed by the Fixture -- model port as a concept spans the high-level
** and low-level view. A model port can be associated both to a pipe within a timeline ** and low-level view. A model port can be associated both to a pipe within a timeline
@ -44,16 +44,16 @@
** to become the valid current model port configuration. After that switch, model ports ** to become the valid current model port configuration. After that switch, model ports
** are immutable. ** are immutable.
** **
** Model ports are to be accessed, enumerated and grouped in various ways, because each ** Model ports are to be accessed, enumerated and grouped in various ways, because
** port belongs to a specific timeline and is used for producing data of a single ** each port belongs to a specific timeline and is used to produce data of a single
** StreamType solely. But all those referrals, searching and grouping happens only ** StreamType solely. But all those referrals, searching and grouping happens only
** after the build process has discovered all model ports currently available. ** after the build process has discovered all model ports currently available.
** Thus actually the ModelPort elements handed out to client code are just ** Thus actually the ModelPort elements handed out to client code are just
** smart-handles, accessing a global ModelPortRegistry behind the scenes. ** smart-handles, accessing a global ModelPortRegistry behind the scenes.
** Validity of these handles will be checked on each access. The actual ** Validity of these handles will be checked on each access. The actual
** model port descriptors are owned and managed by the fixture; ** model port descriptors are owned and managed by the fixture;
** they are bulk allocated in a similar manner than the ** @todo they might bulk allocated in a similar manner than the
** ProcNode and WiringDescriptor objects. ** ProcNode and WiringDescriptor objects are.
** **
** @see ModelPortRegistry_test abstract usage example ** @see ModelPortRegistry_test abstract usage example
** @see ModelPortRegistry management interface ** @see ModelPortRegistry management interface
@ -72,8 +72,8 @@
namespace mobject { namespace mobject {
LUMIERA_ERROR_DECLARE (INVALID_MODEL_PORT); ///< Referral to unknown model port LUMIERA_ERROR_DECLARE (INVALID_MODEL_PORT); ///< Referral to unknown model port
LUMIERA_ERROR_DECLARE (UNCONNECTED_MODEL_PORT); ///< Attempt to operate on an existing but unconnected model port LUMIERA_ERROR_DECLARE (UNCONNECTED_MODEL_PORT); ///< Attempt to operate on an existing but unconnected model port
using asset::ID; using asset::ID;
@ -81,21 +81,21 @@ namespace mobject {
/** /**
* Handle denoting a port within the model, * Handle denoting a point within the model,
* where actually output data can be pulled. * where actually output data can be pulled.
* ModelPort is a frontend to be used by clients. * ModelPort is a frontend to be used by clients.
* These ModelPort handle objects may be copied and stored * These ModelPort handle objects may be copied and stored
* at will, but their validity will be verified on each access. * at will, but their validity will be verified on each access.
* Actually, the Builder will discover any model ports and * Actually, the Builder will discover any model ports and
* maintain a ModelPortRegistry behind the scenes. * maintain a ModelPortRegistry behind the scenes.
* *
* Each model port corresponds to a (global) pipe within a * Each model port corresponds to a (global) pipe within a
* specific Timeline; consequently each such port is also * specific Timeline ("holder"); consequently each such port is also
* bound to produce data of a specific StreamType (as defined by * bound to produce data of a specific StreamType (as defined by
* the corresponding pipe). A model port may be in \em unconnected * the corresponding pipe). A model port may be in \em unconnected
* state, which can be checked by \c bool conversion. While the * state, which can be checked through \c bool conversion. While
* ModelPort handles are value objects, the identity of the * the ModelPort handles are value objects, the identity of the
* underlying model port (descriptor) is given by the * underlying model port (descriptor) is given by the
* corresponding pipe-ID, thus effectively resulting * corresponding pipe-ID, thus effectively resulting
* in a global namespace for model ports. * in a global namespace for model ports.
* *

View file

@ -152,6 +152,7 @@ namespace session {
closeSessionInterface() closeSessionInterface()
{ /////////////////////// TICKET #699 { /////////////////////// TICKET #699
INFO (session, "closing session interfaces."); INFO (session, "closing session interfaces.");
TODO ("actually close session interfaces :) and don't babble in the log when NOT closing anything...");
} }

View file

@ -15,7 +15,7 @@ PLANNED "BuildSegment_test" BuildSegment_test <<END
END END
PLANNED "ModelPort registry" ModelPortRegistry_test <<END TEST "ModelPort registry" ModelPortRegistry_test <<END
return: 0 return: 0
END END

View file

@ -24,25 +24,18 @@
#include "lib/test/run.hpp" #include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp" #include "lib/test/test-helper.hpp"
#include "proc/mobject/builder/model-port-registry.hpp" #include "proc/mobject/builder/model-port-registry.hpp"
#include "proc/asset/pipe.hpp"
#include "proc/asset/timeline.hpp" #include "proc/asset/timeline.hpp"
#include "proc/asset/pipe.hpp"
#include "lib/query.hpp" #include "lib/query.hpp"
#include "lib/util.hpp" #include "lib/util.hpp"
//#include <boost/format.hpp>
//#include <boost/scoped_ptr.hpp>
#include <string>
namespace mobject { namespace mobject {
namespace builder { namespace builder {
namespace test { namespace test {
//using boost::format;
//using boost::scoped_ptr;
using util::isSameObject; using util::isSameObject;
using util::isnil; using util::isnil;
using std::string;
using asset::Pipe; using asset::Pipe;
using asset::PPipe; using asset::PPipe;
@ -53,6 +46,8 @@ namespace test {
typedef asset::ID<Pipe> PID; typedef asset::ID<Pipe> PID;
typedef asset::ID<Struct> TID; typedef asset::ID<Struct> TID;
typedef ModelPortRegistry::ModelPortDescriptor const& MPDescriptor;
namespace { // test environment namespace { // test environment
@ -69,8 +64,6 @@ namespace test {
return asset::Struct::retrieve (Query<Timeline> ("id("+id+")"))->getID(); return asset::Struct::retrieve (Query<Timeline> ("id("+id+")"))->getID();
} }
typedef ModelPortRegistry::ModelPortDescriptor const& MPDescriptor;
struct TestContext struct TestContext
{ {
ModelPortRegistry registry_; ModelPortRegistry registry_;
@ -91,14 +84,15 @@ namespace test {
ModelPortRegistry::shutdown(); ModelPortRegistry::shutdown();
} }
}; };
} }
/********************************************************************************* /*********************************************************************************
* @test create a standalone model port registry to verify the behaviour of * @test create a standalone model port registry to verify the behaviour of
* model ports, accessed through reference handles. This test provides * model ports, accessed through reference handles. This test provides an
* an example setup detached from the real usage situation within the builder. * example setup detached from the real usage situation within the builder.
* The ModelPortRegistry management interface is used to create and track a * The ModelPortRegistry management interface is used to create and track a
* set of model ports, to be made visible by an atomic, transactional switch. * set of model ports, to be made visible by an atomic, transactional switch.
* The access for client code through the ModelPort frontend is then verified. * The access for client code through the ModelPort frontend is then verified.
@ -126,7 +120,6 @@ namespace test {
/* == some Assets to play with == */ /* == some Assets to play with == */
PID pipeA = getPipe ("pipeA"); PID pipeA = getPipe ("pipeA");
PID pipeB = getPipe ("pipeB"); PID pipeB = getPipe ("pipeB");
PID pipeWC = getPipe ("WCpipe");
TID someTimeline = getTimeline ("some_test_Timeline"); TID someTimeline = getTimeline ("some_test_Timeline");
// start out with defining some new model ports...... // start out with defining some new model ports......
@ -158,17 +151,18 @@ namespace test {
ModelPort mp1(pipeA); ModelPort mp1(pipeA);
ModelPort mp2(pipeB); ModelPort mp2(pipeB);
VERIFY_ERROR (INVALID_MODEL_PORT, ModelPort(pipeWC)); VERIFY_ERROR (INVALID_MODEL_PORT, ModelPort unbefitting(pipeWC) );
ModelPort mp1x(pipeA); ModelPort mp1x(pipeA); // can be created multiple times
ModelPort mpNull; ModelPort mp2x(mp1x); // can be copied at will
ModelPort mpNull; // can be default constructed (->unconnected)
CHECK (mp1); CHECK (mp1);
CHECK (mp2); CHECK (mp2);
CHECK (mp1x); CHECK (mp1x);
CHECK (!mpNull); CHECK (!mpNull); // bool check verifies setup and connected state
CHECK ( ModelPort::exists (pipeA)); CHECK ( ModelPort::exists (pipeA)); // this is the same check, but invoked just with an pipe-ID
CHECK ( ModelPort::exists (pipeB)); CHECK ( ModelPort::exists (pipeB));
CHECK (!ModelPort::exists (pipeWC)); CHECK (!ModelPort::exists (pipeWC));
@ -182,7 +176,8 @@ namespace test {
CHECK (mp1.pipe() == pipeA); CHECK (mp1.pipe() == pipeA);
CHECK (mp2.pipe() == pipeB); CHECK (mp2.pipe() == pipeB);
CHECK (mp1x.pipe() == pipeA); CHECK (mp1x.pipe() == pipeA);
VERIFY_ERROR (UNCONNECTED_MODEL_PORT, mpNull.pipe()); VERIFY_ERROR (UNCONNECTED_MODEL_PORT, mpNull.pipe()); // any further operations on an unconnected port will throw
VERIFY_ERROR (UNCONNECTED_MODEL_PORT, mpNull.holder());
CHECK (mp1.streamType() == pipeA.streamType()); CHECK (mp1.streamType() == pipeA.streamType());
} }
@ -201,8 +196,8 @@ namespace test {
CHECK (ModelPort::exists (pipeA)); CHECK (ModelPort::exists (pipeA));
CHECK (registry.contains (pipeA)); CHECK (registry.contains (pipeA));
registry.remove (pipeA); registry.remove (pipeA);
CHECK ( ModelPort::exists (pipeA)); CHECK (!registry.contains (pipeA)); // removed from the current (pending) transaction
CHECK (!registry.contains (pipeA)); CHECK ( ModelPort::exists (pipeA)); // but not yet publicly visible
// now create a new and differing definition of port A // now create a new and differing definition of port A
TID anotherTimeline = getTimeline ("another_test_Timeline"); TID anotherTimeline = getTimeline ("another_test_Timeline");
@ -211,16 +206,18 @@ namespace test {
CHECK (anotherTimeline == p1.holder()); CHECK (anotherTimeline == p1.holder());
CHECK (ModelPort(pipeA).holder() != anotherTimeline); CHECK (ModelPort(pipeA).holder() != anotherTimeline);
registry.remove (pipeB); registry.remove (pipeB); // some more wired definitions
registry.definePort (pipeWC,anotherTimeline); registry.definePort (pipeWC, anotherTimeline);
CHECK (!registry.contains (pipeB)); CHECK (!registry.contains (pipeB));
CHECK ( registry.contains (pipeWC)); CHECK ( registry.contains (pipeWC));
CHECK ( ModelPort::exists (pipeB)); CHECK ( ModelPort::exists (pipeB));
CHECK (!ModelPort::exists (pipeWC)); CHECK (!ModelPort::exists (pipeWC));
CHECK ( registry.isRegistered (pipeB)); // this is the same as ModelPort::exists
ModelPort portA(pipeA); CHECK (!registry.isRegistered (pipeWC)); //
// Note: pending transaction not yet committed
ModelPort portA(pipeA); // ...... thus the changes aren't reflected to client code
ModelPort portB(pipeB); ModelPort portB(pipeB);
VERIFY_ERROR (INVALID_MODEL_PORT, ModelPort(pipeWC)); VERIFY_ERROR (INVALID_MODEL_PORT, ModelPort ineptly(pipeWC));
CHECK (portA); CHECK (portA);
CHECK (portB); CHECK (portB);
CHECK (portA.pipe() == pipeA); CHECK (portA.pipe() == pipeA);
@ -228,30 +225,44 @@ namespace test {
CHECK (portA.holder() != anotherTimeline); CHECK (portA.holder() != anotherTimeline);
registry.commit(); registry.commit();
CHECK ( ModelPort::exists (pipeA)); CHECK ( ModelPort::exists (pipeA)); // now all our changes got publicly visible
CHECK (!ModelPort::exists (pipeB)); CHECK (!ModelPort::exists (pipeB));
CHECK ( ModelPort::exists (pipeWC)); CHECK ( ModelPort::exists (pipeWC));
CHECK ( portA); CHECK ( portA);
CHECK (!portB); CHECK (!portB);
CHECK (portA.holder() == anotherTimeline); CHECK (portA.holder() == anotherTimeline);
CHECK (portA.pipe() == pipeA); CHECK (portA.pipe() == pipeA);
VERIFY_ERROR (UNCONNECTED_MODEL_PORT, portB.pipe()); VERIFY_ERROR (INVALID_MODEL_PORT, portB.pipe());
ModelPort pwc(pipeWC); ModelPort pwc(pipeWC); // now clients may also use the now officially promoted new port
CHECK (pwc); CHECK (pwc);
CHECK (pwc.pipe() == pipeWC); CHECK (pwc.pipe() == pipeWC);
CHECK (pwc.holder() == anotherTimeline); CHECK (pwc.holder() == anotherTimeline);
// Next: doing several changes,
// but finally *not* committing them...
CHECK ( registry.contains (pipeA));
CHECK (!registry.contains (pipeB));
CHECK ( registry.contains (pipeWC));
registry.remove (pipeA); registry.remove (pipeA);
registry.clear(); registry.clear(); // remove everything from the pending transaction
CHECK (!registry.contains (pipeA)); CHECK (!registry.contains (pipeA));
CHECK (!registry.contains (pipeB)); CHECK (!registry.contains (pipeB));
CHECK (!registry.contains (pipeWC)); CHECK (!registry.contains (pipeWC));
registry.rollback(); registry.definePort (pipeB, anotherTimeline);
CHECK ( registry.contains (pipeA));
CHECK ( registry.contains (pipeB)); CHECK ( registry.contains (pipeB));
CHECK (!portB); // not committed and thus not visible
CHECK (portA);
CHECK (pwc);
registry.rollback();
CHECK ( registry.contains (pipeA)); // no effect to the officialy visible state
CHECK (!registry.contains (pipeB));
CHECK ( registry.contains (pipeWC)); CHECK ( registry.contains (pipeWC));
VERIFY_ERROR(INVALID_MODEL_PORT, registry.get(pipeB) );
CHECK (!portB);
} }
}; };

View file

@ -2819,7 +2819,7 @@ These are used as token for dealing with other objects and have no identity of t
</pre> </pre>
</div> </div>
<div title="ModelPort" modifier="Ichthyostega" modified="201012091252" created="201011100234" tags="def spec" changecount="6"> <div title="ModelPort" modifier="Ichthyostega" modified="201012112233" created="201011100234" tags="def spec" changecount="8">
<pre>Any point where output possibly might be produced. Model port entities are located within the [[Fixture]] &amp;mdash; model port as a concept spans the high-level and low-level view. A model port can be associated both to a pipe in the HighLevelModel but at the same time denotes a set of corresponding [[exit nodes|ExitNode]] within the [[segments|Segmentation]] of the render nodes network. <pre>Any point where output possibly might be produced. Model port entities are located within the [[Fixture]] &amp;mdash; model port as a concept spans the high-level and low-level view. A model port can be associated both to a pipe in the HighLevelModel but at the same time denotes a set of corresponding [[exit nodes|ExitNode]] within the [[segments|Segmentation]] of the render nodes network.
A model port is rather derived than configured; it emerges when a pipe [[claims|WiringClaim]] an output destination and some other entity actually uses this designation as a target, either directly or indirectly. This match of provision and usage is detected during the build process and produces an entry in the fixture's model port table. These model ports in the fixture are keyed by ~Pipe-ID, thus each model port has an associated StreamType. A model port is rather derived than configured; it emerges when a pipe [[claims|WiringClaim]] an output destination and some other entity actually uses this designation as a target, either directly or indirectly. This match of provision and usage is detected during the build process and produces an entry in the fixture's model port table. These model ports in the fixture are keyed by ~Pipe-ID, thus each model port has an associated StreamType.
@ -2827,13 +2827,13 @@ A model port is rather derived than configured; it emerges when a pipe [[claims|
Model ports are the effective, resulting outputs of each timeline; additional ports result from [[connecting a viewer|ViewerPlayConnection]]. Any render or display process happens at a model port. Model ports are the effective, resulting outputs of each timeline; additional ports result from [[connecting a viewer|ViewerPlayConnection]]. Any render or display process happens at a model port.
!formal specification !formal specification
Model port is a //conceptual entity,// denoting the possibility to pull generated data of a distinct (stream)type from a specific bus within the model -- any possible output produced or provided by Lumiera is bound to appear at a model port. The namespace of model ports is global, each being denoted by a ~Pipe-ID. Model port is a //conceptual entity,// denoting the possibility to pull generated data of a distinct (stream)type from a specific bus within the model -- any possible output produced or provided by Lumiera is bound to appear at a model port. The namespace of model ports is global, each being associated with a ~Pipe-ID.
Model ports are represented by small non-copyable descriptor objects with distinct identity, which are owned and managed by the [[Fixture]]. Clients are bound to resolve a model port on each usage, as configuration changes within the model might cause ports to appear and decease. Each model port belongs to a specific Timeline and is aware of this association, as is the timeline, allowing to get the collection of all ports of a given timeline. Besides, within the Fixture each model port refers to a specific [[segmentation of the time axis|Segmentation]] (relevant for this special timeline actually). Thus, with the help of this segmentation, a model port can yield an ExitNode to pull frames for a given time. Model ports are represented by small non-copyable descriptor objects with distinct identity, which are owned and managed by the [[Fixture]]. Clients are bound to resolve a model port on each usage, as configuration changes within the model might cause ports to appear and decease. To stress this usage pattern, actually {{{ModelPort}}} instances are small copyable value objects (smart handles), which can be used to access data within an opaque registry. Each model port belongs to a specific Timeline and is aware of this association, as is the timeline, allowing to get the collection of all ports of a given timeline. Besides, within the Fixture each model port refers to a specific [[segmentation of the time axis|Segmentation]] (relevant for this special timeline actually). Thus, with the help of this segmentation, a model port can yield an ExitNode to pull frames for a given time.
</pre> </pre>
</div> </div>
<div title="ModelPortRegistry" modifier="Ichthyostega" modified="201012092325" created="201012030314" tags="Model impl" changecount="2"> <div title="ModelPortRegistry" modifier="Ichthyostega" modified="201012112230" created="201012030314" tags="Model impl" changecount="3">
<pre>Model ports are conceptual entities, denoting the points where output might possibly be produced &amp;rarr; see [[definition|ModelPort]]. <pre>Model ports are conceptual entities, denoting the points where output might possibly be produced &amp;rarr; see [[definition|ModelPort]].
But there is an actual representation, a collection of small descriptor objects managed by the Fixture and organised within the model port table datastructure. Because model ports are discovered during the build process, we need the ability to (re)build this table dynamically, finally swapping in the modified configuration with a transactional switch. Only the builder is allowed to perform such mutations, while for client code model ports are immutable. But there is an actual representation, a collection of small descriptor objects managed by the Fixture and organised within the model port table datastructure. Because model ports are discovered during the build process, we need the ability to (re)build this table dynamically, finally swapping in the modified configuration with a transactional switch. Only the builder is allowed to perform such mutations, while for client code model ports are immutable.
@ -2851,7 +2851,7 @@ Model ports are added once and never changed. The corresponding timeline and pip
!Implementation considerations !Implementation considerations
The transactional switch creates a clear partitioning in the lifespan of the model port table. //Before// that point, entries are just added, but not accessed in any way. //After// that point, no further mutation occurs, but lookup is frequent and happens in a variety of different configurations and transient orderings. The transactional switch creates a clear partitioning in the lifespan of the model port table. //Before// that point, entries are just added, but not accessed in any way. //After// that point, no further mutation occurs, but lookup is frequent and happens in a variety of different configurations and transient orderings.
This observation leads to the idea of using //model port references// to provide all kinds of access, searching and reordering. These encapsulate the actual access by silently assuming reference to &quot;the&quot; global current model port configuration. Thus, the actual model port descriptors could be bulk allocated in a similar manner as the processing nodes and wiring descriptors. Access to stale model ports could be detected by the port references, allowing also for a {{{bool}}} checkable &quot;has no port&quot; information. This observation leads to the idea of using //model port references// as frontend to provide all kinds of access, searching and reordering. These encapsulate the actual access by silently assuming reference to &quot;the&quot; global current model port configuration. This way the actual model port descriptors could be bulk allocated in a similar manner as the processing nodes and wiring descriptors. Access to stale model ports could be detected by the port references, allowing also for a {{{bool}}} checkable &quot;has no port&quot; information.
A model port registry, maintained by the builder, is responsible for storing the discovered model ports within a model port table, which is then swapped in after completing the build process. The {{{builder::ModelPortRegistry}}} acts as management interface, while client code accesses just the {{{ModelPort}}} frontend. A link to the actual registry instance is hooked into that frontend when bringing up the builder subsystem. A model port registry, maintained by the builder, is responsible for storing the discovered model ports within a model port table, which is then swapped in after completing the build process. The {{{builder::ModelPortRegistry}}} acts as management interface, while client code accesses just the {{{ModelPort}}} frontend. A link to the actual registry instance is hooked into that frontend when bringing up the builder subsystem.
</pre> </pre>