tools/reorder/interval_map.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/tools/reorder/interval_map.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,326 @@
     1.4 +/* -*- Mode: C++ -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#ifndef interval_map_h__
    1.10 +#define interval_map_h__
    1.11 +
    1.12 +/*
    1.13 +
    1.14 +  A utility class that maps an interval to an object, allowing clients
    1.15 +  to look up the object by a point within the interval.
    1.16 +
    1.17 + */
    1.18 +
    1.19 +// TODO:
    1.20 +//   - removing intervals
    1.21 +//   - container iterators
    1.22 +
    1.23 +#include <fstream>
    1.24 +#include <assert.h>
    1.25 +
    1.26 +template<class coord, class T>
    1.27 +class interval_map {
    1.28 +protected:
    1.29 +    class const_iterator;
    1.30 +    friend class const_iterator;
    1.31 +
    1.32 +    struct node {
    1.33 +        T      m_data;
    1.34 +        coord  m_min;
    1.35 +        coord  m_max;
    1.36 +        node  *m_before; // intervals before this one
    1.37 +        node  *m_within; // intervals within this one
    1.38 +        node  *m_after;  // intervals after this one
    1.39 +        int    m_bal;
    1.40 +    };
    1.41 +
    1.42 +public:
    1.43 +    /**
    1.44 +     * A unidirectional const iterator that is used to enumerate the
    1.45 +     * intervals that overlap a specific point.
    1.46 +     */
    1.47 +    class const_iterator {
    1.48 +    protected:
    1.49 +        const node  *m_node;
    1.50 +        const coord  m_point;
    1.51 +
    1.52 +        friend class interval_map;
    1.53 +        const_iterator(const node *n, const coord &point)
    1.54 +            : m_node(n), m_point(point) {}
    1.55 +
    1.56 +        void advance();
    1.57 +
    1.58 +    public:
    1.59 +        const_iterator() : m_node(0), m_point(0) {}
    1.60 +
    1.61 +        const_iterator(const const_iterator &iter)
    1.62 +            : m_node(iter.m_node), m_point(iter.m_point) {}
    1.63 +
    1.64 +        const_iterator &
    1.65 +        operator=(const const_iterator &iter) {
    1.66 +            m_node = iter.m_node;
    1.67 +            m_point = iter.m_point; }
    1.68 +
    1.69 +        const T &
    1.70 +        operator*() const { return m_node->m_data; }
    1.71 +
    1.72 +        const T *
    1.73 +        operator->() const { return &m_node->m_data; }
    1.74 +
    1.75 +        const_iterator &
    1.76 +        operator++() { advance(); return *this; }
    1.77 +
    1.78 +        const_iterator
    1.79 +        operator++(int) {
    1.80 +            const_iterator temp(*this);
    1.81 +            advance();
    1.82 +            return temp; }
    1.83 +
    1.84 +        bool
    1.85 +        operator==(const const_iterator &iter) const {
    1.86 +            return m_node == iter.m_node; }
    1.87 +
    1.88 +        bool
    1.89 +        operator!=(const const_iterator &iter) const {
    1.90 +            return !iter.operator==(*this); }
    1.91 +    };
    1.92 +
    1.93 +    interval_map() : m_root(0) {}
    1.94 +
    1.95 +    ~interval_map() { delete m_root; }
    1.96 +
    1.97 +    /**
    1.98 +     * Insert aData for the interval [aMin, aMax]
    1.99 +     */
   1.100 +    void put(coord min, coord max, const T &data) {
   1.101 +        put_into(&m_root, min, max, data);
   1.102 +#ifdef DEBUG
   1.103 +        verify(m_root, 0);
   1.104 +#endif
   1.105 +    }
   1.106 +
   1.107 +
   1.108 +    /**
   1.109 +     * Return an iterator that will enumerate the data for all intervals
   1.110 +     * intersecting |aPoint|.
   1.111 +     */
   1.112 +    const_iterator get(coord point) const;
   1.113 +
   1.114 +    /**
   1.115 +     * Return an iterator that marks the end-point of iteration.
   1.116 +     */
   1.117 +    const_iterator end() const {
   1.118 +        return const_iterator(0, 0); }
   1.119 +
   1.120 +protected:
   1.121 +    void put_into(node **link, coord min, coord max, const T &data, bool *subsumed = 0);
   1.122 +
   1.123 +    void left_rotate(node **link, node *node);
   1.124 +    void right_rotate(node **link, node *node);
   1.125 +#ifdef DEBUG
   1.126 +    void verify(node *node, int depth);
   1.127 +#endif
   1.128 +    node *m_root;
   1.129 +};
   1.130 +
   1.131 +template<class coord, class T>
   1.132 +void
   1.133 +interval_map<coord, T>::put_into(node **root, coord min, coord max, const T &data, bool *subsumed)
   1.134 +{
   1.135 +    assert(min < max);
   1.136 +    node *interval = *root;
   1.137 +
   1.138 +    if (interval) {
   1.139 +        bool before = min < interval->m_min;
   1.140 +        bool after = max > interval->m_max;
   1.141 +
   1.142 +        if (!before || !after) {
   1.143 +            // The interval we're adding does not completely subsume
   1.144 +            // the |interval|. So we've got one of these situations:
   1.145 +            //
   1.146 +            //      |======|   |======|   |======|
   1.147 +            //   |------|        |--|        |------|
   1.148 +            //
   1.149 +            // where |==| is the existing interval, and |--| is the
   1.150 +            // new interval we're inserting. If there's left or right
   1.151 +            // slop, then we ``split'' the new interval in half:
   1.152 +            //
   1.153 +            //      |======|              |======|
   1.154 +            //   |--|---|                    |---|--|
   1.155 +            //
   1.156 +            // and insert it both in the ``within'' and ``before'' (or
   1.157 +            // ``after'') subtrees.
   1.158 +            //
   1.159 +            if (before) {
   1.160 +                if (max > interval->m_min) {
   1.161 +                    put_into(&interval->m_within, interval->m_min, max, data);
   1.162 +                    max = interval->m_min;
   1.163 +                }
   1.164 +
   1.165 +                bool was_subsumed = true;
   1.166 +                put_into(&interval->m_before, min, max, data, &was_subsumed);
   1.167 +
   1.168 +                if (! was_subsumed) {
   1.169 +                    if (interval->m_bal < 0) {
   1.170 +                        if (interval->m_before->m_bal > 0)
   1.171 +                            left_rotate(&interval->m_before, interval->m_before);
   1.172 +
   1.173 +                        right_rotate(root, interval);
   1.174 +                    }
   1.175 +                    else
   1.176 +                        --interval->m_bal;
   1.177 +
   1.178 +                    if (subsumed)
   1.179 +                        *subsumed = (interval->m_bal == 0);
   1.180 +                }
   1.181 +
   1.182 +                return;
   1.183 +            }
   1.184 +
   1.185 +            if (after) {
   1.186 +                if (min < interval->m_max) {
   1.187 +                    put_into(&interval->m_within, min, interval->m_max, data);
   1.188 +                    min = interval->m_max;
   1.189 +                }
   1.190 +
   1.191 +                bool was_subsumed = true;
   1.192 +                put_into(&interval->m_after, min, max, data, &was_subsumed);
   1.193 +
   1.194 +                if (! was_subsumed) {
   1.195 +                    if (interval->m_bal > 0) {
   1.196 +                        if (interval->m_after->m_bal < 0)
   1.197 +                            right_rotate(&interval->m_after, interval->m_after);
   1.198 +
   1.199 +                        left_rotate(root, interval);
   1.200 +                    }
   1.201 +                    else
   1.202 +                        ++interval->m_bal;
   1.203 +
   1.204 +                    if (subsumed)
   1.205 +                        *subsumed = (interval->m_bal == 0);
   1.206 +                }
   1.207 +
   1.208 +                return;
   1.209 +            }
   1.210 +
   1.211 +            put_into(&interval->m_within, min, max, data);
   1.212 +            return;
   1.213 +        }
   1.214 +
   1.215 +        // If we get here, the interval we're adding completely
   1.216 +        // subsumes |interval|. We'll go ahead and insert a new
   1.217 +        // interval immediately above |interval|, with |interval| as
   1.218 +        // the new interval's |m_within|.
   1.219 +    }
   1.220 +
   1.221 +    if (subsumed)
   1.222 +        *subsumed = false;
   1.223 +
   1.224 +    node *n = new node();
   1.225 +    n->m_data   = data;
   1.226 +    n->m_before = n->m_after = 0;
   1.227 +    n->m_min    = min;
   1.228 +    n->m_max    = max;
   1.229 +    n->m_within = interval;
   1.230 +    n->m_bal    = 0;
   1.231 +    *root = n;
   1.232 +}
   1.233 +
   1.234 +/*
   1.235 + *    (*link)                               (*link)
   1.236 + *       |         == left rotate ==>          |
   1.237 + *      (x)                                   (y)
   1.238 + *     /   \                                 /   \
   1.239 + *    a    (y)    <== right rotate ==      (x)    c
   1.240 + *        /   \                           /   \
   1.241 + *       b     c                         a     b
   1.242 + */
   1.243 +template<class coord, class T>
   1.244 +void
   1.245 +interval_map<coord, T>::left_rotate(node **link, node *x)
   1.246 +{
   1.247 +    node *y = x->m_after;
   1.248 +    x->m_after = y->m_before;
   1.249 +    *link = y;
   1.250 +    y->m_before = x;
   1.251 +    --x->m_bal;
   1.252 +    --y->m_bal;
   1.253 +}
   1.254 +
   1.255 +template<class coord, class T>
   1.256 +void
   1.257 +interval_map<coord, T>::right_rotate(node **link, node *y)
   1.258 +{
   1.259 +    node *x = y->m_before;
   1.260 +    y->m_before = x->m_after;
   1.261 +    *link = x;
   1.262 +    x->m_after = y;
   1.263 +    ++y->m_bal;
   1.264 +    ++x->m_bal;
   1.265 +}
   1.266 +
   1.267 +template<class coord, class T>
   1.268 +interval_map<coord, T>::const_iterator
   1.269 +interval_map<coord, T>::get(coord point) const
   1.270 +{
   1.271 +    node *interval = m_root;
   1.272 +
   1.273 +    while (interval) {
   1.274 +        if (point < interval->m_min)
   1.275 +            interval = interval->m_before;
   1.276 +        else if (point > interval->m_max)
   1.277 +            interval = interval->m_after;
   1.278 +        else
   1.279 +            break;
   1.280 +    }
   1.281 +
   1.282 +    return const_iterator(interval, point);
   1.283 +}
   1.284 +
   1.285 +
   1.286 +template<class coord, class T>
   1.287 +void
   1.288 +interval_map<coord, T>::const_iterator::advance()
   1.289 +{
   1.290 +    assert(m_node);
   1.291 +
   1.292 +    m_node = m_node->m_within;
   1.293 +
   1.294 +    while (m_node) {
   1.295 +        if (m_point < m_node->m_min)
   1.296 +            m_node = m_node->m_before;
   1.297 +        else if (m_point > m_node->m_max)
   1.298 +            m_node = m_node->m_after;
   1.299 +        else
   1.300 +            break;
   1.301 +    }
   1.302 +}
   1.303 +
   1.304 +#ifdef DEBUG
   1.305 +template<class coord, class T>
   1.306 +void
   1.307 +interval_map<coord, T>::verify(node<coord, T> *node, int depth)
   1.308 +{
   1.309 +    if (node->m_after)
   1.310 +        verify(node->m_after, depth + 1);
   1.311 +
   1.312 +    for (int i = 0; i < depth; ++i)
   1.313 +        cout << "  ";
   1.314 +
   1.315 +    hex(cout);
   1.316 +    cout << node << "(";
   1.317 +    dec(cout);
   1.318 +    cout << node->m_bal << ")";
   1.319 +    hex(cout);
   1.320 +    cout << "[" << node->m_min << "," << node->m_max << "]";
   1.321 +    cout << "@" << node->m_data;
   1.322 +    cout << endl;
   1.323 +
   1.324 +    if (node->m_before)
   1.325 +        verify(node->m_before, depth + 1);
   1.326 +}
   1.327 +#endif // DEBUG
   1.328 +
   1.329 +#endif // interval_map_h__

mercurial