]> git.saurik.com Git - apple/system_cmds.git/blame - CPPUtil/UtilTRange.hpp
system_cmds-671.10.3.tar.gz
[apple/system_cmds.git] / CPPUtil / UtilTRange.hpp
CommitLineData
bd6521f0
A
1//
2// UtilTRange.hpp
3// CPPUtil
4//
5// Created by James McIlree on 4/14/13.
6// Copyright (c) 2013 Apple. All rights reserved.
7//
8
9#ifndef CPPUtil_UtilTRange_hpp
10#define CPPUtil_UtilTRange_hpp
11
12template <typename T>
13class TRange {
14 protected:
15 T _location;
16 T _length;
17
18 public:
19 TRange() : _location(0), _length(0) {}
20 TRange(T location, T length) : _location(location), _length(length) {
21 DEBUG_ONLY(validate());
22 };
23
24 bool operator==(const TRange &rhs) const { return this->_location == rhs.location() && this->_length == rhs.length(); }
25
26 bool operator!=(const TRange &rhs) const { return !(*this == rhs); }
27
28 bool operator<(const TRange& rhs) const { return this->_location < rhs.location(); }
29 bool operator<(const TRange* rhs) const { return this->_location < rhs->location(); }
30
31 const T location() const { return _location; }
32 const T length() const { return _length; }
33 const T max() const { return _location + _length; }
34
35 void set_location(T location) { _location = location; DEBUG_ONLY(validate()); }
36 void set_length(T length) { _length = length; DEBUG_ONLY(validate()); }
37 void set_max(T max) { ASSERT(max >= _location, "Sanity"); _length = max - _location; }
38
39 const bool contains(const TRange& other) const { return (other.location() >= location()) && (other.max() <= max()); }
40 const bool contains(const T loc) const { return loc - _location < _length; } // Assumes unsigned!
41
42 const bool intersects(const TRange& o) const { return this->location() < o.max() && o.location() < this->max(); }
43
44 // "union" is a keyword :-(
45 TRange union_range(const TRange& other) const {
46 T maxend = (this->max() > other.max()) ? this->max() : other.max();
47 T minloc = this->location() < other.location() ? this->location() : other.location();
48 return TRange(minloc, maxend - minloc);
49 }
50
51 TRange intersection_range(const TRange& other) const {
52 if (this->intersects(other)) {
53 auto intersection_start = std::max(_location, other.location());
54 auto intersection_end = std::min(max(), other.max());
55 return TRange(intersection_start, intersection_end - intersection_start);
56 }
57
58 return TRange(T(0),T(0));
59 }
60
61 void validate() const { ASSERT((_location + _length >= _location) /*|| (_location + 1 == 0)*/, "range must not wrap"); }
62};
63
64template <typename TRANGE>
65bool is_trange_vector_sorted_and_non_overlapping(const std::vector<TRANGE>& vec) {
66 if (vec.size() > 1) {
67 auto last_it = vec.begin();
68 auto it = last_it + 1;
69
70 while (it < vec.end()) {
71 if (it < last_it)
72 return false;
73
74 if (last_it->intersects(*it))
75 return false;
76
77 last_it = it;
78 it++;
79 }
80 }
81 return true;
82}
83
84template <typename TRANGE>
85bool is_trange_vector_sorted(const std::vector<TRANGE>& vec) {
86 if (vec.size() > 1) {
87 auto last_it = vec.begin();
88 auto it = last_it + 1;
89
90 while (it < vec.end()) {
91 if (it < last_it)
92 return false;
93
94 last_it = it;
95 it++;
96 }
97 }
98 return true;
99}
100
101// NOTE!
102//
103// This produces an output vector with the
104// intervals "flattened".
105//
106// IOW, this:
107//
108// vec1: XXXXXXXX AAAAAAAAAA
109// YYYYYYYYYYY ZZZZZZZZZ
110//
111// becomes:
112//
113// res: IIIIIIIIIIII IIIIIIIIIIII
114//
115// The input vector should be sorted.
116//
117template <typename TRANGE>
118std::vector<TRANGE> trange_vector_union(std::vector<TRANGE>& input) {
119 std::vector<TRANGE> union_vec;
120
121 ASSERT(is_trange_vector_sorted(input), "Sanity");
122
123 if (!input.empty()) {
124 auto input_it = input.begin();
125 union_vec.push_back(*input_it);
126 while (++input_it < input.end()) {
127 TRANGE union_range = union_vec.back();
128
129 if (union_range.intersects(*input_it)) {
130 union_vec.pop_back();
131 union_vec.push_back(union_range.union_range(*input_it));
132 } else {
133 ASSERT(union_range < *input_it, "Out of order merging");
134 union_vec.push_back(*input_it);
135 }
136 }
137 }
138
139 ASSERT(is_trange_vector_sorted_and_non_overlapping(union_vec), "union'd vector fails invariant");
140
141 return union_vec;
142}
143
144// NOTE!
145//
146// This will coalesce intervals that intersect.
147//
148// IOW, given two input vectors:
149//
150// vec1: XXXX XXXX
151// vec2: XXX
152//
153// res: XXXX XXX XXXX
154//
155// --------------------------------
156//
157// vec1: XXXX XX
158// vec2: XXXXXXXXXXXXXXX
159//
160// res: XXXXXXXXXXXXXXXXX
161
162template <typename TRANGE>
163std::vector<TRANGE> trange_vector_union(std::vector<TRANGE>& vec1, std::vector<TRANGE>& vec2) {
164 std::vector<TRANGE> union_vec;
165
166 ASSERT(is_trange_vector_sorted_and_non_overlapping(vec1), "input vector violates invariants");
167 ASSERT(is_trange_vector_sorted_and_non_overlapping(vec2), "input vector violates invariants");
168
169 // while (not done)
170 // select next interval (lowest location)
171 // if intersects with last union_vec entry, union, pop_back, push_back
172 // else push_back
173
174 auto vec1_it = vec1.begin();
175 auto vec2_it = vec2.begin();
176
177 while (uint32_t chose_vector = (((vec1_it != vec1.end()) ? 1 : 0) + ((vec2_it != vec2.end()) ? 2 : 0))) {
178 //
179 // This is a fancy "chose" algorithm
180 //
181 // vec1 == bit 1
182 // vec2 == bit 2
183 //
184 decltype(vec1_it) merge_it;
185 switch (chose_vector) {
186 case 1:
187 merge_it = vec1_it++;
188 break;
189
190 case 2:
191 merge_it = vec2_it++;
192 break;
193
194 case 3:
195 merge_it = (*vec1_it < * vec2_it) ? vec1_it++ : vec2_it++;
196 break;
197
198 default:
199 ASSERT(false, "ShouldNotReachHere");
200 return std::vector<TRANGE>();
201 }
202
203 if (union_vec.empty()) {
204 union_vec.push_back(*merge_it);
205 } else {
206 TRANGE last_range = union_vec.back();
207
208 if (last_range.intersects(*merge_it)) {
209 union_vec.pop_back();
210 union_vec.push_back(last_range.union_range(*merge_it));
211 } else {
212 ASSERT(last_range < *merge_it, "Out of order merging");
213 union_vec.push_back(*merge_it);
214 }
215 }
216 }
217
218 ASSERT(is_trange_vector_sorted_and_non_overlapping(union_vec), "union'd vector fails invariant");
219
220 return union_vec;
221}
222
223template <typename TRANGE>
224std::vector<TRANGE> trange_vector_intersect(std::vector<TRANGE>& vec1, std::vector<TRANGE>& vec2) {
225 std::vector<TRANGE> intersect_vec;
226
227 ASSERT(is_trange_vector_sorted_and_non_overlapping(vec1), "input vector violates invariants");
228 ASSERT(is_trange_vector_sorted_and_non_overlapping(vec2), "input vector violates invariants");
229
230 auto vec1_it = vec1.begin();
231 auto vec2_it = vec2.begin();
232
233 // As soon as one vector empties, there can be no more intersections
234 while (vec1_it != vec1.end() && vec2_it != vec2.end()) {
235 TRANGE temp = vec1_it->intersection_range(*vec2_it);
236 if (temp.length() > 0) {
237 intersect_vec.push_back(temp);
238 }
239
240 // We keep the interval that ends last
241
242 if (vec1_it->max() > vec2_it->max()) {
243 vec2_it++;
244 } else {
245 vec1_it++;
246 }
247 }
248
249 ASSERT(is_trange_vector_sorted_and_non_overlapping(intersect_vec), "intersection vector fails invariant");
250
251 return intersect_vec;
252}
253
254#endif