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/unwrap_iter.h> 15 #include <__config> 16 #include <__format/formatter.h> // for __char_type TODO FMT Move the concept? 17 #include <__iterator/back_insert_iterator.h> 18 #include <__iterator/concepts.h> 19 #include <__iterator/iterator_traits.h> 20 #include <__iterator/wrap_iter.h> 21 #include <__utility/move.h> 22 #include <concepts> 23 #include <cstddef> 24 #include <type_traits> 25 26 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 27 # pragma GCC system_header 28 #endif 29 30 _LIBCPP_BEGIN_NAMESPACE_STD 31 32 #if _LIBCPP_STD_VER > 17 33 34 namespace __format { 35 36 /// A "buffer" that handles writing to the proper iterator. 37 /// 38 /// This helper is used together with the @ref back_insert_iterator to offer 39 /// type-erasure for the formatting functions. This reduces the number to 40 /// template instantiations. 41 template <__formatter::__char_type _CharT> 42 class _LIBCPP_TEMPLATE_VIS __output_buffer { 43 public: 44 using value_type = _CharT; 45 46 template <class _Tp> 47 _LIBCPP_HIDE_FROM_ABI explicit __output_buffer(_CharT* __ptr, 48 size_t __capacity, _Tp* __obj) 49 : __ptr_(__ptr), __capacity_(__capacity), 50 __flush_([](_CharT* __p, size_t __size, void* __o) { 51 static_cast<_Tp*>(__o)->flush(__p, __size); 52 }), 53 __obj_(__obj) {} 54 55 _LIBCPP_HIDE_FROM_ABI void reset(_CharT* __ptr, size_t __capacity) { 56 __ptr_ = __ptr; 57 __capacity_ = __capacity; 58 } 59 60 _LIBCPP_HIDE_FROM_ABI auto make_output_iterator() { 61 return back_insert_iterator{*this}; 62 } 63 64 // TODO FMT It would be nice to have an overload taking a 65 // basic_string_view<_CharT> and append it directly. 66 _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) { 67 __ptr_[__size_++] = __c; 68 69 // Profiling showed flushing after adding is more efficient than flushing 70 // when entering the function. 71 if (__size_ == __capacity_) 72 flush(); 73 } 74 75 _LIBCPP_HIDE_FROM_ABI void flush() { 76 __flush_(__ptr_, __size_, __obj_); 77 __size_ = 0; 78 } 79 80 private: 81 _CharT* __ptr_; 82 size_t __capacity_; 83 size_t __size_{0}; 84 void (*__flush_)(_CharT*, size_t, void*); 85 void* __obj_; 86 }; 87 88 /// A storage using an internal buffer. 89 /// 90 /// This storage is used when writing a single element to the output iterator 91 /// is expensive. 92 template <__formatter::__char_type _CharT> 93 class _LIBCPP_TEMPLATE_VIS __internal_storage { 94 public: 95 _LIBCPP_HIDE_FROM_ABI _CharT* begin() { return __buffer_; } 96 _LIBCPP_HIDE_FROM_ABI size_t capacity() { return __buffer_size_; } 97 98 private: 99 static constexpr size_t __buffer_size_ = 256 / sizeof(_CharT); 100 _CharT __buffer_[__buffer_size_]; 101 }; 102 103 /// A storage writing directly to the storage. 104 /// 105 /// This requires the storage to be a contiguous buffer of \a _CharT. 106 /// Since the output is directly written to the underlying storage this class 107 /// is just an empty class. 108 template <__formatter::__char_type _CharT> 109 class _LIBCPP_TEMPLATE_VIS __direct_storage {}; 110 111 template <class _OutIt, class _CharT> 112 concept __enable_direct_output = __formatter::__char_type<_CharT> && 113 (same_as<_OutIt, _CharT*> 114 #if _LIBCPP_DEBUG_LEVEL < 2 115 || same_as<_OutIt, __wrap_iter<_CharT*>> 116 #endif 117 ); 118 119 /// Write policy for directly writing to the underlying output. 120 template <class _OutIt, __formatter::__char_type _CharT> 121 class _LIBCPP_TEMPLATE_VIS __writer_direct { 122 public: 123 _LIBCPP_HIDE_FROM_ABI explicit __writer_direct(_OutIt __out_it) 124 : __out_it_(__out_it) {} 125 126 _LIBCPP_HIDE_FROM_ABI auto out() { return __out_it_; } 127 128 _LIBCPP_HIDE_FROM_ABI void flush(_CharT*, size_t __size) { 129 // _OutIt can be a __wrap_iter<CharT*>. Therefore the original iterator 130 // is adjusted. 131 __out_it_ += __size; 132 } 133 134 private: 135 _OutIt __out_it_; 136 }; 137 138 /// Write policy for copying the buffer to the output. 139 template <class _OutIt, __formatter::__char_type _CharT> 140 class _LIBCPP_TEMPLATE_VIS __writer_iterator { 141 public: 142 _LIBCPP_HIDE_FROM_ABI explicit __writer_iterator(_OutIt __out_it) 143 : __out_it_{_VSTD::move(__out_it)} {} 144 145 _LIBCPP_HIDE_FROM_ABI auto out() { return __out_it_; } 146 147 _LIBCPP_HIDE_FROM_ABI void flush(_CharT* __ptr, size_t __size) { 148 __out_it_ = _VSTD::copy_n(__ptr, __size, _VSTD::move(__out_it_)); 149 } 150 151 private: 152 _OutIt __out_it_; 153 }; 154 155 /// Selects the type of the writer used for the output iterator. 156 template <class _OutIt, class _CharT> 157 class _LIBCPP_TEMPLATE_VIS __writer_selector { 158 public: 159 using type = conditional_t<__enable_direct_output<_OutIt, _CharT>, 160 __writer_direct<_OutIt, _CharT>, 161 __writer_iterator<_OutIt, _CharT>>; 162 }; 163 164 /// The generic formatting buffer. 165 template <class _OutIt, __formatter::__char_type _CharT> 166 requires(output_iterator<_OutIt, const _CharT&>) class _LIBCPP_TEMPLATE_VIS 167 __format_buffer { 168 using _Storage = 169 conditional_t<__enable_direct_output<_OutIt, _CharT>, 170 __direct_storage<_CharT>, __internal_storage<_CharT>>; 171 172 public: 173 _LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it) requires( 174 same_as<_Storage, __internal_storage<_CharT>>) 175 : __output_(__storage_.begin(), __storage_.capacity(), this), 176 __writer_(_VSTD::move(__out_it)) {} 177 178 _LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it) requires( 179 same_as<_Storage, __direct_storage<_CharT>>) 180 : __output_(_VSTD::__unwrap_iter(__out_it), size_t(-1), this), 181 __writer_(_VSTD::move(__out_it)) {} 182 183 _LIBCPP_HIDE_FROM_ABI auto make_output_iterator() { 184 return __output_.make_output_iterator(); 185 } 186 187 _LIBCPP_HIDE_FROM_ABI void flush(_CharT* __ptr, size_t __size) { 188 __writer_.flush(__ptr, __size); 189 } 190 191 _LIBCPP_HIDE_FROM_ABI _OutIt out() && { 192 __output_.flush(); 193 return _VSTD::move(__writer_).out(); 194 } 195 196 private: 197 _LIBCPP_NO_UNIQUE_ADDRESS _Storage __storage_; 198 __output_buffer<_CharT> __output_; 199 typename __writer_selector<_OutIt, _CharT>::type __writer_; 200 }; 201 } // namespace __format 202 203 #endif //_LIBCPP_STD_VER > 17 204 205 _LIBCPP_END_NAMESPACE_STD 206 207 #endif // _LIBCPP___FORMAT_BUFFER_H 208