tools/reorder/interval_map.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial