OLD | NEW |
---|---|
(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>, | |
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_) {} | |
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 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 NumericLimits::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 NumericLimits::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 // Not allowed if we're already at map_->end(). | |
135 void operator++() { | |
136 DCHECK(second_ != map_->end()); | |
137 first_ = second_; | |
138 second_++; | |
139 } | |
140 | |
141 // Go to the previous range. | |
142 // The end of the previous range always matches the beginning of the current | |
143 // range. (But should always have a different value.) | |
144 // Not allowed if we're already at map_->begin(). | |
145 void operator--() { | |
146 DCHECK(first_ != map_->end()); | |
147 second_ = first_; | |
148 if (first_ == map_->begin()) { | |
149 first_ = map_->end(); | |
150 } else { | |
151 first_--; | |
152 } | |
153 } | |
154 | |
155 private: | |
156 const MapType* map_; | |
157 | |
158 // Pointer to the entry in the RangeMap that specifies the | |
159 // beginning of the current range. (Or map_->end() if we are | |
160 // currently at the first range.) | |
161 typename MapType::const_iterator first_; | |
162 | |
163 // Pointer to the entry in the RangeMap that specifies the | |
164 // end of the current range (non-inclusive) Or, it will | |
165 // point to map_->end() if we are currently at the last range. | |
166 // Note that if there are no entries in map_, both first_ and | |
167 // second_ will point to map_->end(). | |
168 typename MapType::const_iterator second_; | |
169 }; | |
170 | |
171 template <typename KeyType, | |
172 typename ValueType, | |
173 class Compare = std::less<KeyType>, | |
174 class NumericLimits = std::numeric_limits<KeyType>> | |
175 class RangeMap { | |
176 public: | |
177 typedef std::map<KeyType, ValueType, Compare> MapType; | |
178 typedef RangeMapConstIterator<KeyType, ValueType, Compare, NumericLimits> | |
179 const_iterator; | |
xhwang
2015/11/11 07:46:22
nit: How about typedef MapType::iterator and MapTy
hubbe
2015/11/12 06:57:44
It seems like it would hurt readability proportion
| |
180 | |
181 // Returns the value at a particular point. | |
182 // Defaults to ValueType(). | |
183 ValueType operator[](const KeyType& k) const { | |
184 typename MapType::const_iterator i = map_.upper_bound(k); | |
185 if (i == map_.begin()) { | |
186 return 0; | |
187 } else { | |
188 --i; | |
189 return i->second; | |
190 } | |
191 } | |
192 | |
193 // Increase [from..to) by |how_much|. | |
194 void IncrementRange(KeyType from, KeyType to, ValueType how_much) { | |
195 DCHECK_GT(to, from); | |
196 if (how_much == 0) | |
197 return; | |
198 typename MapType::iterator a = MakeEntry(from); | |
199 typename MapType::iterator b = MakeEntry(to); | |
200 for (typename MapType::iterator i = a; i != b; ++i) { | |
201 i->second += how_much; | |
202 } | |
203 RemoveDuplicates(a); | |
204 // b may be invalid | |
205 RemoveDuplicates(map_.lower_bound(to)); | |
206 } | |
207 | |
208 // Set [from..to) to |how_much|. | |
209 void SetRange(KeyType from, KeyType to, ValueType how_much) { | |
210 DCHECK_GT(to, from); | |
211 typename MapType::iterator a = MakeEntry(from); | |
212 typename MapType::iterator b = MakeEntry(to); | |
213 a->second = how_much; | |
214 while (true) { | |
215 typename MapType::iterator c = a; | |
216 ++c; | |
217 if (c == b) { | |
218 break; | |
219 } else { | |
220 map_.erase(c); | |
221 } | |
222 } | |
223 RemoveDuplicates(a); | |
224 // b may be invalid | |
225 RemoveDuplicates(map_.lower_bound(to)); | |
226 } | |
227 | |
228 // Returns an iterator to the first range. | |
229 // Note, there is always at least one range. | |
230 const_iterator begin() const { | |
231 return const_iterator(&map(), map_.end(), map_.begin()); | |
232 } | |
233 | |
234 // Returns an iterator to the last range. | |
235 // Note that this works slightly different than most containers | |
236 // as end() returns a valid, but mostly uninteresting iterator. | |
xhwang
2015/11/11 07:46:22
This seems a bit counter-intuitive. I don't know h
hubbe
2015/11/12 06:57:44
Should be more intuitive now.
Adding an explicit e
| |
237 // For example, if you have you do: | |
238 // RangeMap<int, int> tmp; | |
239 // tmp.IncrementRange(-5, 5, 1); | |
240 // Then end will return the range [6, maxint) with a value of 0. | |
241 const_iterator end() const { | |
242 if (map_.empty()) { | |
243 return const_iterator(&map(), map_.end(), map_.end()); | |
244 } | |
245 typename MapType::const_iterator i = map_.end(); | |
246 --i; | |
247 return const_iterator(&map(), i, map_.end()); | |
248 } | |
249 | |
250 // Returns an iterator to the range containing |k|. | |
251 // Always returns a valid iterator. | |
252 const_iterator find(KeyType k) const { | |
253 if (map_.empty()) { | |
254 return const_iterator(&map(), map_.end(), map_.end()); | |
255 } | |
256 typename MapType::const_iterator i = map_.upper_bound(k); | |
257 typename MapType::const_iterator j = i; | |
xhwang
2015/11/11 07:46:22
nit: replace i, j with second, first to match what
hubbe
2015/11/12 06:57:43
Good idea, done.
| |
258 if (j == map_.begin()) { | |
259 j = map_.end(); | |
260 } else { | |
261 --j; | |
262 } | |
263 return const_iterator(&map(), j, i); | |
264 } | |
265 | |
266 private: | |
267 const MapType& map() const { return map_; } | |
268 | |
269 // Make an entry in map_ with the key |k| and return it's iterator. | |
270 // If such an entry already exists, just re-use it. | |
271 // If a new entry is created, it's value will be set to the same | |
272 // as the preceeding entry, or ValueType() if no preceeding entry exists. | |
273 // After calling this function, we'll need to call RemoveDuplicates() | |
274 // to clean up any duplicates that we made. | |
275 typename MapType::iterator MakeEntry(KeyType k) { | |
276 typename MapType::value_type tmp(k, 0); | |
277 std::pair<typename MapType::iterator, bool> insert_result; | |
278 insert_result = map_.insert(tmp); | |
279 if (insert_result.second) { | |
280 if (insert_result.first != map_.begin()) { | |
281 typename MapType::iterator i = insert_result.first; | |
282 --i; | |
283 insert_result.first->second = i->second; | |
284 } | |
285 } | |
286 return insert_result.first; | |
287 } | |
288 | |
289 // Remove duplicates before and after |i|. | |
290 void RemoveDuplicates(typename MapType::iterator i) { | |
291 if (i == map_.end()) | |
292 return; | |
293 if (i == map_.begin() && i->second == 0) { | |
294 typename MapType::iterator j = i; | |
295 ++i; | |
296 map_.erase(j); | |
297 if (i == map_.end()) | |
298 return; | |
299 } | |
300 if (i != map_.begin()) { | |
301 typename MapType::iterator j = i; | |
302 --i; | |
303 if (i->second == j->second) { | |
304 map_.erase(j); | |
305 } | |
306 } | |
307 typename MapType::iterator j = i; | |
308 ++j; | |
309 if (j != map_.end() && i->second == j->second) { | |
310 map_.erase(j); | |
311 } | |
312 } | |
313 | |
314 MapType map_; | |
315 }; | |
316 | |
317 } // namespace media | |
318 | |
319 #endif // MEDIA_BLINK_RANGE_MAP_H_ | |
OLD | NEW |