WIP code up external advice API
This commit is contained in:
parent
c9437b3bff
commit
83b5c8c2c2
4 changed files with 127 additions and 22 deletions
|
|
@ -100,68 +100,171 @@ namespace advice {
|
|||
/**
|
||||
* TODO type comment
|
||||
*/
|
||||
template<class AD>
|
||||
class PointOfAdvice
|
||||
{
|
||||
public:
|
||||
/** define or re-define the binding
|
||||
* specifically designating this attachment to the advice system.
|
||||
Binding::Matcher pattern_;
|
||||
PointOfAdvice* resolution_;
|
||||
|
||||
protected:
|
||||
/** define or re-define the binding, which
|
||||
* specifically labels this attachment to the advice system.
|
||||
* @note issuing this on an existing connection is equivalent
|
||||
* to re-connecting with the new binding.
|
||||
*/
|
||||
void defineBinding (Binding const& binding);
|
||||
void setBindingPattern (Binding const& binding)
|
||||
{
|
||||
pattern_ = binding.buildMatcher();
|
||||
}
|
||||
|
||||
/** access the \em current piece of advice */
|
||||
AD const& getAdvice() const;
|
||||
public:
|
||||
explicit
|
||||
PointOfAdvice (Binding const& binding)
|
||||
: pattern_(binding.buildMatcher())
|
||||
, resolution_(0)
|
||||
{ }
|
||||
|
||||
// using default copy/assignment
|
||||
|
||||
|
||||
/* == policy definitions == */ ////TODO: extract into policy classes
|
||||
|
||||
AD const& handleMissingSolution() const;
|
||||
/* == Adapter interface for use within the Index == */
|
||||
|
||||
friend HashVal
|
||||
hash_value (PointOfAdvice const& entry)
|
||||
{
|
||||
return hash_value (entry.pattern_);
|
||||
}
|
||||
|
||||
friend const Binding::Matcher
|
||||
getMatcher (PointOfAdvice const& entry)
|
||||
{
|
||||
return entry.pattern_;
|
||||
}
|
||||
|
||||
friend PointOfAdvice*
|
||||
getSolution (PointOfAdvice& entry)
|
||||
{
|
||||
return entry.resolution_;
|
||||
}
|
||||
|
||||
friend void
|
||||
setSolution (PointOfAdvice* entry, PointOfAdvice* solution =0)
|
||||
{
|
||||
REQUIRE (entry);
|
||||
entry->resolution_ = solution;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Access point for the advising entity (server).
|
||||
* TODO type comment
|
||||
*/
|
||||
template<class AD>
|
||||
class Provision
|
||||
: public PointOfAdvice<AD>
|
||||
: public PointOfAdvice
|
||||
{
|
||||
AD theAdvice_;
|
||||
|
||||
|
||||
/* == policy definitions == */ ////TODO: extract into policy classes
|
||||
|
||||
AD const& handleMissingSolution() const { return AD(); }
|
||||
void deregistrate() { /* NOP */ }
|
||||
|
||||
|
||||
public:
|
||||
explicit
|
||||
Provision (Literal bindingSpec =0)
|
||||
: PointOfAdvice (Binding(bindingSpec).addTypeGuard<AD>())
|
||||
, theAdvice_()
|
||||
{ }
|
||||
|
||||
~Provision()
|
||||
{
|
||||
this->deregistrate();
|
||||
}
|
||||
|
||||
|
||||
AD const&
|
||||
getAdvice() const
|
||||
{
|
||||
UNIMPLEMENTED ("how to embody the piece of advice...");
|
||||
return theAdvice_;
|
||||
}
|
||||
|
||||
void setAdvice (AD const& pieceOfAdvice);
|
||||
void retractAdvice();
|
||||
void setAdvice (AD const& pieceOfAdvice)
|
||||
{
|
||||
theAdvice_ = pieceOfAdvice;
|
||||
UNIMPLEMENTED ("change advice provision registration");
|
||||
}
|
||||
|
||||
void retractAdvice()
|
||||
{
|
||||
theAdvice_ = this->handleMissingSolution();
|
||||
UNIMPLEMENTED ("notify index of retracted advice");
|
||||
}
|
||||
|
||||
void
|
||||
defineBinding (Literal topic)
|
||||
{
|
||||
setBindingPattern (Binding(topic).addTypeGuard<AD>());
|
||||
UNIMPLEMENTED ("propagate binding change to index");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Access point for the advised entity (client).
|
||||
* TODO type comment
|
||||
*/
|
||||
template<class AD>
|
||||
class Request
|
||||
: public PointOfAdvice<AD>
|
||||
: public PointOfAdvice
|
||||
{
|
||||
Provision<AD>* solution_;
|
||||
typedef Provision<AD> AdviceProvision;
|
||||
|
||||
|
||||
/* == policy definitions == */ ////TODO: extract into policy classes
|
||||
|
||||
AD const& handleMissingSolution() const { return AD(); }
|
||||
|
||||
|
||||
public:
|
||||
explicit
|
||||
Request (Literal bindingSpec =0)
|
||||
: PointOfAdvice (Binding(bindingSpec).addTypeGuard<AD>())
|
||||
{
|
||||
UNIMPLEMENTED ("registration with the index");
|
||||
}
|
||||
|
||||
~Request()
|
||||
{
|
||||
UNIMPLEMENTED ("detach from index");
|
||||
}
|
||||
|
||||
|
||||
AD const&
|
||||
getAdvice() const
|
||||
{
|
||||
if (!solution_)
|
||||
AdviceProvision* solution = static_cast<AdviceProvision*> (getSolution (*this));
|
||||
if (!solution)
|
||||
return this->handleMissingSolution();
|
||||
else
|
||||
return solution_->getAdvice();
|
||||
return solution->getAdvice();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
defineBinding (Literal topic)
|
||||
{
|
||||
setBindingPattern (Binding(topic).addTypeGuard<AD>());
|
||||
UNIMPLEMENTED ("propagate binding change to index");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ namespace advice {
|
|||
void addPredicate (Literal spec);
|
||||
|
||||
template<typename TY>
|
||||
void addTypeGuard();
|
||||
Binding const& addTypeGuard();
|
||||
|
||||
|
||||
Matcher buildMatcher() const;
|
||||
|
|
@ -225,10 +225,11 @@ namespace advice {
|
|||
}
|
||||
|
||||
template<typename TY>
|
||||
inline void
|
||||
inline Binding const&
|
||||
Binding::addTypeGuard()
|
||||
{
|
||||
atoms_.insert (Atom ("advice.type."+lumiera::query::buildTypeID<TY>()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -121,7 +121,8 @@ namespace test {
|
|||
CHECK (b0 != b1); CHECK (b1 != b0);
|
||||
CHECK (b0 != b2); CHECK (b2 != b0);
|
||||
|
||||
b2.addPredicate("cat1()");
|
||||
b2.addPredicate("cat1()"); // adding the same predicate multiple times has no effect
|
||||
b2.addPredicate(" cat1 ");
|
||||
CHECK (b1 == b2);
|
||||
b2.addPredicate("cat3(zzz)");
|
||||
CHECK (b1 != b2);
|
||||
|
|
|
|||
|
|
@ -541,14 +541,14 @@ In a more elaborate scheme, the advised entity could provide a signal to be invo
|
|||
&rarr; AdviceImplementation
|
||||
</pre>
|
||||
</div>
|
||||
<div title="AdviceImplementation" modifier="Ichthyostega" modified="201005060151" created="201004100056" tags="impl draft img" changecount="39">
|
||||
<div title="AdviceImplementation" modifier="Ichthyostega" modified="201005081902" created="201004100056" tags="impl draft img" changecount="42">
|
||||
<pre>[<img[Advice solution|uml/fig141573.png]]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
The advice system is //templated on the advice type// &mdash; so basically there is an independent lookup table for each different kind of advice.The advice system is a sytem wide singleton service, but it is never addressed directly by the participants. Rather, instances of ~AdviceProvision and ~AdviceRequest act as point of access. But these aren't completely symmetric; while the ~AdviceRequest is owned by the advised entity, the ~AdviceProvision is a value object, a uniform holder used to introduce new advice into the system. ~AdviceProvision is copied into an internal buffer and managed by the advice system, as is the actual advice item, which is copied alongside.
|
||||
The advice system is //templated on the advice type// &mdash; so basically any collaboration is limited to a distinct advice type. But currently (as of 5/2010), this typed context is kept on the interface level, while the implementation is built on top of a single lookup table (which might create contention problems in the future and thus may be changed without further notice). The advice system is a system wide singleton service, but it is never addressed directly by the participants. Rather, instances of ~AdviceProvision and ~AdviceRequest act as point of access. But these aren't completely symmetric; while the ~AdviceRequest is owned by the advised entity, the ~AdviceProvision is a value object, a uniform holder used to introduce new advice into the system. ~AdviceProvision is copied into an internal buffer and managed by the advice system, as is the actual advice item, which is copied alongside.
|
||||
|
||||
In order to find matches and provide advice solutions, the advice system maintains an index data structure called ''~BindingIndex''. The actual binding predicates are represented by value objects stored within this index table. The matching process is triggered whenever a new possibility for an advice solution enters the system, which could be a new request, a new provision or a change in the specified bindings. A successful match causes a pointer to be set within the ~AdviceRequest, pointing to the ~AdviceProvision acting as solution. Thus, when a solution exists, the advised entity can access the advice value object by dereferencing this pointer. A new advice solution just results in setting a different pointer, which is atomic and doesn't need to be protected by locking. But note, omitting the locking means there is no memory barrier; thus the advised entity might not see any changed advice solution, until the corresponding thread(s) refresh their CPU cache. This might or might not be acceptable, depending on the context, and thus is configurable as policy. Similarly, the handling of default advice is configurable. Usually, advice is a default constructible value object. In this case, when there isn't any advice solution (yet), a pseudo solution holding the default constructed advice value is used to satisfy any advice access by the client (advised entity). The same can be used when the actual ~AdviceProvision gets //retracted.// As an alternative, when this default solution approach doesn't work, we can provide a policy either to throw or to wait blocking &mdash; but this alternative policy is similarly implemented with an //null object// (a placeholder ~AdviceProvision). Anyway, this implementation technique causes the advice system to collect some advice provisions, bindings and advice objects over time. It should use a pooling custom allocator in the final version. As the number of advisors is expected to be rather small, the storage occupied by these elements, which is effectively blocked until application exit, isn't considered a problem.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue