#ifndef XRPL_BASICS_RANGESET_H_INCLUDED #define XRPL_BASICS_RANGESET_H_INCLUDED #include #include #include #include #include #include #include namespace ripple { /** A closed interval over the domain T. For an instance ClosedInterval c, this represents the closed interval (c.first(), c.last()). A single element interval has c.first() == c.last(). This is simply a type-alias for boost interval container library interval set, so users should consult that documentation for available supporting member and free functions. */ template using ClosedInterval = boost::icl::closed_interval; /** Create a closed range interval Helper function to create a closed range interval without having to qualify the template argument. */ template ClosedInterval range(T low, T high) { return ClosedInterval(low, high); } /** A set of closed intervals over the domain T. Represents a set of values of the domain T using the minimum number of disjoint ClosedInterval. This is useful to represent ranges of T where a few instances are missing, e.g. the set 1-5,8-9,11-14. This is simply a type-alias for boost interval container library interval set, so users should consult that documentation for available supporting member and free functions. */ template using RangeSet = boost::icl::interval_set>; /** Convert a ClosedInterval to a styled string The styled string is "c.first()-c.last()" if c.first() != c.last() "c.first()" if c.first() == c.last() @param ci The closed interval to convert @return The style string */ template std::string to_string(ClosedInterval const& ci) { if (ci.first() == ci.last()) return std::to_string(ci.first()); return std::to_string(ci.first()) + "-" + std::to_string(ci.last()); } /** Convert the given RangeSet to a styled string. The styled string representation is the set of disjoint intervals joined by commas. The string "empty" is returned if the set is empty. @param rs The rangeset to convert @return The styled string */ template std::string to_string(RangeSet const& rs) { if (rs.empty()) return "empty"; std::string s; for (auto const& interval : rs) s += ripple::to_string(interval) + ","; s.pop_back(); return s; } /** Convert the given styled string to a RangeSet. The styled string representation is the set of disjoint intervals joined by commas. @param rs The set to be populated @param s The styled string to convert @return True on successfully converting styled string */ template [[nodiscard]] bool from_string(RangeSet& rs, std::string const& s) { std::vector intervals; std::vector tokens; bool result{true}; rs.clear(); boost::split(tokens, s, boost::algorithm::is_any_of(",")); for (auto const& t : tokens) { boost::split(intervals, t, boost::algorithm::is_any_of("-")); switch (intervals.size()) { case 1: { T front; if (!beast::lexicalCastChecked(front, intervals.front())) result = false; else rs.insert(front); break; } case 2: { T front; if (!beast::lexicalCastChecked(front, intervals.front())) result = false; else { T back; if (!beast::lexicalCastChecked(back, intervals.back())) result = false; else rs.insert(range(front, back)); } break; } default: result = false; } if (!result) break; intervals.clear(); } if (!result) rs.clear(); return result; } /** Find the largest value not in the set that is less than a given value. @param rs The set of interest @param t The value that must be larger than the result @param minVal (Default is 0) The smallest allowed value @return The largest v such that minV <= v < t and !contains(rs, v) or std::nullopt if no such v exists. */ template std::optional prevMissing(RangeSet const& rs, T t, T minVal = 0) { if (rs.empty() || t == minVal) return std::nullopt; RangeSet tgt{ClosedInterval{minVal, t - 1}}; tgt -= rs; if (tgt.empty()) return std::nullopt; return boost::icl::last(tgt); } } // namespace ripple #endif