range: Add deoverlap function
This patch adds the deoverlap function to range.hh, which takes in a vector of possibly overlapping ranges and returns a vector of non-overlapping ranges covering the same values. Signed-off-by: Duarte Nunes <duarte@scylladb.com>
This commit is contained in:
52
range.hh
52
range.hh
@@ -24,6 +24,7 @@
|
||||
#include <experimental/optional>
|
||||
#include <iostream>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
#include <boost/range/adaptor/sliced.hpp>
|
||||
|
||||
template<typename T>
|
||||
class range_bound {
|
||||
@@ -94,6 +95,12 @@ private:
|
||||
<= -(!first.b->is_inclusive() && second.b->is_inclusive()));
|
||||
}
|
||||
|
||||
template<typename Comparator>
|
||||
static bool less_than(start_bound_ref first, start_bound_ref second, Comparator&& cmp) {
|
||||
return second.b && (!first.b || cmp(first.b->value(), second.b->value())
|
||||
< (first.b->is_inclusive() && !second.b->is_inclusive()));
|
||||
}
|
||||
|
||||
template<typename Comparator>
|
||||
static bool greater_than_or_equal(end_bound_ref first, end_bound_ref second, Comparator&& cmp) {
|
||||
return !first.b || (second.b && cmp(first.b->value(), second.b->value())
|
||||
@@ -353,6 +360,51 @@ public:
|
||||
return (_start == other._start) && (_end == other._end) && (_singular == other._singular);
|
||||
}
|
||||
|
||||
// Takes a vector of possibly overlapping ranges and returns a vector containing
|
||||
// a set of non-overlapping ranges covering the same values.
|
||||
template<typename Comparator>
|
||||
static std::vector<range<T>> deoverlap(std::vector<range<T>> ranges, Comparator&& cmp) {
|
||||
auto size = ranges.size();
|
||||
if (size <= 1) {
|
||||
return ranges;
|
||||
}
|
||||
|
||||
for (auto it = ranges.begin(); it != ranges.end(); ++it) {
|
||||
if ((*it).is_wrap_around(cmp)) {
|
||||
auto&& unwrapped = it->unwrap();
|
||||
it = ranges.erase(it);
|
||||
it = ranges.emplace(it, std::move(unwrapped.first));
|
||||
it = ranges.emplace(it, std::move(unwrapped.second));
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(ranges.begin(), ranges.end(), [&](auto&& r1, auto&& r2) {
|
||||
return range<T>::less_than(r1.start_bound(), r2.start_bound(), cmp);
|
||||
});
|
||||
|
||||
std::vector<range<T>> deoverlapped_ranges;
|
||||
deoverlapped_ranges.reserve(size);
|
||||
|
||||
auto&& current = ranges[0];
|
||||
for (auto&& r : ranges | boost::adaptors::sliced(1, ranges.size())) {
|
||||
bool includes_end = greater_than_or_equal(r.end_bound(), current.start_bound(), cmp)
|
||||
&& greater_than_or_equal(current.end_bound(), r.end_bound(), cmp);
|
||||
if (includes_end) {
|
||||
continue; // last.start <= r.start <= r.end <= last.end
|
||||
}
|
||||
bool includes_start = greater_than_or_equal(current.end_bound(), r.start_bound(), cmp);
|
||||
if (includes_start) {
|
||||
current = range<T>(std::move(current.start()), std::move(r.end()));
|
||||
} else {
|
||||
deoverlapped_ranges.emplace_back(std::move(current));
|
||||
current = std::move(r);
|
||||
}
|
||||
}
|
||||
|
||||
deoverlapped_ranges.emplace_back(std::move(current));
|
||||
return deoverlapped_ranges;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
friend std::ostream& operator<<(std::ostream& out, const range<U>& r);
|
||||
};
|
||||
|
||||
@@ -505,3 +505,96 @@ BOOST_AUTO_TEST_CASE(test_range_interval_map) {
|
||||
BOOST_REQUIRE(search_item("8") == true);
|
||||
BOOST_REQUIRE(search_item("9") == false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(range_deoverlap_tests) {
|
||||
using ranges = std::vector<range<unsigned>>;
|
||||
|
||||
{
|
||||
ranges rs = { range<unsigned>::make(1, 4), range<unsigned>::make(2, 5) };
|
||||
auto deoverlapped = range<unsigned>::deoverlap(std::move(rs), unsigned_comparator());
|
||||
BOOST_REQUIRE_EQUAL(range<unsigned>::make(1, 5), deoverlapped[0]);
|
||||
BOOST_REQUIRE_EQUAL(1, deoverlapped.size());
|
||||
}
|
||||
|
||||
{
|
||||
ranges rs = { range<unsigned>::make(1, 4), range<unsigned>::make(4, 5) };
|
||||
auto deoverlapped = range<unsigned>::deoverlap(std::move(rs), unsigned_comparator());
|
||||
BOOST_REQUIRE_EQUAL(range<unsigned>::make(1, 5), deoverlapped[0]);
|
||||
BOOST_REQUIRE_EQUAL(1, deoverlapped.size());
|
||||
}
|
||||
|
||||
{
|
||||
ranges rs = { range<unsigned>::make(2, 4), range<unsigned>::make(1, 3) };
|
||||
auto deoverlapped = range<unsigned>::deoverlap(std::move(rs), unsigned_comparator());
|
||||
BOOST_REQUIRE_EQUAL(range<unsigned>::make(1, 4), deoverlapped[0]);
|
||||
BOOST_REQUIRE_EQUAL(1, deoverlapped.size());
|
||||
}
|
||||
|
||||
{
|
||||
ranges rs = { range<unsigned>::make(1, 4), range<unsigned>::make(0, 5), range<unsigned>::make(7, 12), range<unsigned>::make(8, 10) };
|
||||
auto deoverlapped = range<unsigned>::deoverlap(std::move(rs), unsigned_comparator());
|
||||
BOOST_REQUIRE_EQUAL(range<unsigned>::make(0, 5), deoverlapped[0]);
|
||||
BOOST_REQUIRE_EQUAL(range<unsigned>::make(7, 12), deoverlapped[1]);
|
||||
BOOST_REQUIRE_EQUAL(2, deoverlapped.size());
|
||||
}
|
||||
|
||||
{
|
||||
ranges rs = { range<unsigned>::make(1, 4), range<unsigned>({2}, { }) };
|
||||
auto deoverlapped = range<unsigned>::deoverlap(std::move(rs), unsigned_comparator());
|
||||
BOOST_REQUIRE_EQUAL(range<unsigned>({1}, { }), deoverlapped[0]);
|
||||
BOOST_REQUIRE_EQUAL(1, deoverlapped.size());
|
||||
}
|
||||
|
||||
{
|
||||
ranges rs = { range<unsigned>({ }, {4}), range<unsigned>::make(3, 5) };
|
||||
auto deoverlapped = range<unsigned>::deoverlap(std::move(rs), unsigned_comparator());
|
||||
BOOST_REQUIRE_EQUAL(range<unsigned>({ }, {5}), deoverlapped[0]);
|
||||
BOOST_REQUIRE_EQUAL(1, deoverlapped.size());
|
||||
}
|
||||
|
||||
{
|
||||
ranges rs = { range<unsigned>({14}, { }), range<unsigned>({2}, { }) };
|
||||
auto deoverlapped = range<unsigned>::deoverlap(std::move(rs), unsigned_comparator());
|
||||
BOOST_REQUIRE_EQUAL(range<unsigned>({2}, { }), deoverlapped[0]);
|
||||
BOOST_REQUIRE_EQUAL(1, deoverlapped.size());
|
||||
}
|
||||
|
||||
{
|
||||
ranges rs = { range<unsigned>({2}, { }), range<unsigned>({12}, { }) };
|
||||
auto deoverlapped = range<unsigned>::deoverlap(std::move(rs), unsigned_comparator());
|
||||
BOOST_REQUIRE_EQUAL(range<unsigned>({2}, { }), deoverlapped[0]);
|
||||
BOOST_REQUIRE_EQUAL(1, deoverlapped.size());
|
||||
}
|
||||
|
||||
{
|
||||
ranges rs = { range<unsigned>::make(14, 4), range<unsigned>::make(2, 4) };
|
||||
auto deoverlapped = range<unsigned>::deoverlap(std::move(rs), unsigned_comparator());
|
||||
BOOST_REQUIRE_EQUAL(range<unsigned>({ }, {4}), deoverlapped[0]);
|
||||
BOOST_REQUIRE_EQUAL(range<unsigned>({14}, { }), deoverlapped[1]);
|
||||
BOOST_REQUIRE_EQUAL(2, deoverlapped.size());
|
||||
}
|
||||
|
||||
{
|
||||
ranges rs = { range<unsigned>({3}, {{4, false}}), range<unsigned>({{4, false}}, {5}) };
|
||||
auto deoverlapped = range<unsigned>::deoverlap(std::move(rs), unsigned_comparator());
|
||||
BOOST_REQUIRE_EQUAL(range<unsigned>({3}, {{4, false}}), deoverlapped[0]);
|
||||
BOOST_REQUIRE_EQUAL(range<unsigned>({{4, false}}, {5}), deoverlapped[1]);
|
||||
BOOST_REQUIRE_EQUAL(2, deoverlapped.size());
|
||||
}
|
||||
|
||||
{
|
||||
ranges rs = { range<unsigned>({3}, {{4, false}}), range<unsigned>::make(4, 5) };
|
||||
auto deoverlapped = range<unsigned>::deoverlap(std::move(rs), unsigned_comparator());
|
||||
BOOST_REQUIRE_EQUAL(range<unsigned>({3}, {{4, false}}), deoverlapped[0]);
|
||||
BOOST_REQUIRE_EQUAL(range<unsigned>::make(4, 5), deoverlapped[1]);
|
||||
BOOST_REQUIRE_EQUAL(2, deoverlapped.size());
|
||||
}
|
||||
|
||||
{
|
||||
ranges rs = { range<unsigned>::make(3, 4), range<unsigned>({{4, false}}, {5}) };
|
||||
auto deoverlapped = range<unsigned>::deoverlap(std::move(rs), unsigned_comparator());
|
||||
BOOST_REQUIRE_EQUAL(range<unsigned>::make(3, 4), deoverlapped[0]);
|
||||
BOOST_REQUIRE_EQUAL(range<unsigned>({{4, false}}, {5}), deoverlapped[1]);
|
||||
BOOST_REQUIRE_EQUAL(2, deoverlapped.size());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user