#pragma once #include "format_string.h" #include "string_builder.h" #include #include namespace NYT { //////////////////////////////////////////////////////////////////////////////// /* * Format: a type-safe and fast formatting utility. * * Basically works as a type-safe analogue of |sprintf| and is expected to * be backwards-compatible with the latter. * * Like Go's |Sprintf|, supports the ultimate format specifier |v| * causing arguments to be emitted in default format. * This is the default and preferred way of formatting things, * which should be used in newer code. * * |Format| may currently invoke |sprintf| internally for emitting numeric and some other * types. You can always write your own optimized implementation, if you wish :) * * In additional to the usual |sprintf|, supports a number of non-standard flags: * * |q| Causes the argument to be surrounded with single quotes (|'|). * Applies to all types. * * |Q| Causes the argument to be surrounded with double quotes (|"|). * Applies to all types. * * |l| The argument is emitted in "lowercase" style. * Only applies to enums and bools. * * The following argument types are supported: * * Strings (including |const char*|, |TStringBuf|, and |TString|) and chars: * Emitted as is. Fast. * * Numerics and pointers: * Emitted using |sprintf|. Maybe not that fast. * * |bool|: * Emitted either as |True| and |False| or |true| and |false| (if lowercase mode is ON). * * Enums: * Emitted in either camel (|SomeName|) or in lowercase-with-underscores style * (|some_name|, if lowercase mode is ON). * * Nullables: * |std::nullopt| is emitted as ||. * * All others: * Emitted as strings by calling |ToString|. * */ template TString Format(TFormatString format, TArgs&&... args); //////////////////////////////////////////////////////////////////////////////// template void Format(TStringBuilderBase* builder, TFormatString format, TArgs&&... args); //////////////////////////////////////////////////////////////////////////////// template TString ToStringViaBuilder(const T& value, TStringBuf spec = TStringBuf("v")); //////////////////////////////////////////////////////////////////////////////// template struct TFormattableView { using TBegin = std::decay_t().begin())>; using TEnd = std::decay_t().end())>; TBegin RangeBegin; TEnd RangeEnd; TFormatter Formatter; size_t Limit = std::numeric_limits::max(); TBegin begin() const; TEnd end() const; }; //! Annotates a given #range with #formatter to be applied to each item. template TFormattableView MakeFormattableView( const TRange& range, TFormatter&& formatter); template TFormattableView MakeShrunkFormattableView( const TRange& range, TFormatter&& formatter, size_t limit); //////////////////////////////////////////////////////////////////////////////// template struct TCompactIntervalView { using TBegin = std::decay_t().begin())>; using TEnd = std::decay_t().end())>; TBegin RangeBegin; TEnd RangeEnd; TValueGetter ValueGetter; TIntervalFormatter IntervalFormatter; TBegin begin() const; TEnd end() const; }; template struct TDefaultValueGetter { using TIterator = std::decay_t().begin())>; auto operator()(const TIterator& iterator) const -> typename std::iterator_traits::value_type; }; template struct TDefaultIntervalFormatter { using TIterator = std::decay_t().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, class TIntervalFormatter = TDefaultIntervalFormatter > TCompactIntervalView MakeCompactIntervalView( const TRange& range, TValueGetter&& valueGetter = {}, TIntervalFormatter&& intervalFormatter = {}); //////////////////////////////////////////////////////////////////////////////// template struct TFormatterWrapper { TFormatter Formatter; }; // Allows insertion of text conditionally. // Usage: /* NYT::Format( "Value is %v%v", 42, MakeFormatterWrapper([&] (auto* builder) { if (PossiblyMissingInfo_) { builder->AppendString(", PossiblyMissingInfo: "); FormatValue(builder, PossiblyMissingInfo_, "v"); } })); */ template TFormatterWrapper MakeFormatterWrapper( TFormatter&& formatter); //////////////////////////////////////////////////////////////////////////////// template class TLazyMultiValueFormatter; template void FormatValue( TStringBuilderBase* builder, const TLazyMultiValueFormatter& value, TStringBuf /*spec*/); //! A wrapper for a bunch of values that formats them lazily on demand. /*! * The intended use of this class is when you need to use the same formatted string * in several places in the function (e.g. log message tags) and want both to avoid * code duplication and premature formatting of the values until necessary. * * NB: lvalues are captured by reference without lifetime extension. */ template class TLazyMultiValueFormatter : private TNonCopyable { public: TLazyMultiValueFormatter(TStringBuf format, TArgs&&... args); // NB(arkady-e1ppa): We actually have to // forward declare this method as above // and friend-declare it as specialization // here because clang is stupid and would // treat this friend declartion as a hidden friend // declaration which in turn is treated as a separate symbol // causing linker to not find the actual definition. friend void FormatValue<>( TStringBuilderBase* builder, const TLazyMultiValueFormatter& value, TStringBuf /*spec*/); private: const TStringBuf Format_; const std::tuple Args_; }; template auto MakeLazyMultiValueFormatter(TStringBuf format, Args&&... args); //////////////////////////////////////////////////////////////////////////////// /* Example: FormatVector("One: %v, Two: %v, Three: %v", {1, 2, 3}) => "One: 1, Two: 2, Three: 3" */ template void FormatVector( TStringBuilderBase* builder, const char (&format)[Length], const TVector& vec); template void FormatVector( TStringBuilderBase* builder, TStringBuf format, const TVector& vec); template TString FormatVector( const char (&format)[Length], const TVector& vec); template TString FormatVector( TStringBuf format, const TVector& vec); //////////////////////////////////////////////////////////////////////////////// } // namespace NYT #define FORMAT_INL_H_ #include "format-inl.h" #undef FORMAT_INL_H_