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