mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-04 19:25:51 +00:00
Per XLS-0095, we are taking steps to rename ripple(d) to xrpl(d). This change specifically removes all copyright notices referencing Ripple, XRPLF, and certain affiliated contributors upon mutual agreement, so the notice in the LICENSE.md file applies throughout. Copyright notices referencing external contributions remain as-is. Duplicate verbiage is also removed.
178 lines
4.8 KiB
C++
178 lines
4.8 KiB
C++
#ifndef XRPL_BASICS_RANGESET_H_INCLUDED
|
|
#define XRPL_BASICS_RANGESET_H_INCLUDED
|
|
|
|
#include <xrpl/beast/core/LexicalCast.h>
|
|
|
|
#include <boost/algorithm/string.hpp>
|
|
#include <boost/icl/closed_interval.hpp>
|
|
#include <boost/icl/interval_set.hpp>
|
|
|
|
#include <optional>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
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 <class T>
|
|
using ClosedInterval = boost::icl::closed_interval<T>;
|
|
|
|
/** Create a closed range interval
|
|
|
|
Helper function to create a closed range interval without having to qualify
|
|
the template argument.
|
|
*/
|
|
template <class T>
|
|
ClosedInterval<T>
|
|
range(T low, T high)
|
|
{
|
|
return ClosedInterval<T>(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<T>. 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 <class T>
|
|
using RangeSet = boost::icl::interval_set<T, std::less, ClosedInterval<T>>;
|
|
|
|
/** 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 <class T>
|
|
std::string
|
|
to_string(ClosedInterval<T> 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 <class T>
|
|
std::string
|
|
to_string(RangeSet<T> 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 <class T>
|
|
[[nodiscard]] bool
|
|
from_string(RangeSet<T>& rs, std::string const& s)
|
|
{
|
|
std::vector<std::string> intervals;
|
|
std::vector<std::string> 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 <class T>
|
|
std::optional<T>
|
|
prevMissing(RangeSet<T> const& rs, T t, T minVal = 0)
|
|
{
|
|
if (rs.empty() || t == minVal)
|
|
return std::nullopt;
|
|
RangeSet<T> tgt{ClosedInterval<T>{minVal, t - 1}};
|
|
tgt -= rs;
|
|
if (tgt.empty())
|
|
return std::nullopt;
|
|
return boost::icl::last(tgt);
|
|
}
|
|
|
|
} // namespace ripple
|
|
|
|
#endif
|