Commit d85783fd by Abseil Team Committed by vslashg

Export of internal Abseil changes

--
f34cd235a12ad0ee1fea3a1ee5a427272dc2b285 by Abseil Team <absl-team@google.com>:

Migrates uses of deprecated map types to recommended types.

PiperOrigin-RevId: 309945156

--
e3410a47ad32c0775b6911610bc47b22938decad by Matthew Brown <matthewbr@google.com>:

Internal Change

PiperOrigin-RevId: 309856021

--
a58cfa25e0bb59e7fa9647ac1aae65eaccff0086 by Greg Falcon <gfalcon@google.com>:

Internal change.

PiperOrigin-RevId: 309804612

--
cdc5ec310035fbe25f496bda283fe655d94d7769 by Mark Barolak <mbar@google.com>:

Standardize the header comments for friend functions in cord.h

PiperOrigin-RevId: 309779073

--
fe61602701be795e54477b0fdbf5ffc1df12a6b7 by Samuel Benzaquen <sbenza@google.com>:

Implement %f natively for any input.
It evaluates the input at runtime and allocates stack space accordingly.

This removes a potential fallback into snprintf, improves performance, and removes all memory allocations in this formatting path.

PiperOrigin-RevId: 309752501

--
79e2a24f3f959e8b06ddf1d440bbabbd5f89b5b7 by Greg Falcon <gfalcon@google.com>:

Add a Cord::swap() method.  Many other Abseil types already provide this, but it was missing here.

We already provided a two-argument free function form of `swap()`, but that API is better suited for generic code.  The swap member function is a better API when the types are known.

PiperOrigin-RevId: 309751740

--
85cdf60024f153fb4fcb7fe68ed2b14b9faf119d by Derek Mauro <dmauro@google.com>:

Cleanup uses of "linker initialized" SpinLocks

PiperOrigin-RevId: 309581867

--
9e5443bfcec4b94056b13c75326576e987ab88fb by Matt Kulukundis <kfm@google.com>:

Clarify intended mixing properties of `absl::Hash`

PiperOrigin-RevId: 309520174

--
a0630f0827b67f217aaeae68a448fe4c1101e17d by Greg Falcon <gfalcon@google.com>:

Comment out a test in Emscripten to sidestep `long double` issues.

PiperOrigin-RevId: 309482953
GitOrigin-RevId: f34cd235a12ad0ee1fea3a1ee5a427272dc2b285
Change-Id: Icce0c9d547117374d596b9d684e4054ddd118669
parent a1d66899
...@@ -541,7 +541,10 @@ cc_test( ...@@ -541,7 +541,10 @@ cc_test(
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["no_test_ios_x86_64"], tags = ["no_test_ios_x86_64"],
deps = [":malloc_internal"], deps = [
":malloc_internal",
"//absl/container:node_hash_map",
],
) )
cc_test( cc_test(
......
...@@ -497,6 +497,7 @@ absl_cc_test( ...@@ -497,6 +497,7 @@ absl_cc_test(
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::malloc_internal absl::malloc_internal
absl::node_hash_map
Threads::Threads Threads::Threads
) )
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
#include "absl/container/node_hash_map.h"
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace base_internal { namespace base_internal {
...@@ -75,7 +77,7 @@ static bool using_low_level_alloc = false; ...@@ -75,7 +77,7 @@ static bool using_low_level_alloc = false;
// allocations and deallocations are reported via the MallocHook // allocations and deallocations are reported via the MallocHook
// interface. // interface.
static void Test(bool use_new_arena, bool call_malloc_hook, int n) { static void Test(bool use_new_arena, bool call_malloc_hook, int n) {
typedef std::unordered_map<int, BlockDesc> AllocMap; typedef absl::node_hash_map<int, BlockDesc> AllocMap;
AllocMap allocated; AllocMap allocated;
AllocMap::iterator it; AllocMap::iterator it;
BlockDesc block_desc; BlockDesc block_desc;
......
...@@ -149,13 +149,15 @@ struct FileMappingHint { ...@@ -149,13 +149,15 @@ struct FileMappingHint {
// Moreover, we are using only TryLock(), if the decorator list // Moreover, we are using only TryLock(), if the decorator list
// is being modified (is busy), we skip all decorators, and possibly // is being modified (is busy), we skip all decorators, and possibly
// loose some info. Sorry, that's the best we could do. // loose some info. Sorry, that's the best we could do.
base_internal::SpinLock g_decorators_mu(base_internal::kLinkerInitialized); ABSL_CONST_INIT absl::base_internal::SpinLock g_decorators_mu(
absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY);
const int kMaxFileMappingHints = 8; const int kMaxFileMappingHints = 8;
int g_num_file_mapping_hints; int g_num_file_mapping_hints;
FileMappingHint g_file_mapping_hints[kMaxFileMappingHints]; FileMappingHint g_file_mapping_hints[kMaxFileMappingHints];
// Protects g_file_mapping_hints. // Protects g_file_mapping_hints.
base_internal::SpinLock g_file_mapping_mu(base_internal::kLinkerInitialized); ABSL_CONST_INIT absl::base_internal::SpinLock g_file_mapping_mu(
absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY);
// Async-signal-safe function to zero a buffer. // Async-signal-safe function to zero a buffer.
// memset() is not guaranteed to be async-signal-safe. // memset() is not guaranteed to be async-signal-safe.
......
...@@ -37,8 +37,11 @@ ...@@ -37,8 +37,11 @@
// types. Hashing of that combined state is separately done by `absl::Hash`. // types. Hashing of that combined state is separately done by `absl::Hash`.
// //
// One should assume that a hash algorithm is chosen randomly at the start of // One should assume that a hash algorithm is chosen randomly at the start of
// each process. E.g., absl::Hash<int>()(9) in one process and // each process. E.g., `absl::Hash<int>{}(9)` in one process and
// absl::Hash<int>()(9) in another process are likely to differ. // `absl::Hash<int>{}(9)` in another process are likely to differ.
//
// `absl::Hash` is intended to strongly mix input bits with a target of passing
// an [Avalanche Test](https://en.wikipedia.org/wiki/Avalanche_effect).
// //
// Example: // Example:
// //
......
...@@ -130,12 +130,15 @@ TYPED_TEST(GaussianDistributionInterfaceTest, SerializeTest) { ...@@ -130,12 +130,15 @@ TYPED_TEST(GaussianDistributionInterfaceTest, SerializeTest) {
ss >> after; ss >> after;
#if defined(__powerpc64__) || defined(__PPC64__) || defined(__powerpc__) || \ #if defined(__powerpc64__) || defined(__PPC64__) || defined(__powerpc__) || \
defined(__ppc__) || defined(__PPC__) defined(__ppc__) || defined(__PPC__) || defined(__EMSCRIPTEN__)
if (std::is_same<TypeParam, long double>::value) { if (std::is_same<TypeParam, long double>::value) {
// Roundtripping floating point values requires sufficient precision // Roundtripping floating point values requires sufficient precision
// to reconstruct the exact value. It turns out that long double // to reconstruct the exact value. It turns out that long double
// has some errors doing this on ppc, particularly for values // has some errors doing this on ppc, particularly for values
// near {1.0 +/- epsilon}. // near {1.0 +/- epsilon}.
//
// Emscripten is even worse, implementing long double as a 128-bit
// type, but shipping with a strtold() that doesn't support that.
if (mean <= std::numeric_limits<double>::max() && if (mean <= std::numeric_limits<double>::max() &&
mean >= std::numeric_limits<double>::lowest()) { mean >= std::numeric_limits<double>::lowest()) {
EXPECT_EQ(static_cast<double>(before.mean()), EXPECT_EQ(static_cast<double>(before.mean()),
......
...@@ -28,7 +28,7 @@ TEST(WideMultiplyTest, MultiplyU64ToU128Test) { ...@@ -28,7 +28,7 @@ TEST(WideMultiplyTest, MultiplyU64ToU128Test) {
EXPECT_EQ(absl::uint128(0), MultiplyU64ToU128(0, 0)); EXPECT_EQ(absl::uint128(0), MultiplyU64ToU128(0, 0));
// Max uint64 // Max uint64_t
EXPECT_EQ(MultiplyU64ToU128(kMax, kMax), EXPECT_EQ(MultiplyU64ToU128(kMax, kMax),
absl::MakeUint128(0xfffffffffffffffe, 0x0000000000000001)); absl::MakeUint128(0xfffffffffffffffe, 0x0000000000000001));
EXPECT_EQ(absl::MakeUint128(0, kMax), MultiplyU64ToU128(kMax, 1)); EXPECT_EQ(absl::MakeUint128(0, kMax), MultiplyU64ToU128(kMax, 1));
......
...@@ -638,10 +638,13 @@ cc_library( ...@@ -638,10 +638,13 @@ cc_library(
visibility = ["//visibility:private"], visibility = ["//visibility:private"],
deps = [ deps = [
":strings", ":strings",
"//absl/base:bits",
"//absl/base:config", "//absl/base:config",
"//absl/base:core_headers", "//absl/base:core_headers",
"//absl/functional:function_ref",
"//absl/meta:type_traits", "//absl/meta:type_traits",
"//absl/numeric:int128", "//absl/numeric:int128",
"//absl/types:optional",
"//absl/types:span", "//absl/types:span",
], ],
) )
...@@ -718,7 +721,7 @@ cc_test( ...@@ -718,7 +721,7 @@ cc_test(
deps = [ deps = [
":str_format_internal", ":str_format_internal",
"//absl/base:raw_logging_internal", "//absl/base:raw_logging_internal",
"//absl/numeric:int128", "//absl/types:optional",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
], ],
) )
......
...@@ -392,6 +392,7 @@ absl_cc_library( ...@@ -392,6 +392,7 @@ absl_cc_library(
COPTS COPTS
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
DEPS DEPS
absl::bits
absl::strings absl::strings
absl::config absl::config
absl::core_headers absl::core_headers
......
...@@ -162,7 +162,7 @@ class Cord { ...@@ -162,7 +162,7 @@ class Cord {
if (contents_.is_tree()) DestroyCordSlow(); if (contents_.is_tree()) DestroyCordSlow();
} }
// Cord::MakeCordFromExternal(data, callable) // MakeCordFromExternal()
// //
// Creates a Cord that takes ownership of external string memory. The // Creates a Cord that takes ownership of external string memory. The
// contents of `data` are not copied to the Cord; instead, the external // contents of `data` are not copied to the Cord; instead, the external
...@@ -246,10 +246,17 @@ class Cord { ...@@ -246,10 +246,17 @@ class Cord {
// (pos + new_size) >= size(), the result is the subrange [pos, size()). // (pos + new_size) >= size(), the result is the subrange [pos, size()).
Cord Subcord(size_t pos, size_t new_size) const; Cord Subcord(size_t pos, size_t new_size) const;
// Cord::swap()
//
// Swaps the contents of the Cord with `other`.
void swap(Cord& other) noexcept;
// swap() // swap()
// //
// Swaps the data of Cord `x` with Cord `y`. // Swaps the contents of two Cords.
friend void swap(Cord& x, Cord& y) noexcept; friend void swap(Cord& x, Cord& y) noexcept {
x.swap(y);
}
// Cord::size() // Cord::size()
// //
...@@ -1032,6 +1039,10 @@ inline Cord& Cord::operator=(const Cord& x) { ...@@ -1032,6 +1039,10 @@ inline Cord& Cord::operator=(const Cord& x) {
inline Cord::Cord(Cord&& src) noexcept : contents_(std::move(src.contents_)) {} inline Cord::Cord(Cord&& src) noexcept : contents_(std::move(src.contents_)) {}
inline void Cord::swap(Cord& other) noexcept {
contents_.Swap(&other.contents_);
}
inline Cord& Cord::operator=(Cord&& x) noexcept { inline Cord& Cord::operator=(Cord&& x) noexcept {
contents_ = std::move(x.contents_); contents_ = std::move(x.contents_);
return *this; return *this;
...@@ -1308,10 +1319,6 @@ inline bool operator<=(absl::string_view x, const Cord& y) { return !(y < x); } ...@@ -1308,10 +1319,6 @@ inline bool operator<=(absl::string_view x, const Cord& y) { return !(y < x); }
inline bool operator>=(const Cord& x, absl::string_view y) { return !(x < y); } inline bool operator>=(const Cord& x, absl::string_view y) { return !(x < y); }
inline bool operator>=(absl::string_view x, const Cord& y) { return !(x < y); } inline bool operator>=(absl::string_view x, const Cord& y) { return !(x < y); }
// Overload of swap for Cord. The use of non-const references is
// required. :(
inline void swap(Cord& x, Cord& y) noexcept { y.contents_.Swap(&x.contents_); }
// Some internals exposed to test code. // Some internals exposed to test code.
namespace strings_internal { namespace strings_internal {
class CordTestAccess { class CordTestAccess {
......
...@@ -396,6 +396,9 @@ TEST(Cord, Swap) { ...@@ -396,6 +396,9 @@ TEST(Cord, Swap) {
swap(x, y); swap(x, y);
ASSERT_EQ(x, absl::Cord(b)); ASSERT_EQ(x, absl::Cord(b));
ASSERT_EQ(y, absl::Cord(a)); ASSERT_EQ(y, absl::Cord(a));
x.swap(y);
ASSERT_EQ(x, absl::Cord(a));
ASSERT_EQ(y, absl::Cord(b));
} }
static void VerifyCopyToString(const absl::Cord& cord) { static void VerifyCopyToString(const absl::Cord& cord) {
......
...@@ -67,20 +67,24 @@ constexpr FormatConversionCharSet ExtractCharSet(ArgConvertResult<C>) { ...@@ -67,20 +67,24 @@ constexpr FormatConversionCharSet ExtractCharSet(ArgConvertResult<C>) {
using StringConvertResult = using StringConvertResult =
ArgConvertResult<FormatConversionCharSetInternal::s>; ArgConvertResult<FormatConversionCharSetInternal::s>;
ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl( ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
VoidPtr v, ConversionSpec conv, FormatSinkImpl* sink); VoidPtr v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
// Strings. // Strings.
StringConvertResult FormatConvertImpl(const std::string& v, ConversionSpec conv, StringConvertResult FormatConvertImpl(const std::string& v,
FormatConversionSpecImpl conv,
FormatSinkImpl* sink); FormatSinkImpl* sink);
StringConvertResult FormatConvertImpl(string_view v, ConversionSpec conv, StringConvertResult FormatConvertImpl(string_view v,
FormatConversionSpecImpl conv,
FormatSinkImpl* sink); FormatSinkImpl* sink);
ArgConvertResult<FormatConversionCharSetUnion( ArgConvertResult<FormatConversionCharSetUnion(
FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)> FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)>
FormatConvertImpl(const char* v, ConversionSpec conv, FormatSinkImpl* sink); FormatConvertImpl(const char* v, const FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
template <class AbslCord, typename std::enable_if<std::is_same< template <class AbslCord, typename std::enable_if<std::is_same<
AbslCord, absl::Cord>::value>::type* = nullptr> AbslCord, absl::Cord>::value>::type* = nullptr>
StringConvertResult FormatConvertImpl(const AbslCord& value, StringConvertResult FormatConvertImpl(const AbslCord& value,
ConversionSpec conv, FormatConversionSpecImpl conv,
FormatSinkImpl* sink) { FormatSinkImpl* sink) {
if (conv.conversion_char() != FormatConversionCharInternal::s) { if (conv.conversion_char() != FormatConversionCharInternal::s) {
return {false}; return {false};
...@@ -127,50 +131,55 @@ using FloatingConvertResult = ...@@ -127,50 +131,55 @@ using FloatingConvertResult =
ArgConvertResult<FormatConversionCharSetInternal::kFloating>; ArgConvertResult<FormatConversionCharSetInternal::kFloating>;
// Floats. // Floats.
FloatingConvertResult FormatConvertImpl(float v, ConversionSpec conv, FloatingConvertResult FormatConvertImpl(float v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink); FormatSinkImpl* sink);
FloatingConvertResult FormatConvertImpl(double v, ConversionSpec conv, FloatingConvertResult FormatConvertImpl(double v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink); FormatSinkImpl* sink);
FloatingConvertResult FormatConvertImpl(long double v, ConversionSpec conv, FloatingConvertResult FormatConvertImpl(long double v,
FormatConversionSpecImpl conv,
FormatSinkImpl* sink); FormatSinkImpl* sink);
// Chars. // Chars.
IntegralConvertResult FormatConvertImpl(char v, ConversionSpec conv, IntegralConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink); FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(signed char v, ConversionSpec conv, IntegralConvertResult FormatConvertImpl(signed char v,
FormatConversionSpecImpl conv,
FormatSinkImpl* sink); FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(unsigned char v, ConversionSpec conv, IntegralConvertResult FormatConvertImpl(unsigned char v,
FormatConversionSpecImpl conv,
FormatSinkImpl* sink); FormatSinkImpl* sink);
// Ints. // Ints.
IntegralConvertResult FormatConvertImpl(short v, // NOLINT IntegralConvertResult FormatConvertImpl(short v, // NOLINT
ConversionSpec conv, FormatConversionSpecImpl conv,
FormatSinkImpl* sink); FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT
ConversionSpec conv, FormatConversionSpecImpl conv,
FormatSinkImpl* sink); FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(int v, ConversionSpec conv, IntegralConvertResult FormatConvertImpl(int v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink); FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(unsigned v, ConversionSpec conv, IntegralConvertResult FormatConvertImpl(unsigned v,
FormatConversionSpecImpl conv,
FormatSinkImpl* sink); FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(long v, // NOLINT IntegralConvertResult FormatConvertImpl(long v, // NOLINT
ConversionSpec conv, FormatConversionSpecImpl conv,
FormatSinkImpl* sink); FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT
ConversionSpec conv, FormatConversionSpecImpl conv,
FormatSinkImpl* sink); FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(long long v, // NOLINT IntegralConvertResult FormatConvertImpl(long long v, // NOLINT
ConversionSpec conv, FormatConversionSpecImpl conv,
FormatSinkImpl* sink); FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT
ConversionSpec conv, FormatConversionSpecImpl conv,
FormatSinkImpl* sink); FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(int128 v, ConversionSpec conv, IntegralConvertResult FormatConvertImpl(int128 v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink); FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(uint128 v, ConversionSpec conv, IntegralConvertResult FormatConvertImpl(uint128 v,
FormatConversionSpecImpl conv,
FormatSinkImpl* sink); FormatSinkImpl* sink);
template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0> 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) { FormatSinkImpl* sink) {
return FormatConvertImpl(static_cast<int>(v), conv, sink); return FormatConvertImpl(static_cast<int>(v), conv, sink);
} }
...@@ -181,11 +190,11 @@ template <typename T> ...@@ -181,11 +190,11 @@ template <typename T>
typename std::enable_if<std::is_enum<T>::value && typename std::enable_if<std::is_enum<T>::value &&
!HasUserDefinedConvert<T>::value, !HasUserDefinedConvert<T>::value,
IntegralConvertResult>::type IntegralConvertResult>::type
FormatConvertImpl(T v, ConversionSpec conv, FormatSinkImpl* sink); FormatConvertImpl(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
template <typename T> template <typename T>
StringConvertResult FormatConvertImpl(const StreamedWrapper<T>& v, StringConvertResult FormatConvertImpl(const StreamedWrapper<T>& v,
ConversionSpec conv, FormatConversionSpecImpl conv,
FormatSinkImpl* out) { FormatSinkImpl* out) {
std::ostringstream oss; std::ostringstream oss;
oss << v.v_; oss << v.v_;
...@@ -198,7 +207,8 @@ StringConvertResult FormatConvertImpl(const StreamedWrapper<T>& v, ...@@ -198,7 +207,8 @@ StringConvertResult FormatConvertImpl(const StreamedWrapper<T>& v,
struct FormatCountCaptureHelper { struct FormatCountCaptureHelper {
template <class T = int> template <class T = int>
static ArgConvertResult<FormatConversionCharSetInternal::n> ConvertHelper( static ArgConvertResult<FormatConversionCharSetInternal::n> ConvertHelper(
const FormatCountCapture& v, ConversionSpec conv, FormatSinkImpl* sink) { const FormatCountCapture& v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink) {
const absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v; const absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v;
if (conv.conversion_char() != if (conv.conversion_char() !=
...@@ -212,7 +222,8 @@ struct FormatCountCaptureHelper { ...@@ -212,7 +222,8 @@ struct FormatCountCaptureHelper {
template <class T = int> template <class T = int>
ArgConvertResult<FormatConversionCharSetInternal::n> FormatConvertImpl( ArgConvertResult<FormatConversionCharSetInternal::n> FormatConvertImpl(
const FormatCountCapture& v, ConversionSpec conv, FormatSinkImpl* sink) { const FormatCountCapture& v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink) {
return FormatCountCaptureHelper::ConvertHelper(v, conv, sink); return FormatCountCaptureHelper::ConvertHelper(v, conv, sink);
} }
...@@ -221,13 +232,13 @@ ArgConvertResult<FormatConversionCharSetInternal::n> FormatConvertImpl( ...@@ -221,13 +232,13 @@ ArgConvertResult<FormatConversionCharSetInternal::n> FormatConvertImpl(
struct FormatArgImplFriend { struct FormatArgImplFriend {
template <typename Arg> template <typename Arg>
static bool ToInt(Arg arg, int* out) { static bool ToInt(Arg arg, int* out) {
// A value initialized ConversionSpec has a `none` conv, which tells the // A value initialized FormatConversionSpecImpl has a `none` conv, which
// dispatcher to run the `int` conversion. // tells the dispatcher to run the `int` conversion.
return arg.dispatcher_(arg.data_, {}, out); return arg.dispatcher_(arg.data_, {}, out);
} }
template <typename Arg> template <typename Arg>
static bool Convert(Arg arg, str_format_internal::ConversionSpec conv, static bool Convert(Arg arg, FormatConversionSpecImpl conv,
FormatSinkImpl* out) { FormatSinkImpl* out) {
return arg.dispatcher_(arg.data_, conv, out); return arg.dispatcher_(arg.data_, conv, out);
} }
...@@ -251,7 +262,7 @@ class FormatArgImpl { ...@@ -251,7 +262,7 @@ class FormatArgImpl {
char buf[kInlinedSpace]; char buf[kInlinedSpace];
}; };
using Dispatcher = bool (*)(Data, ConversionSpec, void* out); using Dispatcher = bool (*)(Data, FormatConversionSpecImpl, void* out);
template <typename T> template <typename T>
struct store_by_value struct store_by_value
...@@ -393,7 +404,7 @@ class FormatArgImpl { ...@@ -393,7 +404,7 @@ class FormatArgImpl {
} }
template <typename T> 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. // A `none` conv indicates that we want the `int` conversion.
if (ABSL_PREDICT_FALSE(spec.conversion_char() == if (ABSL_PREDICT_FALSE(spec.conversion_char() ==
FormatConversionCharInternal::kNone)) { FormatConversionCharInternal::kNone)) {
...@@ -410,8 +421,9 @@ class FormatArgImpl { ...@@ -410,8 +421,9 @@ class FormatArgImpl {
Dispatcher dispatcher_; Dispatcher dispatcher_;
}; };
#define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E) \ #define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E) \
E template bool FormatArgImpl::Dispatch<T>(Data, ConversionSpec, void*) E template bool FormatArgImpl::Dispatch<T>(Data, FormatConversionSpecImpl, \
void*)
#define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...) \ #define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...) \
ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(str_format_internal::VoidPtr, \ ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(str_format_internal::VoidPtr, \
......
...@@ -95,8 +95,9 @@ TEST_F(FormatArgImplTest, OtherPtrDecayToVoidPtr) { ...@@ -95,8 +95,9 @@ TEST_F(FormatArgImplTest, OtherPtrDecayToVoidPtr) {
TEST_F(FormatArgImplTest, WorksWithCharArraysOfUnknownSize) { TEST_F(FormatArgImplTest, WorksWithCharArraysOfUnknownSize) {
std::string s; std::string s;
FormatSinkImpl sink(&s); FormatSinkImpl sink(&s);
ConversionSpec conv; FormatConversionSpecImpl conv;
FormatConversionSpecImplFriend::SetConversionChar(ConversionChar::s, &conv); FormatConversionSpecImplFriend::SetConversionChar(FormatConversionChar::s,
&conv);
FormatConversionSpecImplFriend::SetFlags(Flags(), &conv); FormatConversionSpecImplFriend::SetFlags(Flags(), &conv);
FormatConversionSpecImplFriend::SetWidth(-1, &conv); FormatConversionSpecImplFriend::SetWidth(-1, &conv);
FormatConversionSpecImplFriend::SetPrecision(-1, &conv); FormatConversionSpecImplFriend::SetPrecision(-1, &conv);
......
...@@ -19,7 +19,7 @@ class UntypedFormatSpec; ...@@ -19,7 +19,7 @@ class UntypedFormatSpec;
namespace str_format_internal { namespace str_format_internal {
class BoundConversion : public ConversionSpec { class BoundConversion : public FormatConversionSpecImpl {
public: public:
const FormatArgImpl* arg() const { return arg_; } const FormatArgImpl* arg() const { return arg_; }
void set_arg(const FormatArgImpl* a) { arg_ = a; } void set_arg(const FormatArgImpl* a) { arg_ = a; }
...@@ -119,7 +119,7 @@ class FormatSpecTemplate ...@@ -119,7 +119,7 @@ class FormatSpecTemplate
#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
template <Conv... C, template <FormatConversionCharSet... C,
typename = typename std::enable_if< typename = typename std::enable_if<
AllOf(sizeof...(C) == sizeof...(Args), Contains(Args, AllOf(sizeof...(C) == sizeof...(Args), Contains(Args,
C)...)>::type> C)...)>::type>
...@@ -190,7 +190,8 @@ class StreamedWrapper { ...@@ -190,7 +190,8 @@ class StreamedWrapper {
private: private:
template <typename S> template <typename S>
friend ArgConvertResult<FormatConversionCharSetInternal::s> FormatConvertImpl( friend ArgConvertResult<FormatConversionCharSetInternal::s> FormatConvertImpl(
const StreamedWrapper<S>& v, ConversionSpec conv, FormatSinkImpl* out); const StreamedWrapper<S>& v, FormatConversionSpecImpl conv,
FormatSinkImpl* out);
const T& v_; const T& v_;
}; };
......
...@@ -24,7 +24,7 @@ std::string ConvToString(FormatConversionCharSet conv) { ...@@ -24,7 +24,7 @@ std::string ConvToString(FormatConversionCharSet conv) {
} }
TEST(StrFormatChecker, ArgumentToConv) { TEST(StrFormatChecker, ArgumentToConv) {
Conv conv = ArgumentToConv<std::string>(); FormatConversionCharSet conv = ArgumentToConv<std::string>();
EXPECT_EQ(ConvToString(conv), "s"); EXPECT_EQ(ConvToString(conv), "s");
conv = ArgumentToConv<const char*>(); conv = ArgumentToConv<const char*>();
......
...@@ -411,11 +411,6 @@ inline size_t Excess(size_t used, size_t capacity) { ...@@ -411,11 +411,6 @@ inline size_t Excess(size_t used, size_t capacity) {
return used < capacity ? capacity - used : 0; return used < capacity ? capacity - used : 0;
} }
// Type alias for use during migration.
using ConversionChar = FormatConversionChar;
using ConversionSpec = FormatConversionSpecImpl;
using Conv = FormatConversionCharSet;
class FormatConversionSpec { class FormatConversionSpec {
public: public:
// Width and precison are not specified, no flags are set. // Width and precison are not specified, no flags are set.
......
...@@ -7,13 +7,13 @@ namespace absl { ...@@ -7,13 +7,13 @@ namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace str_format_internal { namespace str_format_internal {
bool ConvertFloatImpl(float v, const ConversionSpec &conv, bool ConvertFloatImpl(float v, const FormatConversionSpecImpl &conv,
FormatSinkImpl *sink); FormatSinkImpl *sink);
bool ConvertFloatImpl(double v, const ConversionSpec &conv, bool ConvertFloatImpl(double v, const FormatConversionSpecImpl &conv,
FormatSinkImpl *sink); FormatSinkImpl *sink);
bool ConvertFloatImpl(long double v, const ConversionSpec &conv, bool ConvertFloatImpl(long double v, const FormatConversionSpecImpl &conv,
FormatSinkImpl *sink); FormatSinkImpl *sink);
} // namespace str_format_internal } // namespace str_format_internal
......
...@@ -83,7 +83,7 @@ const char* ConsumeUnboundConversion(const char* p, const char* end, ...@@ -83,7 +83,7 @@ const char* ConsumeUnboundConversion(const char* p, const char* end,
// conversions. // conversions.
class ConvTag { class ConvTag {
public: public:
constexpr ConvTag(ConversionChar conversion_char) // NOLINT constexpr ConvTag(FormatConversionChar conversion_char) // NOLINT
: tag_(static_cast<int8_t>(conversion_char)) {} : tag_(static_cast<int8_t>(conversion_char)) {}
// We invert the length modifiers to make them negative so that we can easily // We invert the length modifiers to make them negative so that we can easily
// test for them. // test for them.
...@@ -94,9 +94,9 @@ class ConvTag { ...@@ -94,9 +94,9 @@ class ConvTag {
bool is_conv() const { return tag_ >= 0; } bool is_conv() const { return tag_ >= 0; }
bool is_length() const { return tag_ < 0 && tag_ != -128; } bool is_length() const { return tag_ < 0 && tag_ != -128; }
ConversionChar as_conv() const { FormatConversionChar as_conv() const {
assert(is_conv()); assert(is_conv());
return static_cast<ConversionChar>(tag_); return static_cast<FormatConversionChar>(tag_);
} }
LengthMod as_length() const { LengthMod as_length() const {
assert(is_length()); assert(is_length());
...@@ -282,7 +282,7 @@ class ParsedFormatBase { ...@@ -282,7 +282,7 @@ class ParsedFormatBase {
// This is the only API that allows the user to pass a runtime specified format // This is the only API that allows the user to pass a runtime specified format
// string. These factory functions will return NULL if the format does not match // string. These factory functions will return NULL if the format does not match
// the conversions requested by the user. // the conversions requested by the user.
template <str_format_internal::Conv... C> template <FormatConversionCharSet... C>
class ExtendedParsedFormat : public str_format_internal::ParsedFormatBase { class ExtendedParsedFormat : public str_format_internal::ParsedFormatBase {
public: public:
explicit ExtendedParsedFormat(string_view format) explicit ExtendedParsedFormat(string_view format)
......
...@@ -41,7 +41,7 @@ TEST(LengthModTest, Names) { ...@@ -41,7 +41,7 @@ TEST(LengthModTest, Names) {
TEST(ConversionCharTest, Names) { TEST(ConversionCharTest, Names) {
struct Expectation { struct Expectation {
ConversionChar id; FormatConversionChar id;
char name; char name;
}; };
// clang-format off // clang-format off
...@@ -57,7 +57,7 @@ TEST(ConversionCharTest, Names) { ...@@ -57,7 +57,7 @@ TEST(ConversionCharTest, Names) {
// clang-format on // clang-format on
for (auto e : kExpect) { for (auto e : kExpect) {
SCOPED_TRACE(e.name); SCOPED_TRACE(e.name);
ConversionChar v = e.id; FormatConversionChar v = e.id;
EXPECT_EQ(e.name, FormatConversionCharToChar(v)); EXPECT_EQ(e.name, FormatConversionCharToChar(v));
} }
} }
...@@ -368,7 +368,7 @@ TEST_F(ParsedFormatTest, ValueSemantics) { ...@@ -368,7 +368,7 @@ TEST_F(ParsedFormatTest, ValueSemantics) {
struct ExpectParse { struct ExpectParse {
const char* in; const char* in;
std::initializer_list<Conv> conv_set; std::initializer_list<FormatConversionCharSet> conv_set;
const char* out; const char* out;
}; };
......
...@@ -532,76 +532,103 @@ TEST_F(ParsedFormatTest, SimpleUncheckedIncorrect) { ...@@ -532,76 +532,103 @@ TEST_F(ParsedFormatTest, SimpleUncheckedIncorrect) {
EXPECT_FALSE((ParsedFormat<'s', 'd', 'g'>::New(format))); EXPECT_FALSE((ParsedFormat<'s', 'd', 'g'>::New(format)));
} }
using str_format_internal::Conv; using absl::str_format_internal::FormatConversionCharSet;
TEST_F(ParsedFormatTest, UncheckedCorrect) { TEST_F(ParsedFormatTest, UncheckedCorrect) {
auto f = ExtendedParsedFormat<Conv::d>::New("ABC%dDEF"); auto f = ExtendedParsedFormat<FormatConversionCharSet::d>::New("ABC%dDEF");
ASSERT_TRUE(f); ASSERT_TRUE(f);
EXPECT_EQ("[ABC]{d:1$d}[DEF]", SummarizeParsedFormat(*f)); EXPECT_EQ("[ABC]{d:1$d}[DEF]", SummarizeParsedFormat(*f));
std::string format = "%sFFF%dZZZ%f"; std::string format = "%sFFF%dZZZ%f";
auto f2 = ExtendedParsedFormat<Conv::kString, Conv::d, Conv::kFloating>::New( auto f2 =
format); ExtendedParsedFormat<FormatConversionCharSet::kString,
FormatConversionCharSet::d,
FormatConversionCharSet::kFloating>::New(format);
ASSERT_TRUE(f2); ASSERT_TRUE(f2);
EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2)); EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
f2 = ExtendedParsedFormat<Conv::kString, Conv::d, Conv::kFloating>::New( f2 =
"%s %d %f"); ExtendedParsedFormat<FormatConversionCharSet::kString,
FormatConversionCharSet::d,
FormatConversionCharSet::kFloating>::New("%s %d %f");
ASSERT_TRUE(f2); ASSERT_TRUE(f2);
EXPECT_EQ("{s:1$s}[ ]{d:2$d}[ ]{f:3$f}", SummarizeParsedFormat(*f2)); EXPECT_EQ("{s:1$s}[ ]{d:2$d}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
auto star = ExtendedParsedFormat<Conv::kStar, Conv::d>::New("%*d"); auto star = ExtendedParsedFormat<FormatConversionCharSet::kStar,
FormatConversionCharSet::d>::New("%*d");
ASSERT_TRUE(star); ASSERT_TRUE(star);
EXPECT_EQ("{*d:2$1$*d}", SummarizeParsedFormat(*star)); EXPECT_EQ("{*d:2$1$*d}", SummarizeParsedFormat(*star));
auto dollar = ExtendedParsedFormat<Conv::d, Conv::s>::New("%2$s %1$d"); auto dollar =
ExtendedParsedFormat<FormatConversionCharSet::d,
FormatConversionCharSet::s>::New("%2$s %1$d");
ASSERT_TRUE(dollar); ASSERT_TRUE(dollar);
EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}", SummarizeParsedFormat(*dollar)); EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}", SummarizeParsedFormat(*dollar));
// with reuse // with reuse
dollar = ExtendedParsedFormat<Conv::d, Conv::s>::New("%2$s %1$d %1$d"); dollar =
ExtendedParsedFormat<FormatConversionCharSet::d,
FormatConversionCharSet::s>::New("%2$s %1$d %1$d");
ASSERT_TRUE(dollar); ASSERT_TRUE(dollar);
EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}[ ]{1$d:1$d}", EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}[ ]{1$d:1$d}",
SummarizeParsedFormat(*dollar)); SummarizeParsedFormat(*dollar));
} }
TEST_F(ParsedFormatTest, UncheckedIgnoredArgs) { TEST_F(ParsedFormatTest, UncheckedIgnoredArgs) {
EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::s>::New("ABC"))); EXPECT_FALSE((ExtendedParsedFormat<FormatConversionCharSet::d,
EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::s>::New("%dABC"))); FormatConversionCharSet::s>::New("ABC")));
EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::s>::New("ABC%2$s"))); EXPECT_FALSE(
auto f = ExtendedParsedFormat<Conv::d, Conv::s>::NewAllowIgnored("ABC"); (ExtendedParsedFormat<FormatConversionCharSet::d,
FormatConversionCharSet::s>::New("%dABC")));
EXPECT_FALSE(
(ExtendedParsedFormat<FormatConversionCharSet::d,
FormatConversionCharSet::s>::New("ABC%2$s")));
auto f =
ExtendedParsedFormat<FormatConversionCharSet::d,
FormatConversionCharSet::s>::NewAllowIgnored("ABC");
ASSERT_TRUE(f); ASSERT_TRUE(f);
EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f)); EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f));
f = ExtendedParsedFormat<Conv::d, Conv::s>::NewAllowIgnored("%dABC"); f = ExtendedParsedFormat<
FormatConversionCharSet::d,
FormatConversionCharSet::s>::NewAllowIgnored("%dABC");
ASSERT_TRUE(f); ASSERT_TRUE(f);
EXPECT_EQ("{d:1$d}[ABC]", SummarizeParsedFormat(*f)); EXPECT_EQ("{d:1$d}[ABC]", SummarizeParsedFormat(*f));
f = ExtendedParsedFormat<Conv::d, Conv::s>::NewAllowIgnored("ABC%2$s"); f = ExtendedParsedFormat<
FormatConversionCharSet::d,
FormatConversionCharSet::s>::NewAllowIgnored("ABC%2$s");
ASSERT_TRUE(f); ASSERT_TRUE(f);
EXPECT_EQ("[ABC]{2$s:2$s}", SummarizeParsedFormat(*f)); EXPECT_EQ("[ABC]{2$s:2$s}", SummarizeParsedFormat(*f));
} }
TEST_F(ParsedFormatTest, UncheckedMultipleTypes) { TEST_F(ParsedFormatTest, UncheckedMultipleTypes) {
auto dx = ExtendedParsedFormat<Conv::d | Conv::x>::New("%1$d %1$x"); auto dx = ExtendedParsedFormat<FormatConversionCharSet::d |
FormatConversionCharSet::x>::New("%1$d %1$x");
EXPECT_TRUE(dx); EXPECT_TRUE(dx);
EXPECT_EQ("{1$d:1$d}[ ]{1$x:1$x}", SummarizeParsedFormat(*dx)); EXPECT_EQ("{1$d:1$d}[ ]{1$x:1$x}", SummarizeParsedFormat(*dx));
dx = ExtendedParsedFormat<Conv::d | Conv::x>::New("%1$d"); dx = ExtendedParsedFormat<FormatConversionCharSet::d |
FormatConversionCharSet::x>::New("%1$d");
EXPECT_TRUE(dx); EXPECT_TRUE(dx);
EXPECT_EQ("{1$d:1$d}", SummarizeParsedFormat(*dx)); EXPECT_EQ("{1$d:1$d}", SummarizeParsedFormat(*dx));
} }
TEST_F(ParsedFormatTest, UncheckedIncorrect) { TEST_F(ParsedFormatTest, UncheckedIncorrect) {
EXPECT_FALSE(ExtendedParsedFormat<Conv::d>::New("")); EXPECT_FALSE(ExtendedParsedFormat<FormatConversionCharSet::d>::New(""));
EXPECT_FALSE(ExtendedParsedFormat<Conv::d>::New("ABC%dDEF%d")); EXPECT_FALSE(
ExtendedParsedFormat<FormatConversionCharSet::d>::New("ABC%dDEF%d"));
std::string format = "%sFFF%dZZZ%f"; std::string format = "%sFFF%dZZZ%f";
EXPECT_FALSE((ExtendedParsedFormat<Conv::s, Conv::d, Conv::g>::New(format))); EXPECT_FALSE((ExtendedParsedFormat<FormatConversionCharSet::s,
FormatConversionCharSet::d,
FormatConversionCharSet::g>::New(format)));
} }
TEST_F(ParsedFormatTest, RegressionMixPositional) { TEST_F(ParsedFormatTest, RegressionMixPositional) {
EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::o>::New("%1$d %o"))); EXPECT_FALSE(
(ExtendedParsedFormat<FormatConversionCharSet::d,
FormatConversionCharSet::o>::New("%1$d %o")));
} }
using FormatWrapperTest = ::testing::Test; using FormatWrapperTest = ::testing::Test;
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
// //
// Supported types: // Supported types:
// * absl::string_view, std::string, const char* (null is equivalent to "") // * absl::string_view, std::string, const char* (null is equivalent to "")
// * int32_t, int64_t, uint32_t, uint64 // * int32_t, int64_t, uint32_t, uint64_t
// * float, double // * float, double
// * bool (Printed as "true" or "false") // * bool (Printed as "true" or "false")
// * pointer types other than char* (Printed as "0x<lower case hex string>", // * pointer types other than char* (Printed as "0x<lower case hex string>",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment