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

Side by Side Diff: media/blink/range_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: lots of comments added 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
« no previous file with comments | « media/blink/media_blink.gyp ('k') | media/blink/range_map_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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_RANGE_MAP_H_
6 #define MEDIA_BLINK_RANGE_MAP_H_
7
8 #include <limits>
9 #include <map>
10
11 #include "base/logging.h"
12
13 namespace media {
14
15 // A RangeMap<KeyType, ValueType> is similar to a std::map<KeyType, ValueType>,
xhwang 2015/11/11 01:05:06 This comment really confused me. There's a fundame
hubbe 2015/11/11 01:29:23 Sure, but I had never heard of a step function bef
xhwang 2015/11/11 07:46:22 Agreed step function isn't super self explanatory.
16 // where incrementing, decrementing and setting ranges of values has been
17 // optimized. The default state for a rangemap is to map all values in
18 // KeyType to ValueType().
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, RangeMap<> 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 // RangeMap<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 // 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 {
58 public:
59 Range(const T& begin_, const T& end_) : begin(begin_), end(end_) {}
xhwang 2015/11/11 01:05:06 I don't think we use |begin_| for non-member varia
hubbe 2015/11/11 01:29:23 I'm pretty sure that results in an "variable used
xhwang 2015/11/11 07:46:22 It should work: http://stackoverflow.com/questions
hubbe 2015/11/12 06:57:43 Done.
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 Minmax = std::numeric_limits<KeyType>>
xhwang 2015/11/11 01:05:06 Minmax can be confusing given we have std::minmax.
hubbe 2015/11/11 01:29:23 I choose you, NumericLimits.
76 class RangeMapConstIterator {
77 public:
78 typedef std::map<KeyType, ValueType, Compare> MapType;
79 RangeMapConstIterator() {}
80 RangeMapConstIterator(const MapType* map,
81 typename MapType::const_iterator first,
82 typename MapType::const_iterator second)
83 : map_(map), first_(first), second_(second) {}
84
85 bool operator==(const RangeMapConstIterator& other) const {
86 return first_ == other.first_ && second_ == other.second_;
87 }
88
89 bool operator!=(const RangeMapConstIterator& other) const {
90 return first_ != other.first_ || second_ != other.second_;
91 }
92
93 // Returns the beginning of the current range.
94 KeyType range_begin() const {
95 if (first_ == map_->end()) {
96 return Minmax::min();
97 } else {
98 return first_->first;
99 }
100 }
101
102 // Returns the end of the current range, non-inclusive.
103 KeyType range_end() const {
104 if (second_ == map_->end()) {
105 return Minmax::max();
106 } else {
107 return second_->first;
108 }
109 }
110
111 // Returns the current range.
112 Range<KeyType> range() const {
113 return Range<KeyType>(range_begin(), range_end());
114 }
115
116 // Returns the value associated with the current range.
117 ValueType value() const {
118 if (first_ == map_->end())
119 return 0;
120 return first_->second;
121 }
122
123 // Needed to make the following construct work:
124 // for (const auto& range_value_pair : rangemap)
125 // Note however that this will skip the "end" range, which
126 // is usually ok since it generally has the default value.
127 std::pair<Range<KeyType>, ValueType> operator*() const {
128 return std::make_pair(range(), value());
129 }
130
131 // Go to the next range.
132 // The beginning of the next range always matches the end of the current
133 // range. (But should always have a different value.)
134 void operator++() {
xhwang 2015/11/11 01:05:06 Add a note that the range could be empty after thi
hubbe 2015/11/11 01:29:23 That shouldn't happen. (Unless you're doing someth
135 first_ = second_;
136 second_++;
137 }
138
139 // Go to the previous range.
140 void operator--() {
xhwang 2015/11/11 01:05:06 ditto
hubbe 2015/11/11 01:29:23 See comment above.
141 second_ = first_;
142 if (first_ == map_->begin()) {
143 first_ = map_->end();
144 } else {
145 first_--;
146 }
147 }
148
149 private:
150 const MapType* map_;
151
152 // Pointer to the entry in the RangeMap that specifies the
153 // beginning of the current range. (Or map_->end() if we are
154 // currently at the first range.)
155 typename MapType::const_iterator first_;
156
157 // Pointer to the entry in the RangeMap that specifies the
158 // end of the current range (non-inclusive) Or, it will
159 // point to map_->end() if we are currently at the last range.
160 // Note that if there are no entries in map_, both first_ and
161 // second_ will point to map_->end().
xhwang 2015/11/11 01:05:06 This could also happen when we are at the first r
hubbe 2015/11/11 01:29:23 Calling operator-- on the first range is not valid
162 typename MapType::const_iterator second_;
163 };
164
165 template <typename KeyType,
166 typename ValueType,
167 class Compare = std::less<KeyType>,
168 class Minmax = std::numeric_limits<KeyType>>
xhwang 2015/11/11 01:05:06 ditto
hubbe 2015/11/11 01:29:23 Done.
169 class RangeMap {
170 public:
171 typedef std::map<KeyType, ValueType, Compare> MapType;
172 typedef RangeMapConstIterator<KeyType, ValueType, Compare, Minmax>
173 const_iterator;
174
175 // Returns the value at a particular point.
176 // Defaults to ValueType().
177 ValueType operator[](const KeyType& k) const {
178 typename MapType::const_iterator i = map_.upper_bound(k);
179 if (i == map_.begin()) {
180 return 0;
181 } else {
182 --i;
183 return i->second;
184 }
185 }
186
187 // Increase [from..to) by |how_much|.
188 void IncrementRange(KeyType from, KeyType to, ValueType how_much) {
189 DCHECK_GE(to, from);
190 if (from == to || how_much == 0)
xhwang 2015/11/11 01:05:06 Why do we allow |from == to|?
hubbe 2015/11/11 01:29:23 No reason I suppose, I don't think I use that beha
191 return;
192 typename MapType::iterator a = MakeEntry(from);
193 typename MapType::iterator b = MakeEntry(to);
194 for (typename MapType::iterator i = a; i != b; ++i) {
195 i->second += how_much;
196 }
197 RemoveDuplicates(a);
198 // b may be invalid
199 RemoveDuplicates(map_.lower_bound(to));
200 }
201
202 // Set [from..to) to |how_much|.
203 void SetRange(KeyType from, KeyType to, ValueType how_much) {
204 DCHECK_GE(to, from);
205 if (from == to)
xhwang 2015/11/11 01:05:06 Why do we allow this?
hubbe 2015/11/11 01:29:23 See comment above.
206 return;
207 typename MapType::iterator a = MakeEntry(from);
208 typename MapType::iterator b = MakeEntry(to);
209 a->second = how_much;
210 while (true) {
211 typename MapType::iterator c = a;
212 ++c;
213 if (c == b) {
214 break;
215 } else {
216 map_.erase(c);
217 }
218 }
219 RemoveDuplicates(a);
220 // b may be invalid
221 RemoveDuplicates(map_.lower_bound(to));
222 }
223
224 // Returns an iterator to the first range.
225 // Note, there is always at least one range.
226 const_iterator begin() const {
227 return const_iterator(&map(), map_.end(), map_.begin());
228 }
229
230 // Returns an iterator to the last range.
231 // Note that this works slightly different than most containers
232 // as end() returns a valid, but mostly uninteresting iterator.
233 // For example, if you have you do:
234 // RangeMap<int, int> tmp;
235 // tmp.IncrementRange(-5, 5, 1);
236 // Then end will return the range [6, maxint) with a value of 0.
237 const_iterator end() const {
238 if (map_.empty()) {
239 return const_iterator(&map(), map_.end(), map_.end());
240 }
241 typename MapType::const_iterator i = map_.end();
242 --i;
243 return const_iterator(&map(), i, map_.end());
244 }
245
246 // Returns an iterator to the range containing |k|.
247 // Always returns a valid iterator.
248 const_iterator find(KeyType k) const {
249 if (map_.empty()) {
250 return const_iterator(&map(), map_.end(), map_.end());
251 }
252 typename MapType::const_iterator i = map_.upper_bound(k);
253 typename MapType::const_iterator j = i;
254 if (j == map_.begin()) {
255 j = map_.end();
256 } else {
257 --j;
258 }
259 return const_iterator(&map(), j, i);
260 }
261
262 private:
263 const MapType& map() const { return map_; }
264
265 // Make an entry in map_ with the key |k| and return it's iterator.
266 // If such an entry already exists, just re-use it.
267 // If a new entry is created, it's value will be set to the same
268 // as the preceeding entry, or ValueType() if no preceeding entry exists.
269 // After calling this function, we'll need to call RemoveDuplicates()
270 // to clean up any duplicates that we made.
271 typename MapType::iterator MakeEntry(KeyType k) {
272 typename MapType::value_type tmp(k, 0);
273 std::pair<typename MapType::iterator, bool> insert_result;
274 insert_result = map_.insert(tmp);
275 if (insert_result.second) {
276 if (insert_result.first != map_.begin()) {
277 typename MapType::iterator i = insert_result.first;
278 --i;
279 insert_result.first->second = i->second;
280 }
281 }
282 return insert_result.first;
283 }
284
285 // Remove duplicates before and after |i|.
286 void RemoveDuplicates(typename MapType::iterator i) {
287 if (i == map_.end())
288 return;
289 if (i == map_.begin() && i->second == 0) {
290 typename MapType::iterator j = i;
291 ++i;
292 map_.erase(j);
293 if (i == map_.end())
294 return;
295 }
296 if (i != map_.begin()) {
297 typename MapType::iterator j = i;
298 --i;
299 if (i->second == j->second) {
300 map_.erase(j);
301 }
302 }
303 typename MapType::iterator j = i;
304 ++j;
305 if (j != map_.end() && i->second == j->second) {
306 map_.erase(j);
307 }
308 }
309
310 MapType map_;
311 };
312
313 } // namespace media
314
315 #endif // MEDIA_BLINK_RANGE_MAP_H_
OLDNEW
« no previous file with comments | « media/blink/media_blink.gyp ('k') | media/blink/range_map_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698