implement registry for element-tracking. passes unit test
This commit is contained in:
parent
9ec865c3ab
commit
dd3d22f950
4 changed files with 112 additions and 34 deletions
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -83,6 +83,9 @@ namespace asset {
|
|||
class Timeline
|
||||
: public Struct
|
||||
{
|
||||
|
||||
public:
|
||||
void detach() { TODO("Timeline-Session registration"); }
|
||||
|
||||
protected:
|
||||
Timeline (const Asset::Ident& idi);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue