2010-03-11 18:27:52 +01:00
|
|
|
|
/*
|
|
|
|
|
|
ELEMENT-TRACKER.hpp - registry for tracking instances automatically
|
2010-12-17 23:28:49 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
Copyright (C)
|
|
|
|
|
|
2010, Hermann Vosseler <Ichthyostega@web.de>
|
2010-12-17 23:28:49 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
**Lumiera** is free software; you can redistribute it and/or modify it
|
|
|
|
|
|
under the terms of the GNU General Public License as published by the
|
|
|
|
|
|
Free Software Foundation; either version 2 of the License, or (at your
|
|
|
|
|
|
option) any later version. See the file COPYING for further details.
|
2010-12-17 23:28:49 +01:00
|
|
|
|
|
2010-03-11 18:27:52 +01:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @file element-tracker.hpp
|
|
|
|
|
|
** Tracking instances automatically on creation and disposal.
|
2010-03-12 01:50:33 +01:00
|
|
|
|
** These helper templates can be used to provide a registry of all objects
|
|
|
|
|
|
** of some kind or type. The class to be used with instance tracking needs
|
|
|
|
|
|
** to cooperate, typically by inheriting from lib::AutoRegistered. Moreover,
|
2010-10-18 05:33:46 +02:00
|
|
|
|
** the instance lifecycle handling is assumed to utilise lumiera::P or a
|
2010-03-12 01:50:33 +01:00
|
|
|
|
** similar smart-ptr, which allows the registry to hold a safe reference.
|
|
|
|
|
|
** Thus, references won't be cleaned up automatically (as there is always
|
|
|
|
|
|
** at least one reference left) -- rather we rely on invoking a dispose or
|
|
|
|
|
|
** unlink function explicitly.
|
2010-03-11 18:27:52 +01:00
|
|
|
|
**
|
2010-03-12 01:50:33 +01:00
|
|
|
|
** The standard use case for this feature is the management of the structural
|
|
|
|
|
|
** facade assets Timeline and Sequence within the session. They're created
|
2025-06-07 23:59:57 +02:00
|
|
|
|
** automatically to reflect some internal structures within the model;
|
2010-03-12 01:50:33 +01:00
|
|
|
|
** with the help of lib::ElementTracker we can expose a list of
|
|
|
|
|
|
** all instances as part of the public Session interface.
|
2010-03-12 22:02:27 +01:00
|
|
|
|
**
|
|
|
|
|
|
** @warning AutoRegistered does not check accessibility of the configured
|
|
|
|
|
|
** registry, when detaching an element. Especially, when detaching in turn
|
|
|
|
|
|
** gets automatically invoked from some kind of cleanup, care has to be taken
|
2010-11-06 22:56:17 +01:00
|
|
|
|
** to ensure the registry is still available. The Functions
|
|
|
|
|
|
** AutoRegistered::is_attached_to and AutoRegistered::deactivateRegistryLink
|
|
|
|
|
|
** can be used for detaching an Registry explicitly before destruction.
|
|
|
|
|
|
** Ignoring this might lead to segfault on application shutdown. /////////////////TICKET #574
|
2012-12-27 03:31:09 +01:00
|
|
|
|
** @warning be sure to understand the implications of object identity,
|
|
|
|
|
|
** especially when it comes to closing and opening the Session. Especially
|
|
|
|
|
|
** note that Assets use a systematic identity, not an instance identity,
|
|
|
|
|
|
** which might lead to removing an old instance from the new session.
|
2010-03-12 22:02:27 +01:00
|
|
|
|
**
|
2010-03-12 01:50:33 +01:00
|
|
|
|
** @see session-element-tracker-test.cpp
|
2010-10-18 05:33:46 +02:00
|
|
|
|
** @see session-interface-modules.hpp
|
2010-03-12 01:50:33 +01:00
|
|
|
|
** @see Timeline
|
|
|
|
|
|
** @see Sequence
|
2010-03-11 18:27:52 +01:00
|
|
|
|
**
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef LIB_ELEMENT_TRACKER_H
|
|
|
|
|
|
#define LIB_ELEMENT_TRACKER_H
|
|
|
|
|
|
|
|
|
|
|
|
#include "lib/p.hpp"
|
2010-11-06 22:56:17 +01:00
|
|
|
|
#include "lib/optional-ref.hpp"
|
2010-03-12 17:16:11 +01:00
|
|
|
|
#include "lib/util-foreach.hpp"
|
2010-03-11 18:27:52 +01:00
|
|
|
|
|
2025-06-01 02:44:40 +02:00
|
|
|
|
#include <vector>
|
2010-03-11 18:27:52 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace lib {
|
|
|
|
|
|
|
2010-03-12 01:50:33 +01:00
|
|
|
|
/**
|
2010-03-12 17:16:11 +01:00
|
|
|
|
* Registry for tracking object instances.
|
2010-03-12 01:50:33 +01:00
|
|
|
|
* Custom implementation of the RefArray interface,
|
2010-03-12 17:16:11 +01:00
|
|
|
|
* 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
|
2025-06-07 23:59:57 +02:00
|
|
|
|
* will be deregistered prior to appending the
|
|
|
|
|
|
* new instance.
|
2010-03-12 01:50:33 +01:00
|
|
|
|
*/
|
|
|
|
|
|
template<typename ELM>
|
|
|
|
|
|
class ElementTracker
|
2025-06-01 02:44:40 +02:00
|
|
|
|
: public std::vector<P<ELM>>
|
2010-03-12 01:50:33 +01:00
|
|
|
|
{
|
2016-12-23 04:23:03 +01:00
|
|
|
|
using _Vec = std::vector<P<ELM>>;
|
|
|
|
|
|
using Iter = typename _Vec::iterator;
|
|
|
|
|
|
using CIter = typename _Vec::const_iterator;
|
2010-03-12 17:16:11 +01:00
|
|
|
|
|
2010-03-12 01:50:33 +01:00
|
|
|
|
public:
|
2010-03-12 17:16:11 +01:00
|
|
|
|
~ElementTracker()
|
|
|
|
|
|
{
|
|
|
|
|
|
try { clear(); }
|
|
|
|
|
|
catch(...) {/*ignored*/}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
clear ()
|
|
|
|
|
|
{
|
|
|
|
|
|
_Vec toKill;
|
|
|
|
|
|
toKill.reserve(_Vec::size());
|
2010-10-18 05:33:46 +02:00
|
|
|
|
toKill.swap(*this); // prevent quadratic detach()
|
2010-03-12 17:16:11 +01:00
|
|
|
|
ASSERT (0 == _Vec::size());
|
|
|
|
|
|
util::for_each (toKill, unlink_it);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-03-12 01:50:33 +01:00
|
|
|
|
void
|
|
|
|
|
|
append (P<ELM> const& asset)
|
|
|
|
|
|
{
|
2010-03-12 17:16:11 +01:00
|
|
|
|
REQUIRE (asset, "Attempt to track a NIL element");
|
|
|
|
|
|
remove (*asset);
|
2012-08-13 19:55:36 +02:00
|
|
|
|
this->push_back (asset);
|
2010-03-12 01:50:33 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
remove (ELM const& asset)
|
|
|
|
|
|
{
|
2010-03-12 17:16:11 +01:00
|
|
|
|
for (Iter i = _Vec::begin();
|
|
|
|
|
|
i != _Vec::end() ; ++i )
|
|
|
|
|
|
if (asset == **i) // _Vec contains smart-ptrs
|
|
|
|
|
|
{ // ELM is required to define '=='
|
2012-08-13 19:55:36 +02:00
|
|
|
|
this->erase (i);
|
2010-03-12 17:16:11 +01:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2010-03-12 01:50:33 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
2010-03-12 17:16:11 +01:00
|
|
|
|
isRegistered (ELM const& asset) const
|
|
|
|
|
|
{
|
|
|
|
|
|
for (CIter i = _Vec::begin();
|
|
|
|
|
|
i != _Vec::end() ; ++i )
|
|
|
|
|
|
if (asset == **i)
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
static void
|
|
|
|
|
|
unlink_it (P<ELM>& elm)
|
2010-03-12 01:50:33 +01:00
|
|
|
|
{
|
2010-03-12 17:16:11 +01:00
|
|
|
|
REQUIRE (elm);
|
|
|
|
|
|
try { elm->detach(); }
|
|
|
|
|
|
catch(...)
|
|
|
|
|
|
{
|
2010-04-04 06:38:22 +02:00
|
|
|
|
WARN (common,"problems while clearing ElementTracker, ignored.");
|
2010-03-12 17:16:11 +01:00
|
|
|
|
}
|
2010-03-12 01:50:33 +01:00
|
|
|
|
}
|
|
|
|
|
|
};
|
2010-03-11 18:27:52 +01:00
|
|
|
|
|
2010-03-12 22:58:46 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Helper mixin template for implementing a type
|
|
|
|
|
|
* intended to participate in automatic element tracking.
|
|
|
|
|
|
* - the element-tracking registry is accessed through
|
|
|
|
|
|
* the static functor #getRegistry
|
|
|
|
|
|
* - a factory and a #detach operation is provided,
|
|
|
|
|
|
* automatically handling registration.
|
|
|
|
|
|
* It is not mandatory to use this template, but
|
|
|
|
|
|
* types participating in automatic element tracking
|
|
|
|
|
|
* should provide equivalent functionality.
|
|
|
|
|
|
*/
|
|
|
|
|
|
template<typename TAR>
|
|
|
|
|
|
class AutoRegistered
|
|
|
|
|
|
{
|
|
|
|
|
|
public:
|
|
|
|
|
|
typedef lib::ElementTracker<TAR> Registry;
|
2010-11-06 22:56:17 +01:00
|
|
|
|
typedef lib::OptionalRef<Registry> RegistryLink;
|
2010-03-12 22:58:46 +01:00
|
|
|
|
|
|
|
|
|
|
/** detach this element
|
|
|
|
|
|
* from the element-tracking registry.
|
|
|
|
|
|
* @note called when destroying an non-empty registry.
|
|
|
|
|
|
*/
|
|
|
|
|
|
void
|
|
|
|
|
|
detach()
|
|
|
|
|
|
{
|
2010-10-20 04:42:22 +02:00
|
|
|
|
if (!getRegistry) return;
|
2010-03-12 22:58:46 +01:00
|
|
|
|
TAR& element = static_cast<TAR&> (*this);
|
|
|
|
|
|
|
|
|
|
|
|
getRegistry().remove(element);
|
|
|
|
|
|
ENSURE (!getRegistry().isRegistered(element));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-12-02 16:10:03 +01:00
|
|
|
|
typedef P<TAR> PTarget;
|
2010-03-12 22:58:46 +01:00
|
|
|
|
|
|
|
|
|
|
/** factory for creating smart-ptr managed
|
|
|
|
|
|
* TAR instances, automatically registered
|
|
|
|
|
|
* with the element-tracking registry.
|
|
|
|
|
|
*/
|
|
|
|
|
|
static PTarget
|
|
|
|
|
|
create()
|
|
|
|
|
|
{
|
|
|
|
|
|
REQUIRE (getRegistry);
|
|
|
|
|
|
|
|
|
|
|
|
PTarget newElement (new TAR());
|
|
|
|
|
|
getRegistry().append (newElement);
|
|
|
|
|
|
|
|
|
|
|
|
ENSURE (newElement);
|
|
|
|
|
|
ENSURE (getRegistry().isRegistered(*newElement));
|
|
|
|
|
|
return newElement;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
setRegistryInstance (Registry& registry_to_use)
|
|
|
|
|
|
{
|
2010-11-06 22:56:17 +01:00
|
|
|
|
getRegistry.link_to (registry_to_use);
|
2010-03-12 22:58:46 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2010-10-20 04:42:22 +02:00
|
|
|
|
static void
|
|
|
|
|
|
deactivateRegistryLink()
|
|
|
|
|
|
{
|
2010-11-06 22:56:17 +01:00
|
|
|
|
getRegistry.clear();
|
2010-10-20 04:42:22 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2010-10-29 05:24:19 +02:00
|
|
|
|
static bool
|
|
|
|
|
|
is_attached_to (Registry const& someRegistry)
|
|
|
|
|
|
{
|
2010-11-06 22:56:17 +01:00
|
|
|
|
return getRegistry.points_to (someRegistry);
|
2010-10-29 05:24:19 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2010-03-12 22:58:46 +01:00
|
|
|
|
protected:
|
|
|
|
|
|
static RegistryLink getRegistry;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** storage for the functor to link an AutoRegistered entity
|
|
|
|
|
|
* to the corresponding registration service */
|
|
|
|
|
|
template<typename TAR>
|
|
|
|
|
|
typename AutoRegistered<TAR>::RegistryLink AutoRegistered<TAR>::getRegistry;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-03-11 18:27:52 +01:00
|
|
|
|
} // namespace lib
|
|
|
|
|
|
#endif
|