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_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_ | |
OLD | NEW |