File indexing completed on 2026-05-03 08:13:49
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef _LIBCPP___FORMAT_FORMAT_ARG_STORE_H
0011 #define _LIBCPP___FORMAT_FORMAT_ARG_STORE_H
0012
0013 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
0014 # pragma GCC system_header
0015 #endif
0016
0017 #include <__concepts/arithmetic.h>
0018 #include <__concepts/same_as.h>
0019 #include <__config>
0020 #include <__format/concepts.h>
0021 #include <__format/format_arg.h>
0022 #include <__type_traits/conditional.h>
0023 #include <__type_traits/extent.h>
0024 #include <__type_traits/remove_const.h>
0025 #include <cstdint>
0026 #include <string>
0027 #include <string_view>
0028
0029 _LIBCPP_BEGIN_NAMESPACE_STD
0030
0031 #if _LIBCPP_STD_VER >= 20
0032
0033 namespace __format {
0034
0035
0036
0037
0038 template <class _Context, class _Tp>
0039 consteval __arg_t __determine_arg_t();
0040
0041
0042 template <class, same_as<bool> _Tp>
0043 consteval __arg_t __determine_arg_t() {
0044 return __arg_t::__boolean;
0045 }
0046
0047
0048 template <class _Context, same_as<typename _Context::char_type> _Tp>
0049 consteval __arg_t __determine_arg_t() {
0050 return __arg_t::__char_type;
0051 }
0052 # if _LIBCPP_HAS_WIDE_CHARACTERS
0053 template <class _Context, class _CharT>
0054 requires(same_as<typename _Context::char_type, wchar_t> && same_as<_CharT, char>)
0055 consteval __arg_t __determine_arg_t() {
0056 return __arg_t::__char_type;
0057 }
0058 # endif
0059
0060
0061 template <class, __libcpp_signed_integer _Tp>
0062 consteval __arg_t __determine_arg_t() {
0063 if constexpr (sizeof(_Tp) <= sizeof(int))
0064 return __arg_t::__int;
0065 else if constexpr (sizeof(_Tp) <= sizeof(long long))
0066 return __arg_t::__long_long;
0067 # if _LIBCPP_HAS_INT128
0068 else if constexpr (sizeof(_Tp) == sizeof(__int128_t))
0069 return __arg_t::__i128;
0070 # endif
0071 else
0072 static_assert(sizeof(_Tp) == 0, "an unsupported signed integer was used");
0073 }
0074
0075
0076 template <class, __libcpp_unsigned_integer _Tp>
0077 consteval __arg_t __determine_arg_t() {
0078 if constexpr (sizeof(_Tp) <= sizeof(unsigned))
0079 return __arg_t::__unsigned;
0080 else if constexpr (sizeof(_Tp) <= sizeof(unsigned long long))
0081 return __arg_t::__unsigned_long_long;
0082 # if _LIBCPP_HAS_INT128
0083 else if constexpr (sizeof(_Tp) == sizeof(__uint128_t))
0084 return __arg_t::__u128;
0085 # endif
0086 else
0087 static_assert(sizeof(_Tp) == 0, "an unsupported unsigned integer was used");
0088 }
0089
0090
0091 template <class, same_as<float> _Tp>
0092 consteval __arg_t __determine_arg_t() {
0093 return __arg_t::__float;
0094 }
0095 template <class, same_as<double> _Tp>
0096 consteval __arg_t __determine_arg_t() {
0097 return __arg_t::__double;
0098 }
0099 template <class, same_as<long double> _Tp>
0100 consteval __arg_t __determine_arg_t() {
0101 return __arg_t::__long_double;
0102 }
0103
0104
0105 template <class _Context, class _Tp>
0106 requires(same_as<typename _Context::char_type*, _Tp> || same_as<const typename _Context::char_type*, _Tp>)
0107 consteval __arg_t __determine_arg_t() {
0108 return __arg_t::__const_char_type_ptr;
0109 }
0110
0111
0112 template <class _Context, class _Tp>
0113 requires(is_array_v<_Tp> && same_as<_Tp, typename _Context::char_type[extent_v<_Tp>]>)
0114 consteval __arg_t __determine_arg_t() {
0115 return __arg_t::__string_view;
0116 }
0117
0118
0119 template <class _Context, class _Tp>
0120 requires(same_as<typename _Context::char_type, typename _Tp::value_type> &&
0121 same_as<_Tp, basic_string_view<typename _Tp::value_type, typename _Tp::traits_type>>)
0122 consteval __arg_t __determine_arg_t() {
0123 return __arg_t::__string_view;
0124 }
0125
0126
0127 template <class _Context, class _Tp>
0128 requires(
0129 same_as<typename _Context::char_type, typename _Tp::value_type> &&
0130 same_as<_Tp, basic_string<typename _Tp::value_type, typename _Tp::traits_type, typename _Tp::allocator_type>>)
0131 consteval __arg_t __determine_arg_t() {
0132 return __arg_t::__string_view;
0133 }
0134
0135
0136 template <class, class _Ptr>
0137 requires(same_as<_Ptr, void*> || same_as<_Ptr, const void*> || same_as<_Ptr, nullptr_t>)
0138 consteval __arg_t __determine_arg_t() {
0139 return __arg_t::__ptr;
0140 }
0141
0142
0143
0144
0145
0146
0147 template <class _Context, class _Tp>
0148 consteval __arg_t __determine_arg_t() {
0149 return __arg_t::__handle;
0150 }
0151
0152
0153
0154 template <class _Context, class _Tp>
0155 requires(!__formattable_with<_Tp, _Context>)
0156 consteval __arg_t __determine_arg_t() {
0157 return __arg_t::__none;
0158 }
0159
0160
0161
0162
0163
0164 template <class _Context, class _Tp>
0165 _LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> __create_format_arg(_Tp& __value) noexcept {
0166 using _Dp = remove_const_t<_Tp>;
0167 constexpr __arg_t __arg = __determine_arg_t<_Context, _Dp>();
0168 static_assert(__arg != __arg_t::__none, "the supplied type is not formattable");
0169 static_assert(__formattable_with<_Tp, _Context>);
0170
0171
0172
0173
0174 if constexpr (__arg == __arg_t::__char_type)
0175
0176 # if _LIBCPP_HAS_WIDE_CHARACTERS
0177 if constexpr (same_as<typename _Context::char_type, wchar_t> && same_as<_Dp, char>)
0178 return basic_format_arg<_Context>{__arg, static_cast<wchar_t>(static_cast<unsigned char>(__value))};
0179 else
0180 # endif
0181 return basic_format_arg<_Context>{__arg, __value};
0182 else if constexpr (__arg == __arg_t::__int)
0183 return basic_format_arg<_Context>{__arg, static_cast<int>(__value)};
0184 else if constexpr (__arg == __arg_t::__long_long)
0185 return basic_format_arg<_Context>{__arg, static_cast<long long>(__value)};
0186 else if constexpr (__arg == __arg_t::__unsigned)
0187 return basic_format_arg<_Context>{__arg, static_cast<unsigned>(__value)};
0188 else if constexpr (__arg == __arg_t::__unsigned_long_long)
0189 return basic_format_arg<_Context>{__arg, static_cast<unsigned long long>(__value)};
0190 else if constexpr (__arg == __arg_t::__string_view)
0191
0192 if constexpr (is_array_v<_Dp>)
0193 return basic_format_arg<_Context>{
0194 __arg, basic_string_view<typename _Context::char_type>{__value, extent_v<_Dp> - 1}};
0195 else
0196
0197
0198 return basic_format_arg<_Context>{
0199 __arg, basic_string_view<typename _Context::char_type>{__value.data(), __value.size()}};
0200 else if constexpr (__arg == __arg_t::__ptr)
0201 return basic_format_arg<_Context>{__arg, static_cast<const void*>(__value)};
0202 else if constexpr (__arg == __arg_t::__handle)
0203 return basic_format_arg<_Context>{__arg, typename __basic_format_arg_value<_Context>::__handle{__value}};
0204 else
0205 return basic_format_arg<_Context>{__arg, __value};
0206 }
0207
0208 template <class _Context, class... _Args>
0209 _LIBCPP_HIDE_FROM_ABI void
0210 __create_packed_storage(uint64_t& __types, __basic_format_arg_value<_Context>* __values, _Args&... __args) noexcept {
0211 int __shift = 0;
0212 (
0213 [&] {
0214 basic_format_arg<_Context> __arg = __format::__create_format_arg<_Context>(__args);
0215 if (__shift != 0)
0216 __types |= static_cast<uint64_t>(__arg.__type_) << __shift;
0217 else
0218
0219 __types = static_cast<uint64_t>(__arg.__type_);
0220 __shift += __packed_arg_t_bits;
0221 *__values++ = __arg.__value_;
0222 }(),
0223 ...);
0224 }
0225
0226 template <class _Context, class... _Args>
0227 _LIBCPP_HIDE_FROM_ABI void __store_basic_format_arg(basic_format_arg<_Context>* __data, _Args&... __args) noexcept {
0228 ([&] { *__data++ = __format::__create_format_arg<_Context>(__args); }(), ...);
0229 }
0230
0231 template <class _Context, size_t _Np>
0232 struct __packed_format_arg_store {
0233 __basic_format_arg_value<_Context> __values_[_Np];
0234 uint64_t __types_ = 0;
0235 };
0236
0237 template <class _Context>
0238 struct __packed_format_arg_store<_Context, 0> {
0239 uint64_t __types_ = 0;
0240 };
0241
0242 template <class _Context, size_t _Np>
0243 struct __unpacked_format_arg_store {
0244 basic_format_arg<_Context> __args_[_Np];
0245 };
0246
0247 }
0248
0249 template <class _Context, class... _Args>
0250 struct _LIBCPP_TEMPLATE_VIS __format_arg_store {
0251 _LIBCPP_HIDE_FROM_ABI __format_arg_store(_Args&... __args) noexcept {
0252 if constexpr (sizeof...(_Args) != 0) {
0253 if constexpr (__format::__use_packed_format_arg_store(sizeof...(_Args)))
0254 __format::__create_packed_storage(__storage.__types_, __storage.__values_, __args...);
0255 else
0256 __format::__store_basic_format_arg<_Context>(__storage.__args_, __args...);
0257 }
0258 }
0259
0260 using _Storage _LIBCPP_NODEBUG =
0261 conditional_t<__format::__use_packed_format_arg_store(sizeof...(_Args)),
0262 __format::__packed_format_arg_store<_Context, sizeof...(_Args)>,
0263 __format::__unpacked_format_arg_store<_Context, sizeof...(_Args)>>;
0264
0265 _Storage __storage;
0266 };
0267
0268 #endif
0269
0270 _LIBCPP_END_NAMESPACE_STD
0271
0272 #endif