181ad6265SDimitry Andric // -*- C++ -*- 281ad6265SDimitry Andric //===----------------------------------------------------------------------===// 381ad6265SDimitry Andric // 481ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 581ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 681ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 781ad6265SDimitry Andric // 881ad6265SDimitry Andric //===----------------------------------------------------------------------===// 981ad6265SDimitry Andric 1081ad6265SDimitry Andric #ifndef _LIBCPP___FORMAT_BUFFER_H 1181ad6265SDimitry Andric #define _LIBCPP___FORMAT_BUFFER_H 1281ad6265SDimitry Andric 1381ad6265SDimitry Andric #include <__algorithm/copy_n.h> 14*bdd1243dSDimitry Andric #include <__algorithm/fill_n.h> 1581ad6265SDimitry Andric #include <__algorithm/max.h> 1681ad6265SDimitry Andric #include <__algorithm/min.h> 17*bdd1243dSDimitry Andric #include <__algorithm/ranges_copy_n.h> 18*bdd1243dSDimitry Andric #include <__algorithm/transform.h> 1981ad6265SDimitry Andric #include <__algorithm/unwrap_iter.h> 20*bdd1243dSDimitry Andric #include <__concepts/same_as.h> 2181ad6265SDimitry Andric #include <__config> 22*bdd1243dSDimitry Andric #include <__format/concepts.h> 2381ad6265SDimitry Andric #include <__format/enable_insertable.h> 2481ad6265SDimitry Andric #include <__format/format_to_n_result.h> 2581ad6265SDimitry Andric #include <__iterator/back_insert_iterator.h> 2681ad6265SDimitry Andric #include <__iterator/concepts.h> 2781ad6265SDimitry Andric #include <__iterator/incrementable_traits.h> 2881ad6265SDimitry Andric #include <__iterator/iterator_traits.h> 2981ad6265SDimitry Andric #include <__iterator/wrap_iter.h> 3081ad6265SDimitry Andric #include <__utility/move.h> 3181ad6265SDimitry Andric #include <cstddef> 32*bdd1243dSDimitry Andric #include <string_view> 3381ad6265SDimitry Andric #include <type_traits> 34*bdd1243dSDimitry Andric #include <vector> 3581ad6265SDimitry Andric 3681ad6265SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 3781ad6265SDimitry Andric # pragma GCC system_header 3881ad6265SDimitry Andric #endif 3981ad6265SDimitry Andric 4081ad6265SDimitry Andric _LIBCPP_PUSH_MACROS 4181ad6265SDimitry Andric #include <__undef_macros> 4281ad6265SDimitry Andric 4381ad6265SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 4481ad6265SDimitry Andric 4581ad6265SDimitry Andric #if _LIBCPP_STD_VER > 17 4681ad6265SDimitry Andric 4781ad6265SDimitry Andric namespace __format { 4881ad6265SDimitry Andric 4981ad6265SDimitry Andric /// A "buffer" that handles writing to the proper iterator. 5081ad6265SDimitry Andric /// 5181ad6265SDimitry Andric /// This helper is used together with the @ref back_insert_iterator to offer 5281ad6265SDimitry Andric /// type-erasure for the formatting functions. This reduces the number to 5381ad6265SDimitry Andric /// template instantiations. 54*bdd1243dSDimitry Andric template <__fmt_char_type _CharT> 5581ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __output_buffer { 5681ad6265SDimitry Andric public: 5781ad6265SDimitry Andric using value_type = _CharT; 5881ad6265SDimitry Andric 5981ad6265SDimitry Andric template <class _Tp> 60*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit __output_buffer(_CharT* __ptr, size_t __capacity, _Tp* __obj) 61*bdd1243dSDimitry Andric : __ptr_(__ptr), 62*bdd1243dSDimitry Andric __capacity_(__capacity), 63*bdd1243dSDimitry Andric __flush_([](_CharT* __p, size_t __n, void* __o) { static_cast<_Tp*>(__o)->__flush(__p, __n); }), 6481ad6265SDimitry Andric __obj_(__obj) {} 6581ad6265SDimitry Andric 66*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __reset(_CharT* __ptr, size_t __capacity) { 6781ad6265SDimitry Andric __ptr_ = __ptr; 6881ad6265SDimitry Andric __capacity_ = __capacity; 6981ad6265SDimitry Andric } 7081ad6265SDimitry Andric 71*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return std::back_insert_iterator{*this}; } 7281ad6265SDimitry Andric 73*bdd1243dSDimitry Andric // Used in std::back_insert_iterator. 7481ad6265SDimitry Andric _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) { 7581ad6265SDimitry Andric __ptr_[__size_++] = __c; 7681ad6265SDimitry Andric 7781ad6265SDimitry Andric // Profiling showed flushing after adding is more efficient than flushing 7881ad6265SDimitry Andric // when entering the function. 7981ad6265SDimitry Andric if (__size_ == __capacity_) 80*bdd1243dSDimitry Andric __flush(); 8181ad6265SDimitry Andric } 8281ad6265SDimitry Andric 83*bdd1243dSDimitry Andric /// Copies the input __str to the buffer. 84*bdd1243dSDimitry Andric /// 85*bdd1243dSDimitry Andric /// Since some of the input is generated by std::to_chars, there needs to be a 86*bdd1243dSDimitry Andric /// conversion when _CharT is wchar_t. 87*bdd1243dSDimitry Andric template <__fmt_char_type _InCharT> 88*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) { 89*bdd1243dSDimitry Andric // When the underlying iterator is a simple iterator the __capacity_ is 90*bdd1243dSDimitry Andric // infinite. For a string or container back_inserter it isn't. This means 91*bdd1243dSDimitry Andric // adding a large string the the buffer can cause some overhead. In that 92*bdd1243dSDimitry Andric // case a better approach could be: 93*bdd1243dSDimitry Andric // - flush the buffer 94*bdd1243dSDimitry Andric // - container.append(__str.begin(), __str.end()); 95*bdd1243dSDimitry Andric // The same holds true for the fill. 96*bdd1243dSDimitry Andric // For transform it might be slightly harder, however the use case for 97*bdd1243dSDimitry Andric // transform is slightly less common; it converts hexadecimal values to 98*bdd1243dSDimitry Andric // upper case. For integral these strings are short. 99*bdd1243dSDimitry Andric // TODO FMT Look at the improvements above. 100*bdd1243dSDimitry Andric size_t __n = __str.size(); 101*bdd1243dSDimitry Andric 102*bdd1243dSDimitry Andric __flush_on_overflow(__n); 103*bdd1243dSDimitry Andric if (__n <= __capacity_) { 104*bdd1243dSDimitry Andric _VSTD::copy_n(__str.data(), __n, _VSTD::addressof(__ptr_[__size_])); 105*bdd1243dSDimitry Andric __size_ += __n; 106*bdd1243dSDimitry Andric return; 107*bdd1243dSDimitry Andric } 108*bdd1243dSDimitry Andric 109*bdd1243dSDimitry Andric // The output doesn't fit in the internal buffer. 110*bdd1243dSDimitry Andric // Copy the data in "__capacity_" sized chunks. 111*bdd1243dSDimitry Andric _LIBCPP_ASSERT(__size_ == 0, "the buffer should be flushed by __flush_on_overflow"); 112*bdd1243dSDimitry Andric const _InCharT* __first = __str.data(); 113*bdd1243dSDimitry Andric do { 114*bdd1243dSDimitry Andric size_t __chunk = _VSTD::min(__n, __capacity_); 115*bdd1243dSDimitry Andric _VSTD::copy_n(__first, __chunk, _VSTD::addressof(__ptr_[__size_])); 116*bdd1243dSDimitry Andric __size_ = __chunk; 117*bdd1243dSDimitry Andric __first += __chunk; 118*bdd1243dSDimitry Andric __n -= __chunk; 119*bdd1243dSDimitry Andric __flush(); 120*bdd1243dSDimitry Andric } while (__n); 121*bdd1243dSDimitry Andric } 122*bdd1243dSDimitry Andric 123*bdd1243dSDimitry Andric /// A std::transform wrapper. 124*bdd1243dSDimitry Andric /// 125*bdd1243dSDimitry Andric /// Like @ref __copy it may need to do type conversion. 126*bdd1243dSDimitry Andric template <__fmt_char_type _InCharT, class _UnaryOperation> 127*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __transform(const _InCharT* __first, const _InCharT* __last, _UnaryOperation __operation) { 128*bdd1243dSDimitry Andric _LIBCPP_ASSERT(__first <= __last, "not a valid range"); 129*bdd1243dSDimitry Andric 130*bdd1243dSDimitry Andric size_t __n = static_cast<size_t>(__last - __first); 131*bdd1243dSDimitry Andric __flush_on_overflow(__n); 132*bdd1243dSDimitry Andric if (__n <= __capacity_) { 133*bdd1243dSDimitry Andric _VSTD::transform(__first, __last, _VSTD::addressof(__ptr_[__size_]), _VSTD::move(__operation)); 134*bdd1243dSDimitry Andric __size_ += __n; 135*bdd1243dSDimitry Andric return; 136*bdd1243dSDimitry Andric } 137*bdd1243dSDimitry Andric 138*bdd1243dSDimitry Andric // The output doesn't fit in the internal buffer. 139*bdd1243dSDimitry Andric // Transform the data in "__capacity_" sized chunks. 140*bdd1243dSDimitry Andric _LIBCPP_ASSERT(__size_ == 0, "the buffer should be flushed by __flush_on_overflow"); 141*bdd1243dSDimitry Andric do { 142*bdd1243dSDimitry Andric size_t __chunk = _VSTD::min(__n, __capacity_); 143*bdd1243dSDimitry Andric _VSTD::transform(__first, __first + __chunk, _VSTD::addressof(__ptr_[__size_]), __operation); 144*bdd1243dSDimitry Andric __size_ = __chunk; 145*bdd1243dSDimitry Andric __first += __chunk; 146*bdd1243dSDimitry Andric __n -= __chunk; 147*bdd1243dSDimitry Andric __flush(); 148*bdd1243dSDimitry Andric } while (__n); 149*bdd1243dSDimitry Andric } 150*bdd1243dSDimitry Andric 151*bdd1243dSDimitry Andric /// A \c fill_n wrapper. 152*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) { 153*bdd1243dSDimitry Andric __flush_on_overflow(__n); 154*bdd1243dSDimitry Andric if (__n <= __capacity_) { 155*bdd1243dSDimitry Andric _VSTD::fill_n(_VSTD::addressof(__ptr_[__size_]), __n, __value); 156*bdd1243dSDimitry Andric __size_ += __n; 157*bdd1243dSDimitry Andric return; 158*bdd1243dSDimitry Andric } 159*bdd1243dSDimitry Andric 160*bdd1243dSDimitry Andric // The output doesn't fit in the internal buffer. 161*bdd1243dSDimitry Andric // Fill the buffer in "__capacity_" sized chunks. 162*bdd1243dSDimitry Andric _LIBCPP_ASSERT(__size_ == 0, "the buffer should be flushed by __flush_on_overflow"); 163*bdd1243dSDimitry Andric do { 164*bdd1243dSDimitry Andric size_t __chunk = _VSTD::min(__n, __capacity_); 165*bdd1243dSDimitry Andric _VSTD::fill_n(_VSTD::addressof(__ptr_[__size_]), __chunk, __value); 166*bdd1243dSDimitry Andric __size_ = __chunk; 167*bdd1243dSDimitry Andric __n -= __chunk; 168*bdd1243dSDimitry Andric __flush(); 169*bdd1243dSDimitry Andric } while (__n); 170*bdd1243dSDimitry Andric } 171*bdd1243dSDimitry Andric 172*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __flush() { 17381ad6265SDimitry Andric __flush_(__ptr_, __size_, __obj_); 17481ad6265SDimitry Andric __size_ = 0; 17581ad6265SDimitry Andric } 17681ad6265SDimitry Andric 17781ad6265SDimitry Andric private: 17881ad6265SDimitry Andric _CharT* __ptr_; 17981ad6265SDimitry Andric size_t __capacity_; 18081ad6265SDimitry Andric size_t __size_{0}; 18181ad6265SDimitry Andric void (*__flush_)(_CharT*, size_t, void*); 18281ad6265SDimitry Andric void* __obj_; 183*bdd1243dSDimitry Andric 184*bdd1243dSDimitry Andric /// Flushes the buffer when the output operation would overflow the buffer. 185*bdd1243dSDimitry Andric /// 186*bdd1243dSDimitry Andric /// A simple approach for the overflow detection would be something along the 187*bdd1243dSDimitry Andric /// lines: 188*bdd1243dSDimitry Andric /// \code 189*bdd1243dSDimitry Andric /// // The internal buffer is large enough. 190*bdd1243dSDimitry Andric /// if (__n <= __capacity_) { 191*bdd1243dSDimitry Andric /// // Flush when we really would overflow. 192*bdd1243dSDimitry Andric /// if (__size_ + __n >= __capacity_) 193*bdd1243dSDimitry Andric /// __flush(); 194*bdd1243dSDimitry Andric /// ... 195*bdd1243dSDimitry Andric /// } 196*bdd1243dSDimitry Andric /// \endcode 197*bdd1243dSDimitry Andric /// 198*bdd1243dSDimitry Andric /// This approach works for all cases but one: 199*bdd1243dSDimitry Andric /// A __format_to_n_buffer_base where \ref __enable_direct_output is true. 200*bdd1243dSDimitry Andric /// In that case the \ref __capacity_ of the buffer changes during the first 201*bdd1243dSDimitry Andric /// \ref __flush. During that operation the output buffer switches from its 202*bdd1243dSDimitry Andric /// __writer_ to its __storage_. The \ref __capacity_ of the former depends 203*bdd1243dSDimitry Andric /// on the value of n, of the latter is a fixed size. For example: 204*bdd1243dSDimitry Andric /// - a format_to_n call with a 10'000 char buffer, 205*bdd1243dSDimitry Andric /// - the buffer is filled with 9'500 chars, 206*bdd1243dSDimitry Andric /// - adding 1'000 elements would overflow the buffer so the buffer gets 207*bdd1243dSDimitry Andric /// changed and the \ref __capacity_ decreases from 10'000 to 208*bdd1243dSDimitry Andric /// __buffer_size (256 at the time of writing). 209*bdd1243dSDimitry Andric /// 210*bdd1243dSDimitry Andric /// This means that the \ref __flush for this class may need to copy a part of 211*bdd1243dSDimitry Andric /// the internal buffer to the proper output. In this example there will be 212*bdd1243dSDimitry Andric /// 500 characters that need this copy operation. 213*bdd1243dSDimitry Andric /// 214*bdd1243dSDimitry Andric /// Note it would be more efficient to write 500 chars directly and then swap 215*bdd1243dSDimitry Andric /// the buffers. This would make the code more complex and \ref format_to_n is 216*bdd1243dSDimitry Andric /// not the most common use case. Therefore the optimization isn't done. 217*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __flush_on_overflow(size_t __n) { 218*bdd1243dSDimitry Andric if (__size_ + __n >= __capacity_) 219*bdd1243dSDimitry Andric __flush(); 220*bdd1243dSDimitry Andric } 22181ad6265SDimitry Andric }; 22281ad6265SDimitry Andric 22381ad6265SDimitry Andric /// A storage using an internal buffer. 22481ad6265SDimitry Andric /// 22581ad6265SDimitry Andric /// This storage is used when writing a single element to the output iterator 22681ad6265SDimitry Andric /// is expensive. 227*bdd1243dSDimitry Andric template <__fmt_char_type _CharT> 22881ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __internal_storage { 22981ad6265SDimitry Andric public: 230*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI _CharT* __begin() { return __buffer_; } 23181ad6265SDimitry Andric 23281ad6265SDimitry Andric static constexpr size_t __buffer_size = 256 / sizeof(_CharT); 23381ad6265SDimitry Andric 23481ad6265SDimitry Andric private: 23581ad6265SDimitry Andric _CharT __buffer_[__buffer_size]; 23681ad6265SDimitry Andric }; 23781ad6265SDimitry Andric 23881ad6265SDimitry Andric /// A storage writing directly to the storage. 23981ad6265SDimitry Andric /// 24081ad6265SDimitry Andric /// This requires the storage to be a contiguous buffer of \a _CharT. 24181ad6265SDimitry Andric /// Since the output is directly written to the underlying storage this class 24281ad6265SDimitry Andric /// is just an empty class. 243*bdd1243dSDimitry Andric template <__fmt_char_type _CharT> 24481ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __direct_storage {}; 24581ad6265SDimitry Andric 24681ad6265SDimitry Andric template <class _OutIt, class _CharT> 247*bdd1243dSDimitry Andric concept __enable_direct_output = __fmt_char_type<_CharT> && 24881ad6265SDimitry Andric (same_as<_OutIt, _CharT*> 24981ad6265SDimitry Andric #ifndef _LIBCPP_ENABLE_DEBUG_MODE 25081ad6265SDimitry Andric || same_as<_OutIt, __wrap_iter<_CharT*>> 25181ad6265SDimitry Andric #endif 25281ad6265SDimitry Andric ); 25381ad6265SDimitry Andric 25481ad6265SDimitry Andric /// Write policy for directly writing to the underlying output. 255*bdd1243dSDimitry Andric template <class _OutIt, __fmt_char_type _CharT> 25681ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __writer_direct { 25781ad6265SDimitry Andric public: 25881ad6265SDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit __writer_direct(_OutIt __out_it) 25981ad6265SDimitry Andric : __out_it_(__out_it) {} 26081ad6265SDimitry Andric 261*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() { return __out_it_; } 26281ad6265SDimitry Andric 263*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __flush(_CharT*, size_t __n) { 26481ad6265SDimitry Andric // _OutIt can be a __wrap_iter<CharT*>. Therefore the original iterator 26581ad6265SDimitry Andric // is adjusted. 266*bdd1243dSDimitry Andric __out_it_ += __n; 26781ad6265SDimitry Andric } 26881ad6265SDimitry Andric 26981ad6265SDimitry Andric private: 27081ad6265SDimitry Andric _OutIt __out_it_; 27181ad6265SDimitry Andric }; 27281ad6265SDimitry Andric 27381ad6265SDimitry Andric /// Write policy for copying the buffer to the output. 274*bdd1243dSDimitry Andric template <class _OutIt, __fmt_char_type _CharT> 27581ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __writer_iterator { 27681ad6265SDimitry Andric public: 27781ad6265SDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit __writer_iterator(_OutIt __out_it) 27881ad6265SDimitry Andric : __out_it_{_VSTD::move(__out_it)} {} 27981ad6265SDimitry Andric 280*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && { return std::move(__out_it_); } 28181ad6265SDimitry Andric 282*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { 283*bdd1243dSDimitry Andric __out_it_ = std::ranges::copy_n(__ptr, __n, std::move(__out_it_)).out; 28481ad6265SDimitry Andric } 28581ad6265SDimitry Andric 28681ad6265SDimitry Andric private: 28781ad6265SDimitry Andric _OutIt __out_it_; 28881ad6265SDimitry Andric }; 28981ad6265SDimitry Andric 29081ad6265SDimitry Andric /// Concept to see whether a \a _Container is insertable. 29181ad6265SDimitry Andric /// 29281ad6265SDimitry Andric /// The concept is used to validate whether multiple calls to a 29381ad6265SDimitry Andric /// \ref back_insert_iterator can be replace by a call to \c _Container::insert. 29481ad6265SDimitry Andric /// 29581ad6265SDimitry Andric /// \note a \a _Container needs to opt-in to the concept by specializing 29681ad6265SDimitry Andric /// \ref __enable_insertable. 29781ad6265SDimitry Andric template <class _Container> 29881ad6265SDimitry Andric concept __insertable = 299*bdd1243dSDimitry Andric __enable_insertable<_Container> && __fmt_char_type<typename _Container::value_type> && 30081ad6265SDimitry Andric requires(_Container& __t, add_pointer_t<typename _Container::value_type> __first, 30181ad6265SDimitry Andric add_pointer_t<typename _Container::value_type> __last) { __t.insert(__t.end(), __first, __last); }; 30281ad6265SDimitry Andric 30381ad6265SDimitry Andric /// Extract the container type of a \ref back_insert_iterator. 30481ad6265SDimitry Andric template <class _It> 30581ad6265SDimitry Andric struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container { 30681ad6265SDimitry Andric using type = void; 30781ad6265SDimitry Andric }; 30881ad6265SDimitry Andric 30981ad6265SDimitry Andric template <__insertable _Container> 31081ad6265SDimitry Andric struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container<back_insert_iterator<_Container>> { 31181ad6265SDimitry Andric using type = _Container; 31281ad6265SDimitry Andric }; 31381ad6265SDimitry Andric 31481ad6265SDimitry Andric /// Write policy for inserting the buffer in a container. 31581ad6265SDimitry Andric template <class _Container> 31681ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __writer_container { 31781ad6265SDimitry Andric public: 31881ad6265SDimitry Andric using _CharT = typename _Container::value_type; 31981ad6265SDimitry Andric 32081ad6265SDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit __writer_container(back_insert_iterator<_Container> __out_it) 32181ad6265SDimitry Andric : __container_{__out_it.__get_container()} {} 32281ad6265SDimitry Andric 323*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI auto __out_it() { return std::back_inserter(*__container_); } 32481ad6265SDimitry Andric 325*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { 326*bdd1243dSDimitry Andric __container_->insert(__container_->end(), __ptr, __ptr + __n); 32781ad6265SDimitry Andric } 32881ad6265SDimitry Andric 32981ad6265SDimitry Andric private: 33081ad6265SDimitry Andric _Container* __container_; 33181ad6265SDimitry Andric }; 33281ad6265SDimitry Andric 33381ad6265SDimitry Andric /// Selects the type of the writer used for the output iterator. 33481ad6265SDimitry Andric template <class _OutIt, class _CharT> 33581ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __writer_selector { 33681ad6265SDimitry Andric using _Container = typename __back_insert_iterator_container<_OutIt>::type; 33781ad6265SDimitry Andric 33881ad6265SDimitry Andric public: 33981ad6265SDimitry Andric using type = conditional_t<!same_as<_Container, void>, __writer_container<_Container>, 34081ad6265SDimitry Andric conditional_t<__enable_direct_output<_OutIt, _CharT>, __writer_direct<_OutIt, _CharT>, 34181ad6265SDimitry Andric __writer_iterator<_OutIt, _CharT>>>; 34281ad6265SDimitry Andric }; 34381ad6265SDimitry Andric 34481ad6265SDimitry Andric /// The generic formatting buffer. 345*bdd1243dSDimitry Andric template <class _OutIt, __fmt_char_type _CharT> 34681ad6265SDimitry Andric requires(output_iterator<_OutIt, const _CharT&>) class _LIBCPP_TEMPLATE_VIS 34781ad6265SDimitry Andric __format_buffer { 34881ad6265SDimitry Andric using _Storage = 34981ad6265SDimitry Andric conditional_t<__enable_direct_output<_OutIt, _CharT>, 35081ad6265SDimitry Andric __direct_storage<_CharT>, __internal_storage<_CharT>>; 35181ad6265SDimitry Andric 35281ad6265SDimitry Andric public: 35381ad6265SDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it) 35481ad6265SDimitry Andric requires(same_as<_Storage, __internal_storage<_CharT>>) 355*bdd1243dSDimitry Andric : __output_(__storage_.__begin(), __storage_.__buffer_size, this), __writer_(_VSTD::move(__out_it)) {} 35681ad6265SDimitry Andric 35781ad6265SDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it) requires( 35881ad6265SDimitry Andric same_as<_Storage, __direct_storage<_CharT>>) 35981ad6265SDimitry Andric : __output_(_VSTD::__unwrap_iter(__out_it), size_t(-1), this), 36081ad6265SDimitry Andric __writer_(_VSTD::move(__out_it)) {} 36181ad6265SDimitry Andric 362*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); } 36381ad6265SDimitry Andric 364*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { __writer_.__flush(__ptr, __n); } 36581ad6265SDimitry Andric 366*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && { 367*bdd1243dSDimitry Andric __output_.__flush(); 368*bdd1243dSDimitry Andric return _VSTD::move(__writer_).__out_it(); 36981ad6265SDimitry Andric } 37081ad6265SDimitry Andric 37181ad6265SDimitry Andric private: 37281ad6265SDimitry Andric _LIBCPP_NO_UNIQUE_ADDRESS _Storage __storage_; 37381ad6265SDimitry Andric __output_buffer<_CharT> __output_; 37481ad6265SDimitry Andric typename __writer_selector<_OutIt, _CharT>::type __writer_; 37581ad6265SDimitry Andric }; 37681ad6265SDimitry Andric 37781ad6265SDimitry Andric /// A buffer that counts the number of insertions. 37881ad6265SDimitry Andric /// 37981ad6265SDimitry Andric /// Since \ref formatted_size only needs to know the size, the output itself is 38081ad6265SDimitry Andric /// discarded. 381*bdd1243dSDimitry Andric template <__fmt_char_type _CharT> 38281ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __formatted_size_buffer { 38381ad6265SDimitry Andric public: 384*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); } 38581ad6265SDimitry Andric 386*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __flush(const _CharT*, size_t __n) { __size_ += __n; } 38781ad6265SDimitry Andric 388*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI size_t __result() && { 389*bdd1243dSDimitry Andric __output_.__flush(); 39081ad6265SDimitry Andric return __size_; 39181ad6265SDimitry Andric } 39281ad6265SDimitry Andric 39381ad6265SDimitry Andric private: 39481ad6265SDimitry Andric __internal_storage<_CharT> __storage_; 395*bdd1243dSDimitry Andric __output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this}; 39681ad6265SDimitry Andric size_t __size_{0}; 39781ad6265SDimitry Andric }; 39881ad6265SDimitry Andric 39981ad6265SDimitry Andric /// The base of a buffer that counts and limits the number of insertions. 400*bdd1243dSDimitry Andric template <class _OutIt, __fmt_char_type _CharT, bool> 40181ad6265SDimitry Andric requires(output_iterator<_OutIt, const _CharT&>) 40281ad6265SDimitry Andric struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base { 40381ad6265SDimitry Andric using _Size = iter_difference_t<_OutIt>; 40481ad6265SDimitry Andric 40581ad6265SDimitry Andric public: 406*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __max_size) 407*bdd1243dSDimitry Andric : __writer_(_VSTD::move(__out_it)), __max_size_(_VSTD::max(_Size(0), __max_size)) {} 40881ad6265SDimitry Andric 409*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { 410*bdd1243dSDimitry Andric if (_Size(__size_) <= __max_size_) 411*bdd1243dSDimitry Andric __writer_.__flush(__ptr, _VSTD::min(_Size(__n), __max_size_ - __size_)); 412*bdd1243dSDimitry Andric __size_ += __n; 41381ad6265SDimitry Andric } 41481ad6265SDimitry Andric 41581ad6265SDimitry Andric protected: 41681ad6265SDimitry Andric __internal_storage<_CharT> __storage_; 417*bdd1243dSDimitry Andric __output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this}; 41881ad6265SDimitry Andric typename __writer_selector<_OutIt, _CharT>::type __writer_; 41981ad6265SDimitry Andric 420*bdd1243dSDimitry Andric _Size __max_size_; 42181ad6265SDimitry Andric _Size __size_{0}; 42281ad6265SDimitry Andric }; 42381ad6265SDimitry Andric 42481ad6265SDimitry Andric /// The base of a buffer that counts and limits the number of insertions. 42581ad6265SDimitry Andric /// 42681ad6265SDimitry Andric /// This version is used when \c __enable_direct_output<_OutIt, _CharT> == true. 42781ad6265SDimitry Andric /// 428*bdd1243dSDimitry Andric /// This class limits the size available to the direct writer so it will not 42981ad6265SDimitry Andric /// exceed the maximum number of code units. 430*bdd1243dSDimitry Andric template <class _OutIt, __fmt_char_type _CharT> 43181ad6265SDimitry Andric requires(output_iterator<_OutIt, const _CharT&>) 43281ad6265SDimitry Andric class _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base<_OutIt, _CharT, true> { 43381ad6265SDimitry Andric using _Size = iter_difference_t<_OutIt>; 43481ad6265SDimitry Andric 43581ad6265SDimitry Andric public: 436*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __max_size) 437*bdd1243dSDimitry Andric : __output_(_VSTD::__unwrap_iter(__out_it), __max_size, this), 438*bdd1243dSDimitry Andric __writer_(_VSTD::move(__out_it)), 439*bdd1243dSDimitry Andric __max_size_(__max_size) { 440*bdd1243dSDimitry Andric if (__max_size <= 0) [[unlikely]] 441*bdd1243dSDimitry Andric __output_.__reset(__storage_.__begin(), __storage_.__buffer_size); 44281ad6265SDimitry Andric } 44381ad6265SDimitry Andric 444*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { 445*bdd1243dSDimitry Andric // A __flush to the direct writer happens in the following occasions: 44681ad6265SDimitry Andric // - The format function has written the maximum number of allowed code 44781ad6265SDimitry Andric // units. At this point it's no longer valid to write to this writer. So 44881ad6265SDimitry Andric // switch to the internal storage. This internal storage doesn't need to 449*bdd1243dSDimitry Andric // be written anywhere so the __flush for that storage writes no output. 450*bdd1243dSDimitry Andric // - Like above, but the next "mass write" operation would overflow the 451*bdd1243dSDimitry Andric // buffer. In that case the buffer is pre-emptively switched. The still 452*bdd1243dSDimitry Andric // valid code units will be written separately. 45381ad6265SDimitry Andric // - The format_to_n function is finished. In this case there's no need to 45481ad6265SDimitry Andric // switch the buffer, but for simplicity the buffers are still switched. 455*bdd1243dSDimitry Andric // When the __max_size <= 0 the constructor already switched the buffers. 456*bdd1243dSDimitry Andric if (__size_ == 0 && __ptr != __storage_.__begin()) { 457*bdd1243dSDimitry Andric __writer_.__flush(__ptr, __n); 458*bdd1243dSDimitry Andric __output_.__reset(__storage_.__begin(), __storage_.__buffer_size); 459*bdd1243dSDimitry Andric } else if (__size_ < __max_size_) { 460*bdd1243dSDimitry Andric // Copies a part of the internal buffer to the output up to n characters. 461*bdd1243dSDimitry Andric // See __output_buffer<_CharT>::__flush_on_overflow for more information. 462*bdd1243dSDimitry Andric _Size __s = _VSTD::min(_Size(__n), __max_size_ - __size_); 463*bdd1243dSDimitry Andric std::copy_n(__ptr, __s, __writer_.__out_it()); 464*bdd1243dSDimitry Andric __writer_.__flush(__ptr, __s); 46581ad6265SDimitry Andric } 46681ad6265SDimitry Andric 467*bdd1243dSDimitry Andric __size_ += __n; 46881ad6265SDimitry Andric } 46981ad6265SDimitry Andric 47081ad6265SDimitry Andric protected: 47181ad6265SDimitry Andric __internal_storage<_CharT> __storage_; 47281ad6265SDimitry Andric __output_buffer<_CharT> __output_; 47381ad6265SDimitry Andric __writer_direct<_OutIt, _CharT> __writer_; 47481ad6265SDimitry Andric 475*bdd1243dSDimitry Andric _Size __max_size_; 47681ad6265SDimitry Andric _Size __size_{0}; 47781ad6265SDimitry Andric }; 47881ad6265SDimitry Andric 47981ad6265SDimitry Andric /// The buffer that counts and limits the number of insertions. 480*bdd1243dSDimitry Andric template <class _OutIt, __fmt_char_type _CharT> 48181ad6265SDimitry Andric requires(output_iterator<_OutIt, const _CharT&>) 48281ad6265SDimitry Andric struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer final 48381ad6265SDimitry Andric : public __format_to_n_buffer_base< _OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>> { 48481ad6265SDimitry Andric using _Base = __format_to_n_buffer_base<_OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>>; 48581ad6265SDimitry Andric using _Size = iter_difference_t<_OutIt>; 48681ad6265SDimitry Andric 48781ad6265SDimitry Andric public: 488*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer(_OutIt __out_it, _Size __max_size) 489*bdd1243dSDimitry Andric : _Base(_VSTD::move(__out_it), __max_size) {} 490*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return this->__output_.__make_output_iterator(); } 49181ad6265SDimitry Andric 492*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __result() && { 493*bdd1243dSDimitry Andric this->__output_.__flush(); 494*bdd1243dSDimitry Andric return {_VSTD::move(this->__writer_).__out_it(), this->__size_}; 49581ad6265SDimitry Andric } 49681ad6265SDimitry Andric }; 497*bdd1243dSDimitry Andric 498*bdd1243dSDimitry Andric // A dynamically growing buffer intended to be used for retargeting a context. 499*bdd1243dSDimitry Andric // 500*bdd1243dSDimitry Andric // P2286 Formatting ranges adds range formatting support. It allows the user to 501*bdd1243dSDimitry Andric // specify the minimum width for the entire formatted range. The width of the 502*bdd1243dSDimitry Andric // range is not known until the range is formatted. Formatting is done to an 503*bdd1243dSDimitry Andric // output_iterator so there's no guarantee it would be possible to add the fill 504*bdd1243dSDimitry Andric // to the front of the output. Instead the range is formatted to a temporary 505*bdd1243dSDimitry Andric // buffer and that buffer is formatted as a string. 506*bdd1243dSDimitry Andric // 507*bdd1243dSDimitry Andric // There is an issue with that approach, the format context used in 508*bdd1243dSDimitry Andric // std::formatter<T>::format contains the output iterator used as part of its 509*bdd1243dSDimitry Andric // type. So using this output iterator means there needs to be a new format 510*bdd1243dSDimitry Andric // context and the format arguments need to be retargeted to the new context. 511*bdd1243dSDimitry Andric // This retargeting is done by a basic_format_context specialized for the 512*bdd1243dSDimitry Andric // __iterator of this container. 513*bdd1243dSDimitry Andric template <__fmt_char_type _CharT> 514*bdd1243dSDimitry Andric class _LIBCPP_TEMPLATE_VIS __retarget_buffer { 515*bdd1243dSDimitry Andric public: 516*bdd1243dSDimitry Andric using value_type = _CharT; 517*bdd1243dSDimitry Andric 518*bdd1243dSDimitry Andric struct __iterator { 519*bdd1243dSDimitry Andric using difference_type = ptrdiff_t; 520*bdd1243dSDimitry Andric 521*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(__retarget_buffer& __buffer) 522*bdd1243dSDimitry Andric : __buffer_(std::addressof(__buffer)) {} 523*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(const _CharT& __c) { 524*bdd1243dSDimitry Andric __buffer_->push_back(__c); 525*bdd1243dSDimitry Andric return *this; 526*bdd1243dSDimitry Andric } 527*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(_CharT&& __c) { 528*bdd1243dSDimitry Andric __buffer_->push_back(__c); 529*bdd1243dSDimitry Andric return *this; 530*bdd1243dSDimitry Andric } 531*bdd1243dSDimitry Andric 532*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator*() { return *this; } 533*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { return *this; } 534*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) { return *this; } 535*bdd1243dSDimitry Andric __retarget_buffer* __buffer_; 536*bdd1243dSDimitry Andric }; 537*bdd1243dSDimitry Andric 538*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit __retarget_buffer(size_t __size_hint) { __buffer_.reserve(__size_hint); } 539*bdd1243dSDimitry Andric 540*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI __iterator __make_output_iterator() { return __iterator{*this}; } 541*bdd1243dSDimitry Andric 542*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) { __buffer_.push_back(__c); } 543*bdd1243dSDimitry Andric 544*bdd1243dSDimitry Andric template <__fmt_char_type _InCharT> 545*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) { 546*bdd1243dSDimitry Andric __buffer_.insert(__buffer_.end(), __str.begin(), __str.end()); 547*bdd1243dSDimitry Andric } 548*bdd1243dSDimitry Andric 549*bdd1243dSDimitry Andric template <__fmt_char_type _InCharT, class _UnaryOperation> 550*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __transform(const _InCharT* __first, const _InCharT* __last, _UnaryOperation __operation) { 551*bdd1243dSDimitry Andric _LIBCPP_ASSERT(__first <= __last, "not a valid range"); 552*bdd1243dSDimitry Andric std::transform(__first, __last, std::back_inserter(__buffer_), std::move(__operation)); 553*bdd1243dSDimitry Andric } 554*bdd1243dSDimitry Andric 555*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) { __buffer_.insert(__buffer_.end(), __n, __value); } 556*bdd1243dSDimitry Andric 557*bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_string_view<_CharT> __view() { return {__buffer_.data(), __buffer_.size()}; } 558*bdd1243dSDimitry Andric 559*bdd1243dSDimitry Andric private: 560*bdd1243dSDimitry Andric // Use vector instead of string to avoid adding zeros after every append 561*bdd1243dSDimitry Andric // operation. The buffer is exposed as a string_view and not as a c-string. 562*bdd1243dSDimitry Andric vector<_CharT> __buffer_; 563*bdd1243dSDimitry Andric }; 564*bdd1243dSDimitry Andric 56581ad6265SDimitry Andric } // namespace __format 56681ad6265SDimitry Andric 56781ad6265SDimitry Andric #endif //_LIBCPP_STD_VER > 17 56881ad6265SDimitry Andric 56981ad6265SDimitry Andric _LIBCPP_END_NAMESPACE_STD 57081ad6265SDimitry Andric 57181ad6265SDimitry Andric _LIBCPP_POP_MACROS 57281ad6265SDimitry Andric 57381ad6265SDimitry Andric #endif // _LIBCPP___FORMAT_BUFFER_H 574