2008-02-29 18:58:29 +01:00
|
|
|
|
/*
|
2010-12-18 00:58:19 +01:00
|
|
|
|
DEFS-REGISTRY.hpp - implementation of the default object store
|
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)
|
|
|
|
|
|
2008, 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
|
|
|
|
|
2008-02-29 18:58:29 +01:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-12-18 00:58:19 +01:00
|
|
|
|
/** @file defs-registry.hpp
|
2008-09-10 04:42:09 +02:00
|
|
|
|
** A piece of implementation code factored out into a separate header (include).
|
2012-12-17 23:17:32 +01:00
|
|
|
|
** Only used through defs-manager-impl.hpp and for the unit tests. We can't place it
|
|
|
|
|
|
** into a separate compilation unit, because config-resolver.cpp defines some explicit
|
2008-12-28 05:20:35 +01:00
|
|
|
|
** template instantiation, which cause the different Slots of the DefsrRegistry#table_
|
2008-09-10 04:42:09 +02:00
|
|
|
|
** to be filled with data and defaults for the specific Types.
|
|
|
|
|
|
**
|
2012-12-17 23:17:32 +01:00
|
|
|
|
** Basically, this piece of code defines a specialised index / storage table to hold
|
|
|
|
|
|
** Queries-for-default objects. This allows to remember what actually was used as
|
|
|
|
|
|
** "default" solution for some query and to oder possible default solutions.
|
2016-11-04 21:26:56 +01:00
|
|
|
|
** @remarks as of 2017, we're still using a fake implementation of the resolution,
|
2012-12-17 23:17:32 +01:00
|
|
|
|
** no real resolution engine. While the basic idea of this "defaults registry"
|
|
|
|
|
|
** is likely to stay, the actual order relation and maybe even the components
|
2025-06-07 23:59:57 +02:00
|
|
|
|
** to be stored in this registry might be subject to change.
|
2012-12-17 23:17:32 +01:00
|
|
|
|
**
|
2008-09-10 04:42:09 +02:00
|
|
|
|
** @see mobject::session::DefsManager
|
2010-12-18 00:58:19 +01:00
|
|
|
|
** @see DefsRegistryImpl_test
|
2008-09-10 04:42:09 +02:00
|
|
|
|
**
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-12-01 08:44:07 +01:00
|
|
|
|
#ifndef LUMIERA_QUERY_DEFS_REGISTRY_H
|
|
|
|
|
|
#define LUMIERA_QUERY_DEFS_REGISTRY_H
|
2008-02-29 18:58:29 +01:00
|
|
|
|
|
|
|
|
|
|
|
2012-12-01 08:44:07 +01:00
|
|
|
|
#include "lib/p.hpp"
|
2008-12-17 17:53:32 +01:00
|
|
|
|
#include "lib/util.hpp"
|
2009-12-29 04:39:27 +01:00
|
|
|
|
#include "lib/util-foreach.hpp"
|
2012-12-01 08:44:07 +01:00
|
|
|
|
#include "lib/sync-classlock.hpp"
|
2012-12-17 23:17:32 +01:00
|
|
|
|
#include "lib/format-string.hpp"
|
2012-12-03 00:18:18 +01:00
|
|
|
|
#include "lib/query-util.hpp"
|
2012-12-01 08:44:07 +01:00
|
|
|
|
#include "common/query.hpp"
|
2018-03-24 05:35:13 +01:00
|
|
|
|
#include "lib/nocopy.hpp"
|
2008-02-29 18:58:29 +01:00
|
|
|
|
|
2008-03-31 03:21:28 +02:00
|
|
|
|
#include <set>
|
|
|
|
|
|
#include <vector>
|
2014-04-03 22:42:48 +02:00
|
|
|
|
#include <memory>
|
2008-02-29 18:58:29 +01:00
|
|
|
|
|
|
|
|
|
|
|
2012-12-01 08:44:07 +01:00
|
|
|
|
namespace lumiera{
|
|
|
|
|
|
namespace query {
|
2010-12-18 00:58:19 +01:00
|
|
|
|
|
2011-12-02 16:10:03 +01:00
|
|
|
|
using lib::P;
|
2010-12-18 00:58:19 +01:00
|
|
|
|
using lib::ClassLock;
|
2014-04-03 22:42:48 +02:00
|
|
|
|
using std::weak_ptr;
|
2010-12-18 00:58:19 +01:00
|
|
|
|
using std::string;
|
|
|
|
|
|
|
|
|
|
|
|
namespace impl {
|
2008-12-15 05:20:30 +01:00
|
|
|
|
|
2010-12-18 00:58:19 +01:00
|
|
|
|
namespace {
|
2012-12-17 23:17:32 +01:00
|
|
|
|
using util::_Fmt;
|
|
|
|
|
|
|
2010-12-18 00:58:19 +01:00
|
|
|
|
uint maxSlots (0); ///< number of different registered Types
|
2012-12-17 23:17:32 +01:00
|
|
|
|
_Fmt dumpRecord ("%2i| %64s --> %s\n");
|
2010-12-18 00:58:19 +01:00
|
|
|
|
}
|
2008-03-31 03:21:28 +02:00
|
|
|
|
|
|
|
|
|
|
|
2025-06-07 23:59:57 +02:00
|
|
|
|
struct TableEntry
|
2010-12-18 00:58:19 +01:00
|
|
|
|
{
|
|
|
|
|
|
virtual ~TableEntry() {};
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** we maintain an independent defaults registry
|
|
|
|
|
|
* for every participating kind of object. */
|
2025-07-05 20:08:18 +02:00
|
|
|
|
using Table = std::vector< P<TableEntry> >;
|
2010-12-18 00:58:19 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2025-06-07 23:59:57 +02:00
|
|
|
|
* holding a single "default object" entry
|
2010-12-18 00:58:19 +01:00
|
|
|
|
*/
|
|
|
|
|
|
template<class TAR>
|
|
|
|
|
|
struct Record
|
|
|
|
|
|
{
|
2012-12-22 00:39:23 +01:00
|
|
|
|
QueryKey queryKey;
|
2010-12-18 00:58:19 +01:00
|
|
|
|
weak_ptr<TAR> objRef;
|
2012-12-22 00:39:23 +01:00
|
|
|
|
uint degree;
|
2008-03-31 03:21:28 +02:00
|
|
|
|
|
2012-12-17 23:17:32 +01:00
|
|
|
|
Record (Query<TAR> const& q, P<TAR> const& obj)
|
2012-12-22 00:39:23 +01:00
|
|
|
|
: queryKey (q)
|
|
|
|
|
|
, objRef (obj)
|
|
|
|
|
|
, degree(queryKey.degree())
|
|
|
|
|
|
{ }
|
2010-12-18 00:58:19 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct Search ///< Functor searching for a specific object
|
|
|
|
|
|
{
|
2012-12-17 23:17:32 +01:00
|
|
|
|
Search (P<TAR> const& obj)
|
2010-12-18 00:58:19 +01:00
|
|
|
|
: obj_(obj) { }
|
|
|
|
|
|
|
2012-12-17 23:17:32 +01:00
|
|
|
|
P<TAR> const& obj_;
|
2010-12-18 00:58:19 +01:00
|
|
|
|
|
2025-06-07 23:59:57 +02:00
|
|
|
|
bool
|
2012-12-17 23:17:32 +01:00
|
|
|
|
operator() (Record const& rec)
|
2008-03-31 03:21:28 +02:00
|
|
|
|
{
|
2010-12-18 00:58:19 +01:00
|
|
|
|
P<TAR> storedObj (rec.objRef.lock());
|
2025-06-07 23:59:57 +02:00
|
|
|
|
return storedObj and (storedObj == obj_);
|
2008-03-31 03:21:28 +02:00
|
|
|
|
}
|
2010-12-18 00:58:19 +01:00
|
|
|
|
};
|
2008-03-31 03:21:28 +02:00
|
|
|
|
|
2012-12-22 00:39:23 +01:00
|
|
|
|
friend bool
|
|
|
|
|
|
operator< (Record one, Record two) ///< @note doesn't touch the objRef
|
|
|
|
|
|
{
|
|
|
|
|
|
return one.queryKey < two.queryKey;
|
|
|
|
|
|
}
|
2008-03-31 03:21:28 +02:00
|
|
|
|
|
2012-12-22 22:01:51 +01:00
|
|
|
|
operator string () const { return dumpRecord % degree % queryKey.display() % dumpObj(); }
|
2010-12-18 00:58:19 +01:00
|
|
|
|
string dumpObj () const { P<TAR> o (objRef.lock()); return o? string(*o):"dead"; }
|
|
|
|
|
|
};
|
2008-09-10 04:42:09 +02:00
|
|
|
|
|
2010-12-18 00:58:19 +01:00
|
|
|
|
/** every new kind of object (Type) creates a new
|
2025-06-07 23:59:57 +02:00
|
|
|
|
* slot in the main Table holding all registered
|
2010-12-18 00:58:19 +01:00
|
|
|
|
* default objects. Each slot actually holds a
|
|
|
|
|
|
* separate tree (set) of registry entries
|
|
|
|
|
|
*/
|
|
|
|
|
|
template<class TAR>
|
2012-12-17 23:17:32 +01:00
|
|
|
|
struct Slot
|
|
|
|
|
|
: public TableEntry
|
2010-12-18 00:58:19 +01:00
|
|
|
|
{
|
2025-07-05 20:08:18 +02:00
|
|
|
|
using Registry = std::set<Record<TAR>>;
|
2010-12-18 00:58:19 +01:00
|
|
|
|
|
|
|
|
|
|
Registry registry;
|
|
|
|
|
|
static size_t index; ///< where to find this Slot in every Table
|
|
|
|
|
|
|
|
|
|
|
|
static Registry&
|
|
|
|
|
|
access (Table& table)
|
|
|
|
|
|
{
|
2025-06-07 23:59:57 +02:00
|
|
|
|
if ( not index
|
|
|
|
|
|
or index > table.size()
|
|
|
|
|
|
or not table[index-1])
|
2010-12-18 00:58:19 +01:00
|
|
|
|
createSlot (table);
|
|
|
|
|
|
|
2025-06-07 23:59:57 +02:00
|
|
|
|
ASSERT (0 < index and index<=table.size() and table[index-1]);
|
2010-12-18 00:58:19 +01:00
|
|
|
|
Slot* item = static_cast<Slot*> (table[index-1].get());
|
|
|
|
|
|
return item->registry;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
static void
|
|
|
|
|
|
createSlot (Table& table)
|
|
|
|
|
|
{
|
2014-08-26 03:31:03 +02:00
|
|
|
|
ClassLock<TableEntry> guard;
|
2010-12-18 00:58:19 +01:00
|
|
|
|
if (!index)
|
|
|
|
|
|
index = ++maxSlots;
|
|
|
|
|
|
if (index > table.size())
|
|
|
|
|
|
table.resize (index);
|
2025-06-07 23:59:57 +02:00
|
|
|
|
table[index-1].reset(new Slot);
|
2010-12-18 00:58:19 +01:00
|
|
|
|
}
|
|
|
|
|
|
};
|
2008-09-10 04:42:09 +02:00
|
|
|
|
|
|
|
|
|
|
|
2010-12-18 00:58:19 +01:00
|
|
|
|
// static vars to organise one Table Slot per type....
|
|
|
|
|
|
template<class TAR>
|
|
|
|
|
|
size_t Slot<TAR>::index (0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-02-29 18:58:29 +01:00
|
|
|
|
/**
|
2008-12-28 05:20:35 +01:00
|
|
|
|
* @internal Helper for organising preconfigured default objects.
|
|
|
|
|
|
* Maintains a collection of objects known or encountered as "default"
|
2008-03-31 03:21:28 +02:00
|
|
|
|
* for a given type. This collection is ordered by "degree of constriction",
|
|
|
|
|
|
* which is implemented by counting the number of predicates in the query
|
|
|
|
|
|
* used to define or identify each object.
|
|
|
|
|
|
* Accessing an object identified by a query causes the query to be resolved
|
|
|
|
|
|
* (executed in prolog), which may result in some additional properties of
|
|
|
|
|
|
* the object being bound or specified.
|
|
|
|
|
|
* @todo as of 3/2008 the real query implementation is missing, and the
|
|
|
|
|
|
* exact behaviour has to be defined.
|
2008-02-29 18:58:29 +01:00
|
|
|
|
*/
|
2012-12-17 23:17:32 +01:00
|
|
|
|
class DefsRegistry
|
2018-03-24 05:35:13 +01:00
|
|
|
|
: util::NonCopyable
|
2008-02-29 18:58:29 +01:00
|
|
|
|
{
|
2008-03-31 03:21:28 +02:00
|
|
|
|
Table table_;
|
|
|
|
|
|
|
2008-02-29 18:58:29 +01:00
|
|
|
|
public:
|
2008-03-31 03:21:28 +02:00
|
|
|
|
/** used for enumerating solutions */
|
|
|
|
|
|
template<class TAR>
|
2025-06-07 23:59:57 +02:00
|
|
|
|
class Iter
|
2008-03-31 03:21:28 +02:00
|
|
|
|
{
|
|
|
|
|
|
friend class DefsRegistry;
|
2025-07-05 20:08:18 +02:00
|
|
|
|
using II = Slot<TAR>::Registry::iterator;
|
2008-03-31 03:21:28 +02:00
|
|
|
|
|
|
|
|
|
|
II p,i,e;
|
2008-05-19 08:46:19 +02:00
|
|
|
|
P<TAR> next, ptr;
|
2008-03-31 03:21:28 +02:00
|
|
|
|
|
2025-06-07 23:59:57 +02:00
|
|
|
|
Iter (II from, II to) ///< just enumerates the given range
|
2008-03-31 03:21:28 +02:00
|
|
|
|
: p(from), i(from), e(to)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (i!=e) ++i; // p is next to be tested, i always one ahead
|
2008-04-05 22:52:20 +02:00
|
|
|
|
operator++ ();
|
2008-03-31 03:21:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-07 23:59:57 +02:00
|
|
|
|
Iter (II match, II from, II to) ///< returns direct match first, then enumerates
|
2008-04-05 22:52:20 +02:00
|
|
|
|
: p(match), i(from), e(to)
|
2025-06-07 23:59:57 +02:00
|
|
|
|
{
|
2008-12-28 05:20:35 +01:00
|
|
|
|
operator++ (); // init to first element (or to null if empty)
|
2008-04-05 22:52:20 +02:00
|
|
|
|
}
|
2008-03-31 03:21:28 +02:00
|
|
|
|
|
2012-12-17 23:17:32 +01:00
|
|
|
|
P<TAR>
|
|
|
|
|
|
findNext () ///< EX_FREE
|
2008-03-31 03:21:28 +02:00
|
|
|
|
{
|
|
|
|
|
|
while (!next)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (p==e) break;
|
|
|
|
|
|
next = p->objRef.lock();
|
|
|
|
|
|
p = i++;
|
|
|
|
|
|
}
|
|
|
|
|
|
return next;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
2008-05-19 08:46:19 +02:00
|
|
|
|
P<TAR> operator* () { return ptr; }
|
2025-06-07 23:59:57 +02:00
|
|
|
|
bool hasNext () { return next or findNext(); }
|
2010-12-18 00:58:19 +01:00
|
|
|
|
Iter& operator++ ()
|
2025-06-07 23:59:57 +02:00
|
|
|
|
{
|
2008-03-31 03:21:28 +02:00
|
|
|
|
ptr=findNext();
|
|
|
|
|
|
next.reset();
|
2025-06-07 23:59:57 +02:00
|
|
|
|
return *this;
|
2008-03-31 03:21:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2008-12-28 05:20:35 +01:00
|
|
|
|
/** find a sequence of "default" objects possibly matching the query.
|
2008-03-31 03:21:28 +02:00
|
|
|
|
* If there was a registration for some object of the given kind with
|
|
|
|
|
|
* the \em same query, this one will be first in the sequence. Besides,
|
|
|
|
|
|
* the sequence will yield all still existing registered "default" objects
|
|
|
|
|
|
* of this kind, ordered ascending by "degree of constriction", i.e. starting
|
2008-12-28 05:20:35 +01:00
|
|
|
|
* with the object registered together with the shortest query.
|
2008-03-31 03:21:28 +02:00
|
|
|
|
* @return a forward input iterator yielding this sequence
|
|
|
|
|
|
* @note none of the queries will be evaluated (we're just counting predicates)
|
|
|
|
|
|
*/
|
|
|
|
|
|
template<class TAR>
|
2012-12-17 23:17:32 +01:00
|
|
|
|
Iter<TAR>
|
|
|
|
|
|
candidates (Query<TAR> const& query)
|
2008-03-31 03:21:28 +02:00
|
|
|
|
{
|
2008-05-19 08:46:19 +02:00
|
|
|
|
P<TAR> dummy;
|
2008-03-31 03:21:28 +02:00
|
|
|
|
Record<TAR> entry (query, dummy);
|
2025-07-05 20:08:18 +02:00
|
|
|
|
using Registry = Slot<TAR>::Registry;
|
2008-03-31 03:21:28 +02:00
|
|
|
|
Registry& registry = Slot<TAR>::access(table_);
|
|
|
|
|
|
|
|
|
|
|
|
// try to get a possible direct match (same query)
|
2025-07-05 20:08:18 +02:00
|
|
|
|
auto pos = registry.find (entry);
|
|
|
|
|
|
auto end = registry.end();
|
2008-03-31 03:21:28 +02:00
|
|
|
|
|
|
|
|
|
|
if (pos==end)
|
2008-12-28 05:20:35 +01:00
|
|
|
|
return Iter<TAR> (registry.begin(), end); // just enumerate contents
|
2008-03-31 03:21:28 +02:00
|
|
|
|
else
|
|
|
|
|
|
return Iter<TAR> (pos, registry.begin(), end); // start with direct match
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** register the object as being "default" when searching something
|
|
|
|
|
|
* similar as designated by the given query. Only a weak ref is stored.
|
2012-12-24 03:20:52 +01:00
|
|
|
|
* @param obj to be recorded as "default". Only a weak pointer will be stored
|
|
|
|
|
|
* @retval true if object has actually been stored
|
|
|
|
|
|
* @retval false if another object is registered for exactly the same query
|
|
|
|
|
|
* Nothing is changed in this case
|
2008-03-31 03:21:28 +02:00
|
|
|
|
*/
|
|
|
|
|
|
template<class TAR>
|
2012-12-17 23:17:32 +01:00
|
|
|
|
bool
|
2012-12-24 03:20:52 +01:00
|
|
|
|
put (P<TAR> const& obj, Query<TAR> const& query)
|
2008-03-31 03:21:28 +02:00
|
|
|
|
{
|
|
|
|
|
|
Record<TAR> entry (query, obj);
|
2025-07-05 20:08:18 +02:00
|
|
|
|
using Registry = Slot<TAR>::Registry;
|
|
|
|
|
|
using RIter = Registry::iterator;
|
2008-03-31 03:21:28 +02:00
|
|
|
|
|
|
|
|
|
|
Registry& registry = Slot<TAR>::access(table_);
|
|
|
|
|
|
RIter pos = registry.lower_bound (entry);
|
2025-06-07 23:59:57 +02:00
|
|
|
|
if (pos!=registry.end() and
|
|
|
|
|
|
pos->queryKey == query)
|
2008-03-31 03:21:28 +02:00
|
|
|
|
{
|
2008-05-19 08:46:19 +02:00
|
|
|
|
P<TAR> storedObj (pos->objRef.lock());
|
2008-03-31 03:21:28 +02:00
|
|
|
|
if (storedObj)
|
2008-04-05 07:26:54 +02:00
|
|
|
|
return (storedObj == obj);
|
2008-03-31 03:21:28 +02:00
|
|
|
|
else
|
2012-12-24 03:20:52 +01:00
|
|
|
|
// use the opportunity to purge the expired entry
|
2008-04-05 22:52:20 +02:00
|
|
|
|
registry.erase(pos++);
|
2008-03-31 03:21:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
// no existing entry....
|
|
|
|
|
|
registry.insert(pos, entry);
|
2008-04-05 22:52:20 +02:00
|
|
|
|
ENSURE (registry.find (entry) != registry.end());
|
2008-03-31 03:21:28 +02:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2008-02-29 18:58:29 +01:00
|
|
|
|
|
2008-03-31 03:21:28 +02:00
|
|
|
|
/** if this object is registered as "default" in some way, drop the registration.
|
|
|
|
|
|
* @return false if the object wasn't registered at all.
|
|
|
|
|
|
*/
|
|
|
|
|
|
template<class TAR>
|
2012-12-17 23:17:32 +01:00
|
|
|
|
bool
|
|
|
|
|
|
forget (P<TAR> const& obj)
|
2008-03-31 03:21:28 +02:00
|
|
|
|
{
|
2025-07-05 20:08:18 +02:00
|
|
|
|
using Registry = Slot<TAR>::Registry;
|
|
|
|
|
|
using SearchFunc = Record<TAR>::Search;
|
2008-03-31 03:21:28 +02:00
|
|
|
|
|
|
|
|
|
|
Registry& registry = Slot<TAR>::access(table_);
|
|
|
|
|
|
return util::remove_if(registry, SearchFunc (obj));
|
|
|
|
|
|
}
|
2008-04-05 22:52:20 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** helper for diagnostics.
|
|
|
|
|
|
* @note to use it, your objects need an operator string()
|
|
|
|
|
|
*/
|
|
|
|
|
|
template<class TAR>
|
2012-12-17 23:17:32 +01:00
|
|
|
|
string
|
|
|
|
|
|
dump ()
|
2008-04-05 22:52:20 +02:00
|
|
|
|
{
|
|
|
|
|
|
string res;
|
|
|
|
|
|
util::for_each ( Slot<TAR>::access(table_)
|
2014-05-12 01:12:45 +02:00
|
|
|
|
, [&] (Record<TAR>& entry)
|
|
|
|
|
|
{
|
|
|
|
|
|
res += string(entry);
|
|
|
|
|
|
}
|
2008-04-05 22:52:20 +02:00
|
|
|
|
);
|
|
|
|
|
|
return res;
|
|
|
|
|
|
}
|
2008-02-29 18:58:29 +01:00
|
|
|
|
};
|
2008-09-10 04:42:09 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-12-18 00:58:19 +01:00
|
|
|
|
} // (End) impl namespace
|
|
|
|
|
|
|
|
|
|
|
|
using impl::DefsRegistry;
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-12-01 08:44:07 +01:00
|
|
|
|
}} // namespace lumiera::query
|
2008-02-29 18:58:29 +01:00
|
|
|
|
#endif
|