From ffc2dfbdf27b0971ed17d0e338d608afea745150 Mon Sep 17 00:00:00 2001 From: Mikhail Gorbushin Date: Tue, 30 Apr 2019 15:43:07 +0300 Subject: [PATCH] Stage 1. Add NonIntersectingIntervals structure to base. --- base/CMakeLists.txt | 1 + base/non_intersecting_intervals.hpp | 76 +++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 base/non_intersecting_intervals.hpp diff --git a/base/CMakeLists.txt b/base/CMakeLists.txt index d5cdd85143..9a5ea7fa42 100644 --- a/base/CMakeLists.txt +++ b/base/CMakeLists.txt @@ -50,6 +50,7 @@ set( mutex.hpp newtype.hpp normalize_unicode.cpp + non_intersecting_intervals.hpp observer_list.hpp pprof.cpp pprof.hpp diff --git a/base/non_intersecting_intervals.hpp b/base/non_intersecting_intervals.hpp new file mode 100644 index 0000000000..db4d411e74 --- /dev/null +++ b/base/non_intersecting_intervals.hpp @@ -0,0 +1,76 @@ +#pragma once + +#include "base/assert.hpp" + +#include +#include +#include + +namespace base +{ +///\brief Data structure that maintains a set of non-intersecting intervals. +/// A new interval may only be added to the set if it does not intersect any +/// of the present intervals, thus the choice which intervals to keep is made +/// in a greedy online fashion with no lookahead. +template +class NonIntersectingIntervals +{ +public: + /// \brief Adds new interval to set if it doesn't intersect with any that has been already added. + /// \return true if there are no such intervals, that intersect the [left, right] interval. + bool AddInterval(T left, T right); + +private: + struct Interval + { + Interval(T left, T right); + + struct LessByLeftEnd + { + bool operator()(Interval const & lhs, Interval const & rhs) const; + }; + + bool Intersects(Interval const & rhs) const; + + T m_left{}; + T m_right{}; + }; + + std::set m_leftEnds; +}; + +template +bool NonIntersectingIntervals::AddInterval(T left, T right) +{ + Interval interval(left, right); + auto it = m_leftEnds.lower_bound(interval); + if (it != m_leftEnds.end() && interval.Intersects(*it)) + return false; + + if (it != m_leftEnds.begin() && interval.Intersects(*std::prev(it))) + return false; + + m_leftEnds.emplace(left, right); + return true; +} + +template +NonIntersectingIntervals::Interval::Interval(T left, T right) + : m_left(left), m_right(right) +{ + CHECK_LESS_OR_EQUAL(left, right, ()); +} + +template +bool NonIntersectingIntervals::Interval::LessByLeftEnd::operator()(Interval const & lhs, + Interval const & rhs) const +{ + return lhs.m_left < rhs.m_left; +}; + +template +bool NonIntersectingIntervals::Interval::Intersects(Interval const & rhs) const +{ + return std::max(m_left, rhs.m_left) <= std::min(m_right, rhs.m_right); +} +} // namespace coding