From 8ff1374008259719b54a8cb128ef951c02da164c Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 12 Sep 2018 11:03:25 -0700 Subject: [PATCH] Export of internal Abseil changes. -- 821196cfb2a3b943ffdc4c9e75daec92d7ffb28b by Abseil Team : Performance improvements PiperOrigin-RevId: 212668992 -- 704858e2e767016bad27d53eec01d9d48e546b23 by Abseil Team : Low-level Portability enchancements for Abseil Mutex on WebAssembly. Emscripten Pthreads do not use signals, so remove use of pthread_sigmask or other async-signal-safe related handling code. PiperOrigin-RevId: 212527958 -- be3e38cb4d493b755132d20c8c2d1a51e45d5449 by Jon Cohen : Internal change. PiperOrigin-RevId: 212523797 GitOrigin-RevId: 821196cfb2a3b943ffdc4c9e75daec92d7ffb28b Change-Id: I5694e23e4e09364a15dd6fc4e2e3f15e38835687 --- absl/base/internal/low_level_alloc.cc | 14 +- absl/base/internal/low_level_alloc.h | 7 +- absl/base/internal/thread_identity.cc | 10 + absl/memory/memory_test.cc | 1 - absl/strings/internal/str_format/arg.cc | 80 +++---- absl/strings/internal/str_format/arg.h | 210 +++++++++---------- absl/strings/internal/str_format/bind.h | 2 +- absl/strings/internal/str_format/extension.h | 10 +- absl/strings/str_format_test.cc | 36 ++++ 9 files changed, 199 insertions(+), 171 deletions(-) diff --git a/absl/base/internal/low_level_alloc.cc b/absl/base/internal/low_level_alloc.cc index 0a6f3070534..6e636a02c5d 100644 --- a/absl/base/internal/low_level_alloc.cc +++ b/absl/base/internal/low_level_alloc.cc @@ -401,16 +401,20 @@ bool LowLevelAlloc::DeleteArena(Arena *arena) { ABSL_RAW_CHECK(munmap_result != 0, "LowLevelAlloc::DeleteArena: VitualFree failed"); #else +#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) == 0) { munmap_result = munmap(region, size); } else { munmap_result = base_internal::DirectMunmap(region, size); } +#else + munmap_result = munmap(region, size); +#endif // ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING if (munmap_result != 0) { ABSL_RAW_LOG(FATAL, "LowLevelAlloc::DeleteArena: munmap failed: %d", errno); } -#endif +#endif // _WIN32 } section.Leave(); arena->~Arena(); @@ -545,6 +549,7 @@ static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) { MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); ABSL_RAW_CHECK(new_pages != nullptr, "VirtualAlloc failed"); #else +#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) { new_pages = base_internal::DirectMmap(nullptr, new_pages_size, PROT_WRITE|PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); @@ -552,10 +557,15 @@ static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) { new_pages = mmap(nullptr, new_pages_size, PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); } +#else + new_pages = mmap(nullptr, new_pages_size, PROT_WRITE | PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); +#endif // ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING if (new_pages == MAP_FAILED) { ABSL_RAW_LOG(FATAL, "mmap error: %d", errno); } -#endif + +#endif // _WIN32 arena->mu.Lock(); s = reinterpret_cast(new_pages); s->header.size = new_pages_size; diff --git a/absl/base/internal/low_level_alloc.h b/absl/base/internal/low_level_alloc.h index 3c15605bed3..fba9466a757 100644 --- a/absl/base/internal/low_level_alloc.h +++ b/absl/base/internal/low_level_alloc.h @@ -39,10 +39,13 @@ #define ABSL_LOW_LEVEL_ALLOC_MISSING 1 #endif -// Using LowLevelAlloc with kAsyncSignalSafe isn't supported on Windows. +// Using LowLevelAlloc with kAsyncSignalSafe isn't supported on Windows or +// asm.js / WebAssembly. +// See https://kripken.github.io/emscripten-site/docs/porting/pthreads.html +// for more information. #ifdef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING #error ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING cannot be directly set -#elif defined(_WIN32) +#elif defined(_WIN32) || defined(__asmjs__) || defined(__wasm__) #define ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING 1 #endif diff --git a/absl/base/internal/thread_identity.cc b/absl/base/internal/thread_identity.cc index 678e8568d74..cff9c1b4f4d 100644 --- a/absl/base/internal/thread_identity.cc +++ b/absl/base/internal/thread_identity.cc @@ -68,6 +68,14 @@ void SetCurrentThreadIdentity( // NOTE: Not async-safe. But can be open-coded. absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey, reclaimer); + +#ifdef __EMSCRIPTEN__ + // Emscripten PThread implementation does not support signals. + // See https://kripken.github.io/emscripten-site/docs/porting/pthreads.html + // for more information. + pthread_setspecific(thread_identity_pthread_key, + reinterpret_cast(identity)); +#else // We must mask signals around the call to setspecific as with current glibc, // a concurrent getspecific (needed for GetCurrentThreadIdentityIfPresent()) // may zero our value. @@ -81,6 +89,8 @@ void SetCurrentThreadIdentity( pthread_setspecific(thread_identity_pthread_key, reinterpret_cast(identity)); pthread_sigmask(SIG_SETMASK, &curr_signals, nullptr); +#endif // !__EMSCRIPTEN__ + #elif ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS // NOTE: Not async-safe. But can be open-coded. absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey, diff --git a/absl/memory/memory_test.cc b/absl/memory/memory_test.cc index dee9b486a30..2e453e22ba5 100644 --- a/absl/memory/memory_test.cc +++ b/absl/memory/memory_test.cc @@ -149,7 +149,6 @@ TEST(Make_UniqueTest, NotAmbiguousWithStdMakeUnique) { } #if 0 -// TODO(billydonahue): Make a proper NC test. // These tests shouldn't compile. TEST(MakeUniqueTestNC, AcceptMoveOnlyLvalue) { auto m = MoveOnly(); diff --git a/absl/strings/internal/str_format/arg.cc b/absl/strings/internal/str_format/arg.cc index eafb068fe28..b40be8ff382 100644 --- a/absl/strings/internal/str_format/arg.cc +++ b/absl/strings/internal/str_format/arg.cc @@ -112,7 +112,7 @@ class ConvertedIntInfo { // Note: 'o' conversions do not have a base indicator, it's just that // the '#' flag is specified to modify the precision for 'o' conversions. string_view BaseIndicator(const ConvertedIntInfo &info, - const ConversionSpec &conv) { + const ConversionSpec conv) { bool alt = conv.flags().alt; int radix = conv.conv().radix(); if (conv.conv().id() == ConversionChar::p) @@ -127,7 +127,7 @@ string_view BaseIndicator(const ConvertedIntInfo &info, return {}; } -string_view SignColumn(bool neg, const ConversionSpec &conv) { +string_view SignColumn(bool neg, const ConversionSpec conv) { if (conv.conv().is_signed()) { if (neg) return "-"; if (conv.flags().show_pos) return "+"; @@ -136,7 +136,7 @@ string_view SignColumn(bool neg, const ConversionSpec &conv) { return {}; } -bool ConvertCharImpl(unsigned char v, const ConversionSpec &conv, +bool ConvertCharImpl(unsigned char v, const ConversionSpec conv, FormatSinkImpl *sink) { size_t fill = 0; if (conv.width() >= 0) fill = conv.width(); @@ -148,7 +148,7 @@ bool ConvertCharImpl(unsigned char v, const ConversionSpec &conv, } bool ConvertIntImplInner(const ConvertedIntInfo &info, - const ConversionSpec &conv, FormatSinkImpl *sink) { + const ConversionSpec conv, FormatSinkImpl *sink) { // Print as a sequence of Substrings: // [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces] size_t fill = 0; @@ -202,8 +202,7 @@ bool ConvertIntImplInner(const ConvertedIntInfo &info, } template -bool ConvertIntImplInner(T v, const ConversionSpec &conv, - FormatSinkImpl *sink) { +bool ConvertIntImplInner(T v, const ConversionSpec conv, FormatSinkImpl *sink) { ConvertedIntInfo info(v, conv.conv()); if (conv.flags().basic && conv.conv().id() != ConversionChar::p) { if (info.is_neg()) sink->Append(1, '-'); @@ -218,7 +217,7 @@ bool ConvertIntImplInner(T v, const ConversionSpec &conv, } template -bool ConvertIntArg(T v, const ConversionSpec &conv, FormatSinkImpl *sink) { +bool ConvertIntArg(T v, const ConversionSpec conv, FormatSinkImpl *sink) { if (conv.conv().is_float()) { return FormatConvertImpl(static_cast(v), conv, sink).value; } @@ -234,11 +233,11 @@ bool ConvertIntArg(T v, const ConversionSpec &conv, FormatSinkImpl *sink) { } template -bool ConvertFloatArg(T v, const ConversionSpec &conv, FormatSinkImpl *sink) { +bool ConvertFloatArg(T v, const ConversionSpec conv, FormatSinkImpl *sink) { return conv.conv().is_float() && ConvertFloatImpl(v, conv, sink); } -inline bool ConvertStringArg(string_view v, const ConversionSpec &conv, +inline bool ConvertStringArg(string_view v, const ConversionSpec conv, FormatSinkImpl *sink) { if (conv.conv().id() != ConversionChar::s) return false; @@ -254,19 +253,19 @@ inline bool ConvertStringArg(string_view v, const ConversionSpec &conv, // ==================== Strings ==================== ConvertResult FormatConvertImpl(const std::string &v, - const ConversionSpec &conv, + const ConversionSpec conv, FormatSinkImpl *sink) { return {ConvertStringArg(v, conv, sink)}; } ConvertResult FormatConvertImpl(string_view v, - const ConversionSpec &conv, + const ConversionSpec conv, FormatSinkImpl *sink) { return {ConvertStringArg(v, conv, sink)}; } ConvertResult FormatConvertImpl(const char *v, - const ConversionSpec &conv, + const ConversionSpec conv, FormatSinkImpl *sink) { if (conv.conv().id() == ConversionChar::p) return {FormatConvertImpl(VoidPtr(v), conv, sink).value}; @@ -283,7 +282,7 @@ ConvertResult FormatConvertImpl(const char *v, } // ==================== Raw pointers ==================== -ConvertResult FormatConvertImpl(VoidPtr v, const ConversionSpec &conv, +ConvertResult FormatConvertImpl(VoidPtr v, const ConversionSpec conv, FormatSinkImpl *sink) { if (conv.conv().id() != ConversionChar::p) return {false}; @@ -295,104 +294,83 @@ ConvertResult FormatConvertImpl(VoidPtr v, const ConversionSpec &conv, } // ==================== Floats ==================== -FloatingConvertResult FormatConvertImpl(float v, const ConversionSpec &conv, +FloatingConvertResult FormatConvertImpl(float v, const ConversionSpec conv, FormatSinkImpl *sink) { return {ConvertFloatArg(v, conv, sink)}; } -FloatingConvertResult FormatConvertImpl(double v, const ConversionSpec &conv, +FloatingConvertResult FormatConvertImpl(double v, const ConversionSpec conv, FormatSinkImpl *sink) { return {ConvertFloatArg(v, conv, sink)}; } FloatingConvertResult FormatConvertImpl(long double v, - const ConversionSpec &conv, + const ConversionSpec conv, FormatSinkImpl *sink) { return {ConvertFloatArg(v, conv, sink)}; } // ==================== Chars ==================== -IntegralConvertResult FormatConvertImpl(char v, const ConversionSpec &conv, +IntegralConvertResult FormatConvertImpl(char v, const ConversionSpec conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } IntegralConvertResult FormatConvertImpl(signed char v, - const ConversionSpec &conv, + const ConversionSpec conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } IntegralConvertResult FormatConvertImpl(unsigned char v, - const ConversionSpec &conv, + const ConversionSpec conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } // ==================== Ints ==================== IntegralConvertResult FormatConvertImpl(short v, // NOLINT - const ConversionSpec &conv, + const ConversionSpec conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT - const ConversionSpec &conv, + const ConversionSpec conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } -IntegralConvertResult FormatConvertImpl(int v, const ConversionSpec &conv, +IntegralConvertResult FormatConvertImpl(int v, const ConversionSpec conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } -IntegralConvertResult FormatConvertImpl(unsigned v, const ConversionSpec &conv, +IntegralConvertResult FormatConvertImpl(unsigned v, const ConversionSpec conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } IntegralConvertResult FormatConvertImpl(long v, // NOLINT - const ConversionSpec &conv, + const ConversionSpec conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT - const ConversionSpec &conv, + const ConversionSpec conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } IntegralConvertResult FormatConvertImpl(long long v, // NOLINT - const ConversionSpec &conv, + const ConversionSpec conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT - const ConversionSpec &conv, + const ConversionSpec conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } IntegralConvertResult FormatConvertImpl(absl::uint128 v, - const ConversionSpec &conv, + const ConversionSpec conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } -template struct FormatArgImpl::TypedVTable; - -template struct FormatArgImpl::TypedVTable; -template struct FormatArgImpl::TypedVTable; -template struct FormatArgImpl::TypedVTable; -template struct FormatArgImpl::TypedVTable; -template struct FormatArgImpl::TypedVTable; // NOLINT -template struct FormatArgImpl::TypedVTable; // NOLINT -template struct FormatArgImpl::TypedVTable; -template struct FormatArgImpl::TypedVTable; -template struct FormatArgImpl::TypedVTable; // NOLINT -template struct FormatArgImpl::TypedVTable; // NOLINT -template struct FormatArgImpl::TypedVTable; // NOLINT -template struct FormatArgImpl::TypedVTable; // NOLINT -template struct FormatArgImpl::TypedVTable; - -template struct FormatArgImpl::TypedVTable; -template struct FormatArgImpl::TypedVTable; -template struct FormatArgImpl::TypedVTable; - -template struct FormatArgImpl::TypedVTable; -template struct FormatArgImpl::TypedVTable; -template struct FormatArgImpl::TypedVTable; +ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(); + } // namespace str_format_internal diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h index a9562188ea9..3376d48afda 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 struct HasUserDefinedConvert< T, void_t(), std::declval(), + std::declval(), std::declval(), std::declval()))>> : std::true_type {}; template class StreamedWrapper; @@ -50,25 +50,23 @@ struct VoidPtr { : value(ptr ? reinterpret_cast(ptr) : 0) {} uintptr_t value; }; -ConvertResult FormatConvertImpl(VoidPtr v, const ConversionSpec& conv, +ConvertResult FormatConvertImpl(VoidPtr v, ConversionSpec conv, FormatSinkImpl* sink); // Strings. -ConvertResult FormatConvertImpl(const std::string& v, - const ConversionSpec& conv, +ConvertResult FormatConvertImpl(const std::string& v, ConversionSpec conv, FormatSinkImpl* sink); -ConvertResult FormatConvertImpl(string_view v, - const ConversionSpec& conv, +ConvertResult FormatConvertImpl(string_view v, ConversionSpec conv, FormatSinkImpl* sink); ConvertResult FormatConvertImpl(const char* v, - const ConversionSpec& conv, + ConversionSpec conv, FormatSinkImpl* sink); template ::value>::type* = nullptr, class AbslCordReader = ::CordReader> ConvertResult 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; // 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 ::value, int> = 0> -IntegralConvertResult FormatConvertImpl(T v, const ConversionSpec& conv, +IntegralConvertResult FormatConvertImpl(T v, ConversionSpec conv, FormatSinkImpl* sink) { return FormatConvertImpl(static_cast(v), conv, sink); } @@ -159,11 +154,11 @@ template typename std::enable_if::value && !HasUserDefinedConvert::value, IntegralConvertResult>::type -FormatConvertImpl(T v, const ConversionSpec& conv, FormatSinkImpl* sink); +FormatConvertImpl(T v, ConversionSpec conv, FormatSinkImpl* sink); template ConvertResult FormatConvertImpl(const StreamedWrapper& v, - const ConversionSpec& conv, + ConversionSpec conv, FormatSinkImpl* out) { std::ostringstream oss; oss << v.v_; @@ -176,7 +171,7 @@ ConvertResult FormatConvertImpl(const StreamedWrapper& v, struct FormatCountCaptureHelper { template static ConvertResult ConvertHelper(const FormatCountCapture& v, - const ConversionSpec& conv, + ConversionSpec conv, FormatSinkImpl* sink) { const absl::enable_if_t& v2 = v; @@ -189,7 +184,7 @@ struct FormatCountCaptureHelper { template ConvertResult FormatConvertImpl(const FormatCountCapture& v, - const ConversionSpec& conv, + ConversionSpec conv, FormatSinkImpl* sink) { return FormatCountCaptureHelper::ConvertHelper(v, conv, sink); } @@ -199,20 +194,20 @@ ConvertResult FormatConvertImpl(const FormatCountCapture& v, struct FormatArgImplFriend { template 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 - 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 - 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 struct store_by_value @@ -253,10 +244,6 @@ class FormatArgImpl { : ByPointer))> { }; - // An instance of an FormatArgImpl::VTable suitable for 'T'. - template - 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 - void Init(const T& value); + void Init(const T& value) { + data_ = Manager::SetValue(value); + dispatcher_ = &Dispatch; + } template static int ToIntVal(const T& val) { @@ -355,79 +345,75 @@ class FormatArgImpl { return static_cast(val); } - Data data_; - const VTable* vtbl_; -}; - -template -struct FormatArgImpl::TypedVTable { - private: - static bool ConvertImpl(Data arg, - const str_format_internal::ConversionSpec& conv, - FormatSinkImpl* out) { - return str_format_internal::FormatConvertImpl(Manager::Value(arg), conv, - out) - .value; + template + static bool ToInt(Data arg, int* out, std::true_type /* is_integral */, + std::false_type) { + *out = ToIntVal(Manager::Value(arg)); + return true; } - template - struct ToIntImpl { - static constexpr int (*value)(Data) = nullptr; - }; + template + static bool ToInt(Data arg, int* out, std::false_type, + std::true_type /* is_enum */) { + *out = ToIntVal(static_cast::type>( + Manager::Value(arg))); + return true; + } - template - struct ToIntImpl::value>::type> { - static int Invoke(Data arg) { return ToIntVal(Manager::Value(arg)); } - static constexpr int (*value)(Data) = &Invoke; - }; + template + static bool ToInt(Data, int*, std::false_type, std::false_type) { + return false; + } - template - struct ToIntImpl::value>::type> { - static int Invoke(Data arg) { - return ToIntVal(static_cast::type>( - Manager::Value(arg))); + template + 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(arg, static_cast(out), std::is_integral(), + std::is_enum()); } - static constexpr int (*value)(Data) = &Invoke; - }; - public: - static constexpr VTable value{&ConvertImpl, ToIntImpl<>::value}; -}; + return str_format_internal::FormatConvertImpl( + Manager::Value(arg), spec, static_cast(out)) + .value; + } -template -constexpr FormatArgImpl::VTable FormatArgImpl::TypedVTable::value; + Data data_; + Dispatcher dispatcher_; +}; -template -void FormatArgImpl::Init(const T& value) { - data_ = Manager::SetValue(value); - vtbl_ = &TypedVTable::value; -} +#define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E) \ + E template bool FormatArgImpl::Dispatch(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; - -extern template struct FormatArgImpl::TypedVTable; -extern template struct FormatArgImpl::TypedVTable; -extern template struct FormatArgImpl::TypedVTable; -extern template struct FormatArgImpl::TypedVTable; -extern template struct FormatArgImpl::TypedVTable; // NOLINT -extern template struct FormatArgImpl::TypedVTable; // NOLINT -extern template struct FormatArgImpl::TypedVTable; -extern template struct FormatArgImpl::TypedVTable; -extern template struct FormatArgImpl::TypedVTable; // NOLINT -extern template struct FormatArgImpl::TypedVTable; // NOLINT -extern template struct FormatArgImpl::TypedVTable; // NOLINT -extern template struct FormatArgImpl::TypedVTable< - unsigned long long>; // NOLINT -extern template struct FormatArgImpl::TypedVTable; - -extern template struct FormatArgImpl::TypedVTable; -extern template struct FormatArgImpl::TypedVTable; -extern template struct FormatArgImpl::TypedVTable; - -extern template struct FormatArgImpl::TypedVTable; -extern template struct FormatArgImpl::TypedVTable; -extern template struct FormatArgImpl::TypedVTable; } // namespace str_format_internal } // namespace absl diff --git a/absl/strings/internal/str_format/bind.h b/absl/strings/internal/str_format/bind.h index a503b19bb67..1b52df9c7f5 100644 --- a/absl/strings/internal/str_format/bind.h +++ b/absl/strings/internal/str_format/bind.h @@ -186,7 +186,7 @@ class StreamedWrapper { private: template friend ConvertResult FormatConvertImpl(const StreamedWrapper& v, - const ConversionSpec& conv, + ConversionSpec conv, FormatSinkImpl* out); const T& v_; }; diff --git a/absl/strings/internal/str_format/extension.h b/absl/strings/internal/str_format/extension.h index f43195c127b..11b996aefd3 100644 --- a/absl/strings/internal/str_format/extension.h +++ b/absl/strings/internal/str_format/extension.h @@ -18,6 +18,7 @@ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_ #include +#include #include #include @@ -307,7 +308,12 @@ class ConversionSpec { public: Flags flags() const { return flags_; } LengthMod length_mod() const { return length_mod_; } - ConversionChar conv() const { return conv_; } + ConversionChar conv() const { + // Keep this field first in the struct . It generates better code when + // accessing it when ConversionSpec is passed by value in registers. + static_assert(offsetof(ConversionSpec, conv_) == 0, ""); + return conv_; + } // Returns the specified width. If width is unspecfied, it returns a negative // value. @@ -324,9 +330,9 @@ class ConversionSpec { void set_left(bool b) { flags_.left = b; } private: + ConversionChar conv_; Flags flags_; LengthMod length_mod_; - ConversionChar conv_; int width_; int precision_; }; diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc index 9a6576dc825..aa14e211709 100644 --- a/absl/strings/str_format_test.cc +++ b/absl/strings/str_format_test.cc @@ -601,3 +601,39 @@ TEST_F(ParsedFormatTest, RegressionMixPositional) { } // namespace } // namespace absl + +// Some codegen thunks that we can use to easily dump the generated assembly for +// different StrFormat calls. + +inline std::string CodegenAbslStrFormatInt(int i) { + return absl::StrFormat("%d", i); +} + +inline std::string CodegenAbslStrFormatIntStringInt64(int i, const std::string& s, + int64_t i64) { + return absl::StrFormat("%d %s %d", i, s, i64); +} + +inline void CodegenAbslStrAppendFormatInt(std::string* out, int i) { + absl::StrAppendFormat(out, "%d", i); +} + +inline void CodegenAbslStrAppendFormatIntStringInt64(std::string* out, int i, + const std::string& s, + int64_t i64) { + absl::StrAppendFormat(out, "%d %s %d", i, s, i64); +} + +auto absl_internal_str_format_force_codegen_funcs = std::make_tuple( + CodegenAbslStrFormatInt, CodegenAbslStrFormatIntStringInt64, + CodegenAbslStrAppendFormatInt, CodegenAbslStrAppendFormatIntStringInt64); + +bool absl_internal_str_format_force_codegen_always_false; +// Force the compiler to generate the functions by making it look like we +// escape the function pointers. +// It can't statically know that +// absl_internal_str_format_force_codegen_always_false is not changed by someone +// else. +bool absl_internal_str_format_force_codegen = + absl_internal_str_format_force_codegen_always_false && + printf("%p", &absl_internal_str_format_force_codegen_funcs) == 0;