brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.9 KiB · fbb4cad Raw
283 lines · c
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-exception7//8//===----------------------------------------------------------------------===//9 10#ifndef _LIBCPP___FORMAT_FORMAT_ARG_STORE_H11#define _LIBCPP___FORMAT_FORMAT_ARG_STORE_H12 13#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)14#  pragma GCC system_header15#endif16 17#include <__concepts/same_as.h>18#include <__config>19#include <__cstddef/size_t.h>20#include <__format/concepts.h>21#include <__format/format_arg.h>22#include <__type_traits/conditional.h>23#include <__type_traits/extent.h>24#include <__type_traits/integer_traits.h>25#include <__type_traits/remove_const.h>26#include <cstdint>27#include <string>28#include <string_view>29 30_LIBCPP_BEGIN_NAMESPACE_STD31 32#if _LIBCPP_STD_VER >= 2033 34namespace __format {35 36template <class _Arr, class _Elem>37inline constexpr bool __is_bounded_array_of = false;38 39template <class _Elem, size_t _Len>40inline constexpr bool __is_bounded_array_of<_Elem[_Len], _Elem> = true;41 42/// \returns The @c __arg_t based on the type of the formatting argument.43///44/// \pre \c __formattable<_Tp, typename _Context::char_type>45template <class _Context, class _Tp>46consteval __arg_t __determine_arg_t();47 48// Boolean49template <class, same_as<bool> _Tp>50consteval __arg_t __determine_arg_t() {51  return __arg_t::__boolean;52}53 54// Char55template <class _Context, same_as<typename _Context::char_type> _Tp>56consteval __arg_t __determine_arg_t() {57  return __arg_t::__char_type;58}59#  if _LIBCPP_HAS_WIDE_CHARACTERS60template <class _Context, class _CharT>61  requires(same_as<typename _Context::char_type, wchar_t> && same_as<_CharT, char>)62consteval __arg_t __determine_arg_t() {63  return __arg_t::__char_type;64}65#  endif66 67// Signed integers68template <class, __signed_integer _Tp>69consteval __arg_t __determine_arg_t() {70  if constexpr (sizeof(_Tp) <= sizeof(int))71    return __arg_t::__int;72  else if constexpr (sizeof(_Tp) <= sizeof(long long))73    return __arg_t::__long_long;74#  if _LIBCPP_HAS_INT12875  else if constexpr (sizeof(_Tp) == sizeof(__int128_t))76    return __arg_t::__i128;77#  endif78  else79    static_assert(sizeof(_Tp) == 0, "an unsupported signed integer was used");80}81 82// Unsigned integers83template <class, __unsigned_integer _Tp>84consteval __arg_t __determine_arg_t() {85  if constexpr (sizeof(_Tp) <= sizeof(unsigned))86    return __arg_t::__unsigned;87  else if constexpr (sizeof(_Tp) <= sizeof(unsigned long long))88    return __arg_t::__unsigned_long_long;89#  if _LIBCPP_HAS_INT12890  else if constexpr (sizeof(_Tp) == sizeof(__uint128_t))91    return __arg_t::__u128;92#  endif93  else94    static_assert(sizeof(_Tp) == 0, "an unsupported unsigned integer was used");95}96 97// Floating-point98template <class, same_as<float> _Tp>99consteval __arg_t __determine_arg_t() {100  return __arg_t::__float;101}102template <class, same_as<double> _Tp>103consteval __arg_t __determine_arg_t() {104  return __arg_t::__double;105}106template <class, same_as<long double> _Tp>107consteval __arg_t __determine_arg_t() {108  return __arg_t::__long_double;109}110 111// Char pointer112template <class _Context, class _Tp>113  requires(same_as<typename _Context::char_type*, _Tp> || same_as<const typename _Context::char_type*, _Tp>)114consteval __arg_t __determine_arg_t() {115  return __arg_t::__const_char_type_ptr;116}117 118// Char array119template <class _Context, class _Tp>120  requires __is_bounded_array_of<_Tp, typename _Context::char_type>121consteval __arg_t __determine_arg_t() {122  return __arg_t::__string_view;123}124 125// String view126template <class _Context, class _Tp>127  requires(same_as<typename _Context::char_type, typename _Tp::value_type> &&128           same_as<_Tp, basic_string_view<typename _Tp::value_type, typename _Tp::traits_type>>)129consteval __arg_t __determine_arg_t() {130  return __arg_t::__string_view;131}132 133// String134template <class _Context, class _Tp>135  requires(136      same_as<typename _Context::char_type, typename _Tp::value_type> &&137      same_as<_Tp, basic_string<typename _Tp::value_type, typename _Tp::traits_type, typename _Tp::allocator_type>>)138consteval __arg_t __determine_arg_t() {139  return __arg_t::__string_view;140}141 142// Pointers143template <class, class _Ptr>144  requires(same_as<_Ptr, void*> || same_as<_Ptr, const void*> || same_as<_Ptr, nullptr_t>)145consteval __arg_t __determine_arg_t() {146  return __arg_t::__ptr;147}148 149// Handle150//151// Note this version can't be constrained avoiding ambiguous overloads.152// That means it can be instantiated by disabled formatters. To solve this, a153// constrained version for not formattable formatters is added.154template <class _Context, class _Tp>155consteval __arg_t __determine_arg_t() {156  return __arg_t::__handle;157}158 159// The overload for not formattable types allows triggering the static160// assertion below.161template <class _Context, class _Tp>162  requires(!__formattable_with<_Tp, _Context>)163consteval __arg_t __determine_arg_t() {164  return __arg_t::__none;165}166 167// Pseudo constuctor for basic_format_arg168//169// Modeled after template<class T> explicit basic_format_arg(T& v) noexcept;170// [format.arg]/4-6171template <class _Context, class _Tp>172_LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> __create_format_arg(_Tp& __value) noexcept {173  using _Dp               = remove_const_t<_Tp>;174  constexpr __arg_t __arg = __format::__determine_arg_t<_Context, _Dp>();175  static_assert(__arg != __arg_t::__none, "the supplied type is not formattable");176  static_assert(__formattable_with<_Tp, _Context>);177 178  using __context_char_type = _Context::char_type;179  // Not all types can be used to directly initialize the180  // __basic_format_arg_value.  First handle all types needing adjustment, the181  // final else requires no adjustment.182  if constexpr (__arg == __arg_t::__char_type)183 184#  if _LIBCPP_HAS_WIDE_CHARACTERS185    if constexpr (same_as<__context_char_type, wchar_t> && same_as<_Dp, char>)186      return basic_format_arg<_Context>{__arg, static_cast<wchar_t>(static_cast<unsigned char>(__value))};187    else188#  endif189      return basic_format_arg<_Context>{__arg, __value};190  else if constexpr (__arg == __arg_t::__int)191    return basic_format_arg<_Context>{__arg, static_cast<int>(__value)};192  else if constexpr (__arg == __arg_t::__long_long)193    return basic_format_arg<_Context>{__arg, static_cast<long long>(__value)};194  else if constexpr (__arg == __arg_t::__unsigned)195    return basic_format_arg<_Context>{__arg, static_cast<unsigned>(__value)};196  else if constexpr (__arg == __arg_t::__unsigned_long_long)197    return basic_format_arg<_Context>{__arg, static_cast<unsigned long long>(__value)};198  else if constexpr (__arg == __arg_t::__string_view)199    // Using std::size on a character array will add the NUL-terminator to the size.200    if constexpr (__is_bounded_array_of<_Dp, __context_char_type>) {201      const __context_char_type* const __pbegin = std::begin(__value);202      const __context_char_type* const __pzero =203          char_traits<__context_char_type>::find(__pbegin, extent_v<_Dp>, __context_char_type{});204      _LIBCPP_ASSERT_VALID_INPUT_RANGE(__pzero != nullptr, "formatting a non-null-terminated array");205      return basic_format_arg<_Context>{206          __arg, basic_string_view<__context_char_type>{__pbegin, static_cast<size_t>(__pzero - __pbegin)}};207    } else208      // When the _Traits or _Allocator are different an implicit conversion will fail.209      return basic_format_arg<_Context>{__arg, basic_string_view<__context_char_type>{__value.data(), __value.size()}};210  else if constexpr (__arg == __arg_t::__ptr)211    return basic_format_arg<_Context>{__arg, static_cast<const void*>(__value)};212  else if constexpr (__arg == __arg_t::__handle)213    return basic_format_arg<_Context>{__arg, typename __basic_format_arg_value<_Context>::__handle{__value}};214  else215    return basic_format_arg<_Context>{__arg, __value};216}217 218template <class _Context, class... _Args>219_LIBCPP_HIDE_FROM_ABI void220__create_packed_storage(uint64_t& __types, __basic_format_arg_value<_Context>* __values, _Args&... __args) noexcept {221  int __shift = 0;222  (223      [&] {224        basic_format_arg<_Context> __arg = __format::__create_format_arg<_Context>(__args);225        if (__shift != 0)226          __types |= static_cast<uint64_t>(__arg.__type_) << __shift;227        else228          // Assigns the initial value.229          __types = static_cast<uint64_t>(__arg.__type_);230        __shift += __packed_arg_t_bits;231        *__values++ = __arg.__value_;232      }(),233      ...);234}235 236template <class _Context, class... _Args>237_LIBCPP_HIDE_FROM_ABI void __store_basic_format_arg(basic_format_arg<_Context>* __data, _Args&... __args) noexcept {238  ([&] { *__data++ = __format::__create_format_arg<_Context>(__args); }(), ...);239}240 241template <class _Context, size_t _Np>242struct __packed_format_arg_store {243  __basic_format_arg_value<_Context> __values_[_Np];244  uint64_t __types_ = 0;245};246 247template <class _Context>248struct __packed_format_arg_store<_Context, 0> {249  uint64_t __types_ = 0;250};251 252template <class _Context, size_t _Np>253struct __unpacked_format_arg_store {254  basic_format_arg<_Context> __args_[_Np];255};256 257} // namespace __format258 259template <class _Context, class... _Args>260struct __format_arg_store {261  _LIBCPP_HIDE_FROM_ABI __format_arg_store(_Args&... __args) noexcept {262    if constexpr (sizeof...(_Args) != 0) {263      if constexpr (__format::__use_packed_format_arg_store(sizeof...(_Args)))264        __format::__create_packed_storage(__storage.__types_, __storage.__values_, __args...);265      else266        __format::__store_basic_format_arg<_Context>(__storage.__args_, __args...);267    }268  }269 270  using _Storage _LIBCPP_NODEBUG =271      conditional_t<__format::__use_packed_format_arg_store(sizeof...(_Args)),272                    __format::__packed_format_arg_store<_Context, sizeof...(_Args)>,273                    __format::__unpacked_format_arg_store<_Context, sizeof...(_Args)>>;274 275  _Storage __storage;276};277 278#endif // _LIBCPP_STD_VER >= 20279 280_LIBCPP_END_NAMESPACE_STD281 282#endif // _LIBCPP___FORMAT_FORMAT_ARG_STORE_H283