implement registry for element-tracking. passes unit test

This commit is contained in:
Fischlurch 2010-03-12 17:16:11 +01:00
parent 9ec865c3ab
commit dd3d22f950
4 changed files with 112 additions and 34 deletions

View file

@ -50,6 +50,7 @@
#define LIB_ELEMENT_TRACKER_H
#include "lib/p.hpp"
#include "lib/util-foreach.hpp"
#include "lib/ref-array-impl.hpp"
@ -60,32 +61,87 @@ namespace lib {
using lumiera::P;
/**
* Registry for tracking object instances.
* Custom implementation of the RefArray interface,
* used by the Session to keep track of all timelines
* and sequences. The registration/deregistration functions
* are accessible as SessionServices
* based on a vector. Especially used by the Session
* to keep track of all timelines and sequences.
* Typically, ELM will inherit from AutoRegistered<ELM>,
* which in turn will invoke the registration/deregistration.
* Because of the smart-ptr-from-this problem, removal takes
* a direct reference, as opposed to a smart-ptr.
* @note ELM is required to provide an equality test.
* Depending on the semantics of this equality,
* registration might behave surprisingly, as
* previously registered \em equivalent instances
* will be deregistered prior to appending the
* new instance.
*/
template<typename ELM>
class ElementTracker
: public lib::RefArrayVector<P<ELM> >
{
typedef std::vector<P<ELM> > _Vec;
typedef typename _Vec::iterator Iter;
typedef typename _Vec::const_iterator CIter;
public:
~ElementTracker()
{
try { clear(); }
catch(...) {/*ignored*/}
}
void
clear ()
{
_Vec toKill;
toKill.reserve(_Vec::size());
toKill.swap(*this);
ASSERT (0 == _Vec::size());
util::for_each (toKill, unlink_it);
}
void
append (P<ELM> const& asset)
{
UNIMPLEMENTED ("attach entry to session");
REQUIRE (asset, "Attempt to track a NIL element");
remove (*asset);
push_back (asset);
}
void
remove (ELM const& asset)
{
UNIMPLEMENTED ("detach entry from session");
for (Iter i = _Vec::begin();
i != _Vec::end() ; ++i )
if (asset == **i) // _Vec contains smart-ptrs
{ // ELM is required to define '=='
erase (i);
return;
}
}
bool
isRegistered (ELM const& asset)
isRegistered (ELM const& asset) const
{
UNIMPLEMENTED ("detect if the given element is indeed registered within this");
for (CIter i = _Vec::begin();
i != _Vec::end() ; ++i )
if (asset == **i)
return true;
return false;
}
private:
static void
unlink_it (P<ELM>& elm)
{
REQUIRE (elm);
try { elm->detach(); }
catch(...)
{
WARN (common,"ignoring problems while clearing ElementTracker");
}
}
};

View file

@ -78,7 +78,10 @@ namespace asset {
class Sequence
: public Struct
{
public:
void detach() { TODO("Session-Sequence registration"); }
protected:
Sequence (const Asset::Ident& idi);
friend class StructFactoryImpl;

View file

@ -83,6 +83,9 @@ namespace asset {
class Timeline
: public Struct
{
public:
void detach() { TODO("Timeline-Session registration"); }
protected:
Timeline (const Asset::Ident& idi);

View file

@ -53,7 +53,8 @@ namespace test {
namespace { // yet another accounting dummy
int checksum = 0;
uint instance = 0;
int checksum = 0;
using std::tr1::function;
@ -82,19 +83,17 @@ namespace test {
typedef lib::ElementTracker<TAR> Registry;
typedef function<Registry&(void)> RegistryLink;
template<typename FUN>
static void
establishRegistryLink (FUN link)
// virtual ~AutoRegistered() {} ////////////////////////////////////TODO template code bloat?
//
// virtual void ////////////////////////////////////TODO clarify de-registration
void
detach()
{
AutoRegistered::getRegistry = link;
}
static void
setRegistryInstance (Registry& registry_to_use)
{
RegistryLink accessInstance = ReturnRef<Registry>(registry_to_use);
establishRegistryLink (accessInstance);
#if false ///////////////////////////////////////////////////////////////////////////TODO clarify de-registration
getRegistry().remove(*this);
ENSURE (!getRegistry().isRegistered(*this));
#endif ///////////////////////////////////////////////////////////////////////////TODO clarify de-registration
}
@ -114,12 +113,18 @@ namespace test {
}
void
detach()
template<typename FUN>
static void
establishRegistryLink (FUN link)
{
getRegistry().remove(*this);
ENSURE (!getRegistry().isRegistered(*this));
AutoRegistered::getRegistry = link;
}
static void
setRegistryInstance (Registry& registry_to_use)
{
RegistryLink accessInstance = ReturnRef<Registry>(registry_to_use);
establishRegistryLink (accessInstance);
}
protected:
@ -144,22 +149,29 @@ namespace test {
{
const uint id_;
public:
Dummy()
: id_(++checksum)
: id_(++instance)
{
CHECK (getRegistry().isRegistered (*this));
checksum += id_;
}
// to be created by factory...
friend class AutoRegistered<Dummy>;
public:
// virtual void /////////////////////////////TODO
void
unlink()
detach()
{
getRegistry().remove(*this);
ENSURE (!getRegistry().isRegistered(*this));
///////////////////////////////////////////////////////////////TODO: should call the baseclass!
// AutoRegistered<Dummy>::detach();
checksum -= id_;
}
};
bool
operator== (Dummy const& d1, Dummy const& d2)
{
@ -198,13 +210,14 @@ namespace test {
run (Arg)
{
verify_trackingMechanism();
verify_integration();
// verify_integration();
}
void
verify_trackingMechanism()
{
instance = 0;
checksum = 0;
{
typedef Dummy AutoRegisteringDummy;
@ -230,7 +243,7 @@ namespace test {
CHECK (1+2+3 == checksum);
dummy2->unlink();
dummy2->detach();
CHECK (1 + 3 == checksum);
CHECK (2 == trackedDummies.size());
CHECK (dummy1 == trackedDummies[0]);
@ -243,7 +256,10 @@ namespace test {
// deliberately discard our reference,
// so the only remaining ref is within the registry
dummy1.reset();
dummy2.reset();
dummy3.reset();
CHECK (!dummy1);
CHECK ( dummy2);
CHECK (!dummy3);
CHECK (1 == trackedDummies[0].use_count());
CHECK (1 == trackedDummies[1].use_count());
CHECK (1 + 3 == checksum);