aboutsummaryrefslogtreecommitdiffstats
path: root/library
diff options
context:
space:
mode:
Diffstat (limited to 'library')
-rw-r--r--library/cpp/yt/string/format-inl.h126
-rw-r--r--library/cpp/yt/string/format.h59
-rw-r--r--library/cpp/yt/string/unittests/format_ut.cpp7
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;