diff --git a/tests/components/common/typelistutiltest.cpp b/tests/components/common/typelistutiltest.cpp index d0e2f683f..73cab939e 100644 --- a/tests/components/common/typelistutiltest.cpp +++ b/tests/components/common/typelistutiltest.cpp @@ -56,8 +56,8 @@ namespace lumiera /** template for generating lots of different test types */ template - struct Block - { + struct Block + { static string name; string talk() { return name+"::eat(..)"; } }; diff --git a/tests/components/proc/mobject/session/defsmanagerimpltest.cpp b/tests/components/proc/mobject/session/defsmanagerimpltest.cpp index fff9e6966..ff94f8a85 100644 --- a/tests/components/proc/mobject/session/defsmanagerimpltest.cpp +++ b/tests/components/proc/mobject/session/defsmanagerimpltest.cpp @@ -106,10 +106,14 @@ namespace asset // now declare that these objects should be considered "default" ASSERT (Session::current->defaults.define (pipe1, Query (""))); // unrestricted default - ASSERT (Session::current->defaults.define (pipe1, Query ("stream("+sID+")"))); + ASSERT (Session::current->defaults.define (pipe2, Query ("stream("+sID+")"))); ASSERT ( find (pipe1->getPipeID()), "failure declaring object as default"); ASSERT ( find (pipe2->getPipeID()), "failure declaring object as default"); + + ASSERT (sID != pipe1->getProcPatt()->queryStreamID(), "accidental clash"); + ASSERT (!Session::current->defaults.define (pipe1, Query ("stream("+sID+")"))); + // can't be registered with this query, due to failure caused by wrong stream-ID } @@ -143,7 +147,7 @@ namespace asset // now de-register the pipe as "default Pipe" ASSERT (Session::current->defaults.forget (pipe)); ASSERT (!find (pipe->getPipeID())); - ASSERT (cnt == pipe.use_count()); // indicates that DefaultsManager only holds a weak ref. + ASSERT (cnt == pipe.use_count()); // indicates DefaultsManager holding only a weak ref. } }; diff --git a/tests/components/proc/mobject/session/defsmanagertest.cpp b/tests/components/proc/mobject/session/defsmanagertest.cpp index b1c768836..1e66a0553 100644 --- a/tests/components/proc/mobject/session/defsmanagertest.cpp +++ b/tests/components/proc/mobject/session/defsmanagertest.cpp @@ -152,7 +152,7 @@ namespace asset PPipe pipe1 = Session::current->defaults (query_for_pID); hash = pipe1->getID(); } - // now AssetManager should have the only ref + // now AssetManager should hold the only ref ID assetID (hash); AssetManager& aMang (AssetManager::instance()); diff --git a/tests/components/proc/mobject/session/defsregistryimpltest.cpp b/tests/components/proc/mobject/session/defsregistryimpltest.cpp new file mode 100644 index 000000000..49c2fb343 --- /dev/null +++ b/tests/components/proc/mobject/session/defsregistryimpltest.cpp @@ -0,0 +1,308 @@ +/* + DefsRegistryImpl(Test) - verifying correct behaviour of the defaults registry + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + 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 "common/test/run.hpp" +#include "common/util.hpp" + +#include "proc/mobject/session/defsregistry.hpp" +#include "common/factory.hpp" +#include "common/query.hpp" + +#include +#include +#include +#include + +using lumiera::Query; + +using std::tr1::shared_ptr; +using boost::scoped_ptr; +using boost::format; +using util::isnil; +using std::string; +using std::rand; +using std::map; + + +namespace mobject + { + namespace session + { + namespace test + { + + const uint MAX_DEGREE_RAND = 9; + + format typePatt ("Dummy<%2i>"); + format instancePatt ("obj_%s_%i"); + format predicatePatt ("%s_%2i( %s )"); + + const string garbage ("asdfghjklqwertzuiop"); + + + /** create a random new ID */ + string + newID (Symbol prefix) + { + return str (instancePatt % prefix % rand()); + } + + + /** template for generating some different test types */ + template + struct Dummy + { + static string name; + string instanceID; + + Dummy () : instanceID (newID (name)) {} + }; + + template + string Dummy::name = str (typePatt % I); + + + + /** fabricating (random) query strings */ + string + q_str (int degree=0) + { + string fake; + if (!degree) + degree = 1 + rand() % MAX_DEGREE_RAND; + while (0 < --degree) + fake += garbage_term() + ", "; + fake += garbage_term() + "."; + return fake; + } + + string + garbage_term () + { + return (predicatePatt + % char ('a'+ rand() % 26) + % rand() % 100 + % garbage.substr(rand() % 17 , 3) + ); + } + + + /************************************************************************ + * @test build an registry table (just for this test) configured for + * some artificial test Types. Register some entries and verify + * the intended behaviour of the storage structure. + * @see DefsManagerImpl_test for checking the implementation details + * in the actual context used in Lumiera. + */ + class DefsRegistryImpl_test : public Test + { + scoped_ptr reg_; + + typedef shared_ptr > O; + typedef shared_ptr > P; + + typedef Query > Q13; + typedef Query > Q23; + + // fabricating Objects wrapped into smart-ptrs + lumiera::factory::RefcountPtr oFac; + lumiera::factory::RefcountPtr

pFac; + + O o1, o2, o3; + Q13 q1, q2, q3, q4, q5; + map ps; + + DefsRegistryImpl_test () + : o1 (oFac()), o2 (oFac()), o3 (oFac()), + q1 (q_str (1)), + q2 (q_str (2)), + q3 (q_str (3)), + q4 (q_str (4)), + q5 (q_str (5)) + { } + + + virtual void run(Arg arg) + { + this->reg_.reset (new DefsRegistry); + + fill_table (); + check_query (); + check_remove (); + } + + + + + void fill_table () + { + // at start the registry is indeed empty + // thus a query doesnt yield any results.... + ASSERT ( ! *(reg_->candidates(Q13 ("something"))) ); + + reg_->put (o1, q5); + reg_->put (o2, q4); + reg_->put (o3, q3); + reg_->put (o3, q2); + reg_->put (o2, q1); + reg_->put (o1, Q13); // the empty query + + ps.clear(); + for (int i=0; i<100; ++i) + { + P px (pFac()); + Q23 qx (q_str()); + ps[qx] = px; + reg_->put (px, qx); + px.instanceID = qx; + } + } + + + void check_query () + { + DefsRegistry::Iter > i; + i = reg_->candidates(Q13 ("irrelevant query")); + ASSERT ( i.hasNext()); + ASSERT ( *i++ == o1); // ordered according to the degree of the queries + ASSERT ( *i++ == o2); + ASSERT ( *i++ == o3); + ASSERT ( *i++ == o3); + ASSERT ( *i++ == o2); + ASSERT ( *i == o1); + ASSERT (!i.hasNext()); + + i = reg_->candidates(q3); + ASSERT ( *i++ == o3); // found by direct match + ASSERT ( *i++ == o1); // followed by the ordered ennumeration + ASSERT ( *i++ == o2); + ASSERT ( *i++ == o3); + ASSERT ( *i++ == o3); + ASSERT ( *i++ == o2); + ASSERT ( *i++ == o1); + ASSERT (!i.hasNext()); + + i = reg_->candidates(Q13); + ASSERT ( *i++ == o1); // found by direct match to the empty query + ASSERT ( *i++ == o1); + ASSERT ( *i++ == o2); + ASSERT ( *i++ == o3); + ASSERT ( *i++ == o3); + ASSERT ( *i++ == o2); + ASSERT ( *i++ == o1); + ASSERT (!i.hasNext()); + + uint d=0; + uint d_prev=0; + for (i = reg_->candidates(Q23 ("some crap")); + i.hasNext(); ++i ) + { + ASSERT ( *i ); + Q23 qx = (*i)->instanceID; + ASSERT ( ps[qx] == (*i)); + d = lumiera::query::countPraed (qx); + ASSERT ( d_prev <= d ); + d_prev = d; + } + ASSERT (!i.hasNext()); + + // calling with an arbitrary (registered) query + // yields the corresponding object at start of the ennumeration + i = reg_->candidates(ps.begin()->first); + ASSERT ( *i == ps.begin()->second); + + } + + + void check_remove () + { + reg_->forget (o2); + + DefsRegistry::Iter > i; + i = reg_->candidates(q4); + ASSERT ( i.hasNext()); + ASSERT ( *i++ == o1); // ordered according to the degree of the queries + // but the o2 entries are missing + ASSERT ( *i++ == o3); + ASSERT ( *i++ == o3); + // missing + ASSERT ( *i == o1); + ASSERT (!i.hasNext()); + + o3.reset(); // killing the only reference.... + // expires the weak ref in the registry + + i = reg_->candidates(Q13 ("something")); + ASSERT ( i.hasNext()); + ASSERT ( *i++ == o1); // ordered according to the degree of the queries + // but now also the o3 entries are missing... + ASSERT ( *i == o1); + ASSERT (!i.hasNext()); + + ASSERT ( reg_->put (o1, q5)); // trying to register the same object at the same place + // doesn't change anything (but counts as "success") + i = reg_->candidates(q5); + ASSERT ( *i++ == o1); // direct match + ASSERT ( *i++ == o1); + ASSERT ( *i++ == o1); + ASSERT (!i.hasNext()); + + ASSERT ( reg_->put (o2, q5)); // trying to (re)register o2 with a existing query + // counts as failure (nothing chages) + i = reg_->candidates(q5); + ASSERT ( *i++ == o1); // direct match + ASSERT ( *i++ == o1); + ASSERT ( *i++ == o1); + ASSERT (!i.hasNext()); + + ASSERT ( reg_->put (o2, q2)); // trying to (re)register o2 with another query succeeds + i = reg_->candidates(q2); + ASSERT ( *i++ == o2); // direct match + ASSERT ( *i++ == o1); + ASSERT ( *i++ == o2); // inserted here in the dataset + ASSERT ( *i++ == o1); + ASSERT (!i.hasNext()); + + ASSERT ( reg_->forget (o1)); + ASSERT ( reg_->forget (o1)); // failure, because it's already removed + ASSERT (!reg_->forget (o2)); + + o3.reset (oFac()); // another object is another object (it's irrelevant...) + + i = reg_->candidates(q2); + ASSERT (! (*i)); // empty + } + + }; + + + /** Register this test class... */ + LAUNCHER (DefsRegistryImpl_test, "function session"); + + + + } // namespace test + + } // namespace mobject + +} // namespace mobject diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 5f5dbcd9d..5523b8c60 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -842,7 +842,7 @@ This is an very important external Interface, because it links together all thre

[[ProcLayer and Engine]]
 
-
+
As detailed in the [[definition|DefaultsManagement]], {{{default(Obj)}}} is sort of a Joker along the lines "give me a suitable Object and I don't care for further details". Actually, default objects are implemented by the {{{mobject::session::DefsManager}}}, which remembers and keeps track of anything labeled as "default". This defaults manager is a singleton and can be accessed via the [[Session]] interface, meaning that the memory track regarding defaults is part of the session state. Accessing an object via the query for an default actually //tagges// this object (storing a weak ref in the ~DefsManager). Alongside with each object successfully queried via "default", the degree of constriction is remembered, i.e. the number of additional conditions contained in the query. This enables us to search for default objects starting with the most unspecific.
 
 !Skeleton
@@ -858,7 +858,7 @@ This is an very important external Interface, because it links together all thre
 #** otherwise, the newly created object is remembered (tagged) as new default, together with the degree of constriction
 
 !!!Implementation details
-Taken precisely, the "degree of constriction" yields only a partial ordering &mdash; but as the "default"-predicate is sort of a existential quantification anyways, its sole purpose is to avoid polluting the session with unnecessary default objects, and we don't need to care for absolute precision. A suitable approximation is to count the number of predicates terms in the query and use a pqueue (separate for each Type) to store weak refs to the the objects tagged as "default"
+Taken precisely, the "degree of constriction" yields only a partial ordering &mdash; but as the "default"-predicate is sort of a existential quantification anyways, its sole purpose is to avoid polluting the session with unnecessary default objects, and we don't need to care for absolute precision. A suitable approximation is to count the number of predicates terms in the query and use a (sorted) set (separate for each Type) to store weak refs to the the objects tagged as "default"
 {{red{WARN}}} there is an interference with the (planned) Undo function. This is a general problem of the config queries; just ignoring this issue seems reasonable.
 
 !!!Problems with the (preliminary) mock implementation