Export of internal Abseil changes

--
049ac45508e335c6f010f2d28d71016b9fa65b4e by Derek Mauro <dmauro@google.com>:

Fix librt detection

PiperOrigin-RevId: 280207723

--
6382c3a9fb2643af9dc031f92ca846c4a78e249c by Andy Getzendanner <durandal@google.com>:

Fix Conan builds

Import of https://github.com/abseil/abseil-cpp/pull/400

PiperOrigin-RevId: 280025424

--
aebcd52b1686ac82663a8d0193b60d0122a43372 by Samuel Benzaquen <sbenza@google.com>:

Enable the assertion in the iterator's operator== and operator!=

PiperOrigin-RevId: 279998951

--
5b61d909e2159ac6fd45e0e456818db1e725ecd1 by Derek Mauro <dmauro@google.com>:

Add best effort support for compiling much of Abseil with MinGW.
This involves disabling ABSL_ATTRIBUTE_WEAK and adding link flags.

A change to CCTZ is still necessary.

Tests were not run yet, but most of them now build.

PiperOrigin-RevId: 279966541

--
4336f8b10cff906e2defdd7d1d449cde4907da5d by Abseil Team <absl-team@google.com>:

Add comments and relax memory orders in base_internal::CallOnceImpl.

Add a comment to document the memory order guarantee if
base_internal::SpinLockWait() is called and returns kOnceDone.

Add a comment for the load/store sequence in base_internal::CallOnceImpl
based on Mike Burrows' explanation.

The atomic load of 'control' in the #ifndef NDEBUG block does not need
std::memory_order_acquire. It can use std::memory_order_relaxed.

The atomic compare_exchange_strong of 'control' does not need
std::memory_order_acquire in the success case. It can use
std::memory_order_relaxed.
PiperOrigin-RevId: 279814155

--
407de3a5e9af957cded54a136ca0468bde620d4d by Abseil Team <absl-team@google.com>:

Added a script to generate abseil.podspec from all BUILD.bazel files automatically.

PiperOrigin-RevId: 279811441

--
26139497d4a363d6c7bc989c554da593e8819a07 by Derek Mauro <dmauro@google.com>:

Add missing copyright and Apache License to //absl/functional/BUILD.bazel

PiperOrigin-RevId: 279795227

--
98ed625b02af6e5834edf52a920d8ca2dab4cd90 by Matt Kulukundis <kfm@google.com>:

Switch the implementation of hashtablez to *only* work on platforms that have a
PER_THREAD_TLS.

The old case is very slow (global mutex) and nobody collects data from that
configuration anyway.

PiperOrigin-RevId: 279775149

--
07225900ef672c005c38f467ad3f92f38d0922b3 by Derek Mauro <dmauro@google.com>:

Remove the minumum glibc version check

PiperOrigin-RevId: 279750412

--
ec09956a951b4f52228ecc81968b8db7ae19ed15 by Derek Mauro <dmauro@google.com>:

CMake only: link with -lrt to support older glibc versions

PiperOrigin-RevId: 279741661

--
97b113fb2e8246f6152c36330ba13793b37154b6 by Xiaoyi Zhang <zhangxy@google.com>:

Internal change.

PiperOrigin-RevId: 279390188

--
ca8f72f2721546cc9b01bd01b2ea144962e6e0c5 by Andy Getzendanner <durandal@google.com>:

Expose PutTwoDigits for internal use within Abseil.

PiperOrigin-RevId: 279374239

--
14c6384cc03bbdfdefd2e4b635f104af5dd7e026 by Derek Mauro <dmauro@google.com>:

Remove log_severity sources from the base target.
They are already compiled as part of a separate library.

PiperOrigin-RevId: 279372619

--
3c5d926c718f8bf394e3bee87b6ba8d94601e0d3 by Abseil Team <absl-team@google.com>:

s/indepdent/independent/g in SimpleAtof's documentation.

PiperOrigin-RevId: 279350836

--
de2c44be8a8edf9efa1fe2007cba3564f3e5b0b8 by Abseil Team <absl-team@google.com>:

Internal change

PiperOrigin-RevId: 279346990

--
2ba078341423fcf6d0ba5ca1831f86570a26e615 by Samuel Benzaquen <sbenza@google.com>:

Add hash support for std::wstring, std::u16string and std::u32string.

PiperOrigin-RevId: 279320672

--
3272d3ffcfa55283a04f90e5868701912da95ef7 by Andy Soffer <asoffer@google.com>:

Removing a bunch of __restricts that amount to no performance differences. One
of these is the cause of https://github.com/abseil/abseil-cpp/issues/396. In
particular, in one of the Vector128Store functions, restricts on two pointers
that were indeed aliased seems to be the root cause of the issues.

Closes #396

PiperOrigin-RevId: 279318999

--
342f338ab31cc24344d5de8f28cf455bbb629a17 by Jorg Brown <jorg@google.com>:

Support uint128 in SimpleAtoi

PiperOrigin-RevId: 279234038

--
81cb0a04cf2dc4515d303679fc60968712191571 by Derek Mauro <dmauro@google.com>:

Change the check for futex availability to support older Linux systems

PiperOrigin-RevId: 279147079

--
cb4ca4aa4c8d2d710a5d483c56c4ce4f979e14b1 by Abseil Team <absl-team@google.com>:

Add IWYU pragma: export for int128 .inc files.

PiperOrigin-RevId: 279107098

--
b8df86ef610c366729f07326c726f3e34817b4dd by Abseil Team <absl-team@google.com>:

An optimization for Waiter::Post() in the SEM waiter mode.

Like the FUTEX waiter mode, Waiter::Post() only needs to call Poke() if
it incremented the atomic variable from 0.

PiperOrigin-RevId: 279086133
GitOrigin-RevId: 049ac45508e335c6f010f2d28d71016b9fa65b4e
Change-Id: I4c1a4073fff62cb6a1fcb1c104aa7d62dad588c2
This commit is contained in:
Abseil Team 2019-11-13 08:54:32 -08:00 committed by Andy Getz
parent 85092b4b64
commit fa8c75182f
26 changed files with 503 additions and 117 deletions

247
absl/abseil.podspec.gen.py Executable file
View file

@ -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()

View file

@ -192,7 +192,9 @@ cc_library(
], ],
copts = ABSL_DEFAULT_COPTS, copts = ABSL_DEFAULT_COPTS,
linkopts = select({ linkopts = select({
"//absl:windows": [], "//absl:windows": [
"-DEFAULTLIB:shlwapi.lib",
],
"//conditions:default": ["-pthread"], "//conditions:default": ["-pthread"],
}) + ABSL_DEFAULT_LINKOPTS, }) + ABSL_DEFAULT_LINKOPTS,
deps = [ deps = [

View file

@ -14,6 +14,8 @@
# limitations under the License. # limitations under the License.
# #
find_library(LIBRT rt)
absl_cc_library( absl_cc_library(
NAME NAME
atomic_hook atomic_hook
@ -163,16 +165,18 @@ absl_cc_library(
"internal/thread_identity.h" "internal/thread_identity.h"
"internal/tsan_mutex_interface.h" "internal/tsan_mutex_interface.h"
"internal/unscaledcycleclock.h" "internal/unscaledcycleclock.h"
"log_severity.h"
SRCS SRCS
"internal/cycleclock.cc" "internal/cycleclock.cc"
"internal/spinlock.cc" "internal/spinlock.cc"
"internal/sysinfo.cc" "internal/sysinfo.cc"
"internal/thread_identity.cc" "internal/thread_identity.cc"
"internal/unscaledcycleclock.cc" "internal/unscaledcycleclock.cc"
"log_severity.cc"
COPTS COPTS
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
$<$<BOOL:${LIBRT}>:${LIBRT}>
$<$<BOOL:${MINGW}>:"shlwapi">
DEPS DEPS
absl::atomic_hook absl::atomic_hook
absl::base_internal absl::base_internal

View file

@ -158,9 +158,11 @@
// Weak attributes currently do not work properly in LLVM's Windows backend, // 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 // so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598
// for further information. // for further information.
// 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) || \ #if (ABSL_HAVE_ATTRIBUTE(weak) || \
(defined(__GNUC__) && !defined(__clang__))) && \ (defined(__GNUC__) && !defined(__clang__))) && \
!(defined(__llvm__) && defined(_WIN32)) !(defined(__llvm__) && defined(_WIN32)) && !defined(__MINGW32__)
#undef ABSL_ATTRIBUTE_WEAK #undef ABSL_ATTRIBUTE_WEAK
#define ABSL_ATTRIBUTE_WEAK __attribute__((weak)) #define ABSL_ATTRIBUTE_WEAK __attribute__((weak))
#define ABSL_HAVE_ATTRIBUTE_WEAK 1 #define ABSL_HAVE_ATTRIBUTE_WEAK 1

View file

@ -148,7 +148,7 @@ void CallOnceImpl(std::atomic<uint32_t>* control,
Args&&... args) { Args&&... args) {
#ifndef NDEBUG #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 && if (old_control != kOnceInit &&
old_control != kOnceRunning && old_control != kOnceRunning &&
old_control != kOnceWaiter && old_control != kOnceWaiter &&
@ -166,14 +166,23 @@ void CallOnceImpl(std::atomic<uint32_t>* control,
// Must do this before potentially modifying control word's state. // Must do this before potentially modifying control word's state.
base_internal::SchedulingHelper maybe_disable_scheduling(scheduling_mode); base_internal::SchedulingHelper maybe_disable_scheduling(scheduling_mode);
// Short circuit the simplest case to avoid procedure call overhead. // 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; uint32_t old_control = kOnceInit;
if (control->compare_exchange_strong(old_control, kOnceRunning, if (control->compare_exchange_strong(old_control, kOnceRunning,
std::memory_order_acquire,
std::memory_order_relaxed) || std::memory_order_relaxed) ||
base_internal::SpinLockWait(control, ABSL_ARRAYSIZE(trans), trans, base_internal::SpinLockWait(control, ABSL_ARRAYSIZE(trans), trans,
scheduling_mode) == kOnceInit) { scheduling_mode) == kOnceInit) {
base_internal::Invoke(std::forward<Callable>(fn), base_internal::Invoke(std::forward<Callable>(fn),
std::forward<Args>(args)...); 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); old_control = control->load(std::memory_order_relaxed);
control->store(base_internal::kOnceDone, std::memory_order_release); control->store(base_internal::kOnceDone, std::memory_order_release);
if (old_control == base_internal::kOnceWaiter) { if (old_control == base_internal::kOnceWaiter) {

View file

@ -82,16 +82,6 @@
// Standard Library Check // 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) #if defined(_STLPORT_VERSION)
#error "STLPort is not supported." #error "STLPort is not supported."
#endif #endif

View file

@ -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_sample_parameter{1 << 10};
ABSL_CONST_INIT std::atomic<int32_t> g_hashtablez_max_samples{1 << 20}; ABSL_CONST_INIT std::atomic<int32_t> g_hashtablez_max_samples{1 << 20};
#if ABSL_HAVE_THREAD_LOCAL #if ABSL_PER_THREAD_TLS == 1
thread_local absl::base_internal::ExponentialBiased ABSL_PER_THREAD_TLS_KEYWORD absl::base_internal::ExponentialBiased
g_exponential_biased_generator;
#else
ABSL_CONST_INIT static absl::base_internal::ExponentialBiased
g_exponential_biased_generator; g_exponential_biased_generator;
#endif #endif
} // namespace } // 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() { HashtablezSampler& HashtablezSampler::Global() {
static auto* sampler = new HashtablezSampler(); static auto* sampler = new HashtablezSampler();
return *sampler; return *sampler;
@ -189,6 +191,10 @@ HashtablezInfo* SampleSlow(int64_t* next_sample) {
return HashtablezSampler::Global().Register(); 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; bool first = *next_sample < 0;
*next_sample = g_exponential_biased_generator.Get( *next_sample = g_exponential_biased_generator.Get(
g_hashtablez_sample_parameter.load(std::memory_order_relaxed)); g_hashtablez_sample_parameter.load(std::memory_order_relaxed));
@ -210,12 +216,9 @@ HashtablezInfo* SampleSlow(int64_t* next_sample) {
} }
return HashtablezSampler::Global().Register(); 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) { void UnsampleSlow(HashtablezInfo* info) {
HashtablezSampler::Global().Unregister(info); HashtablezSampler::Global().Unregister(info);
} }

View file

@ -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 // Returns an RAII sampling handle that manages registration and unregistation
// with the global sampler. // with the global sampler.
inline HashtablezInfoHandle Sample() { inline HashtablezInfoHandle Sample() {
#if ABSL_PER_THREAD_TLS == 0 #if ABSL_PER_THREAD_TLS == 1
static auto* mu = new absl::Mutex;
static int64_t global_next_sample = 0;
absl::MutexLock l(mu);
#endif // !ABSL_HAVE_THREAD_LOCAL
if (ABSL_PREDICT_TRUE(--global_next_sample > 0)) { if (ABSL_PREDICT_TRUE(--global_next_sample > 0)) {
return HashtablezInfoHandle(nullptr); return HashtablezInfoHandle(nullptr);
} }
return HashtablezInfoHandle(SampleSlow(&global_next_sample)); 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 // Holds samples and their associated stack traces with a soft limit of

View file

@ -168,6 +168,7 @@ TEST(HashtablezInfoTest, RecordRehash) {
EXPECT_EQ(info.num_erases.load(), 0); EXPECT_EQ(info.num_erases.load(), 0);
} }
#if ABSL_PER_THREAD_TLS == 1
TEST(HashtablezSamplerTest, SmallSampleParameter) { TEST(HashtablezSamplerTest, SmallSampleParameter) {
SetHashtablezEnabled(true); SetHashtablezEnabled(true);
SetHashtablezSampleParameter(100); SetHashtablezSampleParameter(100);
@ -211,6 +212,7 @@ TEST(HashtablezSamplerTest, Sample) {
} }
EXPECT_NEAR(sample_rate, 0.01, 0.005); EXPECT_NEAR(sample_rate, 0.01, 0.005);
} }
#endif
TEST(HashtablezSamplerTest, Handle) { TEST(HashtablezSamplerTest, Handle) {
auto& sampler = HashtablezSampler::Global(); auto& sampler = HashtablezSampler::Global();

View file

@ -638,8 +638,8 @@ class raw_hash_set {
} }
friend bool operator==(const iterator& a, const iterator& b) { friend bool operator==(const iterator& a, const iterator& b) {
/* To be enabled: a.assert_is_valid(); */ a.assert_is_valid();
/* To be enabled: b.assert_is_valid(); */ b.assert_is_valid();
return a.ctrl_ == b.ctrl_; return a.ctrl_ == b.ctrl_;
} }
friend bool operator!=(const iterator& a, const iterator& b) { friend bool operator!=(const iterator& a, const iterator& b) {

View file

@ -1841,6 +1841,7 @@ TEST(TableDeathTest, EraseOfEndAsserts) {
EXPECT_DEATH_IF_SUPPORTED(t.erase(t.end()), kDeathMsg); EXPECT_DEATH_IF_SUPPORTED(t.erase(t.end()), kDeathMsg);
} }
#if ABSL_PER_THREAD_TLS == 1
TEST(RawHashSamplerTest, Sample) { TEST(RawHashSamplerTest, Sample) {
// Enable the feature even if the prod default is off. // Enable the feature even if the prod default is off.
SetHashtablezEnabled(true); SetHashtablezEnabled(true);
@ -1861,6 +1862,7 @@ TEST(RawHashSamplerTest, Sample) {
EXPECT_NEAR((end_size - start_size) / static_cast<double>(tables.size()), EXPECT_NEAR((end_size - start_size) / static_cast<double>(tables.size()),
0.01, 0.005); 0.01, 0.005);
} }
#endif
TEST(RawHashSamplerTest, DoNotSampleCustomAllocators) { TEST(RawHashSamplerTest, DoNotSampleCustomAllocators) {
// Enable the feature even if the prod default is off. // Enable the feature even if the prod default is off.

View file

@ -55,7 +55,10 @@ cc_library(
"symbolize.h", "symbolize.h",
], ],
copts = ABSL_DEFAULT_COPTS, copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS + select({
"//absl:windows": ["-DEFAULTLIB:dbghelp.lib"],
"//conditions:default": [],
}),
deps = [ deps = [
":debugging_internal", ":debugging_internal",
":demangle_internal", ":demangle_internal",

View file

@ -44,6 +44,7 @@ absl_cc_library(
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
LINKOPTS LINKOPTS
${ABSL_DEFAULT_LINKOPTS} ${ABSL_DEFAULT_LINKOPTS}
$<$<BOOL:${MINGW}>:"dbghelp">
DEPS DEPS
absl::debugging_internal absl::debugging_internal
absl::demangle_internal absl::demangle_internal

View file

@ -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("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load( load(
"//absl:copts/configure_copts.bzl", "//absl:copts/configure_copts.bzl",

View file

@ -300,6 +300,33 @@ TEST(HashValueTest, Strings) {
SpyHash(absl::string_view("ABC"))); 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) { TEST(HashValueTest, StdArray) {
EXPECT_TRUE((is_hashable<std::array<int, 3>>::value)); EXPECT_TRUE((is_hashable<std::array<int, 3>>::value));

View file

@ -427,6 +427,19 @@ H AbslHashValue(H hash_state, absl::string_view str) {
str.size()); 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 // AbslHashValue for Sequence Containers
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View file

@ -720,9 +720,9 @@ inline uint128& uint128::operator--() {
} }
#if defined(ABSL_HAVE_INTRINSIC_INT128) #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 #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 #endif // ABSL_HAVE_INTRINSIC_INT128
} // namespace absl } // namespace absl

View file

@ -447,6 +447,7 @@ absl_cc_library(
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
LINKOPTS LINKOPTS
${ABSL_DEFAULT_LINKOPTS} ${ABSL_DEFAULT_LINKOPTS}
$<$<BOOL:${MINGW}>:"bcrypt">
DEPS DEPS
absl::core_headers absl::core_headers
absl::optional absl::optional

View file

@ -89,7 +89,10 @@ cc_library(
"seed_material.h", "seed_material.h",
], ],
copts = ABSL_DEFAULT_COPTS, copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS + select({
"//absl:windows": ["-DEFAULTLIB:bcrypt.lib"],
"//conditions:default": [],
}),
deps = [ deps = [
":fast_uniform_bits", ":fast_uniform_bits",
"//absl/base:core_headers", "//absl/base:core_headers",

View file

@ -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 // 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 // store an unchanged vector, but interpreting the bits as a number or input
// to AES will have undefined results. // to AES will have undefined results.
inline ABSL_TARGET_CRYPTO Vector128 inline ABSL_TARGET_CRYPTO Vector128 Vector128Load(const void* from) {
Vector128Load(const void* ABSL_RANDOM_INTERNAL_RESTRICT from) {
return vec_vsx_ld(0, reinterpret_cast<const Vector128*>(from)); return vec_vsx_ld(0, reinterpret_cast<const Vector128*>(from));
} }
inline ABSL_TARGET_CRYPTO void Vector128Store( inline ABSL_TARGET_CRYPTO void Vector128Store(const Vector128& v, void* to) {
const Vector128& v, void* ABSL_RANDOM_INTERNAL_RESTRICT to) {
vec_vsx_st(v, 0, reinterpret_cast<Vector128*>(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. // Enables native loads in the round loop by pre-swapping.
inline ABSL_TARGET_CRYPTO void SwapEndian( inline ABSL_TARGET_CRYPTO void SwapEndian(uint64_t* state) {
uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state) {
using absl::random_internal::RandenTraits; using absl::random_internal::RandenTraits;
constexpr size_t kLanes = 2; constexpr size_t kLanes = 2;
constexpr size_t kFeistelBlocks = RandenTraits::kFeistelBlocks; constexpr size_t kFeistelBlocks = RandenTraits::kFeistelBlocks;
@ -230,13 +227,11 @@ using Vector128 = uint8x16_t;
namespace { namespace {
inline ABSL_TARGET_CRYPTO Vector128 inline ABSL_TARGET_CRYPTO Vector128 Vector128Load(const void* from) {
Vector128Load(const void* ABSL_RANDOM_INTERNAL_RESTRICT from) {
return vld1q_u8(reinterpret_cast<const uint8_t*>(from)); return vld1q_u8(reinterpret_cast<const uint8_t*>(from));
} }
inline ABSL_TARGET_CRYPTO void Vector128Store( inline ABSL_TARGET_CRYPTO void Vector128Store(const Vector128& v, void* to) {
const Vector128& v, void* ABSL_RANDOM_INTERNAL_RESTRICT to) {
vst1q_u8(reinterpret_cast<uint8_t*>(to), v); 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; return vaesmcq_u8(vaeseq_u8(state, uint8x16_t{})) ^ round_key;
} }
inline ABSL_TARGET_CRYPTO void SwapEndian( inline ABSL_TARGET_CRYPTO void SwapEndian(uint64_t*) {}
uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT) {}
} // namespace } // namespace
@ -283,15 +277,12 @@ class Vector128 {
__m128i data_; __m128i data_;
}; };
inline ABSL_TARGET_CRYPTO Vector128 inline ABSL_TARGET_CRYPTO Vector128 Vector128Load(const void* from) {
Vector128Load(const void* ABSL_RANDOM_INTERNAL_RESTRICT from) {
return Vector128(_mm_load_si128(reinterpret_cast<const __m128i*>(from))); return Vector128(_mm_load_si128(reinterpret_cast<const __m128i*>(from)));
} }
inline ABSL_TARGET_CRYPTO void Vector128Store( inline ABSL_TARGET_CRYPTO void Vector128Store(const Vector128& v, void* to) {
const Vector128& v, void* ABSL_RANDOM_INTERNAL_RESTRICT to) { _mm_store_si128(reinterpret_cast<__m128i*>(to), v.data());
_mm_store_si128(reinterpret_cast<__m128i * ABSL_RANDOM_INTERNAL_RESTRICT>(to),
v.data());
} }
// One round of AES. "round_key" is a public constant for breaking the // 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())); return Vector128(_mm_aesenc_si128(state.data(), round_key.data()));
} }
inline ABSL_TARGET_CRYPTO void SwapEndian( inline ABSL_TARGET_CRYPTO void SwapEndian(uint64_t*) {}
uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT) {}
} // namespace } // namespace
@ -402,8 +392,7 @@ constexpr size_t kLanes = 2;
// Block shuffles applies a shuffle to the entire state between AES rounds. // Block shuffles applies a shuffle to the entire state between AES rounds.
// Improved odd-even shuffle from "New criterion for diffusion property". // Improved odd-even shuffle from "New criterion for diffusion property".
inline ABSL_TARGET_CRYPTO void BlockShuffle( inline ABSL_TARGET_CRYPTO void BlockShuffle(uint64_t* state) {
uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state) {
static_assert(kFeistelBlocks == 16, "Expecting 16 FeistelBlocks."); static_assert(kFeistelBlocks == 16, "Expecting 16 FeistelBlocks.");
constexpr size_t shuffle[kFeistelBlocks] = {7, 2, 13, 4, 11, 8, 3, 6, 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 // parallel hides the 7-cycle AESNI latency on HSW. Note that the Feistel
// XORs are 'free' (included in the second AES instruction). // XORs are 'free' (included in the second AES instruction).
inline ABSL_TARGET_CRYPTO const u64x2* FeistelRound( inline ABSL_TARGET_CRYPTO const u64x2* FeistelRound(
uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state, uint64_t* state, const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys) {
const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys) {
static_assert(kFeistelBlocks == 16, "Expecting 16 FeistelBlocks."); static_assert(kFeistelBlocks == 16, "Expecting 16 FeistelBlocks.");
// MSVC does a horrible job at unrolling loops. // 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 // 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. // of Simpira v2, but more efficient than its generic construction for b=16.
inline ABSL_TARGET_CRYPTO void Permute( inline ABSL_TARGET_CRYPTO void Permute(
const void* ABSL_RANDOM_INTERNAL_RESTRICT keys, const void* ABSL_RANDOM_INTERNAL_RESTRICT keys, uint64_t* state) {
uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state) {
const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys128 = const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys128 =
static_cast<const u64x2*>(keys); static_cast<const u64x2*>(keys);
@ -544,10 +531,8 @@ const void* ABSL_TARGET_CRYPTO RandenHwAes::GetKeys() {
// NOLINTNEXTLINE // NOLINTNEXTLINE
void ABSL_TARGET_CRYPTO RandenHwAes::Absorb(const void* seed_void, void ABSL_TARGET_CRYPTO RandenHwAes::Absorb(const void* seed_void,
void* state_void) { void* state_void) {
uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state = auto* state = static_cast<uint64_t*>(state_void);
reinterpret_cast<uint64_t*>(state_void); const auto* seed = static_cast<const uint64_t*>(seed_void);
const uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT seed =
reinterpret_cast<const uint64_t*>(seed_void);
constexpr size_t kCapacityBlocks = kCapacityBytes / sizeof(Vector128); constexpr size_t kCapacityBlocks = kCapacityBytes / sizeof(Vector128);
constexpr size_t kStateBlocks = kStateBytes / 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) { void* state_void) {
static_assert(kCapacityBytes == sizeof(Vector128), "Capacity mismatch"); static_assert(kCapacityBytes == sizeof(Vector128), "Capacity mismatch");
uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state = auto* state = static_cast<uint64_t*>(state_void);
reinterpret_cast<uint64_t*>(state_void);
const Vector128 prev_inner = Vector128Load(state); const Vector128 prev_inner = Vector128Load(state);

View file

@ -42,8 +42,9 @@ inline bool Itoa(IntType value, int base, std::string* destination) {
while (value != 0) { while (value != 0) {
const IntType next_value = value / base; const IntType next_value = value / base;
// Can't use std::abs here because of problems when IntType is unsigned. // Can't use std::abs here because of problems when IntType is unsigned.
int remainder = value > next_value * base ? value - next_value * base int remainder =
: next_value * base - value; static_cast<int>(value > next_value * base ? value - next_value * base
: next_value * base - value);
char c = remainder < 10 ? '0' + remainder : 'A' + remainder - 10; char c = remainder < 10 ? '0' + remainder : 'A' + remainder - 10;
destination->insert(0, 1, c); destination->insert(0, 1, c);
value = next_value; value = next_value;

View file

@ -93,43 +93,6 @@ bool SimpleAtod(absl::string_view str, double* out) {
return true; 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) { bool SimpleAtob(absl::string_view str, bool* out) {
ABSL_RAW_CHECK(out != nullptr, "Output pointer must not be nullptr."); ABSL_RAW_CHECK(out != nullptr, "Output pointer must not be nullptr.");
if (EqualsIgnoreCase(str, "true") || EqualsIgnoreCase(str, "t") || if (EqualsIgnoreCase(str, "true") || EqualsIgnoreCase(str, "t") ||
@ -496,13 +459,13 @@ static ExpDigits SplitToSix(const double value) {
int two_digits = dddddd / 10000; int two_digits = dddddd / 10000;
dddddd -= two_digits * 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; two_digits = dddddd / 100;
dddddd -= two_digits * 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; return exp_dig;
} }
@ -908,6 +871,25 @@ ABSL_CONST_INIT const char kHexTable[513] =
"e0e1e2e3e4e5e6e7e8e9eaebecedeeef" "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; "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) { bool safe_strto32_base(absl::string_view text, int32_t* value, int base) {
return safe_int_internal<int32_t>(text, value, 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); 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 numbers_internal
} // namespace absl } // namespace absl

View file

@ -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 // Converts the given string (optionally followed or preceded by ASCII
// whitespace) into a float, which may be rounded on overflow or underflow. // 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 // 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 // always use the "C" locale. If any errors are encountered, this function
// returns `false`, leaving `out` in an unspecified state. // returns `false`, leaving `out` in an unspecified state.
ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str, float* out); ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str, float* out);
@ -102,12 +102,26 @@ namespace numbers_internal {
// Digit conversion. // Digit conversion.
extern const char kHexChar[17]; // 0123456789abcdef extern const char kHexChar[17]; // 0123456789abcdef
extern const char kHexTable[513]; // 000102030405060708090a0b0c0d0e0f1011... 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() // safe_strto?() functions for implementing SimpleAtoi()
bool safe_strto32_base(absl::string_view text, int32_t* value, int base); 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_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_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_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 kFastToBufferSize = 32;
static const int kSixDigitsToBufferSize = 16; 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); 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 } // namespace absl
#endif // ABSL_STRINGS_NUMBERS_H_ #endif // ABSL_STRINGS_NUMBERS_H_

View file

@ -249,7 +249,9 @@ TEST(Numbers, TestFastPrints) {
template <typename int_type, typename in_val_type> template <typename int_type, typename in_val_type>
void VerifySimpleAtoiGood(in_val_type in_value, int_type exp_value) { 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); int_type x = static_cast<int_type>(~exp_value);
EXPECT_TRUE(SimpleAtoi(s, &x)) EXPECT_TRUE(SimpleAtoi(s, &x))
<< "in_value=" << in_value << " s=" << s << " x=" << 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(), VerifySimpleAtoiGood<uint64_t>(std::numeric_limits<uint64_t>::max(),
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 // Some other types
VerifySimpleAtoiGood<int>(-42, -42); VerifySimpleAtoiGood<int>(-42, -42);
VerifySimpleAtoiGood<int32_t>(-42, -42); VerifySimpleAtoiGood<int32_t>(-42, -42);
@ -657,6 +678,46 @@ TEST(stringtest, safe_strtou32_random) {
TEST(stringtest, safe_strtou64_random) { TEST(stringtest, safe_strtou64_random) {
test_random_integer_parse_base<uint64_t>(&safe_strtou64_base); 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) { TEST(stringtest, safe_strtou32_base) {
for (int i = 0; strtouint32_test_cases()[i].str != nullptr; ++i) { for (int i = 0; strtouint32_test_cases()[i].str != nullptr; ++i) {

View file

@ -342,8 +342,11 @@ bool Waiter::Wait(KernelTimeout t) {
} }
void Waiter::Post() { void Waiter::Post() {
wakeups_.fetch_add(1, std::memory_order_release); // Post a wakeup. // Post a wakeup.
if (wakeups_.fetch_add(1, std::memory_order_release) == 0) {
// We incremented from 0, need to wake a potential waiter.
Poke(); Poke();
}
} }
void Waiter::Poke() { void Waiter::Poke() {

View file

@ -24,6 +24,10 @@
#include <pthread.h> #include <pthread.h>
#endif #endif
#ifdef __linux__
#include <linux/futex.h>
#endif
#ifdef ABSL_HAVE_SEMAPHORE_H #ifdef ABSL_HAVE_SEMAPHORE_H
#include <semaphore.h> #include <semaphore.h>
#endif #endif
@ -44,7 +48,12 @@
#define ABSL_WAITER_MODE ABSL_FORCE_WAITER_MODE #define ABSL_WAITER_MODE ABSL_FORCE_WAITER_MODE
#elif defined(_WIN32) && _WIN32_WINNT >= _WIN32_WINNT_VISTA #elif defined(_WIN32) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
#define ABSL_WAITER_MODE ABSL_WAITER_MODE_WIN32 #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 #define ABSL_WAITER_MODE ABSL_WAITER_MODE_FUTEX
#elif defined(ABSL_HAVE_SEMAPHORE_H) #elif defined(ABSL_HAVE_SEMAPHORE_H)
#define ABSL_WAITER_MODE ABSL_WAITER_MODE_SEM #define ABSL_WAITER_MODE ABSL_WAITER_MODE_SEM