53#include <boost/functional/hash.hpp>
54#include <unordered_map>
62 LUMIERA_ERROR_DEFINE (PLACEMENT_TYPE,
"requested Placement (pointee) type not compatible with data or context");
71 using std::shared_ptr;
72 using std::unordered_map;
73 using std::unordered_multimap;
80 using std::placeholders::_1;
116 using PID = PlacementMO::ID;
117 using IDTable = std::unordered_map<PID, PlacementEntry>;
140 WARN (
session,
"Problem while purging PlacementIndex: %s",
err.what());
177 ENSURE (
id == entry->getID());
206 INFO (
session,
"Purging Placement Tables...");
231 ENSURE (1 ==
size());
238 REQUIRE (0 <
size());
259 ID newID = newEntry->getID();
261 ASSERT (newID,
"invalid");
265 scopeTab_.insert (make_pair (scopeID, newID));
279 throw error::State{
"Unable to remove the specified Placement, "
280 "because it defines an non-empty scope. "
281 "You need to delete any contents first."
282 ,
LERR_(NONEMPTY_SCOPE)};
316 using Slot = IDTable::const_iterator;
323 throw error::Logic(
"lost a Placement expected to be registered within PlacementIndex.");
341 using Pos = ScopeTable::const_iterator;
342 pair<Pos,Pos> searchRange =
scopeTab_.equal_range(scopeID);
344 Pos pos = searchRange.first;
345 Pos end = searchRange.second;
346 for ( ; pos!=end; ++pos)
347 if (pos->second == entryID)
359 using Pos = ScopeTable::const_iterator;
360 pair<Pos,Pos> scopeEntries =
scopeTab_.equal_range(scopeID);
361 Pos first = scopeEntries.first;
362 Pos end = scopeEntries.second;
366 ChildIDs child (eachVal(first,end));
370 for ( ; child; ++child )
392 ID elemID (entry.second);
394 return fetch (elemID);
423 INFO (
session,
"Initialising PlacementIndex...");
425 pTab_->setupRoot(rootDef);
435 return pTab_->getRootElement();
442 ASSERT (0 <
pTab_->size());
443 return pTab_->size() - 1;
450 return pTab_->contains (
id);
457 __check_knownID(*
this,
id);
458 return pTab_->fetch (
id);
471 __check_knownID(*
this,
id);
472 return pTab_->fetchScope (
id);
486 __check_knownID(*
this,
id);
487 return pTab_->queryScopeContents(
id);
507 throw error::Logic (
"Specified a non-registered Placement as scope "
508 "while adding another Placement to the index"
509 ,
LERR_(INVALID_SCOPE));
511 return pTab_->addEntry(newObj, targetScope);
526 return pTab_->removeEntry (
id);
538 if (targetScope ==
getRoot().getID())
541 pTab_->removeAll (targetScope);
567 :
error::Fatal (string(
"Failed test: ")+currentTest+
" : "+failure
568 ,LUMIERA_ERROR_INDEX_CORRUPTED)
590#define VERIFY(_CHECK_, CHECK_ID, DESCRIPTION) \
592 throw SelfCheckFailure (CHECK_ID, (DESCRIPTION));
598 VERIFY ( root,
"(0.1) Basics",
"Root element missing");
599 VERIFY ( root->
isValid(),
"(0.2) Basics",
"Root Placement invalid");
600 VERIFY ( (*root)->isValid(),
"(0.3) Basics",
"Root MObject self-check failure");
606 VERIFY (
tab.
contains(
id),
"(1.1) Elements",
"PlacementIndex main table corrupted");
607 VERIFY (
elm(
id),
"(1.2) Elements",
"Entry doesn't hold a Placement");
608 VERIFY (
id==
elm(
id)->getID(),
"(1.3) Elements",
"Element stored with wrong ID");
609 VERIFY (
elm(
id)->
isValid(),
"(1.4) Elements",
"Index contains invalid Placement")
610 VERIFY (
sco(
id),
"(1.5) Elements",
"Entry has undefined scope");
613 "(1.7) Elements",
"Element associated with an unknown scope");
615 PMO& theElement = *
elm(
id);
616 ID theScope (
sco(
id)->getID());
623 auto equalsTheElement = [&](
PMO& entry) {
return entry == theElement; };
624 bool properlyRegistered = has_any (elementsInScope, equalsTheElement);
626 VERIFY ( properlyRegistered,
"(1.8) Elements",
"Element not registered as member of the enclosing scope: "+ theElement);
632 VERIFY (
tab.
contains(
id),
"(2.1) Scopes",
"Scope not registered in main table");
633 VERIFY (
elm(
id),
"(2.2) Scopes",
"Scope entry doesn't hold a Placement");
634 VERIFY (
sco(
id),
"(2.3) Scopes",
"Scope entry doesn't hold a containing Scope");
638 while (scope and scope !=
sco(scope->getID()))
639 scope =
sco(scope->getID());
641 VERIFY ( root==scope,
"(2.4) Scopes",
"Found a scope not attached below root.");
649 VERIFY (
tab.
contains(entry),
"(2.5) Scopes",
"Scope member not registered in main table");
650 VERIFY (
elm(entry),
"(2.6) Scopes",
"Scope member entry doesn't refer to a valid Placement");
651 VERIFY (
sco(entry),
"(2.7) Scopes",
"Scope member entry is lacking valid scope information");
653 "(2.8) Scopes",
"Scope member registered as belonging to a different scope in main table");
659 VERIFY ( 0 <
tab.
size(),
"(4.1) Storage",
"Implementation table is empty");
662 "(4.3) Storage",
"Number of elements and scope entries disagree");
664 "(4.4) Storage",
"Number of entries doesn't match number of allocated Placement instances");
701 VERIFY (
pTab_,
"(0) Basics" ,
"Implementation tables not initialised");
707 catch(SelfCheckFailure& failure)
710 ERROR (
session,
"%s", failure.what());
Foundation for a custom allocation manager, tracking the created objects by smart-ptrs.
shared_ptr< XX > create(ARGS &&...args)
materialised iterator contents.
Interface and Base definition for all Lumiera Exceptions.
Derived specific exceptions within Lumiera's exception hierarchy.
virtual bool isValid() const =0
MObject self-test (usable for asserting)
Storage and implementation backing the PlacementIndex.
PlacementMO * _scope_4check(ID id)
void removeAll(ID scopeID)
PlacementMO & fetch(ID id) const
bool contains(ID id) const
PlacementMO & fetchScope(ID id) const
PlacementMO * _root_4check()
size_t scope_cnt() const
<
IDIter _contents_4check(ID id)
std::unordered_map< PID, PlacementEntry > IDTable
PlacementEntry const & base_entry(ID key) const
IDIter _eachScope_4check()
IDTable::const_iterator Slot
PlacementIndex::iterator queryScopeContents(ID id) const
pair< ScopeIter, ScopeIter > ScopeContents
PlacementMO & resolveScopeIndexElement(pair< PID, PID > const &entry) const
Helper for building a scope exploring iterator for PlacementIndex: our "reverse index" (scopeTab_) tr...
IDIter _eachEntry_4check()
ElementResolver scopeIndexElementsResolver() const
<
TypedAllocationManager allocator_
void remove_from_scope(ID scopeID, ID entryID)
ElementResolver elementResolver_
size_t element_cnt() const
std::unordered_multimap< PID, PID > ScopeTable
PlacementMO & getRootElement()
void setupRoot(PlacementMO const &rootDef)
insert a specially configured root entry into the yet empty table.
void remove_all_from_scope(ID scopeID)
PlacementMO * _element_4check(ID id)
PlacementEntry remove_base_entry(ID key)
ID addEntry(PlacementMO const &newObj, ID scopeID)
Store a copy of the given Placement as new instance within the index, together with the Scope this Pl...
shared_ptr< PlacementMO > PPlacement
function< PlacementMO &(pair< PID, PID > const &)> ElementResolver
PlacementIndex self-verification code Executes all built-in checks automatically on object creation.
void checkScopeEntry(ID scope, ID entry)
Validator(Table &indexTable)
PlacementIndex::Table & tab
void checkRoot(PMO *root)
unique_ptr< Table > pTab_
PlacementIndex(PlacementMO const &)
_ID_TableIterator iterator
bool remove(PlacementMO &)
bool isValid() const
validity self-check, used for sanity checks and the session self-check.
PlacementMO & getRoot() const
retrieve the logical root scope
bool contains(PlacementMO const &) const
PlacementRef< MObject > PRef
PlacementMO & getScope(PlacementMO const &) const
PlacementMO & find(ID) const
PlacementMO::ID const & ID
iterator getReferrers(ID) const
Retrieve all the elements attached to the given entry (scope) Each element (Placement) can act as a s...
lib::RangeIter< ScopeIter > ScopeRangeIter
ID insert(PlacementMO const &newObj, ID targetScope)
Add a new Placement (Object "instance") into the index.
lumiera_err lumiera_error(void)
Get and clear current error state.
#define LUMIERA_ERROR_DEFINE(err, msg)
Definition and initialisation of an error constant.
#define VERIFY(_CHECK_, DESCRIPTION)
Preconfigured adapters for some STL container standard usage situations.
Extension module to build an opaque data source, accessible as Lumiera Forward Iterator.
This header is for including and configuring NoBug.
_MapT< MAP >::KeyIter eachDistinctKey(MAP &map)
_MapT< MAP >::ValIter eachValForKey(MAP &map, typename _MapT< MAP >::Key key)
_MapT< MAP >::KeyIter eachMapKey(MAP &map)
_MapT< MAP >::ValIter eachVal(MAP &map)
LumieraError< LERR_(STATE)> State
LumieraError< LERR_(FATAL), Logic > Fatal
LumieraError< LERR_(LOGIC)> Logic
Lumiera public interface.
Namespace of Session and user visible high-level objects.
Placement< MObject > PlacementMO
Steam-Layer implementation namespace root.
bool has_any(IT i, IT end, FUN predicate)
Existential quantification: check if any element of a collection satisfies the given predicate.
bool contains(MAP &map, typename MAP::key_type const &key)
shortcut for containment test on a map
disable_if< can_IterForEach< Container >, FUN > for_each(Container const &coll, FUN doIt)
operate on all elements of a STL container.
Core of the session implementation datastructure.
Session and SessionServices Implementation classes.
SelfCheckFailure(lib::Literal currentTest, string failure)
Abstract foundation for building custom allocation managers.
Perform operations "for each element" of a collection.