omni::graph::exec::unstable::Stamp
Defined in omni/graph/exec/unstable/Stamp.h
-
class Stamp
Lazy, light-weight change notification system.
The heart of the EF’s invalidation system is Stamp and SyncStamp.
Stamps track the state/version of a resource. Stamps are implemented as an unsigned number. If the state of a resource changes, the stamp is incremented.
Stamps are broken into two parts.
The first part is implemented by the Stamp class. As a resource changes, Stamp::next()| s called to denote the new state of the resource. Stamp objects are owned by the resource they track.
The second part of stamps is implemented by the SyncStamp class. SyncStamp tracks/synchronizes to the state of a Stamp. SyncStamp objects are owned by the entities that wish to utilize the mutating resource.
For example, consider the following example showing how a consumer of a resource can uses stamps to detect when a resource has changed and update cached data:
By default constructed Stamp and SyncStamp are never in sync, meaning reconstruction will always happen at least once.// wraps a resource (e.g. an array of numbers). updates its Stamp when the // resource is mutated. struct Producer { Stamp stamp; std::vector<int> resource; Producer() : resource(10, 1) // fill with 1 { stamp.next(); } void mutate() { resource[0] = 2; stamp.next(); } }; // consumes a resource (array of numbers). computes the sum of an array of numbers // and caches the result. a SyncStamp is used to determine if the cached result is stale. struct Consumer { const Producer& producer; SyncStamp stampSync; int cachedSum = 0; Consumer(const Producer& p) : producer(p) { } // returns true if sum was computed, false if the cached sum was used bool compute(int& outSum) { bool computedSum = false; if (stampSync.makeSync(producer.stamp)) // returns true if out-of-sync { // the stamp was out-of-sync. we need to recompute our cached value. // // note, makeSync() synchronized the SyncStamp cachedSum = std::accumulate(std::begin(producer.resource), std::end(producer.resource), 0); computedSum = true; } outSum = cachedSum; return computedSum; } }; void example() { Producer p; Consumer c(p); int sum; sum = 0; CHECK(c.compute(sum)); // returns true since the consumer had to compute the sum CHECK(sum == 10); sum = 0; CHECK(!c.compute(sum)); // returns false since the consumer used the cached sum CHECK(sum == 10); // mutate the resource p.mutate(); sum = 0; CHECK(c.compute(sum)); // returns true since the consumer had to compute the new sum CHECK(sum == 11); }
Stamps are a lazy, light-weight alternative to heavier change notification systems such as callbacks.
Stamps use unsigned numbers to detect changes in the tracked resource, relying on overflow behavior to wrap the unsigned number. A check for Stamp::kInvalidStamp is performed during this overflow.
Because of the limited bit depth of Stamp, it is possible, though improbable, that a resource at stamp X, wraps all the way back to X before a SyncStamp tries to synchronize with the stamp. In such a case, the SyncStamp will erroneously believe it is in sync with the resource. Again, this is unlikely, though possible.
EF makes extensive use of stamps to detect changes in pass registration, graph topology, and graph construction. See Graph Invalidation to understand how Stamp is used for invalidation in EF.
This object is ABI-safe and can be passed by pointer or value through the ABI.
Public Types