2
* Copyright Peter G. Jensen, all rights reserved.
7
* Author: Peter G. Jensen <root@petergjoel.dk>
9
* Created on March 31, 2020, 4:32 PM
21
namespace PetriEngine {
22
namespace Reachability {
26
static inline uint32_t min() {
27
return std::numeric_limits<uint32_t>::min();
30
static inline uint32_t max() {
31
return std::numeric_limits<uint32_t>::max();
37
explicit range_t(uint32_t val) : _lower(val), _upper(val) {
40
range_t(uint32_t l, uint32_t u) : _lower(l), _upper(u) {
41
assert(_lower <= _upper);
44
uint32_t _lower = min();
45
uint32_t _upper = max();
47
bool no_upper() const {
48
return _upper == max();
51
bool no_lower() const {
52
return _lower == min();
55
bool unbound() const {
56
return no_lower() && no_upper();
64
std::ostream& print(std::ostream& os) const {
77
std::pair<bool, bool> compare(const range_t& other) const {
78
return std::make_pair(
79
_lower <= other._lower && _upper >= other._upper,
80
_lower >= other._lower && _upper <= other._upper
84
range_t& operator&=(const range_t& other) {
85
_lower = std::max(_lower, other._lower);
86
_upper = std::min(_upper, other._upper);
90
range_t& operator|=(const range_t& other) {
91
_lower = std::min(_lower, other._lower);
92
_upper = std::max(_upper, other._upper);
96
range_t& operator|=(uint32_t val) {
97
_lower = std::min(val, _lower);
98
_upper = std::max(val, _upper);
102
range_t& operator&=(uint32_t val) {
108
range_t& operator-=(uint32_t val) {
109
if (_lower < min() + val)
113
if (_upper != max()) {
114
if (_upper < min() + val) {
123
range_t& operator+=(uint32_t val) {
124
if (_lower != min()) {
125
if (_lower >= max() - val)
130
if (_upper >= max() - val) {
138
struct placerange_t {
140
uint32_t _place = std::numeric_limits<uint32_t>::max();
145
placerange_t(uint32_t place) : _place(place) {
148
placerange_t(uint32_t place, const range_t& r) : _range(r), _place(place) {
151
placerange_t(uint32_t place, range_t&& r) : _range(r), _place(place) {
154
placerange_t(uint32_t place, uint32_t v) : _range(v), _place(place) {
157
placerange_t(uint32_t place, uint32_t l, uint32_t u) : _range(l, u), _place(place) {
160
std::ostream& print(std::ostream& os) const {
161
os << "<P" << _place << "> in ";
162
return _range.print(os);
165
std::pair<bool, bool> compare(const range_t& other) const {
166
return _range.compare(other);
169
std::pair<bool, bool> compare(const placerange_t& other) const {
170
assert(other._place == _place);
171
if (other._place != _place)
172
return std::make_pair(false, false);
173
return _range.compare(other._range);
176
placerange_t& operator|=(uint32_t val) {
181
placerange_t& operator&=(uint32_t val) {
186
placerange_t& operator-=(uint32_t val) {
191
placerange_t& operator+=(uint32_t val) {
196
placerange_t& operator&=(const placerange_t& other) {
197
assert(other._place == _place);
198
_range &= other._range;
202
placerange_t& operator|=(const placerange_t& other) {
203
assert(other._place == _place);
204
_range |= other._range;
208
// used for sorting only!
210
bool operator<(const placerange_t& other) const {
211
return _place < other._place;
216
std::vector<placerange_t> _ranges;
218
const placerange_t* operator[](uint32_t place) const {
219
auto lb = std::lower_bound(_ranges.begin(), _ranges.end(), place);
220
if (lb == _ranges.end() || lb->_place != place) {
227
placerange_t* operator[](uint32_t place) {
228
auto lb = std::lower_bound(_ranges.begin(), _ranges.end(), place);
229
if (lb == _ranges.end() || lb->_place != place) {
236
placerange_t& find_or_add(uint32_t place) {
237
auto lb = std::lower_bound(_ranges.begin(), _ranges.end(), place);
238
if (lb == _ranges.end() || lb->_place != place) {
239
lb = _ranges.emplace(lb, place);
244
uint32_t lower(uint32_t place) const {
245
auto* pr = (*this)[place];
247
return range_t::min();
248
return pr->_range._lower;
251
uint32_t upper(uint32_t place) const {
252
auto* pr = (*this)[place];
254
return range_t::max();
255
return pr->_range._upper;
258
bool unbound(uint32_t place) const {
259
auto* pr = (*this)[place];
262
return pr->_range.unbound();
265
void copy(const prvector_t& other) {
266
_ranges = other._ranges;
271
for (int64_t i = _ranges.size() - 1; i >= 0; --i) {
272
if (_ranges[i]._range.unbound())
273
_ranges.erase(_ranges.begin() + i);
275
assert(is_compact());
278
bool is_compact() const {
279
for (auto& e : _ranges)
280
if (e._range.unbound())
286
int64_t i = _ranges.size();
287
for (--i; i >= 0; --i)
288
if (_ranges[i]._range.unbound())
289
_ranges.erase(_ranges.begin() + i);
292
std::pair<bool, bool> compare(const prvector_t& other) const {
293
assert(is_compact());
294
assert(other.is_compact());
295
auto sit = _ranges.begin();
296
auto oit = other._ranges.begin();
297
std::pair<bool, bool> incl = std::make_pair(true, true);
300
if (sit == _ranges.end()) {
301
incl.second = incl.second && (oit == other._ranges.end());
303
} else if (oit == other._ranges.end()) {
306
} else if (sit->_place == oit->_place) {
307
auto r = sit->compare(*oit);
308
incl.first = incl.first && r.first;
309
incl.second &= incl.second && r.second;
312
} else if (sit->_place < oit->_place) {
315
} else if (sit->_place > oit->_place) {
319
if (!incl.first && !incl.second)
325
std::ostream& print(std::ostream& os) const {
328
for (auto& pr : _ranges) {
330
pr.print(os) << "\n";
336
bool is_true() const {
337
return _ranges.empty();
340
bool is_false(size_t nplaces) const {
341
if (_ranges.size() != nplaces) return false;
342
for (auto& p : _ranges) {
343
if (p._range._lower != 0 ||
344
p._range._upper != 0)
350
bool operator<(const prvector_t& other) const {
351
if (_ranges.size() != other._ranges.size())
352
return _ranges.size() < other._ranges.size();
353
for (size_t i = 0; i < _ranges.size(); ++i) {
354
auto& r = _ranges[i];
355
auto& otr = other._ranges[i];
357
if (r._place != otr._place)
358
return r._place < otr._place;
359
if (r._range._lower != otr._range._lower)
360
return r._range._lower < otr._range._lower;
361
if (r._range._upper != otr._range._upper)
362
return r._range._upper < otr._range._upper;
367
bool operator==(const prvector_t& other) const {
368
auto r = compare(other);
369
return r.first && r.second;
372
prvector_t& operator&=(const placerange_t& other) {
373
auto lb = std::lower_bound(_ranges.begin(), _ranges.end(), other);
374
if (lb == std::end(_ranges) || lb->_place != other._place) {
375
_ranges.insert(lb, other);
382
prvector_t& operator&=(const prvector_t& other) {
383
auto oit = other._ranges.begin();
384
auto sit = _ranges.begin();
385
while (sit != _ranges.end()) {
386
while (oit != other._ranges.end() && oit->_place < sit->_place) {
387
sit = _ranges.insert(sit, *oit);
391
if (oit == other._ranges.end() || oit->_place != sit->_place) {
398
if (oit != other._ranges.end()) {
399
_ranges.insert(_ranges.end(), oit, other._ranges.end());
404
bool restricts(const std::vector<int64_t>& writes) const {
405
auto rit = _ranges.begin();
406
for (auto p : writes) {
407
while (rit != std::end(_ranges) &&
408
(rit->_place < p || rit->_range.unbound()))
410
if (rit == std::end(_ranges)) break;
411
if (rit->_place == p)