diff options
Diffstat (limited to 'library')
-rw-r--r-- | library/cpp/yt/string/format-inl.h | 126 | ||||
-rw-r--r-- | library/cpp/yt/string/format.h | 59 | ||||
-rw-r--r-- | library/cpp/yt/string/unittests/format_ut.cpp | 7 |
3 files changed, 192 insertions, 0 deletions
diff --git a/library/cpp/yt/string/format-inl.h b/library/cpp/yt/string/format-inl.h index d286f3afbb..83d6198674 100644 --- a/library/cpp/yt/string/format-inl.h +++ b/library/cpp/yt/string/format-inl.h @@ -232,6 +232,43 @@ void FormatKeyValueRange(TStringBuilderBase* builder, const TRange& range, const //////////////////////////////////////////////////////////////////////////////// +template <class TRange, class TValueGetter, class TIntervalFormatter> +void FormatCompactIntervalRange( + TStringBuilderBase* builder, + const TRange& range, + const TValueGetter& valueGetter, + const TIntervalFormatter& intervalFormatter) +{ + if (range.begin() == range.end()) { + builder->AppendString("[]"); + return; + } + + builder->AppendChar('['); + + auto first = range.begin(); + auto last = first; + auto current = first + 1; + + while (current != range.end()) { + if (valueGetter(current) != valueGetter(last) + 1) { + bool firstInterval = first == range.begin(); + intervalFormatter(builder, first, last, valueGetter, firstInterval); + first = current; + } + + last = current; + ++current; + } + + bool firstInterval = first == range.begin(); + intervalFormatter(builder, first, last, valueGetter, firstInterval); + + builder->AppendChar(']'); +} + +//////////////////////////////////////////////////////////////////////////////// + template <class R> concept CFormattableRange = NDetail::CKnownRange<R> && @@ -303,6 +340,59 @@ TFormatterWrapper<TFormatter> MakeFormatterWrapper( }; } +template <class TRange, class TValueGetter, class TIntervalFormatter> +auto TCompactIntervalView<TRange, TValueGetter, TIntervalFormatter>::begin() const + -> TBegin +{ + return RangeBegin; +} + +template <class TRange, class TValueGetter, class TIntervalFormatter> +auto TCompactIntervalView<TRange, TValueGetter, TIntervalFormatter>::end() const + -> TEnd +{ + return RangeEnd; +} + +template <class TRange> +auto TDefaultValueGetter<TRange>::operator()(const TIterator& iterator) const + -> typename std::iterator_traits<TIterator>::value_type +{ + return *iterator; +} + +template <class TRange, class TValueGetter> +void TDefaultIntervalFormatter<TRange, TValueGetter>::operator()( + TStringBuilderBase* builder, + const TIterator& first, + const TIterator& last, + const TValueGetter& valueGetter, + bool firstInterval) const +{ + if (!firstInterval) { + builder->AppendString(DefaultJoinToStringDelimiter); + } + + if (first == last) { + builder->AppendFormat("%v", valueGetter(first)); + } else { + builder->AppendFormat("%v-%v", valueGetter(first), valueGetter(last)); + } +} + +template <class TRange, class TValueGetter, class TIntervalFormatter> +TCompactIntervalView<TRange, TValueGetter, TIntervalFormatter> MakeCompactIntervalView( + const TRange& range, + TValueGetter&& valueGetter, + TIntervalFormatter&& intervalFormatter) +{ + return TCompactIntervalView<TRange, TValueGetter, TIntervalFormatter>{ + range.begin(), + range.end(), + std::forward<TValueGetter>(valueGetter), + std::forward<TIntervalFormatter>(intervalFormatter)}; +} + template <class... TArgs> TLazyMultiValueFormatter<TArgs...>::TLazyMultiValueFormatter( TStringBuf format, @@ -671,6 +761,27 @@ void FormatValue( const TFormatterWrapper<TFormatter>& wrapper, TStringBuf spec); +// TCompactIntervalView + +template <class TRange, class TValueGetter, class TIntervalFormatter> +concept CCompactIntervalView = requires ( + TRange range, + TValueGetter valueGetter, + TIntervalFormatter intervalFormatter) +{ + { valueGetter(range.begin()) } -> std::integral; + { + intervalFormatter(nullptr, range.begin(), range.begin(), valueGetter, true) + } -> std::same_as<void>; +}; + +template <class TRange, class TValueGetter, class TIntervalFormatter> + requires CCompactIntervalView<TRange, TValueGetter, TIntervalFormatter> +void FormatValue( + TStringBuilderBase* builder, + const TCompactIntervalView<TRange, TValueGetter, TIntervalFormatter>& compactIntervalView, + TStringBuf spec); + // TLazyMultiValueFormatter template <class... TArgs> void FormatValue( @@ -773,6 +884,21 @@ void FormatValue( NYT::FormatRange(builder, formattableView, formattableView.Formatter, formattableView.Limit); } +// TCompactIntervalView +template <class TRange, class TValueGetter, class TIntervalFormatter> + requires CCompactIntervalView<TRange, TValueGetter, TIntervalFormatter> +void FormatValue( + TStringBuilderBase* builder, + const TCompactIntervalView<TRange, TValueGetter, TIntervalFormatter>& compactIntervalView, + TStringBuf /*spec*/) +{ + NYT::FormatCompactIntervalRange( + builder, + compactIntervalView, + compactIntervalView.ValueGetter, + compactIntervalView.IntervalFormatter); +} + // TFormatterWrapper template <class TFormatter> void FormatValue( diff --git a/library/cpp/yt/string/format.h b/library/cpp/yt/string/format.h index 5e5a76db9d..d15127fae0 100644 --- a/library/cpp/yt/string/format.h +++ b/library/cpp/yt/string/format.h @@ -5,6 +5,8 @@ #include <util/generic/string.h> +#include <iterator> + namespace NYT { //////////////////////////////////////////////////////////////////////////////// @@ -101,6 +103,63 @@ TFormattableView<TRange, TFormatter> MakeShrunkFormattableView( //////////////////////////////////////////////////////////////////////////////// +template <class TRange, class TValueGetter, class TIntervalFormatter> +struct TCompactIntervalView +{ + using TBegin = std::decay_t<decltype(std::declval<const TRange>().begin())>; + using TEnd = std::decay_t<decltype(std::declval<const TRange>().end())>; + + TBegin RangeBegin; + TEnd RangeEnd; + + TValueGetter ValueGetter; + TIntervalFormatter IntervalFormatter; + + TBegin begin() const; + TEnd end() const; +}; + +template <class TRange> +struct TDefaultValueGetter +{ + using TIterator = std::decay_t<decltype(std::declval<const TRange>().begin())>; + + auto operator()(const TIterator& iterator) const + -> typename std::iterator_traits<TIterator>::value_type; +}; + +template <class TRange, class TValueGetter> +struct TDefaultIntervalFormatter +{ + using TIterator = std::decay_t<decltype(std::declval<const TRange>().begin())>; + + void operator()( + TStringBuilderBase* builder, + const TIterator& first, + const TIterator& last, + const TValueGetter& valueGetter, + bool firstInterval) const; +}; + +//////////////////////////////////////////////////////////////////////////////// + +//! Writes a given integral #range as a sequence of intervals. +//! Example: +// MakeCompactIntervalView(std::vector {1, 2, 3, 5, 7, 8}) +// => [1-3,5,7-8] + +template < + class TRange, + class TValueGetter = TDefaultValueGetter<TRange>, + class TIntervalFormatter = TDefaultIntervalFormatter<TRange, TValueGetter> +> +TCompactIntervalView<TRange, TValueGetter, TIntervalFormatter> MakeCompactIntervalView( + const TRange& range, + TValueGetter&& valueGetter = {}, + TIntervalFormatter&& intervalFormatter = {}); + +//////////////////////////////////////////////////////////////////////////////// + template <class TFormatter> struct TFormatterWrapper { diff --git a/library/cpp/yt/string/unittests/format_ut.cpp b/library/cpp/yt/string/unittests/format_ut.cpp index 5ec4a1ffa8..f783efcf11 100644 --- a/library/cpp/yt/string/unittests/format_ut.cpp +++ b/library/cpp/yt/string/unittests/format_ut.cpp @@ -246,6 +246,13 @@ TEST(TFormatTest, Tuples) EXPECT_EQ("{1, 2}", Format("%v", std::pair(1, 2))); } +TEST(TFormatTest, CompactIntervalView) +{ + EXPECT_EQ("[]", Format("%v", MakeCompactIntervalView(std::vector<int>{}))); + EXPECT_EQ("[1]", Format("%v", MakeCompactIntervalView(std::vector<int>{1}))); + EXPECT_EQ("[0, 2-4, 7]", Format("%v", MakeCompactIntervalView(std::vector<int>{0, 2, 3, 4, 7}))); +} + TEST(TFormatTest, LazyMultiValueFormatter) { int i = 1; |