LUMIERA.clone/src/lib/element-tracker.hpp

235 lines
7.2 KiB
C++
Raw Normal View History

/*
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
*/
/** @file element-tracker.hpp
** Tracking instances automatically on creation and disposal.
** 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
** 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.
**
** 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;
** 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
** 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
** @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
**
** @see session-element-tracker-test.cpp
2010-10-18 05:33:46 +02:00
** @see session-interface-modules.hpp
** @see Timeline
** @see Sequence
**
*/
#ifndef LIB_ELEMENT_TRACKER_H
#define LIB_ELEMENT_TRACKER_H
#include "lib/p.hpp"
#include "lib/optional-ref.hpp"
#include "lib/util-foreach.hpp"
#include <vector>
namespace lib {
/**
* Registry for tracking object instances.
* Custom implementation of the RefArray interface,
* 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.
*/
template<typename ELM>
class ElementTracker
: public std::vector<P<ELM>>
{
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;
public:
~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()
ASSERT (0 == _Vec::size());
util::for_each (toKill, unlink_it);
}
void
append (P<ELM> const& asset)
{
REQUIRE (asset, "Attempt to track a NIL element");
remove (*asset);
this->push_back (asset);
}
void
remove (ELM const& asset)
{
for (Iter i = _Vec::begin();
i != _Vec::end() ; ++i )
if (asset == **i) // _Vec contains smart-ptrs
{ // ELM is required to define '=='
this->erase (i);
return;
}
}
bool
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)
{
REQUIRE (elm);
try { elm->detach(); }
catch(...)
{
WARN (common,"problems while clearing ElementTracker, ignored.");
}
}
};
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;
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()
{
if (!getRegistry) return;
2010-03-12 22:58:46 +01:00
TAR& element = static_cast<TAR&> (*this);
getRegistry().remove(element);
ENSURE (!getRegistry().isRegistered(element));
}
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)
{
getRegistry.link_to (registry_to_use);
2010-03-12 22:58:46 +01:00
}
static void
deactivateRegistryLink()
{
getRegistry.clear();
}
static bool
is_attached_to (Registry const& someRegistry)
{
return getRegistry.points_to (someRegistry);
}
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;
} // namespace lib
#endif