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 <__concepts/same_as.h>
14 #include <__config>
15 #include <__format/buffer.h>
16 #include <__format/format_arg.h>
17 #include <__format/format_arg_store.h>
18 #include <__format/format_args.h>
19 #include <__format/format_error.h>
20 #include <__fwd/format.h>
21 #include <__iterator/back_insert_iterator.h>
22 #include <__iterator/concepts.h>
23 #include <__memory/addressof.h>
24 #include <__utility/move.h>
25 #include <__variant/monostate.h>
26 #include <cstddef>
27
28 #ifndef _LIBCPP_HAS_NO_LOCALIZATION
29 # include <__locale>
30 # include <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 <__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>
__format_context_create(_OutIt __out_it,basic_format_args<basic_format_context<_OutIt,_CharT>> __args)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
_LIBCPP_PREFERRED_NAME(format_context)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>
basic_format_context(iterator __out_it,_Context & __ctx)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
arg(size_t __id)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
locale()197 _LIBCPP_HIDE_FROM_ABI std::locale locale() { return __loc_(__ctx_); }
198 # endif
out()199 _LIBCPP_HIDE_FROM_ABI iterator out() { return std::move(__out_it_); }
advance_to(iterator __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___FORMAT_FORMAT_CONTEXT_H
221