44 #ifndef STEAM_ENGINE_BUFFR_METADATA_H 45 #define STEAM_ENGINE_BUFFR_METADATA_H 58 #include <unordered_map> 71 using Buff = StreamType::ImplFacade::DataBuffer;
108 nontrivial (
LocalTag const& toVerify)
121 template<
typename VAL>
123 chainedHash(
HashVal accumulatedHash, VAL changedValue)
125 boost::hash_combine (accumulatedHash, changedValue);
126 return accumulatedHash;
157 , hashID_(chainedHash (familyID, storageSize))
158 , storageSize_(storageSize)
169 Key (
Key const& parent,
size_t differingStorageSize)
170 : parent_(parent.hashID_)
171 , hashID_(chainedHash (parent_, differingStorageSize))
172 , storageSize_(differingStorageSize)
173 , instanceFunc_(parent.instanceFunc_)
174 , specifics_(parent.specifics_)
183 : parent_(parent.hashID_)
184 , hashID_(chainedHash (parent_, differingTypeHandlerFunctions))
185 , storageSize_(parent.storageSize_)
186 , instanceFunc_(differingTypeHandlerFunctions)
187 , specifics_(parent.specifics_)
196 : parent_(parent.hashID_)
197 , hashID_(chainedHash (parent_, anotherTypeSpecificInternalTag))
198 , storageSize_(parent.storageSize_)
199 , instanceFunc_(parent.instanceFunc_)
200 , specifics_(anotherTypeSpecificInternalTag)
214 if (nontrivial(localTag))
216 if (nontrivial(parent.specifics_))
217 throw error::Logic{
"Implementation defined local key should not be overridden. " 218 "Underlying buffer type already defines a nontrivial LocalTag"};
219 newKey.parent_ =
HashVal(parent);
220 newKey.hashID_ = chainedHash(newKey.hashID_, localTag);
221 newKey.specifics_ = localTag;
225 newKey.parent_ =
HashVal(parent);
226 newKey.hashID_ = chainedHash(newKey.hashID_, bufferAddr);
232 useTypeHandlerFrom (
Key const& ref)
234 if (nontrivial(this->instanceFunc_))
235 throw error::Logic (
"unable to supersede an already attached TypeHandler" 237 instanceFunc_ = ref.instanceFunc_;
241 LocalTag const& localTag()
const {
return specifics_;}
242 size_t storageSize()
const {
return storageSize_; }
244 HashVal parentKey()
const {
return parent_;}
245 operator HashVal()
const {
return hashID_;}
271 ,
Buff* bufferPtr =
nullptr 290 ASSERT (!buffer_ or (
NIL != state_ and
FREE != state_));
291 return bool(buffer_);
300 return NIL == state_ and not buffer_;
314 __must_not_be_FREE();
335 if (newState ==
FREE)
336 invokeEmbeddedDtor_and_clear();
338 invokeEmbeddedCtor();
343 throw error::Fatal (
"Invalid buffer state transition.");
347 lock (
Buff* newBuffer)
355 invalidate (
bool invokeDtor =
true)
357 if (buffer_ and invokeDtor)
358 invokeEmbeddedDtor_and_clear();
373 if (nontrivial (instanceFunc_))
374 instanceFunc_.createAttached (buffer_);
384 if (nontrivial (instanceFunc_))
385 instanceFunc_.destroyAttached (buffer_);
391 __must_not_be_NIL()
const 394 throw error::Fatal (
"Buffer metadata entry with state==NIL encountered." 395 "State transition logic broken (programming error)" 400 __must_not_be_FREE()
const 403 throw error::Logic (
"Buffer is inaccessible (marked as free). " 404 "Need a new buffer pointer in order to lock an entry. " 405 "You should invoke markLocked(buffer) prior to access." 410 __must_be_FREE()
const 415 REQUIRE (!buffer_,
"Buffer marked as free, " 416 "but buffer pointer is set.");
420 __buffer_required()
const 423 throw error::Fatal (
"Need concrete buffer for any further operations");
440 typedef std::unordered_map<HashVal,Entry> MetadataStore;
442 MetadataStore entries_;
445 ~
Table() { verify_all_buffers_freed(); }
454 MetadataStore::iterator pos = entries_.find (hashID);
455 if (pos != entries_.end())
456 return &(pos->second);
464 MetadataStore::const_iterator pos = entries_.find (hashID);
465 if (pos != entries_.end())
466 return &(pos->second);
482 REQUIRE (!fetch (newEntry),
"duplicate buffer metadata entry");
483 MetadataStore::iterator pos = entries_.emplace (
HashVal(newEntry), newEntry)
486 ENSURE (pos != entries_.end());
493 uint cnt = entries_.erase (hashID);
494 ENSURE (cnt,
"entry to remove didn't exist");
499 verify_all_buffers_freed()
502 for_each (entries_, verify_is_free);
507 verify_is_free (std::pair<HashVal, Entry>
const& e)
509 WARN_IF (e.second.isLocked(), engine,
510 "Buffer still in use while shutting down BufferProvider? ");
556 : id_(implementationID)
575 REQUIRE (storageSize);
576 Key typeKey = trackKey (family_, storageSize);
578 if (nontrivial(instanceFunc))
579 typeKey = trackKey (typeKey, instanceFunc);
581 if (nontrivial(specifics))
582 typeKey = trackKey (typeKey, specifics);
591 return trackKey (parentKey, instanceFunc);
599 return trackKey (parentKey, specifics);
612 return existing? *existing
613 : markLocked (parentKey,concreteBuffer,specifics);
644 ,
bool onlyNew =
false)
648 , LERR_(BOTTOM_VALUE)};
650 Entry newEntry{parentKey, concreteBuffer, specifics};
653 if (existing and onlyNew)
654 throw error::Logic{
"Attempt to lock a slot for a new buffer, " 655 "while actually the old buffer is still locked" 657 if (existing and existing->
isLocked())
658 throw error::Logic{
"Attempt to re-lock a buffer still in use" 662 return store_as_locked (newEntry);
664 return existing->lock (concreteBuffer);
680 throw error::Invalid (
"Attempt to access an unknown buffer metadata entry");
688 return bool(table_.
fetch (key));
717 throw error::Fatal{
"Attempt to lock for a NULL buffer. Allocation floundered?" 718 , LERR_(BOTTOM_VALUE)};
720 return this->lock (parentKey, buffer, specifics,
true);
732 ASSERT (entry and (key ==
HashVal(*entry)));
739 if (
FREE != entry.state())
740 throw error::Logic{
"Attempt to release a buffer still in use" 743 table_.remove (
HashVal(entry));
750 template<
typename PAR,
typename DEF>
752 trackKey (PAR parent, DEF specialisation)
754 Key newKey{parent, specialisation};
760 maybeStore (
Key const& key)
762 if (isKnown (key))
return;
781 ENSURE (
LOCKED == newEntry.state());
782 ENSURE (newEntry.access());
allocated buffer, no longer in use
Framework for classification of media streams.
#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.
A marker data type used in metadata / buffer management of the render engine.
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.
an opaque mark to be used by the BufferProvider implementation.
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.
Marker types to indicate a literal string and a Symbol.
static const TypeHandler RAW
Marker for the default case: raw buffer without type handling.
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).
static const LocalTag UNKNOWN
Marker when no distinct local key is given.
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
HashVal hash_value(ProcID const &procID)
generate registry hash value based on the distinct data in ProcID.
placeholder type for the contents of a data buffer.
A complete metadata Entry, based on a Key.
Perform operations "for each element" of a collection.