diff --git a/renderdoc/core/intervals.h b/renderdoc/core/intervals.h index 459efabf1..e35fe818e 100644 --- a/renderdoc/core/intervals.h +++ b/renderdoc/core/intervals.h @@ -25,28 +25,100 @@ #include #include +#include "common/common.h" template struct Intervals; -template -struct IntervalsIter +template +class IntervalsIter; + +// An interval in an `Intervals` instance. +template +class ConstIntervalRef +{ + friend class IntervalsIter; + +protected: + Iter iter; + Map *owner; + + ConstIntervalRef(Map *owner, Iter iter) : iter(iter), owner(owner) {} +public: + // Inclusive lower bound + inline uint64_t start() const { return iter->first; } + // Exclusive upper bound + inline uint64_t finish() const + { + Iter next = iter; + next++; + if(next == owner->end()) + { + return UINT64_MAX; + } + return next->first; + } + + // Value associated with this interval + inline const T &value() const { return iter->second; } +}; + +// A mutable interval in an `Intervals` instance +template +class IntervalRef : public ConstIntervalRef +{ + friend class IntervalsIter; + +protected: + IntervalRef(Map *owner, Iter iter) : ConstIntervalRef(owner, iter) {} +public: + inline void setValue(const T &val) { this->iter->second = val; } + // Split this interval into two intervals: + // [start, x), [x, finish) + // This iterator will point to [x, finish) after the split. + // `x` must be in the interval [start, finish). + // If `x == start`, then `split(x)` is a no-op. + inline void split(uint64_t x) + { + RDCASSERT(this->start() <= x && x < this->finish()); + if(this->start() < x) + this->iter = this->owner->insert(std::pair(x, this->value())).first; + } + + // Merge this interval with the interval to the left, if both intervals have + // the same value. + // This iterator will point to the merged interval, if the merge is actually + // performed; otherwise this iterator is unmodified. + inline void mergeLeft() + { + if(this->iter != this->owner->begin()) + { + auto prev_it = this->iter; + prev_it--; + if(this->iter->second == prev_it->second) + { + this->owner->erase(this->iter); + this->iter = prev_it; + } + } + } +}; + +// An iterator in an `Intervals` instance. +template +class IntervalsIter { friend struct Intervals; -private: - typename std::map::iterator iter; - std::map *owner; - IntervalsIter(std::map *owner, typename std::map::iterator iter) - : iter(iter), owner(owner) - { - } - typename std::map::iterator unwrap() { return iter; } +protected: + Interval ref; + IntervalsIter(Map *owner, Iter iter) : ref(owner, iter) {} + Iter unwrap() { return ref.iter; } public: - IntervalsIter(const IntervalsIter &src) : owner(src.owner), iter(src.iter) {} + IntervalsIter(const IntervalsIter &src) : ref(src.ref) {} IntervalsIter &operator++() { - ++iter; + ++ref.iter; return *this; } IntervalsIter operator++(int) @@ -57,7 +129,7 @@ public: } IntervalsIter &operator--() { - --iter; + --ref.iter; return *this; } IntervalsIter operator--(int) @@ -66,106 +138,72 @@ public: operator--(); return tmp; } - bool operator==(const IntervalsIter &rhs) const { return iter == rhs.iter && owner == rhs.owner; } - bool operator!=(const IntervalsIter &rhs) const { return iter != rhs.iter && owner == rhs.owner; } + bool operator==(const IntervalsIter &rhs) const + { + return ref.iter == rhs.ref.iter && ref.owner == rhs.ref.owner; + } + bool operator!=(const IntervalsIter &rhs) const + { + return ref.iter != rhs.ref.iter && ref.owner == rhs.ref.owner; + } IntervalsIter &operator=(const IntervalsIter &rhs) { - iter = rhs.iter; - owner = rhs.owner; + ref.iter = rhs.ref.iter; + ref.owner = rhs.ref.owner; return *this; } - inline uint64_t start() const { return iter->first; } - inline uint64_t end() const - { - typename std::map::iterator next = iter; - next++; - if(next == owner->end()) - { - return UINT64_MAX; - } - return next->first; - } - inline const T &value() const { return iter->second; } - inline void setValue(uint64_t aStart, uint64_t aEnd, const T &aValue) - { - T old_value = this->value(); - if((aValue == old_value || aEnd <= start()) && end() <= aStart) - { - // The value is unchanged, or the specified interval is disjoint from this interval. - return; - } - // Add a new endpoint for aStart, if necessary, and update iter's value to aValue. - if(start() < aStart) - { - // The updated portion of this interval begins at aStart. - iter = owner->insert(std::pair(aStart, aValue)).first; - } - else - { - // The updated portion of this interval begins at start() - iter->second = aValue; - } - - // Add a new endpoint for aEnd, if necessary. - if(aEnd < end()) - { - owner->insert(std::pair(aEnd, old_value)); - } - - // Merge with preceding interval, if necessary - if(iter != owner->begin()) - { - typename std::map::iterator prev_it = iter; - prev_it--; - if(prev_it->second == iter->second) - { - owner->erase(iter); - iter = prev_it; - } - } - - // Merge with succeding interval, if necessary - typename std::map::iterator next_it = iter; - next_it++; - if(next_it != owner->end()) - { - if(next_it->second == iter->second) - { - owner->erase(next_it); - } - } - } + inline Interval *operator->() { return &ref; } }; +// Data structure to efficiently store values for disjoint intervals. template struct Intervals { +public: + typedef IntervalRef, typename std::map::iterator> interval; + typedef IntervalsIter, typename std::map::iterator, interval> iterator; + + typedef ConstIntervalRef, typename std::map::const_iterator> + const_interval; + typedef IntervalsIter, + typename std::map::const_iterator, const_interval> + const_iterator; + private: std::map StartPoints; -public: -private: - IntervalsIter Wrap(typename std::map::iterator iter) + iterator Wrap(typename std::map::iterator iter) { - return IntervalsIter(&StartPoints, iter); + return iterator(&StartPoints, iter); + } + + const_iterator Wrap(typename std::map::const_iterator iter) const + { + return const_iterator(&StartPoints, iter); } public: Intervals() : StartPoints{{0, T()}} {} - IntervalsIter begin() { return Wrap(StartPoints.begin()); } - IntervalsIter end() { return Wrap(StartPoints.end()); } + inline iterator end() { return Wrap(StartPoints.end()); } + inline iterator begin() { return Wrap(StartPoints.begin()); } + inline const_iterator begin() const { return Wrap(StartPoints.begin()); } + inline const_iterator end() const { return Wrap(StartPoints.end()); } // finds the interval containing `x`. - IntervalsIter find(uint64_t x) + iterator find(uint64_t x) { - // Find the first interval which starts AFTER `x` - typename std::map::iterator it = StartPoints.upper_bound(x); - // Because the first interval always starts at 0, the found interval cannot be the first - // interval + auto it = StartPoints.upper_bound(x); // first starting after `x` RDCASSERT(it != StartPoints.begin()); - // Move back 1 interval, to find the last interval that starts no later than `range.start`. - // This is the interval that contains the point - it--; + it--; // last *not* starting after `x` + return Wrap(it); + } + + // finds the interval containing `x`. + const_iterator find(uint64_t x) const + { + auto it = StartPoints.upper_bound(x); // first starting after `x` + RDCASSERT(it != StartPoints.begin()); + it--; // last *not* starting after `x` return Wrap(it); } }; \ No newline at end of file