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