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, |     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 = [ | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|  |  | ||||||
|  | @ -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) { | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -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
 | ||||||
|  |  | ||||||
|  | @ -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(); | ||||||
|  |  | ||||||
|  | @ -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) { | ||||||
|  |  | ||||||
|  | @ -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.
 | ||||||
|  |  | ||||||
|  | @ -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", | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|  |  | ||||||
|  | @ -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", | ||||||
|  |  | ||||||
|  | @ -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)); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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
 | ||||||
| // -----------------------------------------------------------------------------
 | // -----------------------------------------------------------------------------
 | ||||||
|  |  | ||||||
|  | @ -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
 | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|  |  | ||||||
|  | @ -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", | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|  |  | ||||||
|  | @ -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
 | ||||||
|  |  | ||||||
|  | @ -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_
 | ||||||
|  |  | ||||||
|  | @ -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) { | ||||||
|  |  | ||||||
|  | @ -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() { | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue