53 #ifndef STEAM_ENGINE_BUFFR_METADATA_H 54 #define STEAM_ENGINE_BUFFR_METADATA_H 66 #include <unordered_map> 113 return RAW_BUFFER != toVerify;
117 nontrivial (
LocalKey const& toVerify)
119 return UNSPECIFIC != toVerify;
130 template<
typename VAL>
132 chainedHash(
HashVal accumulatedHash, VAL changedValue)
134 boost::hash_combine (accumulatedHash, changedValue);
135 return accumulatedHash;
166 , hashID_(chainedHash (familyID, storageSize))
167 , storageSize_(storageSize)
168 , instanceFunc_(RAW_BUFFER)
169 , specifics_(UNSPECIFIC)
178 Key (
Key const& parent,
size_t differingStorageSize)
179 : parent_(parent.hashID_)
180 , hashID_(chainedHash (parent_, differingStorageSize))
181 , storageSize_(differingStorageSize)
182 , instanceFunc_(parent.instanceFunc_)
183 , specifics_(parent.specifics_)
192 : parent_(parent.hashID_)
193 , hashID_(chainedHash (parent_, differingTypeHandlerFunctions))
194 , storageSize_(parent.storageSize_)
195 , instanceFunc_(differingTypeHandlerFunctions)
196 , specifics_(parent.specifics_)
205 : parent_(parent.hashID_)
206 , hashID_(chainedHash (parent_, anotherTypeSpecificInternalID))
207 , storageSize_(parent.storageSize_)
208 , instanceFunc_(parent.instanceFunc_)
209 , specifics_(anotherTypeSpecificInternalID)
225 newKey.parent_ =
HashVal(parent);
226 newKey.hashID_ = chainedHash(parent, bufferAddr);
227 if (nontrivial(implID))
229 REQUIRE (!newKey.specifics_.isDefined(),
230 "Implementation defined local key should not be overridden. " 231 "Underlying buffer type already defines a nontrivial LocalKey");
232 newKey.specifics_ = implID;
238 useTypeHandlerFrom (
Key const& ref)
240 if (nontrivial(this->instanceFunc_))
241 throw error::Logic (
"unable to supersede an already attached TypeHandler" 243 instanceFunc_ = ref.instanceFunc_;
247 LocalKey const& localKey()
const {
return specifics_;}
248 size_t storageSize()
const {
return storageSize_; }
250 HashVal parentKey()
const {
return parent_;}
251 operator HashVal()
const {
return hashID_;}
276 Entry (
Key const& parent,
void* bufferPtr =0,
LocalKey const& implID =UNSPECIFIC)
293 ASSERT (!buffer_ || (NIL != state_ &&
FREE != state_));
294 return bool(buffer_);
303 return NIL == state_ && !buffer_;
317 __must_not_be_FREE();
338 if (newState ==
FREE)
339 invokeEmbeddedDtor_and_clear();
341 invokeEmbeddedCtor();
346 throw error::Fatal (
"Invalid buffer state transition.");
350 lock (
void* newBuffer)
358 invalidate (
bool invokeDtor =
true)
360 if (buffer_ && invokeDtor)
361 invokeEmbeddedDtor_and_clear();
376 if (nontrivial (instanceFunc_))
377 instanceFunc_.createAttached (buffer_);
387 if (nontrivial (instanceFunc_))
388 instanceFunc_.destroyAttached (buffer_);
394 __must_not_be_NIL()
const 397 throw error::Fatal (
"Buffer metadata entry with state==NIL encountered." 398 "State transition logic broken (programming error)" 403 __must_not_be_FREE()
const 406 throw error::Logic (
"Buffer is inaccessible (marked as free). " 407 "Need a new buffer pointer in order to lock an entry. " 408 "You should invoke markLocked(buffer) prior to access." 413 __must_be_FREE()
const 418 REQUIRE (!buffer_,
"Buffer marked as free, " 419 "but buffer pointer is set.");
423 __buffer_required()
const 426 throw error::Fatal (
"Need concrete buffer for any further operations");
443 typedef std::unordered_map<HashVal,Entry> MetadataStore;
445 MetadataStore entries_;
448 ~
Table() { verify_all_buffers_freed(); }
457 MetadataStore::iterator pos = entries_.find (hashID);
458 if (pos != entries_.end())
459 return &(pos->second);
467 MetadataStore::const_iterator pos = entries_.find (hashID);
468 if (pos != entries_.end())
469 return &(pos->second);
485 using std::make_pair;
486 REQUIRE (!fetch (newEntry),
"duplicate buffer metadata entry");
487 MetadataStore::iterator pos = entries_.insert (make_pair (
HashVal(newEntry), newEntry))
490 ENSURE (pos != entries_.end());
497 uint cnt = entries_.erase (hashID);
498 ENSURE (cnt,
"entry to remove didn't exist");
503 verify_all_buffers_freed()
506 for_each (entries_, verify_is_free);
511 verify_is_free (std::pair<HashVal, Entry>
const& e)
513 WARN_IF (e.second.isLocked(), engine,
514 "Buffer still in use while shutting down BufferProvider? ");
560 : id_(implementationID)
561 , family_(hash_value(id_))
579 REQUIRE (storageSize);
580 Key typeKey = trackKey (family_, storageSize);
582 if (nontrivial(instanceFunc))
583 typeKey = trackKey (typeKey, instanceFunc);
585 if (nontrivial(specifics))
586 typeKey = trackKey (typeKey, specifics);
595 return trackKey (parentKey, instanceFunc);
603 return trackKey (parentKey, specifics);
611 key (Key
const& parentKey,
void* concreteBuffer,
LocalKey const& implID =UNSPECIFIC)
614 Entry* existing = table_.
fetch (derivedKey);
616 return existing? *existing
617 : markLocked (parentKey,concreteBuffer,implID);
644 ,
void* concreteBuffer
646 ,
bool onlyNew =
false)
650 , LERR_(BOTTOM_VALUE)};
652 Entry newEntry(parentKey, concreteBuffer, implID);
653 Entry* existing = table_.
fetch (newEntry);
655 if (existing && onlyNew)
656 throw error::Logic{
"Attempt to lock a slot for a new buffer, " 657 "while actually the old buffer is still locked" 659 if (existing && existing->
isLocked())
660 throw error::Logic{
"Attempt to re-lock a buffer still in use" 664 return store_and_lock (newEntry);
666 return existing->lock (concreteBuffer);
682 throw error::Invalid (
"Attempt to access an unknown buffer metadata entry");
690 return bool(table_.
fetch (key));
719 throw error::Fatal{
"Attempt to lock for a NULL buffer. Allocation floundered?" 720 , LERR_(BOTTOM_VALUE)};
722 return this->lock(parentKey, buffer, implID,
true);
734 ASSERT (entry && (key ==
HashVal(*entry)));
739 release (Entry
const&
entry)
741 if (
FREE != entry.state())
742 throw error::Logic{
"Attempt to release a buffer still in use" 745 table_.remove (
HashVal(entry));
752 template<
typename PAR,
typename DEF>
754 trackKey (PAR parent, DEF specialisation)
756 Key newKey (parent,specialisation);
762 maybeStore (Key
const& key)
764 if (isKnown (key))
return;
765 table_.
store (Entry (key, NULL));
769 store_and_lock (Entry
const& metadata)
771 Entry& newEntry = table_.
store (metadata);
775 ENSURE (
LOCKED == newEntry.state());
776 ENSURE (newEntry.access());
allocated buffer, no longer in use
A marker data type used in metadata / buffer management of the render engine.
#define ERROR_LOG_AND_IGNORE(_FLAG_, _OP_DESCR_)
convenience shortcut for a sequence of catch blocks just logging and consuming an error...
AnyPair entry(Query< TY > const &query, typename WrapReturn< TY >::Wrapper &obj)
helper to simplify creating mock table entries, wrapped correctly
Any copy and copy construction prohibited.
inline string literal This is a marker type to indicate that
bool isTypeKey() const
is this Entry just an (abstract) placeholder for a type?
allocated buffer blocked by protocol failure
This header is for including and configuring NoBug.
allocated buffer, returned from client
allocated buffer actively in use
Entry & mark(BufferState newState)
Buffer state machine.
Steam-Layer implementation namespace root.
void invokeEmbeddedCtor()
Derived specific exceptions within Lumiera's exception hierarchy.
Mix-Ins to allow or prohibit various degrees of copying and cloning.
an opaque ID to be used by the BufferProvider implementation.
Marker types to indicate a literal string and a Symbol.
void invokeEmbeddedDtor_and_clear()
void for_each(CON const &elements, FUN function, P1 &&bind1, ARGS &&...args)
Accept binding for arbitrary function arguments.
bool isLocked() const
is this Entry currently associated to a concrete buffer? Is this buffer in use?
Helper holding a pair of type-build-up and destruction functors.
Lumiera error handling (C++ interface).
Hash value types and utilities.
size_t HashVal
a STL compatible hash value
A pair of functors to maintain a datastructure within a buffer.
BufferState
Buffer states usable within BufferProvider and stored within the metadata.
abstract entry, not yet allocated
A complete metadata Entry, based on a Key.
Perform operations "for each element" of a collection.