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