xref: /freebsd-src/contrib/llvm-project/libcxx/include/__format/format_context.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1349cc55cSDimitry Andric // -*- C++ -*-
2349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
3349cc55cSDimitry Andric //
4349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
6349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7349cc55cSDimitry Andric //
8349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
9349cc55cSDimitry Andric 
10349cc55cSDimitry Andric #ifndef _LIBCPP___FORMAT_FORMAT_CONTEXT_H
11349cc55cSDimitry Andric #define _LIBCPP___FORMAT_FORMAT_CONTEXT_H
12349cc55cSDimitry Andric 
13bdd1243dSDimitry Andric #include <__concepts/same_as.h>
14349cc55cSDimitry Andric #include <__config>
1581ad6265SDimitry Andric #include <__format/buffer.h>
16bdd1243dSDimitry Andric #include <__format/format_arg.h>
17bdd1243dSDimitry Andric #include <__format/format_arg_store.h>
18349cc55cSDimitry Andric #include <__format/format_args.h>
19bdd1243dSDimitry Andric #include <__format/format_error.h>
20*0fca6ea1SDimitry Andric #include <__fwd/format.h>
210eae32dcSDimitry Andric #include <__iterator/back_insert_iterator.h>
22349cc55cSDimitry Andric #include <__iterator/concepts.h>
23bdd1243dSDimitry Andric #include <__memory/addressof.h>
2481ad6265SDimitry Andric #include <__utility/move.h>
25bdd1243dSDimitry Andric #include <__variant/monostate.h>
2681ad6265SDimitry Andric #include <cstddef>
27349cc55cSDimitry Andric 
28349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_LOCALIZATION
29*0fca6ea1SDimitry Andric #  include <__locale>
30349cc55cSDimitry Andric #  include <optional>
31349cc55cSDimitry Andric #endif
32349cc55cSDimitry Andric 
33349cc55cSDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
34349cc55cSDimitry Andric #  pragma GCC system_header
35349cc55cSDimitry Andric #endif
36349cc55cSDimitry Andric 
37b3edf446SDimitry Andric _LIBCPP_PUSH_MACROS
38b3edf446SDimitry Andric #include <__undef_macros>
39b3edf446SDimitry Andric 
40349cc55cSDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
41349cc55cSDimitry Andric 
4206c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20
43349cc55cSDimitry Andric 
44349cc55cSDimitry Andric template <class _OutIt, class _CharT>
45349cc55cSDimitry Andric   requires output_iterator<_OutIt, const _CharT&>
4606c3fb27SDimitry Andric class _LIBCPP_TEMPLATE_VIS basic_format_context;
47349cc55cSDimitry Andric 
48349cc55cSDimitry Andric #  ifndef _LIBCPP_HAS_NO_LOCALIZATION
49349cc55cSDimitry Andric /**
50349cc55cSDimitry Andric  * Helper to create a basic_format_context.
51349cc55cSDimitry Andric  *
52349cc55cSDimitry Andric  * This is needed since the constructor is private.
53349cc55cSDimitry Andric  */
54349cc55cSDimitry Andric template <class _OutIt, class _CharT>
55349cc55cSDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_format_context<_OutIt, _CharT>
56cb14a3feSDimitry Andric __format_context_create(_OutIt __out_it,
57349cc55cSDimitry Andric                         basic_format_args<basic_format_context<_OutIt, _CharT>> __args,
585f757f3fSDimitry Andric                         optional<std::locale>&& __loc = nullopt) {
595f757f3fSDimitry Andric   return std::basic_format_context(std::move(__out_it), __args, std::move(__loc));
60349cc55cSDimitry Andric }
61349cc55cSDimitry Andric #  else
62349cc55cSDimitry Andric template <class _OutIt, class _CharT>
63349cc55cSDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_format_context<_OutIt, _CharT>
64cb14a3feSDimitry Andric __format_context_create(_OutIt __out_it, basic_format_args<basic_format_context<_OutIt, _CharT>> __args) {
655f757f3fSDimitry Andric   return std::basic_format_context(std::move(__out_it), __args);
66349cc55cSDimitry Andric }
67349cc55cSDimitry Andric #  endif
68349cc55cSDimitry Andric 
69cb14a3feSDimitry Andric using format_context = basic_format_context<back_insert_iterator<__format::__output_buffer<char>>, char>;
70349cc55cSDimitry Andric #  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
71cb14a3feSDimitry Andric using wformat_context = basic_format_context< back_insert_iterator<__format::__output_buffer<wchar_t>>, wchar_t>;
72349cc55cSDimitry Andric #  endif
73349cc55cSDimitry Andric 
74349cc55cSDimitry Andric template <class _OutIt, class _CharT>
75349cc55cSDimitry Andric   requires output_iterator<_OutIt, const _CharT&>
76349cc55cSDimitry Andric class
77349cc55cSDimitry Andric     // clang-format off
78349cc55cSDimitry Andric     _LIBCPP_TEMPLATE_VIS
79349cc55cSDimitry Andric     _LIBCPP_PREFERRED_NAME(format_context)
80349cc55cSDimitry Andric     _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wformat_context))
81349cc55cSDimitry Andric     // clang-format on
82349cc55cSDimitry Andric     basic_format_context {
83349cc55cSDimitry Andric public:
84349cc55cSDimitry Andric   using iterator  = _OutIt;
85349cc55cSDimitry Andric   using char_type = _CharT;
86349cc55cSDimitry Andric   template <class _Tp>
87349cc55cSDimitry Andric   using formatter_type = formatter<_Tp, _CharT>;
88349cc55cSDimitry Andric 
89cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI basic_format_arg<basic_format_context> arg(size_t __id) const noexcept {
90349cc55cSDimitry Andric     return __args_.get(__id);
91349cc55cSDimitry Andric   }
92349cc55cSDimitry Andric #  ifndef _LIBCPP_HAS_NO_LOCALIZATION
935f757f3fSDimitry Andric   _LIBCPP_HIDE_FROM_ABI std::locale locale() {
94349cc55cSDimitry Andric     if (!__loc_)
955f757f3fSDimitry Andric       __loc_ = std::locale{};
96349cc55cSDimitry Andric     return *__loc_;
97349cc55cSDimitry Andric   }
98349cc55cSDimitry Andric #  endif
99bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI iterator out() { return std::move(__out_it_); }
100bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = std::move(__it); }
101349cc55cSDimitry Andric 
102349cc55cSDimitry Andric private:
103349cc55cSDimitry Andric   iterator __out_it_;
104349cc55cSDimitry Andric   basic_format_args<basic_format_context> __args_;
105349cc55cSDimitry Andric #  ifndef _LIBCPP_HAS_NO_LOCALIZATION
106349cc55cSDimitry Andric 
107349cc55cSDimitry Andric   // The Standard doesn't specify how the locale is stored.
108349cc55cSDimitry Andric   // [format.context]/6
109349cc55cSDimitry Andric   // std::locale locale();
110349cc55cSDimitry Andric   //   Returns: The locale passed to the formatting function if the latter
111349cc55cSDimitry Andric   //   takes one, and std::locale() otherwise.
112349cc55cSDimitry Andric   // This is done by storing the locale of the constructor in this optional. If
113349cc55cSDimitry Andric   // locale() is called and the optional has no value the value will be created.
114349cc55cSDimitry Andric   // This allows the implementation to lazily create the locale.
115349cc55cSDimitry Andric   // TODO FMT Validate whether lazy creation is the best solution.
1165f757f3fSDimitry Andric   optional<std::locale> __loc_;
117349cc55cSDimitry Andric 
11806c3fb27SDimitry Andric   template <class _OtherOutIt, class _OtherCharT>
119cb14a3feSDimitry Andric   friend _LIBCPP_HIDE_FROM_ABI basic_format_context<_OtherOutIt, _OtherCharT> __format_context_create(
120cb14a3feSDimitry Andric       _OtherOutIt, basic_format_args<basic_format_context<_OtherOutIt, _OtherCharT>>, optional<std::locale>&&);
121349cc55cSDimitry Andric 
122349cc55cSDimitry Andric   // Note: the Standard doesn't specify the required constructors.
123cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit basic_format_context(
124cb14a3feSDimitry Andric       _OutIt __out_it, basic_format_args<basic_format_context> __args, optional<std::locale>&& __loc)
125cb14a3feSDimitry Andric       : __out_it_(std::move(__out_it)), __args_(__args), __loc_(std::move(__loc)) {}
126349cc55cSDimitry Andric #  else
12706c3fb27SDimitry Andric   template <class _OtherOutIt, class _OtherCharT>
12806c3fb27SDimitry Andric   friend _LIBCPP_HIDE_FROM_ABI basic_format_context<_OtherOutIt, _OtherCharT>
12906c3fb27SDimitry Andric       __format_context_create(_OtherOutIt, basic_format_args<basic_format_context<_OtherOutIt, _OtherCharT>>);
130349cc55cSDimitry Andric 
131cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit basic_format_context(_OutIt __out_it, basic_format_args<basic_format_context> __args)
1325f757f3fSDimitry Andric       : __out_it_(std::move(__out_it)), __args_(__args) {}
133349cc55cSDimitry Andric #  endif
134*0fca6ea1SDimitry Andric 
135*0fca6ea1SDimitry Andric   basic_format_context(const basic_format_context&)            = delete;
136*0fca6ea1SDimitry Andric   basic_format_context& operator=(const basic_format_context&) = delete;
137349cc55cSDimitry Andric };
138349cc55cSDimitry Andric 
139bdd1243dSDimitry Andric // A specialization for __retarget_buffer
140bdd1243dSDimitry Andric //
141bdd1243dSDimitry Andric // See __retarget_buffer for the motivation for this specialization.
142bdd1243dSDimitry Andric //
143bdd1243dSDimitry Andric // This context holds a reference to the instance of the basic_format_context
144bdd1243dSDimitry Andric // that is retargeted. It converts a formatting argument when it is requested
145bdd1243dSDimitry Andric // during formatting. It is expected that the usage of the arguments is rare so
146bdd1243dSDimitry Andric // the lookups are not expected to be used often. An alternative would be to
147bdd1243dSDimitry Andric // convert all elements during construction.
148bdd1243dSDimitry Andric //
149bdd1243dSDimitry Andric // The elements of the retargets context are only used when an underlying
150bdd1243dSDimitry Andric // formatter uses a locale specific formatting or an formatting argument is
151bdd1243dSDimitry Andric // part for the format spec. For example
152bdd1243dSDimitry Andric //   format("{:256:{}}", input, 8);
153bdd1243dSDimitry Andric // Here the width of an element in input is determined dynamically.
154bdd1243dSDimitry Andric // Note when the top-level element has no width the retargeting is not needed.
155bdd1243dSDimitry Andric template <class _CharT>
156cb14a3feSDimitry Andric class _LIBCPP_TEMPLATE_VIS basic_format_context<typename __format::__retarget_buffer<_CharT>::__iterator, _CharT> {
157bdd1243dSDimitry Andric public:
158bdd1243dSDimitry Andric   using iterator  = typename __format::__retarget_buffer<_CharT>::__iterator;
159bdd1243dSDimitry Andric   using char_type = _CharT;
160bdd1243dSDimitry Andric   template <class _Tp>
161bdd1243dSDimitry Andric   using formatter_type = formatter<_Tp, _CharT>;
162bdd1243dSDimitry Andric 
163bdd1243dSDimitry Andric   template <class _Context>
164bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit basic_format_context(iterator __out_it, _Context& __ctx)
165bdd1243dSDimitry Andric       : __out_it_(std::move(__out_it)),
166bdd1243dSDimitry Andric #  ifndef _LIBCPP_HAS_NO_LOCALIZATION
167bdd1243dSDimitry Andric         __loc_([](void* __c) { return static_cast<_Context*>(__c)->locale(); }),
168bdd1243dSDimitry Andric #  endif
169bdd1243dSDimitry Andric         __ctx_(std::addressof(__ctx)),
170bdd1243dSDimitry Andric         __arg_([](void* __c, size_t __id) {
171*0fca6ea1SDimitry Andric           auto __visitor = [&](auto __arg) -> basic_format_arg<basic_format_context> {
172bdd1243dSDimitry Andric             if constexpr (same_as<decltype(__arg), monostate>)
173bdd1243dSDimitry Andric               return {};
174bdd1243dSDimitry Andric             else if constexpr (same_as<decltype(__arg), typename basic_format_arg<_Context>::handle>)
175bdd1243dSDimitry Andric               // At the moment it's not possible for formatting to use a re-targeted handle.
176bdd1243dSDimitry Andric               // TODO FMT add this when support is needed.
177bdd1243dSDimitry Andric               std::__throw_format_error("Re-targeting handle not supported");
178bdd1243dSDimitry Andric             else
179bdd1243dSDimitry Andric               return basic_format_arg<basic_format_context>{
180bdd1243dSDimitry Andric                   __format::__determine_arg_t<basic_format_context, decltype(__arg)>(),
181bdd1243dSDimitry Andric                   __basic_format_arg_value<basic_format_context>(__arg)};
182*0fca6ea1SDimitry Andric           };
183*0fca6ea1SDimitry Andric #  if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
184*0fca6ea1SDimitry Andric           return static_cast<_Context*>(__c)->arg(__id).visit(std::move(__visitor));
185*0fca6ea1SDimitry Andric #  else
186*0fca6ea1SDimitry Andric           _LIBCPP_SUPPRESS_DEPRECATED_PUSH
187*0fca6ea1SDimitry Andric           return std::visit_format_arg(std::move(__visitor), static_cast<_Context*>(__c)->arg(__id));
188*0fca6ea1SDimitry Andric           _LIBCPP_SUPPRESS_DEPRECATED_POP
189*0fca6ea1SDimitry Andric #  endif // _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
190bdd1243dSDimitry Andric         }) {
191bdd1243dSDimitry Andric   }
192bdd1243dSDimitry Andric 
193bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI basic_format_arg<basic_format_context> arg(size_t __id) const noexcept {
194bdd1243dSDimitry Andric     return __arg_(__ctx_, __id);
195bdd1243dSDimitry Andric   }
196bdd1243dSDimitry Andric #  ifndef _LIBCPP_HAS_NO_LOCALIZATION
1975f757f3fSDimitry Andric   _LIBCPP_HIDE_FROM_ABI std::locale locale() { return __loc_(__ctx_); }
198bdd1243dSDimitry Andric #  endif
199bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI iterator out() { return std::move(__out_it_); }
200bdd1243dSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = std::move(__it); }
201bdd1243dSDimitry Andric 
202bdd1243dSDimitry Andric private:
203bdd1243dSDimitry Andric   iterator __out_it_;
204bdd1243dSDimitry Andric 
205bdd1243dSDimitry Andric #  ifndef _LIBCPP_HAS_NO_LOCALIZATION
206bdd1243dSDimitry Andric   std::locale (*__loc_)(void* __ctx);
207bdd1243dSDimitry Andric #  endif
208bdd1243dSDimitry Andric 
209bdd1243dSDimitry Andric   void* __ctx_;
210bdd1243dSDimitry Andric   basic_format_arg<basic_format_context> (*__arg_)(void* __ctx, size_t __id);
211bdd1243dSDimitry Andric };
212bdd1243dSDimitry Andric 
213bdd1243dSDimitry Andric _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(basic_format_context);
21406c3fb27SDimitry Andric #endif //_LIBCPP_STD_VER >= 20
215349cc55cSDimitry Andric 
216349cc55cSDimitry Andric _LIBCPP_END_NAMESPACE_STD
217349cc55cSDimitry Andric 
218b3edf446SDimitry Andric _LIBCPP_POP_MACROS
219b3edf446SDimitry Andric 
220349cc55cSDimitry Andric #endif // _LIBCPP___FORMAT_FORMAT_CONTEXT_H
221