source: cpp/frams/util/multirange.cpp

Last change on this file was 1130, checked in by Maciej Komosinski, 3 years ago

Used std::min(), std::max() explicitly to avoid compiler confusion. Used std::size() explicitly instead of the equivalent macro

  • Property svn:eol-style set to native
File size: 5.8 KB
RevLine 
[286]1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
[1130]2// Copyright (C) 1999-2021  Maciej Komosinski and Szymon Ulatowski.
[286]3// See LICENSE.txt for details.
[109]4
5#include "multirange.h"
[1130]6#include <algorithm>
[109]7
8#include <stdio.h>
9
10int IRange::operator==(const IRange& r)
11{
[733]12        if (isEmpty() && r.isEmpty()) return 1;
13        return (begin == r.begin) && (end == r.end);
[109]14}
15
16void IRange::intersect(const IRange& r)
17{
[733]18        if (r.begin > begin) begin = r.begin;
19        if (r.end < end) end = r.end;
[109]20}
21void IRange::add(const IRange& r)
22{
[733]23        if (r.begin < begin) begin = r.begin;
24        if (r.end > end) end = r.end;
[109]25}
26
27void IRange::print() const
28{
[733]29        if (begin == end) printf("[%d]", begin);
30        else printf("[%d-%d]", begin, end);
[109]31}
32
33////////////////////////////////////////
34
35void MultiRange::print() const
36{
[733]37        printf("[");
38        for (int i = 0; i < data.size(); i += 2)
[109]39        {
[733]40                int b = getData(i);
41                int e = getData(i + 1);
42                if (i) printf(",");
43                if (b == e) printf("%d", b);
44                else printf("%d-%d", b, e);
[109]45        }
[733]46        printf("]");
[109]47}
48
49void MultiRange::print2() const
50{
[733]51        const IRange& r = singleRange();
52        for (int i = 0; i <= r.end; i++)
53                printf(contains(i) ? "X" : ".");
[109]54}
55
56void MultiRange::shift(int delta)
57{
[733]58        for (int i = 0; i<data.size(); i++)
59                data.get(i) += delta;
[109]60}
61
62int MultiRange::findRange(int x) const
63{
[733]64        if (isEmpty()) return -1;
65        if (getData(0)>x) return -1;
66        int a, b, c;
67        int n = rangeCount() - 1;
68        a = 0; b = n; // find c = last range with begin<=x
69        while (1){
70                c = (a + b + 1) / 2;
71                if (getBegin(c) <= x)
[109]72                {
[733]73                        if ((c == n) || (getBegin(c + 1) > x)) return c;
74                        a = c;
[109]75                }
[733]76                else
[109]77                {
[733]78                        b = c - 1;
[109]79                }
80        }
81}
82
[733]83void MultiRange::addRange(int i, int b, int e)
[109]84{
[733]85        data.insert(2 * i, b);
86        data.insert(2 * i + 1, e);
[109]87}
88
[733]89void MultiRange::removeRanges(int r1, int r2)
[109]90{
[733]91        //data.remove(2*r1,(r2-r1)*2+2);
92        for (; r2 >= r1; r2--)
93                removeRange(r2);
[109]94}
95
96void MultiRange::removeRange(int i)
97{
[733]98        data.remove(2 * i, 2);
[109]99}
100
101void MultiRange::clear()
[733]102{
103        data.clear();
104}
[109]105
106int MultiRange::isEmpty() const
107{
[733]108        return rangeCount() == 0;
[109]109}
110
111IRange MultiRange::singleRange() const
112{
[733]113        if (isEmpty()) return IRange();
114        int b = getData(0);
115        int e = getData(data.size() - 1);
116        return IRange(b, e);
[109]117}
118
119int MultiRange::rangeCount() const
120{
[733]121        return data.size() / 2;
[109]122}
123
124IRange MultiRange::getRange(int i) const
125{
[733]126        if ((i < 0) || (i >= rangeCount())) return IRange();
127        return IRange(getData(2 * i), getData(2 * i + 1));
[109]128}
129
130void MultiRange::remove(int begin, int end)
131{
[733]132        if (end < begin) return; // NOP
133        int count = rangeCount();
134        if (!count) return;
135        int r1 = findRange(begin);
136        int r2 = findRange(end);
137        if (r2<0) return; // NOP
138        if (r1 == r2)
[109]139        {
[733]140                int e = getEnd(r1);
141                int b = getBegin(r1);
142                if (begin <= e)
[109]143                {
[733]144                        if (end >= e)
[109]145                        {
[733]146                                if (begin>b)
147                                        setEnd(r1, begin - 1);
148                                else
149                                        removeRange(r1);
150                        }
[109]151                        else
152                        {
[733]153                                if (begin > b)
[109]154                                { //split
[733]155                                        addRange(r1 + 1, end + 1, e);
156                                        setEnd(r1, begin - 1);
[109]157                                }
[733]158                                else
[109]159                                {
[733]160                                        setBegin(r1, end + 1);
[109]161                                }
162                        }
163                }
164        }
[733]165        else
[109]166        {
[733]167                if (r1 >= 0)
[109]168                {
[733]169                        int e1 = getEnd(r1);
170                        int b1 = getBegin(r1);
171                        if (begin <= e1)
[109]172                        {
[733]173                                if (begin == b1)
[109]174                                {
[733]175                                        removeRange(r1);
176                                        r2--;
177                                        r1--;
[109]178                                }
[733]179                                else
[109]180                                {
[733]181                                        setEnd(r1, begin - 1);
[109]182                                }
183                        }
184                }
[733]185                int e2 = getEnd(r2);
186                if (end < e2)
[109]187                {
[733]188                        setBegin(r2, end + 1);
189                        removeRanges(r1 + 1, r2 - 1);
[109]190                }
[733]191                else
[109]192                {
[733]193                        removeRanges(r1 + 1, r2);
[109]194                }
195        }
196}
197
198void MultiRange::add(int begin, int end)
199{
[733]200        if (end < begin) return; // NOP
201        int count = rangeCount();
202        int last = count - 1;
203        int r1 = findRange(begin);
204        int r2 = findRange(end);
205        if (r2 < 0) // special case: before first range
[109]206        {
[733]207                if (count && (getData(0) == (end + 1)))
208                        setData(0, begin);
209                else
210                        addRange(0, begin, end);
211                return;
[109]212        }
[733]213        if (r1 < 0) // special case: begin is before first range
[109]214        {
[733]215                setData(0, begin);
216                r1 = 0;
[109]217        }
[733]218        // now r1>=0 and r2>=0
219        int joinbegin = (begin <= (getEnd(r1) + 1));
220        int joinend = (r2 < last) && (end >= (getBegin(r2 + 1) - 1));
221        const int SAME = 1;
222        const int JOINBEGIN = 2;
223        const int JOINEND = 4;
224        int action = ((r1 == r2) ? SAME : 0) + (joinbegin ? JOINBEGIN : 0) + (joinend ? JOINEND : 0);
225        switch (action)
[109]226        {
[733]227        case SAME + JOINBEGIN + JOINEND: // remove 1 range
228                setEnd(r1, getEnd(r1 + 1));
229                removeRange(r1 + 1);
[109]230                break;
[733]231        case SAME + JOINBEGIN: // extend 1 range
[1130]232                setEnd(r1, std::max(getEnd(r2), end));
[109]233                break;
[733]234        case SAME + JOINEND: // extend 1 range
235                setBegin(r1 + 1, begin);
[109]236                break;
237        case SAME: // add 1 range
[733]238                addRange(r1 + 1, begin, end);
[109]239                break;
240
[733]241        case JOINBEGIN + JOINEND: // extend r2+1
242                setBegin(r2 + 1, getBegin(r1));
243                removeRanges(r1, r2);
[109]244                break;
245        case JOINBEGIN: // extend r1
[1130]246                setEnd(r1, std::max(end, getEnd(r2)));
[733]247                removeRanges(r1 + 1, r2);
[109]248                break;
249        case JOINEND: // extend r2+1
[733]250                setBegin(r2 + 1, begin);
251                removeRanges(r1 + 1, r2);
[109]252                break;
253        case 0: // extend r2
[733]254                setBegin(r2, begin);
[1130]255                setEnd(r2, std::max(end, getEnd(r2)));
[733]256                removeRanges(r1 + 1, r2 - 1);
[109]257                break;
258        }
259}
260
261void MultiRange::remove(const MultiRange &mr)
262{
[733]263        for (int i = 0; i < mr.rangeCount(); i++)
[109]264        {
[733]265                IRange r = mr.getRange(i);
266                remove(r);
[109]267        }
268}
269
270void MultiRange::add(const MultiRange &mr)
271{
[733]272        for (int i = 0; i < mr.rangeCount(); i++)
[109]273        {
[733]274                IRange r = mr.getRange(i);
275                add(r);
[109]276        }
277}
278
279void MultiRange::intersect(const MultiRange &mr)
280{
[733]281        // = this - (1-mr)
282        MultiRange full(singleRange());
283        full.remove(mr);
284        remove(full);
[109]285}
286
287int MultiRange::contains(const MultiRange &mr) const
288{
[733]289        for (int i = 0; i < mr.rangeCount(); i++)
[109]290        {
[733]291                IRange r = mr.getRange(i);
292                if (!contains(r)) return 0;
[109]293        }
[733]294        return 1;
[109]295}
296
297int MultiRange::contains(int x) const
298{
[733]299        int r = findRange(x);
300        if (r < 0) return 0;
301        return getEnd(r) >= x;
[109]302}
303
304int MultiRange::contains(const IRange& r) const
305{
[733]306        if (r.isEmpty()) return 0;
307        int r1 = findRange(r.begin);
308        if (r1 < 0) return 0;
309        return getRange(r1).contains(r);
[109]310}
311
312void MultiRange::intersect(int begin, int end)
313{
[733]314        if (isEmpty()) return;
315        if (end < begin) { clear(); return; }
316        IRange sr = singleRange();
317        remove(sr.begin, begin - 1);
318        remove(end + 1, sr.end);
[109]319}
Note: See TracBrowser for help on using the repository browser.