1 /* -*- Mode: C++ -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is ``interval_map''
17 * The Initial Developer of the Original Code is Netscape
18 * Communications Corp. Portions created by the Initial Developer are
19 * Copyright (C) 2001 the Initial Developer. All Rights Reserved.
22 * Chris Waterson <waterson@netscape.com>
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #ifndef interval_map_h__
39 #define interval_map_h__
43 A utility class that maps an interval to an object, allowing clients
44 to look up the object by a point within the interval.
49 // - removing intervals
50 // - container iterators
55 template<class coord
, class T
>
59 friend class const_iterator
;
65 node
*m_before
; // intervals before this one
66 node
*m_within
; // intervals within this one
67 node
*m_after
; // intervals after this one
73 * A unidirectional const iterator that is used to enumerate the
74 * intervals that overlap a specific point.
76 class const_iterator
{
81 friend class interval_map
;
82 const_iterator(const node
*n
, const coord
&point
)
83 : m_node(n
), m_point(point
) {}
88 const_iterator() : m_node(0), m_point(0) {}
90 const_iterator(const const_iterator
&iter
)
91 : m_node(iter
.m_node
), m_point(iter
.m_point
) {}
94 operator=(const const_iterator
&iter
) {
96 m_point
= iter
.m_point
; }
99 operator*() const { return m_node
->m_data
; }
102 operator->() const { return &m_node
->m_data
; }
105 operator++() { advance(); return *this; }
109 const_iterator
temp(*this);
114 operator==(const const_iterator
&iter
) const {
115 return m_node
== iter
.m_node
; }
118 operator!=(const const_iterator
&iter
) const {
119 return !iter
.operator==(*this); }
122 interval_map() : m_root(0) {}
124 ~interval_map() { delete m_root
; }
127 * Insert aData for the interval [aMin, aMax]
129 void put(coord min
, coord max
, const T
&data
) {
130 put_into(&m_root
, min
, max
, data
);
138 * Return an iterator that will enumerate the data for all intervals
139 * intersecting |aPoint|.
141 const_iterator
get(coord point
) const;
144 * Return an iterator that marks the end-point of iteration.
146 const_iterator
end() const {
147 return const_iterator(0, 0); }
150 void put_into(node
**link
, coord min
, coord max
, const T
&data
, bool *subsumed
= 0);
152 void left_rotate(node
**link
, node
*node
);
153 void right_rotate(node
**link
, node
*node
);
155 void verify(node
*node
, int depth
);
160 template<class coord
, class T
>
162 interval_map
<coord
, T
>::put_into(node
**root
, coord min
, coord max
, const T
&data
, bool *subsumed
)
165 node
*interval
= *root
;
168 bool before
= min
< interval
->m_min
;
169 bool after
= max
> interval
->m_max
;
171 if (!before
|| !after
) {
172 // The interval we're adding does not completely subsume
173 // the |interval|. So we've got one of these situations:
175 // |======| |======| |======|
176 // |------| |--| |------|
178 // where |==| is the existing interval, and |--| is the
179 // new interval we're inserting. If there's left or right
180 // slop, then we ``split'' the new interval in half:
185 // and insert it both in the ``within'' and ``before'' (or
186 // ``after'') subtrees.
189 if (max
> interval
->m_min
) {
190 put_into(&interval
->m_within
, interval
->m_min
, max
, data
);
191 max
= interval
->m_min
;
194 bool was_subsumed
= true;
195 put_into(&interval
->m_before
, min
, max
, data
, &was_subsumed
);
197 if (! was_subsumed
) {
198 if (interval
->m_bal
< 0) {
199 if (interval
->m_before
->m_bal
> 0)
200 left_rotate(&interval
->m_before
, interval
->m_before
);
202 right_rotate(root
, interval
);
208 *subsumed
= (interval
->m_bal
== 0);
215 if (min
< interval
->m_max
) {
216 put_into(&interval
->m_within
, min
, interval
->m_max
, data
);
217 min
= interval
->m_max
;
220 bool was_subsumed
= true;
221 put_into(&interval
->m_after
, min
, max
, data
, &was_subsumed
);
223 if (! was_subsumed
) {
224 if (interval
->m_bal
> 0) {
225 if (interval
->m_after
->m_bal
< 0)
226 right_rotate(&interval
->m_after
, interval
->m_after
);
228 left_rotate(root
, interval
);
234 *subsumed
= (interval
->m_bal
== 0);
240 put_into(&interval
->m_within
, min
, max
, data
);
244 // If we get here, the interval we're adding completely
245 // subsumes |interval|. We'll go ahead and insert a new
246 // interval immediately above |interval|, with |interval| as
247 // the new interval's |m_within|.
253 node
*n
= new node();
255 n
->m_before
= n
->m_after
= 0;
258 n
->m_within
= interval
;
265 * | == left rotate ==> |
268 * a (y) <== right rotate == (x) c
272 template<class coord
, class T
>
274 interval_map
<coord
, T
>::left_rotate(node
**link
, node
*x
)
276 node
*y
= x
->m_after
;
277 x
->m_after
= y
->m_before
;
284 template<class coord
, class T
>
286 interval_map
<coord
, T
>::right_rotate(node
**link
, node
*y
)
288 node
*x
= y
->m_before
;
289 y
->m_before
= x
->m_after
;
296 template<class coord
, class T
>
297 interval_map
<coord
, T
>::const_iterator
298 interval_map
<coord
, T
>::get(coord point
) const
300 node
*interval
= m_root
;
303 if (point
< interval
->m_min
)
304 interval
= interval
->m_before
;
305 else if (point
> interval
->m_max
)
306 interval
= interval
->m_after
;
311 return const_iterator(interval
, point
);
315 template<class coord
, class T
>
317 interval_map
<coord
, T
>::const_iterator::advance()
321 m_node
= m_node
->m_within
;
324 if (m_point
< m_node
->m_min
)
325 m_node
= m_node
->m_before
;
326 else if (m_point
> m_node
->m_max
)
327 m_node
= m_node
->m_after
;
334 template<class coord
, class T
>
336 interval_map
<coord
, T
>::verify(node
<coord
, T
> *node
, int depth
)
339 verify(node
->m_after
, depth
+ 1);
341 for (int i
= 0; i
< depth
; ++i
)
347 cout
<< node
->m_bal
<< ")";
349 cout
<< "[" << node
->m_min
<< "," << node
->m_max
<< "]";
350 cout
<< "@" << node
->m_data
;
354 verify(node
->m_before
, depth
+ 1);
358 #endif // interval_map_h__