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 #define LIB_ELEMENT_TRACKER_H
#include "lib/p.hpp" #include "lib/p.hpp"
#include "lib/util-foreach.hpp"
#include "lib/ref-array-impl.hpp" #include "lib/ref-array-impl.hpp"
@ -60,32 +61,87 @@ namespace lib {
using lumiera::P; using lumiera::P;
/** /**
* Registry for tracking object instances.
* Custom implementation of the RefArray interface, * Custom implementation of the RefArray interface,
* used by the Session to keep track of all timelines * based on a vector. Especially used by the Session
* and sequences. The registration/deregistration functions * to keep track of all timelines and sequences.
* are accessible as SessionServices * 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> template<typename ELM>
class ElementTracker class ElementTracker
: public lib::RefArrayVector<P<ELM> > : public lib::RefArrayVector<P<ELM> >
{ {
typedef std::vector<P<ELM> > _Vec;
typedef typename _Vec::iterator Iter;
typedef typename _Vec::const_iterator CIter;
public: 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 void
append (P<ELM> const& asset) append (P<ELM> const& asset)
{ {
UNIMPLEMENTED ("attach entry to session"); REQUIRE (asset, "Attempt to track a NIL element");
remove (*asset);
push_back (asset);
} }
void void
remove (ELM const& asset) 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 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

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

View file

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

View file

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