summaryrefslogtreecommitdiff
path: root/absl/strings/internal
diff options
context:
space:
mode:
Diffstat (limited to 'absl/strings/internal')
-rw-r--r--absl/strings/internal/str_format/arg.cc80
-rw-r--r--absl/strings/internal/str_format/arg.h210
-rw-r--r--absl/strings/internal/str_format/bind.h2
-rw-r--r--absl/strings/internal/str_format/extension.h10
4 files changed, 136 insertions, 166 deletions
diff --git a/absl/strings/internal/str_format/arg.cc b/absl/strings/internal/str_format/arg.cc
index eafb068f..b40be8ff 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 <typename T>
-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 <typename T>
-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<double>(v), conv, sink).value;
}
@@ -234,11 +233,11 @@ bool ConvertIntArg(T v, const ConversionSpec &conv, FormatSinkImpl *sink) {
}
template <typename T>
-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<Conv::s> FormatConvertImpl(const std::string &v,
- const ConversionSpec &conv,
+ const ConversionSpec conv,
FormatSinkImpl *sink) {
return {ConvertStringArg(v, conv, sink)};
}
ConvertResult<Conv::s> FormatConvertImpl(string_view v,
- const ConversionSpec &conv,
+ const ConversionSpec conv,
FormatSinkImpl *sink) {
return {ConvertStringArg(v, conv, sink)};
}
ConvertResult<Conv::s | Conv::p> 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<Conv::s | Conv::p> FormatConvertImpl(const char *v,
}
// ==================== Raw pointers ====================
-ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, const ConversionSpec &conv,
+ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, const ConversionSpec conv,
FormatSinkImpl *sink) {
if (conv.conv().id() != ConversionChar::p)
return {false};
@@ -295,104 +294,83 @@ ConvertResult<Conv::p> 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<str_format_internal::VoidPtr>;
-
-template struct FormatArgImpl::TypedVTable<bool>;
-template struct FormatArgImpl::TypedVTable<char>;
-template struct FormatArgImpl::TypedVTable<signed char>;
-template struct FormatArgImpl::TypedVTable<unsigned char>;
-template struct FormatArgImpl::TypedVTable<short>; // NOLINT
-template struct FormatArgImpl::TypedVTable<unsigned short>; // NOLINT
-template struct FormatArgImpl::TypedVTable<int>;
-template struct FormatArgImpl::TypedVTable<unsigned>;
-template struct FormatArgImpl::TypedVTable<long>; // NOLINT
-template struct FormatArgImpl::TypedVTable<unsigned long>; // NOLINT
-template struct FormatArgImpl::TypedVTable<long long>; // NOLINT
-template struct FormatArgImpl::TypedVTable<unsigned long long>; // NOLINT
-template struct FormatArgImpl::TypedVTable<absl::uint128>;
-
-template struct FormatArgImpl::TypedVTable<float>;
-template struct FormatArgImpl::TypedVTable<double>;
-template struct FormatArgImpl::TypedVTable<long double>;
-
-template struct FormatArgImpl::TypedVTable<const char *>;
-template struct FormatArgImpl::TypedVTable<std::string>;
-template struct FormatArgImpl::TypedVTable<string_view>;
+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 a9562188..3376d48a 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
diff --git a/absl/strings/internal/str_format/bind.h b/absl/strings/internal/str_format/bind.h
index a503b19b..1b52df9c 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 <typename S>
friend ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<S>& 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 f43195c1..11b996ae 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 <limits.h>
+#include <cstddef>
#include <cstring>
#include <ostream>
@@ -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_;
};