diff --git a/src/proc/mobject/session/placement-index.cpp b/src/proc/mobject/session/placement-index.cpp index bda82bc90..ed6395a10 100644 --- a/src/proc/mobject/session/placement-index.cpp +++ b/src/proc/mobject/session/placement-index.cpp @@ -47,6 +47,7 @@ #include #include #include +//#include #include //#include @@ -60,16 +61,18 @@ namespace session { using std::tr1::unordered_map; using std::tr1::unordered_multimap; using lib::TypedAllocationManager; -//using util::getValue_or_default; + using util::getValue_or_default; //using util::contains; //using std::string; //using std::map; using std::make_pair; + using std::pair; using namespace lumiera; LUMIERA_ERROR_DEFINE (NOT_IN_SESSION, "referring to a Placement not known to the current session"); LUMIERA_ERROR_DEFINE (PLACEMENT_TYPE, "requested Placement (pointee) type not compatible with data or context"); + LUMIERA_ERROR_DEFINE (NONEMPTY_SCOPE, "Placement scope (still) contains other elements"); @@ -95,12 +98,22 @@ namespace session { typedef PlacementIndex::ID ID; + /** + * Storage and implementation + * backing the PlacementIndex + */ class PlacementIndex::Table { typedef shared_ptr PPlacement; + struct PlacementEntry + { + PPlacement element; + PPlacement scope; + }; + // using a hashtables to implement the index - typedef unordered_map > IDTable; + typedef unordered_map > IDTable; typedef std::tr1::unordered_multimap > ScopeTable; @@ -139,13 +152,25 @@ namespace session { fetch (ID id) const { REQUIRE (contains (id)); - PPlacement const& entry = getEntry_or_throw (placementTab_,id); + PPlacement const& entry = getEntry_or_throw (placementTab_,id).element; ENSURE (entry); ENSURE (id == entry->getID()); return *entry; } + PlacementMO& + fetchScope (ID id) const + { + REQUIRE (contains (id)); + PPlacement const& scope = getEntry_or_throw (placementTab_,id).scope; + + ENSURE (scope); + ENSURE (contains (scope->getID())); + return *scope; + } + + void clear() @@ -155,22 +180,83 @@ namespace session { placementTab_.clear(); } + /** Store a copy of the given Placement as new instance + * within the index, together with the Scope this Placement + * belongs to. + * @note we discard the specific type info. + * It can be rediscovered later with the help + * of the pointee's vtable + * @see Placement#isCompatible + */ ID addEntry (PlacementMO const& newObj, PlacementMO const& targetScope) { ID scopeID = targetScope.getID(); REQUIRE (contains (scopeID)); - /////////////////////////////////////////////////////////////////////TICKET #436 PPlacement newEntry = allocator_.create (newObj); ID newID = newEntry->getID(); ASSERT (!contains (newID)); - placementTab_[newID] = newEntry; + placementTab_[newID].element = newEntry; + placementTab_[newID].scope = placementTab_[scopeID].element; scopeTab_.insert (make_pair (scopeID, newID)); return newID; } + bool + removeEntry (ID id) + { + if (!contains (id)) + { + ENSURE (!util::contains(scopeTab_, id)); + return false; + } + + if (util::contains(scopeTab_, id)) + throw error::State ("Unable to remove the specified Placement, " + "because it defines an non-empty scope. " + "You need to delete any contents first." + ,LUMIERA_ERROR_NONEMPTY_SCOPE); ////////////////TICKET #197 + + ASSERT (contains (id)); + PlacementEntry toRemove = remove_base_entry (id); + remove_from_scope (toRemove.scope->getID(), id); + ENSURE (!util::contains(scopeTab_, id)); + ENSURE (!contains (id)); + return true; + } + + + private: + PlacementEntry + remove_base_entry (ID key) + { + IDTable::iterator pos = placementTab_.find (key); + REQUIRE (pos != placementTab_.end()); + PlacementEntry dataToRemove (pos->second); + placementTab_.erase(pos); + return dataToRemove; + } + + void + remove_from_scope (ID scopeID, ID entryID) + { + typedef ScopeTable::iterator Pos; + pair searchRange = scopeTab_.equal_range(scopeID); + + Pos pos = searchRange.first; + Pos end = searchRange.second; + for ( ; pos!=end; ++pos) + if (pos->second == entryID) + { + scopeTab_.erase(pos); + return; + } + + NOTREACHED(); + } + }; @@ -212,20 +298,22 @@ namespace session { PlacementMO& PlacementIndex::find (ID id) const { - if (!contains (id)) - throw error::Invalid ("Accessing Placement not registered within the index" - ,LUMIERA_ERROR_NOT_IN_SESSION); ///////////////////////TICKET #197 - + __check_knownID(*this,id); return pTab_->fetch (id); } + /** retrieve the Scope information + * registered alongside with the denoted Placement. + * @throw error::Invalid when the given ID isn't registered + * @note root is it's own scope, per definition. + */ PlacementMO& - PlacementIndex::getScope (ID) const + PlacementIndex::getScope (ID id) const { - UNIMPLEMENTED ("Secondary core operation of PlacmentIndex: find the 'parent' Placement by using the Placement relation index"); - /// decision: root is his own scope + __check_knownID(*this,id); + return pTab_->fetchScope (id); } @@ -263,10 +351,15 @@ namespace session { } + /** Remove and discard a Placement (Object "instance") from the index. + * Usually this means removing this Object from the session. + * @return \c true if actually removed an object. + * @throw error::State if the object to be removed is an non-empty scope + */ bool - PlacementIndex::remove (ID) + PlacementIndex::remove (ID id) { - UNIMPLEMENTED ("remove a information record from PlacementIndex, and also de-register any placement-relations bound to it"); + return pTab_->removeEntry (id); } diff --git a/src/proc/mobject/session/placement-index.hpp b/src/proc/mobject/session/placement-index.hpp index e11496954..823d826fd 100644 --- a/src/proc/mobject/session/placement-index.hpp +++ b/src/proc/mobject/session/placement-index.hpp @@ -71,6 +71,7 @@ namespace session { LUMIERA_ERROR_DECLARE (NOT_IN_SESSION); ///< referring to a Placement not known to the current session LUMIERA_ERROR_DECLARE (PLACEMENT_TYPE); ///< requested Placement (pointee) type not compatible with data or context + LUMIERA_ERROR_DECLARE (NONEMPTY_SCOPE); ///< Placement scope (still) contains other elements using lib::factory::RefcountFac; @@ -166,17 +167,31 @@ namespace session { /* === forwarding implementations of the templated API === */ - template - inline void - ___check_compatibleType(PlacementMO& questionable) - { - if (!questionable.isCompatible()) - throw lumiera::error::Logic ("Attempt to retrieve a Placement of specific type, " - "while the actual type of the pointee (MObject) " - "registered within the index isn't compatible with the " - "requested specific MObject subclass" - ,LUMIERA_ERROR_PLACEMENT_TYPE); - } + + namespace { // shortcuts... + + template + inline void + ___check_compatibleType(PlacementMO& questionable) + { + if (!questionable.isCompatible()) + throw lumiera::error::Logic ("Attempt to retrieve a Placement of specific type, " + "while the actual type of the pointee (MObject) " + "registered within the index isn't compatible with the " + "requested specific MObject subclass" + ,LUMIERA_ERROR_PLACEMENT_TYPE); + } + + inline void + __check_knownID(PlacementIndex const& idx, PlacementMO::ID id) + { + if (!idx.contains (id)) + throw lumiera::error::Invalid ("Accessing Placement not registered within the index" + ,LUMIERA_ERROR_NOT_IN_SESSION); ///////////////////////TICKET #197 + } + }//(End) shortcuts + + template