Builder: registry for model ports coded up

passes compiler, but not yet unit test....
Needed to change asset::ID to encapsulate the embedded hash value
This commit is contained in:
Fischlurch 2010-12-11 01:52:02 +01:00
parent 0464ca965c
commit be6f555e04
8 changed files with 209 additions and 102 deletions

View file

@ -132,6 +132,12 @@ NOBUG_CPP_DEFINE_FLAG_PARENT ( proc, progress);
NOBUG_CPP_DEFINE_FLAG_PARENT ( command, proc); NOBUG_CPP_DEFINE_FLAG_PARENT ( command, proc);
/** progress log for session datastructure */ /** progress log for session datastructure */
NOBUG_CPP_DEFINE_FLAG_PARENT ( session, proc); NOBUG_CPP_DEFINE_FLAG_PARENT ( session, proc);
/** progress log for the builder and build process */
NOBUG_CPP_DEFINE_FLAG_PARENT ( builder, proc);
/** progress log for running the engine */
NOBUG_CPP_DEFINE_FLAG_PARENT ( engine, proc);
/** progress log for play- and render subsystem */
NOBUG_CPP_DEFINE_FLAG_PARENT ( play, proc);
/** progress log for the gui */ /** progress log for the gui */
NOBUG_CPP_DEFINE_FLAG_PARENT ( gui, progress); NOBUG_CPP_DEFINE_FLAG_PARENT ( gui, progress);
/** progress log for the support lib */ /** progress log for the support lib */
@ -158,13 +164,13 @@ NOBUG_CPP_DEFINE_FLAG_PARENT ( config, logging);
/** base flag for software testing */ /** base flag for software testing */
NOBUG_CPP_DEFINE_FLAG_PARENT ( test, logging); NOBUG_CPP_DEFINE_FLAG_PARENT ( test, logging);
/** base flag for syncronization logging */ /** base flag for synchronisation logging */
NOBUG_CPP_DEFINE_FLAG_PARENT ( sync, logging); // do we need subsections here? backend_mutex_sync proc_mutex_sync etc? NOBUG_CPP_DEFINE_FLAG_PARENT ( sync, logging); // do we need subsections here? backend_mutex_sync proc_mutex_sync etc?
NOBUG_CPP_DEFINE_FLAG_PARENT ( mutex_sync, sync); //locking/unlocking mutexes NOBUG_CPP_DEFINE_FLAG_PARENT ( mutex_sync, sync); //locking/unlocking mutexes
NOBUG_CPP_DEFINE_FLAG_PARENT ( cond_sync, sync); //waiting and signalling condition vars NOBUG_CPP_DEFINE_FLAG_PARENT ( cond_sync, sync); //waiting and signalling condition vars
/** base flag for memory related logging */ /** base flag for memory related logging */
NOBUG_CPP_DEFINE_FLAG_PARENT ( memory, logging); NOBUG_CPP_DEFINE_FLAG_PARENT ( memory, logging);
/** memory busines of the proc layer */ /** proc layer memory handling */
NOBUG_CPP_DEFINE_FLAG_PARENT ( proc_mem, memory); NOBUG_CPP_DEFINE_FLAG_PARENT ( proc_mem, memory);
NOBUG_CPP_DEFINE_FLAG_PARENT ( mobject_mem, proc_mem); NOBUG_CPP_DEFINE_FLAG_PARENT ( mobject_mem, proc_mem);
NOBUG_CPP_DEFINE_FLAG_PARENT ( builder_mem, proc_mem); NOBUG_CPP_DEFINE_FLAG_PARENT ( builder_mem, proc_mem);

View file

@ -103,11 +103,11 @@ namespace asset {
template<class KIND> template<class KIND>
class ID class ID
{ {
HashVal hash_;
public: public:
const HashVal hash; ID (HashVal id) : hash_(id) {}
ID (HashVal id) : hash(id) {} ID (const KIND& asset) : hash_(asset.getID()) {}
ID (const KIND& asset) : hash(asset.getID()) {} operator HashVal() const { return hash_; }
operator HashVal() const { return hash; }
static ID INVALID; static ID INVALID;
}; };

View file

@ -24,25 +24,14 @@
#ifndef MOBJECT_BUILDER_COMMON_H #ifndef MOBJECT_BUILDER_COMMON_H
#define MOBJECT_BUILDER_COMMON_H #define MOBJECT_BUILDER_COMMON_H
#include "lib/error.hpp"
#include "include/logging.h" #include "include/logging.h"
namespace mobject { namespace mobject {
namespace builder { namespace builder {
// TODO NOBUG_DECLARE_FLAG (builder_mem);
}} // namespace mobject::builder
} // namespace builder
} // namespace mobject
#endif #endif
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -37,7 +37,10 @@
#include "lib/error.hpp" #include "lib/error.hpp"
#include "include/logging.h"
#include "lib/sync-classlock.hpp"
//#include "lib/symbol.hpp"// //#include "lib/symbol.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"
@ -55,47 +58,72 @@
namespace mobject { namespace mobject {
namespace builder { namespace builder {
namespace error = lumiera::error;
/**
* TODO type comment
*/
class ModelPortTable
: boost::noncopyable
{
public:
};
typedef ModelPortRegistry::ModelPortDescriptor const& MPDescriptor; typedef ModelPortRegistry::ModelPortDescriptor const& MPDescriptor;
typedef lib::ClassLock<ModelPortRegistry> LockRegistry;
inline MPDescriptor
accessDescriptor()
{
}
ModelPortRegistry& /** storage for the link to the
ModelPortRegistry::setActiveInstance (ModelPortRegistry& newRegistry) global Registry instance currently in charge */
lib::OptionalRef<ModelPortRegistry> ModelPortRegistry::theGlobalRegistry;
/** globally deactivate access to model ports */
void
ModelPortRegistry::shutdown ()
{ {
UNIMPLEMENTED ("handling of active model port registry"); INFO (builder, "disabling ModelPort registry....");
LockRegistry global_lock;
theGlobalRegistry.clear();
} }
/** */ /** 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
* @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.link_to (newRegistry);
return previous;
}
/** access the globally valid registry instance.
* @throw error::State if this global registry is
* already closed or not yet initialised. */
ModelPortRegistry& ModelPortRegistry&
ModelPortRegistry::globalInstance() ModelPortRegistry::globalInstance()
{ {
UNIMPLEMENTED ("access the globally valid registry instance"); LockRegistry global_lock;
if (theGlobalRegistry.isValid())
return theGlobalRegistry();
throw error::State ("global model port registry is not accessible"
, LUMIERA_ERROR_BUILDER_LIFECYCLE);
} }
/** */ /** does the <i>transaction currently being built</i>
* already contain a model port registration for the given ID?
* @note this does \em not query registration state of the
* global registry; use #isRegistered for that...*/
bool bool
ModelPortRegistry::contains (ID<Pipe> pID) const ModelPortRegistry::contains (ID<Pipe> key) const
{ {
UNIMPLEMENTED ("diagnostics querying the state of the pending transaction"); return bool(key)
&& util::contains (transaction_, key);
} }
@ -103,70 +131,117 @@ namespace mobject {
* 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 currently pending * being registered within a pending transaction
* transaction (ongoing build process). */ * (ongoing build process). */
bool bool
ModelPortRegistry::isRegistered (ID<Pipe> key) const ModelPortRegistry::isRegistered (ID<Pipe> key) const
{ {
if (!key) return false; return bool(key)
&& util::contains (currentReg_, key);
UNIMPLEMENTED ("query the publicly valid contents");
} }
/** */ /** basic access operation: access the descriptor
* of a currently valid model port.
* @note no locking (but #accessDescriptor does lock!)
* @throw error::Logic if accessing a non registered port
* @throw error::State if accessing an invalid / disconnected port
*/
MPDescriptor MPDescriptor
ModelPortRegistry::operator[] (ID<Pipe> key) const ModelPortRegistry::get (ID<Pipe> key) const
{ {
UNIMPLEMENTED ("access registered model port"); if (!key)
throw error::State ("This model port is disconnected or NIL"
, LUMIERA_ERROR_UNCONNECTED_MODEL_PORT);
if (!isRegistered (key))
throw error::Logic ("Model port was never registered, or got unregistered meanwhile."
,LUMIERA_ERROR_INVALID_MODEL_PORT);
MPTable::const_iterator pos = currentReg_.find (key);
ASSERT (pos != currentReg_.end());
ASSERT (pos->second.isValid());
return pos->second;
} }
/** */ /** access \em the globally valid model port for the given pipe.
* This (static) function locks and accesses the global model port registry
* to fetch the descriptor record. Typically invoked by client code
* through the ModelPort frontend
* @throw error::State when registry is down or the model port is disconnected
* @throw error::Logic when the given key wasn't registered for a model port */
MPDescriptor MPDescriptor
ModelPortRegistry::accessDescriptor (ID<Pipe> key) ModelPortRegistry::accessDescriptor (ID<Pipe> key)
{ {
UNIMPLEMENTED ("access the current global registry and fetch model port"); LockRegistry global_lock;
return theGlobalRegistry().get(key);
} }
/** */ /* === Mutations === */
/** create and register a new model port entry,
* within the pending transaction */
MPDescriptor MPDescriptor
ModelPortRegistry::definePort (ID<Pipe> pipeA, ID<Struct> element_exposing_this_port) ModelPortRegistry::definePort (ID<Pipe> pipe, ID<Struct> element_exposing_this_port)
{ {
UNIMPLEMENTED ("create and register a new model port entry, within the pending transaction"); LockRegistry global_lock;
if (contains (pipe))
throw error::Logic ("attempt to register a model port with a pipe-ID, "
"which has already been used to register a "
"model port within this transaction (build process)."
, LUMIERA_ERROR_DUPLICATE_MODEL_PORT);
return (transaction_[pipe] = ModelPortDescriptor(pipe, element_exposing_this_port));
} }
/** */ /** remove a model port entry from the pending transaction */
void void
ModelPortRegistry::remove (PID key) ModelPortRegistry::remove (PID key)
{ {
UNIMPLEMENTED ("remove a model port entry from the pending transaction"); LockRegistry global_lock;
transaction_.erase (key);
} }
/** */ /** schedule removal of all registry contents.
* When the currently pending transaction is committed,
* all registered model ports will be removed */
void void
ModelPortRegistry::clear() ModelPortRegistry::clear()
{ {
UNIMPLEMENTED ("schedule removal of all registry contents into the pending transaction"); LockRegistry global_lock;
transaction_.clear();
} }
/** */ /** transactional switch for new/modified model ports.
* Promote the registered model ports from the currently
* pending transaction to become the globally valid model ports
* @note automatically starts a new transaction, initialised
* with the now published mappings.
*/
void void
ModelPortRegistry::commit() ModelPortRegistry::commit()
{ {
UNIMPLEMENTED ("transactional switch for new/modified model ports"); LockRegistry global_lock;
MPTable newTransaction(transaction_);
TRACE (builder, "committing new ModelPort list....");
swap (currentReg_, transaction_);
swap (transaction_, newTransaction);
} }
/** */ /** discard current transaction.
* The global port registration thus
* remains unaltered. */
void void
ModelPortRegistry::rollback() ModelPortRegistry::rollback()
{ {
UNIMPLEMENTED ("discard current transaction"); LockRegistry global_lock;
TRACE (builder, "discarding changes to ModelPort list (rollback)....");
MPTable newTransaction(transaction_);
swap (transaction_, newTransaction);
} }
@ -189,7 +264,8 @@ namespace mobject {
} }
/** */ /** check if the global model port registration
* contains a mapping for the given pipe-ID*/
bool bool
ModelPort::exists (ID<asset::Pipe> key) ModelPort::exists (ID<asset::Pipe> key)
{ {
@ -197,25 +273,35 @@ namespace mobject {
} }
/** */ /** access the Pipe (ID) of the global model port registered
* with the ID underlying this model port.
* @throw error::Logic if no model port is registered for this Pipe-ID
*/
ID<asset::Pipe> ID<asset::Pipe>
ModelPort::pipe() const ModelPort::pipe() const
{ {
ENSURE (this->id_ == builder::ModelPortRegistry::accessDescriptor(this->id_).id); ENSURE (this->id_ == builder::ModelPortRegistry::accessDescriptor(this->id_).id());
return builder::ModelPortRegistry::accessDescriptor(this->id_).id; return builder::ModelPortRegistry::accessDescriptor(this->id_).id();
} }
/** */ /** access the timeline (or similar structural element) holding
* a global pipe which corresponds to this model port
* @throw error::Logic if no model port is registered for this Pipe-ID
*/
ID<asset::Struct> ID<asset::Struct>
ModelPort::holder() const ModelPort::holder() const
{ {
return builder::ModelPortRegistry::accessDescriptor(this->id_).holder; return builder::ModelPortRegistry::accessDescriptor(this->id_).holder();
} }
/** */ /** convenience shortcut to access the stream type
* associated with the pipe-ID corresponding to this model port.
* @note no check if this model port actually is valid
* @throw error::Invalid in case of unknown/unregistered Pipe-ID
*/
StreamType::ID StreamType::ID
ModelPort::streamType() const ModelPort::streamType() const
{ {

View file

@ -34,6 +34,12 @@
** for setting up such a registry, while all other parts of the system just access the current ** for setting up such a registry, while all other parts of the system just access the current
** model ports through the mobject::ModelPort frontend. ** model ports through the mobject::ModelPort frontend.
** **
** @note the locking is rather coarse grained; basically we're using just one
** single global lock for all ModelPortRegistry instances and all access/mutations,
** as well as for accessing the globally valid Registry through the ModelPort frontend.
** Assumed that usually there is just one Registry maintained by the builder, this is
** likely to be sufficient.
**
** @see ModelPort ** @see ModelPort
** @see OutputDesignation ** @see OutputDesignation
** @see ModelPortRegistry_test ** @see ModelPortRegistry_test
@ -44,10 +50,13 @@
#define PROC_MOBJECT_BUILDER_MODEL_PORT_REGISTRY_H #define PROC_MOBJECT_BUILDER_MODEL_PORT_REGISTRY_H
#include "lib/error.hpp" #include "lib/error.hpp"
#include "lib/optional-ref.hpp"
#include "proc/asset/pipe.hpp" #include "proc/asset/pipe.hpp"
#include "proc/asset/struct.hpp" #include "proc/asset/struct.hpp"
#include "proc/mobject/model-port.hpp" #include "proc/mobject/model-port.hpp"
#include <map>
//#include "lib/opaque-holder.hpp" //#include "lib/opaque-holder.hpp"
//#include "lib/meta/typelist-util.hpp" //#include "lib/meta/typelist-util.hpp"
@ -87,7 +96,9 @@ namespace builder {
struct ModelPortDescriptor; struct ModelPortDescriptor;
static ModelPortRegistry& static void shutdown ();
static ModelPortRegistry*
setActiveInstance (ModelPortRegistry& newRegistry); setActiveInstance (ModelPortRegistry& newRegistry);
static ModelPortRegistry& static ModelPortRegistry&
@ -104,7 +115,7 @@ namespace builder {
bool isRegistered (PID) const; bool isRegistered (PID) const;
ModelPortDescriptor const& ModelPortDescriptor const&
operator[] (PID) const; get (PID) const;
void remove (PID); void remove (PID);
@ -122,38 +133,51 @@ namespace builder {
* Silently drop model port definition changes since the last commit. * Silently drop model port definition changes since the last commit.
*/ */
void rollback(); void rollback();
private:
static lib::OptionalRef<ModelPortRegistry> theGlobalRegistry;
typedef std::map<PID, ModelPortDescriptor> MPTable;
MPTable currentReg_;
MPTable transaction_;
}; };
/** ModelPortDescriptor records are used as actual storage /** ModelPortDescriptor records are used as actual storage
* within the model port registration table; they are never * within the model port registration table; they are immutable
* exposed to client code directly. * value objects and never exposed to client code directly.
*/ */
struct ModelPortRegistry::ModelPortDescriptor class ModelPortRegistry::ModelPortDescriptor
{ {
const PID id; PID id_;
const StID holder; StID holder_;
bool protected:
isValid() const ModelPortDescriptor (PID pipe, StID element_exposing_this_port)
{ : id_(pipe)
return bool(id); , holder_(element_exposing_this_port)
} { }
friend class ModelPortRegistry;
public:
ModelPortDescriptor() ModelPortDescriptor()
: id(PID::INVALID) : id_(PID::INVALID)
, holder(StID::INVALID) , holder_(StID::INVALID)
{ } { }
// default copy operations permitted // default copy operations permitted
protected: bool
ModelPortDescriptor (PID pipe, StID element_exposing_this_port) isValid() const
: id(pipe) {
, holder(element_exposing_this_port) return bool(id_);
{ } }
const PID id() const { return id_; }
const StID holder() const { return holder_; }
}; };

View file

@ -26,11 +26,6 @@
namespace mobject { namespace mobject {
namespace builder {
using ::NOBUG_FLAG(memory);
NOBUG_CPP_DEFINE_FLAG_PARENT(buildermem, memory);
}
/** /**
* Main Operation of the Builder: * Main Operation of the Builder:
@ -42,6 +37,9 @@ namespace mobject {
//////////////////////TODO //////////////////////TODO
} }
LUMIERA_ERROR_DEFINE (BUILDER_LIFECYCLE, "Builder activated while in non operational state");
} // namespace mobject } // namespace mobject

View file

@ -31,6 +31,7 @@
namespace mobject { namespace mobject {
LUMIERA_ERROR_DECLARE (BUILDER_LIFECYCLE); ///< Builder activated while in non operational state
/** /**
* Provides unified access to the builder functionality. * Provides unified access to the builder functionality.

View file

@ -74,7 +74,7 @@ namespace test {
struct TestContext struct TestContext
{ {
ModelPortRegistry registry_; ModelPortRegistry registry_;
ModelPortRegistry& previous_; ModelPortRegistry* previous_;
/** setup */ /** setup */
TestContext() TestContext()
@ -85,7 +85,10 @@ namespace test {
/** tear-down */ /** tear-down */
~TestContext() ~TestContext()
{ {
ModelPortRegistry::setActiveInstance (previous_); if (previous_)
ModelPortRegistry::setActiveInstance (*previous_);
else
ModelPortRegistry::shutdown();
} }
}; };
@ -136,10 +139,10 @@ namespace test {
VERIFY_ERROR (DUPLICATE_MODEL_PORT, registry.definePort(pipeB, someTimeline) ); VERIFY_ERROR (DUPLICATE_MODEL_PORT, registry.definePort(pipeB, someTimeline) );
CHECK (registry.contains (pipeB)); CHECK (registry.contains (pipeB));
CHECK (p1.id == pipeA); CHECK (pipeA == p1.id());
CHECK (p2.id == pipeB); CHECK (pipeB == p2.id());
CHECK (p1.holder == someTimeline); CHECK (someTimeline == p1.holder());
CHECK (p2.holder == someTimeline); CHECK (someTimeline == p2.holder());
registry.commit(); registry.commit();
} }
@ -205,7 +208,7 @@ namespace test {
TID anotherTimeline = getTimeline ("another_test_Timeline"); TID anotherTimeline = getTimeline ("another_test_Timeline");
MPDescriptor p1 = registry.definePort (pipeA, anotherTimeline); MPDescriptor p1 = registry.definePort (pipeA, anotherTimeline);
CHECK (registry.contains (pipeA)); CHECK (registry.contains (pipeA));
CHECK (p1.holder == anotherTimeline); CHECK (anotherTimeline == p1.holder());
CHECK (ModelPort(pipeA).holder() != anotherTimeline); CHECK (ModelPort(pipeA).holder() != anotherTimeline);
registry.remove (pipeB); registry.remove (pipeB);