buffer.h 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  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. std::copy_n(__str.data(), __n, std::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_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
  103. const _InCharT* __first = __str.data();
  104. do {
  105. size_t __chunk = std::min(__n, __capacity_);
  106. std::copy_n(__first, __chunk, std::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 <contiguous_iterator _Iterator,
  117. class _UnaryOperation,
  118. __fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
  119. _LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
  120. _LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range");
  121. size_t __n = static_cast<size_t>(__last - __first);
  122. __flush_on_overflow(__n);
  123. if (__n < __capacity_) { // push_back requires the buffer to have room for at least one character (so use <).
  124. std::transform(__first, __last, std::addressof(__ptr_[__size_]), std::move(__operation));
  125. __size_ += __n;
  126. return;
  127. }
  128. // The output doesn't fit in the internal buffer.
  129. // Transform the data in "__capacity_" sized chunks.
  130. _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
  131. do {
  132. size_t __chunk = std::min(__n, __capacity_);
  133. std::transform(__first, __first + __chunk, std::addressof(__ptr_[__size_]), __operation);
  134. __size_ = __chunk;
  135. __first += __chunk;
  136. __n -= __chunk;
  137. __flush();
  138. } while (__n);
  139. }
  140. /// A \c fill_n wrapper.
  141. _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) {
  142. __flush_on_overflow(__n);
  143. if (__n < __capacity_) { // push_back requires the buffer to have room for at least one character (so use <).
  144. std::fill_n(std::addressof(__ptr_[__size_]), __n, __value);
  145. __size_ += __n;
  146. return;
  147. }
  148. // The output doesn't fit in the internal buffer.
  149. // Fill the buffer in "__capacity_" sized chunks.
  150. _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
  151. do {
  152. size_t __chunk = std::min(__n, __capacity_);
  153. std::fill_n(std::addressof(__ptr_[__size_]), __chunk, __value);
  154. __size_ = __chunk;
  155. __n -= __chunk;
  156. __flush();
  157. } while (__n);
  158. }
  159. _LIBCPP_HIDE_FROM_ABI void __flush() {
  160. __flush_(__ptr_, __size_, __obj_);
  161. __size_ = 0;
  162. }
  163. private:
  164. _CharT* __ptr_;
  165. size_t __capacity_;
  166. size_t __size_{0};
  167. void (*__flush_)(_CharT*, size_t, void*);
  168. void* __obj_;
  169. /// Flushes the buffer when the output operation would overflow the buffer.
  170. ///
  171. /// A simple approach for the overflow detection would be something along the
  172. /// lines:
  173. /// \code
  174. /// // The internal buffer is large enough.
  175. /// if (__n <= __capacity_) {
  176. /// // Flush when we really would overflow.
  177. /// if (__size_ + __n >= __capacity_)
  178. /// __flush();
  179. /// ...
  180. /// }
  181. /// \endcode
  182. ///
  183. /// This approach works for all cases but one:
  184. /// A __format_to_n_buffer_base where \ref __enable_direct_output is true.
  185. /// In that case the \ref __capacity_ of the buffer changes during the first
  186. /// \ref __flush. During that operation the output buffer switches from its
  187. /// __writer_ to its __storage_. The \ref __capacity_ of the former depends
  188. /// on the value of n, of the latter is a fixed size. For example:
  189. /// - a format_to_n call with a 10'000 char buffer,
  190. /// - the buffer is filled with 9'500 chars,
  191. /// - adding 1'000 elements would overflow the buffer so the buffer gets
  192. /// changed and the \ref __capacity_ decreases from 10'000 to
  193. /// __buffer_size (256 at the time of writing).
  194. ///
  195. /// This means that the \ref __flush for this class may need to copy a part of
  196. /// the internal buffer to the proper output. In this example there will be
  197. /// 500 characters that need this copy operation.
  198. ///
  199. /// Note it would be more efficient to write 500 chars directly and then swap
  200. /// the buffers. This would make the code more complex and \ref format_to_n is
  201. /// not the most common use case. Therefore the optimization isn't done.
  202. _LIBCPP_HIDE_FROM_ABI void __flush_on_overflow(size_t __n) {
  203. if (__size_ + __n >= __capacity_)
  204. __flush();
  205. }
  206. };
  207. /// A storage using an internal buffer.
  208. ///
  209. /// This storage is used when writing a single element to the output iterator
  210. /// is expensive.
  211. template <__fmt_char_type _CharT>
  212. class _LIBCPP_TEMPLATE_VIS __internal_storage {
  213. public:
  214. _LIBCPP_HIDE_FROM_ABI _CharT* __begin() { return __buffer_; }
  215. static constexpr size_t __buffer_size = 256 / sizeof(_CharT);
  216. private:
  217. _CharT __buffer_[__buffer_size];
  218. };
  219. /// A storage writing directly to the storage.
  220. ///
  221. /// This requires the storage to be a contiguous buffer of \a _CharT.
  222. /// Since the output is directly written to the underlying storage this class
  223. /// is just an empty class.
  224. template <__fmt_char_type _CharT>
  225. class _LIBCPP_TEMPLATE_VIS __direct_storage {};
  226. template <class _OutIt, class _CharT>
  227. concept __enable_direct_output =
  228. __fmt_char_type<_CharT> &&
  229. (same_as<_OutIt, _CharT*>
  230. // TODO(hardening): the following check might not apply to hardened iterators and might need to be wrapped in an
  231. // `#ifdef`.
  232. || same_as<_OutIt, __wrap_iter<_CharT*>>);
  233. /// Write policy for directly writing to the underlying output.
  234. template <class _OutIt, __fmt_char_type _CharT>
  235. class _LIBCPP_TEMPLATE_VIS __writer_direct {
  236. public:
  237. _LIBCPP_HIDE_FROM_ABI explicit __writer_direct(_OutIt __out_it) : __out_it_(__out_it) {}
  238. _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() { return __out_it_; }
  239. _LIBCPP_HIDE_FROM_ABI void __flush(_CharT*, size_t __n) {
  240. // _OutIt can be a __wrap_iter<CharT*>. Therefore the original iterator
  241. // is adjusted.
  242. __out_it_ += __n;
  243. }
  244. private:
  245. _OutIt __out_it_;
  246. };
  247. /// Write policy for copying the buffer to the output.
  248. template <class _OutIt, __fmt_char_type _CharT>
  249. class _LIBCPP_TEMPLATE_VIS __writer_iterator {
  250. public:
  251. _LIBCPP_HIDE_FROM_ABI explicit __writer_iterator(_OutIt __out_it) : __out_it_{std::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,
  270. add_pointer_t<typename _Container::value_type> __first,
  271. add_pointer_t<typename _Container::value_type> __last) { __t.insert(__t.end(), __first, __last); };
  272. /// Extract the container type of a \ref back_insert_iterator.
  273. template <class _It>
  274. struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container {
  275. using type = void;
  276. };
  277. template <__insertable _Container>
  278. struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container<back_insert_iterator<_Container>> {
  279. using type = _Container;
  280. };
  281. /// Write policy for inserting the buffer in a container.
  282. template <class _Container>
  283. class _LIBCPP_TEMPLATE_VIS __writer_container {
  284. public:
  285. using _CharT = typename _Container::value_type;
  286. _LIBCPP_HIDE_FROM_ABI explicit __writer_container(back_insert_iterator<_Container> __out_it)
  287. : __container_{__out_it.__get_container()} {}
  288. _LIBCPP_HIDE_FROM_ABI auto __out_it() { return std::back_inserter(*__container_); }
  289. _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
  290. __container_->insert(__container_->end(), __ptr, __ptr + __n);
  291. }
  292. private:
  293. _Container* __container_;
  294. };
  295. /// Selects the type of the writer used for the output iterator.
  296. template <class _OutIt, class _CharT>
  297. class _LIBCPP_TEMPLATE_VIS __writer_selector {
  298. using _Container = typename __back_insert_iterator_container<_OutIt>::type;
  299. public:
  300. using type =
  301. conditional_t<!same_as<_Container, void>,
  302. __writer_container<_Container>,
  303. conditional_t<__enable_direct_output<_OutIt, _CharT>,
  304. __writer_direct<_OutIt, _CharT>,
  305. __writer_iterator<_OutIt, _CharT>>>;
  306. };
  307. /// The generic formatting buffer.
  308. template <class _OutIt, __fmt_char_type _CharT>
  309. requires(output_iterator<_OutIt, const _CharT&>)
  310. class _LIBCPP_TEMPLATE_VIS __format_buffer {
  311. using _Storage =
  312. conditional_t<__enable_direct_output<_OutIt, _CharT>, __direct_storage<_CharT>, __internal_storage<_CharT>>;
  313. public:
  314. _LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it)
  315. requires(same_as<_Storage, __internal_storage<_CharT>>)
  316. : __output_(__storage_.__begin(), __storage_.__buffer_size, this), __writer_(std::move(__out_it)) {}
  317. _LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it)
  318. requires(same_as<_Storage, __direct_storage<_CharT>>)
  319. : __output_(std::__unwrap_iter(__out_it), size_t(-1), this), __writer_(std::move(__out_it)) {}
  320. _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); }
  321. _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { __writer_.__flush(__ptr, __n); }
  322. _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && {
  323. __output_.__flush();
  324. return std::move(__writer_).__out_it();
  325. }
  326. private:
  327. _LIBCPP_NO_UNIQUE_ADDRESS _Storage __storage_;
  328. __output_buffer<_CharT> __output_;
  329. typename __writer_selector<_OutIt, _CharT>::type __writer_;
  330. };
  331. /// A buffer that counts the number of insertions.
  332. ///
  333. /// Since \ref formatted_size only needs to know the size, the output itself is
  334. /// discarded.
  335. template <__fmt_char_type _CharT>
  336. class _LIBCPP_TEMPLATE_VIS __formatted_size_buffer {
  337. public:
  338. _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); }
  339. _LIBCPP_HIDE_FROM_ABI void __flush(const _CharT*, size_t __n) { __size_ += __n; }
  340. _LIBCPP_HIDE_FROM_ABI size_t __result() && {
  341. __output_.__flush();
  342. return __size_;
  343. }
  344. private:
  345. __internal_storage<_CharT> __storage_;
  346. __output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this};
  347. size_t __size_{0};
  348. };
  349. /// The base of a buffer that counts and limits the number of insertions.
  350. template <class _OutIt, __fmt_char_type _CharT, bool>
  351. requires(output_iterator<_OutIt, const _CharT&>)
  352. struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base {
  353. using _Size = iter_difference_t<_OutIt>;
  354. public:
  355. _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __max_size)
  356. : __writer_(std::move(__out_it)), __max_size_(std::max(_Size(0), __max_size)) {}
  357. _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
  358. if (_Size(__size_) <= __max_size_)
  359. __writer_.__flush(__ptr, std::min(_Size(__n), __max_size_ - __size_));
  360. __size_ += __n;
  361. }
  362. protected:
  363. __internal_storage<_CharT> __storage_;
  364. __output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this};
  365. typename __writer_selector<_OutIt, _CharT>::type __writer_;
  366. _Size __max_size_;
  367. _Size __size_{0};
  368. };
  369. /// The base of a buffer that counts and limits the number of insertions.
  370. ///
  371. /// This version is used when \c __enable_direct_output<_OutIt, _CharT> == true.
  372. ///
  373. /// This class limits the size available to the direct writer so it will not
  374. /// exceed the maximum number of code units.
  375. template <class _OutIt, __fmt_char_type _CharT>
  376. requires(output_iterator<_OutIt, const _CharT&>)
  377. class _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base<_OutIt, _CharT, true> {
  378. using _Size = iter_difference_t<_OutIt>;
  379. public:
  380. _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __max_size)
  381. : __output_(std::__unwrap_iter(__out_it), __max_size, this),
  382. __writer_(std::move(__out_it)),
  383. __max_size_(__max_size) {
  384. if (__max_size <= 0) [[unlikely]]
  385. __output_.__reset(__storage_.__begin(), __storage_.__buffer_size);
  386. }
  387. _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) {
  388. // A __flush to the direct writer happens in the following occasions:
  389. // - The format function has written the maximum number of allowed code
  390. // units. At this point it's no longer valid to write to this writer. So
  391. // switch to the internal storage. This internal storage doesn't need to
  392. // be written anywhere so the __flush for that storage writes no output.
  393. // - Like above, but the next "mass write" operation would overflow the
  394. // buffer. In that case the buffer is pre-emptively switched. The still
  395. // valid code units will be written separately.
  396. // - The format_to_n function is finished. In this case there's no need to
  397. // switch the buffer, but for simplicity the buffers are still switched.
  398. // When the __max_size <= 0 the constructor already switched the buffers.
  399. if (__size_ == 0 && __ptr != __storage_.__begin()) {
  400. __writer_.__flush(__ptr, __n);
  401. __output_.__reset(__storage_.__begin(), __storage_.__buffer_size);
  402. } else if (__size_ < __max_size_) {
  403. // Copies a part of the internal buffer to the output up to n characters.
  404. // See __output_buffer<_CharT>::__flush_on_overflow for more information.
  405. _Size __s = std::min(_Size(__n), __max_size_ - __size_);
  406. std::copy_n(__ptr, __s, __writer_.__out_it());
  407. __writer_.__flush(__ptr, __s);
  408. }
  409. __size_ += __n;
  410. }
  411. protected:
  412. __internal_storage<_CharT> __storage_;
  413. __output_buffer<_CharT> __output_;
  414. __writer_direct<_OutIt, _CharT> __writer_;
  415. _Size __max_size_;
  416. _Size __size_{0};
  417. };
  418. /// The buffer that counts and limits the number of insertions.
  419. template <class _OutIt, __fmt_char_type _CharT>
  420. requires(output_iterator<_OutIt, const _CharT&>)
  421. struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer final
  422. : public __format_to_n_buffer_base< _OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>> {
  423. using _Base = __format_to_n_buffer_base<_OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>>;
  424. using _Size = iter_difference_t<_OutIt>;
  425. public:
  426. _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer(_OutIt __out_it, _Size __max_size)
  427. : _Base(std::move(__out_it), __max_size) {}
  428. _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return this->__output_.__make_output_iterator(); }
  429. _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __result() && {
  430. this->__output_.__flush();
  431. return {std::move(this->__writer_).__out_it(), this->__size_};
  432. }
  433. };
  434. // A dynamically growing buffer intended to be used for retargeting a context.
  435. //
  436. // P2286 Formatting ranges adds range formatting support. It allows the user to
  437. // specify the minimum width for the entire formatted range. The width of the
  438. // range is not known until the range is formatted. Formatting is done to an
  439. // output_iterator so there's no guarantee it would be possible to add the fill
  440. // to the front of the output. Instead the range is formatted to a temporary
  441. // buffer and that buffer is formatted as a string.
  442. //
  443. // There is an issue with that approach, the format context used in
  444. // std::formatter<T>::format contains the output iterator used as part of its
  445. // type. So using this output iterator means there needs to be a new format
  446. // context and the format arguments need to be retargeted to the new context.
  447. // This retargeting is done by a basic_format_context specialized for the
  448. // __iterator of this container.
  449. //
  450. // This class uses its own buffer management, since using vector
  451. // would lead to a circular include with formatter for vector<bool>.
  452. template <__fmt_char_type _CharT>
  453. class _LIBCPP_TEMPLATE_VIS __retarget_buffer {
  454. using _Alloc = allocator<_CharT>;
  455. public:
  456. using value_type = _CharT;
  457. struct __iterator {
  458. using difference_type = ptrdiff_t;
  459. using value_type = _CharT;
  460. _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(__retarget_buffer& __buffer)
  461. : __buffer_(std::addressof(__buffer)) {}
  462. _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(const _CharT& __c) {
  463. __buffer_->push_back(__c);
  464. return *this;
  465. }
  466. _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(_CharT&& __c) {
  467. __buffer_->push_back(__c);
  468. return *this;
  469. }
  470. _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator*() { return *this; }
  471. _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { return *this; }
  472. _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) { return *this; }
  473. __retarget_buffer* __buffer_;
  474. };
  475. __retarget_buffer(const __retarget_buffer&) = delete;
  476. __retarget_buffer& operator=(const __retarget_buffer&) = delete;
  477. _LIBCPP_HIDE_FROM_ABI explicit __retarget_buffer(size_t __size_hint) {
  478. // When the initial size is very small a lot of resizes happen
  479. // when elements added. So use a hard-coded minimum size.
  480. //
  481. // Note a size < 2 will not work
  482. // - 0 there is no buffer, while push_back requires 1 empty element.
  483. // - 1 multiplied by the grow factor is 1 and thus the buffer never
  484. // grows.
  485. auto __result = std::__allocate_at_least(__alloc_, std::max(__size_hint, 256 / sizeof(_CharT)));
  486. __ptr_ = __result.ptr;
  487. __capacity_ = __result.count;
  488. }
  489. _LIBCPP_HIDE_FROM_ABI ~__retarget_buffer() {
  490. ranges::destroy_n(__ptr_, __size_);
  491. allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);
  492. }
  493. _LIBCPP_HIDE_FROM_ABI __iterator __make_output_iterator() { return __iterator{*this}; }
  494. _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) {
  495. std::construct_at(__ptr_ + __size_, __c);
  496. ++__size_;
  497. if (__size_ == __capacity_)
  498. __grow_buffer();
  499. }
  500. template <__fmt_char_type _InCharT>
  501. _LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) {
  502. size_t __n = __str.size();
  503. if (__size_ + __n >= __capacity_)
  504. // Push_back requires the buffer to have room for at least one character.
  505. __grow_buffer(__size_ + __n + 1);
  506. std::uninitialized_copy_n(__str.data(), __n, __ptr_ + __size_);
  507. __size_ += __n;
  508. }
  509. template <contiguous_iterator _Iterator,
  510. class _UnaryOperation,
  511. __fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
  512. _LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
  513. _LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range");
  514. size_t __n = static_cast<size_t>(__last - __first);
  515. if (__size_ + __n >= __capacity_)
  516. // Push_back requires the buffer to have room for at least one character.
  517. __grow_buffer(__size_ + __n + 1);
  518. std::uninitialized_default_construct_n(__ptr_ + __size_, __n);
  519. std::transform(__first, __last, __ptr_ + __size_, std::move(__operation));
  520. __size_ += __n;
  521. }
  522. _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) {
  523. if (__size_ + __n >= __capacity_)
  524. // Push_back requires the buffer to have room for at least one character.
  525. __grow_buffer(__size_ + __n + 1);
  526. std::uninitialized_fill_n(__ptr_ + __size_, __n, __value);
  527. __size_ += __n;
  528. }
  529. _LIBCPP_HIDE_FROM_ABI basic_string_view<_CharT> __view() { return {__ptr_, __size_}; }
  530. private:
  531. _LIBCPP_HIDE_FROM_ABI void __grow_buffer() { __grow_buffer(__capacity_ * 1.6); }
  532. _LIBCPP_HIDE_FROM_ABI void __grow_buffer(size_t __capacity) {
  533. _LIBCPP_ASSERT_INTERNAL(__capacity > __capacity_, "the buffer must grow");
  534. auto __result = std::__allocate_at_least(__alloc_, __capacity);
  535. auto __guard = std::__make_exception_guard([&] {
  536. allocator_traits<_Alloc>::deallocate(__alloc_, __result.ptr, __result.count);
  537. });
  538. // This shouldn't throw, but just to be safe. Note that at -O1 this
  539. // guard is optimized away so there is no runtime overhead.
  540. std::uninitialized_move_n(__ptr_, __size_, __result.ptr);
  541. __guard.__complete();
  542. ranges::destroy_n(__ptr_, __size_);
  543. allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_);
  544. __ptr_ = __result.ptr;
  545. __capacity_ = __result.count;
  546. }
  547. _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_;
  548. _CharT* __ptr_;
  549. size_t __capacity_;
  550. size_t __size_{0};
  551. };
  552. } // namespace __format
  553. #endif //_LIBCPP_STD_VER >= 20
  554. _LIBCPP_END_NAMESPACE_STD
  555. _LIBCPP_POP_MACROS
  556. #endif // _LIBCPP___FORMAT_BUFFER_H