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:
parent
85092b4b64
commit
fa8c75182f
26 changed files with 503 additions and 117 deletions
247
absl/abseil.podspec.gen.py
Executable file
247
absl/abseil.podspec.gen.py
Executable 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()
|
|
@ -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 = [
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -44,6 +44,7 @@ absl_cc_library(
|
|||
${ABSL_DEFAULT_COPTS}
|
||||
LINKOPTS
|
||||
${ABSL_DEFAULT_LINKOPTS}
|
||||
$<$<BOOL:${MINGW}>:"dbghelp">
|
||||
DEPS
|
||||
absl::debugging_internal
|
||||
absl::demangle_internal
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -447,6 +447,7 @@ absl_cc_library(
|
|||
${ABSL_DEFAULT_COPTS}
|
||||
LINKOPTS
|
||||
${ABSL_DEFAULT_LINKOPTS}
|
||||
$<$<BOOL:${MINGW}>:"bcrypt">
|
||||
DEPS
|
||||
absl::core_headers
|
||||
absl::optional
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue