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.
 | ||||
| // 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.
 | ||||
|   // 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…
	
	Add table
		Add a link
		
	
		Reference in a new issue