Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++ -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef interval_map_h__
7 #define interval_map_h__
9 /*
11 A utility class that maps an interval to an object, allowing clients
12 to look up the object by a point within the interval.
14 */
16 // TODO:
17 // - removing intervals
18 // - container iterators
20 #include <fstream>
21 #include <assert.h>
23 template<class coord, class T>
24 class interval_map {
25 protected:
26 class const_iterator;
27 friend class const_iterator;
29 struct node {
30 T m_data;
31 coord m_min;
32 coord m_max;
33 node *m_before; // intervals before this one
34 node *m_within; // intervals within this one
35 node *m_after; // intervals after this one
36 int m_bal;
37 };
39 public:
40 /**
41 * A unidirectional const iterator that is used to enumerate the
42 * intervals that overlap a specific point.
43 */
44 class const_iterator {
45 protected:
46 const node *m_node;
47 const coord m_point;
49 friend class interval_map;
50 const_iterator(const node *n, const coord &point)
51 : m_node(n), m_point(point) {}
53 void advance();
55 public:
56 const_iterator() : m_node(0), m_point(0) {}
58 const_iterator(const const_iterator &iter)
59 : m_node(iter.m_node), m_point(iter.m_point) {}
61 const_iterator &
62 operator=(const const_iterator &iter) {
63 m_node = iter.m_node;
64 m_point = iter.m_point; }
66 const T &
67 operator*() const { return m_node->m_data; }
69 const T *
70 operator->() const { return &m_node->m_data; }
72 const_iterator &
73 operator++() { advance(); return *this; }
75 const_iterator
76 operator++(int) {
77 const_iterator temp(*this);
78 advance();
79 return temp; }
81 bool
82 operator==(const const_iterator &iter) const {
83 return m_node == iter.m_node; }
85 bool
86 operator!=(const const_iterator &iter) const {
87 return !iter.operator==(*this); }
88 };
90 interval_map() : m_root(0) {}
92 ~interval_map() { delete m_root; }
94 /**
95 * Insert aData for the interval [aMin, aMax]
96 */
97 void put(coord min, coord max, const T &data) {
98 put_into(&m_root, min, max, data);
99 #ifdef DEBUG
100 verify(m_root, 0);
101 #endif
102 }
105 /**
106 * Return an iterator that will enumerate the data for all intervals
107 * intersecting |aPoint|.
108 */
109 const_iterator get(coord point) const;
111 /**
112 * Return an iterator that marks the end-point of iteration.
113 */
114 const_iterator end() const {
115 return const_iterator(0, 0); }
117 protected:
118 void put_into(node **link, coord min, coord max, const T &data, bool *subsumed = 0);
120 void left_rotate(node **link, node *node);
121 void right_rotate(node **link, node *node);
122 #ifdef DEBUG
123 void verify(node *node, int depth);
124 #endif
125 node *m_root;
126 };
128 template<class coord, class T>
129 void
130 interval_map<coord, T>::put_into(node **root, coord min, coord max, const T &data, bool *subsumed)
131 {
132 assert(min < max);
133 node *interval = *root;
135 if (interval) {
136 bool before = min < interval->m_min;
137 bool after = max > interval->m_max;
139 if (!before || !after) {
140 // The interval we're adding does not completely subsume
141 // the |interval|. So we've got one of these situations:
142 //
143 // |======| |======| |======|
144 // |------| |--| |------|
145 //
146 // where |==| is the existing interval, and |--| is the
147 // new interval we're inserting. If there's left or right
148 // slop, then we ``split'' the new interval in half:
149 //
150 // |======| |======|
151 // |--|---| |---|--|
152 //
153 // and insert it both in the ``within'' and ``before'' (or
154 // ``after'') subtrees.
155 //
156 if (before) {
157 if (max > interval->m_min) {
158 put_into(&interval->m_within, interval->m_min, max, data);
159 max = interval->m_min;
160 }
162 bool was_subsumed = true;
163 put_into(&interval->m_before, min, max, data, &was_subsumed);
165 if (! was_subsumed) {
166 if (interval->m_bal < 0) {
167 if (interval->m_before->m_bal > 0)
168 left_rotate(&interval->m_before, interval->m_before);
170 right_rotate(root, interval);
171 }
172 else
173 --interval->m_bal;
175 if (subsumed)
176 *subsumed = (interval->m_bal == 0);
177 }
179 return;
180 }
182 if (after) {
183 if (min < interval->m_max) {
184 put_into(&interval->m_within, min, interval->m_max, data);
185 min = interval->m_max;
186 }
188 bool was_subsumed = true;
189 put_into(&interval->m_after, min, max, data, &was_subsumed);
191 if (! was_subsumed) {
192 if (interval->m_bal > 0) {
193 if (interval->m_after->m_bal < 0)
194 right_rotate(&interval->m_after, interval->m_after);
196 left_rotate(root, interval);
197 }
198 else
199 ++interval->m_bal;
201 if (subsumed)
202 *subsumed = (interval->m_bal == 0);
203 }
205 return;
206 }
208 put_into(&interval->m_within, min, max, data);
209 return;
210 }
212 // If we get here, the interval we're adding completely
213 // subsumes |interval|. We'll go ahead and insert a new
214 // interval immediately above |interval|, with |interval| as
215 // the new interval's |m_within|.
216 }
218 if (subsumed)
219 *subsumed = false;
221 node *n = new node();
222 n->m_data = data;
223 n->m_before = n->m_after = 0;
224 n->m_min = min;
225 n->m_max = max;
226 n->m_within = interval;
227 n->m_bal = 0;
228 *root = n;
229 }
231 /*
232 * (*link) (*link)
233 * | == left rotate ==> |
234 * (x) (y)
235 * / \ / \
236 * a (y) <== right rotate == (x) c
237 * / \ / \
238 * b c a b
239 */
240 template<class coord, class T>
241 void
242 interval_map<coord, T>::left_rotate(node **link, node *x)
243 {
244 node *y = x->m_after;
245 x->m_after = y->m_before;
246 *link = y;
247 y->m_before = x;
248 --x->m_bal;
249 --y->m_bal;
250 }
252 template<class coord, class T>
253 void
254 interval_map<coord, T>::right_rotate(node **link, node *y)
255 {
256 node *x = y->m_before;
257 y->m_before = x->m_after;
258 *link = x;
259 x->m_after = y;
260 ++y->m_bal;
261 ++x->m_bal;
262 }
264 template<class coord, class T>
265 interval_map<coord, T>::const_iterator
266 interval_map<coord, T>::get(coord point) const
267 {
268 node *interval = m_root;
270 while (interval) {
271 if (point < interval->m_min)
272 interval = interval->m_before;
273 else if (point > interval->m_max)
274 interval = interval->m_after;
275 else
276 break;
277 }
279 return const_iterator(interval, point);
280 }
283 template<class coord, class T>
284 void
285 interval_map<coord, T>::const_iterator::advance()
286 {
287 assert(m_node);
289 m_node = m_node->m_within;
291 while (m_node) {
292 if (m_point < m_node->m_min)
293 m_node = m_node->m_before;
294 else if (m_point > m_node->m_max)
295 m_node = m_node->m_after;
296 else
297 break;
298 }
299 }
301 #ifdef DEBUG
302 template<class coord, class T>
303 void
304 interval_map<coord, T>::verify(node<coord, T> *node, int depth)
305 {
306 if (node->m_after)
307 verify(node->m_after, depth + 1);
309 for (int i = 0; i < depth; ++i)
310 cout << " ";
312 hex(cout);
313 cout << node << "(";
314 dec(cout);
315 cout << node->m_bal << ")";
316 hex(cout);
317 cout << "[" << node->m_min << "," << node->m_max << "]";
318 cout << "@" << node->m_data;
319 cout << endl;
321 if (node->m_before)
322 verify(node->m_before, depth + 1);
323 }
324 #endif // DEBUG
326 #endif // interval_map_h__