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