Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
index.hpp
Go to the documentation of this file.
1/*
2 INDEX.hpp - data structure for organising advice solutions and matching
3
4 Copyright (C)
5 2010, Hermann Vosseler <Ichthyostega@web.de>
6
7  **Lumiera** is free software; you can redistribute it and/or modify it
8  under the terms of the GNU General Public License as published by the
9  Free Software Foundation; either version 2 of the License, or (at your
10  option) any later version. See the file COPYING for further details.
11
12*/
13
14
77#ifndef LUMIERA_ADVICE_INDEX_H
78#define LUMIERA_ADVICE_INDEX_H
79
80
81#include "lib/error.hpp"
82#include "lib/symbol.hpp"
83#include "include/logging.h"
85#include "lib/format-obj.hpp"
86#include "lib/util-foreach.hpp"
87#include "lib/util.hpp"
89
90#include <unordered_map>
91#include <string>
92
93namespace lumiera{
94namespace advice {
95
96 namespace error = lumiera::error;
97
98 using std::placeholders::_1;
99 using std::unordered_map;
102 using util::toString;
103 using util::for_each;
104 using util::contains;
105 using util::unConst;
106 using lib::Literal;
107 using std::string;
108 using std::vector;
109 using std::pair;
110
111
112
113
114
140 template<class POA>
141 class Index
142 {
143
144 struct Entry
145 : pair<Binding::Matcher, POA*>
146 {
147 explicit
148 Entry (POA& elm)
149 : pair<Binding::Matcher, POA*> (elm.getMatcher(), &elm)
150 { }
151
152 // using default-copy, thus assuming copy is NO_THROW
153
154
155 operator string() const
156 {
157 return "E-" +hash_value(this->first) +"--> "+ this->second ;
158 }
159
160 friend bool
161 operator== (Entry const& a, Entry const& b)
162 {
163 return a.second == b.second;
164 }
165
166 friend bool
167 operator== (Entry const& a, POA const& p)
168 {
169 return a.second == &p;
170 }
171 };
172
173
174 using EntryList = vector<Entry>;
175 using EIter = EntryList::iterator;
176
177
178 struct Cluster
179 {
181
182 size_t
183 size() const
184 {
185 return elms_.size();
186 }
187
188 void
189 append (POA& elm)
190 {
191 REQUIRE (!contains (elm), "Duplicate entry");
192 try { elms_.push_back (Entry(elm)); }
193
194 catch(std::bad_alloc&)
195 {
196 throw error::Fatal("AdviceSystem failure due to exhausted memory");
197 }
198 }
199
200 void
201 overwrite (POA const& oldRef, POA& newElm)
202 {
203 EIter pos = std::find (elms_.begin(),elms_.end(), oldRef);
204 REQUIRE (pos!=elms_.end(), "Attempt to overwrite an entry which isn't there.");
205 REQUIRE_IF (&oldRef != &newElm, !contains (newElm), "Duplicate entry");
206
207 *pos = Entry(newElm);
208
209 REQUIRE_IF (&oldRef != &newElm, !contains (oldRef), "Duplicate entry");
210 }
211
212 void
213 remove (POA const& refElm)
214 {
215 EIter pos = std::find (elms_.begin(),elms_.end(), refElm);
216 if (pos!=elms_.end())
217 elms_.erase(pos);
218
219 ENSURE (!contains (refElm), "Duplicate entry");
220 }
221
222 bool
223 contains (POA const& refElm)
224 {
225 for (EIter i=elms_.begin(); i!=elms_.end(); ++i)
226 if (*i == refElm) return true;
227 return false;
228 }
229
230 operator string() const
231 {
232 string dump{"elmList("+toString(elms_.size())+")\n"};
233 for (auto const& entry : elms_)
234 dump += "E...:"+entry+"\n";
235 return dump;
236 }
237
240 {
241 return eachElm (elms_);
242 }
243 };
244
245
247 : Cluster
248 {
249 POA*
250 find_latest_solution (POA& requestElm)
251 {
252 using RIter = EntryList::reverse_iterator;
253 Binding::Matcher pattern (requestElm.getMatcher());
254 for (RIter ii=this->elms_.rbegin();
255 ii!=this->elms_.rend();
256 ++ii )
257 if (ii->first.matches (pattern))
258 return ii->second;
259
260 return NULL;
261 }
262
263 void
264 publish_latest_solution (POA& requestElm)
265 {
266 POA* solution = find_latest_solution (requestElm);
267 if (solution)
268 // found the most recent advice provision satisfying the (new) request
269 // thus publish this new advice solution into the request object
270 requestElm.setSolution (solution);
271 else
272 requestElm.setSolution ( NULL );
273 // report "no solution" which causes a default solution to be used
274 }
275 };
276
278 : Cluster
279 {
280 void
281 publish_all_solutions (POA& provisionElm)
282 {
283 Binding::Matcher pattern (provisionElm.getMatcher());
284 for (EIter ii=this->elms_.begin();
285 ii!=this->elms_.end();
286 ++ii )
287 if (pattern.matches (ii->first))
288 // the given (new) advice provision satisfies this request
289 // thus publish this new advice solution into the request object
290 ii->second->setSolution (&provisionElm);
291 }
292
293 void
294 retract_all_solutions (POA const& oldProv, ProvisionCluster& possibleReplacementSolutions)
295 {
296 Binding::Matcher pattern (oldProv.getMatcher());
297 for (EIter ii=this->elms_.begin();
298 ii!=this->elms_.end();
299 ++ii )
300 if (pattern.matches (ii->first))
301 // the old advice provision (to be dropped) satisfied this request
302 // which thus needs to be treated anew (could cause quadratic complexity)
303 possibleReplacementSolutions.publish_latest_solution (*(ii->second));
304 }
305
306 void
307 rewrite_all_solutions (POA const& oldProv, POA& newProv, ProvisionCluster& possibleReplacementSolutions)
308 {
309 Binding::Matcher oldPattern (oldProv.getMatcher());
310 Binding::Matcher newPattern (newProv.getMatcher ());
311 for (EIter ii=this->elms_.begin();
312 ii!=this->elms_.end();
313 ++ii )
314 if (newPattern.matches (ii->first))
315 ii->second->setSolution (&newProv);
316 else
317 if (oldPattern.matches (ii->first))
318 possibleReplacementSolutions.publish_latest_solution (*(ii->second));
319 }
320 };
321
322
323
324 /* ==== Index Tables ===== */
325
326 typedef unordered_map<HashVal, RequestCluster> RTable;
327 typedef unordered_map<HashVal, ProvisionCluster> PTable;
328
331
332
333
334 public:
335
336 void
337 addRequest (POA& entry)
338 {
339 HashVal key (hash_value(entry));
340 requestEntries_[key].append (entry); // might throw
341 provisionEntries_[key].publish_latest_solution (entry);
342 }
343
350 void
351 modifyRequest (HashVal oKey, POA& entry)
352 {
353 HashVal nKey (hash_value(entry));
354 if (oKey != nKey)
355 {
356 requestEntries_[nKey].append (entry); // might throw
357 requestEntries_[oKey].remove (entry);
358 }
359 else
360 { // rewrite Entry to include the new binding
361 requestEntries_[nKey].overwrite (entry, entry);
362 }
363 provisionEntries_[nKey].publish_latest_solution (entry);
364 }
365
366 void
367 removeRequest (POA const& refEntry)
368 {
369 HashVal oKey (hash_value(refEntry));
370 requestEntries_[oKey].remove (refEntry);
371 }
372
373
374 void
375 addProvision (POA& entry)
376 {
377 HashVal key (hash_value(entry));
378 provisionEntries_[key].append (entry); // might throw
379 requestEntries_[key].publish_all_solutions (entry);
380 }
381
382 void
383 modifyProvision (POA const& oldRef, POA& newEntry)
384 {
385 HashVal oKey (hash_value(oldRef));
386 HashVal nKey (hash_value(newEntry));
387 if (oKey != nKey)
388 {
389 provisionEntries_[nKey].append (newEntry); // might throw, in which case it has no effect
390 provisionEntries_[oKey].remove (oldRef);
391 requestEntries_[nKey].publish_all_solutions (newEntry);
392 requestEntries_[oKey].retract_all_solutions (oldRef, provisionEntries_[oKey]);
393 }
394 else
395 {
396 provisionEntries_[nKey].overwrite (oldRef, newEntry);
397 requestEntries_[nKey].rewrite_all_solutions (oldRef,newEntry, provisionEntries_[nKey]);
398 }
399 }
400
401 void
402 removeProvision (POA const& refEntry)
403 {
404 HashVal key (hash_value(refEntry));
405 provisionEntries_[key].remove (refEntry); // NO_THROW
406 requestEntries_[key].retract_all_solutions (refEntry, provisionEntries_[key]);
407 }
408
409
414 void
416 {
417 WARN (library, "Purging Advice Binding Index...");
418 requestEntries_.clear();
419 provisionEntries_.clear();
420 }
421
422
423
424 /* == diagnostics == */
425
427 bool isValid() const;
428
429 size_t
430 size() const
431 {
432 return request_count() + provision_count();
433 }
434
435 size_t
437 {
438 return sumClusters (eachVal (requestEntries_));
439 }
440
441 size_t
443 {
444 return sumClusters (eachVal (provisionEntries_));
445 }
446
447 bool
448 hasRequest (POA const& refEntry) const
449 {
450 return requestEntries_[hash_value(refEntry)].contains (refEntry);
451 }
452
453 bool
454 hasProvision (POA const& refEntry) const
455 {
456 return provisionEntries_[hash_value(refEntry)].contains (refEntry);
457 } // note: even just lookup might create a new (empty) cluster;
458 // thus the tables are defined as mutable
459
460
461 private:
464 template<class IT>
465 static size_t
467 {
468 size_t sum=0;
469 for ( ; ii; ++ii )
470 sum += ii->size();
471 return sum;
472 }
473
474 void verify_Entry (Entry const&, HashVal) const;
475 void verify_Request (Entry const&, HashVal) const;
476 };
477
478
479
480
481
482
483
484
485
486
487
488 /* == Self-Verification == */
489
490 namespace { // self-check implementation helpers...
491
492 LUMIERA_ERROR_DEFINE(INDEX_CORRUPTED, "Advice-Index corrupted");
493
496 {
498 : error::Fatal {string("Failed test: ")+failure
499 ,LUMIERA_ERROR_INDEX_CORRUPTED}
500 { }
501 };
502 }
503
504
505
506
513 template<class POA>
514 bool
516 {
517 using RTIter = RTable::const_iterator;
518 using PTIter = PTable::const_iterator;
519
520 try {
521 for (PTIter ii =provisionEntries_.begin();
522 ii != provisionEntries_.end(); ++ii)
523 {
524 HashVal hash (ii->first);
525 Cluster& clu = unConst(ii->second);
526 for_each (clu.allElms(), &Index::verify_Entry, this, _1, hash);
527 }
528 for (RTIter ii=requestEntries_.begin();
529 ii != requestEntries_.end(); ++ii)
530 {
531 HashVal hash (ii->first);
532 Cluster& clu = unConst(ii->second);
533 for_each (clu.allElms(), &Index::verify_Request, this, _1, hash);
534 }
535 return true;
536 }
537
538 catch(SelfCheckFailure& failure)
539 {
541 ERROR (library, "%s", failure.what());
542 }
543 return false;
544 }
545
546
547
548#define VERIFY(_CHECK_, DESCRIPTION) \
549 if (!(_CHECK_)) \
550 throw SelfCheckFailure ((DESCRIPTION));
551
552
553 template<class POA>
554 void
555 Index<POA>::verify_Entry (Entry const& e, HashVal hash) const
556 {
557 VERIFY (hash == hash_value(e.first), "Wrong bucket, hash doesn't match bucket");
558 VERIFY (e.second, "Invalid Entry: back-link is NULL");
559 }
560
561 template<class POA>
562 void
563 Index<POA>::verify_Request (Entry const& e, HashVal hash) const
564 {
565 verify_Entry (e,hash);
566 POA& request = *(e.second);
567 const POA* solution (request.getSolution());
568 if (solution and hasProvision (*solution))
569 {
570 POA* currentSolution = provisionEntries_[hash].find_latest_solution (request);
571 VERIFY (e.first.matches (solution->getMatcher()),"stored advice solution not supported by binding match");
572 VERIFY (bool(currentSolution), "unable to reproduce stored solution with the current provisions")
573 VERIFY (solution == currentSolution, "stored advice solution isn't the topmost solution for this request")
574 }
575 }
576
577#undef VERIFY
578
579
580}} // namespace lumiera::advice
581#endif
Inline string literal.
Definition symbol.hpp:78
Accessing a STL element range through a Lumiera forward iterator, An instance of this iterator adapte...
Functor object for matching against another Binding.
bool matches(Binding const &obi) const
Conjunction of predicates to be matched against a collaboration partner for establishing an Advice co...
Index datastructure for organising advice solutions.
Definition index.hpp:142
EntryList::iterator EIter
Definition index.hpp:175
unordered_map< HashVal, ProvisionCluster > PTable
Definition index.hpp:327
void verify_Request(Entry const &, HashVal) const
Definition index.hpp:563
size_t size() const
Definition index.hpp:430
void verify_Entry(Entry const &, HashVal) const
Definition index.hpp:555
size_t provision_count() const
Definition index.hpp:442
bool isValid() const
validity self-check
Definition index.hpp:515
bool hasRequest(POA const &refEntry) const
Definition index.hpp:448
size_t request_count() const
Definition index.hpp:436
void modifyRequest(HashVal oKey, POA &entry)
Definition index.hpp:351
static size_t sumClusters(IT ii)
internal: sum element count over all clusters in the given hashtable
Definition index.hpp:466
void addRequest(POA &entry)
Definition index.hpp:337
unordered_map< HashVal, RequestCluster > RTable
Definition index.hpp:326
void modifyProvision(POA const &oldRef, POA &newEntry)
Definition index.hpp:383
void removeProvision(POA const &refEntry)
Definition index.hpp:402
vector< Entry > EntryList
Definition index.hpp:174
void addProvision(POA &entry)
Definition index.hpp:375
bool hasProvision(POA const &refEntry) const
Definition index.hpp:454
void removeRequest(POA const &refEntry)
Definition index.hpp:367
Derived specific exceptions within Lumiera's exception hierarchy.
Definition error.hpp:193
A pattern to define and identify a specific attachment to the Advice system.
lumiera_err lumiera_error(void)
Get and clear current error state.
#define LUMIERA_ERROR_DEFINE(err, msg)
Definition and initialisation of an error constant.
Definition error.h:71
Lumiera error handling (C++ interface).
Simple functions to represent objects, for debugging and diagnostics.
#define hash
#define VERIFY(_CHECK_, DESCRIPTION)
Definition index.hpp:548
Preconfigured adapters for some STL container standard usage situations.
return NULL
Definition llist.h:586
This header is for including and configuring NoBug.
_SeqT< CON >::Range eachElm(CON &coll)
_MapT< MAP >::ValIter eachVal(MAP &map)
HashVal hash_value(Binding::Matcher const &bm)
LumieraError< LERR_(FATAL), Logic > Fatal
Definition error.hpp:208
Lumiera public interface.
Definition advice.hpp:102
constexpr IT find(IT, IT, V const &)
bool contains(MAP &map, typename MAP::key_type const &key)
shortcut for containment test on a map
Definition util.hpp:230
std::string toString(TY const &val) noexcept
get some string representation of any object, reliably.
OBJ * unConst(const OBJ *)
shortcut to save some typing when having to define const and non-const variants of member functions
Definition util.hpp:358
disable_if< can_IterForEach< Container >, FUN > for_each(Container const &coll, FUN doIt)
operate on all elements of a STL container.
void remove(POA const &refElm)
Definition index.hpp:213
bool contains(POA const &refElm)
Definition index.hpp:223
lib::RangeIter< EIter > allElms()
Definition index.hpp:239
void overwrite(POA const &oldRef, POA &newElm)
Definition index.hpp:201
friend bool operator==(Entry const &a, Entry const &b)
Definition index.hpp:161
POA * find_latest_solution(POA &requestElm)
Definition index.hpp:250
void publish_latest_solution(POA &requestElm)
Definition index.hpp:264
void publish_all_solutions(POA &provisionElm)
Definition index.hpp:281
void retract_all_solutions(POA const &oldProv, ProvisionCluster &possibleReplacementSolutions)
Definition index.hpp:294
void rewrite_all_solutions(POA const &oldProv, POA &newProv, ProvisionCluster &possibleReplacementSolutions)
Definition index.hpp:307
Marker types to indicate a literal string and a Symbol.
Perform operations "for each element" of a collection.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...