string_builder-inl.h 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. #ifndef STRING_BUILDER_INL_H_
  2. #error "Direct inclusion of this file is not allowed, include string.h"
  3. // For the sake of sane code completion.
  4. #include "string_builder.h"
  5. #endif
  6. #include <library/cpp/yt/assert/assert.h>
  7. #include <util/stream/str.h>
  8. namespace NYT {
  9. ////////////////////////////////////////////////////////////////////////////////
  10. inline char* TStringBuilderBase::Preallocate(size_t size)
  11. {
  12. Reserve(size + GetLength());
  13. return Current_;
  14. }
  15. inline void TStringBuilderBase::Reserve(size_t size)
  16. {
  17. if (Y_UNLIKELY(End_ - Begin_ < static_cast<ssize_t>(size))) {
  18. size_t length = GetLength();
  19. auto newLength = std::max(size, MinBufferLength);
  20. DoReserve(newLength);
  21. Current_ = Begin_ + length;
  22. }
  23. }
  24. inline size_t TStringBuilderBase::GetLength() const
  25. {
  26. return Current_ ? Current_ - Begin_ : 0;
  27. }
  28. inline TStringBuf TStringBuilderBase::GetBuffer() const
  29. {
  30. return TStringBuf(Begin_, Current_);
  31. }
  32. inline void TStringBuilderBase::Advance(size_t size)
  33. {
  34. Current_ += size;
  35. YT_ASSERT(Current_ <= End_);
  36. }
  37. inline void TStringBuilderBase::AppendChar(char ch)
  38. {
  39. *Preallocate(1) = ch;
  40. Advance(1);
  41. }
  42. inline void TStringBuilderBase::AppendChar(char ch, int n)
  43. {
  44. YT_ASSERT(n >= 0);
  45. if (Y_LIKELY(0 != n)) {
  46. char* dst = Preallocate(n);
  47. ::memset(dst, ch, n);
  48. Advance(n);
  49. }
  50. }
  51. inline void TStringBuilderBase::AppendString(TStringBuf str)
  52. {
  53. if (Y_LIKELY(str)) {
  54. char* dst = Preallocate(str.length());
  55. ::memcpy(dst, str.begin(), str.length());
  56. Advance(str.length());
  57. }
  58. }
  59. inline void TStringBuilderBase::AppendString(const char* str)
  60. {
  61. AppendString(TStringBuf(str));
  62. }
  63. inline void TStringBuilderBase::Reset()
  64. {
  65. Begin_ = Current_ = End_ = nullptr;
  66. DoReset();
  67. }
  68. template <class... TArgs>
  69. void TStringBuilderBase::AppendFormat(TStringBuf format, TArgs&& ... args)
  70. {
  71. Format(this, TRuntimeFormat{format}, std::forward<TArgs>(args)...);
  72. }
  73. template <size_t Length, class... TArgs>
  74. void TStringBuilderBase::AppendFormat(const char (&format)[Length], TArgs&& ... args)
  75. {
  76. Format(this, TRuntimeFormat{format}, std::forward<TArgs>(args)...);
  77. }
  78. ////////////////////////////////////////////////////////////////////////////////
  79. inline TString TStringBuilder::Flush()
  80. {
  81. Buffer_.resize(GetLength());
  82. auto result = std::move(Buffer_);
  83. Reset();
  84. return result;
  85. }
  86. inline void TStringBuilder::DoReset()
  87. {
  88. Buffer_ = {};
  89. }
  90. inline void TStringBuilder::DoReserve(size_t newLength)
  91. {
  92. Buffer_.ReserveAndResize(newLength);
  93. auto capacity = Buffer_.capacity();
  94. Buffer_.ReserveAndResize(capacity);
  95. Begin_ = &*Buffer_.begin();
  96. End_ = Begin_ + capacity;
  97. }
  98. ////////////////////////////////////////////////////////////////////////////////
  99. inline void FormatValue(TStringBuilderBase* builder, const TStringBuilder& value, TStringBuf /*spec*/)
  100. {
  101. builder->AppendString(value.GetBuffer());
  102. }
  103. template <class T>
  104. TString ToStringViaBuilder(const T& value, TStringBuf spec)
  105. {
  106. TStringBuilder builder;
  107. FormatValue(&builder, value, spec);
  108. return builder.Flush();
  109. }
  110. ////////////////////////////////////////////////////////////////////////////////
  111. // Compatibility for users of NYT::ToString(nyt_type).
  112. template <CFormattable T>
  113. TString ToString(const T& t)
  114. {
  115. return ToStringViaBuilder(t);
  116. }
  117. // Sometime we want to implement
  118. // FormatValue using util's ToString
  119. // However, if we inside the FormatValue
  120. // we cannot just call the ToString since
  121. // in this scope T is already CFormattable
  122. // and ToString will call the very
  123. // FormatValue we are implementing,
  124. // causing an infinite recursion loop.
  125. // This method is basically a call to
  126. // util's ToString default implementation.
  127. template <class T>
  128. TString ToStringIgnoringFormatValue(const T& t)
  129. {
  130. TString s;
  131. ::TStringOutput o(s);
  132. o << t;
  133. return s;
  134. }
  135. ////////////////////////////////////////////////////////////////////////////////
  136. } // namespace NYT
  137. #include <util/string/cast.h>
  138. // util/string/cast.h extension for yt and std types only
  139. // TODO(arkady-e1ppa): Abolish ::ToString in
  140. // favour of either NYT::ToString or
  141. // automatic formatting wherever it is needed.
  142. namespace NPrivate {
  143. template <class T>
  144. requires (
  145. (NYT::NDetail::IsNYTName<T>() ||
  146. NYT::NDetail::IsStdName<T>()) &&
  147. NYT::CFormattable<T>)
  148. struct TToString<T, false>
  149. {
  150. static TString Cvt(const T& t)
  151. {
  152. return NYT::ToStringViaBuilder(t);
  153. }
  154. };
  155. } // namespace NPrivate