Implement Advice binding pattern
This commit is contained in:
parent
f27024172f
commit
f2269b7e78
12 changed files with 274 additions and 199 deletions
|
|
@ -24,6 +24,14 @@
|
|||
#include "lib/advice/binding.hpp"
|
||||
|
||||
//#include <tr1/functional_hash.h>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
using boost::algorithm::join;
|
||||
using boost::lexical_cast;
|
||||
|
||||
using boost::hash_combine;
|
||||
|
||||
|
||||
namespace lib {
|
||||
|
|
@ -31,39 +39,62 @@ namespace advice {
|
|||
|
||||
// using std::tr1::hash;
|
||||
|
||||
// LUMIERA_ERROR_DEFINE (MISSING_INSTANCE, "Existing ID registration without associated instance");
|
||||
|
||||
|
||||
Binding::Atom::operator string() const
|
||||
{
|
||||
return sym_+"/"+lexical_cast<string> (ari_)
|
||||
+"("+arg_+")";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Binding::parse_and_append (string def)
|
||||
{
|
||||
UNIMPLEMENTED ("do the actual parsing by regexp, create an Atom for each match");
|
||||
}
|
||||
|
||||
|
||||
/* ohlolololohaha */
|
||||
Binding::Binding ()
|
||||
{
|
||||
UNIMPLEMENTED ("create a new empty binding");
|
||||
}
|
||||
: atoms_()
|
||||
{ }
|
||||
|
||||
Binding::Binding (Literal spec)
|
||||
{
|
||||
UNIMPLEMENTED ("parse the spec and create a new binding");
|
||||
parse_and_append (spec);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Binding::addPredicate (Literal spec)
|
||||
{
|
||||
UNIMPLEMENTED ("parse the given spec and create an additional predicte, then re-normalise");
|
||||
parse_and_append (spec);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Binding::operator string() const
|
||||
{
|
||||
UNIMPLEMENTED ("diagnostic string representation of an advice binding");
|
||||
return "Binding[" + join(atoms_, ", ") + "]";
|
||||
}
|
||||
|
||||
|
||||
HashVal
|
||||
Binding::calculateHash() const
|
||||
{
|
||||
UNIMPLEMENTED ("calculate the hash for a normalised advice binding");
|
||||
HashVal hash=0;
|
||||
|
||||
typedef NormalisedAtoms::const_iterator AIter;
|
||||
AIter pos = atoms_.begin();
|
||||
AIter end = atoms_.end();
|
||||
for ( ; pos!=end ; ++pos)
|
||||
{
|
||||
hash_combine (hash, pos->sym());
|
||||
hash_combine (hash, pos->arity());
|
||||
hash_combine (hash, pos->arg()); //////////////TODO: not in final version with variable arguments
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@
|
|||
//#include <tr1/memory>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
namespace lib {
|
||||
namespace advice {
|
||||
|
|
@ -91,6 +92,51 @@ namespace advice {
|
|||
class Binding
|
||||
{
|
||||
|
||||
/**
|
||||
* single predicate
|
||||
* as part of an advice binding pattern
|
||||
*/
|
||||
class Atom
|
||||
{
|
||||
uint ari_;
|
||||
string sym_;
|
||||
string arg_;
|
||||
|
||||
public:
|
||||
Atom (uint arity, string const& symbol, string const& arg ="")
|
||||
: ari_(arity)
|
||||
, sym_(symbol)
|
||||
, arg_(arg)
|
||||
{ }
|
||||
|
||||
string const& sym() const { return sym_; }
|
||||
string const& arg() const { return arg_; }
|
||||
uint arity() const { return ari_; }
|
||||
|
||||
operator string() const;
|
||||
|
||||
int
|
||||
compare (Atom const& oa) const
|
||||
{
|
||||
int res;
|
||||
if (0 != (res=sym().compare (oi.sym()))) return res;
|
||||
if (0 != (res=arity() - (oi.arity()))) return res;
|
||||
return arg().compare (oi.arg()); /////TODO: in the final version, when we'll allow for variable arguments
|
||||
} ///////// and unification, then variable arguments must not be part of
|
||||
///////// the comparison, otherwise the matching by hash will break!
|
||||
friend bool
|
||||
operator< (Atom const& a1, Atom const& a2)
|
||||
{
|
||||
return a1.compare(a2) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
typedef std::set<Atom> NormalisedAtoms;
|
||||
|
||||
NormalisedAtoms atoms_;
|
||||
|
||||
|
||||
public:
|
||||
/**
|
||||
* Functor object for matching against another Binding.
|
||||
|
|
@ -144,7 +190,8 @@ namespace advice {
|
|||
|
||||
|
||||
private:
|
||||
void normalise(); ////TODO necessary??
|
||||
/** internal: parse into atoms, and insert them */
|
||||
void parse_and_append (string def);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ using boost::regex_search;
|
|||
|
||||
#include <iostream>
|
||||
|
||||
namespace util
|
||||
{
|
||||
namespace util {
|
||||
|
||||
|
||||
/** create as a tokenised <i>copy</i> of the current commandline.
|
||||
* Note that argv[0] is always ignored. */
|
||||
|
|
|
|||
|
|
@ -66,12 +66,12 @@ namespace lumiera {
|
|||
if (is_upper (first))
|
||||
id[0] = std::tolower (first);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
namespace // Implementation details
|
||||
{
|
||||
|
||||
namespace{ // Implementation details
|
||||
|
||||
map<Symbol, regex> regexTable;
|
||||
|
||||
Symbol matchArgument = "\\(\\s*([\\w_\\.\\-]+)\\s*\\),?\\s*";
|
||||
|
|
@ -128,7 +128,7 @@ namespace lumiera {
|
|||
* probably get for free when we embed a prolog system)...
|
||||
*/
|
||||
uint
|
||||
countPraed (const string& q)
|
||||
countPred (const string& q)
|
||||
{
|
||||
uint cnt (0);
|
||||
sregex_iterator end;
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ namespace lumiera {
|
|||
* usable for ordering queries, as more predicates usually
|
||||
* mean more conditions, i.e. more constriction
|
||||
*/
|
||||
uint countPraed (const string&);
|
||||
uint countPred (const string&);
|
||||
|
||||
|
||||
const string extractID (Symbol, const string& termString);
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ namespace asset {
|
|||
const uint ver=1);
|
||||
|
||||
|
||||
int compare (const Ident& other) const;
|
||||
int compare (Ident const& other) const;
|
||||
|
||||
/** @note equality ignores version differences */
|
||||
bool operator== (Ident const& oi) const { return compare (oi) ==0; }
|
||||
|
|
@ -308,7 +308,7 @@ namespace asset {
|
|||
* forwarded to the Asset comparison operators.
|
||||
* @note version info is irrelevant */
|
||||
inline int
|
||||
Asset::Ident::compare (const Asset::Ident& oi) const
|
||||
Asset::Ident::compare (Asset::Ident const& oi) const
|
||||
{
|
||||
int res;
|
||||
if (0 != (res=category.compare (oi.category))) return res;
|
||||
|
|
@ -320,7 +320,7 @@ namespace asset {
|
|||
/** promote subtype-ptr to PAsset, e.g. for comparing */
|
||||
template<class A>
|
||||
inline const PcAsset
|
||||
pAsset (const shared_ptr<A>& subPtr)
|
||||
pAsset (shared_ptr<A> const& subPtr)
|
||||
{
|
||||
return static_pointer_cast<const Asset,A> (subPtr);
|
||||
}
|
||||
|
|
@ -336,7 +336,7 @@ namespace asset {
|
|||
|
||||
|
||||
/** convenient for debugging */
|
||||
inline string str (const PcAsset& a)
|
||||
inline string str (PcAsset const& a)
|
||||
{
|
||||
if (a)
|
||||
return string (*a.get());
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ namespace mobject {
|
|||
weak_ptr<TAR> objRef;
|
||||
|
||||
Record (const Query<TAR>& q, const P<TAR>& obj)
|
||||
: degree (lumiera::query::countPraed (q)),
|
||||
: degree (lumiera::query::countPred (q)),
|
||||
query (q),
|
||||
objRef (obj)
|
||||
{ }
|
||||
|
|
|
|||
|
|
@ -27,6 +27,6 @@ return: 0
|
|||
END
|
||||
|
||||
|
||||
TEST "count predicates in query" QueryUtils_test countPraed <<END
|
||||
TEST "count predicates in query" QueryUtils_test countPred <<END
|
||||
return: 0
|
||||
END
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ namespace mobject {
|
|||
ASSERT ( *j );
|
||||
Q23 qx ((*j)->instanceID);
|
||||
ASSERT ( ps[qx] == (*j));
|
||||
d = lumiera::query::countPraed (qx);
|
||||
d = lumiera::query::countPred (qx);
|
||||
ASSERT ( d_prev <= d );
|
||||
d_prev = d;
|
||||
}
|
||||
|
|
|
|||
169
tests/lib/query/query-utils-test.cpp
Normal file
169
tests/lib/query/query-utils-test.cpp
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
QueryUtils(Test) - checking various utils provided for dealing with config queries
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
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.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
#include "lib/test/run.hpp"
|
||||
#include "lib/util.hpp"
|
||||
#include "lib/util-foreach.hpp"
|
||||
|
||||
#include "lib/cmdline.hpp"
|
||||
#include "lib/query.hpp"
|
||||
#include "query/querydiagnostics.hpp"
|
||||
|
||||
#include <tr1/functional>
|
||||
#include <iostream>
|
||||
|
||||
using lumiera::Query;
|
||||
using util::Cmdline;
|
||||
using util::isnil;
|
||||
using util::contains;
|
||||
using util::for_each;
|
||||
|
||||
using std::tr1::placeholders::_1;
|
||||
using std::tr1::bind;
|
||||
using std::string;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
|
||||
|
||||
namespace lumiera {
|
||||
namespace query {
|
||||
namespace test{
|
||||
|
||||
|
||||
struct Thing
|
||||
{
|
||||
virtual ~Thing() {} // add RTTI for Query.asKey();
|
||||
};
|
||||
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* @test check the various small helpers and utilities we utilise
|
||||
* for dealing with ConfigQuery
|
||||
*/
|
||||
class QueryUtils_test : public Test
|
||||
{
|
||||
|
||||
virtual void
|
||||
run (Arg arg)
|
||||
{
|
||||
if (isnil(arg)) arg = Cmdline ("Query normaliseID extractID removeTerm countPred");
|
||||
|
||||
if (contains (arg, "Query" )) check_Query ();
|
||||
if (contains (arg, "normaliseID")) check_normaliseID();
|
||||
if (contains (arg, "extractID" )) check_extractID ();
|
||||
if (contains (arg, "removeTerm" )) check_removeTerm ();
|
||||
if (contains (arg, "countPred" )) check_countPred ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test Query wrapper class basics */
|
||||
void
|
||||
check_Query ()
|
||||
{
|
||||
cout << Query<Thing> ("I am writing a test sentence.").asKey() << endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test sanitising and normalising various tokens */
|
||||
void
|
||||
check_normaliseID ()
|
||||
{
|
||||
Cmdline tokens ("a A AA dufte 1a _1 A_A BÄH");
|
||||
tokens.push_back ("");
|
||||
tokens.push_back (" White space ");
|
||||
tokens.push_back ("§&Ω%€GΩ%€ar ☠☠☠ baäääääge!!!!! ");
|
||||
|
||||
cout << "..original : " << tokens << " :"<<endl;
|
||||
|
||||
for_each (tokens, normaliseID, _1 );
|
||||
|
||||
cout << "normalised : " << tokens << " :"<<endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test the simple regexp extracting a parameter token */
|
||||
void
|
||||
check_extractID ()
|
||||
{
|
||||
ASSERT ("tok" == extractID ("pred", "pred(tok)." ));
|
||||
ASSERT ("tok" == extractID ("pred", " pred( tok )" ));
|
||||
ASSERT ("tok" == extractID ("pred", "pred(tok), pred(tux)." ));
|
||||
ASSERT ("tok" == extractID ("pred", "other(xyz) pred(tok) pred(tux)" ));
|
||||
ASSERT ("tok" == extractID ("pred", "some( pred(tok)" ));
|
||||
|
||||
ASSERT (isnil (extractID ("pred", "pred (tok)")));
|
||||
ASSERT (isnil (extractID ("pred", "pred tok)" )));
|
||||
ASSERT (isnil (extractID ("pred", "pred(tok " )));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test the regexp based cutting of a term with given symbol */
|
||||
void
|
||||
check_removeTerm ()
|
||||
{
|
||||
// successful------Symbol---input-string----------------------extracted------remaining-------------
|
||||
ASSERT_removeTerm ("pred", "pred(tok).", "pred(tok)", "." );
|
||||
ASSERT_removeTerm ("pred", " pred( tok )", "pred(tok)", " " );
|
||||
ASSERT_removeTerm ("pred", "pred(tok), pred(tux).", "pred(tok)", "pred(tux)." );
|
||||
ASSERT_removeTerm ("pred", "other(xyz) pred(tok) pred(tux)", "pred(tok)", "other(xyz) pred(tux)" );
|
||||
ASSERT_removeTerm ("pred", "some( pred(tok)", "pred(tok)", "some( " );
|
||||
|
||||
// not successful
|
||||
ASSERT_removeTerm ("pred", "pred (tok", "", "pred (tok" );
|
||||
ASSERT_removeTerm ("pred", "pred tok)", "", "pred tok)" );
|
||||
ASSERT_removeTerm ("pred", "pred(tok", "", "pred(tok" );
|
||||
}
|
||||
|
||||
void
|
||||
ASSERT_removeTerm (Symbol sym, string input, string extracted, string modified)
|
||||
{
|
||||
ASSERT (extracted == removeTerm (sym, input));
|
||||
ASSERT (modified == input);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test counting of predicates in a query
|
||||
* (currently 4/08 regexp based...)
|
||||
*/
|
||||
void
|
||||
check_countPred ()
|
||||
{
|
||||
for (uint i=1; i <= 30; ++i)
|
||||
ASSERT ( i == countPred (garbage_query (i)));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (QueryUtils_test, "unit query");
|
||||
|
||||
|
||||
|
||||
}}} // namespace lumiera::query::test
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
/*
|
||||
QueryUtils(Test) - checking various utils provided for dealing with config queries
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
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.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
#include "lib/test/run.hpp"
|
||||
#include "lib/util.hpp"
|
||||
#include "lib/util-foreach.hpp"
|
||||
|
||||
#include "lib/cmdline.hpp"
|
||||
#include "lib/query.hpp"
|
||||
#include "query/querydiagnostics.hpp"
|
||||
|
||||
#include <tr1/functional>
|
||||
#include <iostream>
|
||||
|
||||
using lumiera::Query;
|
||||
using util::Cmdline;
|
||||
using util::isnil;
|
||||
using util::contains;
|
||||
using util::for_each;
|
||||
|
||||
using std::tr1::placeholders::_1;
|
||||
using std::tr1::bind;
|
||||
using std::string;
|
||||
using std::cout;
|
||||
|
||||
|
||||
|
||||
namespace lumiera {
|
||||
namespace query {
|
||||
namespace test{
|
||||
|
||||
|
||||
struct Thing
|
||||
{
|
||||
virtual ~Thing() {} // add RTTI for Query.asKey();
|
||||
};
|
||||
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* @test check the various small helpers and utilities we utilise
|
||||
* for dealing with ConfigQuery
|
||||
*/
|
||||
class QueryUtils_test : public Test
|
||||
{
|
||||
|
||||
virtual void
|
||||
run (Arg arg)
|
||||
{
|
||||
if (isnil(arg)) arg = Cmdline ("Query normaliseID extractID removeTerm countPraed");
|
||||
|
||||
if (contains (arg, "Query" )) check_Query ();
|
||||
if (contains (arg, "normaliseID")) check_normaliseID ();
|
||||
if (contains (arg, "extractID" )) check_extractID ();
|
||||
if (contains (arg, "removeTerm" )) check_removeTerm ();
|
||||
if (contains (arg, "countPraed" )) check_countPraed ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test Query wrapper class basics */
|
||||
void
|
||||
check_Query ()
|
||||
{
|
||||
cout << Query<Thing> ("I am writing a test sentence.").asKey() << "\n";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test sanitising and normalising various tokens */
|
||||
void
|
||||
check_normaliseID ()
|
||||
{
|
||||
Cmdline tokens ("a A AA dufte 1a _1 A_A BÄH");
|
||||
tokens.push_back ("");
|
||||
tokens.push_back (" White space ");
|
||||
tokens.push_back ("§&Ω%€GΩ%€ar Ω baäääääge!!!!! ");
|
||||
|
||||
cout << "..original : " << tokens << " :\n";
|
||||
|
||||
for_each (tokens, bind ( &normaliseID, _1 ));
|
||||
|
||||
cout << "normalised : " << tokens << " :\n";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test the simple regexp extracting a parameter token */
|
||||
void
|
||||
check_extractID ()
|
||||
{
|
||||
ASSERT ("tok" == extractID ("pred", "pred(tok)." ));
|
||||
ASSERT ("tok" == extractID ("pred", " pred( tok )" ));
|
||||
ASSERT ("tok" == extractID ("pred", "pred(tok), pred(tux)." ));
|
||||
ASSERT ("tok" == extractID ("pred", "other(xyz) pred(tok) pred(tux)" ));
|
||||
ASSERT ("tok" == extractID ("pred", "some( pred(tok)" ));
|
||||
|
||||
ASSERT (isnil (extractID ("pred", "pred (tok)")));
|
||||
ASSERT (isnil (extractID ("pred", "pred tok)" )));
|
||||
ASSERT (isnil (extractID ("pred", "pred(tok " )));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test the regexp based cutting of a term with given symbol */
|
||||
void
|
||||
check_removeTerm ()
|
||||
{
|
||||
// successful------Symbol---input-string----------------------extracted------remaining-------------
|
||||
ASSERT_removeTerm ("pred", "pred(tok).", "pred(tok)", "." );
|
||||
ASSERT_removeTerm ("pred", " pred( tok )", "pred(tok)", " " );
|
||||
ASSERT_removeTerm ("pred", "pred(tok), pred(tux).", "pred(tok)", "pred(tux)." );
|
||||
ASSERT_removeTerm ("pred", "other(xyz) pred(tok) pred(tux)", "pred(tok)", "other(xyz) pred(tux)" );
|
||||
ASSERT_removeTerm ("pred", "some( pred(tok)", "pred(tok)", "some( " );
|
||||
|
||||
// not successful
|
||||
ASSERT_removeTerm ("pred", "pred (tok", "", "pred (tok" );
|
||||
ASSERT_removeTerm ("pred", "pred tok)", "", "pred tok)" );
|
||||
ASSERT_removeTerm ("pred", "pred(tok", "", "pred(tok" );
|
||||
}
|
||||
|
||||
void
|
||||
ASSERT_removeTerm (Symbol sym, string input, string extracted, string modified)
|
||||
{
|
||||
ASSERT (extracted == removeTerm (sym, input));
|
||||
ASSERT (modified == input);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test counting of predicates in a query
|
||||
* (currently 4/08 regexp based...)
|
||||
*/
|
||||
void
|
||||
check_countPraed ()
|
||||
{
|
||||
for (uint i=1; i <= 30; ++i)
|
||||
ASSERT ( i == countPraed (garbage_query (i)));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (QueryUtils_test, "unit query");
|
||||
|
||||
|
||||
|
||||
} // namespace test
|
||||
|
||||
} // namespace query
|
||||
|
||||
} // namespace lumiera
|
||||
|
|
@ -514,8 +514,8 @@ ColorPalette
|
|||
|
||||
SiteUrl</pre>
|
||||
</div>
|
||||
<div title="Advice" modifier="Ichthyostega" modified="201004110126" created="200910311755" tags="Concepts def spec img" changecount="27">
|
||||
<pre>{{red{WIP 11/09}}}...//about to explicate a pattern which I'm aiming at within the design almost since the beginning//
|
||||
<div title="Advice" modifier="Ichthyostega" modified="201004130150" created="200910311755" tags="Concepts def spec img" changecount="30">
|
||||
<pre>//pattern of collaboration for loosely coupled entities, to be used for various purposes within Proc...//
|
||||
Expecting Advice and giving Advice &mdash; this collaboration ranges somewhere between messaging and dynamic properties, but cross-cutting the primary, often hierarchical relation of dependencies. Always happening at a certain //point of advice,// which creates a distinct, static nature different of being just a convention, on the other hand, Advice is deliberately kept optional and received synchronously, albeit possibly within an continuation.
|
||||
|
||||
!Specification
|
||||
|
|
@ -531,7 +531,7 @@ Expecting Advice and giving Advice &mdash; this collaboration ranges somewhe
|
|||
* ''advice system''
|
||||
* the ''binding''
|
||||
* the ''advice''
|
||||
Usually, the ''advised'' entity opens the collaboration by requesting an advice. The ''advice'' itself is a piece of data of a custom type, which needs to be //copyable.// Obviously, both the advised and the advisor need to share knowledge about the meaning of this advice data. (in a more elaborate version we might allow the advisor to provide a subclass of the advice interface type). The actual advice collaboration happens at a ''point of advice'', which needs to be derived first. To this end, the advised puts up an request by providing his ''binding'', which is a pattern for matching. An entity about to give advice //opens//&nbsp; possible ''advice channels'' by putting up an advisor binding, which similarly is a pattern. The ''advice system'' as mediator resolves both sides, by matching (which in the most general case could be an unification). This process creates an ''advice point solution'' &mdash; allowing the advisor to fed the piece of advice into the advice channel, causing it to be placed into the point of advice. After passing a certain (implementation defined) break point, the advice leaves the influence of the advisor and gets exposed to the advised entities. Especially, this involves copying the advice data into a location managed by the advice system. In the standard case, the advised entity accesses the advice synchronously (an non-blocking). Of course, there could be a status flag to find out if there is new advice. Moreover, typically the advice data type is default constructible and thus there is always a basic form of advice available, thereby completely decoupling the advised entity from the timings related to this collaboration.
|
||||
Usually, the ''advised'' entity opens the collaboration by requesting an advice. The ''advice'' itself is a piece of data of a custom type, which needs to be //copyable.// Obviously, both the advised and the advisor need to share knowledge about the meaning of this advice data. (in a more elaborate version we might allow the advisor to provide a subclass of the advice interface type). The actual advice collaboration happens at a ''point of advice'', which needs to be derived first. To this end, two prerequisites are to be fulfilled (without fixed sequence): The advised puts up an ''advice request'' by specifying his ''binding'', which is a pattern for matching. An entity about to give advice attaches a possible ''advice provision'', combined with an advisor binding, which similarly is a pattern. The ''advice system'' as mediator resolves both sides, by matching (which in the most general case could be an unification). This process creates an ''advice point solution'' &mdash; allowing the advisor to fed the piece of advice into a kind of communication channel (&raquo;advice channel&laquo;), causing the advice data to be placed into the point of advice. After passing a certain (implementation defined) break point, the advice leaves the influence of the advisor and gets exposed to the advised entities. Especially, this involves copying the advice data into a location managed by the advice system. In the standard case, the advised entity picks up the advice synchronously (and non-blocking). Of course, there could be a status flag to find out if there is new advice. Moreover, typically the advice data type is default constructible and thus there is always a basic form of advice available, thereby completely decoupling the advised entity from the timings related to this collaboration.
|
||||
|
||||
!!extensions
|
||||
In a more elaborate scheme, the advised entity could provide a signal to be invoked either in the thread context of the advisor (being still blocked in the advice providing call), or in a completely separate thread. A third solution would be to allow the advised entity to block until receiving new advice. Both of these more elaborate schemes would also allow to create an advice queue &mdash; thereby developing the advice collaboration into a kind of messaging system. Following this route seems questionable though.
|
||||
|
|
|
|||
Loading…
Reference in a new issue