21namespace swoc {
inline namespace SWOC_VERSION_NS {
38 return std::numeric_limits<M>::max();
75 return std::numeric_limits<M>::min();
333 self_type
hull(self_type
const &that)
const;
347 explicit operator bool()
const;
383 using first_argument_type = self_type;
384 using second_argument_type = self_type;
385 using result_type = bool;
388 bool operator()(self_type
const &lhs, self_type
const &rhs)
const;
424 return _min <= value && value <=
_max;
453 return !*
this ? that : !that ? *this : self_type(std::min(
_min, that.
_min), std::max(
_max, that.
_max));
459 if (
_max < that._max) {
460 return ++
metric_type(
_max) < that._max ? EdgeRelation::GAP : EdgeRelation::ADJ;
462 return _min >= that._min ? EdgeRelation::NONE : EdgeRelation::OVLP;
471 retval = Relation::EQUAL;
473 retval = Relation::SUBSET;
475 retval = Relation::SUPERSET;
477 retval = Relation::OVERLAP;
479 retval = Relation::ADJACENT;
623 return lhs.
min() == rhs.
min() && lhs.
max() == rhs.
max();
633 return !(lhs == rhs);
708template <
typename METRIC,
typename PAYLOAD>
class DiscreteSpace {
709 using self_type = DiscreteSpace;
718 using self_type =
Node;
720 friend class DiscreteSpace;
728 using Linkage = swoc::IntrusiveLinkageRebind<self_type, super_type::Linkage>;
736 Node(METRIC
const &min, METRIC
const &max, PAYLOAD
const &
payload) : _range(min, max), _payload(
payload) {}
746 self_type &
assign(range_type
const &range);
761 assign_min(METRIC
const &m,
bool update_tree =
true) {
765 this->ripple_structure_fixup();
771 assign_max(METRIC
const &m,
bool update_tree =
true) {
775 this->ripple_structure_fixup();
794 return static_cast<self_type *
>(_left);
799 return static_cast<self_type *
>(_right);
803 using Direction =
typename Node::Direction;
806 IntrusiveDList<typename Node::Linkage>
_list;
813 return Node::Linkage::prev_ptr(n);
818 return Node::Linkage::next_ptr(n);
823 return static_cast<Node *
>(n->_left);
828 return static_cast<Node *
>(n->_right);
832 using iterator =
typename decltype(_list)::iterator;
833 using const_iterator =
typename decltype(_list)::const_iterator;
835 DiscreteSpace() =
default;
845 self_type &
mark_bulk(std::vector<std::pair<range_type, PAYLOAD>> &marks,
bool is_sorted =
false);
854 self_type &
mark_bulk(std::pair<range_type, PAYLOAD>* start,
size_t n,
bool is_sorted =
false);
865 self_type &
mark(range_type
const &range, PAYLOAD
const &payload,
bool update_tree =
true);
874 self_type &
erase(range_type
const &range);
893 template <
typename F,
typename U = PAYLOAD> self_type &
blend(range_type
const &range, U
const &color, F &&blender);
904 self_type &
fill(range_type
const &range, PAYLOAD
const &payload);
911 iterator
find(METRIC
const &metric);
918 const_iterator
find(METRIC
const &metric)
const;
953 return _list.begin();
963 return _list.begin();
1020 void prepend(Node *node,
bool update_tree =
true);
1029 void append(Node *node,
bool update_tree =
true);
1036 void remove(Node *node,
bool update_tree =
true);
1041template <
typename METRIC,
typename PAYLOAD>
1047template <
typename METRIC,
typename PAYLOAD>
1054template <
typename METRIC,
typename PAYLOAD>
1061template <
typename METRIC,
typename PAYLOAD>
1067 _hull.assign(this->left()->_hull.min(), this->right()->_hull.max());
1069 _hull.assign(this->left()->_hull.min(), _range.max());
1071 _hull.assign(_range.min(), this->right()->_hull.max());
1081template <
typename METRIC,
typename PAYLOAD> DiscreteSpace<METRIC, PAYLOAD>::~DiscreteSpace() {
1083 for (
auto &node :
_list) {
1084 std::destroy_at(&node.payload());
1088template <
typename METRIC,
typename PAYLOAD>
1091 return _list.count();
1094template <
typename METRIC,
typename PAYLOAD>
1097 return _list.empty();
1100template <
typename METRIC,
typename PAYLOAD>
1103 return static_cast<Node *
>(
_list.head());
1106template <
typename METRIC,
typename PAYLOAD>
1109 return static_cast<Node *
>(
_list.tail());
1112template <
typename METRIC,
typename PAYLOAD>
1117 if (metric < n->min()) {
1118 if (n->_hull.contains(metric)) {
1123 }
else if (n->max() < metric) {
1124 if (n->_hull.contains(metric)) {
1130 return _list.iterator_for(n);
1136template <
typename METRIC,
typename PAYLOAD>
1139 return const_cast<self_type *
>(
this)->
find(metric);
1142template <
typename METRIC,
typename PAYLOAD>
1146 Node *zret =
nullptr;
1149 if (
auto ln =
_list.tail(); ln !=
nullptr && ln->max() < target) {
1154 if (target < n->min()) {
1158 if (n->max() < target) {
1168template <
typename METRIC,
typename PAYLOAD>
1172 Node *zret =
nullptr;
1175 if (
auto ln =
_list.tail(); ln ==
nullptr || ln->min() <= target) {
1180 if (target > n->min()) {
1184 if (n->min() > target) {
1193 if (zret && (zret->min() <= target)) {
1200template <
typename METRIC,
typename PAYLOAD>
1204 return n ? iterator(n) : this->
end();
1207template <
typename METRIC,
typename PAYLOAD>
1211 return n ? iterator(n) : this->
end();
1214template <
typename METRIC,
typename PAYLOAD>
1218 if (this->
head() ==
nullptr ||
1219 this->
head()->_range.
min() > range.max() ||
1220 this->tail()->_range.max() < range.min()
1222 return {this->
end(), this->
end()};
1230 if (lower ==
nullptr) {
1231 lower = this->
head();
1232 }
else if (lower->_range.max() < range.min()) {
1233 lower = next(lower);
1234 if (lower->_range.min() > range.max()) {
1235 return {this->
end(), this->
end()};
1239 return {
_list.iterator_for(lower), upper ?
_list.iterator_for(upper) : this->
end()};
1242template <
typename METRIC,
typename PAYLOAD>
1250 _root =
static_cast<Node *
>(
_list.head()->set_child(node, Direction::LEFT)->rebalance_after_insert());
1254 _list.prepend(node);
1257template <
typename METRIC,
typename PAYLOAD>
1266 _root =
static_cast<Node *
>(
_list.tail()->set_child(node, Direction::RIGHT)->rebalance_after_insert());
1273template <
typename METRIC,
typename PAYLOAD>
1284template <
typename METRIC,
typename PAYLOAD>
1289 if (left(spot) ==
nullptr) {
1299 _list.insert_before(spot, node);
1306template <
typename METRIC,
typename PAYLOAD>
1311 if (right(spot) ==
nullptr) {
1312 spot->
set_child(node, Direction::RIGHT);
1321 _list.insert_after(spot, node);
1328template <
typename METRIC,
typename PAYLOAD>
1334 if (n->min() > range.
max()) {
1338 if (n->max() >= range.
min()) {
1339 if (n->max() <= range.
max()) {
1340 if (n->min() >= range.
min()) {
1345 }
else if (n->min() >= range.
min()) {
1359template <
typename METRIC,
typename PAYLOAD>
1362 return this->
mark_bulk(ranges.data(), ranges.size(), is_sorted);
1365template <
typename METRIC,
typename PAYLOAD>
1373 std::stable_sort(start, start + n, [](
const auto &lhs,
const auto &rhs) {
1374 if (lhs.first.
min() != rhs.first.
min()) {
1375 return lhs.first.
min() < rhs.first.
min();
1377 return lhs.first.
max() < rhs.first.
max();
1383 bool isAppend = !
_list.empty() &&
_list.tail()->max() < start[0].first.min();
1386 for (
size_t i = 0; i < n; ++i)
1388 auto const& [range, payload] = start[i];
1389 this->
mark(range, payload, !isAppend);
1399template <
typename METRIC,
typename PAYLOAD>
1415 if (n->min() == range.
min()) {
1420 if (p && p->
payload() == payload && p->max() == min_minus_1) {
1423 x->assign_max(range.
max(), update_tree);
1424 }
else if (n->max() <= range.
max()) {
1427 x->assign_max(range.
max()).
assign(payload);
1428 }
else if (n->
payload() == payload) {
1432 x =
_fa.make(range, payload);
1433 n->assign_min(max_plus_1, update_tree);
1437 }
else if (n->
payload() == payload && n->max() >= min_minus_1) {
1441 if (x->max() >= range.
max()) {
1444 x->assign_max(range.
max(), update_tree);
1445 }
else if (n->max() <= range.
max()) {
1448 if (n->max() >= range.
min()) {
1449 n->assign_max(min_minus_1, update_tree);
1450 }
else if (
nullptr != (y = next(n)) && y->max() <= range.
max()) {
1467 x =
_fa.make(range, payload);
1468 r =
_fa.make(range_type{max_plus_1, n->max()}, n->
payload());
1469 n->assign_max(min_minus_1, update_tree);
1476 x =
_fa.make(range, payload);
1480 this->
append(x, update_tree);
1483 }
else if (
nullptr != (n = this->
head()) &&
1485 (n->max() <= range.
max() || n->min() <= max_plus_1)
1490 x->assign_min(range.
min(), update_tree);
1491 if (x->max() < range.
max()) {
1492 x->assign_max(range.
max(), update_tree);
1495 x =
_fa.make(range, payload);
1496 this->
prepend(x, update_tree);
1502 if (n->max() <= range.
max()) {
1505 this->
remove(y, update_tree);
1506 }
else if (max_plus_1 < n->min()) {
1508 }
else if (n->
payload() == payload) {
1509 x->assign_max(n->max(), update_tree);
1512 this->
remove(y, update_tree);
1513 }
else if (n->min() <= range.
max()) {
1514 n->assign_min(max_plus_1, update_tree);
1524template <
typename METRIC,
typename PAYLOAD>
1531 auto min = range.
min();
1532 auto max = range.
max();
1537 if (n->min() < min) {
1540 if (n->max() < min_1) {
1542 }
else if (n->max() >= max) {
1544 }
else if (n->
payload() != payload) {
1563 auto max_plus1 = max;
1571 if (n->
payload() == payload) {
1573 if (n->max() <= max) {
1576 }
else if (n->min() <= max_plus1) {
1578 x->assign_max(n->max());
1587 if (n->max() <= max) {
1591 }
else if (n->min() <= max_plus1) {
1601 if (max < n->min()) {
1604 }
else if (max <= n->max()) {
1615 if (max < n->min()) {
1619 if (min < n->min()) {
1623 if (max <= n->max()) {
1637 this->
append(
_fa.make(min, max, payload));
1642template <
typename METRIC,
typename PAYLOAD>
1643template <
typename F,
typename U>
1648 PAYLOAD plain_color{};
1649 bool plain_color_p = blender(plain_color, color);
1651 auto node_cleaner = [&](Node *ptr) ->
void { _fa.destroy(ptr); };
1653 using unique_node = std::unique_ptr<Node,
decltype(node_cleaner)>;
1656 Node *n = this->lower_node(range.min());
1659 auto range_max_plus_1 = range.max();
1663 auto remaining = range;
1673 if (n->max() < remaining.min()) {
1681 if (n->min() < remaining.min()) {
1684 unique_node fill{_fa.make(remaining.min(), n->max(), n->payload()), node_cleaner};
1685 bool fill_p = blender(fill->payload(), color);
1688 bool same_color_p = fill->payload() == n->payload();
1689 if (same_color_p && n->max() >= remaining.max()) {
1692 if (!same_color_p) {
1693 auto fn = fill.release();
1694 auto n_max = n->max();
1695 n->assign_max(--metric_type(remaining.min()));
1696 this->insert_after(n, fn);
1697 if (n_max > remaining.max()) {
1698 fn->assign_max(remaining.max());
1699 this->insert_after(fn, _fa.make(++metric_type(remaining.max()), n_max, n->payload()));
1704 remaining.assign_min(++metric_type(n->max()));
1706 auto n_r = n->range();
1707 if (n_r.max() > remaining.max()) {
1709 n->assign_min(++metric_type(remaining.max()));
1710 this->insert_before(n, _fa.make(n_r.min(), --metric_type(remaining.min()), n->payload()));
1713 n->assign_max(--metric_type(remaining.min()));
1714 if (n_r.max() == remaining.max()) {
1717 remaining.assign_min(++metric_type(n_r.max()));
1722 Node *pred = prev(n);
1730 bool right_ext_p = n->max() > remaining.max();
1732 bool right_overlap_p = remaining.contains(n->min());
1734 bool right_adj_p = !right_overlap_p && remaining.is_left_adjacent_to(n->range());
1736 bool n_plain_colored_p = plain_color_p && (n->payload() == plain_color);
1741 if (!right_overlap_p) {
1744 bool pred_plain_colored_p = pred && ++metric_type(pred->max()) == remaining.min() && pred->payload() == plain_color;
1746 if (right_adj_p && n_plain_colored_p) {
1747 n->assign_min(remaining.min());
1748 if (pred_plain_colored_p) {
1749 auto pred_min = pred->min();
1751 n->assign_min(pred_min);
1753 }
else if (pred_plain_colored_p) {
1754 pred->assign_max(remaining.max());
1755 }
else if (!remaining.empty() && plain_color_p) {
1756 this->insert_before(n, _fa.make(remaining.min(), remaining.max(), plain_color));
1764 if (plain_color_p && remaining.min() < n->min()) {
1765 if (n->payload() == plain_color) {
1766 if (pred && pred->payload() == n->payload()) {
1767 auto pred_min{pred->min()};
1769 n->assign_min(pred_min);
1771 n->assign_min(remaining.min());
1774 auto n_min_minus_1{n->min()};
1776 if (pred && pred->payload() == plain_color) {
1777 pred->assign_max(n_min_minus_1);
1779 this->insert_before(n, _fa.make(remaining.min(), n_min_minus_1, plain_color));
1787 auto max{right_ext_p ? remaining.max() : n->max()};
1788 unique_node fill{_fa.make(n->min(), max, n->payload()), node_cleaner};
1789 bool fill_p = blender(fill->payload(), color);
1790 auto next_n = next(n);
1791 remaining.assign_min(++METRIC{fill->max()});
1797 nullptr != (pred = prev(n)) && pred->range().is_left_adjacent_to(fill->range()) && pred->payload() == fill->payload();
1800 if (n->payload() == fill->payload()) {
1801 n->assign_min(fill->min());
1803 n->assign_min(range_max_plus_1);
1805 pred->assign_max(fill->max());
1807 this->insert_before(n, fill.release());
1815 pred->assign_max(fill->max());
1817 this->insert_before(n, fill.release());
1821 }
else if (right_ext_p) {
1822 n->assign_min(range_max_plus_1);
1834 if (plain_color_p && !remaining.empty()) {
1838 if (n && n->max() >= --metric_type{remaining.min()} && n->payload() == plain_color) {
1839 n->assign_max(range.max());
1841 this->append(_fa.make(remaining.min(), remaining.max(), plain_color));
1848template <
typename METRIC,
typename PAYLOAD>
1851 for (
auto &node :
_list) {
1852 std::destroy_at(&node.payload());
constexpr auto maximum(meta::CaseTag< 0 >) -> M
constexpr auto minimum(meta::CaseTag< 0 >) -> M
metric_type const & max() const
Relation relationship(self_type const &that) const
T metric_type
Export metric type.
bool is_strict_subset_of(self_type const &that) const
bool operator!=(self_type const &that) const
Inequality.
bool is_subset_of(self_type const &that) const
bool has_union(self_type const &that) const
self_type & assign_max(metric_type const &max)
bool is_singleton() const
Check if the interval is exactly one element.
bool operator<(DiscreteRange< METRIC > const &lhs, DiscreteRange< METRIC > const &rhs)
bool operator==(self_type const &that) const
Equality.
constexpr DiscreteRange()
bool operator>=(DiscreteRange< T > const &lhs, DiscreteRange< T > const &rhs)
bool has_intersection_with(self_type const &that) const
self_type & assign_min(metric_type const &min)
constexpr DiscreteRange(T const &value)
DiscreteRangeEdgeRelation EdgeRelation
Import type for convenience.
DiscreteRangeRelation Relation
Import type for convenience.
bool operator<=(DiscreteRange< METRIC > const &lhs, DiscreteRange< METRIC > const &rhs)
bool is_superset_of(self_type const &that) const
bool contains(metric_type const &value) const
self_type & clear()
Make the range empty.
EdgeRelation left_edge_relationship(self_type const &that) const
bool is_adjacent_to(self_type const &that) const
bool operator^(DiscreteRange< T > const &lhs, DiscreteRange< T > const &rhs)
self_type intersection(self_type const &that) const
self_type hull(self_type const &that) const
bool is_left_adjacent_to(self_type const &that) const
bool operator>(DiscreteRange< T > const &lhs, DiscreteRange< T > const &rhs)
metric_type const & min() const
self_type & operator|=(self_type const &that)
self_type & assign(metric_type const &min, metric_type const &max)
self_type & operator&=(self_type const &that)
self_type & assign(metric_type const &value)
constexpr DiscreteRange(T const &min, T const &max)
bool is_strict_superset_of(self_type const &that) const
bool operator!=(DiscreteRange< T > const &lhs, DiscreteRange< T > const &rhs)
A node in the range tree.
swoc::IntrusiveLinkageRebind< self_type, super_type::Linkage > Linkage
Linkage for IntrusiveDList.
self_type & assign(range_type const &range)
Node(METRIC const &min, METRIC const &max, PAYLOAD const &payload)
Construct from two metrics and a payload.
void structure_fixup() override
Node()=default
Construct empty node.
Node(range_type const &range, PAYLOAD const &payload)
Construct from range and payload.
self_type & erase(range_type const &range)
iterator lower_bound(METRIC const &m)
self_type & mark(range_type const &range, PAYLOAD const &payload, bool update_tree=true)
void insert_after(Node *spot, Node *node, bool update_tree=true)
const_iterator end() const
Node * lower_node(METRIC const &target)
swoc::FixedArena< Node > _fa
iterator upper_bound(METRIC const &m)
self_type & fill(range_type const &range, PAYLOAD const &payload)
void prepend(Node *node, bool update_tree=true)
self_type & mark_bulk(std::vector< std::pair< range_type, PAYLOAD > > &marks, bool is_sorted=false)
PAYLOAD payload_type
Export.
void insert_before(Node *spot, Node *node, bool update_tree=true)
METRIC metric_type
Export.
const_iterator find(METRIC const &metric) const
Node * upper_node(METRIC const &target)
std::pair< iterator, iterator > intersection(range_type const &range)
void remove(Node *node, bool update_tree=true)
void append(Node *node, bool update_tree=true)
const_iterator begin() const
iterator find(METRIC const &metric)
self_type & mark_bulk(std::pair< range_type, PAYLOAD > *start, size_t n, bool is_sorted=false)
self_type & blend(range_type const &range, U const &color, F &&blender)
void clear()
Remove all ranges.
IntrusiveDList< typename Node::Linkage > _list
For template deduction guides.
DiscreteRangeEdgeRelation
Relationship between one edge of an interval and the "opposite" edge of another.
@ OVLP
Edge is inside interval.
@ ADJ
The edges are adjacent.
@ GAP
There is a gap between the edges.
DiscreteRangeRelation
Relationship between two intervals.
@ ADJACENT
The two intervals are adjacent and disjoint.
@ SUPERSET
Every element in RHS is in LHS.
@ OVERLAP
There exists at least one element in both LHS and RHS.
@ SUBSET
All elements in LHS are also in RHS.
@ NONE
No common elements.
bool operator==(IPAddr const &lhs, sockaddr const *sa)
Equality.
bool operator()(self_type const &lhs, self_type const &rhs) const
self_type * rebalance_after_insert()
Rebalance the tree starting at this node.
self_type * _prev
Previous node.
static self_type * buildTree(self_type *&head, int n)
Recursively build a balanced RB tree from a sorted linked list.
self_type * set_child(self_type *child, Direction dir)
self_type * ripple_structure_fixup()
self_type * _right
right child
self_type * _left
left child
self_type * _next
Next node.
bool remove(path const &p, std::error_code &ec)