buffer.h 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. // -*- C++ -*-
  2. //===----------------------------------------------------------------------===//
  3. //
  4. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  5. // See https://llvm.org/LICENSE.txt for license information.
  6. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #ifndef _LIBCPP___FORMAT_BUFFER_H
  10. #define _LIBCPP___FORMAT_BUFFER_H
  11. #include <__algorithm/copy_n.h>
  12. #include <__algorithm/fill_n.h>
  13. #include <__algorithm/max.h>
  14. #include <__algorithm/min.h>
  15. #include <__algorithm/ranges_copy_n.h>
  16. #include <__algorithm/transform.h>
  17. #include <__algorithm/unwrap_iter.h>
  18. #include <__concepts/same_as.h>
  19. #include <__config>
  20. #include <__format/concepts.h>
  21. #include <__format/enable_insertable.h>
  22. #include <__format/format_to_n_result.h>
  23. #include <__iterator/back_insert_iterator.h>
  24. #include <__iterator/concepts.h>
  25. #include <__iterator/incrementable_traits.h>
  26. #include <__iterator/iterator_traits.h>
  27. #include <__iterator/wrap_iter.h>
  28. #include <__memory/addressof.h>
  29. #include <__memory/allocate_at_least.h>
  30. #include <__memory/allocator_traits.h>
  31. #include <__memory/construct_at.h>
  32. #include <__memory/ranges_construct_at.h>
  33. #include <__memory/uninitialized_algorithms.h>
  34. #include <__type_traits/add_pointer.h>
  35. #include <__type_traits/conditional.h>
  36. #include <__utility/exception_guard.h>
  37. #include <__utility/move.h>
  38. #include <cstddef>
  39. #include <string_view>
  40. #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
  41. # pragma GCC system_header
  42. #endif
  43. _LIBCPP_PUSH_MACROS
  44. #include <__undef_macros>
  45. _LIBCPP_BEGIN_NAMESPACE_STD
  46. #if _LIBCPP_STD_VER >= 20
  47. namespace __format {
  48. /// A "buffer" that handles writing to the proper iterator.
  49. ///
  50. /// This helper is used together with the @ref back_insert_iterator to offer
  51. /// type-erasure for the formatting functions. This reduces the number to
  52. /// template instantiations.
  53. template <__fmt_char_type _CharT>
  54. class _LIBCPP_TEMPLATE_VIS __output_buffer {
  55. public:
  56. using value_type = _CharT;
  57. template <class _Tp>
  58. _LIBCPP_HIDE_FROM_ABI explicit __output_buffer(_CharT* __ptr, size_t __capacity, _Tp* __obj)
  59. : __ptr_(__ptr),
  60. __capacity_(__capacity),
  61. __flush_([](_CharT* __p, size_t __n, void* __o) { static_cast<_Tp*>(__o)->__flush(__p, __n); }),
  62. __obj_(__obj) {}
  63. _LIBCPP_HIDE_FROM_ABI void __reset(_CharT* __ptr, size_t __capacity) {
  64. __ptr_ = __ptr;
  65. __capacity_ = __capacity;
  66. }
  67. _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return std::back_insert_iterator{*this}; }
  68. // Used in std::back_insert_iterator.
  69. _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) {
  70. __ptr_[__size_++] = __c;
  71. // Profiling showed flushing after adding is more efficient than flushing
  72. // when entering the function.
  73. if (__size_ == __capacity_)
  74. __flush();
  75. }
  76. /// Copies the input __str to the buffer.
  77. ///
  78. /// Since some of the input is generated by std::to_chars, there needs to be a
  79. /// conversion when _CharT is wchar_t.
  80. template <__fmt_char_type _InCharT>
  81. _LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) {
  82. // When the underlying iterator is a simple iterator the __capacity_ is
  83. // infinite. For a string or container back_inserter it isn't. This means
  84. // that adding a large string to the buffer can cause some overhead. In that
  85. // case a better approach could be:
  86. // - flush the buffer
  87. // - container.append(__str.begin(), __str.end());
  88. // The same holds true for the fill.
  89. // For transform it might be slightly harder, however the use case for
  90. // transform is slightly less common; it converts hexadecimal values to
  91. // upper case. For integral these strings are short.
  92. // TODO FMT Look at the improvements above.
  93. size_t __n = __str.size();
  94. __flush_on_overflow(__n);
  95. if (__n < __capacity_) { // push_back requires the buffer to have room for at least one character (so use <).
  96. _VSTD::copy_n(__str.data(), __n, _VSTD::addressof(__ptr_[__size_]));
  97. __size_ += __n;
  98. return;
  99. }
  100. // The output doesn't fit in the internal buffer.
  101. // Copy the data in "__capacity_" sized chunks.
  102. _LIBCPP_ASSERT_UNCATEGORIZED(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
  103. const _InCharT* __first = __str.data();
  104. do {
  105. size_t __chunk = _VSTD::min(__n, __capacity_);
  106. _VSTD::copy_n(__first, __chunk, _VSTD::addressof(__ptr_[__size_]));
  107. __size_ = __chunk;
  108. __first += __chunk;
  109. __n -= __chunk;
  110. __flush();
  111. } while (__n);
  112. }
  113. /// A std::transform wrapper.
  114. ///
  115. /// Like @ref __copy it may need to do type conversion.
  116. template <__fmt_char_type _InCharT, class _UnaryOperation>
  117. _LIBCPP_HIDE_FROM_ABI void __transform(const _InCharT* __first, const _InCharT* __last, _UnaryOperation __operation) {
  118. _LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "not a valid range");
  119. size_t __n = static_cast<size_t>(__last - __first);
  120. __flush_on_overflow(__n);
  121. if (__n < __capacity_) { // push_back requires the buffer to have room for at least one character (so use <).
  122. _VSTD::transform(__first, __last, _VSTD::addressof(__ptr_[__size_]), _VSTD::move(__operation));
  123. __size_ += __n;
  124. return;
  125. }
  126. // The output doesn't fit in the internal buffer.
  127. // Transform the data in "__capacity_" sized chunks.
  128. _LIBCPP_ASSERT_UNCATEGORIZED(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
  129. do {
  130. size_t __chunk = _VSTD::min(__n, __capacity_);
  131. _VSTD::transform(__first, __first + __chunk, _VSTD::addressof(__ptr_[__size_]), __operation);
  132. __size_ = __chunk;
  133. __first += __chunk;
  134. __n -= __chunk;
  135. __flush();
  136. } while (__n);
  137. }
  138. /// A \c fill_n wrapper.
  139. _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) {
  140. __flush_on_overflow(__n);
  141. if (__n < __capacity_) { // push_back requires the buffer to have room for at least one character (so use <).
  142. _VSTD::fill_n(_VSTD::addressof(__ptr_[__size_]), __n, __value);
  143. __size_ += __n;
  144. return;
  145. }
  146. // The output doesn't fit in the internal buffer.
  147. // Fill the buffer in "__capacity_" sized chunks.
  148. _LIBCPP_ASSERT_UNCATEGORIZED(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
  149. do {
  150. size_t __chunk = _VSTD::min(__n, __capacity_);
  151. _VSTD::fill_n(_VSTD::addressof(__ptr_[__size_]), __chunk, __value);
  152. __size_ = __chunk;
  153. __n -= __chunk;
  154. __flush();
  155. } while (__n);
  156. }
  157. _LIBCPP_HIDE_FROM_ABI void __flush() {
  158. __flush_(__ptr_, __size_, __obj_);
  159. __size_ = 0;
  160. }
  161. private:
  162. _CharT* __ptr_;
  163. size_t __capacity_;
  164. size_t __size_{0};
  165. void (*__flush_)(_CharT*, size_t, void*);
  166. void* __obj_;
  167. /// Flushes the buffer when the output operation would overflow the buffer.
  168. ///
  169. /// A simple approach for the overflow detection would be something along the
  170. /// lines:
  171. /// \code
  172. /// // The internal buffer is large enough.
  173. /// if (__n <= __capacity_) {
  174. /// // Flush when we really would overflow.
  175. /// if (__size_ + __n >= __capacity_)
  176. /// __flush();
  177. /// ...
  178. /// }
  179. /// \endcode
  180. ///
  181. /// This approach works for all cases but one:
  182. /// A __format_to_n_buffer_base where \ref __enable_direct_output is true.
  183. /// In that case the \ref __capacity_ of the buffer changes during the first
  184. /// \ref __flush. During that operation the output buffer switches from its
  185. /// __writer_ to its __storage_. The \ref __capacity_ of the former depends
  186. /// on the value of n, of the latter is a fixed size. For example:
  187. /// - a format_to_n call with a 10'000 char buffer,
  188. /// - the buffer is filled with 9'500 chars,
  189. /// - adding 1'000 elements would overflow the buffer so the buffer gets
  190. /// changed and the \ref __capacity_ decreases from 10'000 to
  191. /// __buffer_size (256 at the time of writing).
  192. ///
  193. /// This means that the \ref __flush for this class may need to copy a part of
  194. /// the internal buffer to the proper output. In this example there will be
  195. /// 500 characters that need this copy operation.
  196. ///
  197. /// Note it would be more efficient to write 500 chars directly and then swap
  198. /// the buffers. This would make the code more complex and \ref format_to_n is
  199. /// not the most common use case. Therefore the optimization isn't done.
  200. _LIBCPP_HIDE_FROM_ABI void __flush_on_overflow(size_t __n) {
  201. if (__size_ + __n >= __capacity_)
  202. __flush();
  203. }
  204. };
  205. /// A storage using an internal buffer.
  206. ///
  207. /// This storage is used when writing a single element to the output iterator
  208. /// is expensive.
  209. template <__fmt_char_type _CharT>
  210. class _LIBCPP_TEMPLATE_VIS __internal_storage {
  211. public:
  212. _LIBCPP_HIDE_FROM_ABI _CharT* __begin() { return __buffer_; }
  213. static constexpr size_t __buffer_size = 256 / sizeof(_CharT);
  214. private:
  215. _CharT __buffer_[__buffer_size];
  216. };
  217. /// A storage writing directly to the storage.
  218. ///
  219. /// This requires the storage to be a contiguous buffer of \a _CharT.
  220. /// Since the output is directly written to the underlying storage this class
  221. /// is just an empty class.
  222. template <__fmt_char_type _CharT>
  223. class _LIBCPP_TEMPLATE_VIS __direct_storage {};
  224. template <class _OutIt, class _CharT>
  225. concept __enable_direct_output = __fmt_char_type<_CharT> &&
  226. (same_as<_OutIt, _CharT*>
  227. // TODO(hardening): the following check might not apply to hardened iterators and might need to be wrapped in an
  228. // `#ifdef`.
  229. || same_as<_OutIt, __wrap_iter<_CharT*>>
  230. );
  231. /// Write policy for directly writing to the underlying output.
  232. template <class _OutIt, __fmt_char_type _CharT>
  233. class _LIBCPP_TEMPLATE_VIS __writer_direct {
  234. public:
  235. _LIBCPP_HIDE_FROM_ABI explicit __writer_direct(_OutIt __out_it)
  236. : __out_it_(__out_it) {}
  237. _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() { return __out_it_; }
  238. _LIBCPP_HIDE_FROM_ABI void __flush(_CharT*, size_t __n) {
  239. // _OutIt can be a __wrap_iter<CharT*>. Therefore the original iterator
  240. // is adjusted.
  241. __out_it_ += __n;
  242. }
  243. private:
  244. _OutIt __out_it_;
  245. };
  246. /// Write policy for copying the buffer to the output.
  247. template <class _OutIt, __fmt_char_type _CharT>
  248. class _LIBCPP_TEMPLATE_VIS __writer_iterator {
  249. public:
  250. _LIBCPP_HIDE_FROM_ABI explicit __writer_iterator(_OutIt __out_it)
  251. : __out_it_{_VSTD::move(__out_it)} {}
  252. _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && { return std::move(__out_it_); }
  253. _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
  254. __out_it_ = std::ranges::copy_n(__ptr, __n, std::move(__out_it_)).out;
  255. }
  256. private:
  257. _OutIt __out_it_;
  258. };
  259. /// Concept to see whether a \a _Container is insertable.
  260. ///
  261. /// The concept is used to validate whether multiple calls to a
  262. /// \ref back_insert_iterator can be replace by a call to \c _Container::insert.
  263. ///
  264. /// \note a \a _Container needs to opt-in to the concept by specializing
  265. /// \ref __enable_insertable.
  266. template <class _Container>
  267. concept __insertable =
  268. __enable_insertable<_Container> && __fmt_char_type<typename _Container::value_type> &&
  269. requires(_Container& __t, add_pointer_t<typename _Container::value_type> __first,
  270. add_pointer_t<typename _Container::value_type> __last) { __t.insert(__t.end(), __first, __last); };
  271. /// Extract the container type of a \ref back_insert_iterator.
  272. template <class _It>
  273. struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container {
  274. using type = void;
  275. };
  276. template <__insertable _Container>
  277. struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container<back_insert_iterator<_Container>> {
  278. using type = _Container;
  279. };
  280. /// Write policy for inserting the buffer in a container.
  281. template <class _Container>
  282. class _LIBCPP_TEMPLATE_VIS __writer_container {
  283. public:
  284. using _CharT = typename _Container::value_type;
  285. _LIBCPP_HIDE_FROM_ABI explicit __writer_container(back_insert_iterator<_Container> __out_it)
  286. : __container_{__out_it.__get_container()} {}
  287. _LIBCPP_HIDE_FROM_ABI auto __out_it() { return std::back_inserter(*__container_); }
  288. _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
  289. __container_->insert(__container_->end(), __ptr, __ptr + __n);
  290. }
  291. private:
  292. _Container* __container_;
  293. };
  294. /// Selects the type of the writer used for the output iterator.
  295. template <class _OutIt, class _CharT>
  296. class _LIBCPP_TEMPLATE_VIS __writer_selector {
  297. using _Container = typename __back_insert_iterator_container<_OutIt>::type;
  298. public:
  299. using type = conditional_t<!same_as<_Container, void>, __writer_container<_Container>,
  300. conditional_t<__enable_direct_output<_OutIt, _CharT>, __writer_direct<_OutIt, _CharT>,
  301. __writer_iterator<_OutIt, _CharT>>>;
  302. };
  303. /// The generic formatting buffer.
  304. template <class _OutIt, __fmt_char_type _CharT>
  305. requires(output_iterator<_OutIt, const _CharT&>) class _LIBCPP_TEMPLATE_VIS
  306. __format_buffer {
  307. using _Storage =
  308. conditional_t<__enable_direct_output<_OutIt, _CharT>,
  309. __direct_storage<_CharT>, __internal_storage<_CharT>>;
  310. public:
  311. _LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it)
  312. requires(same_as<_Storage, __internal_storage<_CharT>>)
  313. : __output_(__storage_.__begin(), __storage_.__buffer_size, this), __writer_(_VSTD::move(__out_it)) {}
  314. _LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it) requires(
  315. same_as<_Storage, __direct_storage<_CharT>>)
  316. : __output_(_VSTD::__unwrap_iter(__out_it), size_t(-1), this),
  317. __writer_(_VSTD::move(__out_it)) {}
  318. _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); }
  319. _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { __writer_.__flush(__ptr, __n); }
  320. _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && {
  321. __output_.__flush();
  322. return _VSTD::move(__writer_).__out_it();
  323. }
  324. private:
  325. _LIBCPP_NO_UNIQUE_ADDRESS _Storage __storage_;
  326. __output_buffer<_CharT> __output_;
  327. typename __writer_selector<_OutIt, _CharT>::type __writer_;
  328. };
  329. /// A buffer that counts the number of insertions.
  330. ///
  331. /// Since \ref formatted_size only needs to know the size, the output itself is
  332. /// discarded.
  333. template <__fmt_char_type _CharT>
  334. class _LIBCPP_TEMPLATE_VIS __formatted_size_buffer {
  335. public:
  336. _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); }
  337. _LIBCPP_HIDE_FROM_ABI void __flush(const _CharT*, size_t __n) { __size_ += __n; }
  338. _LIBCPP_HIDE_FROM_ABI size_t __result() && {
  339. __output_.__flush();
  340. return __size_;
  341. }
  342. private:
  343. __internal_storage<_CharT> __storage_;
  344. __output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this};
  345. size_t __size_{0};
  346. };
  347. /// The base of a buffer that counts and limits the number of insertions.
  348. template <class _OutIt, __fmt_char_type _CharT, bool>
  349. requires(output_iterator<_OutIt, const _CharT&>)
  350. struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base {
  351. using _Size = iter_difference_t<_OutIt>;
  352. public:
  353. _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __max_size)
  354. : __writer_(_VSTD::move(__out_it)), __max_size_(_VSTD::max(_Size(0), __max_size)) {}
  355. _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
  356. if (_Size(__size_) <= __max_size_)
  357. __writer_.__flush(__ptr, _VSTD::min(_Size(__n), __max_size_ - __size_));
  358. __size_ += __n;
  359. }
  360. protected:
  361. __internal_storage<_CharT> __storage_;
  362. __output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this};
  363. typename __writer_selector<_OutIt, _CharT>::type __writer_;
  364. _Size __max_size_;
  365. _Size __size_{0};
  366. };
  367. /// The base of a buffer that counts and limits the number of insertions.
  368. ///
  369. /// This version is used when \c __enable_direct_output<_OutIt, _CharT> == true.
  370. ///
  371. /// This class limits the size available to the direct writer so it will not
  372. /// exceed the maximum number of code units.
  373. template <class _OutIt, __fmt_char_type _CharT>
  374. requires(output_iterator<_OutIt, const _CharT&>)
  375. class _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base<_OutIt, _CharT, true> {
  376. using _Size = iter_difference_t<_OutIt>;
  377. public:
  378. _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __max_size)
  379. : __output_(_VSTD::__unwrap_iter(__out_it), __max_size, this),
  380. __writer_(_VSTD::move(__out_it)),
  381. __max_size_(__max_size) {
  382. if (__max_size <= 0) [[unlikely]]
  383. __output_.__reset(__storage_.__begin(), __storage_.__buffer_size);
  384. }
  385. _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
  386. // A __flush to the direct writer happens in the following occasions:
  387. // - The format function has written the maximum number of allowed code
  388. // units. At this point it's no longer valid to write to this writer. So
  389. // switch to the internal storage. This internal storage doesn't need to
  390. // be written anywhere so the __flush for that storage writes no output.
  391. // - Like above, but the next "mass write" operation would overflow the
  392. // buffer. In that case the buffer is pre-emptively switched. The still
  393. // valid code units will be written separately.
  394. // - The format_to_n function is finished. In this case there's no need to
  395. // switch the buffer, but for simplicity the buffers are still switched.
  396. // When the __max_size <= 0 the constructor already switched the buffers.
  397. if (__size_ == 0 && __ptr != __storage_.__begin()) {
  398. __writer_.__flush(__ptr, __n);
  399. __output_.__reset(__storage_.__begin(), __storage_.__buffer_size);
  400. } else if (__size_ < __max_size_) {
  401. // Copies a part of the internal buffer to the output up to n characters.
  402. // See __output_buffer<_CharT>::__flush_on_overflow for more information.
  403. _Size __s = _VSTD::min(_Size(__n), __max_size_ - __size_);
  404. std::copy_n(__ptr, __s, __writer_.__out_it());
  405. __writer_.__flush(__ptr, __s);
  406. }
  407. __size_ += __n;
  408. }
  409. protected:
  410. __internal_storage<_CharT> __storage_;
  411. __output_buffer<_CharT> __output_;
  412. __writer_direct<_OutIt, _CharT> __writer_;
  413. _Size __max_size_;
  414. _Size __size_{0};
  415. };
  416. /// The buffer that counts and limits the number of insertions.
  417. template <class _OutIt, __fmt_char_type _CharT>
  418. requires(output_iterator<_OutIt, const _CharT&>)
  419. struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer final
  420. : public __format_to_n_buffer_base< _OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>> {
  421. using _Base = __format_to_n_buffer_base<_OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>>;
  422. using _Size = iter_difference_t<_OutIt>;
  423. public:
  424. _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer(_OutIt __out_it, _Size __max_size)
  425. : _Base(_VSTD::move(__out_it), __max_size) {}
  426. _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return this->__output_.__make_output_iterator(); }
  427. _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __result() && {
  428. this->__output_.__flush();
  429. return {_VSTD::move(this->__writer_).__out_it(), this->__size_};
  430. }
  431. };
  432. // A dynamically growing buffer intended to be used for retargeting a context.
  433. //
  434. // P2286 Formatting ranges adds range formatting support. It allows the user to
  435. // specify the minimum width for the entire formatted range. The width of the
  436. // range is not known until the range is formatted. Formatting is done to an
  437. // output_iterator so there's no guarantee it would be possible to add the fill
  438. // to the front of the output. Instead the range is formatted to a temporary
  439. // buffer and that buffer is formatted as a string.
  440. //
  441. // There is an issue with that approach, the format context used in
  442. // std::formatter<T>::format contains the output iterator used as part of its
  443. // type. So using this output iterator means there needs to be a new format
  444. // context and the format arguments need to be retargeted to the new context.
  445. // This retargeting is done by a basic_format_context specialized for the
  446. // __iterator of this container.
  447. //
  448. // This class uses its own buffer management, since using vector
  449. // would lead to a circular include with formatter for vector<bool>.
  450. template <__fmt_char_type _CharT>
  451. class _LIBCPP_TEMPLATE_VIS __retarget_buffer {
  452. using _Alloc = allocator<_CharT>;
  453. public:
  454. using value_type = _CharT;
  455. struct __iterator {
  456. using difference_type = ptrdiff_t;
  457. using value_type = _CharT;
  458. _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(__retarget_buffer& __buffer)
  459. : __buffer_(std::addressof(__buffer)) {}
  460. _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(const _CharT& __c) {
  461. __buffer_->push_back(__c);
  462. return *this;
  463. }
  464. _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(_CharT&& __c) {
  465. __buffer_->push_back(__c);
  466. return *this;
  467. }
  468. _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator*() { return *this; }
  469. _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { return *this; }
  470. _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) { return *this; }
  471. __retarget_buffer* __buffer_;
  472. };
  473. __retarget_buffer(const __retarget_buffer&) = delete;
  474. __retarget_buffer& operator=(const __retarget_buffer&) = delete;
  475. _LIBCPP_HIDE_FROM_ABI explicit __retarget_buffer(size_t __size_hint) {
  476. // When the initial size is very small a lot of resizes happen
  477. // when elements added. So use a hard-coded minimum size.
  478. //
  479. // Note a size < 2 will not work
  480. // - 0 there is no buffer, while push_back requires 1 empty element.
  481. // - 1 multiplied by the grow factor is 1 and thus the buffer never
  482. // grows.
  483. auto __result = std::__allocate_at_least(__alloc_, std::max(__size_hint, 256 / sizeof(_CharT)));
  484. __ptr_ = __result.ptr;
  485. __capacity_ = __result.count;
  486. }
  487. _LIBCPP_HIDE_FROM_ABI ~__retarget_buffer() {
  488. ranges::destroy_n(__ptr_, __size_);
  489. allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);
  490. }
  491. _LIBCPP_HIDE_FROM_ABI __iterator __make_output_iterator() { return __iterator{*this}; }
  492. _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) {
  493. std::construct_at(__ptr_ + __size_, __c);
  494. ++__size_;
  495. if (__size_ == __capacity_)
  496. __grow_buffer();
  497. }
  498. template <__fmt_char_type _InCharT>
  499. _LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) {
  500. size_t __n = __str.size();
  501. if (__size_ + __n >= __capacity_)
  502. // Push_back requires the buffer to have room for at least one character.
  503. __grow_buffer(__size_ + __n + 1);
  504. std::uninitialized_copy_n(__str.data(), __n, __ptr_ + __size_);
  505. __size_ += __n;
  506. }
  507. template <__fmt_char_type _InCharT, class _UnaryOperation>
  508. _LIBCPP_HIDE_FROM_ABI void __transform(const _InCharT* __first, const _InCharT* __last, _UnaryOperation __operation) {
  509. _LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "not a valid range");
  510. size_t __n = static_cast<size_t>(__last - __first);
  511. if (__size_ + __n >= __capacity_)
  512. // Push_back requires the buffer to have room for at least one character.
  513. __grow_buffer(__size_ + __n + 1);
  514. std::uninitialized_default_construct_n(__ptr_ + __size_, __n);
  515. std::transform(__first, __last, __ptr_ + __size_, std::move(__operation));
  516. __size_ += __n;
  517. }
  518. _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) {
  519. if (__size_ + __n >= __capacity_)
  520. // Push_back requires the buffer to have room for at least one character.
  521. __grow_buffer(__size_ + __n + 1);
  522. std::uninitialized_fill_n(__ptr_ + __size_, __n, __value);
  523. __size_ += __n;
  524. }
  525. _LIBCPP_HIDE_FROM_ABI basic_string_view<_CharT> __view() { return {__ptr_, __size_}; }
  526. private:
  527. _LIBCPP_HIDE_FROM_ABI void __grow_buffer() { __grow_buffer(__capacity_ * 1.6); }
  528. _LIBCPP_HIDE_FROM_ABI void __grow_buffer(size_t __capacity) {
  529. _LIBCPP_ASSERT_UNCATEGORIZED(__capacity > __capacity_, "the buffer must grow");
  530. auto __result = std::__allocate_at_least(__alloc_, __capacity);
  531. auto __guard = std::__make_exception_guard([&] {
  532. allocator_traits<_Alloc>::deallocate(__alloc_, __result.ptr, __result.count);
  533. });
  534. // This shouldn't throw, but just to be safe. Note that at -O1 this
  535. // guard is optimized away so there is no runtime overhead.
  536. std::uninitialized_move_n(__ptr_, __size_, __result.ptr);
  537. __guard.__complete();
  538. ranges::destroy_n(__ptr_, __size_);
  539. allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);
  540. __ptr_ = __result.ptr;
  541. __capacity_ = __result.count;
  542. }
  543. _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_;
  544. _CharT* __ptr_;
  545. size_t __capacity_;
  546. size_t __size_{0};
  547. };
  548. } // namespace __format
  549. #endif //_LIBCPP_STD_VER >= 20
  550. _LIBCPP_END_NAMESPACE_STD
  551. _LIBCPP_POP_MACROS
  552. #endif // _LIBCPP___FORMAT_BUFFER_H