xref: /freebsd-src/contrib/llvm-project/libcxx/include/__format/format_arg.h (revision 1199d38d8ec764ce8545888b4c091d00441842bf)
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_ARG_H
11349cc55cSDimitry Andric #define _LIBCPP___FORMAT_FORMAT_ARG_H
12349cc55cSDimitry Andric 
1381ad6265SDimitry Andric #include <__assert>
14349cc55cSDimitry Andric #include <__concepts/arithmetic.h>
15349cc55cSDimitry Andric #include <__config>
1606c3fb27SDimitry Andric #include <__format/concepts.h>
1704eeddc0SDimitry Andric #include <__format/format_parse_context.h>
1881ad6265SDimitry Andric #include <__functional/invoke.h>
19*0fca6ea1SDimitry Andric #include <__fwd/format.h>
2004eeddc0SDimitry Andric #include <__memory/addressof.h>
2106c3fb27SDimitry Andric #include <__type_traits/conditional.h>
2281ad6265SDimitry Andric #include <__utility/forward.h>
2306c3fb27SDimitry Andric #include <__utility/move.h>
2481ad6265SDimitry Andric #include <__utility/unreachable.h>
25349cc55cSDimitry Andric #include <__variant/monostate.h>
2606c3fb27SDimitry Andric #include <cstdint>
27349cc55cSDimitry Andric #include <string_view>
28349cc55cSDimitry Andric 
29349cc55cSDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
30349cc55cSDimitry Andric #  pragma GCC system_header
31349cc55cSDimitry Andric #endif
32349cc55cSDimitry Andric 
33b3edf446SDimitry Andric _LIBCPP_PUSH_MACROS
34b3edf446SDimitry Andric #include <__undef_macros>
35b3edf446SDimitry Andric 
36349cc55cSDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
37349cc55cSDimitry Andric 
3806c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20
39349cc55cSDimitry Andric 
40349cc55cSDimitry Andric namespace __format {
410eae32dcSDimitry Andric /// The type stored in @ref basic_format_arg.
420eae32dcSDimitry Andric ///
430eae32dcSDimitry Andric /// @note The 128-bit types are unconditionally in the list to avoid the values
440eae32dcSDimitry Andric /// of the enums to depend on the availability of 128-bit integers.
4581ad6265SDimitry Andric ///
4681ad6265SDimitry Andric /// @note The value is stored as a 5-bit value in the __packed_arg_t_bits. This
4781ad6265SDimitry Andric /// limits the maximum number of elements to 32.
4881ad6265SDimitry Andric /// When modifying update the test
4981ad6265SDimitry Andric /// test/libcxx/utilities/format/format.arguments/format.arg/arg_t.compile.pass.cpp
5081ad6265SDimitry Andric /// It could be packed in 4-bits but that means a new type directly becomes an
5181ad6265SDimitry Andric /// ABI break. The packed type is 64-bit so this reduces the maximum number of
5281ad6265SDimitry Andric /// packed elements from 16 to 12.
53bdd1243dSDimitry Andric ///
54bdd1243dSDimitry Andric /// @note Some members of this enum are an extension. These extensions need
55bdd1243dSDimitry Andric /// special behaviour in visit_format_arg. There they need to be wrapped in a
56bdd1243dSDimitry Andric /// handle to satisfy the user observable behaviour. The internal function
57bdd1243dSDimitry Andric /// __visit_format_arg doesn't do this wrapping. So in the format functions
58bdd1243dSDimitry Andric /// this function is used to avoid unneeded overhead.
595f757f3fSDimitry Andric enum class __arg_t : uint8_t {
60349cc55cSDimitry Andric   __none,
61349cc55cSDimitry Andric   __boolean,
62349cc55cSDimitry Andric   __char_type,
63349cc55cSDimitry Andric   __int,
64349cc55cSDimitry Andric   __long_long,
65bdd1243dSDimitry Andric   __i128, // extension
66349cc55cSDimitry Andric   __unsigned,
67349cc55cSDimitry Andric   __unsigned_long_long,
68bdd1243dSDimitry Andric   __u128, // extension
69349cc55cSDimitry Andric   __float,
70349cc55cSDimitry Andric   __double,
71349cc55cSDimitry Andric   __long_double,
72349cc55cSDimitry Andric   __const_char_type_ptr,
73349cc55cSDimitry Andric   __string_view,
7404eeddc0SDimitry Andric   __ptr,
7504eeddc0SDimitry Andric   __handle
76349cc55cSDimitry Andric };
7781ad6265SDimitry Andric 
7881ad6265SDimitry Andric inline constexpr unsigned __packed_arg_t_bits = 5;
7981ad6265SDimitry Andric inline constexpr uint8_t __packed_arg_t_mask  = 0x1f;
8081ad6265SDimitry Andric 
8181ad6265SDimitry Andric inline constexpr unsigned __packed_types_storage_bits = 64;
8281ad6265SDimitry Andric inline constexpr unsigned __packed_types_max          = __packed_types_storage_bits / __packed_arg_t_bits;
8381ad6265SDimitry Andric 
84cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr bool __use_packed_format_arg_store(size_t __size) {
85cb14a3feSDimitry Andric   return __size <= __packed_types_max;
86cb14a3feSDimitry Andric }
8781ad6265SDimitry Andric 
88cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr __arg_t __get_packed_type(uint64_t __types, size_t __id) {
891db9f3b2SDimitry Andric   _LIBCPP_ASSERT_INTERNAL(__id <= __packed_types_max, "");
9081ad6265SDimitry Andric 
9181ad6265SDimitry Andric   if (__id > 0)
9281ad6265SDimitry Andric     __types >>= __id * __packed_arg_t_bits;
9381ad6265SDimitry Andric 
9481ad6265SDimitry Andric   return static_cast<__format::__arg_t>(__types & __packed_arg_t_mask);
9581ad6265SDimitry Andric }
9681ad6265SDimitry Andric 
97349cc55cSDimitry Andric } // namespace __format
98349cc55cSDimitry Andric 
99*0fca6ea1SDimitry Andric // This function is not user observable, so it can directly use the non-standard
100bdd1243dSDimitry Andric // types of the "variant". See __arg_t for more details.
101349cc55cSDimitry Andric template <class _Visitor, class _Context>
102cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI decltype(auto) __visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) {
103349cc55cSDimitry Andric   switch (__arg.__type_) {
104349cc55cSDimitry Andric   case __format::__arg_t::__none:
1055f757f3fSDimitry Andric     return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__monostate_);
106349cc55cSDimitry Andric   case __format::__arg_t::__boolean:
1075f757f3fSDimitry Andric     return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__boolean_);
108349cc55cSDimitry Andric   case __format::__arg_t::__char_type:
1095f757f3fSDimitry Andric     return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__char_type_);
110349cc55cSDimitry Andric   case __format::__arg_t::__int:
1115f757f3fSDimitry Andric     return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__int_);
112349cc55cSDimitry Andric   case __format::__arg_t::__long_long:
1135f757f3fSDimitry Andric     return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__long_long_);
114349cc55cSDimitry Andric   case __format::__arg_t::__i128:
1150eae32dcSDimitry Andric #  ifndef _LIBCPP_HAS_NO_INT128
1165f757f3fSDimitry Andric     return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__i128_);
1170eae32dcSDimitry Andric #  else
11881ad6265SDimitry Andric     __libcpp_unreachable();
119349cc55cSDimitry Andric #  endif
120349cc55cSDimitry Andric   case __format::__arg_t::__unsigned:
1215f757f3fSDimitry Andric     return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__unsigned_);
122349cc55cSDimitry Andric   case __format::__arg_t::__unsigned_long_long:
1235f757f3fSDimitry Andric     return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__unsigned_long_long_);
124349cc55cSDimitry Andric   case __format::__arg_t::__u128:
1250eae32dcSDimitry Andric #  ifndef _LIBCPP_HAS_NO_INT128
1265f757f3fSDimitry Andric     return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__u128_);
1270eae32dcSDimitry Andric #  else
12881ad6265SDimitry Andric     __libcpp_unreachable();
129349cc55cSDimitry Andric #  endif
130349cc55cSDimitry Andric   case __format::__arg_t::__float:
1315f757f3fSDimitry Andric     return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__float_);
132349cc55cSDimitry Andric   case __format::__arg_t::__double:
1335f757f3fSDimitry Andric     return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__double_);
134349cc55cSDimitry Andric   case __format::__arg_t::__long_double:
1355f757f3fSDimitry Andric     return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__long_double_);
136349cc55cSDimitry Andric   case __format::__arg_t::__const_char_type_ptr:
1375f757f3fSDimitry Andric     return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__const_char_type_ptr_);
138349cc55cSDimitry Andric   case __format::__arg_t::__string_view:
1395f757f3fSDimitry Andric     return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__string_view_);
140349cc55cSDimitry Andric   case __format::__arg_t::__ptr:
1415f757f3fSDimitry Andric     return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__ptr_);
14204eeddc0SDimitry Andric   case __format::__arg_t::__handle:
143cb14a3feSDimitry Andric     return std::invoke(
144cb14a3feSDimitry Andric         std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__arg.__value_.__handle_});
145349cc55cSDimitry Andric   }
14681ad6265SDimitry Andric 
14781ad6265SDimitry Andric   __libcpp_unreachable();
148349cc55cSDimitry Andric }
149349cc55cSDimitry Andric 
150*0fca6ea1SDimitry Andric #  if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
151*0fca6ea1SDimitry Andric 
152*0fca6ea1SDimitry Andric template <class _Rp, class _Visitor, class _Context>
153*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI _Rp __visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) {
154*0fca6ea1SDimitry Andric   switch (__arg.__type_) {
155*0fca6ea1SDimitry Andric   case __format::__arg_t::__none:
156*0fca6ea1SDimitry Andric     return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__monostate_);
157*0fca6ea1SDimitry Andric   case __format::__arg_t::__boolean:
158*0fca6ea1SDimitry Andric     return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__boolean_);
159*0fca6ea1SDimitry Andric   case __format::__arg_t::__char_type:
160*0fca6ea1SDimitry Andric     return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__char_type_);
161*0fca6ea1SDimitry Andric   case __format::__arg_t::__int:
162*0fca6ea1SDimitry Andric     return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__int_);
163*0fca6ea1SDimitry Andric   case __format::__arg_t::__long_long:
164*0fca6ea1SDimitry Andric     return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__long_long_);
165*0fca6ea1SDimitry Andric   case __format::__arg_t::__i128:
166*0fca6ea1SDimitry Andric #    ifndef _LIBCPP_HAS_NO_INT128
167*0fca6ea1SDimitry Andric     return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__i128_);
168*0fca6ea1SDimitry Andric #    else
169*0fca6ea1SDimitry Andric     __libcpp_unreachable();
170*0fca6ea1SDimitry Andric #    endif
171*0fca6ea1SDimitry Andric   case __format::__arg_t::__unsigned:
172*0fca6ea1SDimitry Andric     return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__unsigned_);
173*0fca6ea1SDimitry Andric   case __format::__arg_t::__unsigned_long_long:
174*0fca6ea1SDimitry Andric     return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__unsigned_long_long_);
175*0fca6ea1SDimitry Andric   case __format::__arg_t::__u128:
176*0fca6ea1SDimitry Andric #    ifndef _LIBCPP_HAS_NO_INT128
177*0fca6ea1SDimitry Andric     return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__u128_);
178*0fca6ea1SDimitry Andric #    else
179*0fca6ea1SDimitry Andric     __libcpp_unreachable();
180*0fca6ea1SDimitry Andric #    endif
181*0fca6ea1SDimitry Andric   case __format::__arg_t::__float:
182*0fca6ea1SDimitry Andric     return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__float_);
183*0fca6ea1SDimitry Andric   case __format::__arg_t::__double:
184*0fca6ea1SDimitry Andric     return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__double_);
185*0fca6ea1SDimitry Andric   case __format::__arg_t::__long_double:
186*0fca6ea1SDimitry Andric     return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__long_double_);
187*0fca6ea1SDimitry Andric   case __format::__arg_t::__const_char_type_ptr:
188*0fca6ea1SDimitry Andric     return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__const_char_type_ptr_);
189*0fca6ea1SDimitry Andric   case __format::__arg_t::__string_view:
190*0fca6ea1SDimitry Andric     return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__string_view_);
191*0fca6ea1SDimitry Andric   case __format::__arg_t::__ptr:
192*0fca6ea1SDimitry Andric     return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__ptr_);
193*0fca6ea1SDimitry Andric   case __format::__arg_t::__handle:
194*0fca6ea1SDimitry Andric     return std::invoke_r<_Rp>(
195*0fca6ea1SDimitry Andric         std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__arg.__value_.__handle_});
196*0fca6ea1SDimitry Andric   }
197*0fca6ea1SDimitry Andric 
198*0fca6ea1SDimitry Andric   __libcpp_unreachable();
199*0fca6ea1SDimitry Andric }
200*0fca6ea1SDimitry Andric 
201*0fca6ea1SDimitry Andric #  endif // _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
202*0fca6ea1SDimitry Andric 
20381ad6265SDimitry Andric /// Contains the values used in basic_format_arg.
20481ad6265SDimitry Andric ///
20581ad6265SDimitry Andric /// This is a separate type so it's possible to store the values and types in
20681ad6265SDimitry Andric /// separate arrays.
20781ad6265SDimitry Andric template <class _Context>
20881ad6265SDimitry Andric class __basic_format_arg_value {
20981ad6265SDimitry Andric   using _CharT = typename _Context::char_type;
21081ad6265SDimitry Andric 
21181ad6265SDimitry Andric public:
21281ad6265SDimitry Andric   /// Contains the implementation for basic_format_arg::handle.
21381ad6265SDimitry Andric   struct __handle {
21481ad6265SDimitry Andric     template <class _Tp>
21506c3fb27SDimitry Andric     _LIBCPP_HIDE_FROM_ABI explicit __handle(_Tp& __v) noexcept
2165f757f3fSDimitry Andric         : __ptr_(std::addressof(__v)),
21781ad6265SDimitry Andric           __format_([](basic_format_parse_context<_CharT>& __parse_ctx, _Context& __ctx, const void* __ptr) {
21806c3fb27SDimitry Andric             using _Dp = remove_const_t<_Tp>;
21906c3fb27SDimitry Andric             using _Qp = conditional_t<__formattable_with<const _Dp, _Context>, const _Dp, _Dp>;
22006c3fb27SDimitry Andric             static_assert(__formattable_with<_Qp, _Context>, "Mandated by [format.arg]/10");
221753f127fSDimitry Andric 
22206c3fb27SDimitry Andric             typename _Context::template formatter_type<_Dp> __f;
22381ad6265SDimitry Andric             __parse_ctx.advance_to(__f.parse(__parse_ctx));
224753f127fSDimitry Andric             __ctx.advance_to(__f.format(*const_cast<_Qp*>(static_cast<const _Dp*>(__ptr)), __ctx));
22581ad6265SDimitry Andric           }) {}
22681ad6265SDimitry Andric 
22781ad6265SDimitry Andric     const void* __ptr_;
22881ad6265SDimitry Andric     void (*__format_)(basic_format_parse_context<_CharT>&, _Context&, const void*);
22981ad6265SDimitry Andric   };
23081ad6265SDimitry Andric 
23181ad6265SDimitry Andric   union {
23281ad6265SDimitry Andric     monostate __monostate_;
23381ad6265SDimitry Andric     bool __boolean_;
23481ad6265SDimitry Andric     _CharT __char_type_;
23581ad6265SDimitry Andric     int __int_;
23681ad6265SDimitry Andric     unsigned __unsigned_;
23781ad6265SDimitry Andric     long long __long_long_;
23881ad6265SDimitry Andric     unsigned long long __unsigned_long_long_;
23981ad6265SDimitry Andric #  ifndef _LIBCPP_HAS_NO_INT128
24081ad6265SDimitry Andric     __int128_t __i128_;
24181ad6265SDimitry Andric     __uint128_t __u128_;
24281ad6265SDimitry Andric #  endif
24381ad6265SDimitry Andric     float __float_;
24481ad6265SDimitry Andric     double __double_;
24581ad6265SDimitry Andric     long double __long_double_;
24681ad6265SDimitry Andric     const _CharT* __const_char_type_ptr_;
24781ad6265SDimitry Andric     basic_string_view<_CharT> __string_view_;
24881ad6265SDimitry Andric     const void* __ptr_;
24981ad6265SDimitry Andric     __handle __handle_;
25081ad6265SDimitry Andric   };
25181ad6265SDimitry Andric 
25281ad6265SDimitry Andric   // These constructors contain the exact storage type used. If adjustments are
25381ad6265SDimitry Andric   // required, these will be done in __create_format_arg.
25481ad6265SDimitry Andric 
25581ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value() noexcept : __monostate_() {}
25681ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(bool __value) noexcept : __boolean_(__value) {}
25781ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(_CharT __value) noexcept : __char_type_(__value) {}
25881ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(int __value) noexcept : __int_(__value) {}
25981ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(unsigned __value) noexcept : __unsigned_(__value) {}
26081ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(long long __value) noexcept : __long_long_(__value) {}
26181ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(unsigned long long __value) noexcept
26281ad6265SDimitry Andric       : __unsigned_long_long_(__value) {}
26381ad6265SDimitry Andric #  ifndef _LIBCPP_HAS_NO_INT128
26481ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(__int128_t __value) noexcept : __i128_(__value) {}
26581ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(__uint128_t __value) noexcept : __u128_(__value) {}
26681ad6265SDimitry Andric #  endif
26781ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(float __value) noexcept : __float_(__value) {}
26881ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(double __value) noexcept : __double_(__value) {}
26981ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(long double __value) noexcept : __long_double_(__value) {}
27081ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(const _CharT* __value) noexcept : __const_char_type_ptr_(__value) {}
27181ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(basic_string_view<_CharT> __value) noexcept
27281ad6265SDimitry Andric       : __string_view_(__value) {}
27381ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(const void* __value) noexcept : __ptr_(__value) {}
27406c3fb27SDimitry Andric   _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(__handle&& __value) noexcept : __handle_(std::move(__value)) {}
27581ad6265SDimitry Andric };
27681ad6265SDimitry Andric 
277349cc55cSDimitry Andric template <class _Context>
27806c3fb27SDimitry Andric class _LIBCPP_TEMPLATE_VIS basic_format_arg {
279349cc55cSDimitry Andric public:
28004eeddc0SDimitry Andric   class _LIBCPP_TEMPLATE_VIS handle;
281349cc55cSDimitry Andric 
282cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI basic_format_arg() noexcept : __type_{__format::__arg_t::__none} {}
283349cc55cSDimitry Andric 
284cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit operator bool() const noexcept { return __type_ != __format::__arg_t::__none; }
285349cc55cSDimitry Andric 
286*0fca6ea1SDimitry Andric #  if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
287*0fca6ea1SDimitry Andric 
288*0fca6ea1SDimitry Andric   // This function is user facing, so it must wrap the non-standard types of
289*0fca6ea1SDimitry Andric   // the "variant" in a handle to stay conforming. See __arg_t for more details.
290*0fca6ea1SDimitry Andric   template <class _Visitor>
291*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI decltype(auto) visit(this basic_format_arg __arg, _Visitor&& __vis) {
292*0fca6ea1SDimitry Andric     switch (__arg.__type_) {
293*0fca6ea1SDimitry Andric #    ifndef _LIBCPP_HAS_NO_INT128
294*0fca6ea1SDimitry Andric     case __format::__arg_t::__i128: {
295*0fca6ea1SDimitry Andric       typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__i128_};
296*0fca6ea1SDimitry Andric       return std::invoke(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
297*0fca6ea1SDimitry Andric     }
298*0fca6ea1SDimitry Andric 
299*0fca6ea1SDimitry Andric     case __format::__arg_t::__u128: {
300*0fca6ea1SDimitry Andric       typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__u128_};
301*0fca6ea1SDimitry Andric       return std::invoke(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
302*0fca6ea1SDimitry Andric     }
303*0fca6ea1SDimitry Andric #    endif
304*0fca6ea1SDimitry Andric     default:
305*0fca6ea1SDimitry Andric       return std::__visit_format_arg(std::forward<_Visitor>(__vis), __arg);
306*0fca6ea1SDimitry Andric     }
307*0fca6ea1SDimitry Andric   }
308*0fca6ea1SDimitry Andric 
309*0fca6ea1SDimitry Andric   // This function is user facing, so it must wrap the non-standard types of
310*0fca6ea1SDimitry Andric   // the "variant" in a handle to stay conforming. See __arg_t for more details.
311*0fca6ea1SDimitry Andric   template <class _Rp, class _Visitor>
312*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI _Rp visit(this basic_format_arg __arg, _Visitor&& __vis) {
313*0fca6ea1SDimitry Andric     switch (__arg.__type_) {
314*0fca6ea1SDimitry Andric #    ifndef _LIBCPP_HAS_NO_INT128
315*0fca6ea1SDimitry Andric     case __format::__arg_t::__i128: {
316*0fca6ea1SDimitry Andric       typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__i128_};
317*0fca6ea1SDimitry Andric       return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
318*0fca6ea1SDimitry Andric     }
319*0fca6ea1SDimitry Andric 
320*0fca6ea1SDimitry Andric     case __format::__arg_t::__u128: {
321*0fca6ea1SDimitry Andric       typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__u128_};
322*0fca6ea1SDimitry Andric       return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
323*0fca6ea1SDimitry Andric     }
324*0fca6ea1SDimitry Andric #    endif
325*0fca6ea1SDimitry Andric     default:
326*0fca6ea1SDimitry Andric       return std::__visit_format_arg<_Rp>(std::forward<_Visitor>(__vis), __arg);
327*0fca6ea1SDimitry Andric     }
328*0fca6ea1SDimitry Andric   }
329*0fca6ea1SDimitry Andric 
330*0fca6ea1SDimitry Andric #  endif // _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
331*0fca6ea1SDimitry Andric 
332349cc55cSDimitry Andric private:
333349cc55cSDimitry Andric   using char_type = typename _Context::char_type;
334349cc55cSDimitry Andric 
335349cc55cSDimitry Andric   // TODO FMT Implement constrain [format.arg]/4
336349cc55cSDimitry Andric   // Constraints: The template specialization
337349cc55cSDimitry Andric   //   typename Context::template formatter_type<T>
338349cc55cSDimitry Andric   // meets the Formatter requirements ([formatter.requirements]).  The extent
339349cc55cSDimitry Andric   // to which an implementation determines that the specialization meets the
340349cc55cSDimitry Andric   // Formatter requirements is unspecified, except that as a minimum the
341349cc55cSDimitry Andric   // expression
342349cc55cSDimitry Andric   //   typename Context::template formatter_type<T>()
343349cc55cSDimitry Andric   //    .format(declval<const T&>(), declval<Context&>())
344349cc55cSDimitry Andric   // shall be well-formed when treated as an unevaluated operand.
345349cc55cSDimitry Andric 
34681ad6265SDimitry Andric public:
34781ad6265SDimitry Andric   __basic_format_arg_value<_Context> __value_;
348349cc55cSDimitry Andric   __format::__arg_t __type_;
349349cc55cSDimitry Andric 
35081ad6265SDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(__format::__arg_t __type,
35181ad6265SDimitry Andric                                                   __basic_format_arg_value<_Context> __value) noexcept
35281ad6265SDimitry Andric       : __value_(__value), __type_(__type) {}
35304eeddc0SDimitry Andric };
35404eeddc0SDimitry Andric 
35504eeddc0SDimitry Andric template <class _Context>
35604eeddc0SDimitry Andric class _LIBCPP_TEMPLATE_VIS basic_format_arg<_Context>::handle {
35704eeddc0SDimitry Andric public:
358cb14a3feSDimitry Andric   _LIBCPP_HIDE_FROM_ABI void format(basic_format_parse_context<char_type>& __parse_ctx, _Context& __ctx) const {
35981ad6265SDimitry Andric     __handle_.__format_(__parse_ctx, __ctx, __handle_.__ptr_);
36004eeddc0SDimitry Andric   }
36104eeddc0SDimitry Andric 
362753f127fSDimitry Andric   _LIBCPP_HIDE_FROM_ABI explicit handle(typename __basic_format_arg_value<_Context>::__handle& __handle) noexcept
36381ad6265SDimitry Andric       : __handle_(__handle) {}
36481ad6265SDimitry Andric 
36504eeddc0SDimitry Andric private:
366753f127fSDimitry Andric   typename __basic_format_arg_value<_Context>::__handle& __handle_;
367349cc55cSDimitry Andric };
368349cc55cSDimitry Andric 
369bdd1243dSDimitry Andric // This function is user facing, so it must wrap the non-standard types of
370bdd1243dSDimitry Andric // the "variant" in a handle to stay conforming. See __arg_t for more details.
371bdd1243dSDimitry Andric template <class _Visitor, class _Context>
372*0fca6ea1SDimitry Andric #  if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
373*0fca6ea1SDimitry Andric _LIBCPP_DEPRECATED_IN_CXX26
374*0fca6ea1SDimitry Andric #  endif
375*0fca6ea1SDimitry Andric     _LIBCPP_HIDE_FROM_ABI decltype(auto)
376*0fca6ea1SDimitry Andric     visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) {
377bdd1243dSDimitry Andric   switch (__arg.__type_) {
378bdd1243dSDimitry Andric #  ifndef _LIBCPP_HAS_NO_INT128
379bdd1243dSDimitry Andric   case __format::__arg_t::__i128: {
380bdd1243dSDimitry Andric     typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__i128_};
3815f757f3fSDimitry Andric     return std::invoke(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
382bdd1243dSDimitry Andric   }
383bdd1243dSDimitry Andric 
384bdd1243dSDimitry Andric   case __format::__arg_t::__u128: {
385bdd1243dSDimitry Andric     typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__u128_};
3865f757f3fSDimitry Andric     return std::invoke(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
387bdd1243dSDimitry Andric   }
388*0fca6ea1SDimitry Andric #  endif // _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
389bdd1243dSDimitry Andric   default:
3905f757f3fSDimitry Andric     return std::__visit_format_arg(std::forward<_Visitor>(__vis), __arg);
391bdd1243dSDimitry Andric   }
392bdd1243dSDimitry Andric }
393bdd1243dSDimitry Andric 
39406c3fb27SDimitry Andric #endif //_LIBCPP_STD_VER >= 20
395349cc55cSDimitry Andric 
396349cc55cSDimitry Andric _LIBCPP_END_NAMESPACE_STD
397349cc55cSDimitry Andric 
398b3edf446SDimitry Andric _LIBCPP_POP_MACROS
399b3edf446SDimitry Andric 
400349cc55cSDimitry Andric #endif // _LIBCPP___FORMAT_FORMAT_ARG_H
401