ModelPort registry unit test pass (closes #727)
This commit is contained in:
parent
be6f555e04
commit
8a54e00b6b
7 changed files with 92 additions and 97 deletions
|
|
@ -21,13 +21,13 @@
|
|||
* *****************************************************/
|
||||
|
||||
|
||||
/** @file model-port-registry.cpp
|
||||
/** @file model-port-registry.cpp
|
||||
** 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
|
||||
** this translation unit.
|
||||
**
|
||||
** TODO: comment necessary?
|
||||
** this translation unit. Both the client interface (ModelPort) and
|
||||
** the management interface (ModelPortRegistry) are backed by this
|
||||
** common translation unit.
|
||||
**
|
||||
** @see OutputDesignation
|
||||
** @see OutputMapping
|
||||
|
|
@ -39,22 +39,10 @@
|
|||
#include "lib/error.hpp"
|
||||
#include "include/logging.h"
|
||||
#include "lib/sync-classlock.hpp"
|
||||
//#include "lib/symbol.hpp"//
|
||||
#include "proc/mobject/builderfacade.hpp"
|
||||
#include "proc/mobject/model-port.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 builder {
|
||||
|
||||
|
|
@ -65,8 +53,8 @@ namespace mobject {
|
|||
typedef lib::ClassLock<ModelPortRegistry> LockRegistry;
|
||||
|
||||
|
||||
/** storage for the link to the
|
||||
global Registry instance currently in charge */
|
||||
/** storage for the link to the global
|
||||
Registry instance currently in charge */
|
||||
lib::OptionalRef<ModelPortRegistry> ModelPortRegistry::theGlobalRegistry;
|
||||
|
||||
|
||||
|
|
@ -82,18 +70,19 @@ namespace mobject {
|
|||
|
||||
|
||||
/** switch the implicit link to \em the global ModelPort registry
|
||||
* to point to the given implementation instance. Typically used within
|
||||
* the Builder subsystem lifecycle methods, or for unit tests to use
|
||||
* a test instance of the registry temporarily
|
||||
* to point to the given implementation instance. Typically used
|
||||
* within the Builder subsystem lifecycle methods, or for
|
||||
* temporarily exchanging the registry for unit tests
|
||||
* @return the registry instance previously in use or \c NULL
|
||||
*/
|
||||
ModelPortRegistry*
|
||||
ModelPortRegistry::setActiveInstance (ModelPortRegistry& newRegistry)
|
||||
{
|
||||
INFO (builder, "activating new ModelPort registry.");
|
||||
LockRegistry global_lock;
|
||||
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);
|
||||
return previous;
|
||||
}
|
||||
|
|
@ -112,7 +101,7 @@ namespace mobject {
|
|||
throw error::State ("global model port registry is not accessible"
|
||||
, LUMIERA_ERROR_BUILDER_LIFECYCLE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** does the <i>transaction currently being built</i>
|
||||
|
|
@ -128,8 +117,8 @@ namespace mobject {
|
|||
|
||||
|
||||
/** @return true if the given pipe-ID actually denotes an
|
||||
* existing, connected and usable model port.
|
||||
* @note reflects the state of the publicly visible
|
||||
* existing, connected and usable model port.
|
||||
* @note reflects the state of the publicly visible
|
||||
* model port registry, \em not any model ports
|
||||
* being registered within a pending transaction
|
||||
* (ongoing build process). */
|
||||
|
|
@ -240,22 +229,22 @@ namespace mobject {
|
|||
{
|
||||
LockRegistry global_lock;
|
||||
TRACE (builder, "discarding changes to ModelPort list (rollback)....");
|
||||
MPTable newTransaction(transaction_);
|
||||
MPTable newTransaction(currentReg_);
|
||||
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");
|
||||
|
||||
} // namespace builder
|
||||
|
||||
}// namespace builder
|
||||
|
||||
|
||||
|
||||
|
||||
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");
|
||||
|
||||
|
||||
|
||||
ModelPort::ModelPort (ID<asset::Pipe> refID)
|
||||
: id_(refID)
|
||||
|
|
@ -307,8 +296,7 @@ namespace mobject {
|
|||
{
|
||||
return this->id_.streamType();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace mobject
|
||||
|
|
|
|||
|
|
@ -57,19 +57,11 @@
|
|||
|
||||
#include <map>
|
||||
|
||||
//#include "lib/opaque-holder.hpp"
|
||||
//#include "lib/meta/typelist-util.hpp"
|
||||
|
||||
//extern "C" {
|
||||
//#include "lib/luid.h"
|
||||
//}
|
||||
|
||||
namespace mobject {
|
||||
namespace builder {
|
||||
|
||||
using asset::ID;
|
||||
using asset::Pipe;
|
||||
//using asset::PPipe;
|
||||
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
|
||||
|
|
@ -92,18 +84,19 @@ namespace builder {
|
|||
typedef ID<Struct> StID;
|
||||
|
||||
public:
|
||||
|
||||
/** @internal record to describe a model port */
|
||||
struct ModelPortDescriptor;
|
||||
|
||||
|
||||
static void shutdown ();
|
||||
|
||||
|
||||
static ModelPortRegistry*
|
||||
setActiveInstance (ModelPortRegistry& newRegistry);
|
||||
|
||||
static ModelPortRegistry&
|
||||
globalInstance();
|
||||
|
||||
|
||||
static ModelPortDescriptor const&
|
||||
accessDescriptor (PID);
|
||||
|
||||
|
|
@ -134,6 +127,7 @@ namespace builder {
|
|||
*/
|
||||
void rollback();
|
||||
|
||||
|
||||
private:
|
||||
static lib::OptionalRef<ModelPortRegistry> theGlobalRegistry;
|
||||
|
||||
|
|
@ -145,6 +139,7 @@ namespace builder {
|
|||
|
||||
|
||||
|
||||
|
||||
/** ModelPortDescriptor records are used as actual storage
|
||||
* within the model port registration table; they are immutable
|
||||
* value objects and never exposed to client code directly.
|
||||
|
|
@ -179,7 +174,7 @@ namespace builder {
|
|||
const PID id() const { return id_; }
|
||||
const StID holder() const { return holder_; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}} // namespace mobject::builder
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
** Organising the output data calculation possibilities.
|
||||
** Model ports are conceptual entities, denoting the points where output might
|
||||
** 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
|
||||
** 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
|
||||
|
|
@ -44,16 +44,16 @@
|
|||
** to become the valid current model port configuration. After that switch, model ports
|
||||
** are immutable.
|
||||
**
|
||||
** Model ports are to be accessed, enumerated and grouped in various ways, because each
|
||||
** port belongs to a specific timeline and is used for producing data of a single
|
||||
** Model ports are to be accessed, enumerated and grouped in various ways, because
|
||||
** 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
|
||||
** after the build process has discovered all model ports currently available.
|
||||
** Thus actually the ModelPort elements handed out to client code are just
|
||||
** smart-handles, accessing a global ModelPortRegistry behind the scenes.
|
||||
** Validity of these handles will be checked on each access. The actual
|
||||
** model port descriptors are owned and managed by the fixture;
|
||||
** they are bulk allocated in a similar manner than the
|
||||
** ProcNode and WiringDescriptor objects.
|
||||
** @todo they might bulk allocated in a similar manner than the
|
||||
** ProcNode and WiringDescriptor objects are.
|
||||
**
|
||||
** @see ModelPortRegistry_test abstract usage example
|
||||
** @see ModelPortRegistry management interface
|
||||
|
|
@ -72,8 +72,8 @@
|
|||
|
||||
namespace mobject {
|
||||
|
||||
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 (INVALID_MODEL_PORT); ///< Referral to unknown model port
|
||||
LUMIERA_ERROR_DECLARE (UNCONNECTED_MODEL_PORT); ///< Attempt to operate on an existing but unconnected model port
|
||||
|
||||
|
||||
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.
|
||||
* ModelPort is a frontend to be used by clients.
|
||||
* 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
|
||||
* maintain a ModelPortRegistry behind the scenes.
|
||||
*
|
||||
* 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
|
||||
* the corresponding pipe). A model port may be in \em unconnected
|
||||
* state, which can be checked by \c bool conversion. While the
|
||||
* ModelPort handles are value objects, the identity of the
|
||||
* underlying model port (descriptor) is given by the
|
||||
* state, which can be checked through \c bool conversion. While
|
||||
* the ModelPort handles are value objects, the identity of the
|
||||
* underlying model port (descriptor) is given by the
|
||||
* corresponding pipe-ID, thus effectively resulting
|
||||
* in a global namespace for model ports.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -152,6 +152,7 @@ namespace session {
|
|||
closeSessionInterface()
|
||||
{ /////////////////////// TICKET #699
|
||||
INFO (session, "closing session interfaces.");
|
||||
TODO ("actually close session interfaces :) and don't babble in the log when NOT closing anything...");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ PLANNED "BuildSegment_test" BuildSegment_test <<END
|
|||
END
|
||||
|
||||
|
||||
PLANNED "ModelPort registry" ModelPortRegistry_test <<END
|
||||
TEST "ModelPort registry" ModelPortRegistry_test <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
|
|
|||
|
|
@ -24,25 +24,18 @@
|
|||
#include "lib/test/run.hpp"
|
||||
#include "lib/test/test-helper.hpp"
|
||||
#include "proc/mobject/builder/model-port-registry.hpp"
|
||||
#include "proc/asset/pipe.hpp"
|
||||
#include "proc/asset/timeline.hpp"
|
||||
#include "proc/asset/pipe.hpp"
|
||||
#include "lib/query.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
//#include <boost/format.hpp>
|
||||
//#include <boost/scoped_ptr.hpp>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace mobject {
|
||||
namespace builder {
|
||||
namespace test {
|
||||
|
||||
//using boost::format;
|
||||
//using boost::scoped_ptr;
|
||||
using util::isSameObject;
|
||||
using util::isnil;
|
||||
using std::string;
|
||||
|
||||
using asset::Pipe;
|
||||
using asset::PPipe;
|
||||
|
|
@ -53,6 +46,8 @@ namespace test {
|
|||
|
||||
typedef asset::ID<Pipe> PID;
|
||||
typedef asset::ID<Struct> TID;
|
||||
|
||||
typedef ModelPortRegistry::ModelPortDescriptor const& MPDescriptor;
|
||||
|
||||
|
||||
namespace { // test environment
|
||||
|
|
@ -69,8 +64,6 @@ namespace test {
|
|||
return asset::Struct::retrieve (Query<Timeline> ("id("+id+")"))->getID();
|
||||
}
|
||||
|
||||
typedef ModelPortRegistry::ModelPortDescriptor const& MPDescriptor;
|
||||
|
||||
struct TestContext
|
||||
{
|
||||
ModelPortRegistry registry_;
|
||||
|
|
@ -91,14 +84,15 @@ namespace test {
|
|||
ModelPortRegistry::shutdown();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*********************************************************************************
|
||||
* @test create a standalone model port registry to verify the behaviour of
|
||||
* model ports, accessed through reference handles. This test provides
|
||||
* an example setup detached from the real usage situation within the builder.
|
||||
* model ports, accessed through reference handles. This test provides an
|
||||
* example setup detached from the real usage situation within the builder.
|
||||
* The ModelPortRegistry management interface is used to create and track a
|
||||
* 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.
|
||||
|
|
@ -126,7 +120,6 @@ namespace test {
|
|||
/* == some Assets to play with == */
|
||||
PID pipeA = getPipe ("pipeA");
|
||||
PID pipeB = getPipe ("pipeB");
|
||||
PID pipeWC = getPipe ("WCpipe");
|
||||
TID someTimeline = getTimeline ("some_test_Timeline");
|
||||
|
||||
// start out with defining some new model ports......
|
||||
|
|
@ -158,17 +151,18 @@ namespace test {
|
|||
ModelPort mp1(pipeA);
|
||||
ModelPort mp2(pipeB);
|
||||
|
||||
VERIFY_ERROR (INVALID_MODEL_PORT, ModelPort(pipeWC));
|
||||
VERIFY_ERROR (INVALID_MODEL_PORT, ModelPort unbefitting(pipeWC) );
|
||||
|
||||
ModelPort mp1x(pipeA);
|
||||
ModelPort mpNull;
|
||||
ModelPort mp1x(pipeA); // can be created multiple times
|
||||
ModelPort mp2x(mp1x); // can be copied at will
|
||||
ModelPort mpNull; // can be default constructed (->unconnected)
|
||||
|
||||
CHECK (mp1);
|
||||
CHECK (mp2);
|
||||
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 (pipeWC));
|
||||
|
||||
|
|
@ -182,7 +176,8 @@ namespace test {
|
|||
CHECK (mp1.pipe() == pipeA);
|
||||
CHECK (mp2.pipe() == pipeB);
|
||||
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());
|
||||
}
|
||||
|
|
@ -201,8 +196,8 @@ namespace test {
|
|||
CHECK (ModelPort::exists (pipeA));
|
||||
CHECK (registry.contains (pipeA));
|
||||
registry.remove (pipeA);
|
||||
CHECK ( ModelPort::exists (pipeA));
|
||||
CHECK (!registry.contains (pipeA));
|
||||
CHECK (!registry.contains (pipeA)); // removed from the current (pending) transaction
|
||||
CHECK ( ModelPort::exists (pipeA)); // but not yet publicly visible
|
||||
|
||||
// now create a new and differing definition of port A
|
||||
TID anotherTimeline = getTimeline ("another_test_Timeline");
|
||||
|
|
@ -211,16 +206,18 @@ namespace test {
|
|||
CHECK (anotherTimeline == p1.holder());
|
||||
CHECK (ModelPort(pipeA).holder() != anotherTimeline);
|
||||
|
||||
registry.remove (pipeB);
|
||||
registry.definePort (pipeWC,anotherTimeline);
|
||||
registry.remove (pipeB); // some more wired definitions
|
||||
registry.definePort (pipeWC, anotherTimeline);
|
||||
CHECK (!registry.contains (pipeB));
|
||||
CHECK ( registry.contains (pipeWC));
|
||||
CHECK ( ModelPort::exists (pipeB));
|
||||
CHECK (!ModelPort::exists (pipeWC));
|
||||
|
||||
ModelPort portA(pipeA);
|
||||
CHECK ( registry.isRegistered (pipeB)); // this is the same as ModelPort::exists
|
||||
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);
|
||||
VERIFY_ERROR (INVALID_MODEL_PORT, ModelPort(pipeWC));
|
||||
VERIFY_ERROR (INVALID_MODEL_PORT, ModelPort ineptly(pipeWC));
|
||||
CHECK (portA);
|
||||
CHECK (portB);
|
||||
CHECK (portA.pipe() == pipeA);
|
||||
|
|
@ -228,30 +225,44 @@ namespace test {
|
|||
CHECK (portA.holder() != anotherTimeline);
|
||||
|
||||
registry.commit();
|
||||
CHECK ( ModelPort::exists (pipeA));
|
||||
CHECK ( ModelPort::exists (pipeA)); // now all our changes got publicly visible
|
||||
CHECK (!ModelPort::exists (pipeB));
|
||||
CHECK ( ModelPort::exists (pipeWC));
|
||||
CHECK ( portA);
|
||||
CHECK (!portB);
|
||||
CHECK (portA.holder() == anotherTimeline);
|
||||
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.pipe() == pipeWC);
|
||||
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.clear();
|
||||
registry.clear(); // remove everything from the pending transaction
|
||||
CHECK (!registry.contains (pipeA));
|
||||
CHECK (!registry.contains (pipeB));
|
||||
CHECK (!registry.contains (pipeWC));
|
||||
|
||||
registry.rollback();
|
||||
CHECK ( registry.contains (pipeA));
|
||||
registry.definePort (pipeB, anotherTimeline);
|
||||
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));
|
||||
|
||||
VERIFY_ERROR(INVALID_MODEL_PORT, registry.get(pipeB) );
|
||||
CHECK (!portB);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2819,7 +2819,7 @@ These are used as token for dealing with other objects and have no identity of t
|
|||
|
||||
</pre>
|
||||
</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]] &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.
|
||||
|
|
@ -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.
|
||||
|
||||
!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>
|
||||
</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 &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.
|
||||
|
||||
|
|
@ -2851,7 +2851,7 @@ Model ports are added once and never changed. The corresponding timeline and pip
|
|||
!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.
|
||||
|
||||
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 "the" 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 "has no port" 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 "the" 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 "has no port" 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.
|
||||
</pre>
|
||||
|
|
|
|||
Loading…
Reference in a new issue