Export of internal Abseil changes.
-- 5da9755667df37e38ccaf6938c9f408e294110bb by Shaindel Schwartz <shaindel@google.com>: Import of CCTZ from GitHub. PiperOrigin-RevId: 232942734 -- b6fb275769c66fdd2bd92b119198c59e9a7dd737 by Samuel Benzaquen <sbenza@google.com>: Fix integral underflow when from-arg width is INT_MIN. PiperOrigin-RevId: 232888037 -- 4135dbba4a26c4642277fc2a7e2a833d593daa1c by Abseil Team <absl-team@google.com>: Add the insert_return_type alias to raw_hash_set. PiperOrigin-RevId: 232683892 -- 0b120b7d3693800bbb886f6fc607ae54a9338cb1 by Abseil Team <absl-team@google.com>: Macros to detect and disabled SafeStack https://clang.llvm.org/docs/SafeStack.html PiperOrigin-RevId: 232680114 -- a77b3fb533a9e37966d1d6ef5ccd09c73fff2ca1 by Abseil Team <absl-team@google.com>: Avoid potential red zone clobber Pushing on the stack on x86-64 may clobber local variables held below %rsp in the red zone. Avoid this by using lea on x86-64. PiperOrigin-RevId: 232592478 -- bf326a0eefa92f4e704287563df0c5a5b1873b6d by Eric Fiselier <ericwf@google.com>: Add additional tests for AbslHashValue. PiperOrigin-RevId: 232344325 -- 816e4f98fd7632c944c779db87b7dac4e138afcf by Eric Fiselier <ericwf@google.com>: Avoid upcoming GCC 9.0 warnings about base class init. Currently, in trunk, GCC has a new warning under -Wextra that diagnoses when a derived class fails to explicitly initialize the base class in a constructor initializer list. This patch avoids this warning. PiperOrigin-RevId: 232327626 -- 779c0f44b3c2b7a04d4bdf978641eb8180515bf6 by Eric Fiselier <ericwf@google.com>: Guard against C++2a char8_t change. PiperOrigin-RevId: 232326178 -- 41e5395b85bbbfb5bf418cc21b04ad4ccb15a284 by Eric Fiselier <ericwf@google.com>: Avoid Clang Warning PiperOrigin-RevId: 232138866 GitOrigin-RevId: 5da9755667df37e38ccaf6938c9f408e294110bb Change-Id: I49ee4f58db177b81b039d7d949f671c97c5a7933
This commit is contained in:
parent
d78310fe5a
commit
2901ec32a9
18 changed files with 287 additions and 145 deletions
|
@ -287,6 +287,17 @@
|
|||
#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK
|
||||
//
|
||||
// Tells the SafeStack to not instrument a given function.
|
||||
// See https://clang.llvm.org/docs/SafeStack.html for details.
|
||||
#if defined(__GNUC__) && defined(SAFESTACK_SANITIZER)
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK \
|
||||
__attribute__((no_sanitize("safe-stack")))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_RETURNS_NONNULL
|
||||
//
|
||||
// Tells the compiler that a particular function never returns a null pointer.
|
||||
|
|
|
@ -542,6 +542,7 @@ cc_library(
|
|||
copts = ABSL_DEFAULT_COPTS,
|
||||
deps = [
|
||||
"//absl/meta:type_traits",
|
||||
"//absl/types:optional",
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -565,7 +566,6 @@ cc_library(
|
|||
"//absl/base:endian",
|
||||
"//absl/memory",
|
||||
"//absl/meta:type_traits",
|
||||
"//absl/types:optional",
|
||||
"//absl/utility",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -869,4 +869,21 @@ TEST(FixedArrayTest, AddressSanitizerAnnotations4) {
|
|||
}
|
||||
#endif // ADDRESS_SANITIZER
|
||||
|
||||
TEST(FixedArrayTest, AbslHashValueWorks) {
|
||||
using V = absl::FixedArray<int>;
|
||||
std::vector<V> cases;
|
||||
|
||||
// Generate a variety of vectors some of these are small enough for the inline
|
||||
// space but are stored out of line.
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
V v(i);
|
||||
for (int j = 0; j < i; ++j) {
|
||||
v[j] = j;
|
||||
}
|
||||
cases.push_back(v);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(cases));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -1762,4 +1762,23 @@ TEST(AllocatorSupportTest, SizeAllocConstructor) {
|
|||
}
|
||||
}
|
||||
|
||||
TEST(InlinedVectorTest, AbslHashValueWorks) {
|
||||
using V = absl::InlinedVector<int, 4>;
|
||||
std::vector<V> cases;
|
||||
|
||||
// Generate a variety of vectors some of these are small enough for the inline
|
||||
// space but are stored out of line.
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
V v;
|
||||
for (int j = 0; j < i; ++j) {
|
||||
v.push_back(j);
|
||||
}
|
||||
cases.push_back(v);
|
||||
v.resize(i % 4);
|
||||
cases.push_back(v);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(cases));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <type_traits>
|
||||
|
||||
#include "absl/meta/type_traits.h"
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
namespace absl {
|
||||
namespace container_internal {
|
||||
|
@ -42,7 +43,140 @@ struct KeyArg<false> {
|
|||
using type = key_type;
|
||||
};
|
||||
|
||||
// The node_handle concept from C++17.
|
||||
// We specialize node_handle for sets and maps. node_handle_base holds the
|
||||
// common API of both.
|
||||
template <typename PolicyTraits, typename Alloc>
|
||||
class node_handle_base {
|
||||
protected:
|
||||
using slot_type = typename PolicyTraits::slot_type;
|
||||
|
||||
public:
|
||||
using allocator_type = Alloc;
|
||||
|
||||
constexpr node_handle_base() {}
|
||||
node_handle_base(node_handle_base&& other) noexcept {
|
||||
*this = std::move(other);
|
||||
}
|
||||
~node_handle_base() { destroy(); }
|
||||
node_handle_base& operator=(node_handle_base&& other) noexcept {
|
||||
destroy();
|
||||
if (!other.empty()) {
|
||||
alloc_ = other.alloc_;
|
||||
PolicyTraits::transfer(alloc(), slot(), other.slot());
|
||||
other.reset();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool empty() const noexcept { return !alloc_; }
|
||||
explicit operator bool() const noexcept { return !empty(); }
|
||||
allocator_type get_allocator() const { return *alloc_; }
|
||||
|
||||
protected:
|
||||
friend struct CommonAccess;
|
||||
|
||||
node_handle_base(const allocator_type& a, slot_type* s) : alloc_(a) {
|
||||
PolicyTraits::transfer(alloc(), slot(), s);
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
if (!empty()) {
|
||||
PolicyTraits::destroy(alloc(), slot());
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
assert(alloc_.has_value());
|
||||
alloc_ = absl::nullopt;
|
||||
}
|
||||
|
||||
slot_type* slot() const {
|
||||
assert(!empty());
|
||||
return reinterpret_cast<slot_type*>(std::addressof(slot_space_));
|
||||
}
|
||||
allocator_type* alloc() { return std::addressof(*alloc_); }
|
||||
|
||||
private:
|
||||
absl::optional<allocator_type> alloc_;
|
||||
mutable absl::aligned_storage_t<sizeof(slot_type), alignof(slot_type)>
|
||||
slot_space_;
|
||||
};
|
||||
|
||||
// For sets.
|
||||
template <typename Policy, typename PolicyTraits, typename Alloc,
|
||||
typename = void>
|
||||
class node_handle : public node_handle_base<PolicyTraits, Alloc> {
|
||||
using Base = typename node_handle::node_handle_base;
|
||||
|
||||
public:
|
||||
using value_type = typename PolicyTraits::value_type;
|
||||
|
||||
constexpr node_handle() {}
|
||||
|
||||
value_type& value() const { return PolicyTraits::element(this->slot()); }
|
||||
|
||||
private:
|
||||
friend struct CommonAccess;
|
||||
|
||||
node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {}
|
||||
};
|
||||
|
||||
// For maps.
|
||||
template <typename Policy, typename PolicyTraits, typename Alloc>
|
||||
class node_handle<Policy, PolicyTraits, Alloc,
|
||||
absl::void_t<typename Policy::mapped_type>>
|
||||
: public node_handle_base<PolicyTraits, Alloc> {
|
||||
using Base = typename node_handle::node_handle_base;
|
||||
|
||||
public:
|
||||
using key_type = typename Policy::key_type;
|
||||
using mapped_type = typename Policy::mapped_type;
|
||||
|
||||
constexpr node_handle() {}
|
||||
|
||||
auto key() const -> decltype(PolicyTraits::key(this->slot())) {
|
||||
return PolicyTraits::key(this->slot());
|
||||
}
|
||||
|
||||
mapped_type& mapped() const {
|
||||
return PolicyTraits::value(&PolicyTraits::element(this->slot()));
|
||||
}
|
||||
|
||||
private:
|
||||
friend struct CommonAccess;
|
||||
|
||||
node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {}
|
||||
};
|
||||
|
||||
// Provide access to non-public node-handle functions.
|
||||
struct CommonAccess {
|
||||
template <typename Node>
|
||||
static auto GetSlot(const Node& node) -> decltype(node.slot()) {
|
||||
return node.slot();
|
||||
}
|
||||
|
||||
template <typename Node>
|
||||
static void Reset(Node* node) {
|
||||
node->reset();
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
static T Make(Args&&... args) {
|
||||
return T(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
// Implement the insert_return_type<> concept of C++17.
|
||||
template <class Iterator, class NodeType>
|
||||
struct InsertReturnType {
|
||||
Iterator position;
|
||||
bool inserted;
|
||||
NodeType node;
|
||||
};
|
||||
|
||||
} // namespace container_internal
|
||||
} // namespace absl
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_CONTAINER_INTERNAL_CONTAINER_H_
|
||||
|
|
|
@ -254,7 +254,7 @@ HashtablezInfo* SampleSlow(int64_t* next_sample) {
|
|||
}
|
||||
|
||||
#if ABSL_PER_THREAD_TLS == 1
|
||||
ABSL_PER_THREAD_TLS_KEYWORD int64_t next_sample = 0;
|
||||
ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample = 0;
|
||||
#endif // ABSL_PER_THREAD_TLS == 1
|
||||
|
||||
void UnsampleSlow(HashtablezInfo* info) {
|
||||
|
|
|
@ -146,23 +146,23 @@ class HashtablezInfoHandle {
|
|||
HashtablezInfo* info_;
|
||||
};
|
||||
|
||||
// Returns an RAII sampling handle that manages registration and unregistation
|
||||
// with the global sampler.
|
||||
#if ABSL_PER_THREAD_TLS == 1
|
||||
extern ABSL_PER_THREAD_TLS_KEYWORD int64_t next_sample;
|
||||
extern ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample;
|
||||
#endif // ABSL_PER_THREAD_TLS
|
||||
|
||||
// Returns an RAII sampling handle that manages registration and unregistation
|
||||
// with the global sampler.
|
||||
inline HashtablezInfoHandle Sample() {
|
||||
#if ABSL_PER_THREAD_TLS == 0
|
||||
static auto* mu = new absl::Mutex;
|
||||
static int64_t next_sample = 0;
|
||||
static int64_t global_next_sample = 0;
|
||||
absl::MutexLock l(mu);
|
||||
#endif // !ABSL_HAVE_THREAD_LOCAL
|
||||
|
||||
if (ABSL_PREDICT_TRUE(--next_sample > 0)) {
|
||||
if (ABSL_PREDICT_TRUE(--global_next_sample > 0)) {
|
||||
return HashtablezInfoHandle(nullptr);
|
||||
}
|
||||
return HashtablezInfoHandle(SampleSlow(&next_sample));
|
||||
return HashtablezInfoHandle(SampleSlow(&global_next_sample));
|
||||
}
|
||||
|
||||
// Holds samples and their associated stack traces with a soft limit of
|
||||
|
|
|
@ -115,7 +115,6 @@
|
|||
#include "absl/container/internal/layout.h"
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/meta/type_traits.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "absl/utility/utility.h"
|
||||
|
||||
namespace absl {
|
||||
|
@ -502,126 +501,6 @@ inline size_t GrowthToLowerboundCapacity(size_t growth) {
|
|||
return growth + static_cast<size_t>((static_cast<int64_t>(growth) - 1) / 7);
|
||||
}
|
||||
|
||||
// The node_handle concept from C++17.
|
||||
// We specialize node_handle for sets and maps. node_handle_base holds the
|
||||
// common API of both.
|
||||
template <typename Policy, typename Alloc>
|
||||
class node_handle_base {
|
||||
protected:
|
||||
using PolicyTraits = hash_policy_traits<Policy>;
|
||||
using slot_type = typename PolicyTraits::slot_type;
|
||||
|
||||
public:
|
||||
using allocator_type = Alloc;
|
||||
|
||||
constexpr node_handle_base() {}
|
||||
node_handle_base(node_handle_base&& other) noexcept {
|
||||
*this = std::move(other);
|
||||
}
|
||||
~node_handle_base() { destroy(); }
|
||||
node_handle_base& operator=(node_handle_base&& other) {
|
||||
destroy();
|
||||
if (!other.empty()) {
|
||||
alloc_ = other.alloc_;
|
||||
PolicyTraits::transfer(alloc(), slot(), other.slot());
|
||||
other.reset();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool empty() const noexcept { return !alloc_; }
|
||||
explicit operator bool() const noexcept { return !empty(); }
|
||||
allocator_type get_allocator() const { return *alloc_; }
|
||||
|
||||
protected:
|
||||
template <typename, typename, typename, typename>
|
||||
friend class raw_hash_set;
|
||||
|
||||
node_handle_base(const allocator_type& a, slot_type* s) : alloc_(a) {
|
||||
PolicyTraits::transfer(alloc(), slot(), s);
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
if (!empty()) {
|
||||
PolicyTraits::destroy(alloc(), slot());
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
assert(alloc_.has_value());
|
||||
alloc_ = absl::nullopt;
|
||||
}
|
||||
|
||||
slot_type* slot() const {
|
||||
assert(!empty());
|
||||
return reinterpret_cast<slot_type*>(std::addressof(slot_space_));
|
||||
}
|
||||
allocator_type* alloc() { return std::addressof(*alloc_); }
|
||||
|
||||
private:
|
||||
absl::optional<allocator_type> alloc_;
|
||||
mutable absl::aligned_storage_t<sizeof(slot_type), alignof(slot_type)>
|
||||
slot_space_;
|
||||
};
|
||||
|
||||
// For sets.
|
||||
template <typename Policy, typename Alloc, typename = void>
|
||||
class node_handle : public node_handle_base<Policy, Alloc> {
|
||||
using Base = typename node_handle::node_handle_base;
|
||||
|
||||
public:
|
||||
using value_type = typename Base::PolicyTraits::value_type;
|
||||
|
||||
constexpr node_handle() {}
|
||||
|
||||
value_type& value() const {
|
||||
return Base::PolicyTraits::element(this->slot());
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename, typename, typename, typename>
|
||||
friend class raw_hash_set;
|
||||
|
||||
node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {}
|
||||
};
|
||||
|
||||
// For maps.
|
||||
template <typename Policy, typename Alloc>
|
||||
class node_handle<Policy, Alloc, absl::void_t<typename Policy::mapped_type>>
|
||||
: public node_handle_base<Policy, Alloc> {
|
||||
using Base = typename node_handle::node_handle_base;
|
||||
|
||||
public:
|
||||
using key_type = typename Policy::key_type;
|
||||
using mapped_type = typename Policy::mapped_type;
|
||||
|
||||
constexpr node_handle() {}
|
||||
|
||||
auto key() const -> decltype(Base::PolicyTraits::key(this->slot())) {
|
||||
return Base::PolicyTraits::key(this->slot());
|
||||
}
|
||||
|
||||
mapped_type& mapped() const {
|
||||
return Base::PolicyTraits::value(
|
||||
&Base::PolicyTraits::element(this->slot()));
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename, typename, typename, typename>
|
||||
friend class raw_hash_set;
|
||||
|
||||
node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {}
|
||||
};
|
||||
|
||||
// Implement the insert_return_type<> concept of C++17.
|
||||
template <class Iterator, class NodeType>
|
||||
struct insert_return_type {
|
||||
Iterator position;
|
||||
bool inserted;
|
||||
NodeType node;
|
||||
};
|
||||
|
||||
// Policy: a policy defines how to perform different operations on
|
||||
// the slots of the hashtable (see hash_policy_traits.h for the full interface
|
||||
// of policy).
|
||||
|
@ -828,7 +707,8 @@ class raw_hash_set {
|
|||
iterator inner_;
|
||||
};
|
||||
|
||||
using node_type = container_internal::node_handle<Policy, Alloc>;
|
||||
using node_type = node_handle<Policy, hash_policy_traits<Policy>, Alloc>;
|
||||
using insert_return_type = InsertReturnType<iterator, node_type>;
|
||||
|
||||
raw_hash_set() noexcept(
|
||||
std::is_nothrow_default_constructible<hasher>::value&&
|
||||
|
@ -1136,13 +1016,14 @@ class raw_hash_set {
|
|||
insert(ilist.begin(), ilist.end());
|
||||
}
|
||||
|
||||
insert_return_type<iterator, node_type> insert(node_type&& node) {
|
||||
insert_return_type insert(node_type&& node) {
|
||||
if (!node) return {end(), false, node_type()};
|
||||
const auto& elem = PolicyTraits::element(node.slot());
|
||||
const auto& elem = PolicyTraits::element(CommonAccess::GetSlot(node));
|
||||
auto res = PolicyTraits::apply(
|
||||
InsertSlot<false>{*this, std::move(*node.slot())}, elem);
|
||||
InsertSlot<false>{*this, std::move(*CommonAccess::GetSlot(node))},
|
||||
elem);
|
||||
if (res.second) {
|
||||
node.reset();
|
||||
CommonAccess::Reset(&node);
|
||||
return {res.first, true, node_type()};
|
||||
} else {
|
||||
return {res.first, false, std::move(node)};
|
||||
|
@ -1306,7 +1187,8 @@ class raw_hash_set {
|
|||
}
|
||||
|
||||
node_type extract(const_iterator position) {
|
||||
node_type node(alloc_ref(), position.inner_.slot_);
|
||||
auto node =
|
||||
CommonAccess::Make<node_type>(alloc_ref(), position.inner_.slot_);
|
||||
erase_meta_only(position);
|
||||
return node;
|
||||
}
|
||||
|
|
|
@ -1706,7 +1706,7 @@ TEST(Nodes, ExtractInsert) {
|
|||
EXPECT_FALSE(node.empty());
|
||||
|
||||
StringTable t2;
|
||||
auto res = t2.insert(std::move(node));
|
||||
StringTable::insert_return_type res = t2.insert(std::move(node));
|
||||
EXPECT_TRUE(res.inserted);
|
||||
EXPECT_THAT(*res.position, Pair(k0, ""));
|
||||
EXPECT_FALSE(res.node);
|
||||
|
|
|
@ -392,16 +392,20 @@ TEST(Symbolize, ForEachSection) {
|
|||
extern "C" {
|
||||
inline void *ABSL_ATTRIBUTE_ALWAYS_INLINE inline_func() {
|
||||
void *pc = nullptr;
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
__asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
|
||||
#if defined(__i386__)
|
||||
__asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [ PC ] "=r"(pc));
|
||||
#elif defined(__x86_64__)
|
||||
__asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [ PC ] "=r"(pc));
|
||||
#endif
|
||||
return pc;
|
||||
}
|
||||
|
||||
void *ABSL_ATTRIBUTE_NOINLINE non_inline_func() {
|
||||
void *pc = nullptr;
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
__asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
|
||||
#if defined(__i386__)
|
||||
__asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [ PC ] "=r"(pc));
|
||||
#elif defined(__x86_64__)
|
||||
__asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [ PC ] "=r"(pc));
|
||||
#endif
|
||||
return pc;
|
||||
}
|
||||
|
|
|
@ -440,4 +440,29 @@ TEST(Uint128, NumericLimitsTest) {
|
|||
EXPECT_EQ(absl::Uint128Max(), std::numeric_limits<absl::uint128>::max());
|
||||
}
|
||||
|
||||
TEST(Uint128, Hash) {
|
||||
EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({
|
||||
// Some simple values
|
||||
absl::uint128{0},
|
||||
absl::uint128{1},
|
||||
~absl::uint128{},
|
||||
// 64 bit limits
|
||||
absl::uint128{std::numeric_limits<int64_t>::max()},
|
||||
absl::uint128{std::numeric_limits<uint64_t>::max()} + 0,
|
||||
absl::uint128{std::numeric_limits<uint64_t>::max()} + 1,
|
||||
absl::uint128{std::numeric_limits<uint64_t>::max()} + 2,
|
||||
// Keeping high same
|
||||
absl::uint128{1} << 62,
|
||||
absl::uint128{1} << 63,
|
||||
// Keeping low same
|
||||
absl::uint128{1} << 64,
|
||||
absl::uint128{1} << 65,
|
||||
// 128 bit limits
|
||||
std::numeric_limits<absl::uint128>::max(),
|
||||
std::numeric_limits<absl::uint128>::max() - 1,
|
||||
std::numeric_limits<absl::uint128>::min() + 1,
|
||||
std::numeric_limits<absl::uint128>::min(),
|
||||
}));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -53,7 +53,8 @@ inline bool ArgContext::Bind(const UnboundConversion* unbound,
|
|||
// "A negative field width is taken as a '-' flag followed by a
|
||||
// positive field width."
|
||||
force_left = true;
|
||||
width = -width;
|
||||
// Make sure we don't overflow the width when negating it.
|
||||
width = -std::max(width, -std::numeric_limits<int>::max());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "absl/strings/internal/str_format/bind.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <limits>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
|
@ -91,6 +92,20 @@ TEST_F(FormatBindTest, BindSingle) {
|
|||
}
|
||||
}
|
||||
|
||||
TEST_F(FormatBindTest, WidthUnderflowRegression) {
|
||||
UnboundConversion props;
|
||||
BoundConversion bound;
|
||||
int next = 0;
|
||||
const int args_i[] = {std::numeric_limits<int>::min(), 17};
|
||||
const FormatArgImpl args[] = {FormatArgImpl(args_i[0]),
|
||||
FormatArgImpl(args_i[1])};
|
||||
ASSERT_TRUE(Extract("*d", &props, &next));
|
||||
ASSERT_TRUE(BindWithPack(&props, args, &bound));
|
||||
|
||||
EXPECT_EQ(bound.width(), std::numeric_limits<int>::max());
|
||||
EXPECT_EQ(bound.arg(), args + 1);
|
||||
}
|
||||
|
||||
TEST_F(FormatBindTest, FormatPack) {
|
||||
struct Expectation {
|
||||
int line;
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
|
||||
namespace {
|
||||
|
||||
#if !defined(__cpp_char8_t)
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wc++2a-compat"
|
||||
#endif
|
||||
TEST(EncodeUTF8Char, BasicFunction) {
|
||||
std::pair<char32_t, std::string> tests[] = {{0x0030, u8"\u0030"},
|
||||
{0x00A3, u8"\u00A3"},
|
||||
|
@ -53,5 +58,9 @@ TEST(EncodeUTF8Char, BasicFunction) {
|
|||
EXPECT_LE(absl::strings_internal::EncodeUTF8Char(buf2, -1),
|
||||
absl::strings_internal::kMaxEncodedUTF8Size);
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
#endif // !defined(__cpp_char8_t)
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -647,6 +647,11 @@ TEST(Split, StringDelimiter) {
|
|||
}
|
||||
}
|
||||
|
||||
#if !defined(__cpp_char8_t)
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wc++2a-compat"
|
||||
#endif
|
||||
TEST(Split, UTF8) {
|
||||
// Tests splitting utf8 strings and utf8 delimiters.
|
||||
std::string utf8_string = u8"\u03BA\u1F79\u03C3\u03BC\u03B5";
|
||||
|
@ -673,6 +678,10 @@ TEST(Split, UTF8) {
|
|||
EXPECT_THAT(v, ElementsAre("Foo", u8"h\u00E4llo", u8"th\u4E1Ere"));
|
||||
}
|
||||
}
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
#endif // !defined(__cpp_char8_t)
|
||||
|
||||
TEST(Split, EmptyStringDelimiter) {
|
||||
{
|
||||
|
|
|
@ -54,7 +54,7 @@ ZoneInfoSourceFactory default_factory = DefaultFactory;
|
|||
#pragma comment( \
|
||||
linker, \
|
||||
"/alternatename:?zone_info_source_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZA=?default_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZA")
|
||||
#elif defined(_M_IA_64) || defined(_M_AMD64)
|
||||
#elif defined(_M_IA_64) || defined(_M_AMD64) || defined(_M_ARM64)
|
||||
#pragma comment( \
|
||||
linker, \
|
||||
"/alternatename:?zone_info_source_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZEA=?default_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZEA")
|
||||
|
|
|
@ -295,7 +295,7 @@ class optional_data<T, false> : public optional_data_base<T> {
|
|||
|
||||
optional_data() = default;
|
||||
|
||||
optional_data(const optional_data& rhs) {
|
||||
optional_data(const optional_data& rhs) : optional_data_base<T>() {
|
||||
if (rhs.engaged_) {
|
||||
this->construct(rhs.data_);
|
||||
}
|
||||
|
@ -303,7 +303,8 @@ class optional_data<T, false> : public optional_data_base<T> {
|
|||
|
||||
optional_data(optional_data&& rhs) noexcept(
|
||||
absl::default_allocator_is_nothrow::value ||
|
||||
std::is_nothrow_move_constructible<T>::value) {
|
||||
std::is_nothrow_move_constructible<T>::value)
|
||||
: optional_data_base<T>() {
|
||||
if (rhs.engaged_) {
|
||||
this->construct(std::move(rhs.data_));
|
||||
}
|
||||
|
|
|
@ -779,4 +779,19 @@ TEST(Span, SpanSize) {
|
|||
EXPECT_LE(sizeof(absl::Span<BigStruct>), 2 * sizeof(void*));
|
||||
}
|
||||
|
||||
TEST(Span, Hash) {
|
||||
int array[] = {1, 2, 3, 4};
|
||||
int array2[] = {1, 2, 3};
|
||||
using T = absl::Span<const int>;
|
||||
EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
|
||||
{// Empties
|
||||
T(), T(nullptr, 0), T(array, 0), T(array2, 0),
|
||||
// Different array with same value
|
||||
T(array, 3), T(array2), T({1, 2, 3}),
|
||||
// Same array, but different length
|
||||
T(array, 1), T(array, 2),
|
||||
// Same length, but different array
|
||||
T(array + 1, 2), T(array + 2, 2)}));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
Loading…
Reference in a new issue