From 02f0ab209314000bc1c8fdff0d60378995316f9c Mon Sep 17 00:00:00 2001 From: Randolf J <34705014+jun-sheaf@users.noreply.github.com> Date: Fri, 7 Oct 2022 13:02:41 +0200 Subject: [PATCH 0001/1238] Update charconv.cc --- absl/strings/charconv.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/absl/strings/charconv.cc b/absl/strings/charconv.cc index c08623c477e..25ac44996e3 100644 --- a/absl/strings/charconv.cc +++ b/absl/strings/charconv.cc @@ -347,7 +347,8 @@ bool HandleEdgeCase(const strings_internal::ParsedFloat& input, bool negative, // https://bugs.llvm.org/show_bug.cgi?id=37778 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86113 constexpr ptrdiff_t kNanBufferSize = 128; -#if defined(__GNUC__) || (defined(__clang__) && __clang_major__ < 7) +#if (defined(__GNUC__) && !defined(__clang__)) || \ + (defined(__clang__) && __clang_major__ < 7) volatile char n_char_sequence[kNanBufferSize]; #else char n_char_sequence[kNanBufferSize]; From 7e22b3022ea5ec584298135811e119b3e65789bc Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 8 May 2023 01:41:38 -0700 Subject: [PATCH 0002/1238] Nop change. PiperOrigin-RevId: 530238518 Change-Id: I2bfca582c0734f7e6943c5359730a2857809e2d2 --- absl/synchronization/internal/futex_waiter.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/absl/synchronization/internal/futex_waiter.cc b/absl/synchronization/internal/futex_waiter.cc index 7c07fbe2a35..87eb3b23cd2 100644 --- a/absl/synchronization/internal/futex_waiter.cc +++ b/absl/synchronization/internal/futex_waiter.cc @@ -63,7 +63,6 @@ bool FutexWaiter::Wait(KernelTimeout t) { // Note that, since the thread ticker is just reset, we don't need to check // whether the thread is idle on the very first pass of the loop. bool first_pass = true; - while (true) { int32_t x = futex_.load(std::memory_order_relaxed); while (x != 0) { From 2662ae4a293b8bb866eba4567323e0a4d34eb2f0 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 8 May 2023 08:24:37 -0700 Subject: [PATCH 0003/1238] Add missing dependency on dynamic_annotations to stacktrace, which is needed in some of the builds. PiperOrigin-RevId: 530308301 Change-Id: I7c885156e14d9c8c444c7c6f8d38e7aaac7c01a7 --- absl/debugging/BUILD.bazel | 1 + absl/debugging/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel index 86063da2964..e89dbae8071 100644 --- a/absl/debugging/BUILD.bazel +++ b/absl/debugging/BUILD.bazel @@ -49,6 +49,7 @@ cc_library( ":debugging_internal", "//absl/base:config", "//absl/base:core_headers", + "//absl/base:dynamic_annotations", "//absl/base:raw_logging_internal", ], ) diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt index 8f29cc07f40..ef6b49659fc 100644 --- a/absl/debugging/CMakeLists.txt +++ b/absl/debugging/CMakeLists.txt @@ -41,6 +41,7 @@ absl_cc_library( absl::debugging_internal absl::config absl::core_headers + absl::dynamic_annotations absl::raw_logging_internal PUBLIC ) From 4aa4f33125e19dc9f118c1ac334c7714d2be2252 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Mon, 8 May 2023 10:53:05 -0700 Subject: [PATCH 0004/1238] For Bazel builds, mark some of the low-level tests that are dependent on timing as flaky. This will run them up to 3 times (in the default configuration) and only consider the test failed if it fails each time. PiperOrigin-RevId: 530348477 Change-Id: Ib77bd8a166828b82a1b49ee5ef2e8321752e51d0 --- absl/synchronization/BUILD.bazel | 2 ++ 1 file changed, 2 insertions(+) diff --git a/absl/synchronization/BUILD.bazel b/absl/synchronization/BUILD.bazel index a0cd433d75a..5074044e853 100644 --- a/absl/synchronization/BUILD.bazel +++ b/absl/synchronization/BUILD.bazel @@ -238,6 +238,7 @@ cc_test( size = "large", srcs = ["mutex_test.cc"], copts = ABSL_TEST_COPTS, + flaky = 1, linkopts = ABSL_DEFAULT_LINKOPTS, shard_count = 25, deps = [ @@ -300,6 +301,7 @@ cc_test( size = "small", srcs = ["notification_test.cc"], copts = ABSL_TEST_COPTS, + flaky = 1, linkopts = ABSL_DEFAULT_LINKOPTS, tags = ["no_test_lexan"], deps = [ From 41aecd0270bb711c9b9f462c6729c5ddfa97b707 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 8 May 2023 16:58:10 -0700 Subject: [PATCH 0005/1238] Add semicolon at the end of the line on code example PiperOrigin-RevId: 530445615 Change-Id: I0c112773e7f42989840cb8b915167ade8833ef73 --- absl/status/statusor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/absl/status/statusor.h b/absl/status/statusor.h index f19322387ae..935366d5561 100644 --- a/absl/status/statusor.h +++ b/absl/status/statusor.h @@ -146,7 +146,7 @@ class ABSL_MUST_USE_RESULT StatusOr; // // absl::StatusOr i = GetCount(); // if (i.ok()) { -// updated_total += *i +// updated_total += *i; // } // // NOTE: using `absl::StatusOr::value()` when no valid value is present will From b19ec98accca194511616f789c0a448c2b9d40e7 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Tue, 9 May 2023 06:50:05 -0700 Subject: [PATCH 0006/1238] Stop moving an absl::FunctionRef, since the class isn't movable, it will just be a copy anyway. Also remove the typedef so that it is clear from the type at the callsite that moving it isn't necessary. Fixes #1443 PiperOrigin-RevId: 530596294 Change-Id: I58ffc370bbccc0816bca4c4f85c3bb12c7ee2eb2 --- absl/strings/internal/cord_rep_consume.cc | 8 +++++--- absl/strings/internal/cord_rep_consume.h | 11 ++++------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/absl/strings/internal/cord_rep_consume.cc b/absl/strings/internal/cord_rep_consume.cc index 20a55797673..db7d4fefc4b 100644 --- a/absl/strings/internal/cord_rep_consume.cc +++ b/absl/strings/internal/cord_rep_consume.cc @@ -42,7 +42,8 @@ CordRep* ClipSubstring(CordRepSubstring* substring) { } // namespace -void Consume(CordRep* rep, ConsumeFn consume_fn) { +void Consume(CordRep* rep, + FunctionRef consume_fn) { size_t offset = 0; size_t length = rep->length; @@ -53,8 +54,9 @@ void Consume(CordRep* rep, ConsumeFn consume_fn) { consume_fn(rep, offset, length); } -void ReverseConsume(CordRep* rep, ConsumeFn consume_fn) { - return Consume(rep, std::move(consume_fn)); +void ReverseConsume(CordRep* rep, + FunctionRef consume_fn) { + return Consume(rep, consume_fn); } } // namespace cord_internal diff --git a/absl/strings/internal/cord_rep_consume.h b/absl/strings/internal/cord_rep_consume.h index d46fca2b217..bece1874ac4 100644 --- a/absl/strings/internal/cord_rep_consume.h +++ b/absl/strings/internal/cord_rep_consume.h @@ -24,11 +24,6 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { -// Functor for the Consume() and ReverseConsume() functions: -// void ConsumeFunc(CordRep* rep, size_t offset, size_t length); -// See the Consume() and ReverseConsume() function comments for documentation. -using ConsumeFn = FunctionRef; - // Consume() and ReverseConsume() consume CONCAT based trees and invoke the // provided functor with the contained nodes in the proper forward or reverse // order, which is used to convert CONCAT trees into other tree or cord data. @@ -40,8 +35,10 @@ using ConsumeFn = FunctionRef; // violations, we can not 100% guarantee that all code respects 'new format' // settings and flags, so we need to be able to parse old data on the fly until // all old code is deprecated / no longer the default format. -void Consume(CordRep* rep, ConsumeFn consume_fn); -void ReverseConsume(CordRep* rep, ConsumeFn consume_fn); +void Consume(CordRep* rep, + FunctionRef consume_fn); +void ReverseConsume(CordRep* rep, + FunctionRef consume_fn); } // namespace cord_internal ABSL_NAMESPACE_END From 67f9650c93a4fa04728a5b754ae8297d2c55d898 Mon Sep 17 00:00:00 2001 From: Laramie Leavitt Date: Wed, 10 May 2023 14:01:54 -0700 Subject: [PATCH 0007/1238] YuleSimon/SkewedLow: Cleanup/move benchmarks and overload tests. PiperOrigin-RevId: 530999471 Change-Id: Ifca68cd53be629088244eaa3560d43fd81090747 --- absl/random/benchmarks.cc | 2 +- absl/random/generators_test.cc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/absl/random/benchmarks.cc b/absl/random/benchmarks.cc index 87bbb9810a7..0900e81839f 100644 --- a/absl/random/benchmarks.cc +++ b/absl/random/benchmarks.cc @@ -62,7 +62,7 @@ class PrecompiledSeedSeq { public: using result_type = uint32_t; - PrecompiledSeedSeq() {} + PrecompiledSeedSeq() = default; template PrecompiledSeedSeq(Iterator begin, Iterator end) {} diff --git a/absl/random/generators_test.cc b/absl/random/generators_test.cc index c36756749de..20091309b95 100644 --- a/absl/random/generators_test.cc +++ b/absl/random/generators_test.cc @@ -117,6 +117,7 @@ void TestBernoulli(URBG* gen) { absl::Bernoulli(*gen, 0.5); } + template void TestZipf(URBG* gen) { absl::Zipf(*gen, 100); From 2526926b9275076b03159e7e0a9f1f32b9ed8d09 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 11 May 2023 14:04:11 -0700 Subject: [PATCH 0008/1238] Remove ABSL_HARDENING_ASSERT in AnyInvocable to avoid performance impact in optimized builds PiperOrigin-RevId: 531301442 Change-Id: Ib5a67f827bf89a66a0a8d24d3191f278566af6c8 --- absl/functional/any_invocable_test.cc | 2 +- absl/functional/internal/any_invocable.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/absl/functional/any_invocable_test.cc b/absl/functional/any_invocable_test.cc index 10a4dee5027..a740faa60da 100644 --- a/absl/functional/any_invocable_test.cc +++ b/absl/functional/any_invocable_test.cc @@ -1418,7 +1418,7 @@ TYPED_TEST_P(AnyInvTestRvalue, NonConstCrashesOnSecondCall) { // Ensure we're still valid EXPECT_TRUE(static_cast(fun)); // NOLINT(bugprone-use-after-move) -#if !defined(NDEBUG) || ABSL_OPTION_HARDENED == 1 +#if !defined(NDEBUG) EXPECT_DEATH_IF_SUPPORTED(std::move(fun)(7, 8, 9), ""); #endif } diff --git a/absl/functional/internal/any_invocable.h b/absl/functional/internal/any_invocable.h index b6a38e37b35..d41b7e56ec2 100644 --- a/absl/functional/internal/any_invocable.h +++ b/absl/functional/internal/any_invocable.h @@ -824,7 +824,7 @@ using CanAssignReferenceWrapper = TrueAlias< auto* invoker = this->invoker_; \ if (!std::is_const::value && \ std::is_rvalue_reference::value) { \ - ABSL_HARDENING_ASSERT([this]() { \ + ABSL_ASSERT([this]() { \ /* We checked that this isn't const above, so const_cast is safe */ \ const_cast(this)->invoker_ = InvokedAfterMove; \ return this->HasValue(); \ From 3aa3377ef66e6388ed19fd7c862bf0dc3a3630e0 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Fri, 12 May 2023 08:45:48 -0700 Subject: [PATCH 0009/1238] Fixed Windows DLL builds of test targets This is a heavily modified version of https://github.com/abseil/abseil-cpp/pull/1445, which adds some missing test libraries to the test DLL. Unlike #1445, this change moves several global variables out of headers that did not need to be in headers. For instance, cord_btree_exhaustive_validation was a global defined/declared in cord_internal, but only used in cord_rep_btree and its test. cordz_handle defined a queue in its header even though it wasn't needed, which also led to ODR problems. The Spinlock used in CordzHandle is replaced with a Mutex. This was originally a Mutex, but Chromium asked us to change it to a Spinlock to avoid a static initializer. After this change, the static initializer is no longer an issue. #1407 PiperOrigin-RevId: 531516991 Change-Id: I0e431a193698b20ba03fac6e414c26f153f330a7 --- CMake/AbseilDll.cmake | 4 ++ CMake/AbseilHelpers.cmake | 4 ++ absl/strings/internal/cord_internal.cc | 1 - absl/strings/internal/cord_internal.h | 6 -- absl/strings/internal/cord_rep_btree.cc | 17 +++-- absl/strings/internal/cord_rep_btree.h | 8 +++ absl/strings/internal/cord_rep_btree_test.cc | 8 +-- absl/strings/internal/cordz_handle.cc | 66 ++++++++++++++------ absl/strings/internal/cordz_handle.h | 33 ---------- 9 files changed, 79 insertions(+), 68 deletions(-) diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index 32b51411abc..aa73ae5135c 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake @@ -589,6 +589,10 @@ set(ABSL_INTERNAL_TEST_DLL_FILES "hash/hash_testing.h" "log/scoped_mock_log.cc" "log/scoped_mock_log.h" + "random/internal/chi_square.cc" + "random/internal/chi_square.h" + "random/internal/distribution_test_util.cc" + "random/internal/distribution_test_util.h" "random/internal/mock_helpers.h" "random/internal/mock_overload_set.h" "random/mocking_bit_gen.h" diff --git a/CMake/AbseilHelpers.cmake b/CMake/AbseilHelpers.cmake index f1b3158ca58..de63531b7f7 100644 --- a/CMake/AbseilHelpers.cmake +++ b/CMake/AbseilHelpers.cmake @@ -413,6 +413,10 @@ function(absl_cc_test) DEPS ${ABSL_CC_TEST_DEPS} OUTPUT ABSL_CC_TEST_DEPS ) + absl_internal_dll_targets( + DEPS ${ABSL_CC_TEST_LINKOPTS} + OUTPUT ABSL_CC_TEST_LINKOPTS + ) else() target_compile_definitions(${_NAME} PUBLIC diff --git a/absl/strings/internal/cord_internal.cc b/absl/strings/internal/cord_internal.cc index b6b06cfa2a3..b7874385de0 100644 --- a/absl/strings/internal/cord_internal.cc +++ b/absl/strings/internal/cord_internal.cc @@ -33,7 +33,6 @@ ABSL_CONST_INIT std::atomic cord_ring_buffer_enabled( kCordEnableRingBufferDefault); ABSL_CONST_INIT std::atomic shallow_subcords_enabled( kCordShallowSubcordsDefault); -ABSL_CONST_INIT std::atomic cord_btree_exhaustive_validation(false); void LogFatalNodeType(CordRep* rep) { ABSL_INTERNAL_LOG(FATAL, absl::StrCat("Unexpected node type: ", diff --git a/absl/strings/internal/cord_internal.h b/absl/strings/internal/cord_internal.h index e6f0d544b6f..8d9836ba8b8 100644 --- a/absl/strings/internal/cord_internal.h +++ b/absl/strings/internal/cord_internal.h @@ -69,12 +69,6 @@ enum CordFeatureDefaults { extern std::atomic cord_ring_buffer_enabled; extern std::atomic shallow_subcords_enabled; -// `cord_btree_exhaustive_validation` can be set to force exhaustive validation -// in debug assertions, and code that calls `IsValid()` explicitly. By default, -// assertions should be relatively cheap and AssertValid() can easily lead to -// O(n^2) complexity as recursive / full tree validation is O(n). -extern std::atomic cord_btree_exhaustive_validation; - inline void enable_cord_ring_buffer(bool enable) { cord_ring_buffer_enabled.store(enable, std::memory_order_relaxed); } diff --git a/absl/strings/internal/cord_rep_btree.cc b/absl/strings/internal/cord_rep_btree.cc index a86fdc0b4e9..05bd0e20675 100644 --- a/absl/strings/internal/cord_rep_btree.cc +++ b/absl/strings/internal/cord_rep_btree.cc @@ -14,6 +14,7 @@ #include "absl/strings/internal/cord_rep_btree.h" +#include #include #include #include @@ -49,9 +50,7 @@ using CopyResult = CordRepBtree::CopyResult; constexpr auto kFront = CordRepBtree::kFront; constexpr auto kBack = CordRepBtree::kBack; -inline bool exhaustive_validation() { - return cord_btree_exhaustive_validation.load(std::memory_order_relaxed); -} +ABSL_CONST_INIT std::atomic cord_btree_exhaustive_validation(false); // Implementation of the various 'Dump' functions. // Prints the entire tree structure or 'rep'. External callers should @@ -362,6 +361,15 @@ struct StackOperations { } // namespace +void SetCordBtreeExhaustiveValidation(bool do_exaustive_validation) { + cord_btree_exhaustive_validation.store(do_exaustive_validation, + std::memory_order_relaxed); +} + +bool IsCordBtreeExhaustiveValidationEnabled() { + return cord_btree_exhaustive_validation.load(std::memory_order_relaxed); +} + void CordRepBtree::Dump(const CordRep* rep, absl::string_view label, bool include_contents, std::ostream& stream) { stream << "===================================\n"; @@ -450,7 +458,8 @@ bool CordRepBtree::IsValid(const CordRepBtree* tree, bool shallow) { child_length += edge->length; } NODE_CHECK_EQ(child_length, tree->length); - if ((!shallow || exhaustive_validation()) && tree->height() > 0) { + if ((!shallow || IsCordBtreeExhaustiveValidationEnabled()) && + tree->height() > 0) { for (CordRep* edge : tree->Edges()) { if (!IsValid(edge->btree(), shallow)) return false; } diff --git a/absl/strings/internal/cord_rep_btree.h b/absl/strings/internal/cord_rep_btree.h index 4209e51256b..be94b62ec8e 100644 --- a/absl/strings/internal/cord_rep_btree.h +++ b/absl/strings/internal/cord_rep_btree.h @@ -32,6 +32,14 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { +// `SetCordBtreeExhaustiveValidation()` can be set to force exhaustive +// validation in debug assertions, and code that calls `IsValid()` +// explicitly. By default, assertions should be relatively cheap and +// AssertValid() can easily lead to O(n^2) complexity as recursive / full tree +// validation is O(n). +void SetCordBtreeExhaustiveValidation(bool do_exaustive_validation); +bool IsCordBtreeExhaustiveValidationEnabled(); + class CordRepBtreeNavigator; // CordRepBtree is as the name implies a btree implementation of a Cordrep tree. diff --git a/absl/strings/internal/cord_rep_btree_test.cc b/absl/strings/internal/cord_rep_btree_test.cc index 82aeca37cb1..840acf9f520 100644 --- a/absl/strings/internal/cord_rep_btree_test.cc +++ b/absl/strings/internal/cord_rep_btree_test.cc @@ -1355,9 +1355,9 @@ TEST(CordRepBtreeTest, AssertValid) { TEST(CordRepBtreeTest, CheckAssertValidShallowVsDeep) { // Restore exhaustive validation on any exit. - const bool exhaustive_validation = cord_btree_exhaustive_validation.load(); + const bool exhaustive_validation = IsCordBtreeExhaustiveValidationEnabled(); auto cleanup = absl::MakeCleanup([exhaustive_validation] { - cord_btree_exhaustive_validation.store(exhaustive_validation); + SetCordBtreeExhaustiveValidation(exhaustive_validation); }); // Create a tree of at least 2 levels, and mess with the original flat, which @@ -1372,7 +1372,7 @@ TEST(CordRepBtreeTest, CheckAssertValidShallowVsDeep) { } flat->length = 100; - cord_btree_exhaustive_validation.store(false); + SetCordBtreeExhaustiveValidation(false); EXPECT_FALSE(CordRepBtree::IsValid(tree)); EXPECT_TRUE(CordRepBtree::IsValid(tree, true)); EXPECT_FALSE(CordRepBtree::IsValid(tree, false)); @@ -1382,7 +1382,7 @@ TEST(CordRepBtreeTest, CheckAssertValidShallowVsDeep) { EXPECT_DEBUG_DEATH(CordRepBtree::AssertValid(tree, false), ".*"); #endif - cord_btree_exhaustive_validation.store(true); + SetCordBtreeExhaustiveValidation(true); EXPECT_FALSE(CordRepBtree::IsValid(tree)); EXPECT_FALSE(CordRepBtree::IsValid(tree, true)); EXPECT_FALSE(CordRepBtree::IsValid(tree, false)); diff --git a/absl/strings/internal/cordz_handle.cc b/absl/strings/internal/cordz_handle.cc index a73fefed591..a7061dbe225 100644 --- a/absl/strings/internal/cordz_handle.cc +++ b/absl/strings/internal/cordz_handle.cc @@ -16,34 +16,60 @@ #include #include "absl/base/internal/raw_logging.h" // For ABSL_RAW_CHECK -#include "absl/base/internal/spinlock.h" +#include "absl/synchronization/mutex.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { -using ::absl::base_internal::SpinLockHolder; +namespace { -ABSL_CONST_INIT CordzHandle::Queue CordzHandle::global_queue_(absl::kConstInit); +struct Queue { + Queue() = default; + + absl::Mutex mutex; + std::atomic dq_tail ABSL_GUARDED_BY(mutex){nullptr}; + + // Returns true if this delete queue is empty. This method does not acquire + // the lock, but does a 'load acquire' observation on the delete queue tail. + // It is used inside Delete() to check for the presence of a delete queue + // without holding the lock. The assumption is that the caller is in the + // state of 'being deleted', and can not be newly discovered by a concurrent + // 'being constructed' snapshot instance. Practically, this means that any + // such discovery (`find`, 'first' or 'next', etc) must have proper 'happens + // before / after' semantics and atomic fences. + bool IsEmpty() const ABSL_NO_THREAD_SAFETY_ANALYSIS { + return dq_tail.load(std::memory_order_acquire) == nullptr; + } +}; + +static Queue* GlobalQueue() { + static Queue* global_queue = new Queue; + return global_queue; +} + +} // namespace CordzHandle::CordzHandle(bool is_snapshot) : is_snapshot_(is_snapshot) { + Queue* global_queue = GlobalQueue(); if (is_snapshot) { - SpinLockHolder lock(&queue_->mutex); - CordzHandle* dq_tail = queue_->dq_tail.load(std::memory_order_acquire); + MutexLock lock(&global_queue->mutex); + CordzHandle* dq_tail = + global_queue->dq_tail.load(std::memory_order_acquire); if (dq_tail != nullptr) { dq_prev_ = dq_tail; dq_tail->dq_next_ = this; } - queue_->dq_tail.store(this, std::memory_order_release); + global_queue->dq_tail.store(this, std::memory_order_release); } } CordzHandle::~CordzHandle() { - ODRCheck(); + Queue* global_queue = GlobalQueue(); if (is_snapshot_) { std::vector to_delete; { - SpinLockHolder lock(&queue_->mutex); + MutexLock lock(&global_queue->mutex); CordzHandle* next = dq_next_; if (dq_prev_ == nullptr) { // We were head of the queue, delete every CordzHandle until we reach @@ -59,7 +85,7 @@ CordzHandle::~CordzHandle() { if (next) { next->dq_prev_ = dq_prev_; } else { - queue_->dq_tail.store(dq_prev_, std::memory_order_release); + global_queue->dq_tail.store(dq_prev_, std::memory_order_release); } } for (CordzHandle* handle : to_delete) { @@ -69,16 +95,15 @@ CordzHandle::~CordzHandle() { } bool CordzHandle::SafeToDelete() const { - return is_snapshot_ || queue_->IsEmpty(); + return is_snapshot_ || GlobalQueue()->IsEmpty(); } void CordzHandle::Delete(CordzHandle* handle) { assert(handle); if (handle) { - handle->ODRCheck(); - Queue* const queue = handle->queue_; + Queue* const queue = GlobalQueue(); if (!handle->SafeToDelete()) { - SpinLockHolder lock(&queue->mutex); + MutexLock lock(&queue->mutex); CordzHandle* dq_tail = queue->dq_tail.load(std::memory_order_acquire); if (dq_tail != nullptr) { handle->dq_prev_ = dq_tail; @@ -93,8 +118,9 @@ void CordzHandle::Delete(CordzHandle* handle) { std::vector CordzHandle::DiagnosticsGetDeleteQueue() { std::vector handles; - SpinLockHolder lock(&global_queue_.mutex); - CordzHandle* dq_tail = global_queue_.dq_tail.load(std::memory_order_acquire); + Queue* global_queue = GlobalQueue(); + MutexLock lock(&global_queue->mutex); + CordzHandle* dq_tail = global_queue->dq_tail.load(std::memory_order_acquire); for (const CordzHandle* p = dq_tail; p; p = p->dq_prev_) { handles.push_back(p); } @@ -103,13 +129,13 @@ std::vector CordzHandle::DiagnosticsGetDeleteQueue() { bool CordzHandle::DiagnosticsHandleIsSafeToInspect( const CordzHandle* handle) const { - ODRCheck(); if (!is_snapshot_) return false; if (handle == nullptr) return true; if (handle->is_snapshot_) return false; bool snapshot_found = false; - SpinLockHolder lock(&queue_->mutex); - for (const CordzHandle* p = queue_->dq_tail; p; p = p->dq_prev_) { + Queue* global_queue = GlobalQueue(); + MutexLock lock(&global_queue->mutex); + for (const CordzHandle* p = global_queue->dq_tail; p; p = p->dq_prev_) { if (p == handle) return !snapshot_found; if (p == this) snapshot_found = true; } @@ -119,13 +145,13 @@ bool CordzHandle::DiagnosticsHandleIsSafeToInspect( std::vector CordzHandle::DiagnosticsGetSafeToInspectDeletedHandles() { - ODRCheck(); std::vector handles; if (!is_snapshot()) { return handles; } - SpinLockHolder lock(&queue_->mutex); + Queue* global_queue = GlobalQueue(); + MutexLock lock(&global_queue->mutex); for (const CordzHandle* p = dq_next_; p != nullptr; p = p->dq_next_) { if (!p->is_snapshot()) { handles.push_back(p); diff --git a/absl/strings/internal/cordz_handle.h b/absl/strings/internal/cordz_handle.h index 3c800b433fb..9afe9a218d0 100644 --- a/absl/strings/internal/cordz_handle.h +++ b/absl/strings/internal/cordz_handle.h @@ -20,8 +20,6 @@ #include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" -#include "absl/base/internal/spinlock.h" -#include "absl/synchronization/mutex.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -79,37 +77,6 @@ class CordzHandle { virtual ~CordzHandle(); private: - // Global queue data. CordzHandle stores a pointer to the global queue - // instance to harden against ODR violations. - struct Queue { - constexpr explicit Queue(absl::ConstInitType) - : mutex(absl::kConstInit, - absl::base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL) {} - - absl::base_internal::SpinLock mutex; - std::atomic dq_tail ABSL_GUARDED_BY(mutex){nullptr}; - - // Returns true if this delete queue is empty. This method does not acquire - // the lock, but does a 'load acquire' observation on the delete queue tail. - // It is used inside Delete() to check for the presence of a delete queue - // without holding the lock. The assumption is that the caller is in the - // state of 'being deleted', and can not be newly discovered by a concurrent - // 'being constructed' snapshot instance. Practically, this means that any - // such discovery (`find`, 'first' or 'next', etc) must have proper 'happens - // before / after' semantics and atomic fences. - bool IsEmpty() const ABSL_NO_THREAD_SAFETY_ANALYSIS { - return dq_tail.load(std::memory_order_acquire) == nullptr; - } - }; - - void ODRCheck() const { -#ifndef NDEBUG - ABSL_RAW_CHECK(queue_ == &global_queue_, "ODR violation in Cord"); -#endif - } - - ABSL_CONST_INIT static Queue global_queue_; - Queue* const queue_ = &global_queue_; const bool is_snapshot_; // dq_prev_ and dq_next_ require the global queue mutex to be held. From df283a2060f2a958b774298086f8762c63cfdf7b Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Tue, 7 Feb 2023 13:01:27 +1100 Subject: [PATCH 0010/1238] fix some missing ABSL_INTERNAL_DLL_TARGETS for shared builds --- CMake/AbseilDll.cmake | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index aa73ae5135c..8e6e21dcdf5 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake @@ -462,8 +462,14 @@ set(ABSL_INTERNAL_DLL_TARGETS "container_common" "container_memory" "cord" + "cord_internal" + "cordz_functions" + "cordz_handle" + "cordz_info" + "cordz_sample_token" "core_headers" "counting_allocator" + "crc_cord_state" "crc_cpu_detect" "crc_internal" "crc32c" @@ -518,6 +524,7 @@ set(ABSL_INTERNAL_DLL_TARGETS "log_internal_structured" "log_severity" "log_structured" + "low_level_hash" "malloc_internal" "memory" "meta" @@ -569,8 +576,10 @@ set(ABSL_INTERNAL_DLL_TARGETS "stack_consumption" "stacktrace" "status" + "statusor" "str_format" "str_format_internal" + "strerror" "strings" "strings_internal" "symbolize" @@ -606,6 +615,7 @@ set(ABSL_INTERNAL_TEST_DLL_TARGETS "cordz_test_helpers" "hash_testing" "random_mocking_bit_gen" + "random_internal_distribution_test_util" "random_internal_mock_overload_set" "scoped_mock_log" ) From 34dd639a768761e555b080224a1381a459ab2885 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Mon, 15 May 2023 11:34:17 -0700 Subject: [PATCH 0011/1238] Mutex: Remove the deprecated absl::RegisterSymbolizer() hook absl::RegisterSymbolizer() has been deprecated for 5 years. It is being removed following our compatibility policy. PiperOrigin-RevId: 532174866 Change-Id: Id5c3b86698e389099d3d707c4e57f30f1f155d2e --- absl/synchronization/mutex.cc | 11 ++--------- absl/synchronization/mutex.h | 17 ----------------- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc index a8911614115..16a8fbffa9c 100644 --- a/absl/synchronization/mutex.cc +++ b/absl/synchronization/mutex.cc @@ -103,9 +103,6 @@ ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES absl::base_internal::AtomicHook cond_var_tracer; -ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES absl::base_internal::AtomicHook< - bool (*)(const void *pc, char *out, int out_size)> - symbolizer(absl::Symbolize); } // namespace @@ -126,10 +123,6 @@ void RegisterCondVarTracer(void (*fn)(const char *msg, const void *cv)) { cond_var_tracer.Store(fn); } -void RegisterSymbolizer(bool (*fn)(const void *pc, char *out, int out_size)) { - symbolizer.Store(fn); -} - namespace { // Represents the strategy for spin and yield. // See the comment in GetMutexGlobals() for more information. @@ -1289,7 +1282,7 @@ static inline void DebugOnlyLockLeave(Mutex *mu) { static char *StackString(void **pcs, int n, char *buf, int maxlen, bool symbolize) { - static const int kSymLen = 200; + static constexpr int kSymLen = 200; char sym[kSymLen]; int len = 0; for (int i = 0; i != n; i++) { @@ -1297,7 +1290,7 @@ static char *StackString(void **pcs, int n, char *buf, int maxlen, return buf; size_t count = static_cast(maxlen - len); if (symbolize) { - if (!symbolizer(pcs[i], sym, kSymLen)) { + if (!absl::Symbolize(pcs[i], sym, kSymLen)) { sym[0] = '\0'; } snprintf(buf + len, count, "%s\t@ %p %s\n", (i == 0 ? "\n" : ""), pcs[i], diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h index 8bbcae88e1b..0b6a9e18d59 100644 --- a/absl/synchronization/mutex.h +++ b/absl/synchronization/mutex.h @@ -1105,23 +1105,6 @@ void RegisterMutexTracer(void (*fn)(const char *msg, const void *obj, // RegisterMutexProfiler() above. void RegisterCondVarTracer(void (*fn)(const char *msg, const void *cv)); -// Register a hook for symbolizing stack traces in deadlock detector reports. -// -// 'pc' is the program counter being symbolized, 'out' is the buffer to write -// into, and 'out_size' is the size of the buffer. This function can return -// false if symbolizing failed, or true if a NUL-terminated symbol was written -// to 'out.' -// -// This has the same ordering and single-use limitations as -// RegisterMutexProfiler() above. -// -// DEPRECATED: The default symbolizer function is absl::Symbolize() and the -// ability to register a different hook for symbolizing stack traces will be -// removed on or after 2023-05-01. -ABSL_DEPRECATED("absl::RegisterSymbolizer() is deprecated and will be removed " - "on or after 2023-05-01") -void RegisterSymbolizer(bool (*fn)(const void *pc, char *out, int out_size)); - // EnableMutexInvariantDebugging() // // Enable or disable global support for Mutex invariant debugging. If enabled, From c8b33b0191a2db8364cacf94b267ea8a3f20ad83 Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Tue, 16 May 2023 13:14:32 -0700 Subject: [PATCH 0012/1238] Add non-public API for internal users PiperOrigin-RevId: 532553508 Change-Id: I813841ff3e5085b64c9b02ca41897bf7f6a8570e --- absl/status/internal/status_internal.h | 4 ++++ absl/status/status.cc | 7 +++++++ absl/status/status.h | 9 +++++++++ absl/status/status_test.cc | 23 +++++++++++++++++++++++ 4 files changed, 43 insertions(+) diff --git a/absl/status/internal/status_internal.h b/absl/status/internal/status_internal.h index 873eb5c245d..6198e726b3c 100644 --- a/absl/status/internal/status_internal.h +++ b/absl/status/internal/status_internal.h @@ -66,6 +66,10 @@ struct StatusRep { std::atomic ref; absl::StatusCode code; + + // As an internal implementation detail, we guarantee that if status.message() + // is non-empty, then the resulting string_view is null terminated. + // This is required to implement 'StatusMessageAsCStr(...)' std::string message; std::unique_ptr payloads; }; diff --git a/absl/status/status.cc b/absl/status/status.cc index d011075a00e..26e68294acf 100644 --- a/absl/status/status.cc +++ b/absl/status/status.cc @@ -616,5 +616,12 @@ std::string* MakeCheckFailString(const absl::Status* status, } // namespace status_internal +const char* StatusMessageAsCStr(const Status& status) { + // As an internal implementation detail, we guarantee that if status.message() + // is non-empty, then the resulting string_view is null terminated. + auto sv_message = status.message(); + return sv_message.empty() ? "" : sv_message.data(); +} + ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/status/status.h b/absl/status/status.h index c6c1cd41fe7..595064c0f1d 100644 --- a/absl/status/status.h +++ b/absl/status/status.h @@ -886,6 +886,15 @@ inline Status OkStatus() { return Status(); } // message-less kCancelled errors are common in the infrastructure. inline Status CancelledError() { return Status(absl::StatusCode::kCancelled); } +// Retrieves a message's status as a null terminated C string. The lifetime of +// this string is tied to the lifetime of the status object itself. +// +// If the status's message is empty, the empty string is returned. +// +// StatusMessageAsCStr exists for C support. Use `status.message()` in C++. +const char* StatusMessageAsCStr( + const Status& status ABSL_ATTRIBUTE_LIFETIME_BOUND); + ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/status/status_test.cc b/absl/status/status_test.cc index 74a64ace27d..898a9cb202f 100644 --- a/absl/status/status_test.cc +++ b/absl/status/status_test.cc @@ -132,6 +132,29 @@ TEST(Status, ConstructorWithCodeMessage) { } } +TEST(Status, StatusMessageCStringTest) { + { + absl::Status status = absl::OkStatus(); + EXPECT_EQ(status.message(), ""); + EXPECT_STREQ(absl::StatusMessageAsCStr(status), ""); + EXPECT_EQ(status.message(), absl::StatusMessageAsCStr(status)); + EXPECT_NE(absl::StatusMessageAsCStr(status), nullptr); + } + { + absl::Status status; + EXPECT_EQ(status.message(), ""); + EXPECT_NE(absl::StatusMessageAsCStr(status), nullptr); + EXPECT_STREQ(absl::StatusMessageAsCStr(status), ""); + } + { + absl::Status status(absl::StatusCode::kInternal, "message"); + EXPECT_FALSE(status.ok()); + EXPECT_EQ(absl::StatusCode::kInternal, status.code()); + EXPECT_EQ("message", status.message()); + EXPECT_STREQ("message", absl::StatusMessageAsCStr(status)); + } +} + TEST(Status, ConstructOutOfRangeCode) { const int kRawCode = 9999; absl::Status status(static_cast(kRawCode), ""); From 07e8b2a14d340984ff72fbea1181cc1469a4277a Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Wed, 17 May 2023 13:36:58 -0700 Subject: [PATCH 0013/1238] Add compiler deprecation warnings for absl::ConvertDateTime() and absl::FromDateTime(). These have been marked deprecated in the comments for some time, (since f340f773edab951656b19b6f1a77c964a78ec4c2) but the warnings were never enabled. A warning suppression is enabled for Abseil code so that when we declare types in our code, we don't get a warning. PiperOrigin-RevId: 532891102 Change-Id: Ife0c5696a061ea44769e02869e4e3d1196e86f9d --- absl/base/attributes.h | 22 ++++++++++++++++++++++ absl/time/time.cc | 9 ++++++++- absl/time/time.h | 19 +++++++++++++------ 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/absl/base/attributes.h b/absl/base/attributes.h index 3e5aafba115..34a3553801a 100644 --- a/absl/base/attributes.h +++ b/absl/base/attributes.h @@ -685,6 +685,28 @@ #define ABSL_DEPRECATED(message) #endif +// When deprecating Abseil code, it is sometimes necessary to turn off the +// warning within Abseil, until the deprecated code is actually removed. The +// deprecated code can be surrounded with these directives to acheive that +// result. +// +// class ABSL_DEPRECATED("Use Bar instead") Foo; +// +// ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING +// Baz ComputeBazFromFoo(Foo f); +// ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING +#ifdef __GNUC__ +// Clang also supports these GCC pragmas. +#define ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#define ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING \ + _Pragma("GCC diagnostic pop") +#else +#define ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING +#define ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING +#endif // __GNUC__ + // ABSL_CONST_INIT // // A variable declaration annotated with the `ABSL_CONST_INIT` attribute will diff --git a/absl/time/time.cc b/absl/time/time.cc index a11e8e9b82a..d983c12bb55 100644 --- a/absl/time/time.cc +++ b/absl/time/time.cc @@ -66,6 +66,7 @@ inline int64_t FloorToUnit(absl::Duration d, absl::Duration unit) { : q - 1; } +ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING inline absl::Time::Breakdown InfiniteFutureBreakdown() { absl::Time::Breakdown bd; bd.year = std::numeric_limits::max(); @@ -99,6 +100,7 @@ inline absl::Time::Breakdown InfinitePastBreakdown() { bd.zone_abbr = "-00"; return bd; } +ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING inline absl::TimeZone::CivilInfo InfiniteFutureCivilInfo() { TimeZone::CivilInfo ci; @@ -120,6 +122,7 @@ inline absl::TimeZone::CivilInfo InfinitePastCivilInfo() { return ci; } +ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING inline absl::TimeConversion InfiniteFutureTimeConversion() { absl::TimeConversion tc; tc.pre = tc.trans = tc.post = absl::InfiniteFuture(); @@ -135,6 +138,7 @@ inline TimeConversion InfinitePastTimeConversion() { tc.normalized = true; return tc; } +ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING // Makes a Time from sec, overflowing to InfiniteFuture/InfinitePast as // necessary. If sec is min/max, then consult cs+tz to check for overflow. @@ -203,6 +207,7 @@ bool FindTransition(const cctz::time_zone& tz, // Time // +ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING absl::Time::Breakdown Time::In(absl::TimeZone tz) const { if (*this == absl::InfiniteFuture()) return InfiniteFutureBreakdown(); if (*this == absl::InfinitePast()) return InfinitePastBreakdown(); @@ -227,6 +232,7 @@ absl::Time::Breakdown Time::In(absl::TimeZone tz) const { bd.zone_abbr = al.abbr; return bd; } +ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING // // Conversions from/to other time types. @@ -398,7 +404,7 @@ bool TimeZone::PrevTransition(Time t, CivilTransition* trans) const { // // Conversions involving time zones. // - +ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING absl::TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour, int min, int sec, TimeZone tz) { // Avoids years that are too extreme for CivilSecond to normalize. @@ -430,6 +436,7 @@ absl::TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour, } return tc; } +ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING absl::Time FromTM(const struct tm& tm, absl::TimeZone tz) { civil_year_t tm_year = tm.tm_year; diff --git a/absl/time/time.h b/absl/time/time.h index 29178c777ea..37580805e2c 100644 --- a/absl/time/time.h +++ b/absl/time/time.h @@ -802,8 +802,7 @@ class Time { // `absl::TimeZone`. // // Deprecated. Use `absl::TimeZone::CivilInfo`. - struct - Breakdown { + struct ABSL_DEPRECATED("Use `absl::TimeZone::CivilInfo`.") Breakdown { int64_t year; // year (e.g., 2013) int month; // month of year [1:12] int day; // day of month [1:31] @@ -829,7 +828,10 @@ class Time { // Returns the breakdown of this instant in the given TimeZone. // // Deprecated. Use `absl::TimeZone::At(Time)`. + ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING + ABSL_DEPRECATED("Use `absl::TimeZone::At(Time)`.") Breakdown In(TimeZone tz) const; + ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING template friend H AbslHashValue(H h, Time t) { @@ -1323,8 +1325,7 @@ ABSL_ATTRIBUTE_PURE_FUNCTION inline Time FromCivil(CivilSecond ct, // `absl::ConvertDateTime()`. Legacy version of `absl::TimeZone::TimeInfo`. // // Deprecated. Use `absl::TimeZone::TimeInfo`. -struct - TimeConversion { +struct ABSL_DEPRECATED("Use `absl::TimeZone::TimeInfo`.") TimeConversion { Time pre; // time calculated using the pre-transition offset Time trans; // when the civil-time discontinuity occurred Time post; // time calculated using the post-transition offset @@ -1358,8 +1359,11 @@ struct // // absl::ToCivilDay(tc.pre, tz).day() == 1 // // Deprecated. Use `absl::TimeZone::At(CivilSecond)`. +ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING +ABSL_DEPRECATED("Use `absl::TimeZone::At(CivilSecond)`.") TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour, int min, int sec, TimeZone tz); +ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING // FromDateTime() // @@ -1376,9 +1380,12 @@ TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour, // Deprecated. Use `absl::FromCivil(CivilSecond, TimeZone)`. Note that the // behavior of `FromCivil()` differs from `FromDateTime()` for skipped civil // times. If you care about that see `absl::TimeZone::At(absl::CivilSecond)`. -inline Time FromDateTime(int64_t year, int mon, int day, int hour, - int min, int sec, TimeZone tz) { +ABSL_DEPRECATED("Use `absl::FromCivil(CivilSecond, TimeZone)`.") +inline Time FromDateTime(int64_t year, int mon, int day, int hour, int min, + int sec, TimeZone tz) { + ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING return ConvertDateTime(year, mon, day, hour, min, sec, tz).pre; + ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING } // FromTM() From 486db28adc2c48c255fffbfde1d59415f4762b71 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Wed, 17 May 2023 13:35:35 +0900 Subject: [PATCH 0014/1238] Use UB impl of launder on when using clang < 8 and c++17 libstdc++'s definition of std::launder places it behind a check for __builtin_launder, which is not available before clang 8. Fixes: #1309 --- absl/functional/internal/any_invocable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/absl/functional/internal/any_invocable.h b/absl/functional/internal/any_invocable.h index d41b7e56ec2..634984cabc1 100644 --- a/absl/functional/internal/any_invocable.h +++ b/absl/functional/internal/any_invocable.h @@ -197,7 +197,7 @@ union TypeErasedState { template T& ObjectInLocalStorage(TypeErasedState* const state) { // We launder here because the storage may be reused with the same type. -#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L +#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L && __cpp_lib_launder >= 201606L return *std::launder(reinterpret_cast(&state->storage)); #elif ABSL_HAVE_BUILTIN(__builtin_launder) return *__builtin_launder(reinterpret_cast(&state->storage)); From bd748714ce32841d410b1b8ec5f2daa5043ee6b2 Mon Sep 17 00:00:00 2001 From: Niranjan Nilakantan Date: Thu, 18 May 2023 19:23:52 -0700 Subject: [PATCH 0015/1238] Add a declaration for __cpuid for the IntelLLVM compiler. __cpuid is declared in intrin.h, but is "excluded" on non-Windows platforms. We add this declaration to compensate. Fixes #1358 --- absl/random/internal/randen_detect.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/absl/random/internal/randen_detect.cc b/absl/random/internal/randen_detect.cc index 6dababa3511..0ad23cb2747 100644 --- a/absl/random/internal/randen_detect.cc +++ b/absl/random/internal/randen_detect.cc @@ -45,6 +45,10 @@ #if defined(ABSL_INTERNAL_USE_X86_CPUID) #if defined(_WIN32) || defined(_WIN64) #include // NOLINT(build/include_order) +#elif ABSL_HAVE_BUILTIN(__cpuid) +// MSVC-equivalent __cpuid intrinsic declaration for clang-like compilers +// for non-Windows build environments. +void __cpuid(int[4], int); #else // MSVC-equivalent __cpuid intrinsic function. static void __cpuid(int cpu_info[4], int info_type) { From aaf81ec85bafbddf9ced2f73f22091d7559c8f31 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Fri, 19 May 2023 08:02:03 -0700 Subject: [PATCH 0016/1238] Import of CCTZ from GitHub. PiperOrigin-RevId: 533455360 Change-Id: Ia95b225f8c186a831801f1ee008d7a5c0fff544b --- .../cctz/src/time_zone_format_test.cc | 465 +++++++++++------- .../cctz/src/time_zone_lookup_test.cc | 44 +- 2 files changed, 302 insertions(+), 207 deletions(-) diff --git a/absl/time/internal/cctz/src/time_zone_format_test.cc b/absl/time/internal/cctz/src/time_zone_format_test.cc index f1f79a20fc9..7a03e7d29f5 100644 --- a/absl/time/internal/cctz/src/time_zone_format_test.cc +++ b/absl/time/internal/cctz/src/time_zone_format_test.cc @@ -64,10 +64,13 @@ const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z"; template void TestFormatSpecifier(time_point tp, time_zone tz, const std::string& fmt, const std::string& ans) { - EXPECT_EQ(ans, format(fmt, tp, tz)) << fmt; - EXPECT_EQ("xxx " + ans, format("xxx " + fmt, tp, tz)); - EXPECT_EQ(ans + " yyy", format(fmt + " yyy", tp, tz)); - EXPECT_EQ("xxx " + ans + " yyy", format("xxx " + fmt + " yyy", tp, tz)); + EXPECT_EQ(ans, absl::time_internal::cctz::format(fmt, tp, tz)) << fmt; + EXPECT_EQ("xxx " + ans, + absl::time_internal::cctz::format("xxx " + fmt, tp, tz)); + EXPECT_EQ(ans + " yyy", + absl::time_internal::cctz::format(fmt + " yyy", tp, tz)); + EXPECT_EQ("xxx " + ans + " yyy", + absl::time_internal::cctz::format("xxx " + fmt + " yyy", tp, tz)); } } // namespace @@ -83,26 +86,29 @@ TEST(Format, TimePointResolution) { chrono::system_clock::from_time_t(1420167845) + chrono::milliseconds(123) + chrono::microseconds(456) + chrono::nanoseconds(789); - EXPECT_EQ( - "03:04:05.123456789", - format(kFmt, chrono::time_point_cast(t0), utc)); - EXPECT_EQ( - "03:04:05.123456", - format(kFmt, chrono::time_point_cast(t0), utc)); - EXPECT_EQ( - "03:04:05.123", - format(kFmt, chrono::time_point_cast(t0), utc)); + EXPECT_EQ("03:04:05.123456789", + absl::time_internal::cctz::format( + kFmt, chrono::time_point_cast(t0), utc)); + EXPECT_EQ("03:04:05.123456", + absl::time_internal::cctz::format( + kFmt, chrono::time_point_cast(t0), utc)); + EXPECT_EQ("03:04:05.123", + absl::time_internal::cctz::format( + kFmt, chrono::time_point_cast(t0), utc)); EXPECT_EQ("03:04:05", - format(kFmt, chrono::time_point_cast(t0), utc)); + absl::time_internal::cctz::format( + kFmt, chrono::time_point_cast(t0), utc)); EXPECT_EQ( "03:04:05", - format(kFmt, - chrono::time_point_cast(t0), - utc)); + absl::time_internal::cctz::format( + kFmt, chrono::time_point_cast(t0), + utc)); EXPECT_EQ("03:04:00", - format(kFmt, chrono::time_point_cast(t0), utc)); + absl::time_internal::cctz::format( + kFmt, chrono::time_point_cast(t0), utc)); EXPECT_EQ("03:00:00", - format(kFmt, chrono::time_point_cast(t0), utc)); + absl::time_internal::cctz::format( + kFmt, chrono::time_point_cast(t0), utc)); } TEST(Format, TimePointExtendedResolution) { @@ -137,24 +143,28 @@ TEST(Format, Basics) { time_point tp = chrono::system_clock::from_time_t(0); // Starts with a couple basic edge cases. - EXPECT_EQ("", format("", tp, tz)); - EXPECT_EQ(" ", format(" ", tp, tz)); - EXPECT_EQ(" ", format(" ", tp, tz)); - EXPECT_EQ("xxx", format("xxx", tp, tz)); + EXPECT_EQ("", absl::time_internal::cctz::format("", tp, tz)); + EXPECT_EQ(" ", absl::time_internal::cctz::format(" ", tp, tz)); + EXPECT_EQ(" ", absl::time_internal::cctz::format(" ", tp, tz)); + EXPECT_EQ("xxx", absl::time_internal::cctz::format("xxx", tp, tz)); std::string big(128, 'x'); - EXPECT_EQ(big, format(big, tp, tz)); + EXPECT_EQ(big, absl::time_internal::cctz::format(big, tp, tz)); // Cause the 1024-byte buffer to grow. std::string bigger(100000, 'x'); - EXPECT_EQ(bigger, format(bigger, tp, tz)); + EXPECT_EQ(bigger, absl::time_internal::cctz::format(bigger, tp, tz)); tp += chrono::hours(13) + chrono::minutes(4) + chrono::seconds(5); tp += chrono::milliseconds(6) + chrono::microseconds(7) + chrono::nanoseconds(8); - EXPECT_EQ("1970-01-01", format("%Y-%m-%d", tp, tz)); - EXPECT_EQ("13:04:05", format("%H:%M:%S", tp, tz)); - EXPECT_EQ("13:04:05.006", format("%H:%M:%E3S", tp, tz)); - EXPECT_EQ("13:04:05.006007", format("%H:%M:%E6S", tp, tz)); - EXPECT_EQ("13:04:05.006007008", format("%H:%M:%E9S", tp, tz)); + EXPECT_EQ("1970-01-01", + absl::time_internal::cctz::format("%Y-%m-%d", tp, tz)); + EXPECT_EQ("13:04:05", absl::time_internal::cctz::format("%H:%M:%S", tp, tz)); + EXPECT_EQ("13:04:05.006", + absl::time_internal::cctz::format("%H:%M:%E3S", tp, tz)); + EXPECT_EQ("13:04:05.006007", + absl::time_internal::cctz::format("%H:%M:%E6S", tp, tz)); + EXPECT_EQ("13:04:05.006007008", + absl::time_internal::cctz::format("%H:%M:%E9S", tp, tz)); } TEST(Format, PosixConversions) { @@ -277,49 +287,61 @@ TEST(Format, ExtendedSeconds) { // No subseconds. time_point tp = chrono::system_clock::from_time_t(0); tp += chrono::seconds(5); - EXPECT_EQ("05", format("%E*S", tp, tz)); - EXPECT_EQ("05", format("%E0S", tp, tz)); - EXPECT_EQ("05.0", format("%E1S", tp, tz)); - EXPECT_EQ("05.00", format("%E2S", tp, tz)); - EXPECT_EQ("05.000", format("%E3S", tp, tz)); - EXPECT_EQ("05.0000", format("%E4S", tp, tz)); - EXPECT_EQ("05.00000", format("%E5S", tp, tz)); - EXPECT_EQ("05.000000", format("%E6S", tp, tz)); - EXPECT_EQ("05.0000000", format("%E7S", tp, tz)); - EXPECT_EQ("05.00000000", format("%E8S", tp, tz)); - EXPECT_EQ("05.000000000", format("%E9S", tp, tz)); - EXPECT_EQ("05.0000000000", format("%E10S", tp, tz)); - EXPECT_EQ("05.00000000000", format("%E11S", tp, tz)); - EXPECT_EQ("05.000000000000", format("%E12S", tp, tz)); - EXPECT_EQ("05.0000000000000", format("%E13S", tp, tz)); - EXPECT_EQ("05.00000000000000", format("%E14S", tp, tz)); - EXPECT_EQ("05.000000000000000", format("%E15S", tp, tz)); + EXPECT_EQ("05", absl::time_internal::cctz::format("%E*S", tp, tz)); + EXPECT_EQ("05", absl::time_internal::cctz::format("%E0S", tp, tz)); + EXPECT_EQ("05.0", absl::time_internal::cctz::format("%E1S", tp, tz)); + EXPECT_EQ("05.00", absl::time_internal::cctz::format("%E2S", tp, tz)); + EXPECT_EQ("05.000", absl::time_internal::cctz::format("%E3S", tp, tz)); + EXPECT_EQ("05.0000", absl::time_internal::cctz::format("%E4S", tp, tz)); + EXPECT_EQ("05.00000", absl::time_internal::cctz::format("%E5S", tp, tz)); + EXPECT_EQ("05.000000", absl::time_internal::cctz::format("%E6S", tp, tz)); + EXPECT_EQ("05.0000000", absl::time_internal::cctz::format("%E7S", tp, tz)); + EXPECT_EQ("05.00000000", absl::time_internal::cctz::format("%E8S", tp, tz)); + EXPECT_EQ("05.000000000", absl::time_internal::cctz::format("%E9S", tp, tz)); + EXPECT_EQ("05.0000000000", + absl::time_internal::cctz::format("%E10S", tp, tz)); + EXPECT_EQ("05.00000000000", + absl::time_internal::cctz::format("%E11S", tp, tz)); + EXPECT_EQ("05.000000000000", + absl::time_internal::cctz::format("%E12S", tp, tz)); + EXPECT_EQ("05.0000000000000", + absl::time_internal::cctz::format("%E13S", tp, tz)); + EXPECT_EQ("05.00000000000000", + absl::time_internal::cctz::format("%E14S", tp, tz)); + EXPECT_EQ("05.000000000000000", + absl::time_internal::cctz::format("%E15S", tp, tz)); // With subseconds. tp += chrono::milliseconds(6) + chrono::microseconds(7) + chrono::nanoseconds(8); - EXPECT_EQ("05.006007008", format("%E*S", tp, tz)); - EXPECT_EQ("05", format("%E0S", tp, tz)); - EXPECT_EQ("05.0", format("%E1S", tp, tz)); - EXPECT_EQ("05.00", format("%E2S", tp, tz)); - EXPECT_EQ("05.006", format("%E3S", tp, tz)); - EXPECT_EQ("05.0060", format("%E4S", tp, tz)); - EXPECT_EQ("05.00600", format("%E5S", tp, tz)); - EXPECT_EQ("05.006007", format("%E6S", tp, tz)); - EXPECT_EQ("05.0060070", format("%E7S", tp, tz)); - EXPECT_EQ("05.00600700", format("%E8S", tp, tz)); - EXPECT_EQ("05.006007008", format("%E9S", tp, tz)); - EXPECT_EQ("05.0060070080", format("%E10S", tp, tz)); - EXPECT_EQ("05.00600700800", format("%E11S", tp, tz)); - EXPECT_EQ("05.006007008000", format("%E12S", tp, tz)); - EXPECT_EQ("05.0060070080000", format("%E13S", tp, tz)); - EXPECT_EQ("05.00600700800000", format("%E14S", tp, tz)); - EXPECT_EQ("05.006007008000000", format("%E15S", tp, tz)); + EXPECT_EQ("05.006007008", absl::time_internal::cctz::format("%E*S", tp, tz)); + EXPECT_EQ("05", absl::time_internal::cctz::format("%E0S", tp, tz)); + EXPECT_EQ("05.0", absl::time_internal::cctz::format("%E1S", tp, tz)); + EXPECT_EQ("05.00", absl::time_internal::cctz::format("%E2S", tp, tz)); + EXPECT_EQ("05.006", absl::time_internal::cctz::format("%E3S", tp, tz)); + EXPECT_EQ("05.0060", absl::time_internal::cctz::format("%E4S", tp, tz)); + EXPECT_EQ("05.00600", absl::time_internal::cctz::format("%E5S", tp, tz)); + EXPECT_EQ("05.006007", absl::time_internal::cctz::format("%E6S", tp, tz)); + EXPECT_EQ("05.0060070", absl::time_internal::cctz::format("%E7S", tp, tz)); + EXPECT_EQ("05.00600700", absl::time_internal::cctz::format("%E8S", tp, tz)); + EXPECT_EQ("05.006007008", absl::time_internal::cctz::format("%E9S", tp, tz)); + EXPECT_EQ("05.0060070080", + absl::time_internal::cctz::format("%E10S", tp, tz)); + EXPECT_EQ("05.00600700800", + absl::time_internal::cctz::format("%E11S", tp, tz)); + EXPECT_EQ("05.006007008000", + absl::time_internal::cctz::format("%E12S", tp, tz)); + EXPECT_EQ("05.0060070080000", + absl::time_internal::cctz::format("%E13S", tp, tz)); + EXPECT_EQ("05.00600700800000", + absl::time_internal::cctz::format("%E14S", tp, tz)); + EXPECT_EQ("05.006007008000000", + absl::time_internal::cctz::format("%E15S", tp, tz)); // Times before the Unix epoch. tp = chrono::system_clock::from_time_t(0) + chrono::microseconds(-1); EXPECT_EQ("1969-12-31 23:59:59.999999", - format("%Y-%m-%d %H:%M:%E*S", tp, tz)); + absl::time_internal::cctz::format("%Y-%m-%d %H:%M:%E*S", tp, tz)); // Here is a "%E*S" case we got wrong for a while. While the first // instant below is correctly rendered as "...:07.333304", the second @@ -327,10 +349,10 @@ TEST(Format, ExtendedSeconds) { tp = chrono::system_clock::from_time_t(0) + chrono::microseconds(1395024427333304); EXPECT_EQ("2014-03-17 02:47:07.333304", - format("%Y-%m-%d %H:%M:%E*S", tp, tz)); + absl::time_internal::cctz::format("%Y-%m-%d %H:%M:%E*S", tp, tz)); tp += chrono::microseconds(1); EXPECT_EQ("2014-03-17 02:47:07.333305", - format("%Y-%m-%d %H:%M:%E*S", tp, tz)); + absl::time_internal::cctz::format("%Y-%m-%d %H:%M:%E*S", tp, tz)); } TEST(Format, ExtendedSubeconds) { @@ -339,60 +361,69 @@ TEST(Format, ExtendedSubeconds) { // No subseconds. time_point tp = chrono::system_clock::from_time_t(0); tp += chrono::seconds(5); - EXPECT_EQ("0", format("%E*f", tp, tz)); - EXPECT_EQ("", format("%E0f", tp, tz)); - EXPECT_EQ("0", format("%E1f", tp, tz)); - EXPECT_EQ("00", format("%E2f", tp, tz)); - EXPECT_EQ("000", format("%E3f", tp, tz)); - EXPECT_EQ("0000", format("%E4f", tp, tz)); - EXPECT_EQ("00000", format("%E5f", tp, tz)); - EXPECT_EQ("000000", format("%E6f", tp, tz)); - EXPECT_EQ("0000000", format("%E7f", tp, tz)); - EXPECT_EQ("00000000", format("%E8f", tp, tz)); - EXPECT_EQ("000000000", format("%E9f", tp, tz)); - EXPECT_EQ("0000000000", format("%E10f", tp, tz)); - EXPECT_EQ("00000000000", format("%E11f", tp, tz)); - EXPECT_EQ("000000000000", format("%E12f", tp, tz)); - EXPECT_EQ("0000000000000", format("%E13f", tp, tz)); - EXPECT_EQ("00000000000000", format("%E14f", tp, tz)); - EXPECT_EQ("000000000000000", format("%E15f", tp, tz)); + EXPECT_EQ("0", absl::time_internal::cctz::format("%E*f", tp, tz)); + EXPECT_EQ("", absl::time_internal::cctz::format("%E0f", tp, tz)); + EXPECT_EQ("0", absl::time_internal::cctz::format("%E1f", tp, tz)); + EXPECT_EQ("00", absl::time_internal::cctz::format("%E2f", tp, tz)); + EXPECT_EQ("000", absl::time_internal::cctz::format("%E3f", tp, tz)); + EXPECT_EQ("0000", absl::time_internal::cctz::format("%E4f", tp, tz)); + EXPECT_EQ("00000", absl::time_internal::cctz::format("%E5f", tp, tz)); + EXPECT_EQ("000000", absl::time_internal::cctz::format("%E6f", tp, tz)); + EXPECT_EQ("0000000", absl::time_internal::cctz::format("%E7f", tp, tz)); + EXPECT_EQ("00000000", absl::time_internal::cctz::format("%E8f", tp, tz)); + EXPECT_EQ("000000000", absl::time_internal::cctz::format("%E9f", tp, tz)); + EXPECT_EQ("0000000000", absl::time_internal::cctz::format("%E10f", tp, tz)); + EXPECT_EQ("00000000000", absl::time_internal::cctz::format("%E11f", tp, tz)); + EXPECT_EQ("000000000000", absl::time_internal::cctz::format("%E12f", tp, tz)); + EXPECT_EQ("0000000000000", + absl::time_internal::cctz::format("%E13f", tp, tz)); + EXPECT_EQ("00000000000000", + absl::time_internal::cctz::format("%E14f", tp, tz)); + EXPECT_EQ("000000000000000", + absl::time_internal::cctz::format("%E15f", tp, tz)); // With subseconds. tp += chrono::milliseconds(6) + chrono::microseconds(7) + chrono::nanoseconds(8); - EXPECT_EQ("006007008", format("%E*f", tp, tz)); - EXPECT_EQ("", format("%E0f", tp, tz)); - EXPECT_EQ("0", format("%E1f", tp, tz)); - EXPECT_EQ("00", format("%E2f", tp, tz)); - EXPECT_EQ("006", format("%E3f", tp, tz)); - EXPECT_EQ("0060", format("%E4f", tp, tz)); - EXPECT_EQ("00600", format("%E5f", tp, tz)); - EXPECT_EQ("006007", format("%E6f", tp, tz)); - EXPECT_EQ("0060070", format("%E7f", tp, tz)); - EXPECT_EQ("00600700", format("%E8f", tp, tz)); - EXPECT_EQ("006007008", format("%E9f", tp, tz)); - EXPECT_EQ("0060070080", format("%E10f", tp, tz)); - EXPECT_EQ("00600700800", format("%E11f", tp, tz)); - EXPECT_EQ("006007008000", format("%E12f", tp, tz)); - EXPECT_EQ("0060070080000", format("%E13f", tp, tz)); - EXPECT_EQ("00600700800000", format("%E14f", tp, tz)); - EXPECT_EQ("006007008000000", format("%E15f", tp, tz)); + EXPECT_EQ("006007008", absl::time_internal::cctz::format("%E*f", tp, tz)); + EXPECT_EQ("", absl::time_internal::cctz::format("%E0f", tp, tz)); + EXPECT_EQ("0", absl::time_internal::cctz::format("%E1f", tp, tz)); + EXPECT_EQ("00", absl::time_internal::cctz::format("%E2f", tp, tz)); + EXPECT_EQ("006", absl::time_internal::cctz::format("%E3f", tp, tz)); + EXPECT_EQ("0060", absl::time_internal::cctz::format("%E4f", tp, tz)); + EXPECT_EQ("00600", absl::time_internal::cctz::format("%E5f", tp, tz)); + EXPECT_EQ("006007", absl::time_internal::cctz::format("%E6f", tp, tz)); + EXPECT_EQ("0060070", absl::time_internal::cctz::format("%E7f", tp, tz)); + EXPECT_EQ("00600700", absl::time_internal::cctz::format("%E8f", tp, tz)); + EXPECT_EQ("006007008", absl::time_internal::cctz::format("%E9f", tp, tz)); + EXPECT_EQ("0060070080", absl::time_internal::cctz::format("%E10f", tp, tz)); + EXPECT_EQ("00600700800", absl::time_internal::cctz::format("%E11f", tp, tz)); + EXPECT_EQ("006007008000", absl::time_internal::cctz::format("%E12f", tp, tz)); + EXPECT_EQ("0060070080000", + absl::time_internal::cctz::format("%E13f", tp, tz)); + EXPECT_EQ("00600700800000", + absl::time_internal::cctz::format("%E14f", tp, tz)); + EXPECT_EQ("006007008000000", + absl::time_internal::cctz::format("%E15f", tp, tz)); // Times before the Unix epoch. tp = chrono::system_clock::from_time_t(0) + chrono::microseconds(-1); - EXPECT_EQ("1969-12-31 23:59:59.999999", - format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz)); + EXPECT_EQ( + "1969-12-31 23:59:59.999999", + absl::time_internal::cctz::format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz)); // Here is a "%E*S" case we got wrong for a while. While the first // instant below is correctly rendered as "...:07.333304", the second // one used to appear as "...:07.33330499999999999". tp = chrono::system_clock::from_time_t(0) + chrono::microseconds(1395024427333304); - EXPECT_EQ("2014-03-17 02:47:07.333304", - format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz)); + EXPECT_EQ( + "2014-03-17 02:47:07.333304", + absl::time_internal::cctz::format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz)); tp += chrono::microseconds(1); - EXPECT_EQ("2014-03-17 02:47:07.333305", - format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz)); + EXPECT_EQ( + "2014-03-17 02:47:07.333305", + absl::time_internal::cctz::format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz)); } TEST(Format, CompareExtendSecondsVsSubseconds) { @@ -408,15 +439,17 @@ TEST(Format, CompareExtendSecondsVsSubseconds) { time_point tp = chrono::system_clock::from_time_t(0); tp += chrono::seconds(5); // ... %E*S and %S.%E*f are different. - EXPECT_EQ("05", format(fmt_A("*"), tp, tz)); - EXPECT_EQ("05.0", format(fmt_B("*"), tp, tz)); + EXPECT_EQ("05", absl::time_internal::cctz::format(fmt_A("*"), tp, tz)); + EXPECT_EQ("05.0", absl::time_internal::cctz::format(fmt_B("*"), tp, tz)); // ... %E0S and %S.%E0f are different. - EXPECT_EQ("05", format(fmt_A("0"), tp, tz)); - EXPECT_EQ("05.", format(fmt_B("0"), tp, tz)); + EXPECT_EQ("05", absl::time_internal::cctz::format(fmt_A("0"), tp, tz)); + EXPECT_EQ("05.", absl::time_internal::cctz::format(fmt_B("0"), tp, tz)); // ... %ES and %S.%Ef are the same for prec in [1:15]. for (int prec = 1; prec <= 15; ++prec) { - const std::string a = format(fmt_A(std::to_string(prec)), tp, tz); - const std::string b = format(fmt_B(std::to_string(prec)), tp, tz); + const std::string a = + absl::time_internal::cctz::format(fmt_A(std::to_string(prec)), tp, tz); + const std::string b = + absl::time_internal::cctz::format(fmt_B(std::to_string(prec)), tp, tz); EXPECT_EQ(a, b) << "prec=" << prec; } @@ -424,15 +457,19 @@ TEST(Format, CompareExtendSecondsVsSubseconds) { // ... %E*S and %S.%E*f are the same. tp += chrono::milliseconds(6) + chrono::microseconds(7) + chrono::nanoseconds(8); - EXPECT_EQ("05.006007008", format(fmt_A("*"), tp, tz)); - EXPECT_EQ("05.006007008", format(fmt_B("*"), tp, tz)); + EXPECT_EQ("05.006007008", + absl::time_internal::cctz::format(fmt_A("*"), tp, tz)); + EXPECT_EQ("05.006007008", + absl::time_internal::cctz::format(fmt_B("*"), tp, tz)); // ... %E0S and %S.%E0f are different. - EXPECT_EQ("05", format(fmt_A("0"), tp, tz)); - EXPECT_EQ("05.", format(fmt_B("0"), tp, tz)); + EXPECT_EQ("05", absl::time_internal::cctz::format(fmt_A("0"), tp, tz)); + EXPECT_EQ("05.", absl::time_internal::cctz::format(fmt_B("0"), tp, tz)); // ... %ES and %S.%Ef are the same for prec in [1:15]. for (int prec = 1; prec <= 15; ++prec) { - const std::string a = format(fmt_A(std::to_string(prec)), tp, tz); - const std::string b = format(fmt_B(std::to_string(prec)), tp, tz); + const std::string a = + absl::time_internal::cctz::format(fmt_A(std::to_string(prec)), tp, tz); + const std::string b = + absl::time_internal::cctz::format(fmt_B(std::to_string(prec)), tp, tz); EXPECT_EQ(a, b) << "prec=" << prec; } } @@ -605,31 +642,31 @@ TEST(Format, ExtendedYears) { // %E4Y zero-pads the year to produce at least 4 chars, including the sign. auto tp = convert(civil_second(-999, 11, 27, 0, 0, 0), utc); - EXPECT_EQ("-9991127", format(e4y_fmt, tp, utc)); + EXPECT_EQ("-9991127", absl::time_internal::cctz::format(e4y_fmt, tp, utc)); tp = convert(civil_second(-99, 11, 27, 0, 0, 0), utc); - EXPECT_EQ("-0991127", format(e4y_fmt, tp, utc)); + EXPECT_EQ("-0991127", absl::time_internal::cctz::format(e4y_fmt, tp, utc)); tp = convert(civil_second(-9, 11, 27, 0, 0, 0), utc); - EXPECT_EQ("-0091127", format(e4y_fmt, tp, utc)); + EXPECT_EQ("-0091127", absl::time_internal::cctz::format(e4y_fmt, tp, utc)); tp = convert(civil_second(-1, 11, 27, 0, 0, 0), utc); - EXPECT_EQ("-0011127", format(e4y_fmt, tp, utc)); + EXPECT_EQ("-0011127", absl::time_internal::cctz::format(e4y_fmt, tp, utc)); tp = convert(civil_second(0, 11, 27, 0, 0, 0), utc); - EXPECT_EQ("00001127", format(e4y_fmt, tp, utc)); + EXPECT_EQ("00001127", absl::time_internal::cctz::format(e4y_fmt, tp, utc)); tp = convert(civil_second(1, 11, 27, 0, 0, 0), utc); - EXPECT_EQ("00011127", format(e4y_fmt, tp, utc)); + EXPECT_EQ("00011127", absl::time_internal::cctz::format(e4y_fmt, tp, utc)); tp = convert(civil_second(9, 11, 27, 0, 0, 0), utc); - EXPECT_EQ("00091127", format(e4y_fmt, tp, utc)); + EXPECT_EQ("00091127", absl::time_internal::cctz::format(e4y_fmt, tp, utc)); tp = convert(civil_second(99, 11, 27, 0, 0, 0), utc); - EXPECT_EQ("00991127", format(e4y_fmt, tp, utc)); + EXPECT_EQ("00991127", absl::time_internal::cctz::format(e4y_fmt, tp, utc)); tp = convert(civil_second(999, 11, 27, 0, 0, 0), utc); - EXPECT_EQ("09991127", format(e4y_fmt, tp, utc)); + EXPECT_EQ("09991127", absl::time_internal::cctz::format(e4y_fmt, tp, utc)); tp = convert(civil_second(9999, 11, 27, 0, 0, 0), utc); - EXPECT_EQ("99991127", format(e4y_fmt, tp, utc)); + EXPECT_EQ("99991127", absl::time_internal::cctz::format(e4y_fmt, tp, utc)); // When the year is outside [-999:9999], more than 4 chars are produced. tp = convert(civil_second(-1000, 11, 27, 0, 0, 0), utc); - EXPECT_EQ("-10001127", format(e4y_fmt, tp, utc)); + EXPECT_EQ("-10001127", absl::time_internal::cctz::format(e4y_fmt, tp, utc)); tp = convert(civil_second(10000, 11, 27, 0, 0, 0), utc); - EXPECT_EQ("100001127", format(e4y_fmt, tp, utc)); + EXPECT_EQ("100001127", absl::time_internal::cctz::format(e4y_fmt, tp, utc)); } TEST(Format, RFC3339Format) { @@ -638,45 +675,64 @@ TEST(Format, RFC3339Format) { time_point tp = convert(civil_second(1977, 6, 28, 9, 8, 7), tz); - EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_full, tp, tz)); - EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07-07:00", + absl::time_internal::cctz::format(RFC3339_full, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07-07:00", + absl::time_internal::cctz::format(RFC3339_sec, tp, tz)); tp += chrono::milliseconds(100); - EXPECT_EQ("1977-06-28T09:08:07.1-07:00", format(RFC3339_full, tp, tz)); - EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07.1-07:00", + absl::time_internal::cctz::format(RFC3339_full, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07-07:00", + absl::time_internal::cctz::format(RFC3339_sec, tp, tz)); tp += chrono::milliseconds(20); - EXPECT_EQ("1977-06-28T09:08:07.12-07:00", format(RFC3339_full, tp, tz)); - EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07.12-07:00", + absl::time_internal::cctz::format(RFC3339_full, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07-07:00", + absl::time_internal::cctz::format(RFC3339_sec, tp, tz)); tp += chrono::milliseconds(3); - EXPECT_EQ("1977-06-28T09:08:07.123-07:00", format(RFC3339_full, tp, tz)); - EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07.123-07:00", + absl::time_internal::cctz::format(RFC3339_full, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07-07:00", + absl::time_internal::cctz::format(RFC3339_sec, tp, tz)); tp += chrono::microseconds(400); - EXPECT_EQ("1977-06-28T09:08:07.1234-07:00", format(RFC3339_full, tp, tz)); - EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07.1234-07:00", + absl::time_internal::cctz::format(RFC3339_full, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07-07:00", + absl::time_internal::cctz::format(RFC3339_sec, tp, tz)); tp += chrono::microseconds(50); - EXPECT_EQ("1977-06-28T09:08:07.12345-07:00", format(RFC3339_full, tp, tz)); - EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07.12345-07:00", + absl::time_internal::cctz::format(RFC3339_full, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07-07:00", + absl::time_internal::cctz::format(RFC3339_sec, tp, tz)); tp += chrono::microseconds(6); - EXPECT_EQ("1977-06-28T09:08:07.123456-07:00", format(RFC3339_full, tp, tz)); - EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07.123456-07:00", + absl::time_internal::cctz::format(RFC3339_full, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07-07:00", + absl::time_internal::cctz::format(RFC3339_sec, tp, tz)); tp += chrono::nanoseconds(700); - EXPECT_EQ("1977-06-28T09:08:07.1234567-07:00", format(RFC3339_full, tp, tz)); - EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07.1234567-07:00", + absl::time_internal::cctz::format(RFC3339_full, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07-07:00", + absl::time_internal::cctz::format(RFC3339_sec, tp, tz)); tp += chrono::nanoseconds(80); - EXPECT_EQ("1977-06-28T09:08:07.12345678-07:00", format(RFC3339_full, tp, tz)); - EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07.12345678-07:00", + absl::time_internal::cctz::format(RFC3339_full, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07-07:00", + absl::time_internal::cctz::format(RFC3339_sec, tp, tz)); tp += chrono::nanoseconds(9); EXPECT_EQ("1977-06-28T09:08:07.123456789-07:00", - format(RFC3339_full, tp, tz)); - EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); + absl::time_internal::cctz::format(RFC3339_full, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07-07:00", + absl::time_internal::cctz::format(RFC3339_sec, tp, tz)); } TEST(Format, RFC1123Format) { // locale specific @@ -684,36 +740,50 @@ TEST(Format, RFC1123Format) { // locale specific EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz)); auto tp = convert(civil_second(1977, 6, 28, 9, 8, 7), tz); - EXPECT_EQ("Tue, 28 Jun 1977 09:08:07 -0700", format(RFC1123_full, tp, tz)); - EXPECT_EQ("28 Jun 1977 09:08:07 -0700", format(RFC1123_no_wday, tp, tz)); + EXPECT_EQ("Tue, 28 Jun 1977 09:08:07 -0700", + absl::time_internal::cctz::format(RFC1123_full, tp, tz)); + EXPECT_EQ("28 Jun 1977 09:08:07 -0700", + absl::time_internal::cctz::format(RFC1123_no_wday, tp, tz)); } TEST(Format, Week) { const time_zone utc = utc_time_zone(); auto tp = convert(civil_second(2017, 1, 1, 0, 0, 0), utc); - EXPECT_EQ("2017-01-7", format("%Y-%U-%u", tp, utc)); - EXPECT_EQ("2017-00-0", format("%Y-%W-%w", tp, utc)); + EXPECT_EQ("2017-01-7", + absl::time_internal::cctz::format("%Y-%U-%u", tp, utc)); + EXPECT_EQ("2017-00-0", + absl::time_internal::cctz::format("%Y-%W-%w", tp, utc)); tp = convert(civil_second(2017, 12, 31, 0, 0, 0), utc); - EXPECT_EQ("2017-53-7", format("%Y-%U-%u", tp, utc)); - EXPECT_EQ("2017-52-0", format("%Y-%W-%w", tp, utc)); + EXPECT_EQ("2017-53-7", + absl::time_internal::cctz::format("%Y-%U-%u", tp, utc)); + EXPECT_EQ("2017-52-0", + absl::time_internal::cctz::format("%Y-%W-%w", tp, utc)); tp = convert(civil_second(2018, 1, 1, 0, 0, 0), utc); - EXPECT_EQ("2018-00-1", format("%Y-%U-%u", tp, utc)); - EXPECT_EQ("2018-01-1", format("%Y-%W-%w", tp, utc)); + EXPECT_EQ("2018-00-1", + absl::time_internal::cctz::format("%Y-%U-%u", tp, utc)); + EXPECT_EQ("2018-01-1", + absl::time_internal::cctz::format("%Y-%W-%w", tp, utc)); tp = convert(civil_second(2018, 12, 31, 0, 0, 0), utc); - EXPECT_EQ("2018-52-1", format("%Y-%U-%u", tp, utc)); - EXPECT_EQ("2018-53-1", format("%Y-%W-%w", tp, utc)); + EXPECT_EQ("2018-52-1", + absl::time_internal::cctz::format("%Y-%U-%u", tp, utc)); + EXPECT_EQ("2018-53-1", + absl::time_internal::cctz::format("%Y-%W-%w", tp, utc)); tp = convert(civil_second(2019, 1, 1, 0, 0, 0), utc); - EXPECT_EQ("2019-00-2", format("%Y-%U-%u", tp, utc)); - EXPECT_EQ("2019-00-2", format("%Y-%W-%w", tp, utc)); + EXPECT_EQ("2019-00-2", + absl::time_internal::cctz::format("%Y-%U-%u", tp, utc)); + EXPECT_EQ("2019-00-2", + absl::time_internal::cctz::format("%Y-%W-%w", tp, utc)); tp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc); - EXPECT_EQ("2019-52-2", format("%Y-%U-%u", tp, utc)); - EXPECT_EQ("2019-52-2", format("%Y-%W-%w", tp, utc)); + EXPECT_EQ("2019-52-2", + absl::time_internal::cctz::format("%Y-%U-%u", tp, utc)); + EXPECT_EQ("2019-52-2", + absl::time_internal::cctz::format("%Y-%W-%w", tp, utc)); } // @@ -726,39 +796,46 @@ TEST(Parse, TimePointResolution) { time_point tp_ns; EXPECT_TRUE(parse(kFmt, "03:04:05.123456789", utc, &tp_ns)); - EXPECT_EQ("03:04:05.123456789", format(kFmt, tp_ns, utc)); + EXPECT_EQ("03:04:05.123456789", + absl::time_internal::cctz::format(kFmt, tp_ns, utc)); EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_ns)); - EXPECT_EQ("03:04:05.123456", format(kFmt, tp_ns, utc)); + EXPECT_EQ("03:04:05.123456", + absl::time_internal::cctz::format(kFmt, tp_ns, utc)); time_point tp_us; EXPECT_TRUE(parse(kFmt, "03:04:05.123456789", utc, &tp_us)); - EXPECT_EQ("03:04:05.123456", format(kFmt, tp_us, utc)); + EXPECT_EQ("03:04:05.123456", + absl::time_internal::cctz::format(kFmt, tp_us, utc)); EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_us)); - EXPECT_EQ("03:04:05.123456", format(kFmt, tp_us, utc)); + EXPECT_EQ("03:04:05.123456", + absl::time_internal::cctz::format(kFmt, tp_us, utc)); EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_us)); - EXPECT_EQ("03:04:05.123", format(kFmt, tp_us, utc)); + EXPECT_EQ("03:04:05.123", + absl::time_internal::cctz::format(kFmt, tp_us, utc)); time_point tp_ms; EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_ms)); - EXPECT_EQ("03:04:05.123", format(kFmt, tp_ms, utc)); + EXPECT_EQ("03:04:05.123", + absl::time_internal::cctz::format(kFmt, tp_ms, utc)); EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_ms)); - EXPECT_EQ("03:04:05.123", format(kFmt, tp_ms, utc)); + EXPECT_EQ("03:04:05.123", + absl::time_internal::cctz::format(kFmt, tp_ms, utc)); EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_ms)); - EXPECT_EQ("03:04:05", format(kFmt, tp_ms, utc)); + EXPECT_EQ("03:04:05", absl::time_internal::cctz::format(kFmt, tp_ms, utc)); time_point tp_s; EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_s)); - EXPECT_EQ("03:04:05", format(kFmt, tp_s, utc)); + EXPECT_EQ("03:04:05", absl::time_internal::cctz::format(kFmt, tp_s, utc)); EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_s)); - EXPECT_EQ("03:04:05", format(kFmt, tp_s, utc)); + EXPECT_EQ("03:04:05", absl::time_internal::cctz::format(kFmt, tp_s, utc)); time_point tp_m; EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_m)); - EXPECT_EQ("03:04:00", format(kFmt, tp_m, utc)); + EXPECT_EQ("03:04:00", absl::time_internal::cctz::format(kFmt, tp_m, utc)); time_point tp_h; EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_h)); - EXPECT_EQ("03:00:00", format(kFmt, tp_h, utc)); + EXPECT_EQ("03:00:00", absl::time_internal::cctz::format(kFmt, tp_h, utc)); } TEST(Parse, TimePointExtendedResolution) { @@ -1550,7 +1627,7 @@ TEST(Parse, TimePointOverflow) { parse(RFC3339_full, "2262-04-11T23:47:16.8547758079+00:00", utc, &tp)); EXPECT_EQ(tp, time_point::max()); EXPECT_EQ("2262-04-11T23:47:16.854775807+00:00", - format(RFC3339_full, tp, utc)); + absl::time_internal::cctz::format(RFC3339_full, tp, utc)); #if 0 // TODO(#199): Will fail until cctz::parse() properly detects overflow. EXPECT_FALSE( @@ -1559,7 +1636,7 @@ TEST(Parse, TimePointOverflow) { parse(RFC3339_full, "1677-09-21T00:12:43.1452241920+00:00", utc, &tp)); EXPECT_EQ(tp, time_point::min()); EXPECT_EQ("1677-09-21T00:12:43.145224192+00:00", - format(RFC3339_full, tp, utc)); + absl::time_internal::cctz::format(RFC3339_full, tp, utc)); EXPECT_FALSE( parse(RFC3339_full, "1677-09-21T00:12:43.1452241919+00:00", utc, &tp)); #endif @@ -1569,12 +1646,14 @@ TEST(Parse, TimePointOverflow) { EXPECT_TRUE(parse(RFC3339_full, "1970-01-01T00:02:07.9+00:00", utc, &stp)); EXPECT_EQ(stp, time_point::max()); - EXPECT_EQ("1970-01-01T00:02:07+00:00", format(RFC3339_full, stp, utc)); + EXPECT_EQ("1970-01-01T00:02:07+00:00", + absl::time_internal::cctz::format(RFC3339_full, stp, utc)); EXPECT_FALSE(parse(RFC3339_full, "1970-01-01T00:02:08+00:00", utc, &stp)); EXPECT_TRUE(parse(RFC3339_full, "1969-12-31T23:57:52+00:00", utc, &stp)); EXPECT_EQ(stp, time_point::min()); - EXPECT_EQ("1969-12-31T23:57:52+00:00", format(RFC3339_full, stp, utc)); + EXPECT_EQ("1969-12-31T23:57:52+00:00", + absl::time_internal::cctz::format(RFC3339_full, stp, utc)); EXPECT_FALSE(parse(RFC3339_full, "1969-12-31T23:57:51.9+00:00", utc, &stp)); using DM = chrono::duration; @@ -1582,12 +1661,14 @@ TEST(Parse, TimePointOverflow) { EXPECT_TRUE(parse(RFC3339_full, "1970-01-01T02:07:59+00:00", utc, &mtp)); EXPECT_EQ(mtp, time_point::max()); - EXPECT_EQ("1970-01-01T02:07:00+00:00", format(RFC3339_full, mtp, utc)); + EXPECT_EQ("1970-01-01T02:07:00+00:00", + absl::time_internal::cctz::format(RFC3339_full, mtp, utc)); EXPECT_FALSE(parse(RFC3339_full, "1970-01-01T02:08:00+00:00", utc, &mtp)); EXPECT_TRUE(parse(RFC3339_full, "1969-12-31T21:52:00+00:00", utc, &mtp)); EXPECT_EQ(mtp, time_point::min()); - EXPECT_EQ("1969-12-31T21:52:00+00:00", format(RFC3339_full, mtp, utc)); + EXPECT_EQ("1969-12-31T21:52:00+00:00", + absl::time_internal::cctz::format(RFC3339_full, mtp, utc)); EXPECT_FALSE(parse(RFC3339_full, "1969-12-31T21:51:59+00:00", utc, &mtp)); } @@ -1601,7 +1682,7 @@ TEST(Parse, TimePointOverflowFloor) { parse(RFC3339_full, "294247-01-10T04:00:54.7758079+00:00", utc, &tp)); EXPECT_EQ(tp, time_point::max()); EXPECT_EQ("294247-01-10T04:00:54.775807+00:00", - format(RFC3339_full, tp, utc)); + absl::time_internal::cctz::format(RFC3339_full, tp, utc)); #if 0 // TODO(#199): Will fail until cctz::parse() properly detects overflow. EXPECT_FALSE( @@ -1610,7 +1691,7 @@ TEST(Parse, TimePointOverflowFloor) { parse(RFC3339_full, "-290308-12-21T19:59:05.2241920+00:00", utc, &tp)); EXPECT_EQ(tp, time_point::min()); EXPECT_EQ("-290308-12-21T19:59:05.224192+00:00", - format(RFC3339_full, tp, utc)); + absl::time_internal::cctz::format(RFC3339_full, tp, utc)); EXPECT_FALSE( parse(RFC3339_full, "-290308-12-21T19:59:05.2241919+00:00", utc, &tp)); #endif @@ -1629,7 +1710,8 @@ TEST(FormatParse, RoundTrip) { // RFC3339, which renders subseconds. { time_point out; - const std::string s = format(RFC3339_full, in + subseconds, lax); + const std::string s = + absl::time_internal::cctz::format(RFC3339_full, in + subseconds, lax); EXPECT_TRUE(parse(RFC3339_full, s, lax, &out)) << s; EXPECT_EQ(in + subseconds, out); // RFC3339_full includes %Ez } @@ -1637,7 +1719,8 @@ TEST(FormatParse, RoundTrip) { // RFC1123, which only does whole seconds. { time_point out; - const std::string s = format(RFC1123_full, in, lax); + const std::string s = + absl::time_internal::cctz::format(RFC1123_full, in, lax); EXPECT_TRUE(parse(RFC1123_full, s, lax, &out)) << s; EXPECT_EQ(in, out); // RFC1123_full includes %z } @@ -1655,7 +1738,7 @@ TEST(FormatParse, RoundTrip) { { time_point out; time_zone utc = utc_time_zone(); - const std::string s = format("%c", in, utc); + const std::string s = absl::time_internal::cctz::format("%c", in, utc); EXPECT_TRUE(parse("%c", s, utc, &out)) << s; EXPECT_EQ(in, out); } @@ -1666,7 +1749,8 @@ TEST(FormatParse, RoundTripDistantFuture) { const time_zone utc = utc_time_zone(); const time_point in = time_point::max(); - const std::string s = format(RFC3339_full, in, utc); + const std::string s = + absl::time_internal::cctz::format(RFC3339_full, in, utc); time_point out; EXPECT_TRUE(parse(RFC3339_full, s, utc, &out)) << s; EXPECT_EQ(in, out); @@ -1676,7 +1760,8 @@ TEST(FormatParse, RoundTripDistantPast) { const time_zone utc = utc_time_zone(); const time_point in = time_point::min(); - const std::string s = format(RFC3339_full, in, utc); + const std::string s = + absl::time_internal::cctz::format(RFC3339_full, in, utc); time_point out; EXPECT_TRUE(parse(RFC3339_full, s, utc, &out)) << s; EXPECT_EQ(in, out); diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc index ab461f04515..4b093b37837 100644 --- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc +++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc @@ -911,19 +911,19 @@ TEST(MakeTime, TimePointResolution) { const time_zone utc = utc_time_zone(); const time_point tp_ns = convert(civil_second(2015, 1, 2, 3, 4, 5), utc); - EXPECT_EQ("04:05", format("%M:%E*S", tp_ns, utc)); + EXPECT_EQ("04:05", absl::time_internal::cctz::format("%M:%E*S", tp_ns, utc)); const time_point tp_us = convert(civil_second(2015, 1, 2, 3, 4, 5), utc); - EXPECT_EQ("04:05", format("%M:%E*S", tp_us, utc)); + EXPECT_EQ("04:05", absl::time_internal::cctz::format("%M:%E*S", tp_us, utc)); const time_point tp_ms = convert(civil_second(2015, 1, 2, 3, 4, 5), utc); - EXPECT_EQ("04:05", format("%M:%E*S", tp_ms, utc)); + EXPECT_EQ("04:05", absl::time_internal::cctz::format("%M:%E*S", tp_ms, utc)); const time_point tp_s = convert(civil_second(2015, 1, 2, 3, 4, 5), utc); - EXPECT_EQ("04:05", format("%M:%E*S", tp_s, utc)); + EXPECT_EQ("04:05", absl::time_internal::cctz::format("%M:%E*S", tp_s, utc)); const time_point tp_s64 = convert(civil_second(2015, 1, 2, 3, 4, 5), utc); - EXPECT_EQ("04:05", format("%M:%E*S", tp_s64, utc)); + EXPECT_EQ("04:05", absl::time_internal::cctz::format("%M:%E*S", tp_s64, utc)); // These next two require chrono::time_point_cast because the conversion // from a resolution of seconds (the return value of convert()) to a @@ -931,10 +931,10 @@ TEST(MakeTime, TimePointResolution) { const time_point tp_m = chrono::time_point_cast( convert(civil_second(2015, 1, 2, 3, 4, 5), utc)); - EXPECT_EQ("04:00", format("%M:%E*S", tp_m, utc)); + EXPECT_EQ("04:00", absl::time_internal::cctz::format("%M:%E*S", tp_m, utc)); const time_point tp_h = chrono::time_point_cast( convert(civil_second(2015, 1, 2, 3, 4, 5), utc)); - EXPECT_EQ("00:00", format("%M:%E*S", tp_h, utc)); + EXPECT_EQ("00:00", absl::time_internal::cctz::format("%M:%E*S", tp_h, utc)); } TEST(MakeTime, Normalization) { @@ -960,9 +960,11 @@ TEST(MakeTime, SysSecondsLimits) { // Approach the maximal time_point value from below. tp = convert(civil_second(292277026596, 12, 4, 15, 30, 6), utc); - EXPECT_EQ("292277026596-12-04T15:30:06+00:00", format(RFC3339, tp, utc)); + EXPECT_EQ("292277026596-12-04T15:30:06+00:00", + absl::time_internal::cctz::format(RFC3339, tp, utc)); tp = convert(civil_second(292277026596, 12, 4, 15, 30, 7), utc); - EXPECT_EQ("292277026596-12-04T15:30:07+00:00", format(RFC3339, tp, utc)); + EXPECT_EQ("292277026596-12-04T15:30:07+00:00", + absl::time_internal::cctz::format(RFC3339, tp, utc)); EXPECT_EQ(time_point::max(), tp); tp = convert(civil_second(292277026596, 12, 4, 15, 30, 8), utc); EXPECT_EQ(time_point::max(), tp); @@ -971,7 +973,8 @@ TEST(MakeTime, SysSecondsLimits) { // Checks that we can also get the maximal value for a far-east zone. tp = convert(civil_second(292277026596, 12, 5, 5, 30, 7), east); - EXPECT_EQ("292277026596-12-05T05:30:07+14:00", format(RFC3339, tp, east)); + EXPECT_EQ("292277026596-12-05T05:30:07+14:00", + absl::time_internal::cctz::format(RFC3339, tp, east)); EXPECT_EQ(time_point::max(), tp); tp = convert(civil_second(292277026596, 12, 5, 5, 30, 8), east); EXPECT_EQ(time_point::max(), tp); @@ -980,7 +983,8 @@ TEST(MakeTime, SysSecondsLimits) { // Checks that we can also get the maximal value for a far-west zone. tp = convert(civil_second(292277026596, 12, 4, 1, 30, 7), west); - EXPECT_EQ("292277026596-12-04T01:30:07-14:00", format(RFC3339, tp, west)); + EXPECT_EQ("292277026596-12-04T01:30:07-14:00", + absl::time_internal::cctz::format(RFC3339, tp, west)); EXPECT_EQ(time_point::max(), tp); tp = convert(civil_second(292277026596, 12, 4, 7, 30, 8), west); EXPECT_EQ(time_point::max(), tp); @@ -989,9 +993,11 @@ TEST(MakeTime, SysSecondsLimits) { // Approach the minimal time_point value from above. tp = convert(civil_second(-292277022657, 1, 27, 8, 29, 53), utc); - EXPECT_EQ("-292277022657-01-27T08:29:53+00:00", format(RFC3339, tp, utc)); + EXPECT_EQ("-292277022657-01-27T08:29:53+00:00", + absl::time_internal::cctz::format(RFC3339, tp, utc)); tp = convert(civil_second(-292277022657, 1, 27, 8, 29, 52), utc); - EXPECT_EQ("-292277022657-01-27T08:29:52+00:00", format(RFC3339, tp, utc)); + EXPECT_EQ("-292277022657-01-27T08:29:52+00:00", + absl::time_internal::cctz::format(RFC3339, tp, utc)); EXPECT_EQ(time_point::min(), tp); tp = convert(civil_second(-292277022657, 1, 27, 8, 29, 51), utc); EXPECT_EQ(time_point::min(), tp); @@ -1000,7 +1006,8 @@ TEST(MakeTime, SysSecondsLimits) { // Checks that we can also get the minimal value for a far-east zone. tp = convert(civil_second(-292277022657, 1, 27, 22, 29, 52), east); - EXPECT_EQ("-292277022657-01-27T22:29:52+14:00", format(RFC3339, tp, east)); + EXPECT_EQ("-292277022657-01-27T22:29:52+14:00", + absl::time_internal::cctz::format(RFC3339, tp, east)); EXPECT_EQ(time_point::min(), tp); tp = convert(civil_second(-292277022657, 1, 27, 22, 29, 51), east); EXPECT_EQ(time_point::min(), tp); @@ -1009,7 +1016,8 @@ TEST(MakeTime, SysSecondsLimits) { // Checks that we can also get the minimal value for a far-west zone. tp = convert(civil_second(-292277022657, 1, 26, 18, 29, 52), west); - EXPECT_EQ("-292277022657-01-26T18:29:52-14:00", format(RFC3339, tp, west)); + EXPECT_EQ("-292277022657-01-26T18:29:52-14:00", + absl::time_internal::cctz::format(RFC3339, tp, west)); EXPECT_EQ(time_point::min(), tp); tp = convert(civil_second(-292277022657, 1, 26, 18, 29, 51), west); EXPECT_EQ(time_point::min(), tp); @@ -1029,14 +1037,16 @@ TEST(MakeTime, SysSecondsLimits) { #if defined(__FreeBSD__) || defined(__OpenBSD__) // The BSD gmtime_r() fails on extreme positive tm_year values. #else - EXPECT_EQ("2147485547-12-31T23:59:59+00:00", format(RFC3339, tp, cut)); + EXPECT_EQ("2147485547-12-31T23:59:59+00:00", + absl::time_internal::cctz::format(RFC3339, tp, cut)); #endif const year_t min_tm_year = year_t{std::numeric_limits::min()} + 1900; tp = convert(civil_second(min_tm_year, 1, 1, 0, 0, 0), cut); #if defined(__Fuchsia__) // Fuchsia's gmtime_r() fails on extreme negative values (fxbug.dev/78527). #else - EXPECT_EQ("-2147481748-01-01T00:00:00+00:00", format(RFC3339, tp, cut)); + EXPECT_EQ("-2147481748-01-01T00:00:00+00:00", + absl::time_internal::cctz::format(RFC3339, tp, cut)); #endif #endif } From 15d26cdd0179f83b328f3b62ae7d08388ffeef0b Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 19 May 2023 16:17:08 -0700 Subject: [PATCH 0017/1238] Optimize absl::StrCat for integers Previous implementation used a lookup table of 200 bytes which, if not in L1 cache, could cause memory stalls and consumes 3-4 cache lines. This is suboptimal in real world scenarious. We are going to use a purely scalar version of merging 2/4/8 bytes together. PiperOrigin-RevId: 533576619 Change-Id: Icd730d18536f7eb35979b62582f6edf86b786019 --- absl/strings/numbers.cc | 245 +++++++++++++++++++++++----------------- 1 file changed, 143 insertions(+), 102 deletions(-) diff --git a/absl/strings/numbers.cc b/absl/strings/numbers.cc index c2b861ae733..8c05ff0e485 100644 --- a/absl/strings/numbers.cc +++ b/absl/strings/numbers.cc @@ -32,6 +32,7 @@ #include "absl/base/attributes.h" #include "absl/base/internal/raw_logging.h" +#include "absl/base/optimization.h" #include "absl/numeric/bits.h" #include "absl/strings/ascii.h" #include "absl/strings/charconv.h" @@ -136,82 +137,123 @@ bool SimpleAtob(absl::string_view str, bool* out) { namespace { -// Used to optimize printing a decimal number's final digit. -const char one_ASCII_final_digits[10][2] { - {'0', 0}, {'1', 0}, {'2', 0}, {'3', 0}, {'4', 0}, - {'5', 0}, {'6', 0}, {'7', 0}, {'8', 0}, {'9', 0}, -}; +// Various routines to encode integers to strings. + +// We split data encodings into a group of 2 digits, 4 digits, 8 digits as +// it's easier to combine powers of two into scalar arithmetic. + +// Previous implementation used a lookup table of 200 bytes for every 2 bytes +// and it was memory bound, any L1 cache miss would result in a much slower +// result. When benchmarking with a cache eviction rate of several percent, +// this implementation proved to be better. + +// These constants represent '00', '0000' and '00000000' as ascii strings in +// integers. We can add these numbers if we encode to bytes from 0 to 9. as +// 'i' = '0' + i for 0 <= i <= 9. +constexpr uint32_t kTwoZeroBytes = 0x0101 * '0'; +constexpr uint64_t kFourZeroBytes = 0x01010101 * '0'; +constexpr uint64_t kEightZeroBytes = 0x0101010101010101ull * '0'; + +// * 103 / 1024 is a division by 10 for values from 0 to 99. It's also a +// division of a structure [k takes 2 bytes][m takes 2 bytes], then * 103 / 1024 +// will be [k / 10][m / 10]. It allows parallel division. +constexpr uint64_t kDivisionBy10Mul = 103u; +constexpr uint64_t kDivisionBy10Div = 1 << 10; + +// * 10486 / 1048576 is a division by 100 for values from 0 to 9999. +constexpr uint64_t kDivisionBy100Mul = 10486u; +constexpr uint64_t kDivisionBy100Div = 1 << 20; + +// Encode functions write the ASCII output of input `n` to `out_str`. +inline char* EncodeHundred(uint32_t n, char* out_str) { + int num_digits = static_cast(n - 10) >> 8; + uint32_t base = kTwoZeroBytes; + uint32_t div10 = (n * kDivisionBy10Mul) / kDivisionBy10Div; + uint32_t mod10 = n - 10u * div10; + base += div10 + (mod10 << 8); + base >>= num_digits & 8; + memcpy(out_str, &base, 2); + return out_str + 2 + num_digits; +} -} // namespace +inline char* EncodeTenThousand(uint32_t n, char* out_str) { + // We split lower 2 digits and upper 2 digits of n into 2 byte consecutive + // blocks. 123 -> [\0\1][\0\23]. We divide by 10 both blocks + // (it's 1 division + zeroing upper bits), and compute modulo 10 as well "in + // parallel". Then we combine both results to have both ASCII digits, + // strip trailing zeros, add ASCII '0000' and return. + uint32_t div100 = (n * kDivisionBy100Mul) / kDivisionBy100Div; + uint32_t mod100 = n - 100ull * div100; + uint32_t hundreds = (mod100 << 16) + div100; + uint32_t tens = (hundreds * kDivisionBy10Mul) / kDivisionBy10Div; + tens &= (0xFull << 16) | 0xFull; + tens += (hundreds - 10ull * tens) << 8; + ABSL_ASSUME(tens != 0); + // The result can contain trailing zero bits, we need to strip them to a first + // significant byte in a final representation. For example, for n = 123, we + // have tens to have representation \0\1\2\3. We do `& -8` to round + // to a multiple to 8 to strip zero bytes, not all zero bits. + // countr_zero to help. + // 0 minus 8 to make MSVC happy. + uint32_t zeroes = static_cast(absl::countr_zero(tens)) & (0 - 8ull); + tens += kFourZeroBytes; + tens >>= zeroes; + memcpy(out_str, &tens, sizeof(tens)); + return out_str + sizeof(tens) - zeroes / 8; +} -char* numbers_internal::FastIntToBuffer(uint32_t i, char* buffer) { - uint32_t digits; - // The idea of this implementation is to trim the number of divides to as few - // as possible, and also reducing memory stores and branches, by going in - // steps of two digits at a time rather than one whenever possible. - // The huge-number case is first, in the hopes that the compiler will output - // that case in one branch-free block of code, and only output conditional - // branches into it from below. - if (i >= 1000000000) { // >= 1,000,000,000 - digits = i / 100000000; // 100,000,000 - i -= digits * 100000000; - PutTwoDigits(digits, buffer); - buffer += 2; - lt100_000_000: - digits = i / 1000000; // 1,000,000 - i -= digits * 1000000; - PutTwoDigits(digits, buffer); - buffer += 2; - lt1_000_000: - digits = i / 10000; // 10,000 - i -= digits * 10000; - PutTwoDigits(digits, buffer); - buffer += 2; - lt10_000: - digits = i / 100; - i -= digits * 100; - PutTwoDigits(digits, buffer); - buffer += 2; - lt100: - digits = i; - PutTwoDigits(digits, buffer); - buffer += 2; - *buffer = 0; - return buffer; - } +// Prepare functions return an integer that should be written to out_str +// (but possibly include trailing zeros). +// For hi < 10000, lo < 10000 returns uint64_t as encoded in ASCII with +// possibly trailing zeroes of the number hi * 10000 + lo. +inline uint64_t PrepareTenThousands(uint64_t hi, uint64_t lo) { + uint64_t merged = hi | (lo << 32); + uint64_t div100 = ((merged * kDivisionBy100Mul) / kDivisionBy100Div) & + ((0x7Full << 32) | 0x7Full); + uint64_t mod100 = merged - 100ull * div100; + uint64_t hundreds = (mod100 << 16) + div100; + uint64_t tens = (hundreds * kDivisionBy10Mul) / kDivisionBy10Div; + tens &= (0xFull << 48) | (0xFull << 32) | (0xFull << 16) | 0xFull; + tens += (hundreds - 10ull * tens) << 8; + return tens; +} - if (i < 100) { - digits = i; - if (i >= 10) goto lt100; - memcpy(buffer, one_ASCII_final_digits[i], 2); - return buffer + 1; - } - if (i < 10000) { // 10,000 - if (i >= 1000) goto lt10_000; - digits = i / 100; - i -= digits * 100; - *buffer++ = '0' + static_cast(digits); - goto lt100; +inline char* EncodeFullU32(uint32_t n, char* out_str) { + if (n < 100'000'000) { + uint64_t bottom = PrepareTenThousands(n / 10000, n % 10000); + ABSL_ASSUME(bottom != 0); + // 0 minus 8 to make MSVC happy. + uint32_t zeroes = static_cast(absl::countr_zero(bottom)) + & (0 - 8ull); + uint64_t bottom_res = bottom + kEightZeroBytes; + bottom_res >>= zeroes; + memcpy(out_str, &bottom_res, sizeof(bottom)); + return out_str + sizeof(bottom) - zeroes / 8; } - if (i < 1000000) { // 1,000,000 - if (i >= 100000) goto lt1_000_000; - digits = i / 10000; // 10,000 - i -= digits * 10000; - *buffer++ = '0' + static_cast(digits); - goto lt10_000; + uint32_t top = n / 100'000'000; + n %= 100'000'000; + uint64_t bottom = PrepareTenThousands(n / 10000, n % 10000); + uint64_t bottom_res = bottom + kEightZeroBytes; + out_str = EncodeHundred(top, out_str); + memcpy(out_str, &bottom_res, sizeof(bottom)); + return out_str + sizeof(bottom); +} + +} // namespace + +char* numbers_internal::FastIntToBuffer(uint32_t n, char* out_str) { + if (n < 100) { + out_str = EncodeHundred(n, out_str); + goto set_last_zero; } - if (i < 100000000) { // 100,000,000 - if (i >= 10000000) goto lt100_000_000; - digits = i / 1000000; // 1,000,000 - i -= digits * 1000000; - *buffer++ = '0' + static_cast(digits); - goto lt1_000_000; + if (n < 10000) { + out_str = EncodeTenThousand(n, out_str); + goto set_last_zero; } - // we already know that i < 1,000,000,000 - digits = i / 100000000; // 100,000,000 - i -= digits * 100000000; - *buffer++ = '0' + static_cast(digits); - goto lt100_000_000; + out_str = EncodeFullU32(n, out_str); +set_last_zero: + *out_str = '\0'; + return out_str; } char* numbers_internal::FastIntToBuffer(int32_t i, char* buffer) { @@ -230,41 +272,40 @@ char* numbers_internal::FastIntToBuffer(uint64_t i, char* buffer) { uint32_t u32 = static_cast(i); if (u32 == i) return numbers_internal::FastIntToBuffer(u32, buffer); - // Here we know i has at least 10 decimal digits. - uint64_t top_1to11 = i / 1000000000; - u32 = static_cast(i - top_1to11 * 1000000000); - uint32_t top_1to11_32 = static_cast(top_1to11); + // 10**9 < 2**32 <= i < 10**10, we can do 2+8 + uint64_t div08 = i / 100'000'000ull; + uint64_t mod08 = i % 100'000'000ull; + uint64_t mod_result = + PrepareTenThousands(mod08 / 10000, mod08 % 10000) + kEightZeroBytes; + if (i < 10'000'000'000ull) { + buffer = EncodeHundred(static_cast(div08), buffer); + memcpy(buffer, &mod_result, 8); + buffer += 8; + goto set_last_zero; + } - if (top_1to11_32 == top_1to11) { - buffer = numbers_internal::FastIntToBuffer(top_1to11_32, buffer); + // i < 10**16, in this case 8+8 + if (i < 10'000'000'000'000'000ull) { + buffer = EncodeFullU32(static_cast(div08), buffer); + memcpy(buffer, &mod_result, 8); + buffer += 8; + goto set_last_zero; } else { - // top_1to11 has more than 32 bits too; print it in two steps. - uint32_t top_8to9 = static_cast(top_1to11 / 100); - uint32_t mid_2 = static_cast(top_1to11 - top_8to9 * 100); - buffer = numbers_internal::FastIntToBuffer(top_8to9, buffer); - PutTwoDigits(mid_2, buffer); - buffer += 2; + // 4 + 8 + 8 + uint64_t div016 = i / 10'000'000'000'000'000ull; + buffer = EncodeTenThousand(static_cast(div016), buffer); + uint64_t mid_result = div08 - div016 * 100'000'000ull; + mid_result = PrepareTenThousands(mid_result / 10000, mid_result % 10000) + + kEightZeroBytes; + memcpy(buffer, &mid_result, 8); + buffer += 8; + memcpy(buffer, &mod_result, 8); + buffer += 8; + goto set_last_zero; } - - // We have only 9 digits now, again the maximum uint32_t can handle fully. - uint32_t digits = u32 / 10000000; // 10,000,000 - u32 -= digits * 10000000; - PutTwoDigits(digits, buffer); - buffer += 2; - digits = u32 / 100000; // 100,000 - u32 -= digits * 100000; - PutTwoDigits(digits, buffer); - buffer += 2; - digits = u32 / 1000; // 1,000 - u32 -= digits * 1000; - PutTwoDigits(digits, buffer); - buffer += 2; - digits = u32 / 10; - u32 -= digits * 10; - PutTwoDigits(digits, buffer); - buffer += 2; - memcpy(buffer, one_ASCII_final_digits[u32], 2); - return buffer + 1; +set_last_zero: + *buffer = '\0'; + return buffer; } char* numbers_internal::FastIntToBuffer(int64_t i, char* buffer) { From 68be7315913c8ef8a791a0fb60d98e98787d88b6 Mon Sep 17 00:00:00 2001 From: Andy Getzendanner Date: Fri, 19 May 2023 18:53:34 -0700 Subject: [PATCH 0018/1238] Rename ABSL_*_IMPL macros to match the other ABSL_LOG_INTERNAL_* macros and to make sure it's clear that they're internal. Also rename the log and check test files from .h to .inc per https://google.github.io/styleguide/cppguide.html#Self_contained_Headers. PiperOrigin-RevId: 533603350 Change-Id: Iad5d8b683e33b63784cc8e64b84da09f5fc3bf1e --- absl/log/BUILD.bazel | 4 +- absl/log/CMakeLists.txt | 9 +- absl/log/absl_check.h | 86 +++++++----- absl/log/absl_check_test.cc | 2 +- absl/log/absl_log.h | 69 +++++----- absl/log/absl_log_basic_test.cc | 2 +- absl/log/check.h | 100 +++++++++----- absl/log/check_test.cc | 2 +- ...{check_test_impl.h => check_test_impl.inc} | 0 absl/log/internal/check_impl.h | 126 +++++++++--------- absl/log/internal/log_impl.h | 100 +++++++------- absl/log/log.h | 72 +++++----- absl/log/log_basic_test.cc | 2 +- ...ic_test_impl.h => log_basic_test_impl.inc} | 18 +-- 14 files changed, 327 insertions(+), 265 deletions(-) rename absl/log/{check_test_impl.h => check_test_impl.inc} (100%) rename absl/log/{log_basic_test_impl.h => log_basic_test_impl.inc} (98%) diff --git a/absl/log/BUILD.bazel b/absl/log/BUILD.bazel index 4813111fd0f..560f6c4417d 100644 --- a/absl/log/BUILD.bazel +++ b/absl/log/BUILD.bazel @@ -289,7 +289,7 @@ cc_library( "no_test_ios", "no_test_wasm", ], - textual_hdrs = ["check_test_impl.h"], + textual_hdrs = ["check_test_impl.inc"], visibility = ["//visibility:private"], deps = [ "//absl/base:config", @@ -373,7 +373,7 @@ cc_library( testonly = True, copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - textual_hdrs = ["log_basic_test_impl.h"], + textual_hdrs = ["log_basic_test_impl.inc"], visibility = ["//visibility:private"], deps = [ "//absl/base", diff --git a/absl/log/CMakeLists.txt b/absl/log/CMakeLists.txt index 4cba008277c..2990984f488 100644 --- a/absl/log/CMakeLists.txt +++ b/absl/log/CMakeLists.txt @@ -1,4 +1,3 @@ -# # Copyright 2022 The Abseil Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -679,7 +678,7 @@ absl_cc_test( absl_check_test SRCS "absl_check_test.cc" - "check_test_impl.h" + "check_test_impl.inc" COPTS ${ABSL_TEST_COPTS} LINKOPTS @@ -699,7 +698,7 @@ absl_cc_test( absl_log_basic_test SRCS "log_basic_test.cc" - "log_basic_test_impl.h" + "log_basic_test_impl.inc" COPTS ${ABSL_TEST_COPTS} LINKOPTS @@ -723,7 +722,7 @@ absl_cc_test( check_test SRCS "check_test.cc" - "check_test_impl.h" + "check_test_impl.inc" COPTS ${ABSL_TEST_COPTS} LINKOPTS @@ -759,7 +758,7 @@ absl_cc_test( log_basic_test SRCS "log_basic_test.cc" - "log_basic_test_impl.h" + "log_basic_test_impl.inc" COPTS ${ABSL_TEST_COPTS} LINKOPTS diff --git a/absl/log/absl_check.h b/absl/log/absl_check.h index 14a2307feb2..1bb43bd3442 100644 --- a/absl/log/absl_check.h +++ b/absl/log/absl_check.h @@ -37,69 +37,81 @@ #include "absl/log/internal/check_impl.h" -#define ABSL_CHECK(condition) ABSL_CHECK_IMPL((condition), #condition) -#define ABSL_QCHECK(condition) ABSL_QCHECK_IMPL((condition), #condition) -#define ABSL_PCHECK(condition) ABSL_PCHECK_IMPL((condition), #condition) -#define ABSL_DCHECK(condition) ABSL_DCHECK_IMPL((condition), #condition) +#define ABSL_CHECK(condition) \ + ABSL_LOG_INTERNAL_CHECK_IMPL((condition), #condition) +#define ABSL_QCHECK(condition) \ + ABSL_LOG_INTERNAL_QCHECK_IMPL((condition), #condition) +#define ABSL_PCHECK(condition) \ + ABSL_LOG_INTERNAL_PCHECK_IMPL((condition), #condition) +#define ABSL_DCHECK(condition) \ + ABSL_LOG_INTERNAL_DCHECK_IMPL((condition), #condition) #define ABSL_CHECK_EQ(val1, val2) \ - ABSL_CHECK_EQ_IMPL((val1), #val1, (val2), #val2) + ABSL_LOG_INTERNAL_CHECK_EQ_IMPL((val1), #val1, (val2), #val2) #define ABSL_CHECK_NE(val1, val2) \ - ABSL_CHECK_NE_IMPL((val1), #val1, (val2), #val2) + ABSL_LOG_INTERNAL_CHECK_NE_IMPL((val1), #val1, (val2), #val2) #define ABSL_CHECK_LE(val1, val2) \ - ABSL_CHECK_LE_IMPL((val1), #val1, (val2), #val2) + ABSL_LOG_INTERNAL_CHECK_LE_IMPL((val1), #val1, (val2), #val2) #define ABSL_CHECK_LT(val1, val2) \ - ABSL_CHECK_LT_IMPL((val1), #val1, (val2), #val2) + ABSL_LOG_INTERNAL_CHECK_LT_IMPL((val1), #val1, (val2), #val2) #define ABSL_CHECK_GE(val1, val2) \ - ABSL_CHECK_GE_IMPL((val1), #val1, (val2), #val2) + ABSL_LOG_INTERNAL_CHECK_GE_IMPL((val1), #val1, (val2), #val2) #define ABSL_CHECK_GT(val1, val2) \ - ABSL_CHECK_GT_IMPL((val1), #val1, (val2), #val2) + ABSL_LOG_INTERNAL_CHECK_GT_IMPL((val1), #val1, (val2), #val2) #define ABSL_QCHECK_EQ(val1, val2) \ - ABSL_QCHECK_EQ_IMPL((val1), #val1, (val2), #val2) + ABSL_LOG_INTERNAL_QCHECK_EQ_IMPL((val1), #val1, (val2), #val2) #define ABSL_QCHECK_NE(val1, val2) \ - ABSL_QCHECK_NE_IMPL((val1), #val1, (val2), #val2) + ABSL_LOG_INTERNAL_QCHECK_NE_IMPL((val1), #val1, (val2), #val2) #define ABSL_QCHECK_LE(val1, val2) \ - ABSL_QCHECK_LE_IMPL((val1), #val1, (val2), #val2) + ABSL_LOG_INTERNAL_QCHECK_LE_IMPL((val1), #val1, (val2), #val2) #define ABSL_QCHECK_LT(val1, val2) \ - ABSL_QCHECK_LT_IMPL((val1), #val1, (val2), #val2) + ABSL_LOG_INTERNAL_QCHECK_LT_IMPL((val1), #val1, (val2), #val2) #define ABSL_QCHECK_GE(val1, val2) \ - ABSL_QCHECK_GE_IMPL((val1), #val1, (val2), #val2) + ABSL_LOG_INTERNAL_QCHECK_GE_IMPL((val1), #val1, (val2), #val2) #define ABSL_QCHECK_GT(val1, val2) \ - ABSL_QCHECK_GT_IMPL((val1), #val1, (val2), #val2) + ABSL_LOG_INTERNAL_QCHECK_GT_IMPL((val1), #val1, (val2), #val2) #define ABSL_DCHECK_EQ(val1, val2) \ - ABSL_DCHECK_EQ_IMPL((val1), #val1, (val2), #val2) + ABSL_LOG_INTERNAL_DCHECK_EQ_IMPL((val1), #val1, (val2), #val2) #define ABSL_DCHECK_NE(val1, val2) \ - ABSL_DCHECK_NE_IMPL((val1), #val1, (val2), #val2) + ABSL_LOG_INTERNAL_DCHECK_NE_IMPL((val1), #val1, (val2), #val2) #define ABSL_DCHECK_LE(val1, val2) \ - ABSL_DCHECK_LE_IMPL((val1), #val1, (val2), #val2) + ABSL_LOG_INTERNAL_DCHECK_LE_IMPL((val1), #val1, (val2), #val2) #define ABSL_DCHECK_LT(val1, val2) \ - ABSL_DCHECK_LT_IMPL((val1), #val1, (val2), #val2) + ABSL_LOG_INTERNAL_DCHECK_LT_IMPL((val1), #val1, (val2), #val2) #define ABSL_DCHECK_GE(val1, val2) \ - ABSL_DCHECK_GE_IMPL((val1), #val1, (val2), #val2) + ABSL_LOG_INTERNAL_DCHECK_GE_IMPL((val1), #val1, (val2), #val2) #define ABSL_DCHECK_GT(val1, val2) \ - ABSL_DCHECK_GT_IMPL((val1), #val1, (val2), #val2) + ABSL_LOG_INTERNAL_DCHECK_GT_IMPL((val1), #val1, (val2), #val2) -#define ABSL_CHECK_OK(status) ABSL_CHECK_OK_IMPL((status), #status) -#define ABSL_QCHECK_OK(status) ABSL_QCHECK_OK_IMPL((status), #status) -#define ABSL_DCHECK_OK(status) ABSL_DCHECK_OK_IMPL((status), #status) +#define ABSL_CHECK_OK(status) ABSL_LOG_INTERNAL_CHECK_OK_IMPL((status), #status) +#define ABSL_QCHECK_OK(status) \ + ABSL_LOG_INTERNAL_QCHECK_OK_IMPL((status), #status) +#define ABSL_DCHECK_OK(status) \ + ABSL_LOG_INTERNAL_DCHECK_OK_IMPL((status), #status) -#define ABSL_CHECK_STREQ(s1, s2) ABSL_CHECK_STREQ_IMPL((s1), #s1, (s2), #s2) -#define ABSL_CHECK_STRNE(s1, s2) ABSL_CHECK_STRNE_IMPL((s1), #s1, (s2), #s2) +#define ABSL_CHECK_STREQ(s1, s2) \ + ABSL_LOG_INTERNAL_CHECK_STREQ_IMPL((s1), #s1, (s2), #s2) +#define ABSL_CHECK_STRNE(s1, s2) \ + ABSL_LOG_INTERNAL_CHECK_STRNE_IMPL((s1), #s1, (s2), #s2) #define ABSL_CHECK_STRCASEEQ(s1, s2) \ - ABSL_CHECK_STRCASEEQ_IMPL((s1), #s1, (s2), #s2) + ABSL_LOG_INTERNAL_CHECK_STRCASEEQ_IMPL((s1), #s1, (s2), #s2) #define ABSL_CHECK_STRCASENE(s1, s2) \ - ABSL_CHECK_STRCASENE_IMPL((s1), #s1, (s2), #s2) -#define ABSL_QCHECK_STREQ(s1, s2) ABSL_QCHECK_STREQ_IMPL((s1), #s1, (s2), #s2) -#define ABSL_QCHECK_STRNE(s1, s2) ABSL_QCHECK_STRNE_IMPL((s1), #s1, (s2), #s2) + ABSL_LOG_INTERNAL_CHECK_STRCASENE_IMPL((s1), #s1, (s2), #s2) +#define ABSL_QCHECK_STREQ(s1, s2) \ + ABSL_LOG_INTERNAL_QCHECK_STREQ_IMPL((s1), #s1, (s2), #s2) +#define ABSL_QCHECK_STRNE(s1, s2) \ + ABSL_LOG_INTERNAL_QCHECK_STRNE_IMPL((s1), #s1, (s2), #s2) #define ABSL_QCHECK_STRCASEEQ(s1, s2) \ - ABSL_QCHECK_STRCASEEQ_IMPL((s1), #s1, (s2), #s2) + ABSL_LOG_INTERNAL_QCHECK_STRCASEEQ_IMPL((s1), #s1, (s2), #s2) #define ABSL_QCHECK_STRCASENE(s1, s2) \ - ABSL_QCHECK_STRCASENE_IMPL((s1), #s1, (s2), #s2) -#define ABSL_DCHECK_STREQ(s1, s2) ABSL_DCHECK_STREQ_IMPL((s1), #s1, (s2), #s2) -#define ABSL_DCHECK_STRNE(s1, s2) ABSL_DCHECK_STRNE_IMPL((s1), #s1, (s2), #s2) + ABSL_LOG_INTERNAL_QCHECK_STRCASENE_IMPL((s1), #s1, (s2), #s2) +#define ABSL_DCHECK_STREQ(s1, s2) \ + ABSL_LOG_INTERNAL_DCHECK_STREQ_IMPL((s1), #s1, (s2), #s2) +#define ABSL_DCHECK_STRNE(s1, s2) \ + ABSL_LOG_INTERNAL_DCHECK_STRNE_IMPL((s1), #s1, (s2), #s2) #define ABSL_DCHECK_STRCASEEQ(s1, s2) \ - ABSL_DCHECK_STRCASEEQ_IMPL((s1), #s1, (s2), #s2) + ABSL_LOG_INTERNAL_DCHECK_STRCASEEQ_IMPL((s1), #s1, (s2), #s2) #define ABSL_DCHECK_STRCASENE(s1, s2) \ - ABSL_DCHECK_STRCASENE_IMPL((s1), #s1, (s2), #s2) + ABSL_LOG_INTERNAL_DCHECK_STRCASENE_IMPL((s1), #s1, (s2), #s2) #endif // ABSL_LOG_ABSL_CHECK_H_ diff --git a/absl/log/absl_check_test.cc b/absl/log/absl_check_test.cc index 8ddacdb1a35..d84940fa129 100644 --- a/absl/log/absl_check_test.cc +++ b/absl/log/absl_check_test.cc @@ -55,4 +55,4 @@ #define ABSL_TEST_QCHECK_STRCASENE ABSL_QCHECK_STRCASENE #include "gtest/gtest.h" -#include "absl/log/check_test_impl.h" +#include "absl/log/check_test_impl.inc" diff --git a/absl/log/absl_log.h b/absl/log/absl_log.h index 1c6cf263e8a..0517760b6dc 100644 --- a/absl/log/absl_log.h +++ b/absl/log/absl_log.h @@ -35,60 +35,69 @@ #include "absl/log/internal/log_impl.h" -#define ABSL_LOG(severity) ABSL_LOG_IMPL(_##severity) -#define ABSL_PLOG(severity) ABSL_PLOG_IMPL(_##severity) -#define ABSL_DLOG(severity) ABSL_DLOG_IMPL(_##severity) +#define ABSL_LOG(severity) ABSL_LOG_INTERNAL_LOG_IMPL(_##severity) +#define ABSL_PLOG(severity) ABSL_LOG_INTERNAL_PLOG_IMPL(_##severity) +#define ABSL_DLOG(severity) ABSL_LOG_INTERNAL_DLOG_IMPL(_##severity) #define ABSL_LOG_IF(severity, condition) \ - ABSL_LOG_IF_IMPL(_##severity, condition) + ABSL_LOG_INTERNAL_LOG_IF_IMPL(_##severity, condition) #define ABSL_PLOG_IF(severity, condition) \ - ABSL_PLOG_IF_IMPL(_##severity, condition) + ABSL_LOG_INTERNAL_PLOG_IF_IMPL(_##severity, condition) #define ABSL_DLOG_IF(severity, condition) \ - ABSL_DLOG_IF_IMPL(_##severity, condition) + ABSL_LOG_INTERNAL_DLOG_IF_IMPL(_##severity, condition) -#define ABSL_LOG_EVERY_N(severity, n) ABSL_LOG_EVERY_N_IMPL(_##severity, n) -#define ABSL_LOG_FIRST_N(severity, n) ABSL_LOG_FIRST_N_IMPL(_##severity, n) -#define ABSL_LOG_EVERY_POW_2(severity) ABSL_LOG_EVERY_POW_2_IMPL(_##severity) +#define ABSL_LOG_EVERY_N(severity, n) \ + ABSL_LOG_INTERNAL_LOG_EVERY_N_IMPL(_##severity, n) +#define ABSL_LOG_FIRST_N(severity, n) \ + ABSL_LOG_INTERNAL_LOG_FIRST_N_IMPL(_##severity, n) +#define ABSL_LOG_EVERY_POW_2(severity) \ + ABSL_LOG_INTERNAL_LOG_EVERY_POW_2_IMPL(_##severity) #define ABSL_LOG_EVERY_N_SEC(severity, n_seconds) \ - ABSL_LOG_EVERY_N_SEC_IMPL(_##severity, n_seconds) + ABSL_LOG_INTERNAL_LOG_EVERY_N_SEC_IMPL(_##severity, n_seconds) -#define ABSL_PLOG_EVERY_N(severity, n) ABSL_PLOG_EVERY_N_IMPL(_##severity, n) -#define ABSL_PLOG_FIRST_N(severity, n) ABSL_PLOG_FIRST_N_IMPL(_##severity, n) -#define ABSL_PLOG_EVERY_POW_2(severity) ABSL_PLOG_EVERY_POW_2_IMPL(_##severity) +#define ABSL_PLOG_EVERY_N(severity, n) \ + ABSL_LOG_INTERNAL_PLOG_EVERY_N_IMPL(_##severity, n) +#define ABSL_PLOG_FIRST_N(severity, n) \ + ABSL_LOG_INTERNAL_PLOG_FIRST_N_IMPL(_##severity, n) +#define ABSL_PLOG_EVERY_POW_2(severity) \ + ABSL_LOG_INTERNAL_PLOG_EVERY_POW_2_IMPL(_##severity) #define ABSL_PLOG_EVERY_N_SEC(severity, n_seconds) \ - ABSL_PLOG_EVERY_N_SEC_IMPL(_##severity, n_seconds) + ABSL_LOG_INTERNAL_PLOG_EVERY_N_SEC_IMPL(_##severity, n_seconds) -#define ABSL_DLOG_EVERY_N(severity, n) ABSL_DLOG_EVERY_N_IMPL(_##severity, n) -#define ABSL_DLOG_FIRST_N(severity, n) ABSL_DLOG_FIRST_N_IMPL(_##severity, n) -#define ABSL_DLOG_EVERY_POW_2(severity) ABSL_DLOG_EVERY_POW_2_IMPL(_##severity) +#define ABSL_DLOG_EVERY_N(severity, n) \ + ABSL_LOG_INTERNAL_DLOG_EVERY_N_IMPL(_##severity, n) +#define ABSL_DLOG_FIRST_N(severity, n) \ + ABSL_LOG_INTERNAL_DLOG_FIRST_N_IMPL(_##severity, n) +#define ABSL_DLOG_EVERY_POW_2(severity) \ + ABSL_LOG_INTERNAL_DLOG_EVERY_POW_2_IMPL(_##severity) #define ABSL_DLOG_EVERY_N_SEC(severity, n_seconds) \ - ABSL_DLOG_EVERY_N_SEC_IMPL(_##severity, n_seconds) + ABSL_LOG_INTERNAL_DLOG_EVERY_N_SEC_IMPL(_##severity, n_seconds) #define ABSL_LOG_IF_EVERY_N(severity, condition, n) \ - ABSL_LOG_IF_EVERY_N_IMPL(_##severity, condition, n) + ABSL_LOG_INTERNAL_LOG_IF_EVERY_N_IMPL(_##severity, condition, n) #define ABSL_LOG_IF_FIRST_N(severity, condition, n) \ - ABSL_LOG_IF_FIRST_N_IMPL(_##severity, condition, n) + ABSL_LOG_INTERNAL_LOG_IF_FIRST_N_IMPL(_##severity, condition, n) #define ABSL_LOG_IF_EVERY_POW_2(severity, condition) \ - ABSL_LOG_IF_EVERY_POW_2_IMPL(_##severity, condition) + ABSL_LOG_INTERNAL_LOG_IF_EVERY_POW_2_IMPL(_##severity, condition) #define ABSL_LOG_IF_EVERY_N_SEC(severity, condition, n_seconds) \ - ABSL_LOG_IF_EVERY_N_SEC_IMPL(_##severity, condition, n_seconds) + ABSL_LOG_INTERNAL_LOG_IF_EVERY_N_SEC_IMPL(_##severity, condition, n_seconds) #define ABSL_PLOG_IF_EVERY_N(severity, condition, n) \ - ABSL_PLOG_IF_EVERY_N_IMPL(_##severity, condition, n) + ABSL_LOG_INTERNAL_PLOG_IF_EVERY_N_IMPL(_##severity, condition, n) #define ABSL_PLOG_IF_FIRST_N(severity, condition, n) \ - ABSL_PLOG_IF_FIRST_N_IMPL(_##severity, condition, n) + ABSL_LOG_INTERNAL_PLOG_IF_FIRST_N_IMPL(_##severity, condition, n) #define ABSL_PLOG_IF_EVERY_POW_2(severity, condition) \ - ABSL_PLOG_IF_EVERY_POW_2_IMPL(_##severity, condition) + ABSL_LOG_INTERNAL_PLOG_IF_EVERY_POW_2_IMPL(_##severity, condition) #define ABSL_PLOG_IF_EVERY_N_SEC(severity, condition, n_seconds) \ - ABSL_PLOG_IF_EVERY_N_SEC_IMPL(_##severity, condition, n_seconds) + ABSL_LOG_INTERNAL_PLOG_IF_EVERY_N_SEC_IMPL(_##severity, condition, n_seconds) #define ABSL_DLOG_IF_EVERY_N(severity, condition, n) \ - ABSL_DLOG_IF_EVERY_N_IMPL(_##severity, condition, n) + ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_IMPL(_##severity, condition, n) #define ABSL_DLOG_IF_FIRST_N(severity, condition, n) \ - ABSL_DLOG_IF_FIRST_N_IMPL(_##severity, condition, n) + ABSL_LOG_INTERNAL_DLOG_IF_FIRST_N_IMPL(_##severity, condition, n) #define ABSL_DLOG_IF_EVERY_POW_2(severity, condition) \ - ABSL_DLOG_IF_EVERY_POW_2_IMPL(_##severity, condition) + ABSL_LOG_INTERNAL_DLOG_IF_EVERY_POW_2_IMPL(_##severity, condition) #define ABSL_DLOG_IF_EVERY_N_SEC(severity, condition, n_seconds) \ - ABSL_DLOG_IF_EVERY_N_SEC_IMPL(_##severity, condition, n_seconds) + ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_SEC_IMPL(_##severity, condition, n_seconds) #endif // ABSL_LOG_ABSL_LOG_H_ diff --git a/absl/log/absl_log_basic_test.cc b/absl/log/absl_log_basic_test.cc index bc8a787d8c4..3a4b83c15ab 100644 --- a/absl/log/absl_log_basic_test.cc +++ b/absl/log/absl_log_basic_test.cc @@ -18,4 +18,4 @@ #define ABSL_TEST_LOG ABSL_LOG #include "gtest/gtest.h" -#include "absl/log/log_basic_test_impl.h" +#include "absl/log/log_basic_test_impl.inc" diff --git a/absl/log/check.h b/absl/log/check.h index 33145a57e9d..0a2f2e4e4ca 100644 --- a/absl/log/check.h +++ b/absl/log/check.h @@ -54,7 +54,7 @@ // Might produce a message like: // // Check failed: !cheese.empty() Out of Cheese -#define CHECK(condition) ABSL_CHECK_IMPL((condition), #condition) +#define CHECK(condition) ABSL_LOG_INTERNAL_CHECK_IMPL((condition), #condition) // QCHECK() // @@ -62,7 +62,7 @@ // not run registered error handlers (as `QFATAL`). It is useful when the // problem is definitely unrelated to program flow, e.g. when validating user // input. -#define QCHECK(condition) ABSL_QCHECK_IMPL((condition), #condition) +#define QCHECK(condition) ABSL_LOG_INTERNAL_QCHECK_IMPL((condition), #condition) // PCHECK() // @@ -77,7 +77,7 @@ // Might produce a message like: // // Check failed: fd != -1 posix is difficult: No such file or directory [2] -#define PCHECK(condition) ABSL_PCHECK_IMPL((condition), #condition) +#define PCHECK(condition) ABSL_LOG_INTERNAL_PCHECK_IMPL((condition), #condition) // DCHECK() // @@ -85,7 +85,7 @@ // `DLOG`). Unlike with `CHECK` (but as with `assert`), it is not safe to rely // on evaluation of `condition`: when `NDEBUG` is enabled, DCHECK does not // evaluate the condition. -#define DCHECK(condition) ABSL_DCHECK_IMPL((condition), #condition) +#define DCHECK(condition) ABSL_LOG_INTERNAL_DCHECK_IMPL((condition), #condition) // `CHECK_EQ` and friends are syntactic sugar for `CHECK(x == y)` that // automatically output the expression being tested and the evaluated values on @@ -113,24 +113,42 @@ // // WARNING: Passing `NULL` as an argument to `CHECK_EQ` and similar macros does // not compile. Use `nullptr` instead. -#define CHECK_EQ(val1, val2) ABSL_CHECK_EQ_IMPL((val1), #val1, (val2), #val2) -#define CHECK_NE(val1, val2) ABSL_CHECK_NE_IMPL((val1), #val1, (val2), #val2) -#define CHECK_LE(val1, val2) ABSL_CHECK_LE_IMPL((val1), #val1, (val2), #val2) -#define CHECK_LT(val1, val2) ABSL_CHECK_LT_IMPL((val1), #val1, (val2), #val2) -#define CHECK_GE(val1, val2) ABSL_CHECK_GE_IMPL((val1), #val1, (val2), #val2) -#define CHECK_GT(val1, val2) ABSL_CHECK_GT_IMPL((val1), #val1, (val2), #val2) -#define QCHECK_EQ(val1, val2) ABSL_QCHECK_EQ_IMPL((val1), #val1, (val2), #val2) -#define QCHECK_NE(val1, val2) ABSL_QCHECK_NE_IMPL((val1), #val1, (val2), #val2) -#define QCHECK_LE(val1, val2) ABSL_QCHECK_LE_IMPL((val1), #val1, (val2), #val2) -#define QCHECK_LT(val1, val2) ABSL_QCHECK_LT_IMPL((val1), #val1, (val2), #val2) -#define QCHECK_GE(val1, val2) ABSL_QCHECK_GE_IMPL((val1), #val1, (val2), #val2) -#define QCHECK_GT(val1, val2) ABSL_QCHECK_GT_IMPL((val1), #val1, (val2), #val2) -#define DCHECK_EQ(val1, val2) ABSL_DCHECK_EQ_IMPL((val1), #val1, (val2), #val2) -#define DCHECK_NE(val1, val2) ABSL_DCHECK_NE_IMPL((val1), #val1, (val2), #val2) -#define DCHECK_LE(val1, val2) ABSL_DCHECK_LE_IMPL((val1), #val1, (val2), #val2) -#define DCHECK_LT(val1, val2) ABSL_DCHECK_LT_IMPL((val1), #val1, (val2), #val2) -#define DCHECK_GE(val1, val2) ABSL_DCHECK_GE_IMPL((val1), #val1, (val2), #val2) -#define DCHECK_GT(val1, val2) ABSL_DCHECK_GT_IMPL((val1), #val1, (val2), #val2) +#define CHECK_EQ(val1, val2) \ + ABSL_LOG_INTERNAL_CHECK_EQ_IMPL((val1), #val1, (val2), #val2) +#define CHECK_NE(val1, val2) \ + ABSL_LOG_INTERNAL_CHECK_NE_IMPL((val1), #val1, (val2), #val2) +#define CHECK_LE(val1, val2) \ + ABSL_LOG_INTERNAL_CHECK_LE_IMPL((val1), #val1, (val2), #val2) +#define CHECK_LT(val1, val2) \ + ABSL_LOG_INTERNAL_CHECK_LT_IMPL((val1), #val1, (val2), #val2) +#define CHECK_GE(val1, val2) \ + ABSL_LOG_INTERNAL_CHECK_GE_IMPL((val1), #val1, (val2), #val2) +#define CHECK_GT(val1, val2) \ + ABSL_LOG_INTERNAL_CHECK_GT_IMPL((val1), #val1, (val2), #val2) +#define QCHECK_EQ(val1, val2) \ + ABSL_LOG_INTERNAL_QCHECK_EQ_IMPL((val1), #val1, (val2), #val2) +#define QCHECK_NE(val1, val2) \ + ABSL_LOG_INTERNAL_QCHECK_NE_IMPL((val1), #val1, (val2), #val2) +#define QCHECK_LE(val1, val2) \ + ABSL_LOG_INTERNAL_QCHECK_LE_IMPL((val1), #val1, (val2), #val2) +#define QCHECK_LT(val1, val2) \ + ABSL_LOG_INTERNAL_QCHECK_LT_IMPL((val1), #val1, (val2), #val2) +#define QCHECK_GE(val1, val2) \ + ABSL_LOG_INTERNAL_QCHECK_GE_IMPL((val1), #val1, (val2), #val2) +#define QCHECK_GT(val1, val2) \ + ABSL_LOG_INTERNAL_QCHECK_GT_IMPL((val1), #val1, (val2), #val2) +#define DCHECK_EQ(val1, val2) \ + ABSL_LOG_INTERNAL_DCHECK_EQ_IMPL((val1), #val1, (val2), #val2) +#define DCHECK_NE(val1, val2) \ + ABSL_LOG_INTERNAL_DCHECK_NE_IMPL((val1), #val1, (val2), #val2) +#define DCHECK_LE(val1, val2) \ + ABSL_LOG_INTERNAL_DCHECK_LE_IMPL((val1), #val1, (val2), #val2) +#define DCHECK_LT(val1, val2) \ + ABSL_LOG_INTERNAL_DCHECK_LT_IMPL((val1), #val1, (val2), #val2) +#define DCHECK_GE(val1, val2) \ + ABSL_LOG_INTERNAL_DCHECK_GE_IMPL((val1), #val1, (val2), #val2) +#define DCHECK_GT(val1, val2) \ + ABSL_LOG_INTERNAL_DCHECK_GT_IMPL((val1), #val1, (val2), #val2) // `CHECK_OK` and friends validate that the provided `absl::Status` or // `absl::StatusOr` is OK. If it isn't, they print a failure message that @@ -146,9 +164,9 @@ // Might produce a message like: // // Check failed: FunctionReturnsStatus(x, y, z) is OK (ABORTED: timeout) oops! -#define CHECK_OK(status) ABSL_CHECK_OK_IMPL((status), #status) -#define QCHECK_OK(status) ABSL_QCHECK_OK_IMPL((status), #status) -#define DCHECK_OK(status) ABSL_DCHECK_OK_IMPL((status), #status) +#define CHECK_OK(status) ABSL_LOG_INTERNAL_CHECK_OK_IMPL((status), #status) +#define QCHECK_OK(status) ABSL_LOG_INTERNAL_QCHECK_OK_IMPL((status), #status) +#define DCHECK_OK(status) ABSL_LOG_INTERNAL_DCHECK_OK_IMPL((status), #status) // `CHECK_STREQ` and friends provide `CHECK_EQ` functionality for C strings, // i.e., nul-terminated char arrays. The `CASE` versions are case-insensitive. @@ -163,21 +181,29 @@ // Example: // // CHECK_STREQ(Foo().c_str(), Bar().c_str()); -#define CHECK_STREQ(s1, s2) ABSL_CHECK_STREQ_IMPL((s1), #s1, (s2), #s2) -#define CHECK_STRNE(s1, s2) ABSL_CHECK_STRNE_IMPL((s1), #s1, (s2), #s2) -#define CHECK_STRCASEEQ(s1, s2) ABSL_CHECK_STRCASEEQ_IMPL((s1), #s1, (s2), #s2) -#define CHECK_STRCASENE(s1, s2) ABSL_CHECK_STRCASENE_IMPL((s1), #s1, (s2), #s2) -#define QCHECK_STREQ(s1, s2) ABSL_QCHECK_STREQ_IMPL((s1), #s1, (s2), #s2) -#define QCHECK_STRNE(s1, s2) ABSL_QCHECK_STRNE_IMPL((s1), #s1, (s2), #s2) +#define CHECK_STREQ(s1, s2) \ + ABSL_LOG_INTERNAL_CHECK_STREQ_IMPL((s1), #s1, (s2), #s2) +#define CHECK_STRNE(s1, s2) \ + ABSL_LOG_INTERNAL_CHECK_STRNE_IMPL((s1), #s1, (s2), #s2) +#define CHECK_STRCASEEQ(s1, s2) \ + ABSL_LOG_INTERNAL_CHECK_STRCASEEQ_IMPL((s1), #s1, (s2), #s2) +#define CHECK_STRCASENE(s1, s2) \ + ABSL_LOG_INTERNAL_CHECK_STRCASENE_IMPL((s1), #s1, (s2), #s2) +#define QCHECK_STREQ(s1, s2) \ + ABSL_LOG_INTERNAL_QCHECK_STREQ_IMPL((s1), #s1, (s2), #s2) +#define QCHECK_STRNE(s1, s2) \ + ABSL_LOG_INTERNAL_QCHECK_STRNE_IMPL((s1), #s1, (s2), #s2) #define QCHECK_STRCASEEQ(s1, s2) \ - ABSL_QCHECK_STRCASEEQ_IMPL((s1), #s1, (s2), #s2) + ABSL_LOG_INTERNAL_QCHECK_STRCASEEQ_IMPL((s1), #s1, (s2), #s2) #define QCHECK_STRCASENE(s1, s2) \ - ABSL_QCHECK_STRCASENE_IMPL((s1), #s1, (s2), #s2) -#define DCHECK_STREQ(s1, s2) ABSL_DCHECK_STREQ_IMPL((s1), #s1, (s2), #s2) -#define DCHECK_STRNE(s1, s2) ABSL_DCHECK_STRNE_IMPL((s1), #s1, (s2), #s2) + ABSL_LOG_INTERNAL_QCHECK_STRCASENE_IMPL((s1), #s1, (s2), #s2) +#define DCHECK_STREQ(s1, s2) \ + ABSL_LOG_INTERNAL_DCHECK_STREQ_IMPL((s1), #s1, (s2), #s2) +#define DCHECK_STRNE(s1, s2) \ + ABSL_LOG_INTERNAL_DCHECK_STRNE_IMPL((s1), #s1, (s2), #s2) #define DCHECK_STRCASEEQ(s1, s2) \ - ABSL_DCHECK_STRCASEEQ_IMPL((s1), #s1, (s2), #s2) + ABSL_LOG_INTERNAL_DCHECK_STRCASEEQ_IMPL((s1), #s1, (s2), #s2) #define DCHECK_STRCASENE(s1, s2) \ - ABSL_DCHECK_STRCASENE_IMPL((s1), #s1, (s2), #s2) + ABSL_LOG_INTERNAL_DCHECK_STRCASENE_IMPL((s1), #s1, (s2), #s2) #endif // ABSL_LOG_CHECK_H_ diff --git a/absl/log/check_test.cc b/absl/log/check_test.cc index f44a686eab3..ef415bd4227 100644 --- a/absl/log/check_test.cc +++ b/absl/log/check_test.cc @@ -55,4 +55,4 @@ #define ABSL_TEST_QCHECK_STRCASENE QCHECK_STRCASENE #include "gtest/gtest.h" -#include "absl/log/check_test_impl.h" +#include "absl/log/check_test_impl.inc" diff --git a/absl/log/check_test_impl.h b/absl/log/check_test_impl.inc similarity index 100% rename from absl/log/check_test_impl.h rename to absl/log/check_test_impl.inc diff --git a/absl/log/internal/check_impl.h b/absl/log/internal/check_impl.h index c9c28e3ea6a..00f25f80ba2 100644 --- a/absl/log/internal/check_impl.h +++ b/absl/log/internal/check_impl.h @@ -22,128 +22,128 @@ #include "absl/log/internal/strip.h" // CHECK -#define ABSL_CHECK_IMPL(condition, condition_text) \ +#define ABSL_LOG_INTERNAL_CHECK_IMPL(condition, condition_text) \ ABSL_LOG_INTERNAL_CONDITION_FATAL(STATELESS, \ ABSL_PREDICT_FALSE(!(condition))) \ ABSL_LOG_INTERNAL_CHECK(condition_text).InternalStream() -#define ABSL_QCHECK_IMPL(condition, condition_text) \ +#define ABSL_LOG_INTERNAL_QCHECK_IMPL(condition, condition_text) \ ABSL_LOG_INTERNAL_CONDITION_QFATAL(STATELESS, \ ABSL_PREDICT_FALSE(!(condition))) \ ABSL_LOG_INTERNAL_QCHECK(condition_text).InternalStream() -#define ABSL_PCHECK_IMPL(condition, condition_text) \ - ABSL_CHECK_IMPL(condition, condition_text).WithPerror() +#define ABSL_LOG_INTERNAL_PCHECK_IMPL(condition, condition_text) \ + ABSL_LOG_INTERNAL_CHECK_IMPL(condition, condition_text).WithPerror() #ifndef NDEBUG -#define ABSL_DCHECK_IMPL(condition, condition_text) \ - ABSL_CHECK_IMPL(condition, condition_text) +#define ABSL_LOG_INTERNAL_DCHECK_IMPL(condition, condition_text) \ + ABSL_LOG_INTERNAL_CHECK_IMPL(condition, condition_text) #else -#define ABSL_DCHECK_IMPL(condition, condition_text) \ - ABSL_CHECK_IMPL(true || (condition), "true") +#define ABSL_LOG_INTERNAL_DCHECK_IMPL(condition, condition_text) \ + ABSL_LOG_INTERNAL_CHECK_IMPL(true || (condition), "true") #endif // CHECK_EQ -#define ABSL_CHECK_EQ_IMPL(val1, val1_text, val2, val2_text) \ +#define ABSL_LOG_INTERNAL_CHECK_EQ_IMPL(val1, val1_text, val2, val2_text) \ ABSL_LOG_INTERNAL_CHECK_OP(Check_EQ, ==, val1, val1_text, val2, val2_text) -#define ABSL_CHECK_NE_IMPL(val1, val1_text, val2, val2_text) \ +#define ABSL_LOG_INTERNAL_CHECK_NE_IMPL(val1, val1_text, val2, val2_text) \ ABSL_LOG_INTERNAL_CHECK_OP(Check_NE, !=, val1, val1_text, val2, val2_text) -#define ABSL_CHECK_LE_IMPL(val1, val1_text, val2, val2_text) \ +#define ABSL_LOG_INTERNAL_CHECK_LE_IMPL(val1, val1_text, val2, val2_text) \ ABSL_LOG_INTERNAL_CHECK_OP(Check_LE, <=, val1, val1_text, val2, val2_text) -#define ABSL_CHECK_LT_IMPL(val1, val1_text, val2, val2_text) \ +#define ABSL_LOG_INTERNAL_CHECK_LT_IMPL(val1, val1_text, val2, val2_text) \ ABSL_LOG_INTERNAL_CHECK_OP(Check_LT, <, val1, val1_text, val2, val2_text) -#define ABSL_CHECK_GE_IMPL(val1, val1_text, val2, val2_text) \ +#define ABSL_LOG_INTERNAL_CHECK_GE_IMPL(val1, val1_text, val2, val2_text) \ ABSL_LOG_INTERNAL_CHECK_OP(Check_GE, >=, val1, val1_text, val2, val2_text) -#define ABSL_CHECK_GT_IMPL(val1, val1_text, val2, val2_text) \ +#define ABSL_LOG_INTERNAL_CHECK_GT_IMPL(val1, val1_text, val2, val2_text) \ ABSL_LOG_INTERNAL_CHECK_OP(Check_GT, >, val1, val1_text, val2, val2_text) -#define ABSL_QCHECK_EQ_IMPL(val1, val1_text, val2, val2_text) \ +#define ABSL_LOG_INTERNAL_QCHECK_EQ_IMPL(val1, val1_text, val2, val2_text) \ ABSL_LOG_INTERNAL_QCHECK_OP(Check_EQ, ==, val1, val1_text, val2, val2_text) -#define ABSL_QCHECK_NE_IMPL(val1, val1_text, val2, val2_text) \ +#define ABSL_LOG_INTERNAL_QCHECK_NE_IMPL(val1, val1_text, val2, val2_text) \ ABSL_LOG_INTERNAL_QCHECK_OP(Check_NE, !=, val1, val1_text, val2, val2_text) -#define ABSL_QCHECK_LE_IMPL(val1, val1_text, val2, val2_text) \ +#define ABSL_LOG_INTERNAL_QCHECK_LE_IMPL(val1, val1_text, val2, val2_text) \ ABSL_LOG_INTERNAL_QCHECK_OP(Check_LE, <=, val1, val1_text, val2, val2_text) -#define ABSL_QCHECK_LT_IMPL(val1, val1_text, val2, val2_text) \ +#define ABSL_LOG_INTERNAL_QCHECK_LT_IMPL(val1, val1_text, val2, val2_text) \ ABSL_LOG_INTERNAL_QCHECK_OP(Check_LT, <, val1, val1_text, val2, val2_text) -#define ABSL_QCHECK_GE_IMPL(val1, val1_text, val2, val2_text) \ +#define ABSL_LOG_INTERNAL_QCHECK_GE_IMPL(val1, val1_text, val2, val2_text) \ ABSL_LOG_INTERNAL_QCHECK_OP(Check_GE, >=, val1, val1_text, val2, val2_text) -#define ABSL_QCHECK_GT_IMPL(val1, val1_text, val2, val2_text) \ +#define ABSL_LOG_INTERNAL_QCHECK_GT_IMPL(val1, val1_text, val2, val2_text) \ ABSL_LOG_INTERNAL_QCHECK_OP(Check_GT, >, val1, val1_text, val2, val2_text) #ifndef NDEBUG -#define ABSL_DCHECK_EQ_IMPL(val1, val1_text, val2, val2_text) \ - ABSL_CHECK_EQ_IMPL(val1, val1_text, val2, val2_text) -#define ABSL_DCHECK_NE_IMPL(val1, val1_text, val2, val2_text) \ - ABSL_CHECK_NE_IMPL(val1, val1_text, val2, val2_text) -#define ABSL_DCHECK_LE_IMPL(val1, val1_text, val2, val2_text) \ - ABSL_CHECK_LE_IMPL(val1, val1_text, val2, val2_text) -#define ABSL_DCHECK_LT_IMPL(val1, val1_text, val2, val2_text) \ - ABSL_CHECK_LT_IMPL(val1, val1_text, val2, val2_text) -#define ABSL_DCHECK_GE_IMPL(val1, val1_text, val2, val2_text) \ - ABSL_CHECK_GE_IMPL(val1, val1_text, val2, val2_text) -#define ABSL_DCHECK_GT_IMPL(val1, val1_text, val2, val2_text) \ - ABSL_CHECK_GT_IMPL(val1, val1_text, val2, val2_text) +#define ABSL_LOG_INTERNAL_DCHECK_EQ_IMPL(val1, val1_text, val2, val2_text) \ + ABSL_LOG_INTERNAL_CHECK_EQ_IMPL(val1, val1_text, val2, val2_text) +#define ABSL_LOG_INTERNAL_DCHECK_NE_IMPL(val1, val1_text, val2, val2_text) \ + ABSL_LOG_INTERNAL_CHECK_NE_IMPL(val1, val1_text, val2, val2_text) +#define ABSL_LOG_INTERNAL_DCHECK_LE_IMPL(val1, val1_text, val2, val2_text) \ + ABSL_LOG_INTERNAL_CHECK_LE_IMPL(val1, val1_text, val2, val2_text) +#define ABSL_LOG_INTERNAL_DCHECK_LT_IMPL(val1, val1_text, val2, val2_text) \ + ABSL_LOG_INTERNAL_CHECK_LT_IMPL(val1, val1_text, val2, val2_text) +#define ABSL_LOG_INTERNAL_DCHECK_GE_IMPL(val1, val1_text, val2, val2_text) \ + ABSL_LOG_INTERNAL_CHECK_GE_IMPL(val1, val1_text, val2, val2_text) +#define ABSL_LOG_INTERNAL_DCHECK_GT_IMPL(val1, val1_text, val2, val2_text) \ + ABSL_LOG_INTERNAL_CHECK_GT_IMPL(val1, val1_text, val2, val2_text) #else // ndef NDEBUG -#define ABSL_DCHECK_EQ_IMPL(val1, val1_text, val2, val2_text) \ +#define ABSL_LOG_INTERNAL_DCHECK_EQ_IMPL(val1, val1_text, val2, val2_text) \ ABSL_LOG_INTERNAL_DCHECK_NOP(val1, val2) -#define ABSL_DCHECK_NE_IMPL(val1, val1_text, val2, val2_text) \ +#define ABSL_LOG_INTERNAL_DCHECK_NE_IMPL(val1, val1_text, val2, val2_text) \ ABSL_LOG_INTERNAL_DCHECK_NOP(val1, val2) -#define ABSL_DCHECK_LE_IMPL(val1, val1_text, val2, val2_text) \ +#define ABSL_LOG_INTERNAL_DCHECK_LE_IMPL(val1, val1_text, val2, val2_text) \ ABSL_LOG_INTERNAL_DCHECK_NOP(val1, val2) -#define ABSL_DCHECK_LT_IMPL(val1, val1_text, val2, val2_text) \ +#define ABSL_LOG_INTERNAL_DCHECK_LT_IMPL(val1, val1_text, val2, val2_text) \ ABSL_LOG_INTERNAL_DCHECK_NOP(val1, val2) -#define ABSL_DCHECK_GE_IMPL(val1, val1_text, val2, val2_text) \ +#define ABSL_LOG_INTERNAL_DCHECK_GE_IMPL(val1, val1_text, val2, val2_text) \ ABSL_LOG_INTERNAL_DCHECK_NOP(val1, val2) -#define ABSL_DCHECK_GT_IMPL(val1, val1_text, val2, val2_text) \ +#define ABSL_LOG_INTERNAL_DCHECK_GT_IMPL(val1, val1_text, val2, val2_text) \ ABSL_LOG_INTERNAL_DCHECK_NOP(val1, val2) #endif // def NDEBUG // CHECK_OK -#define ABSL_CHECK_OK_IMPL(status, status_text) \ +#define ABSL_LOG_INTERNAL_CHECK_OK_IMPL(status, status_text) \ ABSL_LOG_INTERNAL_CHECK_OK(status, status_text) -#define ABSL_QCHECK_OK_IMPL(status, status_text) \ +#define ABSL_LOG_INTERNAL_QCHECK_OK_IMPL(status, status_text) \ ABSL_LOG_INTERNAL_QCHECK_OK(status, status_text) #ifndef NDEBUG -#define ABSL_DCHECK_OK_IMPL(status, status_text) \ +#define ABSL_LOG_INTERNAL_DCHECK_OK_IMPL(status, status_text) \ ABSL_LOG_INTERNAL_CHECK_OK(status, status_text) #else -#define ABSL_DCHECK_OK_IMPL(status, status_text) \ +#define ABSL_LOG_INTERNAL_DCHECK_OK_IMPL(status, status_text) \ ABSL_LOG_INTERNAL_DCHECK_NOP(status, nullptr) #endif // CHECK_STREQ -#define ABSL_CHECK_STREQ_IMPL(s1, s1_text, s2, s2_text) \ +#define ABSL_LOG_INTERNAL_CHECK_STREQ_IMPL(s1, s1_text, s2, s2_text) \ ABSL_LOG_INTERNAL_CHECK_STROP(strcmp, ==, true, s1, s1_text, s2, s2_text) -#define ABSL_CHECK_STRNE_IMPL(s1, s1_text, s2, s2_text) \ +#define ABSL_LOG_INTERNAL_CHECK_STRNE_IMPL(s1, s1_text, s2, s2_text) \ ABSL_LOG_INTERNAL_CHECK_STROP(strcmp, !=, false, s1, s1_text, s2, s2_text) -#define ABSL_CHECK_STRCASEEQ_IMPL(s1, s1_text, s2, s2_text) \ +#define ABSL_LOG_INTERNAL_CHECK_STRCASEEQ_IMPL(s1, s1_text, s2, s2_text) \ ABSL_LOG_INTERNAL_CHECK_STROP(strcasecmp, ==, true, s1, s1_text, s2, s2_text) -#define ABSL_CHECK_STRCASENE_IMPL(s1, s1_text, s2, s2_text) \ +#define ABSL_LOG_INTERNAL_CHECK_STRCASENE_IMPL(s1, s1_text, s2, s2_text) \ ABSL_LOG_INTERNAL_CHECK_STROP(strcasecmp, !=, false, s1, s1_text, s2, s2_text) -#define ABSL_QCHECK_STREQ_IMPL(s1, s1_text, s2, s2_text) \ +#define ABSL_LOG_INTERNAL_QCHECK_STREQ_IMPL(s1, s1_text, s2, s2_text) \ ABSL_LOG_INTERNAL_QCHECK_STROP(strcmp, ==, true, s1, s1_text, s2, s2_text) -#define ABSL_QCHECK_STRNE_IMPL(s1, s1_text, s2, s2_text) \ +#define ABSL_LOG_INTERNAL_QCHECK_STRNE_IMPL(s1, s1_text, s2, s2_text) \ ABSL_LOG_INTERNAL_QCHECK_STROP(strcmp, !=, false, s1, s1_text, s2, s2_text) -#define ABSL_QCHECK_STRCASEEQ_IMPL(s1, s1_text, s2, s2_text) \ +#define ABSL_LOG_INTERNAL_QCHECK_STRCASEEQ_IMPL(s1, s1_text, s2, s2_text) \ ABSL_LOG_INTERNAL_QCHECK_STROP(strcasecmp, ==, true, s1, s1_text, s2, s2_text) -#define ABSL_QCHECK_STRCASENE_IMPL(s1, s1_text, s2, s2_text) \ - ABSL_LOG_INTERNAL_QCHECK_STROP(strcasecmp, !=, false, s1, s1_text, s2, \ +#define ABSL_LOG_INTERNAL_QCHECK_STRCASENE_IMPL(s1, s1_text, s2, s2_text) \ + ABSL_LOG_INTERNAL_QCHECK_STROP(strcasecmp, !=, false, s1, s1_text, s2, \ s2_text) #ifndef NDEBUG -#define ABSL_DCHECK_STREQ_IMPL(s1, s1_text, s2, s2_text) \ - ABSL_CHECK_STREQ_IMPL(s1, s1_text, s2, s2_text) -#define ABSL_DCHECK_STRCASEEQ_IMPL(s1, s1_text, s2, s2_text) \ - ABSL_CHECK_STRCASEEQ_IMPL(s1, s1_text, s2, s2_text) -#define ABSL_DCHECK_STRNE_IMPL(s1, s1_text, s2, s2_text) \ - ABSL_CHECK_STRNE_IMPL(s1, s1_text, s2, s2_text) -#define ABSL_DCHECK_STRCASENE_IMPL(s1, s1_text, s2, s2_text) \ - ABSL_CHECK_STRCASENE_IMPL(s1, s1_text, s2, s2_text) +#define ABSL_LOG_INTERNAL_DCHECK_STREQ_IMPL(s1, s1_text, s2, s2_text) \ + ABSL_LOG_INTERNAL_CHECK_STREQ_IMPL(s1, s1_text, s2, s2_text) +#define ABSL_LOG_INTERNAL_DCHECK_STRCASEEQ_IMPL(s1, s1_text, s2, s2_text) \ + ABSL_LOG_INTERNAL_CHECK_STRCASEEQ_IMPL(s1, s1_text, s2, s2_text) +#define ABSL_LOG_INTERNAL_DCHECK_STRNE_IMPL(s1, s1_text, s2, s2_text) \ + ABSL_LOG_INTERNAL_CHECK_STRNE_IMPL(s1, s1_text, s2, s2_text) +#define ABSL_LOG_INTERNAL_DCHECK_STRCASENE_IMPL(s1, s1_text, s2, s2_text) \ + ABSL_LOG_INTERNAL_CHECK_STRCASENE_IMPL(s1, s1_text, s2, s2_text) #else // ndef NDEBUG -#define ABSL_DCHECK_STREQ_IMPL(s1, s1_text, s2, s2_text) \ +#define ABSL_LOG_INTERNAL_DCHECK_STREQ_IMPL(s1, s1_text, s2, s2_text) \ ABSL_LOG_INTERNAL_DCHECK_NOP(s1, s2) -#define ABSL_DCHECK_STRCASEEQ_IMPL(s1, s1_text, s2, s2_text) \ +#define ABSL_LOG_INTERNAL_DCHECK_STRCASEEQ_IMPL(s1, s1_text, s2, s2_text) \ ABSL_LOG_INTERNAL_DCHECK_NOP(s1, s2) -#define ABSL_DCHECK_STRNE_IMPL(s1, s1_text, s2, s2_text) \ +#define ABSL_LOG_INTERNAL_DCHECK_STRNE_IMPL(s1, s1_text, s2, s2_text) \ ABSL_LOG_INTERNAL_DCHECK_NOP(s1, s2) -#define ABSL_DCHECK_STRCASENE_IMPL(s1, s1_text, s2, s2_text) \ +#define ABSL_LOG_INTERNAL_DCHECK_STRCASENE_IMPL(s1, s1_text, s2, s2_text) \ ABSL_LOG_INTERNAL_DCHECK_NOP(s1, s2) #endif // def NDEBUG diff --git a/absl/log/internal/log_impl.h b/absl/log/internal/log_impl.h index 82b5ed84d68..9326780dc69 100644 --- a/absl/log/internal/log_impl.h +++ b/absl/log/internal/log_impl.h @@ -20,190 +20,194 @@ #include "absl/log/internal/strip.h" // ABSL_LOG() -#define ABSL_LOG_IMPL(severity) \ +#define ABSL_LOG_INTERNAL_LOG_IMPL(severity) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, true) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() // ABSL_PLOG() -#define ABSL_PLOG_IMPL(severity) \ +#define ABSL_LOG_INTERNAL_PLOG_IMPL(severity) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, true) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() \ .WithPerror() // ABSL_DLOG() #ifndef NDEBUG -#define ABSL_DLOG_IMPL(severity) \ +#define ABSL_LOG_INTERNAL_DLOG_IMPL(severity) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, true) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() #else -#define ABSL_DLOG_IMPL(severity) \ +#define ABSL_LOG_INTERNAL_DLOG_IMPL(severity) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, false) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() #endif -#define ABSL_LOG_IF_IMPL(severity, condition) \ +#define ABSL_LOG_INTERNAL_LOG_IF_IMPL(severity, condition) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, condition) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() -#define ABSL_PLOG_IF_IMPL(severity, condition) \ +#define ABSL_LOG_INTERNAL_PLOG_IF_IMPL(severity, condition) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, condition) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() \ .WithPerror() #ifndef NDEBUG -#define ABSL_DLOG_IF_IMPL(severity, condition) \ +#define ABSL_LOG_INTERNAL_DLOG_IF_IMPL(severity, condition) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, condition) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() #else -#define ABSL_DLOG_IF_IMPL(severity, condition) \ +#define ABSL_LOG_INTERNAL_DLOG_IF_IMPL(severity, condition) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATELESS, false && (condition)) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() #endif // ABSL_LOG_EVERY_N -#define ABSL_LOG_EVERY_N_IMPL(severity, n) \ +#define ABSL_LOG_INTERNAL_LOG_EVERY_N_IMPL(severity, n) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(EveryN, n) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() // ABSL_LOG_FIRST_N -#define ABSL_LOG_FIRST_N_IMPL(severity, n) \ +#define ABSL_LOG_INTERNAL_LOG_FIRST_N_IMPL(severity, n) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(FirstN, n) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() // ABSL_LOG_EVERY_POW_2 -#define ABSL_LOG_EVERY_POW_2_IMPL(severity) \ +#define ABSL_LOG_INTERNAL_LOG_EVERY_POW_2_IMPL(severity) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(EveryPow2) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() // ABSL_LOG_EVERY_N_SEC -#define ABSL_LOG_EVERY_N_SEC_IMPL(severity, n_seconds) \ +#define ABSL_LOG_INTERNAL_LOG_EVERY_N_SEC_IMPL(severity, n_seconds) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(EveryNSec, n_seconds) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() -#define ABSL_PLOG_EVERY_N_IMPL(severity, n) \ +#define ABSL_LOG_INTERNAL_PLOG_EVERY_N_IMPL(severity, n) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(EveryN, n) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() \ .WithPerror() -#define ABSL_PLOG_FIRST_N_IMPL(severity, n) \ +#define ABSL_LOG_INTERNAL_PLOG_FIRST_N_IMPL(severity, n) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(FirstN, n) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() \ .WithPerror() -#define ABSL_PLOG_EVERY_POW_2_IMPL(severity) \ +#define ABSL_LOG_INTERNAL_PLOG_EVERY_POW_2_IMPL(severity) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(EveryPow2) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() \ .WithPerror() -#define ABSL_PLOG_EVERY_N_SEC_IMPL(severity, n_seconds) \ +#define ABSL_LOG_INTERNAL_PLOG_EVERY_N_SEC_IMPL(severity, n_seconds) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, true)(EveryNSec, n_seconds) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() \ .WithPerror() #ifndef NDEBUG -#define ABSL_DLOG_EVERY_N_IMPL(severity, n) \ - ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true) \ +#define ABSL_LOG_INTERNAL_DLOG_EVERY_N_IMPL(severity, n) \ + ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true) \ (EveryN, n) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() -#define ABSL_DLOG_FIRST_N_IMPL(severity, n) \ - ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true) \ +#define ABSL_LOG_INTERNAL_DLOG_FIRST_N_IMPL(severity, n) \ + ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true) \ (FirstN, n) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() -#define ABSL_DLOG_EVERY_POW_2_IMPL(severity) \ - ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true) \ +#define ABSL_LOG_INTERNAL_DLOG_EVERY_POW_2_IMPL(severity) \ + ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true) \ (EveryPow2) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() -#define ABSL_DLOG_EVERY_N_SEC_IMPL(severity, n_seconds) \ - ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true) \ +#define ABSL_LOG_INTERNAL_DLOG_EVERY_N_SEC_IMPL(severity, n_seconds) \ + ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, true) \ (EveryNSec, n_seconds) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() #else // def NDEBUG -#define ABSL_DLOG_EVERY_N_IMPL(severity, n) \ - ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false) \ +#define ABSL_LOG_INTERNAL_DLOG_EVERY_N_IMPL(severity, n) \ + ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false) \ (EveryN, n) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() -#define ABSL_DLOG_FIRST_N_IMPL(severity, n) \ - ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false) \ +#define ABSL_LOG_INTERNAL_DLOG_FIRST_N_IMPL(severity, n) \ + ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false) \ (FirstN, n) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() -#define ABSL_DLOG_EVERY_POW_2_IMPL(severity) \ - ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false) \ +#define ABSL_LOG_INTERNAL_DLOG_EVERY_POW_2_IMPL(severity) \ + ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false) \ (EveryPow2) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() -#define ABSL_DLOG_EVERY_N_SEC_IMPL(severity, n_seconds) \ - ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false) \ +#define ABSL_LOG_INTERNAL_DLOG_EVERY_N_SEC_IMPL(severity, n_seconds) \ + ABSL_LOG_INTERNAL_CONDITION_INFO(STATEFUL, false) \ (EveryNSec, n_seconds) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() #endif // def NDEBUG -#define ABSL_LOG_IF_EVERY_N_IMPL(severity, condition, n) \ +#define ABSL_LOG_INTERNAL_LOG_IF_EVERY_N_IMPL(severity, condition, n) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryN, n) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() -#define ABSL_LOG_IF_FIRST_N_IMPL(severity, condition, n) \ +#define ABSL_LOG_INTERNAL_LOG_IF_FIRST_N_IMPL(severity, condition, n) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(FirstN, n) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() -#define ABSL_LOG_IF_EVERY_POW_2_IMPL(severity, condition) \ +#define ABSL_LOG_INTERNAL_LOG_IF_EVERY_POW_2_IMPL(severity, condition) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryPow2) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() -#define ABSL_LOG_IF_EVERY_N_SEC_IMPL(severity, condition, n_seconds) \ +#define ABSL_LOG_INTERNAL_LOG_IF_EVERY_N_SEC_IMPL(severity, condition, \ + n_seconds) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryNSec, \ n_seconds) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() -#define ABSL_PLOG_IF_EVERY_N_IMPL(severity, condition, n) \ +#define ABSL_LOG_INTERNAL_PLOG_IF_EVERY_N_IMPL(severity, condition, n) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryN, n) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() \ .WithPerror() -#define ABSL_PLOG_IF_FIRST_N_IMPL(severity, condition, n) \ +#define ABSL_LOG_INTERNAL_PLOG_IF_FIRST_N_IMPL(severity, condition, n) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(FirstN, n) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() \ .WithPerror() -#define ABSL_PLOG_IF_EVERY_POW_2_IMPL(severity, condition) \ +#define ABSL_LOG_INTERNAL_PLOG_IF_EVERY_POW_2_IMPL(severity, condition) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryPow2) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() \ .WithPerror() -#define ABSL_PLOG_IF_EVERY_N_SEC_IMPL(severity, condition, n_seconds) \ +#define ABSL_LOG_INTERNAL_PLOG_IF_EVERY_N_SEC_IMPL(severity, condition, \ + n_seconds) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryNSec, \ n_seconds) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() \ .WithPerror() #ifndef NDEBUG -#define ABSL_DLOG_IF_EVERY_N_IMPL(severity, condition, n) \ +#define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_IMPL(severity, condition, n) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryN, n) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() -#define ABSL_DLOG_IF_FIRST_N_IMPL(severity, condition, n) \ +#define ABSL_LOG_INTERNAL_DLOG_IF_FIRST_N_IMPL(severity, condition, n) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(FirstN, n) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() -#define ABSL_DLOG_IF_EVERY_POW_2_IMPL(severity, condition) \ +#define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_POW_2_IMPL(severity, condition) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryPow2) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() -#define ABSL_DLOG_IF_EVERY_N_SEC_IMPL(severity, condition, n_seconds) \ +#define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_SEC_IMPL(severity, condition, \ + n_seconds) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, condition)(EveryNSec, \ n_seconds) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() #else // def NDEBUG -#define ABSL_DLOG_IF_EVERY_N_IMPL(severity, condition, n) \ +#define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_IMPL(severity, condition, n) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, false && (condition))( \ EveryN, n) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() -#define ABSL_DLOG_IF_FIRST_N_IMPL(severity, condition, n) \ +#define ABSL_LOG_INTERNAL_DLOG_IF_FIRST_N_IMPL(severity, condition, n) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, false && (condition))( \ FirstN, n) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() -#define ABSL_DLOG_IF_EVERY_POW_2_IMPL(severity, condition) \ +#define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_POW_2_IMPL(severity, condition) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, false && (condition))( \ EveryPow2) ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() -#define ABSL_DLOG_IF_EVERY_N_SEC_IMPL(severity, condition, n_seconds) \ +#define ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_SEC_IMPL(severity, condition, \ + n_seconds) \ ABSL_LOG_INTERNAL_CONDITION##severity(STATEFUL, false && (condition))( \ EveryNSec, n_seconds) \ ABSL_LOGGING_INTERNAL_LOG##severity.InternalStream() diff --git a/absl/log/log.h b/absl/log/log.h index e060a0b69b7..602b5acf07d 100644 --- a/absl/log/log.h +++ b/absl/log/log.h @@ -196,29 +196,32 @@ // Example: // // LOG(INFO) << "Found " << num_cookies << " cookies"; -#define LOG(severity) ABSL_LOG_IMPL(_##severity) +#define LOG(severity) ABSL_LOG_INTERNAL_LOG_IMPL(_##severity) // PLOG() // // `PLOG` behaves like `LOG` except that a description of the current state of // `errno` is appended to the streamed message. -#define PLOG(severity) ABSL_PLOG_IMPL(_##severity) +#define PLOG(severity) ABSL_LOG_INTERNAL_PLOG_IMPL(_##severity) // DLOG() // // `DLOG` behaves like `LOG` in debug mode (i.e. `#ifndef NDEBUG`). Otherwise // it compiles away and does nothing. Note that `DLOG(FATAL)` does not // terminate the program if `NDEBUG` is defined. -#define DLOG(severity) ABSL_DLOG_IMPL(_##severity) +#define DLOG(severity) ABSL_LOG_INTERNAL_DLOG_IMPL(_##severity) // `LOG_IF` and friends add a second argument which specifies a condition. If // the condition is false, nothing is logged. // Example: // // LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; -#define LOG_IF(severity, condition) ABSL_LOG_IF_IMPL(_##severity, condition) -#define PLOG_IF(severity, condition) ABSL_PLOG_IF_IMPL(_##severity, condition) -#define DLOG_IF(severity, condition) ABSL_DLOG_IF_IMPL(_##severity, condition) +#define LOG_IF(severity, condition) \ + ABSL_LOG_INTERNAL_LOG_IF_IMPL(_##severity, condition) +#define PLOG_IF(severity, condition) \ + ABSL_LOG_INTERNAL_PLOG_IF_IMPL(_##severity, condition) +#define DLOG_IF(severity, condition) \ + ABSL_LOG_INTERNAL_DLOG_IF_IMPL(_##severity, condition) // LOG_EVERY_N // @@ -231,21 +234,24 @@ // // LOG_EVERY_N(WARNING, 1000) << "Got a packet with a bad CRC (" << COUNTER // << " total)"; -#define LOG_EVERY_N(severity, n) ABSL_LOG_EVERY_N_IMPL(_##severity, n) +#define LOG_EVERY_N(severity, n) \ + ABSL_LOG_INTERNAL_LOG_EVERY_N_IMPL(_##severity, n) // LOG_FIRST_N // // `LOG_FIRST_N` behaves like `LOG_EVERY_N` except that the specified message is // logged when the counter's value is less than `n`. `LOG_FIRST_N` is // thread-safe. -#define LOG_FIRST_N(severity, n) ABSL_LOG_FIRST_N_IMPL(_##severity, n) +#define LOG_FIRST_N(severity, n) \ + ABSL_LOG_INTERNAL_LOG_FIRST_N_IMPL(_##severity, n) // LOG_EVERY_POW_2 // // `LOG_EVERY_POW_2` behaves like `LOG_EVERY_N` except that the specified // message is logged when the counter's value is a power of 2. // `LOG_EVERY_POW_2` is thread-safe. -#define LOG_EVERY_POW_2(severity) ABSL_LOG_EVERY_POW_2_IMPL(_##severity) +#define LOG_EVERY_POW_2(severity) \ + ABSL_LOG_INTERNAL_LOG_EVERY_POW_2_IMPL(_##severity) // LOG_EVERY_N_SEC // @@ -257,19 +263,25 @@ // // LOG_EVERY_N_SEC(INFO, 2.5) << "Got " << COUNTER << " cookies so far"; #define LOG_EVERY_N_SEC(severity, n_seconds) \ - ABSL_LOG_EVERY_N_SEC_IMPL(_##severity, n_seconds) + ABSL_LOG_INTERNAL_LOG_EVERY_N_SEC_IMPL(_##severity, n_seconds) -#define PLOG_EVERY_N(severity, n) ABSL_PLOG_EVERY_N_IMPL(_##severity, n) -#define PLOG_FIRST_N(severity, n) ABSL_PLOG_FIRST_N_IMPL(_##severity, n) -#define PLOG_EVERY_POW_2(severity) ABSL_PLOG_EVERY_POW_2_IMPL(_##severity) +#define PLOG_EVERY_N(severity, n) \ + ABSL_LOG_INTERNAL_PLOG_EVERY_N_IMPL(_##severity, n) +#define PLOG_FIRST_N(severity, n) \ + ABSL_LOG_INTERNAL_PLOG_FIRST_N_IMPL(_##severity, n) +#define PLOG_EVERY_POW_2(severity) \ + ABSL_LOG_INTERNAL_PLOG_EVERY_POW_2_IMPL(_##severity) #define PLOG_EVERY_N_SEC(severity, n_seconds) \ - ABSL_PLOG_EVERY_N_SEC_IMPL(_##severity, n_seconds) + ABSL_LOG_INTERNAL_PLOG_EVERY_N_SEC_IMPL(_##severity, n_seconds) -#define DLOG_EVERY_N(severity, n) ABSL_DLOG_EVERY_N_IMPL(_##severity, n) -#define DLOG_FIRST_N(severity, n) ABSL_DLOG_FIRST_N_IMPL(_##severity, n) -#define DLOG_EVERY_POW_2(severity) ABSL_DLOG_EVERY_POW_2_IMPL(_##severity) +#define DLOG_EVERY_N(severity, n) \ + ABSL_LOG_INTERNAL_DLOG_EVERY_N_IMPL(_##severity, n) +#define DLOG_FIRST_N(severity, n) \ + ABSL_LOG_INTERNAL_DLOG_FIRST_N_IMPL(_##severity, n) +#define DLOG_EVERY_POW_2(severity) \ + ABSL_LOG_INTERNAL_DLOG_EVERY_POW_2_IMPL(_##severity) #define DLOG_EVERY_N_SEC(severity, n_seconds) \ - ABSL_DLOG_EVERY_N_SEC_IMPL(_##severity, n_seconds) + ABSL_LOG_INTERNAL_DLOG_EVERY_N_SEC_IMPL(_##severity, n_seconds) // `LOG_IF_EVERY_N` and friends behave as the corresponding `LOG_EVERY_N` // but neither increment a counter nor log a message if condition is false (as @@ -279,30 +291,30 @@ // LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << COUNTER // << "th big cookie"; #define LOG_IF_EVERY_N(severity, condition, n) \ - ABSL_LOG_IF_EVERY_N_IMPL(_##severity, condition, n) + ABSL_LOG_INTERNAL_LOG_IF_EVERY_N_IMPL(_##severity, condition, n) #define LOG_IF_FIRST_N(severity, condition, n) \ - ABSL_LOG_IF_FIRST_N_IMPL(_##severity, condition, n) + ABSL_LOG_INTERNAL_LOG_IF_FIRST_N_IMPL(_##severity, condition, n) #define LOG_IF_EVERY_POW_2(severity, condition) \ - ABSL_LOG_IF_EVERY_POW_2_IMPL(_##severity, condition) + ABSL_LOG_INTERNAL_LOG_IF_EVERY_POW_2_IMPL(_##severity, condition) #define LOG_IF_EVERY_N_SEC(severity, condition, n_seconds) \ - ABSL_LOG_IF_EVERY_N_SEC_IMPL(_##severity, condition, n_seconds) + ABSL_LOG_INTERNAL_LOG_IF_EVERY_N_SEC_IMPL(_##severity, condition, n_seconds) #define PLOG_IF_EVERY_N(severity, condition, n) \ - ABSL_PLOG_IF_EVERY_N_IMPL(_##severity, condition, n) + ABSL_LOG_INTERNAL_PLOG_IF_EVERY_N_IMPL(_##severity, condition, n) #define PLOG_IF_FIRST_N(severity, condition, n) \ - ABSL_PLOG_IF_FIRST_N_IMPL(_##severity, condition, n) + ABSL_LOG_INTERNAL_PLOG_IF_FIRST_N_IMPL(_##severity, condition, n) #define PLOG_IF_EVERY_POW_2(severity, condition) \ - ABSL_PLOG_IF_EVERY_POW_2_IMPL(_##severity, condition) + ABSL_LOG_INTERNAL_PLOG_IF_EVERY_POW_2_IMPL(_##severity, condition) #define PLOG_IF_EVERY_N_SEC(severity, condition, n_seconds) \ - ABSL_PLOG_IF_EVERY_N_SEC_IMPL(_##severity, condition, n_seconds) + ABSL_LOG_INTERNAL_PLOG_IF_EVERY_N_SEC_IMPL(_##severity, condition, n_seconds) #define DLOG_IF_EVERY_N(severity, condition, n) \ - ABSL_DLOG_IF_EVERY_N_IMPL(_##severity, condition, n) + ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_IMPL(_##severity, condition, n) #define DLOG_IF_FIRST_N(severity, condition, n) \ - ABSL_DLOG_IF_FIRST_N_IMPL(_##severity, condition, n) + ABSL_LOG_INTERNAL_DLOG_IF_FIRST_N_IMPL(_##severity, condition, n) #define DLOG_IF_EVERY_POW_2(severity, condition) \ - ABSL_DLOG_IF_EVERY_POW_2_IMPL(_##severity, condition) + ABSL_LOG_INTERNAL_DLOG_IF_EVERY_POW_2_IMPL(_##severity, condition) #define DLOG_IF_EVERY_N_SEC(severity, condition, n_seconds) \ - ABSL_DLOG_IF_EVERY_N_SEC_IMPL(_##severity, condition, n_seconds) + ABSL_LOG_INTERNAL_DLOG_IF_EVERY_N_SEC_IMPL(_##severity, condition, n_seconds) #endif // ABSL_LOG_LOG_H_ diff --git a/absl/log/log_basic_test.cc b/absl/log/log_basic_test.cc index b8d87c94a7c..7fc7111de65 100644 --- a/absl/log/log_basic_test.cc +++ b/absl/log/log_basic_test.cc @@ -18,4 +18,4 @@ #define ABSL_TEST_LOG LOG #include "gtest/gtest.h" -#include "absl/log/log_basic_test_impl.h" +#include "absl/log/log_basic_test_impl.inc" diff --git a/absl/log/log_basic_test_impl.h b/absl/log/log_basic_test_impl.inc similarity index 98% rename from absl/log/log_basic_test_impl.h rename to absl/log/log_basic_test_impl.inc index 35c0b690a87..f340009541f 100644 --- a/absl/log/log_basic_test_impl.h +++ b/absl/log/log_basic_test_impl.inc @@ -94,7 +94,7 @@ TEST_P(BasicLogTest, Info) { EXPECT_CALL( test_sink, Send(AllOf(SourceFilename(Eq(__FILE__)), - SourceBasename(Eq("log_basic_test_impl.h")), + SourceBasename(Eq("log_basic_test_impl.inc")), SourceLine(Eq(log_line)), Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kInfo)), TimestampInMatchWindow(), @@ -123,7 +123,7 @@ TEST_P(BasicLogTest, Warning) { EXPECT_CALL( test_sink, Send(AllOf(SourceFilename(Eq(__FILE__)), - SourceBasename(Eq("log_basic_test_impl.h")), + SourceBasename(Eq("log_basic_test_impl.inc")), SourceLine(Eq(log_line)), Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kWarning)), TimestampInMatchWindow(), @@ -152,7 +152,7 @@ TEST_P(BasicLogTest, Error) { EXPECT_CALL( test_sink, Send(AllOf(SourceFilename(Eq(__FILE__)), - SourceBasename(Eq("log_basic_test_impl.h")), + SourceBasename(Eq("log_basic_test_impl.inc")), SourceLine(Eq(log_line)), Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kError)), TimestampInMatchWindow(), @@ -203,7 +203,7 @@ TEST_P(BasicLogDeathTest, Fatal) { EXPECT_CALL( test_sink, Send(AllOf(SourceFilename(Eq(__FILE__)), - SourceBasename(Eq("log_basic_test_impl.h")), + SourceBasename(Eq("log_basic_test_impl.inc")), SourceLine(Eq(log_line)), Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kFatal)), TimestampInMatchWindow(), @@ -219,7 +219,7 @@ TEST_P(BasicLogDeathTest, Fatal) { EXPECT_CALL( test_sink, Send(AllOf(SourceFilename(Eq(__FILE__)), - SourceBasename(Eq("log_basic_test_impl.h")), + SourceBasename(Eq("log_basic_test_impl.inc")), SourceLine(Eq(log_line)), Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kFatal)), TimestampInMatchWindow(), @@ -257,7 +257,7 @@ TEST_P(BasicLogDeathTest, QFatal) { EXPECT_CALL( test_sink, Send(AllOf(SourceFilename(Eq(__FILE__)), - SourceBasename(Eq("log_basic_test_impl.h")), + SourceBasename(Eq("log_basic_test_impl.inc")), SourceLine(Eq(log_line)), Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kFatal)), TimestampInMatchWindow(), @@ -293,7 +293,7 @@ TEST_P(BasicLogTest, Level) { EXPECT_CALL( test_sink, Send(AllOf(SourceFilename(Eq(__FILE__)), - SourceBasename(Eq("log_basic_test_impl.h")), + SourceBasename(Eq("log_basic_test_impl.inc")), SourceLine(Eq(log_line)), Prefix(IsTrue()), LogSeverity(Eq(severity)), TimestampInMatchWindow(), ThreadID(Eq(absl::base_internal::GetTID())), @@ -336,7 +336,7 @@ TEST_P(BasicLogDeathTest, Level) { EXPECT_CALL( test_sink, Send(AllOf(SourceFilename(Eq(__FILE__)), - SourceBasename(Eq("log_basic_test_impl.h")), + SourceBasename(Eq("log_basic_test_impl.inc")), SourceLine(Eq(log_line)), Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kFatal)), TimestampInMatchWindow(), @@ -351,7 +351,7 @@ TEST_P(BasicLogDeathTest, Level) { EXPECT_CALL( test_sink, Send(AllOf(SourceFilename(Eq(__FILE__)), - SourceBasename(Eq("log_basic_test_impl.h")), + SourceBasename(Eq("log_basic_test_impl.inc")), SourceLine(Eq(log_line)), Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kFatal)), TimestampInMatchWindow(), From 25d7c2aeaf22488cafb15cc703e0cb456beb47fa Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 22 May 2023 10:53:54 -0700 Subject: [PATCH 0019/1238] Fix endianess in FastIntToBuffer PiperOrigin-RevId: 534117706 Change-Id: Id48f1538e71d30286675eb32c9fb3e6f47774aa8 --- absl/strings/numbers.cc | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/absl/strings/numbers.cc b/absl/strings/numbers.cc index 8c05ff0e485..7dc89224eb7 100644 --- a/absl/strings/numbers.cc +++ b/absl/strings/numbers.cc @@ -31,6 +31,7 @@ #include #include "absl/base/attributes.h" +#include "absl/base/internal/endian.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/optimization.h" #include "absl/numeric/bits.h" @@ -172,7 +173,7 @@ inline char* EncodeHundred(uint32_t n, char* out_str) { uint32_t mod10 = n - 10u * div10; base += div10 + (mod10 << 8); base >>= num_digits & 8; - memcpy(out_str, &base, 2); + little_endian::Store16(out_str, static_cast(base)); return out_str + 2 + num_digits; } @@ -198,7 +199,7 @@ inline char* EncodeTenThousand(uint32_t n, char* out_str) { uint32_t zeroes = static_cast(absl::countr_zero(tens)) & (0 - 8ull); tens += kFourZeroBytes; tens >>= zeroes; - memcpy(out_str, &tens, sizeof(tens)); + little_endian::Store32(out_str, tens); return out_str + sizeof(tens) - zeroes / 8; } @@ -227,7 +228,7 @@ inline char* EncodeFullU32(uint32_t n, char* out_str) { & (0 - 8ull); uint64_t bottom_res = bottom + kEightZeroBytes; bottom_res >>= zeroes; - memcpy(out_str, &bottom_res, sizeof(bottom)); + little_endian::Store64(out_str, bottom_res); return out_str + sizeof(bottom) - zeroes / 8; } uint32_t top = n / 100'000'000; @@ -235,7 +236,7 @@ inline char* EncodeFullU32(uint32_t n, char* out_str) { uint64_t bottom = PrepareTenThousands(n / 10000, n % 10000); uint64_t bottom_res = bottom + kEightZeroBytes; out_str = EncodeHundred(top, out_str); - memcpy(out_str, &bottom_res, sizeof(bottom)); + little_endian::Store64(out_str, bottom_res); return out_str + sizeof(bottom); } @@ -279,7 +280,7 @@ char* numbers_internal::FastIntToBuffer(uint64_t i, char* buffer) { PrepareTenThousands(mod08 / 10000, mod08 % 10000) + kEightZeroBytes; if (i < 10'000'000'000ull) { buffer = EncodeHundred(static_cast(div08), buffer); - memcpy(buffer, &mod_result, 8); + little_endian::Store64(buffer, mod_result); buffer += 8; goto set_last_zero; } @@ -287,7 +288,7 @@ char* numbers_internal::FastIntToBuffer(uint64_t i, char* buffer) { // i < 10**16, in this case 8+8 if (i < 10'000'000'000'000'000ull) { buffer = EncodeFullU32(static_cast(div08), buffer); - memcpy(buffer, &mod_result, 8); + little_endian::Store64(buffer, mod_result); buffer += 8; goto set_last_zero; } else { @@ -297,9 +298,9 @@ char* numbers_internal::FastIntToBuffer(uint64_t i, char* buffer) { uint64_t mid_result = div08 - div016 * 100'000'000ull; mid_result = PrepareTenThousands(mid_result / 10000, mid_result % 10000) + kEightZeroBytes; - memcpy(buffer, &mid_result, 8); + little_endian::Store64(buffer, mid_result); buffer += 8; - memcpy(buffer, &mod_result, 8); + little_endian::Store64(buffer, mod_result); buffer += 8; goto set_last_zero; } From 02d1f5e18bb12d9aecade624eb339c319fd866d4 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 22 May 2023 12:38:15 -0700 Subject: [PATCH 0020/1238] Import of CCTZ from GitHub. PiperOrigin-RevId: 534150392 Change-Id: I4c0c111202178031e08d9edad3a4501800d924f0 --- .../cctz/src/time_zone_format_test.cc | 3 +- .../internal/cctz/src/time_zone_lookup.cc | 124 +++++++++++++++++- 2 files changed, 124 insertions(+), 3 deletions(-) diff --git a/absl/time/internal/cctz/src/time_zone_format_test.cc b/absl/time/internal/cctz/src/time_zone_format_test.cc index 7a03e7d29f5..4a6c71f17e3 100644 --- a/absl/time/internal/cctz/src/time_zone_format_test.cc +++ b/absl/time/internal/cctz/src/time_zone_format_test.cc @@ -221,7 +221,8 @@ TEST(Format, LocaleSpecific) { TestFormatSpecifier(tp, tz, "%B", "January"); // %c should at least produce the numeric year and time-of-day. - const std::string s = format("%c", tp, utc_time_zone()); + const std::string s = + absl::time_internal::cctz::format("%c", tp, utc_time_zone()); EXPECT_THAT(s, testing::HasSubstr("1970")); EXPECT_THAT(s, testing::HasSubstr("00:00:00")); diff --git a/absl/time/internal/cctz/src/time_zone_lookup.cc b/absl/time/internal/cctz/src/time_zone_lookup.cc index f6983aeb955..68084ce29e5 100644 --- a/absl/time/internal/cctz/src/time_zone_lookup.cc +++ b/absl/time/internal/cctz/src/time_zone_lookup.cc @@ -35,6 +35,19 @@ #include #endif +#if defined(_WIN32) +#include +// Include only when the SDK is for Windows 10 (and later), and the binary is +// targeted for Windows XP and later. +#if defined(_WIN32_WINNT_WIN10) && (_WIN32_WINNT >= _WIN32_WINNT_WINXP) +#include +#include +#include +#include +#include +#endif +#endif + #include #include #include @@ -47,8 +60,8 @@ ABSL_NAMESPACE_BEGIN namespace time_internal { namespace cctz { -#if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21 namespace { +#if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21 // Android 'L' removes __system_property_get() from the NDK, however // it is still a hidden symbol in libc so we use dlsym() to access it. // See Chromium's base/sys_info_android.cc for a similar example. @@ -72,9 +85,83 @@ int __system_property_get(const char* name, char* value) { static property_get_func system_property_get = LoadSystemPropertyGet(); return system_property_get ? system_property_get(name, value) : -1; } +#endif -} // namespace +#if defined(_WIN32_WINNT_WIN10) && (_WIN32_WINNT >= _WIN32_WINNT_WINXP) +// Calls the WinRT Calendar.GetTimeZone method to obtain the IANA ID of the +// local time zone. Returns an empty vector in case of an error. +std::string win32_local_time_zone(const HMODULE combase) { + std::string result; + const auto ro_activate_instance = + reinterpret_cast( + GetProcAddress(combase, "RoActivateInstance")); + if (!ro_activate_instance) { + return result; + } + const auto windows_create_string_reference = + reinterpret_cast( + GetProcAddress(combase, "WindowsCreateStringReference")); + if (!windows_create_string_reference) { + return result; + } + const auto windows_delete_string = + reinterpret_cast( + GetProcAddress(combase, "WindowsDeleteString")); + if (!windows_delete_string) { + return result; + } + const auto windows_get_string_raw_buffer = + reinterpret_cast( + GetProcAddress(combase, "WindowsGetStringRawBuffer")); + if (!windows_get_string_raw_buffer) { + return result; + } + + // The string returned by WindowsCreateStringReference doesn't need to be + // deleted. + HSTRING calendar_class_id; + HSTRING_HEADER calendar_class_id_header; + HRESULT hr = windows_create_string_reference( + RuntimeClass_Windows_Globalization_Calendar, + sizeof(RuntimeClass_Windows_Globalization_Calendar) / sizeof(wchar_t) - 1, + &calendar_class_id_header, &calendar_class_id); + if (FAILED(hr)) { + return result; + } + + IInspectable* calendar; + hr = ro_activate_instance(calendar_class_id, &calendar); + if (FAILED(hr)) { + return result; + } + + ABI::Windows::Globalization::ITimeZoneOnCalendar* time_zone; + hr = calendar->QueryInterface(IID_PPV_ARGS(&time_zone)); + if (FAILED(hr)) { + calendar->Release(); + return result; + } + + HSTRING tz_hstr; + hr = time_zone->GetTimeZone(&tz_hstr); + if (SUCCEEDED(hr)) { + UINT32 wlen; + const PCWSTR tz_wstr = windows_get_string_raw_buffer(tz_hstr, &wlen); + if (tz_wstr) { + const int size = WideCharToMultiByte(CP_UTF8, 0, tz_wstr, wlen, nullptr, + 0, nullptr, nullptr); + result.resize(size); + WideCharToMultiByte(CP_UTF8, 0, tz_wstr, wlen, &result[0], size, nullptr, + nullptr); + } + windows_delete_string(tz_hstr); + } + time_zone->Release(); + calendar->Release(); + return result; +} #endif +} // namespace std::string time_zone::name() const { return effective_impl().Name(); } @@ -190,6 +277,39 @@ time_zone local_time_zone() { zone = primary_tz.c_str(); } #endif +#if defined(_WIN32_WINNT_WIN10) && (_WIN32_WINNT >= _WIN32_WINNT_WINXP) + // Use the WinRT Calendar class to get the local time zone. This feature is + // available on Windows 10 and later. The library is dynamically linked to + // maintain binary compatibility with Windows XP - Windows 7. On Windows 8, + // The combase.dll API functions are available but the RoActivateInstance + // call will fail for the Calendar class. + std::string winrt_tz; + const HMODULE combase = + LoadLibraryEx(_T("combase.dll"), nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (combase) { + const auto ro_initialize = reinterpret_cast( + GetProcAddress(combase, "RoInitialize")); + const auto ro_uninitialize = reinterpret_cast( + GetProcAddress(combase, "RoUninitialize")); + if (ro_initialize && ro_uninitialize) { + const HRESULT hr = ro_initialize(RO_INIT_MULTITHREADED); + // RPC_E_CHANGED_MODE means that a previous RoInitialize call specified + // a different concurrency model. The WinRT runtime is initialized and + // should work for our purpose here, but we should *not* call + // RoUninitialize because it's a failure. + if (SUCCEEDED(hr) || hr == RPC_E_CHANGED_MODE) { + winrt_tz = win32_local_time_zone(combase); + if (SUCCEEDED(hr)) { + ro_uninitialize(); + } + } + } + FreeLibrary(combase); + } + if (!winrt_tz.empty()) { + zone = winrt_tz.c_str(); + } +#endif // Allow ${TZ} to override to default zone. char* tz_env = nullptr; From 7723d9a1555143c1ccf0d62710a56f6ded4ebc33 Mon Sep 17 00:00:00 2001 From: Niranjan Nilakantan Date: Thu, 18 May 2023 18:26:15 -0700 Subject: [PATCH 0021/1238] Clone the Clang flags section for IntelLLVM. This uses the same flags that Clang based builds use for Windows/Linux. A future change will add floating point related flags and some warning suppressions. So, we clone the section rather than just change the check at line 77. Fixes #1450 --- absl/copts/AbseilConfigureCopts.cmake | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/absl/copts/AbseilConfigureCopts.cmake b/absl/copts/AbseilConfigureCopts.cmake index 8209b262272..3f737c81720 100644 --- a/absl/copts/AbseilConfigureCopts.cmake +++ b/absl/copts/AbseilConfigureCopts.cmake @@ -83,6 +83,16 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") # MATCHES so we get both Clang an set(ABSL_DEFAULT_COPTS "${ABSL_LLVM_FLAGS}") set(ABSL_TEST_COPTS "${ABSL_LLVM_TEST_FLAGS}") endif() +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM") + # IntelLLVM is similar to Clang, with some additional flags. + if(MSVC) + # clang-cl is half MSVC, half LLVM + set(ABSL_DEFAULT_COPTS "${ABSL_CLANG_CL_FLAGS}") + set(ABSL_TEST_COPTS "${ABSL_CLANG_CL_TEST_FLAGS}") + else() + set(ABSL_DEFAULT_COPTS "${ABSL_LLVM_FLAGS}") + set(ABSL_TEST_COPTS "${ABSL_LLVM_TEST_FLAGS}") + endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") set(ABSL_DEFAULT_COPTS "${ABSL_MSVC_FLAGS}") set(ABSL_TEST_COPTS "${ABSL_MSVC_TEST_FLAGS}") From 830dabdbf3d8eded2490be634c34e033a32bad71 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 22 May 2023 16:05:19 -0700 Subject: [PATCH 0022/1238] Rollback of add a declaration for __cpuid for the IntelLLVM compiler. PiperOrigin-RevId: 534213948 Change-Id: I56b897060b9afe9d3d338756c80e52f421653b55 --- absl/crc/internal/cpu_detect.cc | 10 +++------- absl/random/internal/randen_detect.cc | 4 ---- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/absl/crc/internal/cpu_detect.cc b/absl/crc/internal/cpu_detect.cc index 4e29d0fa4fe..d61b7018d19 100644 --- a/absl/crc/internal/cpu_detect.cc +++ b/absl/crc/internal/cpu_detect.cc @@ -34,11 +34,9 @@ namespace crc_internal { #if defined(__x86_64__) || defined(_M_X64) -#if ABSL_HAVE_BUILTIN(__cpuid) -// MSVC-equivalent __cpuid intrinsic declaration for clang-like compilers -// for non-Windows build environments. -extern void __cpuid(int[4], int); -#elif !defined(_WIN32) && !defined(_WIN64) +namespace { + +#if !defined(_WIN32) && !defined(_WIN64) // MSVC defines this function for us. // https://learn.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex static void __cpuid(int cpu_info[4], int info_type) { @@ -49,8 +47,6 @@ static void __cpuid(int cpu_info[4], int info_type) { } #endif // !defined(_WIN32) && !defined(_WIN64) -namespace { - enum class Vendor { kUnknown, kIntel, diff --git a/absl/random/internal/randen_detect.cc b/absl/random/internal/randen_detect.cc index bdeab877b98..6dababa3511 100644 --- a/absl/random/internal/randen_detect.cc +++ b/absl/random/internal/randen_detect.cc @@ -45,10 +45,6 @@ #if defined(ABSL_INTERNAL_USE_X86_CPUID) #if defined(_WIN32) || defined(_WIN64) #include // NOLINT(build/include_order) -#elif ABSL_HAVE_BUILTIN(__cpuid) -// MSVC-equivalent __cpuid intrinsic declaration for clang-like compilers -// for non-Windows build environments. -extern void __cpuid(int[4], int); #else // MSVC-equivalent __cpuid intrinsic function. static void __cpuid(int cpu_info[4], int info_type) { From 9d43470921bef911145ad78a8e822ee1b297f937 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Mon, 22 May 2023 17:27:37 -0700 Subject: [PATCH 0023/1238] CI: Move the GCC-latest testing to GCC 13.1 on Linux This includes an upgrade to CMake 3.26.3 and Bazel 6.2.0 This change includes support for both GCC 12 and 13 since we were only testing GCC 11 before this change. PiperOrigin-RevId: 534235753 Change-Id: I4183a02469b1c3425c52a31b71fcefe403315a42 --- absl/functional/CMakeLists.txt | 2 +- absl/functional/internal/any_invocable.h | 8 ++++++++ absl/strings/internal/cord_rep_flat.h | 8 ++++++++ ci/linux_docker_containers.sh | 2 +- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/absl/functional/CMakeLists.txt b/absl/functional/CMakeLists.txt index 628b2ffcbcf..c704e049d00 100644 --- a/absl/functional/CMakeLists.txt +++ b/absl/functional/CMakeLists.txt @@ -39,7 +39,7 @@ absl_cc_test( "any_invocable_test.cc" "internal/any_invocable.h" COPTS - ${ABSL_DEFAULT_COPTS} + ${ABSL_TEST_COPTS} DEPS absl::any_invocable absl::base_internal diff --git a/absl/functional/internal/any_invocable.h b/absl/functional/internal/any_invocable.h index a5c22ad0cb0..a52fa876a4c 100644 --- a/absl/functional/internal/any_invocable.h +++ b/absl/functional/internal/any_invocable.h @@ -135,8 +135,16 @@ void InvokeR(F&& f, P&&... args) { template ::value, int> = 0> ReturnType InvokeR(F&& f, P&&... args) { + // GCC 12 has a false-positive -Wmaybe-uninitialized warning here. +#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif return absl::base_internal::invoke(std::forward(f), std::forward

(args)...); +#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0) +#pragma GCC diagnostic pop +#endif } // diff --git a/absl/strings/internal/cord_rep_flat.h b/absl/strings/internal/cord_rep_flat.h index e3e27fcd7c4..27c4b21eb5f 100644 --- a/absl/strings/internal/cord_rep_flat.h +++ b/absl/strings/internal/cord_rep_flat.h @@ -120,8 +120,16 @@ struct CordRepFlat : public CordRep { // Round size up so it matches a size we can exactly express in a tag. const size_t size = RoundUpForTag(len + kFlatOverhead); void* const raw_rep = ::operator new(size); + // GCC 13 has a false-positive -Wstringop-overflow warning here. + #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(13, 0) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstringop-overflow" + #endif CordRepFlat* rep = new (raw_rep) CordRepFlat(); rep->tag = AllocatedSizeToTag(size); + #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(13, 0) + #pragma GCC diagnostic pop + #endif return rep; } diff --git a/ci/linux_docker_containers.sh b/ci/linux_docker_containers.sh index dcaf18b950e..4dfa3175f21 100644 --- a/ci/linux_docker_containers.sh +++ b/ci/linux_docker_containers.sh @@ -17,5 +17,5 @@ readonly LINUX_ALPINE_CONTAINER="gcr.io/google.com/absl-177019/alpine:20201026" readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20230217" -readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20230217" +readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20230517" readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20230120" From 962e8be180a0b46ac76b4f0001a8944c99be1e7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Billeter?= Date: Mon, 24 Apr 2023 17:33:01 +0200 Subject: [PATCH 0024/1238] absl/debugging: Fix build on Solaris --- absl/debugging/internal/elf_mem_image.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/absl/debugging/internal/elf_mem_image.h b/absl/debugging/internal/elf_mem_image.h index 113071a9d19..5f4537ba3ca 100644 --- a/absl/debugging/internal/elf_mem_image.h +++ b/absl/debugging/internal/elf_mem_image.h @@ -33,7 +33,7 @@ #if defined(__ELF__) && !defined(__OpenBSD__) && !defined(__QNX__) && \ !defined(__native_client__) && !defined(__asmjs__) && \ - !defined(__wasm__) && !defined(__HAIKU__) + !defined(__wasm__) && !defined(__HAIKU__) && !defined(__sun) #define ABSL_HAVE_ELF_MEM_IMAGE 1 #endif From 79ca5d7aad63973c83a4962a66ab07cd623131ea Mon Sep 17 00:00:00 2001 From: niranjan-nilakantan <123265571+niranjan-nilakantan@users.noreply.github.com> Date: Tue, 23 May 2023 09:27:11 -0700 Subject: [PATCH 0025/1238] Add a declaration for __cpuid for the IntelLLVM compiler. Imported from GitHub PR https://github.com/abseil/abseil-cpp/pull/1452 __cpuid is declared in intrin.h, but is excluded on non-Windows platforms. We add this declaration to compensate. Fixes #1358 PiperOrigin-RevId: 534449804 Change-Id: I91027f79d8d52c4da428d5c3a53e2cec00825c13 --- absl/crc/internal/cpu_detect.cc | 22 ++++++++++++++-------- absl/random/internal/randen_detect.cc | 4 ++++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/absl/crc/internal/cpu_detect.cc b/absl/crc/internal/cpu_detect.cc index d61b7018d19..838380854ff 100644 --- a/absl/crc/internal/cpu_detect.cc +++ b/absl/crc/internal/cpu_detect.cc @@ -28,15 +28,12 @@ #include #endif -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace crc_internal { - #if defined(__x86_64__) || defined(_M_X64) - -namespace { - -#if !defined(_WIN32) && !defined(_WIN64) +#if ABSL_HAVE_BUILTIN(__cpuid) +// MSVC-equivalent __cpuid intrinsic declaration for clang-like compilers +// for non-Windows build environments. +extern void __cpuid(int[4], int); +#elif !defined(_WIN32) && !defined(_WIN64) // MSVC defines this function for us. // https://learn.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex static void __cpuid(int cpu_info[4], int info_type) { @@ -46,6 +43,15 @@ static void __cpuid(int cpu_info[4], int info_type) { : "a"(info_type), "c"(0)); } #endif // !defined(_WIN32) && !defined(_WIN64) +#endif // defined(__x86_64__) || defined(_M_X64) + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace crc_internal { + +#if defined(__x86_64__) || defined(_M_X64) + +namespace { enum class Vendor { kUnknown, diff --git a/absl/random/internal/randen_detect.cc b/absl/random/internal/randen_detect.cc index 6dababa3511..bdeab877b98 100644 --- a/absl/random/internal/randen_detect.cc +++ b/absl/random/internal/randen_detect.cc @@ -45,6 +45,10 @@ #if defined(ABSL_INTERNAL_USE_X86_CPUID) #if defined(_WIN32) || defined(_WIN64) #include // NOLINT(build/include_order) +#elif ABSL_HAVE_BUILTIN(__cpuid) +// MSVC-equivalent __cpuid intrinsic declaration for clang-like compilers +// for non-Windows build environments. +extern void __cpuid(int[4], int); #else // MSVC-equivalent __cpuid intrinsic function. static void __cpuid(int cpu_info[4], int info_type) { From 52747821480e6cadd8b27a0947af5d7933f9dfb4 Mon Sep 17 00:00:00 2001 From: Andy Getzendanner Date: Tue, 23 May 2023 15:46:35 -0700 Subject: [PATCH 0026/1238] Migrate most RAW_LOGs and RAW_CHECKs in tests to regular LOG and CHECK. The non-RAW_ versions provide better output but weren't available when most of these tests were written. There are just a couple spots where RAW_ is actually needed, e.g. signal handlers and malloc hooks. Also fix a couple warnings in layout_test.cc newly surfaced because the optimizer understands CHECK_XX differently than INTERNAL_CHECK. PiperOrigin-RevId: 534584435 Change-Id: I8d36fa809ffdaae5a3813064bd602cb8611c1613 --- absl/container/BUILD.bazel | 9 +- absl/container/CMakeLists.txt | 21 ++- absl/container/flat_hash_map_test.cc | 8 +- absl/container/flat_hash_set_test.cc | 6 +- absl/container/inlined_vector_test.cc | 6 +- absl/container/internal/layout_test.cc | 36 +++--- absl/container/internal/raw_hash_set_test.cc | 5 +- absl/debugging/BUILD.bazel | 12 +- absl/debugging/CMakeLists.txt | 13 +- absl/debugging/failure_signal_handler_test.cc | 5 +- absl/debugging/internal/demangle_test.cc | 4 +- .../internal/stack_consumption_test.cc | 4 +- absl/debugging/leak_check_fail_test.cc | 8 +- absl/debugging/leak_check_test.cc | 6 +- absl/debugging/symbolize_test.cc | 39 +++--- absl/flags/BUILD.bazel | 2 +- absl/flags/CMakeLists.txt | 2 +- absl/flags/parse_test.cc | 5 +- absl/log/BUILD.bazel | 1 - absl/log/CMakeLists.txt | 1 - absl/log/log_sink_test.cc | 3 +- absl/random/BUILD.bazel | 18 +-- absl/random/CMakeLists.txt | 23 ++-- absl/random/beta_distribution_test.cc | 39 +++--- absl/random/discrete_distribution_test.cc | 4 +- absl/random/exponential_distribution_test.cc | 44 +++---- absl/random/gaussian_distribution_test.cc | 44 +++---- absl/random/internal/BUILD.bazel | 8 +- absl/random/internal/nanobenchmark_test.cc | 20 +-- absl/random/internal/randen_engine_test.cc | 7 +- absl/random/internal/randen_hwaes_test.cc | 26 ++-- .../log_uniform_int_distribution_test.cc | 19 ++- absl/random/poisson_distribution_test.cc | 45 +++---- absl/random/uniform_int_distribution_test.cc | 7 +- absl/random/uniform_real_distribution_test.cc | 9 +- absl/random/zipf_distribution_test.cc | 22 ++-- absl/strings/BUILD.bazel | 7 +- absl/strings/CMakeLists.txt | 18 +-- absl/strings/cord_test.cc | 21 ++- absl/strings/internal/charconv_parse_test.cc | 10 +- .../internal/str_format/convert_test.cc | 3 +- absl/strings/numbers_test.cc | 45 +++---- absl/synchronization/BUILD.bazel | 8 +- absl/synchronization/CMakeLists.txt | 10 +- .../internal/graphcycles_test.cc | 41 +++--- absl/synchronization/lifetime_test.cc | 18 +-- absl/synchronization/mutex_test.cc | 122 ++++++++---------- absl/types/BUILD.bazel | 4 +- absl/types/CMakeLists.txt | 4 +- absl/types/any_test.cc | 4 +- absl/types/optional_test.cc | 5 +- 51 files changed, 409 insertions(+), 442 deletions(-) diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel index 902f6ed3b38..f22da59a376 100644 --- a/absl/container/BUILD.bazel +++ b/absl/container/BUILD.bazel @@ -160,8 +160,8 @@ cc_test( "//absl/base:config", "//absl/base:core_headers", "//absl/base:exception_testing", - "//absl/base:raw_logging_internal", "//absl/hash:hash_testing", + "//absl/log:check", "//absl/memory", "//absl/strings", "@com_google_googletest//:gtest_main", @@ -255,7 +255,7 @@ cc_test( ":unordered_map_lookup_test", ":unordered_map_members_test", ":unordered_map_modifiers_test", - "//absl/base:raw_logging_internal", + "//absl/log:check", "//absl/types:any", "@com_google_googletest//:gtest_main", ], @@ -289,7 +289,7 @@ cc_test( ":unordered_set_lookup_test", ":unordered_set_members_test", ":unordered_set_modifiers_test", - "//absl/base:raw_logging_internal", + "//absl/log:check", "//absl/memory", "//absl/strings", "@com_google_googletest//:gtest_main", @@ -656,7 +656,6 @@ cc_test( "//absl/base:config", "//absl/base:core_headers", "//absl/base:prefetch", - "//absl/base:raw_logging_internal", "//absl/log", "//absl/strings", "@com_google_googletest//:gtest_main", @@ -743,7 +742,7 @@ cc_test( ":layout", "//absl/base:config", "//absl/base:core_headers", - "//absl/base:raw_logging_internal", + "//absl/log:check", "//absl/types:span", "@com_google_googletest//:gtest_main", ], diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt index 3c48270b5ca..39d95e029ea 100644 --- a/absl/container/CMakeLists.txt +++ b/absl/container/CMakeLists.txt @@ -221,16 +221,16 @@ absl_cc_test( COPTS ${ABSL_TEST_COPTS} DEPS - absl::counting_allocator - absl::inlined_vector - absl::test_instance_tracker + absl::check absl::config absl::core_headers + absl::counting_allocator absl::exception_testing absl::hash_testing + absl::inlined_vector absl::memory - absl::raw_logging_internal absl::strings + absl::test_instance_tracker GTest::gmock_main ) @@ -300,14 +300,14 @@ absl_cc_test( COPTS ${ABSL_TEST_COPTS} DEPS + absl::any + absl::check absl::flat_hash_map absl::hash_generator_testing absl::unordered_map_constructor_test absl::unordered_map_lookup_test absl::unordered_map_members_test absl::unordered_map_modifiers_test - absl::any - absl::raw_logging_internal GTest::gmock_main ) @@ -337,15 +337,15 @@ absl_cc_test( ${ABSL_TEST_COPTS} "-DUNORDERED_SET_CXX17" DEPS + absl::check absl::flat_hash_set absl::hash_generator_testing + absl::memory + absl::strings absl::unordered_set_constructor_test absl::unordered_set_lookup_test absl::unordered_set_members_test absl::unordered_set_modifiers_test - absl::memory - absl::raw_logging_internal - absl::strings GTest::gmock_main ) @@ -742,7 +742,6 @@ absl_cc_test( absl::log absl::prefetch absl::raw_hash_set - absl::raw_logging_internal absl::strings GTest::gmock_main ) @@ -788,9 +787,9 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::layout + absl::check absl::config absl::core_headers - absl::raw_logging_internal absl::span GTest::gmock_main ) diff --git a/absl/container/flat_hash_map_test.cc b/absl/container/flat_hash_map_test.cc index 03171f6d1cc..e6acbea26f5 100644 --- a/absl/container/flat_hash_map_test.cc +++ b/absl/container/flat_hash_map_test.cc @@ -16,12 +16,12 @@ #include -#include "absl/base/internal/raw_logging.h" #include "absl/container/internal/hash_generator_testing.h" #include "absl/container/internal/unordered_map_constructor_test.h" #include "absl/container/internal/unordered_map_lookup_test.h" #include "absl/container/internal/unordered_map_members_test.h" #include "absl/container/internal/unordered_map_modifiers_test.h" +#include "absl/log/check.h" #include "absl/types/any.h" namespace absl { @@ -40,10 +40,10 @@ struct BeforeMain { BeforeMain() { absl::flat_hash_map x; x.insert({1, 1}); - ABSL_RAW_CHECK(x.find(0) == x.end(), "x should not contain 0"); + CHECK(x.find(0) == x.end()) << "x should not contain 0"; auto it = x.find(1); - ABSL_RAW_CHECK(it != x.end(), "x should contain 1"); - ABSL_RAW_CHECK(it->second, "1 should map to 1"); + CHECK(it != x.end()) << "x should contain 1"; + CHECK(it->second) << "1 should map to 1"; } }; const BeforeMain before_main; diff --git a/absl/container/flat_hash_set_test.cc b/absl/container/flat_hash_set_test.cc index b6a72a20a38..20130f91f48 100644 --- a/absl/container/flat_hash_set_test.cc +++ b/absl/container/flat_hash_set_test.cc @@ -16,12 +16,12 @@ #include -#include "absl/base/internal/raw_logging.h" #include "absl/container/internal/hash_generator_testing.h" #include "absl/container/internal/unordered_set_constructor_test.h" #include "absl/container/internal/unordered_set_lookup_test.h" #include "absl/container/internal/unordered_set_members_test.h" #include "absl/container/internal/unordered_set_modifiers_test.h" +#include "absl/log/check.h" #include "absl/memory/memory.h" #include "absl/strings/string_view.h" @@ -42,8 +42,8 @@ struct BeforeMain { BeforeMain() { absl::flat_hash_set x; x.insert(1); - ABSL_RAW_CHECK(!x.contains(0), "x should not contain 0"); - ABSL_RAW_CHECK(x.contains(1), "x should contain 1"); + CHECK(!x.contains(0)) << "x should not contain 0"; + CHECK(x.contains(1)) << "x should contain 1"; } }; const BeforeMain before_main; diff --git a/absl/container/inlined_vector_test.cc b/absl/container/inlined_vector_test.cc index 808f97ccc85..6f4625dcfa8 100644 --- a/absl/container/inlined_vector_test.cc +++ b/absl/container/inlined_vector_test.cc @@ -31,12 +31,12 @@ #include "gtest/gtest.h" #include "absl/base/attributes.h" #include "absl/base/internal/exception_testing.h" -#include "absl/base/internal/raw_logging.h" #include "absl/base/macros.h" #include "absl/base/options.h" #include "absl/container/internal/counting_allocator.h" #include "absl/container/internal/test_instance_tracker.h" #include "absl/hash/hash_testing.h" +#include "absl/log/check.h" #include "absl/memory/memory.h" #include "absl/strings/str_cat.h" @@ -103,13 +103,13 @@ class RefCounted { } void Ref() const { - ABSL_RAW_CHECK(count_ != nullptr, ""); + CHECK_NE(count_, nullptr); ++(*count_); } void Unref() const { --(*count_); - ABSL_RAW_CHECK(*count_ >= 0, ""); + CHECK_GE(*count_, 0); } int value_; diff --git a/absl/container/internal/layout_test.cc b/absl/container/internal/layout_test.cc index 54e5d5bbb8c..ce599ce79f1 100644 --- a/absl/container/internal/layout_test.cc +++ b/absl/container/internal/layout_test.cc @@ -26,7 +26,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/base/config.h" -#include "absl/base/internal/raw_logging.h" +#include "absl/log/check.h" #include "absl/types/span.h" namespace absl { @@ -38,7 +38,7 @@ using ::absl::Span; using ::testing::ElementsAre; size_t Distance(const void* from, const void* to) { - ABSL_RAW_CHECK(from <= to, "Distance must be non-negative"); + CHECK_LE(from, to) << "Distance must be non-negative"; return static_cast(to) - static_cast(from); } @@ -366,7 +366,7 @@ TEST(Layout, Sizes) { } TEST(Layout, PointerByIndex) { - alignas(max_align_t) const unsigned char p[100] = {}; + alignas(max_align_t) const unsigned char p[100] = {0}; { using L = Layout; EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer<0>(p)))); @@ -447,7 +447,7 @@ TEST(Layout, PointerByIndex) { } TEST(Layout, PointerByType) { - alignas(max_align_t) const unsigned char p[100] = {}; + alignas(max_align_t) const unsigned char p[100] = {0}; { using L = Layout; EXPECT_EQ( @@ -526,7 +526,7 @@ TEST(Layout, PointerByType) { } TEST(Layout, MutablePointerByIndex) { - alignas(max_align_t) unsigned char p[100]; + alignas(max_align_t) unsigned char p[100] = {0}; { using L = Layout; EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer<0>(p)))); @@ -581,7 +581,7 @@ TEST(Layout, MutablePointerByIndex) { } TEST(Layout, MutablePointerByType) { - alignas(max_align_t) unsigned char p[100]; + alignas(max_align_t) unsigned char p[100] = {0}; { using L = Layout; EXPECT_EQ(0, Distance(p, Type(L::Partial().Pointer(p)))); @@ -647,7 +647,7 @@ TEST(Layout, MutablePointerByType) { } TEST(Layout, Pointers) { - alignas(max_align_t) const unsigned char p[100] = {}; + alignas(max_align_t) const unsigned char p[100] = {0}; using L = Layout; { const auto x = L::Partial(); @@ -683,7 +683,7 @@ TEST(Layout, Pointers) { } TEST(Layout, MutablePointers) { - alignas(max_align_t) unsigned char p[100]; + alignas(max_align_t) unsigned char p[100] = {0}; using L = Layout; { const auto x = L::Partial(); @@ -716,7 +716,7 @@ TEST(Layout, MutablePointers) { } TEST(Layout, SliceByIndexSize) { - alignas(max_align_t) const unsigned char p[100] = {}; + alignas(max_align_t) const unsigned char p[100] = {0}; { using L = Layout; EXPECT_EQ(0, L::Partial(0).Slice<0>(p).size()); @@ -744,7 +744,7 @@ TEST(Layout, SliceByIndexSize) { } TEST(Layout, SliceByTypeSize) { - alignas(max_align_t) const unsigned char p[100] = {}; + alignas(max_align_t) const unsigned char p[100] = {0}; { using L = Layout; EXPECT_EQ(0, L::Partial(0).Slice(p).size()); @@ -766,7 +766,7 @@ TEST(Layout, SliceByTypeSize) { } TEST(Layout, MutableSliceByIndexSize) { - alignas(max_align_t) unsigned char p[100]; + alignas(max_align_t) unsigned char p[100] = {0}; { using L = Layout; EXPECT_EQ(0, L::Partial(0).Slice<0>(p).size()); @@ -794,7 +794,7 @@ TEST(Layout, MutableSliceByIndexSize) { } TEST(Layout, MutableSliceByTypeSize) { - alignas(max_align_t) unsigned char p[100]; + alignas(max_align_t) unsigned char p[100] = {0}; { using L = Layout; EXPECT_EQ(0, L::Partial(0).Slice(p).size()); @@ -816,7 +816,7 @@ TEST(Layout, MutableSliceByTypeSize) { } TEST(Layout, SliceByIndexData) { - alignas(max_align_t) const unsigned char p[100] = {}; + alignas(max_align_t) const unsigned char p[100] = {0}; { using L = Layout; EXPECT_EQ( @@ -939,7 +939,7 @@ TEST(Layout, SliceByIndexData) { } TEST(Layout, SliceByTypeData) { - alignas(max_align_t) const unsigned char p[100] = {}; + alignas(max_align_t) const unsigned char p[100] = {0}; { using L = Layout; EXPECT_EQ( @@ -1037,7 +1037,7 @@ TEST(Layout, SliceByTypeData) { } TEST(Layout, MutableSliceByIndexData) { - alignas(max_align_t) unsigned char p[100]; + alignas(max_align_t) unsigned char p[100] = {0}; { using L = Layout; EXPECT_EQ( @@ -1122,7 +1122,7 @@ TEST(Layout, MutableSliceByIndexData) { } TEST(Layout, MutableSliceByTypeData) { - alignas(max_align_t) unsigned char p[100]; + alignas(max_align_t) unsigned char p[100] = {0}; { using L = Layout; EXPECT_EQ( @@ -1268,7 +1268,7 @@ testing::PolymorphicMatcher> Tuple(M... matchers) { } TEST(Layout, Slices) { - alignas(max_align_t) const unsigned char p[100] = {}; + alignas(max_align_t) const unsigned char p[100] = {0}; using L = Layout; { const auto x = L::Partial(); @@ -1302,7 +1302,7 @@ TEST(Layout, Slices) { } TEST(Layout, MutableSlices) { - alignas(max_align_t) unsigned char p[100] = {}; + alignas(max_align_t) unsigned char p[100] = {0}; using L = Layout; { const auto x = L::Partial(); diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc index c46a59398f2..ce1070ba448 100644 --- a/absl/container/internal/raw_hash_set_test.cc +++ b/absl/container/internal/raw_hash_set_test.cc @@ -40,7 +40,6 @@ #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/internal/cycleclock.h" -#include "absl/base/internal/raw_logging.h" #include "absl/base/prefetch.h" #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" @@ -1280,7 +1279,7 @@ ExpectedStats XorSeedExpectedStats() { {{0.95, 0}, {0.99, 1}, {0.999, 4}, {0.9999, 10}}}; } } - ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width"); + LOG(FATAL) << "Unknown Group width"; return {}; } @@ -1376,7 +1375,7 @@ ExpectedStats LinearTransformExpectedStats() { {{0.95, 0}, {0.99, 1}, {0.999, 6}, {0.9999, 10}}}; } } - ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width"); + LOG(FATAL) << "Unknown Group width"; return {}; } diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel index e89dbae8071..42124bfb903 100644 --- a/absl/debugging/BUILD.bazel +++ b/absl/debugging/BUILD.bazel @@ -122,7 +122,8 @@ cc_test( "//absl/base", "//absl/base:config", "//absl/base:core_headers", - "//absl/base:raw_logging_internal", + "//absl/log", + "//absl/log:check", "//absl/memory", "//absl/strings", "@com_google_googletest//:gtest", @@ -180,6 +181,7 @@ cc_test( ":stacktrace", ":symbolize", "//absl/base:raw_logging_internal", + "//absl/log:check", "//absl/strings", "@com_google_googletest//:gtest", ], @@ -233,7 +235,7 @@ cc_test( ":stack_consumption", "//absl/base:config", "//absl/base:core_headers", - "//absl/base:raw_logging_internal", + "//absl/log", "//absl/memory", "@com_google_googletest//:gtest_main", ], @@ -260,7 +262,7 @@ cc_test( deps = [ ":leak_check", "//absl/base:config", - "//absl/base:raw_logging_internal", + "//absl/log", "@com_google_googletest//:gtest_main", ], ) @@ -277,7 +279,7 @@ cc_binary( linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":leak_check", - "//absl/base:raw_logging_internal", + "//absl/log", "@com_google_googletest//:gtest_main", ], ) @@ -306,7 +308,7 @@ cc_test( deps = [ ":stack_consumption", "//absl/base:core_headers", - "//absl/base:raw_logging_internal", + "//absl/log", "@com_google_googletest//:gtest_main", ], ) diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt index ef6b49659fc..65e2af88016 100644 --- a/absl/debugging/CMakeLists.txt +++ b/absl/debugging/CMakeLists.txt @@ -101,14 +101,15 @@ absl_cc_test( LINKOPTS $<$:-DEBUG> DEPS - absl::stack_consumption - absl::symbolize absl::base + absl::check absl::config absl::core_headers + absl::log absl::memory - absl::raw_logging_internal + absl::stack_consumption absl::strings + absl::symbolize GTest::gmock ) @@ -157,6 +158,7 @@ absl_cc_test( COPTS ${ABSL_TEST_COPTS} DEPS + absl::check absl::failure_signal_handler absl::stacktrace absl::symbolize @@ -216,8 +218,8 @@ absl_cc_test( absl::stack_consumption absl::config absl::core_headers + absl::log absl::memory - absl::raw_logging_internal GTest::gmock_main ) @@ -248,6 +250,7 @@ absl_cc_test( DEPS absl::leak_check absl::base + absl::log GTest::gmock_main ) @@ -278,7 +281,7 @@ absl_cc_test( DEPS absl::stack_consumption absl::core_headers - absl::raw_logging_internal + absl::log GTest::gmock_main ) diff --git a/absl/debugging/failure_signal_handler_test.cc b/absl/debugging/failure_signal_handler_test.cc index 6a62428b338..72816a3e727 100644 --- a/absl/debugging/failure_signal_handler_test.cc +++ b/absl/debugging/failure_signal_handler_test.cc @@ -22,11 +22,12 @@ #include #include -#include "gtest/gtest.h" #include "gmock/gmock.h" +#include "gtest/gtest.h" #include "absl/base/internal/raw_logging.h" #include "absl/debugging/stacktrace.h" #include "absl/debugging/symbolize.h" +#include "absl/log/check.h" #include "absl/strings/match.h" #include "absl/strings/str_cat.h" @@ -87,7 +88,7 @@ std::string GetTmpDir() { // This function runs in a fork()ed process on most systems. void InstallHandlerWithWriteToFileAndRaise(const char* file, int signo) { error_file = fopen(file, "w"); - ABSL_RAW_CHECK(error_file != nullptr, "Failed create error_file"); + CHECK_NE(error_file, nullptr) << "Failed create error_file"; absl::FailureSignalHandlerOptions options; options.writerfn = WriteToErrorFile; absl::InstallFailureSignalHandler(options); diff --git a/absl/debugging/internal/demangle_test.cc b/absl/debugging/internal/demangle_test.cc index 2fa4143a2c1..faec72b566a 100644 --- a/absl/debugging/internal/demangle_test.cc +++ b/absl/debugging/internal/demangle_test.cc @@ -19,8 +19,8 @@ #include "gtest/gtest.h" #include "absl/base/config.h" -#include "absl/base/internal/raw_logging.h" #include "absl/debugging/internal/stack_consumption.h" +#include "absl/log/log.h" #include "absl/memory/memory.h" namespace absl { @@ -151,7 +151,7 @@ static const char *DemangleStackConsumption(const char *mangled, int *stack_consumed) { g_mangled = mangled; *stack_consumed = GetSignalHandlerStackConsumption(DemangleSignalHandler); - ABSL_RAW_LOG(INFO, "Stack consumption of Demangle: %d", *stack_consumed); + LOG(INFO) << "Stack consumption of Demangle: " << *stack_consumed; return g_demangle_result; } diff --git a/absl/debugging/internal/stack_consumption_test.cc b/absl/debugging/internal/stack_consumption_test.cc index 80445bf43aa..0255ac8f36c 100644 --- a/absl/debugging/internal/stack_consumption_test.cc +++ b/absl/debugging/internal/stack_consumption_test.cc @@ -20,7 +20,7 @@ #include #include "gtest/gtest.h" -#include "absl/base/internal/raw_logging.h" +#include "absl/log/log.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -33,7 +33,7 @@ static void SimpleSignalHandler(int signo) { // Never true, but prevents compiler from optimizing buf out. if (signo == 0) { - ABSL_RAW_LOG(INFO, "%p", static_cast(buf)); + LOG(INFO) << static_cast(buf); } } diff --git a/absl/debugging/leak_check_fail_test.cc b/absl/debugging/leak_check_fail_test.cc index c49b81a9d9e..46e9fb6297b 100644 --- a/absl/debugging/leak_check_fail_test.cc +++ b/absl/debugging/leak_check_fail_test.cc @@ -13,9 +13,10 @@ // limitations under the License. #include + #include "gtest/gtest.h" -#include "absl/base/internal/raw_logging.h" #include "absl/debugging/leak_check.h" +#include "absl/log/log.h" namespace { @@ -25,7 +26,7 @@ TEST(LeakCheckTest, LeakMemory) { // failed exit code. char* foo = strdup("lsan should complain about this leaked string"); - ABSL_RAW_LOG(INFO, "Should detect leaked string %s", foo); + LOG(INFO) << "Should detect leaked string " << foo; } TEST(LeakCheckTest, LeakMemoryAfterDisablerScope) { @@ -34,8 +35,7 @@ TEST(LeakCheckTest, LeakMemoryAfterDisablerScope) { // failed exit code. { absl::LeakCheckDisabler disabler; } char* foo = strdup("lsan should also complain about this leaked string"); - ABSL_RAW_LOG(INFO, "Re-enabled leak detection.Should detect leaked string %s", - foo); + LOG(INFO) << "Re-enabled leak detection.Should detect leaked string " << foo; } } // namespace diff --git a/absl/debugging/leak_check_test.cc b/absl/debugging/leak_check_test.cc index 6a42e31bada..6f0135ed792 100644 --- a/absl/debugging/leak_check_test.cc +++ b/absl/debugging/leak_check_test.cc @@ -16,8 +16,8 @@ #include "gtest/gtest.h" #include "absl/base/config.h" -#include "absl/base/internal/raw_logging.h" #include "absl/debugging/leak_check.h" +#include "absl/log/log.h" namespace { @@ -26,7 +26,7 @@ TEST(LeakCheckTest, IgnoreLeakSuppressesLeakedMemoryErrors) { GTEST_SKIP() << "LeakChecker is not active"; } auto foo = absl::IgnoreLeak(new std::string("some ignored leaked string")); - ABSL_RAW_LOG(INFO, "Ignoring leaked string %s", foo->c_str()); + LOG(INFO) << "Ignoring leaked string " << foo; } TEST(LeakCheckTest, LeakCheckDisablerIgnoresLeak) { @@ -35,7 +35,7 @@ TEST(LeakCheckTest, LeakCheckDisablerIgnoresLeak) { } absl::LeakCheckDisabler disabler; auto foo = new std::string("some string leaked while checks are disabled"); - ABSL_RAW_LOG(INFO, "Ignoring leaked string %s", foo->c_str()); + LOG(INFO) << "Ignoring leaked string " << foo; } } // namespace diff --git a/absl/debugging/symbolize_test.cc b/absl/debugging/symbolize_test.cc index 3165c6ede1d..1d1199ff79f 100644 --- a/absl/debugging/symbolize_test.cc +++ b/absl/debugging/symbolize_test.cc @@ -29,9 +29,10 @@ #include "absl/base/casts.h" #include "absl/base/config.h" #include "absl/base/internal/per_thread_tls.h" -#include "absl/base/internal/raw_logging.h" #include "absl/base/optimization.h" #include "absl/debugging/internal/stack_consumption.h" +#include "absl/log/check.h" +#include "absl/log/log.h" #include "absl/memory/memory.h" #include "absl/strings/string_view.h" @@ -124,15 +125,17 @@ static char try_symbolize_buffer[4096]; // absl::Symbolize() returns false, otherwise returns try_symbolize_buffer with // the result of absl::Symbolize(). static const char *TrySymbolizeWithLimit(void *pc, int limit) { - ABSL_RAW_CHECK(limit <= sizeof(try_symbolize_buffer), - "try_symbolize_buffer is too small"); + CHECK_LE(limit, sizeof(try_symbolize_buffer)) + << "try_symbolize_buffer is too small"; // Use the heap to facilitate heap and buffer sanitizer tools. auto heap_buffer = absl::make_unique(sizeof(try_symbolize_buffer)); bool found = absl::Symbolize(pc, heap_buffer.get(), limit); if (found) { - ABSL_RAW_CHECK(strnlen(heap_buffer.get(), limit) < limit, - "absl::Symbolize() did not properly terminate the string"); + CHECK_LT(static_cast( + strnlen(heap_buffer.get(), static_cast(limit))), + limit) + << "absl::Symbolize() did not properly terminate the string"; strncpy(try_symbolize_buffer, heap_buffer.get(), sizeof(try_symbolize_buffer) - 1); try_symbolize_buffer[sizeof(try_symbolize_buffer) - 1] = '\0'; @@ -155,8 +158,8 @@ void ABSL_ATTRIBUTE_NOINLINE TestWithReturnAddress() { #if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE) void *return_address = __builtin_return_address(0); const char *symbol = TrySymbolize(return_address); - ABSL_RAW_CHECK(symbol != nullptr, "TestWithReturnAddress failed"); - ABSL_RAW_CHECK(strcmp(symbol, "main") == 0, "TestWithReturnAddress failed"); + CHECK_NE(symbol, nullptr) << "TestWithReturnAddress failed"; + CHECK_STREQ(symbol, "main") << "TestWithReturnAddress failed"; std::cout << "TestWithReturnAddress passed" << std::endl; #endif } @@ -314,8 +317,8 @@ static int FilterElfHeader(struct dl_phdr_info *info, size_t size, void *data) { TEST(Symbolize, SymbolizeWithMultipleMaps) { // Force kPadding0 and kPadding1 to be linked in. if (volatile_bool) { - ABSL_RAW_LOG(INFO, "%s", kPadding0); - ABSL_RAW_LOG(INFO, "%s", kPadding1); + LOG(INFO) << kPadding0; + LOG(INFO) << kPadding1; } // Verify we can symbolize everything. @@ -463,9 +466,9 @@ void ABSL_ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() { (defined(__i386__) || defined(__x86_64__)) void *pc = non_inline_func(); const char *symbol = TrySymbolize(pc); - ABSL_RAW_CHECK(symbol != nullptr, "TestWithPCInsideNonInlineFunction failed"); - ABSL_RAW_CHECK(strcmp(symbol, "non_inline_func") == 0, - "TestWithPCInsideNonInlineFunction failed"); + CHECK_NE(symbol, nullptr) << "TestWithPCInsideNonInlineFunction failed"; + CHECK_STREQ(symbol, "non_inline_func") + << "TestWithPCInsideNonInlineFunction failed"; std::cout << "TestWithPCInsideNonInlineFunction passed" << std::endl; #endif } @@ -475,9 +478,8 @@ void ABSL_ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() { (defined(__i386__) || defined(__x86_64__)) void *pc = inline_func(); // Must be inlined. const char *symbol = TrySymbolize(pc); - ABSL_RAW_CHECK(symbol != nullptr, "TestWithPCInsideInlineFunction failed"); - ABSL_RAW_CHECK(strcmp(symbol, __FUNCTION__) == 0, - "TestWithPCInsideInlineFunction failed"); + CHECK_NE(symbol, nullptr) << "TestWithPCInsideInlineFunction failed"; + CHECK_STREQ(symbol, __FUNCTION__) << "TestWithPCInsideInlineFunction failed"; std::cout << "TestWithPCInsideInlineFunction passed" << std::endl; #endif } @@ -519,9 +521,8 @@ __attribute__((target("arm"))) int ArmThumbOverlapArm(int x) { void ABSL_ATTRIBUTE_NOINLINE TestArmThumbOverlap() { #if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE) const char *symbol = TrySymbolize((void *)&ArmThumbOverlapArm); - ABSL_RAW_CHECK(symbol != nullptr, "TestArmThumbOverlap failed"); - ABSL_RAW_CHECK(strcmp("ArmThumbOverlapArm()", symbol) == 0, - "TestArmThumbOverlap failed"); + CHECK_NE(symbol, nullptr) << "TestArmThumbOverlap failed"; + CHECK_STREQ("ArmThumbOverlapArm()", symbol) << "TestArmThumbOverlap failed"; std::cout << "TestArmThumbOverlap passed" << std::endl; #endif } @@ -584,7 +585,7 @@ int main(int argc, char **argv) { #if !defined(__EMSCRIPTEN__) // Make sure kHpageTextPadding is linked into the binary. if (volatile_bool) { - ABSL_RAW_LOG(INFO, "%s", kHpageTextPadding); + LOG(INFO) << kHpageTextPadding; } #endif // !defined(__EMSCRIPTEN__) diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel index 570d280c89a..627f453a77c 100644 --- a/absl/flags/BUILD.bazel +++ b/absl/flags/BUILD.bazel @@ -452,8 +452,8 @@ cc_test( ":parse", ":reflection", ":usage_internal", - "//absl/base:raw_logging_internal", "//absl/base:scoped_set_env", + "//absl/log", "//absl/strings", "//absl/types:span", "@com_google_googletest//:gtest_main", diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt index b5f6dfc492c..b9d3b97b847 100644 --- a/absl/flags/CMakeLists.txt +++ b/absl/flags/CMakeLists.txt @@ -374,7 +374,7 @@ absl_cc_test( absl::flags_parse absl::flags_reflection absl::flags_usage_internal - absl::raw_logging_internal + absl::log absl::scoped_set_env absl::span absl::strings diff --git a/absl/flags/parse_test.cc b/absl/flags/parse_test.cc index cd32efc88ea..97b78980bd2 100644 --- a/absl/flags/parse_test.cc +++ b/absl/flags/parse_test.cc @@ -24,12 +24,12 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/base/internal/raw_logging.h" #include "absl/base/internal/scoped_set_env.h" #include "absl/flags/flag.h" #include "absl/flags/internal/parse.h" #include "absl/flags/internal/usage.h" #include "absl/flags/reflection.h" +#include "absl/log/log.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "absl/strings/substitute.h" @@ -150,8 +150,7 @@ const std::string& GetTestTempDir() { } if (res->empty()) { - ABSL_INTERNAL_LOG(FATAL, - "Failed to make temporary directory for data files"); + LOG(FATAL) << "Failed to make temporary directory for data files"; } #ifdef _WIN32 diff --git a/absl/log/BUILD.bazel b/absl/log/BUILD.bazel index 560f6c4417d..e1410637812 100644 --- a/absl/log/BUILD.bazel +++ b/absl/log/BUILD.bazel @@ -459,7 +459,6 @@ cc_test( ":log_sink_registry", ":scoped_mock_log", "//absl/base:core_headers", - "//absl/base:raw_logging_internal", "//absl/log/internal:test_actions", "//absl/log/internal:test_helpers", "//absl/log/internal:test_matchers", diff --git a/absl/log/CMakeLists.txt b/absl/log/CMakeLists.txt index 2990984f488..9320ce59fb9 100644 --- a/absl/log/CMakeLists.txt +++ b/absl/log/CMakeLists.txt @@ -905,7 +905,6 @@ absl_cc_test( absl::log_sink absl::log_sink_registry absl::log_severity - absl::raw_logging_internal absl::scoped_mock_log absl::strings GTest::gtest_main diff --git a/absl/log/log_sink_test.cc b/absl/log/log_sink_test.cc index 8903da7266b..fa7430606e6 100644 --- a/absl/log/log_sink_test.cc +++ b/absl/log/log_sink_test.cc @@ -18,7 +18,6 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/base/attributes.h" -#include "absl/base/internal/raw_logging.h" #include "absl/log/internal/test_actions.h" #include "absl/log/internal/test_helpers.h" #include "absl/log/internal/test_matchers.h" @@ -205,7 +204,7 @@ class ReentrancyTest : public ::testing::Test { << "The log is coming from *inside the sink*."; break; default: - ABSL_RAW_LOG(FATAL, "Invalid mode %d.\n", static_cast(mode_)); + LOG(FATAL) << "Invalid mode " << static_cast(mode_); } } diff --git a/absl/random/BUILD.bazel b/absl/random/BUILD.bazel index 133c0659eb6..19130ff78d4 100644 --- a/absl/random/BUILD.bazel +++ b/absl/random/BUILD.bazel @@ -189,7 +189,7 @@ cc_test( deps = [ ":distributions", ":random", - "//absl/base:raw_logging_internal", + "//absl/log", "//absl/numeric:representation", "//absl/random/internal:distribution_test_util", "//absl/random/internal:pcg_engine", @@ -244,7 +244,7 @@ cc_test( deps = [ ":distributions", ":random", - "//absl/base:raw_logging_internal", + "//absl/log", "//absl/random/internal:distribution_test_util", "//absl/random/internal:pcg_engine", "//absl/random/internal:sequence_urbg", @@ -265,7 +265,7 @@ cc_test( deps = [ ":distributions", ":random", - "//absl/base:raw_logging_internal", + "//absl/log", "//absl/random/internal:distribution_test_util", "//absl/random/internal:pcg_engine", "//absl/random/internal:sequence_urbg", @@ -292,8 +292,8 @@ cc_test( ":distributions", ":random", "//absl/base:core_headers", - "//absl/base:raw_logging_internal", "//absl/container:flat_hash_map", + "//absl/log", "//absl/random/internal:distribution_test_util", "//absl/random/internal:pcg_engine", "//absl/random/internal:sequence_urbg", @@ -314,7 +314,7 @@ cc_test( ":distributions", ":random", "//absl/base:core_headers", - "//absl/base:raw_logging_internal", + "//absl/log", "//absl/numeric:representation", "//absl/random/internal:distribution_test_util", "//absl/random/internal:pcg_engine", @@ -338,7 +338,7 @@ cc_test( ":distributions", ":random", "//absl/base:core_headers", - "//absl/base:raw_logging_internal", + "//absl/log", "//absl/numeric:representation", "//absl/random/internal:distribution_test_util", "//absl/random/internal:sequence_urbg", @@ -360,7 +360,7 @@ cc_test( deps = [ ":distributions", ":random", - "//absl/base:raw_logging_internal", + "//absl/log", "//absl/random/internal:distribution_test_util", "//absl/random/internal:pcg_engine", "//absl/random/internal:sequence_urbg", @@ -385,7 +385,7 @@ cc_test( deps = [ ":distributions", ":random", - "//absl/base:raw_logging_internal", + "//absl/log", "//absl/numeric:representation", "//absl/random/internal:distribution_test_util", "//absl/random/internal:pcg_engine", @@ -406,7 +406,7 @@ cc_test( deps = [ ":distributions", ":random", - "//absl/base:raw_logging_internal", + "//absl/log", "//absl/random/internal:distribution_test_util", "//absl/random/internal:pcg_engine", "//absl/random/internal:sequence_urbg", diff --git a/absl/random/CMakeLists.txt b/absl/random/CMakeLists.txt index c74fd30064b..bd363d881cb 100644 --- a/absl/random/CMakeLists.txt +++ b/absl/random/CMakeLists.txt @@ -260,13 +260,13 @@ absl_cc_test( LINKOPTS ${ABSL_DEFAULT_LINKOPTS} DEPS + absl::log absl::numeric_representation absl::random_distributions absl::random_random absl::random_internal_distribution_test_util absl::random_internal_sequence_urbg absl::random_internal_pcg_engine - absl::raw_logging_internal absl::strings absl::str_format GTest::gmock @@ -299,6 +299,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} LINKOPTS ${ABSL_DEFAULT_LINKOPTS} + DEPS absl::random_distributions absl::random_random absl::raw_logging_internal @@ -315,12 +316,13 @@ absl_cc_test( ${ABSL_TEST_COPTS} LINKOPTS ${ABSL_DEFAULT_LINKOPTS} + DEPS + absl::log absl::random_distributions absl::random_internal_distribution_test_util absl::random_internal_pcg_engine absl::random_internal_sequence_urbg absl::random_random - absl::raw_logging_internal absl::strings absl::str_format GTest::gmock @@ -337,12 +339,12 @@ absl_cc_test( LINKOPTS ${ABSL_DEFAULT_LINKOPTS} DEPS + absl::log absl::random_distributions absl::random_internal_distribution_test_util absl::random_internal_pcg_engine absl::random_internal_sequence_urbg absl::random_random - absl::raw_logging_internal absl::strings GTest::gmock GTest::gtest_main @@ -362,10 +364,10 @@ absl_cc_test( absl::random_random absl::core_headers absl::flat_hash_map + absl::log absl::random_internal_distribution_test_util absl::random_internal_pcg_engine absl::random_internal_sequence_urbg - absl::raw_logging_internal absl::strings absl::str_format GTest::gmock @@ -383,13 +385,13 @@ absl_cc_test( ${ABSL_DEFAULT_LINKOPTS} DEPS absl::core_headers + absl::log absl::numeric_representation absl::random_distributions absl::random_internal_distribution_test_util absl::random_internal_pcg_engine absl::random_internal_sequence_urbg absl::random_random - absl::raw_logging_internal absl::strings absl::str_format GTest::gmock @@ -407,12 +409,12 @@ absl_cc_test( ${ABSL_DEFAULT_LINKOPTS} DEPS absl::core_headers + absl::log absl::numeric_representation absl::random_distributions absl::random_internal_distribution_test_util absl::random_internal_sequence_urbg absl::random_random - absl::raw_logging_internal absl::strings absl::str_format GTest::gmock @@ -429,12 +431,12 @@ absl_cc_test( LINKOPTS ${ABSL_DEFAULT_LINKOPTS} DEPS + absl::log absl::random_distributions absl::random_internal_distribution_test_util absl::random_internal_pcg_engine absl::random_internal_sequence_urbg absl::random_random - absl::raw_logging_internal absl::strings GTest::gmock GTest::gtest_main @@ -450,6 +452,7 @@ absl_cc_test( LINKOPTS ${ABSL_DEFAULT_LINKOPTS} DEPS + absl::log absl::numeric_representation absl::random_distributions absl::random_internal_distribution_test_util @@ -471,12 +474,12 @@ absl_cc_test( LINKOPTS ${ABSL_DEFAULT_LINKOPTS} DEPS + absl::log absl::random_distributions absl::random_internal_distribution_test_util absl::random_internal_pcg_engine absl::random_internal_sequence_urbg absl::random_random - absl::raw_logging_internal absl::strings GTest::gmock GTest::gtest_main @@ -1090,9 +1093,9 @@ absl_cc_test( LINKOPTS ${ABSL_DEFAULT_LINKOPTS} DEPS + absl::log absl::random_internal_explicit_seed_seq absl::random_internal_randen_engine - absl::raw_logging_internal absl::strings absl::time GTest::gmock @@ -1142,10 +1145,10 @@ absl_cc_test( LINKOPTS ${ABSL_DEFAULT_LINKOPTS} DEPS + absl::log absl::random_internal_platform absl::random_internal_randen_hwaes absl::random_internal_randen_hwaes_impl - absl::raw_logging_internal absl::str_format GTest::gmock GTest::gtest diff --git a/absl/random/beta_distribution_test.cc b/absl/random/beta_distribution_test.cc index c16fbb4f0eb..c93b2a339cd 100644 --- a/absl/random/beta_distribution_test.cc +++ b/absl/random/beta_distribution_test.cc @@ -28,7 +28,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/base/internal/raw_logging.h" +#include "absl/log/log.h" #include "absl/numeric/internal/representation.h" #include "absl/random/internal/chi_square.h" #include "absl/random/internal/distribution_test_util.h" @@ -107,8 +107,8 @@ TYPED_TEST(BetaDistributionInterfaceTest, SerializeTest) { }; for (TypeParam alpha : kValues) { for (TypeParam beta : kValues) { - ABSL_INTERNAL_LOG( - INFO, absl::StrFormat("Smoke test for Beta(%a, %a)", alpha, beta)); + LOG(INFO) << absl::StreamFormat("Smoke test for Beta(%a, %a)", alpha, + beta); param_type param(alpha, beta); absl::beta_distribution before(alpha, beta); @@ -327,15 +327,13 @@ bool BetaDistributionTest::SingleZTestOnMeanAndVariance(double p, absl::random_internal::Near("z", z_mean, 0.0, max_err) && absl::random_internal::Near("z_variance", z_variance, 0.0, max_err); if (!pass) { - ABSL_INTERNAL_LOG( - INFO, - absl::StrFormat( - "Beta(%f, %f), " - "mean: sample %f, expect %f, which is %f stddevs away, " - "variance: sample %f, expect %f, which is %f stddevs away.", - alpha_, beta_, m.mean, Mean(), - std::abs(m.mean - Mean()) / mean_stddev, m.variance, Variance(), - std::abs(m.variance - Variance()) / variance_stddev)); + LOG(INFO) << "Beta(" << alpha_ << ", " << beta_ << "), mean: sample " + << m.mean << ", expect " << Mean() << ", which is " + << std::abs(m.mean - Mean()) / mean_stddev + << " stddevs away, variance: sample " << m.variance << ", expect " + << Variance() << ", which is " + << std::abs(m.variance - Variance()) / variance_stddev + << " stddevs away."; } return pass; } @@ -396,18 +394,15 @@ bool BetaDistributionTest::SingleChiSquaredTest(double p, size_t samples, const bool pass = (absl::random_internal::ChiSquarePValue(chi_square, dof) >= p); if (!pass) { - for (int i = 0; i < cutoffs.size(); i++) { - ABSL_INTERNAL_LOG( - INFO, absl::StrFormat("cutoff[%d] = %f, actual count %d, expected %d", - i, cutoffs[i], counts[i], - static_cast(expected[i]))); + for (size_t i = 0; i < cutoffs.size(); i++) { + LOG(INFO) << "cutoff[" << i << "] = " << cutoffs[i] << ", actual count " + << counts[i] << ", expected " << static_cast(expected[i]); } - ABSL_INTERNAL_LOG( - INFO, absl::StrFormat( - "Beta(%f, %f) %s %f, p = %f", alpha_, beta_, - absl::random_internal::kChiSquared, chi_square, - absl::random_internal::ChiSquarePValue(chi_square, dof))); + LOG(INFO) << "Beta(" << alpha_ << ", " << beta_ << ") " + << absl::random_internal::kChiSquared << " " << chi_square + << ", p = " + << absl::random_internal::ChiSquarePValue(chi_square, dof); } return pass; } diff --git a/absl/random/discrete_distribution_test.cc b/absl/random/discrete_distribution_test.cc index e528a6a7493..32405ea9ed6 100644 --- a/absl/random/discrete_distribution_test.cc +++ b/absl/random/discrete_distribution_test.cc @@ -26,7 +26,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/base/internal/raw_logging.h" +#include "absl/log/log.h" #include "absl/random/internal/chi_square.h" #include "absl/random/internal/distribution_test_util.h" #include "absl/random/internal/pcg_engine.h" @@ -194,7 +194,7 @@ TEST(DiscreteDistributionTest, ChiSquaredTest50) { absl::StrAppend(&msg, kChiSquared, " p-value ", p_value, "\n"); absl::StrAppend(&msg, "High ", kChiSquared, " value: ", chi_square, " > ", kThreshold); - ABSL_RAW_LOG(INFO, "%s", msg.c_str()); + LOG(INFO) << msg; FAIL() << msg; } } diff --git a/absl/random/exponential_distribution_test.cc b/absl/random/exponential_distribution_test.cc index 3c44d9ec5b3..fb9a0d16182 100644 --- a/absl/random/exponential_distribution_test.cc +++ b/absl/random/exponential_distribution_test.cc @@ -29,8 +29,8 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/base/internal/raw_logging.h" #include "absl/base/macros.h" +#include "absl/log/log.h" #include "absl/numeric/internal/representation.h" #include "absl/random/internal/chi_square.h" #include "absl/random/internal/distribution_test_util.h" @@ -115,9 +115,8 @@ TYPED_TEST(ExponentialDistributionTypedTest, SerializeTest) { if (sample < sample_min) sample_min = sample; } if (!std::is_same::value) { - ABSL_INTERNAL_LOG(INFO, - absl::StrFormat("Range {%f}: %f, %f, lambda=%f", lambda, - sample_min, sample_max, lambda)); + LOG(INFO) << "Range {" << lambda << "}: " << sample_min << ", " + << sample_max << ", lambda=" << lambda; } std::stringstream ss; @@ -219,17 +218,16 @@ bool ExponentialDistributionTests::SingleZTest(const double p, const bool pass = absl::random_internal::Near("z", z, 0.0, max_err); if (!pass) { - ABSL_INTERNAL_LOG( - INFO, absl::StrFormat("p=%f max_err=%f\n" - " lambda=%f\n" - " mean=%f vs. %f\n" - " stddev=%f vs. %f\n" - " skewness=%f vs. %f\n" - " kurtosis=%f vs. %f\n" - " z=%f vs. 0", - p, max_err, lambda(), m.mean, mean(), - std::sqrt(m.variance), stddev(), m.skewness, - skew(), m.kurtosis, kurtosis(), z)); + // clang-format off + LOG(INFO) + << "p=" << p << " max_err=" << max_err << "\n" + " lambda=" << lambda() << "\n" + " mean=" << m.mean << " vs. " << mean() << "\n" + " stddev=" << std::sqrt(m.variance) << " vs. " << stddev() << "\n" + " skewness=" << m.skewness << " vs. " << skew() << "\n" + " kurtosis=" << m.kurtosis << " vs. " << kurtosis() << "\n" + " z=" << z << " vs. 0"; + // clang-format on } return pass; } @@ -274,16 +272,16 @@ double ExponentialDistributionTests::SingleChiSquaredTest() { double p = absl::random_internal::ChiSquarePValue(chi_square, dof); if (chi_square > threshold) { - for (int i = 0; i < cutoffs.size(); i++) { - ABSL_INTERNAL_LOG( - INFO, absl::StrFormat("%d : (%f) = %d", i, cutoffs[i], counts[i])); + for (size_t i = 0; i < cutoffs.size(); i++) { + LOG(INFO) << i << " : (" << cutoffs[i] << ") = " << counts[i]; } - ABSL_INTERNAL_LOG(INFO, - absl::StrCat("lambda ", lambda(), "\n", // - " expected ", expected, "\n", // - kChiSquared, " ", chi_square, " (", p, ")\n", - kChiSquared, " @ 0.98 = ", threshold)); + // clang-format off + LOG(INFO) << "lambda " << lambda() << "\n" + " expected " << expected << "\n" + << kChiSquared << " " << chi_square << " (" << p << ")\n" + << kChiSquared << " @ 0.98 = " << threshold; + // clang-format on } return p; } diff --git a/absl/random/gaussian_distribution_test.cc b/absl/random/gaussian_distribution_test.cc index 4584ac92055..bad3476f270 100644 --- a/absl/random/gaussian_distribution_test.cc +++ b/absl/random/gaussian_distribution_test.cc @@ -26,8 +26,8 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/base/internal/raw_logging.h" #include "absl/base/macros.h" +#include "absl/log/log.h" #include "absl/numeric/internal/representation.h" #include "absl/random/internal/chi_square.h" #include "absl/random/internal/distribution_test_util.h" @@ -116,9 +116,8 @@ TYPED_TEST(GaussianDistributionInterfaceTest, SerializeTest) { EXPECT_LE(sample, before.max()) << before; } if (!std::is_same::value) { - ABSL_INTERNAL_LOG( - INFO, absl::StrFormat("Range{%f, %f}: %f, %f", mean, stddev, - sample_min, sample_max)); + LOG(INFO) << "Range{" << mean << ", " << stddev << "}: " << sample_min + << ", " << sample_max; } std::stringstream ss; @@ -240,17 +239,16 @@ bool GaussianDistributionTests::SingleZTest(const double p, (std::pow(m.skewness, 2.0) + std::pow(m.kurtosis - 3.0, 2.0) / 4.0); if (!pass || jb > 9.21) { - ABSL_INTERNAL_LOG( - INFO, absl::StrFormat("p=%f max_err=%f\n" - " mean=%f vs. %f\n" - " stddev=%f vs. %f\n" - " skewness=%f vs. %f\n" - " kurtosis=%f vs. %f\n" - " z=%f vs. 0\n" - " jb=%f vs. 9.21", - p, max_err, m.mean, mean(), std::sqrt(m.variance), - stddev(), m.skewness, skew(), m.kurtosis, - kurtosis(), z, jb)); + // clang-format off + LOG(INFO) + << "p=" << p << " max_err=" << max_err << "\n" + " mean=" << m.mean << " vs. " << mean() << "\n" + " stddev=" << std::sqrt(m.variance) << " vs. " << stddev() << "\n" + " skewness=" << m.skewness << " vs. " << skew() << "\n" + " kurtosis=" << m.kurtosis << " vs. " << kurtosis() << "\n" + " z=" << z << " vs. 0\n" + " jb=" << jb << " vs. 9.21"; + // clang-format on } return pass; } @@ -297,16 +295,16 @@ double GaussianDistributionTests::SingleChiSquaredTest() { // Log if the chi_square value is above the threshold. if (chi_square > threshold) { - for (int i = 0; i < cutoffs.size(); i++) { - ABSL_INTERNAL_LOG( - INFO, absl::StrFormat("%d : (%f) = %d", i, cutoffs[i], counts[i])); + for (size_t i = 0; i < cutoffs.size(); i++) { + LOG(INFO) << i << " : (" << cutoffs[i] << ") = " << counts[i]; } - ABSL_INTERNAL_LOG( - INFO, absl::StrCat("mean=", mean(), " stddev=", stddev(), "\n", // - " expected ", expected, "\n", // - kChiSquared, " ", chi_square, " (", p, ")\n", // - kChiSquared, " @ 0.98 = ", threshold)); + // clang-format off + LOG(INFO) << "mean=" << mean() << " stddev=" << stddev() << "\n" + " expected " << expected << "\n" + << kChiSquared << " " << chi_square << " (" << p << ")\n" + << kChiSquared << " @ 0.98 = " << threshold; + // clang-format on } return p; } diff --git a/absl/random/internal/BUILD.bazel b/absl/random/internal/BUILD.bazel index a51c937556c..37f4d6e2bf7 100644 --- a/absl/random/internal/BUILD.bazel +++ b/absl/random/internal/BUILD.bazel @@ -601,7 +601,7 @@ cc_test( deps = [ ":explicit_seed_seq", ":randen_engine", - "//absl/base:raw_logging_internal", + "//absl/log", "//absl/strings", "//absl/time", "@com_google_googletest//:gtest_main", @@ -646,7 +646,7 @@ cc_test( ":platform", ":randen_hwaes", ":randen_hwaes_impl", # build_cleaner: keep - "//absl/base:raw_logging_internal", + "//absl/log", "//absl/strings:str_format", "@com_google_googletest//:gtest", ], @@ -707,8 +707,10 @@ cc_test( ], deps = [ ":nanobenchmark", - "//absl/base:raw_logging_internal", + "//absl/log", + "//absl/log:check", "//absl/strings", + "//absl/strings:str_format", ], ) diff --git a/absl/random/internal/nanobenchmark_test.cc b/absl/random/internal/nanobenchmark_test.cc index f1571e269ff..d4f1028dbd3 100644 --- a/absl/random/internal/nanobenchmark_test.cc +++ b/absl/random/internal/nanobenchmark_test.cc @@ -14,8 +14,10 @@ #include "absl/random/internal/nanobenchmark.h" -#include "absl/base/internal/raw_logging.h" +#include "absl/log/check.h" +#include "absl/log/log.h" #include "absl/strings/numbers.h" +#include "absl/strings/str_format.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -36,16 +38,16 @@ void MeasureDiv(const FuncInput (&inputs)[N]) { params.max_evals = 6; // avoid test timeout const size_t num_results = Measure(&Div, nullptr, inputs, N, results, params); if (num_results == 0) { - ABSL_RAW_LOG( - WARNING, - "WARNING: Measurement failed, should not happen when using " - "PinThreadToCPU unless the region to measure takes > 1 second.\n"); + LOG(WARNING) + << "WARNING: Measurement failed, should not happen when using " + "PinThreadToCPU unless the region to measure takes > 1 second."; return; } for (size_t i = 0; i < num_results; ++i) { - ABSL_RAW_LOG(INFO, "%5zu: %6.2f ticks; MAD=%4.2f%%\n", results[i].input, - results[i].ticks, results[i].variability * 100.0); - ABSL_RAW_CHECK(results[i].ticks != 0.0f, "Zero duration"); + LOG(INFO) << absl::StreamFormat("%5u: %6.2f ticks; MAD=%4.2f%%\n", + results[i].input, results[i].ticks, + results[i].variability * 100.0); + CHECK_NE(results[i].ticks, 0.0f) << "Zero duration"; } } @@ -54,7 +56,7 @@ void RunAll(const int argc, char* argv[]) { int cpu = -1; if (argc == 2) { if (!absl::SimpleAtoi(argv[1], &cpu)) { - ABSL_RAW_LOG(FATAL, "The optional argument must be a CPU number >= 0.\n"); + LOG(FATAL) << "The optional argument must be a CPU number >= 0."; } } PinThreadToCPU(cpu); diff --git a/absl/random/internal/randen_engine_test.cc b/absl/random/internal/randen_engine_test.cc index c8e7685bdda..a94f4916052 100644 --- a/absl/random/internal/randen_engine_test.cc +++ b/absl/random/internal/randen_engine_test.cc @@ -21,7 +21,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/base/internal/raw_logging.h" +#include "absl/log/log.h" #include "absl/random/internal/explicit_seed_seq.h" #include "absl/strings/str_cat.h" #include "absl/time/clock.h" @@ -645,9 +645,8 @@ TEST(RandenTest, IsFastOrSlow) { } auto duration = absl::GetCurrentTimeNanos() - start; - ABSL_INTERNAL_LOG(INFO, absl::StrCat(static_cast(duration) / - static_cast(kCount), - "ns")); + LOG(INFO) << static_cast(duration) / static_cast(kCount) + << "ns"; EXPECT_GT(sum, 0); EXPECT_GE(duration, kCount); // Should be slower than 1ns per call. diff --git a/absl/random/internal/randen_hwaes_test.cc b/absl/random/internal/randen_hwaes_test.cc index 2348b55c354..00d96efd3d5 100644 --- a/absl/random/internal/randen_hwaes_test.cc +++ b/absl/random/internal/randen_hwaes_test.cc @@ -16,7 +16,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/base/internal/raw_logging.h" +#include "absl/log/log.h" #include "absl/random/internal/platform.h" #include "absl/random/internal/randen_detect.h" #include "absl/random/internal/randen_traits.h" @@ -67,32 +67,32 @@ TEST(RandenHwAesTest, Default) { int main(int argc, char* argv[]) { testing::InitGoogleTest(&argc, argv); - ABSL_RAW_LOG(INFO, "ABSL_HAVE_ACCELERATED_AES=%d", ABSL_HAVE_ACCELERATED_AES); - ABSL_RAW_LOG(INFO, "ABSL_RANDOM_INTERNAL_AES_DISPATCH=%d", - ABSL_RANDOM_INTERNAL_AES_DISPATCH); + LOG(INFO) << "ABSL_HAVE_ACCELERATED_AES=" << ABSL_HAVE_ACCELERATED_AES; + LOG(INFO) << "ABSL_RANDOM_INTERNAL_AES_DISPATCH=" + << ABSL_RANDOM_INTERNAL_AES_DISPATCH; #if defined(ABSL_ARCH_X86_64) - ABSL_RAW_LOG(INFO, "ABSL_ARCH_X86_64"); + LOG(INFO) << "ABSL_ARCH_X86_64"; #elif defined(ABSL_ARCH_X86_32) - ABSL_RAW_LOG(INFO, "ABSL_ARCH_X86_32"); + LOG(INFO) << "ABSL_ARCH_X86_32"; #elif defined(ABSL_ARCH_AARCH64) - ABSL_RAW_LOG(INFO, "ABSL_ARCH_AARCH64"); + LOG(INFO) << "ABSL_ARCH_AARCH64"; #elif defined(ABSL_ARCH_ARM) - ABSL_RAW_LOG(INFO, "ABSL_ARCH_ARM"); + LOG(INFO) << "ABSL_ARCH_ARM"; #elif defined(ABSL_ARCH_PPC) - ABSL_RAW_LOG(INFO, "ABSL_ARCH_PPC"); + LOG(INFO) << "ABSL_ARCH_PPC"; #else - ABSL_RAW_LOG(INFO, "ARCH Unknown"); + LOG(INFO) << "ARCH Unknown"; #endif int x = absl::random_internal::HasRandenHwAesImplementation(); - ABSL_RAW_LOG(INFO, "HasRandenHwAesImplementation = %d", x); + LOG(INFO) << "HasRandenHwAesImplementation = " << x; int y = absl::random_internal::CPUSupportsRandenHwAes(); - ABSL_RAW_LOG(INFO, "CPUSupportsRandenHwAes = %d", x); + LOG(INFO) << "CPUSupportsRandenHwAes = " << x; if (!x || !y) { - ABSL_RAW_LOG(INFO, "Skipping Randen HWAES tests."); + LOG(INFO) << "Skipping Randen HWAES tests."; return 0; } return RUN_ALL_TESTS(); diff --git a/absl/random/log_uniform_int_distribution_test.cc b/absl/random/log_uniform_int_distribution_test.cc index 0d0fcb9597a..5df3edaca63 100644 --- a/absl/random/log_uniform_int_distribution_test.cc +++ b/absl/random/log_uniform_int_distribution_test.cc @@ -24,7 +24,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/base/internal/raw_logging.h" +#include "absl/log/log.h" #include "absl/random/internal/chi_square.h" #include "absl/random/internal/distribution_test_util.h" #include "absl/random/internal/pcg_engine.h" @@ -108,8 +108,7 @@ TYPED_TEST(LogUniformIntDistributionTypeTest, SerializeTest) { if (sample > sample_max) sample_max = sample; if (sample < sample_min) sample_min = sample; } - ABSL_INTERNAL_LOG(INFO, - absl::StrCat("Range: ", +sample_min, ", ", +sample_max)); + LOG(INFO) << "Range: " << sample_min << ", " << sample_max; } } @@ -182,16 +181,14 @@ double LogUniformIntChiSquaredTest::ChiSquaredTestImpl() { const double p = absl::random_internal::ChiSquarePValue(chi_square, dof); if (chi_square > threshold) { - ABSL_INTERNAL_LOG(INFO, "values"); + LOG(INFO) << "values"; for (size_t i = 0; i < buckets.size(); i++) { - ABSL_INTERNAL_LOG(INFO, absl::StrCat(i, ": ", buckets[i])); + LOG(INFO) << i << ": " << buckets[i]; } - ABSL_INTERNAL_LOG(INFO, - absl::StrFormat("trials=%d\n" - "%s(data, %d) = %f (%f)\n" - "%s @ 0.98 = %f", - trials, kChiSquared, dof, chi_square, p, - kChiSquared, threshold)); + LOG(INFO) << "trials=" << trials << "\n" + << kChiSquared << "(data, " << dof << ") = " << chi_square << " (" + << p << ")\n" + << kChiSquared << " @ 0.98 = " << threshold; } return p; } diff --git a/absl/random/poisson_distribution_test.cc b/absl/random/poisson_distribution_test.cc index 4f585b9b2b4..54755960e10 100644 --- a/absl/random/poisson_distribution_test.cc +++ b/absl/random/poisson_distribution_test.cc @@ -25,9 +25,9 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/base/internal/raw_logging.h" #include "absl/base/macros.h" #include "absl/container/flat_hash_map.h" +#include "absl/log/log.h" #include "absl/random/internal/chi_square.h" #include "absl/random/internal/distribution_test_util.h" #include "absl/random/internal/pcg_engine.h" @@ -134,8 +134,8 @@ TYPED_TEST(PoissonDistributionInterfaceTest, SerializeTest) { if (sample < sample_min) sample_min = sample; } - ABSL_INTERNAL_LOG(INFO, absl::StrCat("Range {", param.mean(), "}: ", - +sample_min, ", ", +sample_max)); + LOG(INFO) << "Range {" << param.mean() << "}: " << sample_min << ", " + << sample_max; // Validate stream serialization. std::stringstream ss; @@ -188,10 +188,9 @@ class PoissonModel { } void LogCDF() { - ABSL_INTERNAL_LOG(INFO, absl::StrCat("CDF (mean = ", mean_, ")")); + LOG(INFO) << "CDF (mean = " << mean_ << ")"; for (const auto c : cdf_) { - ABSL_INTERNAL_LOG(INFO, - absl::StrCat(c.index, ": pmf=", c.pmf, " cdf=", c.cdf)); + LOG(INFO) << c.index << ": pmf=" << c.pmf << " cdf=" << c.cdf; } } @@ -286,16 +285,15 @@ bool PoissonDistributionZTest::SingleZTest(const double p, const bool pass = absl::random_internal::Near("z", z, 0.0, max_err); if (!pass) { - ABSL_INTERNAL_LOG( - INFO, absl::StrFormat("p=%f max_err=%f\n" - " mean=%f vs. %f\n" - " stddev=%f vs. %f\n" - " skewness=%f vs. %f\n" - " kurtosis=%f vs. %f\n" - " z=%f", - p, max_err, m.mean, mean(), std::sqrt(m.variance), - stddev(), m.skewness, skew(), m.kurtosis, - kurtosis(), z)); + // clang-format off + LOG(INFO) + << "p=" << p << " max_err=" << max_err << "\n" + " mean=" << m.mean << " vs. " << mean() << "\n" + " stddev=" << std::sqrt(m.variance) << " vs. " << stddev() << "\n" + " skewness=" << m.skewness << " vs. " << skew() << "\n" + " kurtosis=" << m.kurtosis << " vs. " << kurtosis() << "\n" + " z=" << z; + // clang-format on } return pass; } @@ -439,17 +437,16 @@ double PoissonDistributionChiSquaredTest::ChiSquaredTestImpl() { if (chi_square > threshold) { LogCDF(); - ABSL_INTERNAL_LOG(INFO, absl::StrCat("VALUES buckets=", counts.size(), - " samples=", kSamples)); + LOG(INFO) << "VALUES buckets=" << counts.size() + << " samples=" << kSamples; for (size_t i = 0; i < counts.size(); i++) { - ABSL_INTERNAL_LOG( - INFO, absl::StrCat(cutoffs_[i], ": ", counts[i], " vs. E=", e[i])); + LOG(INFO) << cutoffs_[i] << ": " << counts[i] << " vs. E=" << e[i]; } - ABSL_INTERNAL_LOG( - INFO, - absl::StrCat(kChiSquared, "(data, dof=", dof, ") = ", chi_square, " (", - p, ")\n", " vs.\n", kChiSquared, " @ 0.98 = ", threshold)); + LOG(INFO) << kChiSquared << "(data, dof=" << dof << ") = " << chi_square + << " (" << p << ")\n" + << " vs.\n" + << kChiSquared << " @ 0.98 = " << threshold; } return p; } diff --git a/absl/random/uniform_int_distribution_test.cc b/absl/random/uniform_int_distribution_test.cc index a830117aeb1..b40d6185185 100644 --- a/absl/random/uniform_int_distribution_test.cc +++ b/absl/random/uniform_int_distribution_test.cc @@ -24,7 +24,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/base/internal/raw_logging.h" +#include "absl/log/log.h" #include "absl/random/internal/chi_square.h" #include "absl/random/internal/distribution_test_util.h" #include "absl/random/internal/pcg_engine.h" @@ -107,8 +107,7 @@ TYPED_TEST(UniformIntDistributionTest, ParamSerializeTest) { sample_min = sample; } } - std::string msg = absl::StrCat("Range: ", +sample_min, ", ", +sample_max); - ABSL_RAW_LOG(INFO, "%s", msg.c_str()); + LOG(INFO) << "Range: " << sample_min << ", " << sample_max; } } @@ -210,7 +209,7 @@ TYPED_TEST(UniformIntDistributionTest, ChiSquaredTest50) { absl::StrAppend(&msg, kChiSquared, " p-value ", p_value, "\n"); absl::StrAppend(&msg, "High ", kChiSquared, " value: ", chi_square, " > ", kThreshold); - ABSL_RAW_LOG(INFO, "%s", msg.c_str()); + LOG(INFO) << msg; FAIL() << msg; } } diff --git a/absl/random/uniform_real_distribution_test.cc b/absl/random/uniform_real_distribution_test.cc index 07f199d34cd..260aac96f7e 100644 --- a/absl/random/uniform_real_distribution_test.cc +++ b/absl/random/uniform_real_distribution_test.cc @@ -26,7 +26,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/base/internal/raw_logging.h" +#include "absl/log/log.h" #include "absl/numeric/internal/representation.h" #include "absl/random/internal/chi_square.h" #include "absl/random/internal/distribution_test_util.h" @@ -182,9 +182,8 @@ TYPED_TEST(UniformRealDistributionTest, ParamSerializeTest) { if (!std::is_same::value) { // static_cast(long double) can overflow. - std::string msg = absl::StrCat("Range: ", static_cast(sample_min), - ", ", static_cast(sample_max)); - ABSL_RAW_LOG(INFO, "%s", msg.c_str()); + LOG(INFO) << "Range: " << static_cast(sample_min) << ", " + << static_cast(sample_max); } } } @@ -324,7 +323,7 @@ TYPED_TEST(UniformRealDistributionTest, ChiSquaredTest50) { absl::StrAppend(&msg, kChiSquared, " p-value ", p_value, "\n"); absl::StrAppend(&msg, "High ", kChiSquared, " value: ", chi_square, " > ", kThreshold); - ABSL_RAW_LOG(INFO, "%s", msg.c_str()); + LOG(INFO) << msg; FAIL() << msg; } } diff --git a/absl/random/zipf_distribution_test.cc b/absl/random/zipf_distribution_test.cc index c8bb89db2e6..801ec4f6226 100644 --- a/absl/random/zipf_distribution_test.cc +++ b/absl/random/zipf_distribution_test.cc @@ -25,7 +25,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/base/internal/raw_logging.h" +#include "absl/log/log.h" #include "absl/random/internal/chi_square.h" #include "absl/random/internal/pcg_engine.h" #include "absl/random/internal/sequence_urbg.h" @@ -102,8 +102,7 @@ TYPED_TEST(ZipfDistributionTypedTest, SerializeTest) { if (sample > sample_max) sample_max = sample; if (sample < sample_min) sample_min = sample; } - ABSL_INTERNAL_LOG(INFO, - absl::StrCat("Range: ", +sample_min, ", ", +sample_max)); + LOG(INFO) << "Range: " << sample_min << ", " << sample_max; } } @@ -303,18 +302,15 @@ TEST_P(ZipfTest, ChiSquaredTest) { // Log if the chi_squared value is above the threshold. if (chi_square > threshold) { - ABSL_INTERNAL_LOG(INFO, "values"); + LOG(INFO) << "values"; for (size_t i = 0; i < expected.size(); i++) { - ABSL_INTERNAL_LOG(INFO, absl::StrCat(points[i], ": ", buckets[i], - " vs. E=", expected[i])); + LOG(INFO) << points[i] << ": " << buckets[i] << " vs. E=" << expected[i]; } - ABSL_INTERNAL_LOG(INFO, absl::StrCat("trials ", trials)); - ABSL_INTERNAL_LOG(INFO, - absl::StrCat("mean ", avg, " vs. expected ", mean())); - ABSL_INTERNAL_LOG(INFO, absl::StrCat(kChiSquared, "(data, ", dof, ") = ", - chi_square, " (", p_actual, ")")); - ABSL_INTERNAL_LOG(INFO, - absl::StrCat(kChiSquared, " @ 0.9995 = ", threshold)); + LOG(INFO) << "trials " << trials; + LOG(INFO) << "mean " << avg << " vs. expected " << mean(); + LOG(INFO) << kChiSquared << "(data, " << dof << ") = " << chi_square << " (" + << p_actual << ")"; + LOG(INFO) << kChiSquared << " @ 0.9995 = " << threshold; FAIL() << kChiSquared << " value of " << chi_square << " is above the threshold."; } diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index e48a9a0a495..bd33c533b2d 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -774,10 +774,10 @@ cc_test( "//absl/base:config", "//absl/base:core_headers", "//absl/base:endian", - "//absl/base:raw_logging_internal", "//absl/container:fixed_array", "//absl/hash", "//absl/log", + "//absl/log:check", "//absl/random", "@com_google_googletest//:gtest_main", ], @@ -1019,7 +1019,7 @@ cc_test( ":pow10_helper", ":strings", "//absl/base:config", - "//absl/base:raw_logging_internal", + "//absl/log", "//absl/random", "//absl/random:distributions", "@com_google_googletest//:gtest_main", @@ -1096,7 +1096,7 @@ cc_test( deps = [ ":strings", "//absl/base:config", - "//absl/base:raw_logging_internal", + "//absl/log:check", "@com_google_googletest//:gtest_main", ], ) @@ -1253,6 +1253,7 @@ cc_test( ":strings", "//absl/base:core_headers", "//absl/base:raw_logging_internal", + "//absl/log", "//absl/types:optional", "@com_google_googletest//:gtest_main", ], diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index d2928bd7eb7..9aaa7932b2b 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt @@ -317,7 +317,7 @@ absl_cc_test( absl::core_headers absl::pow10_helper absl::config - absl::raw_logging_internal + absl::log absl::random_random absl::random_distributions absl::strings_internal @@ -372,9 +372,9 @@ absl_cc_test( COPTS ${ABSL_TEST_COPTS} DEPS - absl::strings + absl::check absl::config - absl::raw_logging_internal + absl::strings GTest::gmock_main ) @@ -516,6 +516,7 @@ absl_cc_test( absl::strings absl::str_format_internal absl::core_headers + absl::log absl::raw_logging_internal absl::int128 GTest::gmock_main @@ -960,19 +961,20 @@ absl_cc_test( COPTS ${ABSL_TEST_COPTS} DEPS - absl::cord - absl::str_format - absl::strings absl::base + absl::check absl::config + absl::cord absl::cord_test_helpers absl::cordz_test_helpers absl::core_headers absl::endian + absl::fixed_array absl::hash + absl::log absl::random_random - absl::raw_logging_internal - absl::fixed_array + absl::str_format + absl::strings GTest::gmock_main ) diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc index 3fe3967fa39..55412c7f3e2 100644 --- a/absl/strings/cord_test.cc +++ b/absl/strings/cord_test.cc @@ -30,10 +30,11 @@ #include "gtest/gtest.h" #include "absl/base/config.h" #include "absl/base/internal/endian.h" -#include "absl/base/internal/raw_logging.h" #include "absl/base/macros.h" #include "absl/container/fixed_array.h" #include "absl/hash/hash.h" +#include "absl/log/check.h" +#include "absl/log/log.h" #include "absl/random/random.h" #include "absl/strings/cord_test_helpers.h" #include "absl/strings/cordz_test_helpers.h" @@ -210,9 +211,8 @@ class CordTestPeer { } static Cord MakeSubstring(Cord src, size_t offset, size_t length) { - ABSL_RAW_CHECK(src.contents_.is_tree(), "Can not be inlined"); - ABSL_RAW_CHECK(src.ExpectedChecksum() == absl::nullopt, - "Can not be hardened"); + CHECK(src.contents_.is_tree()) << "Can not be inlined"; + CHECK(!src.ExpectedChecksum().has_value()) << "Can not be hardened"; Cord cord; auto* tree = cord_internal::SkipCrcNode(src.contents_.tree()); auto* rep = CordRepSubstring::Create(CordRep::Ref(tree), offset, length); @@ -374,7 +374,7 @@ TEST_P(CordTest, GigabyteCordFromExternal) { for (int i = 0; i < 1024; ++i) { c.Append(from); } - ABSL_RAW_LOG(INFO, "Made a Cord with %zu bytes!", c.size()); + LOG(INFO) << "Made a Cord with " << c.size() << " bytes!"; // Note: on a 32-bit build, this comes out to 2,818,048,000 bytes. // Note: on a 64-bit build, this comes out to 171,932,385,280 bytes. } @@ -1247,15 +1247,15 @@ absl::Cord BigCord(size_t len, char v) { // Splice block into cord. absl::Cord SpliceCord(const absl::Cord& blob, int64_t offset, const absl::Cord& block) { - ABSL_RAW_CHECK(offset >= 0, ""); - ABSL_RAW_CHECK(offset + block.size() <= blob.size(), ""); + CHECK_GE(offset, 0); + CHECK_LE(static_cast(offset) + block.size(), blob.size()); absl::Cord result(blob); result.RemoveSuffix(blob.size() - offset); result.Append(block); absl::Cord suffix(blob); suffix.RemovePrefix(offset + block.size()); result.Append(suffix); - ABSL_RAW_CHECK(blob.size() == result.size(), ""); + CHECK_EQ(blob.size(), result.size()); return result; } @@ -1855,7 +1855,7 @@ TEST(CordTest, CordMemoryUsageBTree) { // windows DLL, we may have ODR like effects on the flag, meaning the DLL // code will run with the picked up default. if (!absl::CordTestPeer::Tree(cord1)->IsBtree()) { - ABSL_RAW_LOG(WARNING, "Cord library code not respecting btree flag"); + LOG(WARNING) << "Cord library code not respecting btree flag"; return; } @@ -1940,8 +1940,7 @@ TEST_P(CordTest, DiabolicalGrowth) { std::string value; absl::CopyCordToString(cord, &value); EXPECT_EQ(value, expected); - ABSL_RAW_LOG(INFO, "Diabolical size allocated = %zu", - cord.EstimatedMemoryUsage()); + LOG(INFO) << "Diabolical size allocated = " << cord.EstimatedMemoryUsage(); } // The following tests check support for >4GB cords in 64-bit binaries, and diff --git a/absl/strings/internal/charconv_parse_test.cc b/absl/strings/internal/charconv_parse_test.cc index bc2d1118765..2b7b082114b 100644 --- a/absl/strings/internal/charconv_parse_test.cc +++ b/absl/strings/internal/charconv_parse_test.cc @@ -19,7 +19,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/base/internal/raw_logging.h" +#include "absl/log/check.h" #include "absl/strings/str_cat.h" using absl::chars_format; @@ -56,14 +56,14 @@ void ExpectParsedFloat(std::string s, absl::chars_format format_flags, begin_subrange = static_cast(open_bracket_pos); s.replace(open_bracket_pos, 1, ""); std::string::size_type close_bracket_pos = s.find(']'); - ABSL_RAW_CHECK(close_bracket_pos != absl::string_view::npos, - "Test input contains [ without matching ]"); + CHECK_NE(close_bracket_pos, absl::string_view::npos) + << "Test input contains [ without matching ]"; end_subrange = static_cast(close_bracket_pos); s.replace(close_bracket_pos, 1, ""); } const std::string::size_type expected_characters_matched = s.find('$'); - ABSL_RAW_CHECK(expected_characters_matched != std::string::npos, - "Input string must contain $"); + CHECK_NE(expected_characters_matched, std::string::npos) + << "Input string must contain $"; s.replace(expected_characters_matched, 1, ""); ParsedFloat parsed = diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc index 8b5a27ed123..16ff9879e98 100644 --- a/absl/strings/internal/str_format/convert_test.cc +++ b/absl/strings/internal/str_format/convert_test.cc @@ -26,6 +26,7 @@ #include "gtest/gtest.h" #include "absl/base/attributes.h" #include "absl/base/internal/raw_logging.h" +#include "absl/log/log.h" #include "absl/strings/internal/str_format/bind.h" #include "absl/strings/match.h" #include "absl/types/optional.h" @@ -264,7 +265,7 @@ MATCHER_P(MatchesPointerString, ptr, "") { } void* parsed = nullptr; if (sscanf(arg.c_str(), "%p", &parsed) != 1) { - ABSL_RAW_LOG(FATAL, "Could not parse %s", arg.c_str()); + LOG(FATAL) << "Could not parse " << arg; } return ptr == parsed; } diff --git a/absl/strings/numbers_test.cc b/absl/strings/numbers_test.cc index b3c098d1a82..2864bda2e42 100644 --- a/absl/strings/numbers_test.cc +++ b/absl/strings/numbers_test.cc @@ -37,7 +37,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/base/internal/raw_logging.h" +#include "absl/log/log.h" #include "absl/random/distributions.h" #include "absl/random/random.h" #include "absl/strings/internal/numbers_test_common.h" @@ -1337,11 +1337,9 @@ TEST_F(SimpleDtoaTest, ExhaustiveDoubleToSixDigits) { if (strcmp(sixdigitsbuf, snprintfbuf) != 0) { mismatches.push_back(d); if (mismatches.size() < 10) { - ABSL_RAW_LOG(ERROR, "%s", - absl::StrCat("Six-digit failure with double. ", "d=", d, - "=", d, " sixdigits=", sixdigitsbuf, - " printf(%g)=", snprintfbuf) - .c_str()); + LOG(ERROR) << "Six-digit failure with double. d=" << d + << " sixdigits=" << sixdigitsbuf + << " printf(%g)=" << snprintfbuf; } } }; @@ -1389,12 +1387,10 @@ TEST_F(SimpleDtoaTest, ExhaustiveDoubleToSixDigits) { if (kFloatNumCases >= 1e9) { // The exhaustive test takes a very long time, so log progress. char buf[kSixDigitsToBufferSize]; - ABSL_RAW_LOG( - INFO, "%s", - absl::StrCat("Exp ", exponent, " powten=", powten, "(", powten, - ") (", - std::string(buf, SixDigitsToBuffer(powten, buf)), ")") - .c_str()); + LOG(INFO) << "Exp " << exponent << " powten=" << powten << "(" << powten + << ") (" + << absl::string_view(buf, SixDigitsToBuffer(powten, buf)) + << ")"; } for (int digits : digit_testcases) { if (exponent == 308 && digits >= 179769) break; // don't overflow! @@ -1419,20 +1415,17 @@ TEST_F(SimpleDtoaTest, ExhaustiveDoubleToSixDigits) { double before = nextafter(d, 0.0); double after = nextafter(d, 1.7976931348623157e308); char b1[32], b2[kSixDigitsToBufferSize]; - ABSL_RAW_LOG( - ERROR, "%s", - absl::StrCat( - "Mismatch #", i, " d=", d, " (", ToNineDigits(d), ")", - " sixdigits='", sixdigitsbuf, "'", " snprintf='", snprintfbuf, - "'", " Before.=", PerfectDtoa(before), " ", - (SixDigitsToBuffer(before, b2), b2), - " vs snprintf=", (snprintf(b1, sizeof(b1), "%g", before), b1), - " Perfect=", PerfectDtoa(d), " ", (SixDigitsToBuffer(d, b2), b2), - " vs snprintf=", (snprintf(b1, sizeof(b1), "%g", d), b1), - " After.=.", PerfectDtoa(after), " ", - (SixDigitsToBuffer(after, b2), b2), - " vs snprintf=", (snprintf(b1, sizeof(b1), "%g", after), b1)) - .c_str()); + LOG(ERROR) << "Mismatch #" << i << " d=" << d << " (" << ToNineDigits(d) + << ") sixdigits='" << sixdigitsbuf << "' snprintf='" + << snprintfbuf << "' Before.=" << PerfectDtoa(before) << " " + << (SixDigitsToBuffer(before, b2), b2) << " vs snprintf=" + << (snprintf(b1, sizeof(b1), "%g", before), b1) + << " Perfect=" << PerfectDtoa(d) << " " + << (SixDigitsToBuffer(d, b2), b2) + << " vs snprintf=" << (snprintf(b1, sizeof(b1), "%g", d), b1) + << " After.=." << PerfectDtoa(after) << " " + << (SixDigitsToBuffer(after, b2), b2) << " vs snprintf=" + << (snprintf(b1, sizeof(b1), "%g", after), b1); } } } diff --git a/absl/synchronization/BUILD.bazel b/absl/synchronization/BUILD.bazel index 5074044e853..3d405df83b6 100644 --- a/absl/synchronization/BUILD.bazel +++ b/absl/synchronization/BUILD.bazel @@ -198,7 +198,8 @@ cc_test( deps = [ ":graphcycles_internal", "//absl/base:core_headers", - "//absl/base:raw_logging_internal", + "//absl/log", + "//absl/log:check", "@com_google_googletest//:gtest_main", ], ) @@ -247,7 +248,8 @@ cc_test( "//absl/base", "//absl/base:config", "//absl/base:core_headers", - "//absl/base:raw_logging_internal", + "//absl/log", + "//absl/log:check", "//absl/memory", "//absl/time", "@com_google_googletest//:gtest_main", @@ -376,6 +378,6 @@ cc_test( deps = [ ":synchronization", "//absl/base:core_headers", - "//absl/base:raw_logging_internal", + "//absl/log:check", ], ) diff --git a/absl/synchronization/CMakeLists.txt b/absl/synchronization/CMakeLists.txt index 862783496e6..a0f64e5ceaa 100644 --- a/absl/synchronization/CMakeLists.txt +++ b/absl/synchronization/CMakeLists.txt @@ -151,9 +151,10 @@ absl_cc_test( COPTS ${ABSL_TEST_COPTS} DEPS - absl::graphcycles_internal + absl::check absl::core_headers - absl::raw_logging_internal + absl::graphcycles_internal + absl::log GTest::gmock_main ) @@ -183,10 +184,11 @@ absl_cc_test( absl::synchronization absl::thread_pool absl::base + absl::check absl::config absl::core_headers + absl::log absl::memory - absl::raw_logging_internal absl::time GTest::gmock_main ) @@ -278,5 +280,5 @@ absl_cc_test( DEPS absl::synchronization absl::core_headers - absl::raw_logging_internal + absl::check ) diff --git a/absl/synchronization/internal/graphcycles_test.cc b/absl/synchronization/internal/graphcycles_test.cc index 74eaffe7a80..3c6ef7985c1 100644 --- a/absl/synchronization/internal/graphcycles_test.cc +++ b/absl/synchronization/internal/graphcycles_test.cc @@ -21,8 +21,9 @@ #include #include "gtest/gtest.h" -#include "absl/base/internal/raw_logging.h" #include "absl/base/macros.h" +#include "absl/log/check.h" +#include "absl/log/log.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -65,51 +66,51 @@ static bool IsReachable(Edges *edges, int from, int to, } static void PrintEdges(Edges *edges) { - ABSL_RAW_LOG(INFO, "EDGES (%zu)", edges->size()); + LOG(INFO) << "EDGES (" << edges->size() << ")"; for (const auto &edge : *edges) { int a = edge.from; int b = edge.to; - ABSL_RAW_LOG(INFO, "%d %d", a, b); + LOG(INFO) << a << " " << b; } - ABSL_RAW_LOG(INFO, "---"); + LOG(INFO) << "---"; } static void PrintGCEdges(Nodes *nodes, const IdMap &id, GraphCycles *gc) { - ABSL_RAW_LOG(INFO, "GC EDGES"); + LOG(INFO) << "GC EDGES"; for (int a : *nodes) { for (int b : *nodes) { if (gc->HasEdge(Get(id, a), Get(id, b))) { - ABSL_RAW_LOG(INFO, "%d %d", a, b); + LOG(INFO) << a << " " << b; } } } - ABSL_RAW_LOG(INFO, "---"); + LOG(INFO) << "---"; } static void PrintTransitiveClosure(Nodes *nodes, Edges *edges) { - ABSL_RAW_LOG(INFO, "Transitive closure"); + LOG(INFO) << "Transitive closure"; for (int a : *nodes) { for (int b : *nodes) { std::unordered_set seen; if (IsReachable(edges, a, b, &seen)) { - ABSL_RAW_LOG(INFO, "%d %d", a, b); + LOG(INFO) << a << " " << b; } } } - ABSL_RAW_LOG(INFO, "---"); + LOG(INFO) << "---"; } static void PrintGCTransitiveClosure(Nodes *nodes, const IdMap &id, GraphCycles *gc) { - ABSL_RAW_LOG(INFO, "GC Transitive closure"); + LOG(INFO) << "GC Transitive closure"; for (int a : *nodes) { for (int b : *nodes) { if (gc->IsReachable(Get(id, a), Get(id, b))) { - ABSL_RAW_LOG(INFO, "%d %d", a, b); + LOG(INFO) << a << " " << b; } } } - ABSL_RAW_LOG(INFO, "---"); + LOG(INFO) << "---"; } static void CheckTransitiveClosure(Nodes *nodes, Edges *edges, const IdMap &id, @@ -125,9 +126,8 @@ static void CheckTransitiveClosure(Nodes *nodes, Edges *edges, const IdMap &id, PrintGCEdges(nodes, id, gc); PrintTransitiveClosure(nodes, edges); PrintGCTransitiveClosure(nodes, id, gc); - ABSL_RAW_LOG(FATAL, "gc_reachable %s reachable %s a %d b %d", - gc_reachable ? "true" : "false", - reachable ? "true" : "false", a, b); + LOG(FATAL) << "gc_reachable " << gc_reachable << " reachable " + << reachable << " a " << a << " b " << b; } } } @@ -142,7 +142,7 @@ static void CheckEdges(Nodes *nodes, Edges *edges, const IdMap &id, if (!gc->HasEdge(Get(id, a), Get(id, b))) { PrintEdges(edges); PrintGCEdges(nodes, id, gc); - ABSL_RAW_LOG(FATAL, "!gc->HasEdge(%d, %d)", a, b); + LOG(FATAL) << "!gc->HasEdge(" << a << ", " << b << ")"; } } for (const auto &a : *nodes) { @@ -155,13 +155,12 @@ static void CheckEdges(Nodes *nodes, Edges *edges, const IdMap &id, if (count != edges->size()) { PrintEdges(edges); PrintGCEdges(nodes, id, gc); - ABSL_RAW_LOG(FATAL, "edges->size() %zu count %d", edges->size(), count); + LOG(FATAL) << "edges->size() " << edges->size() << " count " << count; } } static void CheckInvariants(const GraphCycles &gc) { - if (ABSL_PREDICT_FALSE(!gc.CheckInvariants())) - ABSL_RAW_LOG(FATAL, "CheckInvariants"); + CHECK(gc.CheckInvariants()) << "CheckInvariants"; } // Returns the index of a randomly chosen node in *nodes. @@ -309,7 +308,7 @@ TEST(GraphCycles, RandomizedTest) { break; default: - ABSL_RAW_LOG(FATAL, "op %d", op); + LOG(FATAL) << "op " << op; } // Very rarely, test graph expansion by adding then removing many nodes. diff --git a/absl/synchronization/lifetime_test.cc b/absl/synchronization/lifetime_test.cc index e6274232f18..d5ce35a175f 100644 --- a/absl/synchronization/lifetime_test.cc +++ b/absl/synchronization/lifetime_test.cc @@ -18,8 +18,8 @@ #include "absl/base/attributes.h" #include "absl/base/const_init.h" -#include "absl/base/internal/raw_logging.h" #include "absl/base/thread_annotations.h" +#include "absl/log/check.h" #include "absl/synchronization/mutex.h" #include "absl/synchronization/notification.h" @@ -35,20 +35,20 @@ namespace { // Thread two waits on 'notification', then sets 'state' inside the 'mutex', // signalling the change via 'condvar'. // -// These tests use ABSL_RAW_CHECK to validate invariants, rather than EXPECT or -// ASSERT from gUnit, because we need to invoke them during global destructors, -// when gUnit teardown would have already begun. +// These tests use CHECK to validate invariants, rather than EXPECT or ASSERT +// from gUnit, because we need to invoke them during global destructors, when +// gUnit teardown would have already begun. void ThreadOne(absl::Mutex* mutex, absl::CondVar* condvar, absl::Notification* notification, bool* state) { // Test that the notification is in a valid initial state. - ABSL_RAW_CHECK(!notification->HasBeenNotified(), "invalid Notification"); - ABSL_RAW_CHECK(*state == false, "*state not initialized"); + CHECK(!notification->HasBeenNotified()) << "invalid Notification"; + CHECK(!*state) << "*state not initialized"; { absl::MutexLock lock(mutex); notification->Notify(); - ABSL_RAW_CHECK(notification->HasBeenNotified(), "invalid Notification"); + CHECK(notification->HasBeenNotified()) << "invalid Notification"; while (*state == false) { condvar->Wait(mutex); @@ -58,11 +58,11 @@ void ThreadOne(absl::Mutex* mutex, absl::CondVar* condvar, void ThreadTwo(absl::Mutex* mutex, absl::CondVar* condvar, absl::Notification* notification, bool* state) { - ABSL_RAW_CHECK(*state == false, "*state not initialized"); + CHECK(!*state) << "*state not initialized"; // Wake thread one notification->WaitForNotification(); - ABSL_RAW_CHECK(notification->HasBeenNotified(), "invalid Notification"); + CHECK(notification->HasBeenNotified()) << "invalid Notification"; { absl::MutexLock lock(mutex); *state = true; diff --git a/absl/synchronization/mutex_test.cc b/absl/synchronization/mutex_test.cc index ec039a70c5b..4ae4d7e7fc4 100644 --- a/absl/synchronization/mutex_test.cc +++ b/absl/synchronization/mutex_test.cc @@ -32,8 +32,9 @@ #include "gtest/gtest.h" #include "absl/base/attributes.h" #include "absl/base/config.h" -#include "absl/base/internal/raw_logging.h" #include "absl/base/internal/sysinfo.h" +#include "absl/log/check.h" +#include "absl/log/log.h" #include "absl/memory/memory.h" #include "absl/synchronization/internal/thread_pool.h" #include "absl/time/clock.h" @@ -87,7 +88,7 @@ static void SetInvariantChecked(bool new_value) { static void CheckSumG0G1(void *v) { TestContext *cxt = static_cast(v); - ABSL_RAW_CHECK(cxt->g0 == -cxt->g1, "Error in CheckSumG0G1"); + CHECK_EQ(cxt->g0, -cxt->g1) << "Error in CheckSumG0G1"; SetInvariantChecked(true); } @@ -132,7 +133,7 @@ static void TestRW(TestContext *cxt, int c) { } else { for (int i = 0; i != cxt->iterations; i++) { absl::ReaderMutexLock l(&cxt->mu); - ABSL_RAW_CHECK(cxt->g0 == -cxt->g1, "Error in TestRW"); + CHECK_EQ(cxt->g0, -cxt->g1) << "Error in TestRW"; cxt->mu.AssertReaderHeld(); } } @@ -157,7 +158,7 @@ static void TestAwait(TestContext *cxt, int c) { cxt->mu.AssertHeld(); while (cxt->g0 < cxt->iterations) { cxt->mu.Await(absl::Condition(&mc, &MyContext::MyTurn)); - ABSL_RAW_CHECK(mc.MyTurn(), "Error in TestAwait"); + CHECK(mc.MyTurn()) << "Error in TestAwait"; cxt->mu.AssertHeld(); if (cxt->g0 < cxt->iterations) { int a = cxt->g0 + 1; @@ -185,7 +186,7 @@ static void TestSignalAll(TestContext *cxt, int c) { } static void TestSignal(TestContext *cxt, int c) { - ABSL_RAW_CHECK(cxt->threads == 2, "TestSignal should use 2 threads"); + CHECK_EQ(cxt->threads, 2) << "TestSignal should use 2 threads"; int target = c; absl::MutexLock l(&cxt->mu); cxt->mu.AssertHeld(); @@ -222,8 +223,8 @@ static void TestCVTimeout(TestContext *cxt, int c) { static bool G0GE2(TestContext *cxt) { return cxt->g0 >= 2; } static void TestTime(TestContext *cxt, int c, bool use_cv) { - ABSL_RAW_CHECK(cxt->iterations == 1, "TestTime should only use 1 iteration"); - ABSL_RAW_CHECK(cxt->threads > 2, "TestTime should use more than 2 threads"); + CHECK_EQ(cxt->iterations, 1) << "TestTime should only use 1 iteration"; + CHECK_GT(cxt->threads, 2) << "TestTime should use more than 2 threads"; const bool kFalse = false; absl::Condition false_cond(&kFalse); absl::Condition g0ge2(G0GE2, cxt); @@ -234,26 +235,24 @@ static void TestTime(TestContext *cxt, int c, bool use_cv) { if (use_cv) { cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1)); } else { - ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)), - "TestTime failed"); + CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1))) + << "TestTime failed"; } absl::Duration elapsed = absl::Now() - start; - ABSL_RAW_CHECK( - absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0), - "TestTime failed"); - ABSL_RAW_CHECK(cxt->g0 == 1, "TestTime failed"); + CHECK(absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0)) + << "TestTime failed"; + CHECK_EQ(cxt->g0, 1) << "TestTime failed"; start = absl::Now(); if (use_cv) { cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1)); } else { - ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)), - "TestTime failed"); + CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1))) + << "TestTime failed"; } elapsed = absl::Now() - start; - ABSL_RAW_CHECK( - absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0), - "TestTime failed"); + CHECK(absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0)) + << "TestTime failed"; cxt->g0++; if (use_cv) { cxt->cv.Signal(); @@ -263,26 +262,24 @@ static void TestTime(TestContext *cxt, int c, bool use_cv) { if (use_cv) { cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(4)); } else { - ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(4)), - "TestTime failed"); + CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(4))) + << "TestTime failed"; } elapsed = absl::Now() - start; - ABSL_RAW_CHECK( - absl::Seconds(3.9) <= elapsed && elapsed <= absl::Seconds(6.0), - "TestTime failed"); - ABSL_RAW_CHECK(cxt->g0 >= 3, "TestTime failed"); + CHECK(absl::Seconds(3.9) <= elapsed && elapsed <= absl::Seconds(6.0)) + << "TestTime failed"; + CHECK_GE(cxt->g0, 3) << "TestTime failed"; start = absl::Now(); if (use_cv) { cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1)); } else { - ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)), - "TestTime failed"); + CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1))) + << "TestTime failed"; } elapsed = absl::Now() - start; - ABSL_RAW_CHECK( - absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0), - "TestTime failed"); + CHECK(absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0)) + << "TestTime failed"; if (use_cv) { cxt->cv.SignalAll(); } @@ -291,14 +288,13 @@ static void TestTime(TestContext *cxt, int c, bool use_cv) { if (use_cv) { cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1)); } else { - ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)), - "TestTime failed"); + CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1))) + << "TestTime failed"; } elapsed = absl::Now() - start; - ABSL_RAW_CHECK( - absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0), - "TestTime failed"); - ABSL_RAW_CHECK(cxt->g0 == cxt->threads, "TestTime failed"); + CHECK(absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0)) + << "TestTime failed"; + CHECK_EQ(cxt->g0, cxt->threads) << "TestTime failed"; } else if (c == 1) { absl::MutexLock l(&cxt->mu); @@ -306,14 +302,12 @@ static void TestTime(TestContext *cxt, int c, bool use_cv) { if (use_cv) { cxt->cv.WaitWithTimeout(&cxt->mu, absl::Milliseconds(500)); } else { - ABSL_RAW_CHECK( - !cxt->mu.AwaitWithTimeout(false_cond, absl::Milliseconds(500)), - "TestTime failed"); + CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Milliseconds(500))) + << "TestTime failed"; } const absl::Duration elapsed = absl::Now() - start; - ABSL_RAW_CHECK( - absl::Seconds(0.4) <= elapsed && elapsed <= absl::Seconds(0.9), - "TestTime failed"); + CHECK(absl::Seconds(0.4) <= elapsed && elapsed <= absl::Seconds(0.9)) + << "TestTime failed"; cxt->g0++; } else if (c == 2) { absl::MutexLock l(&cxt->mu); @@ -322,8 +316,8 @@ static void TestTime(TestContext *cxt, int c, bool use_cv) { cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(100)); } } else { - ABSL_RAW_CHECK(cxt->mu.AwaitWithTimeout(g0ge2, absl::Seconds(100)), - "TestTime failed"); + CHECK(cxt->mu.AwaitWithTimeout(g0ge2, absl::Seconds(100))) + << "TestTime failed"; } cxt->g0++; } else { @@ -400,7 +394,7 @@ static int RunTestWithInvariantDebugging(void (*test)(TestContext *cxt, int), TestContext cxt; cxt.mu.EnableInvariantDebugging(invariant, &cxt); int ret = RunTestCommon(&cxt, test, threads, iterations, operations); - ABSL_RAW_CHECK(GetInvariantChecked(), "Invariant not checked"); + CHECK(GetInvariantChecked()) << "Invariant not checked"; absl::EnableMutexInvariantDebugging(false); // Restore. return ret; } @@ -1093,7 +1087,7 @@ static bool ConditionWithAcquire(AcquireFromConditionStruct *x) { absl::Milliseconds(100)); x->mu1.Unlock(); } - ABSL_RAW_CHECK(x->value < 4, "should not be invoked a fourth time"); + CHECK_LT(x->value, 4) << "should not be invoked a fourth time"; // We arrange for the condition to return true on only the 2nd and 3rd calls. return x->value == 2 || x->value == 3; @@ -1340,11 +1334,9 @@ static bool DelayIsWithinBounds(absl::Duration expected_delay, // different clock than absl::Now(), but these cases should be handled by the // the retry mechanism in each TimeoutTest. if (actual_delay < expected_delay) { - ABSL_RAW_LOG(WARNING, - "Actual delay %s was too short, expected %s (difference %s)", - absl::FormatDuration(actual_delay).c_str(), - absl::FormatDuration(expected_delay).c_str(), - absl::FormatDuration(actual_delay - expected_delay).c_str()); + LOG(WARNING) << "Actual delay " << actual_delay + << " was too short, expected " << expected_delay + << " (difference " << actual_delay - expected_delay << ")"; pass = false; } // If the expected delay is <= zero then allow a small error tolerance, since @@ -1355,11 +1347,9 @@ static bool DelayIsWithinBounds(absl::Duration expected_delay, ? absl::Milliseconds(10) : TimeoutTestAllowedSchedulingDelay(); if (actual_delay > expected_delay + tolerance) { - ABSL_RAW_LOG(WARNING, - "Actual delay %s was too long, expected %s (difference %s)", - absl::FormatDuration(actual_delay).c_str(), - absl::FormatDuration(expected_delay).c_str(), - absl::FormatDuration(actual_delay - expected_delay).c_str()); + LOG(WARNING) << "Actual delay " << actual_delay + << " was too long, expected " << expected_delay + << " (difference " << actual_delay - expected_delay << ")"; pass = false; } return pass; @@ -1409,12 +1399,6 @@ std::ostream &operator<<(std::ostream &os, const TimeoutTestParam ¶m) { << " expected_delay: " << param.expected_delay; } -std::string FormatString(const TimeoutTestParam ¶m) { - std::ostringstream os; - os << param; - return os.str(); -} - // Like `thread::Executor::ScheduleAt` except: // a) Delays zero or negative are executed immediately in the current thread. // b) Infinite delays are never scheduled. @@ -1544,13 +1528,13 @@ INSTANTIATE_TEST_SUITE_P(All, TimeoutTest, TEST_P(TimeoutTest, Await) { const TimeoutTestParam params = GetParam(); - ABSL_RAW_LOG(INFO, "Params: %s", FormatString(params).c_str()); + LOG(INFO) << "Params: " << params; // Because this test asserts bounds on scheduling delays it is flaky. To // compensate it loops forever until it passes. Failures express as test // timeouts, in which case the test log can be used to diagnose the issue. for (int attempt = 1;; ++attempt) { - ABSL_RAW_LOG(INFO, "Attempt %d", attempt); + LOG(INFO) << "Attempt " << attempt; absl::Mutex mu; bool value = false; // condition value (under mu) @@ -1578,13 +1562,13 @@ TEST_P(TimeoutTest, Await) { TEST_P(TimeoutTest, LockWhen) { const TimeoutTestParam params = GetParam(); - ABSL_RAW_LOG(INFO, "Params: %s", FormatString(params).c_str()); + LOG(INFO) << "Params: " << params; // Because this test asserts bounds on scheduling delays it is flaky. To // compensate it loops forever until it passes. Failures express as test // timeouts, in which case the test log can be used to diagnose the issue. for (int attempt = 1;; ++attempt) { - ABSL_RAW_LOG(INFO, "Attempt %d", attempt); + LOG(INFO) << "Attempt " << attempt; absl::Mutex mu; bool value = false; // condition value (under mu) @@ -1613,13 +1597,13 @@ TEST_P(TimeoutTest, LockWhen) { TEST_P(TimeoutTest, ReaderLockWhen) { const TimeoutTestParam params = GetParam(); - ABSL_RAW_LOG(INFO, "Params: %s", FormatString(params).c_str()); + LOG(INFO) << "Params: " << params; // Because this test asserts bounds on scheduling delays it is flaky. To // compensate it loops forever until it passes. Failures express as test // timeouts, in which case the test log can be used to diagnose the issue. for (int attempt = 0;; ++attempt) { - ABSL_RAW_LOG(INFO, "Attempt %d", attempt); + LOG(INFO) << "Attempt " << attempt; absl::Mutex mu; bool value = false; // condition value (under mu) @@ -1649,13 +1633,13 @@ TEST_P(TimeoutTest, ReaderLockWhen) { TEST_P(TimeoutTest, Wait) { const TimeoutTestParam params = GetParam(); - ABSL_RAW_LOG(INFO, "Params: %s", FormatString(params).c_str()); + LOG(INFO) << "Params: " << params; // Because this test asserts bounds on scheduling delays it is flaky. To // compensate it loops forever until it passes. Failures express as test // timeouts, in which case the test log can be used to diagnose the issue. for (int attempt = 0;; ++attempt) { - ABSL_RAW_LOG(INFO, "Attempt %d", attempt); + LOG(INFO) << "Attempt " << attempt; absl::Mutex mu; bool value = false; // condition value (under mu) diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel index bb801012685..b57d3b9bfd2 100644 --- a/absl/types/BUILD.bazel +++ b/absl/types/BUILD.bazel @@ -77,8 +77,8 @@ cc_test( ":any", "//absl/base:config", "//absl/base:exception_testing", - "//absl/base:raw_logging_internal", "//absl/container:test_instance_tracker", + "//absl/log", "@com_google_googletest//:gtest_main", ], ) @@ -185,7 +185,7 @@ cc_test( deps = [ ":optional", "//absl/base:config", - "//absl/base:raw_logging_internal", + "//absl/log", "//absl/meta:type_traits", "//absl/strings", "@com_google_googletest//:gtest_main", diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt index 830953aeced..c0dcee79bec 100644 --- a/absl/types/CMakeLists.txt +++ b/absl/types/CMakeLists.txt @@ -68,7 +68,7 @@ absl_cc_test( absl::any absl::config absl::exception_testing - absl::raw_logging_internal + absl::log absl::test_instance_tracker GTest::gmock_main ) @@ -220,7 +220,7 @@ absl_cc_test( DEPS absl::optional absl::config - absl::raw_logging_internal + absl::log absl::strings absl::type_traits GTest::gmock_main diff --git a/absl/types/any_test.cc b/absl/types/any_test.cc index d382b927c22..666ea5b6a42 100644 --- a/absl/types/any_test.cc +++ b/absl/types/any_test.cc @@ -25,8 +25,8 @@ #include "gtest/gtest.h" #include "absl/base/config.h" #include "absl/base/internal/exception_testing.h" -#include "absl/base/internal/raw_logging.h" #include "absl/container/internal/test_instance_tracker.h" +#include "absl/log/log.h" namespace { using absl::test_internal::CopyableOnlyInstance; @@ -704,7 +704,7 @@ struct BadCopyable { #ifdef ABSL_HAVE_EXCEPTIONS throw BadCopy(); #else - ABSL_RAW_LOG(FATAL, "Bad copy"); + LOG(FATAL) << "Bad copy"; #endif } }; diff --git a/absl/types/optional_test.cc b/absl/types/optional_test.cc index bd5fe082e73..5da297b05cd 100644 --- a/absl/types/optional_test.cc +++ b/absl/types/optional_test.cc @@ -23,7 +23,7 @@ #include "gtest/gtest.h" #include "absl/base/config.h" -#include "absl/base/internal/raw_logging.h" +#include "absl/log/log.h" #include "absl/meta/type_traits.h" #include "absl/strings/string_view.h" @@ -1542,8 +1542,7 @@ TEST(optionalTest, Hash) { struct MoveMeNoThrow { MoveMeNoThrow() : x(0) {} [[noreturn]] MoveMeNoThrow(const MoveMeNoThrow& other) : x(other.x) { - ABSL_RAW_LOG(FATAL, "Should not be called."); - abort(); + LOG(FATAL) << "Should not be called."; } MoveMeNoThrow(MoveMeNoThrow&& other) noexcept : x(other.x) {} int x; From c24ead7ffa2b05a817f0b6af09b2e8d0a1575de6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Billeter?= Date: Wed, 24 May 2023 08:34:21 +0200 Subject: [PATCH 0027/1238] CMake: Link `time_zone` library to `Threads::Threads` `time_zone_impl.cc` uses `std::mutex`. --- absl/time/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/absl/time/CMakeLists.txt b/absl/time/CMakeLists.txt index b3124251091..1c830c7a571 100644 --- a/absl/time/CMakeLists.txt +++ b/absl/time/CMakeLists.txt @@ -84,6 +84,7 @@ absl_cc_library( COPTS ${ABSL_DEFAULT_COPTS} DEPS + Threads::Threads $<$:${CoreFoundation}> ) From 44606a0df52c9aef879bbbd0567af571fe996329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Billeter?= Date: Mon, 15 May 2023 12:40:54 +0200 Subject: [PATCH 0028/1238] absl/base: Fix build on AIX The AIX assembler doesn't support numeric labels. Use a relative jump instead to fix Assembler: /tmp/ccw16WCt.s: line 25: Error In Syntax --- absl/base/internal/unscaledcycleclock.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/absl/base/internal/unscaledcycleclock.cc b/absl/base/internal/unscaledcycleclock.cc index b1c396c69c6..128dc52f0c3 100644 --- a/absl/base/internal/unscaledcycleclock.cc +++ b/absl/base/internal/unscaledcycleclock.cc @@ -71,12 +71,11 @@ int64_t UnscaledCycleClock::Now() { #else int32_t tbu, tbl, tmp; asm volatile( - "0:\n" "mftbu %[hi32]\n" "mftb %[lo32]\n" "mftbu %[tmp]\n" "cmpw %[tmp],%[hi32]\n" - "bne 0b\n" + "bne $-16\n" // retry on failure : [ hi32 ] "=r"(tbu), [ lo32 ] "=r"(tbl), [ tmp ] "=r"(tmp)); return (static_cast(tbu) << 32) | tbl; #endif From 339c79d40535d5e2ea8e56dfbff76c283315f2d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Billeter?= Date: Wed, 24 May 2023 09:41:02 +0200 Subject: [PATCH 0029/1238] absl/status: Fix build on AIX `_LINUX_SOURCE_COMPAT` needs to be defined to fix absl/status/status.cc:494:5: error: duplicate case value 494 | case ENOTEMPTY: // Directory not empty | ^~~~ absl/status/status.cc:480:5: note: previously used here 480 | case EEXIST: // File exists | ^~~~ --- absl/status/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/absl/status/CMakeLists.txt b/absl/status/CMakeLists.txt index 15db36af683..4a3c5d6852d 100644 --- a/absl/status/CMakeLists.txt +++ b/absl/status/CMakeLists.txt @@ -25,6 +25,8 @@ absl_cc_library( "status_payload_printer.cc" COPTS ${ABSL_DEFAULT_COPTS} + DEFINES + "$<$:_LINUX_SOURCE_COMPAT>" DEPS absl::atomic_hook absl::config From 7d7defda388b79e9c8d767c5fa66e4f2cdcb4c12 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 24 May 2023 07:10:39 -0700 Subject: [PATCH 0030/1238] fill ABSL_INTERNAL_(DISABLE|RESTORE)_DEPRECATED_DECLARATION_WARNING macro for clang PiperOrigin-RevId: 534824761 Change-Id: I0ab78fcb211bc5df756fb581761ed8febc3d18fd --- absl/base/attributes.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/absl/base/attributes.h b/absl/base/attributes.h index 34a3553801a..cb3f367f824 100644 --- a/absl/base/attributes.h +++ b/absl/base/attributes.h @@ -695,7 +695,7 @@ // ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING // Baz ComputeBazFromFoo(Foo f); // ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING -#ifdef __GNUC__ +#if defined(__GNUC__) || defined(__clang__) // Clang also supports these GCC pragmas. #define ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING \ _Pragma("GCC diagnostic push") \ @@ -705,7 +705,7 @@ #else #define ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING #define ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING -#endif // __GNUC__ +#endif // defined(__GNUC__) || defined(__clang__) // ABSL_CONST_INIT // From 4e4b48faadecb81dc1bd50ada1024a82bb162366 Mon Sep 17 00:00:00 2001 From: Andy Getzendanner Date: Thu, 25 May 2023 07:09:59 -0700 Subject: [PATCH 0031/1238] Note that AsyncSignalSafeWriteToStderr preserves errno, and inline one use of it into a lambda. PiperOrigin-RevId: 535245982 Change-Id: I816f60c8b6476536df6836500f01c9a3ad88ddd4 --- absl/base/internal/raw_logging.h | 2 +- absl/debugging/failure_signal_handler.cc | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/absl/base/internal/raw_logging.h b/absl/base/internal/raw_logging.h index e8765254b8a..3f852d31c38 100644 --- a/absl/base/internal/raw_logging.h +++ b/absl/base/internal/raw_logging.h @@ -129,7 +129,7 @@ void RawLog(absl::LogSeverity severity, const char* file, int line, const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5); // Writes the provided buffer directly to stderr, in a signal-safe, low-level -// manner. +// manner. Preserves errno. void AsyncSignalSafeWriteToStderr(const char* s, size_t len); // compile-time function to get the "base" filename, that is, the part of diff --git a/absl/debugging/failure_signal_handler.cc b/absl/debugging/failure_signal_handler.cc index 9f399d02bc5..0db2a896828 100644 --- a/absl/debugging/failure_signal_handler.cc +++ b/absl/debugging/failure_signal_handler.cc @@ -236,10 +236,6 @@ static void InstallOneFailureHandler(FailureSignalData* data, #endif -static void WriteToStderr(const char* data) { - absl::raw_log_internal::AsyncSignalSafeWriteToStderr(data, strlen(data)); -} - static void WriteSignalMessage(int signo, int cpu, void (*writerfn)(const char*)) { char buf[96]; @@ -380,7 +376,11 @@ static void AbslFailureSignalHandler(int signo, siginfo_t*, void* ucontext) { #endif // First write to stderr. - WriteFailureInfo(signo, ucontext, my_cpu, WriteToStderr); + WriteFailureInfo( + signo, ucontext, my_cpu, +[](const char* data) { + absl::raw_log_internal::AsyncSignalSafeWriteToStderr(data, + strlen(data)); + }); // Riskier code (because it is less likely to be async-signal-safe) // goes after this point. From c154d20abce2f1ae6bd35bd774313e351493219b Mon Sep 17 00:00:00 2001 From: Benjamin Barenblat Date: Thu, 25 May 2023 10:40:43 -0700 Subject: [PATCH 0032/1238] Split absl/hash/hash_test.cc into two files hash_test.cc leans heavily on INSTANTIATE_TYPED_TEST_SUITE_P, which is quite memory- and CPU-hungry. Split a few heavyweight tests into a new hash_instantiated_test.cc, reducing peak RAM consumption (or, on multicore systems, compilation time). PiperOrigin-RevId: 535305679 Change-Id: Ic204da0a47c749c3f7db5f902ade8d74ed3043bb --- absl/hash/BUILD.bazel | 27 +++- absl/hash/CMakeLists.txt | 21 +++ absl/hash/hash_instantiated_test.cc | 224 +++++++++++++++++++++++++++ absl/hash/hash_test.cc | 228 +--------------------------- absl/hash/internal/hash_test.h | 87 +++++++++++ 5 files changed, 362 insertions(+), 225 deletions(-) create mode 100644 absl/hash/hash_instantiated_test.cc create mode 100644 absl/hash/internal/hash_test.h diff --git a/absl/hash/BUILD.bazel b/absl/hash/BUILD.bazel index a0db919bd1d..7f964ae7871 100644 --- a/absl/hash/BUILD.bazel +++ b/absl/hash/BUILD.bazel @@ -68,13 +68,17 @@ cc_library( cc_test( name = "hash_test", - srcs = ["hash_test.cc"], + srcs = [ + "hash_test.cc", + "internal/hash_test.h", + ], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":hash", ":hash_testing", ":spy_hash_state", + "//absl/base:config", "//absl/base:core_headers", "//absl/container:btree", "//absl/container:flat_hash_map", @@ -88,6 +92,27 @@ cc_test( ], ) +cc_test( + name = "hash_instantiated_test", + srcs = [ + "hash_instantiated_test.cc", + "internal/hash_test.h", + ], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [ + ":hash", + ":hash_testing", + "//absl/base:config", + "//absl/container:btree", + "//absl/container:flat_hash_map", + "//absl/container:flat_hash_set", + "//absl/container:node_hash_map", + "//absl/container:node_hash_set", + "@com_google_googletest//:gtest_main", + ], +) + cc_binary( name = "hash_benchmark", testonly = 1, diff --git a/absl/hash/CMakeLists.txt b/absl/hash/CMakeLists.txt index f99f35bcaaa..1adce61721c 100644 --- a/absl/hash/CMakeLists.txt +++ b/absl/hash/CMakeLists.txt @@ -64,6 +64,7 @@ absl_cc_test( hash_test SRCS "hash_test.cc" + "internal/hash_test.h" COPTS ${ABSL_TEST_COPTS} DEPS @@ -82,6 +83,26 @@ absl_cc_test( GTest::gmock_main ) +absl_cc_test( + NAME + hash_instantiated_test + SRCS + "hash_test.cc" + "internal/hash_test.h" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::hash + absl::hash_testing + absl::config + absl::btree + absl::flat_hash_map + absl::flat_hash_set + absl::node_hash_map + absl::node_hash_set + GTest::gtest_main +) + # Internal-only target, do not depend on directly. # # Note: Even though external code should not depend on this target diff --git a/absl/hash/hash_instantiated_test.cc b/absl/hash/hash_instantiated_test.cc new file mode 100644 index 00000000000..e65de9ca9ed --- /dev/null +++ b/absl/hash/hash_instantiated_test.cc @@ -0,0 +1,224 @@ +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This file contains a few select absl::Hash tests that, due to their reliance +// on INSTANTIATE_TYPED_TEST_SUITE_P, require a large amount of memory to +// compile. Put new tests in hash_test.cc, not this file. + +#include "absl/hash/hash.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" +#include "absl/container/btree_map.h" +#include "absl/container/btree_set.h" +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" +#include "absl/container/node_hash_map.h" +#include "absl/container/node_hash_set.h" +#include "absl/hash/hash_testing.h" +#include "absl/hash/internal/hash_test.h" + +namespace { + +using ::absl::hash_test_internal::is_hashable; +using ::absl::hash_test_internal::TypeErasedContainer; + +// Dummy type with unordered equality and hashing semantics. This preserves +// input order internally, and is used below to ensure we get test coverage +// for equal sequences with different iteraton orders. +template +class UnorderedSequence { + public: + UnorderedSequence() = default; + template + UnorderedSequence(std::initializer_list l) + : values_(l.begin(), l.end()) {} + template ::value, + bool>::type = true> + UnorderedSequence(ForwardIterator begin, ForwardIterator end) + : values_(begin, end) {} + // one-argument constructor of value type T, to appease older toolchains that + // get confused by one-element initializer lists in some contexts + explicit UnorderedSequence(const T& v) : values_(&v, &v + 1) {} + + using value_type = T; + + size_t size() const { return values_.size(); } + typename std::vector::const_iterator begin() const { + return values_.begin(); + } + typename std::vector::const_iterator end() const { return values_.end(); } + + friend bool operator==(const UnorderedSequence& lhs, + const UnorderedSequence& rhs) { + return lhs.size() == rhs.size() && + std::is_permutation(lhs.begin(), lhs.end(), rhs.begin()); + } + friend bool operator!=(const UnorderedSequence& lhs, + const UnorderedSequence& rhs) { + return !(lhs == rhs); + } + template + friend H AbslHashValue(H h, const UnorderedSequence& u) { + return H::combine(H::combine_unordered(std::move(h), u.begin(), u.end()), + u.size()); + } + + private: + std::vector values_; +}; + +template +class HashValueSequenceTest : public testing::Test {}; +TYPED_TEST_SUITE_P(HashValueSequenceTest); + +TYPED_TEST_P(HashValueSequenceTest, BasicUsage) { + EXPECT_TRUE((is_hashable::value)); + + using IntType = typename TypeParam::value_type; + auto a = static_cast(0); + auto b = static_cast(23); + auto c = static_cast(42); + + std::vector exemplars = { + TypeParam(), TypeParam(), TypeParam{a, b, c}, + TypeParam{a, c, b}, TypeParam{c, a, b}, TypeParam{a}, + TypeParam{a, a}, TypeParam{a, a, a}, TypeParam{a, a, b}, + TypeParam{a, b, a}, TypeParam{b, a, a}, TypeParam{a, b}, + TypeParam{b, c}}; + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars)); +} + +REGISTER_TYPED_TEST_SUITE_P(HashValueSequenceTest, BasicUsage); +using IntSequenceTypes = testing::Types< + std::deque, std::forward_list, std::list, std::vector, + std::vector, TypeErasedContainer>, std::set, + std::multiset, UnorderedSequence, + TypeErasedContainer>, std::unordered_set, + std::unordered_multiset, absl::flat_hash_set, + absl::node_hash_set, absl::btree_set>; +INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueSequenceTest, IntSequenceTypes); + +template +class HashValueNestedSequenceTest : public testing::Test {}; +TYPED_TEST_SUITE_P(HashValueNestedSequenceTest); + +TYPED_TEST_P(HashValueNestedSequenceTest, BasicUsage) { + using T = TypeParam; + using V = typename T::value_type; + std::vector exemplars = { + // empty case + T{}, + // sets of empty sets + T{V{}}, T{V{}, V{}}, T{V{}, V{}, V{}}, + // multisets of different values + T{V{1}}, T{V{1, 1}, V{1, 1}}, T{V{1, 1, 1}, V{1, 1, 1}, V{1, 1, 1}}, + // various orderings of same nested sets + T{V{}, V{1, 2}}, T{V{}, V{2, 1}}, T{V{1, 2}, V{}}, T{V{2, 1}, V{}}, + // various orderings of various nested sets, case 2 + T{V{1, 2}, V{3, 4}}, T{V{1, 2}, V{4, 3}}, T{V{1, 3}, V{2, 4}}, + T{V{1, 3}, V{4, 2}}, T{V{1, 4}, V{2, 3}}, T{V{1, 4}, V{3, 2}}, + T{V{2, 3}, V{1, 4}}, T{V{2, 3}, V{4, 1}}, T{V{2, 4}, V{1, 3}}, + T{V{2, 4}, V{3, 1}}, T{V{3, 4}, V{1, 2}}, T{V{3, 4}, V{2, 1}}}; + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars)); +} + +REGISTER_TYPED_TEST_SUITE_P(HashValueNestedSequenceTest, BasicUsage); +template +using TypeErasedSet = TypeErasedContainer>; + +using NestedIntSequenceTypes = testing::Types< + std::vector>, std::vector>, + std::vector>, UnorderedSequence>, + UnorderedSequence>, + UnorderedSequence>, TypeErasedSet>, + TypeErasedSet>, TypeErasedSet>>; +INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueNestedSequenceTest, + NestedIntSequenceTypes); + +template +class HashValueAssociativeMapTest : public testing::Test {}; +TYPED_TEST_SUITE_P(HashValueAssociativeMapTest); + +TYPED_TEST_P(HashValueAssociativeMapTest, BasicUsage) { + using M = TypeParam; + using V = typename M::value_type; + std::vector exemplars{M{}, + M{V{0, "foo"}}, + M{V{1, "foo"}}, + M{V{0, "bar"}}, + M{V{1, "bar"}}, + M{V{0, "foo"}, V{42, "bar"}}, + M{V{42, "bar"}, V{0, "foo"}}, + M{V{1, "foo"}, V{42, "bar"}}, + M{V{1, "foo"}, V{43, "bar"}}, + M{V{1, "foo"}, V{43, "baz"}}}; + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars)); +} + +REGISTER_TYPED_TEST_SUITE_P(HashValueAssociativeMapTest, BasicUsage); +using AssociativeMapTypes = testing::Types< + std::map, std::unordered_map, + absl::flat_hash_map, + absl::node_hash_map, absl::btree_map, + UnorderedSequence>>; +INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueAssociativeMapTest, + AssociativeMapTypes); + +template +class HashValueAssociativeMultimapTest : public testing::Test {}; +TYPED_TEST_SUITE_P(HashValueAssociativeMultimapTest); + +TYPED_TEST_P(HashValueAssociativeMultimapTest, BasicUsage) { + using MM = TypeParam; + using V = typename MM::value_type; + std::vector exemplars{MM{}, + MM{V{0, "foo"}}, + MM{V{1, "foo"}}, + MM{V{0, "bar"}}, + MM{V{1, "bar"}}, + MM{V{0, "foo"}, V{0, "bar"}}, + MM{V{0, "bar"}, V{0, "foo"}}, + MM{V{0, "foo"}, V{42, "bar"}}, + MM{V{1, "foo"}, V{42, "bar"}}, + MM{V{1, "foo"}, V{1, "foo"}, V{43, "bar"}}, + MM{V{1, "foo"}, V{43, "bar"}, V{1, "foo"}}, + MM{V{1, "foo"}, V{43, "baz"}}}; + EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars)); +} + +REGISTER_TYPED_TEST_SUITE_P(HashValueAssociativeMultimapTest, BasicUsage); +using AssociativeMultimapTypes = + testing::Types, + std::unordered_multimap>; +INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueAssociativeMultimapTest, + AssociativeMultimapTypes); + +} // namespace diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc index 6727dafa14c..a0e2e4a7113 100644 --- a/absl/hash/hash_test.cc +++ b/absl/hash/hash_test.cc @@ -48,6 +48,7 @@ #include "absl/container/node_hash_map.h" #include "absl/container/node_hash_set.h" #include "absl/hash/hash_testing.h" +#include "absl/hash/internal/hash_test.h" #include "absl/hash/internal/spy_hash_state.h" #include "absl/meta/type_traits.h" #include "absl/numeric/int128.h" @@ -59,52 +60,9 @@ namespace { -// Utility wrapper of T for the purposes of testing the `AbslHash` type erasure -// mechanism. `TypeErasedValue` can be constructed with a `T`, and can -// be compared and hashed. However, all hashing goes through the hashing -// type-erasure framework. -template -class TypeErasedValue { - public: - TypeErasedValue() = default; - TypeErasedValue(const TypeErasedValue&) = default; - TypeErasedValue(TypeErasedValue&&) = default; - explicit TypeErasedValue(const T& n) : n_(n) {} - - template - friend H AbslHashValue(H hash_state, const TypeErasedValue& v) { - v.HashValue(absl::HashState::Create(&hash_state)); - return hash_state; - } - - void HashValue(absl::HashState state) const { - absl::HashState::combine(std::move(state), n_); - } - - bool operator==(const TypeErasedValue& rhs) const { return n_ == rhs.n_; } - bool operator!=(const TypeErasedValue& rhs) const { return !(*this == rhs); } - - private: - T n_; -}; - -// A TypeErasedValue refinement, for containers. It exposes the wrapped -// `value_type` and is constructible from an initializer list. -template -class TypeErasedContainer : public TypeErasedValue { - public: - using value_type = typename T::value_type; - TypeErasedContainer() = default; - TypeErasedContainer(const TypeErasedContainer&) = default; - TypeErasedContainer(TypeErasedContainer&&) = default; - explicit TypeErasedContainer(const T& n) : TypeErasedValue(n) {} - TypeErasedContainer(std::initializer_list init_list) - : TypeErasedContainer(T(init_list.begin(), init_list.end())) {} - // one-argument constructor of value type T, to appease older toolchains that - // get confused by one-element initializer lists in some contexts - explicit TypeErasedContainer(const value_type& v) - : TypeErasedContainer(T(&v, &v + 1)) {} -}; +using ::absl::hash_test_internal::is_hashable; +using ::absl::hash_test_internal::TypeErasedContainer; +using ::absl::hash_test_internal::TypeErasedValue; template using TypeErasedVector = TypeErasedContainer>; @@ -122,11 +80,6 @@ SpyHashState SpyHash(const T& value) { return SpyHashState::combine(SpyHashState(), value); } -// Helper trait to verify if T is hashable. We use absl::Hash's poison status to -// detect it. -template -using is_hashable = std::is_default_constructible>; - TYPED_TEST_P(HashValueIntTest, BasicUsage) { EXPECT_TRUE((is_hashable::value)); @@ -566,121 +519,6 @@ TEST(HashValueTest, StdBitset) { std::bitset(bit_strings[5].c_str())})); } // namespace -// Dummy type with unordered equality and hashing semantics. This preserves -// input order internally, and is used below to ensure we get test coverage -// for equal sequences with different iteraton orders. -template -class UnorderedSequence { - public: - UnorderedSequence() = default; - template - UnorderedSequence(std::initializer_list l) - : values_(l.begin(), l.end()) {} - template ::value, - bool>::type = true> - UnorderedSequence(ForwardIterator begin, ForwardIterator end) - : values_(begin, end) {} - // one-argument constructor of value type T, to appease older toolchains that - // get confused by one-element initializer lists in some contexts - explicit UnorderedSequence(const T& v) : values_(&v, &v + 1) {} - - using value_type = T; - - size_t size() const { return values_.size(); } - typename std::vector::const_iterator begin() const { - return values_.begin(); - } - typename std::vector::const_iterator end() const { return values_.end(); } - - friend bool operator==(const UnorderedSequence& lhs, - const UnorderedSequence& rhs) { - return lhs.size() == rhs.size() && - std::is_permutation(lhs.begin(), lhs.end(), rhs.begin()); - } - friend bool operator!=(const UnorderedSequence& lhs, - const UnorderedSequence& rhs) { - return !(lhs == rhs); - } - template - friend H AbslHashValue(H h, const UnorderedSequence& u) { - return H::combine(H::combine_unordered(std::move(h), u.begin(), u.end()), - u.size()); - } - - private: - std::vector values_; -}; - -template -class HashValueSequenceTest : public testing::Test { -}; -TYPED_TEST_SUITE_P(HashValueSequenceTest); - -TYPED_TEST_P(HashValueSequenceTest, BasicUsage) { - EXPECT_TRUE((is_hashable::value)); - - using IntType = typename TypeParam::value_type; - auto a = static_cast(0); - auto b = static_cast(23); - auto c = static_cast(42); - - std::vector exemplars = { - TypeParam(), TypeParam(), TypeParam{a, b, c}, - TypeParam{a, c, b}, TypeParam{c, a, b}, TypeParam{a}, - TypeParam{a, a}, TypeParam{a, a, a}, TypeParam{a, a, b}, - TypeParam{a, b, a}, TypeParam{b, a, a}, TypeParam{a, b}, - TypeParam{b, c}}; - EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars)); -} - -REGISTER_TYPED_TEST_SUITE_P(HashValueSequenceTest, BasicUsage); -using IntSequenceTypes = testing::Types< - std::deque, std::forward_list, std::list, std::vector, - std::vector, TypeErasedContainer>, std::set, - std::multiset, UnorderedSequence, - TypeErasedContainer>, std::unordered_set, - std::unordered_multiset, absl::flat_hash_set, - absl::node_hash_set, absl::btree_set>; -INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueSequenceTest, IntSequenceTypes); - -template -class HashValueNestedSequenceTest : public testing::Test {}; -TYPED_TEST_SUITE_P(HashValueNestedSequenceTest); - -TYPED_TEST_P(HashValueNestedSequenceTest, BasicUsage) { - using T = TypeParam; - using V = typename T::value_type; - std::vector exemplars = { - // empty case - T{}, - // sets of empty sets - T{V{}}, T{V{}, V{}}, T{V{}, V{}, V{}}, - // multisets of different values - T{V{1}}, T{V{1, 1}, V{1, 1}}, T{V{1, 1, 1}, V{1, 1, 1}, V{1, 1, 1}}, - // various orderings of same nested sets - T{V{}, V{1, 2}}, T{V{}, V{2, 1}}, T{V{1, 2}, V{}}, T{V{2, 1}, V{}}, - // various orderings of various nested sets, case 2 - T{V{1, 2}, V{3, 4}}, T{V{1, 2}, V{4, 3}}, T{V{1, 3}, V{2, 4}}, - T{V{1, 3}, V{4, 2}}, T{V{1, 4}, V{2, 3}}, T{V{1, 4}, V{3, 2}}, - T{V{2, 3}, V{1, 4}}, T{V{2, 3}, V{4, 1}}, T{V{2, 4}, V{1, 3}}, - T{V{2, 4}, V{3, 1}}, T{V{3, 4}, V{1, 2}}, T{V{3, 4}, V{2, 1}}}; - EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars)); -} - -REGISTER_TYPED_TEST_SUITE_P(HashValueNestedSequenceTest, BasicUsage); -template -using TypeErasedSet = TypeErasedContainer>; - -using NestedIntSequenceTypes = testing::Types< - std::vector>, std::vector>, - std::vector>, UnorderedSequence>, - UnorderedSequence>, - UnorderedSequence>, TypeErasedSet>, - TypeErasedSet>, TypeErasedSet>>; -INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueNestedSequenceTest, - NestedIntSequenceTypes); - // Private type that only supports AbslHashValue to make sure our chosen hash // implementation is recursive within absl::Hash. // It uses std::abs() on the value to provide different bitwise representations @@ -839,64 +677,6 @@ TEST(HashValueTest, Variant) { #endif } -template -class HashValueAssociativeMapTest : public testing::Test {}; -TYPED_TEST_SUITE_P(HashValueAssociativeMapTest); - -TYPED_TEST_P(HashValueAssociativeMapTest, BasicUsage) { - using M = TypeParam; - using V = typename M::value_type; - std::vector exemplars{M{}, - M{V{0, "foo"}}, - M{V{1, "foo"}}, - M{V{0, "bar"}}, - M{V{1, "bar"}}, - M{V{0, "foo"}, V{42, "bar"}}, - M{V{42, "bar"}, V{0, "foo"}}, - M{V{1, "foo"}, V{42, "bar"}}, - M{V{1, "foo"}, V{43, "bar"}}, - M{V{1, "foo"}, V{43, "baz"}}}; - EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars)); -} - -REGISTER_TYPED_TEST_SUITE_P(HashValueAssociativeMapTest, BasicUsage); -using AssociativeMapTypes = testing::Types< - std::map, std::unordered_map, - absl::flat_hash_map, - absl::node_hash_map, absl::btree_map, - UnorderedSequence>>; -INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueAssociativeMapTest, - AssociativeMapTypes); - -template -class HashValueAssociativeMultimapTest : public testing::Test {}; -TYPED_TEST_SUITE_P(HashValueAssociativeMultimapTest); - -TYPED_TEST_P(HashValueAssociativeMultimapTest, BasicUsage) { - using MM = TypeParam; - using V = typename MM::value_type; - std::vector exemplars{MM{}, - MM{V{0, "foo"}}, - MM{V{1, "foo"}}, - MM{V{0, "bar"}}, - MM{V{1, "bar"}}, - MM{V{0, "foo"}, V{0, "bar"}}, - MM{V{0, "bar"}, V{0, "foo"}}, - MM{V{0, "foo"}, V{42, "bar"}}, - MM{V{1, "foo"}, V{42, "bar"}}, - MM{V{1, "foo"}, V{1, "foo"}, V{43, "bar"}}, - MM{V{1, "foo"}, V{43, "bar"}, V{1, "foo"}}, - MM{V{1, "foo"}, V{43, "baz"}}}; - EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(exemplars)); -} - -REGISTER_TYPED_TEST_SUITE_P(HashValueAssociativeMultimapTest, BasicUsage); -using AssociativeMultimapTypes = - testing::Types, - std::unordered_multimap>; -INSTANTIATE_TYPED_TEST_SUITE_P(My, HashValueAssociativeMultimapTest, - AssociativeMultimapTypes); - TEST(HashValueTest, ReferenceWrapper) { EXPECT_TRUE(is_hashable>::value); diff --git a/absl/hash/internal/hash_test.h b/absl/hash/internal/hash_test.h new file mode 100644 index 00000000000..9963dc0b8d9 --- /dev/null +++ b/absl/hash/internal/hash_test.h @@ -0,0 +1,87 @@ +// Copyright 2023 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Common code shared between absl/hash/hash_test.cc and +// absl/hash/hash_instantiated_test.cc. + +#ifndef ABSL_HASH_INTERNAL_HASH_TEST_H_ +#define ABSL_HASH_INTERNAL_HASH_TEST_H_ + +#include +#include + +#include "absl/base/config.h" +#include "absl/hash/hash.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace hash_test_internal { + +// Utility wrapper of T for the purposes of testing the `AbslHash` type erasure +// mechanism. `TypeErasedValue` can be constructed with a `T`, and can +// be compared and hashed. However, all hashing goes through the hashing +// type-erasure framework. +template +class TypeErasedValue { + public: + TypeErasedValue() = default; + TypeErasedValue(const TypeErasedValue&) = default; + TypeErasedValue(TypeErasedValue&&) = default; + explicit TypeErasedValue(const T& n) : n_(n) {} + + template + friend H AbslHashValue(H hash_state, const TypeErasedValue& v) { + v.HashValue(absl::HashState::Create(&hash_state)); + return hash_state; + } + + void HashValue(absl::HashState state) const { + absl::HashState::combine(std::move(state), n_); + } + + bool operator==(const TypeErasedValue& rhs) const { return n_ == rhs.n_; } + bool operator!=(const TypeErasedValue& rhs) const { return !(*this == rhs); } + + private: + T n_; +}; + +// A TypeErasedValue refinement, for containers. It exposes the wrapped +// `value_type` and is constructible from an initializer list. +template +class TypeErasedContainer : public TypeErasedValue { + public: + using value_type = typename T::value_type; + TypeErasedContainer() = default; + TypeErasedContainer(const TypeErasedContainer&) = default; + TypeErasedContainer(TypeErasedContainer&&) = default; + explicit TypeErasedContainer(const T& n) : TypeErasedValue(n) {} + TypeErasedContainer(std::initializer_list init_list) + : TypeErasedContainer(T(init_list.begin(), init_list.end())) {} + // one-argument constructor of value type T, to appease older toolchains that + // get confused by one-element initializer lists in some contexts + explicit TypeErasedContainer(const value_type& v) + : TypeErasedContainer(T(&v, &v + 1)) {} +}; + +// Helper trait to verify if T is hashable. We use absl::Hash's poison status to +// detect it. +template +using is_hashable = std::is_default_constructible>; + +} // namespace hash_test_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_HASH_INTERNAL_HASH_TEST_H_ From 88cc63ef739d83277b492e881be72e9069fcb1fe Mon Sep 17 00:00:00 2001 From: Andy Getzendanner Date: Thu, 25 May 2023 11:32:01 -0700 Subject: [PATCH 0033/1238] Implement a better GetTID on Apple platforms, and a better fallback too. The fallback isn't totally portable, even within POSIX, but we can special case any future platforms where it's not just like this change does for Apple. PiperOrigin-RevId: 535324103 Change-Id: Ib628925c4946b6c112373678fe37e9bb44259090 --- absl/base/internal/sysinfo.cc | 84 ++++++----------------------------- 1 file changed, 13 insertions(+), 71 deletions(-) diff --git a/absl/base/internal/sysinfo.cc b/absl/base/internal/sysinfo.cc index 8429fb90e40..ed20335501c 100644 --- a/absl/base/internal/sysinfo.cc +++ b/absl/base/internal/sysinfo.cc @@ -414,82 +414,24 @@ pid_t GetTID() { return tid; } -#else +#elif defined(__APPLE__) -// Fallback implementation of GetTID using pthread_getspecific. -ABSL_CONST_INIT static once_flag tid_once; -ABSL_CONST_INIT static pthread_key_t tid_key; -ABSL_CONST_INIT static absl::base_internal::SpinLock tid_lock( - absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY); - -// We set a bit per thread in this array to indicate that an ID is in -// use. ID 0 is unused because it is the default value returned by -// pthread_getspecific(). -ABSL_CONST_INIT static std::vector *tid_array - ABSL_GUARDED_BY(tid_lock) = nullptr; -static constexpr int kBitsPerWord = 32; // tid_array is uint32_t. - -// Returns the TID to tid_array. -static void FreeTID(void *v) { - intptr_t tid = reinterpret_cast(v); - intptr_t word = tid / kBitsPerWord; - uint32_t mask = ~(1u << (tid % kBitsPerWord)); - absl::base_internal::SpinLockHolder lock(&tid_lock); - assert(0 <= word && static_cast(word) < tid_array->size()); - (*tid_array)[static_cast(word)] &= mask; +pid_t GetTID() { + uint64_t tid; + // `nullptr` here implies this thread. This only fails if the specified + // thread is invalid or the pointer-to-tid is null, so we needn't worry about + // it. + pthread_threadid_np(nullptr, &tid); + return static_cast(tid); } -static void InitGetTID() { - if (pthread_key_create(&tid_key, FreeTID) != 0) { - // The logging system calls GetTID() so it can't be used here. - perror("pthread_key_create failed"); - abort(); - } - - // Initialize tid_array. - absl::base_internal::SpinLockHolder lock(&tid_lock); - tid_array = new std::vector(1); - (*tid_array)[0] = 1; // ID 0 is never-allocated. -} +#else -// Return a per-thread small integer ID from pthread's thread-specific data. +// Fallback implementation of `GetTID` using `pthread_self`. pid_t GetTID() { - absl::call_once(tid_once, InitGetTID); - - intptr_t tid = reinterpret_cast(pthread_getspecific(tid_key)); - if (tid != 0) { - return static_cast(tid); - } - - int bit; // tid_array[word] = 1u << bit; - size_t word; - { - // Search for the first unused ID. - absl::base_internal::SpinLockHolder lock(&tid_lock); - // First search for a word in the array that is not all ones. - word = 0; - while (word < tid_array->size() && ~(*tid_array)[word] == 0) { - ++word; - } - if (word == tid_array->size()) { - tid_array->push_back(0); // No space left, add kBitsPerWord more IDs. - } - // Search for a zero bit in the word. - bit = 0; - while (bit < kBitsPerWord && (((*tid_array)[word] >> bit) & 1) != 0) { - ++bit; - } - tid = - static_cast((word * kBitsPerWord) + static_cast(bit)); - (*tid_array)[word] |= 1u << bit; // Mark the TID as allocated. - } - - if (pthread_setspecific(tid_key, reinterpret_cast(tid)) != 0) { - perror("pthread_setspecific failed"); - abort(); - } - - return static_cast(tid); + // `pthread_t` need not be arithmetic per POSIX; platforms where it isn't + // should be handled above. + return static_cast(pthread_self()); } #endif From 0f718c568b448005bcb6718e7c0f5b6420ace413 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 26 May 2023 00:28:00 -0700 Subject: [PATCH 0034/1238] Add support for stateful allocators to absl::FixedArray. PiperOrigin-RevId: 535534819 Change-Id: Iccf8da3e0b084131e4c0dba205f3e190d3a66f4e --- absl/container/fixed_array.h | 21 +++++++++++++++------ absl/container/fixed_array_test.cc | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/absl/container/fixed_array.h b/absl/container/fixed_array.h index e99137a482a..9f1c813dcac 100644 --- a/absl/container/fixed_array.h +++ b/absl/container/fixed_array.h @@ -117,14 +117,20 @@ class FixedArray { (N == kFixedArrayUseDefault ? kInlineBytesDefault / sizeof(value_type) : static_cast(N)); - FixedArray( - const FixedArray& other, - const allocator_type& a = allocator_type()) noexcept(NoexceptCopyable()) + FixedArray(const FixedArray& other) noexcept(NoexceptCopyable()) + : FixedArray(other, + AllocatorTraits::select_on_container_copy_construction( + other.storage_.alloc())) {} + + FixedArray(const FixedArray& other, + const allocator_type& a) noexcept(NoexceptCopyable()) : FixedArray(other.begin(), other.end(), a) {} - FixedArray( - FixedArray&& other, - const allocator_type& a = allocator_type()) noexcept(NoexceptMovable()) + FixedArray(FixedArray&& other) noexcept(NoexceptMovable()) + : FixedArray(std::move(other), other.storage_.alloc()) {} + + FixedArray(FixedArray&& other, + const allocator_type& a) noexcept(NoexceptMovable()) : FixedArray(std::make_move_iterator(other.begin()), std::make_move_iterator(other.end()), a) {} @@ -480,6 +486,9 @@ class FixedArray { StorageElement* begin() const { return data_; } StorageElement* end() const { return begin() + size(); } allocator_type& alloc() { return size_alloc_.template get<1>(); } + const allocator_type& alloc() const { + return size_alloc_.template get<1>(); + } private: static bool UsingInlinedStorage(size_type n) { diff --git a/absl/container/fixed_array_test.cc b/absl/container/fixed_array_test.cc index 49598e7a053..9dbf2a84cc6 100644 --- a/absl/container/fixed_array_test.cc +++ b/absl/container/fixed_array_test.cc @@ -768,6 +768,22 @@ TEST(AllocatorSupportTest, SizeValAllocConstructor) { } } +TEST(AllocatorSupportTest, PropagatesStatefulAllocator) { + constexpr size_t inlined_size = 4; + using Alloc = absl::container_internal::CountingAllocator; + using AllocFxdArr = absl::FixedArray; + + auto len = inlined_size * 2; + auto val = 0; + int64_t allocated = 0; + AllocFxdArr arr(len, val, Alloc(&allocated)); + + EXPECT_EQ(allocated, len * sizeof(int)); + + AllocFxdArr copy = arr; + EXPECT_EQ(allocated, len * sizeof(int) * 2); +} + #ifdef ABSL_HAVE_ADDRESS_SANITIZER TEST(FixedArrayTest, AddressSanitizerAnnotations1) { absl::FixedArray a(10); From 8e45685002488b55f24cb67a795eaa8d1c3297a1 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Fri, 26 May 2023 09:43:35 -0700 Subject: [PATCH 0035/1238] Disable the use of the fast GetCurrentTimeNanos() algorithm based on the cyclecounter by default, since it may be unsafe in some situations (for example, if the system may enter a sleep state). Fixes #1460 PiperOrigin-RevId: 535641718 Change-Id: I41c9cc4bc7a8ae7280ff9df00abd57668205045b --- absl/time/clock.cc | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/absl/time/clock.cc b/absl/time/clock.cc index 2bf53d9c61e..aa74367b8a7 100644 --- a/absl/time/clock.cc +++ b/absl/time/clock.cc @@ -48,17 +48,16 @@ Time Now() { ABSL_NAMESPACE_END } // namespace absl -// Decide if we should use the fast GetCurrentTimeNanos() algorithm -// based on the cyclecounter, otherwise just get the time directly -// from the OS on every call. This can be chosen at compile-time via +// Decide if we should use the fast GetCurrentTimeNanos() algorithm based on the +// cyclecounter, otherwise just get the time directly from the OS on every call. +// By default, the fast algorithm based on the cyclecount is disabled because in +// certain situations, for example, if the OS enters a "sleep" mode, it may +// produce incorrect values immediately upon waking. +// This can be chosen at compile-time via // -DABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS=[0|1] #ifndef ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS -#if ABSL_USE_UNSCALED_CYCLECLOCK -#define ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS 1 -#else #define ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS 0 #endif -#endif #if defined(__APPLE__) || defined(_WIN32) #include "absl/time/internal/get_current_time_chrono.inc" From 75fb27c5d385ed7aed36e5fd26fa7d6b6200e389 Mon Sep 17 00:00:00 2001 From: "Bradley C. Kuszmaul" Date: Tue, 30 May 2023 10:01:56 -0400 Subject: [PATCH 0036/1238] Typo gardening --- absl/container/internal/raw_hash_set.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index df7ff79333f..21b161b3b49 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -961,7 +961,7 @@ class CommonFields : public CommonFieldsGenerationInfo { compressed_tuple_{0u, HashtablezInfoHandle{}}; }; -// Returns he number of "cloned control bytes". +// Returns the number of "cloned control bytes". // // This is the number of control bytes that are present both at the beginning // of the control byte array and at the end, such that we can create a From e077941c43da6b050101b5af151396053fb251d8 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 30 May 2023 15:28:44 -0700 Subject: [PATCH 0037/1238] For web assembly, implement WriteToStderr as emscripten_err. This avoids the need to use filesystem APIs just to write to stderr, which emscripten implements the same as this under the hood. PiperOrigin-RevId: 536525710 Change-Id: I0a647a4593eacfba324505b6e8c4acfb577ac839 --- absl/log/internal/globals.cc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/absl/log/internal/globals.cc b/absl/log/internal/globals.cc index 863b047f332..9ba997d52fb 100644 --- a/absl/log/internal/globals.cc +++ b/absl/log/internal/globals.cc @@ -16,6 +16,9 @@ #include #include +#if defined(__EMSCRIPTEN__) +#include +#endif #include "absl/base/attributes.h" #include "absl/base/config.h" @@ -55,9 +58,21 @@ void SetInitialized() { } void WriteToStderr(absl::string_view message, absl::LogSeverity severity) { +#if defined(__EMSCRIPTEN__) + // In WebAssembly, bypass filesystem emulation via fwrite. + // TODO(b/282811932): Avoid this copy if these emscripten functions can + // be updated to accept size directly. + std::string null_terminated_message(message); + if (!null_terminated_message.empty() && + null_terminated_message.back() == '\n') { + null_terminated_message.pop_back(); + } + _emscripten_err(null_terminated_message.c_str()); +#else // Avoid using std::cerr from this module since we may get called during // exit code, and cerr may be partially or fully destroyed by then. std::fwrite(message.data(), message.size(), 1, stderr); +#endif #if defined(_WIN64) || defined(_WIN32) || defined(_WIN16) // C99 requires stderr to not be fully-buffered by default (7.19.3.7), but From 6f72305f9514ee341b0c37470749214fa82c37b4 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 31 May 2023 09:31:34 -0700 Subject: [PATCH 0038/1238] Switch from perror to ABSL_INTERNAL_LOG. Motivation is for WebAssembly to avoid perror which in turn requires file system emulation. PiperOrigin-RevId: 536737294 Change-Id: I5177064c9451fb630ec5e9d0c0a0679fabd98afa --- absl/base/internal/sysinfo.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/absl/base/internal/sysinfo.cc b/absl/base/internal/sysinfo.cc index ed20335501c..7de8ead2139 100644 --- a/absl/base/internal/sysinfo.cc +++ b/absl/base/internal/sysinfo.cc @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -225,8 +226,8 @@ static int64_t ReadMonotonicClockNanos() { int rc = clock_gettime(CLOCK_MONOTONIC, &t); #endif if (rc != 0) { - perror("clock_gettime() failed"); - abort(); + ABSL_INTERNAL_LOG( + FATAL, "clock_gettime() failed: (" + std::to_string(errno) + ")"); } return int64_t{t.tv_sec} * 1000000000 + t.tv_nsec; } From 182925b7c0ef7a1cca7982c1a9e0c81fafa58266 Mon Sep 17 00:00:00 2001 From: "Bradley C. Kuszmaul" Date: Wed, 31 May 2023 16:06:22 -0400 Subject: [PATCH 0039/1238] Convert `raw_hash_set` comments from imperative to indicative mood. https://google.github.io/styleguide/cppguide.html#Function_Comments --- absl/container/internal/raw_hash_set.cc | 11 ++++++----- absl/container/internal/raw_hash_set.h | 6 +++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc index b91d5a47d90..1ccee1edfd4 100644 --- a/absl/container/internal/raw_hash_set.cc +++ b/absl/container/internal/raw_hash_set.cc @@ -107,21 +107,22 @@ FindInfo find_first_non_full_outofline(const CommonFields& common, return find_first_non_full(common, hash); } -// Return address of the ith slot in slots where each slot occupies slot_size. +// Returns the address of the ith slot in slots where each slot occupies +// slot_size. static inline void* SlotAddress(void* slot_array, size_t slot, size_t slot_size) { return reinterpret_cast(reinterpret_cast(slot_array) + (slot * slot_size)); } -// Return the address of the slot just after slot assuming each slot -// has the specified size. +// Returns the address of the slot just after slot assuming each slot has the +// specified size. static inline void* NextSlot(void* slot, size_t slot_size) { return reinterpret_cast(reinterpret_cast(slot) + slot_size); } -// Return the address of the slot just before slot assuming each slot -// has the specified size. +// Returns the address of the slot just before slot assuming each slot has the +// specified size. static inline void* PrevSlot(void* slot, size_t slot_size) { return reinterpret_cast(reinterpret_cast(slot) - slot_size); } diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 03f236f2fbe..2880af70e46 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -376,12 +376,12 @@ class NonIterableBitMask { return static_cast((bit_width(mask_) - 1) >> Shift); } - // Return the number of trailing zero *abstract* bits. + // Returns the number of trailing zero *abstract* bits. uint32_t TrailingZeros() const { return container_internal::TrailingZeros(mask_) >> Shift; } - // Return the number of leading zero *abstract* bits. + // Returns the number of leading zero *abstract* bits. uint32_t LeadingZeros() const { constexpr int total_significant_bits = SignificantBits << Shift; constexpr int extra_bits = sizeof(T) * 8 - total_significant_bits; @@ -1361,7 +1361,7 @@ ABSL_ATTRIBUTE_NOINLINE void InitializeSlots(CommonFields& c, Alloc alloc) { struct PolicyFunctions { size_t slot_size; - // Return the hash of the pointed-to slot. + // Returns the hash of the pointed-to slot. size_t (*hash_slot)(void* set, void* slot); // Transfer the contents of src_slot to dst_slot. From 71ffb09f8c27849c7e92595b5ac883b1ec45b95e Mon Sep 17 00:00:00 2001 From: Paul Wankadia Date: Thu, 1 Jun 2023 00:42:54 -0700 Subject: [PATCH 0040/1238] Update Abseil to RE2 release `2023-06-01`. Note that RE2 has taken a dependency on Abseil, so the `main` branch should be used from now on. The `abseil` branch will go away soon... PiperOrigin-RevId: 536941231 Change-Id: I502fc643a3763de51292396297b0939613473485 --- WORKSPACE | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index ce8e8596663..19e1385c7bc 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -28,13 +28,11 @@ http_archive( ) # RE2 (the regular expression library used by GoogleTest) -# Note this must use a commit from the `abseil` branch of the RE2 project. -# https://github.com/google/re2/tree/abseil http_archive( name = "com_googlesource_code_re2", - sha256 = "0a890c2aa0bb05b2ce906a15efb520d0f5ad4c7d37b8db959c43772802991887", - strip_prefix = "re2-a427f10b9fb4622dd6d8643032600aa1b50fbd12", - urls = ["https://github.com/google/re2/archive/a427f10b9fb4622dd6d8643032600aa1b50fbd12.zip"], # 2022-06-09 + sha256 = "1726508efc93a50854c92e3f7ac66eb28f0e57652e413f11d7c1e28f97d997ba", + strip_prefix = "re2-03da4fc0857c285e3a26782f6bc8931c4c950df4", + urls = ["https://github.com/google/re2/archive/03da4fc0857c285e3a26782f6bc8931c4c950df4.zip"], # 2023-06-01 ) # Google benchmark. From e9bb35cea3d3b18bdaaa273f6e1746d9334aa324 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 1 Jun 2023 13:51:36 -0700 Subject: [PATCH 0041/1238] Adding support for int128 and uint128 flag types PiperOrigin-RevId: 537120102 Change-Id: I7952e53aca10319eb433e4c4d60cf3d7fe74d19a --- absl/flags/BUILD.bazel | 1 + absl/flags/CMakeLists.txt | 1 + absl/flags/marshalling.cc | 27 +++++++ absl/flags/marshalling.h | 3 + absl/flags/marshalling_test.cc | 137 +++++++++++++++++++++++++++++++++ 5 files changed, 169 insertions(+) diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel index 627f453a77c..583e6d94413 100644 --- a/absl/flags/BUILD.bazel +++ b/absl/flags/BUILD.bazel @@ -99,6 +99,7 @@ cc_library( "//absl/base:config", "//absl/base:core_headers", "//absl/base:log_severity", + "//absl/numeric:int128", "//absl/strings", "//absl/strings:str_format", "//absl/types:optional", diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt index b9d3b97b847..6525eb2adcc 100644 --- a/absl/flags/CMakeLists.txt +++ b/absl/flags/CMakeLists.txt @@ -87,6 +87,7 @@ absl_cc_library( absl::config absl::core_headers absl::log_severity + absl::int128 absl::optional absl::strings absl::str_format diff --git a/absl/flags/marshalling.cc b/absl/flags/marshalling.cc index 81f9cebd6f4..cf6312b1f19 100644 --- a/absl/flags/marshalling.cc +++ b/absl/flags/marshalling.cc @@ -26,6 +26,7 @@ #include "absl/base/config.h" #include "absl/base/log_severity.h" #include "absl/base/macros.h" +#include "absl/numeric/int128.h" #include "absl/strings/ascii.h" #include "absl/strings/match.h" #include "absl/strings/numbers.h" @@ -125,6 +126,32 @@ bool AbslParseFlag(absl::string_view text, unsigned long long* dst, return ParseFlagImpl(text, *dst); } +bool AbslParseFlag(absl::string_view text, absl::int128* dst, std::string*) { + text = absl::StripAsciiWhitespace(text); + + // check hex + int base = NumericBase(text); + if (!absl::numbers_internal::safe_strto128_base(text, dst, base)) { + return false; + } + + return base == 16 ? absl::SimpleHexAtoi(text, dst) + : absl::SimpleAtoi(text, dst); +} + +bool AbslParseFlag(absl::string_view text, absl::uint128* dst, std::string*) { + text = absl::StripAsciiWhitespace(text); + + // check hex + int base = NumericBase(text); + if (!absl::numbers_internal::safe_strtou128_base(text, dst, base)) { + return false; + } + + return base == 16 ? absl::SimpleHexAtoi(text, dst) + : absl::SimpleAtoi(text, dst); +} + // -------------------------------------------------------------------- // AbslParseFlag for floating point types. diff --git a/absl/flags/marshalling.h b/absl/flags/marshalling.h index 325e75e5163..21d955d5235 100644 --- a/absl/flags/marshalling.h +++ b/absl/flags/marshalling.h @@ -200,6 +200,7 @@ #define ABSL_FLAGS_MARSHALLING_H_ #include "absl/base/config.h" +#include "absl/numeric/int128.h" #if defined(ABSL_HAVE_STD_OPTIONAL) && !defined(ABSL_USES_STD_OPTIONAL) #include @@ -233,6 +234,8 @@ bool AbslParseFlag(absl::string_view, unsigned long*, std::string*); // NOLINT bool AbslParseFlag(absl::string_view, long long*, std::string*); // NOLINT bool AbslParseFlag(absl::string_view, unsigned long long*, // NOLINT std::string*); +bool AbslParseFlag(absl::string_view, absl::int128*, std::string*); // NOLINT +bool AbslParseFlag(absl::string_view, absl::uint128*, std::string*); // NOLINT bool AbslParseFlag(absl::string_view, float*, std::string*); bool AbslParseFlag(absl::string_view, double*, std::string*); bool AbslParseFlag(absl::string_view, std::string*, std::string*); diff --git a/absl/flags/marshalling_test.cc b/absl/flags/marshalling_test.cc index 7b6d2ad5cf0..d996ca7f5a2 100644 --- a/absl/flags/marshalling_test.cc +++ b/absl/flags/marshalling_test.cc @@ -455,6 +455,143 @@ TEST(MarshallingTest, TestUInt64Parsing) { // -------------------------------------------------------------------- +TEST(MarshallingTest, TestInt128Parsing) { + std::string err; + absl::int128 value; + + absl::int128 zero = 0; + absl::int128 one = 1; + absl::int128 neg_one = -1; + absl::int128 hundred = 100; + absl::int128 hundreds_val = 123; + absl::int128 neg_thousands_val = -98765; + absl::int128 pos_three = 3; + + // Decimal values. + EXPECT_TRUE(absl::ParseFlag("0", &value, &err)); + EXPECT_EQ(value, zero); + EXPECT_TRUE(absl::ParseFlag("1", &value, &err)); + EXPECT_EQ(value, one); + EXPECT_TRUE(absl::ParseFlag("-1", &value, &err)); + EXPECT_EQ(value, neg_one); + EXPECT_TRUE(absl::ParseFlag("123", &value, &err)); + EXPECT_EQ(value, hundreds_val); + EXPECT_TRUE(absl::ParseFlag("-98765", &value, &err)); + EXPECT_EQ(value, neg_thousands_val); + EXPECT_TRUE(absl::ParseFlag("+3", &value, &err)); + EXPECT_EQ(value, pos_three); + + // Leading zero values. + EXPECT_TRUE(absl::ParseFlag("01", &value, &err)); + EXPECT_EQ(value, one); + EXPECT_TRUE(absl::ParseFlag("001", &value, &err)); + EXPECT_EQ(value, one); + EXPECT_TRUE(absl::ParseFlag("0000100", &value, &err)); + EXPECT_EQ(value, hundred); + + absl::int128 sixteen = 16; + absl::int128 quintillion_val = 1152827684197027293; + absl::int128 quintillion_val2 = + absl::MakeInt128(0x000000000000fff, 0xFFFFFFFFFFFFFFF); + + // Hex values. + EXPECT_TRUE(absl::ParseFlag("0x10", &value, &err)); + EXPECT_EQ(value, sixteen); + EXPECT_TRUE(absl::ParseFlag("0xFFFAAABBBCCCDDD", &value, &err)); + EXPECT_EQ(value, quintillion_val); + EXPECT_TRUE(absl::ParseFlag("0xFFF0FFFFFFFFFFFFFFF", &value, &err)); + EXPECT_EQ(value, quintillion_val2); + + // TODO(b/285183223): Add support for parsing negative hex representation + + // Whitespace handling + EXPECT_TRUE(absl::ParseFlag("16 ", &value, &err)); + EXPECT_EQ(value, sixteen); + EXPECT_TRUE(absl::ParseFlag(" 16", &value, &err)); + EXPECT_EQ(value, sixteen); + EXPECT_TRUE(absl::ParseFlag(" 0100 ", &value, &err)); + EXPECT_EQ(value, hundred); + EXPECT_TRUE(absl::ParseFlag(" 0x7B ", &value, &err)); + EXPECT_EQ(value, hundreds_val); // =123 + + // Invalid values. + EXPECT_FALSE(absl::ParseFlag("", &value, &err)); + EXPECT_FALSE(absl::ParseFlag(" ", &value, &err)); + EXPECT_FALSE(absl::ParseFlag(" ", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("--1", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("\n", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("\t", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("2U", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("FFF", &value, &err)); +} + +// -------------------------------------------------------------------- + +TEST(MarshallingTest, TestUint128Parsing) { + std::string err; + absl::uint128 value; + + absl::uint128 zero = 0; + absl::uint128 one = 1; + absl::uint128 hundred = 100; + absl::uint128 hundreds_val = 123; + absl::uint128 pos_three = 3; + + // Decimal values. + EXPECT_TRUE(absl::ParseFlag("0", &value, &err)); + EXPECT_EQ(value, zero); + EXPECT_TRUE(absl::ParseFlag("1", &value, &err)); + EXPECT_EQ(value, one); + EXPECT_TRUE(absl::ParseFlag("123", &value, &err)); + EXPECT_EQ(value, hundreds_val); + EXPECT_TRUE(absl::ParseFlag("+3", &value, &err)); + EXPECT_EQ(value, pos_three); + + // Leading zero values. + EXPECT_TRUE(absl::ParseFlag("01", &value, &err)); + EXPECT_EQ(value, one); + EXPECT_TRUE(absl::ParseFlag("001", &value, &err)); + EXPECT_EQ(value, one); + EXPECT_TRUE(absl::ParseFlag("0000100", &value, &err)); + EXPECT_EQ(value, hundred); + + absl::uint128 sixteen = 16; + absl::uint128 quintillion_val = 1152827684197027293; + absl::uint128 quintillion_val2 = + absl::MakeInt128(0x000000000000fff, 0xFFFFFFFFFFFFFFF); + + // Hex values. + EXPECT_TRUE(absl::ParseFlag("0x10", &value, &err)); + EXPECT_EQ(value, sixteen); + EXPECT_TRUE(absl::ParseFlag("0xFFFAAABBBCCCDDD", &value, &err)); + EXPECT_EQ(value, quintillion_val); + EXPECT_TRUE(absl::ParseFlag("0xFFF0FFFFFFFFFFFFFFF", &value, &err)); + EXPECT_EQ(value, quintillion_val2); + + // Whitespace handling + EXPECT_TRUE(absl::ParseFlag("16 ", &value, &err)); + EXPECT_EQ(value, sixteen); + EXPECT_TRUE(absl::ParseFlag(" 16", &value, &err)); + EXPECT_EQ(value, sixteen); + EXPECT_TRUE(absl::ParseFlag(" 0100 ", &value, &err)); + EXPECT_EQ(value, hundred); + EXPECT_TRUE(absl::ParseFlag(" 0x7B ", &value, &err)); + EXPECT_EQ(value, hundreds_val); // =123 + + // Invalid values. + EXPECT_FALSE(absl::ParseFlag("", &value, &err)); + EXPECT_FALSE(absl::ParseFlag(" ", &value, &err)); + EXPECT_FALSE(absl::ParseFlag(" ", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("-1", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("--1", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("\n", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("\t", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("2U", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("FFF", &value, &err)); +} + +// -------------------------------------------------------------------- + TEST(MarshallingTest, TestFloatParsing) { std::string err; float value; From 55de7357c7f0e1af6bb7d61b924a9a9315cc1e81 Mon Sep 17 00:00:00 2001 From: Dino Radakovic Date: Fri, 2 Jun 2023 11:57:32 -0700 Subject: [PATCH 0042/1238] `absl`: Replace `absl::remove_cv_t>` with `absl::remove_cvref_t` PiperOrigin-RevId: 537372070 Change-Id: I46ff6e42856aea2cd8da6ff7105cf58613603dd4 --- absl/status/internal/statusor_internal.h | 36 ++++++++---------------- absl/status/statusor.h | 8 ++---- 2 files changed, 15 insertions(+), 29 deletions(-) diff --git a/absl/status/internal/statusor_internal.h b/absl/status/internal/statusor_internal.h index eaac2c0b14c..49cead7a7f8 100644 --- a/absl/status/internal/statusor_internal.h +++ b/absl/status/internal/statusor_internal.h @@ -69,11 +69,8 @@ using IsConstructibleOrConvertibleOrAssignableFromStatusOr = template struct IsDirectInitializationAmbiguous : public absl::conditional_t< - std::is_same>, - U>::value, - std::false_type, - IsDirectInitializationAmbiguous< - T, absl::remove_cv_t>>> {}; + std::is_same, U>::value, std::false_type, + IsDirectInitializationAmbiguous>> {}; template struct IsDirectInitializationAmbiguous> @@ -84,14 +81,11 @@ struct IsDirectInitializationAmbiguous> template using IsDirectInitializationValid = absl::disjunction< // Short circuits if T is basically U. - std::is_same>>, + std::is_same>, absl::negation, - absl::remove_cv_t>>, - std::is_same>>, - std::is_same>>, + std::is_same, absl::remove_cvref_t>, + std::is_same>, + std::is_same>, IsDirectInitializationAmbiguous>>>; // This trait detects whether `StatusOr::operator=(U&&)` is ambiguous, which @@ -107,11 +101,8 @@ using IsDirectInitializationValid = absl::disjunction< template struct IsForwardingAssignmentAmbiguous : public absl::conditional_t< - std::is_same>, - U>::value, - std::false_type, - IsForwardingAssignmentAmbiguous< - T, absl::remove_cv_t>>> {}; + std::is_same, U>::value, std::false_type, + IsForwardingAssignmentAmbiguous>> {}; template struct IsForwardingAssignmentAmbiguous> @@ -122,14 +113,11 @@ struct IsForwardingAssignmentAmbiguous> template using IsForwardingAssignmentValid = absl::disjunction< // Short circuits if T is basically U. - std::is_same>>, + std::is_same>, absl::negation, - absl::remove_cv_t>>, - std::is_same>>, - std::is_same>>, + std::is_same, absl::remove_cvref_t>, + std::is_same>, + std::is_same>, IsForwardingAssignmentAmbiguous>>>; class Helper { diff --git a/absl/status/statusor.h b/absl/status/statusor.h index 935366d5561..54c7ce023f6 100644 --- a/absl/status/statusor.h +++ b/absl/status/statusor.h @@ -411,7 +411,7 @@ class StatusOr : private internal_statusor::StatusOrData, typename = typename std::enable_if, std::is_assignable, absl::disjunction< - std::is_same>, T>, + std::is_same, T>, absl::conjunction< absl::negation>, absl::negation, internal_statusor::IsDirectInitializationValid, std::is_constructible, std::is_convertible, absl::disjunction< - std::is_same>, - T>, + std::is_same, T>, absl::conjunction< absl::negation>, absl::negation< @@ -461,8 +460,7 @@ class StatusOr : private internal_statusor::StatusOrData, absl::conjunction< internal_statusor::IsDirectInitializationValid, absl::disjunction< - std::is_same>, - T>, + std::is_same, T>, absl::conjunction< absl::negation>, absl::negation< From 77ba7ca9d2a523ef9f1837e53554fa65c232abc8 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 2 Jun 2023 13:49:30 -0700 Subject: [PATCH 0043/1238] Lifetime checks for `absl::StrSplit()` PiperOrigin-RevId: 537400816 Change-Id: I06794a6b8b6a441e34121047024380190d42869a --- absl/strings/internal/str_split_internal.h | 62 +++++++++++++++++++--- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/absl/strings/internal/str_split_internal.h b/absl/strings/internal/str_split_internal.h index 35edf3aa439..081ad85ad43 100644 --- a/absl/strings/internal/str_split_internal.h +++ b/absl/strings/internal/str_split_internal.h @@ -235,6 +235,24 @@ struct SplitterIsConvertibleTo HasMappedType::value> { }; +template +struct ShouldUseLifetimeBound : std::false_type {}; + +template +struct ShouldUseLifetimeBound< + StringType, Container, + std::enable_if_t< + std::is_same::value && + std::is_same::value>> + : std::true_type {}; + +template +using ShouldUseLifetimeBoundForPair = std::integral_constant< + bool, std::is_same::value && + (std::is_same::value || + std::is_same::value)>; + + // This class implements the range that is returned by absl::StrSplit(). This // class has templated conversion operators that allow it to be implicitly // converted to a variety of types that the caller may have specified on the @@ -281,10 +299,24 @@ class Splitter { // An implicit conversion operator that is restricted to only those containers // that the splitter is convertible to. - template ::value>::type> - operator Container() const { // NOLINT(runtime/explicit) + template < + typename Container, + std::enable_if_t::value && + SplitterIsConvertibleTo::value, + std::nullptr_t> = nullptr> + // NOLINTNEXTLINE(google-explicit-constructor) + operator Container() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + return ConvertToContainer::value>()(*this); + } + + template < + typename Container, + std::enable_if_t::value && + SplitterIsConvertibleTo::value, + std::nullptr_t> = nullptr> + // NOLINTNEXTLINE(google-explicit-constructor) + operator Container() const { return ConvertToContainer::value>()(*this); } @@ -293,8 +325,27 @@ class Splitter { // strings returned by the begin() iterator. Either/both of .first and .second // will be constructed with empty strings if the iterator doesn't have a // corresponding value. + template ::value, + std::nullptr_t> = nullptr> + // NOLINTNEXTLINE(google-explicit-constructor) + operator std::pair() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + return ConvertToPair(); + } + + template ::value, + std::nullptr_t> = nullptr> + // NOLINTNEXTLINE(google-explicit-constructor) + operator std::pair() const { + return ConvertToPair(); + } + + private: template - operator std::pair() const { // NOLINT(runtime/explicit) + std::pair ConvertToPair() const { absl::string_view first, second; auto it = begin(); if (it != end()) { @@ -306,7 +357,6 @@ class Splitter { return {First(first), Second(second)}; } - private: // ConvertToContainer is a functor converting a Splitter to the requested // Container of ValueType. It is specialized below to optimize splitting to // certain combinations of Container and ValueType. From f6c72c3ce81d8d050c6c051032a8a2a53a4de74e Mon Sep 17 00:00:00 2001 From: Silvio Traversaro Date: Sun, 4 Jun 2023 12:52:15 +0200 Subject: [PATCH 0044/1238] CMake: Add absl::abseil_dll ALIAS target for abseil_dll --- CMake/AbseilDll.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index 8e6e21dcdf5..624a9c99a5e 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake @@ -815,4 +815,6 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n") LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) + + add_library(absl::${_dll} ALIAS ${_dll}) endfunction() From 7a74153a05aa8bacb8cb9ae3fa707e5407adc2c9 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 5 Jun 2023 03:36:06 -0700 Subject: [PATCH 0045/1238] Import of CCTZ from GitHub. PiperOrigin-RevId: 537825067 Change-Id: I3ce8712d5130068fb7d77b563eb502e2e9560810 --- absl/time/internal/cctz/src/time_zone_lookup.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/absl/time/internal/cctz/src/time_zone_lookup.cc b/absl/time/internal/cctz/src/time_zone_lookup.cc index 68084ce29e5..9a30ba5e0c8 100644 --- a/absl/time/internal/cctz/src/time_zone_lookup.cc +++ b/absl/time/internal/cctz/src/time_zone_lookup.cc @@ -148,11 +148,12 @@ std::string win32_local_time_zone(const HMODULE combase) { UINT32 wlen; const PCWSTR tz_wstr = windows_get_string_raw_buffer(tz_hstr, &wlen); if (tz_wstr) { - const int size = WideCharToMultiByte(CP_UTF8, 0, tz_wstr, wlen, nullptr, - 0, nullptr, nullptr); - result.resize(size); - WideCharToMultiByte(CP_UTF8, 0, tz_wstr, wlen, &result[0], size, nullptr, - nullptr); + const int size = + WideCharToMultiByte(CP_UTF8, 0, tz_wstr, static_cast(wlen), + nullptr, 0, nullptr, nullptr); + result.resize(static_cast(size)); + WideCharToMultiByte(CP_UTF8, 0, tz_wstr, static_cast(wlen), + &result[0], size, nullptr, nullptr); } windows_delete_string(tz_hstr); } From 66406fdf1553de6ad672576167e7cc7ca2d764cb Mon Sep 17 00:00:00 2001 From: Greg Falcon Date: Mon, 5 Jun 2023 14:27:37 -0700 Subject: [PATCH 0046/1238] Add a unit test that captures the current behavior of formatting of char types and char-backed enum types through StrCat(), StrFormat("%v"), and Substitute(). This test allows us to modify the behavior in this space without introducing undesired changes elsewhere. PiperOrigin-RevId: 537981963 Change-Id: Icda91b66efcc0dc8c263011b137e130a3db2dc19 --- absl/strings/BUILD.bazel | 12 ++ absl/strings/CMakeLists.txt | 14 ++ absl/strings/char_formatting_test.cc | 189 +++++++++++++++++++++++++++ 3 files changed, 215 insertions(+) create mode 100644 absl/strings/char_formatting_test.cc diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index bd33c533b2d..4a111b5a375 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -1319,3 +1319,15 @@ cc_binary( "//absl/types:optional", ], ) + +cc_test( + name = "char_formatting_test", + srcs = [ + "char_formatting_test.cc", + ], + deps = [ + ":str_format", + ":strings", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index 9aaa7932b2b..2ad052a3607 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt @@ -548,6 +548,20 @@ absl_cc_test( GTest::gmock_main ) +absl_cc_test( + NAME + char_formatting_test + SRCS + "char_formatting_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::base + absl::str_format + absl::strings + GTest::gmock_main +) + # Internal-only target, do not depend on directly. absl_cc_library( NAME diff --git a/absl/strings/char_formatting_test.cc b/absl/strings/char_formatting_test.cc new file mode 100644 index 00000000000..60416af3ec2 --- /dev/null +++ b/absl/strings/char_formatting_test.cc @@ -0,0 +1,189 @@ +// Copyright 2023 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "gtest/gtest.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" +#include "absl/strings/substitute.h" + +namespace { + +TEST(CharFormatting, Char) { + const char v = 'A'; + + // Desired behavior: does not compile: + // EXPECT_EQ(absl::StrCat(v, "B"), "AB"); + // EXPECT_EQ(absl::StrFormat("%vB", v), "AB"); + + // Legacy behavior: format as char: + EXPECT_EQ(absl::Substitute("$0B", v), "AB"); +} + +enum CharEnum : char {}; +TEST(CharFormatting, CharEnum) { + auto v = static_cast('A'); + + // Desired behavior: format as decimal + // (No APIs do this today.) + + // BUG: internally fails + EXPECT_EQ(absl::StrFormat("%vB", v), ""); + + // Legacy behavior: does not compile: + // EXPECT_EQ(absl::StrCat(ch, "B"), "AB"); + + // Legacy behavior: format as character: + + // Some older versions of gcc behave differently in this one case. +#if !defined(__GNUC__) || defined(__clang__) + EXPECT_EQ(absl::Substitute("$0B", v), "AB"); +#endif +} + +enum class CharEnumClass: char {}; +TEST(CharFormatting, CharEnumClass) { + auto v = static_cast('A'); + + // Desired behavior: format as decimal + // (No APIs do this today.) + + // BUG: internally fails + EXPECT_EQ(absl::StrFormat("%vB", v), ""); + + // Legacy behavior: does not compile: + // EXPECT_EQ(absl::StrCat(ch, "B"), "AB"); + + // Legacy behavior: format as character: + EXPECT_EQ(absl::Substitute("$0B", v), "AB"); +} + +TEST(CharFormatting, UnsignedChar) { + const unsigned char v = 'A'; + + // Desired behavior: format as decimal: + EXPECT_EQ(absl::StrCat(v, "B"), "65B"); + EXPECT_EQ(absl::Substitute("$0B", v), "65B"); + + // Legacy behavior: does not compile: + // EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); + + // Signedness check + const unsigned char w = 255; + EXPECT_EQ(absl::StrCat(w, "B"), "255B"); + EXPECT_EQ(absl::Substitute("$0B", w), "255B"); + // EXPECT_EQ(absl::StrFormat("%vB", v), "255B"); +} + +TEST(CharFormatting, SignedChar) { + const signed char v = 'A'; + + // Desired behavior: format as decimal: + EXPECT_EQ(absl::StrCat(v, "B"), "65B"); + EXPECT_EQ(absl::Substitute("$0B", v), "65B"); + + // Legacy behavior: does not compile: + // EXPECT_EQ(absl::StrFormat("%vB", v), "AB"); + + // Signedness check + const signed char w = -128; + EXPECT_EQ(absl::StrCat(w, "B"), "-128B"); + EXPECT_EQ(absl::Substitute("$0B", w), "-128B"); +} + +enum UnsignedCharEnum : unsigned char {}; +TEST(CharFormatting, UnsignedCharEnum) { + auto v = static_cast('A'); + + // Desired behavior: format as decimal: + EXPECT_EQ(absl::StrCat(v, "B"), "65B"); + EXPECT_EQ(absl::Substitute("$0B", v), "65B"); + + // BUG: internally fails + EXPECT_EQ(absl::StrFormat("%vB", v), ""); + + // Signedness check + auto w = static_cast(255); + EXPECT_EQ(absl::StrCat(w, "B"), "255B"); + EXPECT_EQ(absl::Substitute("$0B", w), "255B"); +} + +enum SignedCharEnum : signed char {}; +TEST(CharFormatting, SignedCharEnum) { + auto v = static_cast('A'); + + // Desired behavior: format as decimal: + EXPECT_EQ(absl::StrCat(v, "B"), "65B"); + EXPECT_EQ(absl::Substitute("$0B", v), "65B"); + + // BUG: internally fails + EXPECT_EQ(absl::StrFormat("%vB", v), ""); + + // Signedness check + auto w = static_cast(-128); + EXPECT_EQ(absl::StrCat(w, "B"), "-128B"); + EXPECT_EQ(absl::Substitute("$0B", w), "-128B"); +} + +enum class UnsignedCharEnumClass : unsigned char {}; +TEST(CharFormatting, UnsignedCharEnumClass) { + auto v = static_cast('A'); + + // Desired behavior: format as decimal: + EXPECT_EQ(absl::StrCat(v, "B"), "65B"); + EXPECT_EQ(absl::Substitute("$0B", v), "65B"); + + // BUG: internally fails + EXPECT_EQ(absl::StrFormat("%vB", v), ""); + + // Signedness check + auto w = static_cast(255); + EXPECT_EQ(absl::StrCat(w, "B"), "255B"); + EXPECT_EQ(absl::Substitute("$0B", w), "255B"); +} + +enum SignedCharEnumClass : signed char {}; +TEST(CharFormatting, SignedCharEnumClass) { + auto v = static_cast('A'); + + // Desired behavior: format as decimal: + EXPECT_EQ(absl::StrCat(v, "B"), "65B"); + EXPECT_EQ(absl::Substitute("$0B", v), "65B"); + + // BUG: internally fails + EXPECT_EQ(absl::StrFormat("%vB", v), ""); + + // Signedness check + auto w = static_cast(-128); + EXPECT_EQ(absl::StrCat(w, "B"), "-128B"); + EXPECT_EQ(absl::Substitute("$0B", w), "-128B"); +} + +#ifdef __cpp_lib_byte +TEST(CharFormatting, StdByte) { + auto v = static_cast('A'); + // Desired behavior: format as 0xff + // (No APIs do this today.) + + // BUG: internally fails + EXPECT_EQ(absl::StrFormat("%vB", v), ""); + + // Legacy behavior: format as decimal: + EXPECT_EQ(absl::StrCat(v, "B"), "65B"); + EXPECT_EQ(absl::Substitute("$0B", v), "65B"); +} +#endif // _cpp_lib_byte + +} // namespace From c3b5a293aa684130320523b2dab63c8a2bb10fec Mon Sep 17 00:00:00 2001 From: Romain Geissler Date: Mon, 5 Jun 2023 10:12:12 +0000 Subject: [PATCH 0047/1238] Silence std::aligned_storage warnings in C++23 mode. This is only a workaround, working only with gcc/clang, while waiting for a better long term fix not using std::aligned_storage, which is tracked by b/260219225. --- absl/meta/type_traits.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h index abaf96afc28..d5da93f3447 100644 --- a/absl/meta/type_traits.h +++ b/absl/meta/type_traits.h @@ -40,6 +40,7 @@ #include #include "absl/base/config.h" +#include "absl/base/attributes.h" // Defines the default alignment. `__STDCPP_DEFAULT_NEW_ALIGNMENT__` is a C++17 // feature. @@ -278,6 +279,7 @@ using remove_extent_t = typename std::remove_extent::type; template using remove_all_extents_t = typename std::remove_all_extents::type; +ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING namespace type_traits_internal { // This trick to retrieve a default alignment is necessary for our // implementation of aligned_storage_t to be consistent with any @@ -296,6 +298,7 @@ struct default_alignment_of_aligned_storage< template ::value> using aligned_storage_t = typename std::aligned_storage::type; +ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING template using decay_t = typename std::decay::type; From 1285ca4b4f06e40ca0238bde7197e0cb3648a451 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 6 Jun 2023 11:23:59 -0700 Subject: [PATCH 0048/1238] Import of CCTZ from GitHub. PiperOrigin-RevId: 538241594 Change-Id: Ie6f0d913bcf07dea2f33e47198ba952b3800d70e --- absl/time/internal/cctz/src/time_zone_if.cc | 2 + absl/time/internal/cctz/src/time_zone_libc.cc | 61 ++++++++++--------- .../cctz/src/time_zone_lookup_test.cc | 21 +++++-- 3 files changed, 49 insertions(+), 35 deletions(-) diff --git a/absl/time/internal/cctz/src/time_zone_if.cc b/absl/time/internal/cctz/src/time_zone_if.cc index 0319b2f98e6..1d44dde7f28 100644 --- a/absl/time/internal/cctz/src/time_zone_if.cc +++ b/absl/time/internal/cctz/src/time_zone_if.cc @@ -26,6 +26,8 @@ namespace cctz { std::unique_ptr TimeZoneIf::Load(const std::string& name) { // Support "libc:localtime" and "libc:*" to access the legacy // localtime and UTC support respectively from the C library. + // NOTE: The "libc:*" zones are internal, test-only interfaces, and + // are subject to change/removal without notice. Do not use them. if (name.compare(0, 5, "libc:") == 0) { return std::unique_ptr(new TimeZoneLibC(name.substr(5))); } diff --git a/absl/time/internal/cctz/src/time_zone_libc.cc b/absl/time/internal/cctz/src/time_zone_libc.cc index 887dd097c65..af9f063e21c 100644 --- a/absl/time/internal/cctz/src/time_zone_libc.cc +++ b/absl/time/internal/cctz/src/time_zone_libc.cc @@ -125,31 +125,30 @@ inline std::tm* local_time(const std::time_t* timep, std::tm* result) { #endif } -// Converts a civil second and "dst" flag into a time_t and UTC offset. +// Converts a civil second and "dst" flag into a time_t and a struct tm. // Returns false if time_t cannot represent the requested civil second. // Caller must have already checked that cs.year() will fit into a tm_year. -bool make_time(const civil_second& cs, int is_dst, std::time_t* t, int* off) { - std::tm tm; - tm.tm_year = static_cast(cs.year() - year_t{1900}); - tm.tm_mon = cs.month() - 1; - tm.tm_mday = cs.day(); - tm.tm_hour = cs.hour(); - tm.tm_min = cs.minute(); - tm.tm_sec = cs.second(); - tm.tm_isdst = is_dst; - *t = std::mktime(&tm); +bool make_time(const civil_second& cs, int is_dst, std::time_t* t, + std::tm* tm) { + tm->tm_year = static_cast(cs.year() - year_t{1900}); + tm->tm_mon = cs.month() - 1; + tm->tm_mday = cs.day(); + tm->tm_hour = cs.hour(); + tm->tm_min = cs.minute(); + tm->tm_sec = cs.second(); + tm->tm_isdst = is_dst; + *t = std::mktime(tm); if (*t == std::time_t{-1}) { std::tm tm2; const std::tm* tmp = local_time(t, &tm2); - if (tmp == nullptr || tmp->tm_year != tm.tm_year || - tmp->tm_mon != tm.tm_mon || tmp->tm_mday != tm.tm_mday || - tmp->tm_hour != tm.tm_hour || tmp->tm_min != tm.tm_min || - tmp->tm_sec != tm.tm_sec) { + if (tmp == nullptr || tmp->tm_year != tm->tm_year || + tmp->tm_mon != tm->tm_mon || tmp->tm_mday != tm->tm_mday || + tmp->tm_hour != tm->tm_hour || tmp->tm_min != tm->tm_min || + tmp->tm_sec != tm->tm_sec) { // A true error (not just one second before the epoch). return false; } } - *off = static_cast(tm_gmtoff(tm)); return true; } @@ -254,33 +253,37 @@ time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const { // We probe with "is_dst" values of 0 and 1 to try to distinguish unique // civil seconds from skipped or repeated ones. This is not always possible // however, as the "dst" flag does not change over some offset transitions. - // We are also subject to the vagaries of mktime() implementations. + // We are also subject to the vagaries of mktime() implementations. For + // example, some implementations treat "tm_isdst" as a demand (useless), + // and some as a disambiguator (useful). std::time_t t0, t1; - int offset0, offset1; - if (make_time(cs, 0, &t0, &offset0) && make_time(cs, 1, &t1, &offset1)) { - if (t0 == t1) { + std::tm tm0, tm1; + if (make_time(cs, 0, &t0, &tm0) && make_time(cs, 1, &t1, &tm1)) { + if (tm0.tm_isdst == tm1.tm_isdst) { // The civil time was singular (pre == trans == post). - const time_point tp = FromUnixSeconds(t0); + const time_point tp = FromUnixSeconds(tm0.tm_isdst ? t1 : t0); return {time_zone::civil_lookup::UNIQUE, tp, tp, tp}; } - if (t0 > t1) { + int offset = tm_gmtoff(tm0); + if (t0 < t1) { // negative DST std::swap(t0, t1); - std::swap(offset0, offset1); + offset = tm_gmtoff(tm1); } - const std::time_t tt = find_trans(t0, t1, offset1); + + const std::time_t tt = find_trans(t1, t0, offset); const time_point trans = FromUnixSeconds(tt); - if (offset0 < offset1) { + if (tm0.tm_isdst) { // The civil time did not exist (pre >= trans > post). - const time_point pre = FromUnixSeconds(t1); - const time_point post = FromUnixSeconds(t0); + const time_point pre = FromUnixSeconds(t0); + const time_point post = FromUnixSeconds(t1); return {time_zone::civil_lookup::SKIPPED, pre, trans, post}; } // The civil time was ambiguous (pre < trans <= post). - const time_point pre = FromUnixSeconds(t0); - const time_point post = FromUnixSeconds(t1); + const time_point pre = FromUnixSeconds(t1); + const time_point post = FromUnixSeconds(t0); return {time_zone::civil_lookup::REPEATED, pre, trans, post}; } diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc index 4b093b37837..38f10f48ecc 100644 --- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc +++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc @@ -1034,16 +1034,16 @@ TEST(MakeTime, SysSecondsLimits) { const time_zone cut = LoadZone("libc:UTC"); const year_t max_tm_year = year_t{std::numeric_limits::max()} + 1900; tp = convert(civil_second(max_tm_year, 12, 31, 23, 59, 59), cut); -#if defined(__FreeBSD__) || defined(__OpenBSD__) - // The BSD gmtime_r() fails on extreme positive tm_year values. +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__) + // Some gmtime_r() impls fail on extreme positive values. #else EXPECT_EQ("2147485547-12-31T23:59:59+00:00", absl::time_internal::cctz::format(RFC3339, tp, cut)); #endif const year_t min_tm_year = year_t{std::numeric_limits::min()} + 1900; tp = convert(civil_second(min_tm_year, 1, 1, 0, 0, 0), cut); -#if defined(__Fuchsia__) - // Fuchsia's gmtime_r() fails on extreme negative values (fxbug.dev/78527). +#if defined(__Fuchsia__) || defined(__EMSCRIPTEN__) + // Some gmtime_r() impls fail on extreme negative values (fxbug.dev/78527). #else EXPECT_EQ("-2147481748-01-01T00:00:00+00:00", absl::time_internal::cctz::format(RFC3339, tp, cut)); @@ -1072,7 +1072,7 @@ TEST(MakeTime, LocalTimeLibC) { tp = zi.lookup(transition.to).trans) { const auto fcl = zi.lookup(transition.from); const auto tcl = zi.lookup(transition.to); - civil_second cs; // compare cs in zi and lc + civil_second cs, us; // compare cs and us in zi and lc if (fcl.kind == time_zone::civil_lookup::UNIQUE) { if (tcl.kind == time_zone::civil_lookup::UNIQUE) { // Both unique; must be an is_dst or abbr change. @@ -1088,12 +1088,14 @@ TEST(MakeTime, LocalTimeLibC) { } ASSERT_EQ(time_zone::civil_lookup::REPEATED, tcl.kind); cs = transition.to; + us = transition.from; } else { ASSERT_EQ(time_zone::civil_lookup::UNIQUE, tcl.kind); ASSERT_EQ(time_zone::civil_lookup::SKIPPED, fcl.kind); cs = transition.from; + us = transition.to; } - if (cs.year() > 2037) break; // limit test time (and to 32-bit time_t) + if (us.year() > 2037) break; // limit test time (and to 32-bit time_t) const auto cl_zi = zi.lookup(cs); if (zi.lookup(cl_zi.pre).is_dst == zi.lookup(cl_zi.post).is_dst) { // The "libc" implementation cannot correctly classify transitions @@ -1125,6 +1127,13 @@ TEST(MakeTime, LocalTimeLibC) { EXPECT_EQ(cl_zi.pre, cl_lc.pre); EXPECT_EQ(cl_zi.trans, cl_lc.trans); EXPECT_EQ(cl_zi.post, cl_lc.post); + const auto ucl_zi = zi.lookup(us); + const auto ucl_lc = lc.lookup(us); + SCOPED_TRACE(testing::Message() << "For " << us << " in " << *np); + EXPECT_EQ(ucl_zi.kind, ucl_lc.kind); + EXPECT_EQ(ucl_zi.pre, ucl_lc.pre); + EXPECT_EQ(ucl_zi.trans, ucl_lc.trans); + EXPECT_EQ(ucl_zi.post, ucl_lc.post); } } if (ep == nullptr) { From 86aaa72a33a9f6729d6cf3f7a8d551935cf5b5f8 Mon Sep 17 00:00:00 2001 From: Gennadiy Rozental Date: Wed, 7 Jun 2023 07:24:05 -0700 Subject: [PATCH 0049/1238] Update XML output to properly print special characters. Non printable characters are skipped in output. All the "whitespace-like" (including \t, \r, \n) characters printed as plain space ' '. PiperOrigin-RevId: 538479923 Change-Id: I62dff39bb21f376d00a7b9480f8f1d31d7015e45 --- absl/flags/internal/usage.cc | 11 +++++- absl/flags/internal/usage_test.cc | 63 +++++++++++++++++++++++-------- 2 files changed, 57 insertions(+), 17 deletions(-) diff --git a/absl/flags/internal/usage.cc b/absl/flags/internal/usage.cc index 6a56fce9555..13852e14678 100644 --- a/absl/flags/internal/usage.cc +++ b/absl/flags/internal/usage.cc @@ -92,8 +92,16 @@ class XMLElement { case '>': out << ">"; break; + case '\n': + case '\v': + case '\f': + case '\t': + out << " "; + break; default: - out << c; + if (IsValidXmlCharacter(static_cast(c))) { + out << c; + } break; } } @@ -102,6 +110,7 @@ class XMLElement { } private: + static bool IsValidXmlCharacter(unsigned char c) { return c >= 0x20; } absl::string_view tag_; absl::string_view txt_; }; diff --git a/absl/flags/internal/usage_test.cc b/absl/flags/internal/usage_test.cc index c3ab4a42d15..6847386f222 100644 --- a/absl/flags/internal/usage_test.cc +++ b/absl/flags/internal/usage_test.cc @@ -39,6 +39,8 @@ ABSL_FLAG(double, usage_reporting_test_flag_03, 1.03, "usage_reporting_test_flag_03 help message"); ABSL_FLAG(int64_t, usage_reporting_test_flag_04, 1000000000000004L, "usage_reporting_test_flag_04 help message"); +ABSL_FLAG(std::string, usage_reporting_test_flag_07, "\r\n\f\v\a\b\t ", + "usage_reporting_test_flag_07 help \r\n\f\v\a\b\t "); static const char kTestUsageMessage[] = "Custom usage message"; @@ -203,8 +205,12 @@ TEST_F(UsageReportingTest, TestFlagsHelpHRF) { Some more help. Even more long long long long long long long long long long long long help - message.); default: ""; + message.); default: "";)" + + "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 " + "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n" + R"( Try --helpfull to get a list of all flags or --help=substring shows help for flags which include specified substring in either in the name, or description or path. @@ -267,8 +273,9 @@ TEST_F(UsageReportingTest, TestUsageFlag_helpshort) { std::stringstream test_buf; EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), flags::HelpMode::kShort); - EXPECT_EQ(test_buf.str(), - R"(usage_test: Custom usage message + EXPECT_EQ( + test_buf.str(), + R"(usage_test: Custom usage message Flags from absl/flags/internal/usage_test.cc: --usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message); @@ -285,8 +292,12 @@ TEST_F(UsageReportingTest, TestUsageFlag_helpshort) { Some more help. Even more long long long long long long long long long long long long help - message.); default: ""; + message.); default: "";)" + + "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 " + "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n" + R"( Try --helpfull to get a list of all flags or --help=substring shows help for flags which include specified substring in either in the name, or description or path. @@ -301,8 +312,9 @@ TEST_F(UsageReportingTest, TestUsageFlag_help_simple) { std::stringstream test_buf; EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), flags::HelpMode::kImportant); - EXPECT_EQ(test_buf.str(), - R"(usage_test: Custom usage message + EXPECT_EQ( + test_buf.str(), + R"(usage_test: Custom usage message Flags from absl/flags/internal/usage_test.cc: --usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message); @@ -319,8 +331,12 @@ TEST_F(UsageReportingTest, TestUsageFlag_help_simple) { Some more help. Even more long long long long long long long long long long long long help - message.); default: ""; + message.); default: "";)" + + "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 " + "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n" + R"( Try --helpfull to get a list of all flags or --help=substring shows help for flags which include specified substring in either in the name, or description or path. @@ -361,8 +377,9 @@ TEST_F(UsageReportingTest, TestUsageFlag_help_multiple_flag) { std::stringstream test_buf; EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), flags::HelpMode::kMatch); - EXPECT_EQ(test_buf.str(), - R"(usage_test: Custom usage message + EXPECT_EQ( + test_buf.str(), + R"(usage_test: Custom usage message Flags from absl/flags/internal/usage_test.cc: --usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message); @@ -379,8 +396,12 @@ TEST_F(UsageReportingTest, TestUsageFlag_help_multiple_flag) { Some more help. Even more long long long long long long long long long long long long help - message.); default: ""; + message.); default: "";)" + + "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 " + "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n" + R"( Try --helpfull to get a list of all flags or --help=substring shows help for flags which include specified substring in either in the name, or description or path. @@ -395,8 +416,9 @@ TEST_F(UsageReportingTest, TestUsageFlag_helppackage) { std::stringstream test_buf; EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), flags::HelpMode::kPackage); - EXPECT_EQ(test_buf.str(), - R"(usage_test: Custom usage message + EXPECT_EQ( + test_buf.str(), + R"(usage_test: Custom usage message Flags from absl/flags/internal/usage_test.cc: --usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message); @@ -413,8 +435,12 @@ TEST_F(UsageReportingTest, TestUsageFlag_helppackage) { Some more help. Even more long long long long long long long long long long long long help - message.); default: ""; + message.); default: "";)" + "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 " + "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n" + + R"( Try --helpfull to get a list of all flags or --help=substring shows help for flags which include specified substring in either in the name, or description or path. @@ -471,8 +497,9 @@ path. std::stringstream test_buf_02; EXPECT_EQ(flags::HandleUsageFlags(test_buf_02, kTestUsageMessage), flags::HelpMode::kMatch); - EXPECT_EQ(test_buf_02.str(), - R"(usage_test: Custom usage message + EXPECT_EQ( + test_buf_02.str(), + R"(usage_test: Custom usage message Flags from absl/flags/internal/usage_test.cc: --usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message); @@ -489,8 +516,12 @@ path. Some more help. Even more long long long long long long long long long long long long help - message.); default: ""; + message.); default: "";)" + + "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 " + "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n" + R"( Try --helpfull to get a list of all flags or --help=substring shows help for flags which include specified substring in either in the name, or description or path. From bb6f5ff1c0ed895c008befa9fcef3834347c42a6 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Wed, 7 Jun 2023 10:50:25 -0700 Subject: [PATCH 0050/1238] Remove redundant redeclarations causing -Wredundant-decls warnings Fixes #1469 PiperOrigin-RevId: 538534014 Change-Id: Iab84f73c0a0665355b614e85c62f686dc54c8671 --- absl/numeric/int128_have_intrinsic.inc | 3 --- 1 file changed, 3 deletions(-) diff --git a/absl/numeric/int128_have_intrinsic.inc b/absl/numeric/int128_have_intrinsic.inc index 3945fa29837..6f1ac644141 100644 --- a/absl/numeric/int128_have_intrinsic.inc +++ b/absl/numeric/int128_have_intrinsic.inc @@ -162,9 +162,6 @@ inline int128::operator long double() const { } #else // Clang on PowerPC -// Forward declaration for conversion operators to floating point types. -constexpr int128 operator-(int128 v); -constexpr bool operator!=(int128 lhs, int128 rhs); inline int128::operator float() const { // We must convert the absolute value and then negate as needed, because From 872d99b48da314ed949770b9997bad404b73cb86 Mon Sep 17 00:00:00 2001 From: Bin Lan Date: Wed, 7 Jun 2023 15:40:52 +0800 Subject: [PATCH 0051/1238] Add VxWorks support --- absl/base/config.h | 9 +++++---- absl/debugging/internal/elf_mem_image.h | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/absl/base/config.h b/absl/base/config.h index 7d06e11c734..3cc46660069 100644 --- a/absl/base/config.h +++ b/absl/base/config.h @@ -412,7 +412,7 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || defined(__asmjs__) || defined(__wasm__) || defined(__Fuchsia__) || \ defined(__sun) || defined(__ASYLO__) || defined(__myriad2__) || \ defined(__HAIKU__) || defined(__OpenBSD__) || defined(__NetBSD__) || \ - defined(__QNX__) + defined(__QNX__) || defined(__VXWORKS__) #define ABSL_HAVE_MMAP 1 #endif @@ -424,7 +424,7 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #error ABSL_HAVE_PTHREAD_GETSCHEDPARAM cannot be directly set #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ defined(_AIX) || defined(__ros__) || defined(__OpenBSD__) || \ - defined(__NetBSD__) + defined(__NetBSD__) || defined(__VXWORKS__) #define ABSL_HAVE_PTHREAD_GETSCHEDPARAM 1 #endif @@ -443,7 +443,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || // POSIX.1-2001. #ifdef ABSL_HAVE_SCHED_YIELD #error ABSL_HAVE_SCHED_YIELD cannot be directly set -#elif defined(__linux__) || defined(__ros__) || defined(__native_client__) +#elif defined(__linux__) || defined(__ros__) || defined(__native_client__) || \ + defined(__VXWORKS__) #define ABSL_HAVE_SCHED_YIELD 1 #endif @@ -458,7 +459,7 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || // platforms. #ifdef ABSL_HAVE_SEMAPHORE_H #error ABSL_HAVE_SEMAPHORE_H cannot be directly set -#elif defined(__linux__) || defined(__ros__) +#elif defined(__linux__) || defined(__ros__) || defined(__VXWORKS__) #define ABSL_HAVE_SEMAPHORE_H 1 #endif diff --git a/absl/debugging/internal/elf_mem_image.h b/absl/debugging/internal/elf_mem_image.h index 5f4537ba3ca..8d95d0ba7c8 100644 --- a/absl/debugging/internal/elf_mem_image.h +++ b/absl/debugging/internal/elf_mem_image.h @@ -33,7 +33,8 @@ #if defined(__ELF__) && !defined(__OpenBSD__) && !defined(__QNX__) && \ !defined(__native_client__) && !defined(__asmjs__) && \ - !defined(__wasm__) && !defined(__HAIKU__) && !defined(__sun) + !defined(__wasm__) && !defined(__HAIKU__) && !defined(__sun) && \ + !defined(__VXWORKS__) #define ABSL_HAVE_ELF_MEM_IMAGE 1 #endif From 1524b1ac07c77f8c58e18a828b7efb92ff7a660e Mon Sep 17 00:00:00 2001 From: pateldeev Date: Thu, 8 Jun 2023 20:51:33 -0700 Subject: [PATCH 0052/1238] Use InlinedVector --- absl/strings/BUILD.bazel | 1 + absl/strings/internal/str_format/bind.h | 20 +++----------------- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index 4a111b5a375..313ba1ab7c3 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -1169,6 +1169,7 @@ cc_library( ":strings", "//absl/base:config", "//absl/base:core_headers", + "//absl/container:inlined_vector", "//absl/functional:function_ref", "//absl/meta:type_traits", "//absl/numeric:bits", diff --git a/absl/strings/internal/str_format/bind.h b/absl/strings/internal/str_format/bind.h index b73c50287c9..4424c4b06e9 100644 --- a/absl/strings/internal/str_format/bind.h +++ b/absl/strings/internal/str_format/bind.h @@ -21,6 +21,7 @@ #include #include "absl/base/port.h" +#include "absl/container/inlined_vector.h" #include "absl/strings/internal/str_format/arg.h" #include "absl/strings/internal/str_format/checker.h" #include "absl/strings/internal/str_format/parser.h" @@ -177,17 +178,7 @@ class Streamable { public: Streamable(const UntypedFormatSpecImpl& format, absl::Span args) - : format_(format) { - if (args.size() <= ABSL_ARRAYSIZE(few_args_)) { - for (size_t i = 0; i < args.size(); ++i) { - few_args_[i] = args[i]; - } - args_ = absl::MakeSpan(few_args_, args.size()); - } else { - many_args_.assign(args.begin(), args.end()); - args_ = many_args_; - } - } + : format_(format), args_(args.begin(), args.end()) { } std::ostream& Print(std::ostream& os) const; @@ -197,12 +188,7 @@ class Streamable { private: const UntypedFormatSpecImpl& format_; - absl::Span args_; - // if args_.size() is 4 or less: - FormatArgImpl few_args_[4] = {FormatArgImpl(0), FormatArgImpl(0), - FormatArgImpl(0), FormatArgImpl(0)}; - // if args_.size() is more than 4: - std::vector many_args_; + absl::InlinedVector args_; }; // for testing From 66eae02ea7c8c41108590de510e70517304d2b6a Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 9 Jun 2023 02:27:24 -0700 Subject: [PATCH 0053/1238] Implement GetTID for NACL platform. in NACL pthread_self() returns a pointer that isn't directly convertible to arithmetic type. PiperOrigin-RevId: 539023020 Change-Id: I3745ec5565f3a99ccb1d9df12c27a80e57ca4755 --- absl/base/internal/sysinfo.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/absl/base/internal/sysinfo.cc b/absl/base/internal/sysinfo.cc index 7de8ead2139..605a11ebce6 100644 --- a/absl/base/internal/sysinfo.cc +++ b/absl/base/internal/sysinfo.cc @@ -426,6 +426,15 @@ pid_t GetTID() { return static_cast(tid); } +#elif defined(__native_client__) + +pid_t GetTID() { + auto* thread = pthread_self(); + static_assert(sizeof(pid_t) == sizeof(thread), + "In NaCL int expected to be the same size as a pointer"); + return reinterpret_cast(thread); +} + #else // Fallback implementation of `GetTID` using `pthread_self`. From 87ce390379440febee9caa500e527afa3fa55bef Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 9 Jun 2023 07:46:15 -0700 Subject: [PATCH 0054/1238] The previous code was using `memmove` under the hood (`string::append`). This patch makes it use `memcpy` for performance and consistency with other overloads. PiperOrigin-RevId: 539079130 Change-Id: I5aea9dd9b8a1ce708c787df7d6c9a75ae419c484 --- absl/strings/str_cat.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/absl/strings/str_cat.cc b/absl/strings/str_cat.cc index 6c198f8582d..2e49c31b68e 100644 --- a/absl/strings/str_cat.cc +++ b/absl/strings/str_cat.cc @@ -146,7 +146,13 @@ void AppendPieces(std::string* dest, void StrAppend(std::string* dest, const AlphaNum& a) { ASSERT_NO_OVERLAP(*dest, a); - dest->append(a.data(), a.size()); + std::string::size_type old_size = dest->size(); + strings_internal::STLStringResizeUninitializedAmortized(dest, + old_size + a.size()); + char* const begin = &(*dest)[0]; + char* out = begin + old_size; + out = Append(out, a); + assert(out == begin + dest->size()); } void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b) { From 163cade8645fad00682b6829b4eac92be9e71b89 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 9 Jun 2023 09:37:27 -0700 Subject: [PATCH 0055/1238] Import of CCTZ from GitHub. PiperOrigin-RevId: 539104398 Change-Id: I6385662e0c5694d40c57887f983b16adc9eced14 --- absl/time/internal/cctz/src/time_zone_format.cc | 6 ++++-- absl/time/internal/cctz/src/time_zone_libc.cc | 15 +++++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/absl/time/internal/cctz/src/time_zone_format.cc b/absl/time/internal/cctz/src/time_zone_format.cc index 2e5f5329117..0bea75a4436 100644 --- a/absl/time/internal/cctz/src/time_zone_format.cc +++ b/absl/time/internal/cctz/src/time_zone_format.cc @@ -13,8 +13,10 @@ // limitations under the License. #if !defined(HAS_STRPTIME) -#if !defined(_MSC_VER) && !defined(__MINGW32__) -#define HAS_STRPTIME 1 // assume everyone has strptime() except windows +#if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__VXWORKS__) +#define HAS_STRPTIME \ + 1 // assume everyone has strptime() except windows + // and VxWorks #endif #endif diff --git a/absl/time/internal/cctz/src/time_zone_libc.cc b/absl/time/internal/cctz/src/time_zone_libc.cc index af9f063e21c..e503a8584bd 100644 --- a/absl/time/internal/cctz/src/time_zone_libc.cc +++ b/absl/time/internal/cctz/src/time_zone_libc.cc @@ -71,6 +71,16 @@ auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) { const bool is_dst = tm.tm_isdst > 0; return tzname[is_dst]; } +#elif defined(__VXWORKS__) +// Uses the globals: 'timezone' and 'tzname'. +auto tm_gmtoff(const std::tm& tm) -> decltype(timezone + 0) { + const bool is_dst = tm.tm_isdst > 0; + return timezone + (is_dst ? 60 * 60 : 0); +} +auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) { + const bool is_dst = tm.tm_isdst > 0; + return tzname[is_dst]; +} #else // Adapt to different spellings of the struct std::tm extension fields. #if defined(tm_gmtoff) @@ -108,6 +118,7 @@ auto tm_zone(const T& tm) -> decltype(tm.__tm_zone) { } #endif // tm_zone #endif +using tm_gmtoff_t = decltype(tm_gmtoff(std::tm{})); inline std::tm* gm_time(const std::time_t* timep, std::tm* result) { #if defined(_WIN32) || defined(_WIN64) @@ -154,7 +165,7 @@ bool make_time(const civil_second& cs, int is_dst, std::time_t* t, // Find the least time_t in [lo:hi] where local time matches offset, given: // (1) lo doesn't match, (2) hi does, and (3) there is only one transition. -std::time_t find_trans(std::time_t lo, std::time_t hi, int offset) { +std::time_t find_trans(std::time_t lo, std::time_t hi, tm_gmtoff_t offset) { std::tm tm; while (lo + 1 != hi) { const std::time_t mid = lo + (hi - lo) / 2; @@ -265,7 +276,7 @@ time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const { return {time_zone::civil_lookup::UNIQUE, tp, tp, tp}; } - int offset = tm_gmtoff(tm0); + tm_gmtoff_t offset = tm_gmtoff(tm0); if (t0 < t1) { // negative DST std::swap(t0, t1); offset = tm_gmtoff(tm1); From 0f4133aacfa2ebc84c76f69e6ab02ce58603072f Mon Sep 17 00:00:00 2001 From: Greg Falcon Date: Fri, 9 Jun 2023 09:38:13 -0700 Subject: [PATCH 0056/1238] StrFormat() simplification: Treat %v unconditionally as %d when formatting integers. This is a simplification but not a behavior change; we used to choose %u for unsigned ints, but %u and %d generate the same output for these types. PiperOrigin-RevId: 539104599 Change-Id: I9d7ff561b969a6287889f95063636d6b77a4a78b --- absl/strings/internal/str_format/arg.cc | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/absl/strings/internal/str_format/arg.cc b/absl/strings/internal/str_format/arg.cc index 018dd052351..6033a75a534 100644 --- a/absl/strings/internal/str_format/arg.cc +++ b/absl/strings/internal/str_format/arg.cc @@ -278,24 +278,6 @@ bool ConvertIntImplInnerSlow(const IntDigits &as_digits, return true; } -template ::value && - std::is_signed::value) || - std::is_same::value, - int>::type = 0> -constexpr auto ConvertV(T) { - return FormatConversionCharInternal::d; -} - -template ::value && - std::is_unsigned::value) || - std::is_same::value, - int>::type = 0> -constexpr auto ConvertV(T) { - return FormatConversionCharInternal::u; -} - template bool ConvertFloatArg(T v, FormatConversionSpecImpl conv, FormatSinkImpl *sink) { if (conv.conversion_char() == FormatConversionCharInternal::v) { @@ -332,10 +314,6 @@ bool ConvertIntArg(T v, FormatConversionSpecImpl conv, FormatSinkImpl *sink) { using U = typename MakeUnsigned::type; IntDigits as_digits; - if (conv.conversion_char() == FormatConversionCharInternal::v) { - conv.set_conversion_char(ConvertV(T{})); - } - // This odd casting is due to a bug in -Wswitch behavior in gcc49 which causes // it to complain about a switch/case type mismatch, even though both are // FormatConverionChar. Likely this is because at this point @@ -361,6 +339,7 @@ bool ConvertIntArg(T v, FormatConversionSpecImpl conv, FormatSinkImpl *sink) { case static_cast(FormatConversionCharInternal::d): case static_cast(FormatConversionCharInternal::i): + case static_cast(FormatConversionCharInternal::v): as_digits.PrintAsDec(v); break; From 2b042424db44e9614d3c100832dff1a54f37b351 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 9 Jun 2023 10:10:46 -0700 Subject: [PATCH 0057/1238] Fix unwinding through nested signal frames on aarch64. This fixes an endless loop in the absl Arm stack unwinder where encountering a second signal return trampoline (as one has in nested signal frames), would restart unwinding at the outermost signal, resulting in an endless loop. This does not change any behavior in the non-nested signal case, so I believe it is safe for any stack that hasn't encountered this bug already. I would love to test this beyond the absl unwinding test cases and the fingerprint_test included here, but I'm at a loss for other test cases. PiperOrigin-RevId: 539113007 Change-Id: I10037f9fa77b45cc4db61f89b9c6380ec3529113 --- absl/debugging/internal/stacktrace_aarch64-inl.inc | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/absl/debugging/internal/stacktrace_aarch64-inl.inc b/absl/debugging/internal/stacktrace_aarch64-inl.inc index b66beba249f..520e9a84787 100644 --- a/absl/debugging/internal/stacktrace_aarch64-inl.inc +++ b/absl/debugging/internal/stacktrace_aarch64-inl.inc @@ -94,16 +94,21 @@ static void **NextStackFrame(void **old_frame_pointer, const void *uc) { void **const pre_signal_frame_pointer = reinterpret_cast(ucv->uc_mcontext.regs[29]); + // The most recent signal always needs special handling to find the frame + // pointer, but a nested signal does not. If pre_signal_frame_pointer is + // earlier in the stack than the old_frame_pointer, then use it. If it is + // later, then we have already unwound through it and it needs no special + // handling. + if (pre_signal_frame_pointer >= old_frame_pointer) { + new_frame_pointer = pre_signal_frame_pointer; + } // Check that alleged frame pointer is actually readable. This is to // prevent "double fault" in case we hit the first fault due to e.g. // stack corruption. if (!absl::debugging_internal::AddressIsReadable( - pre_signal_frame_pointer)) + new_frame_pointer)) return nullptr; - // Alleged frame pointer is readable, use it for further unwinding. - new_frame_pointer = pre_signal_frame_pointer; - // Skip frame size check if we return from a signal. We may be using a // an alternate stack for signals. check_frame_size = false; From 1feab4fff90f904518e66cf80971063486fbc984 Mon Sep 17 00:00:00 2001 From: Connal de Souza Date: Fri, 9 Jun 2023 12:38:09 -0700 Subject: [PATCH 0058/1238] Optimize Cord Refcount decrement. Introduce kHighRefcountMask which masks off flags and the LSb of the refcount value. In the cases where this mask is used, we don't need to check the LSb because we can assume the refcount is 1 when the rest of the masked RefcountAndFlags is empty, and the LSb doesn't matter if the masked value is not empty (either it's immortal or refcount > 1). This saves an instruction and a cycle (and + cmp -> tst) https://godbolt.org/z/Kz69eqfhq PiperOrigin-RevId: 539151659 Change-Id: I2ec7d72918f052c4b0938edd746af9d5b3052c7e --- absl/strings/internal/cord_internal.h | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/absl/strings/internal/cord_internal.h b/absl/strings/internal/cord_internal.h index 8d9836ba8b8..20dd008cfa4 100644 --- a/absl/strings/internal/cord_internal.h +++ b/absl/strings/internal/cord_internal.h @@ -157,20 +157,19 @@ class RefcountAndFlags { // false will be visible to a thread that just observed this method returning // false. Always returns false when the immortal bit is set. inline bool Decrement() { - int32_t refcount = count_.load(std::memory_order_acquire) & kRefcountMask; - assert(refcount > 0 || refcount & kImmortalFlag); + int32_t refcount = count_.load(std::memory_order_acquire); + assert((refcount & kRefcountMask) > 0 || refcount & kImmortalFlag); return refcount != kRefIncrement && (count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel) & - kRefcountMask) != kRefIncrement; + kHighRefcountMask) != 0; } // Same as Decrement but expect that refcount is greater than 1. inline bool DecrementExpectHighRefcount() { int32_t refcount = - count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel) & - kRefcountMask; - assert(refcount > 0 || refcount & kImmortalFlag); - return refcount != kRefIncrement; + count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel); + assert((refcount & kRefcountMask) > 0 || refcount & kImmortalFlag); + return (refcount & kHighRefcountMask) != 0; } // Returns the current reference count using acquire semantics. @@ -214,6 +213,15 @@ class RefcountAndFlags { // purposes of equality. (A refcount of 0 or 1 does not count as 0 or 1 // if the immortal bit is set.) kRefcountMask = ~kReservedFlag, + + // Bitmask to use when checking if refcount is equal to 1 and not + // immortal when decrementing the refcount. This masks out kRefIncrement and + // all flags except kImmortalFlag. If the masked RefcountAndFlags is 0, we + // assume the refcount is equal to 1, since we know it's not immortal and + // not greater than 1. If the masked RefcountAndFlags is not 0, we can + // assume the refcount is not equal to 1 since either a higher bit in the + // refcount is set, or kImmortal is set. + kHighRefcountMask = kRefcountMask & ~kRefIncrement, }; std::atomic count_; From fc7467b0182914102a97f6dd7e83ae1f8927eb2a Mon Sep 17 00:00:00 2001 From: Andrei Polushin Date: Mon, 12 Jun 2023 17:52:54 +0700 Subject: [PATCH 0059/1238] Fix buffer overflow in a placement `new[]` storage test. AppleClang seem to allocate two extra 64-bit words per each `new[]`. A test should pass larger buffer to a placement `new[]`. Fixes #1090 --- absl/base/exception_safety_testing_test.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/absl/base/exception_safety_testing_test.cc b/absl/base/exception_safety_testing_test.cc index a87fd6a99e7..7c0007ad331 100644 --- a/absl/base/exception_safety_testing_test.cc +++ b/absl/base/exception_safety_testing_test.cc @@ -332,13 +332,16 @@ TEST(ThrowingValueTest, NonThrowingPlacementDelete) { constexpr int kArrayLen = 2; // We intentionally create extra space to store the tag allocated by placement // new[]. - constexpr int kStorageLen = 4; + constexpr size_t kExtraSpaceLen = sizeof(size_t) * 2; alignas(ThrowingValue<>) unsigned char buf[sizeof(ThrowingValue<>)]; alignas(ThrowingValue<>) unsigned char - array_buf[sizeof(ThrowingValue<>[kStorageLen])]; + array_buf[kExtraSpaceLen + sizeof(ThrowingValue<>[kArrayLen])]; auto* placed = new (&buf) ThrowingValue<>(1); auto placed_array = new (&array_buf) ThrowingValue<>[kArrayLen]; + auto* placed_array_end = reinterpret_cast(placed_array) + + sizeof(ThrowingValue<>[kArrayLen]); + EXPECT_LE(placed_array_end, array_buf + sizeof(array_buf)); SetCountdown(); ExpectNoThrow([placed, &buf]() { From 4500c2fada4e952037c59bd65e8be1ba0b29f21e Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Mon, 12 Jun 2023 08:11:36 -0700 Subject: [PATCH 0060/1238] DirectMmap: Use off_t instead of off64_t for the offset parameter off_t is best for portability. Its size varies with the platform. off64_t is non-standard, but is present in glibc and some BSDs. It also matches the signature specified in the manual. https://man7.org/linux/man-pages/man2/mmap.2.html This is a re-spin of #1349, but correctly casts the type to the type expected by the kernel for mmap2. https://man7.org/linux/man-pages/man2/mmap2.2.html Fixes #1473 PiperOrigin-RevId: 539656313 Change-Id: I7a30dd9d3eb6af03a99da0d93d721a86f6521b25 --- absl/base/internal/direct_mmap.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/absl/base/internal/direct_mmap.h b/absl/base/internal/direct_mmap.h index 815b8d23ba3..1beb2ee4e52 100644 --- a/absl/base/internal/direct_mmap.h +++ b/absl/base/internal/direct_mmap.h @@ -72,7 +72,7 @@ namespace base_internal { // Platform specific logic extracted from // https://chromium.googlesource.com/linux-syscall-support/+/master/linux_syscall_support.h inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd, - off64_t offset) noexcept { + off_t offset) noexcept { #if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \ defined(__m68k__) || defined(__sh__) || \ (defined(__hppa__) && !defined(__LP64__)) || \ @@ -102,7 +102,7 @@ inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd, #else return reinterpret_cast( syscall(SYS_mmap2, start, length, prot, flags, fd, - static_cast(offset / pagesize))); + static_cast(offset / pagesize))); // NOLINT #endif #elif defined(__s390x__) // On s390x, mmap() arguments are passed in memory. From a3d9a943253f596bd88538f18cc6b07aaba6d3c0 Mon Sep 17 00:00:00 2001 From: Greg Falcon Date: Mon, 12 Jun 2023 08:25:06 -0700 Subject: [PATCH 0061/1238] Fix behaviors of StrCat() and StrFormat() regarding char types and enum types. This is a conservative change, in that it only contains bugfixes and allows new patterns that used to be compile errors. There are other changes we would like to make (as reflected in the comments in char_formatting_test.cc), but we are being careful about the implications of such behavior changes. The two implementation changes are: * Apply integral promotions to enums before printing them, so they are always treated as integers (and not chars) by StrCat and StrFormat. * Classify `unsigned char` and `signed char` as integer-like rather than char-like, so that `StrFormat("%v", v)` accepts those types as integers (consistent with `StrCat()`.) The behavior changes are: * StrCat() now accepts char-backed enums (rather than failing to compile). * StrFormat("%v") now accepts `signed char` and `unsigned char` as integral (rather than failing to compile). * StrFormat("%v") now correctly formats 8-bit enums as integers (rather than failing internally and emitting nothing). Tested: Modified the char_formatting_test.cc case to reflect changes. Re-ran all other tests. PiperOrigin-RevId: 539659674 Change-Id: Ief56335f5a57e4582af396d00eaa9e7b6be4ddc6 --- absl/strings/char_formatting_test.cc | 54 ++++++++----------------- absl/strings/internal/str_format/arg.cc | 16 ++++---- absl/strings/internal/str_format/arg.h | 16 ++++---- absl/strings/str_cat.h | 18 +++++++-- absl/strings/str_format.h | 1 + 5 files changed, 48 insertions(+), 57 deletions(-) diff --git a/absl/strings/char_formatting_test.cc b/absl/strings/char_formatting_test.cc index 60416af3ec2..1692da7028f 100644 --- a/absl/strings/char_formatting_test.cc +++ b/absl/strings/char_formatting_test.cc @@ -37,17 +37,12 @@ TEST(CharFormatting, CharEnum) { auto v = static_cast('A'); // Desired behavior: format as decimal - // (No APIs do this today.) - - // BUG: internally fails - EXPECT_EQ(absl::StrFormat("%vB", v), ""); - - // Legacy behavior: does not compile: - // EXPECT_EQ(absl::StrCat(ch, "B"), "AB"); + EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); + EXPECT_EQ(absl::StrCat(v, "B"), "65B"); // Legacy behavior: format as character: - // Some older versions of gcc behave differently in this one case. + // Some older versions of gcc behave differently in this one case #if !defined(__GNUC__) || defined(__clang__) EXPECT_EQ(absl::Substitute("$0B", v), "AB"); #endif @@ -57,14 +52,9 @@ enum class CharEnumClass: char {}; TEST(CharFormatting, CharEnumClass) { auto v = static_cast('A'); - // Desired behavior: format as decimal - // (No APIs do this today.) - - // BUG: internally fails - EXPECT_EQ(absl::StrFormat("%vB", v), ""); - - // Legacy behavior: does not compile: - // EXPECT_EQ(absl::StrCat(ch, "B"), "AB"); + // Desired behavior: format as decimal: + EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); + EXPECT_EQ(absl::StrCat(v, "B"), "65B"); // Legacy behavior: format as character: EXPECT_EQ(absl::Substitute("$0B", v), "AB"); @@ -76,9 +66,7 @@ TEST(CharFormatting, UnsignedChar) { // Desired behavior: format as decimal: EXPECT_EQ(absl::StrCat(v, "B"), "65B"); EXPECT_EQ(absl::Substitute("$0B", v), "65B"); - - // Legacy behavior: does not compile: - // EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); + EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); // Signedness check const unsigned char w = 255; @@ -93,9 +81,7 @@ TEST(CharFormatting, SignedChar) { // Desired behavior: format as decimal: EXPECT_EQ(absl::StrCat(v, "B"), "65B"); EXPECT_EQ(absl::Substitute("$0B", v), "65B"); - - // Legacy behavior: does not compile: - // EXPECT_EQ(absl::StrFormat("%vB", v), "AB"); + EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); // Signedness check const signed char w = -128; @@ -110,14 +96,13 @@ TEST(CharFormatting, UnsignedCharEnum) { // Desired behavior: format as decimal: EXPECT_EQ(absl::StrCat(v, "B"), "65B"); EXPECT_EQ(absl::Substitute("$0B", v), "65B"); - - // BUG: internally fails - EXPECT_EQ(absl::StrFormat("%vB", v), ""); + EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); // Signedness check auto w = static_cast(255); EXPECT_EQ(absl::StrCat(w, "B"), "255B"); EXPECT_EQ(absl::Substitute("$0B", w), "255B"); + EXPECT_EQ(absl::StrFormat("%vB", w), "255B"); } enum SignedCharEnum : signed char {}; @@ -127,14 +112,13 @@ TEST(CharFormatting, SignedCharEnum) { // Desired behavior: format as decimal: EXPECT_EQ(absl::StrCat(v, "B"), "65B"); EXPECT_EQ(absl::Substitute("$0B", v), "65B"); - - // BUG: internally fails - EXPECT_EQ(absl::StrFormat("%vB", v), ""); + EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); // Signedness check auto w = static_cast(-128); EXPECT_EQ(absl::StrCat(w, "B"), "-128B"); EXPECT_EQ(absl::Substitute("$0B", w), "-128B"); + EXPECT_EQ(absl::StrFormat("%vB", w), "-128B"); } enum class UnsignedCharEnumClass : unsigned char {}; @@ -144,14 +128,13 @@ TEST(CharFormatting, UnsignedCharEnumClass) { // Desired behavior: format as decimal: EXPECT_EQ(absl::StrCat(v, "B"), "65B"); EXPECT_EQ(absl::Substitute("$0B", v), "65B"); - - // BUG: internally fails - EXPECT_EQ(absl::StrFormat("%vB", v), ""); + EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); // Signedness check auto w = static_cast(255); EXPECT_EQ(absl::StrCat(w, "B"), "255B"); EXPECT_EQ(absl::Substitute("$0B", w), "255B"); + EXPECT_EQ(absl::StrFormat("%vB", w), "255B"); } enum SignedCharEnumClass : signed char {}; @@ -161,14 +144,13 @@ TEST(CharFormatting, SignedCharEnumClass) { // Desired behavior: format as decimal: EXPECT_EQ(absl::StrCat(v, "B"), "65B"); EXPECT_EQ(absl::Substitute("$0B", v), "65B"); - - // BUG: internally fails - EXPECT_EQ(absl::StrFormat("%vB", v), ""); + EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); // Signedness check auto w = static_cast(-128); EXPECT_EQ(absl::StrCat(w, "B"), "-128B"); EXPECT_EQ(absl::Substitute("$0B", w), "-128B"); + EXPECT_EQ(absl::StrFormat("%vB", w), "-128B"); } #ifdef __cpp_lib_byte @@ -177,12 +159,10 @@ TEST(CharFormatting, StdByte) { // Desired behavior: format as 0xff // (No APIs do this today.) - // BUG: internally fails - EXPECT_EQ(absl::StrFormat("%vB", v), ""); - // Legacy behavior: format as decimal: EXPECT_EQ(absl::StrCat(v, "B"), "65B"); EXPECT_EQ(absl::Substitute("$0B", v), "65B"); + EXPECT_EQ(absl::StrFormat("%vB", v), "65B"); } #endif // _cpp_lib_byte diff --git a/absl/strings/internal/str_format/arg.cc b/absl/strings/internal/str_format/arg.cc index 6033a75a534..7f4057f9581 100644 --- a/absl/strings/internal/str_format/arg.cc +++ b/absl/strings/internal/str_format/arg.cc @@ -461,18 +461,18 @@ CharConvertResult FormatConvertImpl(char v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } -CharConvertResult FormatConvertImpl(signed char v, - const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { + +// ==================== Ints ==================== +IntegralConvertResult FormatConvertImpl(signed char v, + const FormatConversionSpecImpl conv, + FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } -CharConvertResult FormatConvertImpl(unsigned char v, - const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { +IntegralConvertResult FormatConvertImpl(unsigned char v, + const FormatConversionSpecImpl conv, + FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } - -// ==================== Ints ==================== IntegralConvertResult FormatConvertImpl(short v, // NOLINT const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h index e4b16628274..3ce30feb49c 100644 --- a/absl/strings/internal/str_format/arg.h +++ b/absl/strings/internal/str_format/arg.h @@ -279,14 +279,14 @@ FloatingConvertResult FormatConvertImpl(long double v, // Chars. CharConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); -CharConvertResult FormatConvertImpl(signed char v, - FormatConversionSpecImpl conv, - FormatSinkImpl* sink); -CharConvertResult FormatConvertImpl(unsigned char v, - FormatConversionSpecImpl conv, - FormatSinkImpl* sink); // Ints. +IntegralConvertResult FormatConvertImpl(signed char v, + FormatConversionSpecImpl conv, + FormatSinkImpl* sink); +IntegralConvertResult FormatConvertImpl(unsigned char v, + FormatConversionSpecImpl conv, + FormatSinkImpl* sink); IntegralConvertResult FormatConvertImpl(short v, // NOLINT FormatConversionSpecImpl conv, FormatSinkImpl* sink); @@ -441,7 +441,7 @@ class FormatArgImpl { // For everything else: // - Decay char* and char arrays into `const char*` // - Decay any other pointer to `const void*` - // - Decay all enums to their underlying type. + // - Decay all enums to the integral promotion of their underlying type. // - Decay function pointers to void*. template struct DecayType { @@ -461,7 +461,7 @@ class FormatArgImpl { !str_format_internal::HasUserDefinedConvert::value && !strings_internal::HasAbslStringify::value && std::is_enum::value>::type> { - using type = typename std::underlying_type::type; + using type = decltype(+typename std::underlying_type::type()); }; public: diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h index fcd48c4ea81..d5f71ff003f 100644 --- a/absl/strings/str_cat.h +++ b/absl/strings/str_cat.h @@ -374,14 +374,24 @@ class AlphaNum { const char* data() const { return piece_.data(); } absl::string_view Piece() const { return piece_; } - // Normal enums are already handled by the integer formatters. - // This overload matches only scoped enums. + // Match unscoped enums. Use integral promotion so that a `char`-backed + // enum becomes a wider integral type AlphaNum will accept. template {} && !std::is_convertible{} && + std::is_enum{} && std::is_convertible{} && !strings_internal::HasAbslStringify::value>::type> AlphaNum(T e) // NOLINT(runtime/explicit) - : AlphaNum(static_cast::type>(e)) {} + : AlphaNum(+e) {} + + // This overload matches scoped enums. We must explicitly cast to the + // underlying type, but use integral promotion for the same reason as above. + template {} && !std::is_convertible{} && + !strings_internal::HasAbslStringify::value, + char*>::type = nullptr> + AlphaNum(T e) // NOLINT(runtime/explicit) + : AlphaNum(+static_cast::type>(e)) {} // vector::reference and const_reference require special help to // convert to `AlphaNum` because it requires two user defined conversions. diff --git a/absl/strings/str_format.h b/absl/strings/str_format.h index fc4bf39e457..023e4350d37 100644 --- a/absl/strings/str_format.h +++ b/absl/strings/str_format.h @@ -259,6 +259,7 @@ class FormatCountCapture { // * Characters: `char`, `signed char`, `unsigned char` // * Integers: `int`, `short`, `unsigned short`, `unsigned`, `long`, // `unsigned long`, `long long`, `unsigned long long` +// * Enums: printed as their underlying integral value // * Floating-point: `float`, `double`, `long double` // // However, in the `str_format` library, a format conversion specifies a broader From 5d1f1cf9dd9455b9ff41fa3e6009f9c40feaf2f2 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 12 Jun 2023 12:13:38 -0700 Subject: [PATCH 0062/1238] Adding more support and testing for int128 and uint128 flags from cl/534444213 PiperOrigin-RevId: 539726003 Change-Id: Ie38f8d48a7b4c9d498fc1c4c4af6138048f80f68 --- absl/flags/BUILD.bazel | 1 + absl/flags/CMakeLists.txt | 1 + absl/flags/flag_test.cc | 64 +++++++++++++++++++++++++++++++++- absl/flags/marshalling.cc | 12 +++++++ absl/flags/marshalling.h | 2 ++ absl/flags/marshalling_test.cc | 34 ++++++++++++++++++ 6 files changed, 113 insertions(+), 1 deletion(-) diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel index 583e6d94413..50bf387cd6b 100644 --- a/absl/flags/BUILD.bazel +++ b/absl/flags/BUILD.bazel @@ -388,6 +388,7 @@ cc_test( ":reflection", "//absl/base:core_headers", "//absl/base:malloc_internal", + "//absl/numeric:int128", "//absl/strings", "//absl/time", "@com_google_googletest//:gtest_main", diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt index 6525eb2adcc..b20463f50bb 100644 --- a/absl/flags/CMakeLists.txt +++ b/absl/flags/CMakeLists.txt @@ -346,6 +346,7 @@ absl_cc_test( absl::flags_internal absl::flags_marshalling absl::flags_reflection + absl::int128 absl::strings absl::time GTest::gtest_main diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc index 845b4ebac6c..f9cda02e8ca 100644 --- a/absl/flags/flag_test.cc +++ b/absl/flags/flag_test.cc @@ -34,6 +34,7 @@ #include "absl/flags/marshalling.h" #include "absl/flags/reflection.h" #include "absl/flags/usage_config.h" +#include "absl/numeric/int128.h" #include "absl/strings/match.h" #include "absl/strings/numbers.h" #include "absl/strings/str_cat.h" @@ -127,6 +128,11 @@ TEST_F(FlagTest, Traits) { flags::FlagValueStorageKind::kAlignedBuffer); EXPECT_EQ(flags::StorageKind>(), flags::FlagValueStorageKind::kAlignedBuffer); + + EXPECT_EQ(flags::StorageKind(), + flags::FlagValueStorageKind::kSequenceLocked); + EXPECT_EQ(flags::StorageKind(), + flags::FlagValueStorageKind::kSequenceLocked); } // -------------------------------------------------------------------- @@ -135,6 +141,8 @@ constexpr flags::FlagHelpArg help_arg{flags::FlagHelpMsg("literal help"), flags::FlagHelpKind::kLiteral}; using String = std::string; +using int128 = absl::int128; +using uint128 = absl::uint128; #if !defined(_MSC_VER) || defined(__clang__) #define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind) \ @@ -171,6 +179,8 @@ DEFINE_CONSTRUCTED_FLAG(float, 7.8, kOneWord); DEFINE_CONSTRUCTED_FLAG(double, 9.10, kOneWord); DEFINE_CONSTRUCTED_FLAG(String, &TestMakeDflt, kGenFunc); DEFINE_CONSTRUCTED_FLAG(UDT, &TestMakeDflt, kGenFunc); +DEFINE_CONSTRUCTED_FLAG(int128, 13, kGenFunc); +DEFINE_CONSTRUCTED_FLAG(uint128, 14, kGenFunc); template bool TestConstructionFor(const absl::Flag& f1, absl::Flag& f2) { @@ -202,6 +212,8 @@ TEST_F(FlagTest, TestConstruction) { TEST_CONSTRUCTED_FLAG(double); TEST_CONSTRUCTED_FLAG(String); TEST_CONSTRUCTED_FLAG(UDT); + TEST_CONSTRUCTED_FLAG(int128); + TEST_CONSTRUCTED_FLAG(uint128); } // -------------------------------------------------------------------- @@ -220,6 +232,8 @@ ABSL_DECLARE_FLAG(double, test_flag_09); ABSL_DECLARE_FLAG(float, test_flag_10); ABSL_DECLARE_FLAG(std::string, test_flag_11); ABSL_DECLARE_FLAG(absl::Duration, test_flag_12); +ABSL_DECLARE_FLAG(absl::int128, test_flag_13); +ABSL_DECLARE_FLAG(absl::uint128, test_flag_14); namespace { @@ -251,6 +265,10 @@ TEST_F(FlagTest, TestFlagDeclaration) { "test_flag_11"); EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Name(), "test_flag_12"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_13).Name(), + "test_flag_13"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_14).Name(), + "test_flag_14"); } #endif // !ABSL_FLAGS_STRIP_NAMES @@ -270,6 +288,9 @@ ABSL_FLAG(double, test_flag_09, -9.876e-50, "test flag 09"); ABSL_FLAG(float, test_flag_10, 1.234e12f, "test flag 10"); ABSL_FLAG(std::string, test_flag_11, "", "test flag 11"); ABSL_FLAG(absl::Duration, test_flag_12, absl::Minutes(10), "test flag 12"); +ABSL_FLAG(absl::int128, test_flag_13, absl::MakeInt128(-1, 0), "test flag 13"); +ABSL_FLAG(absl::uint128, test_flag_14, absl::MakeUint128(0, 0xFFFAAABBBCCCDDD), + "test flag 14"); namespace { @@ -384,6 +405,24 @@ TEST_F(FlagTest, TestFlagDefinition) { absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Filename(), expected_file_name)) << absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Filename(); + + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_13).Name(), + "test_flag_13"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_13).Help(), + "test flag 13"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_13).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_13).Filename(); + + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_14).Name(), + "test_flag_14"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_14).Help(), + "test flag 14"); + EXPECT_TRUE(absl::EndsWith( + absl::GetFlagReflectionHandle(FLAGS_test_flag_14).Filename(), + expected_file_name)) + << absl::GetFlagReflectionHandle(FLAGS_test_flag_14).Filename(); } #endif // !ABSL_FLAGS_STRIP_NAMES @@ -414,6 +453,10 @@ TEST_F(FlagTest, TestDefault) { ""); EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).DefaultValue(), "10m"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_13).DefaultValue(), + "-18446744073709551616"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_14).DefaultValue(), + "1152827684197027293"); EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).CurrentValue(), "true"); @@ -439,6 +482,10 @@ TEST_F(FlagTest, TestDefault) { ""); EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).CurrentValue(), "10m"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_13).CurrentValue(), + "-18446744073709551616"); + EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_14).CurrentValue(), + "1152827684197027293"); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), true); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234); @@ -452,6 +499,9 @@ TEST_F(FlagTest, TestDefault) { EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), 1.234e12f, 1e5f); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), ""); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Minutes(10)); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), absl::MakeInt128(-1, 0)); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_14), + absl::MakeUint128(0, 0xFFFAAABBBCCCDDD)); } // -------------------------------------------------------------------- @@ -553,6 +603,13 @@ TEST_F(FlagTest, TestGetSet) { absl::SetFlag(&FLAGS_test_flag_12, absl::Seconds(110)); EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Seconds(110)); + + absl::SetFlag(&FLAGS_test_flag_13, absl::MakeInt128(-1, 0)); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), absl::MakeInt128(-1, 0)); + + absl::SetFlag(&FLAGS_test_flag_14, absl::MakeUint128(0, 0xFFFAAABBBCCCDDD)); + EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_14), + absl::MakeUint128(0, 0xFFFAAABBBCCCDDD)); } // -------------------------------------------------------------------- @@ -582,6 +639,11 @@ TEST_F(FlagTest, TestGetViaReflection) { EXPECT_EQ(*handle->TryGet(), ""); handle = absl::FindCommandLineFlag("test_flag_12"); EXPECT_EQ(*handle->TryGet(), absl::Minutes(10)); + handle = absl::FindCommandLineFlag("test_flag_13"); + EXPECT_EQ(*handle->TryGet(), absl::MakeInt128(-1, 0)); + handle = absl::FindCommandLineFlag("test_flag_14"); + EXPECT_EQ(*handle->TryGet(), + absl::MakeUint128(0, 0xFFFAAABBBCCCDDD)); } // -------------------------------------------------------------------- @@ -980,7 +1042,7 @@ TEST_F(FlagTest, TesTypeWrappingEnum) { // This is a compile test to ensure macros are expanded within ABSL_FLAG and // ABSL_DECLARE_FLAG. -#define FLAG_NAME_MACRO(name) prefix_ ## name +#define FLAG_NAME_MACRO(name) prefix_##name ABSL_DECLARE_FLAG(int, FLAG_NAME_MACRO(test_macro_named_flag)); ABSL_FLAG(int, FLAG_NAME_MACRO(test_macro_named_flag), 0, "Testing macro expansion within ABSL_FLAG"); diff --git a/absl/flags/marshalling.cc b/absl/flags/marshalling.cc index cf6312b1f19..50b7b33170a 100644 --- a/absl/flags/marshalling.cc +++ b/absl/flags/marshalling.cc @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -198,6 +199,17 @@ std::string Unparse(long v) { return absl::StrCat(v); } std::string Unparse(unsigned long v) { return absl::StrCat(v); } std::string Unparse(long long v) { return absl::StrCat(v); } std::string Unparse(unsigned long long v) { return absl::StrCat(v); } +std::string Unparse(absl::int128 v) { + std::stringstream ss; + ss << v; + return ss.str(); +} +std::string Unparse(absl::uint128 v) { + std::stringstream ss; + ss << v; + return ss.str(); +} + template std::string UnparseFloatingPointVal(T v) { // digits10 is guaranteed to roundtrip correctly in string -> value -> string diff --git a/absl/flags/marshalling.h b/absl/flags/marshalling.h index 21d955d5235..301213a9a6e 100644 --- a/absl/flags/marshalling.h +++ b/absl/flags/marshalling.h @@ -313,6 +313,8 @@ std::string Unparse(long v); // NOLINT std::string Unparse(unsigned long v); // NOLINT std::string Unparse(long long v); // NOLINT std::string Unparse(unsigned long long v); // NOLINT +std::string Unparse(absl::int128 v); +std::string Unparse(absl::uint128 v); std::string Unparse(float v); std::string Unparse(double v); diff --git a/absl/flags/marshalling_test.cc b/absl/flags/marshalling_test.cc index d996ca7f5a2..57356672258 100644 --- a/absl/flags/marshalling_test.cc +++ b/absl/flags/marshalling_test.cc @@ -981,6 +981,40 @@ TEST(MarshallingTest, TestUint64Unparsing) { // -------------------------------------------------------------------- +TEST(MarshallingTest, TestInt128Unparsing) { + absl::int128 value; + + value = 1; + EXPECT_EQ(absl::UnparseFlag(value), "1"); + value = 0; + EXPECT_EQ(absl::UnparseFlag(value), "0"); + value = -1; + EXPECT_EQ(absl::UnparseFlag(value), "-1"); + value = 123456789L; + EXPECT_EQ(absl::UnparseFlag(value), "123456789"); + value = -987654321L; + EXPECT_EQ(absl::UnparseFlag(value), "-987654321"); + value = 0x7FFFFFFFFFFFFFFF; + EXPECT_EQ(absl::UnparseFlag(value), "9223372036854775807"); +} + +// -------------------------------------------------------------------- + +TEST(MarshallingTest, TestUint128Unparsing) { + absl::uint128 value; + + value = 1; + EXPECT_EQ(absl::UnparseFlag(value), "1"); + value = 0; + EXPECT_EQ(absl::UnparseFlag(value), "0"); + value = 123456789L; + EXPECT_EQ(absl::UnparseFlag(value), "123456789"); + value = absl::MakeUint128(0, 0xFFFFFFFFFFFFFFFF); + EXPECT_EQ(absl::UnparseFlag(value), "18446744073709551615"); +} + +// -------------------------------------------------------------------- + TEST(MarshallingTest, TestFloatUnparsing) { float value; From dfc7f46d9c8425933ffe2c275f982f956d33d06f Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 12 Jun 2023 13:43:18 -0700 Subject: [PATCH 0063/1238] Removes unused methods CRC::Empty() and CRC::Concat() from the internal implementation. PiperOrigin-RevId: 539749773 Change-Id: Iec83431ffd360a077b153cea00427580ae287d1f --- absl/crc/internal/crc.cc | 31 ------------------------------- absl/crc/internal/crc.h | 8 -------- absl/crc/internal/crc_internal.h | 2 -- 3 files changed, 41 deletions(-) diff --git a/absl/crc/internal/crc.cc b/absl/crc/internal/crc.cc index ba4c6d13bdf..22e91c53c68 100644 --- a/absl/crc/internal/crc.cc +++ b/absl/crc/internal/crc.cc @@ -176,9 +176,6 @@ CRCImpl* CRCImpl::NewInternal() { return result; } -// The CRC of the empty string is always the CRC polynomial itself. -void CRCImpl::Empty(uint32_t* crc) const { *crc = kCrc32cPoly; } - // The 32-bit implementation void CRC32::InitTables() { @@ -435,34 +432,6 @@ CRC* CRC::Crc32c() { return singleton; } -// This Concat implementation works for arbitrary polynomials. -void CRC::Concat(uint32_t* px, uint32_t y, size_t ylen) { - // https://en.wikipedia.org/wiki/Mathematics_of_cyclic_redundancy_checks - // The CRC of a message M is the remainder of polynomial division modulo G, - // where the coefficient arithmetic is performed modulo 2 (so +/- are XOR): - // R(x) = M(x) x**n (mod G) - // (n is the degree of G) - // In practice, we use an initial value A and a bitmask B to get - // R = (A ^ B)x**|M| ^ Mx**n ^ B (mod G) - // If M is the concatenation of two strings S and T, and Z is the string of - // len(T) 0s, then the remainder CRC(ST) can be expressed as: - // R = (A ^ B)x**|ST| ^ STx**n ^ B - // = (A ^ B)x**|SZ| ^ SZx**n ^ B ^ Tx**n - // = CRC(SZ) ^ Tx**n - // CRC(Z) = (A ^ B)x**|T| ^ B - // CRC(T) = (A ^ B)x**|T| ^ Tx**n ^ B - // So R = CRC(SZ) ^ CRC(Z) ^ CRC(T) - // - // And further, since CRC(SZ) = Extend(CRC(S), Z), - // CRC(SZ) ^ CRC(Z) = Extend(CRC(S) ^ CRC(''), Z). - uint32_t z; - uint32_t t; - Empty(&z); - t = *px ^ z; - ExtendByZeroes(&t, ylen); - *px = t ^ y; -} - } // namespace crc_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/crc/internal/crc.h b/absl/crc/internal/crc.h index e683c25f9d4..4efdd0325ab 100644 --- a/absl/crc/internal/crc.h +++ b/absl/crc/internal/crc.h @@ -40,9 +40,6 @@ class CRC { public: virtual ~CRC(); - // Place the CRC of the empty string in "*crc" - virtual void Empty(uint32_t* crc) const = 0; - // If "*crc" is the CRC of bytestring A, place the CRC of // the bytestring formed from the concatenation of A and the "length" // bytes at "bytes" into "*crc". @@ -58,11 +55,6 @@ class CRC { // with those zero bytes removed. virtual void UnextendByZeroes(uint32_t* crc, size_t length) const = 0; - // If *px is the CRC (as defined by *crc) of some string X, - // and y is the CRC of some string Y that is ylen bytes long, set - // *px to the CRC of the concatenation of X followed by Y. - virtual void Concat(uint32_t* px, uint32_t y, size_t ylen); - // Apply a non-linear transformation to "*crc" so that // it is safe to CRC the result with the same polynomial without // any reduction of error-detection ability in the outer CRC. diff --git a/absl/crc/internal/crc_internal.h b/absl/crc/internal/crc_internal.h index 7d77bdf586c..4d3582d98fe 100644 --- a/absl/crc/internal/crc_internal.h +++ b/absl/crc/internal/crc_internal.h @@ -70,8 +70,6 @@ class CRCImpl : public CRC { // Implementation of the abstract class CRC // The internal version of CRC::New(). static CRCImpl* NewInternal(); - void Empty(uint32_t* crc) const override; - // Fill in a table for updating a CRC by one word of 'word_size' bytes // [last_lo, last_hi] contains the answer if the last bit in the word // is set. From 77111e3d5b40df6019fedc85198f7376c120bffb Mon Sep 17 00:00:00 2001 From: Tsige Solomon Date: Mon, 12 Jun 2023 15:56:24 -0700 Subject: [PATCH 0064/1238] Functions added: FindLongestCommonSuffix, FindLongestCommonPrefix. PiperOrigin-RevId: 539784770 Change-Id: Ie224afa04af023bbddc89b967e8c8440f9e8a887 --- absl/strings/match.cc | 67 ++++++++++++++++++++- absl/strings/match.h | 10 ++++ absl/strings/match_test.cc | 117 +++++++++++++++++++++++++++++++++++++ 3 files changed, 193 insertions(+), 1 deletion(-) diff --git a/absl/strings/match.cc b/absl/strings/match.cc index b65cbc67a3d..3b81b2c0529 100644 --- a/absl/strings/match.cc +++ b/absl/strings/match.cc @@ -13,8 +13,13 @@ // limitations under the License. #include "absl/strings/match.h" -#include "absl/strings/ascii.h" +#include +#include + +#include "absl/base/internal/endian.h" +#include "absl/numeric/bits.h" +#include "absl/strings/ascii.h" #include "absl/strings/internal/memutil.h" namespace absl { @@ -61,5 +66,65 @@ bool EndsWithIgnoreCase(absl::string_view text, EqualsIgnoreCase(text.substr(text.size() - suffix.size()), suffix); } +absl::string_view FindLongestCommonPrefix(absl::string_view a, + absl::string_view b) { + const absl::string_view::size_type limit = std::min(a.size(), b.size()); + const char* const pa = a.data(); + const char* const pb = b.data(); + absl::string_view::size_type count = (unsigned) 0; + + if (ABSL_PREDICT_FALSE(limit < 8)) { + while (ABSL_PREDICT_TRUE(count + 2 <= limit)) { + uint16_t xor_bytes = absl::little_endian::Load16(pa + count) ^ + absl::little_endian::Load16(pb + count); + if (ABSL_PREDICT_FALSE(xor_bytes != 0)) { + if (ABSL_PREDICT_TRUE((xor_bytes & 0xff) == 0)) ++count; + return absl::string_view(pa, count); + } + count += 2; + } + if (ABSL_PREDICT_TRUE(count != limit)) { + if (ABSL_PREDICT_TRUE(pa[count] == pb[count])) ++count; + } + return absl::string_view(pa, count); + } + + do { + uint64_t xor_bytes = absl::little_endian::Load64(pa + count) ^ + absl::little_endian::Load64(pb + count); + if (ABSL_PREDICT_FALSE(xor_bytes != 0)) { + count += static_cast(absl::countr_zero(xor_bytes) >> 3); + return absl::string_view(pa, count); + } + count += 8; + } while (ABSL_PREDICT_TRUE(count + 8 < limit)); + + count = limit - 8; + uint64_t xor_bytes = absl::little_endian::Load64(pa + count) ^ + absl::little_endian::Load64(pb + count); + if (ABSL_PREDICT_TRUE(xor_bytes != 0)) { + count += static_cast(absl::countr_zero(xor_bytes) >> 3); + return absl::string_view(pa, count); + } + return absl::string_view(pa, limit); +} + +absl::string_view FindLongestCommonSuffix(absl::string_view a, + absl::string_view b) { + const absl::string_view::size_type limit = std::min(a.size(), b.size()); + if (limit == 0) return absl::string_view(); + + const char* pa = a.data() + a.size() - 1; + const char* pb = b.data() + b.size() - 1; + absl::string_view::size_type count = (unsigned) 0; + while (count < limit && *pa == *pb) { + --pa; + --pb; + ++count; + } + + return absl::string_view(++pa, count); +} + ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/strings/match.h b/absl/strings/match.h index 1dc0beaff65..1eeafbbf679 100644 --- a/absl/strings/match.h +++ b/absl/strings/match.h @@ -103,6 +103,16 @@ bool StartsWithIgnoreCase(absl::string_view text, bool EndsWithIgnoreCase(absl::string_view text, absl::string_view suffix) noexcept; +// Yields the longest prefix in common between both input strings. +// Pointer-wise, the returned result is a subset of input "a". +absl::string_view FindLongestCommonPrefix(absl::string_view a, + absl::string_view b); + +// Yields the longest suffix in common between both input strings. +// Pointer-wise, the returned result is a subset of input "a". +absl::string_view FindLongestCommonSuffix(absl::string_view a, + absl::string_view b); + ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/strings/match_test.cc b/absl/strings/match_test.cc index f063b4ea6cf..71618f71f0c 100644 --- a/absl/strings/match_test.cc +++ b/absl/strings/match_test.cc @@ -168,4 +168,121 @@ TEST(MatchTest, ContainsCharIgnoreCase) { EXPECT_FALSE(absl::StrContainsIgnoreCase("", '0')); } +TEST(MatchTest, FindLongestCommonPrefix) { + EXPECT_EQ(absl::FindLongestCommonPrefix("", ""), ""); + EXPECT_EQ(absl::FindLongestCommonPrefix("", "abc"), ""); + EXPECT_EQ(absl::FindLongestCommonPrefix("abc", ""), ""); + EXPECT_EQ(absl::FindLongestCommonPrefix("ab", "abc"), "ab"); + EXPECT_EQ(absl::FindLongestCommonPrefix("abc", "ab"), "ab"); + EXPECT_EQ(absl::FindLongestCommonPrefix("abc", "abd"), "ab"); + EXPECT_EQ(absl::FindLongestCommonPrefix("abc", "abcd"), "abc"); + EXPECT_EQ(absl::FindLongestCommonPrefix("abcd", "abcd"), "abcd"); + EXPECT_EQ(absl::FindLongestCommonPrefix("abcd", "efgh"), ""); + + // "abcde" v. "abc" but in the middle of other data + EXPECT_EQ(absl::FindLongestCommonPrefix( + absl::string_view("1234 abcdef").substr(5, 5), + absl::string_view("5678 abcdef").substr(5, 3)), + "abc"); +} + +// Since the little-endian implementation involves a bit of if-else and various +// return paths, the following tests aims to provide full test coverage of the +// implementation. +TEST(MatchTest, FindLongestCommonPrefixLoad16Mismatch) { + const std::string x1 = "abcdefgh"; + const std::string x2 = "abcde_"; + EXPECT_EQ(absl::FindLongestCommonPrefix(x1, x2), "abcde"); + EXPECT_EQ(absl::FindLongestCommonPrefix(x2, x1), "abcde"); +} + +TEST(MatchTest, FindLongestCommonPrefixLoad16MatchesNoLast) { + const std::string x1 = "abcdef"; + const std::string x2 = "abcdef"; + EXPECT_EQ(absl::FindLongestCommonPrefix(x1, x2), "abcdef"); + EXPECT_EQ(absl::FindLongestCommonPrefix(x2, x1), "abcdef"); +} + +TEST(MatchTest, FindLongestCommonPrefixLoad16MatchesLastCharMismatches) { + const std::string x1 = "abcdefg"; + const std::string x2 = "abcdef_h"; + EXPECT_EQ(absl::FindLongestCommonPrefix(x1, x2), "abcdef"); + EXPECT_EQ(absl::FindLongestCommonPrefix(x2, x1), "abcdef"); +} + +TEST(MatchTest, FindLongestCommonPrefixLoad16MatchesLastMatches) { + const std::string x1 = "abcde"; + const std::string x2 = "abcdefgh"; + EXPECT_EQ(absl::FindLongestCommonPrefix(x1, x2), "abcde"); + EXPECT_EQ(absl::FindLongestCommonPrefix(x2, x1), "abcde"); +} + +TEST(MatchTest, FindLongestCommonPrefixSize8Load64Mismatches) { + const std::string x1 = "abcdefghijk"; + const std::string x2 = "abcde_g_"; + EXPECT_EQ(absl::FindLongestCommonPrefix(x1, x2), "abcde"); + EXPECT_EQ(absl::FindLongestCommonPrefix(x2, x1), "abcde"); +} + +TEST(MatchTest, FindLongestCommonPrefixSize8Load64Matches) { + const std::string x1 = "abcdefgh"; + const std::string x2 = "abcdefgh"; + EXPECT_EQ(absl::FindLongestCommonPrefix(x1, x2), "abcdefgh"); + EXPECT_EQ(absl::FindLongestCommonPrefix(x2, x1), "abcdefgh"); +} + +TEST(MatchTest, FindLongestCommonPrefixSize15Load64Mismatches) { + const std::string x1 = "012345670123456"; + const std::string x2 = "0123456701_34_6"; + EXPECT_EQ(absl::FindLongestCommonPrefix(x1, x2), "0123456701"); + EXPECT_EQ(absl::FindLongestCommonPrefix(x2, x1), "0123456701"); +} + +TEST(MatchTest, FindLongestCommonPrefixSize15Load64Matches) { + const std::string x1 = "012345670123456"; + const std::string x2 = "0123456701234567"; + EXPECT_EQ(absl::FindLongestCommonPrefix(x1, x2), "012345670123456"); + EXPECT_EQ(absl::FindLongestCommonPrefix(x2, x1), "012345670123456"); +} + +TEST(MatchTest, FindLongestCommonPrefixSizeFirstByteOfLast8BytesMismatch) { + const std::string x1 = "012345670123456701234567"; + const std::string x2 = "0123456701234567_1234567"; + EXPECT_EQ(absl::FindLongestCommonPrefix(x1, x2), "0123456701234567"); + EXPECT_EQ(absl::FindLongestCommonPrefix(x2, x1), "0123456701234567"); +} + +TEST(MatchTest, FindLongestCommonPrefixLargeLastCharMismatches) { + const std::string x1(300, 'x'); + std::string x2 = x1; + x2.back() = '#'; + EXPECT_EQ(absl::FindLongestCommonPrefix(x1, x2), std::string(299, 'x')); + EXPECT_EQ(absl::FindLongestCommonPrefix(x2, x1), std::string(299, 'x')); +} + +TEST(MatchTest, FindLongestCommonPrefixLargeFullMatch) { + const std::string x1(300, 'x'); + const std::string x2 = x1; + EXPECT_EQ(absl::FindLongestCommonPrefix(x1, x2), std::string(300, 'x')); + EXPECT_EQ(absl::FindLongestCommonPrefix(x2, x1), std::string(300, 'x')); +} + +TEST(MatchTest, FindLongestCommonSuffix) { + EXPECT_EQ(absl::FindLongestCommonSuffix("", ""), ""); + EXPECT_EQ(absl::FindLongestCommonSuffix("", "abc"), ""); + EXPECT_EQ(absl::FindLongestCommonSuffix("abc", ""), ""); + EXPECT_EQ(absl::FindLongestCommonSuffix("bc", "abc"), "bc"); + EXPECT_EQ(absl::FindLongestCommonSuffix("abc", "bc"), "bc"); + EXPECT_EQ(absl::FindLongestCommonSuffix("abc", "dbc"), "bc"); + EXPECT_EQ(absl::FindLongestCommonSuffix("bcd", "abcd"), "bcd"); + EXPECT_EQ(absl::FindLongestCommonSuffix("abcd", "abcd"), "abcd"); + EXPECT_EQ(absl::FindLongestCommonSuffix("abcd", "efgh"), ""); + + // "abcde" v. "cde" but in the middle of other data + EXPECT_EQ(absl::FindLongestCommonSuffix( + absl::string_view("1234 abcdef").substr(5, 5), + absl::string_view("5678 abcdef").substr(7, 3)), + "cde"); +} + } // namespace From 8a1b239cce0cb1997f9f1a896ed27d87cd4d8434 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 13 Jun 2023 02:25:41 -0700 Subject: [PATCH 0065/1238] Remove two_ASCII_digits and replace with a scalar algorithm PiperOrigin-RevId: 539900072 Change-Id: I675386e3184f6f5ab70b851add970c91d1dde9c5 --- absl/log/internal/log_format.cc | 18 +++++++++------- absl/strings/internal/str_format/arg.cc | 2 +- absl/strings/numbers.cc | 28 ++++++++----------------- absl/strings/numbers.h | 7 +------ 4 files changed, 21 insertions(+), 34 deletions(-) diff --git a/absl/log/internal/log_format.cc b/absl/log/internal/log_format.cc index 0dcbc795b2e..23cef88a24c 100644 --- a/absl/log/internal/log_format.cc +++ b/absl/log/internal/log_format.cc @@ -113,27 +113,29 @@ size_t FormatBoundedFields(absl::LogSeverity severity, absl::Time timestamp, char* p = buf.data(); *p++ = absl::LogSeverityName(severity)[0]; const absl::TimeZone::CivilInfo ci = tz->At(timestamp); - absl::numbers_internal::PutTwoDigits(static_cast(ci.cs.month()), p); + absl::numbers_internal::PutTwoDigits(static_cast(ci.cs.month()), p); p += 2; - absl::numbers_internal::PutTwoDigits(static_cast(ci.cs.day()), p); + absl::numbers_internal::PutTwoDigits(static_cast(ci.cs.day()), p); p += 2; *p++ = ' '; - absl::numbers_internal::PutTwoDigits(static_cast(ci.cs.hour()), p); + absl::numbers_internal::PutTwoDigits(static_cast(ci.cs.hour()), p); p += 2; *p++ = ':'; - absl::numbers_internal::PutTwoDigits(static_cast(ci.cs.minute()), p); + absl::numbers_internal::PutTwoDigits(static_cast(ci.cs.minute()), + p); p += 2; *p++ = ':'; - absl::numbers_internal::PutTwoDigits(static_cast(ci.cs.second()), p); + absl::numbers_internal::PutTwoDigits(static_cast(ci.cs.second()), + p); p += 2; *p++ = '.'; const int64_t usecs = absl::ToInt64Microseconds(ci.subsecond); - absl::numbers_internal::PutTwoDigits(static_cast(usecs / 10000), p); + absl::numbers_internal::PutTwoDigits(static_cast(usecs / 10000), p); p += 2; - absl::numbers_internal::PutTwoDigits(static_cast(usecs / 100 % 100), + absl::numbers_internal::PutTwoDigits(static_cast(usecs / 100 % 100), p); p += 2; - absl::numbers_internal::PutTwoDigits(static_cast(usecs % 100), p); + absl::numbers_internal::PutTwoDigits(static_cast(usecs % 100), p); p += 2; *p++ = ' '; PutLeadingWhitespace(tid, p); diff --git a/absl/strings/internal/str_format/arg.cc b/absl/strings/internal/str_format/arg.cc index 7f4057f9581..c0a9a28ef9d 100644 --- a/absl/strings/internal/str_format/arg.cc +++ b/absl/strings/internal/str_format/arg.cc @@ -106,7 +106,7 @@ class IntDigits { char *p = storage_ + sizeof(storage_); do { p -= 2; - numbers_internal::PutTwoDigits(static_cast(v % 100), p); + numbers_internal::PutTwoDigits(static_cast(v % 100), p); v /= 100; } while (v); if (p[0] == '0') { diff --git a/absl/strings/numbers.cc b/absl/strings/numbers.cc index 7dc89224eb7..c43c6bcc195 100644 --- a/absl/strings/numbers.cc +++ b/absl/strings/numbers.cc @@ -242,6 +242,15 @@ inline char* EncodeFullU32(uint32_t n, char* out_str) { } // namespace +void numbers_internal::PutTwoDigits(uint32_t i, char* buf) { + assert(i < 100); + uint32_t base = kTwoZeroBytes; + uint32_t div10 = (i * kDivisionBy10Mul) / kDivisionBy10Div; + uint32_t mod10 = i - 10u * div10; + base += div10 + (mod10 << 8); + little_endian::Store16(buf, static_cast(base)); +} + char* numbers_internal::FastIntToBuffer(uint32_t n, char* out_str) { if (n < 100) { out_str = EncodeHundred(n, out_str); @@ -1090,25 +1099,6 @@ ABSL_CONST_INIT ABSL_DLL const char kHexTable[513] = "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; -ABSL_CONST_INIT ABSL_DLL const char two_ASCII_digits[100][2] = { - {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'}, - {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, {'1', '0'}, {'1', '1'}, - {'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'}, - {'1', '8'}, {'1', '9'}, {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'}, - {'2', '4'}, {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'}, - {'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, {'3', '5'}, - {'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'}, {'4', '0'}, {'4', '1'}, - {'4', '2'}, {'4', '3'}, {'4', '4'}, {'4', '5'}, {'4', '6'}, {'4', '7'}, - {'4', '8'}, {'4', '9'}, {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'}, - {'5', '4'}, {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'}, - {'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, {'6', '5'}, - {'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'}, {'7', '0'}, {'7', '1'}, - {'7', '2'}, {'7', '3'}, {'7', '4'}, {'7', '5'}, {'7', '6'}, {'7', '7'}, - {'7', '8'}, {'7', '9'}, {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'}, - {'8', '4'}, {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'}, - {'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'}, - {'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}}; - bool safe_strto32_base(absl::string_view text, int32_t* value, int base) { return safe_int_internal(text, value, base); } diff --git a/absl/strings/numbers.h b/absl/strings/numbers.h index 86c84ed39b7..d7630cef9c1 100644 --- a/absl/strings/numbers.h +++ b/absl/strings/numbers.h @@ -125,8 +125,6 @@ namespace numbers_internal { ABSL_DLL extern const char kHexChar[17]; // 0123456789abcdef ABSL_DLL extern const char kHexTable[513]; // 000102030405060708090a0b0c0d0e0f1011... -ABSL_DLL extern const char - two_ASCII_digits[100][2]; // 00, 01, 02, 03... // Writes a two-character representation of 'i' to 'buf'. 'i' must be in the // range 0 <= i < 100, and buf must have space for two characters. Example: @@ -134,10 +132,7 @@ ABSL_DLL extern const char // PutTwoDigits(42, buf); // // buf[0] == '4' // // buf[1] == '2' -inline void PutTwoDigits(size_t i, char* buf) { - assert(i < 100); - memcpy(buf, two_ASCII_digits[i], 2); -} +void PutTwoDigits(uint32_t i, char* buf); // safe_strto?() functions for implementing SimpleAtoi() From dc37a887fdc3d91ec9a67b93af9fa4c1ccb02545 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Tue, 13 Jun 2023 07:41:19 -0700 Subject: [PATCH 0066/1238] CI: Update the Docker container used to test Alpine Linux PiperOrigin-RevId: 539960446 Change-Id: If2de8bf32ffeed849280f78f8ac0685e11e80f59 --- ci/linux_docker_containers.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/linux_docker_containers.sh b/ci/linux_docker_containers.sh index 4dfa3175f21..a07c64ce103 100644 --- a/ci/linux_docker_containers.sh +++ b/ci/linux_docker_containers.sh @@ -15,7 +15,7 @@ # The file contains Docker container identifiers currently used by test scripts. # Test scripts should source this file to get the identifiers. -readonly LINUX_ALPINE_CONTAINER="gcr.io/google.com/absl-177019/alpine:20201026" +readonly LINUX_ALPINE_CONTAINER="gcr.io/google.com/absl-177019/alpine:20230612" readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20230217" readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20230517" readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20230120" From 4a82a1f4699348673426e255bbf8f8d8fadc7682 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 14 Jun 2023 13:41:04 -0700 Subject: [PATCH 0067/1238] For web assembly, implement raw logging as direct JS console logging. This bypasses the need for filesystem APIs just for stderr access. PiperOrigin-RevId: 540367155 Change-Id: Ib91dadac28cb5c8e571407b5dfa60c3e65539c95 --- absl/base/internal/raw_logging.cc | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/absl/base/internal/raw_logging.cc b/absl/base/internal/raw_logging.cc index 6273e8471bc..5ea49bca2aa 100644 --- a/absl/base/internal/raw_logging.cc +++ b/absl/base/internal/raw_logging.cc @@ -21,6 +21,10 @@ #include #include +#ifdef __EMSCRIPTEN__ +#include +#endif + #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/internal/atomic_hook.h" @@ -203,7 +207,27 @@ void DefaultInternalLog(absl::LogSeverity severity, const char* file, int line, void AsyncSignalSafeWriteToStderr(const char* s, size_t len) { absl::base_internal::ErrnoSaver errno_saver; -#if defined(ABSL_HAVE_SYSCALL_WRITE) +#if defined(__EMSCRIPTEN__) + // In WebAssembly, bypass filesystem emulation via fwrite. + // TODO(b/282811932): Avoid this copy if these emscripten functions can + // be updated to accept size directly. + char buf[kLogBufSize]; + if (len >= kLogBufSize) { + len = kLogBufSize - 1; + size_t trunc_len = sizeof(kTruncated) - 2; + strncpy(buf + len - trunc_len, kTruncated, trunc_len); + buf[len] = '\0'; + len -= trunc_len; + } else if (len && s[len - 1] == '\n') { + len--; + } + strncpy(buf, s, len); + if (len) { + buf[len] = '\0'; + // Skip a trailing newline character as emscripten_err adds one itself. + _emscripten_err(buf); + } +#elif defined(ABSL_HAVE_SYSCALL_WRITE) // We prefer calling write via `syscall` to minimize the risk of libc doing // something "helpful". syscall(SYS_write, STDERR_FILENO, s, len); From 5922d12960110b75e8fe7f8a7ea1a1d6a5bec708 Mon Sep 17 00:00:00 2001 From: Tsige Solomon Date: Thu, 15 Jun 2023 08:17:16 -0700 Subject: [PATCH 0068/1238] Bug fix PiperOrigin-RevId: 540586646 Change-Id: Iac1e133647fbaa5036ac9ef7322f9af5886c658e --- absl/flags/marshalling.cc | 6 +- absl/flags/marshalling_test.cc | 137 ++++++++++++++------------------- 2 files changed, 62 insertions(+), 81 deletions(-) diff --git a/absl/flags/marshalling.cc b/absl/flags/marshalling.cc index 50b7b33170a..dc69754f000 100644 --- a/absl/flags/marshalling.cc +++ b/absl/flags/marshalling.cc @@ -70,8 +70,10 @@ bool AbslParseFlag(absl::string_view text, bool* dst, std::string*) { // puts us in base 16. But leading 0 does not put us in base 8. It // caused too many bugs when we had that behavior. static int NumericBase(absl::string_view text) { - const bool hex = (text.size() >= 2 && text[0] == '0' && - (text[1] == 'x' || text[1] == 'X')); + if (text.empty()) return 0; + size_t num_start = (text[0] == '-' || text[0] == '+') ? 1 : 0; + const bool hex = (text.size() >= num_start + 2 && text[num_start] == '0' && + (text[num_start + 1] == 'x' || text[num_start + 1] == 'X')); return hex ? 16 : 10; } diff --git a/absl/flags/marshalling_test.cc b/absl/flags/marshalling_test.cc index 57356672258..b0e055f5f62 100644 --- a/absl/flags/marshalling_test.cc +++ b/absl/flags/marshalling_test.cc @@ -137,11 +137,10 @@ TEST(MarshallingTest, TestInt16Parsing) { EXPECT_EQ(value, 16); EXPECT_TRUE(absl::ParseFlag("0X234", &value, &err)); EXPECT_EQ(value, 564); - // TODO(rogeeff): fix below validations - EXPECT_FALSE(absl::ParseFlag("-0x7FFD", &value, &err)); - EXPECT_NE(value, -3); - EXPECT_FALSE(absl::ParseFlag("+0x31", &value, &err)); - EXPECT_NE(value, 49); + EXPECT_TRUE(absl::ParseFlag("-0x7FFD", &value, &err)); + EXPECT_EQ(value, -32765); + EXPECT_TRUE(absl::ParseFlag("+0x31", &value, &err)); + EXPECT_EQ(value, 49); // Whitespace handling EXPECT_TRUE(absl::ParseFlag("10 ", &value, &err)); @@ -194,9 +193,8 @@ TEST(MarshallingTest, TestUint16Parsing) { EXPECT_EQ(value, 16); EXPECT_TRUE(absl::ParseFlag("0X234", &value, &err)); EXPECT_EQ(value, 564); - // TODO(rogeeff): fix below validations - EXPECT_FALSE(absl::ParseFlag("+0x31", &value, &err)); - EXPECT_NE(value, 49); + EXPECT_TRUE(absl::ParseFlag("+0x31", &value, &err)); + EXPECT_EQ(value, 49); // Whitespace handling EXPECT_TRUE(absl::ParseFlag("10 ", &value, &err)); @@ -254,11 +252,11 @@ TEST(MarshallingTest, TestInt32Parsing) { EXPECT_EQ(value, 16); EXPECT_TRUE(absl::ParseFlag("0X234", &value, &err)); EXPECT_EQ(value, 564); - // TODO(rogeeff): fix below validations - EXPECT_FALSE(absl::ParseFlag("-0x7FFFFFFD", &value, &err)); - EXPECT_NE(value, -3); - EXPECT_FALSE(absl::ParseFlag("+0x31", &value, &err)); - EXPECT_NE(value, 49); + + EXPECT_TRUE(absl::ParseFlag("-0x7FFFFFFD", &value, &err)); + EXPECT_EQ(value, -2147483645); + EXPECT_TRUE(absl::ParseFlag("+0x31", &value, &err)); + EXPECT_EQ(value, 49); // Whitespace handling EXPECT_TRUE(absl::ParseFlag("10 ", &value, &err)); @@ -311,9 +309,8 @@ TEST(MarshallingTest, TestUint32Parsing) { EXPECT_EQ(value, 564); EXPECT_TRUE(absl::ParseFlag("0xFFFFFFFD", &value, &err)); EXPECT_EQ(value, 4294967293); - // TODO(rogeeff): fix below validations - EXPECT_FALSE(absl::ParseFlag("+0x31", &value, &err)); - EXPECT_NE(value, 49); + EXPECT_TRUE(absl::ParseFlag("+0x31", &value, &err)); + EXPECT_EQ(value, 49); // Whitespace handling EXPECT_TRUE(absl::ParseFlag("10 ", &value, &err)); @@ -371,11 +368,12 @@ TEST(MarshallingTest, TestInt64Parsing) { EXPECT_EQ(value, 16); EXPECT_TRUE(absl::ParseFlag("0XFFFAAABBBCCCDDD", &value, &err)); EXPECT_EQ(value, 1152827684197027293); - // TODO(rogeeff): fix below validation - EXPECT_FALSE(absl::ParseFlag("-0x7FFFFFFFFFFFFFFE", &value, &err)); - EXPECT_NE(value, -2); - EXPECT_FALSE(absl::ParseFlag("+0x31", &value, &err)); - EXPECT_NE(value, 49); + EXPECT_TRUE(absl::ParseFlag("-0x7FFFFFFFFFFFFFFE", &value, &err)); + EXPECT_EQ(value, -9223372036854775806); + EXPECT_TRUE(absl::ParseFlag("-0x02", &value, &err)); + EXPECT_EQ(value, -2); + EXPECT_TRUE(absl::ParseFlag("+0x31", &value, &err)); + EXPECT_EQ(value, 49); // Whitespace handling EXPECT_TRUE(absl::ParseFlag("10 ", &value, &err)); @@ -428,9 +426,8 @@ TEST(MarshallingTest, TestUInt64Parsing) { EXPECT_EQ(value, 16); EXPECT_TRUE(absl::ParseFlag("0XFFFF", &value, &err)); EXPECT_EQ(value, 65535); - // TODO(rogeeff): fix below validation - EXPECT_FALSE(absl::ParseFlag("+0x31", &value, &err)); - EXPECT_NE(value, 49); + EXPECT_TRUE(absl::ParseFlag("+0x31", &value, &err)); + EXPECT_EQ(value, 49); // Whitespace handling EXPECT_TRUE(absl::ParseFlag("10 ", &value, &err)); @@ -459,60 +456,50 @@ TEST(MarshallingTest, TestInt128Parsing) { std::string err; absl::int128 value; - absl::int128 zero = 0; - absl::int128 one = 1; - absl::int128 neg_one = -1; - absl::int128 hundred = 100; - absl::int128 hundreds_val = 123; - absl::int128 neg_thousands_val = -98765; - absl::int128 pos_three = 3; - // Decimal values. EXPECT_TRUE(absl::ParseFlag("0", &value, &err)); - EXPECT_EQ(value, zero); + EXPECT_EQ(value, 0); EXPECT_TRUE(absl::ParseFlag("1", &value, &err)); - EXPECT_EQ(value, one); + EXPECT_EQ(value, 1); EXPECT_TRUE(absl::ParseFlag("-1", &value, &err)); - EXPECT_EQ(value, neg_one); + EXPECT_EQ(value, -1); EXPECT_TRUE(absl::ParseFlag("123", &value, &err)); - EXPECT_EQ(value, hundreds_val); + EXPECT_EQ(value, 123); EXPECT_TRUE(absl::ParseFlag("-98765", &value, &err)); - EXPECT_EQ(value, neg_thousands_val); + EXPECT_EQ(value, -98765); EXPECT_TRUE(absl::ParseFlag("+3", &value, &err)); - EXPECT_EQ(value, pos_three); + EXPECT_EQ(value, 3); // Leading zero values. EXPECT_TRUE(absl::ParseFlag("01", &value, &err)); - EXPECT_EQ(value, one); + EXPECT_EQ(value, 1); EXPECT_TRUE(absl::ParseFlag("001", &value, &err)); - EXPECT_EQ(value, one); + EXPECT_EQ(value, 1); EXPECT_TRUE(absl::ParseFlag("0000100", &value, &err)); - EXPECT_EQ(value, hundred); - - absl::int128 sixteen = 16; - absl::int128 quintillion_val = 1152827684197027293; - absl::int128 quintillion_val2 = - absl::MakeInt128(0x000000000000fff, 0xFFFFFFFFFFFFFFF); + EXPECT_EQ(value, 100); // Hex values. EXPECT_TRUE(absl::ParseFlag("0x10", &value, &err)); - EXPECT_EQ(value, sixteen); + EXPECT_EQ(value, 16); EXPECT_TRUE(absl::ParseFlag("0xFFFAAABBBCCCDDD", &value, &err)); - EXPECT_EQ(value, quintillion_val); + EXPECT_EQ(value, 1152827684197027293); EXPECT_TRUE(absl::ParseFlag("0xFFF0FFFFFFFFFFFFFFF", &value, &err)); - EXPECT_EQ(value, quintillion_val2); + EXPECT_EQ(value, absl::MakeInt128(0x000000000000fff, 0xFFFFFFFFFFFFFFF)); - // TODO(b/285183223): Add support for parsing negative hex representation + EXPECT_TRUE(absl::ParseFlag("-0x10000000000000000", &value, &err)); + EXPECT_EQ(value, absl::MakeInt128(-1, 0)); + EXPECT_TRUE(absl::ParseFlag("+0x31", &value, &err)); + EXPECT_EQ(value, 49); // Whitespace handling EXPECT_TRUE(absl::ParseFlag("16 ", &value, &err)); - EXPECT_EQ(value, sixteen); + EXPECT_EQ(value, 16); EXPECT_TRUE(absl::ParseFlag(" 16", &value, &err)); - EXPECT_EQ(value, sixteen); + EXPECT_EQ(value, 16); EXPECT_TRUE(absl::ParseFlag(" 0100 ", &value, &err)); - EXPECT_EQ(value, hundred); + EXPECT_EQ(value, 100); EXPECT_TRUE(absl::ParseFlag(" 0x7B ", &value, &err)); - EXPECT_EQ(value, hundreds_val); // =123 + EXPECT_EQ(value, 123); // Invalid values. EXPECT_FALSE(absl::ParseFlag("", &value, &err)); @@ -531,52 +518,43 @@ TEST(MarshallingTest, TestUint128Parsing) { std::string err; absl::uint128 value; - absl::uint128 zero = 0; - absl::uint128 one = 1; - absl::uint128 hundred = 100; - absl::uint128 hundreds_val = 123; - absl::uint128 pos_three = 3; - // Decimal values. EXPECT_TRUE(absl::ParseFlag("0", &value, &err)); - EXPECT_EQ(value, zero); + EXPECT_EQ(value, 0); EXPECT_TRUE(absl::ParseFlag("1", &value, &err)); - EXPECT_EQ(value, one); + EXPECT_EQ(value, 1); EXPECT_TRUE(absl::ParseFlag("123", &value, &err)); - EXPECT_EQ(value, hundreds_val); + EXPECT_EQ(value, 123); EXPECT_TRUE(absl::ParseFlag("+3", &value, &err)); - EXPECT_EQ(value, pos_three); + EXPECT_EQ(value, 3); // Leading zero values. EXPECT_TRUE(absl::ParseFlag("01", &value, &err)); - EXPECT_EQ(value, one); + EXPECT_EQ(value, 1); EXPECT_TRUE(absl::ParseFlag("001", &value, &err)); - EXPECT_EQ(value, one); + EXPECT_EQ(value, 1); EXPECT_TRUE(absl::ParseFlag("0000100", &value, &err)); - EXPECT_EQ(value, hundred); - - absl::uint128 sixteen = 16; - absl::uint128 quintillion_val = 1152827684197027293; - absl::uint128 quintillion_val2 = - absl::MakeInt128(0x000000000000fff, 0xFFFFFFFFFFFFFFF); + EXPECT_EQ(value, 100); // Hex values. EXPECT_TRUE(absl::ParseFlag("0x10", &value, &err)); - EXPECT_EQ(value, sixteen); + EXPECT_EQ(value, 16); EXPECT_TRUE(absl::ParseFlag("0xFFFAAABBBCCCDDD", &value, &err)); - EXPECT_EQ(value, quintillion_val); + EXPECT_EQ(value, 1152827684197027293); EXPECT_TRUE(absl::ParseFlag("0xFFF0FFFFFFFFFFFFFFF", &value, &err)); - EXPECT_EQ(value, quintillion_val2); + EXPECT_EQ(value, absl::MakeInt128(0x000000000000fff, 0xFFFFFFFFFFFFFFF)); + EXPECT_TRUE(absl::ParseFlag("+0x31", &value, &err)); + EXPECT_EQ(value, 49); // Whitespace handling EXPECT_TRUE(absl::ParseFlag("16 ", &value, &err)); - EXPECT_EQ(value, sixteen); + EXPECT_EQ(value, 16); EXPECT_TRUE(absl::ParseFlag(" 16", &value, &err)); - EXPECT_EQ(value, sixteen); + EXPECT_EQ(value, 16); EXPECT_TRUE(absl::ParseFlag(" 0100 ", &value, &err)); - EXPECT_EQ(value, hundred); + EXPECT_EQ(value, 100); EXPECT_TRUE(absl::ParseFlag(" 0x7B ", &value, &err)); - EXPECT_EQ(value, hundreds_val); // =123 + EXPECT_EQ(value, 123); // Invalid values. EXPECT_FALSE(absl::ParseFlag("", &value, &err)); @@ -588,6 +566,7 @@ TEST(MarshallingTest, TestUint128Parsing) { EXPECT_FALSE(absl::ParseFlag("\t", &value, &err)); EXPECT_FALSE(absl::ParseFlag("2U", &value, &err)); EXPECT_FALSE(absl::ParseFlag("FFF", &value, &err)); + EXPECT_FALSE(absl::ParseFlag("-0x10000000000000000", &value, &err)); } // -------------------------------------------------------------------- From 04e0dcae14f6bde8f4feec4516b12d4f787a517f Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 15 Jun 2023 12:18:13 -0700 Subject: [PATCH 0069/1238] Rename AsyncSignalSafeWriteToStderr to AsyncSignalSafeWriteError. It no longer strictly writes to stderr, since Emscripten/WebAssembly now use _emscripten_err which might be replaced by something that is not the same as stderr by the host. PiperOrigin-RevId: 540655336 Change-Id: Icc2a430a0db53a1282ef5558e9f3648db67e972c --- absl/base/internal/raw_logging.cc | 4 ++-- absl/base/internal/raw_logging.h | 2 +- absl/debugging/failure_signal_handler.cc | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/absl/base/internal/raw_logging.cc b/absl/base/internal/raw_logging.cc index 5ea49bca2aa..c866d957e90 100644 --- a/absl/base/internal/raw_logging.cc +++ b/absl/base/internal/raw_logging.cc @@ -177,7 +177,7 @@ void RawLogVA(absl::LogSeverity severity, const char* file, int line, } else { DoRawLog(&buf, &size, "%s", kTruncated); } - AsyncSignalSafeWriteToStderr(buffer, strlen(buffer)); + AsyncSignalSafeWriteError(buffer, strlen(buffer)); } #else static_cast(format); @@ -205,7 +205,7 @@ void DefaultInternalLog(absl::LogSeverity severity, const char* file, int line, } // namespace -void AsyncSignalSafeWriteToStderr(const char* s, size_t len) { +void AsyncSignalSafeWriteError(const char* s, size_t len) { absl::base_internal::ErrnoSaver errno_saver; #if defined(__EMSCRIPTEN__) // In WebAssembly, bypass filesystem emulation via fwrite. diff --git a/absl/base/internal/raw_logging.h b/absl/base/internal/raw_logging.h index 3f852d31c38..b79550b2b75 100644 --- a/absl/base/internal/raw_logging.h +++ b/absl/base/internal/raw_logging.h @@ -130,7 +130,7 @@ void RawLog(absl::LogSeverity severity, const char* file, int line, // Writes the provided buffer directly to stderr, in a signal-safe, low-level // manner. Preserves errno. -void AsyncSignalSafeWriteToStderr(const char* s, size_t len); +void AsyncSignalSafeWriteError(const char* s, size_t len); // compile-time function to get the "base" filename, that is, the part of // a filename after the last "/" or "\" path separator. The search starts at diff --git a/absl/debugging/failure_signal_handler.cc b/absl/debugging/failure_signal_handler.cc index 0db2a896828..fd6a49273eb 100644 --- a/absl/debugging/failure_signal_handler.cc +++ b/absl/debugging/failure_signal_handler.cc @@ -378,8 +378,7 @@ static void AbslFailureSignalHandler(int signo, siginfo_t*, void* ucontext) { // First write to stderr. WriteFailureInfo( signo, ucontext, my_cpu, +[](const char* data) { - absl::raw_log_internal::AsyncSignalSafeWriteToStderr(data, - strlen(data)); + absl::raw_log_internal::AsyncSignalSafeWriteError(data, strlen(data)); }); // Riskier code (because it is less likely to be async-signal-safe) From bf69aa3ca20aa04350fbd04efd8ac7ad4bb22e79 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 15 Jun 2023 12:18:37 -0700 Subject: [PATCH 0070/1238] The current aarch64 large-stack frame error handling is unsophisticated, which makes it give up in certain situations where the x86 handler works fine This change adopts x86's more sophisticated stack-bounds-checking method for aarch64, and enables the HugeStack test to pass on aarch64. PiperOrigin-RevId: 540655431 Change-Id: If7d816330327722bbe5c135abfa77fda5e7e452b --- .../internal/stacktrace_aarch64-inl.inc | 43 +++++++++++++++---- absl/debugging/stacktrace_test.cc | 4 +- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/absl/debugging/internal/stacktrace_aarch64-inl.inc b/absl/debugging/internal/stacktrace_aarch64-inl.inc index 520e9a84787..c8b84397949 100644 --- a/absl/debugging/internal/stacktrace_aarch64-inl.inc +++ b/absl/debugging/internal/stacktrace_aarch64-inl.inc @@ -20,6 +20,10 @@ #include "absl/debugging/stacktrace.h" static const size_t kUnknownFrameSize = 0; +// Stack end to use when we don't know the actual stack end +// (effectively just the end of address space). +constexpr uintptr_t kUnknownStackEnd = + std::numeric_limits::max() - sizeof(void *); #if defined(__linux__) // Returns the address of the VDSO __kernel_rt_sigreturn function, if present. @@ -79,8 +83,9 @@ static inline size_t ComputeStackFrameSize(const T* low, // "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned. template ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. -ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. -static void **NextStackFrame(void **old_frame_pointer, const void *uc) { +ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. +static void **NextStackFrame(void **old_frame_pointer, const void *uc, + size_t stack_low, size_t stack_high) { void **new_frame_pointer = reinterpret_cast(*old_frame_pointer); bool check_frame_size = true; @@ -126,8 +131,26 @@ static void **NextStackFrame(void **old_frame_pointer, const void *uc) { const size_t max_size = STRICT_UNWINDING ? 100000 : 1000000; const size_t frame_size = ComputeStackFrameSize(old_frame_pointer, new_frame_pointer); - if (frame_size == kUnknownFrameSize || frame_size > max_size) - return nullptr; + if (frame_size == kUnknownFrameSize) + return nullptr; + // A very large frame may mean corrupt memory or an erroneous frame + // pointer. But also maybe just a plain-old large frame. Assume that if the + // frame is within the known stack, then it is valid. + if (frame_size > max_size) { + if (stack_high < kUnknownStackEnd && + static_cast(getpagesize()) < stack_low) { + const uintptr_t new_fp_u = + reinterpret_cast(new_frame_pointer); + // Stack bounds are known. + if (!(stack_low < new_fp_u && new_fp_u <= stack_high)) { + // new_frame_pointer is not within the known stack. + return nullptr; + } + } else { + // Stack bounds are unknown, prefer truncated stack to possible crash. + return nullptr; + } + } } return new_frame_pointer; @@ -146,6 +169,10 @@ static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, skip_count++; // Skip the frame for this function. int n = 0; + // Assume that the first page is not stack. + size_t stack_low = static_cast(getpagesize()); + size_t stack_high = kUnknownStackEnd; + // The frame pointer points to low address of a frame. The first 64-bit // word of a frame points to the next frame up the call chain, which normally // is just after the high address of the current frame. The second word of @@ -178,8 +205,8 @@ static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, // Use the non-strict unwinding rules to produce a stack trace // that is as complete as possible (even if it contains a few bogus // entries in some rare cases). - frame_pointer = - NextStackFrame(frame_pointer, ucp); + frame_pointer = NextStackFrame( + frame_pointer, ucp, stack_low, stack_high); } if (min_dropped_frames != nullptr) { @@ -193,8 +220,8 @@ static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, } else { num_dropped_frames++; } - frame_pointer = - NextStackFrame(frame_pointer, ucp); + frame_pointer = NextStackFrame( + frame_pointer, ucp, stack_low, stack_high); } *min_dropped_frames = num_dropped_frames; } diff --git a/absl/debugging/stacktrace_test.cc b/absl/debugging/stacktrace_test.cc index 78ce7ad0a40..31f7723cdd3 100644 --- a/absl/debugging/stacktrace_test.cc +++ b/absl/debugging/stacktrace_test.cc @@ -20,8 +20,8 @@ namespace { -// This test is currently only known to pass on linux/x86_64. -#if defined(__linux__) && defined(__x86_64__) +// This test is currently only known to pass on Linux x86_64/aarch64. +#if defined(__linux__) && (defined(__x86_64__) || defined(__aarch64__)) ABSL_ATTRIBUTE_NOINLINE void Unwind(void* p) { ABSL_ATTRIBUTE_UNUSED static void* volatile sink = p; constexpr int kSize = 16; From b6a417bbd7eba01b83a03748710d180372be5e67 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 15 Jun 2023 23:40:29 -0700 Subject: [PATCH 0071/1238] absl: move comment in mutex.cc to where it belongs Move the comment that relates to kMuDesig close to kMuDesig definition. Currently it's placed in between unrelated flags. NFC PiperOrigin-RevId: 540792401 Change-Id: I5f6a928cd9e01664812b2a7c3d9eb087c0723d7f --- absl/synchronization/mutex.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc index 16a8fbffa9c..0742680c9b8 100644 --- a/absl/synchronization/mutex.cc +++ b/absl/synchronization/mutex.cc @@ -639,18 +639,18 @@ void Mutex::InternalAttemptToUseMutexInFatalSignalHandler() { // o kMuWriter / kMuReader == kMuWrWait / kMuWait, // to enable the bit-twiddling trick in CheckForMutexCorruption(). static const intptr_t kMuReader = 0x0001L; // a reader holds the lock -static const intptr_t kMuDesig = 0x0002L; // there's a designated waker -static const intptr_t kMuWait = 0x0004L; // threads are waiting -static const intptr_t kMuWriter = 0x0008L; // a writer holds the lock -static const intptr_t kMuEvent = 0x0010L; // record this mutex's events +// There's a designated waker. // INVARIANT1: there's a thread that was blocked on the mutex, is // no longer, yet has not yet acquired the mutex. If there's a // designated waker, all threads can avoid taking the slow path in // unlock because the designated waker will subsequently acquire // the lock and wake someone. To maintain INVARIANT1 the bit is // set when a thread is unblocked(INV1a), and threads that were -// unblocked reset the bit when they either acquire or re-block -// (INV1b). +// unblocked reset the bit when they either acquire or re-block (INV1b). +static const intptr_t kMuDesig = 0x0002L; +static const intptr_t kMuWait = 0x0004L; // threads are waiting +static const intptr_t kMuWriter = 0x0008L; // a writer holds the lock +static const intptr_t kMuEvent = 0x0010L; // record this mutex's events static const intptr_t kMuWrWait = 0x0020L; // runnable writer is waiting // for a reader static const intptr_t kMuSpin = 0x0040L; // spinlock protects wait list From cef7c4e81afba04c30ead19cc689e337edbf1901 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 16 Jun 2023 01:48:02 -0700 Subject: [PATCH 0072/1238] absl: fix Mutex writer starvation related to uninit priority Currently when we queue the first thread, we don't init its priority. Subsequent queued threads init priority, but they compare it against the first thread priority, which is uninit. Thus the order can be wrong. It can lead to complete false starvation in some corner cases. On Linux the default priority is 0, which matches the uninit value, thus the problem is harder to spot on Linux (only possible if explicit thread priorities are used). But on Darwin the default priority is 31, thus the first thread falsely looks like lower priority than subsequently queued threads. The added test exposes the problem on Darwin. Always initialize the priority before queuing threads. PiperOrigin-RevId: 540814133 Change-Id: I513ce1493a67afe77d3e92fb49000b046b42a9f2 --- absl/synchronization/mutex.cc | 51 +++++++++++++++++------------- absl/synchronization/mutex_test.cc | 30 ++++++++++++++++++ 2 files changed, 59 insertions(+), 22 deletions(-) diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc index 0742680c9b8..e2ee411fbf9 100644 --- a/absl/synchronization/mutex.cc +++ b/absl/synchronization/mutex.cc @@ -648,11 +648,16 @@ static const intptr_t kMuReader = 0x0001L; // a reader holds the lock // set when a thread is unblocked(INV1a), and threads that were // unblocked reset the bit when they either acquire or re-block (INV1b). static const intptr_t kMuDesig = 0x0002L; -static const intptr_t kMuWait = 0x0004L; // threads are waiting -static const intptr_t kMuWriter = 0x0008L; // a writer holds the lock -static const intptr_t kMuEvent = 0x0010L; // record this mutex's events -static const intptr_t kMuWrWait = 0x0020L; // runnable writer is waiting - // for a reader +static const intptr_t kMuWait = 0x0004L; // threads are waiting +static const intptr_t kMuWriter = 0x0008L; // a writer holds the lock +static const intptr_t kMuEvent = 0x0010L; // record this mutex's events +// Runnable writer is waiting for a reader. +// If set, new readers will not lock the mutex to avoid writer starvation. +// Note: if a reader has higher priority than the writer, it will still lock +// the mutex ahead of the waiting writer, but in a very inefficient manner: +// the reader will first queue itself and block, but then the last unlocking +// reader will wake it. +static const intptr_t kMuWrWait = 0x0020L; static const intptr_t kMuSpin = 0x0040L; // spinlock protects wait list static const intptr_t kMuLow = 0x00ffL; // mask all mutex bits static const intptr_t kMuHigh = ~kMuLow; // mask pointer/reader count @@ -919,6 +924,25 @@ static PerThreadSynch *Enqueue(PerThreadSynch *head, s->may_skip = true; // always true on entering queue s->wake = false; // not being woken s->cond_waiter = ((flags & kMuIsCond) != 0); +#ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM + int64_t now_cycles = base_internal::CycleClock::Now(); + if (s->next_priority_read_cycles < now_cycles) { + // Every so often, update our idea of the thread's priority. + // pthread_getschedparam() is 5% of the block/wakeup time; + // base_internal::CycleClock::Now() is 0.5%. + int policy; + struct sched_param param; + const int err = pthread_getschedparam(pthread_self(), &policy, ¶m); + if (err != 0) { + ABSL_RAW_LOG(ERROR, "pthread_getschedparam failed: %d", err); + } else { + s->priority = param.sched_priority; + s->next_priority_read_cycles = + now_cycles + + static_cast(base_internal::CycleClock::Frequency()); + } + } +#endif if (head == nullptr) { // s is the only waiter s->next = s; // it's the only entry in the cycle s->readers = mu; // reader count is from mu word @@ -927,23 +951,6 @@ static PerThreadSynch *Enqueue(PerThreadSynch *head, } else { PerThreadSynch *enqueue_after = nullptr; // we'll put s after this element #ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM - int64_t now_cycles = base_internal::CycleClock::Now(); - if (s->next_priority_read_cycles < now_cycles) { - // Every so often, update our idea of the thread's priority. - // pthread_getschedparam() is 5% of the block/wakeup time; - // base_internal::CycleClock::Now() is 0.5%. - int policy; - struct sched_param param; - const int err = pthread_getschedparam(pthread_self(), &policy, ¶m); - if (err != 0) { - ABSL_RAW_LOG(ERROR, "pthread_getschedparam failed: %d", err); - } else { - s->priority = param.sched_priority; - s->next_priority_read_cycles = - now_cycles + - static_cast(base_internal::CycleClock::Frequency()); - } - } if (s->priority > head->priority) { // s's priority is above head's // try to put s in priority-fifo order, or failing that at the front. if (!head->maybe_unlocking) { diff --git a/absl/synchronization/mutex_test.cc b/absl/synchronization/mutex_test.cc index 4ae4d7e7fc4..35802b2e876 100644 --- a/absl/synchronization/mutex_test.cc +++ b/absl/synchronization/mutex_test.cc @@ -1838,4 +1838,34 @@ TEST(Mutex, SignalExitedThread) { for (auto &th : top) th.join(); } +TEST(Mutex, WriterPriority) { + absl::Mutex mu; + bool wrote = false; + std::atomic saw_wrote{false}; + auto readfunc = [&]() { + for (size_t i = 0; i < 10; ++i) { + absl::ReaderMutexLock lock(&mu); + if (wrote) { + saw_wrote = true; + break; + } + absl::SleepFor(absl::Seconds(1)); + } + }; + std::thread t1(readfunc); + absl::SleepFor(absl::Milliseconds(500)); + std::thread t2(readfunc); + // Note: this test guards against a bug that was related to an uninit + // PerThreadSynch::priority, so the writer intentionally runs on a new thread. + std::thread t3([&]() { + // The writer should be able squeeze between the two alternating readers. + absl::MutexLock lock(&mu); + wrote = true; + }); + t1.join(); + t2.join(); + t3.join(); + EXPECT_TRUE(saw_wrote.load()); +} + } // namespace From 049aa40e7ec9e37ed47c4dd2452affb13cd62ebe Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Fri, 16 Jun 2023 10:41:20 -0700 Subject: [PATCH 0073/1238] Use std::is_final instead of a non-portable implementation PiperOrigin-RevId: 540928490 Change-Id: Idf022b28ce101a948be4efd5336888a66f5eacf9 --- absl/container/internal/compressed_tuple.h | 24 +++------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/absl/container/internal/compressed_tuple.h b/absl/container/internal/compressed_tuple.h index 5ebe1649424..59e70eb21de 100644 --- a/absl/container/internal/compressed_tuple.h +++ b/absl/container/internal/compressed_tuple.h @@ -64,19 +64,6 @@ struct Elem, I> template using ElemT = typename Elem::type; -// Use the __is_final intrinsic if available. Where it's not available, classes -// declared with the 'final' specifier cannot be used as CompressedTuple -// elements. -// TODO(sbenza): Replace this with std::is_final in C++14. -template -constexpr bool IsFinal() { -#if defined(__clang__) || defined(__GNUC__) - return __is_final(T); -#else - return false; -#endif -} - // We can't use EBCO on other CompressedTuples because that would mean that we // derive from multiple Storage<> instantiations with the same I parameter, // and potentially from multiple identical Storage<> instantiations. So anytime @@ -86,20 +73,15 @@ struct uses_inheritance {}; template constexpr bool ShouldUseBase() { - return std::is_class::value && std::is_empty::value && !IsFinal() && + return std::is_class::value && std::is_empty::value && + !std::is_final::value && !std::is_base_of::value; } // The storage class provides two specializations: // - For empty classes, it stores T as a base class. // - For everything else, it stores T as a member. -template ::type>()> -#else - bool UseBase = ShouldUseBase()> -#endif +template ()> struct Storage { T value; constexpr Storage() = default; From 76548f868453259834c6b96a3c2e434200d9d289 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 16 Jun 2023 22:45:08 -0700 Subject: [PATCH 0074/1238] Ensure arrays are 16-byte aligned before casting to uint128 PiperOrigin-RevId: 541111597 Change-Id: I88165130e30e548a03d8d6173dadab33dc18b21e --- absl/random/internal/randen_benchmarks.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/absl/random/internal/randen_benchmarks.cc b/absl/random/internal/randen_benchmarks.cc index f589172c046..ec086cea49d 100644 --- a/absl/random/internal/randen_benchmarks.cc +++ b/absl/random/internal/randen_benchmarks.cc @@ -47,8 +47,10 @@ static constexpr size_t kSeedSizeT = Randen::kSeedBytes / sizeof(uint32_t); // Randen implementation benchmarks. template struct AbsorbFn : public T { - mutable uint64_t state[kStateSizeT] = {}; - mutable uint32_t seed[kSeedSizeT] = {}; + // These are both cast to uint128* in the RandenHwAes implementation, so + // ensure they are 16 byte aligned. + alignas(16) mutable uint64_t state[kStateSizeT] = {}; + alignas(16) mutable uint32_t seed[kSeedSizeT] = {}; static constexpr size_t bytes() { return sizeof(seed); } From 5668c20e027f161eeb0b0bfe6ddbc814705c1c6b Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 20 Jun 2023 07:29:20 -0700 Subject: [PATCH 0075/1238] Add Nullability annotations to Abseil. PiperOrigin-RevId: 541915097 Change-Id: I7ebfbafc36db38b59b30ab5b312cd7e22082a805 --- CMake/AbseilDll.cmake | 2 + absl/base/BUILD.bazel | 22 +++ absl/base/CMakeLists.txt | 27 ++++ absl/base/internal/nullability_impl.h | 106 ++++++++++++ absl/base/nullability.h | 224 ++++++++++++++++++++++++++ absl/base/nullability_test.cc | 129 +++++++++++++++ 6 files changed, 510 insertions(+) create mode 100644 absl/base/internal/nullability_impl.h create mode 100644 absl/base/nullability.h create mode 100644 absl/base/nullability_test.cc diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index b64f133caec..f8dea458b62 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake @@ -26,6 +26,7 @@ set(ABSL_INTERNAL_DLL_FILES "base/internal/low_level_alloc.cc" "base/internal/low_level_alloc.h" "base/internal/low_level_scheduling.h" + "base/internal/nullability_impl.h" "base/internal/per_thread_tls.h" "base/internal/prefetch.h" "base/prefetch.h" @@ -56,6 +57,7 @@ set(ABSL_INTERNAL_DLL_FILES "base/log_severity.cc" "base/log_severity.h" "base/macros.h" + "base/nullability.h" "base/optimization.h" "base/options.h" "base/policy_checks.h" diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel index 28cbf28f882..fb008db3df4 100644 --- a/absl/base/BUILD.bazel +++ b/absl/base/BUILD.bazel @@ -62,6 +62,18 @@ cc_library( ], ) +cc_library( + name = "nullability", + srcs = ["internal/nullability_impl.h"], + hdrs = ["nullability.h"], + copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [ + ":core_headers", + "//absl/meta:type_traits", + ], +) + cc_library( name = "raw_logging_internal", srcs = ["internal/raw_logging.cc"], @@ -552,6 +564,16 @@ cc_test( ], ) +cc_test( + name = "nullability_test", + srcs = ["nullability_test.cc"], + deps = [ + ":core_headers", + ":nullability", + "@com_google_googletest//:gtest_main", + ], +) + cc_test( name = "raw_logging_test", srcs = ["raw_logging_test.cc"], diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt index 71b9379540f..76c4ff1d799 100644 --- a/absl/base/CMakeLists.txt +++ b/absl/base/CMakeLists.txt @@ -54,6 +54,33 @@ absl_cc_library( ${ABSL_DEFAULT_COPTS} ) +absl_cc_library( + NAME + nullability + HDRS + "nullability.h" + SRCS + "internal/nullability_impl.h" + DEPS + absl::core_headers + absl::type_traits + COPTS + ${ABSL_DEFAULT_COPTS} +) + +absl_cc_test( + NAME + nullability_test + SRCS + "nullability_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::core_headers + absl::nullability + GTest::gtest_main +) + # Internal-only target, do not depend on directly. absl_cc_library( NAME diff --git a/absl/base/internal/nullability_impl.h b/absl/base/internal/nullability_impl.h new file mode 100644 index 00000000000..74f4a4177af --- /dev/null +++ b/absl/base/internal/nullability_impl.h @@ -0,0 +1,106 @@ +// Copyright 2023 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_BASE_INTERNAL_NULLABILITY_IMPL_H_ +#define ABSL_BASE_INTERNAL_NULLABILITY_IMPL_H_ + +#include +#include + +#include "absl/base/attributes.h" +#include "absl/meta/type_traits.h" + +namespace absl { + +namespace nullability_internal { + +// `IsNullabilityCompatible` checks whether its first argument is a class +// explicitly tagged as supporting nullability annotations. The tag is the type +// declaration `absl_nullability_compatible`. +template +struct IsNullabilityCompatible : std::false_type {}; + +template +struct IsNullabilityCompatible< + T, absl::void_t> : std::true_type { +}; + +template +constexpr bool IsSupportedType = IsNullabilityCompatible::value; + +template +constexpr bool IsSupportedType = true; + +template +constexpr bool IsSupportedType = true; + +template +constexpr bool IsSupportedType> = true; + +template +constexpr bool IsSupportedType> = true; + +template +struct EnableNullable { + static_assert(nullability_internal::IsSupportedType>, + "Template argument must be a raw or supported smart pointer " + "type. See absl/base/nullability.h."); + using type = T; +}; + +template +struct EnableNonNull { + static_assert(nullability_internal::IsSupportedType>, + "Template argument must be a raw or supported smart pointer " + "type. See absl/base/nullability.h."); + using type = T; +}; + +template +struct EnableNullabilityUnknown { + static_assert(nullability_internal::IsSupportedType>, + "Template argument must be a raw or supported smart pointer " + "type. See absl/base/nullability.h."); + using type = T; +}; + +// Note: we do not apply Clang nullability attributes (e.g. _Nullable). These +// only support raw pointers, and conditionally enabling them only for raw +// pointers inhibits template arg deduction. Ideally, they would support all +// pointer-like types. +template ::type> +using NullableImpl +#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate) + [[clang::annotate("Nullable")]] +#endif + = T; + +template ::type> +using NonNullImpl +#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate) + [[clang::annotate("Nonnull")]] +#endif + = T; + +template ::type> +using NullabilityUnknownImpl +#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate) + [[clang::annotate("Nullability_Unspecified")]] +#endif + = T; + +} // namespace nullability_internal +} // namespace absl + +#endif // ABSL_BASE_INTERNAL_NULLABILITY_IMPL_H_ diff --git a/absl/base/nullability.h b/absl/base/nullability.h new file mode 100644 index 00000000000..42525dd0d63 --- /dev/null +++ b/absl/base/nullability.h @@ -0,0 +1,224 @@ +// Copyright 2023 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: nullability.h +// ----------------------------------------------------------------------------- +// +// This header file defines a set of "templated annotations" for designating the +// expected nullability of pointers. These annotations allow you to designate +// pointers in one of three classification states: +// +// * "Non-null" (for pointers annotated `NonNull`), indicating that it is +// invalid for the given pointer to ever be null. +// * "Nullable" (for pointers annotated `Nullable`), indicating that it is +// valid for the given pointer to be null. +// * "Unknown" (for pointers annotated `NullabilityUnknown`), indicating +// that the given pointer has not been yet classified as either nullable or +// non-null. This is the default state of unannotated pointers. +// +// NOTE: unannotated pointers implicitly bear the annotation +// `NullabilityUnknown`; you should rarely, if ever, see this annotation used +// in the codebase explicitly. +// +// ----------------------------------------------------------------------------- +// Nullability and Contracts +// ----------------------------------------------------------------------------- +// +// These nullability annotations allow you to more clearly specify contracts on +// software components by narrowing the *preconditions*, *postconditions*, and +// *invariants* of pointer state(s) in any given interface. It then depends on +// context who is responsible for fulfilling the annotation's requirements. +// +// For example, a function may receive a pointer argument. Designating that +// pointer argument as "non-null" tightens the precondition of the contract of +// that function. It is then the responsibility of anyone calling such a +// function to ensure that the passed pointer is not null. +// +// Similarly, a function may have a pointer as a return value. Designating that +// return value as "non-null" tightens the postcondition of the contract of that +// function. In this case, however, it is the responsibility of the function +// itself to ensure that the returned pointer is not null. +// +// Clearly defining these contracts allows providers (and consumers) of such +// pointers to have more confidence in their null state. If a function declares +// a return value as "non-null", for example, the caller should not need to +// check whether the returned value is `nullptr`; it can simply assume the +// pointer is valid. +// +// Of course most interfaces already have expectations on the nullability state +// of pointers, and these expectations are, in effect, a contract; often, +// however, those contracts are either poorly or partially specified, assumed, +// or misunderstood. These nullability annotations are designed to allow you to +// formalize those contracts within the codebase. +// +// ----------------------------------------------------------------------------- +// Using Nullability Annotations +// ----------------------------------------------------------------------------- +// +// It is important to note that these annotations are not distinct strong +// *types*. They are alias templates defined to be equal to the underlying +// pointer type. A pointer annotated `NonNull`, for example, is simply a +// pointer of type `T*`. Each annotation acts as a form of documentation about +// the contract for the given pointer. Each annotation requires providers or +// consumers of these pointers across API boundaries to take appropriate steps +// when setting or using these pointers: +// +// * "Non-null" pointers should never be null. It is the responsibility of the +// provider of this pointer to ensure that the pointer may never be set to +// null. Consumers of such pointers can treat such pointers as non-null. +// * "Nullable" pointers may or may not be null. Consumers of such pointers +// should precede any usage of that pointer (e.g. a dereference operation) +// with a a `nullptr` check. +// * "Unknown" pointers may be either "non-null" or "nullable" but have not been +// definitively determined to be in either classification state. Providers of +// such pointers across API boundaries should determine -- over time -- to +// annotate the pointer in either of the above two states. Consumers of such +// pointers across an API boundary should continue to treat such pointers as +// they currently do. +// +// Example: +// +// // PaySalary() requires the passed pointer to an `Employee` to be non-null. +// void PaySalary(absl::NonNull e) { +// pay(e->salary); // OK to dereference +// } +// +// // CompleteTransaction() guarantees the returned pointer to an `Account` to +// // be non-null. +// absl::NonNull balance CompleteTransaction(double fee) { +// ... +// } +// +// // Note that specifying a nullability annotation does not prevent someone +// // from violating the contract: +// +// Nullable find(Map& employees, std::string_view name); +// +// void g(Map& employees) { +// Employee *e = find(employees, "Pat"); +// // `e` can now be null. +// PaySalary(e); // Violates contract, but compiles! +// } +// +// Nullability annotations, in other words, are useful for defining and +// narrowing contracts; *enforcement* of those contracts depends on use and any +// additional (static or dynamic analysis) tooling. +// +// NOTE: The "unknown" annotation state indicates that a pointer's contract has +// not yet been positively identified. The unknown state therefore acts as a +// form of documentation of your technical debt, and a codebase that adopts +// nullability annotations should aspire to annotate every pointer as either +// "non-null" or "nullable". +// +// ----------------------------------------------------------------------------- +// Applicability of Nullability Annotations +// ----------------------------------------------------------------------------- +// +// By default, nullability annotations are applicable to raw and smart +// pointers. User-defined types can indicate compatibility with nullability +// annotations by providing an `absl_nullability_compatible` nested type. The +// actual definition of this inner type is not relevant as it is used merely as +// a marker. It is common to use a using declaration of +// `absl_nullability_compatible` set to void. +// +// // Example: +// struct MyPtr { +// using absl_nullability_compatible = void; +// ... +// }; +// +// DISCLAIMER: +// =========================================================================== +// These nullability annotations are primarily a human readable signal about the +// intended contract of the pointer. They are not *types* and do not currently +// provide any correctness guarantees. For example, a pointer annotated as +// `NonNull` is *not guaranteed* to be non-null, and the compiler won't +// alert or prevent assignment of a `Nullable` to a `NonNull`. +// =========================================================================== +#ifndef ABSL_BASE_NULLABILITY_H_ +#define ABSL_BASE_NULLABILITY_H_ + +#include "absl/base/internal/nullability_impl.h" + +namespace absl { + +// absl::NonNull +// +// The indicated pointer is never null. It is the responsibility of the provider +// of this pointer across an API boundary to ensure that the pointer is never be +// set to null. Consumers of this pointer across an API boundary may safely +// dereference the pointer. +// +// Example: +// +// // `employee` is designated as not null. +// void PaySalary(absl::NotNull employee) { +// pay(*employee); // OK to dereference +// } +template +using NonNull = nullability_internal::NonNullImpl; + +// absl::Nullable +// +// The indicated pointer may, by design, be either null or non-null. Consumers +// of this pointer across an API boundary should perform a `nullptr` check +// before performing any operation using the pointer. +// +// Example: +// +// // `employee` may be null. +// void PaySalary(absl::Nullable employee) { +// if (employee != nullptr) { +// Pay(*employee); // OK to dereference +// } +// } +template +using Nullable = nullability_internal::NullableImpl; + +// absl::NullabilityUnknown (default) +// +// The indicated pointer has not yet been determined to be definitively +// "non-null" or "nullable." Providers of such pointers across API boundaries +// should, over time, annotate such pointers as either "non-null" or "nullable." +// Consumers of these pointers across an API boundary should treat such pointers +// with the same caution they treat currently unannotated pointers. Most +// existing code will have "unknown" pointers, which should eventually be +// migrated into one of the above two nullability states: `NonNull` or +// `Nullable`. +// +// NOTE: Because this annotation is the global default state, pointers without +// any annotation are assumed to have "unknown" semantics. This assumption is +// designed to minimize churn and reduce clutter within the codebase. +// +// Example: +// +// // `employee`s nullability state is unknown. +// void PaySalary(absl::NullabilityUnknown employee) { +// Pay(*employee); // Potentially dangerous. API provider should investigate. +// } +// +// Note that a pointer without an annotation, by default, is assumed to have the +// annotation `NullabilityUnknown`. +// +// // `employee`s nullability state is unknown. +// void PaySalary(Employee* employee) { +// Pay(*employee); // Potentially dangerous. API provider should investigate. +// } +template +using NullabilityUnknown = nullability_internal::NullabilityUnknownImpl; + +} // namespace absl + +#endif // ABSL_BASE_NULLABILITY_H_ diff --git a/absl/base/nullability_test.cc b/absl/base/nullability_test.cc new file mode 100644 index 00000000000..6edd7cd144a --- /dev/null +++ b/absl/base/nullability_test.cc @@ -0,0 +1,129 @@ +// Copyright 2023 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/base/nullability.h" + +#include +#include +#include + +#include "gtest/gtest.h" +#include "absl/base/attributes.h" + +namespace { +using ::absl::NonNull; +using ::absl::NullabilityUnknown; +using ::absl::Nullable; + +void funcWithNonnullArg(NonNull /*arg*/) {} +template +void funcWithDeducedNonnullArg(NonNull /*arg*/) {} + +TEST(NonNullTest, NonNullArgument) { + int var = 0; + funcWithNonnullArg(&var); + funcWithDeducedNonnullArg(&var); +} + +NonNull funcWithNonnullReturn() { + static int var = 0; + return &var; +} + +TEST(NonNullTest, NonNullReturn) { + auto var = funcWithNonnullReturn(); + (void)var; +} + +TEST(PassThroughTest, PassesThroughRawPointerToInt) { + EXPECT_TRUE((std::is_same, int*>::value)); + EXPECT_TRUE((std::is_same, int*>::value)); + EXPECT_TRUE((std::is_same, int*>::value)); +} + +TEST(PassThroughTest, PassesThroughRawPointerToVoid) { + EXPECT_TRUE((std::is_same, void*>::value)); + EXPECT_TRUE((std::is_same, void*>::value)); + EXPECT_TRUE((std::is_same, void*>::value)); +} + +TEST(PassThroughTest, PassesThroughUniquePointerToInt) { + using T = std::unique_ptr; + EXPECT_TRUE((std::is_same, T>::value)); + EXPECT_TRUE((std::is_same, T>::value)); + EXPECT_TRUE((std::is_same, T>::value)); +} + +TEST(PassThroughTest, PassesThroughSharedPointerToInt) { + using T = std::shared_ptr; + EXPECT_TRUE((std::is_same, T>::value)); + EXPECT_TRUE((std::is_same, T>::value)); + EXPECT_TRUE((std::is_same, T>::value)); +} + +TEST(PassThroughTest, PassesThroughSharedPointerToVoid) { + using T = std::shared_ptr; + EXPECT_TRUE((std::is_same, T>::value)); + EXPECT_TRUE((std::is_same, T>::value)); + EXPECT_TRUE((std::is_same, T>::value)); +} + +TEST(PassThroughTest, PassesThroughPointerToMemberObject) { + using T = decltype(&std::pair::first); + EXPECT_TRUE((std::is_same, T>::value)); + EXPECT_TRUE((std::is_same, T>::value)); + EXPECT_TRUE((std::is_same, T>::value)); +} + +TEST(PassThroughTest, PassesThroughPointerToMemberFunction) { + using T = decltype(&std::unique_ptr::reset); + EXPECT_TRUE((std::is_same, T>::value)); + EXPECT_TRUE((std::is_same, T>::value)); + EXPECT_TRUE((std::is_same, T>::value)); +} + +} // namespace + +// Nullable ADL lookup test +namespace util { +// Helper for NullableAdlTest. Returns true, denoting that argument-dependent +// lookup found this implementation of DidAdlWin. Must be in namespace +// util itself, not a nested anonymous namespace. +template +bool DidAdlWin(T*) { + return true; +} + +// Because this type is defined in namespace util, an unqualified call to +// DidAdlWin with a pointer to MakeAdlWin will find the above implementation. +struct MakeAdlWin {}; +} // namespace util + +namespace { +// Returns false, denoting that ADL did not inspect namespace util. If it +// had, the better match (T*) above would have won out over the (...) here. +bool DidAdlWin(...) { return false; } + +TEST(NullableAdlTest, NullableAddsNothingToArgumentDependentLookup) { + // Treatment: util::Nullable contributes nothing to ADL because + // int* itself doesn't. + EXPECT_FALSE(DidAdlWin((int*)nullptr)); + EXPECT_FALSE(DidAdlWin((Nullable)nullptr)); + + // Control: Argument-dependent lookup does find the implementation in + // namespace util when the underlying pointee type resides there. + EXPECT_TRUE(DidAdlWin((util::MakeAdlWin*)nullptr)); + EXPECT_TRUE(DidAdlWin((Nullable)nullptr)); +} +} // namespace From cffa80b913305c7ff6d6464e7efda23bb48bfa91 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 20 Jun 2023 10:53:00 -0700 Subject: [PATCH 0076/1238] absl: reformat Mutex-related files Reformat Mutex-related files so that incremental formatting changes don't distract during review of logical changes. These files are subtle and any unnecessary diffs make reviews harder. No changes besides running clang-format. PiperOrigin-RevId: 541981737 Change-Id: I41cccb7a97158c78d17adaff6fe553c2c9c2b9ed --- absl/base/internal/thread_identity.cc | 15 +- absl/base/internal/thread_identity.h | 15 +- .../internal/create_thread_identity.cc | 1 + absl/synchronization/mutex.cc | 675 +++++++++--------- absl/synchronization/mutex.h | 187 ++--- 5 files changed, 443 insertions(+), 450 deletions(-) diff --git a/absl/base/internal/thread_identity.cc b/absl/base/internal/thread_identity.cc index 79853f09f52..0eeb7d0015d 100644 --- a/absl/base/internal/thread_identity.cc +++ b/absl/base/internal/thread_identity.cc @@ -58,18 +58,19 @@ void AllocateThreadIdentityKey(ThreadIdentityReclaimerFunction reclaimer) { // that protected visibility is unsupported. ABSL_CONST_INIT // Must come before __attribute__((visibility("protected"))) #if ABSL_HAVE_ATTRIBUTE(visibility) && !defined(__APPLE__) -__attribute__((visibility("protected"))) + __attribute__((visibility("protected"))) #endif // ABSL_HAVE_ATTRIBUTE(visibility) && !defined(__APPLE__) #if ABSL_PER_THREAD_TLS -// Prefer __thread to thread_local as benchmarks indicate it is a bit faster. -ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr = nullptr; + // Prefer __thread to thread_local as benchmarks indicate it is a bit + // faster. + ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr = nullptr; #elif defined(ABSL_HAVE_THREAD_LOCAL) -thread_local ThreadIdentity* thread_identity_ptr = nullptr; + thread_local ThreadIdentity* thread_identity_ptr = nullptr; #endif // ABSL_PER_THREAD_TLS #endif // TLS or CPP11 -void SetCurrentThreadIdentity( - ThreadIdentity* identity, ThreadIdentityReclaimerFunction reclaimer) { +void SetCurrentThreadIdentity(ThreadIdentity* identity, + ThreadIdentityReclaimerFunction reclaimer) { assert(CurrentThreadIdentityIfPresent() == nullptr); // Associate our destructor. // NOTE: This call to pthread_setspecific is currently the only immovable @@ -134,7 +135,7 @@ void ClearCurrentThreadIdentity() { ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11 thread_identity_ptr = nullptr; #elif ABSL_THREAD_IDENTITY_MODE == \ - ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC + ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC // pthread_setspecific expected to clear value on destruction assert(CurrentThreadIdentityIfPresent() == nullptr); #endif diff --git a/absl/base/internal/thread_identity.h b/absl/base/internal/thread_identity.h index 496ec2142c2..b6e917ce804 100644 --- a/absl/base/internal/thread_identity.h +++ b/absl/base/internal/thread_identity.h @@ -62,8 +62,8 @@ struct PerThreadSynch { return reinterpret_cast(this); } - PerThreadSynch *next; // Circular waiter queue; initialized to 0. - PerThreadSynch *skip; // If non-zero, all entries in Mutex queue + PerThreadSynch* next; // Circular waiter queue; initialized to 0. + PerThreadSynch* skip; // If non-zero, all entries in Mutex queue // up to and including "skip" have same // condition as this, and will be woken later bool may_skip; // if false while on mutex queue, a mutex unlocker @@ -104,10 +104,7 @@ struct PerThreadSynch { // // Transitions from kAvailable to kQueued require no barrier, they // are externally ordered by the Mutex. - enum State { - kAvailable, - kQueued - }; + enum State { kAvailable, kQueued }; std::atomic state; // The wait parameters of the current wait. waitp is null if the @@ -122,14 +119,14 @@ struct PerThreadSynch { // pointer unchanged. SynchWaitParams* waitp; - intptr_t readers; // Number of readers in mutex. + intptr_t readers; // Number of readers in mutex. // When priority will next be read (cycles). int64_t next_priority_read_cycles; // Locks held; used during deadlock detection. // Allocated in Synch_GetAllLocks() and freed in ReclaimThreadIdentity(). - SynchLocksHeld *all_locks; + SynchLocksHeld* all_locks; }; // The instances of this class are allocated in NewThreadIdentity() with an @@ -220,7 +217,7 @@ void ClearCurrentThreadIdentity(); #define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11 #elif defined(__APPLE__) && defined(ABSL_HAVE_THREAD_LOCAL) #define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11 -#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \ +#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \ (__GOOGLE_GRTE_VERSION__ >= 20140228L) // Support for async-safe TLS was specifically added in GRTEv4. It's not // present in the upstream eglibc. diff --git a/absl/synchronization/internal/create_thread_identity.cc b/absl/synchronization/internal/create_thread_identity.cc index f1ddbbb92f6..eacaa28d7b2 100644 --- a/absl/synchronization/internal/create_thread_identity.cc +++ b/absl/synchronization/internal/create_thread_identity.cc @@ -13,6 +13,7 @@ // limitations under the License. #include + #include // This file is a no-op if the required LowLevelAlloc support is missing. diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc index e2ee411fbf9..edd9974f5c6 100644 --- a/absl/synchronization/mutex.cc +++ b/absl/synchronization/mutex.cc @@ -98,15 +98,15 @@ ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES absl::base_internal::AtomicHook submit_profile_data; ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES absl::base_internal::AtomicHook + const char* msg, const void* obj, int64_t wait_cycles)> mutex_tracer; ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES - absl::base_internal::AtomicHook - cond_var_tracer; +absl::base_internal::AtomicHook + cond_var_tracer; } // namespace -static inline bool EvalConditionAnnotated(const Condition *cond, Mutex *mu, +static inline bool EvalConditionAnnotated(const Condition* cond, Mutex* mu, bool locking, bool trylock, bool read_lock); @@ -114,12 +114,12 @@ void RegisterMutexProfiler(void (*fn)(int64_t wait_cycles)) { submit_profile_data.Store(fn); } -void RegisterMutexTracer(void (*fn)(const char *msg, const void *obj, +void RegisterMutexTracer(void (*fn)(const char* msg, const void* obj, int64_t wait_cycles)) { mutex_tracer.Store(fn); } -void RegisterCondVarTracer(void (*fn)(const char *msg, const void *cv)) { +void RegisterCondVarTracer(void (*fn)(const char* msg, const void* cv)) { cond_var_tracer.Store(fn); } @@ -141,7 +141,7 @@ absl::Duration MeasureTimeToYield() { return absl::Now() - before; } -const MutexGlobals &GetMutexGlobals() { +const MutexGlobals& GetMutexGlobals() { ABSL_CONST_INIT static MutexGlobals data; absl::base_internal::LowLevelCallOnce(&data.once, [&]() { const int num_cpus = absl::base_internal::NumCPUs(); @@ -212,8 +212,7 @@ static void AtomicSetBits(std::atomic* pv, intptr_t bits, v = pv->load(std::memory_order_relaxed); } while ((v & bits) != bits && ((v & wait_until_clear) != 0 || - !pv->compare_exchange_weak(v, v | bits, - std::memory_order_release, + !pv->compare_exchange_weak(v, v | bits, std::memory_order_release, std::memory_order_relaxed))); } @@ -228,8 +227,7 @@ static void AtomicClearBits(std::atomic* pv, intptr_t bits, v = pv->load(std::memory_order_relaxed); } while ((v & bits) != 0 && ((v & wait_until_clear) != 0 || - !pv->compare_exchange_weak(v, v & ~bits, - std::memory_order_release, + !pv->compare_exchange_weak(v, v & ~bits, std::memory_order_release, std::memory_order_relaxed))); } @@ -240,7 +238,7 @@ ABSL_CONST_INIT static absl::base_internal::SpinLock deadlock_graph_mu( absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY); // Graph used to detect deadlocks. -ABSL_CONST_INIT static GraphCycles *deadlock_graph +ABSL_CONST_INIT static GraphCycles* deadlock_graph ABSL_GUARDED_BY(deadlock_graph_mu) ABSL_PT_GUARDED_BY(deadlock_graph_mu); //------------------------------------------------------------------ @@ -284,7 +282,7 @@ enum { // Event flags // Properties of the events. static const struct { int flags; - const char *msg; + const char* msg; } event_properties[] = { {SYNCH_F_LCK_W | SYNCH_F_TRY, "TryLock succeeded "}, {0, "TryLock failed "}, @@ -309,12 +307,12 @@ ABSL_CONST_INIT static absl::base_internal::SpinLock synch_event_mu( // Can't be too small, as it's used for deadlock detection information. static constexpr uint32_t kNSynchEvent = 1031; -static struct SynchEvent { // this is a trivial hash table for the events +static struct SynchEvent { // this is a trivial hash table for the events // struct is freed when refcount reaches 0 int refcount ABSL_GUARDED_BY(synch_event_mu); // buckets have linear, 0-terminated chains - SynchEvent *next ABSL_GUARDED_BY(synch_event_mu); + SynchEvent* next ABSL_GUARDED_BY(synch_event_mu); // Constant after initialization uintptr_t masked_addr; // object at this address is called "name" @@ -322,13 +320,13 @@ static struct SynchEvent { // this is a trivial hash table for the events // No explicit synchronization used. Instead we assume that the // client who enables/disables invariants/logging on a Mutex does so // while the Mutex is not being concurrently accessed by others. - void (*invariant)(void *arg); // called on each event - void *arg; // first arg to (*invariant)() - bool log; // logging turned on + void (*invariant)(void* arg); // called on each event + void* arg; // first arg to (*invariant)() + bool log; // logging turned on // Constant after initialization - char name[1]; // actually longer---NUL-terminated string -} * synch_event[kNSynchEvent] ABSL_GUARDED_BY(synch_event_mu); + char name[1]; // actually longer---NUL-terminated string +}* synch_event[kNSynchEvent] ABSL_GUARDED_BY(synch_event_mu); // Ensure that the object at "addr" has a SynchEvent struct associated with it, // set "bits" in the word there (waiting until lockbit is clear before doing @@ -337,11 +335,11 @@ static struct SynchEvent { // this is a trivial hash table for the events // the string name is copied into it. // When used with a mutex, the caller should also ensure that kMuEvent // is set in the mutex word, and similarly for condition variables and kCVEvent. -static SynchEvent *EnsureSynchEvent(std::atomic *addr, - const char *name, intptr_t bits, +static SynchEvent* EnsureSynchEvent(std::atomic* addr, + const char* name, intptr_t bits, intptr_t lockbit) { uint32_t h = reinterpret_cast(addr) % kNSynchEvent; - SynchEvent *e; + SynchEvent* e; // first look for existing SynchEvent struct.. synch_event_mu.Lock(); for (e = synch_event[h]; @@ -353,9 +351,9 @@ static SynchEvent *EnsureSynchEvent(std::atomic *addr, name = ""; } size_t l = strlen(name); - e = reinterpret_cast( + e = reinterpret_cast( base_internal::LowLevelAlloc::Alloc(sizeof(*e) + l)); - e->refcount = 2; // one for return value, one for linked list + e->refcount = 2; // one for return value, one for linked list e->masked_addr = base_internal::HidePtr(addr); e->invariant = nullptr; e->arg = nullptr; @@ -365,19 +363,19 @@ static SynchEvent *EnsureSynchEvent(std::atomic *addr, AtomicSetBits(addr, bits, lockbit); synch_event[h] = e; } else { - e->refcount++; // for return value + e->refcount++; // for return value } synch_event_mu.Unlock(); return e; } // Deallocate the SynchEvent *e, whose refcount has fallen to zero. -static void DeleteSynchEvent(SynchEvent *e) { +static void DeleteSynchEvent(SynchEvent* e) { base_internal::LowLevelAlloc::Free(e); } // Decrement the reference count of *e, or do nothing if e==null. -static void UnrefSynchEvent(SynchEvent *e) { +static void UnrefSynchEvent(SynchEvent* e) { if (e != nullptr) { synch_event_mu.Lock(); bool del = (--(e->refcount) == 0); @@ -391,11 +389,11 @@ static void UnrefSynchEvent(SynchEvent *e) { // Forget the mapping from the object (Mutex or CondVar) at address addr // to SynchEvent object, and clear "bits" in its word (waiting until lockbit // is clear before doing so). -static void ForgetSynchEvent(std::atomic *addr, intptr_t bits, +static void ForgetSynchEvent(std::atomic* addr, intptr_t bits, intptr_t lockbit) { uint32_t h = reinterpret_cast(addr) % kNSynchEvent; - SynchEvent **pe; - SynchEvent *e; + SynchEvent** pe; + SynchEvent* e; synch_event_mu.Lock(); for (pe = &synch_event[h]; (e = *pe) != nullptr && e->masked_addr != base_internal::HidePtr(addr); @@ -416,9 +414,9 @@ static void ForgetSynchEvent(std::atomic *addr, intptr_t bits, // Return a refcounted reference to the SynchEvent of the object at address // "addr", if any. The pointer returned is valid until the UnrefSynchEvent() is // called. -static SynchEvent *GetSynchEvent(const void *addr) { +static SynchEvent* GetSynchEvent(const void* addr) { uint32_t h = reinterpret_cast(addr) % kNSynchEvent; - SynchEvent *e; + SynchEvent* e; synch_event_mu.Lock(); for (e = synch_event[h]; e != nullptr && e->masked_addr != base_internal::HidePtr(addr); @@ -433,17 +431,17 @@ static SynchEvent *GetSynchEvent(const void *addr) { // Called when an event "ev" occurs on a Mutex of CondVar "obj" // if event recording is on -static void PostSynchEvent(void *obj, int ev) { - SynchEvent *e = GetSynchEvent(obj); +static void PostSynchEvent(void* obj, int ev) { + SynchEvent* e = GetSynchEvent(obj); // logging is on if event recording is on and either there's no event struct, // or it explicitly says to log if (e == nullptr || e->log) { - void *pcs[40]; + void* pcs[40]; int n = absl::GetStackTrace(pcs, ABSL_ARRAYSIZE(pcs), 1); // A buffer with enough space for the ASCII for all the PCs, even on a // 64-bit machine. char buffer[ABSL_ARRAYSIZE(pcs) * 24]; - int pos = snprintf(buffer, sizeof (buffer), " @"); + int pos = snprintf(buffer, sizeof(buffer), " @"); for (int i = 0; i != n; i++) { int b = snprintf(&buffer[pos], sizeof(buffer) - static_cast(pos), " %p", pcs[i]); @@ -465,13 +463,13 @@ static void PostSynchEvent(void *obj, int ev) { // get false positive race reports later. // Reuse EvalConditionAnnotated to properly call into user code. struct local { - static bool pred(SynchEvent *ev) { + static bool pred(SynchEvent* ev) { (*ev->invariant)(ev->arg); return false; } }; Condition cond(&local::pred, e); - Mutex *mu = static_cast(obj); + Mutex* mu = static_cast(obj); const bool locking = (flags & SYNCH_F_UNLOCK) == 0; const bool trylock = (flags & SYNCH_F_TRY) != 0; const bool read_lock = (flags & SYNCH_F_R) != 0; @@ -497,10 +495,10 @@ static void PostSynchEvent(void *obj, int ev) { // PerThreadSynch struct points at the most recent SynchWaitParams struct when // the thread is on a Mutex's waiter queue. struct SynchWaitParams { - SynchWaitParams(Mutex::MuHow how_arg, const Condition *cond_arg, - KernelTimeout timeout_arg, Mutex *cvmu_arg, - PerThreadSynch *thread_arg, - std::atomic *cv_word_arg) + SynchWaitParams(Mutex::MuHow how_arg, const Condition* cond_arg, + KernelTimeout timeout_arg, Mutex* cvmu_arg, + PerThreadSynch* thread_arg, + std::atomic* cv_word_arg) : how(how_arg), cond(cond_arg), timeout(timeout_arg), @@ -511,18 +509,18 @@ struct SynchWaitParams { should_submit_contention_data(false) {} const Mutex::MuHow how; // How this thread needs to wait. - const Condition *cond; // The condition that this thread is waiting for. - // In Mutex, this field is set to zero if a timeout - // expires. + const Condition* cond; // The condition that this thread is waiting for. + // In Mutex, this field is set to zero if a timeout + // expires. KernelTimeout timeout; // timeout expiry---absolute time // In Mutex, this field is set to zero if a timeout // expires. - Mutex *const cvmu; // used for transfer from cond var to mutex - PerThreadSynch *const thread; // thread that is waiting + Mutex* const cvmu; // used for transfer from cond var to mutex + PerThreadSynch* const thread; // thread that is waiting // If not null, thread should be enqueued on the CondVar whose state // word is cv_word instead of queueing normally on the Mutex. - std::atomic *cv_word; + std::atomic* cv_word; int64_t contention_start_cycles; // Time (in cycles) when this thread started // to contend for the mutex. @@ -530,12 +528,12 @@ struct SynchWaitParams { }; struct SynchLocksHeld { - int n; // number of valid entries in locks[] - bool overflow; // true iff we overflowed the array at some point + int n; // number of valid entries in locks[] + bool overflow; // true iff we overflowed the array at some point struct { - Mutex *mu; // lock acquired - int32_t count; // times acquired - GraphId id; // deadlock_graph id of acquired lock + Mutex* mu; // lock acquired + int32_t count; // times acquired + GraphId id; // deadlock_graph id of acquired lock } locks[40]; // If a thread overfills the array during deadlock detection, we // continue, discarding information as needed. If no overflow has @@ -545,11 +543,11 @@ struct SynchLocksHeld { // A sentinel value in lists that is not 0. // A 0 value is used to mean "not on a list". -static PerThreadSynch *const kPerThreadSynchNull = - reinterpret_cast(1); +static PerThreadSynch* const kPerThreadSynchNull = + reinterpret_cast(1); -static SynchLocksHeld *LocksHeldAlloc() { - SynchLocksHeld *ret = reinterpret_cast( +static SynchLocksHeld* LocksHeldAlloc() { + SynchLocksHeld* ret = reinterpret_cast( base_internal::LowLevelAlloc::Alloc(sizeof(SynchLocksHeld))); ret->n = 0; ret->overflow = false; @@ -557,24 +555,24 @@ static SynchLocksHeld *LocksHeldAlloc() { } // Return the PerThreadSynch-struct for this thread. -static PerThreadSynch *Synch_GetPerThread() { - ThreadIdentity *identity = GetOrCreateCurrentThreadIdentity(); +static PerThreadSynch* Synch_GetPerThread() { + ThreadIdentity* identity = GetOrCreateCurrentThreadIdentity(); return &identity->per_thread_synch; } -static PerThreadSynch *Synch_GetPerThreadAnnotated(Mutex *mu) { +static PerThreadSynch* Synch_GetPerThreadAnnotated(Mutex* mu) { if (mu) { ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0); } - PerThreadSynch *w = Synch_GetPerThread(); + PerThreadSynch* w = Synch_GetPerThread(); if (mu) { ABSL_TSAN_MUTEX_POST_DIVERT(mu, 0); } return w; } -static SynchLocksHeld *Synch_GetAllLocks() { - PerThreadSynch *s = Synch_GetPerThread(); +static SynchLocksHeld* Synch_GetAllLocks() { + PerThreadSynch* s = Synch_GetPerThread(); if (s->all_locks == nullptr) { s->all_locks = LocksHeldAlloc(); // Freed by ReclaimThreadIdentity. } @@ -582,7 +580,7 @@ static SynchLocksHeld *Synch_GetAllLocks() { } // Post on "w"'s associated PerThreadSem. -void Mutex::IncrementSynchSem(Mutex *mu, PerThreadSynch *w) { +void Mutex::IncrementSynchSem(Mutex* mu, PerThreadSynch* w) { if (mu) { ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0); // We miss synchronization around passing PerThreadSynch between threads @@ -598,7 +596,7 @@ void Mutex::IncrementSynchSem(Mutex *mu, PerThreadSynch *w) { } // Wait on "w"'s associated PerThreadSem; returns false if timeout expired. -bool Mutex::DecrementSynchSem(Mutex *mu, PerThreadSynch *w, KernelTimeout t) { +bool Mutex::DecrementSynchSem(Mutex* mu, PerThreadSynch* w, KernelTimeout t) { if (mu) { ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0); } @@ -619,7 +617,7 @@ bool Mutex::DecrementSynchSem(Mutex *mu, PerThreadSynch *w, KernelTimeout t) { // Mutex code checking that the "waitp" field has not been reused. void Mutex::InternalAttemptToUseMutexInFatalSignalHandler() { // Fix the per-thread state only if it exists. - ThreadIdentity *identity = CurrentThreadIdentityIfPresent(); + ThreadIdentity* identity = CurrentThreadIdentityIfPresent(); if (identity != nullptr) { identity->per_thread_synch.suppress_fatal_errors = true; } @@ -638,7 +636,7 @@ void Mutex::InternalAttemptToUseMutexInFatalSignalHandler() { // bit-twiddling trick in Mutex::Unlock(). // o kMuWriter / kMuReader == kMuWrWait / kMuWait, // to enable the bit-twiddling trick in CheckForMutexCorruption(). -static const intptr_t kMuReader = 0x0001L; // a reader holds the lock +static const intptr_t kMuReader = 0x0001L; // a reader holds the lock // There's a designated waker. // INVARIANT1: there's a thread that was blocked on the mutex, is // no longer, yet has not yet acquired the mutex. If there's a @@ -658,9 +656,9 @@ static const intptr_t kMuEvent = 0x0010L; // record this mutex's events // the reader will first queue itself and block, but then the last unlocking // reader will wake it. static const intptr_t kMuWrWait = 0x0020L; -static const intptr_t kMuSpin = 0x0040L; // spinlock protects wait list -static const intptr_t kMuLow = 0x00ffL; // mask all mutex bits -static const intptr_t kMuHigh = ~kMuLow; // mask pointer/reader count +static const intptr_t kMuSpin = 0x0040L; // spinlock protects wait list +static const intptr_t kMuLow = 0x00ffL; // mask all mutex bits +static const intptr_t kMuHigh = ~kMuLow; // mask pointer/reader count // Hack to make constant values available to gdb pretty printer enum { @@ -756,8 +754,8 @@ Mutex::~Mutex() { ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); } -void Mutex::EnableDebugLog(const char *name) { - SynchEvent *e = EnsureSynchEvent(&this->mu_, name, kMuEvent, kMuSpin); +void Mutex::EnableDebugLog(const char* name) { + SynchEvent* e = EnsureSynchEvent(&this->mu_, name, kMuEvent, kMuSpin); e->log = true; UnrefSynchEvent(e); } @@ -766,11 +764,10 @@ void EnableMutexInvariantDebugging(bool enabled) { synch_check_invariants.store(enabled, std::memory_order_release); } -void Mutex::EnableInvariantDebugging(void (*invariant)(void *), - void *arg) { +void Mutex::EnableInvariantDebugging(void (*invariant)(void*), void* arg) { if (synch_check_invariants.load(std::memory_order_acquire) && invariant != nullptr) { - SynchEvent *e = EnsureSynchEvent(&this->mu_, nullptr, kMuEvent, kMuSpin); + SynchEvent* e = EnsureSynchEvent(&this->mu_, nullptr, kMuEvent, kMuSpin); e->invariant = invariant; e->arg = arg; UnrefSynchEvent(e); @@ -786,15 +783,15 @@ void SetMutexDeadlockDetectionMode(OnDeadlockCycle mode) { // waiters with the same condition, type of lock, and thread priority. // // Requires that x and y be waiting on the same Mutex queue. -static bool MuEquivalentWaiter(PerThreadSynch *x, PerThreadSynch *y) { +static bool MuEquivalentWaiter(PerThreadSynch* x, PerThreadSynch* y) { return x->waitp->how == y->waitp->how && x->priority == y->priority && Condition::GuaranteedEqual(x->waitp->cond, y->waitp->cond); } // Given the contents of a mutex word containing a PerThreadSynch pointer, // return the pointer. -static inline PerThreadSynch *GetPerThreadSynch(intptr_t v) { - return reinterpret_cast(v & kMuHigh); +static inline PerThreadSynch* GetPerThreadSynch(intptr_t v) { + return reinterpret_cast(v & kMuHigh); } // The next several routines maintain the per-thread next and skip fields @@ -852,17 +849,17 @@ static inline PerThreadSynch *GetPerThreadSynch(intptr_t v) { // except those in the added node and the former "head" node. This implies // that the new node is added after head, and so must be the new head or the // new front of the queue. -static PerThreadSynch *Skip(PerThreadSynch *x) { - PerThreadSynch *x0 = nullptr; - PerThreadSynch *x1 = x; - PerThreadSynch *x2 = x->skip; +static PerThreadSynch* Skip(PerThreadSynch* x) { + PerThreadSynch* x0 = nullptr; + PerThreadSynch* x1 = x; + PerThreadSynch* x2 = x->skip; if (x2 != nullptr) { // Each iteration attempts to advance sequence (x0,x1,x2) to next sequence // such that x1 == x0->skip && x2 == x1->skip while ((x0 = x1, x1 = x2, x2 = x2->skip) != nullptr) { - x0->skip = x2; // short-circuit skip from x0 to x2 + x0->skip = x2; // short-circuit skip from x0 to x2 } - x->skip = x1; // short-circuit skip from x to result + x->skip = x1; // short-circuit skip from x to result } return x1; } @@ -871,7 +868,7 @@ static PerThreadSynch *Skip(PerThreadSynch *x) { // The latter is going to be removed out of order, because of a timeout. // Check whether "ancestor" has a skip field pointing to "to_be_removed", // and fix it if it does. -static void FixSkip(PerThreadSynch *ancestor, PerThreadSynch *to_be_removed) { +static void FixSkip(PerThreadSynch* ancestor, PerThreadSynch* to_be_removed) { if (ancestor->skip == to_be_removed) { // ancestor->skip left dangling if (to_be_removed->skip != nullptr) { ancestor->skip = to_be_removed->skip; // can skip past to_be_removed @@ -883,7 +880,7 @@ static void FixSkip(PerThreadSynch *ancestor, PerThreadSynch *to_be_removed) { } } -static void CondVarEnqueue(SynchWaitParams *waitp); +static void CondVarEnqueue(SynchWaitParams* waitp); // Enqueue thread "waitp->thread" on a waiter queue. // Called with mutex spinlock held if head != nullptr @@ -904,8 +901,8 @@ static void CondVarEnqueue(SynchWaitParams *waitp); // returned. This mechanism is used by CondVar to queue a thread on the // condition variable queue instead of the mutex queue in implementing Wait(). // In this case, Enqueue() can return nullptr (if head==nullptr). -static PerThreadSynch *Enqueue(PerThreadSynch *head, - SynchWaitParams *waitp, intptr_t mu, int flags) { +static PerThreadSynch* Enqueue(PerThreadSynch* head, SynchWaitParams* waitp, + intptr_t mu, int flags) { // If we have been given a cv_word, call CondVarEnqueue() and return // the previous head of the Mutex waiter queue. if (waitp->cv_word != nullptr) { @@ -913,16 +910,16 @@ static PerThreadSynch *Enqueue(PerThreadSynch *head, return head; } - PerThreadSynch *s = waitp->thread; + PerThreadSynch* s = waitp->thread; ABSL_RAW_CHECK( s->waitp == nullptr || // normal case s->waitp == waitp || // Fer()---transfer from condition variable s->suppress_fatal_errors, "detected illegal recursion into Mutex code"); s->waitp = waitp; - s->skip = nullptr; // maintain skip invariant (see above) - s->may_skip = true; // always true on entering queue - s->wake = false; // not being woken + s->skip = nullptr; // maintain skip invariant (see above) + s->may_skip = true; // always true on entering queue + s->wake = false; // not being woken s->cond_waiter = ((flags & kMuIsCond) != 0); #ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM int64_t now_cycles = base_internal::CycleClock::Now(); @@ -949,7 +946,7 @@ static PerThreadSynch *Enqueue(PerThreadSynch *head, s->maybe_unlocking = false; // no one is searching an empty list head = s; // s is new head } else { - PerThreadSynch *enqueue_after = nullptr; // we'll put s after this element + PerThreadSynch* enqueue_after = nullptr; // we'll put s after this element #ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM if (s->priority > head->priority) { // s's priority is above head's // try to put s in priority-fifo order, or failing that at the front. @@ -960,20 +957,20 @@ static PerThreadSynch *Enqueue(PerThreadSynch *head, // Within a skip chain, all waiters have the same priority, so we can // skip forward through the chains until we find one with a lower // priority than the waiter to be enqueued. - PerThreadSynch *advance_to = head; // next value of enqueue_after + PerThreadSynch* advance_to = head; // next value of enqueue_after do { enqueue_after = advance_to; // (side-effect: optimizes skip chain) advance_to = Skip(enqueue_after->next); } while (s->priority <= advance_to->priority); - // termination guaranteed because s->priority > head->priority - // and head is the end of a skip chain + // termination guaranteed because s->priority > head->priority + // and head is the end of a skip chain } else if (waitp->how == kExclusive && Condition::GuaranteedEqual(waitp->cond, nullptr)) { // An unlocker could be scanning the queue, but we know it will recheck // the queue front for writers that have no condition, which is what s // is, so an insert at front is safe. - enqueue_after = head; // add after head, at front + enqueue_after = head; // add after head, at front } } #endif @@ -998,12 +995,12 @@ static PerThreadSynch *Enqueue(PerThreadSynch *head, enqueue_after->skip = enqueue_after->next; } if (MuEquivalentWaiter(s, s->next)) { // s->may_skip is known to be true - s->skip = s->next; // s may skip to its successor + s->skip = s->next; // s may skip to its successor } - } else { // enqueue not done any other way, so - // we're inserting s at the back + } else { // enqueue not done any other way, so + // we're inserting s at the back // s will become new head; copy data from head into it - s->next = head->next; // add s after head + s->next = head->next; // add s after head head->next = s; s->readers = head->readers; // reader count is from previous head s->maybe_unlocking = head->maybe_unlocking; // same for unlock hint @@ -1022,17 +1019,17 @@ static PerThreadSynch *Enqueue(PerThreadSynch *head, // whose last element is head. The new head element is returned, or null // if the list is made empty. // Dequeue is called with both spinlock and Mutex held. -static PerThreadSynch *Dequeue(PerThreadSynch *head, PerThreadSynch *pw) { - PerThreadSynch *w = pw->next; - pw->next = w->next; // snip w out of list - if (head == w) { // we removed the head +static PerThreadSynch* Dequeue(PerThreadSynch* head, PerThreadSynch* pw) { + PerThreadSynch* w = pw->next; + pw->next = w->next; // snip w out of list + if (head == w) { // we removed the head head = (pw == w) ? nullptr : pw; // either emptied list, or pw is new head } else if (pw != head && MuEquivalentWaiter(pw, pw->next)) { // pw can skip to its new successor if (pw->next->skip != nullptr) { // either skip to its successors skip target pw->skip = pw->next->skip; - } else { // or to pw's successor + } else { // or to pw's successor pw->skip = pw->next; } } @@ -1045,27 +1042,27 @@ static PerThreadSynch *Dequeue(PerThreadSynch *head, PerThreadSynch *pw) { // singly-linked list wake_list in the order found. Assumes that // there is only one such element if the element has how == kExclusive. // Return the new head. -static PerThreadSynch *DequeueAllWakeable(PerThreadSynch *head, - PerThreadSynch *pw, - PerThreadSynch **wake_tail) { - PerThreadSynch *orig_h = head; - PerThreadSynch *w = pw->next; +static PerThreadSynch* DequeueAllWakeable(PerThreadSynch* head, + PerThreadSynch* pw, + PerThreadSynch** wake_tail) { + PerThreadSynch* orig_h = head; + PerThreadSynch* w = pw->next; bool skipped = false; do { - if (w->wake) { // remove this element + if (w->wake) { // remove this element ABSL_RAW_CHECK(pw->skip == nullptr, "bad skip in DequeueAllWakeable"); // we're removing pw's successor so either pw->skip is zero or we should // already have removed pw since if pw->skip!=null, pw has the same // condition as w. head = Dequeue(head, pw); - w->next = *wake_tail; // keep list terminated - *wake_tail = w; // add w to wake_list; - wake_tail = &w->next; // next addition to end + w->next = *wake_tail; // keep list terminated + *wake_tail = w; // add w to wake_list; + wake_tail = &w->next; // next addition to end if (w->waitp->how == kExclusive) { // wake at most 1 writer break; } - } else { // not waking this one; skip - pw = Skip(w); // skip as much as possible + } else { // not waking this one; skip + pw = Skip(w); // skip as much as possible skipped = true; } w = pw->next; @@ -1083,7 +1080,7 @@ static PerThreadSynch *DequeueAllWakeable(PerThreadSynch *head, // Try to remove thread s from the list of waiters on this mutex. // Does nothing if s is not on the waiter list. -void Mutex::TryRemove(PerThreadSynch *s) { +void Mutex::TryRemove(PerThreadSynch* s) { SchedulingGuard::ScopedDisable disable_rescheduling; intptr_t v = mu_.load(std::memory_order_relaxed); // acquire spinlock & lock @@ -1091,16 +1088,16 @@ void Mutex::TryRemove(PerThreadSynch *s) { mu_.compare_exchange_strong(v, v | kMuSpin | kMuWriter, std::memory_order_acquire, std::memory_order_relaxed)) { - PerThreadSynch *h = GetPerThreadSynch(v); + PerThreadSynch* h = GetPerThreadSynch(v); if (h != nullptr) { - PerThreadSynch *pw = h; // pw is w's predecessor - PerThreadSynch *w; + PerThreadSynch* pw = h; // pw is w's predecessor + PerThreadSynch* w; if ((w = pw->next) != s) { // search for thread, do { // processing at least one element // If the current element isn't equivalent to the waiter to be // removed, we can skip the entire chain. if (!MuEquivalentWaiter(s, w)) { - pw = Skip(w); // so skip all that won't match + pw = Skip(w); // so skip all that won't match // we don't have to worry about dangling skip fields // in the threads we skipped; none can point to s // because they are in a different equivalence class. @@ -1112,7 +1109,7 @@ void Mutex::TryRemove(PerThreadSynch *s) { // process the first thread again. } while ((w = pw->next) != s && pw != h); } - if (w == s) { // found thread; remove it + if (w == s) { // found thread; remove it // pw->skip may be non-zero here; the loop above ensured that // no ancestor of s can skip to s, so removal is safe anyway. h = Dequeue(h, pw); @@ -1121,16 +1118,15 @@ void Mutex::TryRemove(PerThreadSynch *s) { } } intptr_t nv; - do { // release spinlock and lock + do { // release spinlock and lock v = mu_.load(std::memory_order_relaxed); nv = v & (kMuDesig | kMuEvent); if (h != nullptr) { nv |= kMuWait | reinterpret_cast(h); - h->readers = 0; // we hold writer lock + h->readers = 0; // we hold writer lock h->maybe_unlocking = false; // finished unlocking } - } while (!mu_.compare_exchange_weak(v, nv, - std::memory_order_release, + } while (!mu_.compare_exchange_weak(v, nv, std::memory_order_release, std::memory_order_relaxed)); } } @@ -1140,7 +1136,7 @@ void Mutex::TryRemove(PerThreadSynch *s) { // if the wait extends past the absolute time specified, even if "s" is still // on the mutex queue. In this case, remove "s" from the queue and return // true, otherwise return false. -void Mutex::Block(PerThreadSynch *s) { +void Mutex::Block(PerThreadSynch* s) { while (s->state.load(std::memory_order_acquire) == PerThreadSynch::kQueued) { if (!DecrementSynchSem(this, s, s->waitp->timeout)) { // After a timeout, we go into a spin loop until we remove ourselves @@ -1159,7 +1155,7 @@ void Mutex::Block(PerThreadSynch *s) { // is not on the queue. this->TryRemove(s); } - s->waitp->timeout = KernelTimeout::Never(); // timeout is satisfied + s->waitp->timeout = KernelTimeout::Never(); // timeout is satisfied s->waitp->cond = nullptr; // condition no longer relevant for wakeups } } @@ -1169,8 +1165,8 @@ void Mutex::Block(PerThreadSynch *s) { } // Wake thread w, and return the next thread in the list. -PerThreadSynch *Mutex::Wakeup(PerThreadSynch *w) { - PerThreadSynch *next = w->next; +PerThreadSynch* Mutex::Wakeup(PerThreadSynch* w) { + PerThreadSynch* next = w->next; w->next = nullptr; w->state.store(PerThreadSynch::kAvailable, std::memory_order_release); IncrementSynchSem(this, w); @@ -1178,7 +1174,7 @@ PerThreadSynch *Mutex::Wakeup(PerThreadSynch *w) { return next; } -static GraphId GetGraphIdLocked(Mutex *mu) +static GraphId GetGraphIdLocked(Mutex* mu) ABSL_EXCLUSIVE_LOCKS_REQUIRED(deadlock_graph_mu) { if (!deadlock_graph) { // (re)create the deadlock graph. deadlock_graph = @@ -1188,7 +1184,7 @@ static GraphId GetGraphIdLocked(Mutex *mu) return deadlock_graph->GetId(mu); } -static GraphId GetGraphId(Mutex *mu) ABSL_LOCKS_EXCLUDED(deadlock_graph_mu) { +static GraphId GetGraphId(Mutex* mu) ABSL_LOCKS_EXCLUDED(deadlock_graph_mu) { deadlock_graph_mu.Lock(); GraphId id = GetGraphIdLocked(mu); deadlock_graph_mu.Unlock(); @@ -1198,7 +1194,7 @@ static GraphId GetGraphId(Mutex *mu) ABSL_LOCKS_EXCLUDED(deadlock_graph_mu) { // Record a lock acquisition. This is used in debug mode for deadlock // detection. The held_locks pointer points to the relevant data // structure for each case. -static void LockEnter(Mutex* mu, GraphId id, SynchLocksHeld *held_locks) { +static void LockEnter(Mutex* mu, GraphId id, SynchLocksHeld* held_locks) { int n = held_locks->n; int i = 0; while (i != n && held_locks->locks[i].id != id) { @@ -1222,7 +1218,7 @@ static void LockEnter(Mutex* mu, GraphId id, SynchLocksHeld *held_locks) { // eventually followed by a call to LockLeave(mu, id, x) by the same thread. // It does not process the event if is not needed when deadlock detection is // disabled. -static void LockLeave(Mutex* mu, GraphId id, SynchLocksHeld *held_locks) { +static void LockLeave(Mutex* mu, GraphId id, SynchLocksHeld* held_locks) { int n = held_locks->n; int i = 0; while (i != n && held_locks->locks[i].id != id) { @@ -1237,11 +1233,11 @@ static void LockLeave(Mutex* mu, GraphId id, SynchLocksHeld *held_locks) { i++; } if (i == n) { // mu missing means releasing unheld lock - SynchEvent *mu_events = GetSynchEvent(mu); + SynchEvent* mu_events = GetSynchEvent(mu); ABSL_RAW_LOG(FATAL, "thread releasing lock it does not hold: %p %s; " , - static_cast(mu), + static_cast(mu), mu_events == nullptr ? "" : mu_events->name); } } @@ -1258,7 +1254,7 @@ static void LockLeave(Mutex* mu, GraphId id, SynchLocksHeld *held_locks) { } // Call LockEnter() if in debug mode and deadlock detection is enabled. -static inline void DebugOnlyLockEnter(Mutex *mu) { +static inline void DebugOnlyLockEnter(Mutex* mu) { if (kDebugMode) { if (synch_deadlock_detection.load(std::memory_order_acquire) != OnDeadlockCycle::kIgnore) { @@ -1268,7 +1264,7 @@ static inline void DebugOnlyLockEnter(Mutex *mu) { } // Call LockEnter() if in debug mode and deadlock detection is enabled. -static inline void DebugOnlyLockEnter(Mutex *mu, GraphId id) { +static inline void DebugOnlyLockEnter(Mutex* mu, GraphId id) { if (kDebugMode) { if (synch_deadlock_detection.load(std::memory_order_acquire) != OnDeadlockCycle::kIgnore) { @@ -1278,7 +1274,7 @@ static inline void DebugOnlyLockEnter(Mutex *mu, GraphId id) { } // Call LockLeave() if in debug mode and deadlock detection is enabled. -static inline void DebugOnlyLockLeave(Mutex *mu) { +static inline void DebugOnlyLockLeave(Mutex* mu) { if (kDebugMode) { if (synch_deadlock_detection.load(std::memory_order_acquire) != OnDeadlockCycle::kIgnore) { @@ -1287,7 +1283,7 @@ static inline void DebugOnlyLockLeave(Mutex *mu) { } } -static char *StackString(void **pcs, int n, char *buf, int maxlen, +static char* StackString(void** pcs, int n, char* buf, int maxlen, bool symbolize) { static constexpr int kSymLen = 200; char sym[kSymLen]; @@ -1310,15 +1306,17 @@ static char *StackString(void **pcs, int n, char *buf, int maxlen, return buf; } -static char *CurrentStackString(char *buf, int maxlen, bool symbolize) { - void *pcs[40]; +static char* CurrentStackString(char* buf, int maxlen, bool symbolize) { + void* pcs[40]; return StackString(pcs, absl::GetStackTrace(pcs, ABSL_ARRAYSIZE(pcs), 2), buf, maxlen, symbolize); } namespace { -enum { kMaxDeadlockPathLen = 10 }; // maximum length of a deadlock cycle; - // a path this long would be remarkable +enum { + kMaxDeadlockPathLen = 10 +}; // maximum length of a deadlock cycle; + // a path this long would be remarkable // Buffers required to report a deadlock. // We do not allocate them on stack to avoid large stack frame. struct DeadlockReportBuffers { @@ -1328,11 +1326,11 @@ struct DeadlockReportBuffers { struct ScopedDeadlockReportBuffers { ScopedDeadlockReportBuffers() { - b = reinterpret_cast( + b = reinterpret_cast( base_internal::LowLevelAlloc::Alloc(sizeof(*b))); } ~ScopedDeadlockReportBuffers() { base_internal::LowLevelAlloc::Free(b); } - DeadlockReportBuffers *b; + DeadlockReportBuffers* b; }; // Helper to pass to GraphCycles::UpdateStackTrace. @@ -1343,13 +1341,13 @@ int GetStack(void** stack, int max_depth) { // Called in debug mode when a thread is about to acquire a lock in a way that // may block. -static GraphId DeadlockCheck(Mutex *mu) { +static GraphId DeadlockCheck(Mutex* mu) { if (synch_deadlock_detection.load(std::memory_order_acquire) == OnDeadlockCycle::kIgnore) { return InvalidGraphId(); } - SynchLocksHeld *all_locks = Synch_GetAllLocks(); + SynchLocksHeld* all_locks = Synch_GetAllLocks(); absl::base_internal::SpinLockHolder lock(&deadlock_graph_mu); const GraphId mu_id = GetGraphIdLocked(mu); @@ -1371,8 +1369,8 @@ static GraphId DeadlockCheck(Mutex *mu) { // For each other mutex already held by this thread: for (int i = 0; i != all_locks->n; i++) { const GraphId other_node_id = all_locks->locks[i].id; - const Mutex *other = - static_cast(deadlock_graph->Ptr(other_node_id)); + const Mutex* other = + static_cast(deadlock_graph->Ptr(other_node_id)); if (other == nullptr) { // Ignore stale lock continue; @@ -1381,7 +1379,7 @@ static GraphId DeadlockCheck(Mutex *mu) { // Add the acquired-before edge to the graph. if (!deadlock_graph->InsertEdge(other_node_id, mu_id)) { ScopedDeadlockReportBuffers scoped_buffers; - DeadlockReportBuffers *b = scoped_buffers.b; + DeadlockReportBuffers* b = scoped_buffers.b; static int number_of_reported_deadlocks = 0; number_of_reported_deadlocks++; // Symbolize only 2 first deadlock report to avoid huge slowdowns. @@ -1392,25 +1390,25 @@ static GraphId DeadlockCheck(Mutex *mu) { for (int j = 0; j != all_locks->n; j++) { void* pr = deadlock_graph->Ptr(all_locks->locks[j].id); if (pr != nullptr) { - snprintf(b->buf + len, sizeof (b->buf) - len, " %p", pr); + snprintf(b->buf + len, sizeof(b->buf) - len, " %p", pr); len += strlen(&b->buf[len]); } } ABSL_RAW_LOG(ERROR, "Acquiring absl::Mutex %p while holding %s; a cycle in the " "historical lock ordering graph has been observed", - static_cast(mu), b->buf); + static_cast(mu), b->buf); ABSL_RAW_LOG(ERROR, "Cycle: "); - int path_len = deadlock_graph->FindPath( - mu_id, other_node_id, ABSL_ARRAYSIZE(b->path), b->path); + int path_len = deadlock_graph->FindPath(mu_id, other_node_id, + ABSL_ARRAYSIZE(b->path), b->path); for (int j = 0; j != path_len && j != ABSL_ARRAYSIZE(b->path); j++) { GraphId id = b->path[j]; - Mutex *path_mu = static_cast(deadlock_graph->Ptr(id)); + Mutex* path_mu = static_cast(deadlock_graph->Ptr(id)); if (path_mu == nullptr) continue; void** stack; int depth = deadlock_graph->GetStackTrace(id, &stack); snprintf(b->buf, sizeof(b->buf), - "mutex@%p stack: ", static_cast(path_mu)); + "mutex@%p stack: ", static_cast(path_mu)); StackString(stack, depth, b->buf + strlen(b->buf), static_cast(sizeof(b->buf) - strlen(b->buf)), symbolize); @@ -1425,7 +1423,7 @@ static GraphId DeadlockCheck(Mutex *mu) { ABSL_RAW_LOG(FATAL, "dying due to potential deadlock"); return mu_id; } - break; // report at most one potential deadlock per acquisition + break; // report at most one potential deadlock per acquisition } } @@ -1434,7 +1432,7 @@ static GraphId DeadlockCheck(Mutex *mu) { // Invoke DeadlockCheck() iff we're in debug mode and // deadlock checking has been enabled. -static inline GraphId DebugOnlyDeadlockCheck(Mutex *mu) { +static inline GraphId DebugOnlyDeadlockCheck(Mutex* mu) { if (kDebugMode && synch_deadlock_detection.load(std::memory_order_acquire) != OnDeadlockCycle::kIgnore) { return DeadlockCheck(mu); @@ -1461,13 +1459,13 @@ void Mutex::AssertNotHeld() const { (mu_.load(std::memory_order_relaxed) & (kMuWriter | kMuReader)) != 0 && synch_deadlock_detection.load(std::memory_order_acquire) != OnDeadlockCycle::kIgnore) { - GraphId id = GetGraphId(const_cast(this)); - SynchLocksHeld *locks = Synch_GetAllLocks(); + GraphId id = GetGraphId(const_cast(this)); + SynchLocksHeld* locks = Synch_GetAllLocks(); for (int i = 0; i != locks->n; i++) { if (locks->locks[i].id == id) { - SynchEvent *mu_events = GetSynchEvent(this); + SynchEvent* mu_events = GetSynchEvent(this); ABSL_RAW_LOG(FATAL, "thread should not hold mutex %p %s", - static_cast(this), + static_cast(this), (mu_events == nullptr ? "" : mu_events->name)); } } @@ -1480,8 +1478,8 @@ static bool TryAcquireWithSpinning(std::atomic* mu) { int c = GetMutexGlobals().spinloop_iterations; do { // do/while somewhat faster on AMD intptr_t v = mu->load(std::memory_order_relaxed); - if ((v & (kMuReader|kMuEvent)) != 0) { - return false; // a reader or tracing -> give up + if ((v & (kMuReader | kMuEvent)) != 0) { + return false; // a reader or tracing -> give up } else if (((v & kMuWriter) == 0) && // no holder -> try to acquire mu->compare_exchange_strong(v, kMuWriter | v, std::memory_order_acquire, @@ -1498,8 +1496,7 @@ void Mutex::Lock() { intptr_t v = mu_.load(std::memory_order_relaxed); // try fast acquire, then spin loop if ((v & (kMuWriter | kMuReader | kMuEvent)) != 0 || - !mu_.compare_exchange_strong(v, kMuWriter | v, - std::memory_order_acquire, + !mu_.compare_exchange_strong(v, kMuWriter | v, std::memory_order_acquire, std::memory_order_relaxed)) { // try spin acquire, then slow loop if (!TryAcquireWithSpinning(&this->mu_)) { @@ -1525,7 +1522,7 @@ void Mutex::ReaderLock() { ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_read_lock, 0); } -void Mutex::LockWhen(const Condition &cond) { +void Mutex::LockWhen(const Condition& cond) { ABSL_TSAN_MUTEX_PRE_LOCK(this, 0); GraphId id = DebugOnlyDeadlockCheck(this); this->LockSlow(kExclusive, &cond, 0); @@ -1533,27 +1530,26 @@ void Mutex::LockWhen(const Condition &cond) { ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0); } -bool Mutex::LockWhenWithTimeout(const Condition &cond, absl::Duration timeout) { +bool Mutex::LockWhenWithTimeout(const Condition& cond, absl::Duration timeout) { ABSL_TSAN_MUTEX_PRE_LOCK(this, 0); GraphId id = DebugOnlyDeadlockCheck(this); - bool res = LockSlowWithDeadline(kExclusive, &cond, - KernelTimeout(timeout), 0); + bool res = LockSlowWithDeadline(kExclusive, &cond, KernelTimeout(timeout), 0); DebugOnlyLockEnter(this, id); ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0); return res; } -bool Mutex::LockWhenWithDeadline(const Condition &cond, absl::Time deadline) { +bool Mutex::LockWhenWithDeadline(const Condition& cond, absl::Time deadline) { ABSL_TSAN_MUTEX_PRE_LOCK(this, 0); GraphId id = DebugOnlyDeadlockCheck(this); - bool res = LockSlowWithDeadline(kExclusive, &cond, - KernelTimeout(deadline), 0); + bool res = + LockSlowWithDeadline(kExclusive, &cond, KernelTimeout(deadline), 0); DebugOnlyLockEnter(this, id); ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0); return res; } -void Mutex::ReaderLockWhen(const Condition &cond) { +void Mutex::ReaderLockWhen(const Condition& cond) { ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_read_lock); GraphId id = DebugOnlyDeadlockCheck(this); this->LockSlow(kShared, &cond, 0); @@ -1561,7 +1557,7 @@ void Mutex::ReaderLockWhen(const Condition &cond) { ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_read_lock, 0); } -bool Mutex::ReaderLockWhenWithTimeout(const Condition &cond, +bool Mutex::ReaderLockWhenWithTimeout(const Condition& cond, absl::Duration timeout) { ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_read_lock); GraphId id = DebugOnlyDeadlockCheck(this); @@ -1571,7 +1567,7 @@ bool Mutex::ReaderLockWhenWithTimeout(const Condition &cond, return res; } -bool Mutex::ReaderLockWhenWithDeadline(const Condition &cond, +bool Mutex::ReaderLockWhenWithDeadline(const Condition& cond, absl::Time deadline) { ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_read_lock); GraphId id = DebugOnlyDeadlockCheck(this); @@ -1581,19 +1577,19 @@ bool Mutex::ReaderLockWhenWithDeadline(const Condition &cond, return res; } -void Mutex::Await(const Condition &cond) { - if (cond.Eval()) { // condition already true; nothing to do +void Mutex::Await(const Condition& cond) { + if (cond.Eval()) { // condition already true; nothing to do if (kDebugMode) { this->AssertReaderHeld(); } - } else { // normal case + } else { // normal case ABSL_RAW_CHECK(this->AwaitCommon(cond, KernelTimeout::Never()), "condition untrue on return from Await"); } } -bool Mutex::AwaitWithTimeout(const Condition &cond, absl::Duration timeout) { - if (cond.Eval()) { // condition already true; nothing to do +bool Mutex::AwaitWithTimeout(const Condition& cond, absl::Duration timeout) { + if (cond.Eval()) { // condition already true; nothing to do if (kDebugMode) { this->AssertReaderHeld(); } @@ -1607,8 +1603,8 @@ bool Mutex::AwaitWithTimeout(const Condition &cond, absl::Duration timeout) { return res; } -bool Mutex::AwaitWithDeadline(const Condition &cond, absl::Time deadline) { - if (cond.Eval()) { // condition already true; nothing to do +bool Mutex::AwaitWithDeadline(const Condition& cond, absl::Time deadline) { + if (cond.Eval()) { // condition already true; nothing to do if (kDebugMode) { this->AssertReaderHeld(); } @@ -1622,14 +1618,14 @@ bool Mutex::AwaitWithDeadline(const Condition &cond, absl::Time deadline) { return res; } -bool Mutex::AwaitCommon(const Condition &cond, KernelTimeout t) { +bool Mutex::AwaitCommon(const Condition& cond, KernelTimeout t) { this->AssertReaderHeld(); MuHow how = (mu_.load(std::memory_order_relaxed) & kMuWriter) ? kExclusive : kShared; ABSL_TSAN_MUTEX_PRE_UNLOCK(this, TsanFlags(how)); - SynchWaitParams waitp( - how, &cond, t, nullptr /*no cvmu*/, Synch_GetPerThreadAnnotated(this), - nullptr /*no cv_word*/); + SynchWaitParams waitp(how, &cond, t, nullptr /*no cvmu*/, + Synch_GetPerThreadAnnotated(this), + nullptr /*no cv_word*/); int flags = kMuHasBlocked; if (!Condition::GuaranteedEqual(&cond, nullptr)) { flags |= kMuIsCond; @@ -1649,14 +1645,13 @@ bool Mutex::TryLock() { ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock); intptr_t v = mu_.load(std::memory_order_relaxed); if ((v & (kMuWriter | kMuReader | kMuEvent)) == 0 && // try fast acquire - mu_.compare_exchange_strong(v, kMuWriter | v, - std::memory_order_acquire, + mu_.compare_exchange_strong(v, kMuWriter | v, std::memory_order_acquire, std::memory_order_relaxed)) { DebugOnlyLockEnter(this); ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_try_lock, 0); return true; } - if ((v & kMuEvent) != 0) { // we're recording events + if ((v & kMuEvent) != 0) { // we're recording events if ((v & kExclusive->slow_need_zero) == 0 && // try fast acquire mu_.compare_exchange_strong( v, (kExclusive->fast_or | v) + kExclusive->fast_add, @@ -1682,7 +1677,7 @@ bool Mutex::ReaderTryLock() { // changing (typically because the reader count changes) under the CAS. We // limit the number of attempts to avoid having to think about livelock. int loop_limit = 5; - while ((v & (kMuWriter|kMuWait|kMuEvent)) == 0 && loop_limit != 0) { + while ((v & (kMuWriter | kMuWait | kMuEvent)) == 0 && loop_limit != 0) { if (mu_.compare_exchange_strong(v, (kMuReader | v) + kMuOne, std::memory_order_acquire, std::memory_order_relaxed)) { @@ -1694,7 +1689,7 @@ bool Mutex::ReaderTryLock() { loop_limit--; v = mu_.load(std::memory_order_relaxed); } - if ((v & kMuEvent) != 0) { // we're recording events + if ((v & kMuEvent) != 0) { // we're recording events loop_limit = 5; while ((v & kShared->slow_need_zero) == 0 && loop_limit != 0) { if (mu_.compare_exchange_strong(v, (kMuReader | v) + kMuOne, @@ -1733,7 +1728,7 @@ void Mutex::Unlock() { // should_try_cas is whether we'll try a compare-and-swap immediately. // NOTE: optimized out when kDebugMode is false. bool should_try_cas = ((v & (kMuEvent | kMuWriter)) == kMuWriter && - (v & (kMuWait | kMuDesig)) != kMuWait); + (v & (kMuWait | kMuDesig)) != kMuWait); // But, we can use an alternate computation of it, that compilers // currently don't find on their own. When that changes, this function // can be simplified. @@ -1750,10 +1745,9 @@ void Mutex::Unlock() { static_cast(v), static_cast(x), static_cast(y)); } - if (x < y && - mu_.compare_exchange_strong(v, v & ~(kMuWrWait | kMuWriter), - std::memory_order_release, - std::memory_order_relaxed)) { + if (x < y && mu_.compare_exchange_strong(v, v & ~(kMuWrWait | kMuWriter), + std::memory_order_release, + std::memory_order_relaxed)) { // fast writer release (writer with no waiters or with designated waker) } else { this->UnlockSlow(nullptr /*no waitp*/); // take slow path @@ -1763,7 +1757,7 @@ void Mutex::Unlock() { // Requires v to represent a reader-locked state. static bool ExactlyOneReader(intptr_t v) { - assert((v & (kMuWriter|kMuReader)) == kMuReader); + assert((v & (kMuWriter | kMuReader)) == kMuReader); assert((v & kMuHigh) != 0); // The more straightforward "(v & kMuHigh) == kMuOne" also works, but // on some architectures the following generates slightly smaller code. @@ -1776,12 +1770,11 @@ void Mutex::ReaderUnlock() { ABSL_TSAN_MUTEX_PRE_UNLOCK(this, __tsan_mutex_read_lock); DebugOnlyLockLeave(this); intptr_t v = mu_.load(std::memory_order_relaxed); - assert((v & (kMuWriter|kMuReader)) == kMuReader); - if ((v & (kMuReader|kMuWait|kMuEvent)) == kMuReader) { + assert((v & (kMuWriter | kMuReader)) == kMuReader); + if ((v & (kMuReader | kMuWait | kMuEvent)) == kMuReader) { // fast reader release (reader with no waiters) - intptr_t clear = ExactlyOneReader(v) ? kMuReader|kMuOne : kMuOne; - if (mu_.compare_exchange_strong(v, v - clear, - std::memory_order_release, + intptr_t clear = ExactlyOneReader(v) ? kMuReader | kMuOne : kMuOne; + if (mu_.compare_exchange_strong(v, v - clear, std::memory_order_release, std::memory_order_relaxed)) { ABSL_TSAN_MUTEX_POST_UNLOCK(this, __tsan_mutex_read_lock); return; @@ -1820,7 +1813,7 @@ static intptr_t IgnoreWaitingWritersMask(int flag) { } // Internal version of LockWhen(). See LockSlowWithDeadline() -ABSL_ATTRIBUTE_NOINLINE void Mutex::LockSlow(MuHow how, const Condition *cond, +ABSL_ATTRIBUTE_NOINLINE void Mutex::LockSlow(MuHow how, const Condition* cond, int flags) { ABSL_RAW_CHECK( this->LockSlowWithDeadline(how, cond, KernelTimeout::Never(), flags), @@ -1828,7 +1821,7 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::LockSlow(MuHow how, const Condition *cond, } // Compute cond->Eval() and tell race detectors that we do it under mutex mu. -static inline bool EvalConditionAnnotated(const Condition *cond, Mutex *mu, +static inline bool EvalConditionAnnotated(const Condition* cond, Mutex* mu, bool locking, bool trylock, bool read_lock) { // Delicate annotation dance. @@ -1878,7 +1871,7 @@ static inline bool EvalConditionAnnotated(const Condition *cond, Mutex *mu, // tsan). As the result there is no tsan-visible synchronization between the // addition and this thread. So if we would enable race detection here, // it would race with the predicate initialization. -static inline bool EvalConditionIgnored(Mutex *mu, const Condition *cond) { +static inline bool EvalConditionIgnored(Mutex* mu, const Condition* cond) { // Memory accesses are already ignored inside of lock/unlock operations, // but synchronization operations are also ignored. When we evaluate the // predicate we must ignore only memory accesses but not synchronization, @@ -1903,7 +1896,7 @@ static inline bool EvalConditionIgnored(Mutex *mu, const Condition *cond) { // obstruct this call // - kMuIsCond indicates that this is a conditional acquire (condition variable, // Await, LockWhen) so contention profiling should be suppressed. -bool Mutex::LockSlowWithDeadline(MuHow how, const Condition *cond, +bool Mutex::LockSlowWithDeadline(MuHow how, const Condition* cond, KernelTimeout t, int flags) { intptr_t v = mu_.load(std::memory_order_relaxed); bool unlock = false; @@ -1920,9 +1913,9 @@ bool Mutex::LockSlowWithDeadline(MuHow how, const Condition *cond, } unlock = true; } - SynchWaitParams waitp( - how, cond, t, nullptr /*no cvmu*/, Synch_GetPerThreadAnnotated(this), - nullptr /*no cv_word*/); + SynchWaitParams waitp(how, cond, t, nullptr /*no cvmu*/, + Synch_GetPerThreadAnnotated(this), + nullptr /*no cv_word*/); if (!Condition::GuaranteedEqual(cond, nullptr)) { flags |= kMuIsCond; } @@ -1963,20 +1956,20 @@ static void CheckForMutexCorruption(intptr_t v, const char* label) { if (ABSL_PREDICT_TRUE((w & (w << 3) & (kMuWriter | kMuWrWait)) == 0)) return; RAW_CHECK_FMT((v & (kMuWriter | kMuReader)) != (kMuWriter | kMuReader), "%s: Mutex corrupt: both reader and writer lock held: %p", - label, reinterpret_cast(v)); + label, reinterpret_cast(v)); RAW_CHECK_FMT((v & (kMuWait | kMuWrWait)) != kMuWrWait, - "%s: Mutex corrupt: waiting writer with no waiters: %p", - label, reinterpret_cast(v)); + "%s: Mutex corrupt: waiting writer with no waiters: %p", label, + reinterpret_cast(v)); assert(false); } -void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) { +void Mutex::LockSlowLoop(SynchWaitParams* waitp, int flags) { SchedulingGuard::ScopedDisable disable_rescheduling; int c = 0; intptr_t v = mu_.load(std::memory_order_relaxed); if ((v & kMuEvent) != 0) { - PostSynchEvent(this, - waitp->how == kExclusive? SYNCH_EV_LOCK: SYNCH_EV_READERLOCK); + PostSynchEvent( + this, waitp->how == kExclusive ? SYNCH_EV_LOCK : SYNCH_EV_READERLOCK); } ABSL_RAW_CHECK( waitp->thread->waitp == nullptr || waitp->thread->suppress_fatal_errors, @@ -2001,11 +1994,11 @@ void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) { flags |= kMuHasBlocked; c = 0; } - } else { // need to access waiter list + } else { // need to access waiter list bool dowait = false; - if ((v & (kMuSpin|kMuWait)) == 0) { // no waiters + if ((v & (kMuSpin | kMuWait)) == 0) { // no waiters // This thread tries to become the one and only waiter. - PerThreadSynch *new_h = Enqueue(nullptr, waitp, v, flags); + PerThreadSynch* new_h = Enqueue(nullptr, waitp, v, flags); intptr_t nv = (v & ClearDesignatedWakerMask(flags & kMuHasBlocked) & kMuLow) | kMuWait; @@ -2017,7 +2010,7 @@ void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) { v, reinterpret_cast(new_h) | nv, std::memory_order_release, std::memory_order_relaxed)) { dowait = true; - } else { // attempted Enqueue() failed + } else { // attempted Enqueue() failed // zero out the waitp field set by Enqueue() waitp->thread->waitp = nullptr; } @@ -2030,9 +2023,9 @@ void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) { (v & ClearDesignatedWakerMask(flags & kMuHasBlocked)) | kMuSpin | kMuReader, std::memory_order_acquire, std::memory_order_relaxed)) { - PerThreadSynch *h = GetPerThreadSynch(v); - h->readers += kMuOne; // inc reader count in waiter - do { // release spinlock + PerThreadSynch* h = GetPerThreadSynch(v); + h->readers += kMuOne; // inc reader count in waiter + do { // release spinlock v = mu_.load(std::memory_order_relaxed); } while (!mu_.compare_exchange_weak(v, (v & ~kMuSpin) | kMuReader, std::memory_order_release, @@ -2042,7 +2035,7 @@ void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) { waitp->how == kShared)) { break; // we timed out, or condition true, so return } - this->UnlockSlow(waitp); // got lock but condition false + this->UnlockSlow(waitp); // got lock but condition false this->Block(waitp->thread); flags |= kMuHasBlocked; c = 0; @@ -2053,18 +2046,19 @@ void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) { (v & ClearDesignatedWakerMask(flags & kMuHasBlocked)) | kMuSpin | kMuWait, std::memory_order_acquire, std::memory_order_relaxed)) { - PerThreadSynch *h = GetPerThreadSynch(v); - PerThreadSynch *new_h = Enqueue(h, waitp, v, flags); + PerThreadSynch* h = GetPerThreadSynch(v); + PerThreadSynch* new_h = Enqueue(h, waitp, v, flags); intptr_t wr_wait = 0; ABSL_RAW_CHECK(new_h != nullptr, "Enqueue to list failed"); if (waitp->how == kExclusive && (v & kMuReader) != 0) { - wr_wait = kMuWrWait; // give priority to a waiting writer + wr_wait = kMuWrWait; // give priority to a waiting writer } - do { // release spinlock + do { // release spinlock v = mu_.load(std::memory_order_relaxed); } while (!mu_.compare_exchange_weak( - v, (v & (kMuLow & ~kMuSpin)) | kMuWait | wr_wait | - reinterpret_cast(new_h), + v, + (v & (kMuLow & ~kMuSpin)) | kMuWait | wr_wait | + reinterpret_cast(new_h), std::memory_order_release, std::memory_order_relaxed)); dowait = true; } @@ -2084,9 +2078,9 @@ void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) { waitp->thread->waitp == nullptr || waitp->thread->suppress_fatal_errors, "detected illegal recursion into Mutex code"); if ((v & kMuEvent) != 0) { - PostSynchEvent(this, - waitp->how == kExclusive? SYNCH_EV_LOCK_RETURNING : - SYNCH_EV_READERLOCK_RETURNING); + PostSynchEvent(this, waitp->how == kExclusive + ? SYNCH_EV_LOCK_RETURNING + : SYNCH_EV_READERLOCK_RETURNING); } } @@ -2095,28 +2089,28 @@ void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) { // which holds the lock but is not runnable because its condition is false // or it is in the process of blocking on a condition variable; it must requeue // itself on the mutex/condvar to wait for its condition to become true. -ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) { +ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams* waitp) { SchedulingGuard::ScopedDisable disable_rescheduling; intptr_t v = mu_.load(std::memory_order_relaxed); this->AssertReaderHeld(); CheckForMutexCorruption(v, "Unlock"); if ((v & kMuEvent) != 0) { - PostSynchEvent(this, - (v & kMuWriter) != 0? SYNCH_EV_UNLOCK: SYNCH_EV_READERUNLOCK); + PostSynchEvent( + this, (v & kMuWriter) != 0 ? SYNCH_EV_UNLOCK : SYNCH_EV_READERUNLOCK); } int c = 0; // the waiter under consideration to wake, or zero - PerThreadSynch *w = nullptr; + PerThreadSynch* w = nullptr; // the predecessor to w or zero - PerThreadSynch *pw = nullptr; + PerThreadSynch* pw = nullptr; // head of the list searched previously, or zero - PerThreadSynch *old_h = nullptr; + PerThreadSynch* old_h = nullptr; // a condition that's known to be false. - const Condition *known_false = nullptr; - PerThreadSynch *wake_list = kPerThreadSynchNull; // list of threads to wake - intptr_t wr_wait = 0; // set to kMuWrWait if we wake a reader and a - // later writer could have acquired the lock - // (starvation avoidance) + const Condition* known_false = nullptr; + PerThreadSynch* wake_list = kPerThreadSynchNull; // list of threads to wake + intptr_t wr_wait = 0; // set to kMuWrWait if we wake a reader and a + // later writer could have acquired the lock + // (starvation avoidance) ABSL_RAW_CHECK(waitp == nullptr || waitp->thread->waitp == nullptr || waitp->thread->suppress_fatal_errors, "detected illegal recursion into Mutex code"); @@ -2136,8 +2130,7 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) { } else if ((v & (kMuReader | kMuWait)) == kMuReader && waitp == nullptr) { // fast reader release (reader with no waiters) intptr_t clear = ExactlyOneReader(v) ? kMuReader | kMuOne : kMuOne; - if (mu_.compare_exchange_strong(v, v - clear, - std::memory_order_release, + if (mu_.compare_exchange_strong(v, v - clear, std::memory_order_release, std::memory_order_relaxed)) { return; } @@ -2145,16 +2138,16 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) { mu_.compare_exchange_strong(v, v | kMuSpin, std::memory_order_acquire, std::memory_order_relaxed)) { - if ((v & kMuWait) == 0) { // no one to wake + if ((v & kMuWait) == 0) { // no one to wake intptr_t nv; bool do_enqueue = true; // always Enqueue() the first time ABSL_RAW_CHECK(waitp != nullptr, "UnlockSlow is confused"); // about to sleep - do { // must loop to release spinlock as reader count may change + do { // must loop to release spinlock as reader count may change v = mu_.load(std::memory_order_relaxed); // decrement reader count if there are readers - intptr_t new_readers = (v >= kMuOne)? v - kMuOne : v; - PerThreadSynch *new_h = nullptr; + intptr_t new_readers = (v >= kMuOne) ? v - kMuOne : v; + PerThreadSynch* new_h = nullptr; if (do_enqueue) { // If we are enqueuing on a CondVar (waitp->cv_word != nullptr) then // we must not retry here. The initial attempt will always have @@ -2178,21 +2171,20 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) { } // release spinlock & our lock; retry if reader-count changed // (writer count cannot change since we hold lock) - } while (!mu_.compare_exchange_weak(v, nv, - std::memory_order_release, + } while (!mu_.compare_exchange_weak(v, nv, std::memory_order_release, std::memory_order_relaxed)); break; } // There are waiters. // Set h to the head of the circular waiter list. - PerThreadSynch *h = GetPerThreadSynch(v); + PerThreadSynch* h = GetPerThreadSynch(v); if ((v & kMuReader) != 0 && (h->readers & kMuHigh) > kMuOne) { // a reader but not the last - h->readers -= kMuOne; // release our lock - intptr_t nv = v; // normally just release spinlock + h->readers -= kMuOne; // release our lock + intptr_t nv = v; // normally just release spinlock if (waitp != nullptr) { // but waitp!=nullptr => must queue ourselves - PerThreadSynch *new_h = Enqueue(h, waitp, v, kMuIsCond); + PerThreadSynch* new_h = Enqueue(h, waitp, v, kMuIsCond); ABSL_RAW_CHECK(new_h != nullptr, "waiters disappeared during Enqueue()!"); nv &= kMuLow; @@ -2210,8 +2202,8 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) { // The lock is becoming free, and there's a waiter if (old_h != nullptr && - !old_h->may_skip) { // we used old_h as a terminator - old_h->may_skip = true; // allow old_h to skip once more + !old_h->may_skip) { // we used old_h as a terminator + old_h->may_skip = true; // allow old_h to skip once more ABSL_RAW_CHECK(old_h->skip == nullptr, "illegal skip from head"); if (h != old_h && MuEquivalentWaiter(old_h, old_h->next)) { old_h->skip = old_h->next; // old_h not head & can skip to successor @@ -2220,7 +2212,7 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) { if (h->next->waitp->how == kExclusive && Condition::GuaranteedEqual(h->next->waitp->cond, nullptr)) { // easy case: writer with no condition; no need to search - pw = h; // wake w, the successor of h (=pw) + pw = h; // wake w, the successor of h (=pw) w = h->next; w->wake = true; // We are waking up a writer. This writer may be racing against @@ -2243,13 +2235,13 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) { // waiter has a condition or is a reader. We avoid searching over // waiters we've searched on previous iterations by starting at // old_h if it's set. If old_h==h, there's no one to wakeup at all. - if (old_h == h) { // we've searched before, and nothing's new - // so there's no one to wake. - intptr_t nv = (v & ~(kMuReader|kMuWriter|kMuWrWait)); + if (old_h == h) { // we've searched before, and nothing's new + // so there's no one to wake. + intptr_t nv = (v & ~(kMuReader | kMuWriter | kMuWrWait)); h->readers = 0; - h->maybe_unlocking = false; // finished unlocking - if (waitp != nullptr) { // we must queue ourselves and sleep - PerThreadSynch *new_h = Enqueue(h, waitp, v, kMuIsCond); + h->maybe_unlocking = false; // finished unlocking + if (waitp != nullptr) { // we must queue ourselves and sleep + PerThreadSynch* new_h = Enqueue(h, waitp, v, kMuIsCond); nv &= kMuLow; if (new_h != nullptr) { nv |= kMuWait | reinterpret_cast(new_h); @@ -2263,12 +2255,12 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) { } // set up to walk the list - PerThreadSynch *w_walk; // current waiter during list walk - PerThreadSynch *pw_walk; // previous waiter during list walk + PerThreadSynch* w_walk; // current waiter during list walk + PerThreadSynch* pw_walk; // previous waiter during list walk if (old_h != nullptr) { // we've searched up to old_h before pw_walk = old_h; w_walk = old_h->next; - } else { // no prior search, start at beginning + } else { // no prior search, start at beginning pw_walk = nullptr; // h->next's predecessor may change; don't record it w_walk = h->next; @@ -2294,7 +2286,7 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) { // to walk the path from w_walk to h inclusive. (TryRemove() can remove // a waiter anywhere, but it acquires both the spinlock and the Mutex) - old_h = h; // remember we searched to here + old_h = h; // remember we searched to here // Walk the path upto and including h looking for waiters we can wake. while (pw_walk != h) { @@ -2306,24 +2298,24 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) { // is in fact true EvalConditionIgnored(this, w_walk->waitp->cond))) { if (w == nullptr) { - w_walk->wake = true; // can wake this waiter + w_walk->wake = true; // can wake this waiter w = w_walk; pw = pw_walk; if (w_walk->waitp->how == kExclusive) { wr_wait = kMuWrWait; - break; // bail if waking this writer + break; // bail if waking this writer } } else if (w_walk->waitp->how == kShared) { // wake if a reader w_walk->wake = true; - } else { // writer with true condition + } else { // writer with true condition wr_wait = kMuWrWait; } - } else { // can't wake; condition false + } else { // can't wake; condition false known_false = w_walk->waitp->cond; // remember last false condition } - if (w_walk->wake) { // we're waking reader w_walk - pw_walk = w_walk; // don't skip similar waiters - } else { // not waking; skip as much as possible + if (w_walk->wake) { // we're waking reader w_walk + pw_walk = w_walk; // don't skip similar waiters + } else { // not waking; skip as much as possible pw_walk = Skip(w_walk); } // If pw_walk == h, then load of pw_walk->next can race with @@ -2350,8 +2342,8 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) { h = DequeueAllWakeable(h, pw, &wake_list); intptr_t nv = (v & kMuEvent) | kMuDesig; - // assume no waiters left, - // set kMuDesig for INV1a + // assume no waiters left, + // set kMuDesig for INV1a if (waitp != nullptr) { // we must queue ourselves and sleep h = Enqueue(h, waitp, v, kMuIsCond); @@ -2364,7 +2356,7 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) { if (h != nullptr) { // there are waiters left h->readers = 0; - h->maybe_unlocking = false; // finished unlocking + h->maybe_unlocking = false; // finished unlocking nv |= wr_wait | kMuWait | reinterpret_cast(h); } @@ -2375,7 +2367,7 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) { } // aggressive here; no one can proceed till we do c = synchronization_internal::MutexDelay(c, AGGRESSIVE); - } // end of for(;;)-loop + } // end of for(;;)-loop if (wake_list != kPerThreadSynchNull) { int64_t total_wait_cycles = 0; @@ -2392,7 +2384,7 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) { wake_list->waitp->contention_start_cycles = now; wake_list->waitp->should_submit_contention_data = true; } - wake_list = Wakeup(wake_list); // wake waiters + wake_list = Wakeup(wake_list); // wake waiters } while (wake_list != kPerThreadSynchNull); if (total_wait_cycles > 0) { mutex_tracer("slow release", this, total_wait_cycles); @@ -2420,7 +2412,7 @@ void Mutex::Trans(MuHow how) { // condition variable. If this mutex is free, we simply wake the thread. // It will later acquire the mutex with high probability. Otherwise, we // enqueue thread w on this mutex. -void Mutex::Fer(PerThreadSynch *w) { +void Mutex::Fer(PerThreadSynch* w) { SchedulingGuard::ScopedDisable disable_rescheduling; int c = 0; ABSL_RAW_CHECK(w->waitp->cond == nullptr, @@ -2445,9 +2437,9 @@ void Mutex::Fer(PerThreadSynch *w) { IncrementSynchSem(this, w); return; } else { - if ((v & (kMuSpin|kMuWait)) == 0) { // no waiters + if ((v & (kMuSpin | kMuWait)) == 0) { // no waiters // This thread tries to become the one and only waiter. - PerThreadSynch *new_h = Enqueue(nullptr, w->waitp, v, kMuIsCond); + PerThreadSynch* new_h = Enqueue(nullptr, w->waitp, v, kMuIsCond); ABSL_RAW_CHECK(new_h != nullptr, "Enqueue failed"); // we must queue ourselves if (mu_.compare_exchange_strong( @@ -2457,8 +2449,8 @@ void Mutex::Fer(PerThreadSynch *w) { } } else if ((v & kMuSpin) == 0 && mu_.compare_exchange_strong(v, v | kMuSpin | kMuWait)) { - PerThreadSynch *h = GetPerThreadSynch(v); - PerThreadSynch *new_h = Enqueue(h, w->waitp, v, kMuIsCond); + PerThreadSynch* h = GetPerThreadSynch(v); + PerThreadSynch* new_h = Enqueue(h, w->waitp, v, kMuIsCond); ABSL_RAW_CHECK(new_h != nullptr, "Enqueue failed"); // we must queue ourselves do { @@ -2477,19 +2469,18 @@ void Mutex::Fer(PerThreadSynch *w) { void Mutex::AssertHeld() const { if ((mu_.load(std::memory_order_relaxed) & kMuWriter) == 0) { - SynchEvent *e = GetSynchEvent(this); + SynchEvent* e = GetSynchEvent(this); ABSL_RAW_LOG(FATAL, "thread should hold write lock on Mutex %p %s", - static_cast(this), - (e == nullptr ? "" : e->name)); + static_cast(this), (e == nullptr ? "" : e->name)); } } void Mutex::AssertReaderHeld() const { if ((mu_.load(std::memory_order_relaxed) & (kMuReader | kMuWriter)) == 0) { - SynchEvent *e = GetSynchEvent(this); - ABSL_RAW_LOG( - FATAL, "thread should hold at least a read lock on Mutex %p %s", - static_cast(this), (e == nullptr ? "" : e->name)); + SynchEvent* e = GetSynchEvent(this); + ABSL_RAW_LOG(FATAL, + "thread should hold at least a read lock on Mutex %p %s", + static_cast(this), (e == nullptr ? "" : e->name)); } } @@ -2500,13 +2491,17 @@ static const intptr_t kCvEvent = 0x0002L; // record events static const intptr_t kCvLow = 0x0003L; // low order bits of CV // Hack to make constant values available to gdb pretty printer -enum { kGdbCvSpin = kCvSpin, kGdbCvEvent = kCvEvent, kGdbCvLow = kCvLow, }; +enum { + kGdbCvSpin = kCvSpin, + kGdbCvEvent = kCvEvent, + kGdbCvLow = kCvLow, +}; static_assert(PerThreadSynch::kAlignment > kCvLow, "PerThreadSynch::kAlignment must be greater than kCvLow"); -void CondVar::EnableDebugLog(const char *name) { - SynchEvent *e = EnsureSynchEvent(&this->cv_, name, kCvEvent, kCvSpin); +void CondVar::EnableDebugLog(const char* name) { + SynchEvent* e = EnsureSynchEvent(&this->cv_, name, kCvEvent, kCvSpin); e->log = true; UnrefSynchEvent(e); } @@ -2517,25 +2512,23 @@ CondVar::~CondVar() { } } - // Remove thread s from the list of waiters on this condition variable. -void CondVar::Remove(PerThreadSynch *s) { +void CondVar::Remove(PerThreadSynch* s) { SchedulingGuard::ScopedDisable disable_rescheduling; intptr_t v; int c = 0; for (v = cv_.load(std::memory_order_relaxed);; v = cv_.load(std::memory_order_relaxed)) { if ((v & kCvSpin) == 0 && // attempt to acquire spinlock - cv_.compare_exchange_strong(v, v | kCvSpin, - std::memory_order_acquire, + cv_.compare_exchange_strong(v, v | kCvSpin, std::memory_order_acquire, std::memory_order_relaxed)) { - PerThreadSynch *h = reinterpret_cast(v & ~kCvLow); + PerThreadSynch* h = reinterpret_cast(v & ~kCvLow); if (h != nullptr) { - PerThreadSynch *w = h; + PerThreadSynch* w = h; while (w->next != s && w->next != h) { // search for thread w = w->next; } - if (w->next == s) { // found thread; remove it + if (w->next == s) { // found thread; remove it w->next = s->next; if (h == s) { h = (w == s) ? nullptr : w; @@ -2544,7 +2537,7 @@ void CondVar::Remove(PerThreadSynch *s) { s->state.store(PerThreadSynch::kAvailable, std::memory_order_release); } } - // release spinlock + // release spinlock cv_.store((v & kCvEvent) | reinterpret_cast(h), std::memory_order_release); return; @@ -2567,14 +2560,14 @@ void CondVar::Remove(PerThreadSynch *s) { // variable queue just before the mutex is to be unlocked, and (most // importantly) after any call to an external routine that might re-enter the // mutex code. -static void CondVarEnqueue(SynchWaitParams *waitp) { +static void CondVarEnqueue(SynchWaitParams* waitp) { // This thread might be transferred to the Mutex queue by Fer() when // we are woken. To make sure that is what happens, Enqueue() doesn't // call CondVarEnqueue() again but instead uses its normal code. We // must do this before we queue ourselves so that cv_word will be null // when seen by the dequeuer, who may wish immediately to requeue // this thread on another queue. - std::atomic *cv_word = waitp->cv_word; + std::atomic* cv_word = waitp->cv_word; waitp->cv_word = nullptr; intptr_t v = cv_word->load(std::memory_order_relaxed); @@ -2587,8 +2580,8 @@ static void CondVarEnqueue(SynchWaitParams *waitp) { v = cv_word->load(std::memory_order_relaxed); } ABSL_RAW_CHECK(waitp->thread->waitp == nullptr, "waiting when shouldn't be"); - waitp->thread->waitp = waitp; // prepare ourselves for waiting - PerThreadSynch *h = reinterpret_cast(v & ~kCvLow); + waitp->thread->waitp = waitp; // prepare ourselves for waiting + PerThreadSynch* h = reinterpret_cast(v & ~kCvLow); if (h == nullptr) { // add this thread to waiter list waitp->thread->next = waitp->thread; } else { @@ -2601,8 +2594,8 @@ static void CondVarEnqueue(SynchWaitParams *waitp) { std::memory_order_release); } -bool CondVar::WaitCommon(Mutex *mutex, KernelTimeout t) { - bool rc = false; // return value; true iff we timed-out +bool CondVar::WaitCommon(Mutex* mutex, KernelTimeout t) { + bool rc = false; // return value; true iff we timed-out intptr_t mutex_v = mutex->mu_.load(std::memory_order_relaxed); Mutex::MuHow mutex_how = ((mutex_v & kMuWriter) != 0) ? kExclusive : kShared; @@ -2669,27 +2662,25 @@ bool CondVar::WaitCommon(Mutex *mutex, KernelTimeout t) { return rc; } -bool CondVar::WaitWithTimeout(Mutex *mu, absl::Duration timeout) { +bool CondVar::WaitWithTimeout(Mutex* mu, absl::Duration timeout) { return WaitCommon(mu, KernelTimeout(timeout)); } -bool CondVar::WaitWithDeadline(Mutex *mu, absl::Time deadline) { +bool CondVar::WaitWithDeadline(Mutex* mu, absl::Time deadline) { return WaitCommon(mu, KernelTimeout(deadline)); } -void CondVar::Wait(Mutex *mu) { - WaitCommon(mu, KernelTimeout::Never()); -} +void CondVar::Wait(Mutex* mu) { WaitCommon(mu, KernelTimeout::Never()); } // Wake thread w // If it was a timed wait, w will be waiting on w->cv // Otherwise, if it was not a Mutex mutex, w will be waiting on w->sem // Otherwise, w is transferred to the Mutex mutex via Mutex::Fer(). -void CondVar::Wakeup(PerThreadSynch *w) { +void CondVar::Wakeup(PerThreadSynch* w) { if (w->waitp->timeout.has_timeout() || w->waitp->cvmu == nullptr) { // The waiting thread only needs to observe "w->state == kAvailable" to be // released, we must cache "cvmu" before clearing "next". - Mutex *mu = w->waitp->cvmu; + Mutex* mu = w->waitp->cvmu; w->next = nullptr; w->state.store(PerThreadSynch::kAvailable, std::memory_order_release); Mutex::IncrementSynchSem(mu, w); @@ -2706,11 +2697,10 @@ void CondVar::Signal() { for (v = cv_.load(std::memory_order_relaxed); v != 0; v = cv_.load(std::memory_order_relaxed)) { if ((v & kCvSpin) == 0 && // attempt to acquire spinlock - cv_.compare_exchange_strong(v, v | kCvSpin, - std::memory_order_acquire, + cv_.compare_exchange_strong(v, v | kCvSpin, std::memory_order_acquire, std::memory_order_relaxed)) { - PerThreadSynch *h = reinterpret_cast(v & ~kCvLow); - PerThreadSynch *w = nullptr; + PerThreadSynch* h = reinterpret_cast(v & ~kCvLow); + PerThreadSynch* w = nullptr; if (h != nullptr) { // remove first waiter w = h->next; if (w == h) { @@ -2719,11 +2709,11 @@ void CondVar::Signal() { h->next = w->next; } } - // release spinlock + // release spinlock cv_.store((v & kCvEvent) | reinterpret_cast(h), std::memory_order_release); if (w != nullptr) { - CondVar::Wakeup(w); // wake waiter, if there was one + CondVar::Wakeup(w); // wake waiter, if there was one cond_var_tracer("Signal wakeup", this); } if ((v & kCvEvent) != 0) { @@ -2738,7 +2728,7 @@ void CondVar::Signal() { ABSL_TSAN_MUTEX_POST_SIGNAL(nullptr, 0); } -void CondVar::SignalAll () { +void CondVar::SignalAll() { ABSL_TSAN_MUTEX_PRE_SIGNAL(nullptr, 0); intptr_t v; int c = 0; @@ -2752,11 +2742,11 @@ void CondVar::SignalAll () { if ((v & kCvSpin) == 0 && cv_.compare_exchange_strong(v, v & kCvEvent, std::memory_order_acquire, std::memory_order_relaxed)) { - PerThreadSynch *h = reinterpret_cast(v & ~kCvLow); + PerThreadSynch* h = reinterpret_cast(v & ~kCvLow); if (h != nullptr) { - PerThreadSynch *w; - PerThreadSynch *n = h->next; - do { // for every thread, wake it up + PerThreadSynch* w; + PerThreadSynch* n = h->next; + do { // for every thread, wake it up w = n; n = n->next; CondVar::Wakeup(w); @@ -2784,42 +2774,41 @@ void ReleasableMutexLock::Release() { } #ifdef ABSL_HAVE_THREAD_SANITIZER -extern "C" void __tsan_read1(void *addr); +extern "C" void __tsan_read1(void* addr); #else #define __tsan_read1(addr) // do nothing if TSan not enabled #endif // A function that just returns its argument, dereferenced -static bool Dereference(void *arg) { +static bool Dereference(void* arg) { // ThreadSanitizer does not instrument this file for memory accesses. // This function dereferences a user variable that can participate // in a data race, so we need to manually tell TSan about this memory access. __tsan_read1(arg); - return *(static_cast(arg)); + return *(static_cast(arg)); } ABSL_CONST_INIT const Condition Condition::kTrue; -Condition::Condition(bool (*func)(void *), void *arg) - : eval_(&CallVoidPtrFunction), - arg_(arg) { +Condition::Condition(bool (*func)(void*), void* arg) + : eval_(&CallVoidPtrFunction), arg_(arg) { static_assert(sizeof(&func) <= sizeof(callback_), "An overlarge function pointer passed to Condition."); StoreCallback(func); } -bool Condition::CallVoidPtrFunction(const Condition *c) { - using FunctionPointer = bool (*)(void *); +bool Condition::CallVoidPtrFunction(const Condition* c) { + using FunctionPointer = bool (*)(void*); FunctionPointer function_pointer; std::memcpy(&function_pointer, c->callback_, sizeof(function_pointer)); return (*function_pointer)(c->arg_); } -Condition::Condition(const bool *cond) +Condition::Condition(const bool* cond) : eval_(CallVoidPtrFunction), // const_cast is safe since Dereference does not modify arg - arg_(const_cast(cond)) { - using FunctionPointer = bool (*)(void *); + arg_(const_cast(cond)) { + using FunctionPointer = bool (*)(void*); const FunctionPointer dereference = Dereference; StoreCallback(dereference); } @@ -2829,7 +2818,7 @@ bool Condition::Eval() const { return (this->eval_ == nullptr) || (*this->eval_)(this); } -bool Condition::GuaranteedEqual(const Condition *a, const Condition *b) { +bool Condition::GuaranteedEqual(const Condition* a, const Condition* b) { // kTrue logic. if (a == nullptr || a->eval_ == nullptr) { return b == nullptr || b->eval_ == nullptr; diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h index 0b6a9e18d59..184a585a9e9 100644 --- a/absl/synchronization/mutex.h +++ b/absl/synchronization/mutex.h @@ -141,8 +141,9 @@ struct SynchWaitParams; // issues that could potentially result in race conditions and deadlocks. // // For more information about the lock annotations, please see -// [Thread Safety Analysis](http://clang.llvm.org/docs/ThreadSafetyAnalysis.html) -// in the Clang documentation. +// [Thread Safety +// Analysis](http://clang.llvm.org/docs/ThreadSafetyAnalysis.html) in the Clang +// documentation. // // See also `MutexLock`, below, for scoped `Mutex` acquisition. @@ -323,7 +324,7 @@ class ABSL_LOCKABLE Mutex { // `true`, `Await()` *may* skip the release/re-acquire step. // // `Await()` requires that this thread holds this `Mutex` in some mode. - void Await(const Condition &cond); + void Await(const Condition& cond); // Mutex::LockWhen() // Mutex::ReaderLockWhen() @@ -333,11 +334,11 @@ class ABSL_LOCKABLE Mutex { // be acquired, then atomically acquires this `Mutex`. `LockWhen()` is // logically equivalent to `*Lock(); Await();` though they may have different // performance characteristics. - void LockWhen(const Condition &cond) ABSL_EXCLUSIVE_LOCK_FUNCTION(); + void LockWhen(const Condition& cond) ABSL_EXCLUSIVE_LOCK_FUNCTION(); - void ReaderLockWhen(const Condition &cond) ABSL_SHARED_LOCK_FUNCTION(); + void ReaderLockWhen(const Condition& cond) ABSL_SHARED_LOCK_FUNCTION(); - void WriterLockWhen(const Condition &cond) ABSL_EXCLUSIVE_LOCK_FUNCTION() { + void WriterLockWhen(const Condition& cond) ABSL_EXCLUSIVE_LOCK_FUNCTION() { this->LockWhen(cond); } @@ -362,9 +363,9 @@ class ABSL_LOCKABLE Mutex { // Negative timeouts are equivalent to a zero timeout. // // This method requires that this thread holds this `Mutex` in some mode. - bool AwaitWithTimeout(const Condition &cond, absl::Duration timeout); + bool AwaitWithTimeout(const Condition& cond, absl::Duration timeout); - bool AwaitWithDeadline(const Condition &cond, absl::Time deadline); + bool AwaitWithDeadline(const Condition& cond, absl::Time deadline); // Mutex::LockWhenWithTimeout() // Mutex::ReaderLockWhenWithTimeout() @@ -377,11 +378,11 @@ class ABSL_LOCKABLE Mutex { // `true` on return. // // Negative timeouts are equivalent to a zero timeout. - bool LockWhenWithTimeout(const Condition &cond, absl::Duration timeout) + bool LockWhenWithTimeout(const Condition& cond, absl::Duration timeout) ABSL_EXCLUSIVE_LOCK_FUNCTION(); - bool ReaderLockWhenWithTimeout(const Condition &cond, absl::Duration timeout) + bool ReaderLockWhenWithTimeout(const Condition& cond, absl::Duration timeout) ABSL_SHARED_LOCK_FUNCTION(); - bool WriterLockWhenWithTimeout(const Condition &cond, absl::Duration timeout) + bool WriterLockWhenWithTimeout(const Condition& cond, absl::Duration timeout) ABSL_EXCLUSIVE_LOCK_FUNCTION() { return this->LockWhenWithTimeout(cond, timeout); } @@ -397,11 +398,11 @@ class ABSL_LOCKABLE Mutex { // on return. // // Deadlines in the past are equivalent to an immediate deadline. - bool LockWhenWithDeadline(const Condition &cond, absl::Time deadline) + bool LockWhenWithDeadline(const Condition& cond, absl::Time deadline) ABSL_EXCLUSIVE_LOCK_FUNCTION(); - bool ReaderLockWhenWithDeadline(const Condition &cond, absl::Time deadline) + bool ReaderLockWhenWithDeadline(const Condition& cond, absl::Time deadline) ABSL_SHARED_LOCK_FUNCTION(); - bool WriterLockWhenWithDeadline(const Condition &cond, absl::Time deadline) + bool WriterLockWhenWithDeadline(const Condition& cond, absl::Time deadline) ABSL_EXCLUSIVE_LOCK_FUNCTION() { return this->LockWhenWithDeadline(cond, deadline); } @@ -423,7 +424,7 @@ class ABSL_LOCKABLE Mutex { // substantially reduce `Mutex` performance; it should be set only for // non-production runs. Optimization options may also disable invariant // checks. - void EnableInvariantDebugging(void (*invariant)(void *), void *arg); + void EnableInvariantDebugging(void (*invariant)(void*), void* arg); // Mutex::EnableDebugLog() // @@ -432,7 +433,7 @@ class ABSL_LOCKABLE Mutex { // call to `EnableInvariantDebugging()` or `EnableDebugLog()` has been made. // // Note: This method substantially reduces `Mutex` performance. - void EnableDebugLog(const char *name); + void EnableDebugLog(const char* name); // Deadlock detection @@ -460,7 +461,7 @@ class ABSL_LOCKABLE Mutex { // A `MuHow` is a constant that indicates how a lock should be acquired. // Internal implementation detail. Clients should ignore. - typedef const struct MuHowS *MuHow; + typedef const struct MuHowS* MuHow; // Mutex::InternalAttemptToUseMutexInFatalSignalHandler() // @@ -482,37 +483,37 @@ class ABSL_LOCKABLE Mutex { // Post()/Wait() versus associated PerThreadSem; in class for required // friendship with PerThreadSem. - static void IncrementSynchSem(Mutex *mu, base_internal::PerThreadSynch *w); - static bool DecrementSynchSem(Mutex *mu, base_internal::PerThreadSynch *w, + static void IncrementSynchSem(Mutex* mu, base_internal::PerThreadSynch* w); + static bool DecrementSynchSem(Mutex* mu, base_internal::PerThreadSynch* w, synchronization_internal::KernelTimeout t); // slow path acquire - void LockSlowLoop(SynchWaitParams *waitp, int flags); + void LockSlowLoop(SynchWaitParams* waitp, int flags); // wrappers around LockSlowLoop() - bool LockSlowWithDeadline(MuHow how, const Condition *cond, + bool LockSlowWithDeadline(MuHow how, const Condition* cond, synchronization_internal::KernelTimeout t, int flags); - void LockSlow(MuHow how, const Condition *cond, + void LockSlow(MuHow how, const Condition* cond, int flags) ABSL_ATTRIBUTE_COLD; // slow path release - void UnlockSlow(SynchWaitParams *waitp) ABSL_ATTRIBUTE_COLD; + void UnlockSlow(SynchWaitParams* waitp) ABSL_ATTRIBUTE_COLD; // Common code between Await() and AwaitWithTimeout/Deadline() - bool AwaitCommon(const Condition &cond, + bool AwaitCommon(const Condition& cond, synchronization_internal::KernelTimeout t); // Attempt to remove thread s from queue. - void TryRemove(base_internal::PerThreadSynch *s); + void TryRemove(base_internal::PerThreadSynch* s); // Block a thread on mutex. - void Block(base_internal::PerThreadSynch *s); + void Block(base_internal::PerThreadSynch* s); // Wake a thread; return successor. - base_internal::PerThreadSynch *Wakeup(base_internal::PerThreadSynch *w); + base_internal::PerThreadSynch* Wakeup(base_internal::PerThreadSynch* w); friend class CondVar; // for access to Trans()/Fer(). void Trans(MuHow how); // used for CondVar->Mutex transfer void Fer( - base_internal::PerThreadSynch *w); // used for CondVar->Mutex transfer + base_internal::PerThreadSynch* w); // used for CondVar->Mutex transfer // Catch the error of writing Mutex when intending MutexLock. - Mutex(const volatile Mutex * /*ignored*/) {} // NOLINT(runtime/explicit) + Mutex(const volatile Mutex* /*ignored*/) {} // NOLINT(runtime/explicit) Mutex(const Mutex&) = delete; Mutex& operator=(const Mutex&) = delete; @@ -547,28 +548,28 @@ class ABSL_SCOPED_LOCKABLE MutexLock { // Calls `mu->Lock()` and returns when that call returns. That is, `*mu` is // guaranteed to be locked when this object is constructed. Requires that // `mu` be dereferenceable. - explicit MutexLock(Mutex *mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) { + explicit MutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) { this->mu_->Lock(); } // Like above, but calls `mu->LockWhen(cond)` instead. That is, in addition to // the above, the condition given by `cond` is also guaranteed to hold when // this object is constructed. - explicit MutexLock(Mutex *mu, const Condition &cond) + explicit MutexLock(Mutex* mu, const Condition& cond) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) { this->mu_->LockWhen(cond); } - MutexLock(const MutexLock &) = delete; // NOLINT(runtime/mutex) - MutexLock(MutexLock&&) = delete; // NOLINT(runtime/mutex) + MutexLock(const MutexLock&) = delete; // NOLINT(runtime/mutex) + MutexLock(MutexLock&&) = delete; // NOLINT(runtime/mutex) MutexLock& operator=(const MutexLock&) = delete; MutexLock& operator=(MutexLock&&) = delete; ~MutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->Unlock(); } private: - Mutex *const mu_; + Mutex* const mu_; }; // ReaderMutexLock @@ -577,11 +578,11 @@ class ABSL_SCOPED_LOCKABLE MutexLock { // releases a shared lock on a `Mutex` via RAII. class ABSL_SCOPED_LOCKABLE ReaderMutexLock { public: - explicit ReaderMutexLock(Mutex *mu) ABSL_SHARED_LOCK_FUNCTION(mu) : mu_(mu) { + explicit ReaderMutexLock(Mutex* mu) ABSL_SHARED_LOCK_FUNCTION(mu) : mu_(mu) { mu->ReaderLock(); } - explicit ReaderMutexLock(Mutex *mu, const Condition &cond) + explicit ReaderMutexLock(Mutex* mu, const Condition& cond) ABSL_SHARED_LOCK_FUNCTION(mu) : mu_(mu) { mu->ReaderLockWhen(cond); @@ -595,7 +596,7 @@ class ABSL_SCOPED_LOCKABLE ReaderMutexLock { ~ReaderMutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->ReaderUnlock(); } private: - Mutex *const mu_; + Mutex* const mu_; }; // WriterMutexLock @@ -604,12 +605,12 @@ class ABSL_SCOPED_LOCKABLE ReaderMutexLock { // releases a write (exclusive) lock on a `Mutex` via RAII. class ABSL_SCOPED_LOCKABLE WriterMutexLock { public: - explicit WriterMutexLock(Mutex *mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) + explicit WriterMutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) { mu->WriterLock(); } - explicit WriterMutexLock(Mutex *mu, const Condition &cond) + explicit WriterMutexLock(Mutex* mu, const Condition& cond) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) { mu->WriterLockWhen(cond); @@ -623,7 +624,7 @@ class ABSL_SCOPED_LOCKABLE WriterMutexLock { ~WriterMutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->WriterUnlock(); } private: - Mutex *const mu_; + Mutex* const mu_; }; // ----------------------------------------------------------------------------- @@ -681,7 +682,7 @@ class ABSL_SCOPED_LOCKABLE WriterMutexLock { class Condition { public: // A Condition that returns the result of "(*func)(arg)" - Condition(bool (*func)(void *), void *arg); + Condition(bool (*func)(void*), void* arg); // Templated version for people who are averse to casts. // @@ -692,8 +693,8 @@ class Condition { // Note: lambdas in this case must contain no bound variables. // // See class comment for performance advice. - template - Condition(bool (*func)(T *), T *arg); + template + Condition(bool (*func)(T*), T* arg); // Same as above, but allows for cases where `arg` comes from a pointer that // is convertible to the function parameter type `T*` but not an exact match. @@ -707,7 +708,7 @@ class Condition { // a function template is passed as `func`. Also, the dummy `typename = void` // template parameter exists just to work around a MSVC mangling bug. template - Condition(bool (*func)(T *), typename absl::internal::identity::type *arg); + Condition(bool (*func)(T*), typename absl::internal::identity::type* arg); // Templated version for invoking a method that returns a `bool`. // @@ -717,16 +718,16 @@ class Condition { // Implementation Note: `absl::internal::identity` is used to allow methods to // come from base classes. A simpler signature like // `Condition(T*, bool (T::*)())` does not suffice. - template - Condition(T *object, bool (absl::internal::identity::type::* method)()); + template + Condition(T* object, bool (absl::internal::identity::type::*method)()); // Same as above, for const members - template - Condition(const T *object, - bool (absl::internal::identity::type::* method)() const); + template + Condition(const T* object, + bool (absl::internal::identity::type::*method)() const); // A Condition that returns the value of `*cond` - explicit Condition(const bool *cond); + explicit Condition(const bool* cond); // Templated version for invoking a functor that returns a `bool`. // This approach accepts pointers to non-mutable lambdas, `std::function`, @@ -753,9 +754,9 @@ class Condition { // Implementation note: The second template parameter ensures that this // constructor doesn't participate in overload resolution if T doesn't have // `bool operator() const`. - template (&T::operator()))> - explicit Condition(const T *obj) + template ( + &T::operator()))> + explicit Condition(const T* obj) : Condition(obj, static_cast(&T::operator())) {} // A Condition that always returns `true`. @@ -771,7 +772,7 @@ class Condition { // Two `Condition` values are guaranteed equal if both their `func` and `arg` // components are the same. A null pointer is equivalent to a `true` // condition. - static bool GuaranteedEqual(const Condition *a, const Condition *b); + static bool GuaranteedEqual(const Condition* a, const Condition* b); private: // Sizing an allocation for a method pointer can be subtle. In the Itanium @@ -799,12 +800,14 @@ class Condition { bool (*eval_)(const Condition*) = nullptr; // Either an argument for a function call or an object for a method call. - void *arg_ = nullptr; + void* arg_ = nullptr; // Various functions eval_ can point to: static bool CallVoidPtrFunction(const Condition*); - template static bool CastAndCallFunction(const Condition* c); - template static bool CastAndCallMethod(const Condition* c); + template + static bool CastAndCallFunction(const Condition* c); + template + static bool CastAndCallMethod(const Condition* c); // Helper methods for storing, validating, and reading callback arguments. template @@ -816,7 +819,7 @@ class Condition { } template - inline void ReadCallback(T *callback) const { + inline void ReadCallback(T* callback) const { std::memcpy(callback, callback_, sizeof(*callback)); } @@ -873,7 +876,7 @@ class CondVar { // spurious wakeup), then reacquires the `Mutex` and returns. // // Requires and ensures that the current thread holds the `Mutex`. - void Wait(Mutex *mu); + void Wait(Mutex* mu); // CondVar::WaitWithTimeout() // @@ -888,7 +891,7 @@ class CondVar { // to return `true` or `false`. // // Requires and ensures that the current thread holds the `Mutex`. - bool WaitWithTimeout(Mutex *mu, absl::Duration timeout); + bool WaitWithTimeout(Mutex* mu, absl::Duration timeout); // CondVar::WaitWithDeadline() // @@ -905,7 +908,7 @@ class CondVar { // to return `true` or `false`. // // Requires and ensures that the current thread holds the `Mutex`. - bool WaitWithDeadline(Mutex *mu, absl::Time deadline); + bool WaitWithDeadline(Mutex* mu, absl::Time deadline); // CondVar::Signal() // @@ -922,18 +925,17 @@ class CondVar { // Causes all subsequent uses of this `CondVar` to be logged via // `ABSL_RAW_LOG(INFO)`. Log entries are tagged with `name` if `name != 0`. // Note: this method substantially reduces `CondVar` performance. - void EnableDebugLog(const char *name); + void EnableDebugLog(const char* name); private: - bool WaitCommon(Mutex *mutex, synchronization_internal::KernelTimeout t); - void Remove(base_internal::PerThreadSynch *s); - void Wakeup(base_internal::PerThreadSynch *w); + bool WaitCommon(Mutex* mutex, synchronization_internal::KernelTimeout t); + void Remove(base_internal::PerThreadSynch* s); + void Wakeup(base_internal::PerThreadSynch* w); std::atomic cv_; // Condition variable state. CondVar(const CondVar&) = delete; CondVar& operator=(const CondVar&) = delete; }; - // Variants of MutexLock. // // If you find yourself using one of these, consider instead using @@ -944,14 +946,14 @@ class CondVar { // MutexLockMaybe is like MutexLock, but is a no-op when mu is null. class ABSL_SCOPED_LOCKABLE MutexLockMaybe { public: - explicit MutexLockMaybe(Mutex *mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) + explicit MutexLockMaybe(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) { if (this->mu_ != nullptr) { this->mu_->Lock(); } } - explicit MutexLockMaybe(Mutex *mu, const Condition &cond) + explicit MutexLockMaybe(Mutex* mu, const Condition& cond) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) { if (this->mu_ != nullptr) { @@ -960,11 +962,13 @@ class ABSL_SCOPED_LOCKABLE MutexLockMaybe { } ~MutexLockMaybe() ABSL_UNLOCK_FUNCTION() { - if (this->mu_ != nullptr) { this->mu_->Unlock(); } + if (this->mu_ != nullptr) { + this->mu_->Unlock(); + } } private: - Mutex *const mu_; + Mutex* const mu_; MutexLockMaybe(const MutexLockMaybe&) = delete; MutexLockMaybe(MutexLockMaybe&&) = delete; MutexLockMaybe& operator=(const MutexLockMaybe&) = delete; @@ -977,25 +981,27 @@ class ABSL_SCOPED_LOCKABLE MutexLockMaybe { // mutex before destruction. `Release()` may be called at most once. class ABSL_SCOPED_LOCKABLE ReleasableMutexLock { public: - explicit ReleasableMutexLock(Mutex *mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) + explicit ReleasableMutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) { this->mu_->Lock(); } - explicit ReleasableMutexLock(Mutex *mu, const Condition &cond) + explicit ReleasableMutexLock(Mutex* mu, const Condition& cond) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) { this->mu_->LockWhen(cond); } ~ReleasableMutexLock() ABSL_UNLOCK_FUNCTION() { - if (this->mu_ != nullptr) { this->mu_->Unlock(); } + if (this->mu_ != nullptr) { + this->mu_->Unlock(); + } } void Release() ABSL_UNLOCK_FUNCTION(); private: - Mutex *mu_; + Mutex* mu_; ReleasableMutexLock(const ReleasableMutexLock&) = delete; ReleasableMutexLock(ReleasableMutexLock&&) = delete; ReleasableMutexLock& operator=(const ReleasableMutexLock&) = delete; @@ -1012,8 +1018,8 @@ inline CondVar::CondVar() : cv_(0) {} // static template -bool Condition::CastAndCallMethod(const Condition *c) { - T *object = static_cast(c->arg_); +bool Condition::CastAndCallMethod(const Condition* c) { + T* object = static_cast(c->arg_); bool (T::*method_pointer)(); c->ReadCallback(&method_pointer); return (object->*method_pointer)(); @@ -1021,44 +1027,43 @@ bool Condition::CastAndCallMethod(const Condition *c) { // static template -bool Condition::CastAndCallFunction(const Condition *c) { - bool (*function)(T *); +bool Condition::CastAndCallFunction(const Condition* c) { + bool (*function)(T*); c->ReadCallback(&function); - T *argument = static_cast(c->arg_); + T* argument = static_cast(c->arg_); return (*function)(argument); } template -inline Condition::Condition(bool (*func)(T *), T *arg) +inline Condition::Condition(bool (*func)(T*), T* arg) : eval_(&CastAndCallFunction), - arg_(const_cast(static_cast(arg))) { + arg_(const_cast(static_cast(arg))) { static_assert(sizeof(&func) <= sizeof(callback_), "An overlarge function pointer was passed to Condition."); StoreCallback(func); } template -inline Condition::Condition(bool (*func)(T *), - typename absl::internal::identity::type *arg) +inline Condition::Condition(bool (*func)(T*), + typename absl::internal::identity::type* arg) // Just delegate to the overload above. : Condition(func, arg) {} template -inline Condition::Condition(T *object, +inline Condition::Condition(T* object, bool (absl::internal::identity::type::*method)()) - : eval_(&CastAndCallMethod), - arg_(object) { + : eval_(&CastAndCallMethod), arg_(object) { static_assert(sizeof(&method) <= sizeof(callback_), "An overlarge method pointer was passed to Condition."); StoreCallback(method); } template -inline Condition::Condition(const T *object, +inline Condition::Condition(const T* object, bool (absl::internal::identity::type::*method)() const) : eval_(&CastAndCallMethod), - arg_(reinterpret_cast(const_cast(object))) { + arg_(reinterpret_cast(const_cast(object))) { StoreCallback(method); } @@ -1088,7 +1093,7 @@ void RegisterMutexProfiler(void (*fn)(int64_t wait_cycles)); // // This has the same ordering and single-use limitations as // RegisterMutexProfiler() above. -void RegisterMutexTracer(void (*fn)(const char *msg, const void *obj, +void RegisterMutexTracer(void (*fn)(const char* msg, const void* obj, int64_t wait_cycles)); // Register a hook for CondVar tracing. @@ -1103,7 +1108,7 @@ void RegisterMutexTracer(void (*fn)(const char *msg, const void *obj, // // This has the same ordering and single-use limitations as // RegisterMutexProfiler() above. -void RegisterCondVarTracer(void (*fn)(const char *msg, const void *cv)); +void RegisterCondVarTracer(void (*fn)(const char* msg, const void* cv)); // EnableMutexInvariantDebugging() // @@ -1120,7 +1125,7 @@ void EnableMutexInvariantDebugging(bool enabled); enum class OnDeadlockCycle { kIgnore, // Neither report on nor attempt to track cycles in lock ordering kReport, // Report lock cycles to stderr when detected - kAbort, // Report lock cycles to stderr when detected, then abort + kAbort, // Report lock cycles to stderr when detected, then abort }; // SetMutexDeadlockDetectionMode() From 4ba63810304974e121d32df0fe41b23640a691b2 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 20 Jun 2023 11:48:05 -0700 Subject: [PATCH 0077/1238] absl: cosmetic changes for Mutex Few pure cosmetic changes: - remove unused headers - add using for CycleClock since it's used multiple times - restructure GetMutexGlobals to be more consistent PiperOrigin-RevId: 542002120 Change-Id: I117faae05cb8224041f7e3771999f3a35bdf4aef --- absl/synchronization/mutex.cc | 38 ++++++++++++++++------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc index edd9974f5c6..df7577b55d5 100644 --- a/absl/synchronization/mutex.cc +++ b/absl/synchronization/mutex.cc @@ -35,10 +35,8 @@ #include #include -#include #include #include -#include #include // NOLINT(build/c++11) #include "absl/base/attributes.h" @@ -55,7 +53,6 @@ #include "absl/base/internal/thread_identity.h" #include "absl/base/internal/tsan_mutex_interface.h" #include "absl/base/optimization.h" -#include "absl/base/port.h" #include "absl/debugging/stacktrace.h" #include "absl/debugging/symbolize.h" #include "absl/synchronization/internal/graphcycles.h" @@ -63,6 +60,7 @@ #include "absl/time/time.h" using absl::base_internal::CurrentThreadIdentityIfPresent; +using absl::base_internal::CycleClock; using absl::base_internal::PerThreadSynch; using absl::base_internal::SchedulingGuard; using absl::base_internal::ThreadIdentity; @@ -144,22 +142,21 @@ absl::Duration MeasureTimeToYield() { const MutexGlobals& GetMutexGlobals() { ABSL_CONST_INIT static MutexGlobals data; absl::base_internal::LowLevelCallOnce(&data.once, [&]() { - const int num_cpus = absl::base_internal::NumCPUs(); - data.spinloop_iterations = num_cpus > 1 ? 1500 : 0; - // If this a uniprocessor, only yield/sleep. - // Real-time threads are often unable to yield, so the sleep time needs - // to be long enough to keep the calling thread asleep until scheduling - // happens. - // If this is multiprocessor, allow spinning. If the mode is - // aggressive then spin many times before yielding. If the mode is - // gentle then spin only a few times before yielding. Aggressive spinning - // is used to ensure that an Unlock() call, which must get the spin lock - // for any thread to make progress gets it without undue delay. - if (num_cpus > 1) { + if (absl::base_internal::NumCPUs() > 1) { + // If this is multiprocessor, allow spinning. If the mode is + // aggressive then spin many times before yielding. If the mode is + // gentle then spin only a few times before yielding. Aggressive spinning + // is used to ensure that an Unlock() call, which must get the spin lock + // for any thread to make progress gets it without undue delay. + data.spinloop_iterations = 1500; data.mutex_sleep_spins[AGGRESSIVE] = 5000; data.mutex_sleep_spins[GENTLE] = 250; data.mutex_sleep_time = absl::Microseconds(10); } else { + // If this a uniprocessor, only yield/sleep. Real-time threads are often + // unable to yield, so the sleep time needs to be long enough to keep + // the calling thread asleep until scheduling happens. + data.spinloop_iterations = 0; data.mutex_sleep_spins[AGGRESSIVE] = 0; data.mutex_sleep_spins[GENTLE] = 0; data.mutex_sleep_time = MeasureTimeToYield() * 5; @@ -505,7 +502,7 @@ struct SynchWaitParams { cvmu(cvmu_arg), thread(thread_arg), cv_word(cv_word_arg), - contention_start_cycles(base_internal::CycleClock::Now()), + contention_start_cycles(CycleClock::Now()), should_submit_contention_data(false) {} const Mutex::MuHow how; // How this thread needs to wait. @@ -922,11 +919,11 @@ static PerThreadSynch* Enqueue(PerThreadSynch* head, SynchWaitParams* waitp, s->wake = false; // not being woken s->cond_waiter = ((flags & kMuIsCond) != 0); #ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM - int64_t now_cycles = base_internal::CycleClock::Now(); + int64_t now_cycles = CycleClock::Now(); if (s->next_priority_read_cycles < now_cycles) { // Every so often, update our idea of the thread's priority. // pthread_getschedparam() is 5% of the block/wakeup time; - // base_internal::CycleClock::Now() is 0.5%. + // CycleClock::Now() is 0.5%. int policy; struct sched_param param; const int err = pthread_getschedparam(pthread_self(), &policy, ¶m); @@ -935,8 +932,7 @@ static PerThreadSynch* Enqueue(PerThreadSynch* head, SynchWaitParams* waitp, } else { s->priority = param.sched_priority; s->next_priority_read_cycles = - now_cycles + - static_cast(base_internal::CycleClock::Frequency()); + now_cycles + static_cast(CycleClock::Frequency()); } } #endif @@ -2372,7 +2368,7 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams* waitp) { if (wake_list != kPerThreadSynchNull) { int64_t total_wait_cycles = 0; int64_t max_wait_cycles = 0; - int64_t now = base_internal::CycleClock::Now(); + int64_t now = CycleClock::Now(); do { // Profile lock contention events only if the waiter was trying to acquire // the lock, not waiting on a condition variable or Condition. From aaf4842c10ee26a8aa20a93d7f834a5c362ab1f2 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Tue, 20 Jun 2023 12:58:41 -0700 Subject: [PATCH 0078/1238] Avoid trying to use __is_trivially_relocatable with NVCC Fixes #1479 PiperOrigin-RevId: 542022998 Change-Id: I9d6059341fe867ad5539ef2a4d57925858a9cfc0 --- absl/meta/type_traits.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h index 4f9ea017682..cf71164b386 100644 --- a/absl/meta/type_traits.h +++ b/absl/meta/type_traits.h @@ -500,8 +500,12 @@ using swap_internal::StdSwapIsUnconstrained; // there. // // TODO(b/275003464): remove the opt-out once the bug is fixed. -#if ABSL_HAVE_BUILTIN(__is_trivially_relocatable) && \ - !(defined(__clang__) && (defined(_WIN32) || defined(_WIN64))) +// +// According to https://github.com/abseil/abseil-cpp/issues/1479, this does not +// work with NVCC either. +#if ABSL_HAVE_BUILTIN(__is_trivially_relocatable) && \ + !(defined(__clang__) && (defined(_WIN32) || defined(_WIN64))) && \ + !defined(__NVCC__) template struct is_trivially_relocatable : std::integral_constant {}; From 94d77fe3604dd86b5198f942110c240f01242439 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Tue, 20 Jun 2023 12:58:51 -0700 Subject: [PATCH 0079/1238] Add missing #include Fixes #1482 PiperOrigin-RevId: 542023050 Change-Id: Iba712083edc9a24732a71f51be22ea970115809c --- absl/debugging/internal/stacktrace_aarch64-inl.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/absl/debugging/internal/stacktrace_aarch64-inl.inc b/absl/debugging/internal/stacktrace_aarch64-inl.inc index c8b84397949..3f087162022 100644 --- a/absl/debugging/internal/stacktrace_aarch64-inl.inc +++ b/absl/debugging/internal/stacktrace_aarch64-inl.inc @@ -13,6 +13,7 @@ #include #include #include +#include #include "absl/base/attributes.h" #include "absl/debugging/internal/address_is_readable.h" From 55e8345c57bf8d88342f634f279239d19e77826c Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 20 Jun 2023 21:20:15 -0700 Subject: [PATCH 0080/1238] absl: fix lint errors in Mutex Currently linter warns on all changes: missing #include for 'std::atexit' and single-argument constructors must be marked explicit to avoid unintentional implicit conversions Fix that. PiperOrigin-RevId: 542135136 Change-Id: Ic86649de6baef7f2de71f45875bb66bd730bf6e1 --- absl/synchronization/mutex.cc | 1 + absl/synchronization/mutex.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc index df7577b55d5..3aa5560a32f 100644 --- a/absl/synchronization/mutex.cc +++ b/absl/synchronization/mutex.cc @@ -36,6 +36,7 @@ #include #include #include +#include #include #include // NOLINT(build/c++11) diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h index 184a585a9e9..2fd077c8d44 100644 --- a/absl/synchronization/mutex.h +++ b/absl/synchronization/mutex.h @@ -513,7 +513,7 @@ class ABSL_LOCKABLE Mutex { base_internal::PerThreadSynch* w); // used for CondVar->Mutex transfer // Catch the error of writing Mutex when intending MutexLock. - Mutex(const volatile Mutex* /*ignored*/) {} // NOLINT(runtime/explicit) + explicit Mutex(const volatile Mutex* /*ignored*/) {} Mutex(const Mutex&) = delete; Mutex& operator=(const Mutex&) = delete; From 166d71d18f01aa73fd35aae611692320952a75b5 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 20 Jun 2023 22:03:47 -0700 Subject: [PATCH 0081/1238] absl: add a Mutex::Await/LockWhen test Check various corner cases for Await/LockWhen return value with always true/always false conditions. I don't see this explicitly tested anywhere else. PiperOrigin-RevId: 542141533 Change-Id: Ia116c6dc199de606ad446c205951169ec5e2abe1 --- absl/synchronization/mutex_test.cc | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/absl/synchronization/mutex_test.cc b/absl/synchronization/mutex_test.cc index 35802b2e876..b585c342e6b 100644 --- a/absl/synchronization/mutex_test.cc +++ b/absl/synchronization/mutex_test.cc @@ -1868,4 +1868,29 @@ TEST(Mutex, WriterPriority) { EXPECT_TRUE(saw_wrote.load()); } +TEST(Mutex, LockWhenWithTimeoutResult) { + // Check various corner cases for Await/LockWhen return value + // with always true/always false conditions. + absl::Mutex mu; + const bool kAlwaysTrue = true, kAlwaysFalse = false; + const absl::Condition kTrueCond(&kAlwaysTrue), kFalseCond(&kAlwaysFalse); + EXPECT_TRUE(mu.LockWhenWithTimeout(kTrueCond, absl::Milliseconds(1))); + mu.Unlock(); + EXPECT_FALSE(mu.LockWhenWithTimeout(kFalseCond, absl::Milliseconds(1))); + EXPECT_TRUE(mu.AwaitWithTimeout(kTrueCond, absl::Milliseconds(1))); + EXPECT_FALSE(mu.AwaitWithTimeout(kFalseCond, absl::Milliseconds(1))); + std::thread th1([&]() { + EXPECT_TRUE(mu.LockWhenWithTimeout(kTrueCond, absl::Milliseconds(1))); + mu.Unlock(); + }); + std::thread th2([&]() { + EXPECT_FALSE(mu.LockWhenWithTimeout(kFalseCond, absl::Milliseconds(1))); + mu.Unlock(); + }); + absl::SleepFor(absl::Milliseconds(100)); + mu.Unlock(); + th1.join(); + th2.join(); +} + } // namespace From 34eb767645347f100bdd66fc1e35eee96e357961 Mon Sep 17 00:00:00 2001 From: Tsige Solomon Date: Wed, 21 Jun 2023 08:52:53 -0700 Subject: [PATCH 0082/1238] Support for int128 to string type conversion. PiperOrigin-RevId: 542269673 Change-Id: Ib6f7e9a57f83d73dd6fb9c45fc9f85ff0fdd75fe --- absl/numeric/BUILD.bazel | 1 + absl/numeric/CMakeLists.txt | 1 + absl/numeric/int128.cc | 12 ++++++++++++ absl/numeric/int128.h | 17 +++++++++++++++++ absl/numeric/int128_stream_test.cc | 7 +++++++ 5 files changed, 38 insertions(+) diff --git a/absl/numeric/BUILD.bazel b/absl/numeric/BUILD.bazel index ec0b8701e7b..c5aaf72b2e7 100644 --- a/absl/numeric/BUILD.bazel +++ b/absl/numeric/BUILD.bazel @@ -97,6 +97,7 @@ cc_test( "//absl/base", "//absl/hash:hash_testing", "//absl/meta:type_traits", + "//absl/strings", "@com_google_googletest//:gtest_main", ], ) diff --git a/absl/numeric/CMakeLists.txt b/absl/numeric/CMakeLists.txt index 384c0fc01ee..7181b91ab5a 100644 --- a/absl/numeric/CMakeLists.txt +++ b/absl/numeric/CMakeLists.txt @@ -72,6 +72,7 @@ absl_cc_test( absl::base absl::hash_testing absl::type_traits + absl::strings GTest::gmock_main ) diff --git a/absl/numeric/int128.cc b/absl/numeric/int128.cc index 6ffe43d5e9b..daa32b51833 100644 --- a/absl/numeric/int128.cc +++ b/absl/numeric/int128.cc @@ -202,6 +202,10 @@ std::string Uint128ToFormattedString(uint128 v, std::ios_base::fmtflags flags) { } // namespace +std::string uint128::ToString() const { + return Uint128ToFormattedString(*this, std::ios_base::dec); +} + std::ostream& operator<<(std::ostream& os, uint128 v) { std::ios_base::fmtflags flags = os.flags(); std::string rep = Uint128ToFormattedString(v, flags); @@ -285,6 +289,14 @@ int128 operator%(int128 lhs, int128 rhs) { } #endif // ABSL_HAVE_INTRINSIC_INT128 +std::string int128::ToString() const { + std::string rep; + if (Int128High64(*this) < 0) rep = "-"; + rep.append(Uint128ToFormattedString(UnsignedAbsoluteValue(*this), + std::ios_base::dec)); + return rep; +} + std::ostream& operator<<(std::ostream& os, int128 v) { std::ios_base::fmtflags flags = os.flags(); std::string rep; diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h index aa0f86f7b36..7530a793410 100644 --- a/absl/numeric/int128.h +++ b/absl/numeric/int128.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "absl/base/config.h" @@ -217,9 +218,17 @@ class return H::combine(std::move(h), Uint128High64(v), Uint128Low64(v)); } + // Support for absl::StrCat() etc. + template + friend void AbslStringify(Sink& sink, uint128 v) { + sink.Append(v.ToString()); + } + private: constexpr uint128(uint64_t high, uint64_t low); + std::string ToString() const; + // TODO(strel) Update implementation to use __int128 once all users of // uint128 are fixed to not depend on alignof(uint128) == 8. Also add // alignas(16) to class definition to keep alignment consistent across @@ -454,9 +463,17 @@ class int128 { return H::combine(std::move(h), Int128High64(v), Int128Low64(v)); } + // Support for absl::StrCat() etc. + template + friend void AbslStringify(Sink& sink, int128 v) { + sink.Append(v.ToString()); + } + private: constexpr int128(int64_t high, uint64_t low); + std::string ToString() const; + #if defined(ABSL_HAVE_INTRINSIC_INT128) __int128 v_; #else // ABSL_HAVE_INTRINSIC_INT128 diff --git a/absl/numeric/int128_stream_test.cc b/absl/numeric/int128_stream_test.cc index 81d2adeefbc..bd937847d0a 100644 --- a/absl/numeric/int128_stream_test.cc +++ b/absl/numeric/int128_stream_test.cc @@ -18,6 +18,7 @@ #include #include "gtest/gtest.h" +#include "absl/strings/str_cat.h" namespace { @@ -87,6 +88,9 @@ constexpr std::ios::fmtflags kBase = std::ios::showbase; constexpr std::ios::fmtflags kPos = std::ios::showpos; void CheckUint128Case(const Uint128TestCase& test_case) { + if (test_case.flags == kDec && test_case.width == 0) { + EXPECT_EQ(absl::StrCat(test_case.value), test_case.expected); + } std::ostringstream os; os.flags(test_case.flags); os.width(test_case.width); @@ -155,6 +159,9 @@ struct Int128TestCase { }; void CheckInt128Case(const Int128TestCase& test_case) { + if (test_case.flags == kDec && test_case.width == 0) { + EXPECT_EQ(absl::StrCat(test_case.value), test_case.expected); + } std::ostringstream os; os.flags(test_case.flags); os.width(test_case.width); From 474d21b580e2765aec2e85d2995bf45820be258e Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 23 Jun 2023 23:10:38 -0700 Subject: [PATCH 0083/1238] Add absl::HwasanTagPointer() to allow users to change HWASAN tags It's NOOP without HWASAN. PiperOrigin-RevId: 543045322 Change-Id: Ibb5f28d316bfc5e8aa51861fd55e50ecb517a9a3 --- absl/base/dynamic_annotations.h | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/absl/base/dynamic_annotations.h b/absl/base/dynamic_annotations.h index 3ea7c1568cc..7ba8912ea63 100644 --- a/absl/base/dynamic_annotations.h +++ b/absl/base/dynamic_annotations.h @@ -46,6 +46,7 @@ #define ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ #include +#include #include "absl/base/attributes.h" #include "absl/base/config.h" @@ -53,6 +54,10 @@ #include "absl/base/macros.h" #endif +#ifdef ABSL_HAVE_HWADDRESS_SANITIZER +#include +#endif + // TODO(rogeeff): Remove after the backward compatibility period. #include "absl/base/internal/dynamic_annotations.h" // IWYU pragma: export @@ -111,7 +116,7 @@ #if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1 // Some of the symbols used in this section (e.g. AnnotateBenignRaceSized) are -// defined by the compiler-based santizer implementation, not by the Abseil +// defined by the compiler-based sanitizer implementation, not by the Abseil // library. Therefore they do not use ABSL_INTERNAL_C_SYMBOL. // ------------------------------------------------------------- @@ -456,6 +461,26 @@ ABSL_NAMESPACE_END #endif // ABSL_HAVE_ADDRESS_SANITIZER +// ------------------------------------------------------------------------- +// HWAddress sanitizer annotations + +#ifdef __cplusplus +namespace absl { +#ifdef ABSL_HAVE_HWADDRESS_SANITIZER +// Under HWASAN changes the tag of the pointer. +template +T* HwasanTagPointer(T* ptr, uintptr_t tag) { + return reinterpret_cast(__hwasan_tag_pointer(ptr, tag)); +} +#else +template +T* HwasanTagPointer(T* ptr, uintptr_t) { + return ptr; +} +#endif +} // namespace absl +#endif + // ------------------------------------------------------------------------- // Undefine the macros intended only for this file. From 20089ec0e4cd409cb5428223db168f5e88d7035f Mon Sep 17 00:00:00 2001 From: Dino Radakovic Date: Mon, 26 Jun 2023 10:31:09 -0700 Subject: [PATCH 0084/1238] AnyInvocable: Use enums instead of ints in initialization overload set This trick was introduced to work around a compiler bug in msvc 2017, which abseil doesn't support anymore: https://github.com/google/oss-policies-info/blob/3aa4b98f497fdfac983b8de78cf6bd693cb0cf4f/foundational-cxx-support-matrix.md PiperOrigin-RevId: 543477428 Change-Id: I332c1b359b75811536ce900d3166979ac3c196a3 --- absl/functional/internal/any_invocable.h | 31 ++++++++++++------------ 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/absl/functional/internal/any_invocable.h b/absl/functional/internal/any_invocable.h index a52fa876a4c..f096bb02e15 100644 --- a/absl/functional/internal/any_invocable.h +++ b/absl/functional/internal/any_invocable.h @@ -440,11 +440,11 @@ class CoreImpl { CoreImpl() noexcept : manager_(EmptyManager), invoker_(nullptr) {} - enum class TargetType : int { - kPointer = 0, - kCompatibleAnyInvocable = 1, - kIncompatibleAnyInvocable = 2, - kOther = 3, + enum class TargetType { + kPointer, + kCompatibleAnyInvocable, + kIncompatibleAnyInvocable, + kOther, }; // Note: QualDecayedTRef here includes the cv-ref qualifiers associated with @@ -466,8 +466,7 @@ class CoreImpl { // NOTE: We only use integers instead of enums as template parameters in // order to work around a bug on C++14 under MSVC 2017. // See b/236131881. - Initialize(kTargetType), QualDecayedTRef>( - std::forward(f)); + Initialize(std::forward(f)); } // Note: QualTRef here includes the cv-ref qualifiers associated with the @@ -518,8 +517,8 @@ class CoreImpl { invoker_ = nullptr; } - template = 0> + template = 0> void Initialize(F&& f) { // This condition handles types that decay into pointers, which includes // function references. Since function references cannot be null, GCC warns @@ -543,8 +542,9 @@ class CoreImpl { InitializeStorage(std::forward(f)); } - template = 0> + template = 0> void Initialize(F&& f) { // In this case we can "steal the guts" of the other AnyInvocable. f.manager_(FunctionToCall::relocate_from_to, &f.state_, &state_); @@ -555,8 +555,9 @@ class CoreImpl { f.invoker_ = nullptr; } - template = 0> + template = 0> void Initialize(F&& f) { if (f.HasValue()) { InitializeStorage(std::forward(f)); @@ -566,8 +567,8 @@ class CoreImpl { } } - template > + template > void Initialize(F&& f) { InitializeStorage(std::forward(f)); } From e6c09ae4b2acd421a29706f86e66eaa422262ad0 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Mon, 26 Jun 2023 12:30:38 -0700 Subject: [PATCH 0085/1238] Fix the check for #include Previously this was guarded with macros that are defined by itself. Note that libc++ also had a bug that was fixed last week https://github.com/llvm/llvm-project/commit/a4f0764aefd6ea41e83a5974f582a1a7e985667d PiperOrigin-RevId: 543511181 Change-Id: I1b8efa32f721ad450f8d1803c6c6c8373ad0371c --- absl/numeric/bits.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/absl/numeric/bits.h b/absl/numeric/bits.h index df81b9a929e..5466af072c6 100644 --- a/absl/numeric/bits.h +++ b/absl/numeric/bits.h @@ -38,13 +38,13 @@ #include #include -#if (defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L) || \ - (defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L) +#include "absl/base/config.h" + +#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L #include #endif #include "absl/base/attributes.h" -#include "absl/base/config.h" #include "absl/numeric/internal/bits.h" namespace absl { From d65595c8dd994b47b7fdfdf9427bb546c577467b Mon Sep 17 00:00:00 2001 From: Gennadiy Rozental Date: Tue, 27 Jun 2023 17:22:39 -0700 Subject: [PATCH 0086/1238] Import of CCTZ from GitHub. PiperOrigin-RevId: 543896343 Change-Id: Ia91b3e082b764b750bbbe9a3ce63192263d51438 --- .../internal/cctz/include/cctz/time_zone.h | 1 + .../internal/cctz/src/time_zone_format.cc | 6 +- absl/time/internal/cctz/src/time_zone_if.cc | 12 +- absl/time/internal/cctz/src/time_zone_if.h | 9 +- absl/time/internal/cctz/src/time_zone_impl.cc | 6 +- absl/time/internal/cctz/src/time_zone_impl.h | 4 + absl/time/internal/cctz/src/time_zone_info.cc | 602 +++++++++--------- absl/time/internal/cctz/src/time_zone_info.h | 25 +- absl/time/internal/cctz/src/time_zone_libc.cc | 10 +- absl/time/internal/cctz/src/time_zone_libc.h | 8 +- .../cctz/src/time_zone_lookup_test.cc | 4 + 11 files changed, 361 insertions(+), 326 deletions(-) diff --git a/absl/time/internal/cctz/include/cctz/time_zone.h b/absl/time/internal/cctz/include/cctz/time_zone.h index 6e382dc6c9f..b2b0cf6f511 100644 --- a/absl/time/internal/cctz/include/cctz/time_zone.h +++ b/absl/time/internal/cctz/include/cctz/time_zone.h @@ -23,6 +23,7 @@ #include #include #include +#include // NOLINT: We use std::ratio in this header #include #include diff --git a/absl/time/internal/cctz/src/time_zone_format.cc b/absl/time/internal/cctz/src/time_zone_format.cc index 0bea75a4436..96268a830b0 100644 --- a/absl/time/internal/cctz/src/time_zone_format.cc +++ b/absl/time/internal/cctz/src/time_zone_format.cc @@ -14,15 +14,13 @@ #if !defined(HAS_STRPTIME) #if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__VXWORKS__) -#define HAS_STRPTIME \ - 1 // assume everyone has strptime() except windows - // and VxWorks +#define HAS_STRPTIME 1 // Assume everyone else has strptime(). #endif #endif #if defined(HAS_STRPTIME) && HAS_STRPTIME #if !defined(_XOPEN_SOURCE) && !defined(__OpenBSD__) -#define _XOPEN_SOURCE // Definedness suffices for strptime. +#define _XOPEN_SOURCE // Definedness suffices for strptime(). #endif #endif diff --git a/absl/time/internal/cctz/src/time_zone_if.cc b/absl/time/internal/cctz/src/time_zone_if.cc index 1d44dde7f28..0e65cd9e73a 100644 --- a/absl/time/internal/cctz/src/time_zone_if.cc +++ b/absl/time/internal/cctz/src/time_zone_if.cc @@ -23,19 +23,19 @@ ABSL_NAMESPACE_BEGIN namespace time_internal { namespace cctz { -std::unique_ptr TimeZoneIf::Load(const std::string& name) { +std::unique_ptr TimeZoneIf::UTC() { return TimeZoneInfo::UTC(); } + +std::unique_ptr TimeZoneIf::Make(const std::string& name) { // Support "libc:localtime" and "libc:*" to access the legacy // localtime and UTC support respectively from the C library. // NOTE: The "libc:*" zones are internal, test-only interfaces, and // are subject to change/removal without notice. Do not use them. if (name.compare(0, 5, "libc:") == 0) { - return std::unique_ptr(new TimeZoneLibC(name.substr(5))); + return TimeZoneLibC::Make(name.substr(5)); } - // Otherwise use the "zoneinfo" implementation by default. - std::unique_ptr tz(new TimeZoneInfo); - if (!tz->Load(name)) tz.reset(); - return std::unique_ptr(tz.release()); + // Otherwise use the "zoneinfo" implementation. + return TimeZoneInfo::Make(name); } // Defined out-of-line to avoid emitting a weak vtable in all TUs. diff --git a/absl/time/internal/cctz/src/time_zone_if.h b/absl/time/internal/cctz/src/time_zone_if.h index 7d3e42d3cd5..bec9beb5cb7 100644 --- a/absl/time/internal/cctz/src/time_zone_if.h +++ b/absl/time/internal/cctz/src/time_zone_if.h @@ -33,8 +33,9 @@ namespace cctz { // Subclasses implement the functions for civil-time conversions in the zone. class TimeZoneIf { public: - // A factory function for TimeZoneIf implementations. - static std::unique_ptr Load(const std::string& name); + // Factory functions for TimeZoneIf implementations. + static std::unique_ptr UTC(); // never fails + static std::unique_ptr Make(const std::string& name); virtual ~TimeZoneIf(); @@ -51,7 +52,9 @@ class TimeZoneIf { virtual std::string Description() const = 0; protected: - TimeZoneIf() {} + TimeZoneIf() = default; + TimeZoneIf(const TimeZoneIf&) = delete; + TimeZoneIf& operator=(const TimeZoneIf&) = delete; }; // Convert between time_point and a count of seconds since the diff --git a/absl/time/internal/cctz/src/time_zone_impl.cc b/absl/time/internal/cctz/src/time_zone_impl.cc index f34e3aec84d..aadbb77da28 100644 --- a/absl/time/internal/cctz/src/time_zone_impl.cc +++ b/absl/time/internal/cctz/src/time_zone_impl.cc @@ -99,11 +99,13 @@ void time_zone::Impl::ClearTimeZoneMapTestOnly() { } } +time_zone::Impl::Impl() : name_("UTC"), zone_(TimeZoneIf::UTC()) {} + time_zone::Impl::Impl(const std::string& name) - : name_(name), zone_(TimeZoneIf::Load(name_)) {} + : name_(name), zone_(TimeZoneIf::Make(name_)) {} const time_zone::Impl* time_zone::Impl::UTCImpl() { - static const Impl* utc_impl = new Impl("UTC"); // never fails + static const Impl* utc_impl = new Impl; return utc_impl; } diff --git a/absl/time/internal/cctz/src/time_zone_impl.h b/absl/time/internal/cctz/src/time_zone_impl.h index 7d747ba9661..8308a3b49e0 100644 --- a/absl/time/internal/cctz/src/time_zone_impl.h +++ b/absl/time/internal/cctz/src/time_zone_impl.h @@ -78,7 +78,11 @@ class time_zone::Impl { std::string Description() const { return zone_->Description(); } private: + Impl(); explicit Impl(const std::string& name); + Impl(const Impl&) = delete; + Impl& operator=(const Impl&) = delete; + static const Impl* UTCImpl(); const std::string name_; diff --git a/absl/time/internal/cctz/src/time_zone_info.cc b/absl/time/internal/cctz/src/time_zone_info.cc index 787426f755d..4bc7b50bb66 100644 --- a/absl/time/internal/cctz/src/time_zone_info.cc +++ b/absl/time/internal/cctz/src/time_zone_info.cc @@ -134,6 +134,49 @@ std::int_fast64_t Decode64(const char* cp) { return static_cast(v - s64maxU - 1) - s64max - 1; } +struct Header { // counts of: + std::size_t timecnt; // transition times + std::size_t typecnt; // transition types + std::size_t charcnt; // zone abbreviation characters + std::size_t leapcnt; // leap seconds (we expect none) + std::size_t ttisstdcnt; // UTC/local indicators (unused) + std::size_t ttisutcnt; // standard/wall indicators (unused) + + bool Build(const tzhead& tzh); + std::size_t DataLength(std::size_t time_len) const; +}; + +// Builds the in-memory header using the raw bytes from the file. +bool Header::Build(const tzhead& tzh) { + std::int_fast32_t v; + if ((v = Decode32(tzh.tzh_timecnt)) < 0) return false; + timecnt = static_cast(v); + if ((v = Decode32(tzh.tzh_typecnt)) < 0) return false; + typecnt = static_cast(v); + if ((v = Decode32(tzh.tzh_charcnt)) < 0) return false; + charcnt = static_cast(v); + if ((v = Decode32(tzh.tzh_leapcnt)) < 0) return false; + leapcnt = static_cast(v); + if ((v = Decode32(tzh.tzh_ttisstdcnt)) < 0) return false; + ttisstdcnt = static_cast(v); + if ((v = Decode32(tzh.tzh_ttisutcnt)) < 0) return false; + ttisutcnt = static_cast(v); + return true; +} + +// How many bytes of data are associated with this header. The result +// depends upon whether this is a section with 4-byte or 8-byte times. +std::size_t Header::DataLength(std::size_t time_len) const { + std::size_t len = 0; + len += (time_len + 1) * timecnt; // unix_time + type_index + len += (4 + 1 + 1) * typecnt; // utc_offset + is_dst + abbr_index + len += 1 * charcnt; // abbreviations + len += (time_len + 4) * leapcnt; // leap-time + TAI-UTC + len += 1 * ttisstdcnt; // UTC/local indicators + len += 1 * ttisutcnt; // standard/wall indicators + return len; +} + // Does the rule for future transitions call for year-round daylight time? // See tz/zic.c:stringzone() for the details on how such rules are encoded. bool AllYearDST(const PosixTimeZone& posix) { @@ -217,98 +260,6 @@ inline civil_second YearShift(const civil_second& cs, year_t shift) { } // namespace -// What (no leap-seconds) UTC+seconds zoneinfo would look like. -bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) { - transition_types_.resize(1); - TransitionType& tt(transition_types_.back()); - tt.utc_offset = static_cast(offset.count()); - tt.is_dst = false; - tt.abbr_index = 0; - - // We temporarily add some redundant, contemporary (2015 through 2025) - // transitions for performance reasons. See TimeZoneInfo::LocalTime(). - // TODO: Fix the performance issue and remove the extra transitions. - transitions_.clear(); - transitions_.reserve(12); - for (const std::int_fast64_t unix_time : { - -(1LL << 59), // a "first half" transition - 1420070400LL, // 2015-01-01T00:00:00+00:00 - 1451606400LL, // 2016-01-01T00:00:00+00:00 - 1483228800LL, // 2017-01-01T00:00:00+00:00 - 1514764800LL, // 2018-01-01T00:00:00+00:00 - 1546300800LL, // 2019-01-01T00:00:00+00:00 - 1577836800LL, // 2020-01-01T00:00:00+00:00 - 1609459200LL, // 2021-01-01T00:00:00+00:00 - 1640995200LL, // 2022-01-01T00:00:00+00:00 - 1672531200LL, // 2023-01-01T00:00:00+00:00 - 1704067200LL, // 2024-01-01T00:00:00+00:00 - 1735689600LL, // 2025-01-01T00:00:00+00:00 - }) { - Transition& tr(*transitions_.emplace(transitions_.end())); - tr.unix_time = unix_time; - tr.type_index = 0; - tr.civil_sec = LocalTime(tr.unix_time, tt).cs; - tr.prev_civil_sec = tr.civil_sec - 1; - } - - default_transition_type_ = 0; - abbreviations_ = FixedOffsetToAbbr(offset); - abbreviations_.append(1, '\0'); - future_spec_.clear(); // never needed for a fixed-offset zone - extended_ = false; - - tt.civil_max = LocalTime(seconds::max().count(), tt).cs; - tt.civil_min = LocalTime(seconds::min().count(), tt).cs; - - transitions_.shrink_to_fit(); - return true; -} - -// Builds the in-memory header using the raw bytes from the file. -bool TimeZoneInfo::Header::Build(const tzhead& tzh) { - std::int_fast32_t v; - if ((v = Decode32(tzh.tzh_timecnt)) < 0) return false; - timecnt = static_cast(v); - if ((v = Decode32(tzh.tzh_typecnt)) < 0) return false; - typecnt = static_cast(v); - if ((v = Decode32(tzh.tzh_charcnt)) < 0) return false; - charcnt = static_cast(v); - if ((v = Decode32(tzh.tzh_leapcnt)) < 0) return false; - leapcnt = static_cast(v); - if ((v = Decode32(tzh.tzh_ttisstdcnt)) < 0) return false; - ttisstdcnt = static_cast(v); - if ((v = Decode32(tzh.tzh_ttisutcnt)) < 0) return false; - ttisutcnt = static_cast(v); - return true; -} - -// How many bytes of data are associated with this header. The result -// depends upon whether this is a section with 4-byte or 8-byte times. -std::size_t TimeZoneInfo::Header::DataLength(std::size_t time_len) const { - std::size_t len = 0; - len += (time_len + 1) * timecnt; // unix_time + type_index - len += (4 + 1 + 1) * typecnt; // utc_offset + is_dst + abbr_index - len += 1 * charcnt; // abbreviations - len += (time_len + 4) * leapcnt; // leap-time + TAI-UTC - len += 1 * ttisstdcnt; // UTC/local indicators - len += 1 * ttisutcnt; // standard/wall indicators - return len; -} - -// zic(8) can generate no-op transitions when a zone changes rules at an -// instant when there is actually no discontinuity. So we check whether -// two transitions have equivalent types (same offset/is_dst/abbr). -bool TimeZoneInfo::EquivTransitions(std::uint_fast8_t tt1_index, - std::uint_fast8_t tt2_index) const { - if (tt1_index == tt2_index) return true; - const TransitionType& tt1(transition_types_[tt1_index]); - const TransitionType& tt2(transition_types_[tt2_index]); - if (tt1.utc_offset != tt2.utc_offset) return false; - if (tt1.is_dst != tt2.is_dst) return false; - if (tt1.abbr_index != tt2.abbr_index) return false; - return true; -} - // Find/make a transition type with these attributes. bool TimeZoneInfo::GetTransitionType(std::int_fast32_t utc_offset, bool is_dst, const std::string& abbr, @@ -341,6 +292,20 @@ bool TimeZoneInfo::GetTransitionType(std::int_fast32_t utc_offset, bool is_dst, return true; } +// zic(8) can generate no-op transitions when a zone changes rules at an +// instant when there is actually no discontinuity. So we check whether +// two transitions have equivalent types (same offset/is_dst/abbr). +bool TimeZoneInfo::EquivTransitions(std::uint_fast8_t tt1_index, + std::uint_fast8_t tt2_index) const { + if (tt1_index == tt2_index) return true; + const TransitionType& tt1(transition_types_[tt1_index]); + const TransitionType& tt2(transition_types_[tt2_index]); + if (tt1.utc_offset != tt2.utc_offset) return false; + if (tt1.is_dst != tt2.is_dst) return false; + if (tt1.abbr_index != tt2.abbr_index) return false; + return true; +} + // Use the POSIX-TZ-environment-variable-style string to handle times // in years after the last transition stored in the zoneinfo data. bool TimeZoneInfo::ExtendTransitions() { @@ -394,206 +359,19 @@ bool TimeZoneInfo::ExtendTransitions() { auto dst_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_start); auto std_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_end); dst.unix_time = jan1_time + dst_trans_off - posix.std_offset; - std.unix_time = jan1_time + std_trans_off - posix.dst_offset; - const auto* ta = dst.unix_time < std.unix_time ? &dst : &std; - const auto* tb = dst.unix_time < std.unix_time ? &std : &dst; - if (last_time < tb->unix_time) { - if (last_time < ta->unix_time) transitions_.push_back(*ta); - transitions_.push_back(*tb); - } - if (last_year_ == limit) break; - jan1_time += kSecsPerYear[leap_year]; - jan1_weekday = (jan1_weekday + kDaysPerYear[leap_year]) % 7; - leap_year = !leap_year && IsLeap(last_year_ + 1); - } - - return true; -} - -bool TimeZoneInfo::Load(ZoneInfoSource* zip) { - // Read and validate the header. - tzhead tzh; - if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false; - if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0) - return false; - Header hdr; - if (!hdr.Build(tzh)) return false; - std::size_t time_len = 4; - if (tzh.tzh_version[0] != '\0') { - // Skip the 4-byte data. - if (zip->Skip(hdr.DataLength(time_len)) != 0) return false; - // Read and validate the header for the 8-byte data. - if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false; - if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0) - return false; - if (tzh.tzh_version[0] == '\0') return false; - if (!hdr.Build(tzh)) return false; - time_len = 8; - } - if (hdr.typecnt == 0) return false; - if (hdr.leapcnt != 0) { - // This code assumes 60-second minutes so we do not want - // the leap-second encoded zoneinfo. We could reverse the - // compensation, but the "right" encoding is rarely used - // so currently we simply reject such data. - return false; - } - if (hdr.ttisstdcnt != 0 && hdr.ttisstdcnt != hdr.typecnt) return false; - if (hdr.ttisutcnt != 0 && hdr.ttisutcnt != hdr.typecnt) return false; - - // Read the data into a local buffer. - std::size_t len = hdr.DataLength(time_len); - std::vector tbuf(len); - if (zip->Read(tbuf.data(), len) != len) return false; - const char* bp = tbuf.data(); - - // Decode and validate the transitions. - transitions_.reserve(hdr.timecnt + 2); - transitions_.resize(hdr.timecnt); - for (std::size_t i = 0; i != hdr.timecnt; ++i) { - transitions_[i].unix_time = (time_len == 4) ? Decode32(bp) : Decode64(bp); - bp += time_len; - if (i != 0) { - // Check that the transitions are ordered by time (as zic guarantees). - if (!Transition::ByUnixTime()(transitions_[i - 1], transitions_[i])) - return false; // out of order - } - } - bool seen_type_0 = false; - for (std::size_t i = 0; i != hdr.timecnt; ++i) { - transitions_[i].type_index = Decode8(bp++); - if (transitions_[i].type_index >= hdr.typecnt) return false; - if (transitions_[i].type_index == 0) seen_type_0 = true; - } - - // Decode and validate the transition types. - transition_types_.reserve(hdr.typecnt + 2); - transition_types_.resize(hdr.typecnt); - for (std::size_t i = 0; i != hdr.typecnt; ++i) { - transition_types_[i].utc_offset = - static_cast(Decode32(bp)); - if (transition_types_[i].utc_offset >= kSecsPerDay || - transition_types_[i].utc_offset <= -kSecsPerDay) - return false; - bp += 4; - transition_types_[i].is_dst = (Decode8(bp++) != 0); - transition_types_[i].abbr_index = Decode8(bp++); - if (transition_types_[i].abbr_index >= hdr.charcnt) return false; - } - - // Determine the before-first-transition type. - default_transition_type_ = 0; - if (seen_type_0 && hdr.timecnt != 0) { - std::uint_fast8_t index = 0; - if (transition_types_[0].is_dst) { - index = transitions_[0].type_index; - while (index != 0 && transition_types_[index].is_dst) --index; - } - while (index != hdr.typecnt && transition_types_[index].is_dst) ++index; - if (index != hdr.typecnt) default_transition_type_ = index; - } - - // Copy all the abbreviations. - abbreviations_.reserve(hdr.charcnt + 10); - abbreviations_.assign(bp, hdr.charcnt); - bp += hdr.charcnt; - - // Skip the unused portions. We've already dispensed with leap-second - // encoded zoneinfo. The ttisstd/ttisgmt indicators only apply when - // interpreting a POSIX spec that does not include start/end rules, and - // that isn't the case here (see "zic -p"). - bp += (time_len + 4) * hdr.leapcnt; // leap-time + TAI-UTC - bp += 1 * hdr.ttisstdcnt; // UTC/local indicators - bp += 1 * hdr.ttisutcnt; // standard/wall indicators - assert(bp == tbuf.data() + tbuf.size()); - - future_spec_.clear(); - if (tzh.tzh_version[0] != '\0') { - // Snarf up the NL-enclosed future POSIX spec. Note - // that version '3' files utilize an extended format. - auto get_char = [](ZoneInfoSource* azip) -> int { - unsigned char ch; // all non-EOF results are positive - return (azip->Read(&ch, 1) == 1) ? ch : EOF; - }; - if (get_char(zip) != '\n') return false; - for (int c = get_char(zip); c != '\n'; c = get_char(zip)) { - if (c == EOF) return false; - future_spec_.push_back(static_cast(c)); - } - } - - // We don't check for EOF so that we're forwards compatible. - - // If we did not find version information during the standard loading - // process (as of tzh_version '3' that is unsupported), then ask the - // ZoneInfoSource for any out-of-bound version string it may be privy to. - if (version_.empty()) { - version_ = zip->Version(); - } - - // Trim redundant transitions. zic may have added these to work around - // differences between the glibc and reference implementations (see - // zic.c:dontmerge) or to avoid bugs in old readers. For us, they just - // get in the way when we do future_spec_ extension. - while (hdr.timecnt > 1) { - if (!EquivTransitions(transitions_[hdr.timecnt - 1].type_index, - transitions_[hdr.timecnt - 2].type_index)) { - break; - } - hdr.timecnt -= 1; - } - transitions_.resize(hdr.timecnt); - - // Ensure that there is always a transition in the first half of the - // time line (the second half is handled below) so that the signed - // difference between a civil_second and the civil_second of its - // previous transition is always representable, without overflow. - if (transitions_.empty() || transitions_.front().unix_time >= 0) { - Transition& tr(*transitions_.emplace(transitions_.begin())); - tr.unix_time = -(1LL << 59); // -18267312070-10-26T17:01:52+00:00 - tr.type_index = default_transition_type_; - } - - // Extend the transitions using the future specification. - if (!ExtendTransitions()) return false; - - // Ensure that there is always a transition in the second half of the - // time line (the first half is handled above) so that the signed - // difference between a civil_second and the civil_second of its - // previous transition is always representable, without overflow. - const Transition& last(transitions_.back()); - if (last.unix_time < 0) { - const std::uint_fast8_t type_index = last.type_index; - Transition& tr(*transitions_.emplace(transitions_.end())); - tr.unix_time = 2147483647; // 2038-01-19T03:14:07+00:00 - tr.type_index = type_index; - } - - // Compute the local civil time for each transition and the preceding - // second. These will be used for reverse conversions in MakeTime(). - const TransitionType* ttp = &transition_types_[default_transition_type_]; - for (std::size_t i = 0; i != transitions_.size(); ++i) { - Transition& tr(transitions_[i]); - tr.prev_civil_sec = LocalTime(tr.unix_time, *ttp).cs - 1; - ttp = &transition_types_[tr.type_index]; - tr.civil_sec = LocalTime(tr.unix_time, *ttp).cs; - if (i != 0) { - // Check that the transitions are ordered by civil time. Essentially - // this means that an offset change cannot cross another such change. - // No one does this in practice, and we depend on it in MakeTime(). - if (!Transition::ByCivilTime()(transitions_[i - 1], tr)) - return false; // out of order + std.unix_time = jan1_time + std_trans_off - posix.dst_offset; + const auto* ta = dst.unix_time < std.unix_time ? &dst : &std; + const auto* tb = dst.unix_time < std.unix_time ? &std : &dst; + if (last_time < tb->unix_time) { + if (last_time < ta->unix_time) transitions_.push_back(*ta); + transitions_.push_back(*tb); } + if (last_year_ == limit) break; + jan1_time += kSecsPerYear[leap_year]; + jan1_weekday = (jan1_weekday + kDaysPerYear[leap_year]) % 7; + leap_year = !leap_year && IsLeap(last_year_ + 1); } - // Compute the maximum/minimum civil times that can be converted to a - // time_point for each of the zone's transition types. - for (auto& tt : transition_types_) { - tt.civil_max = LocalTime(seconds::max().count(), tt).cs; - tt.civil_min = LocalTime(seconds::min().count(), tt).cs; - } - - transitions_.shrink_to_fit(); return true; } @@ -795,6 +573,240 @@ std::unique_ptr FuchsiaZoneInfoSource::Open( } // namespace +// What (no leap-seconds) UTC+seconds zoneinfo would look like. +bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) { + transition_types_.resize(1); + TransitionType& tt(transition_types_.back()); + tt.utc_offset = static_cast(offset.count()); + tt.is_dst = false; + tt.abbr_index = 0; + + // We temporarily add some redundant, contemporary (2015 through 2025) + // transitions for performance reasons. See TimeZoneInfo::LocalTime(). + // TODO: Fix the performance issue and remove the extra transitions. + transitions_.clear(); + transitions_.reserve(12); + for (const std::int_fast64_t unix_time : { + -(1LL << 59), // a "first half" transition + 1420070400LL, // 2015-01-01T00:00:00+00:00 + 1451606400LL, // 2016-01-01T00:00:00+00:00 + 1483228800LL, // 2017-01-01T00:00:00+00:00 + 1514764800LL, // 2018-01-01T00:00:00+00:00 + 1546300800LL, // 2019-01-01T00:00:00+00:00 + 1577836800LL, // 2020-01-01T00:00:00+00:00 + 1609459200LL, // 2021-01-01T00:00:00+00:00 + 1640995200LL, // 2022-01-01T00:00:00+00:00 + 1672531200LL, // 2023-01-01T00:00:00+00:00 + 1704067200LL, // 2024-01-01T00:00:00+00:00 + 1735689600LL, // 2025-01-01T00:00:00+00:00 + }) { + Transition& tr(*transitions_.emplace(transitions_.end())); + tr.unix_time = unix_time; + tr.type_index = 0; + tr.civil_sec = LocalTime(tr.unix_time, tt).cs; + tr.prev_civil_sec = tr.civil_sec - 1; + } + + default_transition_type_ = 0; + abbreviations_ = FixedOffsetToAbbr(offset); + abbreviations_.append(1, '\0'); + future_spec_.clear(); // never needed for a fixed-offset zone + extended_ = false; + + tt.civil_max = LocalTime(seconds::max().count(), tt).cs; + tt.civil_min = LocalTime(seconds::min().count(), tt).cs; + + transitions_.shrink_to_fit(); + return true; +} + +bool TimeZoneInfo::Load(ZoneInfoSource* zip) { + // Read and validate the header. + tzhead tzh; + if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false; + if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0) + return false; + Header hdr; + if (!hdr.Build(tzh)) return false; + std::size_t time_len = 4; + if (tzh.tzh_version[0] != '\0') { + // Skip the 4-byte data. + if (zip->Skip(hdr.DataLength(time_len)) != 0) return false; + // Read and validate the header for the 8-byte data. + if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false; + if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0) + return false; + if (tzh.tzh_version[0] == '\0') return false; + if (!hdr.Build(tzh)) return false; + time_len = 8; + } + if (hdr.typecnt == 0) return false; + if (hdr.leapcnt != 0) { + // This code assumes 60-second minutes so we do not want + // the leap-second encoded zoneinfo. We could reverse the + // compensation, but the "right" encoding is rarely used + // so currently we simply reject such data. + return false; + } + if (hdr.ttisstdcnt != 0 && hdr.ttisstdcnt != hdr.typecnt) return false; + if (hdr.ttisutcnt != 0 && hdr.ttisutcnt != hdr.typecnt) return false; + + // Read the data into a local buffer. + std::size_t len = hdr.DataLength(time_len); + std::vector tbuf(len); + if (zip->Read(tbuf.data(), len) != len) return false; + const char* bp = tbuf.data(); + + // Decode and validate the transitions. + transitions_.reserve(hdr.timecnt + 2); + transitions_.resize(hdr.timecnt); + for (std::size_t i = 0; i != hdr.timecnt; ++i) { + transitions_[i].unix_time = (time_len == 4) ? Decode32(bp) : Decode64(bp); + bp += time_len; + if (i != 0) { + // Check that the transitions are ordered by time (as zic guarantees). + if (!Transition::ByUnixTime()(transitions_[i - 1], transitions_[i])) + return false; // out of order + } + } + bool seen_type_0 = false; + for (std::size_t i = 0; i != hdr.timecnt; ++i) { + transitions_[i].type_index = Decode8(bp++); + if (transitions_[i].type_index >= hdr.typecnt) return false; + if (transitions_[i].type_index == 0) seen_type_0 = true; + } + + // Decode and validate the transition types. + transition_types_.reserve(hdr.typecnt + 2); + transition_types_.resize(hdr.typecnt); + for (std::size_t i = 0; i != hdr.typecnt; ++i) { + transition_types_[i].utc_offset = + static_cast(Decode32(bp)); + if (transition_types_[i].utc_offset >= kSecsPerDay || + transition_types_[i].utc_offset <= -kSecsPerDay) + return false; + bp += 4; + transition_types_[i].is_dst = (Decode8(bp++) != 0); + transition_types_[i].abbr_index = Decode8(bp++); + if (transition_types_[i].abbr_index >= hdr.charcnt) return false; + } + + // Determine the before-first-transition type. + default_transition_type_ = 0; + if (seen_type_0 && hdr.timecnt != 0) { + std::uint_fast8_t index = 0; + if (transition_types_[0].is_dst) { + index = transitions_[0].type_index; + while (index != 0 && transition_types_[index].is_dst) --index; + } + while (index != hdr.typecnt && transition_types_[index].is_dst) ++index; + if (index != hdr.typecnt) default_transition_type_ = index; + } + + // Copy all the abbreviations. + abbreviations_.reserve(hdr.charcnt + 10); + abbreviations_.assign(bp, hdr.charcnt); + bp += hdr.charcnt; + + // Skip the unused portions. We've already dispensed with leap-second + // encoded zoneinfo. The ttisstd/ttisgmt indicators only apply when + // interpreting a POSIX spec that does not include start/end rules, and + // that isn't the case here (see "zic -p"). + bp += (time_len + 4) * hdr.leapcnt; // leap-time + TAI-UTC + bp += 1 * hdr.ttisstdcnt; // UTC/local indicators + bp += 1 * hdr.ttisutcnt; // standard/wall indicators + assert(bp == tbuf.data() + tbuf.size()); + + future_spec_.clear(); + if (tzh.tzh_version[0] != '\0') { + // Snarf up the NL-enclosed future POSIX spec. Note + // that version '3' files utilize an extended format. + auto get_char = [](ZoneInfoSource* azip) -> int { + unsigned char ch; // all non-EOF results are positive + return (azip->Read(&ch, 1) == 1) ? ch : EOF; + }; + if (get_char(zip) != '\n') return false; + for (int c = get_char(zip); c != '\n'; c = get_char(zip)) { + if (c == EOF) return false; + future_spec_.push_back(static_cast(c)); + } + } + + // We don't check for EOF so that we're forwards compatible. + + // If we did not find version information during the standard loading + // process (as of tzh_version '3' that is unsupported), then ask the + // ZoneInfoSource for any out-of-bound version string it may be privy to. + if (version_.empty()) { + version_ = zip->Version(); + } + + // Trim redundant transitions. zic may have added these to work around + // differences between the glibc and reference implementations (see + // zic.c:dontmerge) or to avoid bugs in old readers. For us, they just + // get in the way when we do future_spec_ extension. + while (hdr.timecnt > 1) { + if (!EquivTransitions(transitions_[hdr.timecnt - 1].type_index, + transitions_[hdr.timecnt - 2].type_index)) { + break; + } + hdr.timecnt -= 1; + } + transitions_.resize(hdr.timecnt); + + // Ensure that there is always a transition in the first half of the + // time line (the second half is handled below) so that the signed + // difference between a civil_second and the civil_second of its + // previous transition is always representable, without overflow. + if (transitions_.empty() || transitions_.front().unix_time >= 0) { + Transition& tr(*transitions_.emplace(transitions_.begin())); + tr.unix_time = -(1LL << 59); // -18267312070-10-26T17:01:52+00:00 + tr.type_index = default_transition_type_; + } + + // Extend the transitions using the future specification. + if (!ExtendTransitions()) return false; + + // Ensure that there is always a transition in the second half of the + // time line (the first half is handled above) so that the signed + // difference between a civil_second and the civil_second of its + // previous transition is always representable, without overflow. + const Transition& last(transitions_.back()); + if (last.unix_time < 0) { + const std::uint_fast8_t type_index = last.type_index; + Transition& tr(*transitions_.emplace(transitions_.end())); + tr.unix_time = 2147483647; // 2038-01-19T03:14:07+00:00 + tr.type_index = type_index; + } + + // Compute the local civil time for each transition and the preceding + // second. These will be used for reverse conversions in MakeTime(). + const TransitionType* ttp = &transition_types_[default_transition_type_]; + for (std::size_t i = 0; i != transitions_.size(); ++i) { + Transition& tr(transitions_[i]); + tr.prev_civil_sec = LocalTime(tr.unix_time, *ttp).cs - 1; + ttp = &transition_types_[tr.type_index]; + tr.civil_sec = LocalTime(tr.unix_time, *ttp).cs; + if (i != 0) { + // Check that the transitions are ordered by civil time. Essentially + // this means that an offset change cannot cross another such change. + // No one does this in practice, and we depend on it in MakeTime(). + if (!Transition::ByCivilTime()(transitions_[i - 1], tr)) + return false; // out of order + } + } + + // Compute the maximum/minimum civil times that can be converted to a + // time_point for each of the zone's transition types. + for (auto& tt : transition_types_) { + tt.civil_max = LocalTime(seconds::max().count(), tt).cs; + tt.civil_min = LocalTime(seconds::min().count(), tt).cs; + } + + transitions_.shrink_to_fit(); + return true; +} + bool TimeZoneInfo::Load(const std::string& name) { // We can ensure that the loading of UTC or any other fixed-offset // zone never fails because the simple, fixed-offset state can be @@ -816,6 +828,18 @@ bool TimeZoneInfo::Load(const std::string& name) { return zip != nullptr && Load(zip.get()); } +std::unique_ptr TimeZoneInfo::UTC() { + auto tz = std::unique_ptr(new TimeZoneInfo); + tz->ResetToBuiltinUTC(seconds::zero()); + return tz; +} + +std::unique_ptr TimeZoneInfo::Make(const std::string& name) { + auto tz = std::unique_ptr(new TimeZoneInfo); + if (!tz->Load(name)) tz.reset(); // fallback to UTC + return tz; +} + // BreakTime() translation for a particular transition type. time_zone::absolute_lookup TimeZoneInfo::LocalTime( std::int_fast64_t unix_time, const TransitionType& tt) const { diff --git a/absl/time/internal/cctz/src/time_zone_info.h b/absl/time/internal/cctz/src/time_zone_info.h index 2467ff559d3..689df6f9c0e 100644 --- a/absl/time/internal/cctz/src/time_zone_info.h +++ b/absl/time/internal/cctz/src/time_zone_info.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -64,12 +65,9 @@ struct TransitionType { // A time zone backed by the IANA Time Zone Database (zoneinfo). class TimeZoneInfo : public TimeZoneIf { public: - TimeZoneInfo() = default; - TimeZoneInfo(const TimeZoneInfo&) = delete; - TimeZoneInfo& operator=(const TimeZoneInfo&) = delete; - - // Loads the zoneinfo for the given name, returning true if successful. - bool Load(const std::string& name); + // Factories. + static std::unique_ptr UTC(); // never fails + static std::unique_ptr Make(const std::string& name); // TimeZoneIf implementations. time_zone::absolute_lookup BreakTime( @@ -83,17 +81,9 @@ class TimeZoneInfo : public TimeZoneIf { std::string Description() const override; private: - struct Header { // counts of: - std::size_t timecnt; // transition times - std::size_t typecnt; // transition types - std::size_t charcnt; // zone abbreviation characters - std::size_t leapcnt; // leap seconds (we expect none) - std::size_t ttisstdcnt; // UTC/local indicators (unused) - std::size_t ttisutcnt; // standard/wall indicators (unused) - - bool Build(const tzhead& tzh); - std::size_t DataLength(std::size_t time_len) const; - }; + TimeZoneInfo() = default; + TimeZoneInfo(const TimeZoneInfo&) = delete; + TimeZoneInfo& operator=(const TimeZoneInfo&) = delete; bool GetTransitionType(std::int_fast32_t utc_offset, bool is_dst, const std::string& abbr, std::uint_least8_t* index); @@ -102,6 +92,7 @@ class TimeZoneInfo : public TimeZoneIf { bool ExtendTransitions(); bool ResetToBuiltinUTC(const seconds& offset); + bool Load(const std::string& name); bool Load(ZoneInfoSource* zip); // Helpers for BreakTime() and MakeTime(). diff --git a/absl/time/internal/cctz/src/time_zone_libc.cc b/absl/time/internal/cctz/src/time_zone_libc.cc index e503a8584bd..d01461222e9 100644 --- a/absl/time/internal/cctz/src/time_zone_libc.cc +++ b/absl/time/internal/cctz/src/time_zone_libc.cc @@ -62,7 +62,7 @@ auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) { } #elif defined(__native_client__) || defined(__myriad2__) || \ defined(__EMSCRIPTEN__) -// Uses the globals: 'timezone' and 'tzname'. +// Uses the globals: '_timezone' and 'tzname'. auto tm_gmtoff(const std::tm& tm) -> decltype(_timezone + 0) { const bool is_dst = tm.tm_isdst > 0; return _timezone + (is_dst ? 60 * 60 : 0); @@ -193,8 +193,9 @@ std::time_t find_trans(std::time_t lo, std::time_t hi, tm_gmtoff_t offset) { } // namespace -TimeZoneLibC::TimeZoneLibC(const std::string& name) - : local_(name == "localtime") {} +std::unique_ptr TimeZoneLibC::Make(const std::string& name) { + return std::unique_ptr(new TimeZoneLibC(name)); +} time_zone::absolute_lookup TimeZoneLibC::BreakTime( const time_point& tp) const { @@ -323,6 +324,9 @@ std::string TimeZoneLibC::Description() const { return local_ ? "localtime" : "UTC"; } +TimeZoneLibC::TimeZoneLibC(const std::string& name) + : local_(name == "localtime") {} + } // namespace cctz } // namespace time_internal ABSL_NAMESPACE_END diff --git a/absl/time/internal/cctz/src/time_zone_libc.h b/absl/time/internal/cctz/src/time_zone_libc.h index 1da9039a15e..2d6fa686cf8 100644 --- a/absl/time/internal/cctz/src/time_zone_libc.h +++ b/absl/time/internal/cctz/src/time_zone_libc.h @@ -27,10 +27,10 @@ namespace cctz { // A time zone backed by gmtime_r(3), localtime_r(3), and mktime(3), // and which therefore only supports UTC and the local time zone. -// TODO: Add support for fixed offsets from UTC. class TimeZoneLibC : public TimeZoneIf { public: - explicit TimeZoneLibC(const std::string& name); + // Factory. + static std::unique_ptr Make(const std::string& name); // TimeZoneIf implementations. time_zone::absolute_lookup BreakTime( @@ -44,6 +44,10 @@ class TimeZoneLibC : public TimeZoneIf { std::string Description() const override; private: + explicit TimeZoneLibC(const std::string& name); + TimeZoneLibC(const TimeZoneLibC&) = delete; + TimeZoneLibC& operator=(const TimeZoneLibC&) = delete; + const bool local_; // localtime or UTC }; diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc index 38f10f48ecc..fc6592668fe 100644 --- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc +++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc @@ -734,6 +734,10 @@ TEST(TimeZone, UTC) { time_zone loaded_utc0; EXPECT_TRUE(load_time_zone("UTC0", &loaded_utc0)); EXPECT_EQ(loaded_utc0, utc); + + time_zone loaded_bad; + EXPECT_FALSE(load_time_zone("Invalid/TimeZone", &loaded_bad)); + EXPECT_EQ(loaded_bad, utc); } TEST(TimeZone, NamedTimeZones) { From 17014064a4ea367952eb4a595796f48c688c1467 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 28 Jun 2023 08:11:49 -0700 Subject: [PATCH 0087/1238] Rollback of CCTZ update due to crash in clang ObjcLink. PiperOrigin-RevId: 544060862 Change-Id: I6ca631385826f6e10f6c3eeec1af532402d0b532 --- .../internal/cctz/include/cctz/time_zone.h | 1 - .../internal/cctz/src/time_zone_format.cc | 6 +- absl/time/internal/cctz/src/time_zone_if.cc | 12 +- absl/time/internal/cctz/src/time_zone_if.h | 9 +- absl/time/internal/cctz/src/time_zone_impl.cc | 6 +- absl/time/internal/cctz/src/time_zone_impl.h | 4 - absl/time/internal/cctz/src/time_zone_info.cc | 590 +++++++++--------- absl/time/internal/cctz/src/time_zone_info.h | 25 +- absl/time/internal/cctz/src/time_zone_libc.cc | 10 +- absl/time/internal/cctz/src/time_zone_libc.h | 8 +- .../cctz/src/time_zone_lookup_test.cc | 4 - 11 files changed, 320 insertions(+), 355 deletions(-) diff --git a/absl/time/internal/cctz/include/cctz/time_zone.h b/absl/time/internal/cctz/include/cctz/time_zone.h index b2b0cf6f511..6e382dc6c9f 100644 --- a/absl/time/internal/cctz/include/cctz/time_zone.h +++ b/absl/time/internal/cctz/include/cctz/time_zone.h @@ -23,7 +23,6 @@ #include #include #include -#include // NOLINT: We use std::ratio in this header #include #include diff --git a/absl/time/internal/cctz/src/time_zone_format.cc b/absl/time/internal/cctz/src/time_zone_format.cc index 96268a830b0..0bea75a4436 100644 --- a/absl/time/internal/cctz/src/time_zone_format.cc +++ b/absl/time/internal/cctz/src/time_zone_format.cc @@ -14,13 +14,15 @@ #if !defined(HAS_STRPTIME) #if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__VXWORKS__) -#define HAS_STRPTIME 1 // Assume everyone else has strptime(). +#define HAS_STRPTIME \ + 1 // assume everyone has strptime() except windows + // and VxWorks #endif #endif #if defined(HAS_STRPTIME) && HAS_STRPTIME #if !defined(_XOPEN_SOURCE) && !defined(__OpenBSD__) -#define _XOPEN_SOURCE // Definedness suffices for strptime(). +#define _XOPEN_SOURCE // Definedness suffices for strptime. #endif #endif diff --git a/absl/time/internal/cctz/src/time_zone_if.cc b/absl/time/internal/cctz/src/time_zone_if.cc index 0e65cd9e73a..1d44dde7f28 100644 --- a/absl/time/internal/cctz/src/time_zone_if.cc +++ b/absl/time/internal/cctz/src/time_zone_if.cc @@ -23,19 +23,19 @@ ABSL_NAMESPACE_BEGIN namespace time_internal { namespace cctz { -std::unique_ptr TimeZoneIf::UTC() { return TimeZoneInfo::UTC(); } - -std::unique_ptr TimeZoneIf::Make(const std::string& name) { +std::unique_ptr TimeZoneIf::Load(const std::string& name) { // Support "libc:localtime" and "libc:*" to access the legacy // localtime and UTC support respectively from the C library. // NOTE: The "libc:*" zones are internal, test-only interfaces, and // are subject to change/removal without notice. Do not use them. if (name.compare(0, 5, "libc:") == 0) { - return TimeZoneLibC::Make(name.substr(5)); + return std::unique_ptr(new TimeZoneLibC(name.substr(5))); } - // Otherwise use the "zoneinfo" implementation. - return TimeZoneInfo::Make(name); + // Otherwise use the "zoneinfo" implementation by default. + std::unique_ptr tz(new TimeZoneInfo); + if (!tz->Load(name)) tz.reset(); + return std::unique_ptr(tz.release()); } // Defined out-of-line to avoid emitting a weak vtable in all TUs. diff --git a/absl/time/internal/cctz/src/time_zone_if.h b/absl/time/internal/cctz/src/time_zone_if.h index bec9beb5cb7..7d3e42d3cd5 100644 --- a/absl/time/internal/cctz/src/time_zone_if.h +++ b/absl/time/internal/cctz/src/time_zone_if.h @@ -33,9 +33,8 @@ namespace cctz { // Subclasses implement the functions for civil-time conversions in the zone. class TimeZoneIf { public: - // Factory functions for TimeZoneIf implementations. - static std::unique_ptr UTC(); // never fails - static std::unique_ptr Make(const std::string& name); + // A factory function for TimeZoneIf implementations. + static std::unique_ptr Load(const std::string& name); virtual ~TimeZoneIf(); @@ -52,9 +51,7 @@ class TimeZoneIf { virtual std::string Description() const = 0; protected: - TimeZoneIf() = default; - TimeZoneIf(const TimeZoneIf&) = delete; - TimeZoneIf& operator=(const TimeZoneIf&) = delete; + TimeZoneIf() {} }; // Convert between time_point and a count of seconds since the diff --git a/absl/time/internal/cctz/src/time_zone_impl.cc b/absl/time/internal/cctz/src/time_zone_impl.cc index aadbb77da28..f34e3aec84d 100644 --- a/absl/time/internal/cctz/src/time_zone_impl.cc +++ b/absl/time/internal/cctz/src/time_zone_impl.cc @@ -99,13 +99,11 @@ void time_zone::Impl::ClearTimeZoneMapTestOnly() { } } -time_zone::Impl::Impl() : name_("UTC"), zone_(TimeZoneIf::UTC()) {} - time_zone::Impl::Impl(const std::string& name) - : name_(name), zone_(TimeZoneIf::Make(name_)) {} + : name_(name), zone_(TimeZoneIf::Load(name_)) {} const time_zone::Impl* time_zone::Impl::UTCImpl() { - static const Impl* utc_impl = new Impl; + static const Impl* utc_impl = new Impl("UTC"); // never fails return utc_impl; } diff --git a/absl/time/internal/cctz/src/time_zone_impl.h b/absl/time/internal/cctz/src/time_zone_impl.h index 8308a3b49e0..7d747ba9661 100644 --- a/absl/time/internal/cctz/src/time_zone_impl.h +++ b/absl/time/internal/cctz/src/time_zone_impl.h @@ -78,11 +78,7 @@ class time_zone::Impl { std::string Description() const { return zone_->Description(); } private: - Impl(); explicit Impl(const std::string& name); - Impl(const Impl&) = delete; - Impl& operator=(const Impl&) = delete; - static const Impl* UTCImpl(); const std::string name_; diff --git a/absl/time/internal/cctz/src/time_zone_info.cc b/absl/time/internal/cctz/src/time_zone_info.cc index 4bc7b50bb66..787426f755d 100644 --- a/absl/time/internal/cctz/src/time_zone_info.cc +++ b/absl/time/internal/cctz/src/time_zone_info.cc @@ -134,49 +134,6 @@ std::int_fast64_t Decode64(const char* cp) { return static_cast(v - s64maxU - 1) - s64max - 1; } -struct Header { // counts of: - std::size_t timecnt; // transition times - std::size_t typecnt; // transition types - std::size_t charcnt; // zone abbreviation characters - std::size_t leapcnt; // leap seconds (we expect none) - std::size_t ttisstdcnt; // UTC/local indicators (unused) - std::size_t ttisutcnt; // standard/wall indicators (unused) - - bool Build(const tzhead& tzh); - std::size_t DataLength(std::size_t time_len) const; -}; - -// Builds the in-memory header using the raw bytes from the file. -bool Header::Build(const tzhead& tzh) { - std::int_fast32_t v; - if ((v = Decode32(tzh.tzh_timecnt)) < 0) return false; - timecnt = static_cast(v); - if ((v = Decode32(tzh.tzh_typecnt)) < 0) return false; - typecnt = static_cast(v); - if ((v = Decode32(tzh.tzh_charcnt)) < 0) return false; - charcnt = static_cast(v); - if ((v = Decode32(tzh.tzh_leapcnt)) < 0) return false; - leapcnt = static_cast(v); - if ((v = Decode32(tzh.tzh_ttisstdcnt)) < 0) return false; - ttisstdcnt = static_cast(v); - if ((v = Decode32(tzh.tzh_ttisutcnt)) < 0) return false; - ttisutcnt = static_cast(v); - return true; -} - -// How many bytes of data are associated with this header. The result -// depends upon whether this is a section with 4-byte or 8-byte times. -std::size_t Header::DataLength(std::size_t time_len) const { - std::size_t len = 0; - len += (time_len + 1) * timecnt; // unix_time + type_index - len += (4 + 1 + 1) * typecnt; // utc_offset + is_dst + abbr_index - len += 1 * charcnt; // abbreviations - len += (time_len + 4) * leapcnt; // leap-time + TAI-UTC - len += 1 * ttisstdcnt; // UTC/local indicators - len += 1 * ttisutcnt; // standard/wall indicators - return len; -} - // Does the rule for future transitions call for year-round daylight time? // See tz/zic.c:stringzone() for the details on how such rules are encoded. bool AllYearDST(const PosixTimeZone& posix) { @@ -260,6 +217,98 @@ inline civil_second YearShift(const civil_second& cs, year_t shift) { } // namespace +// What (no leap-seconds) UTC+seconds zoneinfo would look like. +bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) { + transition_types_.resize(1); + TransitionType& tt(transition_types_.back()); + tt.utc_offset = static_cast(offset.count()); + tt.is_dst = false; + tt.abbr_index = 0; + + // We temporarily add some redundant, contemporary (2015 through 2025) + // transitions for performance reasons. See TimeZoneInfo::LocalTime(). + // TODO: Fix the performance issue and remove the extra transitions. + transitions_.clear(); + transitions_.reserve(12); + for (const std::int_fast64_t unix_time : { + -(1LL << 59), // a "first half" transition + 1420070400LL, // 2015-01-01T00:00:00+00:00 + 1451606400LL, // 2016-01-01T00:00:00+00:00 + 1483228800LL, // 2017-01-01T00:00:00+00:00 + 1514764800LL, // 2018-01-01T00:00:00+00:00 + 1546300800LL, // 2019-01-01T00:00:00+00:00 + 1577836800LL, // 2020-01-01T00:00:00+00:00 + 1609459200LL, // 2021-01-01T00:00:00+00:00 + 1640995200LL, // 2022-01-01T00:00:00+00:00 + 1672531200LL, // 2023-01-01T00:00:00+00:00 + 1704067200LL, // 2024-01-01T00:00:00+00:00 + 1735689600LL, // 2025-01-01T00:00:00+00:00 + }) { + Transition& tr(*transitions_.emplace(transitions_.end())); + tr.unix_time = unix_time; + tr.type_index = 0; + tr.civil_sec = LocalTime(tr.unix_time, tt).cs; + tr.prev_civil_sec = tr.civil_sec - 1; + } + + default_transition_type_ = 0; + abbreviations_ = FixedOffsetToAbbr(offset); + abbreviations_.append(1, '\0'); + future_spec_.clear(); // never needed for a fixed-offset zone + extended_ = false; + + tt.civil_max = LocalTime(seconds::max().count(), tt).cs; + tt.civil_min = LocalTime(seconds::min().count(), tt).cs; + + transitions_.shrink_to_fit(); + return true; +} + +// Builds the in-memory header using the raw bytes from the file. +bool TimeZoneInfo::Header::Build(const tzhead& tzh) { + std::int_fast32_t v; + if ((v = Decode32(tzh.tzh_timecnt)) < 0) return false; + timecnt = static_cast(v); + if ((v = Decode32(tzh.tzh_typecnt)) < 0) return false; + typecnt = static_cast(v); + if ((v = Decode32(tzh.tzh_charcnt)) < 0) return false; + charcnt = static_cast(v); + if ((v = Decode32(tzh.tzh_leapcnt)) < 0) return false; + leapcnt = static_cast(v); + if ((v = Decode32(tzh.tzh_ttisstdcnt)) < 0) return false; + ttisstdcnt = static_cast(v); + if ((v = Decode32(tzh.tzh_ttisutcnt)) < 0) return false; + ttisutcnt = static_cast(v); + return true; +} + +// How many bytes of data are associated with this header. The result +// depends upon whether this is a section with 4-byte or 8-byte times. +std::size_t TimeZoneInfo::Header::DataLength(std::size_t time_len) const { + std::size_t len = 0; + len += (time_len + 1) * timecnt; // unix_time + type_index + len += (4 + 1 + 1) * typecnt; // utc_offset + is_dst + abbr_index + len += 1 * charcnt; // abbreviations + len += (time_len + 4) * leapcnt; // leap-time + TAI-UTC + len += 1 * ttisstdcnt; // UTC/local indicators + len += 1 * ttisutcnt; // standard/wall indicators + return len; +} + +// zic(8) can generate no-op transitions when a zone changes rules at an +// instant when there is actually no discontinuity. So we check whether +// two transitions have equivalent types (same offset/is_dst/abbr). +bool TimeZoneInfo::EquivTransitions(std::uint_fast8_t tt1_index, + std::uint_fast8_t tt2_index) const { + if (tt1_index == tt2_index) return true; + const TransitionType& tt1(transition_types_[tt1_index]); + const TransitionType& tt2(transition_types_[tt2_index]); + if (tt1.utc_offset != tt2.utc_offset) return false; + if (tt1.is_dst != tt2.is_dst) return false; + if (tt1.abbr_index != tt2.abbr_index) return false; + return true; +} + // Find/make a transition type with these attributes. bool TimeZoneInfo::GetTransitionType(std::int_fast32_t utc_offset, bool is_dst, const std::string& abbr, @@ -292,20 +341,6 @@ bool TimeZoneInfo::GetTransitionType(std::int_fast32_t utc_offset, bool is_dst, return true; } -// zic(8) can generate no-op transitions when a zone changes rules at an -// instant when there is actually no discontinuity. So we check whether -// two transitions have equivalent types (same offset/is_dst/abbr). -bool TimeZoneInfo::EquivTransitions(std::uint_fast8_t tt1_index, - std::uint_fast8_t tt2_index) const { - if (tt1_index == tt2_index) return true; - const TransitionType& tt1(transition_types_[tt1_index]); - const TransitionType& tt2(transition_types_[tt2_index]); - if (tt1.utc_offset != tt2.utc_offset) return false; - if (tt1.is_dst != tt2.is_dst) return false; - if (tt1.abbr_index != tt2.abbr_index) return false; - return true; -} - // Use the POSIX-TZ-environment-variable-style string to handle times // in years after the last transition stored in the zoneinfo data. bool TimeZoneInfo::ExtendTransitions() { @@ -366,12 +401,199 @@ bool TimeZoneInfo::ExtendTransitions() { if (last_time < ta->unix_time) transitions_.push_back(*ta); transitions_.push_back(*tb); } - if (last_year_ == limit) break; - jan1_time += kSecsPerYear[leap_year]; - jan1_weekday = (jan1_weekday + kDaysPerYear[leap_year]) % 7; - leap_year = !leap_year && IsLeap(last_year_ + 1); + if (last_year_ == limit) break; + jan1_time += kSecsPerYear[leap_year]; + jan1_weekday = (jan1_weekday + kDaysPerYear[leap_year]) % 7; + leap_year = !leap_year && IsLeap(last_year_ + 1); + } + + return true; +} + +bool TimeZoneInfo::Load(ZoneInfoSource* zip) { + // Read and validate the header. + tzhead tzh; + if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false; + if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0) + return false; + Header hdr; + if (!hdr.Build(tzh)) return false; + std::size_t time_len = 4; + if (tzh.tzh_version[0] != '\0') { + // Skip the 4-byte data. + if (zip->Skip(hdr.DataLength(time_len)) != 0) return false; + // Read and validate the header for the 8-byte data. + if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false; + if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0) + return false; + if (tzh.tzh_version[0] == '\0') return false; + if (!hdr.Build(tzh)) return false; + time_len = 8; + } + if (hdr.typecnt == 0) return false; + if (hdr.leapcnt != 0) { + // This code assumes 60-second minutes so we do not want + // the leap-second encoded zoneinfo. We could reverse the + // compensation, but the "right" encoding is rarely used + // so currently we simply reject such data. + return false; + } + if (hdr.ttisstdcnt != 0 && hdr.ttisstdcnt != hdr.typecnt) return false; + if (hdr.ttisutcnt != 0 && hdr.ttisutcnt != hdr.typecnt) return false; + + // Read the data into a local buffer. + std::size_t len = hdr.DataLength(time_len); + std::vector tbuf(len); + if (zip->Read(tbuf.data(), len) != len) return false; + const char* bp = tbuf.data(); + + // Decode and validate the transitions. + transitions_.reserve(hdr.timecnt + 2); + transitions_.resize(hdr.timecnt); + for (std::size_t i = 0; i != hdr.timecnt; ++i) { + transitions_[i].unix_time = (time_len == 4) ? Decode32(bp) : Decode64(bp); + bp += time_len; + if (i != 0) { + // Check that the transitions are ordered by time (as zic guarantees). + if (!Transition::ByUnixTime()(transitions_[i - 1], transitions_[i])) + return false; // out of order + } + } + bool seen_type_0 = false; + for (std::size_t i = 0; i != hdr.timecnt; ++i) { + transitions_[i].type_index = Decode8(bp++); + if (transitions_[i].type_index >= hdr.typecnt) return false; + if (transitions_[i].type_index == 0) seen_type_0 = true; + } + + // Decode and validate the transition types. + transition_types_.reserve(hdr.typecnt + 2); + transition_types_.resize(hdr.typecnt); + for (std::size_t i = 0; i != hdr.typecnt; ++i) { + transition_types_[i].utc_offset = + static_cast(Decode32(bp)); + if (transition_types_[i].utc_offset >= kSecsPerDay || + transition_types_[i].utc_offset <= -kSecsPerDay) + return false; + bp += 4; + transition_types_[i].is_dst = (Decode8(bp++) != 0); + transition_types_[i].abbr_index = Decode8(bp++); + if (transition_types_[i].abbr_index >= hdr.charcnt) return false; + } + + // Determine the before-first-transition type. + default_transition_type_ = 0; + if (seen_type_0 && hdr.timecnt != 0) { + std::uint_fast8_t index = 0; + if (transition_types_[0].is_dst) { + index = transitions_[0].type_index; + while (index != 0 && transition_types_[index].is_dst) --index; + } + while (index != hdr.typecnt && transition_types_[index].is_dst) ++index; + if (index != hdr.typecnt) default_transition_type_ = index; + } + + // Copy all the abbreviations. + abbreviations_.reserve(hdr.charcnt + 10); + abbreviations_.assign(bp, hdr.charcnt); + bp += hdr.charcnt; + + // Skip the unused portions. We've already dispensed with leap-second + // encoded zoneinfo. The ttisstd/ttisgmt indicators only apply when + // interpreting a POSIX spec that does not include start/end rules, and + // that isn't the case here (see "zic -p"). + bp += (time_len + 4) * hdr.leapcnt; // leap-time + TAI-UTC + bp += 1 * hdr.ttisstdcnt; // UTC/local indicators + bp += 1 * hdr.ttisutcnt; // standard/wall indicators + assert(bp == tbuf.data() + tbuf.size()); + + future_spec_.clear(); + if (tzh.tzh_version[0] != '\0') { + // Snarf up the NL-enclosed future POSIX spec. Note + // that version '3' files utilize an extended format. + auto get_char = [](ZoneInfoSource* azip) -> int { + unsigned char ch; // all non-EOF results are positive + return (azip->Read(&ch, 1) == 1) ? ch : EOF; + }; + if (get_char(zip) != '\n') return false; + for (int c = get_char(zip); c != '\n'; c = get_char(zip)) { + if (c == EOF) return false; + future_spec_.push_back(static_cast(c)); + } + } + + // We don't check for EOF so that we're forwards compatible. + + // If we did not find version information during the standard loading + // process (as of tzh_version '3' that is unsupported), then ask the + // ZoneInfoSource for any out-of-bound version string it may be privy to. + if (version_.empty()) { + version_ = zip->Version(); + } + + // Trim redundant transitions. zic may have added these to work around + // differences between the glibc and reference implementations (see + // zic.c:dontmerge) or to avoid bugs in old readers. For us, they just + // get in the way when we do future_spec_ extension. + while (hdr.timecnt > 1) { + if (!EquivTransitions(transitions_[hdr.timecnt - 1].type_index, + transitions_[hdr.timecnt - 2].type_index)) { + break; + } + hdr.timecnt -= 1; + } + transitions_.resize(hdr.timecnt); + + // Ensure that there is always a transition in the first half of the + // time line (the second half is handled below) so that the signed + // difference between a civil_second and the civil_second of its + // previous transition is always representable, without overflow. + if (transitions_.empty() || transitions_.front().unix_time >= 0) { + Transition& tr(*transitions_.emplace(transitions_.begin())); + tr.unix_time = -(1LL << 59); // -18267312070-10-26T17:01:52+00:00 + tr.type_index = default_transition_type_; + } + + // Extend the transitions using the future specification. + if (!ExtendTransitions()) return false; + + // Ensure that there is always a transition in the second half of the + // time line (the first half is handled above) so that the signed + // difference between a civil_second and the civil_second of its + // previous transition is always representable, without overflow. + const Transition& last(transitions_.back()); + if (last.unix_time < 0) { + const std::uint_fast8_t type_index = last.type_index; + Transition& tr(*transitions_.emplace(transitions_.end())); + tr.unix_time = 2147483647; // 2038-01-19T03:14:07+00:00 + tr.type_index = type_index; + } + + // Compute the local civil time for each transition and the preceding + // second. These will be used for reverse conversions in MakeTime(). + const TransitionType* ttp = &transition_types_[default_transition_type_]; + for (std::size_t i = 0; i != transitions_.size(); ++i) { + Transition& tr(transitions_[i]); + tr.prev_civil_sec = LocalTime(tr.unix_time, *ttp).cs - 1; + ttp = &transition_types_[tr.type_index]; + tr.civil_sec = LocalTime(tr.unix_time, *ttp).cs; + if (i != 0) { + // Check that the transitions are ordered by civil time. Essentially + // this means that an offset change cannot cross another such change. + // No one does this in practice, and we depend on it in MakeTime(). + if (!Transition::ByCivilTime()(transitions_[i - 1], tr)) + return false; // out of order + } + } + + // Compute the maximum/minimum civil times that can be converted to a + // time_point for each of the zone's transition types. + for (auto& tt : transition_types_) { + tt.civil_max = LocalTime(seconds::max().count(), tt).cs; + tt.civil_min = LocalTime(seconds::min().count(), tt).cs; } + transitions_.shrink_to_fit(); return true; } @@ -573,240 +795,6 @@ std::unique_ptr FuchsiaZoneInfoSource::Open( } // namespace -// What (no leap-seconds) UTC+seconds zoneinfo would look like. -bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) { - transition_types_.resize(1); - TransitionType& tt(transition_types_.back()); - tt.utc_offset = static_cast(offset.count()); - tt.is_dst = false; - tt.abbr_index = 0; - - // We temporarily add some redundant, contemporary (2015 through 2025) - // transitions for performance reasons. See TimeZoneInfo::LocalTime(). - // TODO: Fix the performance issue and remove the extra transitions. - transitions_.clear(); - transitions_.reserve(12); - for (const std::int_fast64_t unix_time : { - -(1LL << 59), // a "first half" transition - 1420070400LL, // 2015-01-01T00:00:00+00:00 - 1451606400LL, // 2016-01-01T00:00:00+00:00 - 1483228800LL, // 2017-01-01T00:00:00+00:00 - 1514764800LL, // 2018-01-01T00:00:00+00:00 - 1546300800LL, // 2019-01-01T00:00:00+00:00 - 1577836800LL, // 2020-01-01T00:00:00+00:00 - 1609459200LL, // 2021-01-01T00:00:00+00:00 - 1640995200LL, // 2022-01-01T00:00:00+00:00 - 1672531200LL, // 2023-01-01T00:00:00+00:00 - 1704067200LL, // 2024-01-01T00:00:00+00:00 - 1735689600LL, // 2025-01-01T00:00:00+00:00 - }) { - Transition& tr(*transitions_.emplace(transitions_.end())); - tr.unix_time = unix_time; - tr.type_index = 0; - tr.civil_sec = LocalTime(tr.unix_time, tt).cs; - tr.prev_civil_sec = tr.civil_sec - 1; - } - - default_transition_type_ = 0; - abbreviations_ = FixedOffsetToAbbr(offset); - abbreviations_.append(1, '\0'); - future_spec_.clear(); // never needed for a fixed-offset zone - extended_ = false; - - tt.civil_max = LocalTime(seconds::max().count(), tt).cs; - tt.civil_min = LocalTime(seconds::min().count(), tt).cs; - - transitions_.shrink_to_fit(); - return true; -} - -bool TimeZoneInfo::Load(ZoneInfoSource* zip) { - // Read and validate the header. - tzhead tzh; - if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false; - if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0) - return false; - Header hdr; - if (!hdr.Build(tzh)) return false; - std::size_t time_len = 4; - if (tzh.tzh_version[0] != '\0') { - // Skip the 4-byte data. - if (zip->Skip(hdr.DataLength(time_len)) != 0) return false; - // Read and validate the header for the 8-byte data. - if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false; - if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0) - return false; - if (tzh.tzh_version[0] == '\0') return false; - if (!hdr.Build(tzh)) return false; - time_len = 8; - } - if (hdr.typecnt == 0) return false; - if (hdr.leapcnt != 0) { - // This code assumes 60-second minutes so we do not want - // the leap-second encoded zoneinfo. We could reverse the - // compensation, but the "right" encoding is rarely used - // so currently we simply reject such data. - return false; - } - if (hdr.ttisstdcnt != 0 && hdr.ttisstdcnt != hdr.typecnt) return false; - if (hdr.ttisutcnt != 0 && hdr.ttisutcnt != hdr.typecnt) return false; - - // Read the data into a local buffer. - std::size_t len = hdr.DataLength(time_len); - std::vector tbuf(len); - if (zip->Read(tbuf.data(), len) != len) return false; - const char* bp = tbuf.data(); - - // Decode and validate the transitions. - transitions_.reserve(hdr.timecnt + 2); - transitions_.resize(hdr.timecnt); - for (std::size_t i = 0; i != hdr.timecnt; ++i) { - transitions_[i].unix_time = (time_len == 4) ? Decode32(bp) : Decode64(bp); - bp += time_len; - if (i != 0) { - // Check that the transitions are ordered by time (as zic guarantees). - if (!Transition::ByUnixTime()(transitions_[i - 1], transitions_[i])) - return false; // out of order - } - } - bool seen_type_0 = false; - for (std::size_t i = 0; i != hdr.timecnt; ++i) { - transitions_[i].type_index = Decode8(bp++); - if (transitions_[i].type_index >= hdr.typecnt) return false; - if (transitions_[i].type_index == 0) seen_type_0 = true; - } - - // Decode and validate the transition types. - transition_types_.reserve(hdr.typecnt + 2); - transition_types_.resize(hdr.typecnt); - for (std::size_t i = 0; i != hdr.typecnt; ++i) { - transition_types_[i].utc_offset = - static_cast(Decode32(bp)); - if (transition_types_[i].utc_offset >= kSecsPerDay || - transition_types_[i].utc_offset <= -kSecsPerDay) - return false; - bp += 4; - transition_types_[i].is_dst = (Decode8(bp++) != 0); - transition_types_[i].abbr_index = Decode8(bp++); - if (transition_types_[i].abbr_index >= hdr.charcnt) return false; - } - - // Determine the before-first-transition type. - default_transition_type_ = 0; - if (seen_type_0 && hdr.timecnt != 0) { - std::uint_fast8_t index = 0; - if (transition_types_[0].is_dst) { - index = transitions_[0].type_index; - while (index != 0 && transition_types_[index].is_dst) --index; - } - while (index != hdr.typecnt && transition_types_[index].is_dst) ++index; - if (index != hdr.typecnt) default_transition_type_ = index; - } - - // Copy all the abbreviations. - abbreviations_.reserve(hdr.charcnt + 10); - abbreviations_.assign(bp, hdr.charcnt); - bp += hdr.charcnt; - - // Skip the unused portions. We've already dispensed with leap-second - // encoded zoneinfo. The ttisstd/ttisgmt indicators only apply when - // interpreting a POSIX spec that does not include start/end rules, and - // that isn't the case here (see "zic -p"). - bp += (time_len + 4) * hdr.leapcnt; // leap-time + TAI-UTC - bp += 1 * hdr.ttisstdcnt; // UTC/local indicators - bp += 1 * hdr.ttisutcnt; // standard/wall indicators - assert(bp == tbuf.data() + tbuf.size()); - - future_spec_.clear(); - if (tzh.tzh_version[0] != '\0') { - // Snarf up the NL-enclosed future POSIX spec. Note - // that version '3' files utilize an extended format. - auto get_char = [](ZoneInfoSource* azip) -> int { - unsigned char ch; // all non-EOF results are positive - return (azip->Read(&ch, 1) == 1) ? ch : EOF; - }; - if (get_char(zip) != '\n') return false; - for (int c = get_char(zip); c != '\n'; c = get_char(zip)) { - if (c == EOF) return false; - future_spec_.push_back(static_cast(c)); - } - } - - // We don't check for EOF so that we're forwards compatible. - - // If we did not find version information during the standard loading - // process (as of tzh_version '3' that is unsupported), then ask the - // ZoneInfoSource for any out-of-bound version string it may be privy to. - if (version_.empty()) { - version_ = zip->Version(); - } - - // Trim redundant transitions. zic may have added these to work around - // differences between the glibc and reference implementations (see - // zic.c:dontmerge) or to avoid bugs in old readers. For us, they just - // get in the way when we do future_spec_ extension. - while (hdr.timecnt > 1) { - if (!EquivTransitions(transitions_[hdr.timecnt - 1].type_index, - transitions_[hdr.timecnt - 2].type_index)) { - break; - } - hdr.timecnt -= 1; - } - transitions_.resize(hdr.timecnt); - - // Ensure that there is always a transition in the first half of the - // time line (the second half is handled below) so that the signed - // difference between a civil_second and the civil_second of its - // previous transition is always representable, without overflow. - if (transitions_.empty() || transitions_.front().unix_time >= 0) { - Transition& tr(*transitions_.emplace(transitions_.begin())); - tr.unix_time = -(1LL << 59); // -18267312070-10-26T17:01:52+00:00 - tr.type_index = default_transition_type_; - } - - // Extend the transitions using the future specification. - if (!ExtendTransitions()) return false; - - // Ensure that there is always a transition in the second half of the - // time line (the first half is handled above) so that the signed - // difference between a civil_second and the civil_second of its - // previous transition is always representable, without overflow. - const Transition& last(transitions_.back()); - if (last.unix_time < 0) { - const std::uint_fast8_t type_index = last.type_index; - Transition& tr(*transitions_.emplace(transitions_.end())); - tr.unix_time = 2147483647; // 2038-01-19T03:14:07+00:00 - tr.type_index = type_index; - } - - // Compute the local civil time for each transition and the preceding - // second. These will be used for reverse conversions in MakeTime(). - const TransitionType* ttp = &transition_types_[default_transition_type_]; - for (std::size_t i = 0; i != transitions_.size(); ++i) { - Transition& tr(transitions_[i]); - tr.prev_civil_sec = LocalTime(tr.unix_time, *ttp).cs - 1; - ttp = &transition_types_[tr.type_index]; - tr.civil_sec = LocalTime(tr.unix_time, *ttp).cs; - if (i != 0) { - // Check that the transitions are ordered by civil time. Essentially - // this means that an offset change cannot cross another such change. - // No one does this in practice, and we depend on it in MakeTime(). - if (!Transition::ByCivilTime()(transitions_[i - 1], tr)) - return false; // out of order - } - } - - // Compute the maximum/minimum civil times that can be converted to a - // time_point for each of the zone's transition types. - for (auto& tt : transition_types_) { - tt.civil_max = LocalTime(seconds::max().count(), tt).cs; - tt.civil_min = LocalTime(seconds::min().count(), tt).cs; - } - - transitions_.shrink_to_fit(); - return true; -} - bool TimeZoneInfo::Load(const std::string& name) { // We can ensure that the loading of UTC or any other fixed-offset // zone never fails because the simple, fixed-offset state can be @@ -828,18 +816,6 @@ bool TimeZoneInfo::Load(const std::string& name) { return zip != nullptr && Load(zip.get()); } -std::unique_ptr TimeZoneInfo::UTC() { - auto tz = std::unique_ptr(new TimeZoneInfo); - tz->ResetToBuiltinUTC(seconds::zero()); - return tz; -} - -std::unique_ptr TimeZoneInfo::Make(const std::string& name) { - auto tz = std::unique_ptr(new TimeZoneInfo); - if (!tz->Load(name)) tz.reset(); // fallback to UTC - return tz; -} - // BreakTime() translation for a particular transition type. time_zone::absolute_lookup TimeZoneInfo::LocalTime( std::int_fast64_t unix_time, const TransitionType& tt) const { diff --git a/absl/time/internal/cctz/src/time_zone_info.h b/absl/time/internal/cctz/src/time_zone_info.h index 689df6f9c0e..2467ff559d3 100644 --- a/absl/time/internal/cctz/src/time_zone_info.h +++ b/absl/time/internal/cctz/src/time_zone_info.h @@ -18,7 +18,6 @@ #include #include #include -#include #include #include @@ -65,9 +64,12 @@ struct TransitionType { // A time zone backed by the IANA Time Zone Database (zoneinfo). class TimeZoneInfo : public TimeZoneIf { public: - // Factories. - static std::unique_ptr UTC(); // never fails - static std::unique_ptr Make(const std::string& name); + TimeZoneInfo() = default; + TimeZoneInfo(const TimeZoneInfo&) = delete; + TimeZoneInfo& operator=(const TimeZoneInfo&) = delete; + + // Loads the zoneinfo for the given name, returning true if successful. + bool Load(const std::string& name); // TimeZoneIf implementations. time_zone::absolute_lookup BreakTime( @@ -81,9 +83,17 @@ class TimeZoneInfo : public TimeZoneIf { std::string Description() const override; private: - TimeZoneInfo() = default; - TimeZoneInfo(const TimeZoneInfo&) = delete; - TimeZoneInfo& operator=(const TimeZoneInfo&) = delete; + struct Header { // counts of: + std::size_t timecnt; // transition times + std::size_t typecnt; // transition types + std::size_t charcnt; // zone abbreviation characters + std::size_t leapcnt; // leap seconds (we expect none) + std::size_t ttisstdcnt; // UTC/local indicators (unused) + std::size_t ttisutcnt; // standard/wall indicators (unused) + + bool Build(const tzhead& tzh); + std::size_t DataLength(std::size_t time_len) const; + }; bool GetTransitionType(std::int_fast32_t utc_offset, bool is_dst, const std::string& abbr, std::uint_least8_t* index); @@ -92,7 +102,6 @@ class TimeZoneInfo : public TimeZoneIf { bool ExtendTransitions(); bool ResetToBuiltinUTC(const seconds& offset); - bool Load(const std::string& name); bool Load(ZoneInfoSource* zip); // Helpers for BreakTime() and MakeTime(). diff --git a/absl/time/internal/cctz/src/time_zone_libc.cc b/absl/time/internal/cctz/src/time_zone_libc.cc index d01461222e9..e503a8584bd 100644 --- a/absl/time/internal/cctz/src/time_zone_libc.cc +++ b/absl/time/internal/cctz/src/time_zone_libc.cc @@ -62,7 +62,7 @@ auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) { } #elif defined(__native_client__) || defined(__myriad2__) || \ defined(__EMSCRIPTEN__) -// Uses the globals: '_timezone' and 'tzname'. +// Uses the globals: 'timezone' and 'tzname'. auto tm_gmtoff(const std::tm& tm) -> decltype(_timezone + 0) { const bool is_dst = tm.tm_isdst > 0; return _timezone + (is_dst ? 60 * 60 : 0); @@ -193,9 +193,8 @@ std::time_t find_trans(std::time_t lo, std::time_t hi, tm_gmtoff_t offset) { } // namespace -std::unique_ptr TimeZoneLibC::Make(const std::string& name) { - return std::unique_ptr(new TimeZoneLibC(name)); -} +TimeZoneLibC::TimeZoneLibC(const std::string& name) + : local_(name == "localtime") {} time_zone::absolute_lookup TimeZoneLibC::BreakTime( const time_point& tp) const { @@ -324,9 +323,6 @@ std::string TimeZoneLibC::Description() const { return local_ ? "localtime" : "UTC"; } -TimeZoneLibC::TimeZoneLibC(const std::string& name) - : local_(name == "localtime") {} - } // namespace cctz } // namespace time_internal ABSL_NAMESPACE_END diff --git a/absl/time/internal/cctz/src/time_zone_libc.h b/absl/time/internal/cctz/src/time_zone_libc.h index 2d6fa686cf8..1da9039a15e 100644 --- a/absl/time/internal/cctz/src/time_zone_libc.h +++ b/absl/time/internal/cctz/src/time_zone_libc.h @@ -27,10 +27,10 @@ namespace cctz { // A time zone backed by gmtime_r(3), localtime_r(3), and mktime(3), // and which therefore only supports UTC and the local time zone. +// TODO: Add support for fixed offsets from UTC. class TimeZoneLibC : public TimeZoneIf { public: - // Factory. - static std::unique_ptr Make(const std::string& name); + explicit TimeZoneLibC(const std::string& name); // TimeZoneIf implementations. time_zone::absolute_lookup BreakTime( @@ -44,10 +44,6 @@ class TimeZoneLibC : public TimeZoneIf { std::string Description() const override; private: - explicit TimeZoneLibC(const std::string& name); - TimeZoneLibC(const TimeZoneLibC&) = delete; - TimeZoneLibC& operator=(const TimeZoneLibC&) = delete; - const bool local_; // localtime or UTC }; diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc index fc6592668fe..38f10f48ecc 100644 --- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc +++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc @@ -734,10 +734,6 @@ TEST(TimeZone, UTC) { time_zone loaded_utc0; EXPECT_TRUE(load_time_zone("UTC0", &loaded_utc0)); EXPECT_EQ(loaded_utc0, utc); - - time_zone loaded_bad; - EXPECT_FALSE(load_time_zone("Invalid/TimeZone", &loaded_bad)); - EXPECT_EQ(loaded_bad, utc); } TEST(TimeZone, NamedTimeZones) { From bba65bd11506292aad0258ab516fe9eabf507e18 Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Wed, 28 Jun 2023 11:09:29 -0700 Subject: [PATCH 0088/1238] Refactor bit tests to allow for the testing of more types PiperOrigin-RevId: 544107572 Change-Id: I8016ee690ad5df78bf80ba0786e528fba4e51907 --- absl/numeric/bits.h | 2 +- absl/numeric/bits_test.cc | 68 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/absl/numeric/bits.h b/absl/numeric/bits.h index 5466af072c6..5ed36f52964 100644 --- a/absl/numeric/bits.h +++ b/absl/numeric/bits.h @@ -49,8 +49,8 @@ namespace absl { ABSL_NAMESPACE_BEGIN - #if !(defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L) + // rotating template ABSL_MUST_USE_RESULT constexpr diff --git a/absl/numeric/bits_test.cc b/absl/numeric/bits_test.cc index 7c942aaecde..14955eb3519 100644 --- a/absl/numeric/bits_test.cc +++ b/absl/numeric/bits_test.cc @@ -15,6 +15,7 @@ #include "absl/numeric/bits.h" #include +#include #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -24,6 +25,73 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace { +template +class IntegerTypesTest : public ::testing::Test {}; + +using OneByteIntegerTypes = ::testing::Types< + unsigned char, + uint8_t + >; + +TYPED_TEST_SUITE(IntegerTypesTest, OneByteIntegerTypes); + +TYPED_TEST(IntegerTypesTest, HandlesTypes) { + using UIntType = TypeParam; + + EXPECT_EQ(rotl(UIntType{0x12}, 0), uint8_t{0x12}); + EXPECT_EQ(rotr(UIntType{0x12}, -4), uint8_t{0x21}); + static_assert(rotl(UIntType{0x12}, 0) == uint8_t{0x12}, ""); + + static_assert(rotr(UIntType{0x12}, 0) == uint8_t{0x12}, ""); + EXPECT_EQ(rotr(UIntType{0x12}, 0), uint8_t{0x12}); + +#if ABSL_INTERNAL_HAS_CONSTEXPR_CLZ + static_assert(countl_zero(UIntType{}) == 8, ""); + static_assert(countl_zero(static_cast(-1)) == 0, ""); + + static_assert(countl_one(UIntType{}) == 0, ""); + static_assert(countl_one(static_cast(-1)) == 8, ""); + + static_assert(countr_zero(UIntType{}) == 8, ""); + static_assert(countr_zero(static_cast(-1)) == 0, ""); + + static_assert(countr_one(UIntType{}) == 0, ""); + static_assert(countr_one(static_cast(-1)) == 8, ""); + + static_assert(popcount(UIntType{}) == 0, ""); + static_assert(popcount(UIntType{1}) == 1, ""); + static_assert(popcount(static_cast(-1)) == 8, ""); + + static_assert(bit_width(UIntType{}) == 0, ""); + static_assert(bit_width(UIntType{1}) == 1, ""); + static_assert(bit_width(UIntType{3}) == 2, ""); + static_assert(bit_width(static_cast(-1)) == 8, ""); +#endif + + EXPECT_EQ(countl_zero(UIntType{}), 8); + EXPECT_EQ(countl_zero(static_cast(-1)), 0); + + EXPECT_EQ(countl_one(UIntType{}), 0); + EXPECT_EQ(countl_one(static_cast(-1)), 8); + + EXPECT_EQ(countr_zero(UIntType{}), 8); + EXPECT_EQ(countr_zero(static_cast(-1)), 0); + + EXPECT_EQ(countr_one(UIntType{}), 0); + EXPECT_EQ(countr_one(static_cast(-1)), 8); + + EXPECT_EQ(popcount(UIntType{}), 0); + EXPECT_EQ(popcount(UIntType{1}), 1); + + EXPECT_FALSE(has_single_bit(UIntType{})); + EXPECT_FALSE(has_single_bit(static_cast(-1))); + + EXPECT_EQ(bit_width(UIntType{}), 0); + EXPECT_EQ(bit_width(UIntType{1}), 1); + EXPECT_EQ(bit_width(UIntType{3}), 2); + EXPECT_EQ(bit_width(static_cast(-1)), 8); +} + TEST(Rotate, Left) { static_assert(rotl(uint8_t{0x12}, 0) == uint8_t{0x12}, ""); static_assert(rotl(uint16_t{0x1234}, 0) == uint16_t{0x1234}, ""); From 2119e40e17b56e38d077279fa7480b04d769d01d Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 28 Jun 2023 13:34:32 -0700 Subject: [PATCH 0089/1238] Roll forward of CCTZ update; fixed by clang release. PiperOrigin-RevId: 544146637 Change-Id: I5ca44465f451956ae246081ce826891599b18b9c --- .../internal/cctz/include/cctz/time_zone.h | 1 + .../internal/cctz/src/time_zone_format.cc | 6 +- absl/time/internal/cctz/src/time_zone_if.cc | 12 +- absl/time/internal/cctz/src/time_zone_if.h | 9 +- absl/time/internal/cctz/src/time_zone_impl.cc | 6 +- absl/time/internal/cctz/src/time_zone_impl.h | 4 + absl/time/internal/cctz/src/time_zone_info.cc | 602 +++++++++--------- absl/time/internal/cctz/src/time_zone_info.h | 25 +- absl/time/internal/cctz/src/time_zone_libc.cc | 10 +- absl/time/internal/cctz/src/time_zone_libc.h | 8 +- .../cctz/src/time_zone_lookup_test.cc | 4 + 11 files changed, 361 insertions(+), 326 deletions(-) diff --git a/absl/time/internal/cctz/include/cctz/time_zone.h b/absl/time/internal/cctz/include/cctz/time_zone.h index 6e382dc6c9f..b2b0cf6f511 100644 --- a/absl/time/internal/cctz/include/cctz/time_zone.h +++ b/absl/time/internal/cctz/include/cctz/time_zone.h @@ -23,6 +23,7 @@ #include #include #include +#include // NOLINT: We use std::ratio in this header #include #include diff --git a/absl/time/internal/cctz/src/time_zone_format.cc b/absl/time/internal/cctz/src/time_zone_format.cc index 0bea75a4436..96268a830b0 100644 --- a/absl/time/internal/cctz/src/time_zone_format.cc +++ b/absl/time/internal/cctz/src/time_zone_format.cc @@ -14,15 +14,13 @@ #if !defined(HAS_STRPTIME) #if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__VXWORKS__) -#define HAS_STRPTIME \ - 1 // assume everyone has strptime() except windows - // and VxWorks +#define HAS_STRPTIME 1 // Assume everyone else has strptime(). #endif #endif #if defined(HAS_STRPTIME) && HAS_STRPTIME #if !defined(_XOPEN_SOURCE) && !defined(__OpenBSD__) -#define _XOPEN_SOURCE // Definedness suffices for strptime. +#define _XOPEN_SOURCE // Definedness suffices for strptime(). #endif #endif diff --git a/absl/time/internal/cctz/src/time_zone_if.cc b/absl/time/internal/cctz/src/time_zone_if.cc index 1d44dde7f28..0e65cd9e73a 100644 --- a/absl/time/internal/cctz/src/time_zone_if.cc +++ b/absl/time/internal/cctz/src/time_zone_if.cc @@ -23,19 +23,19 @@ ABSL_NAMESPACE_BEGIN namespace time_internal { namespace cctz { -std::unique_ptr TimeZoneIf::Load(const std::string& name) { +std::unique_ptr TimeZoneIf::UTC() { return TimeZoneInfo::UTC(); } + +std::unique_ptr TimeZoneIf::Make(const std::string& name) { // Support "libc:localtime" and "libc:*" to access the legacy // localtime and UTC support respectively from the C library. // NOTE: The "libc:*" zones are internal, test-only interfaces, and // are subject to change/removal without notice. Do not use them. if (name.compare(0, 5, "libc:") == 0) { - return std::unique_ptr(new TimeZoneLibC(name.substr(5))); + return TimeZoneLibC::Make(name.substr(5)); } - // Otherwise use the "zoneinfo" implementation by default. - std::unique_ptr tz(new TimeZoneInfo); - if (!tz->Load(name)) tz.reset(); - return std::unique_ptr(tz.release()); + // Otherwise use the "zoneinfo" implementation. + return TimeZoneInfo::Make(name); } // Defined out-of-line to avoid emitting a weak vtable in all TUs. diff --git a/absl/time/internal/cctz/src/time_zone_if.h b/absl/time/internal/cctz/src/time_zone_if.h index 7d3e42d3cd5..bec9beb5cb7 100644 --- a/absl/time/internal/cctz/src/time_zone_if.h +++ b/absl/time/internal/cctz/src/time_zone_if.h @@ -33,8 +33,9 @@ namespace cctz { // Subclasses implement the functions for civil-time conversions in the zone. class TimeZoneIf { public: - // A factory function for TimeZoneIf implementations. - static std::unique_ptr Load(const std::string& name); + // Factory functions for TimeZoneIf implementations. + static std::unique_ptr UTC(); // never fails + static std::unique_ptr Make(const std::string& name); virtual ~TimeZoneIf(); @@ -51,7 +52,9 @@ class TimeZoneIf { virtual std::string Description() const = 0; protected: - TimeZoneIf() {} + TimeZoneIf() = default; + TimeZoneIf(const TimeZoneIf&) = delete; + TimeZoneIf& operator=(const TimeZoneIf&) = delete; }; // Convert between time_point and a count of seconds since the diff --git a/absl/time/internal/cctz/src/time_zone_impl.cc b/absl/time/internal/cctz/src/time_zone_impl.cc index f34e3aec84d..aadbb77da28 100644 --- a/absl/time/internal/cctz/src/time_zone_impl.cc +++ b/absl/time/internal/cctz/src/time_zone_impl.cc @@ -99,11 +99,13 @@ void time_zone::Impl::ClearTimeZoneMapTestOnly() { } } +time_zone::Impl::Impl() : name_("UTC"), zone_(TimeZoneIf::UTC()) {} + time_zone::Impl::Impl(const std::string& name) - : name_(name), zone_(TimeZoneIf::Load(name_)) {} + : name_(name), zone_(TimeZoneIf::Make(name_)) {} const time_zone::Impl* time_zone::Impl::UTCImpl() { - static const Impl* utc_impl = new Impl("UTC"); // never fails + static const Impl* utc_impl = new Impl; return utc_impl; } diff --git a/absl/time/internal/cctz/src/time_zone_impl.h b/absl/time/internal/cctz/src/time_zone_impl.h index 7d747ba9661..8308a3b49e0 100644 --- a/absl/time/internal/cctz/src/time_zone_impl.h +++ b/absl/time/internal/cctz/src/time_zone_impl.h @@ -78,7 +78,11 @@ class time_zone::Impl { std::string Description() const { return zone_->Description(); } private: + Impl(); explicit Impl(const std::string& name); + Impl(const Impl&) = delete; + Impl& operator=(const Impl&) = delete; + static const Impl* UTCImpl(); const std::string name_; diff --git a/absl/time/internal/cctz/src/time_zone_info.cc b/absl/time/internal/cctz/src/time_zone_info.cc index 787426f755d..4bc7b50bb66 100644 --- a/absl/time/internal/cctz/src/time_zone_info.cc +++ b/absl/time/internal/cctz/src/time_zone_info.cc @@ -134,6 +134,49 @@ std::int_fast64_t Decode64(const char* cp) { return static_cast(v - s64maxU - 1) - s64max - 1; } +struct Header { // counts of: + std::size_t timecnt; // transition times + std::size_t typecnt; // transition types + std::size_t charcnt; // zone abbreviation characters + std::size_t leapcnt; // leap seconds (we expect none) + std::size_t ttisstdcnt; // UTC/local indicators (unused) + std::size_t ttisutcnt; // standard/wall indicators (unused) + + bool Build(const tzhead& tzh); + std::size_t DataLength(std::size_t time_len) const; +}; + +// Builds the in-memory header using the raw bytes from the file. +bool Header::Build(const tzhead& tzh) { + std::int_fast32_t v; + if ((v = Decode32(tzh.tzh_timecnt)) < 0) return false; + timecnt = static_cast(v); + if ((v = Decode32(tzh.tzh_typecnt)) < 0) return false; + typecnt = static_cast(v); + if ((v = Decode32(tzh.tzh_charcnt)) < 0) return false; + charcnt = static_cast(v); + if ((v = Decode32(tzh.tzh_leapcnt)) < 0) return false; + leapcnt = static_cast(v); + if ((v = Decode32(tzh.tzh_ttisstdcnt)) < 0) return false; + ttisstdcnt = static_cast(v); + if ((v = Decode32(tzh.tzh_ttisutcnt)) < 0) return false; + ttisutcnt = static_cast(v); + return true; +} + +// How many bytes of data are associated with this header. The result +// depends upon whether this is a section with 4-byte or 8-byte times. +std::size_t Header::DataLength(std::size_t time_len) const { + std::size_t len = 0; + len += (time_len + 1) * timecnt; // unix_time + type_index + len += (4 + 1 + 1) * typecnt; // utc_offset + is_dst + abbr_index + len += 1 * charcnt; // abbreviations + len += (time_len + 4) * leapcnt; // leap-time + TAI-UTC + len += 1 * ttisstdcnt; // UTC/local indicators + len += 1 * ttisutcnt; // standard/wall indicators + return len; +} + // Does the rule for future transitions call for year-round daylight time? // See tz/zic.c:stringzone() for the details on how such rules are encoded. bool AllYearDST(const PosixTimeZone& posix) { @@ -217,98 +260,6 @@ inline civil_second YearShift(const civil_second& cs, year_t shift) { } // namespace -// What (no leap-seconds) UTC+seconds zoneinfo would look like. -bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) { - transition_types_.resize(1); - TransitionType& tt(transition_types_.back()); - tt.utc_offset = static_cast(offset.count()); - tt.is_dst = false; - tt.abbr_index = 0; - - // We temporarily add some redundant, contemporary (2015 through 2025) - // transitions for performance reasons. See TimeZoneInfo::LocalTime(). - // TODO: Fix the performance issue and remove the extra transitions. - transitions_.clear(); - transitions_.reserve(12); - for (const std::int_fast64_t unix_time : { - -(1LL << 59), // a "first half" transition - 1420070400LL, // 2015-01-01T00:00:00+00:00 - 1451606400LL, // 2016-01-01T00:00:00+00:00 - 1483228800LL, // 2017-01-01T00:00:00+00:00 - 1514764800LL, // 2018-01-01T00:00:00+00:00 - 1546300800LL, // 2019-01-01T00:00:00+00:00 - 1577836800LL, // 2020-01-01T00:00:00+00:00 - 1609459200LL, // 2021-01-01T00:00:00+00:00 - 1640995200LL, // 2022-01-01T00:00:00+00:00 - 1672531200LL, // 2023-01-01T00:00:00+00:00 - 1704067200LL, // 2024-01-01T00:00:00+00:00 - 1735689600LL, // 2025-01-01T00:00:00+00:00 - }) { - Transition& tr(*transitions_.emplace(transitions_.end())); - tr.unix_time = unix_time; - tr.type_index = 0; - tr.civil_sec = LocalTime(tr.unix_time, tt).cs; - tr.prev_civil_sec = tr.civil_sec - 1; - } - - default_transition_type_ = 0; - abbreviations_ = FixedOffsetToAbbr(offset); - abbreviations_.append(1, '\0'); - future_spec_.clear(); // never needed for a fixed-offset zone - extended_ = false; - - tt.civil_max = LocalTime(seconds::max().count(), tt).cs; - tt.civil_min = LocalTime(seconds::min().count(), tt).cs; - - transitions_.shrink_to_fit(); - return true; -} - -// Builds the in-memory header using the raw bytes from the file. -bool TimeZoneInfo::Header::Build(const tzhead& tzh) { - std::int_fast32_t v; - if ((v = Decode32(tzh.tzh_timecnt)) < 0) return false; - timecnt = static_cast(v); - if ((v = Decode32(tzh.tzh_typecnt)) < 0) return false; - typecnt = static_cast(v); - if ((v = Decode32(tzh.tzh_charcnt)) < 0) return false; - charcnt = static_cast(v); - if ((v = Decode32(tzh.tzh_leapcnt)) < 0) return false; - leapcnt = static_cast(v); - if ((v = Decode32(tzh.tzh_ttisstdcnt)) < 0) return false; - ttisstdcnt = static_cast(v); - if ((v = Decode32(tzh.tzh_ttisutcnt)) < 0) return false; - ttisutcnt = static_cast(v); - return true; -} - -// How many bytes of data are associated with this header. The result -// depends upon whether this is a section with 4-byte or 8-byte times. -std::size_t TimeZoneInfo::Header::DataLength(std::size_t time_len) const { - std::size_t len = 0; - len += (time_len + 1) * timecnt; // unix_time + type_index - len += (4 + 1 + 1) * typecnt; // utc_offset + is_dst + abbr_index - len += 1 * charcnt; // abbreviations - len += (time_len + 4) * leapcnt; // leap-time + TAI-UTC - len += 1 * ttisstdcnt; // UTC/local indicators - len += 1 * ttisutcnt; // standard/wall indicators - return len; -} - -// zic(8) can generate no-op transitions when a zone changes rules at an -// instant when there is actually no discontinuity. So we check whether -// two transitions have equivalent types (same offset/is_dst/abbr). -bool TimeZoneInfo::EquivTransitions(std::uint_fast8_t tt1_index, - std::uint_fast8_t tt2_index) const { - if (tt1_index == tt2_index) return true; - const TransitionType& tt1(transition_types_[tt1_index]); - const TransitionType& tt2(transition_types_[tt2_index]); - if (tt1.utc_offset != tt2.utc_offset) return false; - if (tt1.is_dst != tt2.is_dst) return false; - if (tt1.abbr_index != tt2.abbr_index) return false; - return true; -} - // Find/make a transition type with these attributes. bool TimeZoneInfo::GetTransitionType(std::int_fast32_t utc_offset, bool is_dst, const std::string& abbr, @@ -341,6 +292,20 @@ bool TimeZoneInfo::GetTransitionType(std::int_fast32_t utc_offset, bool is_dst, return true; } +// zic(8) can generate no-op transitions when a zone changes rules at an +// instant when there is actually no discontinuity. So we check whether +// two transitions have equivalent types (same offset/is_dst/abbr). +bool TimeZoneInfo::EquivTransitions(std::uint_fast8_t tt1_index, + std::uint_fast8_t tt2_index) const { + if (tt1_index == tt2_index) return true; + const TransitionType& tt1(transition_types_[tt1_index]); + const TransitionType& tt2(transition_types_[tt2_index]); + if (tt1.utc_offset != tt2.utc_offset) return false; + if (tt1.is_dst != tt2.is_dst) return false; + if (tt1.abbr_index != tt2.abbr_index) return false; + return true; +} + // Use the POSIX-TZ-environment-variable-style string to handle times // in years after the last transition stored in the zoneinfo data. bool TimeZoneInfo::ExtendTransitions() { @@ -394,206 +359,19 @@ bool TimeZoneInfo::ExtendTransitions() { auto dst_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_start); auto std_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_end); dst.unix_time = jan1_time + dst_trans_off - posix.std_offset; - std.unix_time = jan1_time + std_trans_off - posix.dst_offset; - const auto* ta = dst.unix_time < std.unix_time ? &dst : &std; - const auto* tb = dst.unix_time < std.unix_time ? &std : &dst; - if (last_time < tb->unix_time) { - if (last_time < ta->unix_time) transitions_.push_back(*ta); - transitions_.push_back(*tb); - } - if (last_year_ == limit) break; - jan1_time += kSecsPerYear[leap_year]; - jan1_weekday = (jan1_weekday + kDaysPerYear[leap_year]) % 7; - leap_year = !leap_year && IsLeap(last_year_ + 1); - } - - return true; -} - -bool TimeZoneInfo::Load(ZoneInfoSource* zip) { - // Read and validate the header. - tzhead tzh; - if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false; - if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0) - return false; - Header hdr; - if (!hdr.Build(tzh)) return false; - std::size_t time_len = 4; - if (tzh.tzh_version[0] != '\0') { - // Skip the 4-byte data. - if (zip->Skip(hdr.DataLength(time_len)) != 0) return false; - // Read and validate the header for the 8-byte data. - if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false; - if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0) - return false; - if (tzh.tzh_version[0] == '\0') return false; - if (!hdr.Build(tzh)) return false; - time_len = 8; - } - if (hdr.typecnt == 0) return false; - if (hdr.leapcnt != 0) { - // This code assumes 60-second minutes so we do not want - // the leap-second encoded zoneinfo. We could reverse the - // compensation, but the "right" encoding is rarely used - // so currently we simply reject such data. - return false; - } - if (hdr.ttisstdcnt != 0 && hdr.ttisstdcnt != hdr.typecnt) return false; - if (hdr.ttisutcnt != 0 && hdr.ttisutcnt != hdr.typecnt) return false; - - // Read the data into a local buffer. - std::size_t len = hdr.DataLength(time_len); - std::vector tbuf(len); - if (zip->Read(tbuf.data(), len) != len) return false; - const char* bp = tbuf.data(); - - // Decode and validate the transitions. - transitions_.reserve(hdr.timecnt + 2); - transitions_.resize(hdr.timecnt); - for (std::size_t i = 0; i != hdr.timecnt; ++i) { - transitions_[i].unix_time = (time_len == 4) ? Decode32(bp) : Decode64(bp); - bp += time_len; - if (i != 0) { - // Check that the transitions are ordered by time (as zic guarantees). - if (!Transition::ByUnixTime()(transitions_[i - 1], transitions_[i])) - return false; // out of order - } - } - bool seen_type_0 = false; - for (std::size_t i = 0; i != hdr.timecnt; ++i) { - transitions_[i].type_index = Decode8(bp++); - if (transitions_[i].type_index >= hdr.typecnt) return false; - if (transitions_[i].type_index == 0) seen_type_0 = true; - } - - // Decode and validate the transition types. - transition_types_.reserve(hdr.typecnt + 2); - transition_types_.resize(hdr.typecnt); - for (std::size_t i = 0; i != hdr.typecnt; ++i) { - transition_types_[i].utc_offset = - static_cast(Decode32(bp)); - if (transition_types_[i].utc_offset >= kSecsPerDay || - transition_types_[i].utc_offset <= -kSecsPerDay) - return false; - bp += 4; - transition_types_[i].is_dst = (Decode8(bp++) != 0); - transition_types_[i].abbr_index = Decode8(bp++); - if (transition_types_[i].abbr_index >= hdr.charcnt) return false; - } - - // Determine the before-first-transition type. - default_transition_type_ = 0; - if (seen_type_0 && hdr.timecnt != 0) { - std::uint_fast8_t index = 0; - if (transition_types_[0].is_dst) { - index = transitions_[0].type_index; - while (index != 0 && transition_types_[index].is_dst) --index; - } - while (index != hdr.typecnt && transition_types_[index].is_dst) ++index; - if (index != hdr.typecnt) default_transition_type_ = index; - } - - // Copy all the abbreviations. - abbreviations_.reserve(hdr.charcnt + 10); - abbreviations_.assign(bp, hdr.charcnt); - bp += hdr.charcnt; - - // Skip the unused portions. We've already dispensed with leap-second - // encoded zoneinfo. The ttisstd/ttisgmt indicators only apply when - // interpreting a POSIX spec that does not include start/end rules, and - // that isn't the case here (see "zic -p"). - bp += (time_len + 4) * hdr.leapcnt; // leap-time + TAI-UTC - bp += 1 * hdr.ttisstdcnt; // UTC/local indicators - bp += 1 * hdr.ttisutcnt; // standard/wall indicators - assert(bp == tbuf.data() + tbuf.size()); - - future_spec_.clear(); - if (tzh.tzh_version[0] != '\0') { - // Snarf up the NL-enclosed future POSIX spec. Note - // that version '3' files utilize an extended format. - auto get_char = [](ZoneInfoSource* azip) -> int { - unsigned char ch; // all non-EOF results are positive - return (azip->Read(&ch, 1) == 1) ? ch : EOF; - }; - if (get_char(zip) != '\n') return false; - for (int c = get_char(zip); c != '\n'; c = get_char(zip)) { - if (c == EOF) return false; - future_spec_.push_back(static_cast(c)); - } - } - - // We don't check for EOF so that we're forwards compatible. - - // If we did not find version information during the standard loading - // process (as of tzh_version '3' that is unsupported), then ask the - // ZoneInfoSource for any out-of-bound version string it may be privy to. - if (version_.empty()) { - version_ = zip->Version(); - } - - // Trim redundant transitions. zic may have added these to work around - // differences between the glibc and reference implementations (see - // zic.c:dontmerge) or to avoid bugs in old readers. For us, they just - // get in the way when we do future_spec_ extension. - while (hdr.timecnt > 1) { - if (!EquivTransitions(transitions_[hdr.timecnt - 1].type_index, - transitions_[hdr.timecnt - 2].type_index)) { - break; - } - hdr.timecnt -= 1; - } - transitions_.resize(hdr.timecnt); - - // Ensure that there is always a transition in the first half of the - // time line (the second half is handled below) so that the signed - // difference between a civil_second and the civil_second of its - // previous transition is always representable, without overflow. - if (transitions_.empty() || transitions_.front().unix_time >= 0) { - Transition& tr(*transitions_.emplace(transitions_.begin())); - tr.unix_time = -(1LL << 59); // -18267312070-10-26T17:01:52+00:00 - tr.type_index = default_transition_type_; - } - - // Extend the transitions using the future specification. - if (!ExtendTransitions()) return false; - - // Ensure that there is always a transition in the second half of the - // time line (the first half is handled above) so that the signed - // difference between a civil_second and the civil_second of its - // previous transition is always representable, without overflow. - const Transition& last(transitions_.back()); - if (last.unix_time < 0) { - const std::uint_fast8_t type_index = last.type_index; - Transition& tr(*transitions_.emplace(transitions_.end())); - tr.unix_time = 2147483647; // 2038-01-19T03:14:07+00:00 - tr.type_index = type_index; - } - - // Compute the local civil time for each transition and the preceding - // second. These will be used for reverse conversions in MakeTime(). - const TransitionType* ttp = &transition_types_[default_transition_type_]; - for (std::size_t i = 0; i != transitions_.size(); ++i) { - Transition& tr(transitions_[i]); - tr.prev_civil_sec = LocalTime(tr.unix_time, *ttp).cs - 1; - ttp = &transition_types_[tr.type_index]; - tr.civil_sec = LocalTime(tr.unix_time, *ttp).cs; - if (i != 0) { - // Check that the transitions are ordered by civil time. Essentially - // this means that an offset change cannot cross another such change. - // No one does this in practice, and we depend on it in MakeTime(). - if (!Transition::ByCivilTime()(transitions_[i - 1], tr)) - return false; // out of order + std.unix_time = jan1_time + std_trans_off - posix.dst_offset; + const auto* ta = dst.unix_time < std.unix_time ? &dst : &std; + const auto* tb = dst.unix_time < std.unix_time ? &std : &dst; + if (last_time < tb->unix_time) { + if (last_time < ta->unix_time) transitions_.push_back(*ta); + transitions_.push_back(*tb); } + if (last_year_ == limit) break; + jan1_time += kSecsPerYear[leap_year]; + jan1_weekday = (jan1_weekday + kDaysPerYear[leap_year]) % 7; + leap_year = !leap_year && IsLeap(last_year_ + 1); } - // Compute the maximum/minimum civil times that can be converted to a - // time_point for each of the zone's transition types. - for (auto& tt : transition_types_) { - tt.civil_max = LocalTime(seconds::max().count(), tt).cs; - tt.civil_min = LocalTime(seconds::min().count(), tt).cs; - } - - transitions_.shrink_to_fit(); return true; } @@ -795,6 +573,240 @@ std::unique_ptr FuchsiaZoneInfoSource::Open( } // namespace +// What (no leap-seconds) UTC+seconds zoneinfo would look like. +bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) { + transition_types_.resize(1); + TransitionType& tt(transition_types_.back()); + tt.utc_offset = static_cast(offset.count()); + tt.is_dst = false; + tt.abbr_index = 0; + + // We temporarily add some redundant, contemporary (2015 through 2025) + // transitions for performance reasons. See TimeZoneInfo::LocalTime(). + // TODO: Fix the performance issue and remove the extra transitions. + transitions_.clear(); + transitions_.reserve(12); + for (const std::int_fast64_t unix_time : { + -(1LL << 59), // a "first half" transition + 1420070400LL, // 2015-01-01T00:00:00+00:00 + 1451606400LL, // 2016-01-01T00:00:00+00:00 + 1483228800LL, // 2017-01-01T00:00:00+00:00 + 1514764800LL, // 2018-01-01T00:00:00+00:00 + 1546300800LL, // 2019-01-01T00:00:00+00:00 + 1577836800LL, // 2020-01-01T00:00:00+00:00 + 1609459200LL, // 2021-01-01T00:00:00+00:00 + 1640995200LL, // 2022-01-01T00:00:00+00:00 + 1672531200LL, // 2023-01-01T00:00:00+00:00 + 1704067200LL, // 2024-01-01T00:00:00+00:00 + 1735689600LL, // 2025-01-01T00:00:00+00:00 + }) { + Transition& tr(*transitions_.emplace(transitions_.end())); + tr.unix_time = unix_time; + tr.type_index = 0; + tr.civil_sec = LocalTime(tr.unix_time, tt).cs; + tr.prev_civil_sec = tr.civil_sec - 1; + } + + default_transition_type_ = 0; + abbreviations_ = FixedOffsetToAbbr(offset); + abbreviations_.append(1, '\0'); + future_spec_.clear(); // never needed for a fixed-offset zone + extended_ = false; + + tt.civil_max = LocalTime(seconds::max().count(), tt).cs; + tt.civil_min = LocalTime(seconds::min().count(), tt).cs; + + transitions_.shrink_to_fit(); + return true; +} + +bool TimeZoneInfo::Load(ZoneInfoSource* zip) { + // Read and validate the header. + tzhead tzh; + if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false; + if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0) + return false; + Header hdr; + if (!hdr.Build(tzh)) return false; + std::size_t time_len = 4; + if (tzh.tzh_version[0] != '\0') { + // Skip the 4-byte data. + if (zip->Skip(hdr.DataLength(time_len)) != 0) return false; + // Read and validate the header for the 8-byte data. + if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false; + if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0) + return false; + if (tzh.tzh_version[0] == '\0') return false; + if (!hdr.Build(tzh)) return false; + time_len = 8; + } + if (hdr.typecnt == 0) return false; + if (hdr.leapcnt != 0) { + // This code assumes 60-second minutes so we do not want + // the leap-second encoded zoneinfo. We could reverse the + // compensation, but the "right" encoding is rarely used + // so currently we simply reject such data. + return false; + } + if (hdr.ttisstdcnt != 0 && hdr.ttisstdcnt != hdr.typecnt) return false; + if (hdr.ttisutcnt != 0 && hdr.ttisutcnt != hdr.typecnt) return false; + + // Read the data into a local buffer. + std::size_t len = hdr.DataLength(time_len); + std::vector tbuf(len); + if (zip->Read(tbuf.data(), len) != len) return false; + const char* bp = tbuf.data(); + + // Decode and validate the transitions. + transitions_.reserve(hdr.timecnt + 2); + transitions_.resize(hdr.timecnt); + for (std::size_t i = 0; i != hdr.timecnt; ++i) { + transitions_[i].unix_time = (time_len == 4) ? Decode32(bp) : Decode64(bp); + bp += time_len; + if (i != 0) { + // Check that the transitions are ordered by time (as zic guarantees). + if (!Transition::ByUnixTime()(transitions_[i - 1], transitions_[i])) + return false; // out of order + } + } + bool seen_type_0 = false; + for (std::size_t i = 0; i != hdr.timecnt; ++i) { + transitions_[i].type_index = Decode8(bp++); + if (transitions_[i].type_index >= hdr.typecnt) return false; + if (transitions_[i].type_index == 0) seen_type_0 = true; + } + + // Decode and validate the transition types. + transition_types_.reserve(hdr.typecnt + 2); + transition_types_.resize(hdr.typecnt); + for (std::size_t i = 0; i != hdr.typecnt; ++i) { + transition_types_[i].utc_offset = + static_cast(Decode32(bp)); + if (transition_types_[i].utc_offset >= kSecsPerDay || + transition_types_[i].utc_offset <= -kSecsPerDay) + return false; + bp += 4; + transition_types_[i].is_dst = (Decode8(bp++) != 0); + transition_types_[i].abbr_index = Decode8(bp++); + if (transition_types_[i].abbr_index >= hdr.charcnt) return false; + } + + // Determine the before-first-transition type. + default_transition_type_ = 0; + if (seen_type_0 && hdr.timecnt != 0) { + std::uint_fast8_t index = 0; + if (transition_types_[0].is_dst) { + index = transitions_[0].type_index; + while (index != 0 && transition_types_[index].is_dst) --index; + } + while (index != hdr.typecnt && transition_types_[index].is_dst) ++index; + if (index != hdr.typecnt) default_transition_type_ = index; + } + + // Copy all the abbreviations. + abbreviations_.reserve(hdr.charcnt + 10); + abbreviations_.assign(bp, hdr.charcnt); + bp += hdr.charcnt; + + // Skip the unused portions. We've already dispensed with leap-second + // encoded zoneinfo. The ttisstd/ttisgmt indicators only apply when + // interpreting a POSIX spec that does not include start/end rules, and + // that isn't the case here (see "zic -p"). + bp += (time_len + 4) * hdr.leapcnt; // leap-time + TAI-UTC + bp += 1 * hdr.ttisstdcnt; // UTC/local indicators + bp += 1 * hdr.ttisutcnt; // standard/wall indicators + assert(bp == tbuf.data() + tbuf.size()); + + future_spec_.clear(); + if (tzh.tzh_version[0] != '\0') { + // Snarf up the NL-enclosed future POSIX spec. Note + // that version '3' files utilize an extended format. + auto get_char = [](ZoneInfoSource* azip) -> int { + unsigned char ch; // all non-EOF results are positive + return (azip->Read(&ch, 1) == 1) ? ch : EOF; + }; + if (get_char(zip) != '\n') return false; + for (int c = get_char(zip); c != '\n'; c = get_char(zip)) { + if (c == EOF) return false; + future_spec_.push_back(static_cast(c)); + } + } + + // We don't check for EOF so that we're forwards compatible. + + // If we did not find version information during the standard loading + // process (as of tzh_version '3' that is unsupported), then ask the + // ZoneInfoSource for any out-of-bound version string it may be privy to. + if (version_.empty()) { + version_ = zip->Version(); + } + + // Trim redundant transitions. zic may have added these to work around + // differences between the glibc and reference implementations (see + // zic.c:dontmerge) or to avoid bugs in old readers. For us, they just + // get in the way when we do future_spec_ extension. + while (hdr.timecnt > 1) { + if (!EquivTransitions(transitions_[hdr.timecnt - 1].type_index, + transitions_[hdr.timecnt - 2].type_index)) { + break; + } + hdr.timecnt -= 1; + } + transitions_.resize(hdr.timecnt); + + // Ensure that there is always a transition in the first half of the + // time line (the second half is handled below) so that the signed + // difference between a civil_second and the civil_second of its + // previous transition is always representable, without overflow. + if (transitions_.empty() || transitions_.front().unix_time >= 0) { + Transition& tr(*transitions_.emplace(transitions_.begin())); + tr.unix_time = -(1LL << 59); // -18267312070-10-26T17:01:52+00:00 + tr.type_index = default_transition_type_; + } + + // Extend the transitions using the future specification. + if (!ExtendTransitions()) return false; + + // Ensure that there is always a transition in the second half of the + // time line (the first half is handled above) so that the signed + // difference between a civil_second and the civil_second of its + // previous transition is always representable, without overflow. + const Transition& last(transitions_.back()); + if (last.unix_time < 0) { + const std::uint_fast8_t type_index = last.type_index; + Transition& tr(*transitions_.emplace(transitions_.end())); + tr.unix_time = 2147483647; // 2038-01-19T03:14:07+00:00 + tr.type_index = type_index; + } + + // Compute the local civil time for each transition and the preceding + // second. These will be used for reverse conversions in MakeTime(). + const TransitionType* ttp = &transition_types_[default_transition_type_]; + for (std::size_t i = 0; i != transitions_.size(); ++i) { + Transition& tr(transitions_[i]); + tr.prev_civil_sec = LocalTime(tr.unix_time, *ttp).cs - 1; + ttp = &transition_types_[tr.type_index]; + tr.civil_sec = LocalTime(tr.unix_time, *ttp).cs; + if (i != 0) { + // Check that the transitions are ordered by civil time. Essentially + // this means that an offset change cannot cross another such change. + // No one does this in practice, and we depend on it in MakeTime(). + if (!Transition::ByCivilTime()(transitions_[i - 1], tr)) + return false; // out of order + } + } + + // Compute the maximum/minimum civil times that can be converted to a + // time_point for each of the zone's transition types. + for (auto& tt : transition_types_) { + tt.civil_max = LocalTime(seconds::max().count(), tt).cs; + tt.civil_min = LocalTime(seconds::min().count(), tt).cs; + } + + transitions_.shrink_to_fit(); + return true; +} + bool TimeZoneInfo::Load(const std::string& name) { // We can ensure that the loading of UTC or any other fixed-offset // zone never fails because the simple, fixed-offset state can be @@ -816,6 +828,18 @@ bool TimeZoneInfo::Load(const std::string& name) { return zip != nullptr && Load(zip.get()); } +std::unique_ptr TimeZoneInfo::UTC() { + auto tz = std::unique_ptr(new TimeZoneInfo); + tz->ResetToBuiltinUTC(seconds::zero()); + return tz; +} + +std::unique_ptr TimeZoneInfo::Make(const std::string& name) { + auto tz = std::unique_ptr(new TimeZoneInfo); + if (!tz->Load(name)) tz.reset(); // fallback to UTC + return tz; +} + // BreakTime() translation for a particular transition type. time_zone::absolute_lookup TimeZoneInfo::LocalTime( std::int_fast64_t unix_time, const TransitionType& tt) const { diff --git a/absl/time/internal/cctz/src/time_zone_info.h b/absl/time/internal/cctz/src/time_zone_info.h index 2467ff559d3..689df6f9c0e 100644 --- a/absl/time/internal/cctz/src/time_zone_info.h +++ b/absl/time/internal/cctz/src/time_zone_info.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -64,12 +65,9 @@ struct TransitionType { // A time zone backed by the IANA Time Zone Database (zoneinfo). class TimeZoneInfo : public TimeZoneIf { public: - TimeZoneInfo() = default; - TimeZoneInfo(const TimeZoneInfo&) = delete; - TimeZoneInfo& operator=(const TimeZoneInfo&) = delete; - - // Loads the zoneinfo for the given name, returning true if successful. - bool Load(const std::string& name); + // Factories. + static std::unique_ptr UTC(); // never fails + static std::unique_ptr Make(const std::string& name); // TimeZoneIf implementations. time_zone::absolute_lookup BreakTime( @@ -83,17 +81,9 @@ class TimeZoneInfo : public TimeZoneIf { std::string Description() const override; private: - struct Header { // counts of: - std::size_t timecnt; // transition times - std::size_t typecnt; // transition types - std::size_t charcnt; // zone abbreviation characters - std::size_t leapcnt; // leap seconds (we expect none) - std::size_t ttisstdcnt; // UTC/local indicators (unused) - std::size_t ttisutcnt; // standard/wall indicators (unused) - - bool Build(const tzhead& tzh); - std::size_t DataLength(std::size_t time_len) const; - }; + TimeZoneInfo() = default; + TimeZoneInfo(const TimeZoneInfo&) = delete; + TimeZoneInfo& operator=(const TimeZoneInfo&) = delete; bool GetTransitionType(std::int_fast32_t utc_offset, bool is_dst, const std::string& abbr, std::uint_least8_t* index); @@ -102,6 +92,7 @@ class TimeZoneInfo : public TimeZoneIf { bool ExtendTransitions(); bool ResetToBuiltinUTC(const seconds& offset); + bool Load(const std::string& name); bool Load(ZoneInfoSource* zip); // Helpers for BreakTime() and MakeTime(). diff --git a/absl/time/internal/cctz/src/time_zone_libc.cc b/absl/time/internal/cctz/src/time_zone_libc.cc index e503a8584bd..d01461222e9 100644 --- a/absl/time/internal/cctz/src/time_zone_libc.cc +++ b/absl/time/internal/cctz/src/time_zone_libc.cc @@ -62,7 +62,7 @@ auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) { } #elif defined(__native_client__) || defined(__myriad2__) || \ defined(__EMSCRIPTEN__) -// Uses the globals: 'timezone' and 'tzname'. +// Uses the globals: '_timezone' and 'tzname'. auto tm_gmtoff(const std::tm& tm) -> decltype(_timezone + 0) { const bool is_dst = tm.tm_isdst > 0; return _timezone + (is_dst ? 60 * 60 : 0); @@ -193,8 +193,9 @@ std::time_t find_trans(std::time_t lo, std::time_t hi, tm_gmtoff_t offset) { } // namespace -TimeZoneLibC::TimeZoneLibC(const std::string& name) - : local_(name == "localtime") {} +std::unique_ptr TimeZoneLibC::Make(const std::string& name) { + return std::unique_ptr(new TimeZoneLibC(name)); +} time_zone::absolute_lookup TimeZoneLibC::BreakTime( const time_point& tp) const { @@ -323,6 +324,9 @@ std::string TimeZoneLibC::Description() const { return local_ ? "localtime" : "UTC"; } +TimeZoneLibC::TimeZoneLibC(const std::string& name) + : local_(name == "localtime") {} + } // namespace cctz } // namespace time_internal ABSL_NAMESPACE_END diff --git a/absl/time/internal/cctz/src/time_zone_libc.h b/absl/time/internal/cctz/src/time_zone_libc.h index 1da9039a15e..2d6fa686cf8 100644 --- a/absl/time/internal/cctz/src/time_zone_libc.h +++ b/absl/time/internal/cctz/src/time_zone_libc.h @@ -27,10 +27,10 @@ namespace cctz { // A time zone backed by gmtime_r(3), localtime_r(3), and mktime(3), // and which therefore only supports UTC and the local time zone. -// TODO: Add support for fixed offsets from UTC. class TimeZoneLibC : public TimeZoneIf { public: - explicit TimeZoneLibC(const std::string& name); + // Factory. + static std::unique_ptr Make(const std::string& name); // TimeZoneIf implementations. time_zone::absolute_lookup BreakTime( @@ -44,6 +44,10 @@ class TimeZoneLibC : public TimeZoneIf { std::string Description() const override; private: + explicit TimeZoneLibC(const std::string& name); + TimeZoneLibC(const TimeZoneLibC&) = delete; + TimeZoneLibC& operator=(const TimeZoneLibC&) = delete; + const bool local_; // localtime or UTC }; diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc index 38f10f48ecc..fc6592668fe 100644 --- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc +++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc @@ -734,6 +734,10 @@ TEST(TimeZone, UTC) { time_zone loaded_utc0; EXPECT_TRUE(load_time_zone("UTC0", &loaded_utc0)); EXPECT_EQ(loaded_utc0, utc); + + time_zone loaded_bad; + EXPECT_FALSE(load_time_zone("Invalid/TimeZone", &loaded_bad)); + EXPECT_EQ(loaded_bad, utc); } TEST(TimeZone, NamedTimeZones) { From bde85071e497254e954c27b1b81b442a441ad4b0 Mon Sep 17 00:00:00 2001 From: Andy Getzendanner Date: Wed, 28 Jun 2023 16:53:38 -0700 Subject: [PATCH 0090/1238] Wrap the Emscripten version macros into an (internal) macro blob for easier comparison. PiperOrigin-RevId: 544197983 Change-Id: I7eb39563e696d6561ad193d4d25b4161eb6419ae --- absl/base/config.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/absl/base/config.h b/absl/base/config.h index 4a167a2e1a3..6d38d3f49a8 100644 --- a/absl/base/config.h +++ b/absl/base/config.h @@ -924,4 +924,24 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #define ABSL_HAVE_CONSTANT_EVALUATED 1 #endif +// ABSL_INTERNAL_EMSCRIPTEN_VERSION combines Emscripten's three version macros +// into an integer that can be compared against. +#ifdef ABSL_INTERNAL_EMSCRIPTEN_VERSION +#error ABSL_INTERNAL_EMSCRIPTEN_VERSION cannot be directly set +#endif +#ifdef __EMSCRIPTEN__ +#include +#ifdef __EMSCRIPTEN_major__ +#if __EMSCRIPTEN_minor__ >= 1000 +#error __EMSCRIPTEN_minor__ is too big to fit in ABSL_INTERNAL_EMSCRIPTEN_VERSION +#endif +#if __EMSCRIPTEN_tiny__ >= 1000 +#error __EMSCRIPTEN_tiny__ is too big to fit in ABSL_INTERNAL_EMSCRIPTEN_VERSION +#endif +#define ABSL_INTERNAL_EMSCRIPTEN_VERSION \ + ((__EMSCRIPTEN_major__)*1000000 + (__EMSCRIPTEN_minor__)*1000 + \ + (__EMSCRIPTEN_tiny__)) +#endif +#endif + #endif // ABSL_BASE_CONFIG_H_ From 53fbcb883dc8ca208dc58a8cc168d0628fe2556f Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 29 Jun 2023 09:25:56 -0700 Subject: [PATCH 0091/1238] Introduce a kTotalMorePrecise accounting mode for Cord::EstimatedMemoryUsage(). This mode avoids double-counting blocks that a Cord references more than once; otherwise it is similar to the existing kTotal mode. There's no change to the existing kTotal or kFairShare accounting modes. PiperOrigin-RevId: 544378591 Change-Id: I7b4ae55cd93d631194e59a9cd0ff07f47611219e --- absl/strings/cord.h | 35 ++++++++++++++-- absl/strings/cord_analysis.cc | 24 ++++++++++- absl/strings/cord_analysis.h | 18 ++++++++ absl/strings/cord_test.cc | 79 +++++++++++++++++++++++++++++++++++ 4 files changed, 151 insertions(+), 5 deletions(-) diff --git a/absl/strings/cord.h b/absl/strings/cord.h index f5a2da97ca9..457ccf0609a 100644 --- a/absl/strings/cord.h +++ b/absl/strings/cord.h @@ -110,8 +110,29 @@ enum class CordMemoryAccounting { // Counts the *approximate* number of bytes held in full or in part by this // Cord (which may not remain the same between invocations). Cords that share // memory could each be "charged" independently for the same shared memory. + // See also comment on `kTotalMorePrecise` on internally shared memory. kTotal, + // Counts the *approximate* number of bytes held in full or in part by this + // Cord for the distinct memory held by this cord. This option is similar + // to `kTotal`, except that if the cord has multiple references to the same + // memory, that memory is only counted once. + // + // For example: + // absl::Cord cord; + // cord.append(some_other_cord); + // cord.append(some_other_cord); + // // Counts `some_other_cord` twice: + // cord.EstimatedMemoryUsage(kTotal); + // // Counts `some_other_cord` once: + // cord.EstimatedMemoryUsage(kTotalMorePrecise); + // + // The `kTotalMorePrecise` number is more expensive to compute as it requires + // deduplicating all memory references. Applications should prefer to use + // `kFairShare` or `kTotal` unless they really need a more precise estimate + // on "how much memory is potentially held / kept alive by this cord?" + kTotalMorePrecise, + // Counts the *approximate* number of bytes held in full or in part by this // Cord weighted by the sharing ratio of that data. For example, if some data // edge is shared by 4 different Cords, then each cord is attributed 1/4th of @@ -1273,10 +1294,16 @@ inline size_t Cord::EstimatedMemoryUsage( CordMemoryAccounting accounting_method) const { size_t result = sizeof(Cord); if (const absl::cord_internal::CordRep* rep = contents_.tree()) { - if (accounting_method == CordMemoryAccounting::kFairShare) { - result += cord_internal::GetEstimatedFairShareMemoryUsage(rep); - } else { - result += cord_internal::GetEstimatedMemoryUsage(rep); + switch (accounting_method) { + case CordMemoryAccounting::kFairShare: + result += cord_internal::GetEstimatedFairShareMemoryUsage(rep); + break; + case CordMemoryAccounting::kTotalMorePrecise: + result += cord_internal::GetMorePreciseMemoryUsage(rep); + break; + case CordMemoryAccounting::kTotal: + result += cord_internal::GetEstimatedMemoryUsage(rep); + break; } } return result; diff --git a/absl/strings/cord_analysis.cc b/absl/strings/cord_analysis.cc index 73d3c4e6ff8..e859b0db064 100644 --- a/absl/strings/cord_analysis.cc +++ b/absl/strings/cord_analysis.cc @@ -16,6 +16,7 @@ #include #include +#include #include "absl/base/attributes.h" #include "absl/base/config.h" @@ -37,7 +38,7 @@ namespace cord_internal { namespace { // Accounting mode for analyzing memory usage. -enum class Mode { kTotal, kFairShare }; +enum class Mode { kFairShare, kTotal, kTotalMorePrecise }; // CordRepRef holds a `const CordRep*` reference in rep, and depending on mode, // holds a 'fraction' representing a cumulative inverse refcount weight. @@ -62,6 +63,23 @@ struct RawUsage { void Add(size_t size, CordRepRef) { total += size; } }; +// Overloaded representation of RawUsage that tracks the set of objects +// counted, and avoids double-counting objects referenced more than once +// by the same Cord. +template <> +struct RawUsage { + size_t total = 0; + // TODO(b/289250880): Replace this with a flat_hash_set. + std::unordered_set counted; + + void Add(size_t size, CordRepRef repref) { + if (counted.find(repref.rep) == counted.end()) { + counted.insert(repref.rep); + total += size; + } + } +}; + // Returns n / refcount avoiding a div for the common refcount == 1. template double MaybeDiv(double d, refcount_t refcount) { @@ -183,6 +201,10 @@ size_t GetEstimatedFairShareMemoryUsage(const CordRep* rep) { return GetEstimatedUsage(rep); } +size_t GetMorePreciseMemoryUsage(const CordRep* rep) { + return GetEstimatedUsage(rep); +} + } // namespace cord_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/strings/cord_analysis.h b/absl/strings/cord_analysis.h index 7041ad1aa51..9b9527a57d9 100644 --- a/absl/strings/cord_analysis.h +++ b/absl/strings/cord_analysis.h @@ -30,6 +30,24 @@ namespace cord_internal { // memory could each be "charged" independently for the same shared memory. size_t GetEstimatedMemoryUsage(const CordRep* rep); +// Returns the *approximate* number of bytes held in full or in part by this +// Cord for the distinct memory held by this cord. This is similar to +// `GetEstimatedMemoryUsage()`, except that if the cord has multiple references +// to the same memory, that memory is only counted once. +// +// For example: +// absl::Cord cord; +// cord.append(some_other_cord); +// cord.append(some_other_cord); +// // Calls GetEstimatedMemoryUsage() and counts `other_cord` twice: +// cord.EstimatedMemoryUsage(kTotal); +// // Calls GetMorePreciseMemoryUsage() and counts `other_cord` once: +// cord.EstimatedMemoryUsage(kTotalMorePrecise); +// +// This is more expensive than `GetEstimatedMemoryUsage()` as it requires +// deduplicating all memory references. +size_t GetMorePreciseMemoryUsage(const CordRep* rep); + // Returns the *approximate* number of bytes held in full or in part by this // CordRep weighted by the sharing ratio of that data. For example, if some data // edge is shared by 4 different Cords, then each cord is attribute 1/4th of diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc index 55412c7f3e2..36e397ed555 100644 --- a/absl/strings/cord_test.cc +++ b/absl/strings/cord_test.cc @@ -1765,6 +1765,8 @@ TEST_P(CordTest, ExternalMemoryGet) { // of empty and inlined cords, and flat nodes. constexpr auto kFairShare = absl::CordMemoryAccounting::kFairShare; +constexpr auto kTotalMorePrecise = + absl::CordMemoryAccounting::kTotalMorePrecise; // Creates a cord of `n` `c` values, making sure no string stealing occurs. absl::Cord MakeCord(size_t n, char c) { @@ -1776,12 +1778,14 @@ TEST(CordTest, CordMemoryUsageEmpty) { absl::Cord cord; EXPECT_EQ(sizeof(absl::Cord), cord.EstimatedMemoryUsage()); EXPECT_EQ(sizeof(absl::Cord), cord.EstimatedMemoryUsage(kFairShare)); + EXPECT_EQ(sizeof(absl::Cord), cord.EstimatedMemoryUsage(kTotalMorePrecise)); } TEST(CordTest, CordMemoryUsageInlined) { absl::Cord a("hello"); EXPECT_EQ(a.EstimatedMemoryUsage(), sizeof(absl::Cord)); EXPECT_EQ(a.EstimatedMemoryUsage(kFairShare), sizeof(absl::Cord)); + EXPECT_EQ(a.EstimatedMemoryUsage(kTotalMorePrecise), sizeof(absl::Cord)); } TEST(CordTest, CordMemoryUsageExternalMemory) { @@ -1791,6 +1795,7 @@ TEST(CordTest, CordMemoryUsageExternalMemory) { sizeof(absl::Cord) + 1000 + sizeof(CordRepExternal) + sizeof(intptr_t); EXPECT_EQ(cord.EstimatedMemoryUsage(), expected); EXPECT_EQ(cord.EstimatedMemoryUsage(kFairShare), expected); + EXPECT_EQ(cord.EstimatedMemoryUsage(kTotalMorePrecise), expected); } TEST(CordTest, CordMemoryUsageFlat) { @@ -1800,6 +1805,8 @@ TEST(CordTest, CordMemoryUsageFlat) { EXPECT_EQ(cord.EstimatedMemoryUsage(), sizeof(absl::Cord) + flat_size); EXPECT_EQ(cord.EstimatedMemoryUsage(kFairShare), sizeof(absl::Cord) + flat_size); + EXPECT_EQ(cord.EstimatedMemoryUsage(kTotalMorePrecise), + sizeof(absl::Cord) + flat_size); } TEST(CordTest, CordMemoryUsageSubStringSharedFlat) { @@ -1809,6 +1816,8 @@ TEST(CordTest, CordMemoryUsageSubStringSharedFlat) { absl::Cord cord = flat.Subcord(500, 1000); EXPECT_EQ(cord.EstimatedMemoryUsage(), sizeof(absl::Cord) + sizeof(CordRepSubstring) + flat_size); + EXPECT_EQ(cord.EstimatedMemoryUsage(kTotalMorePrecise), + sizeof(absl::Cord) + sizeof(CordRepSubstring) + flat_size); EXPECT_EQ(cord.EstimatedMemoryUsage(kFairShare), sizeof(absl::Cord) + sizeof(CordRepSubstring) + flat_size / 2); } @@ -1819,6 +1828,8 @@ TEST(CordTest, CordMemoryUsageFlatShared) { const size_t flat_size = absl::CordTestPeer::Tree(cord)->flat()->AllocatedSize(); EXPECT_EQ(cord.EstimatedMemoryUsage(), sizeof(absl::Cord) + flat_size); + EXPECT_EQ(cord.EstimatedMemoryUsage(kTotalMorePrecise), + sizeof(absl::Cord) + flat_size); EXPECT_EQ(cord.EstimatedMemoryUsage(kFairShare), sizeof(absl::Cord) + flat_size / 2); } @@ -1837,6 +1848,8 @@ TEST(CordTest, CordMemoryUsageFlatHardenedAndShared) { absl::Cord cord2(cord); EXPECT_EQ(cord2.EstimatedMemoryUsage(), sizeof(absl::Cord) + sizeof(CordRepCrc) + flat_size); + EXPECT_EQ(cord2.EstimatedMemoryUsage(kTotalMorePrecise), + sizeof(absl::Cord) + sizeof(CordRepCrc) + flat_size); EXPECT_EQ(cord2.EstimatedMemoryUsage(kFairShare), sizeof(absl::Cord) + (sizeof(CordRepCrc) + flat_size / 2) / 2); } @@ -1863,6 +1876,8 @@ TEST(CordTest, CordMemoryUsageBTree) { size_t rep1_shared_size = sizeof(CordRepBtree) + flats1_size / 2; EXPECT_EQ(cord1.EstimatedMemoryUsage(), sizeof(absl::Cord) + rep1_size); + EXPECT_EQ(cord1.EstimatedMemoryUsage(kTotalMorePrecise), + sizeof(absl::Cord) + rep1_size); EXPECT_EQ(cord1.EstimatedMemoryUsage(kFairShare), sizeof(absl::Cord) + rep1_shared_size); @@ -1877,6 +1892,8 @@ TEST(CordTest, CordMemoryUsageBTree) { size_t rep2_size = sizeof(CordRepBtree) + flats2_size; EXPECT_EQ(cord2.EstimatedMemoryUsage(), sizeof(absl::Cord) + rep2_size); + EXPECT_EQ(cord2.EstimatedMemoryUsage(kTotalMorePrecise), + sizeof(absl::Cord) + rep2_size); EXPECT_EQ(cord2.EstimatedMemoryUsage(kFairShare), sizeof(absl::Cord) + rep2_size); @@ -1885,6 +1902,8 @@ TEST(CordTest, CordMemoryUsageBTree) { EXPECT_EQ(cord.EstimatedMemoryUsage(), sizeof(absl::Cord) + sizeof(CordRepBtree) + rep1_size + rep2_size); + EXPECT_EQ(cord.EstimatedMemoryUsage(kTotalMorePrecise), + sizeof(absl::Cord) + sizeof(CordRepBtree) + rep1_size + rep2_size); EXPECT_EQ(cord.EstimatedMemoryUsage(kFairShare), sizeof(absl::Cord) + sizeof(CordRepBtree) + rep1_shared_size / 2 + rep2_size); @@ -1903,6 +1922,66 @@ TEST_P(CordTest, CordMemoryUsageInlineRep) { EXPECT_EQ(c1.EstimatedMemoryUsage(), c2.EstimatedMemoryUsage()); } +TEST_P(CordTest, CordMemoryUsageTotalMorePreciseMode) { + constexpr size_t kChunkSize = 2000; + std::string tmp_str(kChunkSize, 'x'); + const absl::Cord flat(std::move(tmp_str)); + + // Construct `fragmented` with two references into the same + // underlying buffer shared with `flat`: + absl::Cord fragmented(flat); + fragmented.Append(flat); + + // Memory usage of `flat`, minus the top-level Cord object: + const size_t flat_internal_usage = + flat.EstimatedMemoryUsage() - sizeof(absl::Cord); + + // `fragmented` holds a Cord and a CordRepBtree. That tree points to two + // copies of flat's internals, which we expect to dedup: + EXPECT_EQ(fragmented.EstimatedMemoryUsage(kTotalMorePrecise), + sizeof(absl::Cord) + + sizeof(CordRepBtree) + + flat_internal_usage); + + // This is a case where kTotal produces an overestimate: + EXPECT_EQ(fragmented.EstimatedMemoryUsage(), + sizeof(absl::Cord) + + sizeof(CordRepBtree) + + 2 * flat_internal_usage); +} + +TEST_P(CordTest, CordMemoryUsageTotalMorePreciseModeWithSubstring) { + constexpr size_t kChunkSize = 2000; + std::string tmp_str(kChunkSize, 'x'); + const absl::Cord flat(std::move(tmp_str)); + + // Construct `fragmented` with two references into the same + // underlying buffer shared with `flat`. + // + // This time, each reference is through a Subcord(): + absl::Cord fragmented; + fragmented.Append(flat.Subcord(1, kChunkSize - 2)); + fragmented.Append(flat.Subcord(1, kChunkSize - 2)); + + // Memory usage of `flat`, minus the top-level Cord object: + const size_t flat_internal_usage = + flat.EstimatedMemoryUsage() - sizeof(absl::Cord); + + // `fragmented` holds a Cord and a CordRepBtree. That tree points to two + // CordRepSubstrings, each pointing at flat's internals. + EXPECT_EQ(fragmented.EstimatedMemoryUsage(kTotalMorePrecise), + sizeof(absl::Cord) + + sizeof(CordRepBtree) + + 2 * sizeof(CordRepSubstring) + + flat_internal_usage); + + // This is a case where kTotal produces an overestimate: + EXPECT_EQ(fragmented.EstimatedMemoryUsage(), + sizeof(absl::Cord) + + sizeof(CordRepBtree) + + 2 * sizeof(CordRepSubstring) + + 2 * flat_internal_usage); +} } // namespace // Regtest for 7510292 (fix a bug introduced by 7465150) From 9402bd32fbb24f762f7923ece6afe131a5b57f35 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 29 Jun 2023 10:48:43 -0700 Subject: [PATCH 0092/1238] Fix typo PiperOrigin-RevId: 544401753 Change-Id: Ie5bb48bb46c8c1bf41ef902242cefefd739e7c37 --- absl/container/internal/raw_hash_set_benchmark.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/absl/container/internal/raw_hash_set_benchmark.cc b/absl/container/internal/raw_hash_set_benchmark.cc index f77f2a7b521..a3647890c2e 100644 --- a/absl/container/internal/raw_hash_set_benchmark.cc +++ b/absl/container/internal/raw_hash_set_benchmark.cc @@ -142,7 +142,7 @@ struct string_generator { template std::string operator()(RNG& rng) const { std::string res; - res.resize(12); + res.resize(size); std::uniform_int_distribution printable_ascii(0x20, 0x7E); std::generate(res.begin(), res.end(), [&] { return printable_ascii(rng); }); return res; From 4eaff9e61e173079bcac644db18f5536cec12d8b Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 29 Jun 2023 12:58:39 -0700 Subject: [PATCH 0093/1238] Support Qualcomm Hexagon DSP targets. PiperOrigin-RevId: 544438364 Change-Id: I22d461f2d0aa8638a0e640eebecdc7e5e2b49ea3 --- absl/base/config.h | 2 ++ absl/base/internal/sysinfo.cc | 8 +++++++- absl/base/internal/thread_identity.cc | 2 +- absl/debugging/internal/elf_mem_image.h | 2 +- absl/log/internal/conditions.h | 2 +- absl/log/internal/nullstream.h | 4 +++- 6 files changed, 15 insertions(+), 5 deletions(-) diff --git a/absl/base/config.h b/absl/base/config.h index 6d38d3f49a8..e6c9d0c2f94 100644 --- a/absl/base/config.h +++ b/absl/base/config.h @@ -487,6 +487,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #elif defined(__Fuchsia__) // Signals don't exist on fuchsia. #elif defined(__native_client__) +// Signals don't exist on hexagon/QuRT +#elif defined(__hexagon__) #else // other standard libraries #define ABSL_HAVE_ALARM 1 diff --git a/absl/base/internal/sysinfo.cc b/absl/base/internal/sysinfo.cc index 605a11ebce6..8bcc4fafaf9 100644 --- a/absl/base/internal/sysinfo.cc +++ b/absl/base/internal/sysinfo.cc @@ -190,7 +190,13 @@ static double GetNominalCPUFrequency() { // and the memory location pointed to by value is set to the value read. static bool ReadLongFromFile(const char *file, long *value) { bool ret = false; - int fd = open(file, O_RDONLY | O_CLOEXEC); +#if defined(_POSIX_C_SOURCE) + const int file_mode = (O_RDONLY | O_CLOEXEC); +#else + const int file_mode = O_RDONLY; +#endif + + int fd = open(file, file_mode); if (fd != -1) { char line[1024]; char *err; diff --git a/absl/base/internal/thread_identity.cc b/absl/base/internal/thread_identity.cc index 0eeb7d0015d..252443ebcd7 100644 --- a/absl/base/internal/thread_identity.cc +++ b/absl/base/internal/thread_identity.cc @@ -80,7 +80,7 @@ void SetCurrentThreadIdentity(ThreadIdentity* identity, absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey, reclaimer); -#if defined(__EMSCRIPTEN__) || defined(__MINGW32__) +#if defined(__EMSCRIPTEN__) || defined(__MINGW32__) || defined(__hexagon__) // Emscripten and MinGW pthread implementations does not support signals. // See https://kripken.github.io/emscripten-site/docs/porting/pthreads.html // for more information. diff --git a/absl/debugging/internal/elf_mem_image.h b/absl/debugging/internal/elf_mem_image.h index 8d95d0ba7c8..e7fe6ab06e2 100644 --- a/absl/debugging/internal/elf_mem_image.h +++ b/absl/debugging/internal/elf_mem_image.h @@ -34,7 +34,7 @@ #if defined(__ELF__) && !defined(__OpenBSD__) && !defined(__QNX__) && \ !defined(__native_client__) && !defined(__asmjs__) && \ !defined(__wasm__) && !defined(__HAIKU__) && !defined(__sun) && \ - !defined(__VXWORKS__) + !defined(__VXWORKS__) && !defined(__hexagon__) #define ABSL_HAVE_ELF_MEM_IMAGE 1 #endif diff --git a/absl/log/internal/conditions.h b/absl/log/internal/conditions.h index b3ce2574272..f576d6500b3 100644 --- a/absl/log/internal/conditions.h +++ b/absl/log/internal/conditions.h @@ -23,7 +23,7 @@ #ifndef ABSL_LOG_INTERNAL_CONDITIONS_H_ #define ABSL_LOG_INTERNAL_CONDITIONS_H_ -#ifdef _WIN32 +#if defined(_WIN32) || defined(__hexagon__) #include #else #include diff --git a/absl/log/internal/nullstream.h b/absl/log/internal/nullstream.h index 16f5f495a82..9266852eb98 100644 --- a/absl/log/internal/nullstream.h +++ b/absl/log/internal/nullstream.h @@ -102,7 +102,9 @@ class NullStreamMaybeFatal final : public NullStream { explicit NullStreamMaybeFatal(absl::LogSeverity severity) : fatal_(severity == absl::LogSeverity::kFatal) {} ~NullStreamMaybeFatal() { - if (fatal_) _exit(1); + if (fatal_) { + _exit(1); + } } private: From 372bfc86105728732fc115af46223d7a4e49f8d9 Mon Sep 17 00:00:00 2001 From: Benjamin Barenblat Date: Thu, 29 Jun 2023 13:05:51 -0700 Subject: [PATCH 0094/1238] Fix symbolization on PowerPC ELF v1 The big-endian PowerPC ELF ABI (ppc64 in Debian) relies on function descriptors mapped in a non-executable segment. Make sure that segment is scanned during symbolization. Also correct bounds computation for that segment. PiperOrigin-RevId: 544440302 Change-Id: Ic05532aa35ae9efa127028318640ee7cdeeecc5f --- absl/debugging/symbolize_elf.inc | 52 ++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/absl/debugging/symbolize_elf.inc b/absl/debugging/symbolize_elf.inc index 0fee89f25e6..30638cb2dc0 100644 --- a/absl/debugging/symbolize_elf.inc +++ b/absl/debugging/symbolize_elf.inc @@ -658,8 +658,10 @@ static bool ShouldPickFirstSymbol(const ElfW(Sym) & symbol1, } // Return true if an address is inside a section. -static bool InSection(const void *address, const ElfW(Shdr) * section) { - const char *start = reinterpret_cast(section->sh_addr); +static bool InSection(const void *address, ptrdiff_t relocation, + const ElfW(Shdr) * section) { + const char *start = reinterpret_cast( + section->sh_addr + static_cast(relocation)); size_t size = static_cast(section->sh_size); return start <= address && address < (start + size); } @@ -699,8 +701,8 @@ static ABSL_ATTRIBUTE_NOINLINE FindSymbolResult FindSymbol( // starting address. However, we do not always want to use the real // starting address because we sometimes want to symbolize a function // pointer into the .opd section, e.g. FindSymbol(&foo,...). - const bool pc_in_opd = - kPlatformUsesOPDSections && opd != nullptr && InSection(pc, opd); + const bool pc_in_opd = kPlatformUsesOPDSections && opd != nullptr && + InSection(pc, relocation, opd); const bool deref_function_descriptor_pointer = kPlatformUsesOPDSections && opd != nullptr && !pc_in_opd; @@ -740,7 +742,7 @@ static ABSL_ATTRIBUTE_NOINLINE FindSymbolResult FindSymbol( #endif if (deref_function_descriptor_pointer && - InSection(original_start_address, opd)) { + InSection(original_start_address, /*relocation=*/0, opd)) { // The opd section is mapped into memory. Just dereference // start_address to get the first double word, which points to the // function entry. @@ -1336,7 +1338,7 @@ static bool MaybeInitializeObjFile(ObjFile *obj) { const int phnum = obj->elf_header.e_phnum; const int phentsize = obj->elf_header.e_phentsize; auto phoff = static_cast(obj->elf_header.e_phoff); - size_t num_executable_load_segments = 0; + size_t num_interesting_load_segments = 0; for (int j = 0; j < phnum; j++) { ElfW(Phdr) phdr; if (!ReadFromOffsetExact(obj->fd, &phdr, sizeof(phdr), phoff)) { @@ -1345,23 +1347,35 @@ static bool MaybeInitializeObjFile(ObjFile *obj) { return false; } phoff += phentsize; - constexpr int rx = PF_X | PF_R; - if (phdr.p_type != PT_LOAD || (phdr.p_flags & rx) != rx) { - // Not a LOAD segment, or not executable code. + +#if defined(__powerpc__) && !(_CALL_ELF > 1) + // On the PowerPC ELF v1 ABI, function pointers actually point to function + // descriptors. These descriptors are stored in an .opd section, which is + // mapped read-only. We thus need to look at all readable segments, not + // just the executable ones. + constexpr int interesting = PF_R; +#else + constexpr int interesting = PF_X | PF_R; +#endif + + if (phdr.p_type != PT_LOAD + || (phdr.p_flags & interesting) != interesting) { + // Not a LOAD segment, not executable code, and not a function + // descriptor. continue; } - if (num_executable_load_segments < obj->phdr.size()) { - memcpy(&obj->phdr[num_executable_load_segments++], &phdr, sizeof(phdr)); + if (num_interesting_load_segments < obj->phdr.size()) { + memcpy(&obj->phdr[num_interesting_load_segments++], &phdr, sizeof(phdr)); } else { ABSL_RAW_LOG( - WARNING, "%s: too many executable LOAD segments: %zu >= %zu", - obj->filename, num_executable_load_segments, obj->phdr.size()); + WARNING, "%s: too many interesting LOAD segments: %zu >= %zu", + obj->filename, num_interesting_load_segments, obj->phdr.size()); break; } } - if (num_executable_load_segments == 0) { - // This object has no "r-x" LOAD segments. That's unexpected. - ABSL_RAW_LOG(WARNING, "%s: no executable LOAD segments", obj->filename); + if (num_interesting_load_segments == 0) { + // This object has no interesting LOAD segments. That's unexpected. + ABSL_RAW_LOG(WARNING, "%s: no interesting LOAD segments", obj->filename); return false; } } @@ -1389,8 +1403,8 @@ const char *Symbolizer::GetUncachedSymbol(const void *pc) { // X in the file will have a start address of [true relocation]+X. relocation = static_cast(start_addr - obj->offset); - // Note: some binaries have multiple "rx" LOAD segments. We must - // find the right one. + // Note: some binaries have multiple LOAD segments that can contain + // function pointers. We must find the right one. ElfW(Phdr) *phdr = nullptr; for (size_t j = 0; j < obj->phdr.size(); j++) { ElfW(Phdr) &p = obj->phdr[j]; @@ -1400,7 +1414,7 @@ const char *Symbolizer::GetUncachedSymbol(const void *pc) { ABSL_RAW_CHECK(p.p_type == PT_NULL, "unexpected p_type"); break; } - if (pc < reinterpret_cast(start_addr + p.p_memsz)) { + if (pc < reinterpret_cast(start_addr + p.p_vaddr + p.p_memsz)) { phdr = &p; break; } From a3020c763c12bd16bbf00804abe853afa5778174 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 29 Jun 2023 13:27:13 -0700 Subject: [PATCH 0095/1238] Import of CCTZ from GitHub. PiperOrigin-RevId: 544445872 Change-Id: Ic7d42dca3461babdf8a6dff4c73a1596e795ffb2 --- absl/time/internal/cctz/src/time_zone_info.cc | 1 + absl/time/internal/cctz/src/time_zone_libc.h | 1 + 2 files changed, 2 insertions(+) diff --git a/absl/time/internal/cctz/src/time_zone_info.cc b/absl/time/internal/cctz/src/time_zone_info.cc index 4bc7b50bb66..a3be65582c4 100644 --- a/absl/time/internal/cctz/src/time_zone_info.cc +++ b/absl/time/internal/cctz/src/time_zone_info.cc @@ -45,6 +45,7 @@ #include #include #include +#include #include "absl/base/config.h" #include "absl/time/internal/cctz/include/cctz/civil_time.h" diff --git a/absl/time/internal/cctz/src/time_zone_libc.h b/absl/time/internal/cctz/src/time_zone_libc.h index 2d6fa686cf8..ae2107376f0 100644 --- a/absl/time/internal/cctz/src/time_zone_libc.h +++ b/absl/time/internal/cctz/src/time_zone_libc.h @@ -15,6 +15,7 @@ #ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_ #define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_ +#include #include #include "absl/base/config.h" From d9a01008ab5bd8b5845b4f3074b3bdb453373736 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 29 Jun 2023 14:20:23 -0700 Subject: [PATCH 0096/1238] Use new emscripten_errn to avoid copying strings. PiperOrigin-RevId: 544461113 Change-Id: Iafbd6daf2d03ae18a49ea449315ee7cd6a0e615e --- absl/base/internal/raw_logging.cc | 26 +++++++++++++++----------- absl/log/internal/globals.cc | 18 +++++++++++------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/absl/base/internal/raw_logging.cc b/absl/base/internal/raw_logging.cc index c866d957e90..1904026f026 100644 --- a/absl/base/internal/raw_logging.cc +++ b/absl/base/internal/raw_logging.cc @@ -206,27 +206,31 @@ void DefaultInternalLog(absl::LogSeverity severity, const char* file, int line, } // namespace void AsyncSignalSafeWriteError(const char* s, size_t len) { + if (!len) return; absl::base_internal::ErrnoSaver errno_saver; #if defined(__EMSCRIPTEN__) // In WebAssembly, bypass filesystem emulation via fwrite. - // TODO(b/282811932): Avoid this copy if these emscripten functions can - // be updated to accept size directly. + if (s[len - 1] == '\n') { + // Skip a trailing newline character as emscripten_errn adds one itself. + len--; + } + // emscripten_errn introduced in emscripten 3.1.41 +#if ABSL_INTERNAL_EMSCRIPTEN_VERSION >= 3001041 + emscripten_errn(s, len); +#else char buf[kLogBufSize]; if (len >= kLogBufSize) { len = kLogBufSize - 1; - size_t trunc_len = sizeof(kTruncated) - 2; - strncpy(buf + len - trunc_len, kTruncated, trunc_len); + constexpr size_t trunc_len = sizeof(kTruncated) - 2; + memcpy(buf + len - trunc_len, kTruncated, trunc_len); buf[len] = '\0'; len -= trunc_len; - } else if (len && s[len - 1] == '\n') { - len--; - } - strncpy(buf, s, len); - if (len) { + } else { buf[len] = '\0'; - // Skip a trailing newline character as emscripten_err adds one itself. - _emscripten_err(buf); } + memcpy(buf, s, len); + _emscripten_err(buf); +#endif #elif defined(ABSL_HAVE_SYSCALL_WRITE) // We prefer calling write via `syscall` to minimize the risk of libc doing // something "helpful". diff --git a/absl/log/internal/globals.cc b/absl/log/internal/globals.cc index 9ba997d52fb..cc7a9836c4c 100644 --- a/absl/log/internal/globals.cc +++ b/absl/log/internal/globals.cc @@ -16,6 +16,7 @@ #include #include + #if defined(__EMSCRIPTEN__) #include #endif @@ -25,6 +26,7 @@ #include "absl/base/internal/raw_logging.h" #include "absl/base/log_severity.h" #include "absl/strings/string_view.h" +#include "absl/strings/strip.h" #include "absl/time/time.h" namespace absl { @@ -58,16 +60,18 @@ void SetInitialized() { } void WriteToStderr(absl::string_view message, absl::LogSeverity severity) { + if (message.empty()) return; #if defined(__EMSCRIPTEN__) // In WebAssembly, bypass filesystem emulation via fwrite. - // TODO(b/282811932): Avoid this copy if these emscripten functions can - // be updated to accept size directly. - std::string null_terminated_message(message); - if (!null_terminated_message.empty() && - null_terminated_message.back() == '\n') { - null_terminated_message.pop_back(); - } + // Skip a trailing newline character as emscripten_errn adds one itself. + const auto message_minus_newline = absl::StripSuffix(message, "\n"); + // emscripten_errn introduced in emscripten 3.1.41 +#if ABSL_INTERNAL_EMSCRIPTEN_VERSION >= 3001041 + emscripten_errn(message_minus_newline.data(), message_minus_newline.size()); +#else + std::string null_terminated_message(message_minus_newline); _emscripten_err(null_terminated_message.c_str()); +#endif #else // Avoid using std::cerr from this module since we may get called during // exit code, and cerr may be partially or fully destroyed by then. From 6879e28c7b11d8e83f446ce4444500fac0d99691 Mon Sep 17 00:00:00 2001 From: Evan Brown Date: Fri, 30 Jun 2023 08:51:07 -0700 Subject: [PATCH 0097/1238] Make data members of CommonFields be private so that it's easier to change how we store this information internally. PiperOrigin-RevId: 544667586 Change-Id: I9b1943ca71ea1c1f8699832422cd7bc095ac8b2d --- absl/container/internal/raw_hash_set.cc | 33 ++++---- absl/container/internal/raw_hash_set.h | 108 ++++++++++++++---------- 2 files changed, 79 insertions(+), 62 deletions(-) diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc index 1ccee1edfd4..37d7e487a8c 100644 --- a/absl/container/internal/raw_hash_set.cc +++ b/absl/container/internal/raw_hash_set.cc @@ -15,6 +15,7 @@ #include "absl/container/internal/raw_hash_set.h" #include +#include #include #include @@ -130,8 +131,8 @@ static inline void* PrevSlot(void* slot, size_t slot_size) { void DropDeletesWithoutResize(CommonFields& common, const PolicyFunctions& policy, void* tmp_space) { void* set = &common; - void* slot_array = common.slots_; - const size_t capacity = common.capacity_; + void* slot_array = common.slots(); + const size_t capacity = common.capacity(); assert(IsValidCapacity(capacity)); assert(!is_small(capacity)); // Algorithm: @@ -150,7 +151,7 @@ void DropDeletesWithoutResize(CommonFields& common, // swap current element with target element // mark target as FULL // repeat procedure for current slot with moved from element (target) - ctrl_t* ctrl = common.control_; + ctrl_t* ctrl = common.control(); ConvertDeletedToEmptyAndFullToDeleted(ctrl, capacity); auto hasher = policy.hash_slot; auto transfer = policy.transfer; @@ -210,11 +211,11 @@ void DropDeletesWithoutResize(CommonFields& common, void EraseMetaOnly(CommonFields& c, ctrl_t* it, size_t slot_size) { assert(IsFull(*it) && "erasing a dangling iterator"); - --c.size_; - const auto index = static_cast(it - c.control_); - const size_t index_before = (index - Group::kWidth) & c.capacity_; + c.set_size(c.size() - 1); + const auto index = static_cast(it - c.control()); + const size_t index_before = (index - Group::kWidth) & c.capacity(); const auto empty_after = Group(it).MaskEmpty(); - const auto empty_before = Group(c.control_ + index_before).MaskEmpty(); + const auto empty_before = Group(c.control() + index_before).MaskEmpty(); // We count how many consecutive non empties we have to the right and to the // left of `it`. If the sum is >= kWidth then there is at least one probe @@ -226,26 +227,26 @@ void EraseMetaOnly(CommonFields& c, ctrl_t* it, size_t slot_size) { SetCtrl(c, index, was_never_full ? ctrl_t::kEmpty : ctrl_t::kDeleted, slot_size); - c.growth_left() += (was_never_full ? 1 : 0); + c.set_growth_left(c.growth_left() + (was_never_full ? 1 : 0)); c.infoz().RecordErase(); } void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy, bool reuse) { - c.size_ = 0; + c.set_size(0); if (reuse) { ResetCtrl(c, policy.slot_size); - c.infoz().RecordStorageChanged(0, c.capacity_); + c.infoz().RecordStorageChanged(0, c.capacity()); } else { void* set = &c; - (*policy.dealloc)(set, policy, c.control_, c.slots_, c.capacity_); - c.control_ = EmptyGroup(); + (*policy.dealloc)(set, policy, c.control(), c.slots(), c.capacity()); + c.set_control(EmptyGroup()); c.set_generation_ptr(EmptyGeneration()); - c.slots_ = nullptr; - c.capacity_ = 0; - c.growth_left() = 0; + c.set_slots(nullptr); + c.set_capacity(0); + c.set_growth_left(0); c.infoz().RecordClearedReservation(); - assert(c.size_ == 0); + assert(c.size() == 0); c.infoz().RecordStorageChanged(0, 0); } } diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 2880af70e46..5a514d7bc46 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -889,6 +889,11 @@ using CommonFieldsGenerationInfo = CommonFieldsGenerationInfoDisabled; using HashSetIteratorGenerationInfo = HashSetIteratorGenerationInfoDisabled; #endif +// Returns whether `n` is a valid capacity (i.e., number of slots). +// +// A valid capacity is a non-zero integer `2^m - 1`. +inline bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; } + // CommonFields hold the fields in raw_hash_set that do not depend // on template parameters. This allows us to conveniently pass all // of this state to helper functions as a single argument. @@ -906,21 +911,34 @@ class CommonFields : public CommonFieldsGenerationInfo { std::move(static_cast(that))), // Explicitly copying fields into "this" and then resetting "that" // fields generates less code then calling absl::exchange per field. - control_(that.control_), - slots_(that.slots_), - size_(that.size_), - capacity_(that.capacity_), + control_(that.control()), + slots_(that.slots()), + size_(that.size()), + capacity_(that.capacity()), compressed_tuple_(that.growth_left(), std::move(that.infoz())) { - that.control_ = EmptyGroup(); - that.slots_ = nullptr; - that.size_ = 0; - that.capacity_ = 0; - that.growth_left() = 0; + that.set_control(EmptyGroup()); + that.set_slots(nullptr); + that.set_size(0); + that.set_capacity(0); + that.set_growth_left(0); } CommonFields& operator=(CommonFields&&) = default; + ctrl_t* control() const { return control_; } + void set_control(ctrl_t* c) { control_ = c; } + void* slots() const { return slots_; } + void set_slots(void* s) { slots_ = s; } + size_t size() const { return size_; } + void set_size(size_t s) { size_ = s; } + size_t capacity() const { return capacity_; } + void set_capacity(size_t c) { + assert(c == 0 || IsValidCapacity(c)); + capacity_ = c; + } + // The number of slots we can still fill without needing to rehash. - size_t& growth_left() { return compressed_tuple_.template get<0>(); } + size_t growth_left() const { return compressed_tuple_.template get<0>(); } + void set_growth_left(size_t gl) { compressed_tuple_.template get<0>() = gl; } HashtablezInfoHandle& infoz() { return compressed_tuple_.template get<1>(); } const HashtablezInfoHandle& infoz() const { @@ -929,15 +947,17 @@ class CommonFields : public CommonFieldsGenerationInfo { bool should_rehash_for_bug_detection_on_insert() const { return CommonFieldsGenerationInfo:: - should_rehash_for_bug_detection_on_insert(control_, capacity_); + should_rehash_for_bug_detection_on_insert(control(), capacity()); } void reset_reserved_growth(size_t reservation) { CommonFieldsGenerationInfo::reset_reserved_growth(reservation, size_); } + private: // TODO(b/259599413): Investigate removing some of these fields: // - control/slots can be derived from each other - // - size can be moved into the slot array + // - growth_left can be moved into the slot array + // - we can use 6 bits for capacity since it's always a power of two minus 1 // The control bytes (and, also, a pointer to the base of the backing array). // @@ -971,11 +991,6 @@ constexpr size_t NumClonedBytes() { return Group::kWidth - 1; } template class raw_hash_set; -// Returns whether `n` is a valid capacity (i.e., number of slots). -// -// A valid capacity is a non-zero integer `2^m - 1`. -inline bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; } - // Returns the next valid capacity after `n`. inline size_t NextCapacity(size_t n) { assert(IsValidCapacity(n) || n == 0); @@ -1216,7 +1231,7 @@ inline probe_seq probe(const ctrl_t* ctrl, const size_t capacity, return probe_seq(H1(hash, ctrl), capacity); } inline probe_seq probe(const CommonFields& common, size_t hash) { - return probe(common.control_, common.capacity_, hash); + return probe(common.control(), common.capacity(), hash); } // Probes an array of control bits using a probe sequence derived from `hash`, @@ -1229,7 +1244,7 @@ inline probe_seq probe(const CommonFields& common, size_t hash) { template inline FindInfo find_first_non_full(const CommonFields& common, size_t hash) { auto seq = probe(common, hash); - const ctrl_t* ctrl = common.control_; + const ctrl_t* ctrl = common.control(); while (true) { Group g{ctrl + seq.offset()}; auto mask = g.MaskEmptyOrDeleted(); @@ -1239,14 +1254,14 @@ inline FindInfo find_first_non_full(const CommonFields& common, size_t hash) { // In debug build we will randomly insert in either the front or back of // the group. // TODO(kfm,sbenza): revisit after we do unconditional mixing - if (!is_small(common.capacity_) && ShouldInsertBackwards(hash, ctrl)) { + if (!is_small(common.capacity()) && ShouldInsertBackwards(hash, ctrl)) { return {seq.offset(mask.HighestBitSet()), seq.index()}; } #endif return {seq.offset(mask.LowestBitSet()), seq.index()}; } seq.next(); - assert(seq.index() <= common.capacity_ && "full table!"); + assert(seq.index() <= common.capacity() && "full table!"); } } @@ -1260,18 +1275,18 @@ extern template FindInfo find_first_non_full(const CommonFields&, size_t); FindInfo find_first_non_full_outofline(const CommonFields&, size_t); inline void ResetGrowthLeft(CommonFields& common) { - common.growth_left() = CapacityToGrowth(common.capacity_) - common.size_; + common.set_growth_left(CapacityToGrowth(common.capacity()) - common.size()); } // Sets `ctrl` to `{kEmpty, kSentinel, ..., kEmpty}`, marking the entire // array as marked as empty. inline void ResetCtrl(CommonFields& common, size_t slot_size) { - const size_t capacity = common.capacity_; - ctrl_t* ctrl = common.control_; + const size_t capacity = common.capacity(); + ctrl_t* ctrl = common.control(); std::memset(ctrl, static_cast(ctrl_t::kEmpty), capacity + 1 + NumClonedBytes()); ctrl[capacity] = ctrl_t::kSentinel; - SanitizerPoisonMemoryRegion(common.slots_, slot_size * capacity); + SanitizerPoisonMemoryRegion(common.slots(), slot_size * capacity); ResetGrowthLeft(common); } @@ -1281,17 +1296,17 @@ inline void ResetCtrl(CommonFields& common, size_t slot_size) { // mirror the value to the cloned tail if necessary. inline void SetCtrl(const CommonFields& common, size_t i, ctrl_t h, size_t slot_size) { - const size_t capacity = common.capacity_; + const size_t capacity = common.capacity(); assert(i < capacity); - auto* slot_i = static_cast(common.slots_) + i * slot_size; + auto* slot_i = static_cast(common.slots()) + i * slot_size; if (IsFull(h)) { SanitizerUnpoisonMemoryRegion(slot_i, slot_size); } else { SanitizerPoisonMemoryRegion(slot_i, slot_size); } - ctrl_t* ctrl = common.control_; + ctrl_t* ctrl = common.control(); ctrl[i] = h; ctrl[((i - NumClonedBytes()) & capacity) + (NumClonedBytes() & capacity)] = h; } @@ -1327,31 +1342,31 @@ inline size_t AllocSize(size_t capacity, size_t slot_size, size_t slot_align) { template ABSL_ATTRIBUTE_NOINLINE void InitializeSlots(CommonFields& c, Alloc alloc) { - assert(c.capacity_); + assert(c.capacity()); // Folks with custom allocators often make unwarranted assumptions about the // behavior of their classes vis-a-vis trivial destructability and what // calls they will or won't make. Avoid sampling for people with custom // allocators to get us out of this mess. This is not a hard guarantee but // a workaround while we plan the exact guarantee we want to provide. const size_t sample_size = - (std::is_same>::value && c.slots_ == nullptr) + (std::is_same>::value && c.slots() == nullptr) ? SizeOfSlot : 0; - const size_t cap = c.capacity_; + const size_t cap = c.capacity(); char* mem = static_cast( Allocate(&alloc, AllocSize(cap, SizeOfSlot, AlignOfSlot))); const GenerationType old_generation = c.generation(); c.set_generation_ptr( reinterpret_cast(mem + GenerationOffset(cap))); c.set_generation(NextGeneration(old_generation)); - c.control_ = reinterpret_cast(mem); - c.slots_ = mem + SlotOffset(cap, AlignOfSlot); + c.set_control(reinterpret_cast(mem)); + c.set_slots(mem + SlotOffset(cap, AlignOfSlot)); ResetCtrl(c, SizeOfSlot); if (sample_size) { c.infoz() = Sample(sample_size); } - c.infoz().RecordStorageChanged(c.size_, cap); + c.infoz().RecordStorageChanged(c.size(), cap); } // PolicyFunctions bundles together some information for a particular @@ -1654,7 +1669,7 @@ class raw_hash_set { const allocator_type& alloc = allocator_type()) : settings_(CommonFields{}, hash, eq, alloc) { if (bucket_count) { - common().capacity_ = NormalizeCapacity(bucket_count); + common().set_capacity(NormalizeCapacity(bucket_count)); initialize_slots(); } } @@ -1767,8 +1782,8 @@ class raw_hash_set { common().maybe_increment_generation_on_insert(); infoz().RecordInsert(hash, target.probe_length); } - common().size_ = that.size(); - growth_left() -= that.size(); + common().set_size(that.size()); + set_growth_left(growth_left() - that.size()); } ABSL_ATTRIBUTE_NOINLINE raw_hash_set(raw_hash_set&& that) noexcept( @@ -1849,8 +1864,8 @@ class raw_hash_set { const_iterator cend() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return end(); } bool empty() const { return !size(); } - size_t size() const { return common().size_; } - size_t capacity() const { return common().capacity_; } + size_t size() const { return common().size(); } + size_t capacity() const { return common().capacity(); } size_t max_size() const { return (std::numeric_limits::max)(); } ABSL_ATTRIBUTE_REINITIALIZES void clear() { @@ -2432,8 +2447,8 @@ class raw_hash_set { assert(IsValidCapacity(new_capacity)); auto* old_ctrl = control(); auto* old_slots = slot_array(); - const size_t old_capacity = common().capacity_; - common().capacity_ = new_capacity; + const size_t old_capacity = common().capacity(); + common().set_capacity(new_capacity); initialize_slots(); auto* new_slots = slot_array(); @@ -2600,8 +2615,8 @@ class raw_hash_set { rehash_and_grow_if_necessary(); target = find_first_non_full(common(), hash); } - ++common().size_; - growth_left() -= IsEmpty(control()[target.offset]); + common().set_size(common().size() + 1); + set_growth_left(growth_left() - IsEmpty(control()[target.offset])); SetCtrl(common(), target.offset, H2(hash), sizeof(slot_type)); common().maybe_increment_generation_on_insert(); infoz().RecordInsert(hash, target.probe_length); @@ -2646,7 +2661,8 @@ class raw_hash_set { // side-effect. // // See `CapacityToGrowth()`. - size_t& growth_left() { return common().growth_left(); } + size_t growth_left() const { return common().growth_left(); } + void set_growth_left(size_t gl) { return common().set_growth_left(gl); } // Prefetch the heap-allocated memory region to resolve potential TLB and // cache misses. This is intended to overlap with execution of calculating the @@ -2660,9 +2676,9 @@ class raw_hash_set { CommonFields& common() { return settings_.template get<0>(); } const CommonFields& common() const { return settings_.template get<0>(); } - ctrl_t* control() const { return common().control_; } + ctrl_t* control() const { return common().control(); } slot_type* slot_array() const { - return static_cast(common().slots_); + return static_cast(common().slots()); } HashtablezInfoHandle& infoz() { return common().infoz(); } From f3ea24d72e6a1a1c77e08b79e886a3721f000823 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 30 Jun 2023 09:32:16 -0700 Subject: [PATCH 0098/1238] Rolls back use of emscripten_errn as some implementations may not be compatible. PiperOrigin-RevId: 544677169 Change-Id: I98874c5c8d1c9a057958b63e2b3c4fdd5daccd39 --- absl/base/internal/raw_logging.cc | 26 +++++++++++--------------- absl/log/internal/globals.cc | 18 +++++++----------- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/absl/base/internal/raw_logging.cc b/absl/base/internal/raw_logging.cc index 1904026f026..c866d957e90 100644 --- a/absl/base/internal/raw_logging.cc +++ b/absl/base/internal/raw_logging.cc @@ -206,31 +206,27 @@ void DefaultInternalLog(absl::LogSeverity severity, const char* file, int line, } // namespace void AsyncSignalSafeWriteError(const char* s, size_t len) { - if (!len) return; absl::base_internal::ErrnoSaver errno_saver; #if defined(__EMSCRIPTEN__) // In WebAssembly, bypass filesystem emulation via fwrite. - if (s[len - 1] == '\n') { - // Skip a trailing newline character as emscripten_errn adds one itself. - len--; - } - // emscripten_errn introduced in emscripten 3.1.41 -#if ABSL_INTERNAL_EMSCRIPTEN_VERSION >= 3001041 - emscripten_errn(s, len); -#else + // TODO(b/282811932): Avoid this copy if these emscripten functions can + // be updated to accept size directly. char buf[kLogBufSize]; if (len >= kLogBufSize) { len = kLogBufSize - 1; - constexpr size_t trunc_len = sizeof(kTruncated) - 2; - memcpy(buf + len - trunc_len, kTruncated, trunc_len); + size_t trunc_len = sizeof(kTruncated) - 2; + strncpy(buf + len - trunc_len, kTruncated, trunc_len); buf[len] = '\0'; len -= trunc_len; - } else { + } else if (len && s[len - 1] == '\n') { + len--; + } + strncpy(buf, s, len); + if (len) { buf[len] = '\0'; + // Skip a trailing newline character as emscripten_err adds one itself. + _emscripten_err(buf); } - memcpy(buf, s, len); - _emscripten_err(buf); -#endif #elif defined(ABSL_HAVE_SYSCALL_WRITE) // We prefer calling write via `syscall` to minimize the risk of libc doing // something "helpful". diff --git a/absl/log/internal/globals.cc b/absl/log/internal/globals.cc index cc7a9836c4c..9ba997d52fb 100644 --- a/absl/log/internal/globals.cc +++ b/absl/log/internal/globals.cc @@ -16,7 +16,6 @@ #include #include - #if defined(__EMSCRIPTEN__) #include #endif @@ -26,7 +25,6 @@ #include "absl/base/internal/raw_logging.h" #include "absl/base/log_severity.h" #include "absl/strings/string_view.h" -#include "absl/strings/strip.h" #include "absl/time/time.h" namespace absl { @@ -60,18 +58,16 @@ void SetInitialized() { } void WriteToStderr(absl::string_view message, absl::LogSeverity severity) { - if (message.empty()) return; #if defined(__EMSCRIPTEN__) // In WebAssembly, bypass filesystem emulation via fwrite. - // Skip a trailing newline character as emscripten_errn adds one itself. - const auto message_minus_newline = absl::StripSuffix(message, "\n"); - // emscripten_errn introduced in emscripten 3.1.41 -#if ABSL_INTERNAL_EMSCRIPTEN_VERSION >= 3001041 - emscripten_errn(message_minus_newline.data(), message_minus_newline.size()); -#else - std::string null_terminated_message(message_minus_newline); + // TODO(b/282811932): Avoid this copy if these emscripten functions can + // be updated to accept size directly. + std::string null_terminated_message(message); + if (!null_terminated_message.empty() && + null_terminated_message.back() == '\n') { + null_terminated_message.pop_back(); + } _emscripten_err(null_terminated_message.c_str()); -#endif #else // Avoid using std::cerr from this module since we may get called during // exit code, and cerr may be partially or fully destroyed by then. From 495399deda56d656e3f3cac734734fefeb84f1e6 Mon Sep 17 00:00:00 2001 From: Evan Brown Date: Fri, 30 Jun 2023 12:07:54 -0700 Subject: [PATCH 0099/1238] rollback: Make data members of CommonFields be private so that it's easier to change how we store this information internally. PiperOrigin-RevId: 544718317 Change-Id: I0ff3e4df7e810be9f7c5db4328995e172eb704a5 --- absl/container/internal/raw_hash_set.cc | 33 ++++---- absl/container/internal/raw_hash_set.h | 108 ++++++++++-------------- 2 files changed, 62 insertions(+), 79 deletions(-) diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc index 37d7e487a8c..1ccee1edfd4 100644 --- a/absl/container/internal/raw_hash_set.cc +++ b/absl/container/internal/raw_hash_set.cc @@ -15,7 +15,6 @@ #include "absl/container/internal/raw_hash_set.h" #include -#include #include #include @@ -131,8 +130,8 @@ static inline void* PrevSlot(void* slot, size_t slot_size) { void DropDeletesWithoutResize(CommonFields& common, const PolicyFunctions& policy, void* tmp_space) { void* set = &common; - void* slot_array = common.slots(); - const size_t capacity = common.capacity(); + void* slot_array = common.slots_; + const size_t capacity = common.capacity_; assert(IsValidCapacity(capacity)); assert(!is_small(capacity)); // Algorithm: @@ -151,7 +150,7 @@ void DropDeletesWithoutResize(CommonFields& common, // swap current element with target element // mark target as FULL // repeat procedure for current slot with moved from element (target) - ctrl_t* ctrl = common.control(); + ctrl_t* ctrl = common.control_; ConvertDeletedToEmptyAndFullToDeleted(ctrl, capacity); auto hasher = policy.hash_slot; auto transfer = policy.transfer; @@ -211,11 +210,11 @@ void DropDeletesWithoutResize(CommonFields& common, void EraseMetaOnly(CommonFields& c, ctrl_t* it, size_t slot_size) { assert(IsFull(*it) && "erasing a dangling iterator"); - c.set_size(c.size() - 1); - const auto index = static_cast(it - c.control()); - const size_t index_before = (index - Group::kWidth) & c.capacity(); + --c.size_; + const auto index = static_cast(it - c.control_); + const size_t index_before = (index - Group::kWidth) & c.capacity_; const auto empty_after = Group(it).MaskEmpty(); - const auto empty_before = Group(c.control() + index_before).MaskEmpty(); + const auto empty_before = Group(c.control_ + index_before).MaskEmpty(); // We count how many consecutive non empties we have to the right and to the // left of `it`. If the sum is >= kWidth then there is at least one probe @@ -227,26 +226,26 @@ void EraseMetaOnly(CommonFields& c, ctrl_t* it, size_t slot_size) { SetCtrl(c, index, was_never_full ? ctrl_t::kEmpty : ctrl_t::kDeleted, slot_size); - c.set_growth_left(c.growth_left() + (was_never_full ? 1 : 0)); + c.growth_left() += (was_never_full ? 1 : 0); c.infoz().RecordErase(); } void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy, bool reuse) { - c.set_size(0); + c.size_ = 0; if (reuse) { ResetCtrl(c, policy.slot_size); - c.infoz().RecordStorageChanged(0, c.capacity()); + c.infoz().RecordStorageChanged(0, c.capacity_); } else { void* set = &c; - (*policy.dealloc)(set, policy, c.control(), c.slots(), c.capacity()); - c.set_control(EmptyGroup()); + (*policy.dealloc)(set, policy, c.control_, c.slots_, c.capacity_); + c.control_ = EmptyGroup(); c.set_generation_ptr(EmptyGeneration()); - c.set_slots(nullptr); - c.set_capacity(0); - c.set_growth_left(0); + c.slots_ = nullptr; + c.capacity_ = 0; + c.growth_left() = 0; c.infoz().RecordClearedReservation(); - assert(c.size() == 0); + assert(c.size_ == 0); c.infoz().RecordStorageChanged(0, 0); } } diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 5a514d7bc46..2880af70e46 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -889,11 +889,6 @@ using CommonFieldsGenerationInfo = CommonFieldsGenerationInfoDisabled; using HashSetIteratorGenerationInfo = HashSetIteratorGenerationInfoDisabled; #endif -// Returns whether `n` is a valid capacity (i.e., number of slots). -// -// A valid capacity is a non-zero integer `2^m - 1`. -inline bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; } - // CommonFields hold the fields in raw_hash_set that do not depend // on template parameters. This allows us to conveniently pass all // of this state to helper functions as a single argument. @@ -911,34 +906,21 @@ class CommonFields : public CommonFieldsGenerationInfo { std::move(static_cast(that))), // Explicitly copying fields into "this" and then resetting "that" // fields generates less code then calling absl::exchange per field. - control_(that.control()), - slots_(that.slots()), - size_(that.size()), - capacity_(that.capacity()), + control_(that.control_), + slots_(that.slots_), + size_(that.size_), + capacity_(that.capacity_), compressed_tuple_(that.growth_left(), std::move(that.infoz())) { - that.set_control(EmptyGroup()); - that.set_slots(nullptr); - that.set_size(0); - that.set_capacity(0); - that.set_growth_left(0); + that.control_ = EmptyGroup(); + that.slots_ = nullptr; + that.size_ = 0; + that.capacity_ = 0; + that.growth_left() = 0; } CommonFields& operator=(CommonFields&&) = default; - ctrl_t* control() const { return control_; } - void set_control(ctrl_t* c) { control_ = c; } - void* slots() const { return slots_; } - void set_slots(void* s) { slots_ = s; } - size_t size() const { return size_; } - void set_size(size_t s) { size_ = s; } - size_t capacity() const { return capacity_; } - void set_capacity(size_t c) { - assert(c == 0 || IsValidCapacity(c)); - capacity_ = c; - } - // The number of slots we can still fill without needing to rehash. - size_t growth_left() const { return compressed_tuple_.template get<0>(); } - void set_growth_left(size_t gl) { compressed_tuple_.template get<0>() = gl; } + size_t& growth_left() { return compressed_tuple_.template get<0>(); } HashtablezInfoHandle& infoz() { return compressed_tuple_.template get<1>(); } const HashtablezInfoHandle& infoz() const { @@ -947,17 +929,15 @@ class CommonFields : public CommonFieldsGenerationInfo { bool should_rehash_for_bug_detection_on_insert() const { return CommonFieldsGenerationInfo:: - should_rehash_for_bug_detection_on_insert(control(), capacity()); + should_rehash_for_bug_detection_on_insert(control_, capacity_); } void reset_reserved_growth(size_t reservation) { CommonFieldsGenerationInfo::reset_reserved_growth(reservation, size_); } - private: // TODO(b/259599413): Investigate removing some of these fields: // - control/slots can be derived from each other - // - growth_left can be moved into the slot array - // - we can use 6 bits for capacity since it's always a power of two minus 1 + // - size can be moved into the slot array // The control bytes (and, also, a pointer to the base of the backing array). // @@ -991,6 +971,11 @@ constexpr size_t NumClonedBytes() { return Group::kWidth - 1; } template class raw_hash_set; +// Returns whether `n` is a valid capacity (i.e., number of slots). +// +// A valid capacity is a non-zero integer `2^m - 1`. +inline bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; } + // Returns the next valid capacity after `n`. inline size_t NextCapacity(size_t n) { assert(IsValidCapacity(n) || n == 0); @@ -1231,7 +1216,7 @@ inline probe_seq probe(const ctrl_t* ctrl, const size_t capacity, return probe_seq(H1(hash, ctrl), capacity); } inline probe_seq probe(const CommonFields& common, size_t hash) { - return probe(common.control(), common.capacity(), hash); + return probe(common.control_, common.capacity_, hash); } // Probes an array of control bits using a probe sequence derived from `hash`, @@ -1244,7 +1229,7 @@ inline probe_seq probe(const CommonFields& common, size_t hash) { template inline FindInfo find_first_non_full(const CommonFields& common, size_t hash) { auto seq = probe(common, hash); - const ctrl_t* ctrl = common.control(); + const ctrl_t* ctrl = common.control_; while (true) { Group g{ctrl + seq.offset()}; auto mask = g.MaskEmptyOrDeleted(); @@ -1254,14 +1239,14 @@ inline FindInfo find_first_non_full(const CommonFields& common, size_t hash) { // In debug build we will randomly insert in either the front or back of // the group. // TODO(kfm,sbenza): revisit after we do unconditional mixing - if (!is_small(common.capacity()) && ShouldInsertBackwards(hash, ctrl)) { + if (!is_small(common.capacity_) && ShouldInsertBackwards(hash, ctrl)) { return {seq.offset(mask.HighestBitSet()), seq.index()}; } #endif return {seq.offset(mask.LowestBitSet()), seq.index()}; } seq.next(); - assert(seq.index() <= common.capacity() && "full table!"); + assert(seq.index() <= common.capacity_ && "full table!"); } } @@ -1275,18 +1260,18 @@ extern template FindInfo find_first_non_full(const CommonFields&, size_t); FindInfo find_first_non_full_outofline(const CommonFields&, size_t); inline void ResetGrowthLeft(CommonFields& common) { - common.set_growth_left(CapacityToGrowth(common.capacity()) - common.size()); + common.growth_left() = CapacityToGrowth(common.capacity_) - common.size_; } // Sets `ctrl` to `{kEmpty, kSentinel, ..., kEmpty}`, marking the entire // array as marked as empty. inline void ResetCtrl(CommonFields& common, size_t slot_size) { - const size_t capacity = common.capacity(); - ctrl_t* ctrl = common.control(); + const size_t capacity = common.capacity_; + ctrl_t* ctrl = common.control_; std::memset(ctrl, static_cast(ctrl_t::kEmpty), capacity + 1 + NumClonedBytes()); ctrl[capacity] = ctrl_t::kSentinel; - SanitizerPoisonMemoryRegion(common.slots(), slot_size * capacity); + SanitizerPoisonMemoryRegion(common.slots_, slot_size * capacity); ResetGrowthLeft(common); } @@ -1296,17 +1281,17 @@ inline void ResetCtrl(CommonFields& common, size_t slot_size) { // mirror the value to the cloned tail if necessary. inline void SetCtrl(const CommonFields& common, size_t i, ctrl_t h, size_t slot_size) { - const size_t capacity = common.capacity(); + const size_t capacity = common.capacity_; assert(i < capacity); - auto* slot_i = static_cast(common.slots()) + i * slot_size; + auto* slot_i = static_cast(common.slots_) + i * slot_size; if (IsFull(h)) { SanitizerUnpoisonMemoryRegion(slot_i, slot_size); } else { SanitizerPoisonMemoryRegion(slot_i, slot_size); } - ctrl_t* ctrl = common.control(); + ctrl_t* ctrl = common.control_; ctrl[i] = h; ctrl[((i - NumClonedBytes()) & capacity) + (NumClonedBytes() & capacity)] = h; } @@ -1342,31 +1327,31 @@ inline size_t AllocSize(size_t capacity, size_t slot_size, size_t slot_align) { template ABSL_ATTRIBUTE_NOINLINE void InitializeSlots(CommonFields& c, Alloc alloc) { - assert(c.capacity()); + assert(c.capacity_); // Folks with custom allocators often make unwarranted assumptions about the // behavior of their classes vis-a-vis trivial destructability and what // calls they will or won't make. Avoid sampling for people with custom // allocators to get us out of this mess. This is not a hard guarantee but // a workaround while we plan the exact guarantee we want to provide. const size_t sample_size = - (std::is_same>::value && c.slots() == nullptr) + (std::is_same>::value && c.slots_ == nullptr) ? SizeOfSlot : 0; - const size_t cap = c.capacity(); + const size_t cap = c.capacity_; char* mem = static_cast( Allocate(&alloc, AllocSize(cap, SizeOfSlot, AlignOfSlot))); const GenerationType old_generation = c.generation(); c.set_generation_ptr( reinterpret_cast(mem + GenerationOffset(cap))); c.set_generation(NextGeneration(old_generation)); - c.set_control(reinterpret_cast(mem)); - c.set_slots(mem + SlotOffset(cap, AlignOfSlot)); + c.control_ = reinterpret_cast(mem); + c.slots_ = mem + SlotOffset(cap, AlignOfSlot); ResetCtrl(c, SizeOfSlot); if (sample_size) { c.infoz() = Sample(sample_size); } - c.infoz().RecordStorageChanged(c.size(), cap); + c.infoz().RecordStorageChanged(c.size_, cap); } // PolicyFunctions bundles together some information for a particular @@ -1669,7 +1654,7 @@ class raw_hash_set { const allocator_type& alloc = allocator_type()) : settings_(CommonFields{}, hash, eq, alloc) { if (bucket_count) { - common().set_capacity(NormalizeCapacity(bucket_count)); + common().capacity_ = NormalizeCapacity(bucket_count); initialize_slots(); } } @@ -1782,8 +1767,8 @@ class raw_hash_set { common().maybe_increment_generation_on_insert(); infoz().RecordInsert(hash, target.probe_length); } - common().set_size(that.size()); - set_growth_left(growth_left() - that.size()); + common().size_ = that.size(); + growth_left() -= that.size(); } ABSL_ATTRIBUTE_NOINLINE raw_hash_set(raw_hash_set&& that) noexcept( @@ -1864,8 +1849,8 @@ class raw_hash_set { const_iterator cend() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return end(); } bool empty() const { return !size(); } - size_t size() const { return common().size(); } - size_t capacity() const { return common().capacity(); } + size_t size() const { return common().size_; } + size_t capacity() const { return common().capacity_; } size_t max_size() const { return (std::numeric_limits::max)(); } ABSL_ATTRIBUTE_REINITIALIZES void clear() { @@ -2447,8 +2432,8 @@ class raw_hash_set { assert(IsValidCapacity(new_capacity)); auto* old_ctrl = control(); auto* old_slots = slot_array(); - const size_t old_capacity = common().capacity(); - common().set_capacity(new_capacity); + const size_t old_capacity = common().capacity_; + common().capacity_ = new_capacity; initialize_slots(); auto* new_slots = slot_array(); @@ -2615,8 +2600,8 @@ class raw_hash_set { rehash_and_grow_if_necessary(); target = find_first_non_full(common(), hash); } - common().set_size(common().size() + 1); - set_growth_left(growth_left() - IsEmpty(control()[target.offset])); + ++common().size_; + growth_left() -= IsEmpty(control()[target.offset]); SetCtrl(common(), target.offset, H2(hash), sizeof(slot_type)); common().maybe_increment_generation_on_insert(); infoz().RecordInsert(hash, target.probe_length); @@ -2661,8 +2646,7 @@ class raw_hash_set { // side-effect. // // See `CapacityToGrowth()`. - size_t growth_left() const { return common().growth_left(); } - void set_growth_left(size_t gl) { return common().set_growth_left(gl); } + size_t& growth_left() { return common().growth_left(); } // Prefetch the heap-allocated memory region to resolve potential TLB and // cache misses. This is intended to overlap with execution of calculating the @@ -2676,9 +2660,9 @@ class raw_hash_set { CommonFields& common() { return settings_.template get<0>(); } const CommonFields& common() const { return settings_.template get<0>(); } - ctrl_t* control() const { return common().control(); } + ctrl_t* control() const { return common().control_; } slot_type* slot_array() const { - return static_cast(common().slots()); + return static_cast(common().slots_); } HashtablezInfoHandle& infoz() { return common().infoz(); } From 40070892631b82c79864ff4d3f7e12105f003157 Mon Sep 17 00:00:00 2001 From: Evan Brown Date: Fri, 30 Jun 2023 13:13:07 -0700 Subject: [PATCH 0100/1238] roll forward: Make data members of CommonFields be private so that it's easier to change how we store this information internally. PiperOrigin-RevId: 544732832 Change-Id: I0c9a30f18edc71b3c7fffe94e2002ff6c52050f8 --- absl/container/internal/raw_hash_set.cc | 33 +++---- absl/container/internal/raw_hash_set.h | 110 ++++++++++++++---------- 2 files changed, 81 insertions(+), 62 deletions(-) diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc index 1ccee1edfd4..a40e38dbba1 100644 --- a/absl/container/internal/raw_hash_set.cc +++ b/absl/container/internal/raw_hash_set.cc @@ -15,6 +15,7 @@ #include "absl/container/internal/raw_hash_set.h" #include +#include #include #include @@ -130,8 +131,8 @@ static inline void* PrevSlot(void* slot, size_t slot_size) { void DropDeletesWithoutResize(CommonFields& common, const PolicyFunctions& policy, void* tmp_space) { void* set = &common; - void* slot_array = common.slots_; - const size_t capacity = common.capacity_; + void* slot_array = common.slots_ptr(); + const size_t capacity = common.capacity(); assert(IsValidCapacity(capacity)); assert(!is_small(capacity)); // Algorithm: @@ -150,7 +151,7 @@ void DropDeletesWithoutResize(CommonFields& common, // swap current element with target element // mark target as FULL // repeat procedure for current slot with moved from element (target) - ctrl_t* ctrl = common.control_; + ctrl_t* ctrl = common.control(); ConvertDeletedToEmptyAndFullToDeleted(ctrl, capacity); auto hasher = policy.hash_slot; auto transfer = policy.transfer; @@ -210,11 +211,11 @@ void DropDeletesWithoutResize(CommonFields& common, void EraseMetaOnly(CommonFields& c, ctrl_t* it, size_t slot_size) { assert(IsFull(*it) && "erasing a dangling iterator"); - --c.size_; - const auto index = static_cast(it - c.control_); - const size_t index_before = (index - Group::kWidth) & c.capacity_; + c.set_size(c.size() - 1); + const auto index = static_cast(it - c.control()); + const size_t index_before = (index - Group::kWidth) & c.capacity(); const auto empty_after = Group(it).MaskEmpty(); - const auto empty_before = Group(c.control_ + index_before).MaskEmpty(); + const auto empty_before = Group(c.control() + index_before).MaskEmpty(); // We count how many consecutive non empties we have to the right and to the // left of `it`. If the sum is >= kWidth then there is at least one probe @@ -226,26 +227,26 @@ void EraseMetaOnly(CommonFields& c, ctrl_t* it, size_t slot_size) { SetCtrl(c, index, was_never_full ? ctrl_t::kEmpty : ctrl_t::kDeleted, slot_size); - c.growth_left() += (was_never_full ? 1 : 0); + c.set_growth_left(c.growth_left() + (was_never_full ? 1 : 0)); c.infoz().RecordErase(); } void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy, bool reuse) { - c.size_ = 0; + c.set_size(0); if (reuse) { ResetCtrl(c, policy.slot_size); - c.infoz().RecordStorageChanged(0, c.capacity_); + c.infoz().RecordStorageChanged(0, c.capacity()); } else { void* set = &c; - (*policy.dealloc)(set, policy, c.control_, c.slots_, c.capacity_); - c.control_ = EmptyGroup(); + (*policy.dealloc)(set, policy, c.control(), c.slots_ptr(), c.capacity()); + c.set_control(EmptyGroup()); c.set_generation_ptr(EmptyGeneration()); - c.slots_ = nullptr; - c.capacity_ = 0; - c.growth_left() = 0; + c.set_slots(nullptr); + c.set_capacity(0); + c.set_growth_left(0); c.infoz().RecordClearedReservation(); - assert(c.size_ == 0); + assert(c.size() == 0); c.infoz().RecordStorageChanged(0, 0); } } diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 2880af70e46..970016f7848 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -889,6 +889,11 @@ using CommonFieldsGenerationInfo = CommonFieldsGenerationInfoDisabled; using HashSetIteratorGenerationInfo = HashSetIteratorGenerationInfoDisabled; #endif +// Returns whether `n` is a valid capacity (i.e., number of slots). +// +// A valid capacity is a non-zero integer `2^m - 1`. +inline bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; } + // CommonFields hold the fields in raw_hash_set that do not depend // on template parameters. This allows us to conveniently pass all // of this state to helper functions as a single argument. @@ -906,21 +911,35 @@ class CommonFields : public CommonFieldsGenerationInfo { std::move(static_cast(that))), // Explicitly copying fields into "this" and then resetting "that" // fields generates less code then calling absl::exchange per field. - control_(that.control_), - slots_(that.slots_), - size_(that.size_), - capacity_(that.capacity_), + control_(that.control()), + slots_(that.slots_ptr()), + size_(that.size()), + capacity_(that.capacity()), compressed_tuple_(that.growth_left(), std::move(that.infoz())) { - that.control_ = EmptyGroup(); - that.slots_ = nullptr; - that.size_ = 0; - that.capacity_ = 0; - that.growth_left() = 0; + that.set_control(EmptyGroup()); + that.set_slots(nullptr); + that.set_size(0); + that.set_capacity(0); + that.set_growth_left(0); } CommonFields& operator=(CommonFields&&) = default; + ctrl_t* control() const { return control_; } + void set_control(ctrl_t* c) { control_ = c; } + // Note: we can't use slots() because Qt defines "slots" as a macro. + void* slots_ptr() const { return slots_; } + void set_slots(void* s) { slots_ = s; } + size_t size() const { return size_; } + void set_size(size_t s) { size_ = s; } + size_t capacity() const { return capacity_; } + void set_capacity(size_t c) { + assert(c == 0 || IsValidCapacity(c)); + capacity_ = c; + } + // The number of slots we can still fill without needing to rehash. - size_t& growth_left() { return compressed_tuple_.template get<0>(); } + size_t growth_left() const { return compressed_tuple_.template get<0>(); } + void set_growth_left(size_t gl) { compressed_tuple_.template get<0>() = gl; } HashtablezInfoHandle& infoz() { return compressed_tuple_.template get<1>(); } const HashtablezInfoHandle& infoz() const { @@ -929,15 +948,17 @@ class CommonFields : public CommonFieldsGenerationInfo { bool should_rehash_for_bug_detection_on_insert() const { return CommonFieldsGenerationInfo:: - should_rehash_for_bug_detection_on_insert(control_, capacity_); + should_rehash_for_bug_detection_on_insert(control(), capacity()); } void reset_reserved_growth(size_t reservation) { CommonFieldsGenerationInfo::reset_reserved_growth(reservation, size_); } + private: // TODO(b/259599413): Investigate removing some of these fields: // - control/slots can be derived from each other - // - size can be moved into the slot array + // - growth_left can be moved into the slot array + // - we can use 6 bits for capacity since it's always a power of two minus 1 // The control bytes (and, also, a pointer to the base of the backing array). // @@ -971,11 +992,6 @@ constexpr size_t NumClonedBytes() { return Group::kWidth - 1; } template class raw_hash_set; -// Returns whether `n` is a valid capacity (i.e., number of slots). -// -// A valid capacity is a non-zero integer `2^m - 1`. -inline bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; } - // Returns the next valid capacity after `n`. inline size_t NextCapacity(size_t n) { assert(IsValidCapacity(n) || n == 0); @@ -1216,7 +1232,7 @@ inline probe_seq probe(const ctrl_t* ctrl, const size_t capacity, return probe_seq(H1(hash, ctrl), capacity); } inline probe_seq probe(const CommonFields& common, size_t hash) { - return probe(common.control_, common.capacity_, hash); + return probe(common.control(), common.capacity(), hash); } // Probes an array of control bits using a probe sequence derived from `hash`, @@ -1229,7 +1245,7 @@ inline probe_seq probe(const CommonFields& common, size_t hash) { template inline FindInfo find_first_non_full(const CommonFields& common, size_t hash) { auto seq = probe(common, hash); - const ctrl_t* ctrl = common.control_; + const ctrl_t* ctrl = common.control(); while (true) { Group g{ctrl + seq.offset()}; auto mask = g.MaskEmptyOrDeleted(); @@ -1239,14 +1255,14 @@ inline FindInfo find_first_non_full(const CommonFields& common, size_t hash) { // In debug build we will randomly insert in either the front or back of // the group. // TODO(kfm,sbenza): revisit after we do unconditional mixing - if (!is_small(common.capacity_) && ShouldInsertBackwards(hash, ctrl)) { + if (!is_small(common.capacity()) && ShouldInsertBackwards(hash, ctrl)) { return {seq.offset(mask.HighestBitSet()), seq.index()}; } #endif return {seq.offset(mask.LowestBitSet()), seq.index()}; } seq.next(); - assert(seq.index() <= common.capacity_ && "full table!"); + assert(seq.index() <= common.capacity() && "full table!"); } } @@ -1260,18 +1276,18 @@ extern template FindInfo find_first_non_full(const CommonFields&, size_t); FindInfo find_first_non_full_outofline(const CommonFields&, size_t); inline void ResetGrowthLeft(CommonFields& common) { - common.growth_left() = CapacityToGrowth(common.capacity_) - common.size_; + common.set_growth_left(CapacityToGrowth(common.capacity()) - common.size()); } // Sets `ctrl` to `{kEmpty, kSentinel, ..., kEmpty}`, marking the entire // array as marked as empty. inline void ResetCtrl(CommonFields& common, size_t slot_size) { - const size_t capacity = common.capacity_; - ctrl_t* ctrl = common.control_; + const size_t capacity = common.capacity(); + ctrl_t* ctrl = common.control(); std::memset(ctrl, static_cast(ctrl_t::kEmpty), capacity + 1 + NumClonedBytes()); ctrl[capacity] = ctrl_t::kSentinel; - SanitizerPoisonMemoryRegion(common.slots_, slot_size * capacity); + SanitizerPoisonMemoryRegion(common.slots_ptr(), slot_size * capacity); ResetGrowthLeft(common); } @@ -1281,17 +1297,17 @@ inline void ResetCtrl(CommonFields& common, size_t slot_size) { // mirror the value to the cloned tail if necessary. inline void SetCtrl(const CommonFields& common, size_t i, ctrl_t h, size_t slot_size) { - const size_t capacity = common.capacity_; + const size_t capacity = common.capacity(); assert(i < capacity); - auto* slot_i = static_cast(common.slots_) + i * slot_size; + auto* slot_i = static_cast(common.slots_ptr()) + i * slot_size; if (IsFull(h)) { SanitizerUnpoisonMemoryRegion(slot_i, slot_size); } else { SanitizerPoisonMemoryRegion(slot_i, slot_size); } - ctrl_t* ctrl = common.control_; + ctrl_t* ctrl = common.control(); ctrl[i] = h; ctrl[((i - NumClonedBytes()) & capacity) + (NumClonedBytes() & capacity)] = h; } @@ -1327,31 +1343,32 @@ inline size_t AllocSize(size_t capacity, size_t slot_size, size_t slot_align) { template ABSL_ATTRIBUTE_NOINLINE void InitializeSlots(CommonFields& c, Alloc alloc) { - assert(c.capacity_); + assert(c.capacity()); // Folks with custom allocators often make unwarranted assumptions about the // behavior of their classes vis-a-vis trivial destructability and what // calls they will or won't make. Avoid sampling for people with custom // allocators to get us out of this mess. This is not a hard guarantee but // a workaround while we plan the exact guarantee we want to provide. const size_t sample_size = - (std::is_same>::value && c.slots_ == nullptr) + (std::is_same>::value && + c.slots_ptr() == nullptr) ? SizeOfSlot : 0; - const size_t cap = c.capacity_; + const size_t cap = c.capacity(); char* mem = static_cast( Allocate(&alloc, AllocSize(cap, SizeOfSlot, AlignOfSlot))); const GenerationType old_generation = c.generation(); c.set_generation_ptr( reinterpret_cast(mem + GenerationOffset(cap))); c.set_generation(NextGeneration(old_generation)); - c.control_ = reinterpret_cast(mem); - c.slots_ = mem + SlotOffset(cap, AlignOfSlot); + c.set_control(reinterpret_cast(mem)); + c.set_slots(mem + SlotOffset(cap, AlignOfSlot)); ResetCtrl(c, SizeOfSlot); if (sample_size) { c.infoz() = Sample(sample_size); } - c.infoz().RecordStorageChanged(c.size_, cap); + c.infoz().RecordStorageChanged(c.size(), cap); } // PolicyFunctions bundles together some information for a particular @@ -1654,7 +1671,7 @@ class raw_hash_set { const allocator_type& alloc = allocator_type()) : settings_(CommonFields{}, hash, eq, alloc) { if (bucket_count) { - common().capacity_ = NormalizeCapacity(bucket_count); + common().set_capacity(NormalizeCapacity(bucket_count)); initialize_slots(); } } @@ -1767,8 +1784,8 @@ class raw_hash_set { common().maybe_increment_generation_on_insert(); infoz().RecordInsert(hash, target.probe_length); } - common().size_ = that.size(); - growth_left() -= that.size(); + common().set_size(that.size()); + set_growth_left(growth_left() - that.size()); } ABSL_ATTRIBUTE_NOINLINE raw_hash_set(raw_hash_set&& that) noexcept( @@ -1849,8 +1866,8 @@ class raw_hash_set { const_iterator cend() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return end(); } bool empty() const { return !size(); } - size_t size() const { return common().size_; } - size_t capacity() const { return common().capacity_; } + size_t size() const { return common().size(); } + size_t capacity() const { return common().capacity(); } size_t max_size() const { return (std::numeric_limits::max)(); } ABSL_ATTRIBUTE_REINITIALIZES void clear() { @@ -2432,8 +2449,8 @@ class raw_hash_set { assert(IsValidCapacity(new_capacity)); auto* old_ctrl = control(); auto* old_slots = slot_array(); - const size_t old_capacity = common().capacity_; - common().capacity_ = new_capacity; + const size_t old_capacity = common().capacity(); + common().set_capacity(new_capacity); initialize_slots(); auto* new_slots = slot_array(); @@ -2600,8 +2617,8 @@ class raw_hash_set { rehash_and_grow_if_necessary(); target = find_first_non_full(common(), hash); } - ++common().size_; - growth_left() -= IsEmpty(control()[target.offset]); + common().set_size(common().size() + 1); + set_growth_left(growth_left() - IsEmpty(control()[target.offset])); SetCtrl(common(), target.offset, H2(hash), sizeof(slot_type)); common().maybe_increment_generation_on_insert(); infoz().RecordInsert(hash, target.probe_length); @@ -2646,7 +2663,8 @@ class raw_hash_set { // side-effect. // // See `CapacityToGrowth()`. - size_t& growth_left() { return common().growth_left(); } + size_t growth_left() const { return common().growth_left(); } + void set_growth_left(size_t gl) { return common().set_growth_left(gl); } // Prefetch the heap-allocated memory region to resolve potential TLB and // cache misses. This is intended to overlap with execution of calculating the @@ -2660,9 +2678,9 @@ class raw_hash_set { CommonFields& common() { return settings_.template get<0>(); } const CommonFields& common() const { return settings_.template get<0>(); } - ctrl_t* control() const { return common().control_; } + ctrl_t* control() const { return common().control(); } slot_type* slot_array() const { - return static_cast(common().slots_); + return static_cast(common().slots_ptr()); } HashtablezInfoHandle& infoz() { return common().infoz(); } From b1fb259ef793de57c2acefeeec07a6e3286ab9bc Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Sat, 1 Jul 2023 01:37:10 -0700 Subject: [PATCH 0101/1238] absl: extend Condition::kTrue comment Explain when kTrue may be useful. Note that Mutex::Await/LockWhen with kTrue condition and a timeout do not return when the timeout is reached. PiperOrigin-RevId: 544846222 Change-Id: I7a14ae5a9314b2e500919f0c7b3a907d4d97c127 --- absl/synchronization/mutex.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h index 2fd077c8d44..645c26d9c39 100644 --- a/absl/synchronization/mutex.h +++ b/absl/synchronization/mutex.h @@ -760,6 +760,16 @@ class Condition { : Condition(obj, static_cast(&T::operator())) {} // A Condition that always returns `true`. + // kTrue is only useful in a narrow set of circumstances, mostly when + // it's passed conditionally. For example: + // + // mu.LockWhen(some_flag ? kTrue : SomeOtherCondition); + // + // Note: {LockWhen,Await}With{Deadline,Timeout} methods with kTrue condition + // don't return immediately when the timeout happens, they still block until + // the Mutex becomes available. The return value of these methods does + // not indicate if the timeout was reached; rather it indicates whether or + // not the condition is true. ABSL_CONST_INIT static const Condition kTrue; // Evaluates the condition. From a0299fa26c3780ee19867fb08fc9f35897034542 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 5 Jul 2023 08:37:20 -0700 Subject: [PATCH 0102/1238] Clarify that lazy_emplace returns an iterator to the new element when lookup fails. PiperOrigin-RevId: 545683736 Change-Id: Ic0abec5037e160898e2f24de1b1489caff7d06fd --- absl/container/internal/raw_hash_set.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 970016f7848..c2fe242de6e 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -2041,7 +2041,8 @@ class raw_hash_set { // Extension API: support for lazy emplace. // // Looks up key in the table. If found, returns the iterator to the element. - // Otherwise calls `f` with one argument of type `raw_hash_set::constructor`. + // Otherwise calls `f` with one argument of type `raw_hash_set::constructor`, + // and returns an iterator to the new element. // // `f` must abide by several restrictions: // - it MUST call `raw_hash_set::constructor` with arguments as if a From 512af68a1d397cd2cfa1ac9c6eca7694bf75f2b0 Mon Sep 17 00:00:00 2001 From: James Y Knight Date: Thu, 6 Jul 2023 09:07:22 -0700 Subject: [PATCH 0103/1238] Correct std::optional/variant/any auto-detection for Apple platforms. In Xcode 14.3, Apple modified the OS versions which support these three types to exclude iOS 11 and watchOS 4. Update abseil accordingly. Those versions of the OS did _not_ actually support the types, and any binaries which used these types, built with prior Xcode versions, would've crashed on startup on an actual iOS 11 or watchOS 4 device due to missing symbols. As of Xcode 14.3, using them is now, correctly, a build failure. This change also drops the conditionals for pre-Xcode 12.5, as that is no longer a supported version. PiperOrigin-RevId: 546005629 Change-Id: Ib0430307ac2ada4910f07c54cfd6e99db8ca1905 --- absl/base/config.h | 48 +++++++++++++++++----------------------------- 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/absl/base/config.h b/absl/base/config.h index e6c9d0c2f94..0037bab9759 100644 --- a/absl/base/config.h +++ b/absl/base/config.h @@ -522,41 +522,29 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #error "absl endian detection needs to be set up for your compiler" #endif -// macOS < 10.13 and iOS < 11 don't let you use , , or -// even though the headers exist and are publicly noted to work, because the -// libc++ shared library shipped on the system doesn't have the requisite -// exported symbols. See https://github.com/abseil/abseil-cpp/issues/207 and +// macOS < 10.13 and iOS < 12 don't support , , or +// because the libc++ shared library shipped on the system doesn't have the +// requisite exported symbols. See +// https://github.com/abseil/abseil-cpp/issues/207 and // https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes // // libc++ spells out the availability requirements in the file // llvm-project/libcxx/include/__config via the #define -// _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS. -// -// Unfortunately, Apple initially mis-stated the requirements as macOS < 10.14 -// and iOS < 12 in the libc++ headers. This was corrected by +// _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS. The set of versions has been +// modified a few times, via // https://github.com/llvm/llvm-project/commit/7fb40e1569dd66292b647f4501b85517e9247953 -// which subsequently made it into the XCode 12.5 release. We need to match the -// old (incorrect) conditions when built with old XCode, but can use the -// corrected earlier versions with new XCode. -#if defined(__APPLE__) && defined(_LIBCPP_VERSION) && \ - ((_LIBCPP_VERSION >= 11000 && /* XCode 12.5 or later: */ \ - ((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ - __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101300) || \ - (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \ - __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 110000) || \ - (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \ - __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 40000) || \ - (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \ - __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 110000))) || \ - (_LIBCPP_VERSION < 11000 && /* Pre-XCode 12.5: */ \ - ((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ - __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101400) || \ - (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \ - __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 120000) || \ - (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \ - __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000) || \ - (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \ - __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 120000)))) +// and +// https://github.com/llvm/llvm-project/commit/0bc451e7e137c4ccadcd3377250874f641ca514a +// The second has the actually correct versions, thus, is what we copy here. +#if defined(__APPLE__) && \ + ((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ + __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101300) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \ + __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 120000) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \ + __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \ + __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 120000)) #define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 1 #else #define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 0 From c26cd952ae342ac519fd9f98b67e6152f135c6ce Mon Sep 17 00:00:00 2001 From: Tom Rybka Date: Thu, 6 Jul 2023 09:11:49 -0700 Subject: [PATCH 0104/1238] symbolize_test: Add an indirection for getting the PC from function ptr. Don't assume that function ptr == PC. Adds a redirection mechanism, GetPCFromFnPtr, and enables more test cases for Emscripten/Wasm. On many (most?) platforms, the address of a function ptr is the same as its Program Counter (PC) for the purpose of most things, including symbolization. In Emscripten WebAssembly, the function ptr is just an index into a table of functions. However, the name section maps function names to their literal offsets into a Wasm binary. The WasmOffsetConverter is actually capable of both indirections, so we can effectively go from function ptr to offset into the binary (which is typically the "PC" for other Stack dumping things in Wasm, including `emscripten_pc_get_function`). More info: https://www.w3.org/TR/wasm-js-api-2/#exported-function-exotic-objects Also fix Emscripten symbolize handling for `nullptr` now that we have tests for that. PiperOrigin-RevId: 546006678 Change-Id: I0d4015ca9035b004158451b36c933cad009184ba --- absl/debugging/symbolize_emscripten.inc | 3 + absl/debugging/symbolize_test.cc | 79 +++++++++++++++++-------- 2 files changed, 58 insertions(+), 24 deletions(-) diff --git a/absl/debugging/symbolize_emscripten.inc b/absl/debugging/symbolize_emscripten.inc index c226c456660..a0f344dd9b5 100644 --- a/absl/debugging/symbolize_emscripten.inc +++ b/absl/debugging/symbolize_emscripten.inc @@ -50,6 +50,9 @@ bool Symbolize(const void* pc, char* out, int out_size) { if (!HaveOffsetConverter()) { return false; } + if (pc == nullptr || out_size <= 0) { + return false; + } const char* func_name = emscripten_pc_get_function(pc); if (func_name == nullptr) { return false; diff --git a/absl/debugging/symbolize_test.cc b/absl/debugging/symbolize_test.cc index 1d1199ff79f..922fe36f5e7 100644 --- a/absl/debugging/symbolize_test.cc +++ b/absl/debugging/symbolize_test.cc @@ -14,6 +14,10 @@ #include "absl/debugging/symbolize.h" +#ifdef __EMSCRIPTEN__ +#include +#endif + #ifndef _WIN32 #include #include @@ -107,6 +111,8 @@ static ABSL_PER_THREAD_TLS_KEYWORD char #endif #if !defined(__EMSCRIPTEN__) +static void *GetPCFromFnPtr(void *ptr) { return ptr; } + // Used below to hopefully inhibit some compiler/linker optimizations // that may remove kHpageTextPadding, kPadding0, and kPadding1 from // the binary. @@ -116,6 +122,13 @@ static volatile bool volatile_bool = false; static constexpr size_t kHpageSize = 1 << 21; const char kHpageTextPadding[kHpageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE( .text) = ""; + +#else +static void *GetPCFromFnPtr(void *ptr) { + return EM_ASM_PTR( + { return wasmOffsetConverter.convert(wasmTable.get($0).name, 0); }, ptr); +} + #endif // !defined(__EMSCRIPTEN__) static char try_symbolize_buffer[4096]; @@ -164,15 +177,14 @@ void ABSL_ATTRIBUTE_NOINLINE TestWithReturnAddress() { #endif } -#ifndef ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE - TEST(Symbolize, Cached) { // Compilers should give us pointers to them. - EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func))); - + EXPECT_STREQ("nonstatic_func", + TrySymbolize(GetPCFromFnPtr((void *)(&nonstatic_func)))); // The name of an internal linkage symbol is not specified; allow either a // mangled or an unmangled name here. - const char *static_func_symbol = TrySymbolize((void *)(&static_func)); + const char *static_func_symbol = + TrySymbolize(GetPCFromFnPtr((void *)(&static_func))); EXPECT_TRUE(strcmp("static_func", static_func_symbol) == 0 || strcmp("static_func()", static_func_symbol) == 0); @@ -182,33 +194,50 @@ TEST(Symbolize, Cached) { TEST(Symbolize, Truncation) { constexpr char kNonStaticFunc[] = "nonstatic_func"; EXPECT_STREQ("nonstatic_func", - TrySymbolizeWithLimit((void *)(&nonstatic_func), + TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)), strlen(kNonStaticFunc) + 1)); EXPECT_STREQ("nonstatic_...", - TrySymbolizeWithLimit((void *)(&nonstatic_func), + TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)), strlen(kNonStaticFunc) + 0)); EXPECT_STREQ("nonstatic...", - TrySymbolizeWithLimit((void *)(&nonstatic_func), + TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)), strlen(kNonStaticFunc) - 1)); - EXPECT_STREQ("n...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 5)); - EXPECT_STREQ("...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 4)); - EXPECT_STREQ("..", TrySymbolizeWithLimit((void *)(&nonstatic_func), 3)); - EXPECT_STREQ(".", TrySymbolizeWithLimit((void *)(&nonstatic_func), 2)); - EXPECT_STREQ("", TrySymbolizeWithLimit((void *)(&nonstatic_func), 1)); - EXPECT_EQ(nullptr, TrySymbolizeWithLimit((void *)(&nonstatic_func), 0)); + EXPECT_STREQ("n...", TrySymbolizeWithLimit( + GetPCFromFnPtr((void *)(&nonstatic_func)), 5)); + EXPECT_STREQ("...", TrySymbolizeWithLimit( + GetPCFromFnPtr((void *)(&nonstatic_func)), 4)); + EXPECT_STREQ("..", TrySymbolizeWithLimit( + GetPCFromFnPtr((void *)(&nonstatic_func)), 3)); + EXPECT_STREQ( + ".", TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)), 2)); + EXPECT_STREQ( + "", TrySymbolizeWithLimit(GetPCFromFnPtr((void *)(&nonstatic_func)), 1)); + EXPECT_EQ(nullptr, TrySymbolizeWithLimit( + GetPCFromFnPtr((void *)(&nonstatic_func)), 0)); } TEST(Symbolize, SymbolizeWithDemangling) { Foo::func(100); - EXPECT_STREQ("Foo::func()", TrySymbolize((void *)(&Foo::func))); +#ifdef __EMSCRIPTEN__ + // Emscripten's online symbolizer is more precise with arguments. + EXPECT_STREQ("Foo::func(int)", + TrySymbolize(GetPCFromFnPtr((void *)(&Foo::func)))); +#else + EXPECT_STREQ("Foo::func()", + TrySymbolize(GetPCFromFnPtr((void *)(&Foo::func)))); +#endif } TEST(Symbolize, SymbolizeSplitTextSections) { - EXPECT_STREQ("unlikely_func()", TrySymbolize((void *)(&unlikely_func))); - EXPECT_STREQ("hot_func()", TrySymbolize((void *)(&hot_func))); - EXPECT_STREQ("startup_func()", TrySymbolize((void *)(&startup_func))); - EXPECT_STREQ("exit_func()", TrySymbolize((void *)(&exit_func))); - EXPECT_STREQ("regular_func()", TrySymbolize((void *)(®ular_func))); + EXPECT_STREQ("unlikely_func()", + TrySymbolize(GetPCFromFnPtr((void *)(&unlikely_func)))); + EXPECT_STREQ("hot_func()", TrySymbolize(GetPCFromFnPtr((void *)(&hot_func)))); + EXPECT_STREQ("startup_func()", + TrySymbolize(GetPCFromFnPtr((void *)(&startup_func)))); + EXPECT_STREQ("exit_func()", + TrySymbolize(GetPCFromFnPtr((void *)(&exit_func)))); + EXPECT_STREQ("regular_func()", + TrySymbolize(GetPCFromFnPtr((void *)(®ular_func)))); } // Tests that verify that Symbolize stack footprint is within some limit. @@ -278,7 +307,8 @@ TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) { #endif // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION -#ifndef ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE +#if !defined(ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE) && \ + !defined(ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE) // Use a 64K page size for PPC. const size_t kPageSize = 64 << 10; // We place a read-only symbols into the .text section and verify that we can @@ -436,8 +466,8 @@ TEST(Symbolize, ForEachSection) { close(fd); } -#endif // !ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE -#endif // !ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE +#endif // !ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE && + // !ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE // x86 specific tests. Uses some inline assembler. extern "C" { @@ -598,7 +628,8 @@ int main(int argc, char **argv) { absl::InitializeSymbolizer(argv[0]); testing::InitGoogleTest(&argc, argv); -#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) || \ +#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) || \ + defined(ABSL_INTERNAL_HAVE_EMSCRIPTEN_SYMBOLIZE) || \ defined(ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE) TestWithPCInsideInlineFunction(); TestWithPCInsideNonInlineFunction(); From 93ef827f6160dd41e11042ce638e052272f77d7b Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 6 Jul 2023 10:49:58 -0700 Subject: [PATCH 0105/1238] Rename `absl::NonNull` to `absl::Nonnull`. The current spelling is inconsistent with standard casing rules: "nonnull" is a single word, not two. PiperOrigin-RevId: 546034114 Change-Id: I04e5a204f4a74ebaa76031dd0b0874ca9cfa902c --- absl/base/internal/nullability_impl.h | 6 +++--- absl/base/nullability.h | 18 +++++++++--------- absl/base/nullability_test.cc | 26 +++++++++++++------------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/absl/base/internal/nullability_impl.h b/absl/base/internal/nullability_impl.h index 74f4a4177af..36e1b33d65a 100644 --- a/absl/base/internal/nullability_impl.h +++ b/absl/base/internal/nullability_impl.h @@ -60,7 +60,7 @@ struct EnableNullable { }; template -struct EnableNonNull { +struct EnableNonnull { static_assert(nullability_internal::IsSupportedType>, "Template argument must be a raw or supported smart pointer " "type. See absl/base/nullability.h."); @@ -86,8 +86,8 @@ using NullableImpl #endif = T; -template ::type> -using NonNullImpl +template ::type> +using NonnullImpl #if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate) [[clang::annotate("Nonnull")]] #endif diff --git a/absl/base/nullability.h b/absl/base/nullability.h index 42525dd0d63..17553d0c54d 100644 --- a/absl/base/nullability.h +++ b/absl/base/nullability.h @@ -20,7 +20,7 @@ // expected nullability of pointers. These annotations allow you to designate // pointers in one of three classification states: // -// * "Non-null" (for pointers annotated `NonNull`), indicating that it is +// * "Non-null" (for pointers annotated `Nonnull`), indicating that it is // invalid for the given pointer to ever be null. // * "Nullable" (for pointers annotated `Nullable`), indicating that it is // valid for the given pointer to be null. @@ -69,7 +69,7 @@ // // It is important to note that these annotations are not distinct strong // *types*. They are alias templates defined to be equal to the underlying -// pointer type. A pointer annotated `NonNull`, for example, is simply a +// pointer type. A pointer annotated `Nonnull`, for example, is simply a // pointer of type `T*`. Each annotation acts as a form of documentation about // the contract for the given pointer. Each annotation requires providers or // consumers of these pointers across API boundaries to take appropriate steps @@ -91,13 +91,13 @@ // Example: // // // PaySalary() requires the passed pointer to an `Employee` to be non-null. -// void PaySalary(absl::NonNull e) { +// void PaySalary(absl::Nonnull e) { // pay(e->salary); // OK to dereference // } // // // CompleteTransaction() guarantees the returned pointer to an `Account` to // // be non-null. -// absl::NonNull balance CompleteTransaction(double fee) { +// absl::Nonnull balance CompleteTransaction(double fee) { // ... // } // @@ -144,8 +144,8 @@ // These nullability annotations are primarily a human readable signal about the // intended contract of the pointer. They are not *types* and do not currently // provide any correctness guarantees. For example, a pointer annotated as -// `NonNull` is *not guaranteed* to be non-null, and the compiler won't -// alert or prevent assignment of a `Nullable` to a `NonNull`. +// `Nonnull` is *not guaranteed* to be non-null, and the compiler won't +// alert or prevent assignment of a `Nullable` to a `Nonnull`. // =========================================================================== #ifndef ABSL_BASE_NULLABILITY_H_ #define ABSL_BASE_NULLABILITY_H_ @@ -154,7 +154,7 @@ namespace absl { -// absl::NonNull +// absl::Nonnull // // The indicated pointer is never null. It is the responsibility of the provider // of this pointer across an API boundary to ensure that the pointer is never be @@ -168,7 +168,7 @@ namespace absl { // pay(*employee); // OK to dereference // } template -using NonNull = nullability_internal::NonNullImpl; +using Nonnull = nullability_internal::NonnullImpl; // absl::Nullable // @@ -195,7 +195,7 @@ using Nullable = nullability_internal::NullableImpl; // Consumers of these pointers across an API boundary should treat such pointers // with the same caution they treat currently unannotated pointers. Most // existing code will have "unknown" pointers, which should eventually be -// migrated into one of the above two nullability states: `NonNull` or +// migrated into one of the above two nullability states: `Nonnull` or // `Nullable`. // // NOTE: Because this annotation is the global default state, pointers without diff --git a/absl/base/nullability_test.cc b/absl/base/nullability_test.cc index 6edd7cd144a..028ea6ca1ee 100644 --- a/absl/base/nullability_test.cc +++ b/absl/base/nullability_test.cc @@ -22,73 +22,73 @@ #include "absl/base/attributes.h" namespace { -using ::absl::NonNull; +using ::absl::Nonnull; using ::absl::NullabilityUnknown; using ::absl::Nullable; -void funcWithNonnullArg(NonNull /*arg*/) {} +void funcWithNonnullArg(Nonnull /*arg*/) {} template -void funcWithDeducedNonnullArg(NonNull /*arg*/) {} +void funcWithDeducedNonnullArg(Nonnull /*arg*/) {} -TEST(NonNullTest, NonNullArgument) { +TEST(NonnullTest, NonnullArgument) { int var = 0; funcWithNonnullArg(&var); funcWithDeducedNonnullArg(&var); } -NonNull funcWithNonnullReturn() { +Nonnull funcWithNonnullReturn() { static int var = 0; return &var; } -TEST(NonNullTest, NonNullReturn) { +TEST(NonnullTest, NonnullReturn) { auto var = funcWithNonnullReturn(); (void)var; } TEST(PassThroughTest, PassesThroughRawPointerToInt) { - EXPECT_TRUE((std::is_same, int*>::value)); + EXPECT_TRUE((std::is_same, int*>::value)); EXPECT_TRUE((std::is_same, int*>::value)); EXPECT_TRUE((std::is_same, int*>::value)); } TEST(PassThroughTest, PassesThroughRawPointerToVoid) { - EXPECT_TRUE((std::is_same, void*>::value)); + EXPECT_TRUE((std::is_same, void*>::value)); EXPECT_TRUE((std::is_same, void*>::value)); EXPECT_TRUE((std::is_same, void*>::value)); } TEST(PassThroughTest, PassesThroughUniquePointerToInt) { using T = std::unique_ptr; - EXPECT_TRUE((std::is_same, T>::value)); + EXPECT_TRUE((std::is_same, T>::value)); EXPECT_TRUE((std::is_same, T>::value)); EXPECT_TRUE((std::is_same, T>::value)); } TEST(PassThroughTest, PassesThroughSharedPointerToInt) { using T = std::shared_ptr; - EXPECT_TRUE((std::is_same, T>::value)); + EXPECT_TRUE((std::is_same, T>::value)); EXPECT_TRUE((std::is_same, T>::value)); EXPECT_TRUE((std::is_same, T>::value)); } TEST(PassThroughTest, PassesThroughSharedPointerToVoid) { using T = std::shared_ptr; - EXPECT_TRUE((std::is_same, T>::value)); + EXPECT_TRUE((std::is_same, T>::value)); EXPECT_TRUE((std::is_same, T>::value)); EXPECT_TRUE((std::is_same, T>::value)); } TEST(PassThroughTest, PassesThroughPointerToMemberObject) { using T = decltype(&std::pair::first); - EXPECT_TRUE((std::is_same, T>::value)); + EXPECT_TRUE((std::is_same, T>::value)); EXPECT_TRUE((std::is_same, T>::value)); EXPECT_TRUE((std::is_same, T>::value)); } TEST(PassThroughTest, PassesThroughPointerToMemberFunction) { using T = decltype(&std::unique_ptr::reset); - EXPECT_TRUE((std::is_same, T>::value)); + EXPECT_TRUE((std::is_same, T>::value)); EXPECT_TRUE((std::is_same, T>::value)); EXPECT_TRUE((std::is_same, T>::value)); } From c3db833081448eb2675481a12578d3fc204b0237 Mon Sep 17 00:00:00 2001 From: Benjamin Buch Date: Fri, 7 Jul 2023 14:14:41 +0200 Subject: [PATCH 0106/1238] enable CMP0141 to allow user CMAKE_MSVC_DEBUG_INFORMATION_FORMAT --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index ae799811a2f..16915a14e76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,11 @@ if (POLICY CMP0067) cmake_policy(SET CMP0067 NEW) endif (POLICY CMP0067) +# Allow the user to specify the CMAKE_MSVC_DEBUG_INFORMATION_FORMAT +if (POLICY CMP0141) + cmake_policy(SET CMP0141 NEW) +endif (POLICY CMP0141) + project(absl LANGUAGES CXX) include(CTest) From 81b9030e78755ca2f581765fc44386cd576f122b Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 10 Jul 2023 09:37:50 -0700 Subject: [PATCH 0107/1238] Fix a typo of absl::Nonnull in the example comment. PiperOrigin-RevId: 546897533 Change-Id: I3ad12f252c49e4672a64d00d0107111fdc5b6ac8 --- absl/base/nullability.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/absl/base/nullability.h b/absl/base/nullability.h index 17553d0c54d..6f49b6f535b 100644 --- a/absl/base/nullability.h +++ b/absl/base/nullability.h @@ -164,7 +164,7 @@ namespace absl { // Example: // // // `employee` is designated as not null. -// void PaySalary(absl::NotNull employee) { +// void PaySalary(absl::Nonnull employee) { // pay(*employee); // OK to dereference // } template From 20cf119df47eb7d1d9e7813d15d01f2ea7dc9bc3 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Mon, 10 Jul 2023 10:37:27 -0700 Subject: [PATCH 0108/1238] Use an allowlist visibility model for //absl/synchronization PiperOrigin-RevId: 546914671 Change-Id: I6f0419103efdd8125e4027e7d5eec124ca604156 --- absl/synchronization/BUILD.bazel | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/absl/synchronization/BUILD.bazel b/absl/synchronization/BUILD.bazel index 3d405df83b6..0ca94e01165 100644 --- a/absl/synchronization/BUILD.bazel +++ b/absl/synchronization/BUILD.bazel @@ -21,7 +21,7 @@ load( "ABSL_TEST_COPTS", ) -package(default_visibility = ["//visibility:public"]) +package(default_visibility = ["//visibility:private"]) licenses(["notice"]) @@ -38,9 +38,6 @@ cc_library( "//conditions:default": [], }), linkopts = ABSL_DEFAULT_LINKOPTS, - visibility = [ - "//absl:__subpackages__", - ], deps = [ "//absl/base", "//absl/base:base_internal", @@ -58,7 +55,6 @@ cc_library( copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ - "//absl/synchronization:__pkg__", ], deps = [ "//absl/base", @@ -123,6 +119,7 @@ cc_library( "//absl:wasm": [], "//conditions:default": ["-pthread"], }) + ABSL_DEFAULT_LINKOPTS, + visibility = ["//visibility:public"], deps = [ ":graphcycles_internal", ":kernel_timeout_internal", @@ -149,7 +146,7 @@ cc_test( copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, tags = [ - "no_test_wasm", + "no_test_wasm", # b/122473323 ], deps = [ ":synchronization", @@ -165,7 +162,7 @@ cc_test( copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, tags = [ - "no_test_wasm", + "no_test_wasm", # b/122473323 ], deps = [ ":synchronization", @@ -181,7 +178,6 @@ cc_binary( copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, tags = ["benchmark"], - visibility = ["//visibility:private"], deps = [ ":synchronization", ":thread_pool", @@ -275,7 +271,6 @@ cc_library( copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, visibility = [ - "//absl/synchronization:__pkg__", ], deps = [ ":synchronization", @@ -292,7 +287,6 @@ cc_binary( testonly = 1, copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - visibility = ["//visibility:private"], deps = [ ":mutex_benchmark_common", ], @@ -319,6 +313,8 @@ cc_library( srcs = ["internal/per_thread_sem_test.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, + visibility = [ + ], deps = [ ":synchronization", "//absl/base", From b2a6c1bca7e177cf033ebe2361e8f2d99fabf9a9 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Tue, 11 Jul 2023 10:57:18 -0700 Subject: [PATCH 0109/1238] Cleanup `//absl/strings/internal/memutil.h` `memmatch()` is only used in `string_view.cc`, so move it there. The moving of `memmatch()` to `string_view.cc` decouples `string_view` from `memutil`, which will allow us to move `string_view` into its own target in a followup. The only other function that is used is `memcasecmp()`, so delete all other functions. PiperOrigin-RevId: 547238386 Change-Id: Id6fad47dd24191c8e8f26dd923fffa1007c8db4a --- absl/strings/internal/memutil.cc | 79 +-------- absl/strings/internal/memutil.h | 116 +----------- absl/strings/internal/memutil_benchmark.cc | 195 --------------------- absl/strings/internal/memutil_test.cc | 142 +-------------- absl/strings/string_view.cc | 30 +++- 5 files changed, 34 insertions(+), 528 deletions(-) diff --git a/absl/strings/internal/memutil.cc b/absl/strings/internal/memutil.cc index 44996a75496..e2e7347c49b 100644 --- a/absl/strings/internal/memutil.cc +++ b/absl/strings/internal/memutil.cc @@ -16,6 +16,8 @@ #include +#include "absl/strings/ascii.h" + namespace absl { ABSL_NAMESPACE_BEGIN namespace strings_internal { @@ -33,83 +35,6 @@ int memcasecmp(const char* s1, const char* s2, size_t len) { return 0; } -char* memdup(const char* s, size_t slen) { - void* copy; - if ((copy = malloc(slen)) == nullptr) return nullptr; - memcpy(copy, s, slen); - return reinterpret_cast(copy); -} - -char* memrchr(const char* s, int c, size_t slen) { - for (const char* e = s + slen - 1; e >= s; e--) { - if (*e == c) return const_cast(e); - } - return nullptr; -} - -size_t memspn(const char* s, size_t slen, const char* accept) { - const char* p = s; - const char* spanp; - char c, sc; - -cont: - c = *p++; - if (slen-- == 0) - return static_cast(p - 1 - s); - for (spanp = accept; (sc = *spanp++) != '\0';) - if (sc == c) goto cont; - return static_cast(p - 1 - s); -} - -size_t memcspn(const char* s, size_t slen, const char* reject) { - const char* p = s; - const char* spanp; - char c, sc; - - while (slen-- != 0) { - c = *p++; - for (spanp = reject; (sc = *spanp++) != '\0';) - if (sc == c) - return static_cast(p - 1 - s); - } - return static_cast(p - s); -} - -char* mempbrk(const char* s, size_t slen, const char* accept) { - const char* scanp; - int sc; - - for (; slen; ++s, --slen) { - for (scanp = accept; (sc = *scanp++) != '\0';) - if (sc == *s) return const_cast(s); - } - return nullptr; -} - -// This is significantly faster for case-sensitive matches with very -// few possible matches. See unit test for benchmarks. -const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle, - size_t neelen) { - if (0 == neelen) { - return phaystack; // even if haylen is 0 - } - if (haylen < neelen) return nullptr; - - const char* match; - const char* hayend = phaystack + haylen - neelen + 1; - // A static cast is used here to work around the fact that memchr returns - // a void* on Posix-compliant systems and const void* on Windows. - while ( - (match = static_cast(memchr( - phaystack, pneedle[0], static_cast(hayend - phaystack))))) { - if (memcmp(match, pneedle, neelen) == 0) - return match; - else - phaystack = match + 1; - } - return nullptr; -} - } // namespace strings_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/strings/internal/memutil.h b/absl/strings/internal/memutil.h index 9ad05358086..b5911a01cd8 100644 --- a/absl/strings/internal/memutil.h +++ b/absl/strings/internal/memutil.h @@ -14,51 +14,6 @@ // limitations under the License. // -// These routines provide mem versions of standard C string routines, -// such as strpbrk. They function exactly the same as the str versions, -// so if you wonder what they are, replace the word "mem" by -// "str" and check out the man page. I could return void*, as the -// strutil.h mem*() routines tend to do, but I return char* instead -// since this is by far the most common way these functions are called. -// -// The difference between the mem and str versions is the mem version -// takes a pointer and a length, rather than a '\0'-terminated string. -// The memcase* routines defined here assume the locale is "C" -// (they use absl::ascii_tolower instead of tolower). -// -// These routines are based on the BSD library. -// -// Here's a list of routines from string.h, and their mem analogues. -// Functions in lowercase are defined in string.h; those in UPPERCASE -// are defined here: -// -// strlen -- -// strcat strncat MEMCAT -// strcpy strncpy memcpy -// -- memccpy (very cool function, btw) -// -- memmove -// -- memset -// strcmp strncmp memcmp -// strcasecmp strncasecmp MEMCASECMP -// strchr memchr -// strcoll -- -// strxfrm -- -// strdup strndup MEMDUP -// strrchr MEMRCHR -// strspn MEMSPN -// strcspn MEMCSPN -// strpbrk MEMPBRK -// strstr MEMSTR MEMMEM -// (g)strcasestr MEMCASESTR MEMCASEMEM -// strtok -- -// strprefix MEMPREFIX (strprefix is from strutil.h) -// strcaseprefix MEMCASEPREFIX (strcaseprefix is from strutil.h) -// strsuffix MEMSUFFIX (strsuffix is from strutil.h) -// strcasesuffix MEMCASESUFFIX (strcasesuffix is from strutil.h) -// -- MEMIS -// -- MEMCASEIS -// strcount MEMCOUNT (strcount is from strutil.h) - #ifndef ABSL_STRINGS_INTERNAL_MEMUTIL_H_ #define ABSL_STRINGS_INTERNAL_MEMUTIL_H_ @@ -72,74 +27,11 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace strings_internal { -inline char* memcat(char* dest, size_t destlen, const char* src, - size_t srclen) { - return reinterpret_cast(memcpy(dest + destlen, src, srclen)); -} - +// Performs a byte-by-byte comparison of `len` bytes of the strings `s1` and +// `s2`, ignoring the case of the characters. It returns an integer less than, +// equal to, or greater than zero if `s1` is found, respectively, to be less +// than, to match, or be greater than `s2`. int memcasecmp(const char* s1, const char* s2, size_t len); -char* memdup(const char* s, size_t slen); -char* memrchr(const char* s, int c, size_t slen); -size_t memspn(const char* s, size_t slen, const char* accept); -size_t memcspn(const char* s, size_t slen, const char* reject); -char* mempbrk(const char* s, size_t slen, const char* accept); - -// This is for internal use only. Don't call this directly -template -const char* int_memmatch(const char* haystack, size_t haylen, - const char* needle, size_t neelen) { - if (0 == neelen) { - return haystack; // even if haylen is 0 - } - const char* hayend = haystack + haylen; - const char* needlestart = needle; - const char* needleend = needlestart + neelen; - - for (; haystack < hayend; ++haystack) { - char hay = case_sensitive - ? *haystack - : absl::ascii_tolower(static_cast(*haystack)); - char nee = case_sensitive - ? *needle - : absl::ascii_tolower(static_cast(*needle)); - if (hay == nee) { - if (++needle == needleend) { - return haystack + 1 - neelen; - } - } else if (needle != needlestart) { - // must back up haystack in case a prefix matched (find "aab" in "aaab") - haystack -= needle - needlestart; // for loop will advance one more - needle = needlestart; - } - } - return nullptr; -} - -// These are the guys you can call directly -inline const char* memstr(const char* phaystack, size_t haylen, - const char* pneedle) { - return int_memmatch(phaystack, haylen, pneedle, strlen(pneedle)); -} - -inline const char* memcasestr(const char* phaystack, size_t haylen, - const char* pneedle) { - return int_memmatch(phaystack, haylen, pneedle, strlen(pneedle)); -} - -inline const char* memmem(const char* phaystack, size_t haylen, - const char* pneedle, size_t needlelen) { - return int_memmatch(phaystack, haylen, pneedle, needlelen); -} - -inline const char* memcasemem(const char* phaystack, size_t haylen, - const char* pneedle, size_t needlelen) { - return int_memmatch(phaystack, haylen, pneedle, needlelen); -} - -// This is significantly faster for case-sensitive matches with very -// few possible matches. See unit test for benchmarks. -const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle, - size_t neelen); } // namespace strings_internal ABSL_NAMESPACE_END diff --git a/absl/strings/internal/memutil_benchmark.cc b/absl/strings/internal/memutil_benchmark.cc index dc95c3e5e55..61e323a4271 100644 --- a/absl/strings/internal/memutil_benchmark.cc +++ b/absl/strings/internal/memutil_benchmark.cc @@ -25,62 +25,6 @@ // - an easy search: 'b' // - a medium search: 'ab'. That means every letter is a possible match. // - a pathological search: 'aaaaaa.......aaaaab' (half as many a's as haytack) -// We benchmark case-sensitive and case-insensitive versions of -// three memmem implementations: -// - memmem() from memutil.h -// - search() from STL -// - memmatch(), a custom implementation using memchr and memcmp. -// Here are sample results: -// -// Run on (12 X 3800 MHz CPU s) -// CPU Caches: -// L1 Data 32K (x6) -// L1 Instruction 32K (x6) -// L2 Unified 256K (x6) -// L3 Unified 15360K (x1) -// ---------------------------------------------------------------- -// Benchmark Time CPU Iterations -// ---------------------------------------------------------------- -// BM_Memmem 3583 ns 3582 ns 196469 2.59966GB/s -// BM_MemmemMedium 13743 ns 13742 ns 50901 693.986MB/s -// BM_MemmemPathological 13695030 ns 13693977 ns 51 713.133kB/s -// BM_Memcasemem 3299 ns 3299 ns 212942 2.82309GB/s -// BM_MemcasememMedium 16407 ns 16406 ns 42170 581.309MB/s -// BM_MemcasememPathological 17267745 ns 17266030 ns 41 565.598kB/s -// BM_Search 1610 ns 1609 ns 431321 5.78672GB/s -// BM_SearchMedium 11111 ns 11110 ns 63001 858.414MB/s -// BM_SearchPathological 12117390 ns 12116397 ns 58 805.984kB/s -// BM_Searchcase 3081 ns 3081 ns 229949 3.02313GB/s -// BM_SearchcaseMedium 16003 ns 16001 ns 44170 595.998MB/s -// BM_SearchcasePathological 15823413 ns 15821909 ns 44 617.222kB/s -// BM_Memmatch 197 ns 197 ns 3584225 47.2951GB/s -// BM_MemmatchMedium 52333 ns 52329 ns 13280 182.244MB/s -// BM_MemmatchPathological 659799 ns 659727 ns 1058 14.4556MB/s -// BM_Memcasematch 5460 ns 5460 ns 127606 1.70586GB/s -// BM_MemcasematchMedium 32861 ns 32857 ns 21258 290.248MB/s -// BM_MemcasematchPathological 15154243 ns 15153089 ns 46 644.464kB/s -// BM_MemmemStartup 5 ns 5 ns 150821500 -// BM_SearchStartup 5 ns 5 ns 150644203 -// BM_MemmatchStartup 7 ns 7 ns 97068802 -// -// Conclusions: -// -// The following recommendations are based on the sample results above. However, -// we have found that the performance of STL search can vary significantly -// depending on compiler and standard library implementation. We recommend you -// run the benchmarks for yourself on relevant platforms. -// -// If you need case-insensitive, STL search is slightly better than memmem for -// all cases. -// -// Case-sensitive is more subtle: -// Custom memmatch is _very_ fast at scanning, so if you have very few possible -// matches in your haystack, that's the way to go. Performance drops -// significantly with more matches. -// -// STL search is slightly faster than memmem in the medium and pathological -// benchmarks. However, the performance of memmem is currently more dependable -// across platforms and build configurations. namespace { @@ -94,96 +38,10 @@ const char* MakeHaystack() { } const char* const kHaystack = MakeHaystack(); -void BM_Memmem(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize( - absl::strings_internal::memmem(kHaystack, kHaystackSize, "b", 1)); - } - state.SetBytesProcessed(kHaystackSize64 * state.iterations()); -} -BENCHMARK(BM_Memmem); - -void BM_MemmemMedium(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize( - absl::strings_internal::memmem(kHaystack, kHaystackSize, "ab", 2)); - } - state.SetBytesProcessed(kHaystackSize64 * state.iterations()); -} -BENCHMARK(BM_MemmemMedium); - -void BM_MemmemPathological(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize(absl::strings_internal::memmem( - kHaystack, kHaystackSize, kHaystack + kHaystackSize / 2, - kHaystackSize - kHaystackSize / 2)); - } - state.SetBytesProcessed(kHaystackSize64 * state.iterations()); -} -BENCHMARK(BM_MemmemPathological); - -void BM_Memcasemem(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize( - absl::strings_internal::memcasemem(kHaystack, kHaystackSize, "b", 1)); - } - state.SetBytesProcessed(kHaystackSize64 * state.iterations()); -} -BENCHMARK(BM_Memcasemem); - -void BM_MemcasememMedium(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize( - absl::strings_internal::memcasemem(kHaystack, kHaystackSize, "ab", 2)); - } - state.SetBytesProcessed(kHaystackSize64 * state.iterations()); -} -BENCHMARK(BM_MemcasememMedium); - -void BM_MemcasememPathological(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize(absl::strings_internal::memcasemem( - kHaystack, kHaystackSize, kHaystack + kHaystackSize / 2, - kHaystackSize - kHaystackSize / 2)); - } - state.SetBytesProcessed(kHaystackSize64 * state.iterations()); -} -BENCHMARK(BM_MemcasememPathological); - bool case_eq(const char a, const char b) { return absl::ascii_tolower(a) == absl::ascii_tolower(b); } -void BM_Search(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize, - kHaystack + kHaystackSize - 1, - kHaystack + kHaystackSize)); - } - state.SetBytesProcessed(kHaystackSize64 * state.iterations()); -} -BENCHMARK(BM_Search); - -void BM_SearchMedium(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize, - kHaystack + kHaystackSize - 2, - kHaystack + kHaystackSize)); - } - state.SetBytesProcessed(kHaystackSize64 * state.iterations()); -} -BENCHMARK(BM_SearchMedium); - -void BM_SearchPathological(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize, - kHaystack + kHaystackSize / 2, - kHaystack + kHaystackSize)); - } - state.SetBytesProcessed(kHaystackSize64 * state.iterations()); -} -BENCHMARK(BM_SearchPathological); - void BM_Searchcase(benchmark::State& state) { for (auto _ : state) { benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize, @@ -241,34 +99,6 @@ const char* memcasematch(const char* phaystack, size_t haylen, return nullptr; } -void BM_Memmatch(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize( - absl::strings_internal::memmatch(kHaystack, kHaystackSize, "b", 1)); - } - state.SetBytesProcessed(kHaystackSize64 * state.iterations()); -} -BENCHMARK(BM_Memmatch); - -void BM_MemmatchMedium(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize( - absl::strings_internal::memmatch(kHaystack, kHaystackSize, "ab", 2)); - } - state.SetBytesProcessed(kHaystackSize64 * state.iterations()); -} -BENCHMARK(BM_MemmatchMedium); - -void BM_MemmatchPathological(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize(absl::strings_internal::memmatch( - kHaystack, kHaystackSize, kHaystack + kHaystackSize / 2, - kHaystackSize - kHaystackSize / 2)); - } - state.SetBytesProcessed(kHaystackSize64 * state.iterations()); -} -BENCHMARK(BM_MemmatchPathological); - void BM_Memcasematch(benchmark::State& state) { for (auto _ : state) { benchmark::DoNotOptimize(memcasematch(kHaystack, kHaystackSize, "b", 1)); @@ -295,29 +125,4 @@ void BM_MemcasematchPathological(benchmark::State& state) { } BENCHMARK(BM_MemcasematchPathological); -void BM_MemmemStartup(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize(absl::strings_internal::memmem( - kHaystack + kHaystackSize - 10, 10, kHaystack + kHaystackSize - 1, 1)); - } -} -BENCHMARK(BM_MemmemStartup); - -void BM_SearchStartup(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize( - std::search(kHaystack + kHaystackSize - 10, kHaystack + kHaystackSize, - kHaystack + kHaystackSize - 1, kHaystack + kHaystackSize)); - } -} -BENCHMARK(BM_SearchStartup); - -void BM_MemmatchStartup(benchmark::State& state) { - for (auto _ : state) { - benchmark::DoNotOptimize(absl::strings_internal::memmatch( - kHaystack + kHaystackSize - 10, 10, kHaystack + kHaystackSize - 1, 1)); - } -} -BENCHMARK(BM_MemmatchStartup); - } // namespace diff --git a/absl/strings/internal/memutil_test.cc b/absl/strings/internal/memutil_test.cc index d8681ddf4e3..277be2c4916 100644 --- a/absl/strings/internal/memutil_test.cc +++ b/absl/strings/internal/memutil_test.cc @@ -19,42 +19,12 @@ #include #include "gtest/gtest.h" -#include "absl/strings/ascii.h" namespace { -static char* memcasechr(const char* s, int c, size_t slen) { - c = absl::ascii_tolower(c); - for (; slen; ++s, --slen) { - if (absl::ascii_tolower(*s) == c) return const_cast(s); - } - return nullptr; -} - -static const char* memcasematch(const char* phaystack, size_t haylen, - const char* pneedle, size_t neelen) { - if (0 == neelen) { - return phaystack; // even if haylen is 0 - } - if (haylen < neelen) return nullptr; - - const char* match; - const char* hayend = phaystack + haylen - neelen + 1; - while ((match = static_cast( - memcasechr(phaystack, pneedle[0], hayend - phaystack)))) { - if (absl::strings_internal::memcasecmp(match, pneedle, neelen) == 0) - return match; - else - phaystack = match + 1; - } - return nullptr; -} - -TEST(MemUtilTest, AllTests) { +TEST(MemUtil, memcasecmp) { // check memutil functions - char a[1000]; - absl::strings_internal::memcat(a, 0, "hello", sizeof("hello") - 1); - absl::strings_internal::memcat(a, 5, " there", sizeof(" there") - 1); + const char a[] = "hello there"; EXPECT_EQ(absl::strings_internal::memcasecmp(a, "heLLO there", sizeof("hello there") - 1), @@ -66,114 +36,6 @@ TEST(MemUtilTest, AllTests) { sizeof("hello there") - 2), 0); EXPECT_EQ(absl::strings_internal::memcasecmp(a, "whatever", 0), 0); - - char* p = absl::strings_internal::memdup("hello", 5); - free(p); - - p = absl::strings_internal::memrchr("hello there", 'e', - sizeof("hello there") - 1); - EXPECT_TRUE(p && p[-1] == 'r'); - p = absl::strings_internal::memrchr("hello there", 'e', - sizeof("hello there") - 2); - EXPECT_TRUE(p && p[-1] == 'h'); - p = absl::strings_internal::memrchr("hello there", 'u', - sizeof("hello there") - 1); - EXPECT_TRUE(p == nullptr); - - int len = absl::strings_internal::memspn("hello there", - sizeof("hello there") - 1, "hole"); - EXPECT_EQ(len, sizeof("hello") - 1); - len = absl::strings_internal::memspn("hello there", sizeof("hello there") - 1, - "u"); - EXPECT_EQ(len, 0); - len = absl::strings_internal::memspn("hello there", sizeof("hello there") - 1, - ""); - EXPECT_EQ(len, 0); - len = absl::strings_internal::memspn("hello there", sizeof("hello there") - 1, - "trole h"); - EXPECT_EQ(len, sizeof("hello there") - 1); - len = absl::strings_internal::memspn("hello there!", - sizeof("hello there!") - 1, "trole h"); - EXPECT_EQ(len, sizeof("hello there") - 1); - len = absl::strings_internal::memspn("hello there!", - sizeof("hello there!") - 2, "trole h!"); - EXPECT_EQ(len, sizeof("hello there!") - 2); - - len = absl::strings_internal::memcspn("hello there", - sizeof("hello there") - 1, "leho"); - EXPECT_EQ(len, 0); - len = absl::strings_internal::memcspn("hello there", - sizeof("hello there") - 1, "u"); - EXPECT_EQ(len, sizeof("hello there") - 1); - len = absl::strings_internal::memcspn("hello there", - sizeof("hello there") - 1, ""); - EXPECT_EQ(len, sizeof("hello there") - 1); - len = absl::strings_internal::memcspn("hello there", - sizeof("hello there") - 1, " "); - EXPECT_EQ(len, 5); - - p = absl::strings_internal::mempbrk("hello there", sizeof("hello there") - 1, - "leho"); - EXPECT_TRUE(p && p[1] == 'e' && p[2] == 'l'); - p = absl::strings_internal::mempbrk("hello there", sizeof("hello there") - 1, - "nu"); - EXPECT_TRUE(p == nullptr); - p = absl::strings_internal::mempbrk("hello there!", - sizeof("hello there!") - 2, "!"); - EXPECT_TRUE(p == nullptr); - p = absl::strings_internal::mempbrk("hello there", sizeof("hello there") - 1, - " t "); - EXPECT_TRUE(p && p[-1] == 'o' && p[1] == 't'); - - { - const char kHaystack[] = "0123456789"; - EXPECT_EQ(absl::strings_internal::memmem(kHaystack, 0, "", 0), kHaystack); - EXPECT_EQ(absl::strings_internal::memmem(kHaystack, 10, "012", 3), - kHaystack); - EXPECT_EQ(absl::strings_internal::memmem(kHaystack, 10, "0xx", 1), - kHaystack); - EXPECT_EQ(absl::strings_internal::memmem(kHaystack, 10, "789", 3), - kHaystack + 7); - EXPECT_EQ(absl::strings_internal::memmem(kHaystack, 10, "9xx", 1), - kHaystack + 9); - EXPECT_TRUE(absl::strings_internal::memmem(kHaystack, 10, "9xx", 3) == - nullptr); - EXPECT_TRUE(absl::strings_internal::memmem(kHaystack, 10, "xxx", 1) == - nullptr); - } - { - const char kHaystack[] = "aBcDeFgHiJ"; - EXPECT_EQ(absl::strings_internal::memcasemem(kHaystack, 0, "", 0), - kHaystack); - EXPECT_EQ(absl::strings_internal::memcasemem(kHaystack, 10, "Abc", 3), - kHaystack); - EXPECT_EQ(absl::strings_internal::memcasemem(kHaystack, 10, "Axx", 1), - kHaystack); - EXPECT_EQ(absl::strings_internal::memcasemem(kHaystack, 10, "hIj", 3), - kHaystack + 7); - EXPECT_EQ(absl::strings_internal::memcasemem(kHaystack, 10, "jxx", 1), - kHaystack + 9); - EXPECT_TRUE(absl::strings_internal::memcasemem(kHaystack, 10, "jxx", 3) == - nullptr); - EXPECT_TRUE(absl::strings_internal::memcasemem(kHaystack, 10, "xxx", 1) == - nullptr); - } - { - const char kHaystack[] = "0123456789"; - EXPECT_EQ(absl::strings_internal::memmatch(kHaystack, 0, "", 0), kHaystack); - EXPECT_EQ(absl::strings_internal::memmatch(kHaystack, 10, "012", 3), - kHaystack); - EXPECT_EQ(absl::strings_internal::memmatch(kHaystack, 10, "0xx", 1), - kHaystack); - EXPECT_EQ(absl::strings_internal::memmatch(kHaystack, 10, "789", 3), - kHaystack + 7); - EXPECT_EQ(absl::strings_internal::memmatch(kHaystack, 10, "9xx", 1), - kHaystack + 9); - EXPECT_TRUE(absl::strings_internal::memmatch(kHaystack, 10, "9xx", 3) == - nullptr); - EXPECT_TRUE(absl::strings_internal::memmatch(kHaystack, 10, "xxx", 1) == - nullptr); - } } } // namespace diff --git a/absl/strings/string_view.cc b/absl/strings/string_view.cc index e2261625f92..f20ff5306e2 100644 --- a/absl/strings/string_view.cc +++ b/absl/strings/string_view.cc @@ -21,12 +21,35 @@ #include #include -#include "absl/strings/internal/memutil.h" - namespace absl { ABSL_NAMESPACE_BEGIN namespace { + +// This is significantly faster for case-sensitive matches with very +// few possible matches. +const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle, + size_t neelen) { + if (0 == neelen) { + return phaystack; // even if haylen is 0 + } + if (haylen < neelen) return nullptr; + + const char* match; + const char* hayend = phaystack + haylen - neelen + 1; + // A static cast is used here to work around the fact that memchr returns + // a void* on Posix-compliant systems and const void* on Windows. + while ( + (match = static_cast(memchr( + phaystack, pneedle[0], static_cast(hayend - phaystack))))) { + if (memcmp(match, pneedle, neelen) == 0) + return match; + else + phaystack = match + 1; + } + return nullptr; +} + void WritePadding(std::ostream& o, size_t pad) { char fill_buf[32]; memset(fill_buf, o.fill(), sizeof(fill_buf)); @@ -84,8 +107,7 @@ string_view::size_type string_view::find(string_view s, if (empty() && pos == 0 && s.empty()) return 0; return npos; } - const char* result = - strings_internal::memmatch(ptr_ + pos, length_ - pos, s.ptr_, s.length_); + const char* result = memmatch(ptr_ + pos, length_ - pos, s.ptr_, s.length_); return result ? static_cast(result - ptr_) : npos; } From 25800da2238f7bcd5cd272bbde9d6c8c8dbaf2f5 Mon Sep 17 00:00:00 2001 From: Mark Barolak Date: Tue, 11 Jul 2023 12:30:02 -0700 Subject: [PATCH 0110/1238] Add a comment to absl/flags/parse.cc indicating that the flags defined there are not intended to be read or set from C++ code. PiperOrigin-RevId: 547264846 Change-Id: Idd0958f308ec74f907c22cce965fac2e06692e2c --- absl/flags/parse.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/absl/flags/parse.cc b/absl/flags/parse.cc index f41ddfcb7aa..4cdd9d0ad31 100644 --- a/absl/flags/parse.cc +++ b/absl/flags/parse.cc @@ -99,6 +99,8 @@ struct SpecifiedFlagsCompare { ABSL_NAMESPACE_END } // namespace absl +// These flags influence how command line flags are parsed and are only intended +// to be set on the command line. Avoid reading or setting them from C++ code. ABSL_FLAG(std::vector, flagfile, {}, "comma-separated list of files to load flags from") .OnUpdate([]() { @@ -148,6 +150,8 @@ ABSL_FLAG(std::vector, tryfromenv, {}, absl::flags_internal::tryfromenv_needs_processing = true; }); +// Rather than reading or setting --undefok from C++ code, please consider using +// ABSL_RETIRED_FLAG instead. ABSL_FLAG(std::vector, undefok, {}, "comma-separated list of flag names that it is okay to specify " "on the command line even if the program does not define a flag " From 1adf896ec842bd9788a1bbede94a33e1402b8ecb Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Tue, 11 Jul 2023 13:36:35 -0700 Subject: [PATCH 0111/1238] Add a smaller library for string_view so that users can depend on string_view without depending on all of //absl/strings:strings New code that uses string_view.h should depend on //absl/strings:string_view (Bazel) or absl::string_view (CMake) instead. PiperOrigin-RevId: 547283268 Change-Id: I6006b19605ce377d12c462129dda14251d16e1c1 --- absl/strings/BUILD.bazel | 25 +++++++++++++++++++++++-- absl/strings/CMakeLists.txt | 20 ++++++++++++++++++-- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index 313ba1ab7c3..819bbe69615 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -27,6 +27,20 @@ package( licenses(["notice"]) +cc_library( + name = "string_view", + srcs = ["string_view.cc"], + hdrs = ["string_view.h"], + copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [ + "//absl/base", + "//absl/base:config", + "//absl/base:core_headers", + "//absl/base:throw_delegate", + ], +) + cc_library( name = "strings", srcs = [ @@ -50,7 +64,6 @@ cc_library( "str_cat.cc", "str_replace.cc", "str_split.cc", - "string_view.cc", "substitute.cc", ], hdrs = [ @@ -72,8 +85,15 @@ cc_library( ], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, + textual_hdrs = [ + # string_view.h was once part of :strings, so string_view.h is + # re-exported for backwards compatibility. + # New code should directly depend on :string_view. + "string_view.h", + ], deps = [ ":internal", + ":string_view", "//absl/base", "//absl/base:config", "//absl/base:core_headers", @@ -263,6 +283,7 @@ cc_test( tags = ["benchmark"], visibility = ["//visibility:private"], deps = [ + ":string_view", ":strings", "//absl/base:core_headers", "//absl/base:raw_logging_internal", @@ -277,7 +298,7 @@ cc_test( copts = ABSL_TEST_COPTS, visibility = ["//visibility:private"], deps = [ - ":strings", + ":string_view", "//absl/base:config", "//absl/base:core_headers", "//absl/base:dynamic_annotations", diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index 878ff4f146c..1959dc91ada 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt @@ -14,6 +14,23 @@ # limitations under the License. # +absl_cc_library( + NAME + string_view + HDRS + string_view.h + SRCS + string_view.cc + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::base + absl::config + absl::core_headers + absl::throw_delegate + PUBLIC +) + absl_cc_library( NAME strings @@ -30,7 +47,6 @@ absl_cc_library( "str_join.h" "str_replace.h" "str_split.h" - "string_view.h" "strip.h" "substitute.h" SRCS @@ -54,11 +70,11 @@ absl_cc_library( "str_cat.cc" "str_replace.cc" "str_split.cc" - "string_view.cc" "substitute.cc" COPTS ${ABSL_DEFAULT_COPTS} DEPS + absl::string_view absl::strings_internal absl::base absl::bits From b8ebbc2ecadb64239dc0767b55296ab9c4510b0f Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 13 Jul 2023 10:51:10 -0700 Subject: [PATCH 0112/1238] Adding sw prefetchers to absl::hash. PiperOrigin-RevId: 547850162 Change-Id: I43208c7fa1eaa2a7acfad5891b80c150ee58c65f --- absl/hash/BUILD.bazel | 1 + absl/hash/CMakeLists.txt | 1 + absl/hash/internal/low_level_hash.cc | 6 ++++++ 3 files changed, 8 insertions(+) diff --git a/absl/hash/BUILD.bazel b/absl/hash/BUILD.bazel index 7f964ae7871..4346fc4954e 100644 --- a/absl/hash/BUILD.bazel +++ b/absl/hash/BUILD.bazel @@ -183,6 +183,7 @@ cc_library( deps = [ "//absl/base:config", "//absl/base:endian", + "//absl/base:prefetch", "//absl/numeric:int128", ], ) diff --git a/absl/hash/CMakeLists.txt b/absl/hash/CMakeLists.txt index 1adce61721c..65fd2a5f70e 100644 --- a/absl/hash/CMakeLists.txt +++ b/absl/hash/CMakeLists.txt @@ -165,6 +165,7 @@ absl_cc_library( absl::config absl::endian absl::int128 + absl::prefetch ) absl_cc_test( diff --git a/absl/hash/internal/low_level_hash.cc b/absl/hash/internal/low_level_hash.cc index c917457a7c9..b5db0b89601 100644 --- a/absl/hash/internal/low_level_hash.cc +++ b/absl/hash/internal/low_level_hash.cc @@ -15,6 +15,7 @@ #include "absl/hash/internal/low_level_hash.h" #include "absl/base/internal/unaligned_access.h" +#include "absl/base/prefetch.h" #include "absl/numeric/int128.h" namespace absl { @@ -29,6 +30,8 @@ static uint64_t Mix(uint64_t v0, uint64_t v1) { uint64_t LowLevelHash(const void* data, size_t len, uint64_t seed, const uint64_t salt[5]) { + // Prefetch the cacheline that data resides in. + PrefetchToLocalCache(data); const uint8_t* ptr = static_cast(data); uint64_t starting_length = static_cast(len); uint64_t current_state = seed ^ salt[0]; @@ -40,6 +43,9 @@ uint64_t LowLevelHash(const void* data, size_t len, uint64_t seed, uint64_t duplicated_state = current_state; do { + // Always prefetch the next cacheline. + PrefetchToLocalCache(ptr + ABSL_CACHELINE_SIZE); + uint64_t a = absl::base_internal::UnalignedLoad64(ptr); uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8); uint64_t c = absl::base_internal::UnalignedLoad64(ptr + 16); From c16a2f43206b0235d49d4f6155f285a4d4939c58 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 13 Jul 2023 13:05:05 -0700 Subject: [PATCH 0113/1238] Use new emscripten_errn to avoid copying strings. PiperOrigin-RevId: 547895328 Change-Id: If5da952604415fa6ed2402052f80add6c4b7dfb3 --- absl/base/internal/raw_logging.cc | 27 ++++++++++++++++----------- absl/log/internal/globals.cc | 19 ++++++++++++------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/absl/base/internal/raw_logging.cc b/absl/base/internal/raw_logging.cc index c866d957e90..4c922ccf2c1 100644 --- a/absl/base/internal/raw_logging.cc +++ b/absl/base/internal/raw_logging.cc @@ -206,27 +206,32 @@ void DefaultInternalLog(absl::LogSeverity severity, const char* file, int line, } // namespace void AsyncSignalSafeWriteError(const char* s, size_t len) { + if (!len) return; absl::base_internal::ErrnoSaver errno_saver; #if defined(__EMSCRIPTEN__) // In WebAssembly, bypass filesystem emulation via fwrite. - // TODO(b/282811932): Avoid this copy if these emscripten functions can - // be updated to accept size directly. + if (s[len - 1] == '\n') { + // Skip a trailing newline character as emscripten_errn adds one itself. + len--; + } + // emscripten_errn was introduced in 3.1.41 but broken in standalone mode + // until 3.1.43. +#if ABSL_INTERNAL_EMSCRIPTEN_VERSION >= 3001043 + emscripten_errn(s, len); +#else char buf[kLogBufSize]; if (len >= kLogBufSize) { len = kLogBufSize - 1; - size_t trunc_len = sizeof(kTruncated) - 2; - strncpy(buf + len - trunc_len, kTruncated, trunc_len); + constexpr size_t trunc_len = sizeof(kTruncated) - 2; + memcpy(buf + len - trunc_len, kTruncated, trunc_len); buf[len] = '\0'; len -= trunc_len; - } else if (len && s[len - 1] == '\n') { - len--; - } - strncpy(buf, s, len); - if (len) { + } else { buf[len] = '\0'; - // Skip a trailing newline character as emscripten_err adds one itself. - _emscripten_err(buf); } + memcpy(buf, s, len); + _emscripten_err(buf); +#endif #elif defined(ABSL_HAVE_SYSCALL_WRITE) // We prefer calling write via `syscall` to minimize the risk of libc doing // something "helpful". diff --git a/absl/log/internal/globals.cc b/absl/log/internal/globals.cc index 9ba997d52fb..359858f15ef 100644 --- a/absl/log/internal/globals.cc +++ b/absl/log/internal/globals.cc @@ -16,6 +16,7 @@ #include #include + #if defined(__EMSCRIPTEN__) #include #endif @@ -25,6 +26,7 @@ #include "absl/base/internal/raw_logging.h" #include "absl/base/log_severity.h" #include "absl/strings/string_view.h" +#include "absl/strings/strip.h" #include "absl/time/time.h" namespace absl { @@ -58,16 +60,19 @@ void SetInitialized() { } void WriteToStderr(absl::string_view message, absl::LogSeverity severity) { + if (message.empty()) return; #if defined(__EMSCRIPTEN__) // In WebAssembly, bypass filesystem emulation via fwrite. - // TODO(b/282811932): Avoid this copy if these emscripten functions can - // be updated to accept size directly. - std::string null_terminated_message(message); - if (!null_terminated_message.empty() && - null_terminated_message.back() == '\n') { - null_terminated_message.pop_back(); - } + // Skip a trailing newline character as emscripten_errn adds one itself. + const auto message_minus_newline = absl::StripSuffix(message, "\n"); + // emscripten_errn was introduced in 3.1.41 but broken in standalone mode + // until 3.1.43. +#if ABSL_INTERNAL_EMSCRIPTEN_VERSION >= 3001043 + emscripten_errn(message_minus_newline.data(), message_minus_newline.size()); +#else + std::string null_terminated_message(message_minus_newline); _emscripten_err(null_terminated_message.c_str()); +#endif #else // Avoid using std::cerr from this module since we may get called during // exit code, and cerr may be partially or fully destroyed by then. From 593826300ac2d1a8a6538bbdefc20d441db648e6 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 14 Jul 2023 10:15:09 -0700 Subject: [PATCH 0114/1238] Test that CHECK respects ABSL_MIN_LOG_LEVEL Ensure that the CHECK expression and message are stripped when FATAL is below ABSL_MIN_LOG_LEVEL. PiperOrigin-RevId: 548157637 Change-Id: I4308ff7ff75aabebdd2dcefa2771cd7e77112817 --- absl/log/stripping_test.cc | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/absl/log/stripping_test.cc b/absl/log/stripping_test.cc index 8b711ec7f83..aff914955fb 100644 --- a/absl/log/stripping_test.cc +++ b/absl/log/stripping_test.cc @@ -345,4 +345,30 @@ TEST_F(StrippingTest, Level) { } } +TEST_F(StrippingTest, Check) { + // Here we also need a variable name with enough entropy that it's unlikely to + // appear in the binary by chance. `volatile` keeps the tautological + // comparison (and the rest of the `CHECK`) from being optimized away. + const std::string var_needle = absl::Base64Escape("StrippingTestCheckVar"); + const std::string msg_needle = absl::Base64Escape("StrippingTest.Check"); + volatile int U3RyaXBwaW5nVGVzdENoZWNrVmFy = 0xCAFE; + // We don't care if the CHECK is actually executed, just that stripping works. + // Hiding it behind `kReallyDie` works around some overly aggressive + // optimizations in older versions of MSVC. + if (kReallyDie) { + CHECK(U3RyaXBwaW5nVGVzdENoZWNrVmFy != U3RyaXBwaW5nVGVzdENoZWNrVmFy) + << "U3RyaXBwaW5nVGVzdC5DaGVjaw=="; + } + + std::unique_ptr> exe = OpenTestExecutable(); + ASSERT_THAT(exe, NotNull()); + if (absl::LogSeverity::kFatal >= kAbslMinLogLevel) { + EXPECT_THAT(exe.get(), FileHasSubstr(var_needle)); + EXPECT_THAT(exe.get(), FileHasSubstr(msg_needle)); + } else { + EXPECT_THAT(exe.get(), Not(FileHasSubstr(var_needle))); + EXPECT_THAT(exe.get(), Not(FileHasSubstr(msg_needle))); + } +} + } // namespace From be85b347a800c0fcbbc3d901f2784efee3a73e1e Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 17 Jul 2023 09:07:19 -0700 Subject: [PATCH 0115/1238] Add Support for mmap on Qualcomm Hexagon DSP targets. PiperOrigin-RevId: 548709037 Change-Id: I6eb03553299265660aa0abc180ae0f197a416ba4 --- absl/base/config.h | 2 +- absl/base/internal/low_level_alloc.cc | 2 +- absl/base/internal/low_level_alloc.h | 3 ++- absl/synchronization/internal/graphcycles.cc | 14 +++++++++----- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/absl/base/config.h b/absl/base/config.h index 0037bab9759..caa74787adc 100644 --- a/absl/base/config.h +++ b/absl/base/config.h @@ -412,7 +412,7 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || defined(__asmjs__) || defined(__wasm__) || defined(__Fuchsia__) || \ defined(__sun) || defined(__ASYLO__) || defined(__myriad2__) || \ defined(__HAIKU__) || defined(__OpenBSD__) || defined(__NetBSD__) || \ - defined(__QNX__) || defined(__VXWORKS__) + defined(__QNX__) || defined(__VXWORKS__) || defined(__hexagon__) #define ABSL_HAVE_MMAP 1 #endif diff --git a/absl/base/internal/low_level_alloc.cc b/absl/base/internal/low_level_alloc.cc index f8c4336f49c..445c34587ae 100644 --- a/absl/base/internal/low_level_alloc.cc +++ b/absl/base/internal/low_level_alloc.cc @@ -58,7 +58,7 @@ #include "absl/base/internal/spinlock.h" // MAP_ANONYMOUS -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(__hexagon__) // For mmap, Linux defines both MAP_ANONYMOUS and MAP_ANON and says MAP_ANON is // deprecated. In Darwin, MAP_ANON is all there is. #if !defined MAP_ANONYMOUS diff --git a/absl/base/internal/low_level_alloc.h b/absl/base/internal/low_level_alloc.h index eabb14a9b49..c2f1f25d8e3 100644 --- a/absl/base/internal/low_level_alloc.h +++ b/absl/base/internal/low_level_alloc.h @@ -46,7 +46,8 @@ // for more information. #ifdef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING #error ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING cannot be directly set -#elif defined(_WIN32) || defined(__asmjs__) || defined(__wasm__) +#elif defined(_WIN32) || defined(__asmjs__) || defined(__wasm__) || \ + defined(__hexagon__) #define ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING 1 #endif diff --git a/absl/synchronization/internal/graphcycles.cc b/absl/synchronization/internal/graphcycles.cc index 014895447dd..39b18482f3f 100644 --- a/absl/synchronization/internal/graphcycles.cc +++ b/absl/synchronization/internal/graphcycles.cc @@ -37,6 +37,7 @@ #include #include +#include #include #include "absl/base/internal/hide_ptr.h" #include "absl/base/internal/raw_logging.h" @@ -386,19 +387,22 @@ bool GraphCycles::CheckInvariants() const { Node* nx = r->nodes_[x]; void* ptr = base_internal::UnhidePtr(nx->masked_ptr); if (ptr != nullptr && static_cast(r->ptrmap_.Find(ptr)) != x) { - ABSL_RAW_LOG(FATAL, "Did not find live node in hash table %u %p", x, ptr); + ABSL_RAW_LOG(FATAL, "Did not find live node in hash table %" PRIu32 " %p", + x, ptr); } if (nx->visited) { - ABSL_RAW_LOG(FATAL, "Did not clear visited marker on node %u", x); + ABSL_RAW_LOG(FATAL, "Did not clear visited marker on node %" PRIu32, x); } if (!ranks.insert(nx->rank)) { - ABSL_RAW_LOG(FATAL, "Duplicate occurrence of rank %d", nx->rank); + ABSL_RAW_LOG(FATAL, "Duplicate occurrence of rank %" PRId32, nx->rank); } HASH_FOR_EACH(y, nx->out) { Node* ny = r->nodes_[static_cast(y)]; if (nx->rank >= ny->rank) { - ABSL_RAW_LOG(FATAL, "Edge %u->%d has bad rank assignment %d->%d", x, y, - nx->rank, ny->rank); + ABSL_RAW_LOG(FATAL, + "Edge %" PRIu32 " ->%" PRId32 + " has bad rank assignment %" PRId32 "->%" PRId32, + x, y, nx->rank, ny->rank); } } } From 5be22f98733c674d532598454ae729253bc53e82 Mon Sep 17 00:00:00 2001 From: Evan Brown Date: Mon, 17 Jul 2023 14:06:54 -0700 Subject: [PATCH 0116/1238] Move growth_left to the backing array. PiperOrigin-RevId: 548794485 Change-Id: Ie82d5f8ad752518ef05b38144ca1e32b21c9def8 --- absl/container/internal/raw_hash_set.cc | 19 +++- absl/container/internal/raw_hash_set.h | 107 ++++++++++++------- absl/container/internal/raw_hash_set_test.cc | 48 ++++++++- 3 files changed, 125 insertions(+), 49 deletions(-) diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc index a40e38dbba1..1389e6e1880 100644 --- a/absl/container/internal/raw_hash_set.cc +++ b/absl/container/internal/raw_hash_set.cc @@ -19,6 +19,7 @@ #include #include +#include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/dynamic_annotations.h" #include "absl/hash/hash.h" @@ -27,9 +28,17 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace container_internal { -// A single block of empty control bytes for tables without any slots allocated. -// This enables removing a branch in the hot path of find(). -alignas(16) ABSL_CONST_INIT ABSL_DLL const ctrl_t kEmptyGroup[16] = { +// We have space for `growth_left` before a single block of control bytes. A +// single block of empty control bytes for tables without any slots allocated. +// This enables removing a branch in the hot path of find(). In order to ensure +// that the control bytes are aligned to 16, we have 16 bytes before the control +// bytes even though growth_left only needs 8. +constexpr ctrl_t ZeroCtrlT() { return static_cast(0); } +alignas(16) ABSL_CONST_INIT ABSL_DLL const ctrl_t kEmptyGroup[32] = { + ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(), + ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(), + ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(), + ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(), ctrl_t::kSentinel, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, @@ -239,12 +248,12 @@ void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy, c.infoz().RecordStorageChanged(0, c.capacity()); } else { void* set = &c; - (*policy.dealloc)(set, policy, c.control(), c.slots_ptr(), c.capacity()); + (*policy.dealloc)(set, policy, c.backing_array_start(), c.slots_ptr(), + c.capacity()); c.set_control(EmptyGroup()); c.set_generation_ptr(EmptyGeneration()); c.set_slots(nullptr); c.set_capacity(0); - c.set_growth_left(0); c.infoz().RecordClearedReservation(); assert(c.size() == 0); c.infoz().RecordStorageChanged(0, 0); diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index c2fe242de6e..e99dc00c50f 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -62,6 +62,8 @@ // pseudo-struct: // // struct BackingArray { +// // The number of elements we can insert before growing the capacity. +// size_t growth_left; // // Control bytes for the "real" slots. // ctrl_t ctrl[capacity]; // // Always `ctrl_t::kSentinel`. This is used by iterators to find when to @@ -174,6 +176,7 @@ #include #include +#include #include #include #include @@ -484,13 +487,14 @@ static_assert(ctrl_t::kDeleted == static_cast(-2), "ctrl_t::kDeleted must be -2 to make the implementation of " "ConvertSpecialToEmptyAndFullToDeleted efficient"); -ABSL_DLL extern const ctrl_t kEmptyGroup[16]; +// See definition comment for why this is size 32. +ABSL_DLL extern const ctrl_t kEmptyGroup[32]; // Returns a pointer to a control byte group that can be used by empty tables. inline ctrl_t* EmptyGroup() { // Const must be cast away here; no uses of this function will actually write // to it, because it is only used for empty tables. - return const_cast(kEmptyGroup); + return const_cast(kEmptyGroup + 16); } // Returns a pointer to a generation to use for an empty hashtable. @@ -913,24 +917,32 @@ class CommonFields : public CommonFieldsGenerationInfo { // fields generates less code then calling absl::exchange per field. control_(that.control()), slots_(that.slots_ptr()), - size_(that.size()), capacity_(that.capacity()), - compressed_tuple_(that.growth_left(), std::move(that.infoz())) { + compressed_tuple_(that.size(), std::move(that.infoz())) { that.set_control(EmptyGroup()); that.set_slots(nullptr); - that.set_size(0); that.set_capacity(0); - that.set_growth_left(0); + that.set_size(0); } CommonFields& operator=(CommonFields&&) = default; ctrl_t* control() const { return control_; } void set_control(ctrl_t* c) { control_ = c; } + void* backing_array_start() const { + // growth_left is stored before control bytes. + assert(reinterpret_cast(control()) % alignof(size_t) == 0); + return control() - sizeof(size_t); + } + // Note: we can't use slots() because Qt defines "slots" as a macro. void* slots_ptr() const { return slots_; } void set_slots(void* s) { slots_ = s; } - size_t size() const { return size_; } - void set_size(size_t s) { size_ = s; } + + // The number of filled slots. + size_t size() const { return compressed_tuple_.template get<0>(); } + void set_size(size_t s) { compressed_tuple_.template get<0>() = s; } + + // The total number of available slots. size_t capacity() const { return capacity_; } void set_capacity(size_t c) { assert(c == 0 || IsValidCapacity(c)); @@ -938,8 +950,13 @@ class CommonFields : public CommonFieldsGenerationInfo { } // The number of slots we can still fill without needing to rehash. - size_t growth_left() const { return compressed_tuple_.template get<0>(); } - void set_growth_left(size_t gl) { compressed_tuple_.template get<0>() = gl; } + // This is stored in the heap allocation before the control bytes. + size_t growth_left() const { + return *reinterpret_cast(backing_array_start()); + } + void set_growth_left(size_t gl) { + *reinterpret_cast(backing_array_start()) = gl; + } HashtablezInfoHandle& infoz() { return compressed_tuple_.template get<1>(); } const HashtablezInfoHandle& infoz() const { @@ -951,32 +968,30 @@ class CommonFields : public CommonFieldsGenerationInfo { should_rehash_for_bug_detection_on_insert(control(), capacity()); } void reset_reserved_growth(size_t reservation) { - CommonFieldsGenerationInfo::reset_reserved_growth(reservation, size_); + CommonFieldsGenerationInfo::reset_reserved_growth(reservation, size()); } private: // TODO(b/259599413): Investigate removing some of these fields: // - control/slots can be derived from each other - // - growth_left can be moved into the slot array // - we can use 6 bits for capacity since it's always a power of two minus 1 - // The control bytes (and, also, a pointer to the base of the backing array). + // The control bytes (and, also, a pointer near to the base of the backing + // array). // // This contains `capacity + 1 + NumClonedBytes()` entries, even // when the table is empty (hence EmptyGroup). + // + // Note that growth_left is stored immediately before this pointer. ctrl_t* control_ = EmptyGroup(); // The beginning of the slots, located at `SlotOffset()` bytes after // `control`. May be null for empty tables. void* slots_ = nullptr; - // The number of filled slots. - size_t size_ = 0; - - // The total number of available slots. size_t capacity_ = 0; - // Bundle together growth_left and HashtablezInfoHandle to ensure EBO for + // Bundle together size and HashtablezInfoHandle to ensure EBO for // HashtablezInfoHandle when sampling is turned off. absl::container_internal::CompressedTuple compressed_tuple_{0u, HashtablezInfoHandle{}}; @@ -1318,20 +1333,28 @@ inline void SetCtrl(const CommonFields& common, size_t i, h2_t h, SetCtrl(common, i, static_cast(h), slot_size); } +// growth_left (which is a size_t) is stored with the backing array. +constexpr size_t BackingArrayAlignment(size_t align_of_slot) { + return (std::max)(align_of_slot, alignof(size_t)); +} + +// Computes the offset from the start of the backing allocation of the control +// bytes. growth_left is stored at the beginning of the backing array. +inline size_t ControlOffset() { return sizeof(size_t); } + // Given the capacity of a table, computes the offset (from the start of the // backing allocation) of the generation counter (if it exists). inline size_t GenerationOffset(size_t capacity) { assert(IsValidCapacity(capacity)); const size_t num_control_bytes = capacity + 1 + NumClonedBytes(); - return num_control_bytes; + return ControlOffset() + num_control_bytes; } // Given the capacity of a table, computes the offset (from the start of the // backing allocation) at which the slots begin. inline size_t SlotOffset(size_t capacity, size_t slot_align) { assert(IsValidCapacity(capacity)); - const size_t num_control_bytes = capacity + 1 + NumClonedBytes(); - return (num_control_bytes + NumGenerationBytes() + slot_align - 1) & + return (GenerationOffset(capacity) + NumGenerationBytes() + slot_align - 1) & (~slot_align + 1); } @@ -1356,13 +1379,15 @@ ABSL_ATTRIBUTE_NOINLINE void InitializeSlots(CommonFields& c, Alloc alloc) { : 0; const size_t cap = c.capacity(); + const size_t alloc_size = AllocSize(cap, SizeOfSlot, AlignOfSlot); + // growth_left (which is a size_t) is stored with the backing array. char* mem = static_cast( - Allocate(&alloc, AllocSize(cap, SizeOfSlot, AlignOfSlot))); + Allocate(&alloc, alloc_size)); const GenerationType old_generation = c.generation(); c.set_generation_ptr( reinterpret_cast(mem + GenerationOffset(cap))); c.set_generation(NextGeneration(old_generation)); - c.set_control(reinterpret_cast(mem)); + c.set_control(reinterpret_cast(mem + ControlOffset())); c.set_slots(mem + SlotOffset(cap, AlignOfSlot)); ResetCtrl(c, SizeOfSlot); if (sample_size) { @@ -1385,8 +1410,8 @@ struct PolicyFunctions { void (*transfer)(void* set, void* dst_slot, void* src_slot); // Deallocate the specified backing store which is sized for n slots. - void (*dealloc)(void* set, const PolicyFunctions& policy, ctrl_t* ctrl, - void* slot_array, size_t n); + void (*dealloc)(void* set, const PolicyFunctions& policy, + void* backing_array_start, void* slot_array, size_t n); }; // ClearBackingArray clears the backing array, either modifying it in place, @@ -1405,14 +1430,14 @@ void EraseMetaOnly(CommonFields& c, ctrl_t* it, size_t slot_size); template ABSL_ATTRIBUTE_NOINLINE void DeallocateStandard(void*, const PolicyFunctions& policy, - ctrl_t* ctrl, void* slot_array, - size_t n) { + void* backing_array_start, + void* slot_array, size_t n) { // Unpoison before returning the memory to the allocator. SanitizerUnpoisonMemoryRegion(slot_array, policy.slot_size * n); std::allocator alloc; - Deallocate(&alloc, ctrl, - AllocSize(n, policy.slot_size, AlignOfSlot)); + Deallocate( + &alloc, backing_array_start, AllocSize(n, policy.slot_size, AlignOfSlot)); } // For trivially relocatable types we use memcpy directly. This allows us to @@ -1773,7 +1798,9 @@ class raw_hash_set { raw_hash_set(const raw_hash_set& that, const allocator_type& a) : raw_hash_set(0, that.hash_ref(), that.eq_ref(), a) { - reserve(that.size()); + const size_t size = that.size(); + if (size == 0) return; + reserve(size); // Because the table is guaranteed to be empty, we can do something faster // than a full `insert`. for (const auto& v : that) { @@ -1784,8 +1811,8 @@ class raw_hash_set { common().maybe_increment_generation_on_insert(); infoz().RecordInsert(hash, target.probe_length); } - common().set_size(that.size()); - set_growth_left(growth_left() - that.size()); + common().set_size(size); + set_growth_left(growth_left() - size); } ABSL_ATTRIBUTE_NOINLINE raw_hash_set(raw_hash_set&& that) noexcept( @@ -1838,8 +1865,8 @@ class raw_hash_set { // Unpoison before returning the memory to the allocator. SanitizerUnpoisonMemoryRegion(slot_array(), sizeof(slot_type) * cap); - Deallocate( - &alloc_ref(), control(), + Deallocate( + &alloc_ref(), common().backing_array_start(), AllocSize(cap, sizeof(slot_type), alignof(slot_type))); infoz().Unregister(); @@ -2470,8 +2497,8 @@ class raw_hash_set { if (old_capacity) { SanitizerUnpoisonMemoryRegion(old_slots, sizeof(slot_type) * old_capacity); - Deallocate( - &alloc_ref(), old_ctrl, + Deallocate( + &alloc_ref(), old_ctrl - ControlOffset(), AllocSize(old_capacity, sizeof(slot_type), alignof(slot_type))); } infoz().RecordRehash(total_probe_length); @@ -2707,15 +2734,15 @@ class raw_hash_set { static_cast(src)); } // Note: dealloc_fn will only be used if we have a non-standard allocator. - static void dealloc_fn(void* set, const PolicyFunctions&, ctrl_t* ctrl, - void* slot_mem, size_t n) { + static void dealloc_fn(void* set, const PolicyFunctions&, + void* backing_array_start, void* slot_mem, size_t n) { auto* h = static_cast(set); // Unpoison before returning the memory to the allocator. SanitizerUnpoisonMemoryRegion(slot_mem, sizeof(slot_type) * n); - Deallocate( - &h->alloc_ref(), ctrl, + Deallocate( + &h->alloc_ref(), backing_array_start, AllocSize(n, sizeof(slot_type), alignof(slot_type))); } diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc index ce1070ba448..6cbf6deae91 100644 --- a/absl/container/internal/raw_hash_set_test.cc +++ b/absl/container/internal/raw_hash_set_test.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -436,6 +437,41 @@ struct CustomAllocIntTable using Base::Base; }; +// Tries to allocate memory at the minimum alignment even when the default +// allocator uses a higher alignment. +template +struct MinimumAlignmentAlloc : std::allocator { + MinimumAlignmentAlloc() = default; + + template + explicit MinimumAlignmentAlloc(const MinimumAlignmentAlloc& /*other*/) {} + + template + struct rebind { + using other = MinimumAlignmentAlloc; + }; + + T* allocate(size_t n) { + T* ptr = std::allocator::allocate(n + 1); + char* cptr = reinterpret_cast(ptr); + cptr += alignof(T); + return reinterpret_cast(cptr); + } + + void deallocate(T* ptr, size_t n) { + char* cptr = reinterpret_cast(ptr); + cptr -= alignof(T); + std::allocator::deallocate(reinterpret_cast(cptr), n + 1); + } +}; + +struct MinimumAlignmentUint8Table + : raw_hash_set, + std::equal_to, MinimumAlignmentAlloc> { + using Base = typename MinimumAlignmentUint8Table::raw_hash_set; + using Base::Base; +}; + struct BadFastHash { template size_t operator()(const T&) const { @@ -460,14 +496,12 @@ TEST(Table, EmptyFunctorOptimization) { void* slots; size_t size; size_t capacity; - size_t growth_left; }; struct MockTableInfozDisabled { void* ctrl; void* slots; size_t size; size_t capacity; - size_t growth_left; }; struct StatelessHash { size_t operator()(absl::string_view) const { return 0; } @@ -2247,11 +2281,17 @@ TEST(Sanitizer, PoisoningOnErase) { } #endif // ABSL_HAVE_ADDRESS_SANITIZER -TEST(Table, AlignOne) { +template +class AlignOneTest : public ::testing::Test {}; +using AlignOneTestTypes = + ::testing::Types; +TYPED_TEST_SUITE(AlignOneTest, AlignOneTestTypes); + +TYPED_TEST(AlignOneTest, AlignOne) { // We previously had a bug in which we were copying a control byte over the // first slot when alignof(value_type) is 1. We test repeated // insertions/erases and verify that the behavior is correct. - Uint8Table t; + TypeParam t; std::unordered_set verifier; // NOLINT // Do repeated insertions/erases from the table. From 47d467e44bea8d799f78490658a6fdd830d1347c Mon Sep 17 00:00:00 2001 From: Phoebe Liang Date: Tue, 18 Jul 2023 14:14:23 -0700 Subject: [PATCH 0117/1238] Add tests for the "%#04x" pattern Verifies that values other than 0 are prepended with "0x", while 0 is printed as "0000". PiperOrigin-RevId: 549108651 Change-Id: Ib0f87d42066c46f3a5d4b05ca5c9d7ac17be9b66 --- absl/strings/str_format_test.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc index 5198fb338db..20fd0289704 100644 --- a/absl/strings/str_format_test.cc +++ b/absl/strings/str_format_test.cc @@ -638,6 +638,8 @@ TEST(StrFormat, BehavesAsDocumented) { EXPECT_EQ(StrFormat("%#o", 10), "012"); EXPECT_EQ(StrFormat("%#x", 15), "0xf"); EXPECT_EQ(StrFormat("%04d", 8), "0008"); + EXPECT_EQ(StrFormat("%#04x", 0), "0000"); + EXPECT_EQ(StrFormat("%#04x", 1), "0x01"); // Posix positional substitution. EXPECT_EQ(absl::StrFormat("%2$s, %3$s, %1$s!", "vici", "veni", "vidi"), "veni, vidi, vici!"); From 89367c603be2c6b3e8c7a3d17f53ea6c3a68bd7d Mon Sep 17 00:00:00 2001 From: Evan Brown Date: Wed, 19 Jul 2023 11:42:55 -0700 Subject: [PATCH 0118/1238] Rename CommonFields::slots_ptr to slot_array to match the name of the corresponding function in raw_hash_set. PiperOrigin-RevId: 549379884 Change-Id: I305745dbea2c15821b2092441c9b4546fc7aabbe --- absl/container/internal/raw_hash_set.cc | 4 ++-- absl/container/internal/raw_hash_set.h | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc index 1389e6e1880..ef2594c9b58 100644 --- a/absl/container/internal/raw_hash_set.cc +++ b/absl/container/internal/raw_hash_set.cc @@ -140,7 +140,7 @@ static inline void* PrevSlot(void* slot, size_t slot_size) { void DropDeletesWithoutResize(CommonFields& common, const PolicyFunctions& policy, void* tmp_space) { void* set = &common; - void* slot_array = common.slots_ptr(); + void* slot_array = common.slot_array(); const size_t capacity = common.capacity(); assert(IsValidCapacity(capacity)); assert(!is_small(capacity)); @@ -248,7 +248,7 @@ void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy, c.infoz().RecordStorageChanged(0, c.capacity()); } else { void* set = &c; - (*policy.dealloc)(set, policy, c.backing_array_start(), c.slots_ptr(), + (*policy.dealloc)(set, policy, c.backing_array_start(), c.slot_array(), c.capacity()); c.set_control(EmptyGroup()); c.set_generation_ptr(EmptyGeneration()); diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index e99dc00c50f..1b9f4d89089 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -916,7 +916,7 @@ class CommonFields : public CommonFieldsGenerationInfo { // Explicitly copying fields into "this" and then resetting "that" // fields generates less code then calling absl::exchange per field. control_(that.control()), - slots_(that.slots_ptr()), + slots_(that.slot_array()), capacity_(that.capacity()), compressed_tuple_(that.size(), std::move(that.infoz())) { that.set_control(EmptyGroup()); @@ -935,7 +935,7 @@ class CommonFields : public CommonFieldsGenerationInfo { } // Note: we can't use slots() because Qt defines "slots" as a macro. - void* slots_ptr() const { return slots_; } + void* slot_array() const { return slots_; } void set_slots(void* s) { slots_ = s; } // The number of filled slots. @@ -1302,7 +1302,7 @@ inline void ResetCtrl(CommonFields& common, size_t slot_size) { std::memset(ctrl, static_cast(ctrl_t::kEmpty), capacity + 1 + NumClonedBytes()); ctrl[capacity] = ctrl_t::kSentinel; - SanitizerPoisonMemoryRegion(common.slots_ptr(), slot_size * capacity); + SanitizerPoisonMemoryRegion(common.slot_array(), slot_size * capacity); ResetGrowthLeft(common); } @@ -1315,7 +1315,7 @@ inline void SetCtrl(const CommonFields& common, size_t i, ctrl_t h, const size_t capacity = common.capacity(); assert(i < capacity); - auto* slot_i = static_cast(common.slots_ptr()) + i * slot_size; + auto* slot_i = static_cast(common.slot_array()) + i * slot_size; if (IsFull(h)) { SanitizerUnpoisonMemoryRegion(slot_i, slot_size); } else { @@ -1374,7 +1374,7 @@ ABSL_ATTRIBUTE_NOINLINE void InitializeSlots(CommonFields& c, Alloc alloc) { // a workaround while we plan the exact guarantee we want to provide. const size_t sample_size = (std::is_same>::value && - c.slots_ptr() == nullptr) + c.slot_array() == nullptr) ? SizeOfSlot : 0; @@ -2708,7 +2708,7 @@ class raw_hash_set { ctrl_t* control() const { return common().control(); } slot_type* slot_array() const { - return static_cast(common().slots_ptr()); + return static_cast(common().slot_array()); } HashtablezInfoHandle& infoz() { return common().infoz(); } From 9f1dcc70d64232e77964de9b90e209e23e0110db Mon Sep 17 00:00:00 2001 From: Evan Brown Date: Thu, 20 Jul 2023 09:56:18 -0700 Subject: [PATCH 0119/1238] Add a special case for erase(begin(), end()) to reset the control bytes. The motivation is to avoid potentially expanding the table unnecessarily later. Note: I prefer doing this as a special case in erase(iterator, iterator) rather than special casing erase(iterator) for size==1 because IIUC that changes the time complexity of erase(iterator) from O(1) to O(N) and in pathological cases, it could change loops from O(N) to O(N^2). PiperOrigin-RevId: 549661855 Change-Id: I8603324260f51a98809db32f840ff09f25cf2481 --- absl/container/internal/raw_hash_set.h | 14 ++++++++++---- absl/container/internal/raw_hash_set_test.cc | 8 ++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 1b9f4d89089..f0e107be817 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -1910,8 +1910,7 @@ class raw_hash_set { // Already guaranteed to be empty; so nothing to do. } else { destroy_slots(); - ClearBackingArray(common(), GetPolicyFunctions(), - /*reuse=*/cap < 128); + ClearBackingArray(common(), GetPolicyFunctions(), /*reuse=*/cap < 128); } common().set_reserved_growth(0); } @@ -2165,6 +2164,14 @@ class raw_hash_set { iterator erase(const_iterator first, const_iterator last) ABSL_ATTRIBUTE_LIFETIME_BOUND { + // We check for empty first because ClearBackingArray requires that + // capacity() > 0 as a precondition. + if (empty()) return end(); + if (first == begin() && last == end()) { + destroy_slots(); + ClearBackingArray(common(), GetPolicyFunctions(), /*reuse=*/true); + return end(); + } while (first != last) { erase(first++); } @@ -2224,8 +2231,7 @@ class raw_hash_set { void rehash(size_t n) { if (n == 0 && capacity() == 0) return; if (n == 0 && size() == 0) { - ClearBackingArray(common(), GetPolicyFunctions(), - /*reuse=*/false); + ClearBackingArray(common(), GetPolicyFunctions(), /*reuse=*/false); return; } diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc index 6cbf6deae91..66621cf050d 100644 --- a/absl/container/internal/raw_hash_set_test.cc +++ b/absl/container/internal/raw_hash_set_test.cc @@ -1093,6 +1093,14 @@ TEST(Table, EraseMaintainsValidIterator) { EXPECT_EQ(num_erase_calls, kNumElements); } +TEST(Table, EraseBeginEnd) { + IntTable t; + for (int i = 0; i < 10; ++i) t.insert(i); + EXPECT_EQ(t.size(), 10); + t.erase(t.begin(), t.end()); + EXPECT_EQ(t.size(), 0); +} + // Collect N bad keys by following algorithm: // 1. Create an empty table and reserve it to 2 * N. // 2. Insert N random elements. From d74b1104a5e9a24964b34c30dcbfbc3bcca88576 Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Fri, 21 Jul 2023 09:16:39 -0700 Subject: [PATCH 0120/1238] `absl/BUILD.bazel`: Make license comment consistent with other bazel build files PiperOrigin-RevId: 549965642 Change-Id: I708dd56a36d60cbc00564fa789e1cb1ef37f950a --- absl/BUILD.bazel | 1 + 1 file changed, 1 insertion(+) diff --git a/absl/BUILD.bazel b/absl/BUILD.bazel index b2300ba9ba1..253c0aeff44 100644 --- a/absl/BUILD.bazel +++ b/absl/BUILD.bazel @@ -12,6 +12,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# load("@bazel_skylib//lib:selects.bzl", "selects") From ac39cc1ec6fed8d3738b4df9589803c23d6d1e3a Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 25 Jul 2023 12:32:02 -0700 Subject: [PATCH 0121/1238] Import of CCTZ from GitHub. PiperOrigin-RevId: 550964088 Change-Id: I54e4bff1cf72442c34e1668dbe8af9337eb0aa46 --- absl/time/internal/cctz/BUILD.bazel | 9 +++++---- absl/time/internal/cctz/src/time_zone_format.cc | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/absl/time/internal/cctz/BUILD.bazel b/absl/time/internal/cctz/BUILD.bazel index edeabd81360..4c5ad07564e 100644 --- a/absl/time/internal/cctz/BUILD.bazel +++ b/absl/time/internal/cctz/BUILD.bazel @@ -53,10 +53,11 @@ cc_library( "include/cctz/time_zone.h", "include/cctz/zone_info_source.h", ], - # OS X and iOS no longer use `linkopts = ["-framework CoreFoundation"]` - # as (1) bazel adds it automatically, and (2) it caused problems when - # cross-compiling for Android. - # See https://github.com/abseil/abseil-cpp/issues/326 for details. + linkopts = select({ + "@platforms//os:osx": ["-Wl,-framework,CoreFoundation"], + "@platforms//os:ios": ["-Wl,-framework,CoreFoundation"], + "//conditions:default": [], + }), visibility = ["//visibility:public"], deps = [ ":civil_time", diff --git a/absl/time/internal/cctz/src/time_zone_format.cc b/absl/time/internal/cctz/src/time_zone_format.cc index 96268a830b0..9b91f61cf09 100644 --- a/absl/time/internal/cctz/src/time_zone_format.cc +++ b/absl/time/internal/cctz/src/time_zone_format.cc @@ -20,7 +20,7 @@ #if defined(HAS_STRPTIME) && HAS_STRPTIME #if !defined(_XOPEN_SOURCE) && !defined(__OpenBSD__) -#define _XOPEN_SOURCE // Definedness suffices for strptime(). +#define _XOPEN_SOURCE 500 // Exposes definitions for SUSv2 (UNIX 98). #endif #endif From 511ad6492eabb7797910ce8689577c45f57bce40 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Tue, 25 Jul 2023 13:04:25 -0700 Subject: [PATCH 0122/1238] InlinedVector: Fix control-flow-inregrity warning when using a class with a vtable The code is getting the pointer, then constructing it on the next line. Using reinterpret_cast on this pointer is legal according to https://clang.llvm.org/docs/ControlFlowIntegrity.html#bad-cast-checking, but it flags it anyway. The docs say it might be necessary for `allocate()`-type APIs, and recommends adding them to an ignorelist. Also note that std::addressof is removed. It is unnecessary since inlined_data is a char-array. PiperOrigin-RevId: 550972834 Change-Id: Ib224cec330bb6bcb770296de6c91881f404ef531 --- absl/base/attributes.h | 2 +- absl/container/inlined_vector_test.cc | 5 +++++ absl/container/internal/inlined_vector.h | 19 ++++++++++++++----- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/absl/base/attributes.h b/absl/base/attributes.h index cb3f367f824..a7f279a0253 100644 --- a/absl/base/attributes.h +++ b/absl/base/attributes.h @@ -274,7 +274,7 @@ // // Tells the ControlFlowIntegrity sanitizer to not instrument a given function. // See https://clang.llvm.org/docs/ControlFlowIntegrity.html for details. -#if ABSL_HAVE_ATTRIBUTE(no_sanitize) +#if ABSL_HAVE_ATTRIBUTE(no_sanitize) && defined(__llvm__) #define ABSL_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi"))) #else #define ABSL_ATTRIBUTE_NO_SANITIZE_CFI diff --git a/absl/container/inlined_vector_test.cc b/absl/container/inlined_vector_test.cc index 6f4625dcfa8..07304518fbc 100644 --- a/absl/container/inlined_vector_test.cc +++ b/absl/container/inlined_vector_test.cc @@ -1621,6 +1621,11 @@ TEST(DynamicVec, DynamicVecCompiles) { (void)v; } +TEST(DynamicVec, CreateNonEmptyDynamicVec) { + DynamicVec v(1); + EXPECT_EQ(v.size(), 1u); +} + TEST(AllocatorSupportTest, Constructors) { using MyAlloc = CountingAllocator; using AllocVec = absl::InlinedVector; diff --git a/absl/container/internal/inlined_vector.h b/absl/container/internal/inlined_vector.h index f886dfa074f..639bf145ad5 100644 --- a/absl/container/internal/inlined_vector.h +++ b/absl/container/internal/inlined_vector.h @@ -391,13 +391,22 @@ class Storage { } Pointer GetInlinedData() { - return reinterpret_cast>( - std::addressof(data_.inlined.inlined_data[0])); + return reinterpret_cast>(data_.inlined.inlined_data); } ConstPointer GetInlinedData() const { - return reinterpret_cast>( - std::addressof(data_.inlined.inlined_data[0])); + return reinterpret_cast>(data_.inlined.inlined_data); + } + + // Like GetInlinedData(), but for data that has not been constructed yet. The + // only difference is ABSL_ATTRIBUTE_NO_SANITIZE_CFI, which is necessary + // because the object is uninitialized. + // https://clang.llvm.org/docs/ControlFlowIntegrity.html#bad-cast-checking + // NOTE: When this was written, LLVM documentation did not explicitly + // mention that casting `char*` and using `reinterpret_cast` qualifies + // as a bad cast. + ABSL_ATTRIBUTE_NO_SANITIZE_CFI Pointer GetInlinedDataUninitialized() { + return reinterpret_cast>(data_.inlined.inlined_data); } SizeType GetAllocatedCapacity() const { @@ -628,7 +637,7 @@ auto Storage::Initialize(ValueAdapter values, SizeType new_size) SetAllocation(allocation); SetIsAllocated(); } else { - construct_data = GetInlinedData(); + construct_data = GetInlinedDataUninitialized(); } ConstructElements(GetAllocator(), construct_data, values, new_size); From c108cd0382a3659eaf2981b22392b4d5fbc122db Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Wed, 26 Jul 2023 07:57:53 -0700 Subject: [PATCH 0123/1238] InlinedVector: Disable CFI checking on GetInlinedData() GetInlinedDataUninitialized() is removed. Just use GetInlinedData() in all cases instead. GetInlinedData() is sometimes used to return uninitialized memory. In these cases it is immediately constructed. This is a followup to 511ad64. See also: https://clang.llvm.org/docs/ControlFlowIntegrity.html#bad-cast-checking. PiperOrigin-RevId: 551205766 Change-Id: I4ddb45e29a723ccf6fc7dc203e762f4ad559fc83 --- absl/container/inlined_vector_test.cc | 6 ++++++ absl/container/internal/inlined_vector.h | 21 ++++++++------------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/absl/container/inlined_vector_test.cc b/absl/container/inlined_vector_test.cc index 07304518fbc..5acad650408 100644 --- a/absl/container/inlined_vector_test.cc +++ b/absl/container/inlined_vector_test.cc @@ -1626,6 +1626,12 @@ TEST(DynamicVec, CreateNonEmptyDynamicVec) { EXPECT_EQ(v.size(), 1u); } +TEST(DynamicVec, EmplaceBack) { + DynamicVec v; + v.emplace_back(Dynamic{}); + EXPECT_EQ(v.size(), 1u); +} + TEST(AllocatorSupportTest, Constructors) { using MyAlloc = CountingAllocator; using AllocVec = absl::InlinedVector; diff --git a/absl/container/internal/inlined_vector.h b/absl/container/internal/inlined_vector.h index 639bf145ad5..cdfd868efda 100644 --- a/absl/container/internal/inlined_vector.h +++ b/absl/container/internal/inlined_vector.h @@ -390,25 +390,20 @@ class Storage { return data_.allocated.allocated_data; } - Pointer GetInlinedData() { - return reinterpret_cast>(data_.inlined.inlined_data); - } - - ConstPointer GetInlinedData() const { - return reinterpret_cast>(data_.inlined.inlined_data); - } - - // Like GetInlinedData(), but for data that has not been constructed yet. The - // only difference is ABSL_ATTRIBUTE_NO_SANITIZE_CFI, which is necessary - // because the object is uninitialized. + // ABSL_ATTRIBUTE_NO_SANITIZE_CFI is used because the memory pointed to may be + // uninitialized, a common pattern in allocate()+construct() APIs. // https://clang.llvm.org/docs/ControlFlowIntegrity.html#bad-cast-checking // NOTE: When this was written, LLVM documentation did not explicitly // mention that casting `char*` and using `reinterpret_cast` qualifies // as a bad cast. - ABSL_ATTRIBUTE_NO_SANITIZE_CFI Pointer GetInlinedDataUninitialized() { + ABSL_ATTRIBUTE_NO_SANITIZE_CFI Pointer GetInlinedData() { return reinterpret_cast>(data_.inlined.inlined_data); } + ConstPointer GetInlinedData() const { + return reinterpret_cast>(data_.inlined.inlined_data); + } + SizeType GetAllocatedCapacity() const { return data_.allocated.allocated_capacity; } @@ -637,7 +632,7 @@ auto Storage::Initialize(ValueAdapter values, SizeType new_size) SetAllocation(allocation); SetIsAllocated(); } else { - construct_data = GetInlinedDataUninitialized(); + construct_data = GetInlinedData(); } ConstructElements(GetAllocator(), construct_data, values, new_size); From 7fc3c7fe7283a8b04fe0f79fe6180b6e688a565f Mon Sep 17 00:00:00 2001 From: Evan Brown Date: Wed, 26 Jul 2023 10:33:14 -0700 Subject: [PATCH 0124/1238] Change the API constraints of erase(const_iterator, const_iterator) so that calling erase(begin(), end()) resets reserved growth. PiperOrigin-RevId: 551248712 Change-Id: I34755c63e3ee40da4ba7047e0d24eec567d28173 --- absl/container/flat_hash_map.h | 6 +- absl/container/flat_hash_set.h | 6 +- absl/container/internal/raw_hash_set.h | 27 ++++++++- absl/container/internal/raw_hash_set_test.cc | 58 ++++++++++++++++++++ absl/container/node_hash_map.h | 6 +- absl/container/node_hash_set.h | 6 +- 6 files changed, 103 insertions(+), 6 deletions(-) diff --git a/absl/container/flat_hash_map.h b/absl/container/flat_hash_map.h index e6bdbd9e4f7..8f4d993911d 100644 --- a/absl/container/flat_hash_map.h +++ b/absl/container/flat_hash_map.h @@ -235,7 +235,11 @@ class flat_hash_map : public absl::container_internal::raw_hash_map< // iterator erase(const_iterator first, const_iterator last): // // Erases the elements in the open interval [`first`, `last`), returning an - // iterator pointing to `last`. + // iterator pointing to `last`. The special case of calling + // `erase(begin(), end())` resets the reserved growth such that if + // `reserve(N)` has previously been called and there has been no intervening + // call to `clear()`, then after calling `erase(begin(), end())`, it is safe + // to assume that inserting N elements will not cause a rehash. // // size_type erase(const key_type& key): // diff --git a/absl/container/flat_hash_set.h b/absl/container/flat_hash_set.h index 17bbf1a46ca..c789c7ef542 100644 --- a/absl/container/flat_hash_set.h +++ b/absl/container/flat_hash_set.h @@ -227,7 +227,11 @@ class flat_hash_set // iterator erase(const_iterator first, const_iterator last): // // Erases the elements in the open interval [`first`, `last`), returning an - // iterator pointing to `last`. + // iterator pointing to `last`. The special case of calling + // `erase(begin(), end())` resets the reserved growth such that if + // `reserve(N)` has previously been called and there has been no intervening + // call to `clear()`, then after calling `erase(begin(), end())`, it is safe + // to assume that inserting N elements will not cause a rehash. // // size_type erase(const key_type& key): // diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index f0e107be817..6da43026e51 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -786,8 +786,11 @@ class CommonFieldsGenerationInfoEnabled { public: CommonFieldsGenerationInfoEnabled() = default; CommonFieldsGenerationInfoEnabled(CommonFieldsGenerationInfoEnabled&& that) - : reserved_growth_(that.reserved_growth_), generation_(that.generation_) { + : reserved_growth_(that.reserved_growth_), + reservation_size_(that.reservation_size_), + generation_(that.generation_) { that.reserved_growth_ = 0; + that.reservation_size_ = 0; that.generation_ = EmptyGeneration(); } CommonFieldsGenerationInfoEnabled& operator=( @@ -813,6 +816,8 @@ class CommonFieldsGenerationInfoEnabled { } size_t reserved_growth() const { return reserved_growth_; } void set_reserved_growth(size_t r) { reserved_growth_ = r; } + size_t reservation_size() const { return reservation_size_; } + void set_reservation_size(size_t r) { reservation_size_ = r; } GenerationType generation() const { return *generation_; } void set_generation(GenerationType g) { *generation_ = g; } GenerationType* generation_ptr() const { return generation_; } @@ -820,10 +825,14 @@ class CommonFieldsGenerationInfoEnabled { private: // The number of insertions remaining that are guaranteed to not rehash due to - // a prior call to reserve. Note: we store reserved growth rather than + // a prior call to reserve. Note: we store reserved growth in addition to // reservation size because calls to erase() decrease size_ but don't decrease // reserved growth. size_t reserved_growth_ = 0; + // The maximum argument to reserve() since the container was cleared. We need + // to keep track of this, in addition to reserved growth, because we reset + // reserved growth to this when erase(begin(), end()) is called. + size_t reservation_size_ = 0; // Pointer to the generation counter, which is used to validate iterators and // is stored in the backing array between the control bytes and the slots. // Note that we can't store the generation inside the container itself and @@ -851,6 +860,8 @@ class CommonFieldsGenerationInfoDisabled { void reset_reserved_growth(size_t, size_t) {} size_t reserved_growth() const { return 0; } void set_reserved_growth(size_t) {} + size_t reservation_size() const { return 0; } + void set_reservation_size(size_t) {} GenerationType generation() const { return 0; } void set_generation(GenerationType) {} GenerationType* generation_ptr() const { return nullptr; } @@ -971,6 +982,12 @@ class CommonFields : public CommonFieldsGenerationInfo { CommonFieldsGenerationInfo::reset_reserved_growth(reservation, size()); } + // Returns the number of control bytes set to kDeleted. For testing only. + size_t TombstonesCount() const { + return static_cast( + std::count(control(), control() + capacity(), ctrl_t::kDeleted)); + } + private: // TODO(b/259599413): Investigate removing some of these fields: // - control/slots can be derived from each other @@ -1913,6 +1930,7 @@ class raw_hash_set { ClearBackingArray(common(), GetPolicyFunctions(), /*reuse=*/cap < 128); } common().set_reserved_growth(0); + common().set_reservation_size(0); } inline void destroy_slots() { @@ -2168,8 +2186,12 @@ class raw_hash_set { // capacity() > 0 as a precondition. if (empty()) return end(); if (first == begin() && last == end()) { + // TODO(ezb): we access control bytes in destroy_slots so it could make + // sense to combine destroy_slots and ClearBackingArray to avoid cache + // misses when the table is large. Note that we also do this in clear(). destroy_slots(); ClearBackingArray(common(), GetPolicyFunctions(), /*reuse=*/true); + common().set_reserved_growth(common().reservation_size()); return end(); } while (first != last) { @@ -2258,6 +2280,7 @@ class raw_hash_set { infoz().RecordReservation(n); } common().reset_reserved_growth(n); + common().set_reservation_size(n); } // Extension API: support for heterogeneous keys. diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc index 66621cf050d..f0947b97975 100644 --- a/absl/container/internal/raw_hash_set_test.cc +++ b/absl/container/internal/raw_hash_set_test.cc @@ -60,6 +60,10 @@ struct RawHashSetTestOnlyAccess { static auto GetSlots(const C& c) -> decltype(c.slot_array()) { return c.slot_array(); } + template + static size_t CountTombstones(const C& c) { + return c.common().TombstonesCount(); + } }; namespace { @@ -472,6 +476,28 @@ struct MinimumAlignmentUint8Table using Base::Base; }; +// Allows for freezing the allocator to expect no further allocations. +template +struct FreezableAlloc : std::allocator { + explicit FreezableAlloc(bool* f) : frozen(f) {} + + template + explicit FreezableAlloc(const FreezableAlloc& other) + : frozen(other.frozen) {} + + template + struct rebind { + using other = FreezableAlloc; + }; + + T* allocate(size_t n) { + EXPECT_FALSE(*frozen); + return std::allocator::allocate(n); + } + + bool* frozen; +}; + struct BadFastHash { template size_t operator()(const T&) const { @@ -479,6 +505,13 @@ struct BadFastHash { } }; +struct BadHashFreezableIntTable + : raw_hash_set, + FreezableAlloc> { + using Base = typename BadHashFreezableIntTable::raw_hash_set; + using Base::Base; +}; + struct BadTable : raw_hash_set, std::allocator> { using Base = typename BadTable::raw_hash_set; @@ -512,6 +545,7 @@ TEST(Table, EmptyFunctorOptimization) { struct GenerationData { size_t reserved_growth; + size_t reservation_size; GenerationType* generation; }; @@ -2387,6 +2421,30 @@ TEST(Table, ReservedGrowthUpdatesWhenTableDoesntGrow) { EXPECT_EQ(*it, 0); } +TEST(Table, EraseBeginEndResetsReservedGrowth) { + bool frozen = false; + BadHashFreezableIntTable t{FreezableAlloc(&frozen)}; + t.reserve(100); + const size_t cap = t.capacity(); + frozen = true; // no further allocs allowed + + for (int i = 0; i < 10; ++i) { + // Create a long run (hash function returns constant). + for (int j = 0; j < 100; ++j) t.insert(j); + // Erase elements from the middle of the long run, which creates tombstones. + for (int j = 30; j < 60; ++j) t.erase(j); + EXPECT_EQ(t.size(), 70); + EXPECT_EQ(t.capacity(), cap); + ASSERT_EQ(RawHashSetTestOnlyAccess::CountTombstones(t), 30); + + t.erase(t.begin(), t.end()); + + EXPECT_EQ(t.size(), 0); + EXPECT_EQ(t.capacity(), cap); + ASSERT_EQ(RawHashSetTestOnlyAccess::CountTombstones(t), 0); + } +} + TEST(Table, GenerationInfoResetsOnClear) { if (!SwisstableGenerationsEnabled()) GTEST_SKIP() << "Generations disabled."; if (kMsvc) GTEST_SKIP() << "MSVC doesn't support | in regexp."; diff --git a/absl/container/node_hash_map.h b/absl/container/node_hash_map.h index dc8d7d9ac09..a396de2eceb 100644 --- a/absl/container/node_hash_map.h +++ b/absl/container/node_hash_map.h @@ -226,7 +226,11 @@ class node_hash_map // iterator erase(const_iterator first, const_iterator last): // // Erases the elements in the open interval [`first`, `last`), returning an - // iterator pointing to `last`. + // iterator pointing to `last`. The special case of calling + // `erase(begin(), end())` resets the reserved growth such that if + // `reserve(N)` has previously been called and there has been no intervening + // call to `clear()`, then after calling `erase(begin(), end())`, it is safe + // to assume that inserting N elements will not cause a rehash. // // size_type erase(const key_type& key): // diff --git a/absl/container/node_hash_set.h b/absl/container/node_hash_set.h index 905a93d81aa..421ff4600a7 100644 --- a/absl/container/node_hash_set.h +++ b/absl/container/node_hash_set.h @@ -218,7 +218,11 @@ class node_hash_set // iterator erase(const_iterator first, const_iterator last): // // Erases the elements in the open interval [`first`, `last`), returning an - // iterator pointing to `last`. + // iterator pointing to `last`. The special case of calling + // `erase(begin(), end())` resets the reserved growth such that if + // `reserve(N)` has previously been called and there has been no intervening + // call to `clear()`, then after calling `erase(begin(), end())`, it is safe + // to assume that inserting N elements will not cause a rehash. // // size_type erase(const key_type& key): // From 4ff6968df3833b11f9ab063675126b1562b8b73b Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 26 Jul 2023 12:46:45 -0700 Subject: [PATCH 0125/1238] Undefine internal `ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR` macro after usage PiperOrigin-RevId: 551287955 Change-Id: Ic77831cec71f6ffe0a4e091baabe932b245269ea --- absl/strings/internal/str_format/constexpr_parser.h | 1 + 1 file changed, 1 insertion(+) diff --git a/absl/strings/internal/str_format/constexpr_parser.h b/absl/strings/internal/str_format/constexpr_parser.h index 3dc1776b425..b70a16e40c6 100644 --- a/absl/strings/internal/str_format/constexpr_parser.h +++ b/absl/strings/internal/str_format/constexpr_parser.h @@ -323,6 +323,7 @@ constexpr const char* ConsumeConversion(const char* pos, const char* const end, if (ABSL_PREDICT_FALSE(c == 'v')) return nullptr; if (ABSL_PREDICT_FALSE(!tag.is_conv())) return nullptr; } +#undef ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR assert(CheckFastPathSetting(*conv)); (void)(&CheckFastPathSetting); From 8f4fcc62cf9b92680bed46655653f224190bfce3 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Thu, 27 Jul 2023 08:44:56 -0700 Subject: [PATCH 0126/1238] InlinedVector: Disable CFI checking during the reinterpret_cast on the heap allocation path. The cast occurs before the memory is initialized. See also: https://clang.llvm.org/docs/ControlFlowIntegrity.html#bad-cast-checking. PiperOrigin-RevId: 551542366 Change-Id: Id5834892c36a5cb8ec095bcfee3e9e31f20c48ae --- absl/container/inlined_vector_test.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/absl/container/inlined_vector_test.cc b/absl/container/inlined_vector_test.cc index 5acad650408..d9946b2aa39 100644 --- a/absl/container/inlined_vector_test.cc +++ b/absl/container/inlined_vector_test.cc @@ -1632,6 +1632,13 @@ TEST(DynamicVec, EmplaceBack) { EXPECT_EQ(v.size(), 1u); } +TEST(DynamicVec, EmplaceBackAfterHeapAllocation) { + DynamicVec v; + v.reserve(10); + v.emplace_back(Dynamic{}); + EXPECT_EQ(v.size(), 1u); +} + TEST(AllocatorSupportTest, Constructors) { using MyAlloc = CountingAllocator; using AllocVec = absl::InlinedVector; From c9c0fd5185067208e1cc4227d16122571762af39 Mon Sep 17 00:00:00 2001 From: Evan Brown Date: Thu, 27 Jul 2023 13:00:49 -0700 Subject: [PATCH 0127/1238] Refactor raw_hash_set deallocation to pass CommonFields instead of passing the results of a bunch of accessors of CommonFields. Motivation: this makes it easier to refactor CommonFields to be smaller. PiperOrigin-RevId: 551616928 Change-Id: I3710443fb156537d716944584bea02f945559e99 --- absl/container/internal/raw_hash_set.cc | 4 +- absl/container/internal/raw_hash_set.h | 100 ++++++++++++------------ 2 files changed, 53 insertions(+), 51 deletions(-) diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc index ef2594c9b58..2ff95b61824 100644 --- a/absl/container/internal/raw_hash_set.cc +++ b/absl/container/internal/raw_hash_set.cc @@ -247,9 +247,7 @@ void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy, ResetCtrl(c, policy.slot_size); c.infoz().RecordStorageChanged(0, c.capacity()); } else { - void* set = &c; - (*policy.dealloc)(set, policy, c.backing_array_start(), c.slot_array(), - c.capacity()); + (*policy.dealloc)(c, policy); c.set_control(EmptyGroup()); c.set_generation_ptr(EmptyGeneration()); c.set_slots(nullptr); diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 6da43026e51..5f89d8efee6 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -909,6 +909,39 @@ using HashSetIteratorGenerationInfo = HashSetIteratorGenerationInfoDisabled; // A valid capacity is a non-zero integer `2^m - 1`. inline bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; } +// Computes the offset from the start of the backing allocation of the control +// bytes. growth_left is stored at the beginning of the backing array. +inline size_t ControlOffset() { return sizeof(size_t); } + +// Returns the number of "cloned control bytes". +// +// This is the number of control bytes that are present both at the beginning +// of the control byte array and at the end, such that we can create a +// `Group::kWidth`-width probe window starting from any control byte. +constexpr size_t NumClonedBytes() { return Group::kWidth - 1; } + +// Given the capacity of a table, computes the offset (from the start of the +// backing allocation) of the generation counter (if it exists). +inline size_t GenerationOffset(size_t capacity) { + assert(IsValidCapacity(capacity)); + const size_t num_control_bytes = capacity + 1 + NumClonedBytes(); + return ControlOffset() + num_control_bytes; +} + +// Given the capacity of a table, computes the offset (from the start of the +// backing allocation) at which the slots begin. +inline size_t SlotOffset(size_t capacity, size_t slot_align) { + assert(IsValidCapacity(capacity)); + return (GenerationOffset(capacity) + NumGenerationBytes() + slot_align - 1) & + (~slot_align + 1); +} + +// Given the capacity of a table, computes the total size of the backing +// array. +inline size_t AllocSize(size_t capacity, size_t slot_size, size_t slot_align) { + return SlotOffset(capacity, slot_align) + capacity * slot_size; +} + // CommonFields hold the fields in raw_hash_set that do not depend // on template parameters. This allows us to conveniently pass all // of this state to helper functions as a single argument. @@ -982,6 +1015,11 @@ class CommonFields : public CommonFieldsGenerationInfo { CommonFieldsGenerationInfo::reset_reserved_growth(reservation, size()); } + // The size of the backing array allocation. + size_t alloc_size(size_t slot_size, size_t slot_align) const { + return AllocSize(capacity(), slot_size, slot_align); + } + // Returns the number of control bytes set to kDeleted. For testing only. size_t TombstonesCount() const { return static_cast( @@ -1014,13 +1052,6 @@ class CommonFields : public CommonFieldsGenerationInfo { compressed_tuple_{0u, HashtablezInfoHandle{}}; }; -// Returns the number of "cloned control bytes". -// -// This is the number of control bytes that are present both at the beginning -// of the control byte array and at the end, such that we can create a -// `Group::kWidth`-width probe window starting from any control byte. -constexpr size_t NumClonedBytes() { return Group::kWidth - 1; } - template class raw_hash_set; @@ -1355,32 +1386,6 @@ constexpr size_t BackingArrayAlignment(size_t align_of_slot) { return (std::max)(align_of_slot, alignof(size_t)); } -// Computes the offset from the start of the backing allocation of the control -// bytes. growth_left is stored at the beginning of the backing array. -inline size_t ControlOffset() { return sizeof(size_t); } - -// Given the capacity of a table, computes the offset (from the start of the -// backing allocation) of the generation counter (if it exists). -inline size_t GenerationOffset(size_t capacity) { - assert(IsValidCapacity(capacity)); - const size_t num_control_bytes = capacity + 1 + NumClonedBytes(); - return ControlOffset() + num_control_bytes; -} - -// Given the capacity of a table, computes the offset (from the start of the -// backing allocation) at which the slots begin. -inline size_t SlotOffset(size_t capacity, size_t slot_align) { - assert(IsValidCapacity(capacity)); - return (GenerationOffset(capacity) + NumGenerationBytes() + slot_align - 1) & - (~slot_align + 1); -} - -// Given the capacity of a table, computes the total size of the backing -// array. -inline size_t AllocSize(size_t capacity, size_t slot_size, size_t slot_align) { - return SlotOffset(capacity, slot_align) + capacity * slot_size; -} - template ABSL_ATTRIBUTE_NOINLINE void InitializeSlots(CommonFields& c, Alloc alloc) { assert(c.capacity()); @@ -1426,9 +1431,8 @@ struct PolicyFunctions { // Transfer the contents of src_slot to dst_slot. void (*transfer)(void* set, void* dst_slot, void* src_slot); - // Deallocate the specified backing store which is sized for n slots. - void (*dealloc)(void* set, const PolicyFunctions& policy, - void* backing_array_start, void* slot_array, size_t n); + // Deallocate the backing store from common. + void (*dealloc)(CommonFields& common, const PolicyFunctions& policy); }; // ClearBackingArray clears the backing array, either modifying it in place, @@ -1445,16 +1449,16 @@ void EraseMetaOnly(CommonFields& c, ctrl_t* it, size_t slot_size); // function body for raw_hash_set instantiations that have the // same slot alignment. template -ABSL_ATTRIBUTE_NOINLINE void DeallocateStandard(void*, - const PolicyFunctions& policy, - void* backing_array_start, - void* slot_array, size_t n) { +ABSL_ATTRIBUTE_NOINLINE void DeallocateStandard(CommonFields& common, + const PolicyFunctions& policy) { // Unpoison before returning the memory to the allocator. - SanitizerUnpoisonMemoryRegion(slot_array, policy.slot_size * n); + SanitizerUnpoisonMemoryRegion(common.slot_array(), + policy.slot_size * common.capacity()); std::allocator alloc; Deallocate( - &alloc, backing_array_start, AllocSize(n, policy.slot_size, AlignOfSlot)); + &alloc, common.backing_array_start(), + common.alloc_size(policy.slot_size, AlignOfSlot)); } // For trivially relocatable types we use memcpy directly. This allows us to @@ -2763,16 +2767,16 @@ class raw_hash_set { static_cast(src)); } // Note: dealloc_fn will only be used if we have a non-standard allocator. - static void dealloc_fn(void* set, const PolicyFunctions&, - void* backing_array_start, void* slot_mem, size_t n) { - auto* h = static_cast(set); + static void dealloc_fn(CommonFields& common, const PolicyFunctions&) { + auto* set = reinterpret_cast(&common); // Unpoison before returning the memory to the allocator. - SanitizerUnpoisonMemoryRegion(slot_mem, sizeof(slot_type) * n); + SanitizerUnpoisonMemoryRegion(common.slot_array(), + sizeof(slot_type) * common.capacity()); Deallocate( - &h->alloc_ref(), backing_array_start, - AllocSize(n, sizeof(slot_type), alignof(slot_type))); + &set->alloc_ref(), common.backing_array_start(), + common.alloc_size(sizeof(slot_type), alignof(slot_type))); } static const PolicyFunctions& GetPolicyFunctions() { From d3ddfaa1e5fa9adb017a3bc0cd87171741985613 Mon Sep 17 00:00:00 2001 From: Dino Radakovic Date: Mon, 31 Jul 2023 10:20:22 -0700 Subject: [PATCH 0128/1238] raw_hash_set_test: Match lowercase "invalid iterator" in death tests PiperOrigin-RevId: 552520562 Change-Id: I5d311871afbc2906894c3b754a503a6abace8ceb --- absl/container/internal/raw_hash_set_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc index f0947b97975..c18dce3b721 100644 --- a/absl/container/internal/raw_hash_set_test.cc +++ b/absl/container/internal/raw_hash_set_test.cc @@ -2156,7 +2156,7 @@ TEST(TableDeathTest, InvalidIteratorAsserts) { // use-of-uninitialized-value in msan, or invalidated iterator assertions. constexpr const char* kInvalidIteratorDeathMessage = "heap-use-after-free|use-of-uninitialized-value|invalidated " - "iterator|Invalid iterator"; + "iterator|Invalid iterator|invalid iterator"; // MSVC doesn't support | in regex. #if defined(_MSC_VER) From 4b6e59a96304c9a44e186295bffa8a890adb8762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Mon, 31 Jul 2023 12:46:00 -0700 Subject: [PATCH 0129/1238] PR #1495: CMake: Link CoreFoundation with -framework Imported from GitHub PR https://github.com/abseil/abseil-cpp/pull/1495 This fixes https://github.com/abseil/abseil-cpp/issues/1494 With CMake 3.24 we can also use `$` but abseil is still at CMake 3.10 The change has been tested here: https://github.com/daschuer/vcpkg/actions/runs/5670741925 Merge f3ff6bc01ff45970d2b803ca51421483b423b72b into c9c0fd5185067208e1cc4227d16122571762af39 Merging this change closes #1495 COPYBARA_INTEGRATE_REVIEW=https://github.com/abseil/abseil-cpp/pull/1495 from daschuer:framework-link-fix f3ff6bc01ff45970d2b803ca51421483b423b72b PiperOrigin-RevId: 552564485 Change-Id: I57b580e5795c54865576110e56220128d8b603b8 --- absl/time/CMakeLists.txt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/absl/time/CMakeLists.txt b/absl/time/CMakeLists.txt index 1c830c7a571..e1ade7a31a8 100644 --- a/absl/time/CMakeLists.txt +++ b/absl/time/CMakeLists.txt @@ -54,10 +54,6 @@ absl_cc_library( ${ABSL_DEFAULT_COPTS} ) -if(APPLE) - find_library(CoreFoundation CoreFoundation) -endif() - absl_cc_library( NAME time_zone @@ -85,7 +81,9 @@ absl_cc_library( ${ABSL_DEFAULT_COPTS} DEPS Threads::Threads - $<$:${CoreFoundation}> + # TODO(#1495): Use $ once our + # minimum CMake version >= 3.24 + $<$:-Wl,-framework,CoreFoundation> ) # Internal-only target, do not depend on directly. From 407f2fdd5ec6f79287919486aa5869b346093906 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Mon, 31 Jul 2023 12:46:32 -0700 Subject: [PATCH 0130/1238] PR #1498: Fix order of link options in pkg-config files Imported from GitHub PR https://github.com/abseil/abseil-cpp/pull/1498 In Windows, a few libraries (`dbghelp`, `advapi32`, and `bcrypt`) are added via link options. However, the .pc files produced for pkg-config erroneously include them before the abseil libraries. This can cause undefined references when trying to build against abseil. This commit swaps the order and adds the custom link options after the abseil dependencies. The following is a list of `.pc` files affected by this and the additional link options used: * all: `-L${libdir}` * `absl_base.pc`: `-ladvapi32` * `absl_random_internal_seed_material.pc`: `-lbcrypt` * `absl_symbolize.pc`: `-ldbghelp` Closes https://github.com/abseil/abseil-cpp/issues/1497 Merge af61f6d5d5fa7b390fc2e009652cd6da68b0fd38 into c9c0fd5185067208e1cc4227d16122571762af39 Merging this change closes #1498 COPYBARA_INTEGRATE_REVIEW=https://github.com/abseil/abseil-cpp/pull/1498 from stanhu:sh-fix-pc-link-order af61f6d5d5fa7b390fc2e009652cd6da68b0fd38 PiperOrigin-RevId: 552564626 Change-Id: I9d2a6ab99993bb4315dc94eade2cd419f1109c13 --- CMake/AbseilDll.cmake | 2 +- CMake/AbseilHelpers.cmake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index f8dea458b62..f0d984ae190 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake @@ -788,7 +788,7 @@ Name: ${_dll}\n\ Description: Abseil DLL library\n\ URL: https://abseil.io/\n\ Version: ${absl_VERSION}\n\ -Libs: -L\${libdir} ${PC_LINKOPTS} $<$>:-l${_dll}>\n\ +Libs: -L\${libdir} $<$>:-l${_dll}> ${PC_LINKOPTS}\n\ Cflags: -I\${includedir}${PC_CFLAGS}\n") INSTALL(FILES "${CMAKE_BINARY_DIR}/lib/pkgconfig/${_dll}.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") diff --git a/CMake/AbseilHelpers.cmake b/CMake/AbseilHelpers.cmake index de63531b7f7..5a6c57fdd9f 100644 --- a/CMake/AbseilHelpers.cmake +++ b/CMake/AbseilHelpers.cmake @@ -211,7 +211,7 @@ Description: Abseil ${_NAME} library\n\ URL: https://abseil.io/\n\ Version: ${PC_VERSION}\n\ Requires:${PC_DEPS}\n\ -Libs: -L\${libdir} ${PC_LINKOPTS} $<$>:${LNK_LIB}>\n\ +Libs: -L\${libdir} $<$>:${LNK_LIB}> ${PC_LINKOPTS}\n\ Cflags: -I\${includedir}${PC_CFLAGS}\n") INSTALL(FILES "${CMAKE_BINARY_DIR}/lib/pkgconfig/absl_${_NAME}.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") From d7aae58cb693aaf8a3351be2e5fce2eefeff30c9 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 31 Jul 2023 17:30:26 -0700 Subject: [PATCH 0131/1238] Remove deprecated function. PiperOrigin-RevId: 552638642 Change-Id: I6b43289ca10ee9aecd6b848e78471863b22b01d1 --- absl/crc/crc32c.h | 1 + 1 file changed, 1 insertion(+) diff --git a/absl/crc/crc32c.h b/absl/crc/crc32c.h index ba09e52a018..79059dc1308 100644 --- a/absl/crc/crc32c.h +++ b/absl/crc/crc32c.h @@ -65,6 +65,7 @@ class crc32c_t final { uint32_t crc_; }; + namespace crc_internal { // Non-inline code path for `absl::ExtendCrc32c()`. Do not call directly. // Call `absl::ExtendCrc32c()` (defined below) instead. From 22091f4c0d6626b3ef40446ce3d4ccab19425ca3 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 1 Aug 2023 07:58:20 -0700 Subject: [PATCH 0132/1238] Speed up StrAppend by up to 4x. PiperOrigin-RevId: 552802740 Change-Id: I662da1b03bfffb7939b44ea3850566d3c209c6cc --- absl/strings/str_cat.cc | 178 +++------------------------------------- absl/strings/str_cat.h | 152 +++++++++++++++++++++++++++------- 2 files changed, 134 insertions(+), 196 deletions(-) diff --git a/absl/strings/str_cat.cc b/absl/strings/str_cat.cc index 2e49c31b68e..5ec029959a0 100644 --- a/absl/strings/str_cat.cc +++ b/absl/strings/str_cat.cc @@ -14,17 +14,9 @@ #include "absl/strings/str_cat.h" -#include - -#include -#include #include -#include #include -#include "absl/strings/ascii.h" -#include "absl/strings/internal/resize_uninitialized.h" -#include "absl/strings/numbers.h" #include "absl/strings/string_view.h" namespace absl { @@ -37,170 +29,26 @@ ABSL_NAMESPACE_BEGIN // of a mix of raw C strings, string_views, strings, and integer values. // ---------------------------------------------------------------------- -// Append is merely a version of memcpy that returns the address of the byte -// after the area just overwritten. -static char* Append(char* out, const AlphaNum& x) { - // memcpy is allowed to overwrite arbitrary memory, so doing this after the - // call would force an extra fetch of x.size(). - char* after = out + x.size(); - if (x.size() != 0) { - memcpy(out, x.data(), x.size()); - } - return after; -} - -std::string StrCat(const AlphaNum& a, const AlphaNum& b) { - std::string result; - absl::strings_internal::STLStringResizeUninitialized(&result, - a.size() + b.size()); - char* const begin = &result[0]; - char* out = begin; - out = Append(out, a); - out = Append(out, b); - assert(out == begin + result.size()); - return result; -} - -std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) { - std::string result; - strings_internal::STLStringResizeUninitialized( - &result, a.size() + b.size() + c.size()); - char* const begin = &result[0]; - char* out = begin; - out = Append(out, a); - out = Append(out, b); - out = Append(out, c); - assert(out == begin + result.size()); - return result; -} - -std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, - const AlphaNum& d) { - std::string result; - strings_internal::STLStringResizeUninitialized( - &result, a.size() + b.size() + c.size() + d.size()); - char* const begin = &result[0]; - char* out = begin; - out = Append(out, a); - out = Append(out, b); - out = Append(out, c); - out = Append(out, d); - assert(out == begin + result.size()); - return result; -} - namespace strings_internal { -// Do not call directly - these are not part of the public API. -std::string CatPieces(std::initializer_list pieces) { - std::string result; - size_t total_size = 0; - for (absl::string_view piece : pieces) total_size += piece.size(); - strings_internal::STLStringResizeUninitialized(&result, total_size); - - char* const begin = &result[0]; - char* out = begin; - for (absl::string_view piece : pieces) { - const size_t this_size = piece.size(); - if (this_size != 0) { - memcpy(out, piece.data(), this_size); - out += this_size; - } - } - assert(out == begin + result.size()); - return result; +bool HaveOverlap(const std::string& x, absl::string_view y) { + if (y.empty()) return false; + // TODO(b/290623057): Re-evaluate the check below: it detects when buffers + // overlap (which is good) but it also introduces undefined behaviour when + // buffers don't overlap (substracting pointers that do not belong to the same + // array is UB [expr.add]). In other words, if compiler assumes that a program + // never has UB, then it can replace `assert(HaveOverlap(x, y))` with + // `assert(false)`. + return (uintptr_t(y.data() - x.data()) <= uintptr_t(x.size())); } -// It's possible to call StrAppend with an absl::string_view that is itself a -// fragment of the string we're appending to. However the results of this are -// random. Therefore, check for this in debug mode. Use unsigned math so we -// only have to do one comparison. Note, there's an exception case: appending an -// empty string is always allowed. -#define ASSERT_NO_OVERLAP(dest, src) \ - assert(((src).size() == 0) || \ - (uintptr_t((src).data() - (dest).data()) > uintptr_t((dest).size()))) - -void AppendPieces(std::string* dest, - std::initializer_list pieces) { - size_t old_size = dest->size(); - size_t total_size = old_size; - for (absl::string_view piece : pieces) { - ASSERT_NO_OVERLAP(*dest, piece); - total_size += piece.size(); - } - strings_internal::STLStringResizeUninitializedAmortized(dest, total_size); - - char* const begin = &(*dest)[0]; - char* out = begin + old_size; - for (absl::string_view piece : pieces) { - const size_t this_size = piece.size(); - if (this_size != 0) { - memcpy(out, piece.data(), this_size); - out += this_size; - } - } - assert(out == begin + dest->size()); +#if defined(__GNUC__) && !defined(__clang__) +char* AppendAlphaNum(char* dst, const AlphaNum& a) { + return std::copy_n(a.data(), a.size(), dst); } +#endif } // namespace strings_internal -void StrAppend(std::string* dest, const AlphaNum& a) { - ASSERT_NO_OVERLAP(*dest, a); - std::string::size_type old_size = dest->size(); - strings_internal::STLStringResizeUninitializedAmortized(dest, - old_size + a.size()); - char* const begin = &(*dest)[0]; - char* out = begin + old_size; - out = Append(out, a); - assert(out == begin + dest->size()); -} - -void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b) { - ASSERT_NO_OVERLAP(*dest, a); - ASSERT_NO_OVERLAP(*dest, b); - std::string::size_type old_size = dest->size(); - strings_internal::STLStringResizeUninitializedAmortized( - dest, old_size + a.size() + b.size()); - char* const begin = &(*dest)[0]; - char* out = begin + old_size; - out = Append(out, a); - out = Append(out, b); - assert(out == begin + dest->size()); -} - -void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c) { - ASSERT_NO_OVERLAP(*dest, a); - ASSERT_NO_OVERLAP(*dest, b); - ASSERT_NO_OVERLAP(*dest, c); - std::string::size_type old_size = dest->size(); - strings_internal::STLStringResizeUninitializedAmortized( - dest, old_size + a.size() + b.size() + c.size()); - char* const begin = &(*dest)[0]; - char* out = begin + old_size; - out = Append(out, a); - out = Append(out, b); - out = Append(out, c); - assert(out == begin + dest->size()); -} - -void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c, const AlphaNum& d) { - ASSERT_NO_OVERLAP(*dest, a); - ASSERT_NO_OVERLAP(*dest, b); - ASSERT_NO_OVERLAP(*dest, c); - ASSERT_NO_OVERLAP(*dest, d); - std::string::size_type old_size = dest->size(); - strings_internal::STLStringResizeUninitializedAmortized( - dest, old_size + a.size() + b.size() + c.size() + d.size()); - char* const begin = &(*dest)[0]; - char* out = begin + old_size; - out = Append(out, a); - out = Append(out, b); - out = Append(out, c); - out = Append(out, d); - assert(out == begin + dest->size()); -} - ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h index d5f71ff003f..f5f2c01623f 100644 --- a/absl/strings/str_cat.h +++ b/absl/strings/str_cat.h @@ -91,7 +91,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -99,6 +101,7 @@ #include "absl/base/attributes.h" #include "absl/base/port.h" #include "absl/strings/internal/has_absl_stringify.h" +#include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/internal/stringify_sink.h" #include "absl/strings/numbers.h" #include "absl/strings/string_view.h" @@ -409,6 +412,93 @@ class AlphaNum { char digits_[numbers_internal::kFastToBufferSize]; }; +namespace strings_internal { + +// Inlining this function improves performance. However, on GCC this triggers +// [-Werror=stringop-overflow=], and in that case we split declaration and +// definition as a workaround. +#if defined(__GNUC__) && !defined(__clang__) +char* AppendAlphaNum(char* dst, const AlphaNum& a); +#else +inline char* AppendAlphaNum(char* dst, const AlphaNum& a) { + return std::copy_n(a.data(), a.size(), dst); +} +#endif + +// It's possible to call StrAppend with an absl::string_view that is itself a +// fragment of the string we're appending to. However the results of this are +// UB. Therefore, check for this in debug mode. Use unsigned math so we +// only have to do one comparison. Note, there's an exception case: appending an +// empty string is always allowed. +bool HaveOverlap(const std::string& x, absl::string_view y); + +// C++14 compatible alternative to left +// https://en.cppreference.com/w/cpp/language/fold expression. +// TODO(b/290784225): Remove `FoldLeft` once Abseil drops C++14 support. +template +auto FoldLeft(const F&, Acc&& acc) { + return std::forward(acc); +} +template +auto FoldLeft(const F& f, Acc&& acc, First&& first, Rest&&... rest) { + return FoldLeft(f, f(std::forward(acc), std::forward(first)), + std::forward(rest)...); +} + +template +inline void StrAppendTemplate(std::index_sequence, + std::string* dest, Tuple args) { + // Note on `Is` and `Tuple`: + // + // The goal is to pass N arguments to `StrAppend` and retain `N` as a + // compile-time constant. Thus, we cannot use dynamically sized collections + // such as `absl::Span` or `std::initialized_list`: `std::tuple` comes to + // the rescue. + // `Tuple` is a fixed-sized collection of N elements of `const AlphaNum&`. + // `Indices` is deduced from `std::make_index_sequence` and is used as a + // helper to writing Fold expressions on `Tuple`. + assert(FoldLeft(std::logical_and<>{}, + !HaveOverlap(*dest, std::get(args).Piece())...)); + size_t old_size = dest->size(); + size_t new_size = + FoldLeft(std::plus<>{}, old_size, std::get(args).size()...); + strings_internal::STLStringResizeUninitializedAmortized(dest, new_size); + FoldLeft(AppendAlphaNum, &(*dest)[old_size], std::get(args)...); +} + +template +inline std::string StrCatTemplate(std::index_sequence, Tuple args) { + // See implementation comments in `StrAppendTemplate`. + std::string dest; + size_t size = FoldLeft(std::plus{}, size_t{0}, + std::get(args).size()...); + strings_internal::STLStringResizeUninitializedAmortized(&dest, size); + FoldLeft(AppendAlphaNum, &dest[0], std::get(args)...); + return dest; +} + +// Template functions `StrAppendImpl` and `StrCatImpl` are not exported directly +// due to historical reasons: there are many existing dependencies that expect +// 0-4 argument overloads to be non-template functions. Hence implementations +// are wrapped to keep the compatibility (0-4 arguments only, 5+ arguments are +// templates). + +template +inline void StrAppendImpl(std::string* dest, const AV&... args) { + strings_internal::StrAppendTemplate( + std::make_index_sequence{}, dest, + std::forward_as_tuple(static_cast(args)...)); +} + +template +inline std::string StrCatImpl(const AV&... args) { + return strings_internal::StrCatTemplate( + std::make_index_sequence{}, + std::forward_as_tuple(static_cast(args)...)); +} + +} // namespace strings_internal + // ----------------------------------------------------------------------------- // StrCat() // ----------------------------------------------------------------------------- @@ -436,36 +526,32 @@ class AlphaNum { // quadratic time operation with O(n) dynamic allocations. // // See `StrAppend()` below for more information. - -namespace strings_internal { - -// Do not call directly - this is not part of the public API. -std::string CatPieces(std::initializer_list pieces); -void AppendPieces(std::string* dest, - std::initializer_list pieces); - -} // namespace strings_internal - ABSL_MUST_USE_RESULT inline std::string StrCat() { return std::string(); } - ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a) { return std::string(a.data(), a.size()); } - -ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b); -ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c); -ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c, const AlphaNum& d); +ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a, + const AlphaNum& b) { + return strings_internal::StrCatImpl(a, b); +} +ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a, + const AlphaNum& b, + const AlphaNum& c) { + return strings_internal::StrCatImpl(a, b, c); +} +ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a, + const AlphaNum& b, + const AlphaNum& c, + const AlphaNum& d) { + return strings_internal::StrCatImpl(a, b, c, d); +} // Support 5 or more arguments template ABSL_MUST_USE_RESULT inline std::string StrCat( const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d, const AlphaNum& e, const AV&... args) { - return strings_internal::CatPieces( - {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(), - static_cast(args).Piece()...}); + return strings_internal::StrCatImpl(a, b, c, d, e, args...); } // ----------------------------------------------------------------------------- @@ -494,23 +580,27 @@ ABSL_MUST_USE_RESULT inline std::string StrCat( // std::string s = "foobar"; // absl::string_view p = s; // StrAppend(&s, p); - inline void StrAppend(std::string*) {} -void StrAppend(std::string* dest, const AlphaNum& a); -void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b); -void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c); -void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c, const AlphaNum& d); - +inline void StrAppend(std::string* dest, const AlphaNum& a) { + strings_internal::StrAppendImpl(dest, a); +} +inline void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b) { + strings_internal::StrAppendImpl(dest, a, b); +} +inline void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, + const AlphaNum& c) { + strings_internal::StrAppendImpl(dest, a, b, c); +} +inline void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, + const AlphaNum& c, const AlphaNum& d) { + strings_internal::StrAppendImpl(dest, a, b, c, d); +} // Support 5 or more arguments template inline void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d, const AlphaNum& e, const AV&... args) { - strings_internal::AppendPieces( - dest, {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(), - static_cast(args).Piece()...}); + strings_internal::StrAppendImpl(dest, a, b, c, d, e, args...); } // Helper function for the future StrCat default floating-point format, %.6g From a4771dbd8a34980a6b41c595c1c07d1d0a1e1e2c Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Tue, 1 Aug 2023 10:33:06 -0700 Subject: [PATCH 0133/1238] InlinedVector: Disable CFI checking on the const GetInlinedData() path as well. Some empty cases can trigger this. See also: https://clang.llvm.org/docs/ControlFlowIntegrity.html#bad-cast-checking. PiperOrigin-RevId: 552846765 Change-Id: I6adb3c0c73efec841ffe8fdac4342f641c68ddbe --- absl/container/inlined_vector_test.cc | 6 ++++++ absl/container/internal/inlined_vector.h | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/absl/container/inlined_vector_test.cc b/absl/container/inlined_vector_test.cc index d9946b2aa39..b9a79f5be2c 100644 --- a/absl/container/inlined_vector_test.cc +++ b/absl/container/inlined_vector_test.cc @@ -1639,6 +1639,12 @@ TEST(DynamicVec, EmplaceBackAfterHeapAllocation) { EXPECT_EQ(v.size(), 1u); } +TEST(DynamicVec, EmptyIteratorComparison) { + DynamicVec v; + EXPECT_EQ(v.begin(), v.end()); + EXPECT_EQ(v.cbegin(), v.cend()); +} + TEST(AllocatorSupportTest, Constructors) { using MyAlloc = CountingAllocator; using AllocVec = absl::InlinedVector; diff --git a/absl/container/internal/inlined_vector.h b/absl/container/internal/inlined_vector.h index cdfd868efda..b2a602db7e2 100644 --- a/absl/container/internal/inlined_vector.h +++ b/absl/container/internal/inlined_vector.h @@ -400,7 +400,7 @@ class Storage { return reinterpret_cast>(data_.inlined.inlined_data); } - ConstPointer GetInlinedData() const { + ABSL_ATTRIBUTE_NO_SANITIZE_CFI ConstPointer GetInlinedData() const { return reinterpret_cast>(data_.inlined.inlined_data); } From f6acd471e2b9063e9d56a6e7867023d87649a03c Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 1 Aug 2023 10:39:31 -0700 Subject: [PATCH 0134/1238] Import of CCTZ from GitHub. PiperOrigin-RevId: 552848883 Change-Id: Ibcf4b59e2ab671d8dd8fddcbc9d74d4c8cd3f0ff --- absl/time/internal/cctz/src/time_zone_info.cc | 14 ++++++++------ .../internal/cctz/src/time_zone_lookup_test.cc | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/absl/time/internal/cctz/src/time_zone_info.cc b/absl/time/internal/cctz/src/time_zone_info.cc index a3be65582c4..f46198ffaa7 100644 --- a/absl/time/internal/cctz/src/time_zone_info.cc +++ b/absl/time/internal/cctz/src/time_zone_info.cc @@ -338,11 +338,13 @@ bool TimeZoneInfo::ExtendTransitions() { return EquivTransitions(transitions_.back().type_index, dst_ti); } - // Extend the transitions for an additional 400 years using the - // future specification. Years beyond those can be handled by - // mapping back to a cycle-equivalent year within that range. - // We may need two additional transitions for the current year. - transitions_.reserve(transitions_.size() + 400 * 2 + 2); + // Extend the transitions for an additional 401 years using the future + // specification. Years beyond those can be handled by mapping back to + // a cycle-equivalent year within that range. Note that we need 401 + // (well, at least the first transition in the 401st year) so that the + // end of the 400th year is mapped back to an extended year. And first + // we may also need two additional transitions for the current year. + transitions_.reserve(transitions_.size() + 2 + 401 * 2); extended_ = true; const Transition& last(transitions_.back()); @@ -356,7 +358,7 @@ bool TimeZoneInfo::ExtendTransitions() { Transition dst = {0, dst_ti, civil_second(), civil_second()}; Transition std = {0, std_ti, civil_second(), civil_second()}; - for (const year_t limit = last_year_ + 400;; ++last_year_) { + for (const year_t limit = last_year_ + 401;; ++last_year_) { auto dst_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_start); auto std_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_end); dst.unix_time = jan1_time + dst_trans_off - posix.std_offset; diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc index fc6592668fe..4884c32eb31 100644 --- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc +++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc @@ -135,6 +135,7 @@ const char* const kTimeZoneNames[] = {"Africa/Abidjan", "America/Cayman", "America/Chicago", "America/Chihuahua", + "America/Ciudad_Juarez", "America/Coral_Harbour", "America/Cordoba", "America/Costa_Rica", From c66815ac2ee561cd97e03780c5aa2ad951fbc90f Mon Sep 17 00:00:00 2001 From: Dino Radakovic Date: Tue, 1 Aug 2023 13:19:00 -0700 Subject: [PATCH 0135/1238] raw_hash_set_test: Expect tsan to catch heap-use-after-free on iterators invalidated by rehashing PiperOrigin-RevId: 552901078 Change-Id: I137d01fe87b1bbf591b400305f6f7919982fc1c9 --- absl/container/internal/raw_hash_set_test.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc index c18dce3b721..242a97cbe3f 100644 --- a/absl/container/internal/raw_hash_set_test.cc +++ b/absl/container/internal/raw_hash_set_test.cc @@ -2204,10 +2204,14 @@ TEST(TableDeathTest, IteratorInvalidAssertsEqualityOperator) { for (int i = 0; i < 10; ++i) t1.insert(i); // There should have been a rehash in t1. if (kMsvc) return; // MSVC doesn't support | in regex. + + // NOTE(b/293887834): After rehashing, iterators will contain pointers to + // freed memory, which may be detected by ThreadSanitizer. const char* const kRehashedDeathMessage = SwisstableGenerationsEnabled() ? kInvalidIteratorDeathMessage - : "Invalid iterator comparison.*might have rehashed.*config=asan"; + : "Invalid iterator comparison.*might have rehashed.*config=asan" + "|ThreadSanitizer: heap-use-after-free"; EXPECT_DEATH_IF_SUPPORTED(void(iter1 == t1.begin()), kRehashedDeathMessage); } From 5b3b0ed81cb514540c3b9d752d9e01efb64056d2 Mon Sep 17 00:00:00 2001 From: Ryan Schmidt Date: Tue, 1 Aug 2023 14:26:51 -0700 Subject: [PATCH 0136/1238] PR #1500: Define MAP_ANONYMOUS if not defined Included are additional automated edits by clang-format on import. Merge d74896699faacc4a1667603e52e72cbdc8006cf6 into 22091f4c0d6626b3ef40446ce3d4ccab19425ca3 Merging this change closes #1500 COPYBARA_INTEGRATE_REVIEW=https://github.com/abseil/abseil-cpp/pull/1500 from ryandesign:MAP_ANONYMOUS d74896699faacc4a1667603e52e72cbdc8006cf6 PiperOrigin-RevId: 552922776 Change-Id: I96a0395cb5e7156d7c7a889491c5d0b4cf755819 --- absl/base/internal/low_level_alloc.cc | 71 +++++++++----------- absl/debugging/failure_signal_handler.cc | 21 +++--- absl/debugging/internal/examine_stack.cc | 3 + absl/debugging/internal/stack_consumption.cc | 7 +- absl/debugging/symbolize_test.cc | 38 +++++------ 5 files changed, 67 insertions(+), 73 deletions(-) diff --git a/absl/base/internal/low_level_alloc.cc b/absl/base/internal/low_level_alloc.cc index 445c34587ae..6d2cfeac3cf 100644 --- a/absl/base/internal/low_level_alloc.cc +++ b/absl/base/internal/low_level_alloc.cc @@ -47,24 +47,20 @@ #endif #include + #include #include #include #include -#include // for placement-new +#include // for placement-new #include "absl/base/dynamic_annotations.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/internal/spinlock.h" -// MAP_ANONYMOUS -#if defined(__APPLE__) || defined(__hexagon__) -// For mmap, Linux defines both MAP_ANONYMOUS and MAP_ANON and says MAP_ANON is -// deprecated. In Darwin, MAP_ANON is all there is. -#if !defined MAP_ANONYMOUS +#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) #define MAP_ANONYMOUS MAP_ANON -#endif // !MAP_ANONYMOUS -#endif // __APPLE__ +#endif namespace absl { ABSL_NAMESPACE_BEGIN @@ -126,7 +122,7 @@ static int IntLog2(size_t size, size_t base) { static int Random(uint32_t *state) { uint32_t r = *state; int result = 1; - while ((((r = r*1103515245 + 12345) >> 30) & 1) == 0) { + while ((((r = r * 1103515245 + 12345) >> 30) & 1) == 0) { result++; } *state = r; @@ -148,7 +144,7 @@ static int LLA_SkiplistLevels(size_t size, size_t base, uint32_t *random) { size_t max_fit = (size - offsetof(AllocList, next)) / sizeof(AllocList *); int level = IntLog2(size, base) + (random != nullptr ? Random(random) : 1); if (static_cast(level) > max_fit) level = static_cast(max_fit); - if (level > kMaxLevel-1) level = kMaxLevel - 1; + if (level > kMaxLevel - 1) level = kMaxLevel - 1; ABSL_RAW_CHECK(level >= 1, "block not big enough for even one level"); return level; } @@ -157,8 +153,8 @@ static int LLA_SkiplistLevels(size_t size, size_t base, uint32_t *random) { // For 0 <= i < head->levels, set prev[i] to "no_greater", where no_greater // points to the last element at level i in the AllocList less than *e, or is // head if no such element exists. -static AllocList *LLA_SkiplistSearch(AllocList *head, - AllocList *e, AllocList **prev) { +static AllocList *LLA_SkiplistSearch(AllocList *head, AllocList *e, + AllocList **prev) { AllocList *p = head; for (int level = head->levels - 1; level >= 0; level--) { for (AllocList *n; (n = p->next[level]) != nullptr && n < e; p = n) { @@ -194,7 +190,7 @@ static void LLA_SkiplistDelete(AllocList *head, AllocList *e, prev[i]->next[i] = e->next[i]; } while (head->levels > 0 && head->next[head->levels - 1] == nullptr) { - head->levels--; // reduce head->levels if level unused + head->levels--; // reduce head->levels if level unused } } @@ -253,9 +249,9 @@ void CreateGlobalArenas() { // Returns a global arena that does not call into hooks. Used by NewArena() // when kCallMallocHook is not set. -LowLevelAlloc::Arena* UnhookedArena() { +LowLevelAlloc::Arena *UnhookedArena() { base_internal::LowLevelCallOnce(&create_globals_once, CreateGlobalArenas); - return reinterpret_cast(&unhooked_arena_storage); + return reinterpret_cast(&unhooked_arena_storage); } #ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING @@ -273,7 +269,7 @@ LowLevelAlloc::Arena *UnhookedAsyncSigSafeArena() { // Returns the default arena, as used by LowLevelAlloc::Alloc() and friends. LowLevelAlloc::Arena *LowLevelAlloc::DefaultArena() { base_internal::LowLevelCallOnce(&create_globals_once, CreateGlobalArenas); - return reinterpret_cast(&default_arena_storage); + return reinterpret_cast(&default_arena_storage); } // magic numbers to identify allocated and unallocated blocks @@ -360,8 +356,7 @@ LowLevelAlloc::Arena::Arena(uint32_t flags_value) min_size(2 * round_up), random(0) { freelist.header.size = 0; - freelist.header.magic = - Magic(kMagicUnallocated, &freelist.header); + freelist.header.magic = Magic(kMagicUnallocated, &freelist.header); freelist.header.arena = this; freelist.levels = 0; memset(freelist.next, 0, sizeof(freelist.next)); @@ -379,7 +374,7 @@ LowLevelAlloc::Arena *LowLevelAlloc::NewArena(uint32_t flags) { meta_data_arena = UnhookedArena(); } Arena *result = - new (AllocWithArena(sizeof (*result), meta_data_arena)) Arena(flags); + new (AllocWithArena(sizeof(*result), meta_data_arena)) Arena(flags); return result; } @@ -484,8 +479,8 @@ static void Coalesce(AllocList *a) { AllocList *prev[kMaxLevel]; LLA_SkiplistDelete(&arena->freelist, n, prev); LLA_SkiplistDelete(&arena->freelist, a, prev); - a->levels = LLA_SkiplistLevels(a->header.size, arena->min_size, - &arena->random); + a->levels = + LLA_SkiplistLevels(a->header.size, arena->min_size, &arena->random); LLA_SkiplistInsert(&arena->freelist, a, prev); } } @@ -493,27 +488,27 @@ static void Coalesce(AllocList *a) { // Adds block at location "v" to the free list // L >= arena->mu static void AddToFreelist(void *v, LowLevelAlloc::Arena *arena) { - AllocList *f = reinterpret_cast( - reinterpret_cast(v) - sizeof (f->header)); + AllocList *f = reinterpret_cast(reinterpret_cast(v) - + sizeof(f->header)); ABSL_RAW_CHECK(f->header.magic == Magic(kMagicAllocated, &f->header), "bad magic number in AddToFreelist()"); ABSL_RAW_CHECK(f->header.arena == arena, "bad arena pointer in AddToFreelist()"); - f->levels = LLA_SkiplistLevels(f->header.size, arena->min_size, - &arena->random); + f->levels = + LLA_SkiplistLevels(f->header.size, arena->min_size, &arena->random); AllocList *prev[kMaxLevel]; LLA_SkiplistInsert(&arena->freelist, f, prev); f->header.magic = Magic(kMagicUnallocated, &f->header); - Coalesce(f); // maybe coalesce with successor - Coalesce(prev[0]); // maybe coalesce with predecessor + Coalesce(f); // maybe coalesce with successor + Coalesce(prev[0]); // maybe coalesce with predecessor } // Frees storage allocated by LowLevelAlloc::Alloc(). // L < arena->mu void LowLevelAlloc::Free(void *v) { if (v != nullptr) { - AllocList *f = reinterpret_cast( - reinterpret_cast(v) - sizeof (f->header)); + AllocList *f = reinterpret_cast(reinterpret_cast(v) - + sizeof(f->header)); LowLevelAlloc::Arena *arena = f->header.arena; ArenaLock section(arena); AddToFreelist(v, arena); @@ -528,21 +523,21 @@ void LowLevelAlloc::Free(void *v) { static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) { void *result = nullptr; if (request != 0) { - AllocList *s; // will point to region that satisfies request + AllocList *s; // will point to region that satisfies request ArenaLock section(arena); // round up with header - size_t req_rnd = RoundUp(CheckedAdd(request, sizeof (s->header)), - arena->round_up); - for (;;) { // loop until we find a suitable region + size_t req_rnd = + RoundUp(CheckedAdd(request, sizeof(s->header)), arena->round_up); + for (;;) { // loop until we find a suitable region // find the minimum levels that a block of this size must have int i = LLA_SkiplistLevels(req_rnd, arena->min_size, nullptr) - 1; - if (i < arena->freelist.levels) { // potential blocks exist + if (i < arena->freelist.levels) { // potential blocks exist AllocList *before = &arena->freelist; // predecessor of s while ((s = Next(i, before, arena)) != nullptr && s->header.size < req_rnd) { before = s; } - if (s != nullptr) { // we found a region + if (s != nullptr) { // we found a region break; } } @@ -596,12 +591,12 @@ static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) { AddToFreelist(&s->levels, arena); // insert new region into free list } AllocList *prev[kMaxLevel]; - LLA_SkiplistDelete(&arena->freelist, s, prev); // remove from free list + LLA_SkiplistDelete(&arena->freelist, s, prev); // remove from free list // s points to the first free region that's big enough if (CheckedAdd(req_rnd, arena->min_size) <= s->header.size) { // big enough to split - AllocList *n = reinterpret_cast - (req_rnd + reinterpret_cast(s)); + AllocList *n = + reinterpret_cast(req_rnd + reinterpret_cast(s)); n->header.size = s->header.size - req_rnd; n->header.magic = Magic(kMagicAllocated, &n->header); n->header.arena = arena; diff --git a/absl/debugging/failure_signal_handler.cc b/absl/debugging/failure_signal_handler.cc index fd6a49273eb..992c89c390f 100644 --- a/absl/debugging/failure_signal_handler.cc +++ b/absl/debugging/failure_signal_handler.cc @@ -31,6 +31,9 @@ #ifdef ABSL_HAVE_MMAP #include +#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) +#define MAP_ANONYMOUS MAP_ANON +#endif #endif #ifdef __linux__ @@ -81,10 +84,10 @@ struct FailureSignalData { struct sigaction previous_action; // StructSigaction is used to silence -Wmissing-field-initializers. using StructSigaction = struct sigaction; - #define FSD_PREVIOUS_INIT FailureSignalData::StructSigaction() +#define FSD_PREVIOUS_INIT FailureSignalData::StructSigaction() #else void (*previous_handler)(int); - #define FSD_PREVIOUS_INIT SIG_DFL +#define FSD_PREVIOUS_INIT SIG_DFL #endif }; @@ -136,7 +139,7 @@ const char* FailureSignalToString(int signo) { #ifdef ABSL_HAVE_SIGALTSTACK static bool SetupAlternateStackOnce() { -#if defined(__wasm__) || defined (__asjms__) +#if defined(__wasm__) || defined(__asjms__) const size_t page_mask = getpagesize() - 1; #else const size_t page_mask = static_cast(sysconf(_SC_PAGESIZE)) - 1; @@ -157,9 +160,6 @@ static bool SetupAlternateStackOnce() { #ifdef ABSL_HAVE_MMAP #ifndef MAP_STACK #define MAP_STACK 0 -#endif -#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) -#define MAP_ANONYMOUS MAP_ANON #endif sigstk.ss_sp = mmap(nullptr, sigstk.ss_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); @@ -248,7 +248,7 @@ static void WriteSignalMessage(int signo, int cpu, if (signal_string != nullptr && signal_string[0] != '\0') { snprintf(buf, sizeof(buf), "*** %s received at time=%ld%s ***\n", signal_string, - static_cast(time(nullptr)), // NOLINT(runtime/int) + static_cast(time(nullptr)), // NOLINT(runtime/int) on_cpu); } else { snprintf(buf, sizeof(buf), "*** Signal %d received at time=%ld%s ***\n", @@ -311,7 +311,8 @@ static void PortableSleepForSeconds(int seconds) { struct timespec sleep_time; sleep_time.tv_sec = seconds; sleep_time.tv_nsec = 0; - while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) {} + while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) { + } #endif } @@ -321,9 +322,7 @@ static void PortableSleepForSeconds(int seconds) { // set amount of time. If AbslFailureSignalHandler() hangs for more than // the alarm timeout, ImmediateAbortSignalHandler() will abort the // program. -static void ImmediateAbortSignalHandler(int) { - RaiseToDefaultHandler(SIGABRT); -} +static void ImmediateAbortSignalHandler(int) { RaiseToDefaultHandler(SIGABRT); } #endif // absl::base_internal::GetTID() returns pid_t on most platforms, but diff --git a/absl/debugging/internal/examine_stack.cc b/absl/debugging/internal/examine_stack.cc index 57863228d8f..3dd6ba1a53e 100644 --- a/absl/debugging/internal/examine_stack.cc +++ b/absl/debugging/internal/examine_stack.cc @@ -24,6 +24,9 @@ #ifdef ABSL_HAVE_MMAP #include +#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) +#define MAP_ANONYMOUS MAP_ANON +#endif #endif #if defined(__linux__) || defined(__APPLE__) diff --git a/absl/debugging/internal/stack_consumption.cc b/absl/debugging/internal/stack_consumption.cc index 6d974992b32..3f40beac6fe 100644 --- a/absl/debugging/internal/stack_consumption.cc +++ b/absl/debugging/internal/stack_consumption.cc @@ -18,14 +18,17 @@ #ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION #include +#include #include #include -#include - #include "absl/base/attributes.h" #include "absl/base/internal/raw_logging.h" +#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) +#define MAP_ANONYMOUS MAP_ANON +#endif + namespace absl { ABSL_NAMESPACE_BEGIN namespace debugging_internal { diff --git a/absl/debugging/symbolize_test.cc b/absl/debugging/symbolize_test.cc index 922fe36f5e7..d0feab2ffa6 100644 --- a/absl/debugging/symbolize_test.cc +++ b/absl/debugging/symbolize_test.cc @@ -40,6 +40,10 @@ #include "absl/memory/memory.h" #include "absl/strings/string_view.h" +#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) +#define MAP_ANONYMOUS MAP_ANON +#endif + using testing::Contains; #ifdef _WIN32 @@ -86,21 +90,13 @@ int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.unlikely) unlikely_func() { return 0; } -int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.hot) hot_func() { - return 0; -} +int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.hot) hot_func() { return 0; } -int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.startup) startup_func() { - return 0; -} +int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.startup) startup_func() { return 0; } -int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.exit) exit_func() { - return 0; -} +int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.exit) exit_func() { return 0; } -int /*ABSL_ATTRIBUTE_SECTION_VARIABLE(.text)*/ regular_func() { - return 0; -} +int /*ABSL_ATTRIBUTE_SECTION_VARIABLE(.text)*/ regular_func() { return 0; } // Thread-local data may confuse the symbolizer, ensure that it does not. // Variable sizes and order are important. @@ -121,7 +117,7 @@ static volatile bool volatile_bool = false; // Force the binary to be large enough that a THP .text remap will succeed. static constexpr size_t kHpageSize = 1 << 21; const char kHpageTextPadding[kHpageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE( - .text) = ""; + .text) = ""; #else static void *GetPCFromFnPtr(void *ptr) { @@ -313,10 +309,8 @@ TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) { const size_t kPageSize = 64 << 10; // We place a read-only symbols into the .text section and verify that we can // symbolize them and other symbols after remapping them. -const char kPadding0[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) = - ""; -const char kPadding1[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) = - ""; +const char kPadding0[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) = ""; +const char kPadding1[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) = ""; static int FilterElfHeader(struct dl_phdr_info *info, size_t size, void *data) { for (int i = 0; i < info->dlpi_phnum; i++) { @@ -474,9 +468,9 @@ extern "C" { inline void *ABSL_ATTRIBUTE_ALWAYS_INLINE inline_func() { void *pc = nullptr; #if defined(__i386__) - __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [ PC ] "=r"(pc)); + __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)); + __asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [PC] "=r"(pc)); #endif return pc; } @@ -484,9 +478,9 @@ inline void *ABSL_ATTRIBUTE_ALWAYS_INLINE inline_func() { void *ABSL_ATTRIBUTE_NOINLINE non_inline_func() { void *pc = nullptr; #if defined(__i386__) - __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [ PC ] "=r"(pc)); + __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)); + __asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [PC] "=r"(pc)); #endif return pc; } @@ -601,7 +595,7 @@ TEST(Symbolize, SymbolizeWithDemangling) { } #endif // !defined(ABSL_CONSUME_DLL) -#else // Symbolizer unimplemented +#else // Symbolizer unimplemented TEST(Symbolize, Unimplemented) { char buf[64]; EXPECT_FALSE(absl::Symbolize((void *)(&nonstatic_func), buf, sizeof(buf))); From fc1dcc0f6a6b22f4ef4a30fc2020d4c81ab1b3c5 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 1 Aug 2023 14:40:45 -0700 Subject: [PATCH 0137/1238] Changes absl::crc32c_t insertion operator (<<) to return value as 0-padded hex instead of dec PiperOrigin-RevId: 552927211 Change-Id: I0375d60a9df4cdfc694fe8d3b3d790f80fc614a1 --- absl/crc/BUILD.bazel | 1 + absl/crc/CMakeLists.txt | 1 + absl/crc/crc32c.h | 3 ++- absl/crc/crc32c_test.cc | 19 +++++++++++++++++++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/absl/crc/BUILD.bazel b/absl/crc/BUILD.bazel index 1c58f46c6f3..29a9964f224 100644 --- a/absl/crc/BUILD.bazel +++ b/absl/crc/BUILD.bazel @@ -93,6 +93,7 @@ cc_library( "//absl/base:endian", "//absl/base:prefetch", "//absl/strings", + "//absl/strings:str_format", ], ) diff --git a/absl/crc/CMakeLists.txt b/absl/crc/CMakeLists.txt index 72ea2094a3b..f49b4b0b487 100644 --- a/absl/crc/CMakeLists.txt +++ b/absl/crc/CMakeLists.txt @@ -77,6 +77,7 @@ absl_cc_library( absl::dynamic_annotations absl::endian absl::prefetch + absl::str_format absl::strings ) diff --git a/absl/crc/crc32c.h b/absl/crc/crc32c.h index 79059dc1308..69799c8bc13 100644 --- a/absl/crc/crc32c.h +++ b/absl/crc/crc32c.h @@ -29,6 +29,7 @@ #include #include "absl/crc/internal/crc32c_inline.h" +#include "absl/strings/str_format.h" #include "absl/strings/string_view.h" namespace absl { @@ -175,7 +176,7 @@ crc32c_t RemoveCrc32cSuffix(crc32c_t full_string_crc, crc32c_t suffix_crc, // // Streams the CRC32C value `crc` to the stream `os`. inline std::ostream& operator<<(std::ostream& os, crc32c_t crc) { - return os << static_cast(crc); + return os << absl::StreamFormat("%08x", static_cast(crc)); } ABSL_NAMESPACE_END diff --git a/absl/crc/crc32c_test.cc b/absl/crc/crc32c_test.cc index 72d422a1eea..635424aa3e5 100644 --- a/absl/crc/crc32c_test.cc +++ b/absl/crc/crc32c_test.cc @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "gtest/gtest.h" @@ -191,4 +192,22 @@ TEST(CRC32C, RemoveSuffix) { EXPECT_EQ(absl::RemoveCrc32cSuffix(crc_ab, crc_b, world.size()), crc_a); } + +TEST(CRC32C, InsertionOperator) { + { + std::ostringstream buf; + buf << absl::crc32c_t{0xc99465aa}; + EXPECT_EQ(buf.str(), "c99465aa"); + } + { + std::ostringstream buf; + buf << absl::crc32c_t{0}; + EXPECT_EQ(buf.str(), "00000000"); + } + { + std::ostringstream buf; + buf << absl::crc32c_t{17}; + EXPECT_EQ(buf.str(), "00000011"); + } +} } // namespace From e945c8d98719d2cca66ef1f0b83696becfa6a880 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 1 Aug 2023 15:23:59 -0700 Subject: [PATCH 0138/1238] Implement AbslStringify for crc32c_t in order to support absl::StrFormat natively PiperOrigin-RevId: 552940359 Change-Id: I925764757404c0c9f2a13ed729190d51f4ac46cf --- absl/crc/BUILD.bazel | 1 + absl/crc/CMakeLists.txt | 1 + absl/crc/crc32c.h | 5 +++++ absl/crc/crc32c_test.cc | 14 ++++++++++++++ 4 files changed, 21 insertions(+) diff --git a/absl/crc/BUILD.bazel b/absl/crc/BUILD.bazel index 29a9964f224..cdbaa9b2c7c 100644 --- a/absl/crc/BUILD.bazel +++ b/absl/crc/BUILD.bazel @@ -106,6 +106,7 @@ cc_test( deps = [ ":crc32c", "//absl/strings", + "//absl/strings:str_format", "@com_google_googletest//:gtest_main", ], ) diff --git a/absl/crc/CMakeLists.txt b/absl/crc/CMakeLists.txt index f49b4b0b487..21247160881 100644 --- a/absl/crc/CMakeLists.txt +++ b/absl/crc/CMakeLists.txt @@ -91,6 +91,7 @@ absl_cc_test( DEPS absl::crc32c absl::strings + absl::str_format GTest::gtest_main ) diff --git a/absl/crc/crc32c.h b/absl/crc/crc32c.h index 69799c8bc13..362861e4a6d 100644 --- a/absl/crc/crc32c.h +++ b/absl/crc/crc32c.h @@ -62,6 +62,11 @@ class crc32c_t final { friend bool operator!=(crc32c_t lhs, crc32c_t rhs) { return !(lhs == rhs); } + template + friend void AbslStringify(Sink& sink, crc32c_t crc) { + absl::Format(&sink, "%08x", static_cast(crc)); + } + private: uint32_t crc_; }; diff --git a/absl/crc/crc32c_test.cc b/absl/crc/crc32c_test.cc index 635424aa3e5..df0afb3e329 100644 --- a/absl/crc/crc32c_test.cc +++ b/absl/crc/crc32c_test.cc @@ -24,6 +24,7 @@ #include "gtest/gtest.h" #include "absl/crc/internal/crc32c.h" #include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" #include "absl/strings/string_view.h" namespace { @@ -210,4 +211,17 @@ TEST(CRC32C, InsertionOperator) { EXPECT_EQ(buf.str(), "00000011"); } } + +TEST(CRC32C, AbslStringify) { + // StrFormat + EXPECT_EQ(absl::StrFormat("%v", absl::crc32c_t{0xc99465aa}), "c99465aa"); + EXPECT_EQ(absl::StrFormat("%v", absl::crc32c_t{0}), "00000000"); + EXPECT_EQ(absl::StrFormat("%v", absl::crc32c_t{17}), "00000011"); + + // StrCat + EXPECT_EQ(absl::StrCat(absl::crc32c_t{0xc99465aa}), "c99465aa"); + EXPECT_EQ(absl::StrCat(absl::crc32c_t{0}), "00000000"); + EXPECT_EQ(absl::StrCat(absl::crc32c_t{17}), "00000011"); +} + } // namespace From 5d06f796b7ed59234c603457d130d23addc400fd Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 2 Aug 2023 08:49:17 -0700 Subject: [PATCH 0139/1238] Rollback of "Speed up StrAppend by up to 4x." PiperOrigin-RevId: 553158292 Change-Id: I28350321550accd72da2f9f6f5992af311fe4b00 --- absl/strings/str_cat.cc | 178 +++++++++++++++++++++++++++++++++++++--- absl/strings/str_cat.h | 152 +++++++--------------------------- 2 files changed, 196 insertions(+), 134 deletions(-) diff --git a/absl/strings/str_cat.cc b/absl/strings/str_cat.cc index 5ec029959a0..2e49c31b68e 100644 --- a/absl/strings/str_cat.cc +++ b/absl/strings/str_cat.cc @@ -14,9 +14,17 @@ #include "absl/strings/str_cat.h" +#include + +#include +#include #include +#include #include +#include "absl/strings/ascii.h" +#include "absl/strings/internal/resize_uninitialized.h" +#include "absl/strings/numbers.h" #include "absl/strings/string_view.h" namespace absl { @@ -29,26 +37,170 @@ ABSL_NAMESPACE_BEGIN // of a mix of raw C strings, string_views, strings, and integer values. // ---------------------------------------------------------------------- +// Append is merely a version of memcpy that returns the address of the byte +// after the area just overwritten. +static char* Append(char* out, const AlphaNum& x) { + // memcpy is allowed to overwrite arbitrary memory, so doing this after the + // call would force an extra fetch of x.size(). + char* after = out + x.size(); + if (x.size() != 0) { + memcpy(out, x.data(), x.size()); + } + return after; +} + +std::string StrCat(const AlphaNum& a, const AlphaNum& b) { + std::string result; + absl::strings_internal::STLStringResizeUninitialized(&result, + a.size() + b.size()); + char* const begin = &result[0]; + char* out = begin; + out = Append(out, a); + out = Append(out, b); + assert(out == begin + result.size()); + return result; +} + +std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) { + std::string result; + strings_internal::STLStringResizeUninitialized( + &result, a.size() + b.size() + c.size()); + char* const begin = &result[0]; + char* out = begin; + out = Append(out, a); + out = Append(out, b); + out = Append(out, c); + assert(out == begin + result.size()); + return result; +} + +std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, + const AlphaNum& d) { + std::string result; + strings_internal::STLStringResizeUninitialized( + &result, a.size() + b.size() + c.size() + d.size()); + char* const begin = &result[0]; + char* out = begin; + out = Append(out, a); + out = Append(out, b); + out = Append(out, c); + out = Append(out, d); + assert(out == begin + result.size()); + return result; +} + namespace strings_internal { -bool HaveOverlap(const std::string& x, absl::string_view y) { - if (y.empty()) return false; - // TODO(b/290623057): Re-evaluate the check below: it detects when buffers - // overlap (which is good) but it also introduces undefined behaviour when - // buffers don't overlap (substracting pointers that do not belong to the same - // array is UB [expr.add]). In other words, if compiler assumes that a program - // never has UB, then it can replace `assert(HaveOverlap(x, y))` with - // `assert(false)`. - return (uintptr_t(y.data() - x.data()) <= uintptr_t(x.size())); +// Do not call directly - these are not part of the public API. +std::string CatPieces(std::initializer_list pieces) { + std::string result; + size_t total_size = 0; + for (absl::string_view piece : pieces) total_size += piece.size(); + strings_internal::STLStringResizeUninitialized(&result, total_size); + + char* const begin = &result[0]; + char* out = begin; + for (absl::string_view piece : pieces) { + const size_t this_size = piece.size(); + if (this_size != 0) { + memcpy(out, piece.data(), this_size); + out += this_size; + } + } + assert(out == begin + result.size()); + return result; } -#if defined(__GNUC__) && !defined(__clang__) -char* AppendAlphaNum(char* dst, const AlphaNum& a) { - return std::copy_n(a.data(), a.size(), dst); +// It's possible to call StrAppend with an absl::string_view that is itself a +// fragment of the string we're appending to. However the results of this are +// random. Therefore, check for this in debug mode. Use unsigned math so we +// only have to do one comparison. Note, there's an exception case: appending an +// empty string is always allowed. +#define ASSERT_NO_OVERLAP(dest, src) \ + assert(((src).size() == 0) || \ + (uintptr_t((src).data() - (dest).data()) > uintptr_t((dest).size()))) + +void AppendPieces(std::string* dest, + std::initializer_list pieces) { + size_t old_size = dest->size(); + size_t total_size = old_size; + for (absl::string_view piece : pieces) { + ASSERT_NO_OVERLAP(*dest, piece); + total_size += piece.size(); + } + strings_internal::STLStringResizeUninitializedAmortized(dest, total_size); + + char* const begin = &(*dest)[0]; + char* out = begin + old_size; + for (absl::string_view piece : pieces) { + const size_t this_size = piece.size(); + if (this_size != 0) { + memcpy(out, piece.data(), this_size); + out += this_size; + } + } + assert(out == begin + dest->size()); } -#endif } // namespace strings_internal +void StrAppend(std::string* dest, const AlphaNum& a) { + ASSERT_NO_OVERLAP(*dest, a); + std::string::size_type old_size = dest->size(); + strings_internal::STLStringResizeUninitializedAmortized(dest, + old_size + a.size()); + char* const begin = &(*dest)[0]; + char* out = begin + old_size; + out = Append(out, a); + assert(out == begin + dest->size()); +} + +void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b) { + ASSERT_NO_OVERLAP(*dest, a); + ASSERT_NO_OVERLAP(*dest, b); + std::string::size_type old_size = dest->size(); + strings_internal::STLStringResizeUninitializedAmortized( + dest, old_size + a.size() + b.size()); + char* const begin = &(*dest)[0]; + char* out = begin + old_size; + out = Append(out, a); + out = Append(out, b); + assert(out == begin + dest->size()); +} + +void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, + const AlphaNum& c) { + ASSERT_NO_OVERLAP(*dest, a); + ASSERT_NO_OVERLAP(*dest, b); + ASSERT_NO_OVERLAP(*dest, c); + std::string::size_type old_size = dest->size(); + strings_internal::STLStringResizeUninitializedAmortized( + dest, old_size + a.size() + b.size() + c.size()); + char* const begin = &(*dest)[0]; + char* out = begin + old_size; + out = Append(out, a); + out = Append(out, b); + out = Append(out, c); + assert(out == begin + dest->size()); +} + +void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, + const AlphaNum& c, const AlphaNum& d) { + ASSERT_NO_OVERLAP(*dest, a); + ASSERT_NO_OVERLAP(*dest, b); + ASSERT_NO_OVERLAP(*dest, c); + ASSERT_NO_OVERLAP(*dest, d); + std::string::size_type old_size = dest->size(); + strings_internal::STLStringResizeUninitializedAmortized( + dest, old_size + a.size() + b.size() + c.size() + d.size()); + char* const begin = &(*dest)[0]; + char* out = begin + old_size; + out = Append(out, a); + out = Append(out, b); + out = Append(out, c); + out = Append(out, d); + assert(out == begin + dest->size()); +} + ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h index f5f2c01623f..d5f71ff003f 100644 --- a/absl/strings/str_cat.h +++ b/absl/strings/str_cat.h @@ -91,9 +91,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -101,7 +99,6 @@ #include "absl/base/attributes.h" #include "absl/base/port.h" #include "absl/strings/internal/has_absl_stringify.h" -#include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/internal/stringify_sink.h" #include "absl/strings/numbers.h" #include "absl/strings/string_view.h" @@ -412,93 +409,6 @@ class AlphaNum { char digits_[numbers_internal::kFastToBufferSize]; }; -namespace strings_internal { - -// Inlining this function improves performance. However, on GCC this triggers -// [-Werror=stringop-overflow=], and in that case we split declaration and -// definition as a workaround. -#if defined(__GNUC__) && !defined(__clang__) -char* AppendAlphaNum(char* dst, const AlphaNum& a); -#else -inline char* AppendAlphaNum(char* dst, const AlphaNum& a) { - return std::copy_n(a.data(), a.size(), dst); -} -#endif - -// It's possible to call StrAppend with an absl::string_view that is itself a -// fragment of the string we're appending to. However the results of this are -// UB. Therefore, check for this in debug mode. Use unsigned math so we -// only have to do one comparison. Note, there's an exception case: appending an -// empty string is always allowed. -bool HaveOverlap(const std::string& x, absl::string_view y); - -// C++14 compatible alternative to left -// https://en.cppreference.com/w/cpp/language/fold expression. -// TODO(b/290784225): Remove `FoldLeft` once Abseil drops C++14 support. -template -auto FoldLeft(const F&, Acc&& acc) { - return std::forward(acc); -} -template -auto FoldLeft(const F& f, Acc&& acc, First&& first, Rest&&... rest) { - return FoldLeft(f, f(std::forward(acc), std::forward(first)), - std::forward(rest)...); -} - -template -inline void StrAppendTemplate(std::index_sequence, - std::string* dest, Tuple args) { - // Note on `Is` and `Tuple`: - // - // The goal is to pass N arguments to `StrAppend` and retain `N` as a - // compile-time constant. Thus, we cannot use dynamically sized collections - // such as `absl::Span` or `std::initialized_list`: `std::tuple` comes to - // the rescue. - // `Tuple` is a fixed-sized collection of N elements of `const AlphaNum&`. - // `Indices` is deduced from `std::make_index_sequence` and is used as a - // helper to writing Fold expressions on `Tuple`. - assert(FoldLeft(std::logical_and<>{}, - !HaveOverlap(*dest, std::get(args).Piece())...)); - size_t old_size = dest->size(); - size_t new_size = - FoldLeft(std::plus<>{}, old_size, std::get(args).size()...); - strings_internal::STLStringResizeUninitializedAmortized(dest, new_size); - FoldLeft(AppendAlphaNum, &(*dest)[old_size], std::get(args)...); -} - -template -inline std::string StrCatTemplate(std::index_sequence, Tuple args) { - // See implementation comments in `StrAppendTemplate`. - std::string dest; - size_t size = FoldLeft(std::plus{}, size_t{0}, - std::get(args).size()...); - strings_internal::STLStringResizeUninitializedAmortized(&dest, size); - FoldLeft(AppendAlphaNum, &dest[0], std::get(args)...); - return dest; -} - -// Template functions `StrAppendImpl` and `StrCatImpl` are not exported directly -// due to historical reasons: there are many existing dependencies that expect -// 0-4 argument overloads to be non-template functions. Hence implementations -// are wrapped to keep the compatibility (0-4 arguments only, 5+ arguments are -// templates). - -template -inline void StrAppendImpl(std::string* dest, const AV&... args) { - strings_internal::StrAppendTemplate( - std::make_index_sequence{}, dest, - std::forward_as_tuple(static_cast(args)...)); -} - -template -inline std::string StrCatImpl(const AV&... args) { - return strings_internal::StrCatTemplate( - std::make_index_sequence{}, - std::forward_as_tuple(static_cast(args)...)); -} - -} // namespace strings_internal - // ----------------------------------------------------------------------------- // StrCat() // ----------------------------------------------------------------------------- @@ -526,32 +436,36 @@ inline std::string StrCatImpl(const AV&... args) { // quadratic time operation with O(n) dynamic allocations. // // See `StrAppend()` below for more information. + +namespace strings_internal { + +// Do not call directly - this is not part of the public API. +std::string CatPieces(std::initializer_list pieces); +void AppendPieces(std::string* dest, + std::initializer_list pieces); + +} // namespace strings_internal + ABSL_MUST_USE_RESULT inline std::string StrCat() { return std::string(); } + ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a) { return std::string(a.data(), a.size()); } -ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a, - const AlphaNum& b) { - return strings_internal::StrCatImpl(a, b); -} -ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a, - const AlphaNum& b, - const AlphaNum& c) { - return strings_internal::StrCatImpl(a, b, c); -} -ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a, - const AlphaNum& b, - const AlphaNum& c, - const AlphaNum& d) { - return strings_internal::StrCatImpl(a, b, c, d); -} + +ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b); +ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b, + const AlphaNum& c); +ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b, + const AlphaNum& c, const AlphaNum& d); // Support 5 or more arguments template ABSL_MUST_USE_RESULT inline std::string StrCat( const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d, const AlphaNum& e, const AV&... args) { - return strings_internal::StrCatImpl(a, b, c, d, e, args...); + return strings_internal::CatPieces( + {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(), + static_cast(args).Piece()...}); } // ----------------------------------------------------------------------------- @@ -580,27 +494,23 @@ ABSL_MUST_USE_RESULT inline std::string StrCat( // std::string s = "foobar"; // absl::string_view p = s; // StrAppend(&s, p); + inline void StrAppend(std::string*) {} -inline void StrAppend(std::string* dest, const AlphaNum& a) { - strings_internal::StrAppendImpl(dest, a); -} -inline void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b) { - strings_internal::StrAppendImpl(dest, a, b); -} -inline void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c) { - strings_internal::StrAppendImpl(dest, a, b, c); -} -inline void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, - const AlphaNum& c, const AlphaNum& d) { - strings_internal::StrAppendImpl(dest, a, b, c, d); -} +void StrAppend(std::string* dest, const AlphaNum& a); +void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b); +void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, + const AlphaNum& c); +void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, + const AlphaNum& c, const AlphaNum& d); + // Support 5 or more arguments template inline void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d, const AlphaNum& e, const AV&... args) { - strings_internal::StrAppendImpl(dest, a, b, c, d, e, args...); + strings_internal::AppendPieces( + dest, {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(), + static_cast(args).Piece()...}); } // Helper function for the future StrCat default floating-point format, %.6g From fdf5be1108ada4b5525f48542d5fd76731cb880e Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Wed, 2 Aug 2023 11:08:54 -0700 Subject: [PATCH 0140/1238] Update Abseil dependencies PiperOrigin-RevId: 553199830 Change-Id: Ida9fc1c51a39b8c21ffd34f95de076b1b21369bd --- WORKSPACE | 42 +++++++++++++++++++-------------------- ci/cmake_common.sh | 2 +- ci/windows_msvc_cmake.bat | 2 +- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index 19e1385c7bc..56279d47f41 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -20,41 +20,41 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # GoogleTest/GoogleMock framework. Used by most unit-tests. http_archive( - name = "com_google_googletest", # 2023-02-28T13:15:29Z - sha256 = "82ad62a4e26c199de52a707778334e80f6b195dd298d48d520d8507d2bcb88c4", - strip_prefix = "googletest-2d4f208765af7fa376b878860a7677ecc0bc390a", - # Keep this URL in sync with ABSL_GOOGLETEST_COMMIT in ci/cmake_common.sh. - urls = ["https://github.com/google/googletest/archive/2d4f208765af7fa376b878860a7677ecc0bc390a.zip"], + name = "com_google_googletest", # 2023-08-02T16:45:10Z + sha256 = "c4f675500e09da97fd5a2b9c3fdadf48de858a036db565d52e6835c96eeea147", + strip_prefix = "googletest-843976e4f582ccb76cf87e0f128585324335779b", + # Keep this URL in sync with ABSL_GOOGLETEST_COMMIT in ci/cmake_common.sh. + urls = ["https://github.com/google/googletest/archive/843976e4f582ccb76cf87e0f128585324335779b.zip"], ) # RE2 (the regular expression library used by GoogleTest) http_archive( - name = "com_googlesource_code_re2", - sha256 = "1726508efc93a50854c92e3f7ac66eb28f0e57652e413f11d7c1e28f97d997ba", - strip_prefix = "re2-03da4fc0857c285e3a26782f6bc8931c4c950df4", - urls = ["https://github.com/google/re2/archive/03da4fc0857c285e3a26782f6bc8931c4c950df4.zip"], # 2023-06-01 + name = "com_googlesource_code_re2", # 2023-03-17T11:36:51Z + sha256 = "cb8b5312a65f2598954545a76e8bce913f35fbb3a21a5c88797a4448e9f9b9d9", + strip_prefix = "re2-578843a516fd1da7084ae46209a75f3613b6065e", + urls = ["https://github.com/google/re2/archive/578843a516fd1da7084ae46209a75f3613b6065e.zip"], ) # Google benchmark. http_archive( - name = "com_github_google_benchmark", # 2023-01-10T16:48:17Z - sha256 = "ede6830512f21490eeea1f238f083702eb178890820c14451c1c3d69fd375b19", - strip_prefix = "benchmark-a3235d7b69c84e8c9ff8722a22b8ac5e1bc716a6", - urls = ["https://github.com/google/benchmark/archive/a3235d7b69c84e8c9ff8722a22b8ac5e1bc716a6.zip"], + name = "com_github_google_benchmark", # 2023-08-01T07:47:09Z + sha256 = "db1e39ee71dc38aa7e57ed007f2c8b3bb59e13656435974781a9dc0617d75cc9", + strip_prefix = "benchmark-02a354f3f323ae8256948e1dc77ddcb1dfc297da", + urls = ["https://github.com/google/benchmark/archive/02a354f3f323ae8256948e1dc77ddcb1dfc297da.zip"], ) # Bazel Skylib. http_archive( - name = "bazel_skylib", # 2022-11-16T18:29:32Z - sha256 = "a22290c26d29d3ecca286466f7f295ac6cbe32c0a9da3a91176a90e0725e3649", - strip_prefix = "bazel-skylib-5bfcb1a684550626ce138fe0fe8f5f702b3764c3", - urls = ["https://github.com/bazelbuild/bazel-skylib/archive/5bfcb1a684550626ce138fe0fe8f5f702b3764c3.zip"], + name = "bazel_skylib", # 2023-05-31T19:24:07Z + sha256 = "08c0386f45821ce246bbbf77503c973246ed6ee5c3463e41efc197fa9bc3a7f4", + strip_prefix = "bazel-skylib-288731ef9f7f688932bd50e704a91a45ec185f9b", + urls = ["https://github.com/bazelbuild/bazel-skylib/archive/288731ef9f7f688932bd50e704a91a45ec185f9b.zip"], ) # Bazel platform rules. http_archive( - name = "platforms", # 2022-11-09T19:18:22Z - sha256 = "b4a3b45dc4202e2b3e34e3bc49d2b5b37295fc23ea58d88fb9e01f3642ad9b55", - strip_prefix = "platforms-3fbc687756043fb58a407c2ea8c944bc2fe1d922", - urls = ["https://github.com/bazelbuild/platforms/archive/3fbc687756043fb58a407c2ea8c944bc2fe1d922.zip"], + name = "platforms", # 2023-07-28T19:44:27Z + sha256 = "40eb313613ff00a5c03eed20aba58890046f4d38dec7344f00bb9a8867853526", + strip_prefix = "platforms-4ad40ef271da8176d4fc0194d2089b8a76e19d7b", + urls = ["https://github.com/bazelbuild/platforms/archive/4ad40ef271da8176d4fc0194d2089b8a76e19d7b.zip"], ) diff --git a/ci/cmake_common.sh b/ci/cmake_common.sh index f62bb8a14e4..4b02cb1fa20 100644 --- a/ci/cmake_common.sh +++ b/ci/cmake_common.sh @@ -14,7 +14,7 @@ # The commit of GoogleTest to be used in the CMake tests in this directory. # Keep this in sync with the commit in the WORKSPACE file. -readonly ABSL_GOOGLETEST_COMMIT="2d4f208765af7fa376b878860a7677ecc0bc390a" +readonly ABSL_GOOGLETEST_COMMIT="843976e4f582ccb76cf87e0f128585324335779b" # Avoid depending on GitHub by looking for a cached copy of the commit first. if [[ -r "${KOKORO_GFILE_DIR:-}/distdir/${ABSL_GOOGLETEST_COMMIT}.zip" ]]; then diff --git a/ci/windows_msvc_cmake.bat b/ci/windows_msvc_cmake.bat index b69e03e5d74..23454b5493b 100755 --- a/ci/windows_msvc_cmake.bat +++ b/ci/windows_msvc_cmake.bat @@ -14,7 +14,7 @@ SETLOCAL ENABLEDELAYEDEXPANSION -SET ABSL_GOOGLETEST_COMMIT=934542165899c786cb5d8a710529c37184730183 +SET ABSL_GOOGLETEST_COMMIT=843976e4f582ccb76cf87e0f128585324335779b IF EXIST %KOKORO_GFILE_DIR%\distdir\%ABSL_GOOGLETEST_COMMIT%.zip ( SET ABSL_GOOGLETEST_DOWNLOAD_URL=file://%KOKORO_GFILE_DIR%\distdir\%ABSL_GOOGLETEST_COMMIT%.zip From d2de53124ec55390ce1ec66fd1fbf28b5a7ec4ec Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 2 Aug 2023 11:40:36 -0700 Subject: [PATCH 0141/1238] Use a shared (reader) lock in absl_flags::WasPresentOnCommandLine PiperOrigin-RevId: 553209806 Change-Id: I6828c3a5df1981471bca7f2f6cb16dfd60e77a96 --- absl/flags/parse.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/absl/flags/parse.cc b/absl/flags/parse.cc index 4cdd9d0ad31..526b61d1d18 100644 --- a/absl/flags/parse.cc +++ b/absl/flags/parse.cc @@ -637,7 +637,7 @@ void ReportUnrecognizedFlags( // -------------------------------------------------------------------- bool WasPresentOnCommandLine(absl::string_view flag_name) { - absl::MutexLock l(&specified_flags_guard); + absl::ReaderMutexLock l(&specified_flags_guard); ABSL_INTERNAL_CHECK(specified_flags != nullptr, "ParseCommandLine is not invoked yet"); From 14a91eefa7a3f3bf0a949e82ce5854659588a5c0 Mon Sep 17 00:00:00 2001 From: Evan Brown Date: Thu, 3 Aug 2023 09:24:57 -0700 Subject: [PATCH 0142/1238] Update the comment for capacity_ to mention recent experiments to compress the field and store it together with size_. PiperOrigin-RevId: 553499768 Change-Id: Ia6eec6d580475a2b76a2415bfb35bcc08131ae34 --- absl/container/internal/raw_hash_set.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 5f89d8efee6..26cd2e54944 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -1027,9 +1027,8 @@ class CommonFields : public CommonFieldsGenerationInfo { } private: - // TODO(b/259599413): Investigate removing some of these fields: + // TODO(b/182800944): Investigate removing some of these fields: // - control/slots can be derived from each other - // - we can use 6 bits for capacity since it's always a power of two minus 1 // The control bytes (and, also, a pointer near to the base of the backing // array). @@ -1044,6 +1043,12 @@ class CommonFields : public CommonFieldsGenerationInfo { // `control`. May be null for empty tables. void* slots_ = nullptr; + // The number of slots in the backing array. This is always 2^N-1 for an + // integer N. NOTE: we tried experimenting with compressing the capacity and + // storing it together with size_: (a) using 6 bits to store the corresponding + // power (N in 2^N-1), and (b) storing 2^N as the most significant bit of + // size_ and storing size in the low bits. Both of these experiments were + // regressions, presumably because we need capacity to do find operations. size_t capacity_ = 0; // Bundle together size and HashtablezInfoHandle to ensure EBO for From 039d70f69b34b59d9696c655689316a94026fd0e Mon Sep 17 00:00:00 2001 From: Connal de Souza Date: Fri, 4 Aug 2023 09:37:41 -0700 Subject: [PATCH 0143/1238] Optimize Swissmap Match on Arm. Currently we require only a single bit to be set in each abstract bit for iterable bitmasks. However, in most cases, where we have a single match, or no matches in a group, iteration is not needed. We move the masking to the iteration function instead of having it as a requirement for iterable Bitmask construction. This is 4-8% faster for Find and Insert operations. This can hurt performance if we need to iterate many times (there are many matches in the same Group), however this is unlikely, even if we assume the table is completely full. If there are 0 or 1 matches in a group, or the first match is the correct item we are looking for, we save 1 instruction/cycle (most cases) If there are 2 matches in a group, and the first is a false positive, this is neutral (< 3%) If there are more than 2 matches in a group and the first two are false positives, this can be slower by 1 cycle/instruction per additional iteration (< 0.1%) No change to x86. PiperOrigin-RevId: 553831814 Change-Id: I08620899847eaf0086da989d829a1029ea24173a --- absl/container/internal/raw_hash_set.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 26cd2e54944..4c1e564a6b8 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -361,7 +361,7 @@ uint32_t TrailingZeros(T x) { // width of an abstract bit in the representation. // This mask provides operations for any number of real bits set in an abstract // bit. To add iteration on top of that, implementation must guarantee no more -// than one real bit is set in an abstract bit. +// than the most significant real bit is set in a set abstract bit. template class NonIterableBitMask { public: @@ -418,6 +418,10 @@ class BitMask : public NonIterableBitMask { using const_iterator = BitMask; BitMask& operator++() { + if (Shift == 3) { + constexpr uint64_t msbs = 0x8080808080808080ULL; + this->mask_ &= msbs; + } this->mask_ &= (this->mask_ - 1); return *this; } @@ -651,9 +655,8 @@ struct GroupAArch64Impl { BitMask Match(h2_t hash) const { uint8x8_t dup = vdup_n_u8(hash); auto mask = vceq_u8(ctrl, dup); - constexpr uint64_t msbs = 0x8080808080808080ULL; return BitMask( - vget_lane_u64(vreinterpret_u64_u8(mask), 0) & msbs); + vget_lane_u64(vreinterpret_u64_u8(mask), 0)); } NonIterableBitMask MaskEmpty() const { From 8f241e778c08cfb4213877b5022442a8d1921b58 Mon Sep 17 00:00:00 2001 From: Evan Brown Date: Fri, 4 Aug 2023 10:34:09 -0700 Subject: [PATCH 0144/1238] Store infoz on the heap instead of inline and store it only when we are sampling the current allocation. PiperOrigin-RevId: 553847957 Change-Id: Idd131d0362bf36bd22d9bd20df54bd9ae50f0e28 --- absl/container/internal/hashtablez_sampler.h | 14 +- .../internal/hashtablez_sampler_test.cc | 8 +- absl/container/internal/raw_hash_set.cc | 9 +- absl/container/internal/raw_hash_set.h | 132 ++++++++++++------ absl/container/internal/raw_hash_set_test.cc | 11 +- 5 files changed, 98 insertions(+), 76 deletions(-) diff --git a/absl/container/internal/hashtablez_sampler.h b/absl/container/internal/hashtablez_sampler.h index d8fd8f34f97..e41ee2d747a 100644 --- a/absl/container/internal/hashtablez_sampler.h +++ b/absl/container/internal/hashtablez_sampler.h @@ -137,18 +137,7 @@ class HashtablezInfoHandle { UnsampleSlow(info_); } - HashtablezInfoHandle(const HashtablezInfoHandle&) = delete; - HashtablezInfoHandle& operator=(const HashtablezInfoHandle&) = delete; - - HashtablezInfoHandle(HashtablezInfoHandle&& o) noexcept - : info_(absl::exchange(o.info_, nullptr)) {} - HashtablezInfoHandle& operator=(HashtablezInfoHandle&& o) noexcept { - if (ABSL_PREDICT_FALSE(info_ != nullptr)) { - UnsampleSlow(info_); - } - info_ = absl::exchange(o.info_, nullptr); - return *this; - } + inline bool IsSampled() const { return ABSL_PREDICT_FALSE(info_ != nullptr); } inline void RecordStorageChanged(size_t size, size_t capacity) { if (ABSL_PREDICT_TRUE(info_ == nullptr)) return; @@ -198,6 +187,7 @@ class HashtablezInfoHandle { explicit HashtablezInfoHandle(std::nullptr_t) {} inline void Unregister() {} + inline bool IsSampled() const { return false; } inline void RecordStorageChanged(size_t /*size*/, size_t /*capacity*/) {} inline void RecordRehash(size_t /*total_probe_length*/) {} inline void RecordReservation(size_t /*target_capacity*/) {} diff --git a/absl/container/internal/hashtablez_sampler_test.cc b/absl/container/internal/hashtablez_sampler_test.cc index 665d518fc70..8ebb08da4a3 100644 --- a/absl/container/internal/hashtablez_sampler_test.cc +++ b/absl/container/internal/hashtablez_sampler_test.cc @@ -42,16 +42,11 @@ namespace container_internal { #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) class HashtablezInfoHandlePeer { public: - static bool IsSampled(const HashtablezInfoHandle& h) { - return h.info_ != nullptr; - } - static HashtablezInfo* GetInfo(HashtablezInfoHandle* h) { return h->info_; } }; #else class HashtablezInfoHandlePeer { public: - static bool IsSampled(const HashtablezInfoHandle&) { return false; } static HashtablezInfo* GetInfo(HashtablezInfoHandle*) { return nullptr; } }; #endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) @@ -267,7 +262,7 @@ TEST(HashtablezSamplerTest, Sample) { for (int i = 0; i < 1000000; ++i) { HashtablezInfoHandle h = Sample(test_element_size); ++total; - if (HashtablezInfoHandlePeer::IsSampled(h)) { + if (h.IsSampled()) { ++num_sampled; } sample_rate = static_cast(num_sampled) / total; @@ -294,6 +289,7 @@ TEST(HashtablezSamplerTest, Handle) { }); EXPECT_TRUE(found); + h.Unregister(); h = HashtablezInfoHandle(); found = false; sampler.Iterate([&](const HashtablezInfo& h) { diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc index 2ff95b61824..df64e7e8376 100644 --- a/absl/container/internal/raw_hash_set.cc +++ b/absl/container/internal/raw_hash_set.cc @@ -220,7 +220,7 @@ void DropDeletesWithoutResize(CommonFields& common, void EraseMetaOnly(CommonFields& c, ctrl_t* it, size_t slot_size) { assert(IsFull(*it) && "erasing a dangling iterator"); - c.set_size(c.size() - 1); + c.decrement_size(); const auto index = static_cast(it - c.control()); const size_t index_before = (index - Group::kWidth) & c.capacity(); const auto empty_after = Group(it).MaskEmpty(); @@ -247,14 +247,15 @@ void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy, ResetCtrl(c, policy.slot_size); c.infoz().RecordStorageChanged(0, c.capacity()); } else { + // We need to record infoz before calling dealloc, which will unregister + // infoz. + c.infoz().RecordClearedReservation(); + c.infoz().RecordStorageChanged(0, 0); (*policy.dealloc)(c, policy); c.set_control(EmptyGroup()); c.set_generation_ptr(EmptyGeneration()); c.set_slots(nullptr); c.set_capacity(0); - c.infoz().RecordClearedReservation(); - assert(c.size() == 0); - c.infoz().RecordStorageChanged(0, 0); } } diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 4c1e564a6b8..39552b0446e 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -62,6 +62,9 @@ // pseudo-struct: // // struct BackingArray { +// // Sampling handler. This field isn't present when the sampling is +// // disabled or this allocation hasn't been selected for sampling. +// HashtablezInfoHandle infoz_; // // The number of elements we can insert before growing the capacity. // size_t growth_left; // // Control bytes for the "real" slots. @@ -175,6 +178,7 @@ #define ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_ #include +#include #include #include #include @@ -912,9 +916,11 @@ using HashSetIteratorGenerationInfo = HashSetIteratorGenerationInfoDisabled; // A valid capacity is a non-zero integer `2^m - 1`. inline bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; } -// Computes the offset from the start of the backing allocation of the control -// bytes. growth_left is stored at the beginning of the backing array. -inline size_t ControlOffset() { return sizeof(size_t); } +// Computes the offset from the start of the backing allocation of control. +// infoz and growth_left are stored at the beginning of the backing array. +inline size_t ControlOffset(bool has_infoz) { + return (has_infoz ? sizeof(HashtablezInfoHandle) : 0) + sizeof(size_t); +} // Returns the number of "cloned control bytes". // @@ -925,24 +931,26 @@ constexpr size_t NumClonedBytes() { return Group::kWidth - 1; } // Given the capacity of a table, computes the offset (from the start of the // backing allocation) of the generation counter (if it exists). -inline size_t GenerationOffset(size_t capacity) { +inline size_t GenerationOffset(size_t capacity, bool has_infoz) { assert(IsValidCapacity(capacity)); const size_t num_control_bytes = capacity + 1 + NumClonedBytes(); - return ControlOffset() + num_control_bytes; + return ControlOffset(has_infoz) + num_control_bytes; } // Given the capacity of a table, computes the offset (from the start of the // backing allocation) at which the slots begin. -inline size_t SlotOffset(size_t capacity, size_t slot_align) { +inline size_t SlotOffset(size_t capacity, size_t slot_align, bool has_infoz) { assert(IsValidCapacity(capacity)); - return (GenerationOffset(capacity) + NumGenerationBytes() + slot_align - 1) & + return (GenerationOffset(capacity, has_infoz) + NumGenerationBytes() + + slot_align - 1) & (~slot_align + 1); } // Given the capacity of a table, computes the total size of the backing // array. -inline size_t AllocSize(size_t capacity, size_t slot_size, size_t slot_align) { - return SlotOffset(capacity, slot_align) + capacity * slot_size; +inline size_t AllocSize(size_t capacity, size_t slot_size, size_t slot_align, + bool has_infoz) { + return SlotOffset(capacity, slot_align, has_infoz) + capacity * slot_size; } // CommonFields hold the fields in raw_hash_set that do not depend @@ -965,20 +973,20 @@ class CommonFields : public CommonFieldsGenerationInfo { control_(that.control()), slots_(that.slot_array()), capacity_(that.capacity()), - compressed_tuple_(that.size(), std::move(that.infoz())) { + size_(that.size_) { that.set_control(EmptyGroup()); that.set_slots(nullptr); that.set_capacity(0); - that.set_size(0); + that.size_ = 0; } CommonFields& operator=(CommonFields&&) = default; ctrl_t* control() const { return control_; } void set_control(ctrl_t* c) { control_ = c; } void* backing_array_start() const { - // growth_left is stored before control bytes. + // growth_left (and maybe infoz) is stored before control bytes. assert(reinterpret_cast(control()) % alignof(size_t) == 0); - return control() - sizeof(size_t); + return control() - ControlOffset(has_infoz()); } // Note: we can't use slots() because Qt defines "slots" as a macro. @@ -986,8 +994,18 @@ class CommonFields : public CommonFieldsGenerationInfo { void set_slots(void* s) { slots_ = s; } // The number of filled slots. - size_t size() const { return compressed_tuple_.template get<0>(); } - void set_size(size_t s) { compressed_tuple_.template get<0>() = s; } + size_t size() const { return size_ >> HasInfozShift(); } + void set_size(size_t s) { + size_ = (s << HasInfozShift()) | (size_ & HasInfozMask()); + } + void increment_size() { + assert(size() < capacity()); + size_ += size_t{1} << HasInfozShift(); + } + void decrement_size() { + assert(size() > 0); + size_ -= size_t{1} << HasInfozShift(); + } // The total number of available slots. size_t capacity() const { return capacity_; } @@ -999,15 +1017,31 @@ class CommonFields : public CommonFieldsGenerationInfo { // The number of slots we can still fill without needing to rehash. // This is stored in the heap allocation before the control bytes. size_t growth_left() const { - return *reinterpret_cast(backing_array_start()); + const size_t* gl_ptr = reinterpret_cast(control()) - 1; + assert(reinterpret_cast(gl_ptr) % alignof(size_t) == 0); + return *gl_ptr; } void set_growth_left(size_t gl) { - *reinterpret_cast(backing_array_start()) = gl; + size_t* gl_ptr = reinterpret_cast(control()) - 1; + assert(reinterpret_cast(gl_ptr) % alignof(size_t) == 0); + *gl_ptr = gl; } - HashtablezInfoHandle& infoz() { return compressed_tuple_.template get<1>(); } - const HashtablezInfoHandle& infoz() const { - return compressed_tuple_.template get<1>(); + bool has_infoz() const { + return ABSL_PREDICT_FALSE((size_ & HasInfozMask()) != 0); + } + void set_has_infoz(bool has_infoz) { + size_ = (size() << HasInfozShift()) | static_cast(has_infoz); + } + + HashtablezInfoHandle infoz() { + return has_infoz() + ? *reinterpret_cast(backing_array_start()) + : HashtablezInfoHandle(); + } + void set_infoz(HashtablezInfoHandle infoz) { + assert(has_infoz()); + *reinterpret_cast(backing_array_start()) = infoz; } bool should_rehash_for_bug_detection_on_insert() const { @@ -1020,7 +1054,7 @@ class CommonFields : public CommonFieldsGenerationInfo { // The size of the backing array allocation. size_t alloc_size(size_t slot_size, size_t slot_align) const { - return AllocSize(capacity(), slot_size, slot_align); + return AllocSize(capacity(), slot_size, slot_align, has_infoz()); } // Returns the number of control bytes set to kDeleted. For testing only. @@ -1030,6 +1064,12 @@ class CommonFields : public CommonFieldsGenerationInfo { } private: + // We store the has_infoz bit in the lowest bit of size_. + static constexpr size_t HasInfozShift() { return 1; } + static constexpr size_t HasInfozMask() { + return (size_t{1} << HasInfozShift()) - 1; + } + // TODO(b/182800944): Investigate removing some of these fields: // - control/slots can be derived from each other @@ -1054,10 +1094,8 @@ class CommonFields : public CommonFieldsGenerationInfo { // regressions, presumably because we need capacity to do find operations. size_t capacity_ = 0; - // Bundle together size and HashtablezInfoHandle to ensure EBO for - // HashtablezInfoHandle when sampling is turned off. - absl::container_internal::CompressedTuple - compressed_tuple_{0u, HashtablezInfoHandle{}}; + // The size and also has one bit that stores whether we have infoz. + size_t size_ = 0; }; template @@ -1407,23 +1445,26 @@ ABSL_ATTRIBUTE_NOINLINE void InitializeSlots(CommonFields& c, Alloc alloc) { c.slot_array() == nullptr) ? SizeOfSlot : 0; + HashtablezInfoHandle infoz = + sample_size > 0 ? Sample(sample_size) : c.infoz(); + const bool has_infoz = infoz.IsSampled(); const size_t cap = c.capacity(); - const size_t alloc_size = AllocSize(cap, SizeOfSlot, AlignOfSlot); - // growth_left (which is a size_t) is stored with the backing array. + const size_t alloc_size = AllocSize(cap, SizeOfSlot, AlignOfSlot, has_infoz); char* mem = static_cast( Allocate(&alloc, alloc_size)); const GenerationType old_generation = c.generation(); - c.set_generation_ptr( - reinterpret_cast(mem + GenerationOffset(cap))); + c.set_generation_ptr(reinterpret_cast( + mem + GenerationOffset(cap, has_infoz))); c.set_generation(NextGeneration(old_generation)); - c.set_control(reinterpret_cast(mem + ControlOffset())); - c.set_slots(mem + SlotOffset(cap, AlignOfSlot)); + c.set_control(reinterpret_cast(mem + ControlOffset(has_infoz))); + c.set_slots(mem + SlotOffset(cap, AlignOfSlot, has_infoz)); ResetCtrl(c, SizeOfSlot); - if (sample_size) { - c.infoz() = Sample(sample_size); + c.set_has_infoz(has_infoz); + if (has_infoz) { + infoz.RecordStorageChanged(c.size(), cap); + c.set_infoz(infoz); } - c.infoz().RecordStorageChanged(c.size(), cap); } // PolicyFunctions bundles together some information for a particular @@ -1464,6 +1505,7 @@ ABSL_ATTRIBUTE_NOINLINE void DeallocateStandard(CommonFields& common, policy.slot_size * common.capacity()); std::allocator alloc; + common.infoz().Unregister(); Deallocate( &alloc, common.backing_array_start(), common.alloc_size(policy.slot_size, AlignOfSlot)); @@ -1894,11 +1936,10 @@ class raw_hash_set { // Unpoison before returning the memory to the allocator. SanitizerUnpoisonMemoryRegion(slot_array(), sizeof(slot_type) * cap); + infoz().Unregister(); Deallocate( &alloc_ref(), common().backing_array_start(), - AllocSize(cap, sizeof(slot_type), alignof(slot_type))); - - infoz().Unregister(); + common().alloc_size(sizeof(slot_type), alignof(slot_type))); } iterator begin() ABSL_ATTRIBUTE_LIFETIME_BOUND { @@ -2518,6 +2559,7 @@ class raw_hash_set { assert(IsValidCapacity(new_capacity)); auto* old_ctrl = control(); auto* old_slots = slot_array(); + const bool had_infoz = common().has_infoz(); const size_t old_capacity = common().capacity(); common().set_capacity(new_capacity); initialize_slots(); @@ -2539,8 +2581,9 @@ class raw_hash_set { SanitizerUnpoisonMemoryRegion(old_slots, sizeof(slot_type) * old_capacity); Deallocate( - &alloc_ref(), old_ctrl - ControlOffset(), - AllocSize(old_capacity, sizeof(slot_type), alignof(slot_type))); + &alloc_ref(), old_ctrl - ControlOffset(had_infoz), + AllocSize(old_capacity, sizeof(slot_type), alignof(slot_type), + had_infoz)); } infoz().RecordRehash(total_probe_length); } @@ -2686,7 +2729,7 @@ class raw_hash_set { rehash_and_grow_if_necessary(); target = find_first_non_full(common(), hash); } - common().set_size(common().size() + 1); + common().increment_size(); set_growth_left(growth_left() - IsEmpty(control()[target.offset])); SetCtrl(common(), target.offset, H2(hash), sizeof(slot_type)); common().maybe_increment_generation_on_insert(); @@ -2751,7 +2794,7 @@ class raw_hash_set { slot_type* slot_array() const { return static_cast(common().slot_array()); } - HashtablezInfoHandle& infoz() { return common().infoz(); } + HashtablezInfoHandle infoz() { return common().infoz(); } hasher& hash_ref() { return settings_.template get<1>(); } const hasher& hash_ref() const { return settings_.template get<1>(); } @@ -2782,6 +2825,7 @@ class raw_hash_set { SanitizerUnpoisonMemoryRegion(common.slot_array(), sizeof(slot_type) * common.capacity()); + common.infoz().Unregister(); Deallocate( &set->alloc_ref(), common.backing_array_start(), common.alloc_size(sizeof(slot_type), alignof(slot_type))); @@ -2855,7 +2899,7 @@ struct HashtableDebugAccess> { static size_t AllocatedByteSize(const Set& c) { size_t capacity = c.capacity(); if (capacity == 0) return 0; - size_t m = AllocSize(capacity, sizeof(Slot), alignof(Slot)); + size_t m = c.common().alloc_size(sizeof(Slot), alignof(Slot)); size_t per_slot = Traits::space_used(static_cast(nullptr)); if (per_slot != ~size_t{}) { @@ -2874,8 +2918,8 @@ struct HashtableDebugAccess> { static size_t LowerBoundAllocatedByteSize(size_t size) { size_t capacity = GrowthToLowerboundCapacity(size); if (capacity == 0) return 0; - size_t m = - AllocSize(NormalizeCapacity(capacity), sizeof(Slot), alignof(Slot)); + size_t m = AllocSize(NormalizeCapacity(capacity), sizeof(Slot), + alignof(Slot), /*has_infoz=*/false); size_t per_slot = Traits::space_used(static_cast(nullptr)); if (per_slot != ~size_t{}) { m += per_slot * size; diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc index 242a97cbe3f..55c6f62e2e6 100644 --- a/absl/container/internal/raw_hash_set_test.cc +++ b/absl/container/internal/raw_hash_set_test.cc @@ -524,13 +524,6 @@ TEST(Table, EmptyFunctorOptimization) { static_assert(std::is_empty>::value, ""); struct MockTable { - void* infoz; - void* ctrl; - void* slots; - size_t size; - size_t capacity; - }; - struct MockTableInfozDisabled { void* ctrl; void* slots; size_t size; @@ -555,9 +548,7 @@ TEST(Table, EmptyFunctorOptimization) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code" #endif - constexpr size_t mock_size = std::is_empty() - ? sizeof(MockTableInfozDisabled) - : sizeof(MockTable); + constexpr size_t mock_size = sizeof(MockTable); constexpr size_t generation_size = SwisstableGenerationsEnabled() ? sizeof(GenerationData) : 0; #if defined(__clang__) From 659b77b713fe5f1f75e6e1bb121c0eed1c8f964a Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 4 Aug 2023 12:16:54 -0700 Subject: [PATCH 0145/1238] Import of CCTZ from GitHub. PiperOrigin-RevId: 553878129 Change-Id: I054a5bd4c9011155c9fe03df0f07803ad7d2ade3 --- absl/time/internal/cctz/src/time_zone_lookup.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/absl/time/internal/cctz/src/time_zone_lookup.cc b/absl/time/internal/cctz/src/time_zone_lookup.cc index 9a30ba5e0c8..d22691bd0dd 100644 --- a/absl/time/internal/cctz/src/time_zone_lookup.cc +++ b/absl/time/internal/cctz/src/time_zone_lookup.cc @@ -39,7 +39,12 @@ #include // Include only when the SDK is for Windows 10 (and later), and the binary is // targeted for Windows XP and later. -#if defined(_WIN32_WINNT_WIN10) && (_WIN32_WINNT >= _WIN32_WINNT_WINXP) +// Note: The Windows SDK added windows.globalization.h file for Windows 10, but +// MinGW did not add it until NTDDI_WIN10_NI (SDK version 10.0.22621.0). +#if ((defined(_WIN32_WINNT_WIN10) && !defined(__MINGW32__)) || \ + (defined(NTDDI_WIN10_NI) && NTDDI_VERSION >= NTDDI_WIN10_NI)) && \ + (_WIN32_WINNT >= _WIN32_WINNT_WINXP) +#define USE_WIN32_LOCAL_TIME_ZONE #include #include #include @@ -87,7 +92,7 @@ int __system_property_get(const char* name, char* value) { } #endif -#if defined(_WIN32_WINNT_WIN10) && (_WIN32_WINNT >= _WIN32_WINNT_WINXP) +#if defined(USE_WIN32_LOCAL_TIME_ZONE) // Calls the WinRT Calendar.GetTimeZone method to obtain the IANA ID of the // local time zone. Returns an empty vector in case of an error. std::string win32_local_time_zone(const HMODULE combase) { @@ -278,7 +283,7 @@ time_zone local_time_zone() { zone = primary_tz.c_str(); } #endif -#if defined(_WIN32_WINNT_WIN10) && (_WIN32_WINNT >= _WIN32_WINNT_WINXP) +#if defined(USE_WIN32_LOCAL_TIME_ZONE) // Use the WinRT Calendar class to get the local time zone. This feature is // available on Windows 10 and later. The library is dynamically linked to // maintain binary compatibility with Windows XP - Windows 7. On Windows 8, From 70172ada858b8739ce07e8c2f1ecd8c11c8768c7 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Fri, 4 Aug 2023 13:54:47 -0700 Subject: [PATCH 0146/1238] Release the `DFATAL` pseudo-LogSeverity level `DFATAL` is defined as `FATAL` in debug mode, and as `ERROR` when `NDEBUG` is defined. Closes #1279 PiperOrigin-RevId: 553904244 Change-Id: Iaa207ee65b2a39b4b7f5da241208c3d39cd5da0e --- absl/base/CMakeLists.txt | 1 + absl/base/log_severity.cc | 1 + absl/base/log_severity.h | 12 ++++++++ absl/log/CMakeLists.txt | 1 + absl/log/globals_test.cc | 29 +++++++++++++++++++ absl/log/internal/conditions.h | 11 ++++++++ absl/log/log.h | 2 ++ absl/log/log_streamer.h | 10 +++++++ absl/log/log_streamer_test.cc | 51 ++++++++++++++++++++++++++++++++++ absl/log/stripping_test.cc | 43 ++++++++++++++++++++++++++++ 10 files changed, 161 insertions(+) diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt index 76c4ff1d799..c3271a10e9c 100644 --- a/absl/base/CMakeLists.txt +++ b/absl/base/CMakeLists.txt @@ -49,6 +49,7 @@ absl_cc_library( SRCS "log_severity.cc" DEPS + absl::config absl::core_headers COPTS ${ABSL_DEFAULT_COPTS} diff --git a/absl/base/log_severity.cc b/absl/base/log_severity.cc index 60a8fc1f89a..8e7bbbc9e0e 100644 --- a/absl/base/log_severity.cc +++ b/absl/base/log_severity.cc @@ -17,6 +17,7 @@ #include #include "absl/base/attributes.h" +#include "absl/base/config.h" namespace absl { ABSL_NAMESPACE_BEGIN diff --git a/absl/base/log_severity.h b/absl/base/log_severity.h index 8bdca38b5fa..c8bcd2fd5f9 100644 --- a/absl/base/log_severity.h +++ b/absl/base/log_severity.h @@ -64,6 +64,8 @@ ABSL_NAMESPACE_BEGIN // --my_log_level=info // --my_log_level=0 // +// `DFATAL` and `kLogDebugFatal` are similarly accepted. +// // Unparsing a flag produces the same result as `absl::LogSeverityName()` for // the standard levels and a base-ten integer otherwise. enum class LogSeverity : int { @@ -82,6 +84,16 @@ constexpr std::array LogSeverities() { absl::LogSeverity::kError, absl::LogSeverity::kFatal}}; } +// `absl::kLogDebugFatal` equals `absl::LogSeverity::kFatal` in debug builds +// (i.e. when `NDEBUG` is not defined) and `absl::LogSeverity::kError` +// otherwise. Avoid ODR-using this variable as it has internal linkage and thus +// distinct storage in different TUs. +#ifdef NDEBUG +static constexpr absl::LogSeverity kLogDebugFatal = absl::LogSeverity::kError; +#else +static constexpr absl::LogSeverity kLogDebugFatal = absl::LogSeverity::kFatal; +#endif + // LogSeverityName() // // Returns the all-caps string representation (e.g. "INFO") of the specified diff --git a/absl/log/CMakeLists.txt b/absl/log/CMakeLists.txt index 9320ce59fb9..2fc34d01c9c 100644 --- a/absl/log/CMakeLists.txt +++ b/absl/log/CMakeLists.txt @@ -845,6 +845,7 @@ absl_cc_test( absl::log_internal_test_helpers absl::log_severity absl::scoped_mock_log + GTest::gmock GTest::gtest_main ) diff --git a/absl/log/globals_test.cc b/absl/log/globals_test.cc index f7af47cd853..3d936cd74b8 100644 --- a/absl/log/globals_test.cc +++ b/absl/log/globals_test.cc @@ -101,4 +101,33 @@ TEST(TestGlobals, AndroidLogTag) { EXPECT_DEATH_IF_SUPPORTED(absl::SetAndroidNativeTag("test_tag_fail"), ".*"); } +TEST(TestExitOnDFatal, OffTest) { + // Turn off... + absl::log_internal::SetExitOnDFatal(false); + EXPECT_FALSE(absl::log_internal::ExitOnDFatal()); + + // We don't die. + { + absl::ScopedMockLog log(absl::MockLogDefault::kDisallowUnexpected); + + // LOG(DFATAL) has severity FATAL if debugging, but is + // downgraded to ERROR if not debugging. + EXPECT_CALL(log, Log(absl::kLogDebugFatal, _, "This should not be fatal")); + + log.StartCapturingLogs(); + LOG(DFATAL) << "This should not be fatal"; + } +} + +#if GTEST_HAS_DEATH_TEST +TEST(TestDeathWhileExitOnDFatal, OnTest) { + absl::log_internal::SetExitOnDFatal(true); + EXPECT_TRUE(absl::log_internal::ExitOnDFatal()); + + // Death comes on little cats' feet. + EXPECT_DEBUG_DEATH({ LOG(DFATAL) << "This should be fatal in debug mode"; }, + "This should be fatal in debug mode"); +} +#endif + } // namespace diff --git a/absl/log/internal/conditions.h b/absl/log/internal/conditions.h index f576d6500b3..41f67215a9c 100644 --- a/absl/log/internal/conditions.h +++ b/absl/log/internal/conditions.h @@ -137,6 +137,15 @@ ? true \ : (::absl::log_internal::ExitQuietly(), false)) \ : false)) +#define ABSL_LOG_INTERNAL_CONDITION_DFATAL(type, condition) \ + ABSL_LOG_INTERNAL_##type##_CONDITION( \ + (ABSL_ASSUME(absl::kLogDebugFatal == absl::LogSeverity::kError || \ + absl::kLogDebugFatal == absl::LogSeverity::kFatal), \ + (condition) && \ + (::absl::kLogDebugFatal >= \ + static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) || \ + (::absl::kLogDebugFatal == ::absl::LogSeverity::kFatal && \ + (::absl::log_internal::AbortQuietly(), false))))) #define ABSL_LOG_INTERNAL_CONDITION_LEVEL(severity) \ for (int log_internal_severity_loop = 1; log_internal_severity_loop; \ @@ -163,6 +172,8 @@ ABSL_LOG_INTERNAL_##type##_CONDITION(condition) #define ABSL_LOG_INTERNAL_CONDITION_QFATAL(type, condition) \ ABSL_LOG_INTERNAL_##type##_CONDITION(condition) +#define ABSL_LOG_INTERNAL_CONDITION_DFATAL(type, condition) \ + ABSL_LOG_INTERNAL_##type##_CONDITION(condition) #define ABSL_LOG_INTERNAL_CONDITION_LEVEL(severity) \ for (int log_internal_severity_loop = 1; log_internal_severity_loop; \ log_internal_severity_loop = 0) \ diff --git a/absl/log/log.h b/absl/log/log.h index 602b5acf07d..99e78ea8f86 100644 --- a/absl/log/log.h +++ b/absl/log/log.h @@ -32,6 +32,8 @@ // * The `QFATAL` pseudo-severity level is equivalent to `FATAL` but triggers // quieter termination messages, e.g. without a full stack trace, and skips // running registered error handlers. +// * The `DFATAL` pseudo-severity level is defined as `FATAL` in debug mode and +// as `ERROR` otherwise. // Some preprocessor shenanigans are used to ensure that e.g. `LOG(INFO)` has // the same meaning even if a local symbol or preprocessor macro named `INFO` is // defined. To specify a severity level using an expression instead of a diff --git a/absl/log/log_streamer.h b/absl/log/log_streamer.h index 2d41a07f9b9..4ed2435d61d 100644 --- a/absl/log/log_streamer.h +++ b/absl/log/log_streamer.h @@ -165,6 +165,16 @@ inline LogStreamer LogFatalStreamer(absl::string_view file, int line) { return absl::LogStreamer(absl::LogSeverity::kFatal, file, line); } +// LogDebugFatalStreamer() +// +// Returns a LogStreamer that writes at level LogSeverity::kLogDebugFatal. +// +// In debug mode, the program will be terminated when this `LogStreamer` is +// destroyed, regardless of whether any data were streamed in. +inline LogStreamer LogDebugFatalStreamer(absl::string_view file, int line) { + return absl::LogStreamer(absl::kLogDebugFatal, file, line); +} + ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/log/log_streamer_test.cc b/absl/log/log_streamer_test.cc index 328d70d0850..40c7d488893 100644 --- a/absl/log/log_streamer_test.cc +++ b/absl/log/log_streamer_test.cc @@ -151,6 +151,57 @@ TEST(LogStreamerDeathTest, LogFatalStreamer) { } #endif +#ifdef NDEBUG +TEST(LogStreamerTest, LogDebugFatalStreamer) { + absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); + + EXPECT_CALL( + test_sink, + Send(AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)), + Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kError)), + TimestampInMatchWindow(), + ThreadID(Eq(absl::base_internal::GetTID())), + TextMessage(Eq("WriteToStream: foo")), + ENCODED_MESSAGE(EqualsProto(R"pb(value { + str: "WriteToStream: foo" + })pb")), + Stacktrace(IsEmpty())))); + + test_sink.StartCapturingLogs(); + WriteToStream("foo", + &absl::LogDebugFatalStreamer("path/file.cc", 1234).stream()); +} +#elif GTEST_HAS_DEATH_TEST +TEST(LogStreamerDeathTest, LogDebugFatalStreamer) { + EXPECT_EXIT( + { + absl::ScopedMockLog test_sink; + + EXPECT_CALL(test_sink, Send) + .Times(AnyNumber()) + .WillRepeatedly(DeathTestUnexpectedLogging()); + + EXPECT_CALL( + test_sink, + Send(AllOf( + SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)), + Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kFatal)), + TimestampInMatchWindow(), + ThreadID(Eq(absl::base_internal::GetTID())), + TextMessage(Eq("WriteToStream: foo")), + ENCODED_MESSAGE(EqualsProto(R"pb(value { + str: "WriteToStream: foo" + })pb"))))) + .WillOnce(DeathTestExpectedLogging()); + + test_sink.StartCapturingLogs(); + WriteToStream( + "foo", &absl::LogDebugFatalStreamer("path/file.cc", 1234).stream()); + }, + DiedOfFatal, DeathTestValidateExpectations()); +} +#endif + TEST(LogStreamerTest, LogStreamer) { absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); diff --git a/absl/log/stripping_test.cc b/absl/log/stripping_test.cc index aff914955fb..35357039d76 100644 --- a/absl/log/stripping_test.cc +++ b/absl/log/stripping_test.cc @@ -322,6 +322,49 @@ TEST_F(StrippingTest, Fatal) { } } +TEST_F(StrippingTest, DFatal) { + // We need to load a copy of the needle string into memory (so we can search + // for it) without leaving it lying around in plaintext in the executable file + // as would happen if we used a literal. We might (or might not) leave it + // lying around later; that's what the tests are for! + const std::string needle = absl::Base64Escape("StrippingTest.DFatal"); + // We don't care if the LOG statement is actually executed, we're just + // checking that it's stripped. + if (kReallyDie) LOG(DFATAL) << "U3RyaXBwaW5nVGVzdC5ERmF0YWw="; + + std::unique_ptr> exe = OpenTestExecutable(); + ASSERT_THAT(exe, NotNull()); + // `DFATAL` can be `ERROR` or `FATAL`, and a compile-time optimizer doesn't + // know which, because `absl::kLogDebugFatal` is declared `extern` and defined + // in another TU. Link-time optimization might do better. We have six cases: + // | `AMLL` is-> | `<=ERROR` | `FATAL` | `>FATAL` | + // | ------------------- | --------- | ------- | -------- | + // | `DFATAL` is `ERROR` | present | ? | stripped | + // | `DFATAL` is `FATAL` | present | present | stripped | + + // These constexpr variables are used to suppress unreachable code warnings + // in the if-else statements below. + + // "present" in the table above: `DFATAL` exceeds `ABSL_MIN_LOG_LEVEL`, so + // `DFATAL` statements should not be stripped (and they should be logged + // when executed, but that's a different testsuite). + constexpr bool kExpectPresent = absl::kLogDebugFatal >= kAbslMinLogLevel; + + // "stripped" in the table above: even though the compiler may not know + // which value `DFATAL` has, it should be able to strip it since both + // possible values ought to be stripped. + constexpr bool kExpectStripped = kAbslMinLogLevel > absl::LogSeverity::kFatal; + + if (kExpectPresent) { + EXPECT_THAT(exe.get(), FileHasSubstr(needle)); + } else if (kExpectStripped) { + EXPECT_THAT(exe.get(), Not(FileHasSubstr(needle))); + } else { + // "?" in the table above; may or may not be stripped depending on whether + // any link-time optimization is done. Either outcome is ok. + } +} + TEST_F(StrippingTest, Level) { const std::string needle = absl::Base64Escape("StrippingTest.Level"); volatile auto severity = absl::LogSeverity::kWarning; From a45b0177705af2513fe462374e695f7e7a070d12 Mon Sep 17 00:00:00 2001 From: Dmitri Gribenko Date: Mon, 7 Aug 2023 06:55:21 -0700 Subject: [PATCH 0147/1238] Remove a reference to the global string type, which does not exist as a separate type anymore PiperOrigin-RevId: 554462574 Change-Id: I749ae0308d76580a2264f35ee8df487da81e0f7b --- absl/strings/cord.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/absl/strings/cord.h b/absl/strings/cord.h index 457ccf0609a..f800207b4f8 100644 --- a/absl/strings/cord.h +++ b/absl/strings/cord.h @@ -1618,7 +1618,7 @@ inline bool operator>=(const Cord& x, const Cord& y) { // Nonmember Cord-to-absl::string_view relational operators. // // Due to implicit conversions, these also enable comparisons of Cord with -// with std::string, ::string, and const char*. +// with std::string and const char*. inline bool operator==(const Cord& lhs, absl::string_view rhs) { size_t lhs_size = lhs.size(); size_t rhs_size = rhs.size(); From 5ab833b904976f5b3c858ff1ddfbae7d1ed7d41a Mon Sep 17 00:00:00 2001 From: Dmitri Gribenko Date: Mon, 7 Aug 2023 12:10:03 -0700 Subject: [PATCH 0148/1238] Remove the no-op full_validation flag in the implementation details of cord.cc PiperOrigin-RevId: 554552096 Change-Id: I0aa1bf705841c8bcee42bd33bc8d14bc15f2728b --- absl/strings/cord.cc | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc index 14976aef584..c5379de34d3 100644 --- a/absl/strings/cord.cc +++ b/absl/strings/cord.cc @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -70,22 +71,11 @@ using ::absl::cord_internal::kMaxBytesToCopy; static void DumpNode(CordRep* rep, bool include_data, std::ostream* os, int indent = 0); -static bool VerifyNode(CordRep* root, CordRep* start_node, - bool full_validation); +static bool VerifyNode(CordRep* root, CordRep* start_node); static inline CordRep* VerifyTree(CordRep* node) { - // Verification is expensive, so only do it in debug mode. - // Even in debug mode we normally do only light validation. - // If you are debugging Cord itself, you should define the - // macro EXTRA_CORD_VALIDATION, e.g. by adding - // --copt=-DEXTRA_CORD_VALIDATION to the blaze line. -#ifdef EXTRA_CORD_VALIDATION - assert(node == nullptr || VerifyNode(node, node, /*full_validation=*/true)); -#else // EXTRA_CORD_VALIDATION - assert(node == nullptr || VerifyNode(node, node, /*full_validation=*/false)); -#endif // EXTRA_CORD_VALIDATION + assert(node == nullptr || VerifyNode(node, node)); static_cast(&VerifyNode); - return node; } @@ -1310,8 +1300,7 @@ static std::string ReportError(CordRep* root, CordRep* node) { return buf.str(); } -static bool VerifyNode(CordRep* root, CordRep* start_node, - bool /* full_validation */) { +static bool VerifyNode(CordRep* root, CordRep* start_node) { absl::InlinedVector worklist; worklist.push_back(start_node); do { From 3a41b2c3a6a3912b8ebf7f60c742547fa8417e91 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Tue, 8 Aug 2023 07:25:19 -0700 Subject: [PATCH 0149/1238] Add missing include for PiperOrigin-RevId: 554817008 Change-Id: If18f5992e2a65ce2e3e3cf7e0732767676c4320c --- absl/time/civil_time_test.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/absl/time/civil_time_test.cc b/absl/time/civil_time_test.cc index ec435ac731e..c7a085bf435 100644 --- a/absl/time/civil_time_test.cc +++ b/absl/time/civil_time_test.cc @@ -14,6 +14,7 @@ #include "absl/time/civil_time.h" +#include #include #include #include From 0ddbfd530c9124c21021970dfaeb2aa5ada57b51 Mon Sep 17 00:00:00 2001 From: Dmitri Gribenko Date: Tue, 8 Aug 2023 09:46:31 -0700 Subject: [PATCH 0150/1238] Include what you spell PiperOrigin-RevId: 554854436 Change-Id: Ifbac5ba447528ac696ac59eced95fd752aacf4f9 --- absl/strings/BUILD.bazel | 17 ++++++++++++++++- absl/strings/CMakeLists.txt | 24 +++++++++++++++++------- absl/strings/ascii.cc | 2 ++ absl/strings/ascii.h | 1 + absl/strings/ascii_benchmark.cc | 2 ++ absl/strings/ascii_test.cc | 2 +- absl/strings/charconv.cc | 5 +++-- absl/strings/charconv_test.cc | 7 ++++++- absl/strings/cord.cc | 22 ++++++++++++---------- absl/strings/cord_analysis.cc | 8 +------- absl/strings/cord_buffer_test.cc | 4 +++- absl/strings/cord_ring_reader_test.cc | 8 ++++---- absl/strings/cord_ring_test.cc | 12 ++++++++---- absl/strings/cord_test.cc | 23 ++++++++++++++++++++--- absl/strings/cordz_test.cc | 10 ++++++---- absl/strings/escaping.cc | 7 ++++--- absl/strings/escaping_benchmark.cc | 4 ++++ absl/strings/escaping_test.cc | 7 +++++-- absl/strings/match.cc | 3 +++ absl/strings/match_test.cc | 3 +++ absl/strings/numbers.cc | 8 ++++---- absl/strings/numbers_benchmark.cc | 2 ++ absl/strings/numbers_test.cc | 3 +++ absl/strings/str_cat.cc | 5 ++--- absl/strings/str_cat_benchmark.cc | 4 ++++ absl/strings/str_cat_test.cc | 5 ++++- absl/strings/str_format_test.cc | 8 +++++++- absl/strings/str_join_test.cc | 3 ++- absl/strings/str_replace.cc | 8 ++++++++ absl/strings/str_replace_test.cc | 4 ++++ absl/strings/str_split.cc | 9 +++------ absl/strings/str_split_benchmark.cc | 1 + absl/strings/str_split_test.cc | 8 +++++--- absl/strings/string_view_benchmark.cc | 1 + absl/strings/string_view_test.cc | 9 ++++++--- absl/strings/substitute.cc | 7 +++++++ absl/strings/substitute_test.cc | 3 +++ 37 files changed, 187 insertions(+), 72 deletions(-) diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index 819bbe69615..e3b8af48b48 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -158,6 +158,7 @@ cc_test( ":strings", "//absl/base:core_headers", "//absl/container:fixed_array", + "//absl/log:check", "@com_google_googletest//:gtest_main", ], ) @@ -485,8 +486,8 @@ cc_library( "//absl/base:core_headers", "//absl/base:endian", "//absl/base:raw_logging_internal", - "//absl/container:fixed_array", "//absl/container:inlined_vector", + "//absl/crc:crc32c", "//absl/crc:crc_cord_state", "//absl/functional:function_ref", "//absl/meta:type_traits", @@ -773,6 +774,7 @@ cc_test( ":cord", ":cord_internal", ":cord_rep_test_util", + ":string_view", "//absl/base:config", "//absl/types:span", "@com_google_googletest//:gtest_main", @@ -787,19 +789,24 @@ cc_test( visibility = ["//visibility:private"], deps = [ ":cord", + ":cord_internal", ":cord_test_helpers", ":cordz_functions", + ":cordz_statistics", ":cordz_test_helpers", + ":cordz_update_tracker", ":str_format", ":strings", "//absl/base:config", "//absl/base:core_headers", "//absl/base:endian", "//absl/container:fixed_array", + "//absl/functional:function_ref", "//absl/hash", "//absl/log", "//absl/log:check", "//absl/random", + "//absl/types:optional", "@com_google_googletest//:gtest_main", ], ) @@ -821,6 +828,7 @@ cc_test( visibility = ["//visibility:private"], deps = [ ":cord", + ":cord_internal", ":cord_test_helpers", ":cordz_functions", ":cordz_info", @@ -849,6 +857,7 @@ cc_test( "//absl/base:core_headers", "//absl/base:raw_logging_internal", "//absl/debugging:leak_check", + "//absl/types:span", "@com_google_googletest//:gtest_main", ], ) @@ -862,8 +871,10 @@ cc_test( deps = [ ":cord_internal", ":strings", + "//absl/base:config", "//absl/base:core_headers", "//absl/debugging:leak_check", + "//absl/types:span", "@com_google_googletest//:gtest_main", ], ) @@ -1041,6 +1052,7 @@ cc_test( ":strings", "//absl/base:config", "//absl/log", + "//absl/numeric:int128", "//absl/random", "//absl/random:distributions", "@com_google_googletest//:gtest_main", @@ -1211,6 +1223,9 @@ cc_test( ":cord", ":str_format", ":strings", + "//absl/base:config", + "//absl/base:core_headers", + "//absl/types:span", "@com_google_googletest//:gtest_main", ], ) diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index 1959dc91ada..0e588674595 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt @@ -138,6 +138,7 @@ absl_cc_test( absl::core_headers absl::fixed_array GTest::gmock_main + absl::check ) absl_cc_test( @@ -329,13 +330,14 @@ absl_cc_test( COPTS ${ABSL_TEST_COPTS} DEPS - absl::strings - absl::core_headers - absl::pow10_helper absl::config + absl::core_headers + absl::int128 absl::log - absl::random_random + absl::pow10_helper absl::random_distributions + absl::random_random + absl::strings absl::strings_internal GTest::gmock_main ) @@ -464,10 +466,12 @@ absl_cc_test( COPTS ${ABSL_TEST_COPTS} DEPS - absl::str_format + absl::config absl::cord - absl::strings absl::core_headers + absl::span + absl::str_format + absl::strings GTest::gmock_main ) @@ -918,9 +922,9 @@ absl_cc_library( absl::cordz_update_scope absl::cordz_update_tracker absl::core_headers + absl::crc32c absl::crc_cord_state absl::endian - absl::fixed_array absl::function_ref absl::inlined_vector absl::optional @@ -1001,8 +1005,10 @@ absl_cc_test( absl::core_headers absl::endian absl::fixed_array + absl::function_ref absl::hash absl::log + absl::optional absl::random_random absl::str_format absl::strings @@ -1109,6 +1115,7 @@ absl_cc_test( absl::cord_internal absl::core_headers absl::raw_logging_internal + absl::span absl::strings GTest::gmock_main ) @@ -1122,8 +1129,10 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::base + absl::config absl::cord_internal absl::core_headers + absl::span absl::strings GTest::gmock_main ) @@ -1137,6 +1146,7 @@ absl_cc_test( ${ABSL_TEST_COPTS} DEPS absl::cord + absl::cord_internal absl::cord_test_helpers absl::cordz_test_helpers absl::cordz_functions diff --git a/absl/strings/ascii.cc b/absl/strings/ascii.cc index 16c96899613..8c6b1e05fd0 100644 --- a/absl/strings/ascii.cc +++ b/absl/strings/ascii.cc @@ -18,6 +18,8 @@ #include #include +#include "absl/base/config.h" + namespace absl { ABSL_NAMESPACE_BEGIN namespace ascii_internal { diff --git a/absl/strings/ascii.h b/absl/strings/ascii.h index 42eadaea6c8..ba6679bd2a2 100644 --- a/absl/strings/ascii.h +++ b/absl/strings/ascii.h @@ -53,6 +53,7 @@ #define ABSL_STRINGS_ASCII_H_ #include +#include #include #include "absl/base/attributes.h" diff --git a/absl/strings/ascii_benchmark.cc b/absl/strings/ascii_benchmark.cc index aca458c8042..b04b28ca03f 100644 --- a/absl/strings/ascii_benchmark.cc +++ b/absl/strings/ascii_benchmark.cc @@ -14,7 +14,9 @@ #include "absl/strings/ascii.h" +#include #include +#include #include #include #include diff --git a/absl/strings/ascii_test.cc b/absl/strings/ascii_test.cc index 4ea262f13d6..117140c1747 100644 --- a/absl/strings/ascii_test.cc +++ b/absl/strings/ascii_test.cc @@ -22,7 +22,7 @@ #include "gtest/gtest.h" #include "absl/base/macros.h" -#include "absl/base/port.h" +#include "absl/strings/string_view.h" namespace { diff --git a/absl/strings/charconv.cc b/absl/strings/charconv.cc index 778a1c75a5e..60b3715c217 100644 --- a/absl/strings/charconv.cc +++ b/absl/strings/charconv.cc @@ -16,9 +16,10 @@ #include #include -#include -#include +#include +#include #include +#include // NOLINT(build/c++11) #include "absl/base/casts.h" #include "absl/base/config.h" diff --git a/absl/strings/charconv_test.cc b/absl/strings/charconv_test.cc index b83de5a0ba2..c16c735c24b 100644 --- a/absl/strings/charconv_test.cc +++ b/absl/strings/charconv_test.cc @@ -14,14 +14,19 @@ #include "absl/strings/charconv.h" +#include +#include #include +#include +#include #include +#include // NOLINT(build/c++11) -#include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/strings/internal/pow10_helper.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" #ifdef _MSC_FULL_VER #define ABSL_COMPILER_DOES_EXACT_ROUNDING 0 diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc index c5379de34d3..0c26e37e5b6 100644 --- a/absl/strings/cord.cc +++ b/absl/strings/cord.cc @@ -15,28 +15,31 @@ #include "absl/strings/cord.h" #include -#include #include #include +#include #include #include +#include #include #include #include #include +#include #include #include -#include -#include -#include +#include +#include -#include "absl/base/casts.h" +#include "absl/base/config.h" +#include "absl/base/internal/endian.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/macros.h" -#include "absl/base/port.h" -#include "absl/container/fixed_array.h" +#include "absl/base/optimization.h" #include "absl/container/inlined_vector.h" +#include "absl/crc/crc32c.h" #include "absl/crc/internal/crc_cord_state.h" +#include "absl/functional/function_ref.h" #include "absl/strings/cord_buffer.h" #include "absl/strings/escaping.h" #include "absl/strings/internal/cord_data_edge.h" @@ -44,13 +47,12 @@ #include "absl/strings/internal/cord_rep_btree.h" #include "absl/strings/internal/cord_rep_crc.h" #include "absl/strings/internal/cord_rep_flat.h" -#include "absl/strings/internal/cordz_statistics.h" -#include "absl/strings/internal/cordz_update_scope.h" #include "absl/strings/internal/cordz_update_tracker.h" #include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/str_cat.h" -#include "absl/strings/str_join.h" #include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "absl/types/span.h" namespace absl { ABSL_NAMESPACE_BEGIN diff --git a/absl/strings/cord_analysis.cc b/absl/strings/cord_analysis.cc index e859b0db064..fa1a0cc8c8e 100644 --- a/absl/strings/cord_analysis.cc +++ b/absl/strings/cord_analysis.cc @@ -14,23 +14,17 @@ #include "absl/strings/cord_analysis.h" +#include #include #include #include -#include "absl/base/attributes.h" #include "absl/base/config.h" -#include "absl/container/inlined_vector.h" #include "absl/strings/internal/cord_data_edge.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" #include "absl/strings/internal/cord_rep_crc.h" -#include "absl/strings/internal/cord_rep_flat.h" #include "absl/strings/internal/cord_rep_ring.h" -// -#include "absl/base/macros.h" -#include "absl/base/port.h" -#include "absl/functional/function_ref.h" namespace absl { ABSL_NAMESPACE_BEGIN diff --git a/absl/strings/cord_buffer_test.cc b/absl/strings/cord_buffer_test.cc index 5c7437aece2..ab628081b0e 100644 --- a/absl/strings/cord_buffer_test.cc +++ b/absl/strings/cord_buffer_test.cc @@ -16,16 +16,18 @@ #include -#include #include +#include #include #include #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/base/config.h" +#include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_flat.h" #include "absl/strings/internal/cord_rep_test_util.h" +#include "absl/strings/string_view.h" #include "absl/types/span.h" using testing::Eq; diff --git a/absl/strings/cord_ring_reader_test.cc b/absl/strings/cord_ring_reader_test.cc index 8e7183bff0a..d135f3cfa61 100644 --- a/absl/strings/cord_ring_reader_test.cc +++ b/absl/strings/cord_ring_reader_test.cc @@ -12,19 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include +#include #include -#include -#include -#include #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/debugging/leak_check.h" +#include "absl/base/config.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_ring.h" #include "absl/strings/internal/cord_rep_ring_reader.h" #include "absl/strings/string_view.h" +#include "absl/types/span.h" namespace absl { ABSL_NAMESPACE_BEGIN diff --git a/absl/strings/cord_ring_test.cc b/absl/strings/cord_ring_test.cc index f39a0a4f8d1..74f57c77560 100644 --- a/absl/strings/cord_ring_test.cc +++ b/absl/strings/cord_ring_test.cc @@ -12,22 +12,26 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include +#include #include -#include +#include +#include #include #include +#include +#include #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/base/config.h" -#include "absl/base/internal/raw_logging.h" -#include "absl/base/macros.h" -#include "absl/debugging/leak_check.h" #include "absl/strings/internal/cord_internal.h" +#include "absl/strings/internal/cord_rep_flat.h" #include "absl/strings/internal/cord_rep_ring.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" +#include "absl/types/span.h" extern thread_local bool cord_ring; diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc index 36e397ed555..51fef3167c9 100644 --- a/absl/strings/cord_test.cc +++ b/absl/strings/cord_test.cc @@ -15,33 +15,50 @@ #include "absl/strings/cord.h" #include -#include +#include +#include +#include +#include #include +#include +#include #include -#include -#include +#include #include +#include #include +#include #include #include #include #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/internal/endian.h" #include "absl/base/macros.h" +#include "absl/base/options.h" #include "absl/container/fixed_array.h" +#include "absl/functional/function_ref.h" #include "absl/hash/hash.h" #include "absl/log/check.h" #include "absl/log/log.h" #include "absl/random/random.h" +#include "absl/strings/cord_buffer.h" #include "absl/strings/cord_test_helpers.h" #include "absl/strings/cordz_test_helpers.h" +#include "absl/strings/internal/cord_internal.h" +#include "absl/strings/internal/cord_rep_crc.h" +#include "absl/strings/internal/cord_rep_flat.h" +#include "absl/strings/internal/cordz_statistics.h" +#include "absl/strings/internal/cordz_update_tracker.h" +#include "absl/strings/internal/string_constant.h" #include "absl/strings/match.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" +#include "absl/types/optional.h" // convenience local constants static constexpr auto FLAT = absl::cord_internal::FLAT; diff --git a/absl/strings/cordz_test.cc b/absl/strings/cordz_test.cc index 2b7d30b0e01..a35493e3fdc 100644 --- a/absl/strings/cordz_test.cc +++ b/absl/strings/cordz_test.cc @@ -12,18 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include +#include +#include +#include #include +#include #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/base/config.h" -#include "absl/base/internal/raw_logging.h" -#include "absl/base/macros.h" #include "absl/strings/cord.h" +#include "absl/strings/cord_buffer.h" #include "absl/strings/cord_test_helpers.h" #include "absl/strings/cordz_test_helpers.h" -#include "absl/strings/internal/cordz_functions.h" +#include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cordz_info.h" #include "absl/strings/internal/cordz_sample_token.h" #include "absl/strings/internal/cordz_statistics.h" diff --git a/absl/strings/escaping.cc b/absl/strings/escaping.cc index 2827fbaa37f..5bf022360e3 100644 --- a/absl/strings/escaping.cc +++ b/absl/strings/escaping.cc @@ -16,21 +16,22 @@ #include #include +#include #include #include -#include #include #include -#include "absl/base/internal/endian.h" +#include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/internal/unaligned_access.h" +#include "absl/strings/ascii.h" #include "absl/strings/internal/char_map.h" #include "absl/strings/internal/escaping.h" #include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/internal/utf8.h" +#include "absl/strings/numbers.h" #include "absl/strings/str_cat.h" -#include "absl/strings/str_join.h" #include "absl/strings/string_view.h" namespace absl { diff --git a/absl/strings/escaping_benchmark.cc b/absl/strings/escaping_benchmark.cc index 10d5b033c52..f792226a712 100644 --- a/absl/strings/escaping_benchmark.cc +++ b/absl/strings/escaping_benchmark.cc @@ -14,13 +14,17 @@ #include "absl/strings/escaping.h" +#include #include #include +#include #include +#include #include "benchmark/benchmark.h" #include "absl/base/internal/raw_logging.h" #include "absl/strings/internal/escaping_test_common.h" +#include "absl/strings/str_cat.h" namespace { diff --git a/absl/strings/escaping_test.cc b/absl/strings/escaping_test.cc index 9f62c1ee98a..ca1ee45c314 100644 --- a/absl/strings/escaping_test.cc +++ b/absl/strings/escaping_test.cc @@ -15,17 +15,20 @@ #include "absl/strings/escaping.h" #include +#include #include #include +#include #include +#include #include -#include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/container/fixed_array.h" +#include "absl/log/check.h" #include "absl/strings/str_cat.h" #include "absl/strings/internal/escaping_test_common.h" +#include "absl/strings/string_view.h" namespace { diff --git a/absl/strings/match.cc b/absl/strings/match.cc index 3b81b2c0529..72ae6a430a8 100644 --- a/absl/strings/match.cc +++ b/absl/strings/match.cc @@ -17,10 +17,13 @@ #include #include +#include "absl/base/config.h" #include "absl/base/internal/endian.h" +#include "absl/base/optimization.h" #include "absl/numeric/bits.h" #include "absl/strings/ascii.h" #include "absl/strings/internal/memutil.h" +#include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN diff --git a/absl/strings/match_test.cc b/absl/strings/match_test.cc index 71618f71f0c..6218ce4e797 100644 --- a/absl/strings/match_test.cc +++ b/absl/strings/match_test.cc @@ -14,7 +14,10 @@ #include "absl/strings/match.h" +#include + #include "gtest/gtest.h" +#include "absl/strings/string_view.h" namespace { diff --git a/absl/strings/numbers.cc b/absl/strings/numbers.cc index c43c6bcc195..5d13f105859 100644 --- a/absl/strings/numbers.cc +++ b/absl/strings/numbers.cc @@ -27,20 +27,20 @@ #include #include #include -#include +#include // NOLINT(build/c++11) #include #include "absl/base/attributes.h" +#include "absl/base/config.h" #include "absl/base/internal/endian.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/optimization.h" #include "absl/numeric/bits.h" +#include "absl/numeric/int128.h" #include "absl/strings/ascii.h" #include "absl/strings/charconv.h" -#include "absl/strings/escaping.h" -#include "absl/strings/internal/memutil.h" #include "absl/strings/match.h" -#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN diff --git a/absl/strings/numbers_benchmark.cc b/absl/strings/numbers_benchmark.cc index 6e79b3e811f..e7cb60a4289 100644 --- a/absl/strings/numbers_benchmark.cc +++ b/absl/strings/numbers_benchmark.cc @@ -13,6 +13,7 @@ // limitations under the License. #include +#include #include #include #include @@ -23,6 +24,7 @@ #include "absl/random/distributions.h" #include "absl/random/random.h" #include "absl/strings/numbers.h" +#include "absl/strings/string_view.h" namespace { diff --git a/absl/strings/numbers_test.cc b/absl/strings/numbers_test.cc index 2864bda2e42..a450b99e3e8 100644 --- a/absl/strings/numbers_test.cc +++ b/absl/strings/numbers_test.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -38,12 +39,14 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/log/log.h" +#include "absl/numeric/int128.h" #include "absl/random/distributions.h" #include "absl/random/random.h" #include "absl/strings/internal/numbers_test_common.h" #include "absl/strings/internal/ostringstream.h" #include "absl/strings/internal/pow10_helper.h" #include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" namespace { diff --git a/absl/strings/str_cat.cc b/absl/strings/str_cat.cc index 2e49c31b68e..17f42d2800b 100644 --- a/absl/strings/str_cat.cc +++ b/absl/strings/str_cat.cc @@ -16,15 +16,14 @@ #include -#include #include #include #include +#include #include -#include "absl/strings/ascii.h" +#include "absl/base/config.h" #include "absl/strings/internal/resize_uninitialized.h" -#include "absl/strings/numbers.h" #include "absl/strings/string_view.h" namespace absl { diff --git a/absl/strings/str_cat_benchmark.cc b/absl/strings/str_cat_benchmark.cc index 02c4dbe6d8f..81b205482c2 100644 --- a/absl/strings/str_cat_benchmark.cc +++ b/absl/strings/str_cat_benchmark.cc @@ -15,9 +15,13 @@ #include "absl/strings/str_cat.h" #include +#include +#include +#include #include #include "benchmark/benchmark.h" +#include "absl/strings/string_view.h" #include "absl/strings/substitute.h" namespace { diff --git a/absl/strings/str_cat_test.cc b/absl/strings/str_cat_test.cc index 2d74245e4c9..7f52e053cfe 100644 --- a/absl/strings/str_cat_test.cc +++ b/absl/strings/str_cat_test.cc @@ -16,13 +16,16 @@ #include "absl/strings/str_cat.h" +#include #include +#include +#include #include #include #include "gtest/gtest.h" #include "absl/strings/str_format.h" -#include "absl/strings/substitute.h" +#include "absl/strings/string_view.h" #ifdef __ANDROID__ // Android assert messages only go to system log, so death tests cannot inspect diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc index 20fd0289704..195ef3fe163 100644 --- a/absl/strings/str_format_test.cc +++ b/absl/strings/str_format_test.cc @@ -14,16 +14,22 @@ #include "absl/strings/str_format.h" +#include #include #include #include +#include +#include #include +#include -#include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/base/config.h" +#include "absl/base/macros.h" #include "absl/strings/cord.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" +#include "absl/types/span.h" namespace absl { ABSL_NAMESPACE_BEGIN diff --git a/absl/strings/str_join_test.cc b/absl/strings/str_join_test.cc index c986e863b6a..449f95be3ed 100644 --- a/absl/strings/str_join_test.cc +++ b/absl/strings/str_join_test.cc @@ -25,8 +25,9 @@ #include #include #include +#include #include -#include +#include #include #include "gtest/gtest.h" diff --git a/absl/strings/str_replace.cc b/absl/strings/str_replace.cc index 2bd5fa98218..9ce49e56579 100644 --- a/absl/strings/str_replace.cc +++ b/absl/strings/str_replace.cc @@ -14,7 +14,15 @@ #include "absl/strings/str_replace.h" +#include +#include +#include +#include +#include + +#include "absl/base/config.h" #include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN diff --git a/absl/strings/str_replace_test.cc b/absl/strings/str_replace_test.cc index 9d8c7f75b57..36cb9551e5d 100644 --- a/absl/strings/str_replace_test.cc +++ b/absl/strings/str_replace_test.cc @@ -16,11 +16,15 @@ #include #include +#include #include +#include +#include #include "gtest/gtest.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_split.h" +#include "absl/strings/string_view.h" TEST(StrReplaceAll, OneReplacement) { std::string s; diff --git a/absl/strings/str_split.cc b/absl/strings/str_split.cc index 72ba7c02df2..9669eb0b125 100644 --- a/absl/strings/str_split.cc +++ b/absl/strings/str_split.cc @@ -15,16 +15,13 @@ #include "absl/strings/str_split.h" #include -#include -#include +#include #include #include -#include -#include -#include +#include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" -#include "absl/strings/ascii.h" +#include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN diff --git a/absl/strings/str_split_benchmark.cc b/absl/strings/str_split_benchmark.cc index f38dfcfe5af..003a66b5a3e 100644 --- a/absl/strings/str_split_benchmark.cc +++ b/absl/strings/str_split_benchmark.cc @@ -14,6 +14,7 @@ #include "absl/strings/str_split.h" +#include #include #include #include diff --git a/absl/strings/str_split_test.cc b/absl/strings/str_split_test.cc index 04a64a42643..eb0c6c00cfe 100644 --- a/absl/strings/str_split_test.cc +++ b/absl/strings/str_split_test.cc @@ -14,26 +14,28 @@ #include "absl/strings/str_split.h" +#include +#include #include #include #include #include #include +#include #include -#include #include #include +#include #include #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/base/dynamic_annotations.h" #include "absl/base/macros.h" #include "absl/container/btree_map.h" #include "absl/container/btree_set.h" #include "absl/container/flat_hash_map.h" #include "absl/container/node_hash_map.h" -#include "absl/strings/numbers.h" +#include "absl/strings/string_view.h" namespace { diff --git a/absl/strings/string_view_benchmark.cc b/absl/strings/string_view_benchmark.cc index 0d74e23e2fc..98f747ca8a6 100644 --- a/absl/strings/string_view_benchmark.cc +++ b/absl/strings/string_view_benchmark.cc @@ -15,6 +15,7 @@ #include "absl/strings/string_view.h" #include +#include #include #include #include diff --git a/absl/strings/string_view_test.cc b/absl/strings/string_view_test.cc index 990c211a8ed..642989b13c9 100644 --- a/absl/strings/string_view_test.cc +++ b/absl/strings/string_view_test.cc @@ -15,20 +15,23 @@ #include "absl/strings/string_view.h" #include + +#include +#include +#include #include +#include #include #include #include +#include #include -#include #include #include #include #include "gtest/gtest.h" #include "absl/base/config.h" -#include "absl/base/dynamic_annotations.h" -#include "absl/base/options.h" #if defined(ABSL_HAVE_STD_STRING_VIEW) || defined(__ANDROID__) // We don't control the death messaging when using std::string_view. diff --git a/absl/strings/substitute.cc b/absl/strings/substitute.cc index 33a39305db0..354c070df71 100644 --- a/absl/strings/substitute.cc +++ b/absl/strings/substitute.cc @@ -15,11 +15,18 @@ #include "absl/strings/substitute.h" #include +#include +#include +#include +#include +#include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" #include "absl/strings/ascii.h" #include "absl/strings/escaping.h" #include "absl/strings/internal/resize_uninitialized.h" +#include "absl/strings/numbers.h" +#include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" namespace absl { diff --git a/absl/strings/substitute_test.cc b/absl/strings/substitute_test.cc index ecf78d6b22c..70f9119b657 100644 --- a/absl/strings/substitute_test.cc +++ b/absl/strings/substitute_test.cc @@ -15,10 +15,13 @@ #include "absl/strings/substitute.h" #include +#include +#include #include #include "gtest/gtest.h" #include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" namespace { From f850728a8afc2871b50a4d95cb4ccea4d3016b75 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 8 Aug 2023 12:02:35 -0700 Subject: [PATCH 0151/1238] Add ATTRIBUTE_LIFETIME_BOUND to Cord::Flatten and TryFlat PiperOrigin-RevId: 554898945 Change-Id: Id19acf5af56b1e7877cd73ac8420cf8e1a841b64 --- absl/strings/cord.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/absl/strings/cord.h b/absl/strings/cord.h index f800207b4f8..0c7727d4340 100644 --- a/absl/strings/cord.h +++ b/absl/strings/cord.h @@ -737,14 +737,15 @@ class Cord { // // If this cord's representation is a single flat array, returns a // string_view referencing that array. Otherwise returns nullopt. - absl::optional TryFlat() const; + absl::optional TryFlat() const + ABSL_ATTRIBUTE_LIFETIME_BOUND; // Cord::Flatten() // // Flattens the cord into a single array and returns a view of the data. // // If the cord was already flat, the contents are not modified. - absl::string_view Flatten(); + absl::string_view Flatten() ABSL_ATTRIBUTE_LIFETIME_BOUND; // Supports absl::Cord as a sink object for absl::Format(). friend void AbslFormatFlush(absl::Cord* cord, absl::string_view part) { From 49146ec1a333631b9a9e30cd2bf0685ad734e4e1 Mon Sep 17 00:00:00 2001 From: Dmitri Gribenko Date: Tue, 8 Aug 2023 14:02:58 -0700 Subject: [PATCH 0152/1238] Remove a doubled up "with" PiperOrigin-RevId: 554934635 Change-Id: Ia666bc28ee8ee84c633f365312760996f0816ca7 --- absl/strings/cord.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/absl/strings/cord.h b/absl/strings/cord.h index 0c7727d4340..1753991d773 100644 --- a/absl/strings/cord.h +++ b/absl/strings/cord.h @@ -1619,7 +1619,7 @@ inline bool operator>=(const Cord& x, const Cord& y) { // Nonmember Cord-to-absl::string_view relational operators. // // Due to implicit conversions, these also enable comparisons of Cord with -// with std::string and const char*. +// std::string and const char*. inline bool operator==(const Cord& lhs, absl::string_view rhs) { size_t lhs_size = lhs.size(); size_t rhs_size = rhs.size(); From a3c403f123050b9cf784dba6ba9578c9981847f5 Mon Sep 17 00:00:00 2001 From: Dmitri Gribenko Date: Tue, 8 Aug 2023 14:06:41 -0700 Subject: [PATCH 0153/1238] Fix ClangTidy warnings * converting integer literal to bool, use bool literal instead * use '= default' to define a trivial default constructor PiperOrigin-RevId: 554935854 Change-Id: If16a435664641df049b8810044b34a05ea2b4028 --- absl/strings/str_replace_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/absl/strings/str_replace_test.cc b/absl/strings/str_replace_test.cc index 36cb9551e5d..04b23af6f89 100644 --- a/absl/strings/str_replace_test.cc +++ b/absl/strings/str_replace_test.cc @@ -179,7 +179,7 @@ TEST(StrReplaceAll, ReplacementsInPlaceInMap) { } struct Cont { - Cont() {} + Cont() = default; explicit Cont(absl::string_view src) : data(src) {} absl::string_view data; From 298fd26156453f169bfb8eb6df0a12f8c06e82ae Mon Sep 17 00:00:00 2001 From: Dmitri Gribenko Date: Tue, 8 Aug 2023 14:07:40 -0700 Subject: [PATCH 0154/1238] Fix warnings: * 'DoNotOptimize' is deprecated: The const-ref version of this method can permit undesired compiler optimizations in benchmarks * missing #include for 'std::string' PiperOrigin-RevId: 554936149 Change-Id: Iaf06cd9b9b0762e3a514b7e1cfe4a4fd6df24083 --- absl/time/civil_time_benchmark.cc | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/absl/time/civil_time_benchmark.cc b/absl/time/civil_time_benchmark.cc index f04dbe200ed..2de0233dc4f 100644 --- a/absl/time/civil_time_benchmark.cc +++ b/absl/time/civil_time_benchmark.cc @@ -14,7 +14,9 @@ #include "absl/time/civil_time.h" +#include #include +#include #include #include "absl/hash/hash.h" @@ -42,7 +44,7 @@ void BM_Difference_Days(benchmark::State& state) { const absl::CivilDay c(2014, 8, 22); const absl::CivilDay epoch(1970, 1, 1); while (state.KeepRunning()) { - const absl::civil_diff_t n = c - epoch; + absl::civil_diff_t n = c - epoch; benchmark::DoNotOptimize(n); } } @@ -60,7 +62,7 @@ BENCHMARK(BM_Step_Days); void BM_Format(benchmark::State& state) { const absl::CivilSecond c(2014, 1, 2, 3, 4, 5); while (state.KeepRunning()) { - const std::string s = absl::FormatCivilTime(c); + std::string s = absl::FormatCivilTime(c); benchmark::DoNotOptimize(s); } } @@ -70,7 +72,7 @@ void BM_Parse(benchmark::State& state) { const std::string f = "2014-01-02T03:04:05"; absl::CivilSecond c; while (state.KeepRunning()) { - const bool b = absl::ParseCivilTime(f, &c); + bool b = absl::ParseCivilTime(f, &c); benchmark::DoNotOptimize(b); } } @@ -80,7 +82,7 @@ void BM_RoundTripFormatParse(benchmark::State& state) { const absl::CivilSecond c(2014, 1, 2, 3, 4, 5); absl::CivilSecond out; while (state.KeepRunning()) { - const bool b = absl::ParseCivilTime(absl::FormatCivilTime(c), &out); + bool b = absl::ParseCivilTime(absl::FormatCivilTime(c), &out); benchmark::DoNotOptimize(b); } } @@ -95,7 +97,8 @@ void BM_CivilTimeAbslHash(benchmark::State& state) { absl::Hash absl_hasher; while (state.KeepRunningBatch(kSize)) { for (const T civil_time : civil_times) { - benchmark::DoNotOptimize(absl_hasher(civil_time)); + size_t hash = absl_hasher(civil_time); + benchmark::DoNotOptimize(hash); } } } From a8720ebe1d044d33dafa6112a3ff8e96b082412c Mon Sep 17 00:00:00 2001 From: Dmitri Gribenko Date: Tue, 8 Aug 2023 14:08:01 -0700 Subject: [PATCH 0155/1238] Include what you spell PiperOrigin-RevId: 554936252 Change-Id: Idb2ffbbc11aa6c98414fdd1ec38873d4687ab5e7 --- absl/crc/internal/crc_memcpy_x86_64.cc | 5 +++-- absl/crc/internal/crc_x86_arm_combined.cc | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/absl/crc/internal/crc_memcpy_x86_64.cc b/absl/crc/internal/crc_memcpy_x86_64.cc index d42b08dc9f1..c39b061cb5d 100644 --- a/absl/crc/internal/crc_memcpy_x86_64.cc +++ b/absl/crc/internal/crc_memcpy_x86_64.cc @@ -49,9 +49,10 @@ #include #include #include -#include +#include +#include -#include "absl/base/dynamic_annotations.h" +#include "absl/base/config.h" #include "absl/base/optimization.h" #include "absl/base/prefetch.h" #include "absl/crc/crc32c.h" diff --git a/absl/crc/internal/crc_x86_arm_combined.cc b/absl/crc/internal/crc_x86_arm_combined.cc index ef521d22d1d..4847bc8364f 100644 --- a/absl/crc/internal/crc_x86_arm_combined.cc +++ b/absl/crc/internal/crc_x86_arm_combined.cc @@ -16,14 +16,14 @@ #include #include +#include +#include #include "absl/base/attributes.h" #include "absl/base/config.h" -#include "absl/base/dynamic_annotations.h" #include "absl/base/internal/endian.h" #include "absl/base/prefetch.h" #include "absl/crc/internal/cpu_detect.h" -#include "absl/crc/internal/crc.h" #include "absl/crc/internal/crc32_x86_arm_combined_simd.h" #include "absl/crc/internal/crc_internal.h" #include "absl/memory/memory.h" From 6d3c39e33472beab681bb7c4b335ec8c1dc9ff14 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 9 Aug 2023 01:07:06 -0700 Subject: [PATCH 0156/1238] Eliminate redundant code branch in `StrAppend`. PiperOrigin-RevId: 555080884 Change-Id: I3f83fbeea1352587cf46fed83861cd7fb75655b0 --- absl/strings/str_cat.cc | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/absl/strings/str_cat.cc b/absl/strings/str_cat.cc index 17f42d2800b..900dc69a62d 100644 --- a/absl/strings/str_cat.cc +++ b/absl/strings/str_cat.cc @@ -29,6 +29,7 @@ namespace absl { ABSL_NAMESPACE_BEGIN + // ---------------------------------------------------------------------- // StrCat() // This merges the given strings or integers, with no delimiter. This @@ -36,9 +37,10 @@ ABSL_NAMESPACE_BEGIN // of a mix of raw C strings, string_views, strings, and integer values. // ---------------------------------------------------------------------- +namespace { // Append is merely a version of memcpy that returns the address of the byte // after the area just overwritten. -static char* Append(char* out, const AlphaNum& x) { +inline char* Append(char* out, const AlphaNum& x) { // memcpy is allowed to overwrite arbitrary memory, so doing this after the // call would force an extra fetch of x.size(). char* after = out + x.size(); @@ -48,6 +50,13 @@ static char* Append(char* out, const AlphaNum& x) { return after; } +inline void STLStringAppendUninitializedAmortized(std::string* dest, + size_t to_append) { + strings_internal::AppendUninitializedTraits::Append(dest, + to_append); +} +} // namespace + std::string StrCat(const AlphaNum& a, const AlphaNum& b) { std::string result; absl::strings_internal::STLStringResizeUninitialized(&result, @@ -122,12 +131,12 @@ std::string CatPieces(std::initializer_list pieces) { void AppendPieces(std::string* dest, std::initializer_list pieces) { size_t old_size = dest->size(); - size_t total_size = old_size; + size_t to_append = 0; for (absl::string_view piece : pieces) { ASSERT_NO_OVERLAP(*dest, piece); - total_size += piece.size(); + to_append += piece.size(); } - strings_internal::STLStringResizeUninitializedAmortized(dest, total_size); + STLStringAppendUninitializedAmortized(dest, to_append); char* const begin = &(*dest)[0]; char* out = begin + old_size; @@ -146,8 +155,7 @@ void AppendPieces(std::string* dest, void StrAppend(std::string* dest, const AlphaNum& a) { ASSERT_NO_OVERLAP(*dest, a); std::string::size_type old_size = dest->size(); - strings_internal::STLStringResizeUninitializedAmortized(dest, - old_size + a.size()); + STLStringAppendUninitializedAmortized(dest, a.size()); char* const begin = &(*dest)[0]; char* out = begin + old_size; out = Append(out, a); @@ -158,8 +166,7 @@ void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b) { ASSERT_NO_OVERLAP(*dest, a); ASSERT_NO_OVERLAP(*dest, b); std::string::size_type old_size = dest->size(); - strings_internal::STLStringResizeUninitializedAmortized( - dest, old_size + a.size() + b.size()); + STLStringAppendUninitializedAmortized(dest, a.size() + b.size()); char* const begin = &(*dest)[0]; char* out = begin + old_size; out = Append(out, a); @@ -173,8 +180,7 @@ void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, ASSERT_NO_OVERLAP(*dest, b); ASSERT_NO_OVERLAP(*dest, c); std::string::size_type old_size = dest->size(); - strings_internal::STLStringResizeUninitializedAmortized( - dest, old_size + a.size() + b.size() + c.size()); + STLStringAppendUninitializedAmortized(dest, a.size() + b.size() + c.size()); char* const begin = &(*dest)[0]; char* out = begin + old_size; out = Append(out, a); @@ -190,8 +196,8 @@ void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, ASSERT_NO_OVERLAP(*dest, c); ASSERT_NO_OVERLAP(*dest, d); std::string::size_type old_size = dest->size(); - strings_internal::STLStringResizeUninitializedAmortized( - dest, old_size + a.size() + b.size() + c.size() + d.size()); + STLStringAppendUninitializedAmortized( + dest, a.size() + b.size() + c.size() + d.size()); char* const begin = &(*dest)[0]; char* out = begin + old_size; out = Append(out, a); From b9a414dd3a8e99eb8f2350c746f19e4f50b25c68 Mon Sep 17 00:00:00 2001 From: Dmitri Gribenko Date: Wed, 9 Aug 2023 10:34:12 -0700 Subject: [PATCH 0157/1238] Include what you spell PiperOrigin-RevId: 555205956 Change-Id: I935b95c29a8d5b69fe45cc0fe1aadb7106d31df3 --- absl/status/BUILD.bazel | 6 ++++++ absl/status/CMakeLists.txt | 9 ++++++--- absl/status/status.cc | 16 +++++++++++++++- absl/status/status_payload_printer.cc | 4 +--- absl/status/status_test.cc | 6 ++++++ absl/status/statusor.cc | 2 ++ absl/status/statusor_test.cc | 4 ++++ 7 files changed, 40 insertions(+), 7 deletions(-) diff --git a/absl/status/BUILD.bazel b/absl/status/BUILD.bazel index 1f58b307521..6a6fb2996a0 100644 --- a/absl/status/BUILD.bazel +++ b/absl/status/BUILD.bazel @@ -43,6 +43,7 @@ cc_library( linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ "//absl/base:atomic_hook", + "//absl/base:config", "//absl/base:core_headers", "//absl/base:raw_logging_internal", "//absl/base:strerror", @@ -50,10 +51,12 @@ cc_library( "//absl/debugging:stacktrace", "//absl/debugging:symbolize", "//absl/functional:function_ref", + "//absl/memory", "//absl/strings", "//absl/strings:cord", "//absl/strings:str_format", "//absl/types:optional", + "//absl/types:span", ], ) @@ -65,6 +68,7 @@ cc_test( deps = [ ":status", "//absl/strings", + "//absl/strings:cord", "@com_google_googletest//:gtest_main", ], ) @@ -83,6 +87,7 @@ cc_library( deps = [ ":status", "//absl/base", + "//absl/base:config", "//absl/base:core_headers", "//absl/base:raw_logging_internal", "//absl/meta:type_traits", @@ -103,6 +108,7 @@ cc_test( "//absl/memory", "//absl/strings", "//absl/types:any", + "//absl/types:variant", "//absl/utility", "@com_google_googletest//:gtest_main", ], diff --git a/absl/status/CMakeLists.txt b/absl/status/CMakeLists.txt index 4a3c5d6852d..ed2e384878c 100644 --- a/absl/status/CMakeLists.txt +++ b/absl/status/CMakeLists.txt @@ -34,11 +34,13 @@ absl_cc_library( absl::core_headers absl::function_ref absl::inlined_vector + absl::memory absl::optional absl::raw_logging_internal + absl::span absl::stacktrace - absl::str_format absl::strerror + absl::str_format absl::strings absl::symbolize PUBLIC @@ -69,11 +71,12 @@ absl_cc_library( ${ABSL_DEFAULT_COPTS} DEPS absl::base - absl::status + absl::config absl::core_headers absl::raw_logging_internal - absl::type_traits + absl::status absl::strings + absl::type_traits absl::utility absl::variant PUBLIC diff --git a/absl/status/status.cc b/absl/status/status.cc index 26e68294acf..577dea4bbd2 100644 --- a/absl/status/status.cc +++ b/absl/status/status.cc @@ -15,19 +15,33 @@ #include -#include +#include +#include +#include +#include +#include +#include +#include #include +#include "absl/base/attributes.h" +#include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/internal/strerror.h" #include "absl/base/macros.h" #include "absl/debugging/stacktrace.h" #include "absl/debugging/symbolize.h" +#include "absl/functional/function_ref.h" +#include "absl/memory/memory.h" +#include "absl/status/internal/status_internal.h" #include "absl/status/status_payload_printer.h" #include "absl/strings/escaping.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/strings/str_split.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "absl/types/span.h" namespace absl { ABSL_NAMESPACE_BEGIN diff --git a/absl/status/status_payload_printer.cc b/absl/status/status_payload_printer.cc index a47aea11c2d..98401e90722 100644 --- a/absl/status/status_payload_printer.cc +++ b/absl/status/status_payload_printer.cc @@ -13,9 +13,7 @@ // limitations under the License. #include "absl/status/status_payload_printer.h" -#include - -#include "absl/base/attributes.h" +#include "absl/base/config.h" #include "absl/base/internal/atomic_hook.h" namespace absl { diff --git a/absl/status/status_test.cc b/absl/status/status_test.cc index 898a9cb202f..6d3cf6fa516 100644 --- a/absl/status/status_test.cc +++ b/absl/status/status_test.cc @@ -16,8 +16,14 @@ #include +#include +#include +#include +#include + #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/strings/cord.h" #include "absl/strings/str_cat.h" namespace { diff --git a/absl/status/statusor.cc b/absl/status/statusor.cc index 96642b340fb..bfad75efe8f 100644 --- a/absl/status/statusor.cc +++ b/absl/status/statusor.cc @@ -17,7 +17,9 @@ #include #include "absl/base/call_once.h" +#include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" +#include "absl/status/internal/statusor_internal.h" #include "absl/status/status.h" #include "absl/strings/str_cat.h" diff --git a/absl/status/statusor_test.cc b/absl/status/statusor_test.cc index e65f5d27a16..b4967e46139 100644 --- a/absl/status/statusor_test.cc +++ b/absl/status/statusor_test.cc @@ -15,11 +15,14 @@ #include "absl/status/statusor.h" #include +#include #include +#include #include #include #include #include +#include #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -28,6 +31,7 @@ #include "absl/status/status.h" #include "absl/strings/string_view.h" #include "absl/types/any.h" +#include "absl/types/variant.h" #include "absl/utility/utility.h" namespace { From c4ce9f74fefc9ba789ec3fb30f08c5263f71b8f4 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Thu, 10 Aug 2023 08:07:37 -0700 Subject: [PATCH 0158/1238] Use the supported method for detecting RTTI in Clang: ABSL_HAVE_FEATURE(cxx_rtti) PiperOrigin-RevId: 555495363 Change-Id: I4f38bbffe1195ebdf26d7ed3bc92bc865dc8dd17 --- absl/base/config.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/absl/base/config.h b/absl/base/config.h index caa74787adc..479a5a87e1c 100644 --- a/absl/base/config.h +++ b/absl/base/config.h @@ -837,11 +837,16 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || // RTTI support. #ifdef ABSL_INTERNAL_HAS_RTTI #error ABSL_INTERNAL_HAS_RTTI cannot be directly set -#elif (defined(__GNUC__) && defined(__GXX_RTTI)) || \ - (defined(_MSC_VER) && defined(_CPPRTTI)) || \ - (!defined(__GNUC__) && !defined(_MSC_VER)) +#elif ABSL_HAVE_FEATURE(cxx_rtti) #define ABSL_INTERNAL_HAS_RTTI 1 -#endif // !defined(__GNUC__) || defined(__GXX_RTTI) +#elif defined(__GNUC__) && defined(__GXX_RTTI) +#define ABSL_INTERNAL_HAS_RTTI 1 +#elif defined(_MSC_VER) && defined(_CPPRTTI) +#define ABSL_INTERNAL_HAS_RTTI 1 +#elif !defined(__GNUC__) && !defined(_MSC_VER) +// Unknown compiler, default to RTTI +#define ABSL_INTERNAL_HAS_RTTI 1 +#endif // ABSL_INTERNAL_HAVE_SSE is used for compile-time detection of SSE support. // See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html for an overview of From baa0a5cd7ad9f3e25d4d149e0a7d5ae8f66b6b15 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 10 Aug 2023 09:05:36 -0700 Subject: [PATCH 0159/1238] Add ATTRIBUTE_LIFETIME_BOUND to Cord iterator methods PiperOrigin-RevId: 555515105 Change-Id: I00929a869880cddd932ed2a08adb8f762a582738 --- absl/strings/cord.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/absl/strings/cord.h b/absl/strings/cord.h index 1753991d773..8a37df9617c 100644 --- a/absl/strings/cord.h +++ b/absl/strings/cord.h @@ -515,7 +515,7 @@ class Cord { // absl::string_view s) { // return std::find(c.chunk_begin(), c.chunk_end(), s); // } - ChunkIterator chunk_begin() const; + ChunkIterator chunk_begin() const ABSL_ATTRIBUTE_LIFETIME_BOUND; // Cord::chunk_end() // @@ -524,7 +524,7 @@ class Cord { // Generally, prefer using `Cord::Chunks()` within a range-based for loop for // iterating over the chunks of a Cord. This method may be useful for getting // a `ChunkIterator` where range-based for-loops may not be available. - ChunkIterator chunk_end() const; + ChunkIterator chunk_end() const ABSL_ATTRIBUTE_LIFETIME_BOUND; //---------------------------------------------------------------------------- // Cord::ChunkRange @@ -578,7 +578,7 @@ class Cord { // // The temporary Cord returned by CordFactory has been destroyed! // } // } - ChunkRange Chunks() const; + ChunkRange Chunks() const ABSL_ATTRIBUTE_LIFETIME_BOUND; //---------------------------------------------------------------------------- // Cord::CharIterator @@ -658,7 +658,7 @@ class Cord { // Generally, prefer using `Cord::Chars()` within a range-based for loop for // iterating over the chunks of a Cord. This method may be useful for getting // a `CharIterator` where range-based for-loops may not be available. - CharIterator char_begin() const; + CharIterator char_begin() const ABSL_ATTRIBUTE_LIFETIME_BOUND; // Cord::char_end() // @@ -667,7 +667,7 @@ class Cord { // Generally, prefer using `Cord::Chars()` within a range-based for loop for // iterating over the chunks of a Cord. This method may be useful for getting // a `CharIterator` where range-based for-loops are not useful. - CharIterator char_end() const; + CharIterator char_end() const ABSL_ATTRIBUTE_LIFETIME_BOUND; // Cord::CharRange // @@ -719,7 +719,7 @@ class Cord { // // The temporary Cord returned by CordFactory has been destroyed! // } // } - CharRange Chars() const; + CharRange Chars() const ABSL_ATTRIBUTE_LIFETIME_BOUND; // Cord::operator[] // From 06fded412db6e2a6c0b439c468757e9f91fac6d0 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Thu, 10 Aug 2023 13:28:45 -0700 Subject: [PATCH 0160/1238] Add StdcppWaiter to the end of the list of waiter implementations Since ABSL_INTERNAL_HAVE_STDCPP_WAITER is defined on all systems it is effectively a fallback. I left the condition there in case we have to disable it on some platform in the future. PiperOrigin-RevId: 555629066 Change-Id: I76ca78c7f36d1d02dc4950a44c66903a2aaf2a52 --- absl/synchronization/internal/waiter.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/absl/synchronization/internal/waiter.h b/absl/synchronization/internal/waiter.h index 1a8b0b83f62..6ba204bea0a 100644 --- a/absl/synchronization/internal/waiter.h +++ b/absl/synchronization/internal/waiter.h @@ -40,6 +40,8 @@ #define ABSL_WAITER_MODE ABSL_WAITER_MODE_SEM #elif defined(ABSL_INTERNAL_HAVE_PTHREAD_WAITER) #define ABSL_WAITER_MODE ABSL_WAITER_MODE_CONDVAR +#elif defined(ABSL_INTERNAL_HAVE_STDCPP_WAITER) +#define ABSL_WAITER_MODE ABSL_WAITER_MODE_STDCPP #else #error ABSL_WAITER_MODE is undefined #endif From a2639e312fae461cb9c6845fac3cfcc2b440a909 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 10 Aug 2023 16:24:10 -0700 Subject: [PATCH 0161/1238] Fixed shared Windows build in Chrome when building MediaPipe. The MediaPipe library calls absl::SleepFor() but that causes linker errors in Chrome's (non-production) shared library build because AbslInternalSleepFor isn't exported. PiperOrigin-RevId: 555699667 Change-Id: I95033857ec13ed72ff2a80001878b5e35bbeee91 --- absl/time/clock.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/absl/time/clock.h b/absl/time/clock.h index 5fe244d6381..3cdc55a7652 100644 --- a/absl/time/clock.h +++ b/absl/time/clock.h @@ -22,6 +22,7 @@ #ifndef ABSL_TIME_CLOCK_H_ #define ABSL_TIME_CLOCK_H_ +#include "absl/base/config.h" #include "absl/base/macros.h" #include "absl/time/time.h" @@ -64,7 +65,8 @@ ABSL_NAMESPACE_END // By changing our extension points to be extern "C", we dodge this // check. extern "C" { -void ABSL_INTERNAL_C_SYMBOL(AbslInternalSleepFor)(absl::Duration duration); +ABSL_DLL void ABSL_INTERNAL_C_SYMBOL(AbslInternalSleepFor)( + absl::Duration duration); } // extern "C" inline void absl::SleepFor(absl::Duration duration) { From 9d05d379aa1e1b56721d23185f5c8634983f2d56 Mon Sep 17 00:00:00 2001 From: Dmitri Gribenko Date: Fri, 11 Aug 2023 04:24:13 -0700 Subject: [PATCH 0162/1238] Include what you spell PiperOrigin-RevId: 555894810 Change-Id: I349c94e7c6e7ba1dbd817aa8e4340c1dada84654 --- absl/container/BUILD.bazel | 4 ++-- absl/container/CMakeLists.txt | 4 ++-- absl/container/internal/layout_test.cc | 7 +++++- .../internal/raw_hash_set_allocator_test.cc | 10 +++++++- absl/flags/BUILD.bazel | 2 +- absl/flags/CMakeLists.txt | 1 - absl/flags/internal/usage.cc | 5 ++++ absl/hash/BUILD.bazel | 4 ++++ absl/hash/CMakeLists.txt | 14 +++++++---- absl/hash/hash_benchmark.cc | 6 +++++ absl/hash/hash_test.cc | 24 +++++++------------ absl/time/duration.cc | 6 ++--- 12 files changed, 56 insertions(+), 31 deletions(-) diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel index f22da59a376..a1f6fd4f938 100644 --- a/absl/container/BUILD.bazel +++ b/absl/container/BUILD.bazel @@ -710,7 +710,7 @@ cc_test( deps = [ ":raw_hash_set", ":tracked", - "//absl/base:core_headers", + "//absl/base:config", "@com_google_googletest//:gtest_main", ], ) @@ -741,9 +741,9 @@ cc_test( deps = [ ":layout", "//absl/base:config", - "//absl/base:core_headers", "//absl/log:check", "//absl/types:span", + "//absl/utility", "@com_google_googletest//:gtest_main", ], ) diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt index 39d95e029ea..f3443a6632e 100644 --- a/absl/container/CMakeLists.txt +++ b/absl/container/CMakeLists.txt @@ -754,9 +754,9 @@ absl_cc_test( COPTS ${ABSL_TEST_COPTS} DEPS + absl::config absl::raw_hash_set absl::tracked - absl::core_headers GTest::gmock_main ) @@ -789,8 +789,8 @@ absl_cc_test( absl::layout absl::check absl::config - absl::core_headers absl::span + absl::utility GTest::gmock_main ) diff --git a/absl/container/internal/layout_test.cc b/absl/container/internal/layout_test.cc index ce599ce79f1..ae55cf7e51c 100644 --- a/absl/container/internal/layout_test.cc +++ b/absl/container/internal/layout_test.cc @@ -19,8 +19,12 @@ #include #include +#include +#include #include -#include +#include +#include +#include #include #include "gmock/gmock.h" @@ -28,6 +32,7 @@ #include "absl/base/config.h" #include "absl/log/check.h" #include "absl/types/span.h" +#include "absl/utility/utility.h" namespace absl { ABSL_NAMESPACE_BEGIN diff --git a/absl/container/internal/raw_hash_set_allocator_test.cc b/absl/container/internal/raw_hash_set_allocator_test.cc index e73f53fd637..53cc5180a25 100644 --- a/absl/container/internal/raw_hash_set_allocator_test.cc +++ b/absl/container/internal/raw_hash_set_allocator_test.cc @@ -12,10 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include +#include +#include #include -#include +#include +#include +#include +#include +#include #include "gtest/gtest.h" +#include "absl/base/config.h" #include "absl/container/internal/raw_hash_set.h" #include "absl/container/internal/tracked.h" diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel index 50bf387cd6b..65577a9be24 100644 --- a/absl/flags/BUILD.bazel +++ b/absl/flags/BUILD.bazel @@ -266,8 +266,8 @@ cc_library( ":reflection", "//absl/base:config", "//absl/base:core_headers", - "//absl/container:flat_hash_map", "//absl/strings", + "//absl/synchronization", ], ) diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt index b20463f50bb..a535b55e843 100644 --- a/absl/flags/CMakeLists.txt +++ b/absl/flags/CMakeLists.txt @@ -243,7 +243,6 @@ absl_cc_library( absl::flags_private_handle_accessor absl::flags_program_name absl::flags_reflection - absl::flat_hash_map absl::strings absl::synchronization ) diff --git a/absl/flags/internal/usage.cc b/absl/flags/internal/usage.cc index 13852e14678..8b169bcdc2c 100644 --- a/absl/flags/internal/usage.cc +++ b/absl/flags/internal/usage.cc @@ -27,7 +27,10 @@ #include #include +#include "absl/base/attributes.h" #include "absl/base/config.h" +#include "absl/base/const_init.h" +#include "absl/base/thread_annotations.h" #include "absl/flags/commandlineflag.h" #include "absl/flags/flag.h" #include "absl/flags/internal/flag.h" @@ -40,6 +43,8 @@ #include "absl/strings/str_cat.h" #include "absl/strings/str_split.h" #include "absl/strings/string_view.h" +#include "absl/strings/strip.h" +#include "absl/synchronization/mutex.h" // Dummy global variables to prevent anyone else defining these. bool FLAGS_help = false; diff --git a/absl/hash/BUILD.bazel b/absl/hash/BUILD.bazel index 4346fc4954e..a520ae62f53 100644 --- a/absl/hash/BUILD.bazel +++ b/absl/hash/BUILD.bazel @@ -85,9 +85,13 @@ cc_test( "//absl/container:flat_hash_set", "//absl/container:node_hash_map", "//absl/container:node_hash_set", + "//absl/memory", "//absl/meta:type_traits", "//absl/numeric:int128", "//absl/strings:cord_test_helpers", + "//absl/strings:string_view", + "//absl/types:optional", + "//absl/types:variant", "@com_google_googletest//:gtest_main", ], ) diff --git a/absl/hash/CMakeLists.txt b/absl/hash/CMakeLists.txt index 65fd2a5f70e..438c1cda85f 100644 --- a/absl/hash/CMakeLists.txt +++ b/absl/hash/CMakeLists.txt @@ -68,18 +68,22 @@ absl_cc_test( COPTS ${ABSL_TEST_COPTS} DEPS + absl::btree absl::cord_test_helpers - absl::hash - absl::hash_testing absl::core_headers - absl::btree absl::flat_hash_map absl::flat_hash_set + absl::hash + absl::hash_testing + absl::int128 + absl::memory + absl::meta absl::node_hash_map absl::node_hash_set + absl::optional absl::spy_hash_state - absl::meta - absl::int128 + absl::string_view + absl::variant GTest::gmock_main ) diff --git a/absl/hash/hash_benchmark.cc b/absl/hash/hash_benchmark.cc index 8712a01ccaa..916fb620c6b 100644 --- a/absl/hash/hash_benchmark.cc +++ b/absl/hash/hash_benchmark.cc @@ -12,7 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include +#include +#include +#include +#include #include +#include #include #include #include diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc index a0e2e4a7113..111f375b70c 100644 --- a/absl/hash/hash_test.cc +++ b/absl/hash/hash_test.cc @@ -17,42 +17,36 @@ #include #include #include +#include #include +#include #include -#include -#include #include #include -#include +#include #include -#include -#include #include -#include -#include +#include #include #include #include #include #include -#include #include #include -#include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/container/btree_map.h" -#include "absl/container/btree_set.h" -#include "absl/container/flat_hash_map.h" +#include "absl/base/config.h" #include "absl/container/flat_hash_set.h" -#include "absl/container/node_hash_map.h" -#include "absl/container/node_hash_set.h" #include "absl/hash/hash_testing.h" #include "absl/hash/internal/hash_test.h" #include "absl/hash/internal/spy_hash_state.h" +#include "absl/memory/memory.h" #include "absl/meta/type_traits.h" -#include "absl/numeric/int128.h" #include "absl/strings/cord_test_helpers.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "absl/types/variant.h" #ifdef ABSL_HAVE_STD_STRING_VIEW #include diff --git a/absl/time/duration.cc b/absl/time/duration.cc index 634e5d58455..bdb16e21092 100644 --- a/absl/time/duration.cc +++ b/absl/time/duration.cc @@ -55,8 +55,7 @@ #include #include -#include -#include +#include // NOLINT(build/c++11) #include #include #include @@ -66,8 +65,9 @@ #include #include +#include "absl/base/attributes.h" #include "absl/base/casts.h" -#include "absl/base/macros.h" +#include "absl/base/config.h" #include "absl/numeric/int128.h" #include "absl/strings/string_view.h" #include "absl/strings/strip.h" From 861e53c8f075c8c4d67bd4c82217c57239fc97cf Mon Sep 17 00:00:00 2001 From: Evan Brown Date: Fri, 11 Aug 2023 13:18:39 -0700 Subject: [PATCH 0163/1238] Add missing includes in raw_hash_set.h. PiperOrigin-RevId: 556065631 Change-Id: I7e69b1495946c42fab185a1bc23e9564bfbd5e41 --- absl/container/internal/raw_hash_set.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 39552b0446e..fb91fc3cb97 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -183,6 +183,7 @@ #include #include #include +#include #include #include #include @@ -191,10 +192,13 @@ #include #include +#include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/internal/endian.h" #include "absl/base/internal/raw_logging.h" +#include "absl/base/macros.h" #include "absl/base/optimization.h" +#include "absl/base/options.h" #include "absl/base/port.h" #include "absl/base/prefetch.h" #include "absl/container/internal/common.h" From 2890217b725a20a8b785b041bc7198fa2ec74870 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 14 Aug 2023 09:27:07 -0700 Subject: [PATCH 0164/1238] Speed up kTotalMorePrecise mode of Cord::EstimatedMemoryUsage() by about 25% by avoiding a redundant map lookup. PiperOrigin-RevId: 556816759 Change-Id: I971e428bf12d91720df72a91cc0bdf0513b0c270 --- absl/strings/cord_analysis.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/absl/strings/cord_analysis.cc b/absl/strings/cord_analysis.cc index fa1a0cc8c8e..e3824281f7c 100644 --- a/absl/strings/cord_analysis.cc +++ b/absl/strings/cord_analysis.cc @@ -67,8 +67,7 @@ struct RawUsage { std::unordered_set counted; void Add(size_t size, CordRepRef repref) { - if (counted.find(repref.rep) == counted.end()) { - counted.insert(repref.rep); + if (counted.insert(repref.rep).second) { total += size; } } From e8f98b24eb3f16f0964c63d1bec9cf1bc3c2606e Mon Sep 17 00:00:00 2001 From: Andy Getzendanner Date: Mon, 14 Aug 2023 13:42:14 -0700 Subject: [PATCH 0165/1238] An FNMatch helper for upcoming functionality. PiperOrigin-RevId: 556898736 Change-Id: Ic310bab090d6a92036034058520ed6641be86fbc --- CMake/AbseilDll.cmake | 2 ++ absl/log/CMakeLists.txt | 31 ++++++++++++++++ absl/log/internal/BUILD.bazel | 23 ++++++++++++ absl/log/internal/fnmatch.cc | 53 +++++++++++++++++++++++++++ absl/log/internal/fnmatch.h | 35 ++++++++++++++++++ absl/log/internal/fnmatch_test.cc | 59 +++++++++++++++++++++++++++++++ 6 files changed, 203 insertions(+) create mode 100644 absl/log/internal/fnmatch.cc create mode 100644 absl/log/internal/fnmatch.h create mode 100644 absl/log/internal/fnmatch_test.cc diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index f0d984ae190..a5a512bdbfb 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake @@ -163,6 +163,8 @@ set(ABSL_INTERNAL_DLL_FILES "log/internal/conditions.cc" "log/internal/conditions.h" "log/internal/config.h" + "log/internal/fnmatch.h" + "log/internal/fnmatch.cc" "log/internal/globals.cc" "log/internal/globals.h" "log/internal/log_format.cc" diff --git a/absl/log/CMakeLists.txt b/absl/log/CMakeLists.txt index 2fc34d01c9c..2c3307dca1e 100644 --- a/absl/log/CMakeLists.txt +++ b/absl/log/CMakeLists.txt @@ -671,6 +671,22 @@ absl_cc_library( PUBLIC ) +absl_cc_library( + NAME + log_internal_fnmatch + SRCS + "internal/fnmatch.cc" + HDRS + "internal/fnmatch.h" + COPTS + ${ABSL_DEFAULT_COPTS} + LINKOPTS + ${ABSL_DEFAULT_LINKOPTS} + DEPS + absl::config + absl::strings +) + # Test targets absl_cc_test( @@ -1041,3 +1057,18 @@ absl_cc_test( GTest::gmock GTest::gtest_main ) + +absl_cc_test( + NAME + internal_fnmatch_test + SRCS + "internal/fnmatch_test.cc" + COPTS + ${ABSL_TEST_COPTS} + LINKOPTS + ${ABSL_DEFAULT_LINKOPTS} + DEPS + absl::log_internal_fnmatch + GTest::gmock + GTest::gtest_main +) \ No newline at end of file diff --git a/absl/log/internal/BUILD.bazel b/absl/log/internal/BUILD.bazel index 555c5e5ce38..b8077a77d1a 100644 --- a/absl/log/internal/BUILD.bazel +++ b/absl/log/internal/BUILD.bazel @@ -357,6 +357,18 @@ cc_library( ], ) +cc_library( + name = "fnmatch", + srcs = ["fnmatch.cc"], + hdrs = ["fnmatch.h"], + copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [ + "//absl/base:config", + "//absl/strings", + ], +) + # Test targets cc_test( name = "stderr_log_sink_test", @@ -381,3 +393,14 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "fnmatch_test", + srcs = ["fnmatch_test.cc"], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [ + ":fnmatch", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/absl/log/internal/fnmatch.cc b/absl/log/internal/fnmatch.cc new file mode 100644 index 00000000000..be4e4b1cd5d --- /dev/null +++ b/absl/log/internal/fnmatch.cc @@ -0,0 +1,53 @@ +// Copyright 2023 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/log/internal/fnmatch.h" + +#include "absl/base/config.h" +#include "absl/strings/string_view.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace log_internal { +bool FNMatch(absl::string_view pattern, absl::string_view str) { + while (true) { + if (pattern.empty()) { + // `pattern` is exhausted; succeed if all of `str` was consumed matching + // it. + return str.empty(); + } + if (str.empty()) { + // `str` is exhausted; succeed if `pattern` is empty or all '*'s. + return pattern.find_first_not_of('*') == pattern.npos; + } + if (pattern.front() == '*') { + pattern.remove_prefix(1); + if (pattern.empty()) return true; + do { + if (FNMatch(pattern, str)) return true; + str.remove_prefix(1); + } while (!str.empty()); + return false; + } + if (pattern.front() == '?' || pattern.front() == str.front()) { + pattern.remove_prefix(1); + str.remove_prefix(1); + continue; + } + return false; + } +} +} // namespace log_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/absl/log/internal/fnmatch.h b/absl/log/internal/fnmatch.h new file mode 100644 index 00000000000..4ea147cc6f7 --- /dev/null +++ b/absl/log/internal/fnmatch.h @@ -0,0 +1,35 @@ +// Copyright 2023 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_LOG_INTERNAL_FNMATCH_H_ +#define ABSL_LOG_INTERNAL_FNMATCH_H_ + +#include "absl/base/config.h" +#include "absl/strings/string_view.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace log_internal { +// Like POSIX `fnmatch`, but: +// * accepts `string_view` +// * does not allocate any dynamic memory +// * only supports * and ? wildcards and not bracket expressions [...] +// * wildcards may match / +// * no backslash-escaping +bool FNMatch(absl::string_view pattern, absl::string_view str); +} // namespace log_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_LOG_INTERNAL_FNMATCH_H_ diff --git a/absl/log/internal/fnmatch_test.cc b/absl/log/internal/fnmatch_test.cc new file mode 100644 index 00000000000..e16a64ece16 --- /dev/null +++ b/absl/log/internal/fnmatch_test.cc @@ -0,0 +1,59 @@ +// Copyright 2023 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/log/internal/fnmatch.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace { +using ::testing::IsFalse; +using ::testing::IsTrue; + +TEST(FNMatchTest, Works) { + using absl::log_internal::FNMatch; + EXPECT_THAT(FNMatch("foo", "foo"), IsTrue()); + EXPECT_THAT(FNMatch("foo", "bar"), IsFalse()); + EXPECT_THAT(FNMatch("foo", "fo"), IsFalse()); + EXPECT_THAT(FNMatch("foo", "foo2"), IsFalse()); + EXPECT_THAT(FNMatch("bar/foo.ext", "bar/foo.ext"), IsTrue()); + EXPECT_THAT(FNMatch("*ba*r/fo*o.ext*", "bar/foo.ext"), IsTrue()); + EXPECT_THAT(FNMatch("bar/foo.ext", "bar/baz.ext"), IsFalse()); + EXPECT_THAT(FNMatch("bar/foo.ext", "bar/foo"), IsFalse()); + EXPECT_THAT(FNMatch("bar/foo.ext", "bar/foo.ext.zip"), IsFalse()); + EXPECT_THAT(FNMatch("ba?/*.ext", "bar/foo.ext"), IsTrue()); + EXPECT_THAT(FNMatch("ba?/*.ext", "baZ/FOO.ext"), IsTrue()); + EXPECT_THAT(FNMatch("ba?/*.ext", "barr/foo.ext"), IsFalse()); + EXPECT_THAT(FNMatch("ba?/*.ext", "bar/foo.ext2"), IsFalse()); + EXPECT_THAT(FNMatch("ba?/*", "bar/foo.ext2"), IsTrue()); + EXPECT_THAT(FNMatch("ba?/*", "bar/"), IsTrue()); + EXPECT_THAT(FNMatch("ba?/?", "bar/"), IsFalse()); + EXPECT_THAT(FNMatch("ba?/*", "bar"), IsFalse()); + EXPECT_THAT(FNMatch("?x", "zx"), IsTrue()); + EXPECT_THAT(FNMatch("*b", "aab"), IsTrue()); + EXPECT_THAT(FNMatch("a*b", "aXb"), IsTrue()); + EXPECT_THAT(FNMatch("", ""), IsTrue()); + EXPECT_THAT(FNMatch("", "a"), IsFalse()); + EXPECT_THAT(FNMatch("ab*", "ab"), IsTrue()); + EXPECT_THAT(FNMatch("ab**", "ab"), IsTrue()); + EXPECT_THAT(FNMatch("ab*?", "ab"), IsFalse()); + EXPECT_THAT(FNMatch("*", "bbb"), IsTrue()); + EXPECT_THAT(FNMatch("*", ""), IsTrue()); + EXPECT_THAT(FNMatch("?", ""), IsFalse()); + EXPECT_THAT(FNMatch("***", "**p"), IsTrue()); + EXPECT_THAT(FNMatch("**", "*"), IsTrue()); + EXPECT_THAT(FNMatch("*?", "*"), IsTrue()); +} + +} // namespace From 71910654b4452f13f543f7c7f433fb3c6d932c33 Mon Sep 17 00:00:00 2001 From: Hannah Lin Date: Mon, 14 Aug 2023 14:34:51 -0700 Subject: [PATCH 0166/1238] Always inline prefetches. PiperOrigin-RevId: 556914455 Change-Id: Ic0169e1099384eefe285e6d354e448eb5189e397 --- absl/base/prefetch.h | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/absl/base/prefetch.h b/absl/base/prefetch.h index de7a180d607..6fd2a8207ea 100644 --- a/absl/base/prefetch.h +++ b/absl/base/prefetch.h @@ -24,6 +24,7 @@ #ifndef ABSL_BASE_PREFETCH_H_ #define ABSL_BASE_PREFETCH_H_ +#include "absl/base/attributes.h" #include "absl/base/config.h" #if defined(ABSL_INTERNAL_HAVE_SSE) @@ -140,15 +141,18 @@ void PrefetchToLocalCacheForWrite(const void* addr); // See __builtin_prefetch: // https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html. // -inline void PrefetchToLocalCache(const void* addr) { +ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCache( + const void* addr) { __builtin_prefetch(addr, 0, 3); } -inline void PrefetchToLocalCacheNta(const void* addr) { +ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheNta( + const void* addr) { __builtin_prefetch(addr, 0, 0); } -inline void PrefetchToLocalCacheForWrite(const void* addr) { +ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheForWrite( + const void* addr) { // [x86] gcc/clang don't generate PREFETCHW for __builtin_prefetch(.., 1) // unless -march=broadwell or newer; this is not generally the default, so we // manually emit prefetchw. PREFETCHW is recognized as a no-op on older Intel @@ -164,15 +168,18 @@ inline void PrefetchToLocalCacheForWrite(const void* addr) { #define ABSL_HAVE_PREFETCH 1 -inline void PrefetchToLocalCache(const void* addr) { +ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCache( + const void* addr) { _mm_prefetch(reinterpret_cast(addr), _MM_HINT_T0); } -inline void PrefetchToLocalCacheNta(const void* addr) { +ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheNta( + const void* addr) { _mm_prefetch(reinterpret_cast(addr), _MM_HINT_NTA); } -inline void PrefetchToLocalCacheForWrite(const void* addr) { +ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheForWrite( + const void* addr) { #if defined(_MM_HINT_ET0) _mm_prefetch(reinterpret_cast(addr), _MM_HINT_ET0); #elif !defined(_MSC_VER) && defined(__x86_64__) @@ -186,9 +193,12 @@ inline void PrefetchToLocalCacheForWrite(const void* addr) { #else -inline void PrefetchToLocalCache(const void* addr) {} -inline void PrefetchToLocalCacheNta(const void* addr) {} -inline void PrefetchToLocalCacheForWrite(const void* addr) {} +ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCache( + const void* addr) {} +ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheNta( + const void* addr) {} +ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheForWrite( + const void* addr) {} #endif From 32f414f4f781b55faede067f1d996f5e8dc885aa Mon Sep 17 00:00:00 2001 From: Andy Getzendanner Date: Mon, 14 Aug 2023 23:44:27 -0700 Subject: [PATCH 0167/1238] Benchmark FNMatch, and use the greedy algorithm with better time and space complexity and no recursion (from 233 to 53.8 ns). PiperOrigin-RevId: 557032497 Change-Id: I7a92feb3d79fa3dc1b7aa5b1097e53a9dae17c81 --- absl/log/BUILD.bazel | 4 +-- absl/log/internal/BUILD.bazel | 12 +++++++ absl/log/internal/fnmatch.cc | 48 ++++++++++++++++++-------- absl/log/internal/fnmatch_benchmark.cc | 29 ++++++++++++++++ 4 files changed, 77 insertions(+), 16 deletions(-) create mode 100644 absl/log/internal/fnmatch_benchmark.cc diff --git a/absl/log/BUILD.bazel b/absl/log/BUILD.bazel index e1410637812..2f393554a87 100644 --- a/absl/log/BUILD.bazel +++ b/absl/log/BUILD.bazel @@ -573,9 +573,9 @@ cc_test( ], ) -cc_binary( +cc_test( name = "log_benchmark", - testonly = 1, + size = "small", srcs = ["log_benchmark.cc"], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, diff --git a/absl/log/internal/BUILD.bazel b/absl/log/internal/BUILD.bazel index b8077a77d1a..d7a30c9ed8d 100644 --- a/absl/log/internal/BUILD.bazel +++ b/absl/log/internal/BUILD.bazel @@ -404,3 +404,15 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "fnmatch_benchmark", + srcs = ["fnmatch_benchmark.cc"], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + tags = ["benchmark"], + deps = [ + ":fnmatch", + "@com_github_google_benchmark//:benchmark_main", + ], +) diff --git a/absl/log/internal/fnmatch.cc b/absl/log/internal/fnmatch.cc index be4e4b1cd5d..26e1e57fe43 100644 --- a/absl/log/internal/fnmatch.cc +++ b/absl/log/internal/fnmatch.cc @@ -14,6 +14,8 @@ #include "absl/log/internal/fnmatch.h" +#include + #include "absl/base/config.h" #include "absl/strings/string_view.h" @@ -21,31 +23,49 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace log_internal { bool FNMatch(absl::string_view pattern, absl::string_view str) { + bool in_wildcard_match = false; while (true) { if (pattern.empty()) { // `pattern` is exhausted; succeed if all of `str` was consumed matching // it. - return str.empty(); + return in_wildcard_match || str.empty(); } if (str.empty()) { // `str` is exhausted; succeed if `pattern` is empty or all '*'s. return pattern.find_first_not_of('*') == pattern.npos; } - if (pattern.front() == '*') { - pattern.remove_prefix(1); - if (pattern.empty()) return true; - do { - if (FNMatch(pattern, str)) return true; + switch (pattern.front()) { + case '*': + pattern.remove_prefix(1); + in_wildcard_match = true; + break; + case '?': + pattern.remove_prefix(1); str.remove_prefix(1); - } while (!str.empty()); - return false; - } - if (pattern.front() == '?' || pattern.front() == str.front()) { - pattern.remove_prefix(1); - str.remove_prefix(1); - continue; + break; + default: + if (in_wildcard_match) { + absl::string_view fixed_portion = pattern; + const size_t end = fixed_portion.find_first_of("*?"); + if (end != fixed_portion.npos) { + fixed_portion = fixed_portion.substr(0, end); + } + const size_t match = str.find(fixed_portion); + if (match == str.npos) { + return false; + } + pattern.remove_prefix(fixed_portion.size()); + str.remove_prefix(match + fixed_portion.size()); + in_wildcard_match = false; + } else { + if (pattern.front() != str.front()) { + return false; + } + pattern.remove_prefix(1); + str.remove_prefix(1); + } + break; } - return false; } } } // namespace log_internal diff --git a/absl/log/internal/fnmatch_benchmark.cc b/absl/log/internal/fnmatch_benchmark.cc new file mode 100644 index 00000000000..f062ba20d45 --- /dev/null +++ b/absl/log/internal/fnmatch_benchmark.cc @@ -0,0 +1,29 @@ +// Copyright 2023 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/log/internal/fnmatch.h" +#include "benchmark/benchmark.h" + +namespace { +void BM_FNMatch(benchmark::State& state) { + while (state.KeepRunning()) { + bool ret = + absl::log_internal::FNMatch("*?*asdf*?*we???asdf**asdf*we", + "QWERFASVWERASDFWEDFASDasdfQWERGFWASDERREWF" + "weHOOasdf@#$%TW#ZSERasdfQW#REGTZSERERwe"); + benchmark::DoNotOptimize(ret); + } +} +BENCHMARK(BM_FNMatch); +} // namespace From 79f3dec06eb5adcc151a68947803f055e1679666 Mon Sep 17 00:00:00 2001 From: Anuraag Agrawal Date: Tue, 15 Aug 2023 10:03:11 -0700 Subject: [PATCH 0168/1238] PR #1509: Allow building when targeting WASI Imported from GitHub PR https://github.com/abseil/abseil-cpp/pull/1509 WASI is similar to emscripten, providing a syscall layer to WebAssembly focused on server side applications. There are some config knobs that are in place to allow building the repo for emscripten which also need to support wasi (as built with LLVM). Aside from that, there are still some features it supports less than escripten, for example related to signals, causing the build to be even more limited for it. Merge ec9fa081609687035005dfdafd312754f31c3fbb into 861e53c8f075c8c4d67bd4c82217c57239fc97cf Merging this change closes #1509 COPYBARA_INTEGRATE_REVIEW=https://github.com/abseil/abseil-cpp/pull/1509 from anuraaga:wasi-sdk-build ec9fa081609687035005dfdafd312754f31c3fbb PiperOrigin-RevId: 557166498 Change-Id: Ic51149d8b092fd888c9a5c383275257fc8ff4232 --- absl/base/config.h | 40 +++++++++++++----------- absl/base/internal/thread_identity.cc | 14 ++++++--- absl/debugging/failure_signal_handler.cc | 2 +- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/absl/base/config.h b/absl/base/config.h index 479a5a87e1c..65a71199b4f 100644 --- a/absl/base/config.h +++ b/absl/base/config.h @@ -332,8 +332,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #ifdef ABSL_HAVE_INTRINSIC_INT128 #error ABSL_HAVE_INTRINSIC_INT128 cannot be directly set #elif defined(__SIZEOF_INT128__) -#if (defined(__clang__) && !defined(_WIN32)) || \ - (defined(__CUDACC__) && __CUDACC_VER_MAJOR__ >= 9) || \ +#if (defined(__clang__) && !defined(_WIN32)) || \ + (defined(__CUDACC__) && __CUDACC_VER_MAJOR__ >= 9) || \ (defined(__GNUC__) && !defined(__clang__) && !defined(__CUDACC__)) #define ABSL_HAVE_INTRINSIC_INT128 1 #elif defined(__CUDACC__) @@ -395,7 +395,7 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || // Windows _WIN32 // NaCL __native_client__ // AsmJS __asmjs__ -// WebAssembly __wasm__ +// WebAssembly (Emscripten) __EMSCRIPTEN__ // Fuchsia __Fuchsia__ // // Note that since Android defines both __ANDROID__ and __linux__, one @@ -407,11 +407,11 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || // POSIX.1-2001. #ifdef ABSL_HAVE_MMAP #error ABSL_HAVE_MMAP cannot be directly set -#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ - defined(_AIX) || defined(__ros__) || defined(__native_client__) || \ - defined(__asmjs__) || defined(__wasm__) || defined(__Fuchsia__) || \ - defined(__sun) || defined(__ASYLO__) || defined(__myriad2__) || \ - defined(__HAIKU__) || defined(__OpenBSD__) || defined(__NetBSD__) || \ +#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ + defined(_AIX) || defined(__ros__) || defined(__native_client__) || \ + defined(__asmjs__) || defined(__EMSCRIPTEN__) || defined(__Fuchsia__) || \ + defined(__sun) || defined(__ASYLO__) || defined(__myriad2__) || \ + defined(__HAIKU__) || defined(__OpenBSD__) || defined(__NetBSD__) || \ defined(__QNX__) || defined(__VXWORKS__) || defined(__hexagon__) #define ABSL_HAVE_MMAP 1 #endif @@ -484,6 +484,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || // https://sourceforge.net/p/mingw-w64/mingw-w64/ci/master/tree/mingw-w64-crt/misc/alarm.c #elif defined(__EMSCRIPTEN__) // emscripten doesn't support signals +#elif defined(__wasi__) +// WASI doesn't support signals #elif defined(__Fuchsia__) // Signals don't exist on fuchsia. #elif defined(__native_client__) @@ -536,14 +538,14 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || // and // https://github.com/llvm/llvm-project/commit/0bc451e7e137c4ccadcd3377250874f641ca514a // The second has the actually correct versions, thus, is what we copy here. -#if defined(__APPLE__) && \ - ((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ - __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101300) || \ - (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \ - __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 120000) || \ - (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \ - __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000) || \ - (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \ +#if defined(__APPLE__) && \ + ((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ + __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101300) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \ + __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 120000) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \ + __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \ __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 120000)) #define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 1 #else @@ -566,7 +568,7 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || // Checks whether C++17 std::optional is available. #ifdef ABSL_HAVE_STD_OPTIONAL #error "ABSL_HAVE_STD_OPTIONAL cannot be directly set." -#elif defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \ +#elif defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \ ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L && \ !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE #define ABSL_HAVE_STD_OPTIONAL 1 @@ -933,8 +935,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #if __EMSCRIPTEN_tiny__ >= 1000 #error __EMSCRIPTEN_tiny__ is too big to fit in ABSL_INTERNAL_EMSCRIPTEN_VERSION #endif -#define ABSL_INTERNAL_EMSCRIPTEN_VERSION \ - ((__EMSCRIPTEN_major__)*1000000 + (__EMSCRIPTEN_minor__)*1000 + \ +#define ABSL_INTERNAL_EMSCRIPTEN_VERSION \ + ((__EMSCRIPTEN_major__) * 1000000 + (__EMSCRIPTEN_minor__) * 1000 + \ (__EMSCRIPTEN_tiny__)) #endif #endif diff --git a/absl/base/internal/thread_identity.cc b/absl/base/internal/thread_identity.cc index 252443ebcd7..0471a25dcea 100644 --- a/absl/base/internal/thread_identity.cc +++ b/absl/base/internal/thread_identity.cc @@ -16,8 +16,12 @@ #if !defined(_WIN32) || defined(__MINGW32__) #include +#ifndef __wasi__ +// WASI does not provide this header, either way we disable use +// of signals with it below. #include #endif +#endif #include #include @@ -80,10 +84,12 @@ void SetCurrentThreadIdentity(ThreadIdentity* identity, absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey, reclaimer); -#if defined(__EMSCRIPTEN__) || defined(__MINGW32__) || defined(__hexagon__) - // Emscripten and MinGW pthread implementations does not support signals. - // See https://kripken.github.io/emscripten-site/docs/porting/pthreads.html - // for more information. +#if defined(__wasi__) || defined(__EMSCRIPTEN__) || defined(__MINGW32__) || \ + defined(__hexagon__) + // Emscripten, WASI and MinGW pthread implementations does not support + // signals. See + // https://kripken.github.io/emscripten-site/docs/porting/pthreads.html for + // more information. pthread_setspecific(thread_identity_pthread_key, reinterpret_cast(identity)); #else diff --git a/absl/debugging/failure_signal_handler.cc b/absl/debugging/failure_signal_handler.cc index 992c89c390f..570d1e504d8 100644 --- a/absl/debugging/failure_signal_handler.cc +++ b/absl/debugging/failure_signal_handler.cc @@ -54,7 +54,7 @@ #include "absl/debugging/internal/examine_stack.h" #include "absl/debugging/stacktrace.h" -#ifndef _WIN32 +#if !defined(_WIN32) && !defined(__wasi__) #define ABSL_HAVE_SIGACTION // Apple WatchOS and TVOS don't allow sigaltstack // Apple macOS has sigaltstack, but using it makes backtrace() unusable. From 334aca32051ef6ede2711487acf45d959e9bdffc Mon Sep 17 00:00:00 2001 From: Evan Brown Date: Tue, 15 Aug 2023 11:05:00 -0700 Subject: [PATCH 0169/1238] Update an old comment that refers to obsolete types. PiperOrigin-RevId: 557187112 Change-Id: I7c3e4be0ab5a7451173da7a0ded53a3d227bb093 --- absl/container/internal/raw_hash_set.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index fb91fc3cb97..678ed7eab4a 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -1906,8 +1906,8 @@ class raw_hash_set { std::swap(common(), that.common()); } else { reserve(that.size()); - // Note: this will copy elements of dense_set and unordered_set instead of - // moving them. This can be fixed if it ever becomes an issue. + // Note: this will copy keys instead of moving them. This can be fixed if + // it ever becomes an issue. for (auto& elem : that) insert(std::move(elem)); } } From 17a3ac4bcc9b16aa1ae020a2f7067008d627ad88 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 16 Aug 2023 10:08:53 -0700 Subject: [PATCH 0170/1238] Implement `Cord::Find()` and `Cord::Contains()` PiperOrigin-RevId: 557523229 Change-Id: I959c0b0b14a4a96bee396d4bc09b80328060287d --- absl/strings/cord.cc | 201 ++++++++++++++++++++++++++++++++++++-- absl/strings/cord.h | 16 +++ absl/strings/cord_test.cc | 87 +++++++++++++++++ 3 files changed, 297 insertions(+), 7 deletions(-) diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc index 0c26e37e5b6..08a165e1a0e 100644 --- a/absl/strings/cord.cc +++ b/absl/strings/cord.cc @@ -31,6 +31,7 @@ #include #include +#include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/internal/endian.h" #include "absl/base/internal/raw_logging.h" @@ -49,8 +50,10 @@ #include "absl/strings/internal/cord_rep_flat.h" #include "absl/strings/internal/cordz_update_tracker.h" #include "absl/strings/internal/resize_uninitialized.h" +#include "absl/strings/match.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" +#include "absl/strings/strip.h" #include "absl/types/optional.h" #include "absl/types/span.h" @@ -565,13 +568,9 @@ CordBuffer Cord::GetAppendBufferSlowPath(size_t block_size, size_t capacity, return CreateAppendBuffer(contents_.data_, block_size, capacity); } -void Cord::Append(const Cord& src) { - AppendImpl(src); -} +void Cord::Append(const Cord& src) { AppendImpl(src); } -void Cord::Append(Cord&& src) { - AppendImpl(std::move(src)); -} +void Cord::Append(Cord&& src) { AppendImpl(std::move(src)); } template > void Cord::Append(T&& src) { @@ -1157,6 +1156,194 @@ char Cord::operator[](size_t i) const { } } +namespace { + +// Tests whether the sequence of chunks beginning at `position` starts with +// `needle`. +// +// REQUIRES: remaining `absl::Cord` starting at `position` is greater than or +// equal to `needle.size()`. +bool IsSubstringInCordAt(absl::Cord::CharIterator position, + absl::string_view needle) { + auto haystack_chunk = absl::Cord::ChunkRemaining(position); + while (true) { + // Precondition is that `absl::Cord::ChunkRemaining(position)` is not + // empty. This assert will trigger if that is not true. + assert(!haystack_chunk.empty()); + auto min_length = std::min(haystack_chunk.size(), needle.size()); + if (!absl::ConsumePrefix(&needle, haystack_chunk.substr(0, min_length))) { + return false; + } + if (needle.empty()) { + return true; + } + absl::Cord::Advance(&position, min_length); + haystack_chunk = absl::Cord::ChunkRemaining(position); + } +} + +} // namespace + +// A few options how this could be implemented: +// (a) Flatten the Cord and find, i.e. +// haystack.Flatten().find(needle) +// For large 'haystack' (where Cord makes sense to be used), this copies +// the whole 'haystack' and can be slow. +// (b) Use std::search, i.e. +// std::search(haystack.char_begin(), haystack.char_end(), +// needle.begin(), needle.end()) +// This avoids the copy, but compares one byte at a time, and branches a +// lot every time it has to advance. It is also not possible to use +// std::search as is, because CharIterator is only an input iterator, not a +// forward iterator. +// (c) Use string_view::find in each fragment, and specifically handle fragment +// boundaries. +// +// This currently implements option (b). +absl::Cord::CharIterator absl::Cord::FindImpl(CharIterator it, + absl::string_view needle) const { + // Ensure preconditions are met by callers first. + + // Needle must not be empty. + assert(!needle.empty()); + // Haystack must be at least as large as needle. + assert(it.chunk_iterator_.bytes_remaining_ >= needle.size()); + + // Cord is a sequence of chunks. To find `needle` we go chunk by chunk looking + // for the first char of needle, up until we have advanced `N` defined as + // `haystack.size() - needle.size()`. If we find the first char of needle at + // `P` and `P` is less than `N`, we then call `IsSubstringInCordAt` to + // see if this is the needle. If not, we advance to `P + 1` and try again. + while (it.chunk_iterator_.bytes_remaining_ >= needle.size()) { + auto haystack_chunk = Cord::ChunkRemaining(it); + assert(!haystack_chunk.empty()); + // Look for the first char of `needle` in the current chunk. + auto idx = haystack_chunk.find(needle.front()); + if (idx == absl::string_view::npos) { + // No potential match in this chunk, advance past it. + Cord::Advance(&it, haystack_chunk.size()); + continue; + } + // We found the start of a potential match in the chunk. Advance the + // iterator and haystack chunk to the match the position. + Cord::Advance(&it, idx); + // Check if there is enough haystack remaining to actually have a match. + if (it.chunk_iterator_.bytes_remaining_ < needle.size()) { + break; + } + // Check if this is `needle`. + if (IsSubstringInCordAt(it, needle)) { + return it; + } + // No match, increment the iterator for the next attempt. + Cord::Advance(&it, 1); + } + // If we got here, we did not find `needle`. + return char_end(); +} + +absl::Cord::CharIterator absl::Cord::Find(absl::string_view needle) const { + if (needle.empty()) { + return char_begin(); + } + if (needle.size() > size()) { + return char_end(); + } + if (needle.size() == size()) { + return *this == needle ? char_begin() : char_end(); + } + return FindImpl(char_begin(), needle); +} + +namespace { + +// Tests whether the sequence of chunks beginning at `haystack` starts with the +// sequence of chunks beginning at `needle_begin` and extending to `needle_end`. +// +// REQUIRES: remaining `absl::Cord` starting at `position` is greater than or +// equal to `needle_end - needle_begin` and `advance`. +bool IsSubcordInCordAt(absl::Cord::CharIterator haystack, + absl::Cord::CharIterator needle_begin, + absl::Cord::CharIterator needle_end) { + while (needle_begin != needle_end) { + auto haystack_chunk = absl::Cord::ChunkRemaining(haystack); + assert(!haystack_chunk.empty()); + auto needle_chunk = absl::Cord::ChunkRemaining(needle_begin); + auto min_length = std::min(haystack_chunk.size(), needle_chunk.size()); + if (haystack_chunk.substr(0, min_length) != + needle_chunk.substr(0, min_length)) { + return false; + } + absl::Cord::Advance(&haystack, min_length); + absl::Cord::Advance(&needle_begin, min_length); + } + return true; +} + +// Tests whether the sequence of chunks beginning at `position` starts with the +// cord `needle`. +// +// REQUIRES: remaining `absl::Cord` starting at `position` is greater than or +// equal to `needle.size()`. +bool IsSubcordInCordAt(absl::Cord::CharIterator position, + const absl::Cord& needle) { + return IsSubcordInCordAt(position, needle.char_begin(), needle.char_end()); +} + +} // namespace + +absl::Cord::CharIterator absl::Cord::Find(const absl::Cord& needle) const { + if (needle.empty()) { + return char_begin(); + } + const auto needle_size = needle.size(); + if (needle_size > size()) { + return char_end(); + } + if (needle_size == size()) { + return *this == needle ? char_begin() : char_end(); + } + const auto needle_chunk = Cord::ChunkRemaining(needle.char_begin()); + auto haystack_it = char_begin(); + while (true) { + haystack_it = FindImpl(haystack_it, needle_chunk); + if (haystack_it == char_end() || + haystack_it.chunk_iterator_.bytes_remaining_ < needle_size) { + break; + } + // We found the first chunk of `needle` at `haystack_it` but not the entire + // subcord. Advance past the first chunk and check for the remainder. + auto haystack_advanced_it = haystack_it; + auto needle_it = needle.char_begin(); + Cord::Advance(&haystack_advanced_it, needle_chunk.size()); + Cord::Advance(&needle_it, needle_chunk.size()); + if (IsSubcordInCordAt(haystack_advanced_it, needle_it, needle.char_end())) { + return haystack_it; + } + Cord::Advance(&haystack_it, 1); + if (haystack_it.chunk_iterator_.bytes_remaining_ < needle_size) { + break; + } + if (haystack_it.chunk_iterator_.bytes_remaining_ == needle_size) { + // Special case, if there is exactly `needle_size` bytes remaining, the + // subcord is either at `haystack_it` or not at all. + if (IsSubcordInCordAt(haystack_it, needle)) { + return haystack_it; + } + break; + } + } + return char_end(); +} + +bool Cord::Contains(absl::string_view rhs) const { + return rhs.empty() || Find(rhs) != char_end(); +} + +bool Cord::Contains(const absl::Cord& rhs) const { + return rhs.empty() || Find(rhs) != char_end(); +} + absl::string_view Cord::FlattenSlowPath() { assert(contents_.is_tree()); size_t total_size = size(); @@ -1281,7 +1468,7 @@ static void DumpNode(CordRep* rep, bool include_data, std::ostream* os, *os << absl::CEscape(std::string(rep->flat()->Data(), rep->length)); *os << "]\n"; } else { - CordRepBtree::Dump(rep, /*label=*/ "", include_data, *os); + CordRepBtree::Dump(rep, /*label=*/"", include_data, *os); } } if (leaf) { diff --git a/absl/strings/cord.h b/absl/strings/cord.h index 8a37df9617c..0dede5c778e 100644 --- a/absl/strings/cord.h +++ b/absl/strings/cord.h @@ -396,6 +396,12 @@ class Cord { bool EndsWith(absl::string_view rhs) const; bool EndsWith(const Cord& rhs) const; + // Cord::Contains() + // + // Determines whether the Cord contains the passed string data `rhs`. + bool Contains(absl::string_view rhs) const; + bool Contains(const Cord& rhs) const; + // Cord::operator std::string() // // Converts a Cord into a `std::string()`. This operator is marked explicit to @@ -747,6 +753,14 @@ class Cord { // If the cord was already flat, the contents are not modified. absl::string_view Flatten() ABSL_ATTRIBUTE_LIFETIME_BOUND; + // Cord::Find() + // + // Returns an iterator to the first occurrance of the substring `needle`. + // + // If the substring `needle` does not occur, `Cord::char_end()` is returned. + CharIterator Find(absl::string_view needle) const; + CharIterator Find(const absl::Cord& needle) const; + // Supports absl::Cord as a sink object for absl::Format(). friend void AbslFormatFlush(absl::Cord* cord, absl::string_view part) { cord->Append(part); @@ -1028,6 +1042,8 @@ class Cord { friend class CrcCord; void SetCrcCordState(crc_internal::CrcCordState state); const crc_internal::CrcCordState* MaybeGetCrcCordState() const; + + CharIterator FindImpl(CharIterator it, absl::string_view needle) const; }; ABSL_NAMESPACE_END diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc index 51fef3167c9..36478890601 100644 --- a/absl/strings/cord_test.cc +++ b/absl/strings/cord_test.cc @@ -501,6 +501,93 @@ TEST_P(CordTest, StartsEndsWith) { ASSERT_TRUE(!empty.EndsWith("xyz")); } +TEST_P(CordTest, Contains) { + auto flat_haystack = absl::Cord("this is a flat cord"); + auto fragmented_haystack = absl::MakeFragmentedCord( + {"this", " ", "is", " ", "a", " ", "fragmented", " ", "cord"}); + + EXPECT_TRUE(flat_haystack.Contains("")); + EXPECT_TRUE(fragmented_haystack.Contains("")); + EXPECT_TRUE(flat_haystack.Contains(absl::Cord(""))); + EXPECT_TRUE(fragmented_haystack.Contains(absl::Cord(""))); + EXPECT_TRUE(absl::Cord("").Contains("")); + EXPECT_TRUE(absl::Cord("").Contains(absl::Cord(""))); + EXPECT_FALSE(absl::Cord("").Contains(flat_haystack)); + EXPECT_FALSE(absl::Cord("").Contains(fragmented_haystack)); + + EXPECT_FALSE(flat_haystack.Contains("z")); + EXPECT_FALSE(fragmented_haystack.Contains("z")); + EXPECT_FALSE(flat_haystack.Contains(absl::Cord("z"))); + EXPECT_FALSE(fragmented_haystack.Contains(absl::Cord("z"))); + + EXPECT_FALSE(flat_haystack.Contains("is an")); + EXPECT_FALSE(fragmented_haystack.Contains("is an")); + EXPECT_FALSE(flat_haystack.Contains(absl::Cord("is an"))); + EXPECT_FALSE(fragmented_haystack.Contains(absl::Cord("is an"))); + EXPECT_FALSE( + flat_haystack.Contains(absl::MakeFragmentedCord({"is", " ", "an"}))); + EXPECT_FALSE(fragmented_haystack.Contains( + absl::MakeFragmentedCord({"is", " ", "an"}))); + + EXPECT_TRUE(flat_haystack.Contains("is a")); + EXPECT_TRUE(fragmented_haystack.Contains("is a")); + EXPECT_TRUE(flat_haystack.Contains(absl::Cord("is a"))); + EXPECT_TRUE(fragmented_haystack.Contains(absl::Cord("is a"))); + EXPECT_TRUE( + flat_haystack.Contains(absl::MakeFragmentedCord({"is", " ", "a"}))); + EXPECT_TRUE( + fragmented_haystack.Contains(absl::MakeFragmentedCord({"is", " ", "a"}))); +} + +TEST_P(CordTest, Find) { + auto flat_haystack = absl::Cord("this is a flat cord"); + auto fragmented_haystack = absl::MakeFragmentedCord( + {"this", " ", "is", " ", "a", " ", "fragmented", " ", "cord"}); + auto empty_haystack = absl::Cord(""); + + EXPECT_EQ(flat_haystack.Find(""), flat_haystack.char_begin()); + EXPECT_EQ(fragmented_haystack.Find(""), fragmented_haystack.char_begin()); + EXPECT_EQ(flat_haystack.Find(absl::Cord("")), flat_haystack.char_begin()); + EXPECT_EQ(fragmented_haystack.Find(absl::Cord("")), + fragmented_haystack.char_begin()); + EXPECT_EQ(empty_haystack.Find(""), empty_haystack.char_begin()); + EXPECT_EQ(empty_haystack.Find(absl::Cord("")), empty_haystack.char_begin()); + EXPECT_EQ(empty_haystack.Find(flat_haystack), empty_haystack.char_end()); + EXPECT_EQ(empty_haystack.Find(fragmented_haystack), + empty_haystack.char_end()); + + EXPECT_EQ(flat_haystack.Find("z"), flat_haystack.char_end()); + EXPECT_EQ(fragmented_haystack.Find("z"), fragmented_haystack.char_end()); + EXPECT_EQ(flat_haystack.Find(absl::Cord("z")), flat_haystack.char_end()); + EXPECT_EQ(fragmented_haystack.Find(absl::Cord("z")), + fragmented_haystack.char_end()); + + EXPECT_EQ(flat_haystack.Find("is an"), flat_haystack.char_end()); + EXPECT_EQ(fragmented_haystack.Find("is an"), fragmented_haystack.char_end()); + EXPECT_EQ(flat_haystack.Find(absl::Cord("is an")), flat_haystack.char_end()); + EXPECT_EQ(fragmented_haystack.Find(absl::Cord("is an")), + fragmented_haystack.char_end()); + EXPECT_EQ(flat_haystack.Find(absl::MakeFragmentedCord({"is", " ", "an"})), + flat_haystack.char_end()); + EXPECT_EQ( + fragmented_haystack.Find(absl::MakeFragmentedCord({"is", " ", "an"})), + fragmented_haystack.char_end()); + + EXPECT_EQ(flat_haystack.Find("is a"), + std::next(flat_haystack.char_begin(), 5)); + EXPECT_EQ(fragmented_haystack.Find("is a"), + std::next(fragmented_haystack.char_begin(), 5)); + EXPECT_EQ(flat_haystack.Find(absl::Cord("is a")), + std::next(flat_haystack.char_begin(), 5)); + EXPECT_EQ(fragmented_haystack.Find(absl::Cord("is a")), + std::next(fragmented_haystack.char_begin(), 5)); + EXPECT_EQ(flat_haystack.Find(absl::MakeFragmentedCord({"is", " ", "a"})), + std::next(flat_haystack.char_begin(), 5)); + EXPECT_EQ( + fragmented_haystack.Find(absl::MakeFragmentedCord({"is", " ", "a"})), + std::next(fragmented_haystack.char_begin(), 5)); +} + TEST_P(CordTest, Subcord) { RandomEngine rng(GTEST_FLAG_GET(random_seed)); const std::string s = RandomLowercaseString(&rng, 1024); From 9a6d9c6eae90f4a5ddb162b8ef49af1e321c9769 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Wed, 16 Aug 2023 11:59:48 -0700 Subject: [PATCH 0171/1238] Use Abseil's implementation of absl::rotl and absl::rotr for libc++ prior to 18.0 to workaround libc++ having the wrong signature for these functions. Upstream issue: https://github.com/llvm/llvm-project/issues/64544 The preprocessor conditions were inverted for readability as the conditions became more complex. PiperOrigin-RevId: 557559472 Change-Id: Ibf7a2651e13a0d2a91846bc0d72ba3a44f56747b --- absl/numeric/bits.h | 58 +++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/absl/numeric/bits.h b/absl/numeric/bits.h index 5ed36f52964..4b90d3fad51 100644 --- a/absl/numeric/bits.h +++ b/absl/numeric/bits.h @@ -49,9 +49,22 @@ namespace absl { ABSL_NAMESPACE_BEGIN -#if !(defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L) -// rotating +// https://github.com/llvm/llvm-project/issues/64544 +// libc++ had the wrong signature for std::rotl and std::rotr +// prior to libc++ 18.0. +// +// b/289016048 requires a workaround for _LIBCPP_GOOGLE3. +#if (defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L) && \ + (!defined(_LIBCPP_VERSION) || _LIBCPP_VERSION >= 180000) && \ + !defined(_LIBCPP_GOOGLE3) + +using std::rotl; +using std::rotr; + +#else + +// Rotating functions template ABSL_MUST_USE_RESULT constexpr typename std::enable_if::value, T>::type @@ -66,6 +79,20 @@ ABSL_MUST_USE_RESULT constexpr return numeric_internal::RotateRight(x, s); } +#endif + +// b/289016048 requires a workaround for _LIBCPP_GOOGLE3. +#if (defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L) && \ + !defined(_LIBCPP_GOOGLE3) + +using std::countl_one; +using std::countl_zero; +using std::countr_one; +using std::countr_zero; +using std::popcount; + +#else + // Counting functions // // While these functions are typically constexpr, on some platforms, they may @@ -107,19 +134,20 @@ ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline popcount(T x) noexcept { return numeric_internal::Popcount(x); } -#else // defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L - -using std::countl_one; -using std::countl_zero; -using std::countr_one; -using std::countr_zero; -using std::popcount; -using std::rotl; -using std::rotr; #endif -#if !(defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L) +// b/289016048 requires a workaround for _LIBCPP_GOOGLE3. +#if (defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L) && \ + !defined(_LIBCPP_GOOGLE3) + +using std::bit_ceil; +using std::bit_floor; +using std::bit_width; +using std::has_single_bit; + +#else + // Returns: true if x is an integral power of two; false otherwise. template constexpr inline typename std::enable_if::value, bool>::type @@ -162,12 +190,6 @@ ABSL_INTERNAL_CONSTEXPR_CLZ inline return has_single_bit(x) ? T{1} << (bit_width(x) - 1) : numeric_internal::BitCeilNonPowerOf2(x); } -#else // defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L - -using std::bit_ceil; -using std::bit_floor; -using std::bit_width; -using std::has_single_bit; #endif From 9377c75bf499af0018542c17abcedf659e094a1e Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Wed, 16 Aug 2023 13:58:00 -0700 Subject: [PATCH 0172/1238] CI: Update the Linux hybrid-latest docker container used for testing The following are the major updates * LLVM 17 branch (https://github.com/llvm/llvm-project b744f4c99cf91155c74a3c92db6f1335232ff3d) * GCC 13.2 * CMake 3.27.1 * Bazel 6.2.1 PiperOrigin-RevId: 557594251 Change-Id: I86f72c8035ab4f3b9fe602bdaf3bfb8200ec3633 --- ci/linux_clang-latest_libcxx_asan_bazel.sh | 4 ++-- ci/linux_clang-latest_libcxx_bazel.sh | 4 ++-- ci/linux_clang-latest_libcxx_tsan_bazel.sh | 4 ++-- ci/linux_docker_containers.sh | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ci/linux_clang-latest_libcxx_asan_bazel.sh b/ci/linux_clang-latest_libcxx_asan_bazel.sh index f9c146b05b9..bbdae65c940 100755 --- a/ci/linux_clang-latest_libcxx_asan_bazel.sh +++ b/ci/linux_clang-latest_libcxx_asan_bazel.sh @@ -70,8 +70,8 @@ for std in ${STD}; do --rm \ -e CC="/opt/llvm/clang/bin/clang" \ -e BAZEL_CXXOPTS="-std=${std}:-nostdinc++" \ - -e BAZEL_LINKOPTS="-L/opt/llvm/libcxx/lib/x86_64-unknown-linux-gnu:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx/lib/x86_64-unknown-linux-gnu" \ - -e CPLUS_INCLUDE_PATH="/opt/llvm/libcxx/include/x86_64-unknown-linux-gnu/c++/v1:/opt/llvm/libcxx/include/c++/v1" \ + -e BAZEL_LINKOPTS="-L/opt/llvm/libcxx/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx/lib" \ + -e CPLUS_INCLUDE_PATH="/opt/llvm/libcxx/include/c++/v1" \ ${DOCKER_EXTRA_ARGS:-} \ ${DOCKER_CONTAINER} \ /usr/local/bin/bazel test ... \ diff --git a/ci/linux_clang-latest_libcxx_bazel.sh b/ci/linux_clang-latest_libcxx_bazel.sh index 38b2d744010..ac4c99ab866 100755 --- a/ci/linux_clang-latest_libcxx_bazel.sh +++ b/ci/linux_clang-latest_libcxx_bazel.sh @@ -71,8 +71,8 @@ for std in ${STD}; do --rm \ -e CC="/opt/llvm/clang/bin/clang" \ -e BAZEL_CXXOPTS="-std=${std}:-nostdinc++" \ - -e BAZEL_LINKOPTS="-L/opt/llvm/libcxx/lib/x86_64-unknown-linux-gnu:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx/lib/x86_64-unknown-linux-gnu" \ - -e CPLUS_INCLUDE_PATH="/opt/llvm/libcxx/include/x86_64-unknown-linux-gnu/c++/v1:/opt/llvm/libcxx/include/c++/v1" \ + -e BAZEL_LINKOPTS="-L/opt/llvm/libcxx/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx/lib" \ + -e CPLUS_INCLUDE_PATH="/opt/llvm/libcxx/include/c++/v1" \ ${DOCKER_EXTRA_ARGS:-} \ ${DOCKER_CONTAINER} \ /bin/sh -c " diff --git a/ci/linux_clang-latest_libcxx_tsan_bazel.sh b/ci/linux_clang-latest_libcxx_tsan_bazel.sh index 34d7940e6c9..593ea3e513e 100755 --- a/ci/linux_clang-latest_libcxx_tsan_bazel.sh +++ b/ci/linux_clang-latest_libcxx_tsan_bazel.sh @@ -70,8 +70,8 @@ for std in ${STD}; do --rm \ -e CC="/opt/llvm/clang/bin/clang" \ -e BAZEL_CXXOPTS="-std=${std}:-nostdinc++" \ - -e BAZEL_LINKOPTS="-L/opt/llvm/libcxx-tsan/lib/x86_64-unknown-linux-gnu:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx-tsan/lib/x86_64-unknown-linux-gnu" \ - -e CPLUS_INCLUDE_PATH="/opt/llvm/libcxx-tsan/include/x86_64-unknown-linux-gnu/c++/v1:/opt/llvm/libcxx-tsan/include/c++/v1" \ + -e BAZEL_LINKOPTS="-L/opt/llvm/libcxx-tsan/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx-tsan/lib" \ + -e CPLUS_INCLUDE_PATH="/opt/llvm/libcxx-tsan/include/c++/v1" \ ${DOCKER_EXTRA_ARGS:-} \ ${DOCKER_CONTAINER} \ /usr/local/bin/bazel test ... \ diff --git a/ci/linux_docker_containers.sh b/ci/linux_docker_containers.sh index a07c64ce103..7220e619c48 100644 --- a/ci/linux_docker_containers.sh +++ b/ci/linux_docker_containers.sh @@ -16,6 +16,6 @@ # Test scripts should source this file to get the identifiers. readonly LINUX_ALPINE_CONTAINER="gcr.io/google.com/absl-177019/alpine:20230612" -readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20230217" -readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20230517" +readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20230816" +readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20230816" readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20230120" From 65d7b6d421f780941dd585d7094f257a546e2510 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 17 Aug 2023 07:04:14 -0700 Subject: [PATCH 0173/1238] StrCat: do not use intermediate buffer when result fits in SSO. PiperOrigin-RevId: 557811632 Change-Id: I370fa17d2fb82a1f1ca86f84529bae31b34b18e4 --- absl/strings/str_cat.h | 64 +++++++++++++++++++++++++++++++ absl/strings/str_cat_benchmark.cc | 11 ++++++ absl/strings/str_cat_test.cc | 16 ++++++++ 3 files changed, 91 insertions(+) diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h index d5f71ff003f..57a5823fed9 100644 --- a/absl/strings/str_cat.h +++ b/absl/strings/str_cat.h @@ -89,8 +89,11 @@ #include #include +#include +#include #include #include +#include #include #include #include @@ -98,7 +101,9 @@ #include "absl/base/attributes.h" #include "absl/base/port.h" +#include "absl/meta/type_traits.h" #include "absl/strings/internal/has_absl_stringify.h" +#include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/internal/stringify_sink.h" #include "absl/strings/numbers.h" #include "absl/strings/string_view.h" @@ -444,10 +449,69 @@ std::string CatPieces(std::initializer_list pieces); void AppendPieces(std::string* dest, std::initializer_list pieces); +template +std::string IntegerToString(Integer i) { + // Any integer (signed/unsigned) up to 64 bits can be formatted into a buffer + // with 22 bytes (including NULL at the end). + constexpr size_t kMaxDigits10 = 22; + std::string result; + strings_internal::STLStringResizeUninitialized(&result, kMaxDigits10); + char* start = &result[0]; + // note: this can be optimized to not write last zero. + char* end = numbers_internal::FastIntToBuffer(i, start); + auto size = static_cast(end - start); + assert((size < result.size()) && + "StrCat(Integer) does not fit into kMaxDigits10"); + result.erase(size); + return result; +} +template +std::string FloatToString(Float f) { + std::string result; + strings_internal::STLStringResizeUninitialized( + &result, numbers_internal::kSixDigitsToBufferSize); + char* start = &result[0]; + result.erase(numbers_internal::SixDigitsToBuffer(f, start)); + return result; +} + +// `SingleArgStrCat` overloads take built-in `int`, `long` and `long long` types +// (signed / unsigned) to avoid ambiguity on the call side. If we used int32_t +// and int64_t, then at least one of the three (`int` / `long` / `long long`) +// would have been ambiguous when passed to `SingleArgStrCat`. +inline std::string SingleArgStrCat(int x) { return IntegerToString(x); } +inline std::string SingleArgStrCat(unsigned int x) { + return IntegerToString(x); +} +// NOLINTNEXTLINE +inline std::string SingleArgStrCat(long x) { return IntegerToString(x); } +// NOLINTNEXTLINE +inline std::string SingleArgStrCat(unsigned long x) { + return IntegerToString(x); +} +// NOLINTNEXTLINE +inline std::string SingleArgStrCat(long long x) { return IntegerToString(x); } +// NOLINTNEXTLINE +inline std::string SingleArgStrCat(unsigned long long x) { + return IntegerToString(x); +} +inline std::string SingleArgStrCat(float x) { return FloatToString(x); } +inline std::string SingleArgStrCat(double x) { return FloatToString(x); } + + +template {} && + !std::is_same{}>> +using EnableIfFastCase = T; + } // namespace strings_internal ABSL_MUST_USE_RESULT inline std::string StrCat() { return std::string(); } +template +ABSL_MUST_USE_RESULT inline std::string StrCat( + strings_internal::EnableIfFastCase a) { + return strings_internal::SingleArgStrCat(a); +} ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a) { return std::string(a.data(), a.size()); } diff --git a/absl/strings/str_cat_benchmark.cc b/absl/strings/str_cat_benchmark.cc index 81b205482c2..e54a9230c5d 100644 --- a/absl/strings/str_cat_benchmark.cc +++ b/absl/strings/str_cat_benchmark.cc @@ -188,4 +188,15 @@ void StrAppendConfig(B* benchmark) { BENCHMARK(BM_StrAppend)->Apply(StrAppendConfig); +void BM_StrCat_int(benchmark::State& state) { + int i = 0; + for (auto s : state) { + std::string result = absl::StrCat(i); + benchmark::DoNotOptimize(result); + i = IncrementAlternatingSign(i); + } +} + +BENCHMARK(BM_StrCat_int); + } // namespace diff --git a/absl/strings/str_cat_test.cc b/absl/strings/str_cat_test.cc index 7f52e053cfe..66eddf0df0b 100644 --- a/absl/strings/str_cat_test.cc +++ b/absl/strings/str_cat_test.cc @@ -665,4 +665,20 @@ TEST(StrCat, AbslStringifyWithEnum) { EXPECT_EQ(absl::StrCat(e), "Choices"); } +template +void CheckSingleArgumentIntegerLimits() { + Integer max = std::numeric_limits::max(); + Integer min = std::numeric_limits::min(); + + EXPECT_EQ(absl::StrCat(max), std::to_string(max)); + EXPECT_EQ(absl::StrCat(min), std::to_string(min)); +} + +TEST(StrCat, SingleArgumentLimits) { + CheckSingleArgumentIntegerLimits(); + CheckSingleArgumentIntegerLimits(); + CheckSingleArgumentIntegerLimits(); + CheckSingleArgumentIntegerLimits(); +} + } // namespace From 88ed1832745ab8cc3aa9cc6ccc40f87ffbd6c9f9 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Thu, 17 Aug 2023 12:09:49 -0700 Subject: [PATCH 0174/1238] Fix typo hash_test.cc -> hash_instantiated_test.cc from c154d20abce2f1ae6bd35bd774313e351493219b and add CMake dependency on gmock #1515 PiperOrigin-RevId: 557897123 Change-Id: I3f8bbcea1f4c293e073e1f77dbbf818ce2b167bd --- absl/hash/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/absl/hash/CMakeLists.txt b/absl/hash/CMakeLists.txt index 438c1cda85f..99d6fa1f8dc 100644 --- a/absl/hash/CMakeLists.txt +++ b/absl/hash/CMakeLists.txt @@ -91,7 +91,7 @@ absl_cc_test( NAME hash_instantiated_test SRCS - "hash_test.cc" + "hash_instantiated_test.cc" "internal/hash_test.h" COPTS ${ABSL_TEST_COPTS} @@ -104,7 +104,7 @@ absl_cc_test( absl::flat_hash_set absl::node_hash_map absl::node_hash_set - GTest::gtest_main + GTest::gmock_main ) # Internal-only target, do not depend on directly. From 76af16444ed33791223b3c123d311ab699f1df01 Mon Sep 17 00:00:00 2001 From: Evan Brown Date: Thu, 17 Aug 2023 13:31:24 -0700 Subject: [PATCH 0175/1238] Remove the has_element function and use FindElement instead. PiperOrigin-RevId: 557920808 Change-Id: I1eb0ca1ea9e9de542321fbc23d82218c5d449fbf --- absl/container/internal/raw_hash_set.h | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 678ed7eab4a..f4cf8367a91 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -2453,8 +2453,10 @@ class raw_hash_set { const raw_hash_set* outer = &a; const raw_hash_set* inner = &b; if (outer->capacity() > inner->capacity()) std::swap(outer, inner); - for (const value_type& elem : *outer) - if (!inner->has_element(elem)) return false; + for (const value_type& elem : *outer) { + auto it = PolicyTraits::apply(FindElement{*inner}, elem); + if (it == inner->end() || !(*it == elem)) return false; + } return true; } @@ -2659,24 +2661,6 @@ class raw_hash_set { } } - bool has_element(const value_type& elem) const { - size_t hash = PolicyTraits::apply(HashElement{hash_ref()}, elem); - auto seq = probe(common(), hash); - const ctrl_t* ctrl = control(); - while (true) { - Group g{ctrl + seq.offset()}; - for (uint32_t i : g.Match(H2(hash))) { - if (ABSL_PREDICT_TRUE( - PolicyTraits::element(slot_array() + seq.offset(i)) == elem)) - return true; - } - if (ABSL_PREDICT_TRUE(g.MaskEmpty())) return false; - seq.next(); - assert(seq.index() <= capacity() && "full table!"); - } - return false; - } - // TODO(alkis): Optimize this assuming *this and that don't overlap. raw_hash_set& move_assign(raw_hash_set&& that, std::true_type) { raw_hash_set tmp(std::move(that)); From 4f3eff442191e7e2ec2d547c9331fad256bf96d1 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Thu, 17 Aug 2023 14:48:32 -0700 Subject: [PATCH 0176/1238] Fix instances where GTest::gtest(_main) should have been GTest::gmock(_main) in log #1515 PiperOrigin-RevId: 557942924 Change-Id: I117e7163de43455471fbfeed3cea3aebc3ac2d10 --- absl/log/CMakeLists.txt | 48 +++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/absl/log/CMakeLists.txt b/absl/log/CMakeLists.txt index 2c3307dca1e..1ca35a16649 100644 --- a/absl/log/CMakeLists.txt +++ b/absl/log/CMakeLists.txt @@ -705,8 +705,7 @@ absl_cc_test( absl::core_headers absl::log_internal_test_helpers absl::status - GTest::gmock - GTest::gtest_main + GTest::gmock_main ) absl_cc_test( @@ -729,8 +728,7 @@ absl_cc_test( absl::log_internal_test_helpers absl::log_internal_test_matchers absl::scoped_mock_log - GTest::gmock - GTest::gtest_main + GTest::gmock_main ) absl_cc_test( @@ -749,8 +747,7 @@ absl_cc_test( absl::core_headers absl::log_internal_test_helpers absl::status - GTest::gmock - GTest::gtest_main + GTest::gmock_main ) absl_cc_test( @@ -789,8 +786,7 @@ absl_cc_test( absl::log_internal_test_helpers absl::log_internal_test_matchers absl::scoped_mock_log - GTest::gmock - GTest::gtest_main + GTest::gmock_main ) absl_cc_test( @@ -814,8 +810,7 @@ absl_cc_test( absl::span absl::strings absl::time - GTest::gmock - GTest::gtest_main + GTest::gmock_main ) absl_cc_test( @@ -840,8 +835,7 @@ absl_cc_test( absl::flags_reflection absl::scoped_mock_log absl::strings - GTest::gmock - GTest::gtest_main + GTest::gmock_main ) absl_cc_test( @@ -861,8 +855,7 @@ absl_cc_test( absl::log_internal_test_helpers absl::log_severity absl::scoped_mock_log - GTest::gmock - GTest::gtest_main + GTest::gmock_main ) absl_cc_test( @@ -882,8 +875,7 @@ absl_cc_test( absl::scoped_mock_log absl::str_format absl::strings - GTest::gmock - GTest::gtest_main + GTest::gmock_main ) absl_cc_test( @@ -900,8 +892,7 @@ absl_cc_test( absl::log absl::log_severity absl::scoped_mock_log - GTest::gmock - GTest::gtest_main + GTest::gmock_main ) absl_cc_test( @@ -924,7 +915,7 @@ absl_cc_test( absl::log_severity absl::scoped_mock_log absl::strings - GTest::gtest_main + GTest::gmock_main ) absl_cc_test( @@ -947,7 +938,7 @@ absl_cc_test( absl::log_severity absl::scoped_mock_log absl::strings - GTest::gtest_main + GTest::gmock_main ) absl_cc_test( @@ -968,8 +959,7 @@ absl_cc_test( absl::scoped_mock_log absl::strings absl::time - GTest::gmock - GTest::gtest_main + GTest::gmock_main ) absl_cc_test( @@ -1012,8 +1002,7 @@ absl_cc_test( absl::log_globals absl::log_internal_test_helpers absl::log_severity - GTest::gmock - GTest::gtest_main + GTest::gmock_main ) absl_cc_test( @@ -1034,8 +1023,7 @@ absl_cc_test( absl::strerror absl::strings absl::str_format - GTest::gmock - GTest::gtest_main + GTest::gmock_main ) absl_cc_test( @@ -1054,8 +1042,7 @@ absl_cc_test( absl::log_internal_test_matchers absl::log_structured absl::scoped_mock_log - GTest::gmock - GTest::gtest_main + GTest::gmock_main ) absl_cc_test( @@ -1069,6 +1056,5 @@ absl_cc_test( ${ABSL_DEFAULT_LINKOPTS} DEPS absl::log_internal_fnmatch - GTest::gmock - GTest::gtest_main -) \ No newline at end of file + GTest::gmock_main +) From 94b37802217a9c9bb182bd99d55096683ef45b2c Mon Sep 17 00:00:00 2001 From: Martijn Vels Date: Fri, 18 Aug 2023 11:32:43 -0700 Subject: [PATCH 0177/1238] Check CRC cordrep child nodes for nullptr. Some time ago the invariant for CRC cordreps was relaxed to allow for nullptr values on empty cords with an explicit empty CRC value. The CordzInfo analysis never checked for nullptr values causing cord sampling to crash if the sampling happened to include a (very unlikely) empty Cord value. PiperOrigin-RevId: 558202613 Change-Id: Ib0e1eadd08047167e4df5d3035b36dca2c285a0d --- absl/strings/internal/cordz_info.cc | 40 ++++++++++++------- .../internal/cordz_info_statistics_test.cc | 30 +++++++++++++- 2 files changed, 53 insertions(+), 17 deletions(-) diff --git a/absl/strings/internal/cordz_info.cc b/absl/strings/internal/cordz_info.cc index 515dfafbb3f..b830c25ccb0 100644 --- a/absl/strings/internal/cordz_info.cc +++ b/absl/strings/internal/cordz_info.cc @@ -33,8 +33,6 @@ namespace absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { -using ::absl::base_internal::SpinLockHolder; - #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL constexpr size_t CordzInfo::kMaxStackDepth; #endif @@ -79,6 +77,8 @@ class CordRepAnalyzer { // adds the results to `statistics`. Note that node counts and memory sizes // are not initialized, computed values are added to any existing values. void AnalyzeCordRep(const CordRep* rep) { + ABSL_ASSERT(rep != nullptr); + // Process all linear nodes. // As per the class comments, use refcout - 1 on the top level node, as the // top level node is assumed to be referenced only for analysis purposes. @@ -86,7 +86,7 @@ class CordRepAnalyzer { RepRef repref{rep, (refcount > 1) ? refcount - 1 : 1}; // Process the top level CRC node, if present. - if (repref.rep->tag == CRC) { + if (repref.tag() == CRC) { statistics_.node_count++; statistics_.node_counts.crc++; memory_usage_.Add(sizeof(CordRepCrc), repref.refcount); @@ -96,15 +96,17 @@ class CordRepAnalyzer { // Process all top level linear nodes (substrings and flats). repref = CountLinearReps(repref, memory_usage_); - if (repref.rep != nullptr) { - if (repref.rep->tag == RING) { + switch (repref.tag()) { + case CordRepKind::RING: AnalyzeRing(repref); - } else if (repref.rep->tag == BTREE) { + break; + case CordRepKind::BTREE: AnalyzeBtree(repref); - } else { - // We should have either a concat, btree, or ring node if not null. - assert(false); - } + break; + default: + // We should have either a btree or ring node if not null. + ABSL_ASSERT(repref.tag() == CordRepKind::UNUSED_0); + break; } // Adds values to output @@ -122,11 +124,19 @@ class CordRepAnalyzer { const CordRep* rep; size_t refcount; - // Returns a 'child' RepRef which contains the cumulative reference count of - // this instance multiplied by the child's reference count. + // Returns a 'child' RepRef which contains the cumulative reference count + // of this instance multiplied by the child's reference count. Returns a + // nullptr RepRef value with a refcount of 0 if `child` is nullptr. RepRef Child(const CordRep* child) const { + if (child == nullptr) return RepRef{nullptr, 0}; return RepRef{child, refcount * child->refcount.Get()}; } + + // Returns the tag of this rep, or UNUSED_0 if this instance is null + constexpr CordRepKind tag() const { + ABSL_ASSERT(rep == nullptr || rep->tag != CordRepKind::UNUSED_0); + return rep ? static_cast(rep->tag) : CordRepKind::UNUSED_0; + } }; // Memory usage values @@ -167,7 +177,7 @@ class CordRepAnalyzer { // buffers where we count children unrounded. RepRef CountLinearReps(RepRef rep, MemoryUsage& memory_usage) { // Consume all substrings - while (rep.rep->tag == SUBSTRING) { + while (rep.tag() == SUBSTRING) { statistics_.node_count++; statistics_.node_counts.substring++; memory_usage.Add(sizeof(CordRepSubstring), rep.refcount); @@ -175,7 +185,7 @@ class CordRepAnalyzer { } // Consume possible FLAT - if (rep.rep->tag >= FLAT) { + if (rep.tag() >= FLAT) { size_t size = rep.rep->flat()->AllocatedSize(); CountFlat(size); memory_usage.Add(size, rep.refcount); @@ -183,7 +193,7 @@ class CordRepAnalyzer { } // Consume possible external - if (rep.rep->tag == EXTERNAL) { + if (rep.tag() == EXTERNAL) { statistics_.node_count++; statistics_.node_counts.external++; size_t size = rep.rep->length + sizeof(CordRepExternalImpl); diff --git a/absl/strings/internal/cordz_info_statistics_test.cc b/absl/strings/internal/cordz_info_statistics_test.cc index 53d2f2ea104..aad3b1ec7a2 100644 --- a/absl/strings/internal/cordz_info_statistics_test.cc +++ b/absl/strings/internal/cordz_info_statistics_test.cc @@ -452,8 +452,7 @@ TEST(CordzInfoStatisticsTest, BtreeNodeShared) { TEST(CordzInfoStatisticsTest, Crc) { RefHelper ref; auto* left = Flat(1000); - auto* crc = - ref.NeedsUnref(CordRepCrc::New(left, crc_internal::CrcCordState())); + auto* crc = ref.NeedsUnref(CordRepCrc::New(left, {})); CordzStatistics expected; expected.size = left->length; @@ -467,6 +466,20 @@ TEST(CordzInfoStatisticsTest, Crc) { EXPECT_THAT(SampleCord(crc), EqStatistics(expected)); } +TEST(CordzInfoStatisticsTest, EmptyCrc) { + RefHelper ref; + auto* crc = ref.NeedsUnref(CordRepCrc::New(nullptr, {})); + + CordzStatistics expected; + expected.size = 0; + expected.estimated_memory_usage = SizeOf(crc); + expected.estimated_fair_share_memory_usage = expected.estimated_memory_usage; + expected.node_count = 1; + expected.node_counts.crc = 1; + + EXPECT_THAT(SampleCord(crc), EqStatistics(expected)); +} + TEST(CordzInfoStatisticsTest, ThreadSafety) { Notification stop; static constexpr int kNumThreads = 8; @@ -497,6 +510,7 @@ TEST(CordzInfoStatisticsTest, ThreadSafety) { InlineData cords[2]; std::minstd_rand gen; std::uniform_int_distribution coin_toss(0, 1); + std::uniform_int_distribution dice_roll(1, 6); while (!stop.HasBeenNotified()) { for (InlineData& cord : cords) { @@ -523,6 +537,18 @@ TEST(CordzInfoStatisticsTest, ThreadSafety) { rep = CordRepBtree::Create(rep); } } + + // Maybe CRC this cord + if (dice_roll(gen) == 6) { + if (dice_roll(gen) == 6) { + // Empty CRC rep + CordRep::Unref(rep); + rep = CordRepCrc::New(nullptr, {}); + } else { + // Regular CRC rep + rep = CordRepCrc::New(rep, {}); + } + } cord.make_tree(rep); // 50/50 sample From 36ff83f3789878044f3d1537fef387925330c579 Mon Sep 17 00:00:00 2001 From: Yuriy Chernyshov Date: Mon, 21 Aug 2023 07:05:50 -0700 Subject: [PATCH 0178/1238] PR #1520: Make use of C++20 feature test macros to bestow better compatibility Imported from GitHub PR https://github.com/abseil/abseil-cpp/pull/1520 Fixes #1519 and removes the burden of manually feature testing all the platforms supported by absl. Merge 26bc4ee13a93edaeee2a21b5eff3569b806acc91 into 94b37802217a9c9bb182bd99d55096683ef45b2c Merging this change closes #1520 COPYBARA_INTEGRATE_REVIEW=https://github.com/abseil/abseil-cpp/pull/1520 from georgthegreat:feature-test-macros 26bc4ee13a93edaeee2a21b5eff3569b806acc91 PiperOrigin-RevId: 558777775 Change-Id: Ie3e1f309761c67fa233a03e42762776cd93c69b4 --- absl/base/config.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/absl/base/config.h b/absl/base/config.h index 65a71199b4f..a8425ba7f86 100644 --- a/absl/base/config.h +++ b/absl/base/config.h @@ -75,6 +75,12 @@ #define ABSL_INTERNAL_CPLUSPLUS_LANG __cplusplus #endif +#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \ + ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L +// Include library feature test macros. +#include +#endif + #if defined(__APPLE__) // Included for TARGET_OS_IPHONE, __IPHONE_OS_VERSION_MIN_REQUIRED, // __IPHONE_8_0. @@ -557,6 +563,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || // Checks whether C++17 std::any is available. #ifdef ABSL_HAVE_STD_ANY #error "ABSL_HAVE_STD_ANY cannot be directly set." +#elif defined(__cpp_lib_any) && __cpp_lib_any >= 201606L +#define ABSL_HAVE_STD_ANY 1 #elif defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \ ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L && \ !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE @@ -568,6 +576,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || // Checks whether C++17 std::optional is available. #ifdef ABSL_HAVE_STD_OPTIONAL #error "ABSL_HAVE_STD_OPTIONAL cannot be directly set." +#elif defined(__cpp_lib_optional) && __cpp_lib_optional >= 202106L +#define ABSL_HAVE_STD_OPTIONAL 1 #elif defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \ ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L && \ !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE @@ -579,6 +589,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || // Checks whether C++17 std::variant is available. #ifdef ABSL_HAVE_STD_VARIANT #error "ABSL_HAVE_STD_VARIANT cannot be directly set." +#elif defined(__cpp_lib_variant) && __cpp_lib_variant >= 201606L +#define ABSL_HAVE_STD_VARIANT 1 #elif defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \ ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L && \ !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE @@ -590,6 +602,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || // Checks whether C++17 std::string_view is available. #ifdef ABSL_HAVE_STD_STRING_VIEW #error "ABSL_HAVE_STD_STRING_VIEW cannot be directly set." +#elif defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L +#define ABSL_HAVE_STD_STRING_VIEW 1 #elif defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \ ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L #define ABSL_HAVE_STD_STRING_VIEW 1 From 7aef7808d6dbe46ab95b37e6c67d1350c1da016b Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Mon, 21 Aug 2023 12:52:42 -0700 Subject: [PATCH 0179/1238] kernel_timeout_test: Add Apple to the list of slow platforms because it runs on non-dedicated Kokoro PiperOrigin-RevId: 558874605 Change-Id: Iba35f558ab8c967f98a3176af056e76341fb67c3 --- absl/synchronization/internal/kernel_timeout_test.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/absl/synchronization/internal/kernel_timeout_test.cc b/absl/synchronization/internal/kernel_timeout_test.cc index 92ed269197c..bc546719b8b 100644 --- a/absl/synchronization/internal/kernel_timeout_test.cc +++ b/absl/synchronization/internal/kernel_timeout_test.cc @@ -47,11 +47,10 @@ extern "C" int clock_gettime(clockid_t c, struct timespec* ts) { namespace { -#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \ - defined(ABSL_HAVE_MEMORY_SANITIZER) || \ - defined(ABSL_HAVE_THREAD_SANITIZER) || \ - defined(__ANDROID__) || \ - defined(_WIN32) || defined(_WIN64) +#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \ + defined(ABSL_HAVE_MEMORY_SANITIZER) || \ + defined(ABSL_HAVE_THREAD_SANITIZER) || defined(__ANDROID__) || \ + defined(__APPLE__) || defined(_WIN32) || defined(_WIN64) constexpr absl::Duration kTimingBound = absl::Milliseconds(5); #else constexpr absl::Duration kTimingBound = absl::Microseconds(250); From 91b861c544afd153fe800fc2bea4736a0da37533 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 23 Aug 2023 07:15:42 -0700 Subject: [PATCH 0180/1238] Add absl::CharSet. PiperOrigin-RevId: 559415517 Change-Id: I5bbc744bf00be2fd15ec7544b725d699e0d982fb --- CMake/AbseilDll.cmake | 2 +- absl/strings/BUILD.bazel | 67 ++++--- absl/strings/CMakeLists.txt | 21 +- absl/strings/charset.h | 164 ++++++++++++++++ ..._map_benchmark.cc => charset_benchmark.cc} | 24 +-- absl/strings/charset_test.cc | 181 ++++++++++++++++++ absl/strings/escaping.cc | 2 +- absl/strings/internal/char_map.h | 158 --------------- absl/strings/internal/char_map_test.cc | 172 ----------------- 9 files changed, 419 insertions(+), 372 deletions(-) create mode 100644 absl/strings/charset.h rename absl/strings/{internal/char_map_benchmark.cc => charset_benchmark.cc} (71%) create mode 100644 absl/strings/charset_test.cc delete mode 100644 absl/strings/internal/char_map.h delete mode 100644 absl/strings/internal/char_map_test.cc diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index a5a512bdbfb..1a20a84fcf4 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake @@ -263,6 +263,7 @@ set(ABSL_INTERNAL_DLL_FILES "strings/ascii.h" "strings/charconv.cc" "strings/charconv.h" + "strings/charset.h" "strings/cord.cc" "strings/cord.h" "strings/cord_analysis.cc" @@ -327,7 +328,6 @@ set(ABSL_INTERNAL_DLL_FILES "strings/strip.h" "strings/substitute.cc" "strings/substitute.h" - "strings/internal/char_map.h" "strings/internal/escaping.h" "strings/internal/escaping.cc" "strings/internal/memutil.cc" diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index e3b8af48b48..a858d0b2fda 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel @@ -92,6 +92,7 @@ cc_library( "string_view.h", ], deps = [ + ":charset", ":internal", ":string_view", "//absl/base", @@ -115,7 +116,6 @@ cc_library( "internal/utf8.cc", ], hdrs = [ - "internal/char_map.h", "internal/escaping.h", "internal/ostringstream.h", "internal/resize_uninitialized.h", @@ -307,6 +307,50 @@ cc_test( ], ) +cc_test( + name = "charset_benchmark", + size = "small", + srcs = [ + "charset_benchmark.cc", + ], + copts = ABSL_TEST_COPTS, + tags = [ + "benchmark", + ], + visibility = ["//visibility:private"], + deps = [ + ":charset", + "//absl/log:check", + "@com_github_google_benchmark//:benchmark_main", + ], +) + +cc_library( + name = "charset", + hdrs = [ + "charset.h", + ], + copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [ + ":string_view", + "//absl/base:core_headers", + ], +) + +cc_test( + name = "charset_test", + size = "small", + srcs = ["charset_test.cc"], + copts = ABSL_TEST_COPTS, + visibility = ["//visibility:private"], + deps = [ + ":charset", + ":strings", + "@com_google_googletest//:gtest_main", + ], +) + cc_library( name = "cord_internal", srcs = [ @@ -1086,27 +1130,6 @@ cc_test( ], ) -cc_test( - name = "char_map_test", - srcs = ["internal/char_map_test.cc"], - copts = ABSL_TEST_COPTS, - deps = [ - ":internal", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "char_map_benchmark", - srcs = ["internal/char_map_benchmark.cc"], - copts = ABSL_TEST_COPTS, - tags = ["benchmark"], - deps = [ - ":internal", - "@com_github_google_benchmark//:benchmark_main", - ], -) - cc_test( name = "charconv_test", srcs = ["charconv_test.cc"], diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index 0e588674595..27e7ce4f4ca 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt @@ -78,6 +78,7 @@ absl_cc_library( absl::strings_internal absl::base absl::bits + absl::charset absl::config absl::core_headers absl::endian @@ -89,12 +90,24 @@ absl_cc_library( PUBLIC ) +absl_cc_library( + NAME + charset + HDRS + charset.h + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::core_headers + absl::string_view + PUBLIC +) + # Internal-only target, do not depend on directly. absl_cc_library( NAME strings_internal HDRS - "internal/char_map.h" "internal/escaping.cc" "internal/escaping.h" "internal/ostringstream.h" @@ -357,13 +370,13 @@ absl_cc_test( absl_cc_test( NAME - char_map_test + charset_test SRCS - "internal/char_map_test.cc" + "charset_test.cc" COPTS ${ABSL_TEST_COPTS} DEPS - absl::strings_internal + absl::strings GTest::gmock_main ) diff --git a/absl/strings/charset.h b/absl/strings/charset.h new file mode 100644 index 00000000000..ff4e81a41fd --- /dev/null +++ b/absl/strings/charset.h @@ -0,0 +1,164 @@ +// Copyright 2022 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: charset.h +// ----------------------------------------------------------------------------- +// +// This file contains absl::CharSet, a fast, bit-vector set of 8-bit unsigned +// characters. +// +// Instances can be initialized as constexpr constants. For example: +// +// constexpr absl::CharSet kJustX = absl::CharSet::Char('x'); +// constexpr absl::CharSet kMySymbols = absl::CharSet("$@!"); +// constexpr absl::CharSet kLetters = absl::CharSet::Range('a', 'z'); +// +// Multiple instances can be combined that still forms a constexpr expression. +// For example: +// +// constexpr absl::CharSet kLettersAndNumbers = +// absl::CharSet::Range('a', 'z') | absl::CharSet::Range('0', '9'); +// +// Several pre-defined character classes are available that mirror the methods +// from . For example: +// +// constexpr absl::CharSet kLettersAndWhitespace = +// absl::CharSet::AsciiAlphabet() | absl::CharSet::AsciiWhitespace(); +// +// To check membership, use the .contains method, e.g. +// +// absl::CharSet hex_letters("abcdef"); +// hex_letters.contains('a'); // true +// hex_letters.contains('g'); // false + +#ifndef ABSL_STRINGS_CHARSET_H_ +#define ABSL_STRINGS_CHARSET_H_ + +#include +#include +#include + +#include "absl/base/macros.h" +#include "absl/base/port.h" +#include "absl/strings/string_view.h" + +namespace absl { + +class CharSet { + public: + constexpr CharSet() : m_() {} + + // Initializes with a given string_view. + constexpr explicit CharSet(absl::string_view str) : m_() { + for (char c : str) { + SetChar(static_cast(c)); + } + } + + constexpr bool contains(char c) const { + return ((m_[static_cast(c) / 64] >> + (static_cast(c) % 64)) & + 0x1) == 0x1; + } + + constexpr bool empty() const { + for (uint64_t c : m_) { + if (c != 0) return false; + } + return true; + } + + // Containing only a single specified char. + static constexpr CharSet Char(char x) { + return CharSet(CharMaskForWord(x, 0), CharMaskForWord(x, 1), + CharMaskForWord(x, 2), CharMaskForWord(x, 3)); + } + + // Containing all the chars in the closed interval [lo,hi]. + static constexpr CharSet Range(char lo, char hi) { + return CharSet(RangeForWord(lo, hi, 0), RangeForWord(lo, hi, 1), + RangeForWord(lo, hi, 2), RangeForWord(lo, hi, 3)); + } + + friend constexpr CharSet operator&(const CharSet& a, const CharSet& b) { + return CharSet(a.m_[0] & b.m_[0], a.m_[1] & b.m_[1], a.m_[2] & b.m_[2], + a.m_[3] & b.m_[3]); + } + + friend constexpr CharSet operator|(const CharSet& a, const CharSet& b) { + return CharSet(a.m_[0] | b.m_[0], a.m_[1] | b.m_[1], a.m_[2] | b.m_[2], + a.m_[3] | b.m_[3]); + } + + friend constexpr CharSet operator~(const CharSet& a) { + return CharSet(~a.m_[0], ~a.m_[1], ~a.m_[2], ~a.m_[3]); + } + + // Mirrors the char-classifying predicates in . + static constexpr CharSet AsciiUppercase() { return CharSet::Range('A', 'Z'); } + static constexpr CharSet AsciiLowercase() { return CharSet::Range('a', 'z'); } + static constexpr CharSet AsciiDigits() { return CharSet::Range('0', '9'); } + static constexpr CharSet AsciiAlphabet() { + return AsciiLowercase() | AsciiUppercase(); + } + static constexpr CharSet AsciiAlphanumerics() { + return AsciiDigits() | AsciiAlphabet(); + } + static constexpr CharSet AsciiHexDigits() { + return AsciiDigits() | CharSet::Range('A', 'F') | CharSet::Range('a', 'f'); + } + static constexpr CharSet AsciiPrintable() { + return CharSet::Range(0x20, 0x7e); + } + static constexpr CharSet AsciiWhitespace() { return CharSet("\t\n\v\f\r "); } + static constexpr CharSet AsciiPunctuation() { + return AsciiPrintable() & ~AsciiWhitespace() & ~AsciiAlphanumerics(); + } + + private: + constexpr CharSet(uint64_t b0, uint64_t b1, uint64_t b2, uint64_t b3) + : m_{b0, b1, b2, b3} {} + + static constexpr uint64_t RangeForWord(char lo, char hi, uint64_t word) { + return OpenRangeFromZeroForWord(static_cast(hi) + 1, word) & + ~OpenRangeFromZeroForWord(static_cast(lo), word); + } + + // All the chars in the specified word of the range [0, upper). + static constexpr uint64_t OpenRangeFromZeroForWord(uint64_t upper, + uint64_t word) { + return (upper <= 64 * word) ? 0 + : (upper >= 64 * (word + 1)) + ? ~static_cast(0) + : (~static_cast(0) >> (64 - upper % 64)); + } + + static constexpr uint64_t CharMaskForWord(char x, uint64_t word) { + return (static_cast(x) / 64 == word) + ? (static_cast(1) + << (static_cast(x) % 64)) + : 0; + } + + constexpr void SetChar(unsigned char c) { + m_[c / 64] |= static_cast(1) << (c % 64); + } + + uint64_t m_[4]; +}; + +} // namespace absl + +#endif // ABSL_STRINGS_CHARSET_H_ diff --git a/absl/strings/internal/char_map_benchmark.cc b/absl/strings/charset_benchmark.cc similarity index 71% rename from absl/strings/internal/char_map_benchmark.cc rename to absl/strings/charset_benchmark.cc index 5cef967b308..bf7ae560678 100644 --- a/absl/strings/internal/char_map_benchmark.cc +++ b/absl/strings/charset_benchmark.cc @@ -1,4 +1,4 @@ -// Copyright 2017 The Abseil Authors. +// Copyright 2020 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,30 +12,30 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "absl/strings/internal/char_map.h" - #include #include "benchmark/benchmark.h" +#include "absl/log/check.h" +#include "absl/strings/charset.h" namespace { -absl::strings_internal::Charmap MakeBenchmarkMap() { - absl::strings_internal::Charmap m; +absl::CharSet MakeBenchmarkMap() { + absl::CharSet m; uint32_t x[] = {0x0, 0x1, 0x2, 0x3, 0xf, 0xe, 0xd, 0xc}; for (uint32_t& t : x) t *= static_cast(0x11111111UL); for (uint32_t i = 0; i < 256; ++i) { - if ((x[i / 32] >> (i % 32)) & 1) - m = m | absl::strings_internal::Charmap::Char(i); + if ((x[i / 32] >> (i % 32)) & 1) m = m | absl::CharSet::Char(i); } return m; } // Micro-benchmark for Charmap::contains. -void BM_Contains(benchmark::State& state) { +static void BM_Contains(benchmark::State& state) { // Loop-body replicated 10 times to increase time per iteration. // Argument continuously changed to avoid generating common subexpressions. - const absl::strings_internal::Charmap benchmark_map = MakeBenchmarkMap(); + // Final CHECK used to discourage unwanted optimization. + const absl::CharSet benchmark_map = MakeBenchmarkMap(); unsigned char c = 0; int ops = 0; for (auto _ : state) { @@ -50,12 +50,8 @@ void BM_Contains(benchmark::State& state) { ops += benchmark_map.contains(c++); ops += benchmark_map.contains(c++); } - benchmark::DoNotOptimize(ops); + CHECK_NE(ops, -1); } BENCHMARK(BM_Contains); -// We don't bother benchmarking Charmap::IsZero or Charmap::IntersectsWith; -// their running time is data-dependent and it is not worth characterizing -// "typical" data. - } // namespace diff --git a/absl/strings/charset_test.cc b/absl/strings/charset_test.cc new file mode 100644 index 00000000000..fff943ae647 --- /dev/null +++ b/absl/strings/charset_test.cc @@ -0,0 +1,181 @@ +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/strings/charset.h" + +#include +#include + +#include +#include + +#include "gtest/gtest.h" +#include "absl/strings/ascii.h" +#include "absl/strings/string_view.h" + +namespace { + +constexpr absl::CharSet everything_map = ~absl::CharSet(); +constexpr absl::CharSet nothing_map = absl::CharSet(); + +TEST(Charmap, AllTests) { + const absl::CharSet also_nothing_map(""); + EXPECT_TRUE(everything_map.contains('\0')); + EXPECT_FALSE(nothing_map.contains('\0')); + EXPECT_FALSE(also_nothing_map.contains('\0')); + for (unsigned char ch = 1; ch != 0; ++ch) { + SCOPED_TRACE(ch); + EXPECT_TRUE(everything_map.contains(ch)); + EXPECT_FALSE(nothing_map.contains(ch)); + EXPECT_FALSE(also_nothing_map.contains(ch)); + } + + const absl::CharSet symbols(absl::string_view("&@#@^!@?", 5)); + EXPECT_TRUE(symbols.contains('&')); + EXPECT_TRUE(symbols.contains('@')); + EXPECT_TRUE(symbols.contains('#')); + EXPECT_TRUE(symbols.contains('^')); + EXPECT_FALSE(symbols.contains('!')); + EXPECT_FALSE(symbols.contains('?')); + int cnt = 0; + for (unsigned char ch = 1; ch != 0; ++ch) cnt += symbols.contains(ch); + EXPECT_EQ(cnt, 4); + + const absl::CharSet lets(absl::string_view("^abcde", 3)); + const absl::CharSet lets2(absl::string_view("fghij\0klmnop", 10)); + const absl::CharSet lets3("fghij\0klmnop"); + EXPECT_TRUE(lets2.contains('k')); + EXPECT_FALSE(lets3.contains('k')); + + EXPECT_FALSE((symbols & lets).empty()); + EXPECT_TRUE((lets2 & lets).empty()); + EXPECT_FALSE((lets & symbols).empty()); + EXPECT_TRUE((lets & lets2).empty()); + + EXPECT_TRUE(nothing_map.empty()); + EXPECT_FALSE(lets.empty()); +} + +std::string Members(const absl::CharSet& m) { + std::string r; + for (size_t i = 0; i < 256; ++i) + if (m.contains(i)) r.push_back(i); + return r; +} + +std::string ClosedRangeString(unsigned char lo, unsigned char hi) { + // Don't depend on lo poi = {0, 1, 2, 3, 4, 7, 8, 9, 15, + 16, 17, 30, 31, 32, 33, 63, 64, 65, + 127, 128, 129, 223, 224, 225, 254, 255}; + for (auto lo = poi.begin(); lo != poi.end(); ++lo) { + SCOPED_TRACE(*lo); + for (auto hi = lo; hi != poi.end(); ++hi) { + SCOPED_TRACE(*hi); + EXPECT_EQ(Members(absl::CharSet::Range(*lo, *hi)), + ClosedRangeString(*lo, *hi)); + } + } +} + +TEST(Charmap, NullByteWithStringView) { + char characters[5] = {'a', 'b', '\0', 'd', 'x'}; + absl::string_view view(characters, 5); + absl::CharSet tester(view); + EXPECT_TRUE(tester.contains('a')); + EXPECT_TRUE(tester.contains('b')); + EXPECT_TRUE(tester.contains('\0')); + EXPECT_TRUE(tester.contains('d')); + EXPECT_TRUE(tester.contains('x')); + EXPECT_FALSE(tester.contains('c')); +} + +TEST(CharmapCtype, Match) { + for (int c = 0; c < 256; ++c) { + SCOPED_TRACE(c); + SCOPED_TRACE(static_cast(c)); + EXPECT_EQ(absl::ascii_isupper(c), + absl::CharSet::AsciiUppercase().contains(c)); + EXPECT_EQ(absl::ascii_islower(c), + absl::CharSet::AsciiLowercase().contains(c)); + EXPECT_EQ(absl::ascii_isdigit(c), absl::CharSet::AsciiDigits().contains(c)); + EXPECT_EQ(absl::ascii_isalpha(c), + absl::CharSet::AsciiAlphabet().contains(c)); + EXPECT_EQ(absl::ascii_isalnum(c), + absl::CharSet::AsciiAlphanumerics().contains(c)); + EXPECT_EQ(absl::ascii_isxdigit(c), + absl::CharSet::AsciiHexDigits().contains(c)); + EXPECT_EQ(absl::ascii_isprint(c), + absl::CharSet::AsciiPrintable().contains(c)); + EXPECT_EQ(absl::ascii_isspace(c), + absl::CharSet::AsciiWhitespace().contains(c)); + EXPECT_EQ(absl::ascii_ispunct(c), + absl::CharSet::AsciiPunctuation().contains(c)); + } +} + +} // namespace diff --git a/absl/strings/escaping.cc b/absl/strings/escaping.cc index 5bf022360e3..1c0eac42d78 100644 --- a/absl/strings/escaping.cc +++ b/absl/strings/escaping.cc @@ -26,7 +26,7 @@ #include "absl/base/internal/raw_logging.h" #include "absl/base/internal/unaligned_access.h" #include "absl/strings/ascii.h" -#include "absl/strings/internal/char_map.h" +#include "absl/strings/charset.h" #include "absl/strings/internal/escaping.h" #include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/internal/utf8.h" diff --git a/absl/strings/internal/char_map.h b/absl/strings/internal/char_map.h deleted file mode 100644 index 70a9034336d..00000000000 --- a/absl/strings/internal/char_map.h +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Character Map Class -// -// A fast, bit-vector map for 8-bit unsigned characters. -// This class is useful for non-character purposes as well. - -#ifndef ABSL_STRINGS_INTERNAL_CHAR_MAP_H_ -#define ABSL_STRINGS_INTERNAL_CHAR_MAP_H_ - -#include -#include -#include - -#include "absl/base/macros.h" -#include "absl/base/port.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace strings_internal { - -class Charmap { - public: - constexpr Charmap() : m_() {} - - // Initializes with a given char*. Note that NUL is not treated as - // a terminator, but rather a char to be flicked. - Charmap(const char* str, int len) : m_() { - while (len--) SetChar(*str++); - } - - // Initializes with a given char*. NUL is treated as a terminator - // and will not be in the charmap. - explicit Charmap(const char* str) : m_() { - while (*str) SetChar(*str++); - } - - constexpr bool contains(unsigned char c) const { - return (m_[c / 64] >> (c % 64)) & 0x1; - } - - // Returns true if and only if a character exists in both maps. - bool IntersectsWith(const Charmap& c) const { - for (size_t i = 0; i < ABSL_ARRAYSIZE(m_); ++i) { - if ((m_[i] & c.m_[i]) != 0) return true; - } - return false; - } - - bool IsZero() const { - for (uint64_t c : m_) { - if (c != 0) return false; - } - return true; - } - - // Containing only a single specified char. - static constexpr Charmap Char(char x) { - return Charmap(CharMaskForWord(x, 0), CharMaskForWord(x, 1), - CharMaskForWord(x, 2), CharMaskForWord(x, 3)); - } - - // Containing all the chars in the C-string 's'. - static constexpr Charmap FromString(const char* s) { - Charmap ret; - while (*s) ret = ret | Char(*s++); - return ret; - } - - // Containing all the chars in the closed interval [lo,hi]. - static constexpr Charmap Range(char lo, char hi) { - return Charmap(RangeForWord(lo, hi, 0), RangeForWord(lo, hi, 1), - RangeForWord(lo, hi, 2), RangeForWord(lo, hi, 3)); - } - - friend constexpr Charmap operator&(const Charmap& a, const Charmap& b) { - return Charmap(a.m_[0] & b.m_[0], a.m_[1] & b.m_[1], a.m_[2] & b.m_[2], - a.m_[3] & b.m_[3]); - } - - friend constexpr Charmap operator|(const Charmap& a, const Charmap& b) { - return Charmap(a.m_[0] | b.m_[0], a.m_[1] | b.m_[1], a.m_[2] | b.m_[2], - a.m_[3] | b.m_[3]); - } - - friend constexpr Charmap operator~(const Charmap& a) { - return Charmap(~a.m_[0], ~a.m_[1], ~a.m_[2], ~a.m_[3]); - } - - private: - constexpr Charmap(uint64_t b0, uint64_t b1, uint64_t b2, uint64_t b3) - : m_{b0, b1, b2, b3} {} - - static constexpr uint64_t RangeForWord(char lo, char hi, uint64_t word) { - return OpenRangeFromZeroForWord(static_cast(hi) + 1, word) & - ~OpenRangeFromZeroForWord(static_cast(lo), word); - } - - // All the chars in the specified word of the range [0, upper). - static constexpr uint64_t OpenRangeFromZeroForWord(uint64_t upper, - uint64_t word) { - return (upper <= 64 * word) - ? 0 - : (upper >= 64 * (word + 1)) - ? ~static_cast(0) - : (~static_cast(0) >> (64 - upper % 64)); - } - - static constexpr uint64_t CharMaskForWord(char x, uint64_t word) { - const auto unsigned_x = static_cast(x); - return (unsigned_x / 64 == word) - ? (static_cast(1) << (unsigned_x % 64)) - : 0; - } - - void SetChar(char c) { - const auto unsigned_c = static_cast(c); - m_[unsigned_c / 64] |= static_cast(1) << (unsigned_c % 64); - } - - uint64_t m_[4]; -}; - -// Mirror the char-classifying predicates in -constexpr Charmap UpperCharmap() { return Charmap::Range('A', 'Z'); } -constexpr Charmap LowerCharmap() { return Charmap::Range('a', 'z'); } -constexpr Charmap DigitCharmap() { return Charmap::Range('0', '9'); } -constexpr Charmap AlphaCharmap() { return LowerCharmap() | UpperCharmap(); } -constexpr Charmap AlnumCharmap() { return DigitCharmap() | AlphaCharmap(); } -constexpr Charmap XDigitCharmap() { - return DigitCharmap() | Charmap::Range('A', 'F') | Charmap::Range('a', 'f'); -} -constexpr Charmap PrintCharmap() { return Charmap::Range(0x20, 0x7e); } -constexpr Charmap SpaceCharmap() { return Charmap::FromString("\t\n\v\f\r "); } -constexpr Charmap CntrlCharmap() { - return Charmap::Range(0, 0x7f) & ~PrintCharmap(); -} -constexpr Charmap BlankCharmap() { return Charmap::FromString("\t "); } -constexpr Charmap GraphCharmap() { return PrintCharmap() & ~SpaceCharmap(); } -constexpr Charmap PunctCharmap() { return GraphCharmap() & ~AlnumCharmap(); } - -} // namespace strings_internal -ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_STRINGS_INTERNAL_CHAR_MAP_H_ diff --git a/absl/strings/internal/char_map_test.cc b/absl/strings/internal/char_map_test.cc deleted file mode 100644 index d3306241a40..00000000000 --- a/absl/strings/internal/char_map_test.cc +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2017 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "absl/strings/internal/char_map.h" - -#include -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -namespace { - -constexpr absl::strings_internal::Charmap everything_map = - ~absl::strings_internal::Charmap(); -constexpr absl::strings_internal::Charmap nothing_map{}; - -TEST(Charmap, AllTests) { - const absl::strings_internal::Charmap also_nothing_map("", 0); - ASSERT_TRUE(everything_map.contains('\0')); - ASSERT_TRUE(!nothing_map.contains('\0')); - ASSERT_TRUE(!also_nothing_map.contains('\0')); - for (unsigned char ch = 1; ch != 0; ++ch) { - ASSERT_TRUE(everything_map.contains(ch)); - ASSERT_TRUE(!nothing_map.contains(ch)); - ASSERT_TRUE(!also_nothing_map.contains(ch)); - } - - const absl::strings_internal::Charmap symbols("&@#@^!@?", 5); - ASSERT_TRUE(symbols.contains('&')); - ASSERT_TRUE(symbols.contains('@')); - ASSERT_TRUE(symbols.contains('#')); - ASSERT_TRUE(symbols.contains('^')); - ASSERT_TRUE(!symbols.contains('!')); - ASSERT_TRUE(!symbols.contains('?')); - int cnt = 0; - for (unsigned char ch = 1; ch != 0; ++ch) - cnt += symbols.contains(ch); - ASSERT_EQ(cnt, 4); - - const absl::strings_internal::Charmap lets("^abcde", 3); - const absl::strings_internal::Charmap lets2("fghij\0klmnop", 10); - const absl::strings_internal::Charmap lets3("fghij\0klmnop"); - ASSERT_TRUE(lets2.contains('k')); - ASSERT_TRUE(!lets3.contains('k')); - - ASSERT_TRUE(symbols.IntersectsWith(lets)); - ASSERT_TRUE(!lets2.IntersectsWith(lets)); - ASSERT_TRUE(lets.IntersectsWith(symbols)); - ASSERT_TRUE(!lets.IntersectsWith(lets2)); - - ASSERT_TRUE(nothing_map.IsZero()); - ASSERT_TRUE(!lets.IsZero()); -} - -namespace { -std::string Members(const absl::strings_internal::Charmap& m) { - std::string r; - for (size_t i = 0; i < 256; ++i) - if (m.contains(i)) r.push_back(i); - return r; -} - -std::string ClosedRangeString(unsigned char lo, unsigned char hi) { - // Don't depend on lo poi = {0, 1, 2, 3, 4, 7, 8, 9, 15, - 16, 17, 30, 31, 32, 33, 63, 64, 65, - 127, 128, 129, 223, 224, 225, 254, 255}; - for (auto lo = poi.begin(); lo != poi.end(); ++lo) { - SCOPED_TRACE(*lo); - for (auto hi = lo; hi != poi.end(); ++hi) { - SCOPED_TRACE(*hi); - EXPECT_THAT(Members(absl::strings_internal::Charmap::Range(*lo, *hi)), - ClosedRangeString(*lo, *hi)); - } - } -} - -bool AsBool(int x) { return static_cast(x); } - -TEST(CharmapCtype, Match) { - for (int c = 0; c < 256; ++c) { - SCOPED_TRACE(c); - SCOPED_TRACE(static_cast(c)); - EXPECT_EQ(AsBool(std::isupper(c)), - absl::strings_internal::UpperCharmap().contains(c)); - EXPECT_EQ(AsBool(std::islower(c)), - absl::strings_internal::LowerCharmap().contains(c)); - EXPECT_EQ(AsBool(std::isdigit(c)), - absl::strings_internal::DigitCharmap().contains(c)); - EXPECT_EQ(AsBool(std::isalpha(c)), - absl::strings_internal::AlphaCharmap().contains(c)); - EXPECT_EQ(AsBool(std::isalnum(c)), - absl::strings_internal::AlnumCharmap().contains(c)); - EXPECT_EQ(AsBool(std::isxdigit(c)), - absl::strings_internal::XDigitCharmap().contains(c)); - EXPECT_EQ(AsBool(std::isprint(c)), - absl::strings_internal::PrintCharmap().contains(c)); - EXPECT_EQ(AsBool(std::isspace(c)), - absl::strings_internal::SpaceCharmap().contains(c)); - EXPECT_EQ(AsBool(std::iscntrl(c)), - absl::strings_internal::CntrlCharmap().contains(c)); - EXPECT_EQ(AsBool(std::isblank(c)), - absl::strings_internal::BlankCharmap().contains(c)); - EXPECT_EQ(AsBool(std::isgraph(c)), - absl::strings_internal::GraphCharmap().contains(c)); - EXPECT_EQ(AsBool(std::ispunct(c)), - absl::strings_internal::PunctCharmap().contains(c)); - } -} - -} // namespace From 8ebad34c3fa54a9ad2f46ca8cab98e75c4f750bf Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Wed, 23 Aug 2023 11:33:26 -0700 Subject: [PATCH 0181/1238] Delete the experimental conformance testing code. This project was never completed. PiperOrigin-RevId: 559492534 Change-Id: Ie4e9661e25731418979ad10669ac946e1c4d60c2 --- CMake/AbseilDll.cmake | 5 - absl/types/BUILD.bazel | 38 - absl/types/CMakeLists.txt | 53 - absl/types/internal/conformance_aliases.h | 447 ----- absl/types/internal/conformance_archetype.h | 978 ----------- absl/types/internal/conformance_profile.h | 933 ---------- absl/types/internal/conformance_testing.h | 1386 --------------- .../internal/conformance_testing_helpers.h | 391 ----- .../internal/conformance_testing_test.cc | 1556 ----------------- absl/types/internal/parentheses.h | 34 - absl/types/internal/transform_args.h | 246 --- 11 files changed, 6067 deletions(-) delete mode 100644 absl/types/internal/conformance_aliases.h delete mode 100644 absl/types/internal/conformance_archetype.h delete mode 100644 absl/types/internal/conformance_profile.h delete mode 100644 absl/types/internal/conformance_testing.h delete mode 100644 absl/types/internal/conformance_testing_helpers.h delete mode 100644 absl/types/internal/conformance_testing_test.cc delete mode 100644 absl/types/internal/parentheses.h delete mode 100644 absl/types/internal/transform_args.h diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index 1a20a84fcf4..9024a06b2f5 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake @@ -423,11 +423,6 @@ set(ABSL_INTERNAL_DLL_FILES "types/bad_variant_access.cc" "types/bad_variant_access.h" "types/compare.h" - "types/internal/conformance_aliases.h" - "types/internal/conformance_archetype.h" - "types/internal/conformance_profile.h" - "types/internal/parentheses.h" - "types/internal/transform_args.h" "types/internal/variant.h" "types/optional.h" "types/internal/optional.h" diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel index b57d3b9bfd2..34f398bbe1a 100644 --- a/absl/types/BUILD.bazel +++ b/absl/types/BUILD.bazel @@ -207,44 +207,6 @@ cc_test( ], ) -cc_library( - name = "conformance_testing", - testonly = 1, - hdrs = [ - "internal/conformance_aliases.h", - "internal/conformance_archetype.h", - "internal/conformance_profile.h", - "internal/conformance_testing.h", - "internal/conformance_testing_helpers.h", - "internal/parentheses.h", - "internal/transform_args.h", - ], - copts = ABSL_TEST_COPTS, - linkopts = ABSL_DEFAULT_LINKOPTS, - deps = [ - "//absl/algorithm:container", - "//absl/meta:type_traits", - "//absl/strings", - "//absl/utility", - "@com_google_googletest//:gtest", - ], -) - -cc_test( - name = "conformance_testing_test", - size = "small", - srcs = [ - "internal/conformance_testing_test.cc", - ], - copts = ABSL_TEST_COPTS, - linkopts = ABSL_DEFAULT_LINKOPTS, - deps = [ - ":conformance_testing", - "//absl/meta:type_traits", - "@com_google_googletest//:gtest_main", - ], -) - cc_library( name = "variant", srcs = ["internal/variant.h"], diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt index c0dcee79bec..1adf3c72c20 100644 --- a/absl/types/CMakeLists.txt +++ b/absl/types/CMakeLists.txt @@ -240,59 +240,6 @@ absl_cc_test( GTest::gmock_main ) -# Internal-only target, do not depend on directly. -absl_cc_library( - NAME - conformance_testing - HDRS - "internal/conformance_aliases.h" - "internal/conformance_archetype.h" - "internal/conformance_profile.h" - "internal/conformance_testing.h" - "internal/conformance_testing_helpers.h" - "internal/parentheses.h" - "internal/transform_args.h" - COPTS - ${ABSL_DEFAULT_COPTS} - DEPS - absl::algorithm - absl::debugging - absl::type_traits - absl::strings - absl::utility - GTest::gmock_main - TESTONLY -) - -absl_cc_test( - NAME - conformance_testing_test - SRCS - "internal/conformance_testing_test.cc" - COPTS - ${ABSL_TEST_COPTS} - ${ABSL_EXCEPTIONS_FLAG} - LINKOPTS - ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} - DEPS - absl::conformance_testing - absl::type_traits - GTest::gmock_main -) - -absl_cc_test( - NAME - conformance_testing_test_no_exceptions - SRCS - "internal/conformance_testing_test.cc" - COPTS - ${ABSL_TEST_COPTS} - DEPS - absl::conformance_testing - absl::type_traits - GTest::gmock_main -) - absl_cc_library( NAME variant diff --git a/absl/types/internal/conformance_aliases.h b/absl/types/internal/conformance_aliases.h deleted file mode 100644 index 0cc6884e309..00000000000 --- a/absl/types/internal/conformance_aliases.h +++ /dev/null @@ -1,447 +0,0 @@ -// Copyright 2018 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// ----------------------------------------------------------------------------- -// regularity_aliases.h -// ----------------------------------------------------------------------------- -// -// This file contains type aliases of common ConformanceProfiles and Archetypes -// so that they can be directly used by name without creating them from scratch. - -#ifndef ABSL_TYPES_INTERNAL_CONFORMANCE_ALIASES_H_ -#define ABSL_TYPES_INTERNAL_CONFORMANCE_ALIASES_H_ - -#include "absl/types/internal/conformance_archetype.h" -#include "absl/types/internal/conformance_profile.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace types_internal { - -// Creates both a Profile and a corresponding Archetype with root name "name". -#define ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(name, ...) \ - struct name##Profile : __VA_ARGS__ {}; \ - \ - using name##Archetype = ::absl::types_internal::Archetype; \ - \ - template \ - using name##Archetype##_ = ::absl::types_internal::Archetype< \ - ::absl::types_internal::StrongProfileTypedef> - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasTrivialDefaultConstructor, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasNothrowDefaultConstructor, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasDefaultConstructor, ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasTrivialMoveConstructor, ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasNothrowMoveConstructor, ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasMoveConstructor, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasTrivialCopyConstructor, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasNothrowCopyConstructor, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasCopyConstructor, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasTrivialMoveAssign, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasNothrowMoveAssign, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasMoveAssign, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasTrivialCopyAssign, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasNothrowCopyAssign, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasCopyAssign, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasTrivialDestructor, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasNothrowDestructor, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasDestructor, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasNothrowEquality, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasEquality, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasNothrowInequality, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasInequality, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasNothrowLessThan, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasLessThan, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasNothrowLessEqual, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasLessEqual, - ConformanceProfile); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasNothrowGreaterEqual, - ConformanceProfile< - default_constructible::maybe, move_constructible::maybe, - copy_constructible::maybe, move_assignable::maybe, - copy_assignable::maybe, destructible::maybe, equality_comparable::maybe, - inequality_comparable::maybe, less_than_comparable::maybe, - less_equal_comparable::maybe, greater_equal_comparable::nothrow>); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasGreaterEqual, - ConformanceProfile< - default_constructible::maybe, move_constructible::maybe, - copy_constructible::maybe, move_assignable::maybe, - copy_assignable::maybe, destructible::maybe, equality_comparable::maybe, - inequality_comparable::maybe, less_than_comparable::maybe, - less_equal_comparable::maybe, greater_equal_comparable::yes>); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasNothrowGreaterThan, - ConformanceProfile< - default_constructible::maybe, move_constructible::maybe, - copy_constructible::maybe, move_assignable::maybe, - copy_assignable::maybe, destructible::maybe, equality_comparable::maybe, - inequality_comparable::maybe, less_than_comparable::maybe, - less_equal_comparable::maybe, greater_equal_comparable::maybe, - greater_than_comparable::nothrow>); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasGreaterThan, - ConformanceProfile< - default_constructible::maybe, move_constructible::maybe, - copy_constructible::maybe, move_assignable::maybe, - copy_assignable::maybe, destructible::maybe, equality_comparable::maybe, - inequality_comparable::maybe, less_than_comparable::maybe, - less_equal_comparable::maybe, greater_equal_comparable::maybe, - greater_than_comparable::yes>); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasNothrowSwap, - ConformanceProfile< - default_constructible::maybe, move_constructible::maybe, - copy_constructible::maybe, move_assignable::maybe, - copy_assignable::maybe, destructible::maybe, equality_comparable::maybe, - inequality_comparable::maybe, less_than_comparable::maybe, - less_equal_comparable::maybe, greater_equal_comparable::maybe, - greater_than_comparable::maybe, swappable::nothrow>); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasSwap, - ConformanceProfile< - default_constructible::maybe, move_constructible::maybe, - copy_constructible::maybe, move_assignable::maybe, - copy_assignable::maybe, destructible::maybe, equality_comparable::maybe, - inequality_comparable::maybe, less_than_comparable::maybe, - less_equal_comparable::maybe, greater_equal_comparable::maybe, - greater_than_comparable::maybe, swappable::yes>); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HasStdHashSpecialization, - ConformanceProfile< - default_constructible::maybe, move_constructible::maybe, - copy_constructible::maybe, move_assignable::maybe, - copy_assignable::maybe, destructible::maybe, equality_comparable::maybe, - inequality_comparable::maybe, less_than_comparable::maybe, - less_equal_comparable::maybe, greater_equal_comparable::maybe, - greater_than_comparable::maybe, swappable::maybe, hashable::yes>); - -//////////////////////////////////////////////////////////////////////////////// -//// The remaining aliases are combinations of the previous aliases. //// -//////////////////////////////////////////////////////////////////////////////// - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - Equatable, CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - Comparable, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - NothrowEquatable, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - NothrowComparable, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - Value, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - EquatableValue, CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - ComparableValue, CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - DefaultConstructibleValue, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - NothrowMoveConstructible, CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - EquatableNothrowMoveConstructible, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - ComparableNothrowMoveConstructible, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - DefaultConstructibleNothrowMoveConstructible, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - CopyConstructible, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - EquatableCopyConstructible, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - ComparableCopyConstructible, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - DefaultConstructibleCopyConstructible, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - NothrowMovable, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - EquatableNothrowMovable, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - ComparableNothrowMovable, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - DefaultConstructibleNothrowMovable, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - TrivialSpecialMemberFunctions, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - TriviallyComplete, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HashableNothrowMoveConstructible, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HashableCopyConstructible, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HashableNothrowMovable, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - HashableValue, - CombineProfiles); - -ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS( - ComparableHashableValue, - CombineProfiles); - -// The "preferred" profiles that we support in Abseil. -template