2008-02-29 18:58:29 +01:00
|
|
|
/*
|
|
|
|
|
DEFSREGISTRY.hpp - implementation of the default object store
|
|
|
|
|
|
2008-03-10 08:38:59 +01:00
|
|
|
Copyright (C) Lumiera.org
|
2008-02-29 18:58:29 +01:00
|
|
|
2008, Hermann Vosseler <Ichthyostega@web.de>
|
|
|
|
|
|
|
|
|
|
This program 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.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
2008-09-10 04:42:09 +02:00
|
|
|
/** @file defsregistry.hpp
|
|
|
|
|
** A piece of implementation code factored out into a separate header (include).
|
|
|
|
|
** Only used in defsmanager.cpp and for the unit tests. We can't place it into
|
|
|
|
|
** a separate compilation unit, because defsmanager.cpp defines some explicit
|
|
|
|
|
** template instantiaton, which cause the different Slots of the DefsrRegistry#table_
|
|
|
|
|
** to be filled with data and defaults for the specific Types.
|
|
|
|
|
**
|
|
|
|
|
** @see mobject::session::DefsManager
|
|
|
|
|
** @see defsregistryimpltest.cpp
|
|
|
|
|
**
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-02-29 18:58:29 +01:00
|
|
|
#ifndef MOBJECT_SESSION_DEFSREGISTRY_H
|
|
|
|
|
#define MOBJECT_SESSION_DEFSREGISTRY_H
|
|
|
|
|
|
|
|
|
|
|
2008-12-26 04:25:01 +01:00
|
|
|
#include "lib/sync-classlock.hpp"
|
2008-12-17 17:53:32 +01:00
|
|
|
#include "lib/query.hpp"
|
|
|
|
|
#include "lib/util.hpp"
|
|
|
|
|
#include "lib/p.hpp"
|
2008-02-29 18:58:29 +01:00
|
|
|
|
2008-03-31 03:21:28 +02:00
|
|
|
#include <set>
|
|
|
|
|
#include <vector>
|
2008-02-29 18:58:29 +01:00
|
|
|
#include <tr1/memory>
|
2008-04-05 22:52:20 +02:00
|
|
|
#include <boost/format.hpp>
|
2008-03-31 03:21:28 +02:00
|
|
|
#include <boost/utility.hpp>
|
2008-04-05 22:52:20 +02:00
|
|
|
#include <boost/lambda/lambda.hpp>
|
2008-02-29 18:58:29 +01:00
|
|
|
|
|
|
|
|
|
2008-12-15 05:20:30 +01:00
|
|
|
namespace mobject {
|
|
|
|
|
namespace session {
|
|
|
|
|
|
2008-05-19 08:46:19 +02:00
|
|
|
using lumiera::P;
|
2008-03-31 03:21:28 +02:00
|
|
|
using lumiera::Query;
|
2008-12-26 03:47:12 +01:00
|
|
|
using lib::ClassLock;
|
2008-05-19 08:46:19 +02:00
|
|
|
using std::tr1::weak_ptr;
|
2008-03-31 03:21:28 +02:00
|
|
|
|
2008-04-05 22:52:20 +02:00
|
|
|
using std::string;
|
|
|
|
|
using boost::format;
|
|
|
|
|
using boost::lambda::_1;
|
|
|
|
|
using boost::lambda::var;
|
2008-03-31 03:21:28 +02:00
|
|
|
|
2008-09-10 04:42:09 +02:00
|
|
|
namespace impl {
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
uint maxSlots (0); ///< number of different registered Types
|
|
|
|
|
format dumpRecord ("%2i| %64s --> %s\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-03-31 03:21:28 +02:00
|
|
|
struct TableEntry
|
|
|
|
|
{
|
|
|
|
|
virtual ~TableEntry() {};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** we maintain an independent defaults registry
|
|
|
|
|
* for every participating kind of objects */
|
2008-05-19 08:46:19 +02:00
|
|
|
typedef std::vector< P<TableEntry> > Table;
|
2008-03-31 03:21:28 +02:00
|
|
|
|
|
|
|
|
|
2008-04-05 22:52:20 +02:00
|
|
|
/**
|
|
|
|
|
* holding a single "default object" entry
|
|
|
|
|
*/
|
2008-03-31 03:21:28 +02:00
|
|
|
template<class TAR>
|
|
|
|
|
struct Record
|
|
|
|
|
{
|
|
|
|
|
uint degree;
|
|
|
|
|
Query<TAR> query;
|
|
|
|
|
weak_ptr<TAR> objRef;
|
|
|
|
|
|
2008-05-19 08:46:19 +02:00
|
|
|
Record (const Query<TAR>& q, const P<TAR>& obj)
|
2008-03-31 03:21:28 +02:00
|
|
|
: degree (lumiera::query::countPraed (q)),
|
|
|
|
|
query (q),
|
|
|
|
|
objRef (obj)
|
|
|
|
|
{ }
|
2008-09-10 04:42:09 +02:00
|
|
|
|
2008-03-31 03:21:28 +02:00
|
|
|
|
|
|
|
|
struct Search ///< Functor searching for a specific object
|
|
|
|
|
{
|
2008-05-19 08:46:19 +02:00
|
|
|
Search (const P<TAR>& obj)
|
2008-03-31 03:21:28 +02:00
|
|
|
: obj_(obj) { }
|
2008-09-10 04:42:09 +02:00
|
|
|
|
2008-05-19 08:46:19 +02:00
|
|
|
const P<TAR>& obj_;
|
2008-03-31 03:21:28 +02:00
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
operator() (const Record& rec)
|
|
|
|
|
{
|
2008-05-19 08:46:19 +02:00
|
|
|
P<TAR> storedObj (rec.objRef.lock());
|
2008-04-05 07:26:54 +02:00
|
|
|
return storedObj && (storedObj == obj_);
|
2008-03-31 03:21:28 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct OrderRelation
|
2008-04-05 22:52:20 +02:00
|
|
|
{
|
|
|
|
|
inline bool
|
|
|
|
|
operator() (Record one, Record two) ///< @note doesn't touch the objRef
|
|
|
|
|
{
|
|
|
|
|
return ( one.degree < two.degree
|
|
|
|
|
||(one.degree == two.degree && one.query < two.query)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
operator string () const { return str (dumpRecord % degree % query % dumpObj()); }
|
2008-05-19 08:46:19 +02:00
|
|
|
string dumpObj () const { P<TAR> o (objRef.lock()); return o? string(*o):"dead"; }
|
2008-03-31 03:21:28 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** every new kind of object (Type) creates a new
|
|
|
|
|
* slot in the main Table holding all registered
|
|
|
|
|
* default objects. Each slot actually holds a
|
|
|
|
|
* separate tree (set) of registry entries
|
|
|
|
|
*/
|
|
|
|
|
template<class TAR>
|
|
|
|
|
struct Slot : public TableEntry
|
|
|
|
|
{
|
|
|
|
|
typedef typename Record<TAR>::OrderRelation Ordering;
|
|
|
|
|
typedef std::set<Record<TAR>, Ordering> Registry;
|
|
|
|
|
|
|
|
|
|
Registry registry;
|
|
|
|
|
static size_t index; ///< where to find this Slot in every Table
|
|
|
|
|
|
|
|
|
|
static Registry&
|
|
|
|
|
access (Table& table)
|
|
|
|
|
{
|
|
|
|
|
if ( !index
|
|
|
|
|
|| index > table.size()
|
|
|
|
|
||!table[index-1])
|
|
|
|
|
createSlot (table);
|
|
|
|
|
|
|
|
|
|
ASSERT (0 < index && index<=table.size() && table[index-1]);
|
|
|
|
|
Slot* item = static_cast<Slot*> (table[index-1].get());
|
|
|
|
|
return item->registry;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
static void
|
|
|
|
|
createSlot (Table& table)
|
|
|
|
|
{
|
2008-12-26 03:47:12 +01:00
|
|
|
ClassLock<TableEntry> guard();
|
2008-03-31 03:21:28 +02:00
|
|
|
if (!index)
|
|
|
|
|
index = ++maxSlots;
|
|
|
|
|
if (index > table.size())
|
|
|
|
|
table.resize (index);
|
|
|
|
|
table[index-1].reset(new Slot);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2008-12-03 06:02:54 +01:00
|
|
|
// static vars to organise one Table Slot per type....
|
2008-03-31 03:21:28 +02:00
|
|
|
template<class TAR>
|
|
|
|
|
size_t Slot<TAR>::index (0);
|
|
|
|
|
|
2008-09-10 04:42:09 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-02-29 18:58:29 +01:00
|
|
|
/**
|
2008-03-31 03:21:28 +02:00
|
|
|
* @internal Helper for organizing preconfigured default objects.
|
|
|
|
|
* Maintaines a collection of objects known or encountered as "default"
|
|
|
|
|
* 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
|
|
|
*/
|
2008-03-31 03:21:28 +02:00
|
|
|
class DefsRegistry : private boost::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>
|
|
|
|
|
class Iter
|
|
|
|
|
{
|
|
|
|
|
friend class DefsRegistry;
|
|
|
|
|
typedef typename Slot<TAR>::Registry::iterator II;
|
|
|
|
|
|
|
|
|
|
II p,i,e;
|
2008-05-19 08:46:19 +02:00
|
|
|
P<TAR> next, ptr;
|
2008-03-31 03:21:28 +02:00
|
|
|
|
|
|
|
|
Iter (II from, II to) ///< just ennumerates the given range
|
|
|
|
|
: 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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Iter (II match, II from, II to) ///< returns direct match first, then ennumerates
|
2008-04-05 22:52:20 +02:00
|
|
|
: p(match), i(from), e(to)
|
|
|
|
|
{
|
|
|
|
|
operator++ (); // init to first element (or to null if emty)
|
|
|
|
|
}
|
2008-03-31 03:21:28 +02:00
|
|
|
|
2008-05-19 08:46:19 +02:00
|
|
|
P<TAR> findNext () throw()
|
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; }
|
|
|
|
|
bool hasNext () { return next || findNext(); }
|
|
|
|
|
Iter operator++ (int) { Iter tmp=*this; operator++(); return tmp; }
|
2008-03-31 03:21:28 +02:00
|
|
|
Iter& operator++ ()
|
|
|
|
|
{
|
|
|
|
|
ptr=findNext();
|
|
|
|
|
next.reset();
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** find a sequence of "default" objects possibliy matching the query.
|
|
|
|
|
* 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
|
|
|
|
|
* with the object registered togehter with the shortest query.
|
|
|
|
|
* @return a forward input iterator yielding this sequence
|
|
|
|
|
* @note none of the queries will be evaluated (we're just counting predicates)
|
|
|
|
|
*/
|
|
|
|
|
template<class TAR>
|
|
|
|
|
Iter<TAR> candidates (const Query<TAR>& query)
|
|
|
|
|
{
|
2008-05-19 08:46:19 +02:00
|
|
|
P<TAR> dummy;
|
2008-03-31 03:21:28 +02:00
|
|
|
Record<TAR> entry (query, dummy);
|
|
|
|
|
typedef typename Slot<TAR>::Registry Registry;
|
|
|
|
|
Registry& registry = Slot<TAR>::access(table_);
|
|
|
|
|
|
|
|
|
|
// try to get a possible direct match (same query)
|
|
|
|
|
typename Registry::iterator pos = registry.find (entry);
|
|
|
|
|
typename Registry::iterator end = registry.end();
|
|
|
|
|
|
|
|
|
|
if (pos==end)
|
|
|
|
|
return Iter<TAR> (registry.begin(), end); // just ennumerate contents
|
|
|
|
|
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.
|
|
|
|
|
* @param obj Will be rebound, if another object is already stored.
|
|
|
|
|
* @return true if object has actually been stored, false if another
|
|
|
|
|
* object is registered for exactly the same query. In this
|
|
|
|
|
* case, also the param obj shared-ptr is rebound!
|
|
|
|
|
*/
|
|
|
|
|
template<class TAR>
|
2008-05-19 08:46:19 +02:00
|
|
|
bool put (P<TAR>& obj, const Query<TAR>& query)
|
2008-03-31 03:21:28 +02:00
|
|
|
{
|
|
|
|
|
Record<TAR> entry (query, obj);
|
|
|
|
|
typedef typename Slot<TAR>::Registry Registry;
|
|
|
|
|
typedef typename Registry::iterator RIter;
|
|
|
|
|
|
|
|
|
|
Registry& registry = Slot<TAR>::access(table_);
|
|
|
|
|
RIter pos = registry.lower_bound (entry);
|
|
|
|
|
if ( pos!=registry.end()
|
|
|
|
|
&& pos->query == query)
|
|
|
|
|
{
|
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
|
|
|
|
|
// use the opportunity and 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>
|
2008-05-19 08:46:19 +02:00
|
|
|
bool forget (const P<TAR>& obj)
|
2008-03-31 03:21:28 +02:00
|
|
|
{
|
|
|
|
|
typedef typename Slot<TAR>::Registry Registry;
|
|
|
|
|
typedef typename Record<TAR>::Search SearchFunc;
|
|
|
|
|
|
|
|
|
|
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>
|
|
|
|
|
string dump()
|
|
|
|
|
{
|
|
|
|
|
string res;
|
|
|
|
|
util::for_each ( Slot<TAR>::access(table_)
|
|
|
|
|
, var(res) += _1
|
|
|
|
|
);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
2008-02-29 18:58:29 +01:00
|
|
|
};
|
|
|
|
|
|
2008-09-10 04:42:09 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
} // (End) impl namespace
|
|
|
|
|
|
|
|
|
|
using impl::DefsRegistry;
|
|
|
|
|
|
|
|
|
|
|
2008-02-29 18:58:29 +01:00
|
|
|
} // namespace mobject::session
|
|
|
|
|
|
|
|
|
|
} // namespace mobject
|
|
|
|
|
|
|
|
|
|
#endif
|