Scope handling within the PlacementIndex

This commit is contained in:
Fischlurch 2009-11-28 22:18:09 +01:00
parent 8a47f1a1ac
commit feb4480f85
2 changed files with 133 additions and 25 deletions

View file

@ -47,6 +47,7 @@
#include <boost/noncopyable.hpp>
#include <tr1/unordered_map>
#include <tr1/memory>
//#include <algorithm>
#include <string>
//#include <map>
@ -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<PlacementMO> PPlacement;
struct PlacementEntry
{
PPlacement element;
PPlacement scope;
};
// using a hashtables to implement the index
typedef unordered_map<ID, PPlacement, hash<ID> > IDTable;
typedef unordered_map<ID, PlacementEntry, hash<ID> > IDTable;
typedef std::tr1::unordered_multimap<ID,ID, hash<ID> > 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<PlacementMO> (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<Pos,Pos> 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);
}

View file

@ -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<class MOX>
inline void
___check_compatibleType(PlacementMO& questionable)
{
if (!questionable.isCompatible<MOX>())
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<class MOX>
inline void
___check_compatibleType(PlacementMO& questionable)
{
if (!questionable.isCompatible<MOX>())
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<class MO>