summaryrefslogtreecommitdiff
path: root/absl/strings/internal/str_format/arg.h
diff options
context:
space:
mode:
Diffstat (limited to 'absl/strings/internal/str_format/arg.h')
-rw-r--r--absl/strings/internal/str_format/arg.h200
1 files changed, 136 insertions, 64 deletions
diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h
index 7a937563..3dbc1526 100644
--- a/absl/strings/internal/str_format/arg.h
+++ b/absl/strings/internal/str_format/arg.h
@@ -25,16 +25,37 @@ class Cord;
class FormatCountCapture;
class FormatSink;
+template <absl::FormatConversionCharSet C>
+struct FormatConvertResult;
+class FormatConversionSpec;
+
namespace str_format_internal {
template <typename T, typename = void>
struct HasUserDefinedConvert : std::false_type {};
template <typename T>
-struct HasUserDefinedConvert<
- T, void_t<decltype(AbslFormatConvert(
- std::declval<const T&>(), std::declval<ConversionSpec>(),
- std::declval<FormatSink*>()))>> : std::true_type {};
+struct HasUserDefinedConvert<T, void_t<decltype(AbslFormatConvert(
+ std::declval<const T&>(),
+ std::declval<const FormatConversionSpec&>(),
+ std::declval<FormatSink*>()))>>
+ : std::true_type {};
+
+void AbslFormatConvert(); // Stops the lexical name lookup
+template <typename T>
+auto FormatConvertImpl(const T& v, FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink)
+ -> decltype(AbslFormatConvert(v,
+ std::declval<const FormatConversionSpec&>(),
+ std::declval<FormatSink*>())) {
+ using FormatConversionSpecT =
+ absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatConversionSpec>;
+ using FormatSinkT =
+ absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatSink>;
+ auto fcs = conv.Wrap<FormatConversionSpecT>();
+ auto fs = sink->Wrap<FormatSinkT>();
+ return AbslFormatConvert(v, fcs, &fs);
+}
template <typename T>
class StreamedWrapper;
@@ -43,6 +64,13 @@ class StreamedWrapper;
// then convert it, appending to `sink` and return `true`.
// Otherwise fail and return `false`.
+// AbslFormatConvert(v, conv, sink) is intended to be found by ADL on 'v'
+// as an extension mechanism. These FormatConvertImpl functions are the default
+// implementations.
+// The ADL search is augmented via the 'Sink*' parameter, which also
+// serves as a disambiguator to reject possible unintended 'AbslFormatConvert'
+// functions in the namespaces associated with 'v'.
+
// Raw pointers.
struct VoidPtr {
VoidPtr() = default;
@@ -52,27 +80,45 @@ struct VoidPtr {
: value(ptr ? reinterpret_cast<uintptr_t>(ptr) : 0) {}
uintptr_t value;
};
-ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, ConversionSpec conv,
- FormatSinkImpl* sink);
+
+template <FormatConversionCharSet C>
+struct ArgConvertResult {
+ bool value;
+};
+
+template <FormatConversionCharSet C>
+constexpr FormatConversionCharSet ExtractCharSet(FormatConvertResult<C>) {
+ return C;
+}
+
+template <FormatConversionCharSet C>
+constexpr FormatConversionCharSet ExtractCharSet(ArgConvertResult<C>) {
+ return C;
+}
+
+using StringConvertResult =
+ ArgConvertResult<FormatConversionCharSetInternal::s>;
+ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
+ VoidPtr v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
// Strings.
-ConvertResult<Conv::s> FormatConvertImpl(const std::string& v,
- ConversionSpec conv,
- FormatSinkImpl* sink);
-ConvertResult<Conv::s> FormatConvertImpl(string_view v, ConversionSpec conv,
- FormatSinkImpl* sink);
-ConvertResult<Conv::s | Conv::p> FormatConvertImpl(const char* v,
- ConversionSpec conv,
- FormatSinkImpl* sink);
-template <class AbslCord,
- typename std::enable_if<
- std::is_same<AbslCord, absl::Cord>::value>::type* = nullptr>
-ConvertResult<Conv::s> FormatConvertImpl(const AbslCord& value,
- ConversionSpec conv,
- FormatSinkImpl* sink) {
- if (conv.conv() != ConversionChar::s) return {false};
-
- bool is_left = conv.flags().left;
+StringConvertResult FormatConvertImpl(const std::string& v,
+ FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink);
+StringConvertResult FormatConvertImpl(string_view v,
+ FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink);
+ArgConvertResult<FormatConversionCharSetUnion(
+ FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)>
+FormatConvertImpl(const char* v, const FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink);
+
+template <class AbslCord, typename std::enable_if<std::is_same<
+ AbslCord, absl::Cord>::value>::type* = nullptr>
+StringConvertResult FormatConvertImpl(const AbslCord& value,
+ FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink) {
+ bool is_left = conv.has_left_flag();
size_t space_remaining = 0;
int width = conv.width();
@@ -105,55 +151,63 @@ ConvertResult<Conv::s> FormatConvertImpl(const AbslCord& value,
return {true};
}
-using IntegralConvertResult =
- ConvertResult<Conv::c | Conv::numeric | Conv::star>;
-using FloatingConvertResult = ConvertResult<Conv::floating>;
+using IntegralConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
+ FormatConversionCharSetInternal::c,
+ FormatConversionCharSetInternal::kNumeric,
+ FormatConversionCharSetInternal::kStar)>;
+using FloatingConvertResult =
+ ArgConvertResult<FormatConversionCharSetInternal::kFloating>;
// Floats.
-FloatingConvertResult FormatConvertImpl(float v, ConversionSpec conv,
+FloatingConvertResult FormatConvertImpl(float v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-FloatingConvertResult FormatConvertImpl(double v, ConversionSpec conv,
+FloatingConvertResult FormatConvertImpl(double v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-FloatingConvertResult FormatConvertImpl(long double v, ConversionSpec conv,
+FloatingConvertResult FormatConvertImpl(long double v,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
// Chars.
-IntegralConvertResult FormatConvertImpl(char v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(signed char v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(signed char v,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(unsigned char v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(unsigned char v,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
// Ints.
IntegralConvertResult FormatConvertImpl(short v, // NOLINT
- ConversionSpec conv,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT
- ConversionSpec conv,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(int v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(int v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(unsigned v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(unsigned v,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(long v, // NOLINT
- ConversionSpec conv,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT
- ConversionSpec conv,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(long long v, // NOLINT
- ConversionSpec conv,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT
- ConversionSpec conv,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(int128 v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(int128 v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(uint128 v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(uint128 v,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0>
-IntegralConvertResult FormatConvertImpl(T v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(T v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink) {
return FormatConvertImpl(static_cast<int>(v), conv, sink);
}
@@ -164,12 +218,12 @@ template <typename T>
typename std::enable_if<std::is_enum<T>::value &&
!HasUserDefinedConvert<T>::value,
IntegralConvertResult>::type
-FormatConvertImpl(T v, ConversionSpec conv, FormatSinkImpl* sink);
+FormatConvertImpl(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
template <typename T>
-ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<T>& v,
- ConversionSpec conv,
- FormatSinkImpl* out) {
+StringConvertResult FormatConvertImpl(const StreamedWrapper<T>& v,
+ FormatConversionSpecImpl conv,
+ FormatSinkImpl* out) {
std::ostringstream oss;
oss << v.v_;
if (!oss) return {false};
@@ -180,21 +234,24 @@ ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<T>& v,
// until after FormatCountCapture is fully defined.
struct FormatCountCaptureHelper {
template <class T = int>
- static ConvertResult<Conv::n> ConvertHelper(const FormatCountCapture& v,
- ConversionSpec conv,
- FormatSinkImpl* sink) {
+ static ArgConvertResult<FormatConversionCharSetInternal::n> ConvertHelper(
+ const FormatCountCapture& v, FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink) {
const absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v;
- if (conv.conv() != str_format_internal::ConversionChar::n) return {false};
+ if (conv.conversion_char() !=
+ str_format_internal::FormatConversionCharInternal::n) {
+ return {false};
+ }
*v2.p_ = static_cast<int>(sink->size());
return {true};
}
};
template <class T = int>
-ConvertResult<Conv::n> FormatConvertImpl(const FormatCountCapture& v,
- ConversionSpec conv,
- FormatSinkImpl* sink) {
+ArgConvertResult<FormatConversionCharSetInternal::n> FormatConvertImpl(
+ const FormatCountCapture& v, FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink) {
return FormatCountCaptureHelper::ConvertHelper(v, conv, sink);
}
@@ -203,13 +260,13 @@ ConvertResult<Conv::n> FormatConvertImpl(const FormatCountCapture& v,
struct FormatArgImplFriend {
template <typename Arg>
static bool ToInt(Arg arg, int* out) {
- // A value initialized ConversionSpec has a `none` conv, which tells the
- // dispatcher to run the `int` conversion.
+ // A value initialized FormatConversionSpecImpl 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, str_format_internal::ConversionSpec conv,
+ static bool Convert(Arg arg, FormatConversionSpecImpl conv,
FormatSinkImpl* out) {
return arg.dispatcher_(arg.data_, conv, out);
}
@@ -220,6 +277,15 @@ struct FormatArgImplFriend {
}
};
+template <typename Arg>
+constexpr FormatConversionCharSet ArgumentToConv() {
+ return absl::str_format_internal::ExtractCharSet(
+ decltype(str_format_internal::FormatConvertImpl(
+ std::declval<const Arg&>(),
+ std::declval<const FormatConversionSpecImpl&>(),
+ std::declval<FormatSinkImpl*>())){});
+}
+
// A type-erased handle to a format argument.
class FormatArgImpl {
private:
@@ -233,7 +299,7 @@ class FormatArgImpl {
char buf[kInlinedSpace];
};
- using Dispatcher = bool (*)(Data, ConversionSpec, void* out);
+ using Dispatcher = bool (*)(Data, FormatConversionSpecImpl, void* out);
template <typename T>
struct store_by_value
@@ -375,15 +441,20 @@ class FormatArgImpl {
}
template <typename T>
- static bool Dispatch(Data arg, ConversionSpec spec, void* out) {
+ static bool Dispatch(Data arg, FormatConversionSpecImpl spec, void* out) {
// A `none` conv indicates that we want the `int` conversion.
- if (ABSL_PREDICT_FALSE(spec.conv() == ConversionChar::none)) {
+ if (ABSL_PREDICT_FALSE(spec.conversion_char() ==
+ FormatConversionCharInternal::kNone)) {
return ToInt<T>(arg, static_cast<int*>(out), std::is_integral<T>(),
std::is_enum<T>());
}
-
+ if (ABSL_PREDICT_FALSE(!Contains(ArgumentToConv<T>(),
+ spec.conversion_char()))) {
+ return false;
+ }
return str_format_internal::FormatConvertImpl(
- Manager<T>::Value(arg), spec, static_cast<FormatSinkImpl*>(out))
+ Manager<T>::Value(arg), spec,
+ static_cast<FormatSinkImpl*>(out))
.value;
}
@@ -391,8 +462,9 @@ class FormatArgImpl {
Dispatcher dispatcher_;
};
-#define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E) \
- E template bool FormatArgImpl::Dispatch<T>(Data, ConversionSpec, void*)
+#define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E) \
+ E template bool FormatArgImpl::Dispatch<T>(Data, FormatConversionSpecImpl, \
+ void*)
#define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...) \
ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(str_format_internal::VoidPtr, \