summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--absl/BUILD.bazel7
-rw-r--r--absl/algorithm/container.h18
-rw-r--r--absl/algorithm/container_test.cc6
-rw-r--r--absl/base/BUILD.bazel16
-rw-r--r--absl/base/CMakeLists.txt9
-rw-r--r--absl/base/attributes.h1
-rw-r--r--absl/container/inlined_vector_exception_safety_test.cc4
-rw-r--r--absl/container/internal/common.h4
-rw-r--r--absl/container/internal/raw_hash_set.h11
-rw-r--r--absl/copts/configure_copts.bzl2
-rw-r--r--absl/debugging/CMakeLists.txt2
-rw-r--r--absl/debugging/internal/stack_consumption.cc12
-rw-r--r--absl/flags/BUILD.bazel3
-rw-r--r--absl/flags/flag.cc4
-rw-r--r--absl/flags/flag.h8
-rw-r--r--absl/flags/internal/commandlineflag.cc6
-rw-r--r--absl/flags/internal/commandlineflag.h24
-rw-r--r--absl/flags/internal/flag.h85
-rw-r--r--absl/flags/internal/registry.cc106
-rw-r--r--absl/random/BUILD.bazel2
-rw-r--r--absl/random/distribution_format_traits.h22
-rw-r--r--absl/random/distributions.h56
-rw-r--r--absl/random/internal/distributions.h30
-rw-r--r--absl/random/internal/uniform_helper.h12
-rw-r--r--absl/strings/BUILD.bazel1
-rw-r--r--absl/strings/CMakeLists.txt1
-rw-r--r--absl/strings/charconv_test.cc7
-rw-r--r--absl/strings/internal/charconv_parse.cc6
-rw-r--r--absl/strings/internal/str_format/convert_test.cc110
-rw-r--r--absl/strings/numbers_test.cc14
-rw-r--r--absl/strings/string_view.h62
-rw-r--r--absl/strings/string_view_test.cc23
-rw-r--r--absl/synchronization/internal/waiter.cc27
-rw-r--r--absl/synchronization/internal/waiter.h2
-rw-r--r--absl/synchronization/mutex.h2
-rw-r--r--absl/time/duration.cc5
-rw-r--r--absl/time/format.cc8
-rw-r--r--absl/time/internal/cctz/src/time_zone_impl.cc11
-rw-r--r--absl/time/time.cc14
-rw-r--r--absl/time/time.h9
-rw-r--r--absl/time/time_test.cc24
41 files changed, 485 insertions, 291 deletions
diff --git a/absl/BUILD.bazel b/absl/BUILD.bazel
index 853330d4..5a03acf8 100644
--- a/absl/BUILD.bazel
+++ b/absl/BUILD.bazel
@@ -14,12 +14,15 @@
# limitations under the License.
#
+load(
+ ":compiler_config_setting.bzl",
+ "create_llvm_config",
+)
+
package(default_visibility = ["//visibility:public"])
licenses(["notice"]) # Apache 2.0
-load(":compiler_config_setting.bzl", "create_llvm_config")
-
create_llvm_config(
name = "llvm_compiler",
visibility = [":__subpackages__"],
diff --git a/absl/algorithm/container.h b/absl/algorithm/container.h
index c84de461..adcea8a7 100644
--- a/absl/algorithm/container.h
+++ b/absl/algorithm/container.h
@@ -112,6 +112,18 @@ template <class Key, class Hash, class KeyEqual, class Allocator>
struct IsUnorderedContainer<std::unordered_set<Key, Hash, KeyEqual, Allocator>>
: std::true_type {};
+// container_algorithm_internal::c_size. It is meant for internal use only.
+
+template <class C>
+auto c_size(C& c) -> decltype(c.size()) {
+ return c.size();
+}
+
+template <class T, std::size_t N>
+constexpr std::size_t c_size(T (&)[N]) {
+ return N;
+}
+
} // namespace container_algorithm_internal
// PUBLIC API
@@ -365,7 +377,8 @@ c_mismatch(C1& c1, C2& c2, BinaryPredicate&& pred) {
template <typename C1, typename C2>
bool c_equal(const C1& c1, const C2& c2) {
- return ((c1.size() == c2.size()) &&
+ return ((container_algorithm_internal::c_size(c1) ==
+ container_algorithm_internal::c_size(c2)) &&
std::equal(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2)));
@@ -375,7 +388,8 @@ bool c_equal(const C1& c1, const C2& c2) {
// the function's test condition.
template <typename C1, typename C2, typename BinaryPredicate>
bool c_equal(const C1& c1, const C2& c2, BinaryPredicate&& pred) {
- return ((c1.size() == c2.size()) &&
+ return ((container_algorithm_internal::c_size(c1) ==
+ container_algorithm_internal::c_size(c2)) &&
std::equal(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2),
diff --git a/absl/algorithm/container_test.cc b/absl/algorithm/container_test.cc
index 86bf9d3e..0a4abe94 100644
--- a/absl/algorithm/container_test.cc
+++ b/absl/algorithm/container_test.cc
@@ -163,23 +163,29 @@ TEST_F(NonMutatingTest, MismatchWithPredicate) {
TEST_F(NonMutatingTest, Equal) {
EXPECT_TRUE(absl::c_equal(vector_, sequence_));
EXPECT_TRUE(absl::c_equal(sequence_, vector_));
+ EXPECT_TRUE(absl::c_equal(sequence_, array_));
+ EXPECT_TRUE(absl::c_equal(array_, vector_));
// Test that behavior appropriately differs from that of equal().
std::vector<int> vector_plus = {1, 2, 3};
vector_plus.push_back(4);
EXPECT_FALSE(absl::c_equal(vector_plus, sequence_));
EXPECT_FALSE(absl::c_equal(sequence_, vector_plus));
+ EXPECT_FALSE(absl::c_equal(array_, vector_plus));
}
TEST_F(NonMutatingTest, EqualWithPredicate) {
EXPECT_TRUE(absl::c_equal(vector_, sequence_, Equals));
EXPECT_TRUE(absl::c_equal(sequence_, vector_, Equals));
+ EXPECT_TRUE(absl::c_equal(array_, sequence_, Equals));
+ EXPECT_TRUE(absl::c_equal(vector_, array_, Equals));
// Test that behavior appropriately differs from that of equal().
std::vector<int> vector_plus = {1, 2, 3};
vector_plus.push_back(4);
EXPECT_FALSE(absl::c_equal(vector_plus, sequence_, Equals));
EXPECT_FALSE(absl::c_equal(sequence_, vector_plus, Equals));
+ EXPECT_FALSE(absl::c_equal(vector_plus, array_, Equals));
}
TEST_F(NonMutatingTest, IsPermutation) {
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
index 1e1f0d2d..d74bac63 100644
--- a/absl/base/BUILD.bazel
+++ b/absl/base/BUILD.bazel
@@ -71,16 +71,16 @@ cc_library(
"internal/spinlock_wait.cc",
"internal/spinlock_win32.inc",
],
- hdrs = [
- "internal/scheduling_mode.h",
- "internal/spinlock_wait.h",
- ],
+ hdrs = ["internal/spinlock_wait.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl/base:__pkg__",
],
- deps = [":core_headers"],
+ deps = [
+ ":base_internal",
+ ":core_headers",
+ ],
)
cc_library(
@@ -141,11 +141,11 @@ cc_library(
],
deps = [
":base",
+ ":base_internal",
":config",
":core_headers",
":dynamic_annotations",
":raw_logging_internal",
- ":spinlock_wait",
],
)
@@ -369,8 +369,8 @@ cc_library(
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":base",
+ ":base_internal",
":core_headers",
- ":spinlock_wait",
"//absl/synchronization",
"@com_google_googletest//:gtest",
],
@@ -385,8 +385,8 @@ cc_test(
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":base",
+ ":base_internal",
":core_headers",
- ":spinlock_wait",
"//absl/synchronization",
"@com_google_googletest//:gtest_main",
],
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt
index 51705a5a..79ee5b93 100644
--- a/absl/base/CMakeLists.txt
+++ b/absl/base/CMakeLists.txt
@@ -56,7 +56,6 @@ absl_cc_library(
NAME
spinlock_wait
HDRS
- "internal/scheduling_mode.h"
"internal/spinlock_wait.h"
SRCS
"internal/spinlock_akaros.inc"
@@ -67,6 +66,7 @@ absl_cc_library(
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
+ absl::base_internal
absl::core_headers
)
@@ -125,11 +125,11 @@ absl_cc_library(
${ABSL_DEFAULT_COPTS}
DEPS
absl::base
+ absl::base_internal
absl::config
absl::core_headers
absl::dynamic_annotations
absl::raw_logging_internal
- absl::spinlock_wait
Threads::Threads
)
@@ -141,6 +141,7 @@ absl_cc_library(
"internal/identity.h"
"internal/inline_variable.h"
"internal/invoke.h"
+ "internal/scheduling_mode.h"
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
@@ -348,8 +349,8 @@ absl_cc_library(
${ABSL_TEST_COPTS}
DEPS
absl::base
+ absl::base_internal
absl::core_headers
- absl::spinlock_wait
absl::synchronization
gtest
TESTONLY
@@ -365,8 +366,8 @@ absl_cc_test(
${ABSL_TEST_COPTS}
DEPS
absl::base
+ absl::base_internal
absl::core_headers
- absl::spinlock_wait
absl::synchronization
gtest_main
)
diff --git a/absl/base/attributes.h b/absl/base/attributes.h
index f298297e..7b7656a8 100644
--- a/absl/base/attributes.h
+++ b/absl/base/attributes.h
@@ -599,7 +599,6 @@
//
// Note that this attribute is redundant if the variable is declared constexpr.
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
-// NOLINTNEXTLINE(whitespace/braces)
#define ABSL_CONST_INIT [[clang::require_constant_initialization]]
#else
#define ABSL_CONST_INIT
diff --git a/absl/container/inlined_vector_exception_safety_test.cc b/absl/container/inlined_vector_exception_safety_test.cc
index 25994f16..937e43a5 100644
--- a/absl/container/inlined_vector_exception_safety_test.cc
+++ b/absl/container/inlined_vector_exception_safety_test.cc
@@ -16,7 +16,7 @@
#include "absl/base/config.h"
-#ifdef ABSL_HAVE_EXCEPTIONS
+#if defined(ABSL_HAVE_EXCEPTIONS)
#include <array>
#include <initializer_list>
@@ -493,4 +493,4 @@ TYPED_TEST(TwoSizeTest, Swap) {
} // namespace
-#endif // ABSL_HAVE_EXCEPTIONS
+#endif // defined(ABSL_HAVE_EXCEPTIONS)
diff --git a/absl/container/internal/common.h b/absl/container/internal/common.h
index 591d3ea1..4bd5d469 100644
--- a/absl/container/internal/common.h
+++ b/absl/container/internal/common.h
@@ -117,7 +117,7 @@ class node_handle_base {
template <typename Policy, typename PolicyTraits, typename Alloc,
typename = void>
class node_handle : public node_handle_base<PolicyTraits, Alloc> {
- using Base = typename node_handle::node_handle_base;
+ using Base = node_handle_base<PolicyTraits, Alloc>;
public:
using value_type = typename PolicyTraits::value_type;
@@ -137,7 +137,7 @@ template <typename Policy, typename PolicyTraits, typename Alloc>
class node_handle<Policy, PolicyTraits, Alloc,
absl::void_t<typename Policy::mapped_type>>
: public node_handle_base<PolicyTraits, Alloc> {
- using Base = typename node_handle::node_handle_base;
+ using Base = node_handle_base<PolicyTraits, Alloc>;
public:
using key_type = typename Policy::key_type;
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index 2e6f4dd3..42b3c468 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -938,8 +938,11 @@ class raw_hash_set {
//
// flat_hash_map<std::string, int> m;
// m.insert(std::make_pair("abc", 42));
+ // TODO(cheshire): A type alias T2 is introduced as a workaround for the nvcc
+ // bug.
template <class T, RequiresInsertable<T> = 0,
- typename std::enable_if<IsDecomposable<T>::value, int>::type = 0,
+ class T2 = T,
+ typename std::enable_if<IsDecomposable<T2>::value, int>::type = 0,
T* = nullptr>
std::pair<iterator, bool> insert(T&& value) {
return emplace(std::forward<T>(value));
@@ -975,8 +978,10 @@ class raw_hash_set {
return emplace(std::move(value));
}
- template <class T, RequiresInsertable<T> = 0,
- typename std::enable_if<IsDecomposable<T>::value, int>::type = 0,
+ // TODO(cheshire): A type alias T2 is introduced as a workaround for the nvcc
+ // bug.
+ template <class T, RequiresInsertable<T> = 0, class T2 = T,
+ typename std::enable_if<IsDecomposable<T2>::value, int>::type = 0,
T* = nullptr>
iterator insert(const_iterator, T&& value) {
return insert(std::forward<T>(value)).first;
diff --git a/absl/copts/configure_copts.bzl b/absl/copts/configure_copts.bzl
index 2829e4ec..9dd6bd0a 100644
--- a/absl/copts/configure_copts.bzl
+++ b/absl/copts/configure_copts.bzl
@@ -6,6 +6,8 @@ change Abseil copts, edit absl/copts/copts.py
load(
"//absl:copts/GENERATED_copts.bzl",
+ "ABSL_CLANG_CL_FLAGS",
+ "ABSL_CLANG_CL_TEST_FLAGS",
"ABSL_GCC_FLAGS",
"ABSL_GCC_TEST_FLAGS",
"ABSL_LLVM_FLAGS",
diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt
index c409e33e..81492c0c 100644
--- a/absl/debugging/CMakeLists.txt
+++ b/absl/debugging/CMakeLists.txt
@@ -238,7 +238,7 @@ absl_cc_test(
SRCS
"leak_check_test.cc"
COPTS
- ${ABSL_DEFAULT_COPTS}
+ ${ABSL_TEST_COPTS}
"$<$<BOOL:${ABSL_HAVE_LSAN}>:-DABSL_EXPECT_LEAK_SANITIZER>"
LINKOPTS
"${ABSL_LSAN_LINKOPTS}"
diff --git a/absl/debugging/internal/stack_consumption.cc b/absl/debugging/internal/stack_consumption.cc
index 4b05f495..d4703264 100644
--- a/absl/debugging/internal/stack_consumption.cc
+++ b/absl/debugging/internal/stack_consumption.cc
@@ -115,10 +115,11 @@ int GetSignalHandlerStackConsumption(void (*signal_handler)(int)) {
// Set up the alt-signal-stack (and save the older one).
stack_t sigstk;
memset(&sigstk, 0, sizeof(sigstk));
- stack_t old_sigstk;
sigstk.ss_sp = altstack;
sigstk.ss_size = kAlternateStackSize;
sigstk.ss_flags = 0;
+ stack_t old_sigstk;
+ memset(&old_sigstk, 0, sizeof(old_sigstk));
ABSL_RAW_CHECK(sigaltstack(&sigstk, &old_sigstk) == 0,
"sigaltstack() failed");
@@ -152,6 +153,15 @@ int GetSignalHandlerStackConsumption(void (*signal_handler)(int)) {
int signal_handler_stack_consumption = GetStackConsumption(altstack);
// Now restore the old alt-signal-stack and signal handlers.
+ if (old_sigstk.ss_sp == nullptr && old_sigstk.ss_size == 0 &&
+ (old_sigstk.ss_flags & SS_DISABLE)) {
+ // https://git.musl-libc.org/cgit/musl/commit/src/signal/sigaltstack.c?id=7829f42a2c8944555439380498ab8b924d0f2070
+ // The original stack has ss_size==0 and ss_flags==SS_DISABLE, but some
+ // versions of musl have a bug that rejects ss_size==0. Work around this by
+ // setting ss_size to MINSIGSTKSZ, which should be ignored by the kernel
+ // when SS_DISABLE is set.
+ old_sigstk.ss_size = MINSIGSTKSZ;
+ }
ABSL_RAW_CHECK(sigaltstack(&old_sigstk, nullptr) == 0,
"sigaltstack() failed");
ABSL_RAW_CHECK(sigaction(SIGUSR1, &old_sa1, nullptr) == 0,
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel
index 2bf562f8..2e0dc389 100644
--- a/absl/flags/BUILD.bazel
+++ b/absl/flags/BUILD.bazel
@@ -40,6 +40,8 @@ cc_library(
deps = [
":handle",
":registry",
+ "//absl/memory",
+ "//absl/strings",
"//absl/synchronization",
],
)
@@ -184,6 +186,7 @@ cc_library(
":marshalling",
"//absl/base",
"//absl/base:core_headers",
+ "//absl/memory",
"//absl/strings",
],
)
diff --git a/absl/flags/flag.cc b/absl/flags/flag.cc
index a02d069e..69038bbf 100644
--- a/absl/flags/flag.cc
+++ b/absl/flags/flag.cc
@@ -49,9 +49,7 @@ namespace flags_internal {
ABSL_CONST_INIT static absl::Mutex construction_guard(absl::kConstInit);
-void LockGlobalConstructionGuard() { construction_guard.Lock(); }
-
-void UnlockGlobalConstructionGuard() { construction_guard.Unlock(); }
+absl::Mutex* GetGlobalConstructionGuard() { return &construction_guard; }
} // namespace flags_internal
diff --git a/absl/flags/flag.h b/absl/flags/flag.h
index 86ad59dd..4927757b 100644
--- a/absl/flags/flag.h
+++ b/absl/flags/flag.h
@@ -80,8 +80,7 @@ using Flag = flags_internal::Flag<T>;
// if two threads attempt to construct the flag concurrently only one wins.
namespace flags_internal {
-void LockGlobalConstructionGuard();
-void UnlockGlobalConstructionGuard();
+absl::Mutex* GetGlobalConstructionGuard();
} // namespace flags_internal
template <typename T>
@@ -100,7 +99,7 @@ class Flag {
flags_internal::Flag<T>* GetImpl() const {
if (!inited_.load(std::memory_order_acquire)) {
- flags_internal::LockGlobalConstructionGuard();
+ absl::MutexLock l(flags_internal::GetGlobalConstructionGuard());
if (inited_.load(std::memory_order_acquire)) {
return impl_;
@@ -109,8 +108,6 @@ class Flag {
impl_ = new flags_internal::Flag<T>(name_, help_gen_, filename_,
marshalling_op_, initial_value_gen_);
inited_.store(true, std::memory_order_release);
-
- flags_internal::UnlockGlobalConstructionGuard();
}
return impl_;
@@ -130,7 +127,6 @@ class Flag {
std::string Filename() const { return GetImpl()->Filename(); }
std::string DefaultValue() const { return GetImpl()->DefaultValue(); }
std::string CurrentValue() const { return GetImpl()->CurrentValue(); }
- bool HasValidatorFn() const { return GetImpl()->HasValidatorFn(); }
bool InvokeValidator(const void* value) const {
return GetImpl()->InvokeValidator(value);
}
diff --git a/absl/flags/internal/commandlineflag.cc b/absl/flags/internal/commandlineflag.cc
index 53e2b84e..99f73611 100644
--- a/absl/flags/internal/commandlineflag.cc
+++ b/absl/flags/internal/commandlineflag.cc
@@ -149,6 +149,12 @@ std::string CommandLineFlag::CurrentValue() const {
return Unparse(marshalling_op_, cur_);
}
+int64_t CommandLineFlag::MutationCounter() const {
+ absl::MutexLock l(InitFlagIfNecessary());
+
+ return counter_;
+}
+
// Attempts to parse supplied `value` string using parsing routine in the `flag`
// argument. If parsing is successful, it will try to validate that the parsed
// value is valid for the specified 'flag'. Finally this function stores the
diff --git a/absl/flags/internal/commandlineflag.h b/absl/flags/internal/commandlineflag.h
index 284286b6..528d3106 100644
--- a/absl/flags/internal/commandlineflag.h
+++ b/absl/flags/internal/commandlineflag.h
@@ -17,6 +17,7 @@
#define ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
#include <atomic>
+#include <memory>
#include "absl/base/macros.h"
#include "absl/flags/marshalling.h"
@@ -186,6 +187,16 @@ class HelpText {
const char* help_message_;
};
+// Handle to FlagState objects. Specific flag state objects will restore state
+// of a flag produced this flag state from method CommandLineFlag::SaveState().
+class FlagStateInterface {
+ public:
+ virtual ~FlagStateInterface() {}
+
+ // Restores the flag originated this object to the saved state.
+ virtual void Restore() const = 0;
+};
+
// Holds all information for a flag.
class CommandLineFlag {
public:
@@ -239,7 +250,6 @@ class CommandLineFlag {
virtual void StoreAtomic() {}
// Interfaces to operate on validators.
- virtual bool HasValidatorFn() const { return false; }
virtual bool InvokeValidator(const void* /*value*/) const { return true; }
// Invoke the flag validators for old flags.
// TODO(rogeeff): implement proper validators for Abseil Flags
@@ -264,6 +274,10 @@ class CommandLineFlag {
return res;
}
+ // Interface to save flag to some persistent state. Returns current flag state
+ // or nullptr if flag does not support saving and restoring a state.
+ virtual std::unique_ptr<FlagStateInterface> SaveState() = 0;
+
// Interfaces to overate on callbacks.
virtual void InvokeCallback() {}
@@ -285,6 +299,9 @@ class CommandLineFlag {
protected:
~CommandLineFlag() = default;
+ // Thread safe access to mutation counter.
+ int64_t MutationCounter() const;
+
const char* const name_;
const HelpText help_;
const char* const filename_;
@@ -323,11 +340,6 @@ class CommandLineFlag {
friend bool TryParseLocked(CommandLineFlag* flag, void* dst,
absl::string_view value, std::string* err);
friend absl::Mutex* InitFlag(CommandLineFlag* flag);
-
- // This is a short term, until we completely rework persistent state
- // storage API.
- virtual void* GetValidator() const { return nullptr; }
- virtual bool SetValidator(void*) { return false; }
};
// Update any copy of the flag value that is stored in an atomic word.
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h
index 16330380..2b21c440 100644
--- a/absl/flags/internal/flag.h
+++ b/absl/flags/internal/flag.h
@@ -20,12 +20,44 @@
#include "absl/flags/internal/commandlineflag.h"
#include "absl/flags/internal/registry.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/str_cat.h"
namespace absl {
namespace flags_internal {
constexpr int64_t AtomicInit() { return 0xababababababababll; }
+template <typename T>
+class Flag;
+
+template <typename T>
+class FlagState : public flags_internal::FlagStateInterface {
+ public:
+ FlagState(Flag<T>* flag, T&& cur, bool modified, bool on_command_line,
+ int64_t counter)
+ : flag_(flag),
+ cur_value_(std::move(cur)),
+ modified_(modified),
+ on_command_line_(on_command_line),
+ counter_(counter) {}
+
+ ~FlagState() override = default;
+
+ private:
+ friend class Flag<T>;
+
+ // Restores the flag to the saved state.
+ void Restore() const override;
+
+ // Flag and saved flag data.
+ Flag<T>* flag_;
+ T cur_value_;
+ bool modified_;
+ bool on_command_line_;
+ int64_t counter_;
+};
+
// Signature for the mutation callback used by watched Flags
// The callback is noexcept.
// TODO(rogeeff): add noexcept after C++17 support is added.
@@ -98,15 +130,12 @@ class Flag final : public flags_internal::CommandLineFlag {
InvokeCallback();
}
- void InvokeCallback() override
- ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) {
- flags_internal::InvokeCallback(&locks_->primary_mu, &locks_->callback_mu,
- callback_);
- }
private:
+ friend class FlagState<T>;
+
void Destroy() const override {
- // Values are heap allocated Abseil Flags.
+ // Values are heap allocated for Abseil Flags.
if (cur_) Delete(op_, cur_);
if (def_) Delete(op_, def_);
@@ -121,6 +150,41 @@ class Flag final : public flags_internal::CommandLineFlag {
}
}
+ // Interfaces to save and restore flags to/from persistent state.
+ // Returns current flag state or nullptr if flag does not support
+ // saving and restoring a state.
+ std::unique_ptr<flags_internal::FlagStateInterface> SaveState() override {
+ T curr_value = Get();
+
+ absl::MutexLock l(InitFlagIfNecessary());
+
+ return absl::make_unique<flags_internal::FlagState<T>>(
+ this, std::move(curr_value), modified_, on_command_line_, counter_);
+ }
+
+ // Restores the flag state to the supplied state object. If there is
+ // nothing to restore returns false. Otherwise returns true.
+ bool RestoreState(const flags_internal::FlagState<T>& flag_state) {
+ if (MutationCounter() == flag_state.counter_) return false;
+
+ Set(flag_state.cur_value_);
+
+ // Race condition here? This should disappear once we move the rest of the
+ // flag's data into Flag's internals.
+
+ absl::MutexLock l(InitFlagIfNecessary());
+ modified_ = flag_state.modified_;
+ on_command_line_ = flag_state.on_command_line_;
+ return true;
+ }
+
+ // Interfaces to overate on callbacks.
+ void InvokeCallback() override
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) {
+ flags_internal::InvokeCallback(&locks_->primary_mu, &locks_->callback_mu,
+ callback_);
+ }
+
// Flag's data
// For some types, a copy of the current value is kept in an atomically
// accessible field.
@@ -128,6 +192,15 @@ class Flag final : public flags_internal::CommandLineFlag {
FlagCallback callback_; // Mutation callback
};
+template <typename T>
+inline void FlagState<T>::Restore() const {
+ if (flag_->RestoreState(*this)) {
+ ABSL_INTERNAL_LOG(INFO,
+ absl::StrCat("Restore saved value of ", flag_->Name(),
+ " to: ", flag_->CurrentValue()));
+ }
+}
+
// This class facilitates Flag object registration and tail expression-based
// flag definition, for example:
// ABSL_FLAG(int, foo, 42, "Foo help").OnUpdate(NotifyFooWatcher);
diff --git a/absl/flags/internal/registry.cc b/absl/flags/internal/registry.cc
index 4bea313b..6b2564d1 100644
--- a/absl/flags/internal/registry.cc
+++ b/absl/flags/internal/registry.cc
@@ -188,114 +188,34 @@ CommandLineFlag* FlagRegistry::FindRetiredFlagLocked(absl::string_view name) {
class FlagSaverImpl {
public:
- // Constructs an empty FlagSaverImpl object.
- FlagSaverImpl() {}
- ~FlagSaverImpl() {
- // reclaim memory from each of our CommandLineFlags
- for (const SavedFlag& src : backup_registry_) {
- Delete(src.op, src.current);
- Delete(src.op, src.default_value);
- }
- }
+ FlagSaverImpl() = default;
+ FlagSaverImpl(const FlagSaverImpl&) = delete;
+ void operator=(const FlagSaverImpl&) = delete;
// Saves the flag states from the flag registry into this object.
// It's an error to call this more than once.
- // Must be called when the registry mutex is not held.
void SaveFromRegistry() {
assert(backup_registry_.empty()); // call only once!
- SavedFlag saved;
flags_internal::ForEachFlag([&](flags_internal::CommandLineFlag* flag) {
- if (flag->IsRetired()) return;
-
- saved.name = flag->Name();
- saved.op = flag->op_;
- saved.marshalling_op = flag->marshalling_op_;
- {
- absl::MutexLock l(flag->InitFlagIfNecessary());
- saved.validator = flag->GetValidator();
- saved.modified = flag->modified_;
- saved.on_command_line = flag->on_command_line_;
- saved.current = Clone(saved.op, flag->cur_);
- saved.default_value = Clone(saved.op, flag->def_);
- saved.counter = flag->counter_;
+ if (auto flag_state = flag->SaveState()) {
+ backup_registry_.emplace_back(std::move(flag_state));
}
- backup_registry_.push_back(saved);
});
}
- // Restores the saved flag states into the flag registry. We
- // assume no flags were added or deleted from the registry since
- // the SaveFromRegistry; if they were, that's trouble! Must be
- // called when the registry mutex is not held.
+ // Restores the saved flag states into the flag registry.
void RestoreToRegistry() {
- FlagRegistry* const global_registry = FlagRegistry::GlobalRegistry();
- FlagRegistryLock frl(global_registry);
- for (const SavedFlag& src : backup_registry_) {
- CommandLineFlag* flag = global_registry->FindFlagLocked(src.name);
- // If null, flag got deleted from registry.
- if (!flag) continue;
-
- bool restored = false;
- {
- // This function encapsulate the lock.
- flag->SetValidator(src.validator);
-
- absl::MutexLock l(flag->InitFlagIfNecessary());
- flag->modified_ = src.modified;
- flag->on_command_line_ = src.on_command_line;
- if (flag->counter_ != src.counter ||
- ChangedDirectly(flag, src.default_value, flag->def_)) {
- restored = true;
- Copy(src.op, src.default_value, flag->def_);
- }
- if (flag->counter_ != src.counter ||
- ChangedDirectly(flag, src.current, flag->cur_)) {
- restored = true;
- Copy(src.op, src.current, flag->cur_);
- UpdateCopy(flag);
- flag->InvokeCallback();
- }
- }
-
- if (restored) {
- flag->counter_++;
-
- // Revalidate the flag because the validator might store state based
- // on the flag's value, which just changed due to the restore.
- // Failing validation is ignored because it's assumed that the flag
- // was valid previously and there's little that can be done about it
- // here, anyway.
- flag->ValidateInputValue(flag->CurrentValue());
-
- ABSL_INTERNAL_LOG(
- INFO, absl::StrCat("Restore saved value of ", flag->Name(), ": ",
- Unparse(src.marshalling_op, src.current)));
- }
+ for (const auto& flag_state : backup_registry_) {
+ flag_state->Restore();
}
}
private:
- struct SavedFlag {
- absl::string_view name;
- FlagOpFn op;
- FlagMarshallingOpFn marshalling_op;
- int64_t counter;
- void* validator;
- bool modified;
- bool on_command_line;
- const void* current; // nullptr after restore
- const void* default_value; // nullptr after restore
- };
-
- std::vector<SavedFlag> backup_registry_;
-
- FlagSaverImpl(const FlagSaverImpl&); // no copying!
- void operator=(const FlagSaverImpl&);
+ std::vector<std::unique_ptr<flags_internal::FlagStateInterface>>
+ backup_registry_;
};
-FlagSaver::FlagSaver() : impl_(new FlagSaverImpl()) {
- impl_->SaveFromRegistry();
-}
+FlagSaver::FlagSaver() : impl_(new FlagSaverImpl) { impl_->SaveFromRegistry(); }
void FlagSaver::Ignore() {
delete impl_;
@@ -376,6 +296,10 @@ class RetiredFlagObj final : public flags_internal::CommandLineFlag {
delete this;
}
+
+ std::unique_ptr<flags_internal::FlagStateInterface> SaveState() override {
+ return nullptr;
+ }
};
} // namespace
diff --git a/absl/random/BUILD.bazel b/absl/random/BUILD.bazel
index c904618d..92111827 100644
--- a/absl/random/BUILD.bazel
+++ b/absl/random/BUILD.bazel
@@ -26,7 +26,7 @@ load(
package(default_visibility = ["//visibility:public"])
-licenses(["notice"]) # Apache 2.0
+licenses(["notice"])
cc_library(
name = "random",
diff --git a/absl/random/distribution_format_traits.h b/absl/random/distribution_format_traits.h
index 3298c2cd..f9f07058 100644
--- a/absl/random/distribution_format_traits.h
+++ b/absl/random/distribution_format_traits.h
@@ -249,12 +249,12 @@ struct DistributionFormatTraits<absl::log_uniform_int_distribution<R>> {
}
};
-template <typename TagType, typename NumType>
+template <typename NumType>
struct UniformDistributionWrapper;
-template <typename TagType, typename NumType>
-struct DistributionFormatTraits<UniformDistributionWrapper<TagType, NumType>> {
- using distribution_t = UniformDistributionWrapper<TagType, NumType>;
+template <typename NumType>
+struct DistributionFormatTraits<UniformDistributionWrapper<NumType>> {
+ using distribution_t = UniformDistributionWrapper<NumType>;
using result_t = NumType;
static constexpr const char* Name() { return "Uniform"; }
@@ -263,19 +263,7 @@ struct DistributionFormatTraits<UniformDistributionWrapper<TagType, NumType>> {
return absl::StrCat(Name(), "<", ScalarTypeName<NumType>(), ">");
}
static std::string FormatArgs(const distribution_t& d) {
- absl::string_view tag;
- if (std::is_same<TagType, IntervalClosedClosedTag>::value) {
- tag = "IntervalClosedClosed";
- } else if (std::is_same<TagType, IntervalClosedOpenTag>::value) {
- tag = "IntervalClosedOpen";
- } else if (std::is_same<TagType, IntervalOpenClosedTag>::value) {
- tag = "IntervalOpenClosed";
- } else if (std::is_same<TagType, IntervalOpenOpenTag>::value) {
- tag = "IntervalOpenOpen";
- } else {
- tag = "[[unknown tag type]]";
- }
- return absl::StrCat(tag, ", ", (d.min)(), ", ", (d.max)());
+ return absl::StrCat((d.min)(), ", ", (d.max)());
}
static std::string FormatResults(absl::Span<const result_t> results) {
return absl::StrJoin(results, ", ");
diff --git a/absl/random/distributions.h b/absl/random/distributions.h
index 3a4e93ab..6ced6061 100644
--- a/absl/random/distributions.h
+++ b/absl/random/distributions.h
@@ -124,7 +124,15 @@ Uniform(TagType tag,
URBG&& urbg, // NOLINT(runtime/references)
R lo, R hi) {
using gen_t = absl::decay_t<URBG>;
- return random_internal::UniformImpl<R, TagType, gen_t>(tag, urbg, lo, hi);
+ using distribution_t = random_internal::UniformDistributionWrapper<R>;
+ using format_t = random_internal::DistributionFormatTraits<distribution_t>;
+
+ auto a = random_internal::uniform_lower_bound(tag, lo, hi);
+ auto b = random_internal::uniform_upper_bound(tag, lo, hi);
+ if (a > b) return a;
+
+ return random_internal::DistributionCaller<gen_t>::template Call<
+ distribution_t, format_t>(&urbg, tag, lo, hi);
}
// absl::Uniform<T>(bitgen, lo, hi)
@@ -135,11 +143,17 @@ template <typename R = void, typename URBG>
typename absl::enable_if_t<!std::is_same<R, void>::value, R> //
Uniform(URBG&& urbg, // NOLINT(runtime/references)
R lo, R hi) {
- constexpr auto tag = absl::IntervalClosedOpen;
- using tag_t = decltype(tag);
using gen_t = absl::decay_t<URBG>;
+ using distribution_t = random_internal::UniformDistributionWrapper<R>;
+ using format_t = random_internal::DistributionFormatTraits<distribution_t>;
+
+ constexpr auto tag = absl::IntervalClosedOpen;
+ auto a = random_internal::uniform_lower_bound(tag, lo, hi);
+ auto b = random_internal::uniform_upper_bound(tag, lo, hi);
+ if (a > b) return a;
- return random_internal::UniformImpl<R, tag_t, gen_t>(tag, urbg, lo, hi);
+ return random_internal::DistributionCaller<gen_t>::template Call<
+ distribution_t, format_t>(&urbg, lo, hi);
}
// absl::Uniform(tag, bitgen, lo, hi)
@@ -156,9 +170,16 @@ Uniform(TagType tag,
A lo, B hi) {
using gen_t = absl::decay_t<URBG>;
using return_t = typename random_internal::uniform_inferred_return_t<A, B>;
+ using distribution_t = random_internal::UniformDistributionWrapper<return_t>;
+ using format_t = random_internal::DistributionFormatTraits<distribution_t>;
- return random_internal::UniformImpl<return_t, TagType, gen_t>(tag, urbg, lo,
- hi);
+ auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi);
+ auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi);
+ if (a > b) return a;
+
+ return random_internal::DistributionCaller<gen_t>::template Call<
+ distribution_t, format_t>(&urbg, tag, static_cast<return_t>(lo),
+ static_cast<return_t>(hi));
}
// absl::Uniform(bitgen, lo, hi)
@@ -171,13 +192,19 @@ typename absl::enable_if_t<std::is_same<R, void>::value,
random_internal::uniform_inferred_return_t<A, B>>
Uniform(URBG&& urbg, // NOLINT(runtime/references)
A lo, B hi) {
- constexpr auto tag = absl::IntervalClosedOpen;
- using tag_t = decltype(tag);
using gen_t = absl::decay_t<URBG>;
using return_t = typename random_internal::uniform_inferred_return_t<A, B>;
+ using distribution_t = random_internal::UniformDistributionWrapper<return_t>;
+ using format_t = random_internal::DistributionFormatTraits<distribution_t>;
- return random_internal::UniformImpl<return_t, tag_t, gen_t>(tag, urbg, lo,
- hi);
+ constexpr auto tag = absl::IntervalClosedOpen;
+ auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi);
+ auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi);
+ if (a > b) return a;
+
+ return random_internal::DistributionCaller<gen_t>::template Call<
+ distribution_t, format_t>(&urbg, static_cast<return_t>(lo),
+ static_cast<return_t>(hi));
}
// absl::Uniform<unsigned T>(bitgen)
@@ -187,13 +214,12 @@ Uniform(URBG&& urbg, // NOLINT(runtime/references)
template <typename R, typename URBG>
typename absl::enable_if_t<!std::is_signed<R>::value, R> //
Uniform(URBG&& urbg) { // NOLINT(runtime/references)
- constexpr auto tag = absl::IntervalClosedClosed;
- constexpr auto lo = std::numeric_limits<R>::lowest();
- constexpr auto hi = (std::numeric_limits<R>::max)();
- using tag_t = decltype(tag);
using gen_t = absl::decay_t<URBG>;
+ using distribution_t = random_internal::UniformDistributionWrapper<R>;
+ using format_t = random_internal::DistributionFormatTraits<distribution_t>;
- return random_internal::UniformImpl<R, tag_t, gen_t>(tag, urbg, lo, hi);
+ return random_internal::DistributionCaller<gen_t>::template Call<
+ distribution_t, format_t>(&urbg);
}
// -----------------------------------------------------------------------------
diff --git a/absl/random/internal/distributions.h b/absl/random/internal/distributions.h
index 96f8bae3..c8cec02b 100644
--- a/absl/random/internal/distributions.h
+++ b/absl/random/internal/distributions.h
@@ -24,36 +24,6 @@
namespace absl {
namespace random_internal {
-template <typename D>
-struct DistributionFormatTraits;
-
-// UniformImpl implements the core logic of the Uniform<T> call, which is to
-// select the correct distribution type, compute the bounds based on the
-// interval tag, and then generate a value.
-template <typename NumType, typename TagType, typename URBG>
-NumType UniformImpl(TagType tag,
- URBG& urbg, // NOLINT(runtime/references)
- NumType lo, NumType hi) {
- static_assert(
- std::is_arithmetic<NumType>::value,
- "absl::Uniform<T>() must use an integer or real parameter type.");
-
- using distribution_t =
- UniformDistributionWrapper<absl::decay_t<TagType>, NumType>;
- using format_t = random_internal::DistributionFormatTraits<distribution_t>;
- auto a = uniform_lower_bound(tag, lo, hi);
- auto b = uniform_upper_bound(tag, lo, hi);
-
- // TODO(lar): it doesn't make a lot of sense to ask for a random number in an
- // empty range. Right now we just return a boundary--even though that
- // boundary is not an acceptable value! Is there something better we can do
- // here?
- if (a > b) return a;
-
- using gen_t = absl::decay_t<URBG>;
- return DistributionCaller<gen_t>::template Call<distribution_t, format_t>(
- &urbg, tag, lo, hi);
-}
// In the absence of an explicitly provided return-type, the template
// "uniform_inferred_return_t<A, B>" is used to derive a suitable type, based on
diff --git a/absl/random/internal/uniform_helper.h b/absl/random/internal/uniform_helper.h
index 2929407e..f68b1823 100644
--- a/absl/random/internal/uniform_helper.h
+++ b/absl/random/internal/uniform_helper.h
@@ -154,12 +154,22 @@ using UniformDistribution =
absl::uniform_int_distribution<NumType>,
absl::uniform_real_distribution<NumType>>::type;
-template <typename TagType, typename NumType>
+template <typename NumType>
struct UniformDistributionWrapper : public UniformDistribution<NumType> {
+ template <typename TagType>
explicit UniformDistributionWrapper(TagType, NumType lo, NumType hi)
: UniformDistribution<NumType>(
uniform_lower_bound<NumType>(TagType{}, lo, hi),
uniform_upper_bound<NumType>(TagType{}, lo, hi)) {}
+
+ explicit UniformDistributionWrapper(NumType lo, NumType hi)
+ : UniformDistribution<NumType>(
+ uniform_lower_bound<NumType>(IntervalClosedOpenTag(), lo, hi),
+ uniform_upper_bound<NumType>(IntervalClosedOpenTag(), lo, hi)) {}
+
+ explicit UniformDistributionWrapper()
+ : UniformDistribution<NumType>(std::numeric_limits<NumType>::lowest(),
+ (std::numeric_limits<NumType>::max)()) {}
};
} // namespace random_internal
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel
index 729bdd76..4863ead2 100644
--- a/absl/strings/BUILD.bazel
+++ b/absl/strings/BUILD.bazel
@@ -630,6 +630,7 @@ cc_test(
visibility = ["//visibility:private"],
deps = [
":str_format_internal",
+ "//absl/base:raw_logging_internal",
"//absl/numeric:int128",
"@com_google_googletest//:gtest_main",
],
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt
index ccff4441..3f907957 100644
--- a/absl/strings/CMakeLists.txt
+++ b/absl/strings/CMakeLists.txt
@@ -461,6 +461,7 @@ absl_cc_test(
${ABSL_TEST_COPTS}
DEPS
absl::str_format_internal
+ absl::raw_logging_internal
absl::int128
gmock_main
)
diff --git a/absl/strings/charconv_test.cc b/absl/strings/charconv_test.cc
index b58fad26..9090e9c8 100644
--- a/absl/strings/charconv_test.cc
+++ b/absl/strings/charconv_test.cc
@@ -511,6 +511,13 @@ TEST(FromChars, Overflow) {
EXPECT_EQ(f, std::numeric_limits<float>::max());
}
+TEST(FromChars, RegressionTestsFromFuzzer) {
+ absl::string_view src = "0x21900000p00000000099";
+ float f;
+ auto result = absl::from_chars(src.data(), src.data() + src.size(), f);
+ EXPECT_EQ(result.ec, std::errc::result_out_of_range);
+}
+
TEST(FromChars, ReturnValuePtr) {
// Check that `ptr` points one past the number scanned, even if that number
// is not representable.
diff --git a/absl/strings/internal/charconv_parse.cc b/absl/strings/internal/charconv_parse.cc
index f3c72324..fa9a8965 100644
--- a/absl/strings/internal/charconv_parse.cc
+++ b/absl/strings/internal/charconv_parse.cc
@@ -253,6 +253,12 @@ std::size_t ConsumeDigits(const char* begin, const char* end, int max_digits,
assert(max_digits * 4 <= std::numeric_limits<T>::digits);
}
const char* const original_begin = begin;
+
+ // Skip leading zeros, but only if *out is zero.
+ // They don't cause an overflow so we don't have to count them for
+ // `max_digits`.
+ while (!*out && end != begin && *begin == '0') ++begin;
+
T accumulator = *out;
const char* significant_digits_end =
(end - begin > max_digits) ? begin + max_digits : end;
diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc
index 814ccf4c..ab8d5391 100644
--- a/absl/strings/internal/str_format/convert_test.cc
+++ b/absl/strings/internal/str_format/convert_test.cc
@@ -5,7 +5,9 @@
#include <cmath>
#include <string>
+#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
#include "absl/strings/internal/str_format/bind.h"
namespace absl {
@@ -157,12 +159,20 @@ TEST_F(FormatConvertTest, StringPrecision) {
EXPECT_EQ("ABC", FormatPack(format2, {FormatArgImpl(p)}));
}
+// Pointer formatting is implementation defined. This checks that the argument
+// can be matched to `ptr`.
+MATCHER_P(MatchesPointerString, ptr, "") {
+ if (ptr == nullptr && arg == "(nil)") {
+ return true;
+ }
+ void* parsed = nullptr;
+ if (sscanf(arg.c_str(), "%p", &parsed) != 1) {
+ ABSL_RAW_LOG(FATAL, "Could not parse %s", arg.c_str());
+ }
+ return ptr == parsed;
+}
+
TEST_F(FormatConvertTest, Pointer) {
-#ifdef _MSC_VER
- // MSVC's printf implementation prints pointers differently. We can't easily
- // compare our implementation to theirs.
- return;
-#endif
static int x = 0;
const int *xp = &x;
char c = 'h';
@@ -173,48 +183,62 @@ TEST_F(FormatConvertTest, Pointer) {
using VoidF = void (*)();
VoidF fp = [] {}, fnil = nullptr;
volatile char vc;
- volatile char* vcp = &vc;
- volatile char* vcnil = nullptr;
- const FormatArgImpl args[] = {
+ volatile char *vcp = &vc;
+ volatile char *vcnil = nullptr;
+ const FormatArgImpl args_array[] = {
FormatArgImpl(xp), FormatArgImpl(cp), FormatArgImpl(inil),
FormatArgImpl(cnil), FormatArgImpl(mcp), FormatArgImpl(fp),
FormatArgImpl(fnil), FormatArgImpl(vcp), FormatArgImpl(vcnil),
};
- struct Expectation {
- std::string out;
- const char *fmt;
- };
- const Expectation kExpect[] = {
- {StrPrint("%p", &x), "%p"},
- {StrPrint("%20p", &x), "%20p"},
- {StrPrint("%.1p", &x), "%.1p"},
- {StrPrint("%.20p", &x), "%.20p"},
- {StrPrint("%30.20p", &x), "%30.20p"},
-
- {StrPrint("%-p", &x), "%-p"},
- {StrPrint("%-20p", &x), "%-20p"},
- {StrPrint("%-.1p", &x), "%-.1p"},
- {StrPrint("%.20p", &x), "%.20p"},
- {StrPrint("%-30.20p", &x), "%-30.20p"},
-
- {StrPrint("%p", cp), "%2$p"}, // const char*
- {"(nil)", "%3$p"}, // null const char *
- {"(nil)", "%4$p"}, // null const int *
- {StrPrint("%p", mcp), "%5$p"}, // nonconst char*
-
- {StrPrint("%p", fp), "%6$p"}, // function pointer
- {StrPrint("%p", vcp), "%8$p"}, // function pointer
-
-#ifndef __APPLE__
- // Apple's printf differs here (0x0 vs. nil)
- {StrPrint("%p", fnil), "%7$p"}, // null function pointer
- {StrPrint("%p", vcnil), "%9$p"}, // null function pointer
-#endif
- };
- for (const Expectation &e : kExpect) {
- UntypedFormatSpecImpl format(e.fmt);
- EXPECT_EQ(e.out, FormatPack(format, absl::MakeSpan(args))) << e.fmt;
- }
+ auto args = absl::MakeConstSpan(args_array);
+
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%p"), args),
+ MatchesPointerString(&x));
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%20p"), args),
+ MatchesPointerString(&x));
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%.1p"), args),
+ MatchesPointerString(&x));
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%.20p"), args),
+ MatchesPointerString(&x));
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%30.20p"), args),
+ MatchesPointerString(&x));
+
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%-p"), args),
+ MatchesPointerString(&x));
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%-20p"), args),
+ MatchesPointerString(&x));
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%-.1p"), args),
+ MatchesPointerString(&x));
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%.20p"), args),
+ MatchesPointerString(&x));
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%-30.20p"), args),
+ MatchesPointerString(&x));
+
+ // const char*
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%2$p"), args),
+ MatchesPointerString(cp));
+ // null const int*
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%3$p"), args),
+ MatchesPointerString(nullptr));
+ // null const char*
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%4$p"), args),
+ MatchesPointerString(nullptr));
+ // nonconst char*
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%5$p"), args),
+ MatchesPointerString(mcp));
+
+ // function pointers
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%6$p"), args),
+ MatchesPointerString(reinterpret_cast<const void*>(fp)));
+ EXPECT_THAT(
+ FormatPack(UntypedFormatSpecImpl("%8$p"), args),
+ MatchesPointerString(reinterpret_cast<volatile const void *>(vcp)));
+
+ // null function pointers
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%7$p"), args),
+ MatchesPointerString(nullptr));
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%9$p"), args),
+ MatchesPointerString(nullptr));
}
struct Cardinal {
diff --git a/absl/strings/numbers_test.cc b/absl/strings/numbers_test.cc
index 77d7e783..4edf8891 100644
--- a/absl/strings/numbers_test.cc
+++ b/absl/strings/numbers_test.cc
@@ -713,11 +713,11 @@ TEST(stringtest, safe_strtou64_base_length_delimited) {
}
}
-// feenableexcept() and fedisableexcept() are missing on macOS, MSVC,
-// and WebAssembly.
-#if defined(_MSC_VER) || defined(__APPLE__) || defined(__EMSCRIPTEN__)
-#define ABSL_MISSING_FEENABLEEXCEPT 1
-#define ABSL_MISSING_FEDISABLEEXCEPT 1
+// feenableexcept() and fedisableexcept() are extensions supported by some libc
+// implementations.
+#if defined(__GLIBC__) || defined(__BIONIC__)
+#define ABSL_HAVE_FEENABLEEXCEPT 1
+#define ABSL_HAVE_FEDISABLEEXCEPT 1
#endif
class SimpleDtoaTest : public testing::Test {
@@ -725,7 +725,7 @@ class SimpleDtoaTest : public testing::Test {
void SetUp() override {
// Store the current floating point env & clear away any pending exceptions.
feholdexcept(&fp_env_);
-#ifndef ABSL_MISSING_FEENABLEEXCEPT
+#ifdef ABSL_HAVE_FEENABLEEXCEPT
// Turn on floating point exceptions.
feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
#endif
@@ -735,7 +735,7 @@ class SimpleDtoaTest : public testing::Test {
// Restore the floating point environment to the original state.
// In theory fedisableexcept is unnecessary; fesetenv will also do it.
// In practice, our toolchains have subtle bugs.
-#ifndef ABSL_MISSING_FEDISABLEEXCEPT
+#ifdef ABSL_HAVE_FEDISABLEEXCEPT
fedisableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
#endif
fesetenv(&fp_env_);
diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h
index 82344eb2..3438ccc1 100644
--- a/absl/strings/string_view.h
+++ b/absl/strings/string_view.h
@@ -40,6 +40,13 @@ using std::string_view;
#else // ABSL_HAVE_STD_STRING_VIEW
+#if ABSL_HAVE_BUILTIN(__builtin_memcmp) || \
+ (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_INTERNAL_STRING_VIEW_MEMCMP __builtin_memcmp
+#else // ABSL_HAVE_BUILTIN(__builtin_memcmp)
+#define ABSL_INTERNAL_STRING_VIEW_MEMCMP memcmp
+#endif // ABSL_HAVE_BUILTIN(__builtin_memcmp)
+
#include <cassert>
#include <cstddef>
#include <cstring>
@@ -381,16 +388,13 @@ class string_view {
// view. Note that in the case of data equality, a further comparison is made
// on the respective sizes of the two `string_view`s to determine which is
// smaller, equal, or greater.
- int compare(string_view x) const noexcept {
- auto min_length = (std::min)(length_, x.length_);
- if (min_length > 0) {
- int r = memcmp(ptr_, x.ptr_, min_length);
- if (r < 0) return -1;
- if (r > 0) return 1;
- }
- if (length_ < x.length_) return -1;
- if (length_ > x.length_) return 1;
- return 0;
+ constexpr int compare(string_view x) const noexcept {
+ return CompareImpl(
+ length_, x.length_,
+ length_ == 0 || x.length_ == 0
+ ? 0
+ : ABSL_INTERNAL_STRING_VIEW_MEMCMP(
+ ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_));
}
// Overload of `string_view::compare()` for comparing a substring of the
@@ -528,6 +532,14 @@ class string_view {
#endif
}
+ static constexpr int CompareImpl(size_type length_a, size_type length_b,
+ int compare_result) {
+ return compare_result == 0 ? static_cast<int>(length_a > length_b) -
+ static_cast<int>(length_a < length_b)
+ : static_cast<int>(compare_result > 0) -
+ static_cast<int>(compare_result < 0);
+ }
+
const char* ptr_;
size_type length_;
};
@@ -535,33 +547,29 @@ class string_view {
// This large function is defined inline so that in a fairly common case where
// one of the arguments is a literal, the compiler can elide a lot of the
// following comparisons.
-inline bool operator==(string_view x, string_view y) noexcept {
- auto len = x.size();
- if (len != y.size()) {
- return false;
- }
-
- return x.data() == y.data() || len <= 0 ||
- memcmp(x.data(), y.data(), len) == 0;
+constexpr bool operator==(string_view x, string_view y) noexcept {
+ return x.size() == y.size() &&
+ (x.empty() ||
+ ABSL_INTERNAL_STRING_VIEW_MEMCMP(x.data(), y.data(), x.size()) == 0);
}
-inline bool operator!=(string_view x, string_view y) noexcept {
+constexpr bool operator!=(string_view x, string_view y) noexcept {
return !(x == y);
}
-inline bool operator<(string_view x, string_view y) noexcept {
- auto min_size = (std::min)(x.size(), y.size());
- const int r = min_size == 0 ? 0 : memcmp(x.data(), y.data(), min_size);
- return (r < 0) || (r == 0 && x.size() < y.size());
+constexpr bool operator<(string_view x, string_view y) noexcept {
+ return x.compare(y) < 0;
}
-inline bool operator>(string_view x, string_view y) noexcept { return y < x; }
+constexpr bool operator>(string_view x, string_view y) noexcept {
+ return y < x;
+}
-inline bool operator<=(string_view x, string_view y) noexcept {
+constexpr bool operator<=(string_view x, string_view y) noexcept {
return !(y < x);
}
-inline bool operator>=(string_view x, string_view y) noexcept {
+constexpr bool operator>=(string_view x, string_view y) noexcept {
return !(x < y);
}
@@ -570,6 +578,8 @@ std::ostream& operator<<(std::ostream& o, string_view piece);
} // namespace absl
+#undef ABSL_INTERNAL_STRING_VIEW_MEMCMP
+
#endif // ABSL_HAVE_STD_STRING_VIEW
namespace absl {
diff --git a/absl/strings/string_view_test.cc b/absl/strings/string_view_test.cc
index eb8b170b..86f2fbcd 100644
--- a/absl/strings/string_view_test.cc
+++ b/absl/strings/string_view_test.cc
@@ -974,6 +974,29 @@ TEST(StringViewTest, ConstexprCompiles) {
EXPECT_EQ(cstr_strlen.length(), 3);
constexpr absl::string_view cstr_strlen2 = "bar";
EXPECT_EQ(cstr_strlen2, "bar");
+
+#if ABSL_HAVE_BUILTIN(__builtin_memcmp) || \
+ (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_COMPARISON 1
+#endif
+#ifdef ABSL_HAVE_CONSTEXPR_STRING_VIEW_COMPARISON
+ constexpr absl::string_view foo = "foo";
+ constexpr absl::string_view bar = "bar";
+ constexpr bool foo_eq_bar = foo == bar;
+ constexpr bool foo_ne_bar = foo != bar;
+ constexpr bool foo_lt_bar = foo < bar;
+ constexpr bool foo_le_bar = foo <= bar;
+ constexpr bool foo_gt_bar = foo > bar;
+ constexpr bool foo_ge_bar = foo >= bar;
+ constexpr int foo_compare_bar = foo.compare(bar);
+ EXPECT_FALSE(foo_eq_bar);
+ EXPECT_TRUE(foo_ne_bar);
+ EXPECT_FALSE(foo_lt_bar);
+ EXPECT_FALSE(foo_le_bar);
+ EXPECT_TRUE(foo_gt_bar);
+ EXPECT_TRUE(foo_ge_bar);
+ EXPECT_GT(foo_compare_bar, 0);
+#endif
#endif
#if !defined(__clang__) || 3 < __clang_major__ || \
diff --git a/absl/synchronization/internal/waiter.cc b/absl/synchronization/internal/waiter.cc
index 96145780..d83d8087 100644
--- a/absl/synchronization/internal/waiter.cc
+++ b/absl/synchronization/internal/waiter.cc
@@ -129,6 +129,9 @@ void Waiter::Init() {
bool Waiter::Wait(KernelTimeout t) {
// Loop until we can atomically decrement futex from a positive
// value, waiting on a futex while we believe it is zero.
+ // 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);
if (x != 0) {
@@ -140,6 +143,8 @@ bool Waiter::Wait(KernelTimeout t) {
return true; // Consumed a wakeup, we are done.
}
+
+ if (!first_pass) MaybeBecomeIdle();
const int err = Futex::WaitUntil(&futex_, 0, t);
if (err != 0) {
if (err == -EINTR || err == -EWOULDBLOCK) {
@@ -150,8 +155,7 @@ bool Waiter::Wait(KernelTimeout t) {
ABSL_RAW_LOG(FATAL, "Futex operation failed with error %d\n", err);
}
}
-
- MaybeBecomeIdle();
+ first_pass = false;
}
}
@@ -219,6 +223,9 @@ bool Waiter::Wait(KernelTimeout t) {
PthreadMutexHolder h(&mu_);
waiter_count_.fetch_add(1, std::memory_order_relaxed);
// Loop until we find a wakeup to consume or timeout.
+ // 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) {
int x = wakeup_count_.load(std::memory_order_relaxed);
if (x != 0) {
@@ -232,6 +239,7 @@ bool Waiter::Wait(KernelTimeout t) {
return true;
}
+ if (!first_pass) MaybeBecomeIdle();
// No wakeups available, time to wait.
if (!t.has_timeout()) {
const int err = pthread_cond_wait(&cv_, &mu_);
@@ -248,7 +256,7 @@ bool Waiter::Wait(KernelTimeout t) {
ABSL_RAW_LOG(FATAL, "pthread_cond_wait failed: %d", err);
}
}
- MaybeBecomeIdle();
+ first_pass = false;
}
}
@@ -288,6 +296,9 @@ bool Waiter::Wait(KernelTimeout t) {
}
// Loop until we timeout or consume a wakeup.
+ // 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) {
int x = wakeups_.load(std::memory_order_relaxed);
if (x != 0) {
@@ -300,6 +311,7 @@ bool Waiter::Wait(KernelTimeout t) {
return true;
}
+ if (!first_pass) MaybeBecomeIdle();
// Nothing to consume, wait (looping on EINTR).
while (true) {
if (!t.has_timeout()) {
@@ -313,7 +325,7 @@ bool Waiter::Wait(KernelTimeout t) {
ABSL_RAW_LOG(FATAL, "sem_timedwait failed: %d", errno);
}
}
- MaybeBecomeIdle();
+ first_pass = false;
}
}
@@ -401,6 +413,9 @@ bool Waiter::Wait(KernelTimeout t) {
waiter_count_.fetch_add(1, std::memory_order_relaxed);
// Loop until we find a wakeup to consume or timeout.
+ // 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) {
int x = wakeup_count_.load(std::memory_order_relaxed);
if (x != 0) {
@@ -414,6 +429,7 @@ bool Waiter::Wait(KernelTimeout t) {
return true;
}
+ if (!first_pass) MaybeBecomeIdle();
// No wakeups available, time to wait.
if (!SleepConditionVariableSRW(cv, mu, t.InMillisecondsFromNow(), 0)) {
// GetLastError() returns a Win32 DWORD, but we assign to
@@ -427,8 +443,7 @@ bool Waiter::Wait(KernelTimeout t) {
ABSL_RAW_LOG(FATAL, "SleepConditionVariableSRW failed: %lu", err);
}
}
-
- MaybeBecomeIdle();
+ first_pass = false;
}
}
diff --git a/absl/synchronization/internal/waiter.h b/absl/synchronization/internal/waiter.h
index 0757b91d..09993545 100644
--- a/absl/synchronization/internal/waiter.h
+++ b/absl/synchronization/internal/waiter.h
@@ -19,7 +19,7 @@
#include "absl/base/config.h"
#ifdef _WIN32
-#include <SdkDdkVer.h>
+#include <sdkddkver.h>
#else
#include <pthread.h>
#endif
diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h
index d33318d3..ccd94618 100644
--- a/absl/synchronization/mutex.h
+++ b/absl/synchronization/mutex.h
@@ -628,7 +628,7 @@ class ABSL_SCOPED_LOCKABLE WriterMutexLock {
// Example:
//
// // assume count_ is not internal reference count
-// int count_ GUARDED_BY(mu_);
+// int count_ ABSL_GUARDED_BY(mu_);
//
// mu_.LockWhen(Condition(+[](int* count) { return *count == 0; },
// &count_));
diff --git a/absl/time/duration.cc b/absl/time/duration.cc
index a3ac61a9..9a876811 100644
--- a/absl/time/duration.cc
+++ b/absl/time/duration.cc
@@ -906,6 +906,11 @@ bool ParseDuration(const std::string& dur_string, Duration* d) {
return true;
}
+bool AbslParseFlag(absl::string_view text, Duration* dst, std::string*) {
+ return ParseDuration(std::string(text), dst);
+}
+
+std::string AbslUnparseFlag(Duration d) { return FormatDuration(d); }
bool ParseFlag(const std::string& text, Duration* dst, std::string* ) {
return ParseDuration(text, dst);
}
diff --git a/absl/time/format.cc b/absl/time/format.cc
index d6ca8600..ebe872cf 100644
--- a/absl/time/format.cc
+++ b/absl/time/format.cc
@@ -129,6 +129,14 @@ bool ParseTime(const std::string& format, const std::string& input,
}
// Functions required to support absl::Time flags.
+bool AbslParseFlag(absl::string_view text, absl::Time* t, std::string* error) {
+ return absl::ParseTime(RFC3339_full, std::string(text), absl::UTCTimeZone(),
+ t, error);
+}
+
+std::string AbslUnparseFlag(absl::Time t) {
+ return absl::FormatTime(RFC3339_full, t, absl::UTCTimeZone());
+}
bool ParseFlag(const std::string& text, absl::Time* t, std::string* error) {
return absl::ParseTime(RFC3339_full, text, absl::UTCTimeZone(), t, error);
}
diff --git a/absl/time/internal/cctz/src/time_zone_impl.cc b/absl/time/internal/cctz/src/time_zone_impl.cc
index a26151d3..a241e951 100644
--- a/absl/time/internal/cctz/src/time_zone_impl.cc
+++ b/absl/time/internal/cctz/src/time_zone_impl.cc
@@ -14,6 +14,7 @@
#include "time_zone_impl.h"
+#include <deque>
#include <mutex>
#include <string>
#include <unordered_map>
@@ -91,8 +92,14 @@ bool time_zone::Impl::LoadTimeZone(const std::string& name, time_zone* tz) {
void time_zone::Impl::ClearTimeZoneMapTestOnly() {
std::lock_guard<std::mutex> lock(TimeZoneMutex());
if (time_zone_map != nullptr) {
- // Existing time_zone::Impl* entries are in the wild, so we simply
- // leak them. Future requests will result in reloading the data.
+ // Existing time_zone::Impl* entries are in the wild, so we can't delete
+ // them. Instead, we move them to a private container, where they are
+ // logically unreachable but not "leaked". Future requests will result
+ // in reloading the data.
+ static auto* cleared = new std::deque<const time_zone::Impl*>;
+ for (const auto& element : *time_zone_map) {
+ cleared->push_back(element.second);
+ }
time_zone_map->clear();
}
}
diff --git a/absl/time/time.cc b/absl/time/time.cc
index 6a387bce..60382be7 100644
--- a/absl/time/time.cc
+++ b/absl/time/time.cc
@@ -430,9 +430,17 @@ absl::TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour,
}
absl::Time FromTM(const struct tm& tm, absl::TimeZone tz) {
- const CivilSecond cs(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec);
- const auto ti = tz.At(cs);
+ civil_year_t tm_year = tm.tm_year;
+ // Avoids years that are too extreme for CivilSecond to normalize.
+ if (tm_year > 300000000000ll) return InfiniteFuture();
+ if (tm_year < -300000000000ll) return InfinitePast();
+ int tm_mon = tm.tm_mon;
+ if (tm_mon == std::numeric_limits<int>::max()) {
+ tm_mon -= 12;
+ tm_year += 1;
+ }
+ const auto ti = tz.At(CivilSecond(tm_year + 1900, tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec));
return tm.tm_isdst == 0 ? ti.post : ti.pre;
}
diff --git a/absl/time/time.h b/absl/time/time.h
index 9c8f3177..0b7312ee 100644
--- a/absl/time/time.h
+++ b/absl/time/time.h
@@ -83,6 +83,7 @@ struct timeval;
#include <type_traits>
#include <utility>
+#include "absl/base/macros.h"
#include "absl/strings/string_view.h"
#include "absl/time/civil_time.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
@@ -545,7 +546,11 @@ bool ParseDuration(const std::string& dur_string, Duration* d);
// Support for flag values of type Duration. Duration flags must be specified
// in a format that is valid input for absl::ParseDuration().
+bool AbslParseFlag(absl::string_view text, Duration* dst, std::string* error);
+std::string AbslUnparseFlag(Duration d);
+ABSL_DEPRECATED("Use AbslParseFlag() instead.")
bool ParseFlag(const std::string& text, Duration* dst, std::string* error);
+ABSL_DEPRECATED("Use AbslUnparseFlag() instead.")
std::string UnparseFlag(Duration d);
// Time
@@ -815,7 +820,11 @@ std::chrono::system_clock::time_point ToChronoTime(Time);
// Additionally, if you'd like to specify a time as a count of
// seconds/milliseconds/etc from the Unix epoch, use an absl::Duration flag
// and add that duration to absl::UnixEpoch() to get an absl::Time.
+bool AbslParseFlag(absl::string_view text, Time* t, std::string* error);
+std::string AbslUnparseFlag(Time t);
+ABSL_DEPRECATED("Use AbslParseFlag() instead.")
bool ParseFlag(const std::string& text, Time* t, std::string* error);
+ABSL_DEPRECATED("Use AbslUnparseFlag() instead.")
std::string UnparseFlag(Time t);
// TimeZone
diff --git a/absl/time/time_test.cc b/absl/time/time_test.cc
index 37af39d9..9c4709e6 100644
--- a/absl/time/time_test.cc
+++ b/absl/time/time_test.cc
@@ -795,6 +795,30 @@ TEST(Time, FromTM) {
tm.tm_isdst = 1;
t = FromTM(tm, nyc);
EXPECT_EQ("2014-03-09T03:30:42-04:00", absl::FormatTime(t, nyc)); // DST
+
+ // Adjusts tm to refer to a time with a year larger than 2147483647.
+ tm.tm_year = 2147483647 - 1900 + 1;
+ tm.tm_mon = 6 - 1;
+ tm.tm_mday = 28;
+ tm.tm_hour = 1;
+ tm.tm_min = 2;
+ tm.tm_sec = 3;
+ tm.tm_isdst = -1;
+ t = FromTM(tm, absl::UTCTimeZone());
+ EXPECT_EQ("2147483648-06-28T01:02:03+00:00",
+ absl::FormatTime(t, absl::UTCTimeZone()));
+
+ // Adjusts tm to refer to a time with a very large month.
+ tm.tm_year = 2019 - 1900;
+ tm.tm_mon = 2147483647;
+ tm.tm_mday = 28;
+ tm.tm_hour = 1;
+ tm.tm_min = 2;
+ tm.tm_sec = 3;
+ tm.tm_isdst = -1;
+ t = FromTM(tm, absl::UTCTimeZone());
+ EXPECT_EQ("178958989-08-28T01:02:03+00:00",
+ absl::FormatTime(t, absl::UTCTimeZone()));
}
TEST(Time, TMRoundTrip) {