adapt the fake-config-rules to use the new Query::Builder

This commit is contained in:
Fischlurch 2012-12-25 01:16:19 +01:00
parent 9369709a46
commit d73c2fa842
11 changed files with 180 additions and 113 deletions

View file

@ -166,7 +166,7 @@ namespace lumiera {
* @query any goals to be fulfilled by the solution.
* @return false if resolution failed. In this case, solution ptr is empty.
*/
virtual bool resolve (P<TY>& solution, const Query<TY>& q) = 0;
virtual bool resolve (P<TY>& solution, Query<TY> const& q) = 0;
};
// TODO: the Idea is to provide specialisations for the concrete types
@ -221,8 +221,8 @@ namespace lumiera {
* will magically succeed with every candidate object provided. This
* is currently necessary to get objects into the defaults manager,
* as the query system is not able to do real query resolution */
void setFakeBypass(string const& q);
bool isFakeBypass (string const& q);
void setFakeBypass(lumiera::QueryKey const& q);
bool isFakeBypass (lumiera::QueryKey const& q);
/////////////////////////////////////////////////////////////////////////////TICKET 710
} // namespace query

View file

@ -87,6 +87,12 @@ namespace lumiera {
{
Kind kind;
IxID type;
explicit
QueryID(Kind k =EMPTY, IxID t=1)
: kind(k)
, type(t)
{ }
};
QueryID const&
@ -151,15 +157,18 @@ namespace lumiera {
/** Context used for generating type-IDs to denote
* the specific result types of issued queries */
typedef lib::TypedContext<Goal::Result> ResultType;
template<typename RES>
inline IxID
getResultTypeID() ///< @return unique ID denoting result type RES
{
return ResultType::ID<RES>::get();
namespace {
/** Context used for generating type-IDs to denote
* the specific result types of issued queries */
typedef lib::TypedContext<Goal::Result> ResultType;
template<typename RES>
inline IxID
getResultTypeID() ///< @return unique ID denoting result type RES
{
return ResultType::ID<RES>::get();
}
}
@ -204,7 +213,7 @@ namespace lumiera {
static QueryID
defineQueryTypeID (Kind queryType = Goal::GENERIC)
{
QueryID id = {queryType, getResultTypeID<RES>() };
QueryID id(queryType, getResultTypeID<RES>());
return id;
}
@ -249,17 +258,14 @@ namespace lumiera {
, def_(querySpec)
{ }
static Builder
build (Kind queryType = Goal::GENERIC);
Builder
rebuild() const;
string
extractID (Symbol predicate) const;
operator QueryKey() const;
static Builder build (Kind queryType = Goal::GENERIC);
Builder rebuild() const;
string extractID (Symbol predicate) const;
bool usesPredicate (Symbol predicate) const;
/* results retrieval */
@ -290,12 +296,6 @@ namespace lumiera {
{
return hash_value (q.def_);
}
friend bool
operator== (Query const& q1, Query const& q2)
{
return q1.def_ == q2.def_;
}
};
@ -318,6 +318,12 @@ namespace lumiera {
, def_(q)
{ }
/** the empty or bottom query key */
QueryKey()
: id_()
, def_("NIL")
{ }
// default copyable
template<class RES>
@ -348,6 +354,12 @@ namespace lumiera {
return def_.degree_of_constriction();
}
bool
empty() const
{
return Goal::EMPTY == id_.kind;
}
friend bool
operator< (QueryKey const& q1, QueryKey const& q2)
@ -358,6 +370,12 @@ namespace lumiera {
||(d1 == d2 && q1.def_ < q2.def_);
}
friend bool
operator== (QueryKey const& q1, QueryKey const& q2)
{
return q1.def_ == q2.def_;
}
friend size_t
hash_value (QueryKey const& q)
{
@ -439,6 +457,14 @@ namespace lumiera {
return *this;
}
Builder&
prependConditions (string additionalQueryPredicates)
{
this->predicateForm_ =
lib::query::appendTerms(additionalQueryPredicates, this->predicateForm_);
return *this;
}
Builder&
fromText (string queryPredicates)
{
@ -481,6 +507,14 @@ namespace lumiera {
}
template<class RES>
inline bool
Query<RES>::usesPredicate (Symbol predicate) const
{
return lib::query::hasTerm(predicate, this->def_);
}
/** automatic conversion from Query to QueryKey for indexing and ordering.
* By defining a parameter of type QueryKey, any provided Query will be
* automatically transformed into an generic representation usable for

View file

@ -23,9 +23,11 @@
#include "lib/error.hpp"
#include "common/query.hpp"
#include "common/config-rules.hpp"
#include "proc/mobject/session/query/fake-configrules.hpp"
using lumiera::QueryKey;
namespace lumiera {
@ -42,11 +44,11 @@ namespace lumiera {
namespace query {
namespace { // local definitions: implementing a backdoor for tests
string fakeBypass;
QueryKey fakeBypass;
}
void setFakeBypass(string const& q) { fakeBypass = q; }
bool isFakeBypass (string const& q) { return q == fakeBypass; }
void setFakeBypass(QueryKey const& q) { fakeBypass = q; }
bool isFakeBypass (QueryKey const& q) { return q == fakeBypass; }
/////////////////////////////////////////////////////////////////////////////TICKET 710
}// namespace query

View file

@ -92,7 +92,7 @@ namespace lib {
* \code extractID ("stream", "id(abc), stream(mpeg)") \endcode
* yields \c "mpeg"
*/
const string
string
extractID (Symbol sym, const string& termString)
{
smatch match;
@ -106,20 +106,30 @@ namespace lib {
/** (preliminary) helper: cut a term with the given symbol.
* The term is matched, removed from the original string and returned
* @note parameter termString will be modified!
* @todo as it seems we're not using the extracted term anymore,
* we could save the effort of rebuilding that term.
*/
const string
removeTerm (Symbol sym, string& termString)
string
removeTerm (Symbol sym, string& queryString)
{
smatch match;
if (regex_search (termString, match, getTermRegex (sym)))
if (regex_search (queryString, match, getTermRegex (sym)))
{
string res (sym); res += "("+match[1]+")";
termString.erase (match.position(), match[0].length());
queryString.erase (match.position(), match[0].length());
return res;
}
else
return "";
}
}
bool
hasTerm (Symbol sym, string const& queryString)
{
smatch match;
return regex_search (queryString, match, getTermRegex (sym));
}
/** @note this is a very hackish preliminary implementation.
@ -146,6 +156,7 @@ namespace lib {
appendTerms (string const& pred1, string const& pred2)
{
return isnil(pred1)? pred2
: isnil(pred2)? pred1
: pred1 + ", " + pred2;
}

View file

@ -58,9 +58,10 @@ namespace lib {
uint countPred (const string&);
const string extractID (Symbol, string const& termString);
string extractID (Symbol, string const& termString);
const string removeTerm (Symbol, string& termString);
string removeTerm (Symbol, string& queryString);
bool hasTerm (Symbol sym, string const& queryString);
string appendTerms (string const& pred1, string const& pred2);

View file

@ -25,6 +25,12 @@
/** @file config-resolver.hpp
** Definition of the concrete frontend for rule based configuration within the session.
**
** @remarks This code will act as a hub to pull in, instrument and activate a lot of further code.
** All the types mentioned in the #InterfaceTypes typelist will be prepared to be used
** in rules based setup and configuration; this definition will drive the generation of
** all the necessary bindings and registration entries to make this work. This is in
** accordance with the principle of <i>generic programming:</i> Instead of making things
** uniform, we use related things in a similar manner.
** @note this is placeholder code using a preliminary/mock implementation... don't take this code too literal!
** @todo clarify the relation of config query and query-for-defaults ///////////////TICKET #705
**

View file

@ -275,7 +275,7 @@ namespace session {
QueryID
whenQueryingFor()
{
QueryID qID = {Goal::DISCOVERY, getResultTypeID<Placement<MO> >()};
QueryID qID(Goal::DISCOVERY, getResultTypeID<Placement<MO> >());
return qID;
}

View file

@ -53,6 +53,7 @@ namespace session {
using asset::PProcPatt;
// using lib::query::extractID;
using lib::query::extractID; ///////////////TODO dto
using lib::query::removeTerm;
@ -128,7 +129,7 @@ namespace session {
/** special case: create a new pipe with matching pipe and stream IDs on the fly when referred... */
bool
MockTable::fabricate_matching_new_Pipe (Query<Pipe>& q, string const& pipeID, string const& streamID)
MockTable::fabricate_matching_new_Pipe (Query<Pipe> const& q, string const& pipeID, string const& streamID)
{
typedef WrapReturn<Pipe>::Wrapper Ptr;
@ -139,7 +140,7 @@ namespace session {
/** special case: create a new pipe for a specific stream ID */
bool
MockTable::fabricate_just_new_Pipe (Query<Pipe>& q )
MockTable::fabricate_just_new_Pipe (Query<Pipe> const& q )
{
typedef WrapReturn<Pipe>::Wrapper Ptr;
@ -150,7 +151,7 @@ namespace session {
/** special case: create/retrieve new processing pattern for given stream ID... */
bool
MockTable::fabricate_ProcPatt_on_demand (Query<const ProcPatt>& q)
MockTable::fabricate_ProcPatt_on_demand (Query<const ProcPatt> const& q)
{
typedef const ProcPatt cPP;
typedef WrapReturn<cPP>::Wrapper Ptr;
@ -165,18 +166,22 @@ namespace session {
* the session's timelines / sequences to retrieve an existing object
* with matching ID... */
bool
MockTable::fabricate_Timeline_on_demand (Query<asset::Timeline>& query)
MockTable::fabricate_Timeline_on_demand (Query<asset::Timeline> const& query)
{
typedef asset::Timeline aTl;
typedef WrapReturn<aTl>::Wrapper Ptr;
UNIMPLEMENTED ("generic query remolding");////////////////////////////////////////////////////////////////////////////////////////////TODO
string nameID = "TODO";//removeTerm ("id", query);////////////////////////////////////////////////////////////////////////////////////////////TODO
typedef asset::Timeline aTL;
typedef WrapReturn<aTL>::Wrapper Ptr;
string nameID = query.extractID("id");
if (isnil (nameID))
nameID = "TODO";//removeTerm ("timeline", query);////////////////////////////////////////////////////////////////////////////////////////////TODO
nameID = query.extractID("timeline");
if (isnil (nameID))
nameID = "prime";
// query.insert (0, "id("+nameID+"), ");
Query<aTL> normalisedQuery =
query.rebuild()
.removeTerm("id")
.removeTerm("timeline")
.prependConditions("id("+nameID+")");
// try to find an existing one with the desired id
Ptr newTimeline;
@ -189,26 +194,29 @@ namespace session {
}
if (!newTimeline)
newTimeline = Struct::retrieve.made4fake (query); // no suitable Timeline found: create and attach new one
answer_->insert (entry<aTl> (query, newTimeline)); // "learn" the found/created Timeline as new solution
newTimeline = Struct::retrieve.made4fake (normalisedQuery); // no suitable Timeline found: create and attach new one
answer_->insert (entry<aTL> (normalisedQuery, newTimeline)); // "learn" the found/created Timeline as new solution
return true;
}
/** special case: fabricate new Timeline, maybe using ID specs from the query... */
bool
MockTable::fabricate_Sequence_on_demand (Query<asset::Sequence>& query)
MockTable::fabricate_Sequence_on_demand (Query<asset::Sequence> const& query)
{
typedef asset::Sequence aSq;
typedef WrapReturn<aSq>::Wrapper Ptr;
UNIMPLEMENTED ("generic Query remolding");////////////////////////////////////////////////////////////////////////////////////////////TODO
string nameID = "TODO";//removeTerm ("id", query);////////////////////////////////////////////////////////////////////////////////////////////TODO
typedef asset::Sequence aSeq;
typedef WrapReturn<aSeq>::Wrapper Ptr;
string nameID = query.extractID("id");
if (isnil (nameID))
nameID = "TODO";//removeTerm ("sequence", query);////////////////////////////////////////////////////////////////////////////////////////////TODO
nameID = query.extractID("sequence");
if (isnil (nameID))
nameID = "first";
// query.insert (0, "id("+nameID+"), ");
Query<aSeq> normalisedQuery =
query.rebuild()
.removeTerm("id")
.removeTerm("sequence")
.prependConditions("id("+nameID+")");
// try to find an existing sequence with the desired id
Ptr newSequence;
@ -220,10 +228,9 @@ namespace session {
break;
}
if (!newSequence)
newSequence = Struct::retrieve.made4fake (query); // no suitable found: create and attach new Sequence
answer_->insert (entry<aSq> (query, newSequence));
if (!newSequence)
newSequence = Struct::retrieve.made4fake (normalisedQuery); // no suitable found: create and attach new Sequence
answer_->insert (entry<aSeq> (normalisedQuery, newSequence)); // "learn" the found/created new solution
return true;
}
@ -231,7 +238,7 @@ namespace session {
/** for entering "valid" solutions on-the-fly from tests */
template<class TY>
bool
MockTable::set_new_mock_solution (Query<TY>& q, typename WrapReturn<TY>::Wrapper& obj)
MockTable::set_new_mock_solution (Query<TY> const& q, typename WrapReturn<TY>::Wrapper& obj)
{
UNIMPLEMENTED ("generic query-key");////////////////////////////////////////////////////////////////////////////////////////////TODO
// answer_->erase (q.asKey());////////////////////////////////////////////////////////////////////////////////////////////TODO
@ -239,7 +246,7 @@ namespace session {
return true;
}
// generate the necessary specialisations-----------------------------
template bool MockTable::set_new_mock_solution (Query<Pipe>&, PPipe&);
template bool MockTable::set_new_mock_solution (Query<Pipe> const&, PPipe&);

View file

@ -29,6 +29,12 @@
** -- later on, when we use a real Prolog interpreter, it still may be useful for
** testing and debugging.
**
** @remarks the primary purpose of this header and fake-configrules.cpp is to define
** the type specialisations of the \c QueryHandler<TY>::resolve(solution,query)
** function(s). Below, there is a really confusing and ugly ping-pong game involving
** the faked solutions and the mocked defaults manager. This is spaghetti code, written
** for the reason everyone writes spaghetti code: to get away with it. So please look
** away, some day the real thing will be there, displacing this mess without further notice.
** @todo to be removed in Alpha, when integrating a real resolution engine /////////////////TICKET #710
**
** @see lumiera::Query
@ -68,8 +74,7 @@ namespace session {
using lib::P;
using lumiera::Query;
using lib::query::removeTerm; //////////////TODO better use Query::Builder
using lib::query::extractID; ///////////////TODO dto
using lumiera::QueryKey;
using lumiera::query::isFakeBypass; /////////TODO placeholder until there is a real resolution engine
using util::contains;
@ -95,10 +100,11 @@ namespace session {
/** helper detecting if a query actually intended to retrieve a "default" object.
* This implementation is quite crude, of course it would be necessary actually to
* parse and evaluate the query. @note query is modified if "default" ... */
template<typename TY>
inline bool
treat_as_defaults_query (string& querySpec)
is_defaults_query (Query<TY> const& querySpec)
{
return !isnil (removeTerm ("default", querySpec));
return querySpec.usesPredicate ("default");
}
} // details (end)
@ -107,7 +113,12 @@ namespace session {
/**
* the actual table holding preconfigured answers
* packaged as boost::any objects.
* packaged as boost::any objects. MockTable is the implementation base;
* subclasses for the individual types are layered below to define the
* \c resolve(..) functions. Finally #MockConfigRules wraps things up.
*
* The implementation relies on boost::any records to stash the objects
* in automatically managed heap memory.
*/
class MockTable
: public proc::ConfigResolver
@ -124,15 +135,15 @@ namespace session {
// special cases....
template<class TY>
bool detect_case (typename WrapReturn<TY>::Wrapper&, Query<TY>& q);
bool fabricate_matching_new_Pipe (Query<Pipe>& q, string const& pipeID, string const& streamID);
bool fabricate_just_new_Pipe (Query<Pipe>& q);
bool fabricate_ProcPatt_on_demand (Query<const ProcPatt>& q);
bool fabricate_Timeline_on_demand (Query<asset::Timeline>& q);
bool fabricate_Sequence_on_demand (Query<asset::Sequence>& q);
bool detect_case (typename WrapReturn<TY>::Wrapper&, Query<TY> const&);
bool fabricate_matching_new_Pipe (Query<Pipe> const& q, string const& pipeID, string const& streamID);
bool fabricate_just_new_Pipe (Query<Pipe> const& q);
bool fabricate_ProcPatt_on_demand (Query<const ProcPatt> const& q);
bool fabricate_Timeline_on_demand (Query<asset::Timeline> const& q);
bool fabricate_Sequence_on_demand (Query<asset::Sequence> const& q);
template<class TY>
bool set_new_mock_solution (Query<TY>& q, typename WrapReturn<TY>::Wrapper& candidate);
bool set_new_mock_solution (Query<TY> const& q, typename WrapReturn<TY>::Wrapper& candidate);
private:
@ -141,8 +152,8 @@ namespace session {
/**
* building block defining how to do
* the mock implementation for \em one type.
* building block providing the
* mock implementation for a \em single type.
* We simply access a table holding pre-created objects.
*/
template<class TY, class BASE>
@ -171,19 +182,17 @@ namespace session {
bool
try_special_case (Ret& solution, Query<TY> const& q)
{
if (true)//solution && isFakeBypass(q)) // backdoor for tests////////////////////////////////////////////////////////////////////////////////////////////TODO
if (solution && isFakeBypass(q)) // backdoor for tests
return solution;
string querySpec ;//(q);////////////////////////////////////////////////////////////////////////////////////////////TODO
if (treat_as_defaults_query (querySpec))
if (is_defaults_query (q))
{
Query<TY> defaultsQuery = Query<TY>::build().fromText(querySpec);
Query<TY> defaultsQuery = q.rebuild().removeTerm("default");
return solution = Session::current->defaults (defaultsQuery);
} // may cause recursion
} // may lead to recursion
Query<TY> newQuery = q;
if (this->detect_case (solution, newQuery))
return resolve (solution, newQuery);
if (this->detect_case (solution, q))
return resolve (solution, q);
return solution = Ret(); // fail: return default-constructed empty smart ptr
}
@ -193,21 +202,20 @@ namespace session {
/** Hook for treating very special cases for individual types only */
template<class TY>
inline bool
MockTable::detect_case (typename WrapReturn<TY>::Wrapper&, Query<TY>& q)
MockTable::detect_case (typename WrapReturn<TY>::Wrapper&, Query<TY> const&)
{
// q.clear(); // end recursion////////////////////////////////////////////////////////////////////////////////////////////TODO
return false;
}
template<>
inline bool
MockTable::detect_case (WrapReturn<Pipe>::Wrapper& candidate, Query<Pipe>& q)
MockTable::detect_case (WrapReturn<Pipe>::Wrapper& candidate, Query<Pipe> const& q)
{
if (true)//!isnil (extractID("make", q)))////////////////////////////////////////////////////////////////////////////////////////////TODO
if (q.usesPredicate ("make"))
// used by tests to force fabrication of a new "solution"
return fabricate_just_new_Pipe (q);
const string pipeID = "TODO";//extractID("pipe", q);////////////////////////////////////////////////////////////////////////////////////////////TODO
const string streamID = "TODO";//extractID("stream", q);////////////////////////////////////////////////////////////////////////////////////////////TODO
const string pipeID = q.extractID("pipe");
const string streamID = q.extractID("stream");
if (candidate && pipeID == candidate->getPipeID())
return set_new_mock_solution (q, candidate); // "learn" this solution to be "valid"
@ -218,39 +226,35 @@ namespace session {
if (!candidate && (!isnil(streamID) || !isnil(pipeID)))
return fabricate_just_new_Pipe (q);
// q.clear();////////////////////////////////////////////////////////////////////////////////////////////TODO
return false;
}
template<>
inline bool
MockTable::detect_case (WrapReturn<const ProcPatt>::Wrapper& candidate, Query<const ProcPatt>& q)
MockTable::detect_case (WrapReturn<const ProcPatt>::Wrapper& candidate, Query<const ProcPatt> const& q)
{
const string streamID = "TODO";//extractID("stream", q);////////////////////////////////////////////////////////////////////////////////////////////TODO
const string streamID = q.extractID("stream");
if (!candidate && !isnil(streamID))
return fabricate_ProcPatt_on_demand (q);
// q.clear();////////////////////////////////////////////////////////////////////////////////////////////TODO
return false;
}
template<>
inline bool
MockTable::detect_case (WrapReturn<asset::Timeline>::Wrapper& candidate, Query<asset::Timeline>& q)
MockTable::detect_case (WrapReturn<asset::Timeline>::Wrapper& candidate, Query<asset::Timeline> const& q)
{
if (!candidate)
return fabricate_Timeline_on_demand (q);
// q.clear();////////////////////////////////////////////////////////////////////////////////////////////TODO
return bool(candidate);
}
template<>
inline bool
MockTable::detect_case (WrapReturn<asset::Sequence>::Wrapper& candidate, Query<asset::Sequence>& q)
MockTable::detect_case (WrapReturn<asset::Sequence>::Wrapper& candidate, Query<asset::Sequence> const& q)
{
if (!candidate)
return fabricate_Sequence_on_demand (q);
// q.clear();////////////////////////////////////////////////////////////////////////////////////////////TODO
return bool(candidate);
}

View file

@ -117,11 +117,13 @@ namespace test {
CHECK (!find (pipe2->getPipeID()), "accidental clash of random test-IDs");
// now declare that these objects should be considered "default"
lumiera::query::setFakeBypass(""); /////////////////////////////////////////////////TODO mock resolution
CHECK (Session::current->defaults.define (pipe1, Query<Pipe> (""))); // unrestricted default
Query<Pipe> justAnyPipe ("");
lumiera::query::setFakeBypass(justAnyPipe); /////////////////////////////////////////////////TODO mock resolution
CHECK (Session::current->defaults.define (pipe1, justAnyPipe)); // unrestricted default
lumiera::query::setFakeBypass("stream("+sID+")"); ///////////////////////////////////TODO mock resolution
CHECK (Session::current->defaults.define (pipe2, Query<Pipe> ("stream("+sID+")")));
Query<Pipe> pipeWithSpecificStream("stream("+sID+")");
lumiera::query::setFakeBypass(pipeWithSpecificStream); ///////////////////////////////////TODO mock resolution
CHECK (Session::current->defaults.define (pipe2, pipeWithSpecificStream));
CHECK ( find (pipe1->getPipeID()), "failure declaring object as default");
CHECK ( find (pipe2->getPipeID()), "failure declaring object as default");

View file

@ -158,8 +158,8 @@ namespace test{
DummyTypedSolutionProducer()
: QueryResolver()
{
Goal::QueryID case1 = {Goal::GENERIC, getResultTypeID<int>()};
Goal::QueryID case2 = {Goal::GENERIC, getResultTypeID<string>()};
Goal::QueryID case1(Goal::GENERIC, getResultTypeID<int>());
Goal::QueryID case2(Goal::GENERIC, getResultTypeID<string>());
installResolutionCase(case1, &resolutionFunction<int> );
installResolutionCase(case2, &resolutionFunction<string> );