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_FORMAT_CONTEXT_H 11 #define _LIBCPP___FORMAT_FORMAT_CONTEXT_H 12 13 #include <__availability> 14 #include <__concepts/same_as.h> 15 #include <__config> 16 #include <__format/buffer.h> 17 #include <__format/format_arg.h> 18 #include <__format/format_arg_store.h> 19 #include <__format/format_args.h> 20 #include <__format/format_error.h> 21 #include <__format/format_fwd.h> 22 #include <__iterator/back_insert_iterator.h> 23 #include <__iterator/concepts.h> 24 #include <__memory/addressof.h> 25 #include <__utility/move.h> 26 #include <__variant/monostate.h> 27 #include <cstddef> 28 29 #ifndef _LIBCPP_HAS_NO_LOCALIZATION 30 #include <locale> 31 #include <optional> 32 #endif 33 34 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 35 # pragma GCC system_header 36 #endif 37 38 _LIBCPP_BEGIN_NAMESPACE_STD 39 40 #if _LIBCPP_STD_VER >= 20 41 42 template <class _OutIt, class _CharT> 43 requires output_iterator<_OutIt, const _CharT&> 44 class _LIBCPP_TEMPLATE_VIS basic_format_context; 45 46 #ifndef _LIBCPP_HAS_NO_LOCALIZATION 47 /** 48 * Helper to create a basic_format_context. 49 * 50 * This is needed since the constructor is private. 51 */ 52 template <class _OutIt, class _CharT> 53 _LIBCPP_HIDE_FROM_ABI basic_format_context<_OutIt, _CharT> 54 __format_context_create( 55 _OutIt __out_it, 56 basic_format_args<basic_format_context<_OutIt, _CharT>> __args, 57 optional<_VSTD::locale>&& __loc = nullopt) { 58 return _VSTD::basic_format_context(_VSTD::move(__out_it), __args, _VSTD::move(__loc)); 59 } 60 #else 61 template <class _OutIt, class _CharT> 62 _LIBCPP_HIDE_FROM_ABI basic_format_context<_OutIt, _CharT> 63 __format_context_create( 64 _OutIt __out_it, 65 basic_format_args<basic_format_context<_OutIt, _CharT>> __args) { 66 return _VSTD::basic_format_context(_VSTD::move(__out_it), __args); 67 } 68 #endif 69 70 using format_context = 71 basic_format_context<back_insert_iterator<__format::__output_buffer<char>>, 72 char>; 73 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS 74 using wformat_context = basic_format_context< 75 back_insert_iterator<__format::__output_buffer<wchar_t>>, wchar_t>; 76 #endif 77 78 template <class _OutIt, class _CharT> 79 requires output_iterator<_OutIt, const _CharT&> 80 class 81 // clang-format off 82 _LIBCPP_TEMPLATE_VIS 83 _LIBCPP_PREFERRED_NAME(format_context) 84 _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wformat_context)) 85 // clang-format on 86 basic_format_context { 87 public: 88 using iterator = _OutIt; 89 using char_type = _CharT; 90 template <class _Tp> 91 using formatter_type = formatter<_Tp, _CharT>; 92 93 _LIBCPP_HIDE_FROM_ABI basic_format_arg<basic_format_context> 94 arg(size_t __id) const noexcept { 95 return __args_.get(__id); 96 } 97 #ifndef _LIBCPP_HAS_NO_LOCALIZATION 98 _LIBCPP_HIDE_FROM_ABI _VSTD::locale locale() { 99 if (!__loc_) 100 __loc_ = _VSTD::locale{}; 101 return *__loc_; 102 } 103 #endif 104 _LIBCPP_HIDE_FROM_ABI iterator out() { return std::move(__out_it_); } 105 _LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = std::move(__it); } 106 107 private: 108 iterator __out_it_; 109 basic_format_args<basic_format_context> __args_; 110 #ifndef _LIBCPP_HAS_NO_LOCALIZATION 111 112 // The Standard doesn't specify how the locale is stored. 113 // [format.context]/6 114 // std::locale locale(); 115 // Returns: The locale passed to the formatting function if the latter 116 // takes one, and std::locale() otherwise. 117 // This is done by storing the locale of the constructor in this optional. If 118 // locale() is called and the optional has no value the value will be created. 119 // This allows the implementation to lazily create the locale. 120 // TODO FMT Validate whether lazy creation is the best solution. 121 optional<_VSTD::locale> __loc_; 122 123 template <class _OtherOutIt, class _OtherCharT> 124 friend _LIBCPP_HIDE_FROM_ABI basic_format_context<_OtherOutIt, _OtherCharT> 125 __format_context_create(_OtherOutIt, basic_format_args<basic_format_context<_OtherOutIt, _OtherCharT>>, 126 optional<_VSTD::locale>&&); 127 128 // Note: the Standard doesn't specify the required constructors. 129 _LIBCPP_HIDE_FROM_ABI 130 explicit basic_format_context(_OutIt __out_it, 131 basic_format_args<basic_format_context> __args, 132 optional<_VSTD::locale>&& __loc) 133 : __out_it_(_VSTD::move(__out_it)), __args_(__args), 134 __loc_(_VSTD::move(__loc)) {} 135 #else 136 template <class _OtherOutIt, class _OtherCharT> 137 friend _LIBCPP_HIDE_FROM_ABI basic_format_context<_OtherOutIt, _OtherCharT> 138 __format_context_create(_OtherOutIt, basic_format_args<basic_format_context<_OtherOutIt, _OtherCharT>>); 139 140 _LIBCPP_HIDE_FROM_ABI 141 explicit basic_format_context(_OutIt __out_it, 142 basic_format_args<basic_format_context> __args) 143 : __out_it_(_VSTD::move(__out_it)), __args_(__args) {} 144 #endif 145 }; 146 147 // A specialization for __retarget_buffer 148 // 149 // See __retarget_buffer for the motivation for this specialization. 150 // 151 // This context holds a reference to the instance of the basic_format_context 152 // that is retargeted. It converts a formatting argument when it is requested 153 // during formatting. It is expected that the usage of the arguments is rare so 154 // the lookups are not expected to be used often. An alternative would be to 155 // convert all elements during construction. 156 // 157 // The elements of the retargets context are only used when an underlying 158 // formatter uses a locale specific formatting or an formatting argument is 159 // part for the format spec. For example 160 // format("{:256:{}}", input, 8); 161 // Here the width of an element in input is determined dynamically. 162 // Note when the top-level element has no width the retargeting is not needed. 163 template <class _CharT> 164 class _LIBCPP_TEMPLATE_VIS 165 basic_format_context<typename __format::__retarget_buffer<_CharT>::__iterator, _CharT> { 166 public: 167 using iterator = typename __format::__retarget_buffer<_CharT>::__iterator; 168 using char_type = _CharT; 169 template <class _Tp> 170 using formatter_type = formatter<_Tp, _CharT>; 171 172 template <class _Context> 173 _LIBCPP_HIDE_FROM_ABI explicit basic_format_context(iterator __out_it, _Context& __ctx) 174 : __out_it_(std::move(__out_it)), 175 # ifndef _LIBCPP_HAS_NO_LOCALIZATION 176 __loc_([](void* __c) { return static_cast<_Context*>(__c)->locale(); }), 177 # endif 178 __ctx_(std::addressof(__ctx)), 179 __arg_([](void* __c, size_t __id) { 180 return std::visit_format_arg( 181 [&](auto __arg) -> basic_format_arg<basic_format_context> { 182 if constexpr (same_as<decltype(__arg), monostate>) 183 return {}; 184 else if constexpr (same_as<decltype(__arg), typename basic_format_arg<_Context>::handle>) 185 // At the moment it's not possible for formatting to use a re-targeted handle. 186 // TODO FMT add this when support is needed. 187 std::__throw_format_error("Re-targeting handle not supported"); 188 else 189 return basic_format_arg<basic_format_context>{ 190 __format::__determine_arg_t<basic_format_context, decltype(__arg)>(), 191 __basic_format_arg_value<basic_format_context>(__arg)}; 192 }, 193 static_cast<_Context*>(__c)->arg(__id)); 194 }) { 195 } 196 197 _LIBCPP_HIDE_FROM_ABI basic_format_arg<basic_format_context> arg(size_t __id) const noexcept { 198 return __arg_(__ctx_, __id); 199 } 200 # ifndef _LIBCPP_HAS_NO_LOCALIZATION 201 _LIBCPP_HIDE_FROM_ABI _VSTD::locale locale() { return __loc_(__ctx_); } 202 # endif 203 _LIBCPP_HIDE_FROM_ABI iterator out() { return std::move(__out_it_); } 204 _LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = std::move(__it); } 205 206 private: 207 iterator __out_it_; 208 209 # ifndef _LIBCPP_HAS_NO_LOCALIZATION 210 std::locale (*__loc_)(void* __ctx); 211 # endif 212 213 void* __ctx_; 214 basic_format_arg<basic_format_context> (*__arg_)(void* __ctx, size_t __id); 215 }; 216 217 _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(basic_format_context); 218 #endif //_LIBCPP_STD_VER >= 20 219 220 _LIBCPP_END_NAMESPACE_STD 221 222 #endif // _LIBCPP___FORMAT_FORMAT_CONTEXT_H 223