| Index: media/blink/interval_map.h
|
| diff --git a/media/blink/interval_map.h b/media/blink/interval_map.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e11a03ceef7abbba90dc105f6dcce49ca1da212e
|
| --- /dev/null
|
| +++ b/media/blink/interval_map.h
|
| @@ -0,0 +1,290 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#ifndef MEDIA_BLINK_INTERVAL_MAP_H_
|
| +#define MEDIA_BLINK_INTERVAL_MAP_H_
|
| +
|
| +#include <limits>
|
| +#include <map>
|
| +
|
| +#include "base/logging.h"
|
| +
|
| +namespace media {
|
| +
|
| +// An IntervalMap<KeyType, ValueType> maps every value of KeyType to
|
| +// a ValueType, and incrementing, decrementing and setting ranges of values
|
| +// has been optimized. The default state is to map all values in
|
| +// KeyType to ValueType(). (Which is usually zero.)
|
| +//
|
| +// Set/Increment operations should generally take
|
| +// O(log(N)) + O(M) time where N is the number of intervals in the map and
|
| +// M is the number of modified intervals.
|
| +//
|
| +// Internally, IntervalMap<> uses an std::map, where the beginning of each
|
| +// interval is stored along with the value for that interval. Adjacent intervals
|
| +// which have the same value are automatically merged. For instance, if you did:
|
| +//
|
| +// IntervalMap<int, int> tmp;
|
| +// tmp.IncrementInterval(2, 5, 2);
|
| +// tmp.IncrementInterval(4, 6, 1);
|
| +//
|
| +// Then:
|
| +// tmp[0] = 0
|
| +// tmp[1] = 0
|
| +// tmp[2] = 2
|
| +// tmp[3] = 2
|
| +// tmp[4] = 3
|
| +// tmp[5] = 1
|
| +// tmp[6] = 0
|
| +//
|
| +// If you iterate over tmp, you get the following intervals:
|
| +// -maxint .. 2 => 0
|
| +// 2 .. 4 => 2
|
| +// 4 .. 5 => 3
|
| +// 5 .. 6 => 1
|
| +// 6 .. maxint => 0
|
| +//
|
| +// Internally, this would be stored in a map as:
|
| +// -maxint:0, 2:2, 4:3, 5:1, 6:0
|
| +//
|
| +// TODO(hubbe): Consider consolidating with media::Ranges.
|
| +
|
| +// Simple interval class.
|
| +// Interval ends are always non-inclusive.
|
| +// Please note that end <= begin is a valid (but empty) interval.
|
| +template <typename T>
|
| +struct Interval {
|
| + public:
|
| + Interval(const T& begin, const T& end) : begin(begin), end(end) {}
|
| +
|
| + // May return empty intervals (begin >= end).
|
| + Interval Intersect(const Interval& other) const {
|
| + return Interval(std::max(begin, other.begin), std::min(end, other.end));
|
| + }
|
| +
|
| + bool Empty() const { return begin >= end; }
|
| +
|
| + T begin;
|
| + T end;
|
| +};
|
| +
|
| +// The IntervalMapConstIterator points to an interval in an
|
| +// IntervalMap where all values are the same. Calling ++/--
|
| +// goes to the next/previous interval, which is guaranteed to
|
| +// have values different from the current interval.
|
| +template <typename KeyType,
|
| + typename ValueType,
|
| + class Compare = std::less<KeyType>,
|
| + class NumericLimits = std::numeric_limits<KeyType>>
|
| +class IntervalMapConstIterator {
|
| + public:
|
| + typedef std::map<KeyType, ValueType, Compare> MapType;
|
| + IntervalMapConstIterator() {}
|
| + IntervalMapConstIterator(const MapType* map,
|
| + typename MapType::const_iterator iter)
|
| + : map_(map), iter_(iter) {}
|
| +
|
| + bool operator==(const IntervalMapConstIterator& other) const {
|
| + return iter_ == other.iter_;
|
| + }
|
| +
|
| + bool operator!=(const IntervalMapConstIterator& other) const {
|
| + return iter_ != other.iter_;
|
| + }
|
| +
|
| + // Returns the beginning of the current interval.
|
| + KeyType interval_begin() const {
|
| + DCHECK(iter_ != map_->end());
|
| + return iter_->first;
|
| + }
|
| +
|
| + // Returns the end of the current interval, non-inclusive.
|
| + KeyType interval_end() const {
|
| + DCHECK(iter_ != map_->end());
|
| + typename MapType::const_iterator next = iter_;
|
| + ++next;
|
| + if (next == map_->end()) {
|
| + return NumericLimits::max();
|
| + } else {
|
| + return next->first;
|
| + }
|
| + }
|
| +
|
| + // Returns the current interval.
|
| + Interval<KeyType> interval() const {
|
| + return Interval<KeyType>(interval_begin(), interval_end());
|
| + }
|
| +
|
| + // Returns the value associated with the current interval.
|
| + ValueType value() const {
|
| + DCHECK(iter_ != map_->end());
|
| + return iter_->second;
|
| + }
|
| +
|
| + // Needed to make the following construct work:
|
| + // for (const auto& interval_value_pair : interval_map)
|
| + // Note however that this will skip the "end" interval, which
|
| + // is usually ok since it generally has the default value.
|
| + std::pair<Interval<KeyType>, ValueType> operator*() const {
|
| + return std::make_pair(interval(), value());
|
| + }
|
| +
|
| + // Go to the next interval.
|
| + // The beginning of the next interval always matches the end of the current
|
| + // interval. (But should always have a different value.)
|
| + // Not allowed if we're already at map_->end().
|
| + void operator++() {
|
| + DCHECK(iter_ != map_->end());
|
| + ++iter_;
|
| + }
|
| +
|
| + // Go to the previous interval.
|
| + // The end of the previous interval always matches the beginning of the
|
| + // current interval. (But should always have a different value.)
|
| + // Not allowed if we're already at map_->begin().
|
| + void operator--() {
|
| + DCHECK(iter_ != map_->begin());
|
| + --iter_;
|
| + }
|
| +
|
| + private:
|
| + const MapType* map_;
|
| +
|
| + // Pointer to the entry in the IntervalMap that specifies the
|
| + // beginning of the current interval.
|
| + typename MapType::const_iterator iter_;
|
| +};
|
| +
|
| +template <typename KeyType,
|
| + typename ValueType,
|
| + class Compare = std::less<KeyType>,
|
| + class NumericLimits = std::numeric_limits<KeyType>>
|
| +class IntervalMap {
|
| + public:
|
| + typedef std::map<KeyType, ValueType, Compare> MapType;
|
| + typedef IntervalMapConstIterator<KeyType, ValueType, Compare, NumericLimits>
|
| + const_iterator;
|
| + IntervalMap() {
|
| + // Adding an explicit entry for the default interval is not strictly needed,
|
| + // but simplifies the code a lot.
|
| + map_[NumericLimits::min()] = ValueType();
|
| + }
|
| +
|
| + // Returns the value at a particular point.
|
| + // Defaults to ValueType().
|
| + ValueType operator[](const KeyType& k) const {
|
| + typename MapType::const_iterator i = map_.upper_bound(k);
|
| + DCHECK(i != map_.begin());
|
| + --i;
|
| + return i->second;
|
| + }
|
| +
|
| + // Increase [from..to) by |how_much|.
|
| + void IncrementInterval(KeyType from, KeyType to, ValueType how_much) {
|
| + DCHECK_GT(to, from);
|
| + if (how_much == 0)
|
| + return;
|
| + typename MapType::iterator a = MakeEntry(from);
|
| + typename MapType::iterator b = MakeEntry(to);
|
| + for (typename MapType::iterator i = a; i != b; ++i) {
|
| + i->second += how_much;
|
| + }
|
| + RemoveDuplicates(a);
|
| + // b may be invalid
|
| + RemoveDuplicates(map_.lower_bound(to));
|
| + }
|
| +
|
| + // Set [from..to) to |how_much|.
|
| + void SetInterval(KeyType from, KeyType to, ValueType how_much) {
|
| + DCHECK_GT(to, from);
|
| + typename MapType::iterator a = MakeEntry(from);
|
| + typename MapType::iterator b = MakeEntry(to);
|
| + a->second = how_much;
|
| + while (true) {
|
| + typename MapType::iterator c = a;
|
| + ++c;
|
| + if (c == b) {
|
| + break;
|
| + } else {
|
| + map_.erase(c);
|
| + }
|
| + }
|
| + RemoveDuplicates(a);
|
| + // b may be invalid
|
| + RemoveDuplicates(map_.lower_bound(to));
|
| + }
|
| +
|
| + // Returns an iterator to the first interval.
|
| + // Note, there is always at least one interval.
|
| + const_iterator begin() const { return const_iterator(&map(), map_.begin()); }
|
| +
|
| + // Returns an end marker iterator.
|
| + const_iterator end() const { return const_iterator(&map(), map_.end()); }
|
| +
|
| + // Returns an iterator to the interval containing |k|.
|
| + // Always returns a valid iterator.
|
| + const_iterator find(KeyType k) const {
|
| + typename MapType::const_iterator iter = map_.upper_bound(k);
|
| + DCHECK(iter != map_.begin());
|
| + --iter;
|
| + return const_iterator(&map(), iter);
|
| + }
|
| +
|
| + bool empty() const { return map().size() == 1; }
|
| + void clear() {
|
| + map_.clear();
|
| + map_[NumericLimits::min()] = ValueType();
|
| + }
|
| +
|
| + private:
|
| + const MapType& map() const { return map_; }
|
| +
|
| + // Make an entry in map_ with the key |k| and return it's iterator.
|
| + // If such an entry already exists, just re-use it.
|
| + // If a new entry is created, it's value will be set to the same
|
| + // as the preceeding entry, or ValueType() if no preceeding entry exists.
|
| + // After calling this function, we'll need to call RemoveDuplicates()
|
| + // to clean up any duplicates that we made.
|
| + typename MapType::iterator MakeEntry(KeyType k) {
|
| + typename MapType::value_type tmp(k, 0);
|
| + std::pair<typename MapType::iterator, bool> insert_result;
|
| + insert_result = map_.insert(tmp);
|
| + if (insert_result.second) {
|
| + if (insert_result.first != map_.begin()) {
|
| + typename MapType::iterator i = insert_result.first;
|
| + --i;
|
| + insert_result.first->second = i->second;
|
| + }
|
| + }
|
| + return insert_result.first;
|
| + }
|
| +
|
| + // Remove duplicates before and after |i|.
|
| + void RemoveDuplicates(typename MapType::iterator i) {
|
| + if (i == map_.end())
|
| + return;
|
| +
|
| + typename MapType::iterator first = i;
|
| + typename MapType::iterator second = i;
|
| + if (i != map_.begin()) {
|
| + --first;
|
| + if (first->second == second->second) {
|
| + map_.erase(second);
|
| + second = first;
|
| + } else {
|
| + first = second;
|
| + }
|
| + }
|
| + ++second;
|
| + if (second != map_.end() && first->second == second->second) {
|
| + map_.erase(second);
|
| + }
|
| + }
|
| +
|
| + MapType map_;
|
| +};
|
| +
|
| +} // namespace media
|
| +
|
| +#endif // MEDIA_BLINK_INTERVAL_MAP_H_
|
|
|