summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xabsl/abseil.podspec.gen.py247
-rw-r--r--absl/base/BUILD.bazel4
-rw-r--r--absl/base/CMakeLists.txt8
-rw-r--r--absl/base/attributes.h6
-rw-r--r--absl/base/call_once.h13
-rw-r--r--absl/base/policy_checks.h10
-rw-r--r--absl/container/internal/hashtablez_sampler.cc21
-rw-r--r--absl/container/internal/hashtablez_sampler.h10
-rw-r--r--absl/container/internal/hashtablez_sampler_test.cc2
-rw-r--r--absl/container/internal/raw_hash_set.h4
-rw-r--r--absl/container/internal/raw_hash_set_test.cc2
-rw-r--r--absl/debugging/BUILD.bazel5
-rw-r--r--absl/debugging/CMakeLists.txt1
-rw-r--r--absl/functional/BUILD.bazel16
-rw-r--r--absl/hash/hash_test.cc27
-rw-r--r--absl/hash/internal/hash.h13
-rw-r--r--absl/numeric/int128.h4
-rw-r--r--absl/random/CMakeLists.txt1
-rw-r--r--absl/random/internal/BUILD.bazel5
-rw-r--r--absl/random/internal/randen_hwaes.cc48
-rw-r--r--absl/strings/internal/numbers_test_common.h5
-rw-r--r--absl/strings/numbers.cc66
-rw-r--r--absl/strings/numbers.h21
-rw-r--r--absl/strings/numbers_test.cc63
-rw-r--r--absl/synchronization/internal/waiter.cc7
-rw-r--r--absl/synchronization/internal/waiter.h11
26 files changed, 503 insertions, 117 deletions
diff --git a/absl/abseil.podspec.gen.py b/absl/abseil.podspec.gen.py
new file mode 100755
index 00000000..2bf153c0
--- /dev/null
+++ b/absl/abseil.podspec.gen.py
@@ -0,0 +1,247 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""This script generates abseil.podspec from all BUILD.bazel files.
+
+This is expected to run on abseil git repository with Bazel 1.0 on Linux.
+It recursively analyzes BUILD.bazel files using query command of Bazel to
+dump its build rules in XML format. From these rules, it constructs podspec
+structure.
+"""
+
+import argparse
+import collections
+import os
+import re
+import subprocess
+import xml.etree.ElementTree
+
+# Template of root podspec.
+SPEC_TEMPLATE = """
+# This file has been automatically generated from a script.
+# Please make modifications to `abseil.podspec.gen.py` instead.
+Pod::Spec.new do |s|
+ s.name = 'abseil'
+ s.version = '${version}'
+ s.summary = 'Abseil Common Libraries (C++) from Google'
+ s.homepage = 'https://abseil.io'
+ s.license = 'Apache License, Version 2.0'
+ s.authors = { 'Abseil Team' => 'abseil-io@googlegroups.com' }
+ s.source = {
+ :git => 'https://github.com/abseil/abseil-cpp.git',
+ :tag => '${tag}',
+ }
+ s.module_name = 'absl'
+ s.header_mappings_dir = 'absl'
+ s.header_dir = 'absl'
+ s.libraries = 'c++'
+ s.compiler_flags = '-Wno-everything'
+ s.pod_target_xcconfig = {
+ 'USER_HEADER_SEARCH_PATHS' => '$(inherited) "$(PODS_TARGET_SRCROOT)"',
+ 'USE_HEADERMAP' => 'NO',
+ 'ALWAYS_SEARCH_USER_PATHS' => 'NO',
+ }
+ s.ios.deployment_target = '7.0'
+ s.osx.deployment_target = '10.9'
+ s.tvos.deployment_target = '9.0'
+ s.watchos.deployment_target = '2.0'
+"""
+
+# Limited platforms that abseil supports.
+# This is mainly because of sigaltstack unavailable on watchOS.
+LIMITED_SUPPORT_PLATFORMS = [
+ "ios.deployment_target = '7.0'",
+ "osx.deployment_target = '10.9'",
+]
+
+# Custom specification per rule.
+CUSTOM_SPEC_MAP = {
+ "//absl/debugging:failure_signal_handler": LIMITED_SUPPORT_PLATFORMS,
+}
+
+# Rule object representing the rule of Bazel BUILD.
+Rule = collections.namedtuple(
+ "Rule", "type name package srcs hdrs textual_hdrs deps visibility testonly")
+
+
+def get_elem_value(elem, name):
+ """Returns the value of XML element with the given name."""
+ for child in elem:
+ if child.attrib.get("name") != name:
+ continue
+ if child.tag == "string":
+ return child.attrib.get("value")
+ if child.tag == "boolean":
+ return child.attrib.get("value") == "true"
+ if child.tag == "list":
+ return [nested_child.attrib.get("value") for nested_child in child]
+ raise "Cannot recognize tag: " + child.tag
+ return None
+
+
+def normalize_paths(paths):
+ """Returns the list of normalized path."""
+ # e.g. ["//absl/strings:dir/header.h"] -> ["absl/strings/dir/header.h"]
+ return [path.lstrip("/").replace(":", "/") for path in paths]
+
+
+def parse_rule(elem, package):
+ """Returns a rule from bazel XML rule."""
+ return Rule(
+ type=elem.attrib["class"],
+ name=get_elem_value(elem, "name"),
+ package=package,
+ srcs=normalize_paths(get_elem_value(elem, "srcs") or []),
+ hdrs=normalize_paths(get_elem_value(elem, "hdrs") or []),
+ textual_hdrs=normalize_paths(get_elem_value(elem, "textual_hdrs") or []),
+ deps=get_elem_value(elem, "deps") or [],
+ visibility=get_elem_value(elem, "visibility") or [],
+ testonly=get_elem_value(elem, "testonly") or False)
+
+
+def read_build(package):
+ """Runs bazel query on given package file and returns all cc rules."""
+ result = subprocess.check_output(
+ ["bazel", "query", package + ":all", "--output", "xml"])
+ root = xml.etree.ElementTree.fromstring(result)
+ return [
+ parse_rule(elem, package)
+ for elem in root
+ if elem.tag == "rule" and elem.attrib["class"].startswith("cc_")
+ ]
+
+
+def collect_rules(root_path):
+ """Collects and returns all rules from root path recursively."""
+ rules = []
+ for cur, _, _ in os.walk(root_path):
+ build_path = os.path.join(cur, "BUILD.bazel")
+ if os.path.exists(build_path):
+ rules.extend(read_build("//" + cur))
+ return rules
+
+
+def relevant_rule(rule):
+ """Returns true if a given rule is relevant when generating a podspec."""
+ return (
+ # cc_library only (ignore cc_test, cc_binary)
+ rule.type == "cc_library" and
+ # ignore empty rule
+ (rule.hdrs + rule.textual_hdrs + rule.srcs) and
+ # ignore test-only rule
+ not rule.testonly)
+
+
+def get_spec_var(depth):
+ """Returns the name of variable for spec with given depth."""
+ return "s" if depth == 0 else "s{}".format(depth)
+
+
+def get_spec_name(label):
+ """Converts the label of bazel rule to the name of podspec."""
+ assert label.startswith("//absl/"), "{} doesn't start with //absl/".format(
+ label)
+ # e.g. //absl/apple/banana -> abseil/apple/banana
+ return "abseil/" + label[7:]
+
+
+def write_podspec(f, rules, args):
+ """Writes a podspec from given rules and args."""
+ rule_dir = build_rule_directory(rules)["abseil"]
+ # Write root part with given arguments
+ spec = re.sub(r"\$\{(\w+)\}", lambda x: args[x.group(1)],
+ SPEC_TEMPLATE).lstrip()
+ f.write(spec)
+ # Write all target rules
+ write_podspec_map(f, rule_dir, 0)
+ f.write("end\n")
+
+
+def build_rule_directory(rules):
+ """Builds a tree-style rule directory from given rules."""
+ rule_dir = {}
+ for rule in rules:
+ cur = rule_dir
+ for frag in get_spec_name(rule.package).split("/"):
+ cur = cur.setdefault(frag, {})
+ cur[rule.name] = rule
+ return rule_dir
+
+
+def write_podspec_map(f, cur_map, depth):
+ """Writes podspec from rule map recursively."""
+ for key, value in sorted(cur_map.items()):
+ indent = " " * (depth + 1)
+ f.write("{indent}{var0}.subspec '{key}' do |{var1}|\n".format(
+ indent=indent,
+ key=key,
+ var0=get_spec_var(depth),
+ var1=get_spec_var(depth + 1)))
+ if isinstance(value, dict):
+ write_podspec_map(f, value, depth + 1)
+ else:
+ write_podspec_rule(f, value, depth + 1)
+ f.write("{indent}end\n".format(indent=indent))
+
+
+def write_podspec_rule(f, rule, depth):
+ """Writes podspec from given rule."""
+ indent = " " * (depth + 1)
+ spec_var = get_spec_var(depth)
+ # Puts all files in hdrs, textual_hdrs, and srcs into source_files.
+ # Since CocoaPods treats header_files a bit differently from bazel,
+ # this won't generate a header_files field so that all source_files
+ # are considered as header files.
+ srcs = sorted(set(rule.hdrs + rule.textual_hdrs + rule.srcs))
+ write_indented_list(
+ f, "{indent}{var}.source_files = ".format(indent=indent, var=spec_var),
+ srcs)
+ # Writes dependencies of this rule.
+ for dep in sorted(rule.deps):
+ name = get_spec_name(dep.replace(":", "/"))
+ f.write("{indent}{var}.dependency '{dep}'\n".format(
+ indent=indent, var=spec_var, dep=name))
+ # Writes custom specification.
+ custom_spec = CUSTOM_SPEC_MAP.get(rule.package + ":" + rule.name)
+ if custom_spec:
+ for spec in custom_spec:
+ f.write("{indent}{var}.{spec}\n".format(
+ indent=indent, var=spec_var, spec=spec))
+
+
+def write_indented_list(f, leading, values):
+ """Writes leading values in an indented style."""
+ f.write(leading)
+ f.write((",\n" + " " * len(leading)).join("'{}'".format(v) for v in values))
+ f.write("\n")
+
+
+def generate(args):
+ """Generates a podspec file from all BUILD files under absl directory."""
+ rules = filter(relevant_rule, collect_rules("absl"))
+ with open(args.output, "wt") as f:
+ write_podspec(f, rules, vars(args))
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description="Generates abseil.podspec from BUILD.bazel")
+ parser.add_argument(
+ "-v", "--version", help="The version of podspec", required=True)
+ parser.add_argument(
+ "-t",
+ "--tag",
+ default=None,
+ help="The name of git tag (default: version)")
+ parser.add_argument(
+ "-o",
+ "--output",
+ default="abseil.podspec",
+ help="The name of output file (default: abseil.podspec)")
+ args = parser.parse_args()
+ if args.tag is None:
+ args.tag = args.version
+ generate(args)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
index 6fc712d9..7e234bc6 100644
--- a/absl/base/BUILD.bazel
+++ b/absl/base/BUILD.bazel
@@ -192,7 +192,9 @@ cc_library(
],
copts = ABSL_DEFAULT_COPTS,
linkopts = select({
- "//absl:windows": [],
+ "//absl:windows": [
+ "-DEFAULTLIB:shlwapi.lib",
+ ],
"//conditions:default": ["-pthread"],
}) + ABSL_DEFAULT_LINKOPTS,
deps = [
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt
index 9550cdb2..7ab6955e 100644
--- a/absl/base/CMakeLists.txt
+++ b/absl/base/CMakeLists.txt
@@ -14,6 +14,8 @@
# limitations under the License.
#
+find_library(LIBRT rt)
+
absl_cc_library(
NAME
atomic_hook
@@ -163,16 +165,18 @@ absl_cc_library(
"internal/thread_identity.h"
"internal/tsan_mutex_interface.h"
"internal/unscaledcycleclock.h"
- "log_severity.h"
SRCS
"internal/cycleclock.cc"
"internal/spinlock.cc"
"internal/sysinfo.cc"
"internal/thread_identity.cc"
"internal/unscaledcycleclock.cc"
- "log_severity.cc"
COPTS
${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ $<$<BOOL:${LIBRT}>:${LIBRT}>
+ $<$<BOOL:${MINGW}>:"shlwapi">
DEPS
absl::atomic_hook
absl::base_internal
diff --git a/absl/base/attributes.h b/absl/base/attributes.h
index 7b7656a8..acd1c526 100644
--- a/absl/base/attributes.h
+++ b/absl/base/attributes.h
@@ -158,9 +158,11 @@
// Weak attributes currently do not work properly in LLVM's Windows backend,
// so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598
// for further information.
-#if (ABSL_HAVE_ATTRIBUTE(weak) || \
+// The MinGW compiler doesn't complain about the weak attribute until the link
+// step, presumably because Windows doesn't use ELF binaries.
+#if (ABSL_HAVE_ATTRIBUTE(weak) || \
(defined(__GNUC__) && !defined(__clang__))) && \
- !(defined(__llvm__) && defined(_WIN32))
+ !(defined(__llvm__) && defined(_WIN32)) && !defined(__MINGW32__)
#undef ABSL_ATTRIBUTE_WEAK
#define ABSL_ATTRIBUTE_WEAK __attribute__((weak))
#define ABSL_HAVE_ATTRIBUTE_WEAK 1
diff --git a/absl/base/call_once.h b/absl/base/call_once.h
index 4aa6360c..e1614e51 100644
--- a/absl/base/call_once.h
+++ b/absl/base/call_once.h
@@ -148,7 +148,7 @@ void CallOnceImpl(std::atomic<uint32_t>* control,
Args&&... args) {
#ifndef NDEBUG
{
- uint32_t old_control = control->load(std::memory_order_acquire);
+ uint32_t old_control = control->load(std::memory_order_relaxed);
if (old_control != kOnceInit &&
old_control != kOnceRunning &&
old_control != kOnceWaiter &&
@@ -166,14 +166,23 @@ void CallOnceImpl(std::atomic<uint32_t>* control,
// Must do this before potentially modifying control word's state.
base_internal::SchedulingHelper maybe_disable_scheduling(scheduling_mode);
// Short circuit the simplest case to avoid procedure call overhead.
+ // The base_internal::SpinLockWait() call returns either kOnceInit or
+ // kOnceDone. If it returns kOnceDone, it must have loaded the control word
+ // with std::memory_order_acquire and seen a value of kOnceDone.
uint32_t old_control = kOnceInit;
if (control->compare_exchange_strong(old_control, kOnceRunning,
- std::memory_order_acquire,
std::memory_order_relaxed) ||
base_internal::SpinLockWait(control, ABSL_ARRAYSIZE(trans), trans,
scheduling_mode) == kOnceInit) {
base_internal::Invoke(std::forward<Callable>(fn),
std::forward<Args>(args)...);
+ // The call to SpinLockWake below is an optimization, because the waiter
+ // in SpinLockWait is waiting with a short timeout. The atomic load/store
+ // sequence is slightly faster than an atomic exchange:
+ // old_control = control->exchange(base_internal::kOnceDone,
+ // std::memory_order_release);
+ // We opt for a slightly faster case when there are no waiters, in spite
+ // of longer tail latency when there are waiters.
old_control = control->load(std::memory_order_relaxed);
control->store(base_internal::kOnceDone, std::memory_order_release);
if (old_control == base_internal::kOnceWaiter) {
diff --git a/absl/base/policy_checks.h b/absl/base/policy_checks.h
index 699fb1a2..4dfa49e5 100644
--- a/absl/base/policy_checks.h
+++ b/absl/base/policy_checks.h
@@ -82,16 +82,6 @@
// Standard Library Check
// -----------------------------------------------------------------------------
-// We have chosen glibc 2.12 as the minimum as it was tagged for release
-// in May, 2010 and includes some functionality used in Google software
-// (for instance pthread_setname_np):
-// https://sourceware.org/ml/libc-alpha/2010-05/msg00000.html
-#if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
-#if !__GLIBC_PREREQ(2, 12)
-#error "Minimum required version of glibc is 2.12."
-#endif
-#endif
-
#if defined(_STLPORT_VERSION)
#error "STLPort is not supported."
#endif
diff --git a/absl/container/internal/hashtablez_sampler.cc b/absl/container/internal/hashtablez_sampler.cc
index 0a7ef61c..4aec0a07 100644
--- a/absl/container/internal/hashtablez_sampler.cc
+++ b/absl/container/internal/hashtablez_sampler.cc
@@ -38,16 +38,18 @@ ABSL_CONST_INIT std::atomic<bool> g_hashtablez_enabled{
ABSL_CONST_INIT std::atomic<int32_t> g_hashtablez_sample_parameter{1 << 10};
ABSL_CONST_INIT std::atomic<int32_t> g_hashtablez_max_samples{1 << 20};
-#if ABSL_HAVE_THREAD_LOCAL
-thread_local absl::base_internal::ExponentialBiased
- g_exponential_biased_generator;
-#else
-ABSL_CONST_INIT static absl::base_internal::ExponentialBiased
+#if ABSL_PER_THREAD_TLS == 1
+ABSL_PER_THREAD_TLS_KEYWORD absl::base_internal::ExponentialBiased
g_exponential_biased_generator;
#endif
} // namespace
+#if ABSL_PER_THREAD_TLS == 1
+ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample = 0;
+#endif // ABSL_PER_THREAD_TLS == 1
+
+
HashtablezSampler& HashtablezSampler::Global() {
static auto* sampler = new HashtablezSampler();
return *sampler;
@@ -189,6 +191,10 @@ HashtablezInfo* SampleSlow(int64_t* next_sample) {
return HashtablezSampler::Global().Register();
}
+#if ABSL_PER_THREAD_TLS == 0
+ *next_sample = std::numeric_limits<int64_t>::max();
+ return nullptr;
+#else
bool first = *next_sample < 0;
*next_sample = g_exponential_biased_generator.Get(
g_hashtablez_sample_parameter.load(std::memory_order_relaxed));
@@ -210,12 +216,9 @@ HashtablezInfo* SampleSlow(int64_t* next_sample) {
}
return HashtablezSampler::Global().Register();
+#endif
}
-#if ABSL_PER_THREAD_TLS == 1
-ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample = 0;
-#endif // ABSL_PER_THREAD_TLS == 1
-
void UnsampleSlow(HashtablezInfo* info) {
HashtablezSampler::Global().Unregister(info);
}
diff --git a/absl/container/internal/hashtablez_sampler.h b/absl/container/internal/hashtablez_sampler.h
index 53996bb9..c694df05 100644
--- a/absl/container/internal/hashtablez_sampler.h
+++ b/absl/container/internal/hashtablez_sampler.h
@@ -186,16 +186,14 @@ extern ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample;
// Returns an RAII sampling handle that manages registration and unregistation
// with the global sampler.
inline HashtablezInfoHandle Sample() {
-#if ABSL_PER_THREAD_TLS == 0
- static auto* mu = new absl::Mutex;
- static int64_t global_next_sample = 0;
- absl::MutexLock l(mu);
-#endif // !ABSL_HAVE_THREAD_LOCAL
-
+#if ABSL_PER_THREAD_TLS == 1
if (ABSL_PREDICT_TRUE(--global_next_sample > 0)) {
return HashtablezInfoHandle(nullptr);
}
return HashtablezInfoHandle(SampleSlow(&global_next_sample));
+#else
+ return HashtablezInfoHandle(nullptr);
+#endif // !ABSL_PER_THREAD_TLS
}
// Holds samples and their associated stack traces with a soft limit of
diff --git a/absl/container/internal/hashtablez_sampler_test.cc b/absl/container/internal/hashtablez_sampler_test.cc
index 7f9e8dd2..af4b5ee1 100644
--- a/absl/container/internal/hashtablez_sampler_test.cc
+++ b/absl/container/internal/hashtablez_sampler_test.cc
@@ -168,6 +168,7 @@ TEST(HashtablezInfoTest, RecordRehash) {
EXPECT_EQ(info.num_erases.load(), 0);
}
+#if ABSL_PER_THREAD_TLS == 1
TEST(HashtablezSamplerTest, SmallSampleParameter) {
SetHashtablezEnabled(true);
SetHashtablezSampleParameter(100);
@@ -211,6 +212,7 @@ TEST(HashtablezSamplerTest, Sample) {
}
EXPECT_NEAR(sample_rate, 0.01, 0.005);
}
+#endif
TEST(HashtablezSamplerTest, Handle) {
auto& sampler = HashtablezSampler::Global();
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index bf0c03c4..469226fe 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -638,8 +638,8 @@ class raw_hash_set {
}
friend bool operator==(const iterator& a, const iterator& b) {
- /* To be enabled: a.assert_is_valid(); */
- /* To be enabled: b.assert_is_valid(); */
+ a.assert_is_valid();
+ b.assert_is_valid();
return a.ctrl_ == b.ctrl_;
}
friend bool operator!=(const iterator& a, const iterator& b) {
diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc
index 33cfa72c..ec8f9231 100644
--- a/absl/container/internal/raw_hash_set_test.cc
+++ b/absl/container/internal/raw_hash_set_test.cc
@@ -1841,6 +1841,7 @@ TEST(TableDeathTest, EraseOfEndAsserts) {
EXPECT_DEATH_IF_SUPPORTED(t.erase(t.end()), kDeathMsg);
}
+#if ABSL_PER_THREAD_TLS == 1
TEST(RawHashSamplerTest, Sample) {
// Enable the feature even if the prod default is off.
SetHashtablezEnabled(true);
@@ -1861,6 +1862,7 @@ TEST(RawHashSamplerTest, Sample) {
EXPECT_NEAR((end_size - start_size) / static_cast<double>(tables.size()),
0.01, 0.005);
}
+#endif
TEST(RawHashSamplerTest, DoNotSampleCustomAllocators) {
// Enable the feature even if the prod default is off.
diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel
index beec279f..2601090b 100644
--- a/absl/debugging/BUILD.bazel
+++ b/absl/debugging/BUILD.bazel
@@ -55,7 +55,10 @@ cc_library(
"symbolize.h",
],
copts = ABSL_DEFAULT_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS + select({
+ "//absl:windows": ["-DEFAULTLIB:dbghelp.lib"],
+ "//conditions:default": [],
+ }),
deps = [
":debugging_internal",
":demangle_internal",
diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt
index b3e35b6d..eff504b4 100644
--- a/absl/debugging/CMakeLists.txt
+++ b/absl/debugging/CMakeLists.txt
@@ -44,6 +44,7 @@ absl_cc_library(
${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
+ $<$<BOOL:${MINGW}>:"dbghelp">
DEPS
absl::debugging_internal
absl::demangle_internal
diff --git a/absl/functional/BUILD.bazel b/absl/functional/BUILD.bazel
index e861b8a5..0a7b588e 100644
--- a/absl/functional/BUILD.bazel
+++ b/absl/functional/BUILD.bazel
@@ -1,3 +1,19 @@
+#
+# Copyright 2019 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.
+#
+
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load(
"//absl:copts/configure_copts.bzl",
diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc
index 61f7661f..42c0c3d8 100644
--- a/absl/hash/hash_test.cc
+++ b/absl/hash/hash_test.cc
@@ -300,6 +300,33 @@ TEST(HashValueTest, Strings) {
SpyHash(absl::string_view("ABC")));
}
+TEST(HashValueTest, WString) {
+ EXPECT_TRUE((is_hashable<std::wstring>::value));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ std::wstring(), std::wstring(L"ABC"), std::wstring(L"ABC"),
+ std::wstring(L"Some other different string"),
+ std::wstring(L"Iñtërnâtiônàlizætiøn"))));
+}
+
+TEST(HashValueTest, U16String) {
+ EXPECT_TRUE((is_hashable<std::u16string>::value));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ std::u16string(), std::u16string(u"ABC"), std::u16string(u"ABC"),
+ std::u16string(u"Some other different string"),
+ std::u16string(u"Iñtërnâtiônàlizætiøn"))));
+}
+
+TEST(HashValueTest, U32String) {
+ EXPECT_TRUE((is_hashable<std::u32string>::value));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ std::u32string(), std::u32string(U"ABC"), std::u32string(U"ABC"),
+ std::u32string(U"Some other different string"),
+ std::u32string(U"Iñtërnâtiônàlizætiøn"))));
+}
+
TEST(HashValueTest, StdArray) {
EXPECT_TRUE((is_hashable<std::array<int, 3>>::value));
diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h
index e99f8e75..7d44f57d 100644
--- a/absl/hash/internal/hash.h
+++ b/absl/hash/internal/hash.h
@@ -427,6 +427,19 @@ H AbslHashValue(H hash_state, absl::string_view str) {
str.size());
}
+// Support std::wstring, std::u16string and std::u32string.
+template <typename Char, typename Alloc, typename H,
+ typename = absl::enable_if_t<std::is_same<Char, wchar_t>::value ||
+ std::is_same<Char, char16_t>::value ||
+ std::is_same<Char, char32_t>::value>>
+H AbslHashValue(
+ H hash_state,
+ const std::basic_string<Char, std::char_traits<Char>, Alloc>& str) {
+ return H::combine(
+ H::combine_contiguous(std::move(hash_state), str.data(), str.size()),
+ str.size());
+}
+
// -----------------------------------------------------------------------------
// AbslHashValue for Sequence Containers
// -----------------------------------------------------------------------------
diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h
index 10be8eca..4f965686 100644
--- a/absl/numeric/int128.h
+++ b/absl/numeric/int128.h
@@ -720,9 +720,9 @@ inline uint128& uint128::operator--() {
}
#if defined(ABSL_HAVE_INTRINSIC_INT128)
-#include "absl/numeric/int128_have_intrinsic.inc"
+#include "absl/numeric/int128_have_intrinsic.inc" // IWYU pragma: export
#else // ABSL_HAVE_INTRINSIC_INT128
-#include "absl/numeric/int128_no_intrinsic.inc"
+#include "absl/numeric/int128_no_intrinsic.inc" // IWYU pragma: export
#endif // ABSL_HAVE_INTRINSIC_INT128
} // namespace absl
diff --git a/absl/random/CMakeLists.txt b/absl/random/CMakeLists.txt
index 289854ff..264a6f3c 100644
--- a/absl/random/CMakeLists.txt
+++ b/absl/random/CMakeLists.txt
@@ -447,6 +447,7 @@ absl_cc_library(
${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
+ $<$<BOOL:${MINGW}>:"bcrypt">
DEPS
absl::core_headers
absl::optional
diff --git a/absl/random/internal/BUILD.bazel b/absl/random/internal/BUILD.bazel
index 91388d19..cc9bc013 100644
--- a/absl/random/internal/BUILD.bazel
+++ b/absl/random/internal/BUILD.bazel
@@ -89,7 +89,10 @@ cc_library(
"seed_material.h",
],
copts = ABSL_DEFAULT_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS + select({
+ "//absl:windows": ["-DEFAULTLIB:bcrypt.lib"],
+ "//conditions:default": [],
+ }),
deps = [
":fast_uniform_bits",
"//absl/base:core_headers",
diff --git a/absl/random/internal/randen_hwaes.cc b/absl/random/internal/randen_hwaes.cc
index 7d5b2b74..6cc36fd3 100644
--- a/absl/random/internal/randen_hwaes.cc
+++ b/absl/random/internal/randen_hwaes.cc
@@ -159,13 +159,11 @@ inline ABSL_TARGET_CRYPTO Vector128 ReverseBytes(const Vector128& v) {
// WARNING: these load/store in native byte order. It is OK to load and then
// store an unchanged vector, but interpreting the bits as a number or input
// to AES will have undefined results.
-inline ABSL_TARGET_CRYPTO Vector128
-Vector128Load(const void* ABSL_RANDOM_INTERNAL_RESTRICT from) {
+inline ABSL_TARGET_CRYPTO Vector128 Vector128Load(const void* from) {
return vec_vsx_ld(0, reinterpret_cast<const Vector128*>(from));
}
-inline ABSL_TARGET_CRYPTO void Vector128Store(
- const Vector128& v, void* ABSL_RANDOM_INTERNAL_RESTRICT to) {
+inline ABSL_TARGET_CRYPTO void Vector128Store(const Vector128& v, void* to) {
vec_vsx_st(v, 0, reinterpret_cast<Vector128*>(to));
}
@@ -177,8 +175,7 @@ inline ABSL_TARGET_CRYPTO Vector128 AesRound(const Vector128& state,
}
// Enables native loads in the round loop by pre-swapping.
-inline ABSL_TARGET_CRYPTO void SwapEndian(
- uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state) {
+inline ABSL_TARGET_CRYPTO void SwapEndian(uint64_t* state) {
using absl::random_internal::RandenTraits;
constexpr size_t kLanes = 2;
constexpr size_t kFeistelBlocks = RandenTraits::kFeistelBlocks;
@@ -230,13 +227,11 @@ using Vector128 = uint8x16_t;
namespace {
-inline ABSL_TARGET_CRYPTO Vector128
-Vector128Load(const void* ABSL_RANDOM_INTERNAL_RESTRICT from) {
+inline ABSL_TARGET_CRYPTO Vector128 Vector128Load(const void* from) {
return vld1q_u8(reinterpret_cast<const uint8_t*>(from));
}
-inline ABSL_TARGET_CRYPTO void Vector128Store(
- const Vector128& v, void* ABSL_RANDOM_INTERNAL_RESTRICT to) {
+inline ABSL_TARGET_CRYPTO void Vector128Store(const Vector128& v, void* to) {
vst1q_u8(reinterpret_cast<uint8_t*>(to), v);
}
@@ -254,8 +249,7 @@ inline ABSL_TARGET_CRYPTO Vector128 AesRound(const Vector128& state,
return vaesmcq_u8(vaeseq_u8(state, uint8x16_t{})) ^ round_key;
}
-inline ABSL_TARGET_CRYPTO void SwapEndian(
- uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT) {}
+inline ABSL_TARGET_CRYPTO void SwapEndian(uint64_t*) {}
} // namespace
@@ -283,15 +277,12 @@ class Vector128 {
__m128i data_;
};
-inline ABSL_TARGET_CRYPTO Vector128
-Vector128Load(const void* ABSL_RANDOM_INTERNAL_RESTRICT from) {
+inline ABSL_TARGET_CRYPTO Vector128 Vector128Load(const void* from) {
return Vector128(_mm_load_si128(reinterpret_cast<const __m128i*>(from)));
}
-inline ABSL_TARGET_CRYPTO void Vector128Store(
- const Vector128& v, void* ABSL_RANDOM_INTERNAL_RESTRICT to) {
- _mm_store_si128(reinterpret_cast<__m128i * ABSL_RANDOM_INTERNAL_RESTRICT>(to),
- v.data());
+inline ABSL_TARGET_CRYPTO void Vector128Store(const Vector128& v, void* to) {
+ _mm_store_si128(reinterpret_cast<__m128i*>(to), v.data());
}
// One round of AES. "round_key" is a public constant for breaking the
@@ -304,8 +295,7 @@ inline ABSL_TARGET_CRYPTO Vector128 AesRound(const Vector128& state,
return Vector128(_mm_aesenc_si128(state.data(), round_key.data()));
}
-inline ABSL_TARGET_CRYPTO void SwapEndian(
- uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT) {}
+inline ABSL_TARGET_CRYPTO void SwapEndian(uint64_t*) {}
} // namespace
@@ -402,8 +392,7 @@ constexpr size_t kLanes = 2;
// Block shuffles applies a shuffle to the entire state between AES rounds.
// Improved odd-even shuffle from "New criterion for diffusion property".
-inline ABSL_TARGET_CRYPTO void BlockShuffle(
- uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state) {
+inline ABSL_TARGET_CRYPTO void BlockShuffle(uint64_t* state) {
static_assert(kFeistelBlocks == 16, "Expecting 16 FeistelBlocks.");
constexpr size_t shuffle[kFeistelBlocks] = {7, 2, 13, 4, 11, 8, 3, 6,
@@ -452,8 +441,7 @@ inline ABSL_TARGET_CRYPTO void BlockShuffle(
// parallel hides the 7-cycle AESNI latency on HSW. Note that the Feistel
// XORs are 'free' (included in the second AES instruction).
inline ABSL_TARGET_CRYPTO const u64x2* FeistelRound(
- uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state,
- const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys) {
+ uint64_t* state, const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys) {
static_assert(kFeistelBlocks == 16, "Expecting 16 FeistelBlocks.");
// MSVC does a horrible job at unrolling loops.
@@ -513,8 +501,7 @@ inline ABSL_TARGET_CRYPTO const u64x2* FeistelRound(
// 2^64 queries if the round function is a PRF. This is similar to the b=8 case
// of Simpira v2, but more efficient than its generic construction for b=16.
inline ABSL_TARGET_CRYPTO void Permute(
- const void* ABSL_RANDOM_INTERNAL_RESTRICT keys,
- uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state) {
+ const void* ABSL_RANDOM_INTERNAL_RESTRICT keys, uint64_t* state) {
const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys128 =
static_cast<const u64x2*>(keys);
@@ -544,10 +531,8 @@ const void* ABSL_TARGET_CRYPTO RandenHwAes::GetKeys() {
// NOLINTNEXTLINE
void ABSL_TARGET_CRYPTO RandenHwAes::Absorb(const void* seed_void,
void* state_void) {
- uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state =
- reinterpret_cast<uint64_t*>(state_void);
- const uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT seed =
- reinterpret_cast<const uint64_t*>(seed_void);
+ auto* state = static_cast<uint64_t*>(state_void);
+ const auto* seed = static_cast<const uint64_t*>(seed_void);
constexpr size_t kCapacityBlocks = kCapacityBytes / sizeof(Vector128);
constexpr size_t kStateBlocks = kStateBytes / sizeof(Vector128);
@@ -623,8 +608,7 @@ void ABSL_TARGET_CRYPTO RandenHwAes::Generate(const void* keys,
void* state_void) {
static_assert(kCapacityBytes == sizeof(Vector128), "Capacity mismatch");
- uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state =
- reinterpret_cast<uint64_t*>(state_void);
+ auto* state = static_cast<uint64_t*>(state_void);
const Vector128 prev_inner = Vector128Load(state);
diff --git a/absl/strings/internal/numbers_test_common.h b/absl/strings/internal/numbers_test_common.h
index 28247205..a263219e 100644
--- a/absl/strings/internal/numbers_test_common.h
+++ b/absl/strings/internal/numbers_test_common.h
@@ -42,8 +42,9 @@ inline bool Itoa(IntType value, int base, std::string* destination) {
while (value != 0) {
const IntType next_value = value / base;
// Can't use std::abs here because of problems when IntType is unsigned.
- int remainder = value > next_value * base ? value - next_value * base
- : next_value * base - value;
+ int remainder =
+ static_cast<int>(value > next_value * base ? value - next_value * base
+ : next_value * base - value);
char c = remainder < 10 ? '0' + remainder : 'A' + remainder - 10;
destination->insert(0, 1, c);
value = next_value;
diff --git a/absl/strings/numbers.cc b/absl/strings/numbers.cc
index d7b94fc1..4890bd54 100644
--- a/absl/strings/numbers.cc
+++ b/absl/strings/numbers.cc
@@ -93,43 +93,6 @@ bool SimpleAtod(absl::string_view str, double* out) {
return true;
}
-namespace {
-
-// 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:
-// char buf[2];
-// PutTwoDigits(42, buf);
-// // buf[0] == '4'
-// // buf[1] == '2'
-inline void PutTwoDigits(size_t i, char* buf) {
- static 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'}
- };
- assert(i < 100);
- memcpy(buf, two_ASCII_digits[i], 2);
-}
-
-} // namespace
-
bool SimpleAtob(absl::string_view str, bool* out) {
ABSL_RAW_CHECK(out != nullptr, "Output pointer must not be nullptr.");
if (EqualsIgnoreCase(str, "true") || EqualsIgnoreCase(str, "t") ||
@@ -496,13 +459,13 @@ static ExpDigits SplitToSix(const double value) {
int two_digits = dddddd / 10000;
dddddd -= two_digits * 10000;
- PutTwoDigits(two_digits, &exp_dig.digits[0]);
+ numbers_internal::PutTwoDigits(two_digits, &exp_dig.digits[0]);
two_digits = dddddd / 100;
dddddd -= two_digits * 100;
- PutTwoDigits(two_digits, &exp_dig.digits[2]);
+ numbers_internal::PutTwoDigits(two_digits, &exp_dig.digits[2]);
- PutTwoDigits(dddddd, &exp_dig.digits[4]);
+ numbers_internal::PutTwoDigits(dddddd, &exp_dig.digits[4]);
return exp_dig;
}
@@ -908,6 +871,25 @@ ABSL_CONST_INIT const char kHexTable[513] =
"e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
+ABSL_CONST_INIT 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<int32_t>(text, value, base);
}
@@ -924,5 +906,9 @@ bool safe_strtou64_base(absl::string_view text, uint64_t* value, int base) {
return safe_uint_internal<uint64_t>(text, value, base);
}
+bool safe_strtou128_base(absl::string_view text, uint128* value, int base) {
+ return safe_uint_internal<absl::uint128>(text, value, base);
+}
+
} // namespace numbers_internal
} // namespace absl
diff --git a/absl/strings/numbers.h b/absl/strings/numbers.h
index 9b8ec89a..5e15ca40 100644
--- a/absl/strings/numbers.h
+++ b/absl/strings/numbers.h
@@ -67,7 +67,7 @@ ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, int_type* out);
// Converts the given string (optionally followed or preceded by ASCII
// whitespace) into a float, which may be rounded on overflow or underflow.
// See https://en.cppreference.com/w/c/string/byte/strtof for details about the
-// allowed formats for `str`, except SimpleAtof() is locale-indepdent and will
+// allowed formats for `str`, except SimpleAtof() is locale-independent and will
// always use the "C" locale. If any errors are encountered, this function
// returns `false`, leaving `out` in an unspecified state.
ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str, float* out);
@@ -102,12 +102,26 @@ namespace numbers_internal {
// Digit conversion.
extern const char kHexChar[17]; // 0123456789abcdef
extern const char kHexTable[513]; // 000102030405060708090a0b0c0d0e0f1011...
+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:
+// char buf[2];
+// 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);
+}
// safe_strto?() functions for implementing SimpleAtoi()
bool safe_strto32_base(absl::string_view text, int32_t* value, int base);
bool safe_strto64_base(absl::string_view text, int64_t* value, int base);
bool safe_strtou32_base(absl::string_view text, uint32_t* value, int base);
bool safe_strtou64_base(absl::string_view text, uint64_t* value, int base);
+bool safe_strtou128_base(absl::string_view text, absl::uint128* value,
+ int base);
static const int kFastToBufferSize = 32;
static const int kSixDigitsToBufferSize = 16;
@@ -232,6 +246,11 @@ ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, int_type* out) {
return numbers_internal::safe_strtoi_base(str, out, 10);
}
+ABSL_MUST_USE_RESULT inline bool SimpleAtoi(absl::string_view str,
+ absl::uint128* out) {
+ return numbers_internal::safe_strtou128_base(str, out, 10);
+}
+
} // namespace absl
#endif // ABSL_STRINGS_NUMBERS_H_
diff --git a/absl/strings/numbers_test.cc b/absl/strings/numbers_test.cc
index b92b9a8c..68229b15 100644
--- a/absl/strings/numbers_test.cc
+++ b/absl/strings/numbers_test.cc
@@ -249,7 +249,9 @@ TEST(Numbers, TestFastPrints) {
template <typename int_type, typename in_val_type>
void VerifySimpleAtoiGood(in_val_type in_value, int_type exp_value) {
- std::string s = absl::StrCat(in_value);
+ std::string s;
+ // uint128 can be streamed but not StrCat'd
+ absl::strings_internal::OStringStream(&s) << in_value;
int_type x = static_cast<int_type>(~exp_value);
EXPECT_TRUE(SimpleAtoi(s, &x))
<< "in_value=" << in_value << " s=" << s << " x=" << x;
@@ -325,6 +327,25 @@ TEST(NumbersTest, Atoi) {
VerifySimpleAtoiGood<uint64_t>(std::numeric_limits<uint64_t>::max(),
std::numeric_limits<uint64_t>::max());
+ // SimpleAtoi(absl::string_view, absl::uint128)
+ VerifySimpleAtoiGood<absl::uint128>(0, 0);
+ VerifySimpleAtoiGood<absl::uint128>(42, 42);
+ VerifySimpleAtoiBad<absl::uint128>(-42);
+
+ VerifySimpleAtoiBad<absl::uint128>(std::numeric_limits<int32_t>::min());
+ VerifySimpleAtoiGood<absl::uint128>(std::numeric_limits<int32_t>::max(),
+ std::numeric_limits<int32_t>::max());
+ VerifySimpleAtoiGood<absl::uint128>(std::numeric_limits<uint32_t>::max(),
+ std::numeric_limits<uint32_t>::max());
+ VerifySimpleAtoiBad<absl::uint128>(std::numeric_limits<int64_t>::min());
+ VerifySimpleAtoiGood<absl::uint128>(std::numeric_limits<int64_t>::max(),
+ std::numeric_limits<int64_t>::max());
+ VerifySimpleAtoiGood<absl::uint128>(std::numeric_limits<uint64_t>::max(),
+ std::numeric_limits<uint64_t>::max());
+ VerifySimpleAtoiGood<absl::uint128>(
+ std::numeric_limits<absl::uint128>::max(),
+ std::numeric_limits<absl::uint128>::max());
+
// Some other types
VerifySimpleAtoiGood<int>(-42, -42);
VerifySimpleAtoiGood<int32_t>(-42, -42);
@@ -657,6 +678,46 @@ TEST(stringtest, safe_strtou32_random) {
TEST(stringtest, safe_strtou64_random) {
test_random_integer_parse_base<uint64_t>(&safe_strtou64_base);
}
+TEST(stringtest, safe_strtou128_random) {
+ // random number generators don't work for uint128, and
+ // uint128 can be streamed but not StrCat'd, so this code must be custom
+ // implemented for uint128, but is generally the same as what's above.
+ // test_random_integer_parse_base<absl::uint128>(
+ // &absl::numbers_internal::safe_strtou128_base);
+ using RandomEngine = std::minstd_rand0;
+ using IntType = absl::uint128;
+ constexpr auto parse_func = &absl::numbers_internal::safe_strtou128_base;
+
+ std::random_device rd;
+ RandomEngine rng(rd());
+ std::uniform_int_distribution<uint64_t> random_uint64(
+ std::numeric_limits<uint64_t>::min());
+ std::uniform_int_distribution<int> random_base(2, 35);
+
+ for (size_t i = 0; i < kNumRandomTests; i++) {
+ IntType value = random_uint64(rng);
+ value = (value << 64) + random_uint64(rng);
+ int base = random_base(rng);
+ std::string str_value;
+ EXPECT_TRUE(Itoa<IntType>(value, base, &str_value));
+ IntType parsed_value;
+
+ // Test successful parse
+ EXPECT_TRUE(parse_func(str_value, &parsed_value, base));
+ EXPECT_EQ(parsed_value, value);
+
+ // Test overflow
+ std::string s;
+ absl::strings_internal::OStringStream(&s)
+ << std::numeric_limits<IntType>::max() << value;
+ EXPECT_FALSE(parse_func(s, &parsed_value, base));
+
+ // Test underflow
+ s.clear();
+ absl::strings_internal::OStringStream(&s) << "-" << value;
+ EXPECT_FALSE(parse_func(s, &parsed_value, base));
+ }
+}
TEST(stringtest, safe_strtou32_base) {
for (int i = 0; strtouint32_test_cases()[i].str != nullptr; ++i) {
diff --git a/absl/synchronization/internal/waiter.cc b/absl/synchronization/internal/waiter.cc
index 8e713770..f1425872 100644
--- a/absl/synchronization/internal/waiter.cc
+++ b/absl/synchronization/internal/waiter.cc
@@ -342,8 +342,11 @@ bool Waiter::Wait(KernelTimeout t) {
}
void Waiter::Post() {
- wakeups_.fetch_add(1, std::memory_order_release); // Post a wakeup.
- Poke();
+ // Post a wakeup.
+ if (wakeups_.fetch_add(1, std::memory_order_release) == 0) {
+ // We incremented from 0, need to wake a potential waiter.
+ Poke();
+ }
}
void Waiter::Poke() {
diff --git a/absl/synchronization/internal/waiter.h b/absl/synchronization/internal/waiter.h
index cac81d5f..9540598b 100644
--- a/absl/synchronization/internal/waiter.h
+++ b/absl/synchronization/internal/waiter.h
@@ -24,6 +24,10 @@
#include <pthread.h>
#endif
+#ifdef __linux__
+#include <linux/futex.h>
+#endif
+
#ifdef ABSL_HAVE_SEMAPHORE_H
#include <semaphore.h>
#endif
@@ -44,7 +48,12 @@
#define ABSL_WAITER_MODE ABSL_FORCE_WAITER_MODE
#elif defined(_WIN32) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
#define ABSL_WAITER_MODE ABSL_WAITER_MODE_WIN32
-#elif defined(__linux__)
+#elif defined(__BIONIC__)
+// Bionic supports all the futex operations we need even when some of the futex
+// definitions are missing.
+#define ABSL_WAITER_MODE ABSL_WAITER_MODE_FUTEX
+#elif defined(__linux__) && defined(FUTEX_CLOCK_REALTIME)
+// FUTEX_CLOCK_REALTIME requires Linux >= 2.6.28.
#define ABSL_WAITER_MODE ABSL_WAITER_MODE_FUTEX
#elif defined(ABSL_HAVE_SEMAPHORE_H)
#define ABSL_WAITER_MODE ABSL_WAITER_MODE_SEM