format.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. #pragma once
  2. #include "string_builder.h"
  3. namespace NYT {
  4. ////////////////////////////////////////////////////////////////////////////////
  5. /*
  6. * Format: a type-safe and fast formatting utility.
  7. *
  8. * Basically works as a type-safe analogue of |sprintf| and is expected to
  9. * be backwards-compatible with the latter.
  10. *
  11. * Like Go's |Sprintf|, supports the ultimate format specifier |v|
  12. * causing arguments to be emitted in default format.
  13. * This is the default and preferred way of formatting things,
  14. * which should be used in newer code.
  15. *
  16. * |Format| may currently invoke |sprintf| internally for emitting numeric and some other
  17. * types. You can always write your own optimized implementation, if you wish :)
  18. *
  19. * In additional to the usual |sprintf|, supports a number of non-standard flags:
  20. *
  21. * |q| Causes the argument to be surrounded with single quotes (|'|).
  22. * Applies to all types.
  23. *
  24. * |Q| Causes the argument to be surrounded with double quotes (|"|).
  25. * Applies to all types.
  26. *
  27. * |l| The argument is emitted in "lowercase" style.
  28. * Only applies to enums and bools.
  29. *
  30. * The following argument types are supported:
  31. *
  32. * Strings (including |const char*|, |TStringBuf|, and |TString|) and chars:
  33. * Emitted as is. Fast.
  34. *
  35. * Numerics and pointers:
  36. * Emitted using |sprintf|. Maybe not that fast.
  37. *
  38. * |bool|:
  39. * Emitted either as |True| and |False| or |true| and |false| (if lowercase mode is ON).
  40. *
  41. * Enums:
  42. * Emitted in either camel (|SomeName|) or in lowercase-with-underscores style
  43. * (|some_name|, if lowercase mode is ON).
  44. *
  45. * Nullables:
  46. * |std::nullopt| is emitted as |<null>|.
  47. *
  48. * All others:
  49. * Emitted as strings by calling |ToString|.
  50. *
  51. */
  52. template <class... TArgs>
  53. void Format(TStringBuilderBase* builder, TStaticFormat<TArgs...> fmt, TArgs&&... args);
  54. template <class... TArgs>
  55. void Format(TStringBuilderBase* builder, TRuntimeFormat fmt, TArgs&&... args);
  56. template <class... TArgs>
  57. TString Format(TStaticFormat<TArgs...> fmt, TArgs&&... args);
  58. template <class... TArgs>
  59. TString Format(TRuntimeFormat fmt, TArgs&&... args);
  60. ////////////////////////////////////////////////////////////////////////////////
  61. template <class TRange, class TFormatter>
  62. struct TFormattableView
  63. {
  64. using TBegin = std::decay_t<decltype(std::declval<const TRange>().begin())>;
  65. using TEnd = std::decay_t<decltype(std::declval<const TRange>().end())>;
  66. TBegin RangeBegin;
  67. TEnd RangeEnd;
  68. TFormatter Formatter;
  69. size_t Limit = std::numeric_limits<size_t>::max();
  70. TBegin begin() const;
  71. TEnd end() const;
  72. };
  73. //! Annotates a given #range with #formatter to be applied to each item.
  74. template <class TRange, class TFormatter>
  75. TFormattableView<TRange, TFormatter> MakeFormattableView(
  76. const TRange& range,
  77. TFormatter&& formatter);
  78. template <class TRange, class TFormatter>
  79. TFormattableView<TRange, TFormatter> MakeShrunkFormattableView(
  80. const TRange& range,
  81. TFormatter&& formatter,
  82. size_t limit);
  83. ////////////////////////////////////////////////////////////////////////////////
  84. template <class TFormatter>
  85. struct TFormatterWrapper
  86. {
  87. TFormatter Formatter;
  88. };
  89. // Allows insertion of text conditionally.
  90. // Usage:
  91. /*
  92. NYT::Format(
  93. "Value is %v%v",
  94. 42,
  95. MakeFormatterWrapper([&] (auto* builder) {
  96. If (PossiblyMissingInfo_) {
  97. builder->AppendString(", PossiblyMissingInfo: ");
  98. FormatValue(builder, PossiblyMissingInfo_, "v");
  99. }
  100. }));
  101. */
  102. template <class TFormatter>
  103. TFormatterWrapper<TFormatter> MakeFormatterWrapper(
  104. TFormatter&& formatter);
  105. ////////////////////////////////////////////////////////////////////////////////
  106. template <class... TArgs>
  107. class TLazyMultiValueFormatter;
  108. template <class... TArgs>
  109. void FormatValue(
  110. TStringBuilderBase* builder,
  111. const TLazyMultiValueFormatter<TArgs...>& value,
  112. TStringBuf /*spec*/);
  113. //! A wrapper for a bunch of values that formats them lazily on demand.
  114. /*!
  115. * The intended use of this class is when you need to use the same formatted string
  116. * in several places in the function (e.g. log message tags) and want both to avoid
  117. * code duplication and premature formatting of the values until necessary.
  118. *
  119. * NB: lvalues are captured by reference without lifetime extension.
  120. */
  121. template <class... TArgs>
  122. class TLazyMultiValueFormatter
  123. : private TNonCopyable
  124. {
  125. public:
  126. TLazyMultiValueFormatter(TStringBuf fmt, TArgs&&... args);
  127. // NB(arkady-e1ppa): We actually have to
  128. // forward declare this method as above
  129. // and friend-declare it as specialization
  130. // here because clang is stupid and would
  131. // treat this friend declartion as a hidden friend
  132. // declaration which in turn is treated as a separate symbol
  133. // causing linker to not find the actual definition.
  134. friend void FormatValue<>(
  135. TStringBuilderBase* builder,
  136. const TLazyMultiValueFormatter& value,
  137. TStringBuf /*spec*/);
  138. private:
  139. const TStringBuf Format_;
  140. const std::tuple<TArgs...> Args_;
  141. };
  142. template <class ... Args>
  143. auto MakeLazyMultiValueFormatter(TStringBuf fmt, Args&&... args);
  144. ////////////////////////////////////////////////////////////////////////////////
  145. /*
  146. Example:
  147. FormatVector("One: %v, Two: %v, Three: %v", {1, 2, 3})
  148. => "One: 1, Two: 2, Three: 3"
  149. */
  150. template <size_t Length, class TVector>
  151. void FormatVector(
  152. TStringBuilderBase* builder,
  153. const char (&fmt)[Length],
  154. const TVector& vec);
  155. template <class TVector>
  156. void FormatVector(
  157. TStringBuilderBase* builder,
  158. TStringBuf fmt,
  159. const TVector& vec);
  160. template <size_t Length, class TVector>
  161. TString FormatVector(
  162. const char (&fmt)[Length],
  163. const TVector& vec);
  164. template <class TVector>
  165. TString FormatVector(
  166. TStringBuf fmt,
  167. const TVector& vec);
  168. ////////////////////////////////////////////////////////////////////////////////
  169. } // namespace NYT
  170. #define FORMAT_INL_H_
  171. #include "format-inl.h"
  172. #undef FORMAT_INL_H_