#pragma once #include #include #include #include #include #include #include #include namespace xrpl { /** * 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 += xrpl::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 fromString(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 xrpl