Commit 4ccc0fce by Abseil Team Committed by Andy Getz

Export of internal Abseil changes

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

Release absl::StrFormat custom type extensions
 - Allows StrFormat methods to be extended to accept types which implement
   AbslFormatConvert()
 - NOLINTNEXTLINE(readability-redundant-declaration) used, declarations are
   required in some compilers.

PiperOrigin-RevId: 316963065

--
4d475b5ad02d41057447d722ad35573fc4f48d1f by Evan Brown <ezb@google.com>:

Small fix to previous change: the first overload of insert_iterator_unique wasn't actually being selected. Fix that issue and add tests to verify that it actually works.

Note: couldn't use TestInstanceTracker here because that counts instances (and decrements in destructor) rather than counting all constructor calls.
PiperOrigin-RevId: 316927690
GitOrigin-RevId: 34c0d521b11ed4191ea3e071a864a84e5e5941b7
Change-Id: If8bbb8317b93af4084ac4cc55b752b99b1581b58
parent 4a851046
...@@ -2416,6 +2416,41 @@ TEST(Btree, SetRangeConstructorAndInsertSupportExplicitConversionComparable) { ...@@ -2416,6 +2416,41 @@ TEST(Btree, SetRangeConstructorAndInsertSupportExplicitConversionComparable) {
EXPECT_THAT(name_set2, ElementsAreArray(names)); EXPECT_THAT(name_set2, ElementsAreArray(names));
} }
// A type that is explicitly convertible from int and counts constructor calls.
struct ConstructorCounted {
explicit ConstructorCounted(int i) : i(i) { ++constructor_calls; }
bool operator==(int other) const { return i == other; }
int i;
static int constructor_calls;
};
int ConstructorCounted::constructor_calls = 0;
struct ConstructorCountedCompare {
bool operator()(int a, const ConstructorCounted &b) const { return a < b.i; }
bool operator()(const ConstructorCounted &a, int b) const { return a.i < b; }
bool operator()(const ConstructorCounted &a,
const ConstructorCounted &b) const {
return a.i < b.i;
}
using is_transparent = void;
};
TEST(Btree,
SetRangeConstructorAndInsertExplicitConvComparableLimitConstruction) {
const int i[] = {0, 1, 1};
ConstructorCounted::constructor_calls = 0;
absl::btree_set<ConstructorCounted, ConstructorCountedCompare> set{
std::begin(i), std::end(i)};
EXPECT_THAT(set, ElementsAre(0, 1));
EXPECT_EQ(ConstructorCounted::constructor_calls, 2);
set.insert(std::begin(i), std::end(i));
EXPECT_THAT(set, ElementsAre(0, 1));
EXPECT_EQ(ConstructorCounted::constructor_calls, 2);
}
TEST(Btree, TEST(Btree,
SetRangeConstructorAndInsertSupportExplicitConversionNonComparable) { SetRangeConstructorAndInsertSupportExplicitConversionNonComparable) {
const int i[] = {0, 1}; const int i[] = {0, 1};
...@@ -2444,6 +2479,21 @@ TEST(Btree, MapRangeConstructorAndInsertSupportExplicitConversionComparable) { ...@@ -2444,6 +2479,21 @@ TEST(Btree, MapRangeConstructorAndInsertSupportExplicitConversionComparable) {
} }
TEST(Btree, TEST(Btree,
MapRangeConstructorAndInsertExplicitConvComparableLimitConstruction) {
const std::pair<int, int> i[] = {{0, 1}, {1, 2}, {1, 3}};
ConstructorCounted::constructor_calls = 0;
absl::btree_map<ConstructorCounted, int, ConstructorCountedCompare> map{
std::begin(i), std::end(i)};
EXPECT_THAT(map, ElementsAre(Pair(0, 1), Pair(1, 2)));
EXPECT_EQ(ConstructorCounted::constructor_calls, 2);
map.insert(std::begin(i), std::end(i));
EXPECT_THAT(map, ElementsAre(Pair(0, 1), Pair(1, 2)));
EXPECT_EQ(ConstructorCounted::constructor_calls, 2);
}
TEST(Btree,
MapRangeConstructorAndInsertSupportExplicitConversionNonComparable) { MapRangeConstructorAndInsertSupportExplicitConversionNonComparable) {
const std::pair<int, int> i[] = {{0, 1}, {1, 2}}; const std::pair<int, int> i[] = {{0, 1}, {1, 2}};
......
...@@ -1208,9 +1208,9 @@ class btree { ...@@ -1208,9 +1208,9 @@ class btree {
// Note: the first overload avoids constructing a value_type if the key // Note: the first overload avoids constructing a value_type if the key
// already exists in the btree. // already exists in the btree.
template <typename InputIterator, template <typename InputIterator,
typename = decltype( typename = decltype(std::declval<const key_compare &>()(
compare_keys(params_type::key(*std::declval<InputIterator>()), params_type::key(*std::declval<InputIterator>()),
std::declval<const key_type &>()))> std::declval<const key_type &>()))>
void insert_iterator_unique(InputIterator b, InputIterator e, int); void insert_iterator_unique(InputIterator b, InputIterator e, int);
// We need the second overload for cases in which we need to construct a // We need the second overload for cases in which we need to construct a
// value_type in order to compare it with the keys already in the btree. // value_type in order to compare it with the keys already in the btree.
......
...@@ -25,10 +25,12 @@ class Cord; ...@@ -25,10 +25,12 @@ class Cord;
class FormatCountCapture; class FormatCountCapture;
class FormatSink; class FormatSink;
namespace str_format_internal { template <absl::FormatConversionCharSet C>
struct FormatConvertResult;
class FormatConversionSpec; class FormatConversionSpec;
namespace str_format_internal {
template <typename T, typename = void> template <typename T, typename = void>
struct HasUserDefinedConvert : std::false_type {}; struct HasUserDefinedConvert : std::false_type {};
...@@ -39,6 +41,22 @@ struct HasUserDefinedConvert<T, void_t<decltype(AbslFormatConvert( ...@@ -39,6 +41,22 @@ struct HasUserDefinedConvert<T, void_t<decltype(AbslFormatConvert(
std::declval<FormatSink*>()))>> std::declval<FormatSink*>()))>>
: std::true_type {}; : 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> template <typename T>
class StreamedWrapper; class StreamedWrapper;
...@@ -46,6 +64,13 @@ class StreamedWrapper; ...@@ -46,6 +64,13 @@ class StreamedWrapper;
// then convert it, appending to `sink` and return `true`. // then convert it, appending to `sink` and return `true`.
// Otherwise fail and return `false`. // 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. // Raw pointers.
struct VoidPtr { struct VoidPtr {
VoidPtr() = default; VoidPtr() = default;
...@@ -62,6 +87,11 @@ struct ArgConvertResult { ...@@ -62,6 +87,11 @@ struct ArgConvertResult {
}; };
template <FormatConversionCharSet C> template <FormatConversionCharSet C>
constexpr FormatConversionCharSet ExtractCharSet(FormatConvertResult<C>) {
return C;
}
template <FormatConversionCharSet C>
constexpr FormatConversionCharSet ExtractCharSet(ArgConvertResult<C>) { constexpr FormatConversionCharSet ExtractCharSet(ArgConvertResult<C>) {
return C; return C;
} }
......
...@@ -23,8 +23,17 @@ class FormatArgImplTest : public ::testing::Test { ...@@ -23,8 +23,17 @@ class FormatArgImplTest : public ::testing::Test {
enum Color { kRed, kGreen, kBlue }; enum Color { kRed, kGreen, kBlue };
static const char *hi() { return "hi"; } static const char *hi() { return "hi"; }
struct X {};
X x_;
}; };
inline FormatConvertResult<FormatConversionCharSet{}> AbslFormatConvert(
const FormatArgImplTest::X &, const FormatConversionSpec &, FormatSink *) {
return {false};
}
TEST_F(FormatArgImplTest, ToInt) { TEST_F(FormatArgImplTest, ToInt) {
int out = 0; int out = 0;
EXPECT_TRUE(FormatArgImplFriend::ToInt(FormatArgImpl(1), &out)); EXPECT_TRUE(FormatArgImplFriend::ToInt(FormatArgImpl(1), &out));
...@@ -59,6 +68,7 @@ TEST_F(FormatArgImplTest, ToInt) { ...@@ -59,6 +68,7 @@ TEST_F(FormatArgImplTest, ToInt) {
FormatArgImpl(static_cast<int *>(nullptr)), &out)); FormatArgImpl(static_cast<int *>(nullptr)), &out));
EXPECT_FALSE(FormatArgImplFriend::ToInt(FormatArgImpl(hi()), &out)); EXPECT_FALSE(FormatArgImplFriend::ToInt(FormatArgImpl(hi()), &out));
EXPECT_FALSE(FormatArgImplFriend::ToInt(FormatArgImpl("hi"), &out)); EXPECT_FALSE(FormatArgImplFriend::ToInt(FormatArgImpl("hi"), &out));
EXPECT_FALSE(FormatArgImplFriend::ToInt(FormatArgImpl(x_), &out));
EXPECT_TRUE(FormatArgImplFriend::ToInt(FormatArgImpl(kBlue), &out)); EXPECT_TRUE(FormatArgImplFriend::ToInt(FormatArgImpl(kBlue), &out));
EXPECT_EQ(2, out); EXPECT_EQ(2, out);
} }
......
...@@ -33,6 +33,29 @@ std::string Flags::ToString() const { ...@@ -33,6 +33,29 @@ std::string Flags::ToString() const {
return s; return s;
} }
#define ABSL_INTERNAL_X_VAL(id) \
constexpr absl::FormatConversionChar FormatConversionCharInternal::id;
ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
#undef ABSL_INTERNAL_X_VAL
// NOLINTNEXTLINE(readability-redundant-declaration)
constexpr absl::FormatConversionChar FormatConversionCharInternal::kNone;
#define ABSL_INTERNAL_CHAR_SET_CASE(c) \
constexpr FormatConversionCharSet FormatConversionCharSetInternal::c;
ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
#undef ABSL_INTERNAL_CHAR_SET_CASE
// NOLINTNEXTLINE(readability-redundant-declaration)
constexpr FormatConversionCharSet FormatConversionCharSetInternal::kStar;
// NOLINTNEXTLINE(readability-redundant-declaration)
constexpr FormatConversionCharSet FormatConversionCharSetInternal::kIntegral;
// NOLINTNEXTLINE(readability-redundant-declaration)
constexpr FormatConversionCharSet FormatConversionCharSetInternal::kFloating;
// NOLINTNEXTLINE(readability-redundant-declaration)
constexpr FormatConversionCharSet FormatConversionCharSetInternal::kNumeric;
// NOLINTNEXTLINE(readability-redundant-declaration)
constexpr FormatConversionCharSet FormatConversionCharSetInternal::kPointer;
bool FormatSinkImpl::PutPaddedString(string_view value, int width, bool FormatSinkImpl::PutPaddedString(string_view value, int width,
int precision, bool left) { int precision, bool left) {
size_t space_remaining = 0; size_t space_remaining = 0;
......
...@@ -31,11 +31,11 @@ ...@@ -31,11 +31,11 @@
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
enum class FormatConversionChar : uint8_t; enum class FormatConversionChar : uint8_t;
enum class FormatConversionCharSet : uint64_t; enum class FormatConversionCharSet : uint64_t;
namespace str_format_internal {
class FormatRawSinkImpl { class FormatRawSinkImpl {
public: public:
// Implicitly convert from any type that provides the hook function as // Implicitly convert from any type that provides the hook function as
...@@ -361,14 +361,12 @@ struct FormatConversionCharSetInternal { ...@@ -361,14 +361,12 @@ struct FormatConversionCharSetInternal {
static constexpr FormatConversionCharSet kStar = static constexpr FormatConversionCharSet kStar =
FormatConversionCharToConvValue('*'); FormatConversionCharToConvValue('*');
// Some predefined values (TODO(matthewbr), delete any that are unused).
static constexpr FormatConversionCharSet kIntegral = static constexpr FormatConversionCharSet kIntegral =
FormatConversionCharSetUnion(d, i, u, o, x, X); FormatConversionCharSetUnion(d, i, u, o, x, X);
static constexpr FormatConversionCharSet kFloating = static constexpr FormatConversionCharSet kFloating =
FormatConversionCharSetUnion(a, e, f, g, A, E, F, G); FormatConversionCharSetUnion(a, e, f, g, A, E, F, G);
static constexpr FormatConversionCharSet kNumeric = static constexpr FormatConversionCharSet kNumeric =
FormatConversionCharSetUnion(kIntegral, kFloating); FormatConversionCharSetUnion(kIntegral, kFloating);
static constexpr FormatConversionCharSet kString = s;
static constexpr FormatConversionCharSet kPointer = p; static constexpr FormatConversionCharSet kPointer = p;
}; };
......
...@@ -80,4 +80,19 @@ TEST(FormatExtensionTest, SinkAppendChars) { ...@@ -80,4 +80,19 @@ TEST(FormatExtensionTest, SinkAppendChars) {
EXPECT_EQ(actual, expected); EXPECT_EQ(actual, expected);
} }
} }
TEST(FormatExtensionTest, VerifyEnumEquality) {
#define X_VAL(id) \
EXPECT_EQ(absl::FormatConversionChar::id, \
absl::str_format_internal::FormatConversionCharInternal::id);
ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(X_VAL, );
#undef X_VAL
#define X_VAL(id) \
EXPECT_EQ(absl::FormatConversionCharSet::id, \
absl::str_format_internal::FormatConversionCharSetInternal::id);
ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(X_VAL, );
#undef X_VAL
}
} // namespace } // namespace
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