Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(911)

Side by Side Diff: media/blink/interval_map.h

Issue 1422523007: RangeMap: A int->int mapping with fast range operations (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@lru
Patch Set: rename RangeMap to IntervalMap & address comments Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef MEDIA_BLINK_INTERVAL_MAP_H_
6 #define MEDIA_BLINK_INTERVAL_MAP_H_
7
8 #include <limits>
9 #include <map>
10
11 #include "base/logging.h"
12
13 namespace media {
14
15 // An IntervalMap<KeyType, ValueType> maps every value of KeyType to
16 // a ValueType, and incrementing, decrementing and setting ranges of values
17 // has been optimized. The default state is to map all values in
18 // KeyType to ValueType(). (Which is usually zero.)
19 //
20 // Set/Increment operations should generally take
21 // O(log(N)) + O(M) time where N is the number of ranges in the map and
22 // M is the number of modified ranges.
23 //
24 // Internally, IntervalMap<> uses an std::map, where the beginning of each range
25 // is stored along with the value for that range. Adjacent ranges which have the
26 // same value are automatically merged. For instance, if you did:
27 //
28 // IntervalMap<int, int> tmp;
29 // tmp.IncrementRange(2, 5, 2);
30 // tmp.IncrementRange(4, 6, 1);
31 //
32 // Then:
33 // tmp[0] = 0
34 // tmp[1] = 0
35 // tmp[2] = 2
36 // tmp[3] = 2
37 // tmp[4] = 3
38 // tmp[5] = 1
39 // tmp[6] = 0
40 //
41 // If you iterate over tmp, you get the following ranges:
42 // -maxint .. 2 => 0
43 // 2 .. 4 => 2
44 // 4 .. 5 => 3
45 // 5 .. 6 => 1
46 // 6 .. maxint => 0
47 //
48 // Internally, this would be stored in a map as:
49 // -maxint:0, 2:2, 4:3, 5:1, 6:0
50 //
51 // TODO(hubbe): Consider consolidating with media::Ranges.
52
53 // Simple range class.
54 // Range ends are always non-inclusive.
55 // Please note that end <= begin is a valid (but empty) range.
56 template <typename T>
57 struct Range {
xhwang 2015/11/12 18:24:58 should this be renamed to Interval as well?
hubbe 2015/11/12 19:03:13 Done.
58 public:
59 Range(const T& begin, const T& end) : begin(begin), end(end) {}
60
61 // May return empty ranges (begin >= end).
62 Range Intersect(const Range& other) const {
63 return Range(std::max(begin, other.begin), std::min(end, other.end));
64 }
65
66 bool Empty() const { return begin >= end; }
67
68 T begin;
69 T end;
70 };
71
72 template <typename KeyType,
73 typename ValueType,
74 class Compare = std::less<KeyType>,
75 class NumericLimits = std::numeric_limits<KeyType>>
76 class IntervalMapConstIterator {
xhwang 2015/11/12 18:24:58 Add a comment that this represents an interval of
hubbe 2015/11/12 19:03:13 Done.
77 public:
78 typedef std::map<KeyType, ValueType, Compare> MapType;
79 IntervalMapConstIterator() {}
80 IntervalMapConstIterator(const MapType* map,
81 typename MapType::const_iterator iter)
82 : map_(map), iter_(iter) {}
83
84 bool operator==(const IntervalMapConstIterator& other) const {
85 return iter_ == other.iter_;
86 }
87
88 bool operator!=(const IntervalMapConstIterator& other) const {
89 return iter_ != other.iter_;
90 }
91
92 // Returns the beginning of the current range.
93 KeyType range_begin() const {
xhwang 2015/11/12 18:24:58 should we replace all "range" to "interval"?
hubbe 2015/11/12 19:03:13 Done.
94 DCHECK(iter_ != map_->end());
95 return iter_->first;
96 }
97
98 // Returns the end of the current range, non-inclusive.
99 KeyType range_end() const {
xhwang 2015/11/12 18:24:58 Wondering how range_end() is used? It seems the ca
hubbe 2015/11/12 19:03:12 They could, except ++iter might point to end(). Re
100 DCHECK(iter_ != map_->end());
101 typename MapType::const_iterator next = iter_;
102 ++next;
103 if (next == map_->end()) {
104 return NumericLimits::max();
105 } else {
106 return next->first;
107 }
108 }
109
110 // Returns the current range.
111 Range<KeyType> range() const {
112 return Range<KeyType>(range_begin(), range_end());
113 }
114
115 // Returns the value associated with the current range.
116 ValueType value() const {
117 DCHECK(iter_ != map_->end());
118 return iter_->second;
119 }
120
121 // Needed to make the following construct work:
122 // for (const auto& range_value_pair : interval_map)
123 // Note however that this will skip the "end" range, which
124 // is usually ok since it generally has the default value.
125 std::pair<Range<KeyType>, ValueType> operator*() const {
126 return std::make_pair(range(), value());
127 }
128
129 // Go to the next range.
130 // The beginning of the next range always matches the end of the current
131 // range. (But should always have a different value.)
132 // Not allowed if we're already at map_->end().
133 void operator++() {
134 DCHECK(iter_ != map_->end());
135 ++iter_;
136 }
137
138 // Go to the previous range.
139 // The end of the previous range always matches the beginning of the current
140 // range. (But should always have a different value.)
141 // Not allowed if we're already at map_->begin().
142 void operator--() {
143 DCHECK(iter_ != map_->begin());
144 --iter_;
145 }
146
147 private:
148 const MapType* map_;
149
150 // Pointer to the entry in the IntervalMap that specifies the
151 // beginning of the current range.
152 typename MapType::const_iterator iter_;
153 };
154
155 template <typename KeyType,
156 typename ValueType,
157 class Compare = std::less<KeyType>,
158 class NumericLimits = std::numeric_limits<KeyType>>
159 class IntervalMap {
160 public:
161 typedef std::map<KeyType, ValueType, Compare> MapType;
162 typedef IntervalMapConstIterator<KeyType, ValueType, Compare, NumericLimits>
163 const_iterator;
164 IntervalMap() {
165 // Adding an explicit entry for the default range is not strictly needed,
166 // but simplifies the code a lot.
167 map_[NumericLimits::min()] = ValueType();
168 }
169
170 // Returns the value at a particular point.
171 // Defaults to ValueType().
172 ValueType operator[](const KeyType& k) const {
173 typename MapType::const_iterator i = map_.upper_bound(k);
174 if (i == map_.begin()) {
175 return 0;
xhwang 2015/11/12 18:24:58 Not possible to happen? how about a DCHECK? We act
hubbe 2015/11/12 19:03:12 Done.
176 } else {
177 --i;
178 return i->second;
179 }
180 }
181
182 // Increase [from..to) by |how_much|.
183 void IncrementRange(KeyType from, KeyType to, ValueType how_much) {
184 DCHECK_GT(to, from);
185 if (how_much == 0)
186 return;
187 typename MapType::iterator a = MakeEntry(from);
188 typename MapType::iterator b = MakeEntry(to);
189 for (typename MapType::iterator i = a; i != b; ++i) {
190 i->second += how_much;
191 }
192 RemoveDuplicates(a);
193 // b may be invalid
194 RemoveDuplicates(map_.lower_bound(to));
195 }
196
197 // Set [from..to) to |how_much|.
198 void SetRange(KeyType from, KeyType to, ValueType how_much) {
199 DCHECK_GT(to, from);
200 typename MapType::iterator a = MakeEntry(from);
201 typename MapType::iterator b = MakeEntry(to);
202 a->second = how_much;
203 while (true) {
204 typename MapType::iterator c = a;
205 ++c;
206 if (c == b) {
207 break;
208 } else {
209 map_.erase(c);
210 }
211 }
212 RemoveDuplicates(a);
213 // b may be invalid
214 RemoveDuplicates(map_.lower_bound(to));
215 }
216
217 // Returns an iterator to the first range.
218 // Note, there is always at least one range.
219 const_iterator begin() const { return const_iterator(&map(), map_.begin()); }
220
221 // Returns an end marker iterator.
222 const_iterator end() const { return const_iterator(&map(), map_.end()); }
223
224 // Returns an iterator to the range containing |k|.
225 // Always returns a valid iterator.
226 const_iterator find(KeyType k) const {
227 typename MapType::const_iterator first = map_.upper_bound(k);
xhwang 2015/11/12 18:24:58 now we don't have "first" and "second" any more...
hubbe 2015/11/12 19:03:12 Done.
228 DCHECK(first != map_.begin());
229 --first;
230 return const_iterator(&map(), first);
231 }
232
233 bool empty() const { return map().size() == 1; }
234
235 private:
236 const MapType& map() const { return map_; }
237
238 // Make an entry in map_ with the key |k| and return it's iterator.
239 // If such an entry already exists, just re-use it.
240 // If a new entry is created, it's value will be set to the same
241 // as the preceeding entry, or ValueType() if no preceeding entry exists.
242 // After calling this function, we'll need to call RemoveDuplicates()
243 // to clean up any duplicates that we made.
244 typename MapType::iterator MakeEntry(KeyType k) {
245 typename MapType::value_type tmp(k, 0);
246 std::pair<typename MapType::iterator, bool> insert_result;
247 insert_result = map_.insert(tmp);
248 if (insert_result.second) {
249 if (insert_result.first != map_.begin()) {
250 typename MapType::iterator i = insert_result.first;
251 --i;
252 insert_result.first->second = i->second;
253 }
254 }
255 return insert_result.first;
256 }
257
258 // Remove duplicates before and after |i|.
259 void RemoveDuplicates(typename MapType::iterator i) {
260 DCHECK(i != map_.begin());
261 if (i == map_.end())
262 return;
263
264 typename MapType::iterator first = i;
265 typename MapType::iterator second = i;
266 --first;
267 if (first->second == second->second) {
268 map_.erase(second);
269 second = first;
270 } else {
271 first = second;
272 }
273 ++second;
274 if (second != map_.end() && first->second == second->second) {
275 map_.erase(second);
276 }
277 }
278
279 MapType map_;
280 };
281
282 } // namespace media
283
284 #endif // MEDIA_BLINK_INTERVAL_MAP_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698