diff --git a/src/proc/mobject/session/scope-path.cpp b/src/proc/mobject/session/scope-path.cpp index e511d356f..2b8896c10 100644 --- a/src/proc/mobject/session/scope-path.cpp +++ b/src/proc/mobject/session/scope-path.cpp @@ -22,49 +22,90 @@ #include "proc/mobject/session/scope-path.hpp" +#include "proc/mobject/session/scope-locator.hpp" +#include "proc/mobject/session/session-service-explore-scope.hpp" +#include "proc/mobject/mobject.hpp" +#include "lib/itertools.hpp" +#include "lib/symbol.hpp" #include "lib/error.hpp" #include "lib/util.hpp" -//#include "proc/mobject/session/track.hpp" -//#include "proc/mobject/placement.hpp" -//#include "proc/mobject/session/mobjectfactory.hpp" -//#include "proc/asset/track.hpp" #include +#include namespace mobject { namespace session { + using std::reverse; + using std::tr1::bind; using std::tr1::function; using std::tr1::placeholders::_1; + using lib::append_all; using util::and_all; using namespace lumiera; - /** by default, a scope path just contains - * the root scope of the current session (PlacementIndex). - * @note invoking this function accesses the session and thus - * may cause an empty default session to be created. + LUMIERA_ERROR_DEFINE (EMPTY_SCOPE_PATH, "Placement scope not locatable (empty model path)"); + + + + namespace { // Helpers and shortcuts.... + + /** issue a query to discover the path to root, + * starting with the given scope */ + inline ScopeQuery::iterator + discoverScopePath (Scope const& leaf) + { + return ScopeLocator::instance().locate (leaf); + } + + + void + ___check_notBottom (const ScopePath *path, lib::Literal operation_descr) + { + REQUIRE (path); + if (path->empty()) + throw error::Invalid (operation_descr+" an empty placement scope path" + , LUMIERA_ERROR_EMPTY_SCOPE_PATH); + } + }//(End) helpers + + + + + /** + * Create an \em empty path. + * By default, a scope path just contains + * the root scope of the current session (PlacementIndex). + * @note invoking this function accesses the session and thus + * may cause an empty default session to be created. */ ScopePath::ScopePath () + : path_() { - UNIMPLEMENTED ("default path just containing root"); + clear(); } - /** When creating a path to a given (leaf) scope, - * the complete sequence of nested scopes leading to - * this special scope is discovered, using the query service - * exposed by the session (through ScopeLocator). - * @note when locating the default (invalid) scope, - * a special empty ScopePath is created - * @throw error::Invalid if the given target scope - * can't be connected to the (implicit) root + /** + * When creating a path to a given (leaf) scope, + * the complete sequence of nested scopes leading to + * this special scope is discovered, using the query service + * exposed by the session (through ScopeLocator). + * @note when locating the default (invalid) scope, + * a special empty ScopePath is created + * @throw error::Invalid if the given target scope + * can't be connected to the (implicit) root */ ScopePath::ScopePath (Scope const& leaf) + : path_() { - UNIMPLEMENTED ("initialise by discovering complete scope sequence"); + if (!leaf.isValid()) return; // invalid leaf defines invalid path.... + + append_all (discoverScopePath(leaf), path_); + reverse (path_.begin(), path_.end()); } @@ -72,54 +113,66 @@ namespace session { const ScopePath ScopePath::INVALID = ScopePath(Scope()); - /* == Diagnostics == */ - /** a \em valid path consists of more than just the root element. * @note contrary to this, an \em empty path doesn't even contain a root element */ - bool + inline bool ScopePath::isValid() const { - UNIMPLEMENTED ("validity self check: more than just root"); + return (0 < length()) +#ifndef NDEBUG + && hasValidRoot() +#endif + ; } - /** an empty path doesn't even contain a root element. - * Many operations throw when invoked on such a path. - * Navigating up from an root path creates an empty path. - */ bool - ScopePath::empty() const + ScopePath::hasValidRoot() const { - UNIMPLEMENTED ("empty == no elements, even no root!"); + REQUIRE (0 < length()); + return path_[0] == currModelRoot(); } + PlacementMO const& + ScopePath::currModelRoot() const + { + return SessionServiceExploreScope::getScopeRoot(); + } + + + /* == Relations == */ - Scope& + Scope const& ScopePath::getLeaf() const { - UNIMPLEMENTED ("access end node of current path"); + ___check_notBottom (this, "Inspecting"); + return path_.back(); } /** verify the scope in question is equivalent * to our leaf scope. Equivalence of scopes means * they are defined by the same scope top placement, - * i.e. registered with the same Placement-ID. + * i.e. registered with the same Placement-ID. */ bool ScopePath::endsAt(Scope const& aScope) const { - UNIMPLEMENTED ("verify the scope in question is identical (same ID) to our leaf scope"); + return aScope == getLeaf(); } bool ScopePath::contains (Scope const& aScope) const { - UNIMPLEMENTED ("containment check"); + for (iterator ii = this->begin(); ii; ++ii) + if (aScope == *ii) + return true; + + return false; } @@ -144,52 +197,83 @@ namespace session { ScopePath commonPrefix (ScopePath const& path1, ScopePath const& path2) { - UNIMPLEMENTED ("determine the common prefix, if any"); + typedef std::vector::iterator VIter; + ScopePath prefix (ScopePath::INVALID); + uint len = std::min (path1.length(), path2.length()); + for (uint pos = 0; pos -//#include -using std::vector; -//using std::string; namespace mobject { namespace session { + LUMIERA_ERROR_DECLARE (EMPTY_SCOPE_PATH); ///< Placement scope not locatable (empty model path) + /** * Sequence of nested scopes within the high-level model. @@ -113,7 +110,7 @@ namespace session { class ScopePath : public lib::BoolCheckable { - vector path_; + std::vector path_; typedef vector _VType; typedef _VType::const_reverse_iterator _VIter; @@ -139,7 +136,7 @@ namespace session { /* == relations == */ - Scope& getLeaf() const; + Scope const& getLeaf() const; bool endsAt (Scope const&) const; bool contains (Scope const&) const; bool contains (ScopePath const&) const; @@ -156,8 +153,17 @@ namespace session { Scope& goRoot(); void navigate (Scope const&); + + private: + bool hasValidRoot() const; + PlacementMO const& currModelRoot() const; + void appendScope (Scope const&); }; -///////////////////////////TODO currently just fleshing the API + + + + + inline bool @@ -186,6 +192,16 @@ namespace session { return path_.size(); } + /** an empty path doesn't even contain a root element. + * Many operations throw when invoked on such a path. + * Navigating up from an root path creates an empty path. + */ + inline bool + ScopePath::empty() const + { + return path_.empty(); + } + inline ScopePath::iterator ScopePath::begin() const diff --git a/src/proc/mobject/session/session-service-explore-scope.hpp b/src/proc/mobject/session/session-service-explore-scope.hpp index 577705cb9..a93b08ba3 100644 --- a/src/proc/mobject/session/session-service-explore-scope.hpp +++ b/src/proc/mobject/session/session-service-explore-scope.hpp @@ -57,6 +57,14 @@ namespace session { + /** + * Implementation-level service for issuing contents/discovery queries. + * Actually, the implementation of this service is backed by the PlacementIndex + * within the current session, but this link isn't disclosed to client code. + * The exposed QueryResolver is able to handle typed DiscoveryQuery instances. + * Usually, on invocation, a search scope needs to be specified. The root Scope + * of the current model (session datastructure) can be obtained by #getScopeRoot + */ struct SessionServiceExploreScope { static QueryResolver const& getResolver(); diff --git a/src/proc/mobject/session/session-services.cpp b/src/proc/mobject/session/session-services.cpp index 87392fe55..65b9a3b2c 100644 --- a/src/proc/mobject/session/session-services.cpp +++ b/src/proc/mobject/session/session-services.cpp @@ -61,7 +61,7 @@ namespace session { } - /** */ + /** Re-define the implicit PlacementIndex temporarily, e.g. for unit tests. */ void SessionServiceMockIndex::reset_PlacementIndex (PPIdx const& alternativeIndex) { @@ -69,7 +69,7 @@ namespace session { } - /** */ + /** @return resolver for DiscoveryQuery instances, actually backed by PlacementIndex */ QueryResolver const& SessionServiceExploreScope::getResolver() { @@ -77,7 +77,7 @@ namespace session { } - /** */ + /** @return root scope of the current model (session datastructure) */ PlacementMO& SessionServiceExploreScope::getScopeRoot() {