implement generic object attach-to-model and purge

This commit is contained in:
Fischlurch 2010-03-28 05:15:45 +02:00
parent c43040985c
commit b21db07aff
10 changed files with 218 additions and 30 deletions

View file

@ -64,6 +64,7 @@
#include "lib/lumitime.hpp"
#include "proc/mobject/placement.hpp"
#include "proc/mobject/placement-ref.hpp"
#include "proc/mobject/session/session-service-mutate.hpp"
#include <string>
@ -134,6 +135,38 @@ namespace mobject {
}
/** attach a child element to the model
* @param newPlacement to be copied into the model, placed
* into the scope of the object denoted by this MORef
* @return MORef designing the newly created and attached object instance
*/
template<class MOX>
MORef<MOX>
attach (Placement<MOX> const& newPlacement)
{
if (!isValid())
throw lumiera::error::State("Attempt to attach a child to an inactive MObject ref"
, LUMIERA_ERROR_BOTTOM_MOBJECTREF);
MORef<MOX> newInstance;
PlacementMO::ID thisScope = pRef_;
return newInstance.activate (
session::SessionServiceMutate::attach_toModel (newPlacement, thisScope));
}
/** detach this object instance from model,
* including all child elements
*/
void
purge ()
{
if (isValid())
session::SessionServiceMutate::detach_and_clear (pRef_);
ENSURE (!isValid());
}
/* === Lifecycle === */

View file

@ -121,18 +121,18 @@ namespace mobject {
static session::SessManager& current;
DefaultsAccess defaults; ///< manages default configured objects
TimelineAccess timelines; ///< collection of timelines (top level)
SequenceAccess sequences; ///< collection of sequences
DefaultsAccess defaults; ///< manages default configured objects
TimelineAccess timelines; ///< collection of timelines (top level)
SequenceAccess sequences; ///< collection of sequences
virtual bool isValid () = 0;
virtual void attach (PMO& placement) = 0;
virtual bool detach (PMO& placement) = 0;
virtual bool isValid () = 0;
virtual MObjectRef attach (PMO& placement) = 0;
virtual bool detach (PMO& placement) = 0;
virtual MObjectRef getRoot() = 0;
virtual MObjectRef getRoot() = 0;
virtual session::PFix& getFixture () = 0;
virtual void rebuildFixture () = 0;
virtual session::PFix& getFixture () = 0;
virtual void rebuildFixture () = 0;
};

View file

@ -296,6 +296,16 @@ namespace session {
return true;
}
void
removeAll (ID scopeID)
{
remove_all_from_scope (scopeID); // recursive
remove_base_entry (scopeID); // discard storage
ENSURE (!util::contains(scopeTab_, scopeID));
ENSURE (!contains (scopeID));
}
/* == access for self-test == */
@ -349,6 +359,21 @@ namespace session {
NOTREACHED();
}
void
remove_all_from_scope (ID scopeID)
{
typedef ScopeTable::const_iterator Pos;
pair<Pos,Pos> searchRange = scopeTab_.equal_range(scopeID);
Pos pos = searchRange.first;
Pos end = searchRange.second;
for ( ; pos!=end; ++pos)
removeAll (pos->second); // depth-first recursion
scopeTab_.erase (pos,end); // assumed to be NOP for pos==end
}
/** Helper for building a scope exploring iterator
* for PlacementIndex: our "reverse index" (#scopeTab_)
@ -499,6 +524,23 @@ namespace session {
}
/** recursively kill a complete scope,
* including the given element and all children.
* @note as an exception, when specifying model root,
* any sub-elements are cleared but root is retained
*/
void
PlacementIndex::clear (ID targetScope)
{
if (targetScope == getRoot().getID())
pTab_->clear();
else
pTab_->removeAll (targetScope);
ENSURE (isValid());
}
void
PlacementIndex::clear()
{

View file

@ -223,7 +223,8 @@ namespace session {
PlacementIndex(PlacementMO const&);
~PlacementIndex() ;
void clear();
void clear (ID targetScope);
void clear ();
};
@ -304,6 +305,7 @@ namespace session {
* immediately followed by creating a typed-ID,
* allowing to retain the original typed context
* @todo this solution is half-baked ///////////////////////////////////TICKET #523
* @todo is this API used in application code? or just used in tests?
*/
template<class PLA>
typename BuildID<PLA>::Type

View file

@ -75,7 +75,7 @@ namespace session {
}
void
MObjectRef
SessionImpl::attach (PMO& placement)
{
UNIMPLEMENTED ("add Placement to the current Session");

View file

@ -84,8 +84,8 @@ namespace session {
/* ==== Session API ==== */
virtual bool isValid ();
virtual void attach (PMO& placement);
virtual bool detach (PMO& placement);
virtual MObjectRef attach (PMO& placement);
virtual bool detach (PMO& placement);
virtual MObjectRef getRoot();
@ -131,6 +131,45 @@ namespace session {
template<class IMPL>
struct ServiceAccessPoint<SessionServiceMutate, IMPL>
: IMPL
{
PMO::ID const&
insertCopy (PMO const& newPlacement, PMO::ID const& scope)
{
return index().insert (newPlacement,scope);
}
bool
purgeScopeRecursively (PMO::ID const& scope)
{
size_t siz = index().size();
if (index().contains (scope))
index().clear (scope);
ENSURE (!index().contains (scope) || (scope == index().getRoot().getID()));
ENSURE (siz >= index().size());
return siz != index().size();
}
bool
detachElement (PMO::ID const& placementID)
{
return index().remove (placementID);
}
private:
PlacementIndex&
index()
{
return IMPL::getPlacementIndex();
}
};
template<class IMPL>
struct ServiceAccessPoint<SessionServiceExploreScope, IMPL>
: IMPL
@ -225,6 +264,7 @@ namespace session {
* global Session PImpl
*/
typedef SessionServices< Types< SessionServiceFetch
, SessionServiceMutate
, SessionServiceExploreScope
, SessionServiceMockIndex
, SessionServiceDefaults

View file

@ -1,8 +1,8 @@
/*
SESSION-SERVICE-FETCH.hpp - session implementation service API: fetch PlacementRef
SESSION-SERVICE-MUTATE.hpp - session implementation service API: add/remove session contents
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
2010, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@ -21,12 +21,14 @@
*/
/** @file session-service-fetch.hpp
** Implementation level session API: resolve a Placement by hash-ID.
** This specialised service is intended to be used by PlacementRef,
** in order to (re)-access the Placement instance within the session,
** given the hash-ID of this placement. An implementation of this
** service is available through the SessionServices access mechanism.
/** @file session-service-mutate.hpp
** Implementation level session API: add or remove Session contents.
** This specialised service is intended to be used by MObjectRef,
** in order to attach a new Placement to the session or to detach
** and purge an existing Placement. An implementation of this service
** service is available through the SessionServices access mechanism,
** and delegates the actual implementation to the PlacementIndex,
** which is the core session datastructure.
**
** @see session-impl.hpp implementation of the service
** @see session-services.cpp implementation of access
@ -34,8 +36,8 @@
*/
#ifndef MOBJECT_SESSION_SESSION_SERVICE_FETCH_H
#define MOBJECT_SESSION_SESSION_SERVICE_FETCH_H
#ifndef MOBJECT_SESSION_SESSION_SERVICE_MUTATE_H
#define MOBJECT_SESSION_SESSION_SERVICE_MUTATE_H
//#include "proc/mobject/session.hpp"
//#include "lib/meta/generator.hpp"
@ -47,9 +49,6 @@
namespace mobject {
namespace session {
// using lumiera::typelist::InstantiateChained;
// using lumiera::typelist::InheritFrom;
// using lumiera::typelist::NullType;
/**
* Implementation-level service for resolving an Placement-ID.
@ -58,13 +57,15 @@ namespace session {
* this index may be overlaid temporarily, by using the
* SessionServiceMockIndex API.
*/
class SessionServiceFetch
class SessionServiceMutate
{
public:
static PlacementMO& resolveID (PlacementMO::ID const&) ;
static bool isRegisteredID (PlacementMO::ID const&) ;
typedef PlacementMO const& PMO;
typedef PlacementMO::ID const& PID;
static bool isAccessible() ;
static PID attach_toModel (PMO, PID) ;
static bool detach_and_clear (PID) ;
static bool detach (PID) ;
};

View file

@ -22,6 +22,7 @@
#include "proc/mobject/session/session-service-fetch.hpp"
#include "proc/mobject/session/session-service-mutate.hpp"
#include "proc/mobject/session/session-service-explore-scope.hpp"
#include "proc/mobject/session/session-service-mock-index.hpp"
#include "proc/mobject/session/session-service-defaults.hpp"
@ -76,6 +77,46 @@ namespace session {
}
/** attach an object by placement onto the session.
* Implemented by registering a copy of the Placement into the
* PlacementIndex in the session. This copy establishes a new kind of
* "object instance", represented by a new placement-ID, which is returned
* and can be used to refer to this "instance" within the session from now on.
* @param scope the (existing) parent scope where to attach the new element
*/
PlacementMO::ID const&
SessionServiceMutate::attach_toModel(PMO newPlacement, PID scope)
{
return SessionImplAPI::current->insertCopy (newPlacement,scope);
}
/** detach the denoted element from the model <i>including all children.</i>
* @return true if actually erased something
* @note when specifying model root, all sub-elements will be cleared,
* but model root itself will be retained.
*/
bool
SessionServiceMutate::detach_and_clear (PID scope)
{
return SessionImplAPI::current->purgeScopeRecursively (scope);
}
/** detach the denoted leaf element from the model.
* @return true if actually erased something
* @throw error::Fatal when attempting to remove the model root
* @throw error::State when the given element contains sub elements
*/
bool
SessionServiceMutate::detach (PID leafElement)
{
return SessionImplAPI::current->detachElement (leafElement);
}
namespace { // deleter function to clean up test/mock PlacementIndex
void
remove_testIndex (PlacementIndex* testIdx)

View file

@ -240,6 +240,31 @@ namespace test {
ASSERT (index.remove(e133)); // but can remove an scope, after emptying it
ASSERT (!index.contains(e133));
// build a complete new subtree
uint siz = index.size();
ID e1321 = index.insert (testObj, e132);
ID e13211 = index.insert (testObj, e1321);
ID e13212 = index.insert (testObj, e1321);
ID e13213 = index.insert (testObj, e1321);
ID e13214 = index.insert (testObj, e1321);
ID e132131 = index.insert (testObj, e13213);
ID e132132 = index.insert (testObj, e13213);
ID e132133 = index.insert (testObj, e13213);
ID e132134 = index.insert (testObj, e13213);
ID e132141 = index.insert (testObj, e13214);
ID e132142 = index.insert (testObj, e13214);
ID e132143 = index.insert (testObj, e13214);
ID e132144 = index.insert (testObj, e13214);
// ...and kill it recursively in one sway
index.clear (e1321);
ASSERT (!index.contains (e1321));
ASSERT (!index.contains (e13211));
ASSERT (!index.contains (e13213));
ASSERT (!index.contains (e132131));
ASSERT (!index.contains (e132144));
ASSERT (siz == index.size());
}

View file

@ -64,6 +64,7 @@ namespace test {
using lumiera::Query;
typedef MORef<session::Clip> RClip;
typedef PlacementMO::ID PID;
@ -303,7 +304,10 @@ namespace test {
CHECK (focus.getObject() == sess->getRoot());
PID currRoot = sess->getRoot.getPlacement().getID();
sess->getRoot().purge(); // purging the root scope effectively resets the session to defaults
CHECK (currRoot == sess->getRoot.getPlacement.getID);
// but the root element itself is retained
CHECK (sess->isValid());
CHECK (1 == sess->timelines.size());
CHECK (1 == sess->sequences.size());