diff options
Diffstat (limited to 'absl/strings/internal/str_format/arg.h')
-rw-r--r-- | absl/strings/internal/str_format/arg.h | 210 |
1 files changed, 98 insertions, 112 deletions
diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h index a9562188ea91..3376d48afda2 100644 --- a/absl/strings/internal/str_format/arg.h +++ b/absl/strings/internal/str_format/arg.h @@ -33,7 +33,7 @@ struct HasUserDefinedConvert : std::false_type {}; template <typename T> struct HasUserDefinedConvert< T, void_t<decltype(AbslFormatConvert( - std::declval<const T&>(), std::declval<const ConversionSpec&>(), + std::declval<const T&>(), std::declval<ConversionSpec>(), std::declval<FormatSink*>()))>> : std::true_type {}; template <typename T> class StreamedWrapper; @@ -50,25 +50,23 @@ struct VoidPtr { : value(ptr ? reinterpret_cast<uintptr_t>(ptr) : 0) {} uintptr_t value; }; -ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, const ConversionSpec& conv, +ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, ConversionSpec conv, FormatSinkImpl* sink); // Strings. -ConvertResult<Conv::s> FormatConvertImpl(const std::string& v, - const ConversionSpec& conv, +ConvertResult<Conv::s> FormatConvertImpl(const std::string& v, ConversionSpec conv, FormatSinkImpl* sink); -ConvertResult<Conv::s> FormatConvertImpl(string_view v, - const ConversionSpec& conv, +ConvertResult<Conv::s> FormatConvertImpl(string_view v, ConversionSpec conv, FormatSinkImpl* sink); ConvertResult<Conv::s | Conv::p> FormatConvertImpl(const char* v, - const ConversionSpec& conv, + ConversionSpec conv, FormatSinkImpl* sink); template <class AbslCord, typename std::enable_if< std::is_same<AbslCord, ::Cord>::value>::type* = nullptr, class AbslCordReader = ::CordReader> ConvertResult<Conv::s> FormatConvertImpl(const AbslCord& value, - const ConversionSpec& conv, + ConversionSpec conv, FormatSinkImpl* sink) { if (conv.conv().id() != ConversionChar::s) return {false}; @@ -104,51 +102,48 @@ using IntegralConvertResult = using FloatingConvertResult = ConvertResult<Conv::floating>; // Floats. -FloatingConvertResult FormatConvertImpl(float v, const ConversionSpec& conv, +FloatingConvertResult FormatConvertImpl(float v, ConversionSpec conv, FormatSinkImpl* sink); -FloatingConvertResult FormatConvertImpl(double v, const ConversionSpec& conv, +FloatingConvertResult FormatConvertImpl(double v, ConversionSpec conv, FormatSinkImpl* sink); -FloatingConvertResult FormatConvertImpl(long double v, - const ConversionSpec& conv, +FloatingConvertResult FormatConvertImpl(long double v, ConversionSpec conv, FormatSinkImpl* sink); // Chars. -IntegralConvertResult FormatConvertImpl(char v, const ConversionSpec& conv, +IntegralConvertResult FormatConvertImpl(char v, ConversionSpec conv, FormatSinkImpl* sink); -IntegralConvertResult FormatConvertImpl(signed char v, - const ConversionSpec& conv, +IntegralConvertResult FormatConvertImpl(signed char v, ConversionSpec conv, FormatSinkImpl* sink); -IntegralConvertResult FormatConvertImpl(unsigned char v, - const ConversionSpec& conv, +IntegralConvertResult FormatConvertImpl(unsigned char v, ConversionSpec conv, FormatSinkImpl* sink); // Ints. IntegralConvertResult FormatConvertImpl(short v, // NOLINT - const ConversionSpec& conv, + ConversionSpec conv, FormatSinkImpl* sink); IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT - const ConversionSpec& conv, + ConversionSpec conv, FormatSinkImpl* sink); -IntegralConvertResult FormatConvertImpl(int v, const ConversionSpec& conv, +IntegralConvertResult FormatConvertImpl(int v, ConversionSpec conv, FormatSinkImpl* sink); -IntegralConvertResult FormatConvertImpl(unsigned v, const ConversionSpec& conv, +IntegralConvertResult FormatConvertImpl(unsigned v, ConversionSpec conv, FormatSinkImpl* sink); IntegralConvertResult FormatConvertImpl(long v, // NOLINT - const ConversionSpec& conv, + ConversionSpec conv, FormatSinkImpl* sink); IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT - const ConversionSpec& conv, + ConversionSpec conv, FormatSinkImpl* sink); IntegralConvertResult FormatConvertImpl(long long v, // NOLINT - const ConversionSpec& conv, + ConversionSpec conv, FormatSinkImpl* sink); IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT - const ConversionSpec& conv, + ConversionSpec conv, FormatSinkImpl* sink); -IntegralConvertResult FormatConvertImpl(uint128 v, const ConversionSpec& conv, +IntegralConvertResult FormatConvertImpl(uint128 v, ConversionSpec conv, FormatSinkImpl* sink); template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0> -IntegralConvertResult FormatConvertImpl(T v, const ConversionSpec& conv, +IntegralConvertResult FormatConvertImpl(T v, ConversionSpec conv, FormatSinkImpl* sink) { return FormatConvertImpl(static_cast<int>(v), conv, sink); } @@ -159,11 +154,11 @@ template <typename T> typename std::enable_if<std::is_enum<T>::value && !HasUserDefinedConvert<T>::value, IntegralConvertResult>::type -FormatConvertImpl(T v, const ConversionSpec& conv, FormatSinkImpl* sink); +FormatConvertImpl(T v, ConversionSpec conv, FormatSinkImpl* sink); template <typename T> ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<T>& v, - const ConversionSpec& conv, + ConversionSpec conv, FormatSinkImpl* out) { std::ostringstream oss; oss << v.v_; @@ -176,7 +171,7 @@ ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<T>& v, struct FormatCountCaptureHelper { template <class T = int> static ConvertResult<Conv::n> ConvertHelper(const FormatCountCapture& v, - const ConversionSpec& conv, + ConversionSpec conv, FormatSinkImpl* sink) { const absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v; @@ -189,7 +184,7 @@ struct FormatCountCaptureHelper { template <class T = int> ConvertResult<Conv::n> FormatConvertImpl(const FormatCountCapture& v, - const ConversionSpec& conv, + ConversionSpec conv, FormatSinkImpl* sink) { return FormatCountCaptureHelper::ConvertHelper(v, conv, sink); } @@ -199,20 +194,20 @@ ConvertResult<Conv::n> FormatConvertImpl(const FormatCountCapture& v, struct FormatArgImplFriend { template <typename Arg> static bool ToInt(Arg arg, int* out) { - if (!arg.vtbl_->to_int) return false; - *out = arg.vtbl_->to_int(arg.data_); - return true; + // A value initialized ConversionSpec has a `none` conv, which tells the + // dispatcher to run the `int` conversion. + return arg.dispatcher_(arg.data_, {}, out); } template <typename Arg> - static bool Convert(Arg arg, const str_format_internal::ConversionSpec& conv, + static bool Convert(Arg arg, str_format_internal::ConversionSpec conv, FormatSinkImpl* out) { - return arg.vtbl_->convert(arg.data_, conv, out); + return arg.dispatcher_(arg.data_, conv, out); } template <typename Arg> - static const void* GetVTablePtrForTest(Arg arg) { - return arg.vtbl_; + static typename Arg::Dispatcher GetVTablePtrForTest(Arg arg) { + return arg.dispatcher_; } }; @@ -229,11 +224,7 @@ class FormatArgImpl { char buf[kInlinedSpace]; }; - struct VTable { - bool (*convert)(Data, const str_format_internal::ConversionSpec& conv, - FormatSinkImpl* out); - int (*to_int)(Data); - }; + using Dispatcher = bool (*)(Data, ConversionSpec, void* out); template <typename T> struct store_by_value @@ -253,10 +244,6 @@ class FormatArgImpl { : ByPointer))> { }; - // An instance of an FormatArgImpl::VTable suitable for 'T'. - template <typename T> - struct TypedVTable; - // To reduce the number of vtables we will decay values before hand. // Anything with a user-defined Convert will get its own vtable. // For everything else: @@ -338,7 +325,10 @@ class FormatArgImpl { }; template <typename T> - void Init(const T& value); + void Init(const T& value) { + data_ = Manager<T>::SetValue(value); + dispatcher_ = &Dispatch<T>; + } template <typename T> static int ToIntVal(const T& val) { @@ -355,79 +345,75 @@ class FormatArgImpl { return static_cast<int>(val); } - Data data_; - const VTable* vtbl_; -}; - -template <typename T> -struct FormatArgImpl::TypedVTable { - private: - static bool ConvertImpl(Data arg, - const str_format_internal::ConversionSpec& conv, - FormatSinkImpl* out) { - return str_format_internal::FormatConvertImpl(Manager<T>::Value(arg), conv, - out) - .value; + template <typename T> + static bool ToInt(Data arg, int* out, std::true_type /* is_integral */, + std::false_type) { + *out = ToIntVal(Manager<T>::Value(arg)); + return true; } - template <typename U = T, typename = void> - struct ToIntImpl { - static constexpr int (*value)(Data) = nullptr; - }; + template <typename T> + static bool ToInt(Data arg, int* out, std::false_type, + std::true_type /* is_enum */) { + *out = ToIntVal(static_cast<typename std::underlying_type<T>::type>( + Manager<T>::Value(arg))); + return true; + } - template <typename U> - struct ToIntImpl<U, - typename std::enable_if<std::is_integral<U>::value>::type> { - static int Invoke(Data arg) { return ToIntVal(Manager<T>::Value(arg)); } - static constexpr int (*value)(Data) = &Invoke; - }; + template <typename T> + static bool ToInt(Data, int*, std::false_type, std::false_type) { + return false; + } - template <typename U> - struct ToIntImpl<U, typename std::enable_if<std::is_enum<U>::value>::type> { - static int Invoke(Data arg) { - return ToIntVal(static_cast<typename std::underlying_type<T>::type>( - Manager<T>::Value(arg))); + template <typename T> + static bool Dispatch(Data arg, ConversionSpec spec, void* out) { + // A `none` conv indicates that we want the `int` conversion. + if (ABSL_PREDICT_FALSE(spec.conv().id() == ConversionChar::none)) { + return ToInt<T>(arg, static_cast<int*>(out), std::is_integral<T>(), + std::is_enum<T>()); } - static constexpr int (*value)(Data) = &Invoke; - }; - public: - static constexpr VTable value{&ConvertImpl, ToIntImpl<>::value}; -}; + return str_format_internal::FormatConvertImpl( + Manager<T>::Value(arg), spec, static_cast<FormatSinkImpl*>(out)) + .value; + } -template <typename T> -constexpr FormatArgImpl::VTable FormatArgImpl::TypedVTable<T>::value; + Data data_; + Dispatcher dispatcher_; +}; -template <typename T> -void FormatArgImpl::Init(const T& value) { - data_ = Manager<T>::SetValue(value); - vtbl_ = &TypedVTable<T>::value; -} +#define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E) \ + E template bool FormatArgImpl::Dispatch<T>(Data, ConversionSpec, void*) + +#define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...) \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(str_format_internal::VoidPtr, \ + __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(bool, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(char, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(signed char, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned char, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(short, __VA_ARGS__); /* NOLINT */ \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned short, /* NOLINT */ \ + __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(int, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned int, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long, __VA_ARGS__); /* NOLINT */ \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long, /* NOLINT */ \ + __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long long, /* NOLINT */ \ + __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long long, /* NOLINT */ \ + __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(uint128, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(float, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(double, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long double, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(const char*, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::string, __VA_ARGS__); \ + ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(string_view, __VA_ARGS__) + +ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(extern); -extern template struct FormatArgImpl::TypedVTable<str_format_internal::VoidPtr>; - -extern template struct FormatArgImpl::TypedVTable<bool>; -extern template struct FormatArgImpl::TypedVTable<char>; -extern template struct FormatArgImpl::TypedVTable<signed char>; -extern template struct FormatArgImpl::TypedVTable<unsigned char>; -extern template struct FormatArgImpl::TypedVTable<short>; // NOLINT -extern template struct FormatArgImpl::TypedVTable<unsigned short>; // NOLINT -extern template struct FormatArgImpl::TypedVTable<int>; -extern template struct FormatArgImpl::TypedVTable<unsigned>; -extern template struct FormatArgImpl::TypedVTable<long>; // NOLINT -extern template struct FormatArgImpl::TypedVTable<unsigned long>; // NOLINT -extern template struct FormatArgImpl::TypedVTable<long long>; // NOLINT -extern template struct FormatArgImpl::TypedVTable< - unsigned long long>; // NOLINT -extern template struct FormatArgImpl::TypedVTable<uint128>; - -extern template struct FormatArgImpl::TypedVTable<float>; -extern template struct FormatArgImpl::TypedVTable<double>; -extern template struct FormatArgImpl::TypedVTable<long double>; - -extern template struct FormatArgImpl::TypedVTable<const char*>; -extern template struct FormatArgImpl::TypedVTable<std::string>; -extern template struct FormatArgImpl::TypedVTable<string_view>; } // namespace str_format_internal } // namespace absl |