xref: /freebsd-src/contrib/llvm-project/libcxx/include/__format/buffer.h (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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