Roll back checking in the third_party directory

This goes back to using a subtree mirror of Chromium's third_party directory (managed by gclient).

The related scripts for syncing the files are also deleted.

The plan is to solve the conflict by creating third_party directories in subdirectories of WebRTC rather than the repo root.

Bug: webrtc:8366
Change-Id: I0b9f6a86c6d4075e2fa12c2db19aa54682ddb11f
Reviewed-on: https://webrtc-review.googlesource.com/85300
Reviewed-by: Oleh Prypin <oprypin@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23757}
This commit is contained in:
Artem Titov
2018-06-27 13:23:17 +02:00
parent 67c8bcf804
commit 42f0d78f1e
4839 changed files with 9 additions and 1897193 deletions

2
.gitignore vendored
View File

@ -45,7 +45,7 @@
/mojo
/out
/testing
/third_party_chromium
/third_party
/tools
/tools_webrtc/android/profiling/flamegraph
/tools_webrtc/android/profiling/simpleperf

14
DEPS
View File

@ -2,9 +2,6 @@
vars = {
'chromium_git': 'https://chromium.googlesource.com',
# Used by the WebRTC DEPS autoroller to update third_party/. If you need to run autoroller localy,
# you can set it via custom_vars section in the .gclient file.
'roll_chromium_into_webrtc': False,
# By default, we should check out everything needed to run on the main
# chromium waterfalls. More info at: crbug.com/570091.
'checkout_configuration': 'default',
@ -40,10 +37,6 @@ vars = {
# the commit queue can handle CLs rolling HarfBuzz
# and whatever else without interference from each other.
'harfbuzz_revision': '957e7756634a4fdf1654041e20e883cf964ecac9',
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling Chromium third_party
# and whatever else without interference from each other.
'chromium_third_party_revision': '46683344d7566fa1caceb097e212afc22afc4312',
}
deps = {
# TODO(kjellander): Move this to be Android-only once the libevent dependency
@ -66,11 +59,8 @@ deps = {
},
'src/testing':
Var('chromium_git') + '/chromium/src/testing' + '@' + '8354b28f744d5b1b1a0b4e7c8cb713408323ee03',
# This entry is used for chromium third_party rolling into webrtc third_party only.
'src/third_party_chromium': {
'url': Var('chromium_git') + '/chromium/src/third_party' + '@' + Var('chromium_third_party_revision'),
'condition': 'roll_chromium_into_webrtc',
},
'src/third_party':
Var('chromium_git') + '/chromium/src/third_party' + '@' + '46683344d7566fa1caceb097e212afc22afc4312',
'src/third_party/android_ndk': {
'url': Var('chromium_git') + '/android_ndk.git' + '@' + '5cd86312e794bdf542a3685c6f10cbb96072990b',
'condition': 'checkout_android',

View File

@ -39,7 +39,6 @@ CPPLINT_BLACKLIST = [
'test',
'tools_webrtc',
'voice_engine',
'third_party',
]
# These filters will always be removed, even if the caller specifies a filter
@ -766,7 +765,6 @@ def CommonChecks(input_api, output_api):
r'^out.*[\\\/].*\.py$',
r'^testing[\\\/].*\.py$',
r'^third_party[\\\/].*\.py$',
r'^third_party_chromium[\\\/].*\.py$',
r'^tools[\\\/].*\.py$',
# TODO(phoglund): should arguably be checked.
r'^tools_webrtc[\\\/]mb[\\\/].*\.py$',
@ -785,8 +783,7 @@ def CommonChecks(input_api, output_api):
# Skip long-lines check for DEPS and GN files.
build_file_filter_list = (r'.+\.gn$', r'.+\.gni$', 'DEPS')
# Also we will skip most checks for third_party directory.
third_party_filter_list = (r'^third_party[\\\/].+',
r'^third_party_chromium[\\\/].+')
third_party_filter_list = (r'^third_party[\\\/].+',)
eighty_char_sources = lambda x: input_api.FilterSourceFile(x,
black_list=build_file_filter_list + objc_filter_list +
third_party_filter_list)
@ -795,7 +792,6 @@ def CommonChecks(input_api, output_api):
non_third_party_sources = lambda x: input_api.FilterSourceFile(x,
black_list=third_party_filter_list)
results.extend(CheckNoGitRepoInThirdParty(input_api, output_api))
results.extend(input_api.canned_checks.CheckLongLines(
input_api, output_api, maxlen=80, source_file_filter=eighty_char_sources))
results.extend(input_api.canned_checks.CheckLongLines(
@ -833,28 +829,9 @@ def CommonChecks(input_api, output_api):
input_api, output_api, source_file_filter=non_third_party_sources))
results.extend(CheckNoStreamUsageIsAdded(
input_api, output_api, non_third_party_sources))
results.extend(CheckThirdPartyChanges(input_api, output_api))
return results
def CheckNoGitRepoInThirdParty(input_api, output_api):
if os.path.isdir(input_api.os_path.join(
input_api.PresubmitLocalPath(), 'third_party', '.git')):
return [output_api.PresubmitError("Please remove third_party/.git "
"directory. This error means that "
"possibly you also have to apply other "
"instructions from the May 11th PSA from "
"titovartem@.")]
return []
def CheckThirdPartyChanges(input_api, output_api):
with _AddToPath(input_api.os_path.join(
input_api.PresubmitLocalPath(), 'tools_webrtc', 'presubmit_checks_lib')):
from check_3pp import CheckThirdPartyDirectory
return CheckThirdPartyDirectory(input_api, output_api)
def CheckChangeOnUpload(input_api, output_api):
results = []
results.extend(CommonChecks(input_api, output_api))
@ -866,23 +843,9 @@ def CheckChangeOnUpload(input_api, output_api):
def CheckChangeOnCommit(input_api, output_api):
results = []
# We have to skip OWNERS check for chromium-specific third_party deps.
chromium_deps_file = input_api.os_path.join(
input_api.PresubmitLocalPath(),
'THIRD_PARTY_CHROMIUM_DEPS.json')
with open(chromium_deps_file, 'rb') as f:
chromium_deps = json.load(f).get('dependencies', [])
deps_blacklist = []
for dep in chromium_deps:
deps_blacklist.append(r'^third_party[\\\/]%s[\\\/].+' % dep)
deps_filter = lambda x: input_api.FilterSourceFile(
x, black_list=deps_blacklist)
results.extend(CommonChecks(input_api, output_api))
results.extend(VerifyNativeApiHeadersListIsValid(input_api, output_api))
results.extend(input_api.canned_checks.CheckOwners(input_api, output_api,
source_file_filter=deps_filter))
results.extend(input_api.canned_checks.CheckOwners(input_api, output_api))
results.extend(input_api.canned_checks.CheckChangeWasUploaded(
input_api, output_api))
results.extend(input_api.canned_checks.CheckChangeHasDescription(

View File

@ -1,80 +0,0 @@
{
"comment": [
"This file determines which parts of Chromium's third_party/ we copy.",
"",
"If you want to add new chromium owned dependency, run",
"./tools_webrtc/autoroller/checkin_chromium_dep.py -d <dep name>",
"",
"It will add specified dependency to third_party directory and will add it to this list",
"properly."
],
"dependencies": [
"abseil-cpp",
"binutils",
"boringssl",
"ced",
"freetype",
"googletest",
"harfbuzz-ng",
"instrumented_libraries",
"jsoncpp",
"libFuzzer",
"libpng",
"libvpx",
"mockito",
"openh264",
"opus",
"protobuf",
"pymock",
"requests",
"rnnoise",
"usrsctp",
"yasm",
"zlib",
"colorama",
"accessibility_test_framework",
"android_platform",
"android_support_test_runner",
"apk-patch-size-estimator",
"ashmem",
"auto",
"bazel",
"bouncycastle",
"breakpad",
"byte_buddy",
"closure_compiler",
"errorprone",
"espresso",
"eu-strip",
"gson",
"guava",
"hamcrest",
"icu4j",
"ijar",
"intellij",
"javax_inject",
"jinja2",
"jsr-305",
"junit",
"libxml",
"markupsafe",
"modp_b64",
"objenesis",
"ow2_asm",
"robolectric",
"sqlite4java",
"tcmalloc",
"ub-uiautomator",
"xstream",
"proguard",
"android_system_sdk",
"ocmock",
"BUILD.gn",
"DEPS",
"libjpeg.gni",
"PRESUBMIT.py",
"README.chromium",
"README.chromium.template",
"r8"
]
}

View File

@ -1,11 +0,0 @@
{
"comment": [
"This file contains list of third party dependencies owned by WebRTC directly,",
"e.g. they're not from Chromium's third party (those are tracked in ",
"THIRD_PARTY_CHROMIUM_DEPS.json)."
],
"dependencies": [
"OWNERS",
"base64"
]
}

View File

@ -1,66 +0,0 @@
# mirror in DEPS. Without it, a lot is wiped and re-downloaded for each sync.
/findbugs/
/gtest-parallel/
/winsdk_samples/
/accessibility_test_framework/lib/
/android_ndk/
/android_protobuf/src
/android_support_test_runner/lib/
/android_tools/
/android_tools_internal/
/apk-patch-size-estimator/lib/
/auto/src
/bazel/desugar/Desugar.jar
/boringssl/src
/bouncycastle/lib/
/byte_buddy/lib/
/catapult
/ced/src
/colorama/src
/depot_tools
/errorprone/lib
/espresso/lib/
/ffmpeg
/freetype/src
/gnu_binutils/
/googletest/src
/gson/lib/
/guava/lib/
/hamcrest/lib/
/harfbuzz-ng/src
/icu
/icu4j/lib/
/intellij/lib/
/instrumented_libraries/scripts/*.tgz
/instrumented_libraries/scripts/out/*
/javax_inject/lib/
/jsoncpp/source
/jsr-305/src
/junit/src
/libFuzzer/src
/libprotobuf-mutator/src
/libjpeg_turbo
/libsrtp
/libvpx/source/libvpx
/libyuv
/llvm-build
/llvm-build-tools
/lss
/mockito/src
/objenesis/lib/
/openmax_dl/
/openh264/src
/ow2_asm/lib/
/r8/lib
/requests/src
/robolectric/lib/
/robolectric/robolectric
/sqlite4java/lib/
/syzygy
/ub-uiautomator/lib
/usrsctp/usrsctplib
/xstream/lib/
/yasm/binaries
/yasm/generate_files.xml
/yasm/source/patched-yasm
/yasm/yasm.xml

68
third_party/BUILD.gn vendored
View File

@ -1,68 +0,0 @@
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/config/freetype/freetype.gni")
import("//third_party/harfbuzz-ng/harfbuzz.gni")
import("//third_party/libjpeg.gni")
assert(!is_ios, "This is not used on iOS, don't drag it in unintentionally")
config("system_libjpeg_config") {
libs = [ "jpeg" ]
defines = [ "USE_SYSTEM_LIBJPEG" ]
}
config("libjpeg_turbo_config") {
defines = [ "USE_LIBJPEG_TURBO=1" ]
}
# This is a meta target that forwards to the system's libjpeg,
# third_party/libjpeg, or third_party/libjpeg_turbo depending on the build args
# declared in this file.
group("jpeg") {
if (use_system_libjpeg) {
public_configs = [ ":system_libjpeg_config" ]
} else if (use_libjpeg_turbo) {
public_deps = [
"//third_party/libjpeg_turbo:libjpeg",
]
public_configs = [ ":libjpeg_turbo_config" ]
} else {
public_deps = [
"//third_party/libjpeg:libjpeg",
]
}
}
# This is a meta target that forwards include paths only to the system's
# libjpeg, third_party/libjpeg, or third_party/libjpeg_turbo depending on the
# build args declared in this file. This is needed, rarely, for targets that
# need to reference libjpeg without explicitly building it.
group("jpeg_includes") {
if (use_system_libjpeg) {
public_configs = [ ":system_libjpeg_config" ]
} else if (use_libjpeg_turbo) {
public_configs = [ "//third_party/libjpeg_turbo:libjpeg_config" ]
} else {
public_configs = [ "//third_party/libjpeg:libjpeg_config" ]
}
}
# FreeType and HarfBuzz libraries are dependent on each other. This component
# will depend on the appropriate source sets or export the system packages
# for both FreeType and HarfBuzz.
component("freetype_harfbuzz") {
public_configs = []
public_deps = []
if (use_system_freetype) {
public_configs += [ "//build/linux:freetype_from_pkgconfig" ]
} else {
public_deps += [ "//third_party/freetype:freetype_source" ]
}
if (use_system_harfbuzz) {
public_configs += [ "//third_party/harfbuzz-ng:harfbuzz_from_pkgconfig" ]
} else {
public_deps += [ "//third_party/harfbuzz-ng:harfbuzz_source" ]
}
}

11
third_party/DEPS vendored
View File

@ -1,11 +0,0 @@
# Undo everything in the include_rules section of src/DEPS.
include_rules = [
'-base',
'-build',
'-ipc',
'-library_loaders',
'-testing',
'-third_party/icu/source/common/unicode',
'-third_party/icu/source/i18n/unicode',
'-url',
]

7
third_party/OWNERS vendored
View File

@ -1,7 +0,0 @@
phoglund@webrtc.org
titovartem@webrtc.org
buildbot@webrtc.org
per-file .gitignore=*

View File

@ -1,147 +0,0 @@
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
ANDROID_WHITELISTED_LICENSES = [
'A(pple )?PSL 2(\.0)?',
'Apache( Version)? 2(\.0)?',
'(New )?([23]-Clause )?BSD( [23]-Clause)?( with advertising clause)?',
'L?GPL ?v?2(\.[01])?( or later)?',
'MIT(/X11)?(-like)?',
'MPL 1\.1 ?/ ?GPL 2(\.0)? ?/ ?LGPL 2\.1',
'MPL 2(\.0)?',
'Microsoft Limited Public License',
'Microsoft Permissive License',
'Public Domain',
'Python',
'SGI Free Software License B',
'University of Illinois\/NCSA Open Source',
'X11',
]
def LicenseIsCompatibleWithAndroid(input_api, license):
regex = '^(%s)$' % '|'.join(ANDROID_WHITELISTED_LICENSES)
tokens = \
[x.strip() for x in input_api.re.split(' and |,', license) if len(x) > 0]
has_compatible_license = False
for token in tokens:
if input_api.re.match(regex, token, input_api.re.IGNORECASE):
has_compatible_license = True
break
return has_compatible_license
def _CheckThirdPartyReadmesUpdated(input_api, output_api):
"""
Checks to make sure that README.chromium files are properly updated
when dependencies in third_party are modified.
"""
readmes = []
files = []
errors = []
for f in input_api.AffectedFiles():
local_path = f.LocalPath()
if input_api.os_path.dirname(local_path) == 'third_party':
continue
if (local_path.startswith('third_party' + input_api.os_path.sep) and
not local_path.startswith('third_party' + input_api.os_path.sep +
'WebKit' + input_api.os_path.sep) and
not local_path.startswith('third_party' + input_api.os_path.sep +
'blink' + input_api.os_path.sep) and
not local_path.startswith('third_party' + input_api.os_path.sep +
'mojo' + input_api.os_path.sep) and
not local_path.startswith('third_party' + input_api.os_path.sep +
'boringssl' + input_api.os_path.sep) and
not local_path.startswith('third_party' + input_api.os_path.sep +
'closure_compiler' + input_api.os_path.sep +
'externs' + input_api.os_path.sep) and
not local_path.startswith('third_party' + input_api.os_path.sep +
'closure_compiler' + input_api.os_path.sep +
'interfaces' + input_api.os_path.sep)):
files.append(f)
if local_path.endswith("README.chromium"):
readmes.append(f)
if files and not readmes:
errors.append(output_api.PresubmitPromptWarning(
'When updating or adding third party code the appropriate\n'
'\'README.chromium\' file should also be updated with the correct\n'
'version and package information.', files))
if not readmes:
return errors
name_pattern = input_api.re.compile(
r'^Name: [a-zA-Z0-9_\-\. \(\)]+\r?$',
input_api.re.IGNORECASE | input_api.re.MULTILINE)
shortname_pattern = input_api.re.compile(
r'^Short Name: [a-zA-Z0-9_\-\.]+\r?$',
input_api.re.IGNORECASE | input_api.re.MULTILINE)
version_pattern = input_api.re.compile(
r'^Version: [a-zA-Z0-9_\-\.:]+\r?$',
input_api.re.IGNORECASE | input_api.re.MULTILINE)
release_pattern = input_api.re.compile(
r'^Security Critical: (yes|no)\r?$',
input_api.re.IGNORECASE | input_api.re.MULTILINE)
license_pattern = input_api.re.compile(
r'^License: (.+)\r?$',
input_api.re.IGNORECASE | input_api.re.MULTILINE)
license_android_compatible_pattern = input_api.re.compile(
r'^License Android Compatible: (yes|no)\r?$',
input_api.re.IGNORECASE | input_api.re.MULTILINE)
for f in readmes:
if 'D' in f.Action():
_IgnoreIfDeleting(input_api, output_api, f, errors)
continue
contents = input_api.ReadFile(f)
if (not shortname_pattern.search(contents)
and not name_pattern.search(contents)):
errors.append(output_api.PresubmitError(
'Third party README files should contain either a \'Short Name\' or\n'
'a \'Name\' which is the name under which the package is\n'
'distributed. Check README.chromium.template for details.',
[f]))
if not version_pattern.search(contents):
errors.append(output_api.PresubmitError(
'Third party README files should contain a \'Version\' field.\n'
'If the package is not versioned or the version is not known\n'
'list the version as \'unknown\'.\n'
'Check README.chromium.template for details.',
[f]))
if not release_pattern.search(contents):
errors.append(output_api.PresubmitError(
'Third party README files should contain a \'Security Critical\'\n'
'field. This field specifies whether the package is built with\n'
'Chromium. Check README.chromium.template for details.',
[f]))
license_match = license_pattern.search(contents)
if not license_match:
errors.append(output_api.PresubmitError(
'Third party README files should contain a \'License\' field.\n'
'This field specifies the license used by the package. Check\n'
'README.chromium.template for details.',
[f]))
elif not LicenseIsCompatibleWithAndroid(input_api, license_match.group(1)) \
and not license_android_compatible_pattern.search(contents):
errors.append(output_api.PresubmitPromptWarning(
'Cannot determine whether specified license is compatible with\n' +
'the Android licensing requirements. Please check that the license\n' +
'name is spelled according to third_party/PRESUBMIT.py. Please see\n' +
'README.chromium.template for details.',
[f]))
return errors
def _IgnoreIfDeleting(input_api, output_api, affected_file, errors):
third_party_dir = input_api.os_path.dirname(affected_file.LocalPath())
for f in input_api.AffectedFiles():
if f.LocalPath().startswith(third_party_dir):
if 'D' not in f.Action():
errors.append(output_api.PresubmitError(
'Third party README should only be removed when the whole\n'
'directory is being removed.\n', [f, affected_file]))
def CheckChangeOnUpload(input_api, output_api):
results = []
results.extend(_CheckThirdPartyReadmesUpdated(input_api, output_api))
return results

View File

@ -1,14 +0,0 @@
The third_party directory contains sources from other projects.
Code in third_party must document the license under which the source is being
used. If the source itself does not include a license header or file, create
an entry in this file that refers to reliable documentation of the project's
license terms on the web (and add a note pointing here in the README file in
that directory).
When adding a new directory, or updating a directory to a version which has
a different license from before, please add chromium-third-party@google.com
as a reviewer on the change.
<Include table of license information here, once it is available>

View File

@ -1,16 +0,0 @@
Name: Descriptive name of the package
Short Name: Name the package is distributed under (ex. libxml, openssl, etc)
URL: The URL where the package lives
Version: A searchable version number for the package (if the package does not version or is versioned by date or revision this field should be "0" and the revision, or date should be enumerated in the appropriate field)
Date: (OPTIONAL if version is supplied) The date that the package was updated
Revision: (OPTIONAL if version is supplied) The current revision of the package
License: The license under which the package is distributed. Standard forms are only accepted, eg MIT/X11/BSD/Apache 2.0/GPL/LGPL. See ANDROID_WHITELISTED_LICENSES in PRESUBMIT.py for allowed patterns.
License File: (OPTIONAL) File that contains a copy of the package's license. Use the special value NOT_SHIPPED to indicate that the package is not included in the shipped product, so its license does not need to be included in about:credits and no license file is required.
Security Critical: Either yes or no depending on whether this package is shipped in releases. For example openssl is critical where cygwin is not.
License Android Compatible: (OPTIONAL) Whether the package uses a license compatible with Android. Required only if the package is compatible and the 'License' field uses a non-standard value.
Description:
A short description of what the package is and is used for.
Local Modifications:
Enumerate any changes that have been made locally to the package from the shipping version listed above.

View File

@ -1,22 +0,0 @@
Please submit a new Abseil Issue using the template below:
## [Short title of proposed API change(s)]
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
## Background
[Provide the background information that is required in order to evaluate the
proposed API changes. No controversial claims should be made here. If there are
design constraints that need to be considered, they should be presented here
**along with justification for those constraints**. Linking to other docs is
good, but please keep the **pertinent information as self contained** as
possible in this section.]
## Proposed API Change (s)
[Please clearly describe the API change(s) being proposed. If multiple changes,
please keep them clearly distinguished. When possible, **use example code
snippets to illustrate before-after API usages**. List pros-n-cons. Highlight
the main questions that you want to be answered. Given the Abseil project compatibility requirements, describe why the API change is safe.]

View File

@ -1,6 +0,0 @@
# This is the list of Abseil authors for copyright purposes.
#
# This does not necessarily list everyone who has contributed code, since in
# some cases, their employer may be the copyright holder. To see the full list
# of contributors, see the revision history in source control.
Google Inc.

View File

@ -1,97 +0,0 @@
# Copyright (c) 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# Flags specified here must not impact ABI. Code compiled with and without these
# opts will be linked together, and in some cases headers compiled with and
# without these options will be part of the same program.
import("//build/toolchain/toolchain.gni")
group("default") {
deps = [
"absl/types:any",
"absl/types:bad_any_cast",
"absl/types:span",
"absl/types:optional",
"absl/types:bad_optional_access",
]
}
config("absl_include_config") {
# Using -isystem (with clang and GCC) and -imsvc (with clang-cl) instead of
# include_dirs (-I), so we don't need to suppress warnings coming from
# Abseil. Doing so would mask warnings in our own code.
if (is_win) {
if (is_clang) {
# clang-cl:
cflags = [
"-imsvc",
rebase_path(".", root_build_dir),
]
} else {
# MSVC doesn't have -isystem, in that case we fallback to include_dirs and
# we use the warning suppression flags defined in :absl_default_cflags_cc.
include_dirs = [ "." ]
}
} else {
# GCC or clang:
cflags = [
"-isystem",
rebase_path(".", root_build_dir),
]
}
}
config("absl_define_config") {
defines = [ "ABSL_ALLOCATOR_NOTHROW=1" ]
}
config("absl_default_cflags_cc") {
cflags_cc = []
if (is_clang) {
cflags_cc += [
# TODO(crbug.com/588506): Explicitly enable conversion warnings.
"-Wbool-conversion",
"-Wconstant-conversion",
"-Wenum-conversion",
"-Wint-conversion",
"-Wliteral-conversion",
"-Wnon-literal-null-conversion",
"-Wnull-conversion",
"-Wobjc-literal-conversion",
"-Wno-sign-conversion",
"-Wstring-conversion",
]
if (!is_nacl && !use_xcode_clang) {
cflags_cc += [ "-Wbitfield-enum-conversion" ]
}
}
if (is_win) {
cflags_cc += [
"/wd4005", # macro-redefinition
"/wd4068", # unknown pragma
"/wd4702", # unreachable code
]
}
}
config("absl_test_cflags_cc") {
cflags_cc = []
if (is_clang || !is_win) {
cflags_cc += [
"-Wno-conversion-null",
"-Wno-missing-declarations",
"-Wno-sign-compare",
"-Wno-unused-function",
"-Wno-unused-parameter",
"-Wno-unused-private-field",
]
}
if (is_win) {
cflags_cc += [
"/wd4018", # signed/unsigned mismatch
"/wd4101", # unreferenced local variable
]
}
}

View File

@ -1,170 +0,0 @@
#
# Copyright 2017 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
#
# http://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.
#
include(CMakeParseArguments)
# The IDE folder for Abseil that will be used if Abseil is included in a CMake
# project that sets
# set_property(GLOBAL PROPERTY USE_FOLDERS ON)
# For example, Visual Studio supports folders.
set(ABSL_IDE_FOLDER Abseil)
#
# create a library in the absl namespace
#
# parameters
# SOURCES : sources files for the library
# PUBLIC_LIBRARIES: targets and flags for linking phase
# PRIVATE_COMPILE_FLAGS: compile flags for the library. Will not be exported.
# EXPORT_NAME: export name for the absl:: target export
# TARGET: target name
#
# create a target associated to <NAME>
# libraries are installed under CMAKE_INSTALL_FULL_LIBDIR by default
#
function(absl_library)
cmake_parse_arguments(ABSL_LIB
"DISABLE_INSTALL" # keep that in case we want to support installation one day
"TARGET;EXPORT_NAME"
"SOURCES;PUBLIC_LIBRARIES;PRIVATE_COMPILE_FLAGS"
${ARGN}
)
set(_NAME ${ABSL_LIB_TARGET})
string(TOUPPER ${_NAME} _UPPER_NAME)
add_library(${_NAME} STATIC ${ABSL_LIB_SOURCES})
target_compile_options(${_NAME} PRIVATE ${ABSL_COMPILE_CXXFLAGS} ${ABSL_LIB_PRIVATE_COMPILE_FLAGS})
target_link_libraries(${_NAME} PUBLIC ${ABSL_LIB_PUBLIC_LIBRARIES})
target_include_directories(${_NAME}
PUBLIC ${ABSL_COMMON_INCLUDE_DIRS} ${ABSL_LIB_PUBLIC_INCLUDE_DIRS}
PRIVATE ${ABSL_LIB_PRIVATE_INCLUDE_DIRS}
)
# Add all Abseil targets to a a folder in the IDE for organization.
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER})
if(ABSL_LIB_EXPORT_NAME)
add_library(absl::${ABSL_LIB_EXPORT_NAME} ALIAS ${_NAME})
endif()
endfunction()
#
# header only virtual target creation
#
function(absl_header_library)
cmake_parse_arguments(ABSL_HO_LIB
"DISABLE_INSTALL"
"EXPORT_NAME;TARGET"
"PUBLIC_LIBRARIES;PRIVATE_COMPILE_FLAGS;PUBLIC_INCLUDE_DIRS;PRIVATE_INCLUDE_DIRS"
${ARGN}
)
set(_NAME ${ABSL_HO_LIB_TARGET})
set(__dummy_header_only_lib_file "${CMAKE_CURRENT_BINARY_DIR}/${_NAME}_header_only_dummy.cc")
if(NOT EXISTS ${__dummy_header_only_lib_file})
file(WRITE ${__dummy_header_only_lib_file}
"/* generated file for header-only cmake target */
namespace absl {
// single meaningless symbol
void ${_NAME}__header_fakesym() {}
} // namespace absl
"
)
endif()
add_library(${_NAME} ${__dummy_header_only_lib_file})
target_link_libraries(${_NAME} PUBLIC ${ABSL_HO_LIB_PUBLIC_LIBRARIES})
target_include_directories(${_NAME}
PUBLIC ${ABSL_COMMON_INCLUDE_DIRS} ${ABSL_HO_LIB_PUBLIC_INCLUDE_DIRS}
PRIVATE ${ABSL_HO_LIB_PRIVATE_INCLUDE_DIRS}
)
# Add all Abseil targets to a a folder in the IDE for organization.
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER})
if(ABSL_HO_LIB_EXPORT_NAME)
add_library(absl::${ABSL_HO_LIB_EXPORT_NAME} ALIAS ${_NAME})
endif()
endfunction()
#
# create an abseil unit_test and add it to the executed test list
#
# parameters
# TARGET: target name prefix
# SOURCES: sources files for the tests
# PUBLIC_LIBRARIES: targets and flags for linking phase.
# PRIVATE_COMPILE_FLAGS: compile flags for the test. Will not be exported.
#
# create a target associated to <NAME>_bin
#
# all tests will be register for execution with add_test()
#
# test compilation and execution is disable when BUILD_TESTING=OFF
#
function(absl_test)
cmake_parse_arguments(ABSL_TEST
""
"TARGET"
"SOURCES;PUBLIC_LIBRARIES;PRIVATE_COMPILE_FLAGS;PUBLIC_INCLUDE_DIRS"
${ARGN}
)
if(BUILD_TESTING)
set(_NAME ${ABSL_TEST_TARGET})
string(TOUPPER ${_NAME} _UPPER_NAME)
add_executable(${_NAME}_bin ${ABSL_TEST_SOURCES})
target_compile_options(${_NAME}_bin PRIVATE ${ABSL_COMPILE_CXXFLAGS} ${ABSL_TEST_PRIVATE_COMPILE_FLAGS})
target_link_libraries(${_NAME}_bin PUBLIC ${ABSL_TEST_PUBLIC_LIBRARIES} ${ABSL_TEST_COMMON_LIBRARIES})
target_include_directories(${_NAME}_bin
PUBLIC ${ABSL_COMMON_INCLUDE_DIRS} ${ABSL_TEST_PUBLIC_INCLUDE_DIRS}
PRIVATE ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS}
)
# Add all Abseil targets to a a folder in the IDE for organization.
set_property(TARGET ${_NAME}_bin PROPERTY FOLDER ${ABSL_IDE_FOLDER})
add_test(${_NAME} ${_NAME}_bin)
endif(BUILD_TESTING)
endfunction()
function(check_target my_target)
if(NOT TARGET ${my_target})
message(FATAL_ERROR " ABSL: compiling absl requires a ${my_target} CMake target in your project,
see CMake/README.md for more details")
endif(NOT TARGET ${my_target})
endfunction()

View File

@ -1,15 +0,0 @@
cmake_minimum_required(VERSION 2.8.2)
project(googletest-download NONE)
include(ExternalProject)
ExternalProject_Add(googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG master
SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src"
BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)

View File

@ -1,32 +0,0 @@
# Downloads and unpacks googletest at configure time. Based on the instructions
# at https://github.com/google/googletest/tree/master/googletest#incorporating-into-an-existing-cmake-project
# Download the latest googletest from Github master
configure_file(
${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt.in
googletest-download/CMakeLists.txt
)
# Configure and build the downloaded googletest source
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )
if(result)
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
endif()
execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
if(result)
message(FATAL_ERROR "Build step for googletest failed: ${result}")
endif()
# Prevent overriding the parent project's compiler/linker settings on Windows
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
# Add googletest directly to our build. This defines the gtest and gtest_main
# targets.
add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
${CMAKE_BINARY_DIR}/googletest-build
EXCLUDE_FROM_ALL)

View File

@ -1,107 +0,0 @@
# Abseil CMake Build Instructions
Abseil comes with a CMake build script ([CMakeLists.txt](../CMakeLists.txt))
that can be used on a wide range of platforms ("C" stands for cross-platform.).
If you don't have CMake installed already, you can download it for free from
<http://www.cmake.org/>.
CMake works by generating native makefiles or build projects that can
be used in the compiler environment of your choice.
For API/ABI compatibility reasons, we strongly recommend building Abseil in a
subdirectory of your project or as an embedded dependency.
## Incorporating Abseil Into a CMake Project
The recommendations below are similar to those for using CMake within the
googletest framework
(<https://github.com/google/googletest/blob/master/googletest/README.md#incorporating-into-an-existing-cmake-project>)
### Step-by-Step Instructions
1. If you want to build the Abseil tests, integrate the Abseil dependency
[Google Test](https://github.com/google/googletest) into your CMake project. To disable Abseil tests, you have to pass
`-DBUILD_TESTING=OFF` when configuring your project with CMake.
2. Download Abseil and copy it into a subdirectory in your CMake project or add
Abseil as a [git submodule](https://git-scm.com/docs/git-submodule) in your
CMake project.
3. You can then use the CMake command
[`add_subdirectory()`](https://cmake.org/cmake/help/latest/command/add_subdirectory.html)
to include Abseil directly in your CMake project.
4. Add the **absl::** target you wish to use to the
[`target_link_libraries()`](https://cmake.org/cmake/help/latest/command/target_link_libraries.html)
section of your executable or of your library.<br>
Here is a short CMakeLists.txt example of a project file using Abseil.
```cmake
cmake_minimum_required(VERSION 2.8.12)
project(my_project)
set(CMAKE_CXX_FLAGS "-std=c++11 -stdlib=libc++ ${CMAKE_CXX_FLAGS}")
if(MSVC)
# /wd4005 macro-redefinition
# /wd4068 unknown pragma
# /wd4244 conversion from 'type1' to 'type2'
# /wd4267 conversion from 'size_t' to 'type2'
# /wd4800 force value to bool 'true' or 'false' (performance warning)
add_compile_options(/wd4005 /wd4068 /wd4244 /wd4267 /wd4800)
add_definitions(/DNOMINMAX /DWIN32_LEAN_AND_MEAN=1 /D_CRT_SECURE_NO_WARNINGS)
endif()
add_subdirectory(abseil-cpp)
add_executable(my_exe source.cpp)
target_link_libraries(my_exe absl::base absl::synchronization absl::strings)
```
### Running Abseil Tests with CMake
Use the `-DABSL_RUN_TESTS=ON` flag to run Abseil tests. Note that if the `-DBUILD_TESTING=OFF` flag is passed then Abseil tests will not be run.
You will need to provide Abseil with a Googletest dependency. There are two
options for how to do this:
* Use `-DABSL_USE_GOOGLETEST_HEAD`. This will automatically download the latest
Googletest source into the build directory at configure time. Googletest will
then be compiled directly alongside Abseil's tests.
* Manually integrate Googletest with your build. See
https://github.com/google/googletest/blob/master/googletest/README.md#using-cmake
for more information on using Googletest in a CMake project.
For example, to run just the Abseil tests, you could use this script:
```
cd path/to/abseil-cpp
mkdir build
cd build
cmake -DABSL_USE_GOOGLETEST_HEAD=ON -DABSL_RUN_TESTS=ON ..
make -j
ctest
```
Currently, we only run our tests with CMake in a Linux environment, but we are
working on the rest of our supported platforms. See
https://github.com/abseil/abseil-cpp/projects/1 and
https://github.com/abseil/abseil-cpp/issues/109 for more information.
### Available Abseil CMake Public Targets
Here's a non-exhaustive list of Abseil CMake public targets:
```cmake
absl::base
absl::algorithm
absl::container
absl::debugging
absl::memory
absl::meta
absl::numeric
absl::strings
absl::synchronization
absl::time
absl::utility
```

View File

@ -1,98 +0,0 @@
#
# Copyright 2017 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
#
# http://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.
#
# We require 3.0 for modern, target-based CMake. We require 3.1 for the use of
# CXX_STANDARD in our targets.
cmake_minimum_required(VERSION 3.1)
project(absl)
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake)
include(GNUInstallDirs)
include(AbseilHelpers)
# config options
if (MSVC)
# /wd4005 macro-redefinition
# /wd4068 unknown pragma
# /wd4244 conversion from 'type1' to 'type2'
# /wd4267 conversion from 'size_t' to 'type2'
# /wd4800 force value to bool 'true' or 'false' (performance warning)
add_compile_options(/W3 /WX /wd4005 /wd4068 /wd4244 /wd4267 /wd4800)
add_definitions(/DNOMINMAX /DWIN32_LEAN_AND_MEAN=1 /D_CRT_SECURE_NO_WARNINGS /D_SCL_SECURE_NO_WARNINGS)
else()
set(ABSL_STD_CXX_FLAG "-std=c++11" CACHE STRING "c++ std flag (default: c++11)")
endif()
##
## Using absl targets
##
## all public absl targets are
## exported with the absl:: prefix
##
## e.g absl::base absl::synchronization absl::strings ....
##
## DO NOT rely on the internal targets outside of the prefix
# include current path
list(APPEND ABSL_COMMON_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR})
# -std=X
set(CMAKE_CXX_FLAGS "${ABSL_STD_CXX_FLAG} ${CMAKE_CXX_FLAGS}")
# -fexceptions
set(ABSL_EXCEPTIONS_FLAG "${CMAKE_CXX_EXCEPTIONS}")
# find dependencies
## pthread
find_package(Threads REQUIRED)
option(ABSL_USE_GOOGLETEST_HEAD
"If ON, abseil will download HEAD from googletest at config time." OFF)
option(ABSL_RUN_TESTS "If ON, Abseil tests will be run." OFF)
if(${ABSL_RUN_TESTS})
# enable CTest. This will set BUILD_TESTING to ON unless otherwise specified
# on the command line
include(CTest)
enable_testing()
endif()
## check targets
if(BUILD_TESTING)
if(${ABSL_USE_GOOGLETEST_HEAD})
include(CMake/DownloadGTest.cmake)
endif()
check_target(gtest)
check_target(gtest_main)
check_target(gmock)
list(APPEND ABSL_TEST_COMMON_LIBRARIES
gtest_main
gtest
gmock
${CMAKE_THREAD_LIBS_INIT}
)
endif()
add_subdirectory(absl)

View File

@ -1,91 +0,0 @@
# How to Contribute to Abseil
We'd love to accept your patches and contributions to this project. There are
just a few small guidelines you need to follow.
NOTE: If you are new to GitHub, please start by reading [Pull Request
howto](https://help.github.com/articles/about-pull-requests/)
## Contributor License Agreement
Contributions to this project must be accompanied by a Contributor License
Agreement. You (or your employer) retain the copyright to your contribution,
this simply gives us permission to use and redistribute your contributions as
part of the project. Head over to <https://cla.developers.google.com/> to see
your current agreements on file or to sign a new one.
You generally only need to submit a CLA once, so if you've already submitted one
(even if it was for a different project), you probably don't need to do it
again.
## Coding Style
To keep the source consistent, readable, diffable and easy to merge, we use a
fairly rigid coding style, as defined by the
[google-styleguide](https://github.com/google/styleguide) project. All patches
will be expected to conform to the style outlined
[here](https://google.github.io/styleguide/cppguide.html).
## Guidelines for Pull Requests
* If you are a Googler, it is preferable to first create an internal CL and
have it reviewed and submitted. The code propagation process will deliver
the change to GitHub.
* Create **small PRs** that are narrowly focused on **addressing a single
concern**. We often receive PRs that are trying to fix several things at a
time, but if only one fix is considered acceptable, nothing gets merged and
both author's & review's time is wasted. Create more PRs to address
different concerns and everyone will be happy.
* For speculative changes, consider opening an [Abseil
issue](https://github.com/abseil/abseil-cpp/issues) and discussing it first.
If you are suggesting a behavioral or API change, consider starting with an
[Abseil proposal template](ABSEIL_ISSUE_TEMPLATE.md).
* Provide a good **PR description** as a record of **what** change is being
made and **why** it was made. Link to a GitHub issue if it exists.
* Don't fix code style and formatting unless you are already changing that
line to address an issue. Formatting of modified lines may be done using
`git clang-format`. PRs with irrelevant changes won't be merged. If
you do want to fix formatting or style, do that in a separate PR.
* Unless your PR is trivial, you should expect there will be reviewer comments
that you'll need to address before merging. We expect you to be reasonably
responsive to those comments, otherwise the PR will be closed after 2-3
weeks of inactivity.
* Maintain **clean commit history** and use **meaningful commit messages**.
PRs with messy commit history are difficult to review and won't be merged.
Use `rebase -i upstream/master` to curate your commit history and/or to
bring in latest changes from master (but avoid rebasing in the middle of a
code review).
* Keep your PR up to date with upstream/master (if there are merge conflicts,
we can't really merge your change).
* **All tests need to be passing** before your change can be merged. We
recommend you **run tests locally** (see below)
* Exceptions to the rules can be made if there's a compelling reason for doing
so. That is - the rules are here to serve us, not the other way around, and
the rules need to be serving their intended purpose to be valuable.
* All submissions, including submissions by project members, require review.
## Running Tests
Use "bazel test <>" functionality to run the unit tests.
Prerequisites for building and running tests are listed in
[README.md](README.md)
## Abseil Committers
The current members of the Abseil engineering team are the only committers at
present.
## Release Process
Abseil lives at head, where latest-and-greatest code can be found.

View File

@ -1,204 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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
http://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.

View File

@ -1,2 +0,0 @@
mbonadei@chromium.org
phoglund@chromium.org

View File

@ -1,34 +0,0 @@
Name: Abseil
Short Name: absl
URL: https://github.com/abseil/abseil-cpp
License: Apache 2.0
License File: LICENSE
Version: 0
Revision: bd40a41cc142b36c73b881099d08a9d83f7f4780
Security Critical: yes
Description:
This directory contains the source code of Abseil for C++. This can be used by
Chromium's dependencies, but shouldn't be used by Chromium itself.
See: https://goo.gl/TgnJb8.
How to update Abseil:
1. Download the code from the Abseil git repository (see URL).
2. Copy the content of the Abseil git repo to //third_party/abseil-cpp.
3. From //third_party/abseil-cpp/ launch ./rename_dynamic_annotations.sh.
This script will rewrite dynamic_annotations macros and function inside
Abseil in order to avoid ODR violations and macro clashing with Chromium
(see: https://github.com/abseil/abseil-cpp/issues/122).
Local Modifications:
* absl/copts.bzl has been translated to //third_party/absl-cpp/BUILD.gn. Both
files contain lists of compiler flags in order to reduce duplication.
* All the BUILD.bazel files has been translated to BUILD.gn files.
* Functions and macros in absl/base/dynamic_annotations.{h,cc} have been renamed
to avoid ODR violations (see step 3).

View File

@ -1,108 +0,0 @@
# Abseil - C++ Common Libraries
The repository contains the Abseil C++ library code. Abseil is an open-source
collection of C++ code (compliant to C++11) designed to augment the C++
standard library.
## Table of Contents
- [About Abseil](#about)
- [Quickstart](#quickstart)
- [Building Abseil](#build)
- [Codemap](#codemap)
- [License](#license)
- [Links](#links)
<a name="about"></a>
## About Abseil
Abseil is an open-source collection of C++ library code designed to augment
the C++ standard library. The Abseil library code is collected from Google's
own C++ code base, has been extensively tested and used in production, and
is the same code we depend on in our daily coding lives.
In some cases, Abseil provides pieces missing from the C++ standard; in
others, Abseil provides alternatives to the standard for special needs
we've found through usage in the Google code base. We denote those cases
clearly within the library code we provide you.
Abseil is not meant to be a competitor to the standard library; we've
just found that many of these utilities serve a purpose within our code
base, and we now want to provide those resources to the C++ community as
a whole.
<a name="quickstart"></a>
## Quickstart
If you want to just get started, make sure you at least run through the
[Abseil Quickstart](https://abseil.io/docs/cpp/quickstart). The Quickstart
contains information about setting up your development environment, downloading
the Abseil code, running tests, and getting a simple binary working.
<a name="build"></a>
## Building Abseil
[Bazel](http://bazel.build) is the official build system for Abseil,
which is supported on most major platforms (Linux, Windows, MacOS, for example)
and compilers. See the [quickstart](https://abseil.io/docs/cpp/quickstart) for
more information on building Abseil using the Bazel build system.
<a name="cmake"></a>
If you require CMake support, please check the
[CMake build instructions](CMake/README.md).
## Codemap
Abseil contains the following C++ library components:
* [`base`](absl/base/) Abseil Fundamentals
<br /> The `base` library contains initialization code and other code which
all other Abseil code depends on. Code within `base` may not depend on any
other code (other than the C++ standard library).
* [`algorithm`](absl/algorithm/)
<br /> The `algorithm` library contains additions to the C++ `<algorithm>`
library and container-based versions of such algorithms.
* [`container`](absl/container/)
<br /> The `container` library contains additional STL-style containers.
* [`debugging`](absl/debugging/)
<br /> The `debugging` library contains code useful for enabling leak
checks. Future updates will add stacktrace and symbolization utilities.
* [`memory`](absl/memory/)
<br /> The `memory` library contains C++11-compatible versions of
`std::make_unique()` and related memory management facilities.
* [`meta`](absl/meta/)
<br /> The `meta` library contains C++11-compatible versions of type checks
available within C++14 and C++17 versions of the C++ `<type_traits>` library.
* [`numeric`](absl/numeric/)
<br /> The `numeric` library contains C++11-compatible 128-bit integers.
* [`strings`](absl/strings/)
<br /> The `strings` library contains a variety of strings routines and
utilities, including a C++11-compatible version of the C++17
`std::string_view` type.
* [`synchronization`](absl/synchronization/)
<br /> The `synchronization` library contains concurrency primitives (Abseil's
`absl::Mutex` class, an alternative to `std::mutex`) and a variety of
synchronization abstractions.
* [`time`](absl/time/)
<br /> The `time` library contains abstractions for computing with absolute
points in time, durations of time, and formatting and parsing time within
time zones.
* [`types`](absl/types/)
<br /> The `types` library contains non-container utility types, like a
C++11-compatible version of the C++17 `std::optional` type.
## License
The Abseil C++ library is licensed under the terms of the Apache
license. See [LICENSE](LICENSE) for more information.
## Links
For more information about Abseil:
* Consult our [Abseil Introduction](http://abseil.io/about/intro)
* Read [Why Adopt Abseil](http://abseil.io/about/philosophy) to understand our
design philosophy.
* Peruse our
[Abseil Compatibility Guarantees](http://abseil.io/about/compatibility) to
understand both what we promise to you, and what we expect of you in return.

View File

@ -1,35 +0,0 @@
workspace(name = "com_google_absl")
# Bazel toolchains
http_archive(
name = "bazel_toolchains",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/2cec6c9f6d12224e93d9b3f337b24e41602de3ba.tar.gz",
"https://github.com/bazelbuild/bazel-toolchains/archive/2cec6c9f6d12224e93d9b3f337b24e41602de3ba.tar.gz",
],
strip_prefix = "bazel-toolchains-2cec6c9f6d12224e93d9b3f337b24e41602de3ba",
sha256 = "9b8d85b61d8945422e86ac31e4d4d2d967542c080d1da1b45364da7fd6bdd638",
)
# GoogleTest/GoogleMock framework. Used by most unit-tests.
http_archive(
name = "com_google_googletest",
urls = ["https://github.com/google/googletest/archive/4e4df226fc197c0dda6e37f5c8c3845ca1e73a49.zip"],
strip_prefix = "googletest-4e4df226fc197c0dda6e37f5c8c3845ca1e73a49",
sha256 = "d4179caf54410968d1fff0b869e7d74803dd30209ee6645ccf1ca65ab6cf5e5a",
)
# Google benchmark.
http_archive(
name = "com_github_google_benchmark",
urls = ["https://github.com/google/benchmark/archive/16703ff83c1ae6d53e5155df3bb3ab0bc96083be.zip"],
strip_prefix = "benchmark-16703ff83c1ae6d53e5155df3bb3ab0bc96083be",
sha256 = "59f918c8ccd4d74b6ac43484467b500f1d64b40cc1010daa055375b322a43ba3",
)
# RE2 regular-expression framework. Used by some unit-tests.
http_archive(
name = "com_googlesource_code_re2",
urls = ["https://github.com/google/re2/archive/6cf8ccd82dbaab2668e9b13596c68183c9ecd13f.zip"],
strip_prefix = "re2-6cf8ccd82dbaab2668e9b13596c68183c9ecd13f",
sha256 = "279a852219dbfc504501775596089d30e9c0b29664ce4128b0ac4c841471a16a",
)

View File

@ -1,52 +0,0 @@
#
# Copyright 2017 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
#
# http://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.
#
package(default_visibility = ["//visibility:public"])
licenses(["notice"]) # Apache 2.0
config_setting(
name = "llvm_compiler",
values = {
"compiler": "llvm",
},
visibility = [":__subpackages__"],
)
# following configs are based on mapping defined in: https://git.io/v5Ijz
config_setting(
name = "ios",
values = {
"cpu": "darwin",
},
visibility = [":__subpackages__"],
)
config_setting(
name = "windows",
values = {
"cpu": "x64_windows",
},
visibility = [":__subpackages__"],
)
config_setting(
name = "ppc",
values = {
"cpu": "ppc",
},
visibility = [":__subpackages__"],
)

View File

@ -1,30 +0,0 @@
#
# Copyright 2017 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
#
# http://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.
#
add_subdirectory(base)
add_subdirectory(algorithm)
add_subdirectory(container)
add_subdirectory(debugging)
add_subdirectory(memory)
add_subdirectory(meta)
add_subdirectory(numeric)
add_subdirectory(strings)
add_subdirectory(synchronization)
add_subdirectory(time)
add_subdirectory(types)
add_subdirectory(utility)

View File

@ -1,13 +0,0 @@
# Long Term Support (LTS) Branches
This repository contains periodic snapshots of the Abseil codebase that are
Long Term Support (LTS) branches. An LTS branch allows you to use a known
version of Abseil without interfering with other projects which may also, in
turn, use Abseil. (For more information about our releases, see the
[Abseil Release Management](https://abseil.io/about/releases) guide.
## LTS Branches
The following lists LTS branches and the date they have been released:
* [LTS Branch June 18, 2018](https://github.com/abseil/abseil-cpp/tree/lts_2018_06_18/)

View File

@ -1,81 +0,0 @@
#
# Copyright 2017 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
#
# http://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(
"//absl:copts.bzl",
"ABSL_DEFAULT_COPTS",
"ABSL_TEST_COPTS",
)
package(default_visibility = ["//visibility:public"])
licenses(["notice"]) # Apache 2.0
cc_library(
name = "algorithm",
hdrs = ["algorithm.h"],
copts = ABSL_DEFAULT_COPTS,
)
cc_test(
name = "algorithm_test",
size = "small",
srcs = ["algorithm_test.cc"],
copts = ABSL_TEST_COPTS,
deps = [
":algorithm",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "algorithm_benchmark",
srcs = ["equal_benchmark.cc"],
copts = ABSL_TEST_COPTS,
tags = ["benchmark"],
deps = [
":algorithm",
"//absl/base:core_headers",
"@com_github_google_benchmark//:benchmark_main",
],
)
cc_library(
name = "container",
hdrs = [
"container.h",
],
copts = ABSL_DEFAULT_COPTS,
deps = [
":algorithm",
"//absl/base:core_headers",
"//absl/meta:type_traits",
],
)
cc_test(
name = "container_test",
srcs = ["container_test.cc"],
copts = ABSL_TEST_COPTS,
deps = [
":container",
"//absl/base",
"//absl/base:core_headers",
"//absl/memory",
"//absl/types:span",
"@com_google_googletest//:gtest_main",
],
)

View File

@ -1,43 +0,0 @@
# Copyright 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build_overrides/build.gni")
if (build_with_chromium) {
visibility = [
"//third_party/webrtc/*",
"//third_party/abseil-cpp/*",
]
} else {
visibility = [ "*" ]
}
source_set("algorithm") {
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
"//build/config/compiler:no_chromium_code",
"//third_party/abseil-cpp:absl_default_cflags_cc",
]
public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
public = [
"algorithm.h",
]
}
source_set("container") {
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
"//build/config/compiler:no_chromium_code",
"//third_party/abseil-cpp:absl_default_cflags_cc",
]
public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
public = [
"container.h",
]
deps = [
":algorithm",
"../base:core_headers",
"../meta:type_traits",
]
}

View File

@ -1,63 +0,0 @@
#
# Copyright 2017 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
#
# http://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.
#
list(APPEND ALGORITHM_PUBLIC_HEADERS
"algorithm.h"
"container.h"
)
#
## TESTS
#
# test algorithm_test
list(APPEND ALGORITHM_TEST_SRC
"algorithm_test.cc"
${ALGORITHM_PUBLIC_HEADERS}
${ALGORITHM_INTERNAL_HEADERS}
)
absl_header_library(
TARGET
absl_algorithm
EXPORT_NAME
algorithm
)
absl_test(
TARGET
algorithm_test
SOURCES
${ALGORITHM_TEST_SRC}
PUBLIC_LIBRARIES
absl::algorithm
)
# test container_test
set(CONTAINER_TEST_SRC "container_test.cc")
absl_test(
TARGET
container_test
SOURCES
${CONTAINER_TEST_SRC}
PUBLIC_LIBRARIES
absl::algorithm
)

View File

@ -1,150 +0,0 @@
// Copyright 2017 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
//
// http://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.
//
// -----------------------------------------------------------------------------
// File: algorithm.h
// -----------------------------------------------------------------------------
//
// This header file contains Google extensions to the standard <algorithm> C++
// header.
#ifndef ABSL_ALGORITHM_ALGORITHM_H_
#define ABSL_ALGORITHM_ALGORITHM_H_
#include <algorithm>
#include <iterator>
#include <type_traits>
namespace absl {
namespace algorithm_internal {
// Performs comparisons with operator==, similar to C++14's `std::equal_to<>`.
struct EqualTo {
template <typename T, typename U>
bool operator()(const T& a, const U& b) const {
return a == b;
}
};
template <typename InputIter1, typename InputIter2, typename Pred>
bool EqualImpl(InputIter1 first1, InputIter1 last1, InputIter2 first2,
InputIter2 last2, Pred pred, std::input_iterator_tag,
std::input_iterator_tag) {
while (true) {
if (first1 == last1) return first2 == last2;
if (first2 == last2) return false;
if (!pred(*first1, *first2)) return false;
++first1;
++first2;
}
}
template <typename InputIter1, typename InputIter2, typename Pred>
bool EqualImpl(InputIter1 first1, InputIter1 last1, InputIter2 first2,
InputIter2 last2, Pred&& pred, std::random_access_iterator_tag,
std::random_access_iterator_tag) {
return (last1 - first1 == last2 - first2) &&
std::equal(first1, last1, first2, std::forward<Pred>(pred));
}
// When we are using our own internal predicate that just applies operator==, we
// forward to the non-predicate form of std::equal. This enables an optimization
// in libstdc++ that can result in std::memcmp being used for integer types.
template <typename InputIter1, typename InputIter2>
bool EqualImpl(InputIter1 first1, InputIter1 last1, InputIter2 first2,
InputIter2 last2, algorithm_internal::EqualTo /* unused */,
std::random_access_iterator_tag,
std::random_access_iterator_tag) {
return (last1 - first1 == last2 - first2) &&
std::equal(first1, last1, first2);
}
template <typename It>
It RotateImpl(It first, It middle, It last, std::true_type) {
return std::rotate(first, middle, last);
}
template <typename It>
It RotateImpl(It first, It middle, It last, std::false_type) {
std::rotate(first, middle, last);
return std::next(first, std::distance(middle, last));
}
} // namespace algorithm_internal
// Compares the equality of two ranges specified by pairs of iterators, using
// the given predicate, returning true iff for each corresponding iterator i1
// and i2 in the first and second range respectively, pred(*i1, *i2) == true
//
// This comparison takes at most min(`last1` - `first1`, `last2` - `first2`)
// invocations of the predicate. Additionally, if InputIter1 and InputIter2 are
// both random-access iterators, and `last1` - `first1` != `last2` - `first2`,
// then the predicate is never invoked and the function returns false.
//
// This is a C++11-compatible implementation of C++14 `std::equal`. See
// http://en.cppreference.com/w/cpp/algorithm/equal for more information.
template <typename InputIter1, typename InputIter2, typename Pred>
bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2,
InputIter2 last2, Pred&& pred) {
return algorithm_internal::EqualImpl(
first1, last1, first2, last2, std::forward<Pred>(pred),
typename std::iterator_traits<InputIter1>::iterator_category{},
typename std::iterator_traits<InputIter2>::iterator_category{});
}
// Performs comparison of two ranges specified by pairs of iterators using
// operator==.
template <typename InputIter1, typename InputIter2>
bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2,
InputIter2 last2) {
return absl::equal(first1, last1, first2, last2,
algorithm_internal::EqualTo{});
}
// Performs a linear search for `value` using the iterator `first` up to
// but not including `last`, returning true if [`first`, `last`) contains an
// element equal to `value`.
//
// A linear search is of O(n) complexity which is guaranteed to make at most
// n = (`last` - `first`) comparisons. A linear search over short containers
// may be faster than a binary search, even when the container is sorted.
template <typename InputIterator, typename EqualityComparable>
bool linear_search(InputIterator first, InputIterator last,
const EqualityComparable& value) {
return std::find(first, last, value) != last;
}
// Performs a left rotation on a range of elements (`first`, `last`) such that
// `middle` is now the first element. `rotate()` returns an iterator pointing to
// the first element before rotation. This function is exactly the same as
// `std::rotate`, but fixes a bug in gcc
// <= 4.9 where `std::rotate` returns `void` instead of an iterator.
//
// The complexity of this algorithm is the same as that of `std::rotate`, but if
// `ForwardIterator` is not a random-access iterator, then `absl::rotate`
// performs an additional pass over the range to construct the return value.
template <typename ForwardIterator>
ForwardIterator rotate(ForwardIterator first, ForwardIterator middle,
ForwardIterator last) {
return algorithm_internal::RotateImpl(
first, middle, last,
std::is_same<decltype(std::rotate(first, middle, last)),
ForwardIterator>());
}
} // namespace absl
#endif // ABSL_ALGORITHM_ALGORITHM_H_

View File

@ -1,182 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include "absl/algorithm/algorithm.h"
#include <algorithm>
#include <list>
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace {
TEST(EqualTest, DefaultComparisonRandomAccess) {
std::vector<int> v1{1, 2, 3};
std::vector<int> v2 = v1;
std::vector<int> v3 = {1, 2};
std::vector<int> v4 = {1, 2, 4};
EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end()));
EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v3.begin(), v3.end()));
EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v4.begin(), v4.end()));
}
TEST(EqualTest, DefaultComparison) {
std::list<int> lst1{1, 2, 3};
std::list<int> lst2 = lst1;
std::list<int> lst3{1, 2};
std::list<int> lst4{1, 2, 4};
EXPECT_TRUE(absl::equal(lst1.begin(), lst1.end(), lst2.begin(), lst2.end()));
EXPECT_FALSE(absl::equal(lst1.begin(), lst1.end(), lst3.begin(), lst3.end()));
EXPECT_FALSE(absl::equal(lst1.begin(), lst1.end(), lst4.begin(), lst4.end()));
}
TEST(EqualTest, EmptyRange) {
std::vector<int> v1{1, 2, 3};
std::vector<int> empty1;
std::vector<int> empty2;
EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), empty1.begin(), empty1.end()));
EXPECT_FALSE(absl::equal(empty1.begin(), empty1.end(), v1.begin(), v1.end()));
EXPECT_TRUE(
absl::equal(empty1.begin(), empty1.end(), empty2.begin(), empty2.end()));
}
TEST(EqualTest, MixedIterTypes) {
std::vector<int> v1{1, 2, 3};
std::list<int> lst1{v1.begin(), v1.end()};
std::list<int> lst2{1, 2, 4};
std::list<int> lst3{1, 2};
EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), lst1.begin(), lst1.end()));
EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), lst2.begin(), lst2.end()));
EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), lst3.begin(), lst3.end()));
}
TEST(EqualTest, MixedValueTypes) {
std::vector<int> v1{1, 2, 3};
std::vector<char> v2{1, 2, 3};
std::vector<char> v3{1, 2};
std::vector<char> v4{1, 2, 4};
EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end()));
EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v3.begin(), v3.end()));
EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v4.begin(), v4.end()));
}
TEST(EqualTest, WeirdIterators) {
std::vector<bool> v1{true, false};
std::vector<bool> v2 = v1;
std::vector<bool> v3{true};
std::vector<bool> v4{true, true, true};
EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end()));
EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v3.begin(), v3.end()));
EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v4.begin(), v4.end()));
}
TEST(EqualTest, CustomComparison) {
int n[] = {1, 2, 3, 4};
std::vector<int*> v1{&n[0], &n[1], &n[2]};
std::vector<int*> v2 = v1;
std::vector<int*> v3{&n[0], &n[1], &n[3]};
std::vector<int*> v4{&n[0], &n[1]};
auto eq = [](int* a, int* b) { return *a == *b; };
EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end(), eq));
EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v3.begin(), v3.end(), eq));
EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v4.begin(), v4.end(), eq));
}
TEST(EqualTest, MoveOnlyPredicate) {
std::vector<int> v1{1, 2, 3};
std::vector<int> v2{4, 5, 6};
// move-only equality predicate
struct Eq {
Eq() = default;
Eq(Eq &&) = default;
Eq(const Eq &) = delete;
Eq &operator=(const Eq &) = delete;
bool operator()(const int a, const int b) const { return a == b; }
};
EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), v1.begin(), v1.end(), Eq()));
EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end(), Eq()));
}
struct CountingTrivialPred {
int* count;
bool operator()(int, int) const {
++*count;
return true;
}
};
TEST(EqualTest, RandomAccessComplexity) {
std::vector<int> v1{1, 1, 3};
std::vector<int> v2 = v1;
std::vector<int> v3{1, 2};
do {
int count = 0;
absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end(),
CountingTrivialPred{&count});
EXPECT_LE(count, 3);
} while (std::next_permutation(v2.begin(), v2.end()));
int count = 0;
absl::equal(v1.begin(), v1.end(), v3.begin(), v3.end(),
CountingTrivialPred{&count});
EXPECT_EQ(count, 0);
}
class LinearSearchTest : public testing::Test {
protected:
LinearSearchTest() : container_{1, 2, 3} {}
static bool Is3(int n) { return n == 3; }
static bool Is4(int n) { return n == 4; }
std::vector<int> container_;
};
TEST_F(LinearSearchTest, linear_search) {
EXPECT_TRUE(absl::linear_search(container_.begin(), container_.end(), 3));
EXPECT_FALSE(absl::linear_search(container_.begin(), container_.end(), 4));
}
TEST_F(LinearSearchTest, linear_searchConst) {
const std::vector<int> *const const_container = &container_;
EXPECT_TRUE(
absl::linear_search(const_container->begin(), const_container->end(), 3));
EXPECT_FALSE(
absl::linear_search(const_container->begin(), const_container->end(), 4));
}
TEST(RotateTest, Rotate) {
std::vector<int> v{0, 1, 2, 3, 4};
EXPECT_EQ(*absl::rotate(v.begin(), v.begin() + 2, v.end()), 0);
EXPECT_THAT(v, testing::ElementsAreArray({2, 3, 4, 0, 1}));
std::list<int> l{0, 1, 2, 3, 4};
EXPECT_EQ(*absl::rotate(l.begin(), std::next(l.begin(), 3), l.end()), 0);
EXPECT_THAT(l, testing::ElementsAreArray({3, 4, 0, 1, 2}));
}
} // namespace

File diff suppressed because it is too large Load Diff

View File

@ -1,997 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include "absl/algorithm/container.h"
#include <functional>
#include <initializer_list>
#include <iterator>
#include <list>
#include <memory>
#include <ostream>
#include <random>
#include <set>
#include <unordered_set>
#include <utility>
#include <valarray>
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/casts.h"
#include "absl/base/macros.h"
#include "absl/memory/memory.h"
#include "absl/types/span.h"
namespace {
using ::testing::Each;
using ::testing::ElementsAre;
using ::testing::Gt;
using ::testing::IsNull;
using ::testing::Lt;
using ::testing::Pointee;
using ::testing::Truly;
using ::testing::UnorderedElementsAre;
// Most of these tests just check that the code compiles, not that it
// does the right thing. That's fine since the functions just forward
// to the STL implementation.
class NonMutatingTest : public testing::Test {
protected:
std::unordered_set<int> container_ = {1, 2, 3};
std::list<int> sequence_ = {1, 2, 3};
std::vector<int> vector_ = {1, 2, 3};
int array_[3] = {1, 2, 3};
};
struct AccumulateCalls {
void operator()(int value) {
calls.push_back(value);
}
std::vector<int> calls;
};
bool Predicate(int value) { return value < 3; }
bool BinPredicate(int v1, int v2) { return v1 < v2; }
bool Equals(int v1, int v2) { return v1 == v2; }
bool IsOdd(int x) { return x % 2 != 0; }
TEST_F(NonMutatingTest, Distance) {
EXPECT_EQ(container_.size(), absl::c_distance(container_));
EXPECT_EQ(sequence_.size(), absl::c_distance(sequence_));
EXPECT_EQ(vector_.size(), absl::c_distance(vector_));
EXPECT_EQ(ABSL_ARRAYSIZE(array_), absl::c_distance(array_));
// Works with a temporary argument.
EXPECT_EQ(vector_.size(), absl::c_distance(std::vector<int>(vector_)));
}
TEST_F(NonMutatingTest, Distance_OverloadedBeginEnd) {
// Works with classes which have custom ADL-selected overloads of std::begin
// and std::end.
std::initializer_list<int> a = {1, 2, 3};
std::valarray<int> b = {1, 2, 3};
EXPECT_EQ(3, absl::c_distance(a));
EXPECT_EQ(3, absl::c_distance(b));
// It is assumed that other c_* functions use the same mechanism for
// ADL-selecting begin/end overloads.
}
TEST_F(NonMutatingTest, ForEach) {
AccumulateCalls c = absl::c_for_each(container_, AccumulateCalls());
// Don't rely on the unordered_set's order.
std::sort(c.calls.begin(), c.calls.end());
EXPECT_EQ(vector_, c.calls);
// Works with temporary container, too.
AccumulateCalls c2 =
absl::c_for_each(std::unordered_set<int>(container_), AccumulateCalls());
std::sort(c2.calls.begin(), c2.calls.end());
EXPECT_EQ(vector_, c2.calls);
}
TEST_F(NonMutatingTest, FindReturnsCorrectType) {
auto it = absl::c_find(container_, 3);
EXPECT_EQ(3, *it);
absl::c_find(absl::implicit_cast<const std::list<int>&>(sequence_), 3);
}
TEST_F(NonMutatingTest, FindIf) { absl::c_find_if(container_, Predicate); }
TEST_F(NonMutatingTest, FindIfNot) {
absl::c_find_if_not(container_, Predicate);
}
TEST_F(NonMutatingTest, FindEnd) {
absl::c_find_end(sequence_, vector_);
absl::c_find_end(vector_, sequence_);
}
TEST_F(NonMutatingTest, FindEndWithPredicate) {
absl::c_find_end(sequence_, vector_, BinPredicate);
absl::c_find_end(vector_, sequence_, BinPredicate);
}
TEST_F(NonMutatingTest, FindFirstOf) {
absl::c_find_first_of(container_, sequence_);
absl::c_find_first_of(sequence_, container_);
}
TEST_F(NonMutatingTest, FindFirstOfWithPredicate) {
absl::c_find_first_of(container_, sequence_, BinPredicate);
absl::c_find_first_of(sequence_, container_, BinPredicate);
}
TEST_F(NonMutatingTest, AdjacentFind) { absl::c_adjacent_find(sequence_); }
TEST_F(NonMutatingTest, AdjacentFindWithPredicate) {
absl::c_adjacent_find(sequence_, BinPredicate);
}
TEST_F(NonMutatingTest, Count) { EXPECT_EQ(1, absl::c_count(container_, 3)); }
TEST_F(NonMutatingTest, CountIf) {
EXPECT_EQ(2, absl::c_count_if(container_, Predicate));
const std::unordered_set<int>& const_container = container_;
EXPECT_EQ(2, absl::c_count_if(const_container, Predicate));
}
TEST_F(NonMutatingTest, Mismatch) {
absl::c_mismatch(container_, sequence_);
absl::c_mismatch(sequence_, container_);
}
TEST_F(NonMutatingTest, MismatchWithPredicate) {
absl::c_mismatch(container_, sequence_, BinPredicate);
absl::c_mismatch(sequence_, container_, BinPredicate);
}
TEST_F(NonMutatingTest, Equal) {
EXPECT_TRUE(absl::c_equal(vector_, sequence_));
EXPECT_TRUE(absl::c_equal(sequence_, vector_));
// Test that behavior appropriately differs from that of equal().
std::vector<int> vector_plus = {1, 2, 3};
vector_plus.push_back(4);
EXPECT_FALSE(absl::c_equal(vector_plus, sequence_));
EXPECT_FALSE(absl::c_equal(sequence_, vector_plus));
}
TEST_F(NonMutatingTest, EqualWithPredicate) {
EXPECT_TRUE(absl::c_equal(vector_, sequence_, Equals));
EXPECT_TRUE(absl::c_equal(sequence_, vector_, Equals));
// Test that behavior appropriately differs from that of equal().
std::vector<int> vector_plus = {1, 2, 3};
vector_plus.push_back(4);
EXPECT_FALSE(absl::c_equal(vector_plus, sequence_, Equals));
EXPECT_FALSE(absl::c_equal(sequence_, vector_plus, Equals));
}
TEST_F(NonMutatingTest, IsPermutation) {
auto vector_permut_ = vector_;
std::next_permutation(vector_permut_.begin(), vector_permut_.end());
EXPECT_TRUE(absl::c_is_permutation(vector_permut_, sequence_));
EXPECT_TRUE(absl::c_is_permutation(sequence_, vector_permut_));
// Test that behavior appropriately differs from that of is_permutation().
std::vector<int> vector_plus = {1, 2, 3};
vector_plus.push_back(4);
EXPECT_FALSE(absl::c_is_permutation(vector_plus, sequence_));
EXPECT_FALSE(absl::c_is_permutation(sequence_, vector_plus));
}
TEST_F(NonMutatingTest, IsPermutationWithPredicate) {
auto vector_permut_ = vector_;
std::next_permutation(vector_permut_.begin(), vector_permut_.end());
EXPECT_TRUE(absl::c_is_permutation(vector_permut_, sequence_, Equals));
EXPECT_TRUE(absl::c_is_permutation(sequence_, vector_permut_, Equals));
// Test that behavior appropriately differs from that of is_permutation().
std::vector<int> vector_plus = {1, 2, 3};
vector_plus.push_back(4);
EXPECT_FALSE(absl::c_is_permutation(vector_plus, sequence_, Equals));
EXPECT_FALSE(absl::c_is_permutation(sequence_, vector_plus, Equals));
}
TEST_F(NonMutatingTest, Search) {
absl::c_search(sequence_, vector_);
absl::c_search(vector_, sequence_);
absl::c_search(array_, sequence_);
}
TEST_F(NonMutatingTest, SearchWithPredicate) {
absl::c_search(sequence_, vector_, BinPredicate);
absl::c_search(vector_, sequence_, BinPredicate);
}
TEST_F(NonMutatingTest, SearchN) { absl::c_search_n(sequence_, 3, 1); }
TEST_F(NonMutatingTest, SearchNWithPredicate) {
absl::c_search_n(sequence_, 3, 1, BinPredicate);
}
TEST_F(NonMutatingTest, LowerBound) {
std::list<int>::iterator i = absl::c_lower_bound(sequence_, 3);
ASSERT_TRUE(i != sequence_.end());
EXPECT_EQ(2, std::distance(sequence_.begin(), i));
EXPECT_EQ(3, *i);
}
TEST_F(NonMutatingTest, LowerBoundWithPredicate) {
std::vector<int> v(vector_);
std::sort(v.begin(), v.end(), std::greater<int>());
std::vector<int>::iterator i = absl::c_lower_bound(v, 3, std::greater<int>());
EXPECT_TRUE(i == v.begin());
EXPECT_EQ(3, *i);
}
TEST_F(NonMutatingTest, UpperBound) {
std::list<int>::iterator i = absl::c_upper_bound(sequence_, 1);
ASSERT_TRUE(i != sequence_.end());
EXPECT_EQ(1, std::distance(sequence_.begin(), i));
EXPECT_EQ(2, *i);
}
TEST_F(NonMutatingTest, UpperBoundWithPredicate) {
std::vector<int> v(vector_);
std::sort(v.begin(), v.end(), std::greater<int>());
std::vector<int>::iterator i = absl::c_upper_bound(v, 1, std::greater<int>());
EXPECT_EQ(3, i - v.begin());
EXPECT_TRUE(i == v.end());
}
TEST_F(NonMutatingTest, EqualRange) {
std::pair<std::list<int>::iterator, std::list<int>::iterator> p =
absl::c_equal_range(sequence_, 2);
EXPECT_EQ(1, std::distance(sequence_.begin(), p.first));
EXPECT_EQ(2, std::distance(sequence_.begin(), p.second));
}
TEST_F(NonMutatingTest, EqualRangeArray) {
auto p = absl::c_equal_range(array_, 2);
EXPECT_EQ(1, std::distance(std::begin(array_), p.first));
EXPECT_EQ(2, std::distance(std::begin(array_), p.second));
}
TEST_F(NonMutatingTest, EqualRangeWithPredicate) {
std::vector<int> v(vector_);
std::sort(v.begin(), v.end(), std::greater<int>());
std::pair<std::vector<int>::iterator, std::vector<int>::iterator> p =
absl::c_equal_range(v, 2, std::greater<int>());
EXPECT_EQ(1, std::distance(v.begin(), p.first));
EXPECT_EQ(2, std::distance(v.begin(), p.second));
}
TEST_F(NonMutatingTest, BinarySearch) {
EXPECT_TRUE(absl::c_binary_search(vector_, 2));
EXPECT_TRUE(absl::c_binary_search(std::vector<int>(vector_), 2));
}
TEST_F(NonMutatingTest, BinarySearchWithPredicate) {
std::vector<int> v(vector_);
std::sort(v.begin(), v.end(), std::greater<int>());
EXPECT_TRUE(absl::c_binary_search(v, 2, std::greater<int>()));
EXPECT_TRUE(
absl::c_binary_search(std::vector<int>(v), 2, std::greater<int>()));
}
TEST_F(NonMutatingTest, MinElement) {
std::list<int>::iterator i = absl::c_min_element(sequence_);
ASSERT_TRUE(i != sequence_.end());
EXPECT_EQ(*i, 1);
}
TEST_F(NonMutatingTest, MinElementWithPredicate) {
std::list<int>::iterator i =
absl::c_min_element(sequence_, std::greater<int>());
ASSERT_TRUE(i != sequence_.end());
EXPECT_EQ(*i, 3);
}
TEST_F(NonMutatingTest, MaxElement) {
std::list<int>::iterator i = absl::c_max_element(sequence_);
ASSERT_TRUE(i != sequence_.end());
EXPECT_EQ(*i, 3);
}
TEST_F(NonMutatingTest, MaxElementWithPredicate) {
std::list<int>::iterator i =
absl::c_max_element(sequence_, std::greater<int>());
ASSERT_TRUE(i != sequence_.end());
EXPECT_EQ(*i, 1);
}
TEST_F(NonMutatingTest, LexicographicalCompare) {
EXPECT_FALSE(absl::c_lexicographical_compare(sequence_, sequence_));
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(4);
EXPECT_TRUE(absl::c_lexicographical_compare(sequence_, v));
EXPECT_TRUE(absl::c_lexicographical_compare(std::list<int>(sequence_), v));
}
TEST_F(NonMutatingTest, LexicographicalCopmareWithPredicate) {
EXPECT_FALSE(absl::c_lexicographical_compare(sequence_, sequence_,
std::greater<int>()));
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(4);
EXPECT_TRUE(
absl::c_lexicographical_compare(v, sequence_, std::greater<int>()));
EXPECT_TRUE(absl::c_lexicographical_compare(
std::vector<int>(v), std::list<int>(sequence_), std::greater<int>()));
}
TEST_F(NonMutatingTest, Includes) {
std::set<int> s(vector_.begin(), vector_.end());
s.insert(4);
EXPECT_TRUE(absl::c_includes(s, vector_));
}
TEST_F(NonMutatingTest, IncludesWithPredicate) {
std::vector<int> v = {3, 2, 1};
std::set<int, std::greater<int>> s(v.begin(), v.end());
s.insert(4);
EXPECT_TRUE(absl::c_includes(s, v, std::greater<int>()));
}
class NumericMutatingTest : public testing::Test {
protected:
std::list<int> list_ = {1, 2, 3};
std::vector<int> output_;
};
TEST_F(NumericMutatingTest, Iota) {
absl::c_iota(list_, 5);
std::list<int> expected{5, 6, 7};
EXPECT_EQ(list_, expected);
}
TEST_F(NonMutatingTest, Accumulate) {
EXPECT_EQ(absl::c_accumulate(sequence_, 4), 1 + 2 + 3 + 4);
}
TEST_F(NonMutatingTest, AccumulateWithBinaryOp) {
EXPECT_EQ(absl::c_accumulate(sequence_, 4, std::multiplies<int>()),
1 * 2 * 3 * 4);
}
TEST_F(NonMutatingTest, AccumulateLvalueInit) {
int lvalue = 4;
EXPECT_EQ(absl::c_accumulate(sequence_, lvalue), 1 + 2 + 3 + 4);
}
TEST_F(NonMutatingTest, AccumulateWithBinaryOpLvalueInit) {
int lvalue = 4;
EXPECT_EQ(absl::c_accumulate(sequence_, lvalue, std::multiplies<int>()),
1 * 2 * 3 * 4);
}
TEST_F(NonMutatingTest, InnerProduct) {
EXPECT_EQ(absl::c_inner_product(sequence_, vector_, 1000),
1000 + 1 * 1 + 2 * 2 + 3 * 3);
}
TEST_F(NonMutatingTest, InnerProductWithBinaryOps) {
EXPECT_EQ(absl::c_inner_product(sequence_, vector_, 10,
std::multiplies<int>(), std::plus<int>()),
10 * (1 + 1) * (2 + 2) * (3 + 3));
}
TEST_F(NonMutatingTest, InnerProductLvalueInit) {
int lvalue = 1000;
EXPECT_EQ(absl::c_inner_product(sequence_, vector_, lvalue),
1000 + 1 * 1 + 2 * 2 + 3 * 3);
}
TEST_F(NonMutatingTest, InnerProductWithBinaryOpsLvalueInit) {
int lvalue = 10;
EXPECT_EQ(absl::c_inner_product(sequence_, vector_, lvalue,
std::multiplies<int>(), std::plus<int>()),
10 * (1 + 1) * (2 + 2) * (3 + 3));
}
TEST_F(NumericMutatingTest, AdjacentDifference) {
auto last = absl::c_adjacent_difference(list_, std::back_inserter(output_));
*last = 1000;
std::vector<int> expected{1, 2 - 1, 3 - 2, 1000};
EXPECT_EQ(output_, expected);
}
TEST_F(NumericMutatingTest, AdjacentDifferenceWithBinaryOp) {
auto last = absl::c_adjacent_difference(list_, std::back_inserter(output_),
std::multiplies<int>());
*last = 1000;
std::vector<int> expected{1, 2 * 1, 3 * 2, 1000};
EXPECT_EQ(output_, expected);
}
TEST_F(NumericMutatingTest, PartialSum) {
auto last = absl::c_partial_sum(list_, std::back_inserter(output_));
*last = 1000;
std::vector<int> expected{1, 1 + 2, 1 + 2 + 3, 1000};
EXPECT_EQ(output_, expected);
}
TEST_F(NumericMutatingTest, PartialSumWithBinaryOp) {
auto last = absl::c_partial_sum(list_, std::back_inserter(output_),
std::multiplies<int>());
*last = 1000;
std::vector<int> expected{1, 1 * 2, 1 * 2 * 3, 1000};
EXPECT_EQ(output_, expected);
}
TEST_F(NonMutatingTest, LinearSearch) {
EXPECT_TRUE(absl::c_linear_search(container_, 3));
EXPECT_FALSE(absl::c_linear_search(container_, 4));
}
TEST_F(NonMutatingTest, AllOf) {
const std::vector<int>& v = vector_;
EXPECT_FALSE(absl::c_all_of(v, [](int x) { return x > 1; }));
EXPECT_TRUE(absl::c_all_of(v, [](int x) { return x > 0; }));
}
TEST_F(NonMutatingTest, AnyOf) {
const std::vector<int>& v = vector_;
EXPECT_TRUE(absl::c_any_of(v, [](int x) { return x > 2; }));
EXPECT_FALSE(absl::c_any_of(v, [](int x) { return x > 5; }));
}
TEST_F(NonMutatingTest, NoneOf) {
const std::vector<int>& v = vector_;
EXPECT_FALSE(absl::c_none_of(v, [](int x) { return x > 2; }));
EXPECT_TRUE(absl::c_none_of(v, [](int x) { return x > 5; }));
}
TEST_F(NonMutatingTest, MinMaxElementLess) {
std::pair<std::vector<int>::const_iterator, std::vector<int>::const_iterator>
p = absl::c_minmax_element(vector_, std::less<int>());
EXPECT_TRUE(p.first == vector_.begin());
EXPECT_TRUE(p.second == vector_.begin() + 2);
}
TEST_F(NonMutatingTest, MinMaxElementGreater) {
std::pair<std::vector<int>::const_iterator, std::vector<int>::const_iterator>
p = absl::c_minmax_element(vector_, std::greater<int>());
EXPECT_TRUE(p.first == vector_.begin() + 2);
EXPECT_TRUE(p.second == vector_.begin());
}
TEST_F(NonMutatingTest, MinMaxElementNoPredicate) {
std::pair<std::vector<int>::const_iterator, std::vector<int>::const_iterator>
p = absl::c_minmax_element(vector_);
EXPECT_TRUE(p.first == vector_.begin());
EXPECT_TRUE(p.second == vector_.begin() + 2);
}
class SortingTest : public testing::Test {
protected:
std::list<int> sorted_ = {1, 2, 3, 4};
std::list<int> unsorted_ = {2, 4, 1, 3};
std::list<int> reversed_ = {4, 3, 2, 1};
};
TEST_F(SortingTest, IsSorted) {
EXPECT_TRUE(absl::c_is_sorted(sorted_));
EXPECT_FALSE(absl::c_is_sorted(unsorted_));
EXPECT_FALSE(absl::c_is_sorted(reversed_));
}
TEST_F(SortingTest, IsSortedWithPredicate) {
EXPECT_FALSE(absl::c_is_sorted(sorted_, std::greater<int>()));
EXPECT_FALSE(absl::c_is_sorted(unsorted_, std::greater<int>()));
EXPECT_TRUE(absl::c_is_sorted(reversed_, std::greater<int>()));
}
TEST_F(SortingTest, IsSortedUntil) {
EXPECT_EQ(1, *absl::c_is_sorted_until(unsorted_));
EXPECT_EQ(4, *absl::c_is_sorted_until(unsorted_, std::greater<int>()));
}
TEST_F(SortingTest, NthElement) {
std::vector<int> unsorted = {2, 4, 1, 3};
absl::c_nth_element(unsorted, unsorted.begin() + 2);
EXPECT_THAT(unsorted,
ElementsAre(Lt(3), Lt(3), 3, Gt(3)));
absl::c_nth_element(unsorted, unsorted.begin() + 2, std::greater<int>());
EXPECT_THAT(unsorted,
ElementsAre(Gt(2), Gt(2), 2, Lt(2)));
}
TEST(MutatingTest, IsPartitioned) {
EXPECT_TRUE(
absl::c_is_partitioned(std::vector<int>{1, 3, 5, 2, 4, 6}, IsOdd));
EXPECT_FALSE(
absl::c_is_partitioned(std::vector<int>{1, 2, 3, 4, 5, 6}, IsOdd));
EXPECT_FALSE(
absl::c_is_partitioned(std::vector<int>{2, 4, 6, 1, 3, 5}, IsOdd));
}
TEST(MutatingTest, Partition) {
std::vector<int> actual = {1, 2, 3, 4, 5};
absl::c_partition(actual, IsOdd);
EXPECT_THAT(actual, Truly([](const std::vector<int>& c) {
return absl::c_is_partitioned(c, IsOdd);
}));
}
TEST(MutatingTest, StablePartition) {
std::vector<int> actual = {1, 2, 3, 4, 5};
absl::c_stable_partition(actual, IsOdd);
EXPECT_THAT(actual, ElementsAre(1, 3, 5, 2, 4));
}
TEST(MutatingTest, PartitionCopy) {
const std::vector<int> initial = {1, 2, 3, 4, 5};
std::vector<int> odds, evens;
auto ends = absl::c_partition_copy(initial, back_inserter(odds),
back_inserter(evens), IsOdd);
*ends.first = 7;
*ends.second = 6;
EXPECT_THAT(odds, ElementsAre(1, 3, 5, 7));
EXPECT_THAT(evens, ElementsAre(2, 4, 6));
}
TEST(MutatingTest, PartitionPoint) {
const std::vector<int> initial = {1, 3, 5, 2, 4};
auto middle = absl::c_partition_point(initial, IsOdd);
EXPECT_EQ(2, *middle);
}
TEST(MutatingTest, CopyMiddle) {
const std::vector<int> initial = {4, -1, -2, -3, 5};
const std::list<int> input = {1, 2, 3};
const std::vector<int> expected = {4, 1, 2, 3, 5};
std::list<int> test_list(initial.begin(), initial.end());
absl::c_copy(input, ++test_list.begin());
EXPECT_EQ(std::list<int>(expected.begin(), expected.end()), test_list);
std::vector<int> test_vector = initial;
absl::c_copy(input, test_vector.begin() + 1);
EXPECT_EQ(expected, test_vector);
}
TEST(MutatingTest, CopyFrontInserter) {
const std::list<int> initial = {4, 5};
const std::list<int> input = {1, 2, 3};
const std::list<int> expected = {3, 2, 1, 4, 5};
std::list<int> test_list = initial;
absl::c_copy(input, std::front_inserter(test_list));
EXPECT_EQ(expected, test_list);
}
TEST(MutatingTest, CopyBackInserter) {
const std::vector<int> initial = {4, 5};
const std::list<int> input = {1, 2, 3};
const std::vector<int> expected = {4, 5, 1, 2, 3};
std::list<int> test_list(initial.begin(), initial.end());
absl::c_copy(input, std::back_inserter(test_list));
EXPECT_EQ(std::list<int>(expected.begin(), expected.end()), test_list);
std::vector<int> test_vector = initial;
absl::c_copy(input, std::back_inserter(test_vector));
EXPECT_EQ(expected, test_vector);
}
TEST(MutatingTest, CopyN) {
const std::vector<int> initial = {1, 2, 3, 4, 5};
const std::vector<int> expected = {1, 2};
std::vector<int> actual;
absl::c_copy_n(initial, 2, back_inserter(actual));
EXPECT_EQ(expected, actual);
}
TEST(MutatingTest, CopyIf) {
const std::list<int> input = {1, 2, 3};
std::vector<int> output;
absl::c_copy_if(input, std::back_inserter(output),
[](int i) { return i != 2; });
EXPECT_THAT(output, ElementsAre(1, 3));
}
TEST(MutatingTest, CopyBackward) {
std::vector<int> actual = {1, 2, 3, 4, 5};
std::vector<int> expected = {1, 2, 1, 2, 3};
absl::c_copy_backward(absl::MakeSpan(actual.data(), 3), actual.end());
EXPECT_EQ(expected, actual);
}
TEST(MutatingTest, Move) {
std::vector<std::unique_ptr<int>> src;
src.emplace_back(absl::make_unique<int>(1));
src.emplace_back(absl::make_unique<int>(2));
src.emplace_back(absl::make_unique<int>(3));
src.emplace_back(absl::make_unique<int>(4));
src.emplace_back(absl::make_unique<int>(5));
std::vector<std::unique_ptr<int>> dest = {};
absl::c_move(src, std::back_inserter(dest));
EXPECT_THAT(src, Each(IsNull()));
EXPECT_THAT(dest, ElementsAre(Pointee(1), Pointee(2), Pointee(3), Pointee(4),
Pointee(5)));
}
TEST(MutatingTest, SwapRanges) {
std::vector<int> odds = {2, 4, 6};
std::vector<int> evens = {1, 3, 5};
absl::c_swap_ranges(odds, evens);
EXPECT_THAT(odds, ElementsAre(1, 3, 5));
EXPECT_THAT(evens, ElementsAre(2, 4, 6));
}
TEST_F(NonMutatingTest, Transform) {
std::vector<int> x{0, 2, 4}, y, z;
auto end = absl::c_transform(x, back_inserter(y), std::negate<int>());
EXPECT_EQ(std::vector<int>({0, -2, -4}), y);
*end = 7;
EXPECT_EQ(std::vector<int>({0, -2, -4, 7}), y);
y = {1, 3, 0};
end = absl::c_transform(x, y, back_inserter(z), std::plus<int>());
EXPECT_EQ(std::vector<int>({1, 5, 4}), z);
*end = 7;
EXPECT_EQ(std::vector<int>({1, 5, 4, 7}), z);
}
TEST(MutatingTest, Replace) {
const std::vector<int> initial = {1, 2, 3, 1, 4, 5};
const std::vector<int> expected = {4, 2, 3, 4, 4, 5};
std::vector<int> test_vector = initial;
absl::c_replace(test_vector, 1, 4);
EXPECT_EQ(expected, test_vector);
std::list<int> test_list(initial.begin(), initial.end());
absl::c_replace(test_list, 1, 4);
EXPECT_EQ(std::list<int>(expected.begin(), expected.end()), test_list);
}
TEST(MutatingTest, ReplaceIf) {
std::vector<int> actual = {1, 2, 3, 4, 5};
const std::vector<int> expected = {0, 2, 0, 4, 0};
absl::c_replace_if(actual, IsOdd, 0);
EXPECT_EQ(expected, actual);
}
TEST(MutatingTest, ReplaceCopy) {
const std::vector<int> initial = {1, 2, 3, 1, 4, 5};
const std::vector<int> expected = {4, 2, 3, 4, 4, 5};
std::vector<int> actual;
absl::c_replace_copy(initial, back_inserter(actual), 1, 4);
EXPECT_EQ(expected, actual);
}
TEST(MutatingTest, Sort) {
std::vector<int> test_vector = {2, 3, 1, 4};
absl::c_sort(test_vector);
EXPECT_THAT(test_vector, ElementsAre(1, 2, 3, 4));
}
TEST(MutatingTest, SortWithPredicate) {
std::vector<int> test_vector = {2, 3, 1, 4};
absl::c_sort(test_vector, std::greater<int>());
EXPECT_THAT(test_vector, ElementsAre(4, 3, 2, 1));
}
// For absl::c_stable_sort tests. Needs an operator< that does not cover all
// fields so that the test can check the sort preserves order of equal elements.
struct Element {
int key;
int value;
friend bool operator<(const Element& e1, const Element& e2) {
return e1.key < e2.key;
}
// Make gmock print useful diagnostics.
friend std::ostream& operator<<(std::ostream& o, const Element& e) {
return o << "{" << e.key << ", " << e.value << "}";
}
};
MATCHER_P2(IsElement, key, value, "") {
return arg.key == key && arg.value == value;
}
TEST(MutatingTest, StableSort) {
std::vector<Element> test_vector = {{1, 1}, {2, 1}, {2, 0}, {1, 0}, {2, 2}};
absl::c_stable_sort(test_vector);
EXPECT_THAT(
test_vector,
ElementsAre(IsElement(1, 1), IsElement(1, 0), IsElement(2, 1),
IsElement(2, 0), IsElement(2, 2)));
}
TEST(MutatingTest, StableSortWithPredicate) {
std::vector<Element> test_vector = {{1, 1}, {2, 1}, {2, 0}, {1, 0}, {2, 2}};
absl::c_stable_sort(test_vector, [](const Element& e1, const Element& e2) {
return e2 < e1;
});
EXPECT_THAT(
test_vector,
ElementsAre(IsElement(2, 1), IsElement(2, 0), IsElement(2, 2),
IsElement(1, 1), IsElement(1, 0)));
}
TEST(MutatingTest, ReplaceCopyIf) {
const std::vector<int> initial = {1, 2, 3, 4, 5};
const std::vector<int> expected = {0, 2, 0, 4, 0};
std::vector<int> actual;
absl::c_replace_copy_if(initial, back_inserter(actual), IsOdd, 0);
EXPECT_EQ(expected, actual);
}
TEST(MutatingTest, Fill) {
std::vector<int> actual(5);
absl::c_fill(actual, 1);
EXPECT_THAT(actual, ElementsAre(1, 1, 1, 1, 1));
}
TEST(MutatingTest, FillN) {
std::vector<int> actual(5, 0);
absl::c_fill_n(actual, 2, 1);
EXPECT_THAT(actual, ElementsAre(1, 1, 0, 0, 0));
}
TEST(MutatingTest, Generate) {
std::vector<int> actual(5);
int x = 0;
absl::c_generate(actual, [&x]() { return ++x; });
EXPECT_THAT(actual, ElementsAre(1, 2, 3, 4, 5));
}
TEST(MutatingTest, GenerateN) {
std::vector<int> actual(5, 0);
int x = 0;
absl::c_generate_n(actual, 3, [&x]() { return ++x; });
EXPECT_THAT(actual, ElementsAre(1, 2, 3, 0, 0));
}
TEST(MutatingTest, RemoveCopy) {
std::vector<int> actual;
absl::c_remove_copy(std::vector<int>{1, 2, 3}, back_inserter(actual), 2);
EXPECT_THAT(actual, ElementsAre(1, 3));
}
TEST(MutatingTest, RemoveCopyIf) {
std::vector<int> actual;
absl::c_remove_copy_if(std::vector<int>{1, 2, 3}, back_inserter(actual),
IsOdd);
EXPECT_THAT(actual, ElementsAre(2));
}
TEST(MutatingTest, UniqueCopy) {
std::vector<int> actual;
absl::c_unique_copy(std::vector<int>{1, 2, 2, 2, 3, 3, 2},
back_inserter(actual));
EXPECT_THAT(actual, ElementsAre(1, 2, 3, 2));
}
TEST(MutatingTest, UniqueCopyWithPredicate) {
std::vector<int> actual;
absl::c_unique_copy(std::vector<int>{1, 2, 3, -1, -2, -3, 1},
back_inserter(actual),
[](int x, int y) { return (x < 0) == (y < 0); });
EXPECT_THAT(actual, ElementsAre(1, -1, 1));
}
TEST(MutatingTest, Reverse) {
std::vector<int> test_vector = {1, 2, 3, 4};
absl::c_reverse(test_vector);
EXPECT_THAT(test_vector, ElementsAre(4, 3, 2, 1));
std::list<int> test_list = {1, 2, 3, 4};
absl::c_reverse(test_list);
EXPECT_THAT(test_list, ElementsAre(4, 3, 2, 1));
}
TEST(MutatingTest, ReverseCopy) {
std::vector<int> actual;
absl::c_reverse_copy(std::vector<int>{1, 2, 3, 4}, back_inserter(actual));
EXPECT_THAT(actual, ElementsAre(4, 3, 2, 1));
}
TEST(MutatingTest, Rotate) {
std::vector<int> actual = {1, 2, 3, 4};
auto it = absl::c_rotate(actual, actual.begin() + 2);
EXPECT_THAT(actual, testing::ElementsAreArray({3, 4, 1, 2}));
EXPECT_EQ(*it, 1);
}
TEST(MutatingTest, RotateCopy) {
std::vector<int> initial = {1, 2, 3, 4};
std::vector<int> actual;
auto end =
absl::c_rotate_copy(initial, initial.begin() + 2, back_inserter(actual));
*end = 5;
EXPECT_THAT(actual, ElementsAre(3, 4, 1, 2, 5));
}
TEST(MutatingTest, Shuffle) {
std::vector<int> actual = {1, 2, 3, 4, 5};
absl::c_shuffle(actual, std::random_device());
EXPECT_THAT(actual, UnorderedElementsAre(1, 2, 3, 4, 5));
}
TEST(MutatingTest, PartialSort) {
std::vector<int> sequence{5, 3, 42, 0};
absl::c_partial_sort(sequence, sequence.begin() + 2);
EXPECT_THAT(absl::MakeSpan(sequence.data(), 2), ElementsAre(0, 3));
absl::c_partial_sort(sequence, sequence.begin() + 2, std::greater<int>());
EXPECT_THAT(absl::MakeSpan(sequence.data(), 2), ElementsAre(42, 5));
}
TEST(MutatingTest, PartialSortCopy) {
const std::vector<int> initial = {5, 3, 42, 0};
std::vector<int> actual(2);
absl::c_partial_sort_copy(initial, actual);
EXPECT_THAT(actual, ElementsAre(0, 3));
absl::c_partial_sort_copy(initial, actual, std::greater<int>());
EXPECT_THAT(actual, ElementsAre(42, 5));
}
TEST(MutatingTest, Merge) {
std::vector<int> actual;
absl::c_merge(std::vector<int>{1, 3, 5}, std::vector<int>{2, 4},
back_inserter(actual));
EXPECT_THAT(actual, ElementsAre(1, 2, 3, 4, 5));
}
TEST(MutatingTest, MergeWithComparator) {
std::vector<int> actual;
absl::c_merge(std::vector<int>{5, 3, 1}, std::vector<int>{4, 2},
back_inserter(actual), std::greater<int>());
EXPECT_THAT(actual, ElementsAre(5, 4, 3, 2, 1));
}
TEST(MutatingTest, InplaceMerge) {
std::vector<int> actual = {1, 3, 5, 2, 4};
absl::c_inplace_merge(actual, actual.begin() + 3);
EXPECT_THAT(actual, ElementsAre(1, 2, 3, 4, 5));
}
TEST(MutatingTest, InplaceMergeWithComparator) {
std::vector<int> actual = {5, 3, 1, 4, 2};
absl::c_inplace_merge(actual, actual.begin() + 3, std::greater<int>());
EXPECT_THAT(actual, ElementsAre(5, 4, 3, 2, 1));
}
class SetOperationsTest : public testing::Test {
protected:
std::vector<int> a_ = {1, 2, 3};
std::vector<int> b_ = {1, 3, 5};
std::vector<int> a_reversed_ = {3, 2, 1};
std::vector<int> b_reversed_ = {5, 3, 1};
};
TEST_F(SetOperationsTest, SetUnion) {
std::vector<int> actual;
absl::c_set_union(a_, b_, back_inserter(actual));
EXPECT_THAT(actual, ElementsAre(1, 2, 3, 5));
}
TEST_F(SetOperationsTest, SetUnionWithComparator) {
std::vector<int> actual;
absl::c_set_union(a_reversed_, b_reversed_, back_inserter(actual),
std::greater<int>());
EXPECT_THAT(actual, ElementsAre(5, 3, 2, 1));
}
TEST_F(SetOperationsTest, SetIntersection) {
std::vector<int> actual;
absl::c_set_intersection(a_, b_, back_inserter(actual));
EXPECT_THAT(actual, ElementsAre(1, 3));
}
TEST_F(SetOperationsTest, SetIntersectionWithComparator) {
std::vector<int> actual;
absl::c_set_intersection(a_reversed_, b_reversed_, back_inserter(actual),
std::greater<int>());
EXPECT_THAT(actual, ElementsAre(3, 1));
}
TEST_F(SetOperationsTest, SetDifference) {
std::vector<int> actual;
absl::c_set_difference(a_, b_, back_inserter(actual));
EXPECT_THAT(actual, ElementsAre(2));
}
TEST_F(SetOperationsTest, SetDifferenceWithComparator) {
std::vector<int> actual;
absl::c_set_difference(a_reversed_, b_reversed_, back_inserter(actual),
std::greater<int>());
EXPECT_THAT(actual, ElementsAre(2));
}
TEST_F(SetOperationsTest, SetSymmetricDifference) {
std::vector<int> actual;
absl::c_set_symmetric_difference(a_, b_, back_inserter(actual));
EXPECT_THAT(actual, ElementsAre(2, 5));
}
TEST_F(SetOperationsTest, SetSymmetricDifferenceWithComparator) {
std::vector<int> actual;
absl::c_set_symmetric_difference(a_reversed_, b_reversed_,
back_inserter(actual), std::greater<int>());
EXPECT_THAT(actual, ElementsAre(5, 2));
}
TEST(HeapOperationsTest, WithoutComparator) {
std::vector<int> heap = {1, 2, 3};
EXPECT_FALSE(absl::c_is_heap(heap));
absl::c_make_heap(heap);
EXPECT_TRUE(absl::c_is_heap(heap));
heap.push_back(4);
EXPECT_EQ(3, absl::c_is_heap_until(heap) - heap.begin());
absl::c_push_heap(heap);
EXPECT_EQ(4, heap[0]);
absl::c_pop_heap(heap);
EXPECT_EQ(4, heap[3]);
absl::c_make_heap(heap);
absl::c_sort_heap(heap);
EXPECT_THAT(heap, ElementsAre(1, 2, 3, 4));
EXPECT_FALSE(absl::c_is_heap(heap));
}
TEST(HeapOperationsTest, WithComparator) {
using greater = std::greater<int>;
std::vector<int> heap = {3, 2, 1};
EXPECT_FALSE(absl::c_is_heap(heap, greater()));
absl::c_make_heap(heap, greater());
EXPECT_TRUE(absl::c_is_heap(heap, greater()));
heap.push_back(0);
EXPECT_EQ(3, absl::c_is_heap_until(heap, greater()) - heap.begin());
absl::c_push_heap(heap, greater());
EXPECT_EQ(0, heap[0]);
absl::c_pop_heap(heap, greater());
EXPECT_EQ(0, heap[3]);
absl::c_make_heap(heap, greater());
absl::c_sort_heap(heap, greater());
EXPECT_THAT(heap, ElementsAre(3, 2, 1, 0));
EXPECT_FALSE(absl::c_is_heap(heap, greater()));
}
TEST(MutatingTest, PermutationOperations) {
std::vector<int> initial = {1, 2, 3, 4};
std::vector<int> permuted = initial;
absl::c_next_permutation(permuted);
EXPECT_TRUE(absl::c_is_permutation(initial, permuted));
EXPECT_TRUE(absl::c_is_permutation(initial, permuted, std::equal_to<int>()));
std::vector<int> permuted2 = initial;
absl::c_prev_permutation(permuted2, std::greater<int>());
EXPECT_EQ(permuted, permuted2);
absl::c_prev_permutation(permuted);
EXPECT_EQ(initial, permuted);
}
} // namespace

View File

@ -1,126 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include <cstdint>
#include <cstring>
#include "benchmark/benchmark.h"
#include "absl/algorithm/algorithm.h"
namespace {
// The range of sequence sizes to benchmark.
constexpr int kMinBenchmarkSize = 1024;
constexpr int kMaxBenchmarkSize = 8 * 1024 * 1024;
// A user-defined type for use in equality benchmarks. Note that we expect
// std::memcmp to win for this type: libstdc++'s std::equal only defers to
// memcmp for integral types. This is because it is not straightforward to
// guarantee that std::memcmp would produce a result "as-if" compared by
// operator== for other types (example gotchas: NaN floats, structs with
// padding).
struct EightBits {
explicit EightBits(int /* unused */) : data(0) {}
bool operator==(const EightBits& rhs) const { return data == rhs.data; }
uint8_t data;
};
template <typename T>
void BM_absl_equal_benchmark(benchmark::State& state) {
std::vector<T> xs(state.range(0), T(0));
std::vector<T> ys = xs;
while (state.KeepRunning()) {
const bool same = absl::equal(xs.begin(), xs.end(), ys.begin(), ys.end());
benchmark::DoNotOptimize(same);
}
}
template <typename T>
void BM_std_equal_benchmark(benchmark::State& state) {
std::vector<T> xs(state.range(0), T(0));
std::vector<T> ys = xs;
while (state.KeepRunning()) {
const bool same = std::equal(xs.begin(), xs.end(), ys.begin());
benchmark::DoNotOptimize(same);
}
}
template <typename T>
void BM_memcmp_benchmark(benchmark::State& state) {
std::vector<T> xs(state.range(0), T(0));
std::vector<T> ys = xs;
while (state.KeepRunning()) {
const bool same =
std::memcmp(xs.data(), ys.data(), xs.size() * sizeof(T)) == 0;
benchmark::DoNotOptimize(same);
}
}
// The expectation is that the compiler should be able to elide the equality
// comparison altogether for sufficiently simple types.
template <typename T>
void BM_absl_equal_self_benchmark(benchmark::State& state) {
std::vector<T> xs(state.range(0), T(0));
while (state.KeepRunning()) {
const bool same = absl::equal(xs.begin(), xs.end(), xs.begin(), xs.end());
benchmark::DoNotOptimize(same);
}
}
BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint8_t)
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint8_t)
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint8_t)
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint8_t)
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint16_t)
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint16_t)
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint16_t)
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint16_t)
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint32_t)
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint32_t)
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint32_t)
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint32_t)
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint64_t)
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint64_t)
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint64_t)
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint64_t)
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, EightBits)
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
BENCHMARK_TEMPLATE(BM_std_equal_benchmark, EightBits)
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
BENCHMARK_TEMPLATE(BM_memcmp_benchmark, EightBits)
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, EightBits)
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
} // namespace

View File

@ -1,421 +0,0 @@
#
# Copyright 2017 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
#
# http://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(
"//absl:copts.bzl",
"ABSL_DEFAULT_COPTS",
"ABSL_TEST_COPTS",
"ABSL_EXCEPTIONS_FLAG",
)
package(default_visibility = ["//visibility:public"])
licenses(["notice"]) # Apache 2.0
cc_library(
name = "spinlock_wait",
srcs = [
"internal/spinlock_akaros.inc",
"internal/spinlock_posix.inc",
"internal/spinlock_wait.cc",
"internal/spinlock_win32.inc",
],
hdrs = [
"internal/scheduling_mode.h",
"internal/spinlock_wait.h",
],
copts = ABSL_DEFAULT_COPTS,
visibility = [
"//absl/base:__pkg__",
],
deps = [":core_headers"],
)
cc_library(
name = "config",
hdrs = [
"config.h",
"policy_checks.h",
],
copts = ABSL_DEFAULT_COPTS,
)
cc_library(
name = "dynamic_annotations",
srcs = ["dynamic_annotations.cc"],
hdrs = ["dynamic_annotations.h"],
copts = ABSL_DEFAULT_COPTS,
defines = ["__CLANG_SUPPORT_DYN_ANNOTATION__"],
)
cc_library(
name = "core_headers",
hdrs = [
"attributes.h",
"macros.h",
"optimization.h",
"port.h",
"thread_annotations.h",
],
copts = ABSL_DEFAULT_COPTS,
deps = [
":config",
":dynamic_annotations",
],
)
cc_library(
name = "malloc_internal",
srcs = [
"internal/low_level_alloc.cc",
],
hdrs = [
"internal/direct_mmap.h",
"internal/low_level_alloc.h",
],
copts = ABSL_DEFAULT_COPTS,
visibility = [
"//absl:__subpackages__",
],
deps = [
":base",
":config",
":core_headers",
":dynamic_annotations",
":spinlock_wait",
],
)
cc_library(
name = "base_internal",
hdrs = [
"internal/hide_ptr.h",
"internal/identity.h",
"internal/inline_variable.h",
"internal/invoke.h",
],
copts = ABSL_DEFAULT_COPTS,
visibility = [
"//absl:__subpackages__",
],
)
cc_library(
name = "base",
srcs = [
"internal/cycleclock.cc",
"internal/raw_logging.cc",
"internal/spinlock.cc",
"internal/sysinfo.cc",
"internal/thread_identity.cc",
"internal/unscaledcycleclock.cc",
],
hdrs = [
"call_once.h",
"casts.h",
"internal/atomic_hook.h",
"internal/cycleclock.h",
"internal/low_level_scheduling.h",
"internal/per_thread_tls.h",
"internal/raw_logging.h",
"internal/spinlock.h",
"internal/sysinfo.h",
"internal/thread_identity.h",
"internal/tsan_mutex_interface.h",
"internal/unscaledcycleclock.h",
"log_severity.h",
],
copts = ABSL_DEFAULT_COPTS,
deps = [
":base_internal",
":config",
":core_headers",
":dynamic_annotations",
":spinlock_wait",
],
)
cc_test(
name = "atomic_hook_test",
size = "small",
srcs = ["internal/atomic_hook_test.cc"],
copts = ABSL_TEST_COPTS,
deps = [
":base",
":core_headers",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "bit_cast_test",
size = "small",
srcs = [
"bit_cast_test.cc",
],
copts = ABSL_TEST_COPTS,
deps = [
":base",
":core_headers",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "throw_delegate",
srcs = ["internal/throw_delegate.cc"],
hdrs = ["internal/throw_delegate.h"],
copts = ABSL_DEFAULT_COPTS + ABSL_EXCEPTIONS_FLAG,
visibility = [
"//absl:__subpackages__",
],
deps = [
":base",
":config",
":core_headers",
],
)
cc_test(
name = "throw_delegate_test",
srcs = ["throw_delegate_test.cc"],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
deps = [
":throw_delegate",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "exception_testing",
testonly = 1,
hdrs = ["internal/exception_testing.h"],
copts = ABSL_TEST_COPTS,
visibility = [
"//absl:__subpackages__",
],
deps = [
":config",
"@com_google_googletest//:gtest",
],
)
cc_library(
name = "pretty_function",
hdrs = ["internal/pretty_function.h"],
visibility = ["//absl:__subpackages__"],
)
cc_library(
name = "exception_safety_testing",
testonly = 1,
srcs = ["internal/exception_safety_testing.cc"],
hdrs = ["internal/exception_safety_testing.h"],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
deps = [
":base",
":config",
":pretty_function",
"//absl/memory",
"//absl/meta:type_traits",
"//absl/strings",
"//absl/types:optional",
"@com_google_googletest//:gtest",
],
)
cc_test(
name = "exception_safety_testing_test",
srcs = ["exception_safety_testing_test.cc"],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
deps = [
":exception_safety_testing",
"//absl/memory",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "inline_variable_test",
size = "small",
srcs = [
"inline_variable_test.cc",
"inline_variable_test_a.cc",
"inline_variable_test_b.cc",
"internal/inline_variable_testing.h",
],
copts = ABSL_TEST_COPTS,
deps = [
":base_internal",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "invoke_test",
size = "small",
srcs = ["invoke_test.cc"],
copts = ABSL_TEST_COPTS,
deps = [
":base_internal",
"//absl/memory",
"//absl/strings",
"@com_google_googletest//:gtest_main",
],
)
# Common test library made available for use in non-absl code that overrides
# AbslInternalSpinLockDelay and AbslInternalSpinLockWake.
cc_library(
name = "spinlock_test_common",
testonly = 1,
srcs = ["spinlock_test_common.cc"],
copts = ABSL_TEST_COPTS,
deps = [
":base",
":core_headers",
":spinlock_wait",
"//absl/synchronization",
"@com_google_googletest//:gtest",
],
alwayslink = 1,
)
cc_test(
name = "spinlock_test",
size = "medium",
srcs = ["spinlock_test_common.cc"],
copts = ABSL_TEST_COPTS,
deps = [
":base",
":core_headers",
":spinlock_wait",
"//absl/synchronization",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "endian",
hdrs = [
"internal/endian.h",
"internal/unaligned_access.h",
],
copts = ABSL_DEFAULT_COPTS,
deps = [
":config",
":core_headers",
],
)
cc_test(
name = "endian_test",
srcs = ["internal/endian_test.cc"],
copts = ABSL_TEST_COPTS,
deps = [
":base",
":config",
":endian",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "config_test",
srcs = ["config_test.cc"],
copts = ABSL_TEST_COPTS,
deps = [
":config",
"//absl/synchronization:thread_pool",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "call_once_test",
srcs = ["call_once_test.cc"],
copts = ABSL_TEST_COPTS,
deps = [
":base",
":core_headers",
"//absl/synchronization",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "raw_logging_test",
srcs = ["raw_logging_test.cc"],
copts = ABSL_TEST_COPTS,
deps = [
":base",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "sysinfo_test",
size = "small",
srcs = ["internal/sysinfo_test.cc"],
copts = ABSL_TEST_COPTS,
deps = [
":base",
"//absl/synchronization",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "low_level_alloc_test",
size = "small",
srcs = ["internal/low_level_alloc_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = select({
"//absl:windows": [],
"//conditions:default": ["-pthread"],
}),
deps = [":malloc_internal"],
)
cc_test(
name = "thread_identity_test",
size = "small",
srcs = ["internal/thread_identity_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = select({
"//absl:windows": [],
"//conditions:default": ["-pthread"],
}),
deps = [
":base",
":core_headers",
"//absl/synchronization",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "thread_identity_benchmark",
srcs = ["internal/thread_identity_benchmark.cc"],
copts = ABSL_TEST_COPTS,
tags = ["benchmark"],
visibility = ["//visibility:private"],
deps = [
":base",
"//absl/synchronization",
"@com_github_google_benchmark//:benchmark_main",
],
)

View File

@ -1,297 +0,0 @@
# Copyright 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build_overrides/build.gni")
if (build_with_chromium) {
visibility = [
"//third_party/webrtc/*",
"//third_party/abseil-cpp/*",
]
} else {
visibility = [ "*" ]
}
source_set("spinlock_wait") {
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
"//build/config/compiler:no_chromium_code",
"//third_party/abseil-cpp:absl_default_cflags_cc",
]
public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
sources = [
"internal/spinlock_akaros.inc",
"internal/spinlock_posix.inc",
"internal/spinlock_wait.cc",
"internal/spinlock_win32.inc",
]
public = [
"internal/scheduling_mode.h",
"internal/spinlock_wait.h",
]
deps = [
":core_headers",
]
visibility = []
visibility += [ "../base:*" ]
}
source_set("config") {
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
"//build/config/compiler:no_chromium_code",
"//third_party/abseil-cpp:absl_default_cflags_cc",
]
public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
public = [
"config.h",
"policy_checks.h",
]
}
config("clang_support_dynamic_annotations") {
cflags_cc = [ "-D__CLANG_SUPPORT_DYN_ANNOTATION__" ]
}
source_set("dynamic_annotations") {
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
"//build/config/compiler:no_chromium_code",
"//third_party/abseil-cpp:absl_default_cflags_cc",
]
public_configs = [
":clang_support_dynamic_annotations",
"//third_party/abseil-cpp:absl_include_config",
]
sources = [
"dynamic_annotations.cc",
]
public = [
"dynamic_annotations.h",
]
# Abseil's dynamic annotations are only visible inside Abseil because
# their usage is deprecated in Chromium (see README.chromium for more info).
visibility = []
visibility = [ "../*" ]
}
source_set("core_headers") {
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
"//build/config/compiler:no_chromium_code",
"//third_party/abseil-cpp:absl_default_cflags_cc",
]
public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
public = [
"attributes.h",
"macros.h",
"optimization.h",
"port.h",
"thread_annotations.h",
]
deps = [
":config",
":dynamic_annotations",
]
}
source_set("malloc_internal") {
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
"//build/config/compiler:no_chromium_code",
"//third_party/abseil-cpp:absl_default_cflags_cc",
]
public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
sources = [
"internal/low_level_alloc.cc",
]
public = [
"internal/direct_mmap.h",
"internal/low_level_alloc.h",
]
deps = [
":base",
":config",
":core_headers",
":dynamic_annotations",
":spinlock_wait",
]
visibility = []
visibility += [ "../*" ]
}
source_set("base_internal") {
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
"//build/config/compiler:no_chromium_code",
"//third_party/abseil-cpp:absl_default_cflags_cc",
]
public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
public = [
"internal/hide_ptr.h",
"internal/identity.h",
"internal/inline_variable.h",
"internal/invoke.h",
]
visibility = []
visibility += [ "../*" ]
}
source_set("base") {
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
"//build/config/compiler:no_chromium_code",
"//third_party/abseil-cpp:absl_default_cflags_cc",
]
public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
sources = [
"internal/cycleclock.cc",
"internal/raw_logging.cc",
"internal/spinlock.cc",
"internal/sysinfo.cc",
"internal/thread_identity.cc",
"internal/unscaledcycleclock.cc",
]
public = [
"call_once.h",
"casts.h",
"internal/atomic_hook.h",
"internal/cycleclock.h",
"internal/low_level_scheduling.h",
"internal/per_thread_tls.h",
"internal/raw_logging.h",
"internal/spinlock.h",
"internal/sysinfo.h",
"internal/thread_identity.h",
"internal/tsan_mutex_interface.h",
"internal/unscaledcycleclock.h",
"log_severity.h",
]
deps = [
":base_internal",
":config",
":core_headers",
":dynamic_annotations",
":spinlock_wait",
]
}
source_set("throw_delegate") {
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
"//build/config/compiler:no_chromium_code",
"//third_party/abseil-cpp:absl_default_cflags_cc",
]
public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
sources = [
"internal/throw_delegate.cc",
]
public = [
"internal/throw_delegate.h",
]
deps = [
":base",
":config",
":core_headers",
]
visibility = []
visibility += [ "../*" ]
}
source_set("exception_testing") {
testonly = true
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
"//build/config/compiler:no_chromium_code",
"//third_party/abseil-cpp:absl_test_cflags_cc",
]
public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
public = [
"internal/exception_testing.h",
]
deps = [
":config",
]
visibility = []
visibility += [ "../*" ]
}
source_set("pretty_function") {
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
"//build/config/compiler:no_chromium_code",
"//third_party/abseil-cpp:absl_default_cflags_cc",
]
public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
public = [
"internal/pretty_function.h",
]
visibility = []
visibility += [ "../*" ]
}
# TODO(mbonadei): This target throws by design. We should probably
# just remove it.
# source_set("exception_safety_testing") {
# testonly = true
# configs -= [ "//build/config/compiler:chromium_code" ]
# configs += [
# "//build/config/compiler:no_chromium_code",
# "//third_party/abseil-cpp:absl_test_cflags_cc",
# ]
# public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
# sources = [
# "internal/exception_safety_testing.cc",
# ]
# public = [
# "internal/exception_safety_testing.h",
# ]
# deps = [
# ":base",
# ":config",
# ":pretty_function",
# "../memory",
# "../meta:type_traits",
# "../strings",
# "../types:optional",
# "//testing/gtest",
# ]
# }
source_set("spinlock_test_common") {
testonly = true
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
"//build/config/compiler:no_chromium_code",
"//third_party/abseil-cpp:absl_test_cflags_cc",
]
public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
sources = [
"spinlock_test_common.cc",
]
deps = [
":base",
":core_headers",
":spinlock_wait",
"../synchronization",
"//testing/gtest",
]
}
source_set("endian") {
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [
"//build/config/compiler:no_chromium_code",
"//third_party/abseil-cpp:absl_default_cflags_cc",
]
public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
public = [
"internal/endian.h",
"internal/unaligned_access.h",
]
deps = [
":config",
":core_headers",
]
}

View File

@ -1,386 +0,0 @@
#
# Copyright 2017 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
#
# http://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.
#
list(APPEND BASE_PUBLIC_HEADERS
"attributes.h"
"call_once.h"
"casts.h"
"config.h"
"dynamic_annotations.h"
"log_severity.h"
"macros.h"
"optimization.h"
"policy_checks.h"
"port.h"
"thread_annotations.h"
)
list(APPEND BASE_INTERNAL_HEADERS
"internal/atomic_hook.h"
"internal/cycleclock.h"
"internal/direct_mmap.h"
"internal/endian.h"
"internal/exception_testing.h"
"internal/exception_safety_testing.h"
"internal/hide_ptr.h"
"internal/identity.h"
"internal/invoke.h"
"internal/inline_variable.h"
"internal/low_level_alloc.h"
"internal/low_level_scheduling.h"
"internal/per_thread_tls.h"
"internal/pretty_function.h"
"internal/raw_logging.h"
"internal/scheduling_mode.h"
"internal/spinlock.h"
"internal/spinlock_wait.h"
"internal/sysinfo.h"
"internal/thread_identity.h"
"internal/throw_delegate.h"
"internal/tsan_mutex_interface.h"
"internal/unaligned_access.h"
"internal/unscaledcycleclock.h"
)
# absl_base main library
list(APPEND BASE_SRC
"internal/cycleclock.cc"
"internal/raw_logging.cc"
"internal/spinlock.cc"
"internal/sysinfo.cc"
"internal/thread_identity.cc"
"internal/unscaledcycleclock.cc"
"internal/low_level_alloc.cc"
${BASE_PUBLIC_HEADERS}
${BASE_INTERNAL_HEADERS}
)
absl_library(
TARGET
absl_base
SOURCES
${BASE_SRC}
PUBLIC_LIBRARIES
absl_dynamic_annotations
absl_spinlock_wait
EXPORT_NAME
base
)
# throw delegate library
set(THROW_DELEGATE_SRC "internal/throw_delegate.cc")
absl_library(
TARGET
absl_throw_delegate
SOURCES
${THROW_DELEGATE_SRC}
PUBLIC_LIBRARIES
${THROW_DELEGATE_PUBLIC_LIBRARIES}
PRIVATE_COMPILE_FLAGS
${ABSL_EXCEPTIONS_FLAG}
EXPORT_NAME
throw_delegate
)
if(BUILD_TESTING)
# exception-safety testing library
set(EXCEPTION_SAFETY_TESTING_SRC
"internal/exception_safety_testing.h"
"internal/exception_safety_testing.cc"
)
set(EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES
${ABSL_TEST_COMMON_LIBRARIES}
absl::base
absl::memory
absl::meta
absl::strings
absl::optional
gtest
)
absl_library(
TARGET
absl_base_internal_exception_safety_testing
SOURCES
${EXCEPTION_SAFETY_TESTING_SRC}
PUBLIC_LIBRARIES
${EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES}
PRIVATE_COMPILE_FLAGS
${ABSL_EXCEPTIONS_FLAG}
)
endif()
# dynamic_annotations library
set(DYNAMIC_ANNOTATIONS_SRC "dynamic_annotations.cc")
absl_library(
TARGET
absl_dynamic_annotations
SOURCES
${DYNAMIC_ANNOTATIONS_SRC}
)
# spinlock_wait library
set(SPINLOCK_WAIT_SRC "internal/spinlock_wait.cc")
absl_library(
TARGET
absl_spinlock_wait
SOURCES
${SPINLOCK_WAIT_SRC}
)
# malloc_internal library
list(APPEND MALLOC_INTERNAL_SRC
"internal/low_level_alloc.cc"
)
absl_library(
TARGET
absl_malloc_internal
SOURCES
${MALLOC_INTERNAL_SRC}
PUBLIC_LIBRARIES
absl_dynamic_annotations
)
#
## TESTS
#
# call once test
set(ATOMIC_HOOK_TEST_SRC "internal/atomic_hook_test.cc")
set(ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES absl::base)
absl_test(
TARGET
atomic_hook_test
SOURCES
${ATOMIC_HOOK_TEST_SRC}
PUBLIC_LIBRARIES
${ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES}
)
# call once test
set(CALL_ONCE_TEST_SRC "call_once_test.cc")
set(CALL_ONCE_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
absl_test(
TARGET
call_once_test
SOURCES
${CALL_ONCE_TEST_SRC}
PUBLIC_LIBRARIES
${CALL_ONCE_TEST_PUBLIC_LIBRARIES}
)
# test bit_cast_test
set(BIT_CAST_TEST_SRC "bit_cast_test.cc")
absl_test(
TARGET
bit_cast_test
SOURCES
${BIT_CAST_TEST_SRC}
)
# test absl_throw_delegate_test
set(THROW_DELEGATE_TEST_SRC "throw_delegate_test.cc")
set(THROW_DELEGATE_TEST_PUBLIC_LIBRARIES absl::base absl_throw_delegate)
absl_test(
TARGET
throw_delegate_test
SOURCES
${THROW_DELEGATE_TEST_SRC}
PUBLIC_LIBRARIES
${THROW_DELEGATE_TEST_PUBLIC_LIBRARIES}
)
# test invoke_test
set(INVOKE_TEST_SRC "invoke_test.cc")
set(INVOKE_TEST_PUBLIC_LIBRARIES absl::strings)
absl_test(
TARGET
invoke_test
SOURCES
${INVOKE_TEST_SRC}
PUBLIC_LIBRARIES
${INVOKE_TEST_PUBLIC_LIBRARIES}
)
# test inline_variable_test
list(APPEND INLINE_VARIABLE_TEST_SRC
"internal/inline_variable_testing.h"
"inline_variable_test.cc"
"inline_variable_test_a.cc"
"inline_variable_test_b.cc"
)
set(INLINE_VARIABLE_TEST_PUBLIC_LIBRARIES absl::base)
absl_test(
TARGET
inline_variable_test
SOURCES
${INLINE_VARIABLE_TEST_SRC}
PUBLIC_LIBRARIES
${INLINE_VARIABLE_TEST_PUBLIC_LIBRARIES}
)
# test spinlock_test_common
set(SPINLOCK_TEST_COMMON_SRC "spinlock_test_common.cc")
set(SPINLOCK_TEST_COMMON_PUBLIC_LIBRARIES absl::base absl::synchronization)
absl_test(
TARGET
spinlock_test_common
SOURCES
${SPINLOCK_TEST_COMMON_SRC}
PUBLIC_LIBRARIES
${SPINLOCK_TEST_COMMON_PUBLIC_LIBRARIES}
)
# test spinlock_test
set(SPINLOCK_TEST_SRC "spinlock_test_common.cc")
set(SPINLOCK_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
absl_test(
TARGET
spinlock_test
SOURCES
${SPINLOCK_TEST_SRC}
PUBLIC_LIBRARIES
${SPINLOCK_TEST_PUBLIC_LIBRARIES}
)
# test endian_test
set(ENDIAN_TEST_SRC "internal/endian_test.cc")
absl_test(
TARGET
endian_test
SOURCES
${ENDIAN_TEST_SRC}
)
# test config_test
set(CONFIG_TEST_SRC "config_test.cc")
set(CONFIG_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
absl_test(
TARGET
config_test
SOURCES
${CONFIG_TEST_SRC}
PUBLIC_LIBRARIES
${CONFIG_TEST_PUBLIC_LIBRARIES}
)
# test raw_logging_test
set(RAW_LOGGING_TEST_SRC "raw_logging_test.cc")
set(RAW_LOGGING_TEST_PUBLIC_LIBRARIES absl::base)
absl_test(
TARGET
raw_logging_test
SOURCES
${RAW_LOGGING_TEST_SRC}
PUBLIC_LIBRARIES
${RAW_LOGGING_TEST_PUBLIC_LIBRARIES}
)
# test sysinfo_test
set(SYSINFO_TEST_SRC "internal/sysinfo_test.cc")
set(SYSINFO_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
absl_test(
TARGET
sysinfo_test
SOURCES
${SYSINFO_TEST_SRC}
PUBLIC_LIBRARIES
${SYSINFO_TEST_PUBLIC_LIBRARIES}
)
# test low_level_alloc_test
set(LOW_LEVEL_ALLOC_TEST_SRC "internal/low_level_alloc_test.cc")
set(LOW_LEVEL_ALLOC_TEST_PUBLIC_LIBRARIES absl::base)
absl_test(
TARGET
low_level_alloc_test
SOURCES
${LOW_LEVEL_ALLOC_TEST_SRC}
PUBLIC_LIBRARIES
${LOW_LEVEL_ALLOC_TEST_PUBLIC_LIBRARIES}
)
# test thread_identity_test
set(THREAD_IDENTITY_TEST_SRC "internal/thread_identity_test.cc")
set(THREAD_IDENTITY_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
absl_test(
TARGET
thread_identity_test
SOURCES
${THREAD_IDENTITY_TEST_SRC}
PUBLIC_LIBRARIES
${THREAD_IDENTITY_TEST_PUBLIC_LIBRARIES}
)
#test exceptions_safety_testing_test
set(EXCEPTION_SAFETY_TESTING_TEST_SRC "exception_safety_testing_test.cc")
set(EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES
absl::base
absl_base_internal_exception_safety_testing
absl::memory
absl::meta
absl::strings
absl::optional
)
absl_test(
TARGET
absl_exception_safety_testing_test
SOURCES
${EXCEPTION_SAFETY_TESTING_TEST_SRC}
PUBLIC_LIBRARIES
${EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES}
PRIVATE_COMPILE_FLAGS
${ABSL_EXCEPTIONS_FLAG}
)

View File

@ -1,568 +0,0 @@
// Copyright 2017 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
//
// http://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.
//
// This header file defines macros for declaring attributes for functions,
// types, and variables.
//
// These macros are used within Abseil and allow the compiler to optimize, where
// applicable, certain function calls.
//
// This file is used for both C and C++!
//
// Most macros here are exposing GCC or Clang features, and are stubbed out for
// other compilers.
//
// GCC attributes documentation:
// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html
// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Variable-Attributes.html
// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Type-Attributes.html
//
// Most attributes in this file are already supported by GCC 4.7. However, some
// of them are not supported in older version of Clang. Thus, we check
// `__has_attribute()` first. If the check fails, we check if we are on GCC and
// assume the attribute exists on GCC (which is verified on GCC 4.7).
//
// -----------------------------------------------------------------------------
// Sanitizer Attributes
// -----------------------------------------------------------------------------
//
// Sanitizer-related attributes are not "defined" in this file (and indeed
// are not defined as such in any file). To utilize the following
// sanitizer-related attributes within your builds, define the following macros
// within your build using a `-D` flag, along with the given value for
// `-fsanitize`:
//
// * `ADDRESS_SANITIZER` + `-fsanitize=address` (Clang, GCC 4.8)
// * `MEMORY_SANITIZER` + `-fsanitize=memory` (Clang-only)
// * `THREAD_SANITIZER + `-fsanitize=thread` (Clang, GCC 4.8+)
// * `UNDEFINED_BEHAVIOR_SANITIZER` + `-fsanitize=undefined` (Clang, GCC 4.9+)
// * `CONTROL_FLOW_INTEGRITY` + -fsanitize=cfi (Clang-only)
//
// Example:
//
// // Enable branches in the Abseil code that are tagged for ASan:
// $ bazel build --copt=-DADDRESS_SANITIZER --copt=-fsanitize=address
// --linkopt=-fsanitize=address *target*
//
// Since these macro names are only supported by GCC and Clang, we only check
// for `__GNUC__` (GCC or Clang) and the above macros.
#ifndef ABSL_BASE_ATTRIBUTES_H_
#define ABSL_BASE_ATTRIBUTES_H_
// ABSL_HAVE_ATTRIBUTE
//
// A function-like feature checking macro that is a wrapper around
// `__has_attribute`, which is defined by GCC 5+ and Clang and evaluates to a
// nonzero constant integer if the attribute is supported or 0 if not.
//
// It evaluates to zero if `__has_attribute` is not defined by the compiler.
//
// GCC: https://gcc.gnu.org/gcc-5/changes.html
// Clang: https://clang.llvm.org/docs/LanguageExtensions.html
#ifdef __has_attribute
#define ABSL_HAVE_ATTRIBUTE(x) __has_attribute(x)
#else
#define ABSL_HAVE_ATTRIBUTE(x) 0
#endif
// ABSL_HAVE_CPP_ATTRIBUTE
//
// A function-like feature checking macro that accepts C++11 style attributes.
// It's a wrapper around `__has_cpp_attribute`, defined by ISO C++ SD-6
// (http://en.cppreference.com/w/cpp/experimental/feature_test). If we don't
// find `__has_cpp_attribute`, will evaluate to 0.
#if defined(__cplusplus) && defined(__has_cpp_attribute)
// NOTE: requiring __cplusplus above should not be necessary, but
// works around https://bugs.llvm.org/show_bug.cgi?id=23435.
#define ABSL_HAVE_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
#else
#define ABSL_HAVE_CPP_ATTRIBUTE(x) 0
#endif
// -----------------------------------------------------------------------------
// Function Attributes
// -----------------------------------------------------------------------------
//
// GCC: https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
// Clang: https://clang.llvm.org/docs/AttributeReference.html
// ABSL_PRINTF_ATTRIBUTE
// ABSL_SCANF_ATTRIBUTE
//
// Tells the compiler to perform `printf` format std::string checking if the
// compiler supports it; see the 'format' attribute in
// <http://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html>.
//
// Note: As the GCC manual states, "[s]ince non-static C++ methods
// have an implicit 'this' argument, the arguments of such methods
// should be counted from two, not one."
#if ABSL_HAVE_ATTRIBUTE(format) || (defined(__GNUC__) && !defined(__clang__))
#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check) \
__attribute__((__format__(__printf__, string_index, first_to_check)))
#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check) \
__attribute__((__format__(__scanf__, string_index, first_to_check)))
#else
#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check)
#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check)
#endif
// ABSL_ATTRIBUTE_ALWAYS_INLINE
// ABSL_ATTRIBUTE_NOINLINE
//
// Forces functions to either inline or not inline. Introduced in gcc 3.1.
#if ABSL_HAVE_ATTRIBUTE(always_inline) || \
(defined(__GNUC__) && !defined(__clang__))
#define ABSL_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline))
#define ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE 1
#else
#define ABSL_ATTRIBUTE_ALWAYS_INLINE
#endif
#if ABSL_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__))
#define ABSL_ATTRIBUTE_NOINLINE __attribute__((noinline))
#define ABSL_HAVE_ATTRIBUTE_NOINLINE 1
#else
#define ABSL_ATTRIBUTE_NOINLINE
#endif
// ABSL_ATTRIBUTE_NO_TAIL_CALL
//
// Prevents the compiler from optimizing away stack frames for functions which
// end in a call to another function.
#if ABSL_HAVE_ATTRIBUTE(disable_tail_calls)
#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
#define ABSL_ATTRIBUTE_NO_TAIL_CALL __attribute__((disable_tail_calls))
#elif defined(__GNUC__) && !defined(__clang__)
#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
#define ABSL_ATTRIBUTE_NO_TAIL_CALL \
__attribute__((optimize("no-optimize-sibling-calls")))
#else
#define ABSL_ATTRIBUTE_NO_TAIL_CALL
#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 0
#endif
// ABSL_ATTRIBUTE_WEAK
//
// Tags a function as weak for the purposes of compilation and linking.
#if ABSL_HAVE_ATTRIBUTE(weak) || (defined(__GNUC__) && !defined(__clang__))
#undef ABSL_ATTRIBUTE_WEAK
#define ABSL_ATTRIBUTE_WEAK __attribute__((weak))
#define ABSL_HAVE_ATTRIBUTE_WEAK 1
#else
#define ABSL_ATTRIBUTE_WEAK
#define ABSL_HAVE_ATTRIBUTE_WEAK 0
#endif
// ABSL_ATTRIBUTE_NONNULL
//
// Tells the compiler either (a) that a particular function parameter
// should be a non-null pointer, or (b) that all pointer arguments should
// be non-null.
//
// Note: As the GCC manual states, "[s]ince non-static C++ methods
// have an implicit 'this' argument, the arguments of such methods
// should be counted from two, not one."
//
// Args are indexed starting at 1.
//
// For non-static class member functions, the implicit `this` argument
// is arg 1, and the first explicit argument is arg 2. For static class member
// functions, there is no implicit `this`, and the first explicit argument is
// arg 1.
//
// Example:
//
// /* arg_a cannot be null, but arg_b can */
// void Function(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(1);
//
// class C {
// /* arg_a cannot be null, but arg_b can */
// void Method(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(2);
//
// /* arg_a cannot be null, but arg_b can */
// static void StaticMethod(void* arg_a, void* arg_b)
// ABSL_ATTRIBUTE_NONNULL(1);
// };
//
// If no arguments are provided, then all pointer arguments should be non-null.
//
// /* No pointer arguments may be null. */
// void Function(void* arg_a, void* arg_b, int arg_c) ABSL_ATTRIBUTE_NONNULL();
//
// NOTE: The GCC nonnull attribute actually accepts a list of arguments, but
// ABSL_ATTRIBUTE_NONNULL does not.
#if ABSL_HAVE_ATTRIBUTE(nonnull) || (defined(__GNUC__) && !defined(__clang__))
#define ABSL_ATTRIBUTE_NONNULL(arg_index) __attribute__((nonnull(arg_index)))
#else
#define ABSL_ATTRIBUTE_NONNULL(...)
#endif
// ABSL_ATTRIBUTE_NORETURN
//
// Tells the compiler that a given function never returns.
#if ABSL_HAVE_ATTRIBUTE(noreturn) || (defined(__GNUC__) && !defined(__clang__))
#define ABSL_ATTRIBUTE_NORETURN __attribute__((noreturn))
#elif defined(_MSC_VER)
#define ABSL_ATTRIBUTE_NORETURN __declspec(noreturn)
#else
#define ABSL_ATTRIBUTE_NORETURN
#endif
// ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
//
// Tells the AddressSanitizer (or other memory testing tools) to ignore a given
// function. Useful for cases when a function reads random locations on stack,
// calls _exit from a cloned subprocess, deliberately accesses buffer
// out of bounds or does other scary things with memory.
// NOTE: GCC supports AddressSanitizer(asan) since 4.8.
// https://gcc.gnu.org/gcc-4.8/changes.html
#if defined(__GNUC__) && defined(ADDRESS_SANITIZER)
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
#else
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
#endif
// ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
//
// Tells the MemorySanitizer to relax the handling of a given function. All
// "Use of uninitialized value" warnings from such functions will be suppressed,
// and all values loaded from memory will be considered fully initialized.
// This attribute is similar to the ADDRESS_SANITIZER attribute above, but deals
// with initialized-ness rather than addressability issues.
// NOTE: MemorySanitizer(msan) is supported by Clang but not GCC.
#if defined(__GNUC__) && defined(MEMORY_SANITIZER)
#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
#else
#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
#endif
// ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
//
// Tells the ThreadSanitizer to not instrument a given function.
// NOTE: GCC supports ThreadSanitizer(tsan) since 4.8.
// https://gcc.gnu.org/gcc-4.8/changes.html
#if defined(__GNUC__) && defined(THREAD_SANITIZER)
#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
#else
#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
#endif
// ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED
//
// Tells the UndefinedSanitizer to ignore a given function. Useful for cases
// where certain behavior (eg. division by zero) is being used intentionally.
// NOTE: GCC supports UndefinedBehaviorSanitizer(ubsan) since 4.9.
// https://gcc.gnu.org/gcc-4.9/changes.html
#if defined(__GNUC__) && \
(defined(UNDEFINED_BEHAVIOR_SANITIZER) || defined(ADDRESS_SANITIZER))
#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
__attribute__((no_sanitize("undefined")))
#else
#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED
#endif
// ABSL_ATTRIBUTE_NO_SANITIZE_CFI
//
// Tells the ControlFlowIntegrity sanitizer to not instrument a given function.
// See https://clang.llvm.org/docs/ControlFlowIntegrity.html for details.
#if defined(__GNUC__) && defined(CONTROL_FLOW_INTEGRITY)
#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi")))
#else
#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI
#endif
// ABSL_ATTRIBUTE_RETURNS_NONNULL
//
// Tells the compiler that a particular function never returns a null pointer.
#if ABSL_HAVE_ATTRIBUTE(returns_nonnull) || \
(defined(__GNUC__) && \
(__GNUC__ > 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) && \
!defined(__clang__))
#define ABSL_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
#else
#define ABSL_ATTRIBUTE_RETURNS_NONNULL
#endif
// ABSL_HAVE_ATTRIBUTE_SECTION
//
// Indicates whether labeled sections are supported. Labeled sections are not
// supported on Darwin/iOS.
#ifdef ABSL_HAVE_ATTRIBUTE_SECTION
#error ABSL_HAVE_ATTRIBUTE_SECTION cannot be directly set
#elif (ABSL_HAVE_ATTRIBUTE(section) || \
(defined(__GNUC__) && !defined(__clang__))) && \
!defined(__APPLE__)
#define ABSL_HAVE_ATTRIBUTE_SECTION 1
// ABSL_ATTRIBUTE_SECTION
//
// Tells the compiler/linker to put a given function into a section and define
// `__start_ ## name` and `__stop_ ## name` symbols to bracket the section.
// This functionality is supported by GNU linker. Any function annotated with
// `ABSL_ATTRIBUTE_SECTION` must not be inlined, or it will be placed into
// whatever section its caller is placed into.
//
#ifndef ABSL_ATTRIBUTE_SECTION
#define ABSL_ATTRIBUTE_SECTION(name) \
__attribute__((section(#name))) __attribute__((noinline))
#endif
// ABSL_ATTRIBUTE_SECTION_VARIABLE
//
// Tells the compiler/linker to put a given variable into a section and define
// `__start_ ## name` and `__stop_ ## name` symbols to bracket the section.
// This functionality is supported by GNU linker.
#ifndef ABSL_ATTRIBUTE_SECTION_VARIABLE
#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name) __attribute__((section(#name)))
#endif
// ABSL_DECLARE_ATTRIBUTE_SECTION_VARS
//
// A weak section declaration to be used as a global declaration
// for ABSL_ATTRIBUTE_SECTION_START|STOP(name) to compile and link
// even without functions with ABSL_ATTRIBUTE_SECTION(name).
// ABSL_DEFINE_ATTRIBUTE_SECTION should be in the exactly one file; it's
// a no-op on ELF but not on Mach-O.
//
#ifndef ABSL_DECLARE_ATTRIBUTE_SECTION_VARS
#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) \
extern char __start_##name[] ABSL_ATTRIBUTE_WEAK; \
extern char __stop_##name[] ABSL_ATTRIBUTE_WEAK
#endif
#ifndef ABSL_DEFINE_ATTRIBUTE_SECTION_VARS
#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name)
#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name)
#endif
// ABSL_ATTRIBUTE_SECTION_START
//
// Returns `void*` pointers to start/end of a section of code with
// functions having ABSL_ATTRIBUTE_SECTION(name).
// Returns 0 if no such functions exist.
// One must ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) for this to compile and
// link.
//
#define ABSL_ATTRIBUTE_SECTION_START(name) \
(reinterpret_cast<void *>(__start_##name))
#define ABSL_ATTRIBUTE_SECTION_STOP(name) \
(reinterpret_cast<void *>(__stop_##name))
#else // !ABSL_HAVE_ATTRIBUTE_SECTION
#define ABSL_HAVE_ATTRIBUTE_SECTION 0
// provide dummy definitions
#define ABSL_ATTRIBUTE_SECTION(name)
#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name)
#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name)
#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name)
#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name)
#define ABSL_ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void *>(0))
#define ABSL_ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void *>(0))
#endif // ABSL_ATTRIBUTE_SECTION
// ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
//
// Support for aligning the stack on 32-bit x86.
#if ABSL_HAVE_ATTRIBUTE(force_align_arg_pointer) || \
(defined(__GNUC__) && !defined(__clang__))
#if defined(__i386__)
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC \
__attribute__((force_align_arg_pointer))
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
#elif defined(__x86_64__)
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (1)
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
#else // !__i386__ && !__x86_64
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
#endif // __i386__
#else
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
#endif
// ABSL_MUST_USE_RESULT
//
// Tells the compiler to warn about unused return values for functions declared
// with this macro. The macro must appear as the very first part of a function
// declaration or definition:
//
// Example:
//
// ABSL_MUST_USE_RESULT Sprocket* AllocateSprocket();
//
// This placement has the broadest compatibility with GCC, Clang, and MSVC, with
// both defs and decls, and with GCC-style attributes, MSVC declspec, C++11
// and C++17 attributes.
//
// ABSL_MUST_USE_RESULT allows using cast-to-void to suppress the unused result
// warning. For that, warn_unused_result is used only for clang but not for gcc.
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425
//
// Note: past advice was to place the macro after the argument list.
#if ABSL_HAVE_ATTRIBUTE(nodiscard)
#define ABSL_MUST_USE_RESULT [[nodiscard]]
#elif defined(__clang__) && ABSL_HAVE_ATTRIBUTE(warn_unused_result)
#define ABSL_MUST_USE_RESULT __attribute__((warn_unused_result))
#else
#define ABSL_MUST_USE_RESULT
#endif
// ABSL_ATTRIBUTE_HOT, ABSL_ATTRIBUTE_COLD
//
// Tells GCC that a function is hot or cold. GCC can use this information to
// improve static analysis, i.e. a conditional branch to a cold function
// is likely to be not-taken.
// This annotation is used for function declarations.
//
// Example:
//
// int foo() ABSL_ATTRIBUTE_HOT;
#if ABSL_HAVE_ATTRIBUTE(hot) || (defined(__GNUC__) && !defined(__clang__))
#define ABSL_ATTRIBUTE_HOT __attribute__((hot))
#else
#define ABSL_ATTRIBUTE_HOT
#endif
#if ABSL_HAVE_ATTRIBUTE(cold) || (defined(__GNUC__) && !defined(__clang__))
#define ABSL_ATTRIBUTE_COLD __attribute__((cold))
#else
#define ABSL_ATTRIBUTE_COLD
#endif
// ABSL_XRAY_ALWAYS_INSTRUMENT, ABSL_XRAY_NEVER_INSTRUMENT, ABSL_XRAY_LOG_ARGS
//
// We define the ABSL_XRAY_ALWAYS_INSTRUMENT and ABSL_XRAY_NEVER_INSTRUMENT
// macro used as an attribute to mark functions that must always or never be
// instrumented by XRay. Currently, this is only supported in Clang/LLVM.
//
// For reference on the LLVM XRay instrumentation, see
// http://llvm.org/docs/XRay.html.
//
// A function with the XRAY_ALWAYS_INSTRUMENT macro attribute in its declaration
// will always get the XRay instrumentation sleds. These sleds may introduce
// some binary size and runtime overhead and must be used sparingly.
//
// These attributes only take effect when the following conditions are met:
//
// * The file/target is built in at least C++11 mode, with a Clang compiler
// that supports XRay attributes.
// * The file/target is built with the -fxray-instrument flag set for the
// Clang/LLVM compiler.
// * The function is defined in the translation unit (the compiler honors the
// attribute in either the definition or the declaration, and must match).
//
// There are cases when, even when building with XRay instrumentation, users
// might want to control specifically which functions are instrumented for a
// particular build using special-case lists provided to the compiler. These
// special case lists are provided to Clang via the
// -fxray-always-instrument=... and -fxray-never-instrument=... flags. The
// attributes in source take precedence over these special-case lists.
//
// To disable the XRay attributes at build-time, users may define
// ABSL_NO_XRAY_ATTRIBUTES. Do NOT define ABSL_NO_XRAY_ATTRIBUTES on specific
// packages/targets, as this may lead to conflicting definitions of functions at
// link-time.
//
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_always_instrument) && \
!defined(ABSL_NO_XRAY_ATTRIBUTES)
#define ABSL_XRAY_ALWAYS_INSTRUMENT [[clang::xray_always_instrument]]
#define ABSL_XRAY_NEVER_INSTRUMENT [[clang::xray_never_instrument]]
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_log_args)
#define ABSL_XRAY_LOG_ARGS(N) \
[[clang::xray_always_instrument, clang::xray_log_args(N)]]
#else
#define ABSL_XRAY_LOG_ARGS(N) [[clang::xray_always_instrument]]
#endif
#else
#define ABSL_XRAY_ALWAYS_INSTRUMENT
#define ABSL_XRAY_NEVER_INSTRUMENT
#define ABSL_XRAY_LOG_ARGS(N)
#endif
// -----------------------------------------------------------------------------
// Variable Attributes
// -----------------------------------------------------------------------------
// ABSL_ATTRIBUTE_UNUSED
//
// Prevents the compiler from complaining about or optimizing away variables
// that appear unused.
#if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__))
#undef ABSL_ATTRIBUTE_UNUSED
#define ABSL_ATTRIBUTE_UNUSED __attribute__((__unused__))
#else
#define ABSL_ATTRIBUTE_UNUSED
#endif
// ABSL_ATTRIBUTE_INITIAL_EXEC
//
// Tells the compiler to use "initial-exec" mode for a thread-local variable.
// See http://people.redhat.com/drepper/tls.pdf for the gory details.
#if ABSL_HAVE_ATTRIBUTE(tls_model) || (defined(__GNUC__) && !defined(__clang__))
#define ABSL_ATTRIBUTE_INITIAL_EXEC __attribute__((tls_model("initial-exec")))
#else
#define ABSL_ATTRIBUTE_INITIAL_EXEC
#endif
// ABSL_ATTRIBUTE_PACKED
//
// Prevents the compiler from padding a structure to natural alignment
#if ABSL_HAVE_ATTRIBUTE(packed) || (defined(__GNUC__) && !defined(__clang__))
#define ABSL_ATTRIBUTE_PACKED __attribute__((__packed__))
#else
#define ABSL_ATTRIBUTE_PACKED
#endif
// ABSL_ATTRIBUTE_FUNC_ALIGN
//
// Tells the compiler to align the function start at least to certain
// alignment boundary
#if ABSL_HAVE_ATTRIBUTE(aligned) || (defined(__GNUC__) && !defined(__clang__))
#define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes) __attribute__((aligned(bytes)))
#else
#define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes)
#endif
// ABSL_CONST_INIT
//
// A variable declaration annotated with the `ABSL_CONST_INIT` attribute will
// not compile (on supported platforms) unless the variable has a constant
// initializer. This is useful for variables with static and thread storage
// duration, because it guarantees that they will not suffer from the so-called
// "static init order fiasco". Prefer to put this attribute on the most visible
// declaration of the variable, if there's more than one, because code that
// accesses the variable can then use the attribute for optimization.
//
// Example:
//
// class MyClass {
// public:
// ABSL_CONST_INIT static MyType my_var;
// };
//
// MyType MyClass::my_var = MakeMyType(...);
//
// Note that this attribute is redundant if the variable is declared constexpr.
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
// NOLINTNEXTLINE(whitespace/braces)
#define ABSL_CONST_INIT [[clang::require_constant_initialization]]
#else
#define ABSL_CONST_INIT
#endif // ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
#endif // ABSL_BASE_ATTRIBUTES_H_

View File

@ -1,107 +0,0 @@
// Copyright 2017 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
//
// http://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.
// Unit test for bit_cast template.
#include <cstdint>
#include <cstring>
#include "gtest/gtest.h"
#include "absl/base/casts.h"
#include "absl/base/macros.h"
namespace absl {
namespace {
template <int N>
struct marshall { char buf[N]; };
template <typename T>
void TestMarshall(const T values[], int num_values) {
for (int i = 0; i < num_values; ++i) {
T t0 = values[i];
marshall<sizeof(T)> m0 = absl::bit_cast<marshall<sizeof(T)> >(t0);
T t1 = absl::bit_cast<T>(m0);
marshall<sizeof(T)> m1 = absl::bit_cast<marshall<sizeof(T)> >(t1);
ASSERT_EQ(0, memcmp(&t0, &t1, sizeof(T)));
ASSERT_EQ(0, memcmp(&m0, &m1, sizeof(T)));
}
}
// Convert back and forth to an integral type. The C++ standard does
// not guarantee this will work, but we test that this works on all the
// platforms we support.
//
// Likewise, we below make assumptions about sizeof(float) and
// sizeof(double) which the standard does not guarantee, but which hold on the
// platforms we support.
template <typename T, typename I>
void TestIntegral(const T values[], int num_values) {
for (int i = 0; i < num_values; ++i) {
T t0 = values[i];
I i0 = absl::bit_cast<I>(t0);
T t1 = absl::bit_cast<T>(i0);
I i1 = absl::bit_cast<I>(t1);
ASSERT_EQ(0, memcmp(&t0, &t1, sizeof(T)));
ASSERT_EQ(i0, i1);
}
}
TEST(BitCast, Bool) {
static const bool bool_list[] = { false, true };
TestMarshall<bool>(bool_list, ABSL_ARRAYSIZE(bool_list));
}
TEST(BitCast, Int32) {
static const int32_t int_list[] =
{ 0, 1, 100, 2147483647, -1, -100, -2147483647, -2147483647-1 };
TestMarshall<int32_t>(int_list, ABSL_ARRAYSIZE(int_list));
}
TEST(BitCast, Int64) {
static const int64_t int64_list[] =
{ 0, 1, 1LL << 40, -1, -(1LL<<40) };
TestMarshall<int64_t>(int64_list, ABSL_ARRAYSIZE(int64_list));
}
TEST(BitCast, Uint64) {
static const uint64_t uint64_list[] =
{ 0, 1, 1LLU << 40, 1LLU << 63 };
TestMarshall<uint64_t>(uint64_list, ABSL_ARRAYSIZE(uint64_list));
}
TEST(BitCast, Float) {
static const float float_list[] =
{ 0.0f, 1.0f, -1.0f, 10.0f, -10.0f,
1e10f, 1e20f, 1e-10f, 1e-20f,
2.71828f, 3.14159f };
TestMarshall<float>(float_list, ABSL_ARRAYSIZE(float_list));
TestIntegral<float, int>(float_list, ABSL_ARRAYSIZE(float_list));
TestIntegral<float, unsigned>(float_list, ABSL_ARRAYSIZE(float_list));
}
TEST(BitCast, Double) {
static const double double_list[] =
{ 0.0, 1.0, -1.0, 10.0, -10.0,
1e10, 1e100, 1e-10, 1e-100,
2.718281828459045,
3.141592653589793238462643383279502884197169399375105820974944 };
TestMarshall<double>(double_list, ABSL_ARRAYSIZE(double_list));
TestIntegral<double, int64_t>(double_list, ABSL_ARRAYSIZE(double_list));
TestIntegral<double, uint64_t>(double_list, ABSL_ARRAYSIZE(double_list));
}
} // namespace
} // namespace absl

View File

@ -1,216 +0,0 @@
// Copyright 2017 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
//
// http://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.
//
// -----------------------------------------------------------------------------
// File: call_once.h
// -----------------------------------------------------------------------------
//
// This header file provides an Abseil version of `std::call_once` for invoking
// a given function at most once, across all threads. This Abseil version is
// faster than the C++11 version and incorporates the C++17 argument-passing
// fix, so that (for example) non-const references may be passed to the invoked
// function.
#ifndef ABSL_BASE_CALL_ONCE_H_
#define ABSL_BASE_CALL_ONCE_H_
#include <algorithm>
#include <atomic>
#include <cstdint>
#include <type_traits>
#include "absl/base/internal/invoke.h"
#include "absl/base/internal/low_level_scheduling.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/scheduling_mode.h"
#include "absl/base/internal/spinlock_wait.h"
#include "absl/base/macros.h"
#include "absl/base/port.h"
namespace absl {
class once_flag;
namespace base_internal {
std::atomic<uint32_t>* ControlWord(absl::once_flag* flag);
} // namespace base_internal
// call_once()
//
// For all invocations using a given `once_flag`, invokes a given `fn` exactly
// once across all threads. The first call to `call_once()` with a particular
// `once_flag` argument (that does not throw an exception) will run the
// specified function with the provided `args`; other calls with the same
// `once_flag` argument will not run the function, but will wait
// for the provided function to finish running (if it is still running).
//
// This mechanism provides a safe, simple, and fast mechanism for one-time
// initialization in a multi-threaded process.
//
// Example:
//
// class MyInitClass {
// public:
// ...
// mutable absl::once_flag once_;
//
// MyInitClass* init() const {
// absl::call_once(once_, &MyInitClass::Init, this);
// return ptr_;
// }
//
template <typename Callable, typename... Args>
void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args);
// once_flag
//
// Objects of this type are used to distinguish calls to `call_once()` and
// ensure the provided function is only invoked once across all threads. This
// type is not copyable or movable. However, it has a `constexpr`
// constructor, and is safe to use as a namespace-scoped global variable.
class once_flag {
public:
constexpr once_flag() : control_(0) {}
once_flag(const once_flag&) = delete;
once_flag& operator=(const once_flag&) = delete;
private:
friend std::atomic<uint32_t>* base_internal::ControlWord(once_flag* flag);
std::atomic<uint32_t> control_;
};
//------------------------------------------------------------------------------
// End of public interfaces.
// Implementation details follow.
//------------------------------------------------------------------------------
namespace base_internal {
// Like call_once, but uses KERNEL_ONLY scheduling. Intended to be used to
// initialize entities used by the scheduler implementation.
template <typename Callable, typename... Args>
void LowLevelCallOnce(absl::once_flag* flag, Callable&& fn, Args&&... args);
// Disables scheduling while on stack when scheduling mode is non-cooperative.
// No effect for cooperative scheduling modes.
class SchedulingHelper {
public:
explicit SchedulingHelper(base_internal::SchedulingMode mode) : mode_(mode) {
if (mode_ == base_internal::SCHEDULE_KERNEL_ONLY) {
guard_result_ = base_internal::SchedulingGuard::DisableRescheduling();
}
}
~SchedulingHelper() {
if (mode_ == base_internal::SCHEDULE_KERNEL_ONLY) {
base_internal::SchedulingGuard::EnableRescheduling(guard_result_);
}
}
private:
base_internal::SchedulingMode mode_;
bool guard_result_;
};
// Bit patterns for call_once state machine values. Internal implementation
// detail, not for use by clients.
//
// The bit patterns are arbitrarily chosen from unlikely values, to aid in
// debugging. However, kOnceInit must be 0, so that a zero-initialized
// once_flag will be valid for immediate use.
enum {
kOnceInit = 0,
kOnceRunning = 0x65C2937B,
kOnceWaiter = 0x05A308D2,
// A very small constant is chosen for kOnceDone so that it fit in a single
// compare with immediate instruction for most common ISAs. This is verified
// for x86, POWER and ARM.
kOnceDone = 221, // Random Number
};
template <typename Callable, typename... Args>
void CallOnceImpl(std::atomic<uint32_t>* control,
base_internal::SchedulingMode scheduling_mode, Callable&& fn,
Args&&... args) {
#ifndef NDEBUG
{
uint32_t old_control = control->load(std::memory_order_acquire);
if (old_control != kOnceInit &&
old_control != kOnceRunning &&
old_control != kOnceWaiter &&
old_control != kOnceDone) {
ABSL_RAW_LOG(
FATAL,
"Unexpected value for control word: %lx. Either the control word "
"has non-static storage duration (where GoogleOnceDynamic might "
"be appropriate), or there's been a memory corruption.",
static_cast<unsigned long>(old_control)); // NOLINT
}
}
#endif // NDEBUG
static const base_internal::SpinLockWaitTransition trans[] = {
{kOnceInit, kOnceRunning, true},
{kOnceRunning, kOnceWaiter, false},
{kOnceDone, kOnceDone, true}};
// 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.
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)...);
old_control = control->load(std::memory_order_relaxed);
control->store(base_internal::kOnceDone, std::memory_order_release);
if (old_control == base_internal::kOnceWaiter) {
base_internal::SpinLockWake(control, true);
}
} // else *control is already kOnceDone
}
inline std::atomic<uint32_t>* ControlWord(once_flag* flag) {
return &flag->control_;
}
template <typename Callable, typename... Args>
void LowLevelCallOnce(absl::once_flag* flag, Callable&& fn, Args&&... args) {
std::atomic<uint32_t>* once = base_internal::ControlWord(flag);
uint32_t s = once->load(std::memory_order_acquire);
if (ABSL_PREDICT_FALSE(s != base_internal::kOnceDone)) {
base_internal::CallOnceImpl(once, base_internal::SCHEDULE_KERNEL_ONLY,
std::forward<Callable>(fn),
std::forward<Args>(args)...);
}
}
} // namespace base_internal
template <typename Callable, typename... Args>
void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args) {
std::atomic<uint32_t>* once = base_internal::ControlWord(&flag);
uint32_t s = once->load(std::memory_order_acquire);
if (ABSL_PREDICT_FALSE(s != base_internal::kOnceDone)) {
base_internal::CallOnceImpl(
once, base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL,
std::forward<Callable>(fn), std::forward<Args>(args)...);
}
}
} // namespace absl
#endif // ABSL_BASE_CALL_ONCE_H_

View File

@ -1,102 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include "absl/base/call_once.h"
#include <thread>
#include <vector>
#include "gtest/gtest.h"
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/mutex.h"
namespace absl {
namespace {
absl::once_flag once;
Mutex counters_mu;
int running_thread_count GUARDED_BY(counters_mu) = 0;
int call_once_invoke_count GUARDED_BY(counters_mu) = 0;
int call_once_finished_count GUARDED_BY(counters_mu) = 0;
int call_once_return_count GUARDED_BY(counters_mu) = 0;
bool done_blocking GUARDED_BY(counters_mu) = false;
// Function to be called from absl::call_once. Waits for a notification.
void WaitAndIncrement() {
counters_mu.Lock();
++call_once_invoke_count;
counters_mu.Unlock();
counters_mu.LockWhen(Condition(&done_blocking));
++call_once_finished_count;
counters_mu.Unlock();
}
void ThreadBody() {
counters_mu.Lock();
++running_thread_count;
counters_mu.Unlock();
absl::call_once(once, WaitAndIncrement);
counters_mu.Lock();
++call_once_return_count;
counters_mu.Unlock();
}
// Returns true if all threads are set up for the test.
bool ThreadsAreSetup(void*) EXCLUSIVE_LOCKS_REQUIRED(counters_mu) {
// All ten threads must be running, and WaitAndIncrement should be blocked.
return running_thread_count == 10 && call_once_invoke_count == 1;
}
TEST(CallOnceTest, ExecutionCount) {
std::vector<std::thread> threads;
// Start 10 threads all calling call_once on the same once_flag.
for (int i = 0; i < 10; ++i) {
threads.emplace_back(ThreadBody);
}
// Wait until all ten threads have started, and WaitAndIncrement has been
// invoked.
counters_mu.LockWhen(Condition(ThreadsAreSetup, nullptr));
// WaitAndIncrement should have been invoked by exactly one call_once()
// instance. That thread should be blocking on a notification, and all other
// call_once instances should be blocking as well.
EXPECT_EQ(call_once_invoke_count, 1);
EXPECT_EQ(call_once_finished_count, 0);
EXPECT_EQ(call_once_return_count, 0);
// Allow WaitAndIncrement to finish executing. Once it does, the other
// call_once waiters will be unblocked.
done_blocking = true;
counters_mu.Unlock();
for (std::thread& thread : threads) {
thread.join();
}
counters_mu.Lock();
EXPECT_EQ(call_once_invoke_count, 1);
EXPECT_EQ(call_once_finished_count, 1);
EXPECT_EQ(call_once_return_count, 10);
counters_mu.Unlock();
}
} // namespace
} // namespace absl

View File

@ -1,140 +0,0 @@
//
// Copyright 2017 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
//
// http://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.
//
// -----------------------------------------------------------------------------
// File: casts.h
// -----------------------------------------------------------------------------
//
// This header file defines casting templates to fit use cases not covered by
// the standard casts provided in the C++ standard. As with all cast operations,
// use these with caution and only if alternatives do not exist.
#ifndef ABSL_BASE_CASTS_H_
#define ABSL_BASE_CASTS_H_
#include <cstring>
#include <type_traits>
#include "absl/base/internal/identity.h"
namespace absl {
// implicit_cast()
//
// Performs an implicit conversion between types following the language
// rules for implicit conversion; if an implicit conversion is otherwise
// allowed by the language in the given context, this function performs such an
// implicit conversion.
//
// Example:
//
// // If the context allows implicit conversion:
// From from;
// To to = from;
//
// // Such code can be replaced by:
// implicit_cast<To>(from);
//
// An `implicit_cast()` may also be used to annotate numeric type conversions
// that, although safe, may produce compiler warnings (such as `long` to `int`).
// Additionally, an `implicit_cast()` is also useful within return statements to
// indicate a specific implicit conversion is being undertaken.
//
// Example:
//
// return implicit_cast<double>(size_in_bytes) / capacity_;
//
// Annotating code with `implicit_cast()` allows you to explicitly select
// particular overloads and template instantiations, while providing a safer
// cast than `reinterpret_cast()` or `static_cast()`.
//
// Additionally, an `implicit_cast()` can be used to allow upcasting within a
// type hierarchy where incorrect use of `static_cast()` could accidentally
// allow downcasting.
//
// Finally, an `implicit_cast()` can be used to perform implicit conversions
// from unrelated types that otherwise couldn't be implicitly cast directly;
// C++ will normally only implicitly cast "one step" in such conversions.
//
// That is, if C is a type which can be implicitly converted to B, with B being
// a type that can be implicitly converted to A, an `implicit_cast()` can be
// used to convert C to B (which the compiler can then implicitly convert to A
// using language rules).
//
// Example:
//
// // Assume an object C is convertible to B, which is implicitly convertible
// // to A
// A a = implicit_cast<B>(C);
//
// Such implicit cast chaining may be useful within template logic.
template <typename To>
inline To implicit_cast(typename absl::internal::identity_t<To> to) {
return to;
}
// bit_cast()
//
// Performs a bitwise cast on a type without changing the underlying bit
// representation of that type's value. The two types must be of the same size
// and both types must be trivially copyable. As with most casts, use with
// caution. A `bit_cast()` might be needed when you need to temporarily treat a
// type as some other type, such as in the following cases:
//
// * Serialization (casting temporarily to `char *` for those purposes is
// always allowed by the C++ standard)
// * Managing the individual bits of a type within mathematical operations
// that are not normally accessible through that type
// * Casting non-pointer types to pointer types (casting the other way is
// allowed by `reinterpret_cast()` but round-trips cannot occur the other
// way).
//
// Example:
//
// float f = 3.14159265358979;
// int i = bit_cast<int32_t>(f);
// // i = 0x40490fdb
//
// Casting non-pointer types to pointer types and then dereferencing them
// traditionally produces undefined behavior.
//
// Example:
//
// // WRONG
// float f = 3.14159265358979; // WRONG
// int i = * reinterpret_cast<int*>(&f); // WRONG
//
// The address-casting method produces undefined behavior according to the ISO
// C++ specification section [basic.lval]. Roughly, this section says: if an
// object in memory has one type, and a program accesses it with a different
// type, the result is undefined behavior for most values of "different type".
//
// Such casting results in type punning: holding an object in memory of one type
// and reading its bits back using a different type. A `bit_cast()` avoids this
// issue by implementing its casts using `memcpy()`, which avoids introducing
// this undefined behavior.
template <typename Dest, typename Source>
inline Dest bit_cast(const Source& source) {
static_assert(sizeof(Dest) == sizeof(Source),
"Source and destination types should have equal sizes.");
Dest dest;
memcpy(&dest, &source, sizeof(dest));
return dest;
}
} // namespace absl
#endif // ABSL_BASE_CASTS_H_

View File

@ -1,427 +0,0 @@
//
// Copyright 2017 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
//
// http://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.
//
// -----------------------------------------------------------------------------
// File: config.h
// -----------------------------------------------------------------------------
//
// This header file defines a set of macros for checking the presence of
// important compiler and platform features. Such macros can be used to
// produce portable code by parameterizing compilation based on the presence or
// lack of a given feature.
//
// We define a "feature" as some interface we wish to program to: for example,
// a library function or system call. A value of `1` indicates support for
// that feature; any other value indicates the feature support is undefined.
//
// Example:
//
// Suppose a programmer wants to write a program that uses the 'mmap()' system
// call. The Abseil macro for that feature (`ABSL_HAVE_MMAP`) allows you to
// selectively include the `mmap.h` header and bracket code using that feature
// in the macro:
//
// #include "absl/base/config.h"
//
// #ifdef ABSL_HAVE_MMAP
// #include "sys/mman.h"
// #endif //ABSL_HAVE_MMAP
//
// ...
// #ifdef ABSL_HAVE_MMAP
// void *ptr = mmap(...);
// ...
// #endif // ABSL_HAVE_MMAP
#ifndef ABSL_BASE_CONFIG_H_
#define ABSL_BASE_CONFIG_H_
// Included for the __GLIBC__ macro (or similar macros on other systems).
#include <limits.h>
#ifdef __cplusplus
// Included for __GLIBCXX__, _LIBCPP_VERSION
#include <cstddef>
#endif // __cplusplus
#if defined(__APPLE__)
// Included for TARGET_OS_IPHONE, __IPHONE_OS_VERSION_MIN_REQUIRED,
// __IPHONE_8_0.
#include <Availability.h>
#include <TargetConditionals.h>
#endif
#include "absl/base/policy_checks.h"
// -----------------------------------------------------------------------------
// Compiler Feature Checks
// -----------------------------------------------------------------------------
// ABSL_HAVE_BUILTIN()
//
// Checks whether the compiler supports a Clang Feature Checking Macro, and if
// so, checks whether it supports the provided builtin function "x" where x
// is one of the functions noted in
// https://clang.llvm.org/docs/LanguageExtensions.html
//
// Note: Use this macro to avoid an extra level of #ifdef __has_builtin check.
// http://releases.llvm.org/3.3/tools/clang/docs/LanguageExtensions.html
#ifdef __has_builtin
#define ABSL_HAVE_BUILTIN(x) __has_builtin(x)
#else
#define ABSL_HAVE_BUILTIN(x) 0
#endif
// ABSL_HAVE_TLS is defined to 1 when __thread should be supported.
// We assume __thread is supported on Linux when compiled with Clang or compiled
// against libstdc++ with _GLIBCXX_HAVE_TLS defined.
#ifdef ABSL_HAVE_TLS
#error ABSL_HAVE_TLS cannot be directly set
#elif defined(__linux__) && (defined(__clang__) || defined(_GLIBCXX_HAVE_TLS))
#define ABSL_HAVE_TLS 1
#endif
// ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
//
// Checks whether `std::is_trivially_destructible<T>` is supported.
//
// Notes: All supported compilers using libc++ support this feature, as does
// gcc >= 4.8.1 using libstdc++, and Visual Studio.
#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
#error ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE cannot be directly set
#elif defined(_LIBCPP_VERSION) || \
(!defined(__clang__) && defined(__GNUC__) && defined(__GLIBCXX__) && \
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || \
defined(_MSC_VER)
#define ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE 1
#endif
// ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
//
// Checks whether `std::is_trivially_default_constructible<T>` and
// `std::is_trivially_copy_constructible<T>` are supported.
// ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
//
// Checks whether `std::is_trivially_copy_assignable<T>` is supported.
// Notes: Clang with libc++ supports these features, as does gcc >= 5.1 with
// either libc++ or libstdc++, and Visual Studio.
#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE)
#error ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE cannot be directly set
#elif defined(ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE)
#error ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE cannot directly set
#elif (defined(__clang__) && defined(_LIBCPP_VERSION)) || \
(!defined(__clang__) && defined(__GNUC__) && \
(__GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)) && \
(defined(_LIBCPP_VERSION) || defined(__GLIBCXX__))) || \
defined(_MSC_VER)
#define ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1
#define ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1
#endif
// ABSL_HAVE_THREAD_LOCAL
//
// Checks whether C++11's `thread_local` storage duration specifier is
// supported.
#ifdef ABSL_HAVE_THREAD_LOCAL
#error ABSL_HAVE_THREAD_LOCAL cannot be directly set
#elif defined(__APPLE__)
// Notes: Xcode's clang did not support `thread_local` until version
// 8, and even then not for all iOS < 9.0. Also, Xcode 9.3 started disallowing
// `thread_local` for 32-bit iOS simulator targeting iOS 9.x.
// `__has_feature` is only supported by Clang so it has be inside
// `defined(__APPLE__)` check.
#if __has_feature(cxx_thread_local)
#define ABSL_HAVE_THREAD_LOCAL 1
#endif
#else // !defined(__APPLE__)
#define ABSL_HAVE_THREAD_LOCAL 1
#endif
// There are platforms for which TLS should not be used even though the compiler
// makes it seem like it's supported (Android NDK < r12b for example).
// This is primarily because of linker problems and toolchain misconfiguration:
// Abseil does not intend to support this indefinitely. Currently, the newest
// toolchain that we intend to support that requires this behavior is the
// r11 NDK - allowing for a 5 year support window on that means this option
// is likely to be removed around June of 2021.
// TLS isn't supported until NDK r12b per
// https://developer.android.com/ndk/downloads/revision_history.html
// Since NDK r16, `__NDK_MAJOR__` and `__NDK_MINOR__` are defined in
// <android/ndk-version.h>. For NDK < r16, users should define these macros,
// e.g. `-D__NDK_MAJOR__=11 -D__NKD_MINOR__=0` for NDK r11.
#if defined(__ANDROID__) && defined(__clang__)
#if __has_include(<android/ndk-version.h>)
#include <android/ndk-version.h>
#endif // __has_include(<android/ndk-version.h>)
#if defined(__ANDROID__) && defined(__clang__) && defined(__NDK_MAJOR__) && \
defined(__NDK_MINOR__) && \
((__NDK_MAJOR__ < 12) || ((__NDK_MAJOR__ == 12) && (__NDK_MINOR__ < 1)))
#undef ABSL_HAVE_TLS
#undef ABSL_HAVE_THREAD_LOCAL
#endif
#endif // defined(__ANDROID__) && defined(__clang__)
// ABSL_HAVE_INTRINSIC_INT128
//
// Checks whether the __int128 compiler extension for a 128-bit integral type is
// supported.
//
// Note: __SIZEOF_INT128__ is defined by Clang and GCC when __int128 is
// supported, but we avoid using it in certain cases:
// * On Clang:
// * Building using Clang for Windows, where the Clang runtime library has
// 128-bit support only on LP64 architectures, but Windows is LLP64.
// * Building for aarch64, where __int128 exists but has exhibits a sporadic
// compiler crashing bug.
// * On Nvidia's nvcc:
// * nvcc also defines __GNUC__ and __SIZEOF_INT128__, but not all versions
// actually support __int128.
#ifdef ABSL_HAVE_INTRINSIC_INT128
#error ABSL_HAVE_INTRINSIC_INT128 cannot be directly set
#elif defined(__SIZEOF_INT128__)
#if (defined(__clang__) && !defined(_WIN32) && !defined(__aarch64__)) || \
(defined(__CUDACC__) && __CUDACC_VER_MAJOR__ >= 9) || \
(defined(__GNUC__) && !defined(__clang__) && !defined(__CUDACC__))
#define ABSL_HAVE_INTRINSIC_INT128 1
#elif defined(__CUDACC__)
// __CUDACC_VER__ is a full version number before CUDA 9, and is defined to a
// std::string explaining that it has been removed starting with CUDA 9. We use
// nested #ifs because there is no short-circuiting in the preprocessor.
// NOTE: `__CUDACC__` could be undefined while `__CUDACC_VER__` is defined.
#if __CUDACC_VER__ >= 70000
#define ABSL_HAVE_INTRINSIC_INT128 1
#endif // __CUDACC_VER__ >= 70000
#endif // defined(__CUDACC__)
#endif // ABSL_HAVE_INTRINSIC_INT128
// ABSL_HAVE_EXCEPTIONS
//
// Checks whether the compiler both supports and enables exceptions. Many
// compilers support a "no exceptions" mode that disables exceptions.
//
// Generally, when ABSL_HAVE_EXCEPTIONS is not defined:
//
// * Code using `throw` and `try` may not compile.
// * The `noexcept` specifier will still compile and behave as normal.
// * The `noexcept` operator may still return `false`.
//
// For further details, consult the compiler's documentation.
#ifdef ABSL_HAVE_EXCEPTIONS
#error ABSL_HAVE_EXCEPTIONS cannot be directly set.
#elif defined(__clang__)
// TODO(calabrese)
// Switch to using __cpp_exceptions when we no longer support versions < 3.6.
// For details on this check, see:
// http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro
#if defined(__EXCEPTIONS) && __has_feature(cxx_exceptions)
#define ABSL_HAVE_EXCEPTIONS 1
#endif // defined(__EXCEPTIONS) && __has_feature(cxx_exceptions)
// Handle remaining special cases and default to exceptions being supported.
#elif !(defined(__GNUC__) && (__GNUC__ < 5) && !defined(__EXCEPTIONS)) && \
!(defined(__GNUC__) && (__GNUC__ >= 5) && !defined(__cpp_exceptions)) && \
!(defined(_MSC_VER) && !defined(_CPPUNWIND))
#define ABSL_HAVE_EXCEPTIONS 1
#endif
// -----------------------------------------------------------------------------
// Platform Feature Checks
// -----------------------------------------------------------------------------
// Currently supported operating systems and associated preprocessor
// symbols:
//
// Linux and Linux-derived __linux__
// Android __ANDROID__ (implies __linux__)
// Linux (non-Android) __linux__ && !__ANDROID__
// Darwin (Mac OS X and iOS) __APPLE__
// Akaros (http://akaros.org) __ros__
// Windows _WIN32
// NaCL __native_client__
// AsmJS __asmjs__
// WebAssembly __wasm__
// Fuchsia __Fuchsia__
//
// Note that since Android defines both __ANDROID__ and __linux__, one
// may probe for either Linux or Android by simply testing for __linux__.
// ABSL_HAVE_MMAP
//
// Checks whether the platform has an mmap(2) implementation as defined in
// POSIX.1-2001.
#ifdef ABSL_HAVE_MMAP
#error ABSL_HAVE_MMAP cannot be directly set
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
defined(__ros__) || defined(__native_client__) || defined(__asmjs__) || \
defined(__wasm__) || defined(__Fuchsia__)
#define ABSL_HAVE_MMAP 1
#endif
// ABSL_HAVE_PTHREAD_GETSCHEDPARAM
//
// Checks whether the platform implements the pthread_(get|set)schedparam(3)
// functions as defined in POSIX.1-2001.
#ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM
#error ABSL_HAVE_PTHREAD_GETSCHEDPARAM cannot be directly set
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
defined(__ros__)
#define ABSL_HAVE_PTHREAD_GETSCHEDPARAM 1
#endif
// ABSL_HAVE_SCHED_YIELD
//
// Checks whether the platform implements sched_yield(2) as defined in
// POSIX.1-2001.
#ifdef ABSL_HAVE_SCHED_YIELD
#error ABSL_HAVE_SCHED_YIELD cannot be directly set
#elif defined(__linux__) || defined(__ros__) || defined(__native_client__)
#define ABSL_HAVE_SCHED_YIELD 1
#endif
// ABSL_HAVE_SEMAPHORE_H
//
// Checks whether the platform supports the <semaphore.h> header and sem_open(3)
// family of functions as standardized in POSIX.1-2001.
//
// Note: While Apple provides <semaphore.h> for both iOS and macOS, it is
// explicitly deprecated and will cause build failures if enabled for those
// platforms. We side-step the issue by not defining it here for Apple
// platforms.
#ifdef ABSL_HAVE_SEMAPHORE_H
#error ABSL_HAVE_SEMAPHORE_H cannot be directly set
#elif defined(__linux__) || defined(__ros__)
#define ABSL_HAVE_SEMAPHORE_H 1
#endif
// ABSL_HAVE_ALARM
//
// Checks whether the platform supports the <signal.h> header and alarm(2)
// function as standardized in POSIX.1-2001.
#ifdef ABSL_HAVE_ALARM
#error ABSL_HAVE_ALARM cannot be directly set
#elif defined(__GOOGLE_GRTE_VERSION__)
// feature tests for Google's GRTE
#define ABSL_HAVE_ALARM 1
#elif defined(__GLIBC__)
// feature test for glibc
#define ABSL_HAVE_ALARM 1
#elif defined(_MSC_VER)
// feature tests for Microsoft's library
#elif defined(__native_client__)
#else
// other standard libraries
#define ABSL_HAVE_ALARM 1
#endif
// ABSL_IS_LITTLE_ENDIAN
// ABSL_IS_BIG_ENDIAN
//
// Checks the endianness of the platform.
//
// Notes: uses the built in endian macros provided by GCC (since 4.6) and
// Clang (since 3.2); see
// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html.
// Otherwise, if _WIN32, assume little endian. Otherwise, bail with an error.
#if defined(ABSL_IS_BIG_ENDIAN)
#error "ABSL_IS_BIG_ENDIAN cannot be directly set."
#endif
#if defined(ABSL_IS_LITTLE_ENDIAN)
#error "ABSL_IS_LITTLE_ENDIAN cannot be directly set."
#endif
#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define ABSL_IS_LITTLE_ENDIAN 1
#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define ABSL_IS_BIG_ENDIAN 1
#elif defined(_WIN32)
#define ABSL_IS_LITTLE_ENDIAN 1
#else
#error "absl endian detection needs to be set up for your compiler"
#endif
// ABSL_HAVE_STD_ANY
//
// Checks whether C++17 std::any is available by checking whether <any> exists.
#ifdef ABSL_HAVE_STD_ANY
#error "ABSL_HAVE_STD_ANY cannot be directly set."
#endif
#ifdef __has_include
#if __has_include(<any>) && __cplusplus >= 201703L
#define ABSL_HAVE_STD_ANY 1
#endif
#endif
// ABSL_HAVE_STD_OPTIONAL
//
// Checks whether C++17 std::optional is available.
#ifdef ABSL_HAVE_STD_OPTIONAL
#error "ABSL_HAVE_STD_OPTIONAL cannot be directly set."
#endif
#ifdef __has_include
#if __has_include(<optional>) && __cplusplus >= 201703L
#define ABSL_HAVE_STD_OPTIONAL 1
#endif
#endif
// ABSL_HAVE_STD_VARIANT
//
// Checks whether C++17 std::variant is available.
#ifdef ABSL_HAVE_STD_VARIANT
#error "ABSL_HAVE_STD_VARIANT cannot be directly set."
#endif
#ifdef __has_include
#if __has_include(<variant>) && __cplusplus >= 201703L
#define ABSL_HAVE_STD_VARIANT 1
#endif
#endif
// ABSL_HAVE_STD_STRING_VIEW
//
// Checks whether C++17 std::string_view is available.
#ifdef ABSL_HAVE_STD_STRING_VIEW
#error "ABSL_HAVE_STD_STRING_VIEW cannot be directly set."
#endif
#ifdef __has_include
#if __has_include(<string_view>) && __cplusplus >= 201703L
#define ABSL_HAVE_STD_STRING_VIEW 1
#endif
#endif
// For MSVC, `__has_include` is supported in VS 2017 15.3, which is later than
// the support for <optional>, <any>, <string_view>, <variant>. So we use
// _MSC_VER to check whether we have VS 2017 RTM (when <optional>, <any>,
// <string_view>, <variant> is implemented) or higher. Also, `__cplusplus` is
// not correctly set by MSVC, so we use `_MSVC_LANG` to check the language
// version.
// TODO(zhangxy): fix tests before enabling aliasing for `std::any`,
// `std::string_view`.
#if defined(_MSC_VER) && _MSC_VER >= 1910 && \
((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || __cplusplus > 201402)
// #define ABSL_HAVE_STD_ANY 1
#define ABSL_HAVE_STD_OPTIONAL 1
#define ABSL_HAVE_STD_VARIANT 1
// #define ABSL_HAVE_STD_STRING_VIEW 1
#endif
#endif // ABSL_BASE_CONFIG_H_

View File

@ -1,60 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include "absl/base/config.h"
#include <cstdint>
#include "gtest/gtest.h"
#include "absl/synchronization/internal/thread_pool.h"
namespace {
TEST(ConfigTest, Endianness) {
union {
uint32_t value;
uint8_t data[sizeof(uint32_t)];
} number;
number.data[0] = 0x00;
number.data[1] = 0x01;
number.data[2] = 0x02;
number.data[3] = 0x03;
#if defined(ABSL_IS_LITTLE_ENDIAN) && defined(ABSL_IS_BIG_ENDIAN)
#error Both ABSL_IS_LITTLE_ENDIAN and ABSL_IS_BIG_ENDIAN are defined
#elif defined(ABSL_IS_LITTLE_ENDIAN)
EXPECT_EQ(UINT32_C(0x03020100), number.value);
#elif defined(ABSL_IS_BIG_ENDIAN)
EXPECT_EQ(UINT32_C(0x00010203), number.value);
#else
#error Unknown endianness
#endif
}
#if defined(ABSL_HAVE_THREAD_LOCAL)
TEST(ConfigTest, ThreadLocal) {
static thread_local int mine_mine_mine = 16;
EXPECT_EQ(16, mine_mine_mine);
{
absl::synchronization_internal::ThreadPool pool(1);
pool.Schedule([&] {
EXPECT_EQ(16, mine_mine_mine);
mine_mine_mine = 32;
EXPECT_EQ(32, mine_mine_mine);
});
}
EXPECT_EQ(16, mine_mine_mine);
}
#endif
} // namespace

View File

@ -1,129 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include <stdlib.h>
#include <string.h>
#include "absl/base/dynamic_annotations.h"
#ifndef __has_feature
#define __has_feature(x) 0
#endif
/* Compiler-based ThreadSanitizer defines
ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL = 1
and provides its own definitions of the functions. */
#ifndef ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL
# define ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL 0
#endif
/* Each function is empty and called (via a macro) only in debug mode.
The arguments are captured by dynamic tools at runtime. */
#if ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 && !defined(__native_client__)
#if __has_feature(memory_sanitizer)
#include <sanitizer/msan_interface.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
void AbslAnnotateRWLockCreate(const char *, int,
const volatile void *){}
void AbslAnnotateRWLockDestroy(const char *, int,
const volatile void *){}
void AbslAnnotateRWLockAcquired(const char *, int,
const volatile void *, long){}
void AbslAnnotateRWLockReleased(const char *, int,
const volatile void *, long){}
void AbslAnnotateBenignRace(const char *, int,
const volatile void *,
const char *){}
void AbslAnnotateBenignRaceSized(const char *, int,
const volatile void *,
size_t,
const char *) {}
void AbslAnnotateThreadName(const char *, int,
const char *){}
void AbslAnnotateIgnoreReadsBegin(const char *, int){}
void AbslAnnotateIgnoreReadsEnd(const char *, int){}
void AbslAnnotateIgnoreWritesBegin(const char *, int){}
void AbslAnnotateIgnoreWritesEnd(const char *, int){}
void AbslAnnotateEnableRaceDetection(const char *, int, int){}
void AbslAnnotateMemoryIsInitialized(const char *, int,
const volatile void *mem, size_t size) {
#if __has_feature(memory_sanitizer)
__msan_unpoison(mem, size);
#else
(void)mem;
(void)size;
#endif
}
void AbslAnnotateMemoryIsUninitialized(const char *, int,
const volatile void *mem, size_t size) {
#if __has_feature(memory_sanitizer)
__msan_allocated_memory(mem, size);
#else
(void)mem;
(void)size;
#endif
}
static int AbslGetRunningOnValgrind(void) {
#ifdef RUNNING_ON_VALGRIND
if (RUNNING_ON_VALGRIND) return 1;
#endif
char *running_on_valgrind_str = getenv("RUNNING_ON_VALGRIND");
if (running_on_valgrind_str) {
return strcmp(running_on_valgrind_str, "0") != 0;
}
return 0;
}
/* See the comments in dynamic_annotations.h */
int AbslRunningOnValgrind(void) {
static volatile int running_on_valgrind = -1;
int local_running_on_valgrind = running_on_valgrind;
/* C doesn't have thread-safe initialization of statics, and we
don't want to depend on pthread_once here, so hack it. */
ABSL_ANNOTATE_BENIGN_RACE(&running_on_valgrind, "safe hack");
if (local_running_on_valgrind == -1)
running_on_valgrind = local_running_on_valgrind = AbslGetRunningOnValgrind();
return local_running_on_valgrind;
}
/* See the comments in dynamic_annotations.h */
double AbslValgrindSlowdown(void) {
/* Same initialization hack as in AbslRunningOnValgrind(). */
static volatile double slowdown = 0.0;
double local_slowdown = slowdown;
ABSL_ANNOTATE_BENIGN_RACE(&slowdown, "safe hack");
if (AbslRunningOnValgrind() == 0) {
return 1.0;
}
if (local_slowdown == 0.0) {
char *env = getenv("VALGRIND_SLOWDOWN");
slowdown = local_slowdown = env ? atof(env) : 50.0;
}
return local_slowdown;
}
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 */

View File

@ -1,388 +0,0 @@
/*
* Copyright 2017 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
*
* http://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.
*/
/* This file defines dynamic annotations for use with dynamic analysis
tool such as valgrind, PIN, etc.
Dynamic annotation is a source code annotation that affects
the generated code (that is, the annotation is not a comment).
Each such annotation is attached to a particular
instruction and/or to a particular object (address) in the program.
The annotations that should be used by users are macros in all upper-case
(e.g., ABSL_ANNOTATE_THREAD_NAME).
Actual implementation of these macros may differ depending on the
dynamic analysis tool being used.
This file supports the following configurations:
- Dynamic Annotations enabled (with static thread-safety warnings disabled).
In this case, macros expand to functions implemented by Thread Sanitizer,
when building with TSan. When not provided an external implementation,
dynamic_annotations.cc provides no-op implementations.
- Static Clang thread-safety warnings enabled.
When building with a Clang compiler that supports thread-safety warnings,
a subset of annotations can be statically-checked at compile-time. We
expand these macros to static-inline functions that can be analyzed for
thread-safety, but afterwards elided when building the final binary.
- All annotations are disabled.
If neither Dynamic Annotations nor Clang thread-safety warnings are
enabled, then all annotation-macros expand to empty. */
#ifndef ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
#define ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
#ifndef ABSL_DYNAMIC_ANNOTATIONS_ENABLED
# define ABSL_DYNAMIC_ANNOTATIONS_ENABLED 0
#endif
#if ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0
/* -------------------------------------------------------------
Annotations that suppress errors. It is usually better to express the
program's synchronization using the other annotations, but these can
be used when all else fails. */
/* Report that we may have a benign race at "pointer", with size
"sizeof(*(pointer))". "pointer" must be a non-void* pointer. Insert at the
point where "pointer" has been allocated, preferably close to the point
where the race happens. See also ABSL_ANNOTATE_BENIGN_RACE_STATIC. */
#define ABSL_ANNOTATE_BENIGN_RACE(pointer, description) \
AbslAnnotateBenignRaceSized(__FILE__, __LINE__, pointer, \
sizeof(*(pointer)), description)
/* Same as ABSL_ANNOTATE_BENIGN_RACE(address, description), but applies to
the memory range [address, address+size). */
#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
AbslAnnotateBenignRaceSized(__FILE__, __LINE__, address, size, description)
/* Enable (enable!=0) or disable (enable==0) race detection for all threads.
This annotation could be useful if you want to skip expensive race analysis
during some period of program execution, e.g. during initialization. */
#define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) \
AbslAnnotateEnableRaceDetection(__FILE__, __LINE__, enable)
/* -------------------------------------------------------------
Annotations useful for debugging. */
/* Report the current thread name to a race detector. */
#define ABSL_ANNOTATE_THREAD_NAME(name) \
AbslAnnotateThreadName(__FILE__, __LINE__, name)
/* -------------------------------------------------------------
Annotations useful when implementing locks. They are not
normally needed by modules that merely use locks.
The "lock" argument is a pointer to the lock object. */
/* Report that a lock has been created at address "lock". */
#define ABSL_ANNOTATE_RWLOCK_CREATE(lock) \
AbslAnnotateRWLockCreate(__FILE__, __LINE__, lock)
/* Report that a linker initialized lock has been created at address "lock".
*/
#ifdef THREAD_SANITIZER
#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
AbslAnnotateRWLockCreateStatic(__FILE__, __LINE__, lock)
#else
#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) ABSL_ANNOTATE_RWLOCK_CREATE(lock)
#endif
/* Report that the lock at address "lock" is about to be destroyed. */
#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) \
AbslAnnotateRWLockDestroy(__FILE__, __LINE__, lock)
/* Report that the lock at address "lock" has been acquired.
is_w=1 for writer lock, is_w=0 for reader lock. */
#define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \
AbslAnnotateRWLockAcquired(__FILE__, __LINE__, lock, is_w)
/* Report that the lock at address "lock" is about to be released. */
#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
AbslAnnotateRWLockReleased(__FILE__, __LINE__, lock, is_w)
#else /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 0 */
#define ABSL_ANNOTATE_RWLOCK_CREATE(lock) /* empty */
#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) /* empty */
#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) /* empty */
#define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) /* empty */
#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) /* empty */
#define ABSL_ANNOTATE_BENIGN_RACE(address, description) /* empty */
#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */
#define ABSL_ANNOTATE_THREAD_NAME(name) /* empty */
#define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) /* empty */
#endif /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED */
/* These annotations are also made available to LLVM's Memory Sanitizer */
#if ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 1 || defined(MEMORY_SANITIZER)
#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
AbslAnnotateMemoryIsInitialized(__FILE__, __LINE__, address, size)
#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
AbslAnnotateMemoryIsUninitialized(__FILE__, __LINE__, address, size)
#else
#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) /* empty */
#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) /* empty */
#endif /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED || MEMORY_SANITIZER */
/* TODO(delesley) -- Replace __CLANG_SUPPORT_DYN_ANNOTATION__ with the
appropriate feature ID. */
#if defined(__clang__) && (!defined(SWIG)) \
&& defined(__CLANG_SUPPORT_DYN_ANNOTATION__)
#if ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 0
#define ABSL_ANNOTALYSIS_ENABLED
#endif
/* When running in opt-mode, GCC will issue a warning, if these attributes are
compiled. Only include them when compiling using Clang. */
#define ABSL_ATTRIBUTE_IGNORE_READS_BEGIN \
__attribute((exclusive_lock_function("*")))
#define ABSL_ATTRIBUTE_IGNORE_READS_END \
__attribute((unlock_function("*")))
#else
#define ABSL_ATTRIBUTE_IGNORE_READS_BEGIN /* empty */
#define ABSL_ATTRIBUTE_IGNORE_READS_END /* empty */
#endif /* defined(__clang__) && ... */
#if (ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0) || defined(ABSL_ANNOTALYSIS_ENABLED)
#define ABSL_ANNOTATIONS_ENABLED
#endif
#if (ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0)
/* Request the analysis tool to ignore all reads in the current thread
until ABSL_ANNOTATE_IGNORE_READS_END is called.
Useful to ignore intentional racey reads, while still checking
other reads and all writes.
See also ABSL_ANNOTATE_UNPROTECTED_READ. */
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
AbslAnnotateIgnoreReadsBegin(__FILE__, __LINE__)
/* Stop ignoring reads. */
#define ABSL_ANNOTATE_IGNORE_READS_END() \
AbslAnnotateIgnoreReadsEnd(__FILE__, __LINE__)
/* Similar to ABSL_ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead. */
#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \
AbslAnnotateIgnoreWritesBegin(__FILE__, __LINE__)
/* Stop ignoring writes. */
#define ABSL_ANNOTATE_IGNORE_WRITES_END() \
AbslAnnotateIgnoreWritesEnd(__FILE__, __LINE__)
/* Clang provides limited support for static thread-safety analysis
through a feature called Annotalysis. We configure macro-definitions
according to whether Annotalysis support is available. */
#elif defined(ABSL_ANNOTALYSIS_ENABLED)
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
AbslStaticAnnotateIgnoreReadsBegin(__FILE__, __LINE__)
#define ABSL_ANNOTATE_IGNORE_READS_END() \
AbslStaticAnnotateIgnoreReadsEnd(__FILE__, __LINE__)
#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \
AbslStaticAnnotateIgnoreWritesBegin(__FILE__, __LINE__)
#define ABSL_ANNOTATE_IGNORE_WRITES_END() \
AbslStaticAnnotateIgnoreWritesEnd(__FILE__, __LINE__)
#else
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() /* empty */
#define ABSL_ANNOTATE_IGNORE_READS_END() /* empty */
#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() /* empty */
#define ABSL_ANNOTATE_IGNORE_WRITES_END() /* empty */
#endif
/* Implement the ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more
primitive annotations defined above. */
#if defined(ABSL_ANNOTATIONS_ENABLED)
/* Start ignoring all memory accesses (both reads and writes). */
#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
do { \
ABSL_ANNOTATE_IGNORE_READS_BEGIN(); \
ABSL_ANNOTATE_IGNORE_WRITES_BEGIN(); \
}while (0)
/* Stop ignoring both reads and writes. */
#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() \
do { \
ABSL_ANNOTATE_IGNORE_WRITES_END(); \
ABSL_ANNOTATE_IGNORE_READS_END(); \
}while (0)
#else
#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() /* empty */
#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() /* empty */
#endif
/* Use the macros above rather than using these functions directly. */
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
void AbslAnnotateRWLockCreate(const char *file, int line,
const volatile void *lock);
void AbslAnnotateRWLockCreateStatic(const char *file, int line,
const volatile void *lock);
void AbslAnnotateRWLockDestroy(const char *file, int line,
const volatile void *lock);
void AbslAnnotateRWLockAcquired(const char *file, int line,
const volatile void *lock, long is_w); /* NOLINT */
void AbslAnnotateRWLockReleased(const char *file, int line,
const volatile void *lock, long is_w); /* NOLINT */
void AbslAnnotateBenignRace(const char *file, int line,
const volatile void *address,
const char *description);
void AbslAnnotateBenignRaceSized(const char *file, int line,
const volatile void *address,
size_t size,
const char *description);
void AbslAnnotateThreadName(const char *file, int line,
const char *name);
void AbslAnnotateEnableRaceDetection(const char *file, int line, int enable);
void AbslAnnotateMemoryIsInitialized(const char *file, int line,
const volatile void *mem, size_t size);
void AbslAnnotateMemoryIsUninitialized(const char *file, int line,
const volatile void *mem, size_t size);
/* Annotations expand to these functions, when Dynamic Annotations are enabled.
These functions are either implemented as no-op calls, if no Sanitizer is
attached, or provided with externally-linked implementations by a library
like ThreadSanitizer. */
void AbslAnnotateIgnoreReadsBegin(const char *file, int line)
ABSL_ATTRIBUTE_IGNORE_READS_BEGIN;
void AbslAnnotateIgnoreReadsEnd(const char *file, int line)
ABSL_ATTRIBUTE_IGNORE_READS_END;
void AbslAnnotateIgnoreWritesBegin(const char *file, int line);
void AbslAnnotateIgnoreWritesEnd(const char *file, int line);
#if defined(ABSL_ANNOTALYSIS_ENABLED)
/* When Annotalysis is enabled without Dynamic Annotations, the use of
static-inline functions allows the annotations to be read at compile-time,
while still letting the compiler elide the functions from the final build.
TODO(delesley) -- The exclusive lock here ignores writes as well, but
allows IGNORE_READS_AND_WRITES to work properly. */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
static inline void AbslStaticAnnotateIgnoreReadsBegin(const char *file, int line)
ABSL_ATTRIBUTE_IGNORE_READS_BEGIN { (void)file; (void)line; }
static inline void AbslStaticAnnotateIgnoreReadsEnd(const char *file, int line)
ABSL_ATTRIBUTE_IGNORE_READS_END { (void)file; (void)line; }
static inline void AbslStaticAnnotateIgnoreWritesBegin(
const char *file, int line) { (void)file; (void)line; }
static inline void AbslStaticAnnotateIgnoreWritesEnd(
const char *file, int line) { (void)file; (void)line; }
#pragma GCC diagnostic pop
#endif
/* Return non-zero value if running under valgrind.
If "valgrind.h" is included into dynamic_annotations.cc,
the regular valgrind mechanism will be used.
See http://valgrind.org/docs/manual/manual-core-adv.html about
RUNNING_ON_VALGRIND and other valgrind "client requests".
The file "valgrind.h" may be obtained by doing
svn co svn://svn.valgrind.org/valgrind/trunk/include
If for some reason you can't use "valgrind.h" or want to fake valgrind,
there are two ways to make this function return non-zero:
- Use environment variable: export RUNNING_ON_VALGRIND=1
- Make your tool intercept the function AbslRunningOnValgrind() and
change its return value.
*/
int AbslRunningOnValgrind(void);
/* AbslValgrindSlowdown returns:
* 1.0, if (AbslRunningOnValgrind() == 0)
* 50.0, if (AbslRunningOnValgrind() != 0 && getenv("VALGRIND_SLOWDOWN") == NULL)
* atof(getenv("VALGRIND_SLOWDOWN")) otherwise
This function can be used to scale timeout values:
EXAMPLE:
for (;;) {
DoExpensiveBackgroundTask();
SleepForSeconds(5 * AbslValgrindSlowdown());
}
*/
double AbslValgrindSlowdown(void);
#ifdef __cplusplus
}
#endif
/* ABSL_ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
Instead of doing
ABSL_ANNOTATE_IGNORE_READS_BEGIN();
... = x;
ABSL_ANNOTATE_IGNORE_READS_END();
one can use
... = ABSL_ANNOTATE_UNPROTECTED_READ(x); */
#if defined(__cplusplus) && defined(ABSL_ANNOTATIONS_ENABLED)
template <typename T>
inline T ABSL_ANNOTATE_UNPROTECTED_READ(const volatile T &x) { /* NOLINT */
ABSL_ANNOTATE_IGNORE_READS_BEGIN();
T res = x;
ABSL_ANNOTATE_IGNORE_READS_END();
return res;
}
#else
#define ABSL_ANNOTATE_UNPROTECTED_READ(x) (x)
#endif
#if ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus)
/* Apply ABSL_ANNOTATE_BENIGN_RACE_SIZED to a static variable. */
#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \
namespace { \
class static_var ## _annotator { \
public: \
static_var ## _annotator() { \
ABSL_ANNOTATE_BENIGN_RACE_SIZED(&static_var, \
sizeof(static_var), \
# static_var ": " description); \
} \
}; \
static static_var ## _annotator the ## static_var ## _annotator;\
} // namespace
#else /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 0 */
#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) /* empty */
#endif /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED */
#ifdef ADDRESS_SANITIZER
/* Describe the current state of a contiguous container such as e.g.
* std::vector or std::string. For more details see
* sanitizer/common_interface_defs.h, which is provided by the compiler. */
#include <sanitizer/common_interface_defs.h>
#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \
__sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid)
#define ABSL_ADDRESS_SANITIZER_REDZONE(name) \
struct { char x[8] __attribute__ ((aligned (8))); } name
#else
#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid)
#define ABSL_ADDRESS_SANITIZER_REDZONE(name)
#endif // ADDRESS_SANITIZER
/* Undefine the macros intended only in this file. */
#undef ABSL_ANNOTALYSIS_ENABLED
#undef ABSL_ANNOTATIONS_ENABLED
#undef ABSL_ATTRIBUTE_IGNORE_READS_BEGIN
#undef ABSL_ATTRIBUTE_IGNORE_READS_END
#endif /* ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ */

View File

@ -1,942 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include "absl/base/internal/exception_safety_testing.h"
#include <cstddef>
#include <exception>
#include <iostream>
#include <list>
#include <type_traits>
#include <vector>
#include "gtest/gtest-spi.h"
#include "gtest/gtest.h"
#include "absl/memory/memory.h"
namespace testing {
namespace {
using ::testing::exceptions_internal::SetCountdown;
using ::testing::exceptions_internal::TestException;
using ::testing::exceptions_internal::UnsetCountdown;
// EXPECT_NO_THROW can't inspect the thrown inspection in general.
template <typename F>
void ExpectNoThrow(const F& f) {
try {
f();
} catch (TestException e) {
ADD_FAILURE() << "Unexpected exception thrown from " << e.what();
}
}
TEST(ThrowingValueTest, Throws) {
SetCountdown();
EXPECT_THROW(ThrowingValue<> bomb, TestException);
// It's not guaranteed that every operator only throws *once*. The default
// ctor only throws once, though, so use it to make sure we only throw when
// the countdown hits 0
SetCountdown(2);
ExpectNoThrow([]() { ThrowingValue<> bomb; });
ExpectNoThrow([]() { ThrowingValue<> bomb; });
EXPECT_THROW(ThrowingValue<> bomb, TestException);
UnsetCountdown();
}
// Tests that an operation throws when the countdown is at 0, doesn't throw when
// the countdown doesn't hit 0, and doesn't modify the state of the
// ThrowingValue if it throws
template <typename F>
void TestOp(const F& f) {
ExpectNoThrow(f);
SetCountdown();
EXPECT_THROW(f(), TestException);
UnsetCountdown();
}
TEST(ThrowingValueTest, ThrowingCtors) {
ThrowingValue<> bomb;
TestOp([]() { ThrowingValue<> bomb(1); });
TestOp([&]() { ThrowingValue<> bomb1 = bomb; });
TestOp([&]() { ThrowingValue<> bomb1 = std::move(bomb); });
}
TEST(ThrowingValueTest, ThrowingAssignment) {
ThrowingValue<> bomb, bomb1;
TestOp([&]() { bomb = bomb1; });
TestOp([&]() { bomb = std::move(bomb1); });
// Test that when assignment throws, the assignment should fail (lhs != rhs)
// and strong guarantee fails (lhs != lhs_copy).
{
ThrowingValue<> lhs(39), rhs(42);
ThrowingValue<> lhs_copy(lhs);
SetCountdown();
EXPECT_THROW(lhs = rhs, TestException);
UnsetCountdown();
EXPECT_NE(lhs, rhs);
EXPECT_NE(lhs_copy, lhs);
}
{
ThrowingValue<> lhs(39), rhs(42);
ThrowingValue<> lhs_copy(lhs), rhs_copy(rhs);
SetCountdown();
EXPECT_THROW(lhs = std::move(rhs), TestException);
UnsetCountdown();
EXPECT_NE(lhs, rhs_copy);
EXPECT_NE(lhs_copy, lhs);
}
}
TEST(ThrowingValueTest, ThrowingComparisons) {
ThrowingValue<> bomb1, bomb2;
TestOp([&]() { return bomb1 == bomb2; });
TestOp([&]() { return bomb1 != bomb2; });
TestOp([&]() { return bomb1 < bomb2; });
TestOp([&]() { return bomb1 <= bomb2; });
TestOp([&]() { return bomb1 > bomb2; });
TestOp([&]() { return bomb1 >= bomb2; });
}
TEST(ThrowingValueTest, ThrowingArithmeticOps) {
ThrowingValue<> bomb1(1), bomb2(2);
TestOp([&bomb1]() { +bomb1; });
TestOp([&bomb1]() { -bomb1; });
TestOp([&bomb1]() { ++bomb1; });
TestOp([&bomb1]() { bomb1++; });
TestOp([&bomb1]() { --bomb1; });
TestOp([&bomb1]() { bomb1--; });
TestOp([&]() { bomb1 + bomb2; });
TestOp([&]() { bomb1 - bomb2; });
TestOp([&]() { bomb1* bomb2; });
TestOp([&]() { bomb1 / bomb2; });
TestOp([&]() { bomb1 << 1; });
TestOp([&]() { bomb1 >> 1; });
}
TEST(ThrowingValueTest, ThrowingLogicalOps) {
ThrowingValue<> bomb1, bomb2;
TestOp([&bomb1]() { !bomb1; });
TestOp([&]() { bomb1&& bomb2; });
TestOp([&]() { bomb1 || bomb2; });
}
TEST(ThrowingValueTest, ThrowingBitwiseOps) {
ThrowingValue<> bomb1, bomb2;
TestOp([&bomb1]() { ~bomb1; });
TestOp([&]() { bomb1& bomb2; });
TestOp([&]() { bomb1 | bomb2; });
TestOp([&]() { bomb1 ^ bomb2; });
}
TEST(ThrowingValueTest, ThrowingCompoundAssignmentOps) {
ThrowingValue<> bomb1(1), bomb2(2);
TestOp([&]() { bomb1 += bomb2; });
TestOp([&]() { bomb1 -= bomb2; });
TestOp([&]() { bomb1 *= bomb2; });
TestOp([&]() { bomb1 /= bomb2; });
TestOp([&]() { bomb1 %= bomb2; });
TestOp([&]() { bomb1 &= bomb2; });
TestOp([&]() { bomb1 |= bomb2; });
TestOp([&]() { bomb1 ^= bomb2; });
TestOp([&]() { bomb1 *= bomb2; });
}
TEST(ThrowingValueTest, ThrowingStreamOps) {
ThrowingValue<> bomb;
TestOp([&]() {
std::istringstream stream;
stream >> bomb;
});
TestOp([&]() {
std::stringstream stream;
stream << bomb;
});
}
// Tests the operator<< of ThrowingValue by forcing ConstructorTracker to emit
// a nonfatal failure that contains the std::string representation of the Thrower
TEST(ThrowingValueTest, StreamOpsOutput) {
using ::testing::TypeSpec;
exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
// Test default spec list (kEverythingThrows)
EXPECT_NONFATAL_FAILURE(
{
using Thrower = ThrowingValue<TypeSpec{}>;
auto thrower = Thrower(123);
thrower.~Thrower();
},
"ThrowingValue<>(123)");
// Test with one item in spec list (kNoThrowCopy)
EXPECT_NONFATAL_FAILURE(
{
using Thrower = ThrowingValue<TypeSpec::kNoThrowCopy>;
auto thrower = Thrower(234);
thrower.~Thrower();
},
"ThrowingValue<kNoThrowCopy>(234)");
// Test with multiple items in spec list (kNoThrowMove, kNoThrowNew)
EXPECT_NONFATAL_FAILURE(
{
using Thrower =
ThrowingValue<TypeSpec::kNoThrowMove | TypeSpec::kNoThrowNew>;
auto thrower = Thrower(345);
thrower.~Thrower();
},
"ThrowingValue<kNoThrowMove | kNoThrowNew>(345)");
// Test with all items in spec list (kNoThrowCopy, kNoThrowMove, kNoThrowNew)
EXPECT_NONFATAL_FAILURE(
{
using Thrower = ThrowingValue<static_cast<TypeSpec>(-1)>;
auto thrower = Thrower(456);
thrower.~Thrower();
},
"ThrowingValue<kNoThrowCopy | kNoThrowMove | kNoThrowNew>(456)");
}
template <typename F>
void TestAllocatingOp(const F& f) {
ExpectNoThrow(f);
SetCountdown();
EXPECT_THROW(f(), exceptions_internal::TestBadAllocException);
UnsetCountdown();
}
TEST(ThrowingValueTest, ThrowingAllocatingOps) {
// make_unique calls unqualified operator new, so these exercise the
// ThrowingValue overloads.
TestAllocatingOp([]() { return absl::make_unique<ThrowingValue<>>(1); });
TestAllocatingOp([]() { return absl::make_unique<ThrowingValue<>[]>(2); });
}
TEST(ThrowingValueTest, NonThrowingMoveCtor) {
ThrowingValue<TypeSpec::kNoThrowMove> nothrow_ctor;
SetCountdown();
ExpectNoThrow([&nothrow_ctor]() {
ThrowingValue<TypeSpec::kNoThrowMove> nothrow1 = std::move(nothrow_ctor);
});
UnsetCountdown();
}
TEST(ThrowingValueTest, NonThrowingMoveAssign) {
ThrowingValue<TypeSpec::kNoThrowMove> nothrow_assign1, nothrow_assign2;
SetCountdown();
ExpectNoThrow([&nothrow_assign1, &nothrow_assign2]() {
nothrow_assign1 = std::move(nothrow_assign2);
});
UnsetCountdown();
}
TEST(ThrowingValueTest, ThrowingCopyCtor) {
ThrowingValue<> tv;
TestOp([&]() { ThrowingValue<> tv_copy(tv); });
}
TEST(ThrowingValueTest, ThrowingCopyAssign) {
ThrowingValue<> tv1, tv2;
TestOp([&]() { tv1 = tv2; });
}
TEST(ThrowingValueTest, NonThrowingCopyCtor) {
ThrowingValue<TypeSpec::kNoThrowCopy> nothrow_ctor;
SetCountdown();
ExpectNoThrow([&nothrow_ctor]() {
ThrowingValue<TypeSpec::kNoThrowCopy> nothrow1(nothrow_ctor);
});
UnsetCountdown();
}
TEST(ThrowingValueTest, NonThrowingCopyAssign) {
ThrowingValue<TypeSpec::kNoThrowCopy> nothrow_assign1, nothrow_assign2;
SetCountdown();
ExpectNoThrow([&nothrow_assign1, &nothrow_assign2]() {
nothrow_assign1 = nothrow_assign2;
});
UnsetCountdown();
}
TEST(ThrowingValueTest, ThrowingSwap) {
ThrowingValue<> bomb1, bomb2;
TestOp([&]() { std::swap(bomb1, bomb2); });
}
TEST(ThrowingValueTest, NonThrowingSwap) {
ThrowingValue<TypeSpec::kNoThrowMove> bomb1, bomb2;
ExpectNoThrow([&]() { std::swap(bomb1, bomb2); });
}
TEST(ThrowingValueTest, NonThrowingAllocation) {
ThrowingValue<TypeSpec::kNoThrowNew>* allocated;
ThrowingValue<TypeSpec::kNoThrowNew>* array;
ExpectNoThrow([&allocated]() {
allocated = new ThrowingValue<TypeSpec::kNoThrowNew>(1);
delete allocated;
});
ExpectNoThrow([&array]() {
array = new ThrowingValue<TypeSpec::kNoThrowNew>[2];
delete[] array;
});
}
TEST(ThrowingValueTest, NonThrowingDelete) {
auto* allocated = new ThrowingValue<>(1);
auto* array = new ThrowingValue<>[2];
SetCountdown();
ExpectNoThrow([allocated]() { delete allocated; });
SetCountdown();
ExpectNoThrow([array]() { delete[] array; });
UnsetCountdown();
}
using Storage =
absl::aligned_storage_t<sizeof(ThrowingValue<>), alignof(ThrowingValue<>)>;
TEST(ThrowingValueTest, NonThrowingPlacementDelete) {
constexpr int kArrayLen = 2;
// We intentionally create extra space to store the tag allocated by placement
// new[].
constexpr int kStorageLen = 4;
Storage buf;
Storage array_buf[kStorageLen];
auto* placed = new (&buf) ThrowingValue<>(1);
auto placed_array = new (&array_buf) ThrowingValue<>[kArrayLen];
SetCountdown();
ExpectNoThrow([placed, &buf]() {
placed->~ThrowingValue<>();
ThrowingValue<>::operator delete(placed, &buf);
});
SetCountdown();
ExpectNoThrow([&, placed_array]() {
for (int i = 0; i < kArrayLen; ++i) placed_array[i].~ThrowingValue<>();
ThrowingValue<>::operator delete[](placed_array, &array_buf);
});
UnsetCountdown();
}
TEST(ThrowingValueTest, NonThrowingDestructor) {
auto* allocated = new ThrowingValue<>();
SetCountdown();
ExpectNoThrow([allocated]() { delete allocated; });
UnsetCountdown();
}
TEST(ThrowingBoolTest, ThrowingBool) {
ThrowingBool t = true;
// Test that it's contextually convertible to bool
if (t) { // NOLINT(whitespace/empty_if_body)
}
EXPECT_TRUE(t);
TestOp([&]() { (void)!t; });
}
TEST(ThrowingAllocatorTest, MemoryManagement) {
// Just exercise the memory management capabilities under LSan to make sure we
// don't leak.
ThrowingAllocator<int> int_alloc;
int* ip = int_alloc.allocate(1);
int_alloc.deallocate(ip, 1);
int* i_array = int_alloc.allocate(2);
int_alloc.deallocate(i_array, 2);
ThrowingAllocator<ThrowingValue<>> tv_alloc;
ThrowingValue<>* ptr = tv_alloc.allocate(1);
tv_alloc.deallocate(ptr, 1);
ThrowingValue<>* tv_array = tv_alloc.allocate(2);
tv_alloc.deallocate(tv_array, 2);
}
TEST(ThrowingAllocatorTest, CallsGlobalNew) {
ThrowingAllocator<ThrowingValue<>, AllocSpec::kNoThrowAllocate> nothrow_alloc;
ThrowingValue<>* ptr;
SetCountdown();
// This will only throw if ThrowingValue::new is called.
ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); });
nothrow_alloc.deallocate(ptr, 1);
UnsetCountdown();
}
TEST(ThrowingAllocatorTest, ThrowingConstructors) {
ThrowingAllocator<int> int_alloc;
int* ip = nullptr;
SetCountdown();
EXPECT_THROW(ip = int_alloc.allocate(1), TestException);
ExpectNoThrow([&]() { ip = int_alloc.allocate(1); });
*ip = 1;
SetCountdown();
EXPECT_THROW(int_alloc.construct(ip, 2), TestException);
EXPECT_EQ(*ip, 1);
int_alloc.deallocate(ip, 1);
UnsetCountdown();
}
TEST(ThrowingAllocatorTest, NonThrowingConstruction) {
{
ThrowingAllocator<int, AllocSpec::kNoThrowAllocate> int_alloc;
int* ip = nullptr;
SetCountdown();
ExpectNoThrow([&]() { ip = int_alloc.allocate(1); });
SetCountdown();
ExpectNoThrow([&]() { int_alloc.construct(ip, 2); });
EXPECT_EQ(*ip, 2);
int_alloc.deallocate(ip, 1);
UnsetCountdown();
}
{
ThrowingAllocator<int> int_alloc;
int* ip = nullptr;
ExpectNoThrow([&]() { ip = int_alloc.allocate(1); });
ExpectNoThrow([&]() { int_alloc.construct(ip, 2); });
EXPECT_EQ(*ip, 2);
int_alloc.deallocate(ip, 1);
}
{
ThrowingAllocator<ThrowingValue<>, AllocSpec::kNoThrowAllocate>
nothrow_alloc;
ThrowingValue<>* ptr;
SetCountdown();
ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); });
SetCountdown();
ExpectNoThrow(
[&]() { nothrow_alloc.construct(ptr, 2, testing::nothrow_ctor); });
EXPECT_EQ(ptr->Get(), 2);
nothrow_alloc.destroy(ptr);
nothrow_alloc.deallocate(ptr, 1);
UnsetCountdown();
}
{
ThrowingAllocator<int> a;
SetCountdown();
ExpectNoThrow([&]() { ThrowingAllocator<double> a1 = a; });
SetCountdown();
ExpectNoThrow([&]() { ThrowingAllocator<double> a1 = std::move(a); });
UnsetCountdown();
}
}
TEST(ThrowingAllocatorTest, ThrowingAllocatorConstruction) {
ThrowingAllocator<int> a;
TestOp([]() { ThrowingAllocator<int> a; });
TestOp([&]() { a.select_on_container_copy_construction(); });
}
TEST(ThrowingAllocatorTest, State) {
ThrowingAllocator<int> a1, a2;
EXPECT_NE(a1, a2);
auto a3 = a1;
EXPECT_EQ(a3, a1);
int* ip = a1.allocate(1);
EXPECT_EQ(a3, a1);
a3.deallocate(ip, 1);
EXPECT_EQ(a3, a1);
}
TEST(ThrowingAllocatorTest, InVector) {
std::vector<ThrowingValue<>, ThrowingAllocator<ThrowingValue<>>> v;
for (int i = 0; i < 20; ++i) v.push_back({});
for (int i = 0; i < 20; ++i) v.pop_back();
}
TEST(ThrowingAllocatorTest, InList) {
std::list<ThrowingValue<>, ThrowingAllocator<ThrowingValue<>>> l;
for (int i = 0; i < 20; ++i) l.push_back({});
for (int i = 0; i < 20; ++i) l.pop_back();
for (int i = 0; i < 20; ++i) l.push_front({});
for (int i = 0; i < 20; ++i) l.pop_front();
}
template <typename TesterInstance, typename = void>
struct NullaryTestValidator : public std::false_type {};
template <typename TesterInstance>
struct NullaryTestValidator<
TesterInstance,
absl::void_t<decltype(std::declval<TesterInstance>().Test())>>
: public std::true_type {};
template <typename TesterInstance>
bool HasNullaryTest(const TesterInstance&) {
return NullaryTestValidator<TesterInstance>::value;
}
void DummyOp(void*) {}
template <typename TesterInstance, typename = void>
struct UnaryTestValidator : public std::false_type {};
template <typename TesterInstance>
struct UnaryTestValidator<
TesterInstance,
absl::void_t<decltype(std::declval<TesterInstance>().Test(DummyOp))>>
: public std::true_type {};
template <typename TesterInstance>
bool HasUnaryTest(const TesterInstance&) {
return UnaryTestValidator<TesterInstance>::value;
}
TEST(ExceptionSafetyTesterTest, IncompleteTypesAreNotTestable) {
using T = exceptions_internal::UninitializedT;
auto op = [](T* t) {};
auto inv = [](T*) { return testing::AssertionSuccess(); };
auto fac = []() { return absl::make_unique<T>(); };
// Test that providing operation and inveriants still does not allow for the
// the invocation of .Test() and .Test(op) because it lacks a factory
auto without_fac =
testing::MakeExceptionSafetyTester().WithOperation(op).WithInvariants(
inv, testing::strong_guarantee);
EXPECT_FALSE(HasNullaryTest(without_fac));
EXPECT_FALSE(HasUnaryTest(without_fac));
// Test that providing invariants and factory allows the invocation of
// .Test(op) but does not allow for .Test() because it lacks an operation
auto without_op = testing::MakeExceptionSafetyTester()
.WithInvariants(inv, testing::strong_guarantee)
.WithFactory(fac);
EXPECT_FALSE(HasNullaryTest(without_op));
EXPECT_TRUE(HasUnaryTest(without_op));
// Test that providing operation and factory still does not allow for the
// the invocation of .Test() and .Test(op) because it lacks invariants
auto without_inv =
testing::MakeExceptionSafetyTester().WithOperation(op).WithFactory(fac);
EXPECT_FALSE(HasNullaryTest(without_inv));
EXPECT_FALSE(HasUnaryTest(without_inv));
}
struct ExampleStruct {};
std::unique_ptr<ExampleStruct> ExampleFunctionFactory() {
return absl::make_unique<ExampleStruct>();
}
void ExampleFunctionOperation(ExampleStruct*) {}
testing::AssertionResult ExampleFunctionInvariant(ExampleStruct*) {
return testing::AssertionSuccess();
}
struct {
std::unique_ptr<ExampleStruct> operator()() const {
return ExampleFunctionFactory();
}
} example_struct_factory;
struct {
void operator()(ExampleStruct*) const {}
} example_struct_operation;
struct {
testing::AssertionResult operator()(ExampleStruct* example_struct) const {
return ExampleFunctionInvariant(example_struct);
}
} example_struct_invariant;
auto example_lambda_factory = []() { return ExampleFunctionFactory(); };
auto example_lambda_operation = [](ExampleStruct*) {};
auto example_lambda_invariant = [](ExampleStruct* example_struct) {
return ExampleFunctionInvariant(example_struct);
};
// Testing that function references, pointers, structs with operator() and
// lambdas can all be used with ExceptionSafetyTester
TEST(ExceptionSafetyTesterTest, MixedFunctionTypes) {
// function reference
EXPECT_TRUE(testing::MakeExceptionSafetyTester()
.WithFactory(ExampleFunctionFactory)
.WithOperation(ExampleFunctionOperation)
.WithInvariants(ExampleFunctionInvariant)
.Test());
// function pointer
EXPECT_TRUE(testing::MakeExceptionSafetyTester()
.WithFactory(&ExampleFunctionFactory)
.WithOperation(&ExampleFunctionOperation)
.WithInvariants(&ExampleFunctionInvariant)
.Test());
// struct
EXPECT_TRUE(testing::MakeExceptionSafetyTester()
.WithFactory(example_struct_factory)
.WithOperation(example_struct_operation)
.WithInvariants(example_struct_invariant)
.Test());
// lambda
EXPECT_TRUE(testing::MakeExceptionSafetyTester()
.WithFactory(example_lambda_factory)
.WithOperation(example_lambda_operation)
.WithInvariants(example_lambda_invariant)
.Test());
}
struct NonNegative {
bool operator==(const NonNegative& other) const { return i == other.i; }
int i;
};
testing::AssertionResult CheckNonNegativeInvariants(NonNegative* g) {
if (g->i >= 0) {
return testing::AssertionSuccess();
}
return testing::AssertionFailure()
<< "i should be non-negative but is " << g->i;
}
struct {
template <typename T>
void operator()(T* t) const {
(*t)();
}
} invoker;
auto tester =
testing::MakeExceptionSafetyTester().WithOperation(invoker).WithInvariants(
CheckNonNegativeInvariants);
auto strong_tester = tester.WithInvariants(testing::strong_guarantee);
struct FailsBasicGuarantee : public NonNegative {
void operator()() {
--i;
ThrowingValue<> bomb;
++i;
}
};
TEST(ExceptionCheckTest, BasicGuaranteeFailure) {
EXPECT_FALSE(tester.WithInitialValue(FailsBasicGuarantee{}).Test());
}
struct FollowsBasicGuarantee : public NonNegative {
void operator()() {
++i;
ThrowingValue<> bomb;
}
};
TEST(ExceptionCheckTest, BasicGuarantee) {
EXPECT_TRUE(tester.WithInitialValue(FollowsBasicGuarantee{}).Test());
}
TEST(ExceptionCheckTest, StrongGuaranteeFailure) {
EXPECT_FALSE(strong_tester.WithInitialValue(FailsBasicGuarantee{}).Test());
EXPECT_FALSE(strong_tester.WithInitialValue(FollowsBasicGuarantee{}).Test());
}
struct BasicGuaranteeWithExtraInvariants : public NonNegative {
// After operator(), i is incremented. If operator() throws, i is set to 9999
void operator()() {
int old_i = i;
i = kExceptionSentinel;
ThrowingValue<> bomb;
i = ++old_i;
}
static constexpr int kExceptionSentinel = 9999;
};
constexpr int BasicGuaranteeWithExtraInvariants::kExceptionSentinel;
TEST(ExceptionCheckTest, BasicGuaranteeWithExtraInvariants) {
auto tester_with_val =
tester.WithInitialValue(BasicGuaranteeWithExtraInvariants{});
EXPECT_TRUE(tester_with_val.Test());
EXPECT_TRUE(
tester_with_val
.WithInvariants([](BasicGuaranteeWithExtraInvariants* o) {
if (o->i == BasicGuaranteeWithExtraInvariants::kExceptionSentinel) {
return testing::AssertionSuccess();
}
return testing::AssertionFailure()
<< "i should be "
<< BasicGuaranteeWithExtraInvariants::kExceptionSentinel
<< ", but is " << o->i;
})
.Test());
}
struct FollowsStrongGuarantee : public NonNegative {
void operator()() { ThrowingValue<> bomb; }
};
TEST(ExceptionCheckTest, StrongGuarantee) {
EXPECT_TRUE(tester.WithInitialValue(FollowsStrongGuarantee{}).Test());
EXPECT_TRUE(strong_tester.WithInitialValue(FollowsStrongGuarantee{}).Test());
}
struct HasReset : public NonNegative {
void operator()() {
i = -1;
ThrowingValue<> bomb;
i = 1;
}
void reset() { i = 0; }
};
testing::AssertionResult CheckHasResetInvariants(HasReset* h) {
h->reset();
return testing::AssertionResult(h->i == 0);
}
TEST(ExceptionCheckTest, ModifyingChecker) {
auto set_to_1000 = [](FollowsBasicGuarantee* g) {
g->i = 1000;
return testing::AssertionSuccess();
};
auto is_1000 = [](FollowsBasicGuarantee* g) {
return testing::AssertionResult(g->i == 1000);
};
auto increment = [](FollowsStrongGuarantee* g) {
++g->i;
return testing::AssertionSuccess();
};
EXPECT_FALSE(tester.WithInitialValue(FollowsBasicGuarantee{})
.WithInvariants(set_to_1000, is_1000)
.Test());
EXPECT_TRUE(strong_tester.WithInitialValue(FollowsStrongGuarantee{})
.WithInvariants(increment)
.Test());
EXPECT_TRUE(testing::MakeExceptionSafetyTester()
.WithInitialValue(HasReset{})
.WithInvariants(CheckHasResetInvariants)
.Test(invoker));
}
struct NonCopyable : public NonNegative {
NonCopyable(const NonCopyable&) = delete;
NonCopyable() : NonNegative{0} {}
void operator()() { ThrowingValue<> bomb; }
};
TEST(ExceptionCheckTest, NonCopyable) {
auto factory = []() { return absl::make_unique<NonCopyable>(); };
EXPECT_TRUE(tester.WithFactory(factory).Test());
EXPECT_TRUE(strong_tester.WithFactory(factory).Test());
}
struct NonEqualityComparable : public NonNegative {
void operator()() { ThrowingValue<> bomb; }
void ModifyOnThrow() {
++i;
ThrowingValue<> bomb;
static_cast<void>(bomb);
--i;
}
};
TEST(ExceptionCheckTest, NonEqualityComparable) {
auto nec_is_strong = [](NonEqualityComparable* nec) {
return testing::AssertionResult(nec->i == NonEqualityComparable().i);
};
auto strong_nec_tester = tester.WithInitialValue(NonEqualityComparable{})
.WithInvariants(nec_is_strong);
EXPECT_TRUE(strong_nec_tester.Test());
EXPECT_FALSE(strong_nec_tester.Test(
[](NonEqualityComparable* n) { n->ModifyOnThrow(); }));
}
template <typename T>
struct ExhaustivenessTester {
void operator()() {
successes |= 1;
T b1;
static_cast<void>(b1);
successes |= (1 << 1);
T b2;
static_cast<void>(b2);
successes |= (1 << 2);
T b3;
static_cast<void>(b3);
successes |= (1 << 3);
}
bool operator==(const ExhaustivenessTester<ThrowingValue<>>&) const {
return true;
}
static unsigned char successes;
};
struct {
template <typename T>
testing::AssertionResult operator()(ExhaustivenessTester<T>*) const {
return testing::AssertionSuccess();
}
} CheckExhaustivenessTesterInvariants;
template <typename T>
unsigned char ExhaustivenessTester<T>::successes = 0;
TEST(ExceptionCheckTest, Exhaustiveness) {
auto exhaust_tester = testing::MakeExceptionSafetyTester()
.WithInvariants(CheckExhaustivenessTesterInvariants)
.WithOperation(invoker);
EXPECT_TRUE(
exhaust_tester.WithInitialValue(ExhaustivenessTester<int>{}).Test());
EXPECT_EQ(ExhaustivenessTester<int>::successes, 0xF);
EXPECT_TRUE(
exhaust_tester.WithInitialValue(ExhaustivenessTester<ThrowingValue<>>{})
.WithInvariants(testing::strong_guarantee)
.Test());
EXPECT_EQ(ExhaustivenessTester<ThrowingValue<>>::successes, 0xF);
}
struct LeaksIfCtorThrows : private exceptions_internal::TrackedObject {
LeaksIfCtorThrows() : TrackedObject(ABSL_PRETTY_FUNCTION) {
++counter;
ThrowingValue<> v;
static_cast<void>(v);
--counter;
}
LeaksIfCtorThrows(const LeaksIfCtorThrows&) noexcept
: TrackedObject(ABSL_PRETTY_FUNCTION) {}
static int counter;
};
int LeaksIfCtorThrows::counter = 0;
TEST(ExceptionCheckTest, TestLeakyCtor) {
testing::TestThrowingCtor<LeaksIfCtorThrows>();
EXPECT_EQ(LeaksIfCtorThrows::counter, 1);
LeaksIfCtorThrows::counter = 0;
}
struct Tracked : private exceptions_internal::TrackedObject {
Tracked() : TrackedObject(ABSL_PRETTY_FUNCTION) {}
};
TEST(ConstructorTrackerTest, CreatedBefore) {
Tracked a, b, c;
exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
}
TEST(ConstructorTrackerTest, CreatedAfter) {
exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
Tracked a, b, c;
}
TEST(ConstructorTrackerTest, NotDestroyedAfter) {
absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage;
EXPECT_NONFATAL_FAILURE(
{
exceptions_internal::ConstructorTracker ct(
exceptions_internal::countdown);
new (&storage) Tracked;
},
"not destroyed");
}
TEST(ConstructorTrackerTest, DestroyedTwice) {
exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
EXPECT_NONFATAL_FAILURE(
{
Tracked t;
t.~Tracked();
},
"re-destroyed");
}
TEST(ConstructorTrackerTest, ConstructedTwice) {
exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage;
EXPECT_NONFATAL_FAILURE(
{
new (&storage) Tracked;
new (&storage) Tracked;
reinterpret_cast<Tracked*>(&storage)->~Tracked();
},
"re-constructed");
}
TEST(ThrowingValueTraitsTest, RelationalOperators) {
ThrowingValue<> a, b;
EXPECT_TRUE((std::is_convertible<decltype(a == b), bool>::value));
EXPECT_TRUE((std::is_convertible<decltype(a != b), bool>::value));
EXPECT_TRUE((std::is_convertible<decltype(a < b), bool>::value));
EXPECT_TRUE((std::is_convertible<decltype(a <= b), bool>::value));
EXPECT_TRUE((std::is_convertible<decltype(a > b), bool>::value));
EXPECT_TRUE((std::is_convertible<decltype(a >= b), bool>::value));
}
TEST(ThrowingAllocatorTraitsTest, Assignablility) {
EXPECT_TRUE(std::is_move_assignable<ThrowingAllocator<int>>::value);
EXPECT_TRUE(std::is_copy_assignable<ThrowingAllocator<int>>::value);
EXPECT_TRUE(std::is_nothrow_move_assignable<ThrowingAllocator<int>>::value);
EXPECT_TRUE(std::is_nothrow_copy_assignable<ThrowingAllocator<int>>::value);
}
} // namespace
} // namespace testing

View File

@ -1,62 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include <type_traits>
#include "absl/base/internal/inline_variable.h"
#include "absl/base/internal/inline_variable_testing.h"
#include "gtest/gtest.h"
namespace absl {
namespace inline_variable_testing_internal {
namespace {
TEST(InlineVariableTest, Constexpr) {
static_assert(inline_variable_foo.value == 5, "");
static_assert(other_inline_variable_foo.value == 5, "");
static_assert(inline_variable_int == 5, "");
static_assert(other_inline_variable_int == 5, "");
}
TEST(InlineVariableTest, DefaultConstructedIdentityEquality) {
EXPECT_EQ(get_foo_a().value, 5);
EXPECT_EQ(get_foo_b().value, 5);
EXPECT_EQ(&get_foo_a(), &get_foo_b());
}
TEST(InlineVariableTest, DefaultConstructedIdentityInequality) {
EXPECT_NE(&inline_variable_foo, &other_inline_variable_foo);
}
TEST(InlineVariableTest, InitializedIdentityEquality) {
EXPECT_EQ(get_int_a(), 5);
EXPECT_EQ(get_int_b(), 5);
EXPECT_EQ(&get_int_a(), &get_int_b());
}
TEST(InlineVariableTest, InitializedIdentityInequality) {
EXPECT_NE(&inline_variable_int, &other_inline_variable_int);
}
TEST(InlineVariableTest, FunPtrType) {
static_assert(
std::is_same<void(*)(),
std::decay<decltype(inline_variable_fun_ptr)>::type>::value,
"");
}
} // namespace
} // namespace inline_variable_testing_internal
} // namespace absl

View File

@ -1,25 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include "absl/base/internal/inline_variable_testing.h"
namespace absl {
namespace inline_variable_testing_internal {
const Foo& get_foo_a() { return inline_variable_foo; }
const int& get_int_a() { return inline_variable_int; }
} // namespace inline_variable_testing_internal
} // namespace absl

View File

@ -1,25 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include "absl/base/internal/inline_variable_testing.h"
namespace absl {
namespace inline_variable_testing_internal {
const Foo& get_foo_b() { return inline_variable_foo; }
const int& get_int_b() { return inline_variable_int; }
} // namespace inline_variable_testing_internal
} // namespace absl

View File

@ -1,165 +0,0 @@
// Copyright 2017 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
//
// http://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.
//
#ifndef ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
#define ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
#include <atomic>
#include <cassert>
#include <cstdint>
#include <utility>
#ifdef _MSC_FULL_VER
#define ABSL_HAVE_WORKING_ATOMIC_POINTER 0
#else
#define ABSL_HAVE_WORKING_ATOMIC_POINTER 1
#endif
namespace absl {
namespace base_internal {
template <typename T>
class AtomicHook;
// AtomicHook is a helper class, templatized on a raw function pointer type, for
// implementing Abseil customization hooks. It is a callable object that
// dispatches to the registered hook.
//
// A default constructed object performs a no-op (and returns a default
// constructed object) if no hook has been registered.
//
// Hooks can be pre-registered via constant initialization, for example,
// ABSL_CONST_INIT static AtomicHook<void(*)()> my_hook(DefaultAction);
// and then changed at runtime via a call to Store().
//
// Reads and writes guarantee memory_order_acquire/memory_order_release
// semantics.
template <typename ReturnType, typename... Args>
class AtomicHook<ReturnType (*)(Args...)> {
public:
using FnPtr = ReturnType (*)(Args...);
// Constructs an object that by default performs a no-op (and
// returns a default constructed object) when no hook as been registered.
constexpr AtomicHook() : AtomicHook(DummyFunction) {}
// Constructs an object that by default dispatches to/returns the
// pre-registered default_fn when no hook has been registered at runtime.
#if ABSL_HAVE_WORKING_ATOMIC_POINTER
explicit constexpr AtomicHook(FnPtr default_fn)
: hook_(default_fn), default_fn_(default_fn) {}
#else
explicit constexpr AtomicHook(FnPtr default_fn)
: hook_(kUninitialized), default_fn_(default_fn) {}
#endif
// Stores the provided function pointer as the value for this hook.
//
// This is intended to be called once. Multiple calls are legal only if the
// same function pointer is provided for each call. The store is implemented
// as a memory_order_release operation, and read accesses are implemented as
// memory_order_acquire.
void Store(FnPtr fn) {
bool success = DoStore(fn);
static_cast<void>(success);
assert(success);
}
// Invokes the registered callback. If no callback has yet been registered, a
// default-constructed object of the appropriate type is returned instead.
template <typename... CallArgs>
ReturnType operator()(CallArgs&&... args) const {
return DoLoad()(std::forward<CallArgs>(args)...);
}
// Returns the registered callback, or nullptr if none has been registered.
// Useful if client code needs to conditionalize behavior based on whether a
// callback was registered.
//
// Note that atomic_hook.Load()() and atomic_hook() have different semantics:
// operator()() will perform a no-op if no callback was registered, while
// Load()() will dereference a null function pointer. Prefer operator()() to
// Load()() unless you must conditionalize behavior on whether a hook was
// registered.
FnPtr Load() const {
FnPtr ptr = DoLoad();
return (ptr == DummyFunction) ? nullptr : ptr;
}
private:
static ReturnType DummyFunction(Args...) {
return ReturnType();
}
// Current versions of MSVC (as of September 2017) have a broken
// implementation of std::atomic<T*>: Its constructor attempts to do the
// equivalent of a reinterpret_cast in a constexpr context, which is not
// allowed.
//
// This causes an issue when building with LLVM under Windows. To avoid this,
// we use a less-efficient, intptr_t-based implementation on Windows.
#if ABSL_HAVE_WORKING_ATOMIC_POINTER
// Return the stored value, or DummyFunction if no value has been stored.
FnPtr DoLoad() const { return hook_.load(std::memory_order_acquire); }
// Store the given value. Returns false if a different value was already
// stored to this object.
bool DoStore(FnPtr fn) {
assert(fn);
FnPtr expected = default_fn_;
const bool store_succeeded = hook_.compare_exchange_strong(
expected, fn, std::memory_order_acq_rel, std::memory_order_acquire);
const bool same_value_already_stored = (expected == fn);
return store_succeeded || same_value_already_stored;
}
std::atomic<FnPtr> hook_;
#else // !ABSL_HAVE_WORKING_ATOMIC_POINTER
// Use a sentinel value unlikely to be the address of an actual function.
static constexpr intptr_t kUninitialized = 0;
static_assert(sizeof(intptr_t) >= sizeof(FnPtr),
"intptr_t can't contain a function pointer");
FnPtr DoLoad() const {
const intptr_t value = hook_.load(std::memory_order_acquire);
if (value == kUninitialized) {
return default_fn_;
}
return reinterpret_cast<FnPtr>(value);
}
bool DoStore(FnPtr fn) {
assert(fn);
const auto value = reinterpret_cast<intptr_t>(fn);
intptr_t expected = kUninitialized;
const bool store_succeeded = hook_.compare_exchange_strong(
expected, value, std::memory_order_acq_rel, std::memory_order_acquire);
const bool same_value_already_stored = (expected == value);
return store_succeeded || same_value_already_stored;
}
std::atomic<intptr_t> hook_;
#endif
const FnPtr default_fn_;
};
#undef ABSL_HAVE_WORKING_ATOMIC_POINTER
} // namespace base_internal
} // namespace absl
#endif // ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_

View File

@ -1,70 +0,0 @@
// Copyright 2018 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
//
// http://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.
#include "absl/base/internal/atomic_hook.h"
#include "gtest/gtest.h"
#include "absl/base/attributes.h"
namespace {
int value = 0;
void TestHook(int x) { value = x; }
TEST(AtomicHookTest, NoDefaultFunction) {
ABSL_CONST_INIT static absl::base_internal::AtomicHook<void(*)(int)> hook;
value = 0;
// Test the default DummyFunction.
EXPECT_TRUE(hook.Load() == nullptr);
EXPECT_EQ(value, 0);
hook(1);
EXPECT_EQ(value, 0);
// Test a stored hook.
hook.Store(TestHook);
EXPECT_TRUE(hook.Load() == TestHook);
EXPECT_EQ(value, 0);
hook(1);
EXPECT_EQ(value, 1);
// Calling Store() with the same hook should not crash.
hook.Store(TestHook);
EXPECT_TRUE(hook.Load() == TestHook);
EXPECT_EQ(value, 1);
hook(2);
EXPECT_EQ(value, 2);
}
TEST(AtomicHookTest, WithDefaultFunction) {
// Set the default value to TestHook at compile-time.
ABSL_CONST_INIT static absl::base_internal::AtomicHook<void (*)(int)> hook(
TestHook);
value = 0;
// Test the default value is TestHook.
EXPECT_TRUE(hook.Load() == TestHook);
EXPECT_EQ(value, 0);
hook(1);
EXPECT_EQ(value, 1);
// Calling Store() with the same hook should not crash.
hook.Store(TestHook);
EXPECT_TRUE(hook.Load() == TestHook);
EXPECT_EQ(value, 1);
hook(2);
EXPECT_EQ(value, 2);
}
} // namespace

View File

@ -1,81 +0,0 @@
// Copyright 2017 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
//
// http://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.
// The implementation of CycleClock::Frequency.
//
// NOTE: only i386 and x86_64 have been well tested.
// PPC, sparc, alpha, and ia64 are based on
// http://peter.kuscsik.com/wordpress/?p=14
// with modifications by m3b. See also
// https://setisvn.ssl.berkeley.edu/svn/lib/fftw-3.0.1/kernel/cycle.h
#include "absl/base/internal/cycleclock.h"
#include <chrono> // NOLINT(build/c++11)
#include "absl/base/internal/unscaledcycleclock.h"
namespace absl {
namespace base_internal {
#if ABSL_USE_UNSCALED_CYCLECLOCK
namespace {
#ifdef NDEBUG
#ifdef ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
// Not debug mode and the UnscaledCycleClock frequency is the CPU
// frequency. Scale the CycleClock to prevent overflow if someone
// tries to represent the time as cycles since the Unix epoch.
static constexpr int32_t kShift = 1;
#else
// Not debug mode and the UnscaledCycleClock isn't operating at the
// raw CPU frequency. There is no need to do any scaling, so don't
// needlessly sacrifice precision.
static constexpr int32_t kShift = 0;
#endif
#else
// In debug mode use a different shift to discourage depending on a
// particular shift value.
static constexpr int32_t kShift = 2;
#endif
static constexpr double kFrequencyScale = 1.0 / (1 << kShift);
} // namespace
int64_t CycleClock::Now() {
return base_internal::UnscaledCycleClock::Now() >> kShift;
}
double CycleClock::Frequency() {
return kFrequencyScale * base_internal::UnscaledCycleClock::Frequency();
}
#else
int64_t CycleClock::Now() {
return std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::steady_clock::now().time_since_epoch())
.count();
}
double CycleClock::Frequency() {
return 1e9;
}
#endif
} // namespace base_internal
} // namespace absl

View File

@ -1,77 +0,0 @@
//
// Copyright 2017 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
//
// http://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.
//
// -----------------------------------------------------------------------------
// File: cycleclock.h
// -----------------------------------------------------------------------------
//
// This header file defines a `CycleClock`, which yields the value and frequency
// of a cycle counter that increments at a rate that is approximately constant.
//
// NOTE:
//
// The cycle counter frequency is not necessarily related to the core clock
// frequency and should not be treated as such. That is, `CycleClock` cycles are
// not necessarily "CPU cycles" and code should not rely on that behavior, even
// if experimentally observed.
//
//
// An arbitrary offset may have been added to the counter at power on.
//
// On some platforms, the rate and offset of the counter may differ
// slightly when read from different CPUs of a multiprocessor. Usually,
// we try to ensure that the operating system adjusts values periodically
// so that values agree approximately. If you need stronger guarantees,
// consider using alternate interfaces.
//
// The CPU is not required to maintain the ordering of a cycle counter read
// with respect to surrounding instructions.
#ifndef ABSL_BASE_INTERNAL_CYCLECLOCK_H_
#define ABSL_BASE_INTERNAL_CYCLECLOCK_H_
#include <cstdint>
namespace absl {
namespace base_internal {
// -----------------------------------------------------------------------------
// CycleClock
// -----------------------------------------------------------------------------
class CycleClock {
public:
// CycleClock::Now()
//
// Returns the value of a cycle counter that counts at a rate that is
// approximately constant.
static int64_t Now();
// CycleClock::Frequency()
//
// Returns the amount by which `CycleClock::Now()` increases per second. Note
// that this value may not necessarily match the core CPU clock frequency.
static double Frequency();
private:
CycleClock() = delete; // no instances
CycleClock(const CycleClock&) = delete;
CycleClock& operator=(const CycleClock&) = delete;
};
} // namespace base_internal
} // namespace absl
#endif // ABSL_BASE_INTERNAL_CYCLECLOCK_H_

View File

@ -1,151 +0,0 @@
// Copyright 2017 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
//
// http://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.
//
// Functions for directly invoking mmap() via syscall, avoiding the case where
// mmap() has been locally overridden.
#ifndef ABSL_BASE_INTERNAL_DIRECT_MMAP_H_
#define ABSL_BASE_INTERNAL_DIRECT_MMAP_H_
#include "absl/base/config.h"
#if ABSL_HAVE_MMAP
#include <sys/mman.h>
#ifdef __linux__
#include <sys/types.h>
#ifdef __BIONIC__
#include <sys/syscall.h>
#else
#include <syscall.h>
#endif
#include <linux/unistd.h>
#include <unistd.h>
#include <cerrno>
#include <cstdarg>
#include <cstdint>
#ifdef __mips__
// Include definitions of the ABI currently in use.
#ifdef __BIONIC__
// Android doesn't have sgidefs.h, but does have asm/sgidefs.h, which has the
// definitions we need.
#include <asm/sgidefs.h>
#else
#include <sgidefs.h>
#endif // __BIONIC__
#endif // __mips__
// SYS_mmap and SYS_munmap are not defined in Android.
#ifdef __BIONIC__
extern "C" void* __mmap2(void*, size_t, int, int, int, size_t);
#if defined(__NR_mmap) && !defined(SYS_mmap)
#define SYS_mmap __NR_mmap
#endif
#ifndef SYS_munmap
#define SYS_munmap __NR_munmap
#endif
#endif // __BIONIC__
namespace absl {
namespace base_internal {
// Platform specific logic extracted from
// https://chromium.googlesource.com/linux-syscall-support/+/master/linux_syscall_support.h
inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd,
off64_t offset) noexcept {
#if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \
(defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \
(defined(__PPC__) && !defined(__PPC64__)) || \
(defined(__s390__) && !defined(__s390x__))
// On these architectures, implement mmap with mmap2.
static int pagesize = 0;
if (pagesize == 0) {
pagesize = getpagesize();
}
if (offset < 0 || offset % pagesize != 0) {
errno = EINVAL;
return MAP_FAILED;
}
#ifdef __BIONIC__
// SYS_mmap2 has problems on Android API level <= 16.
// Workaround by invoking __mmap2() instead.
return __mmap2(start, length, prot, flags, fd, offset / pagesize);
#else
return reinterpret_cast<void*>(
syscall(SYS_mmap2, start, length, prot, flags, fd,
static_cast<off_t>(offset / pagesize)));
#endif
#elif defined(__s390x__)
// On s390x, mmap() arguments are passed in memory.
uint32_t buf[6] = {
reinterpret_cast<uint32_t>(start), static_cast<uint32_t>(length),
static_cast<uint32_t>(prot), static_cast<uint32_t>(flags),
static_cast<uint32_t>(fd), static_cast<uint32_t>(offset)};
return reintrepret_cast<void*>(syscall(SYS_mmap, buf));
#elif defined(__x86_64__)
// The x32 ABI has 32 bit longs, but the syscall interface is 64 bit.
// We need to explicitly cast to an unsigned 64 bit type to avoid implicit
// sign extension. We can't cast pointers directly because those are
// 32 bits, and gcc will dump ugly warnings about casting from a pointer
// to an integer of a different size. We also need to make sure __off64_t
// isn't truncated to 32-bits under x32.
#define MMAP_SYSCALL_ARG(x) ((uint64_t)(uintptr_t)(x))
return reinterpret_cast<void*>(
syscall(SYS_mmap, MMAP_SYSCALL_ARG(start), MMAP_SYSCALL_ARG(length),
MMAP_SYSCALL_ARG(prot), MMAP_SYSCALL_ARG(flags),
MMAP_SYSCALL_ARG(fd), static_cast<uint64_t>(offset)));
#undef MMAP_SYSCALL_ARG
#else // Remaining 64-bit aritectures.
static_assert(sizeof(unsigned long) == 8, "Platform is not 64-bit");
return reinterpret_cast<void*>(
syscall(SYS_mmap, start, length, prot, flags, fd, offset));
#endif
}
inline int DirectMunmap(void* start, size_t length) {
return static_cast<int>(syscall(SYS_munmap, start, length));
}
} // namespace base_internal
} // namespace absl
#else // !__linux__
// For non-linux platforms where we have mmap, just dispatch directly to the
// actual mmap()/munmap() methods.
namespace absl {
namespace base_internal {
inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd,
off_t offset) {
return mmap(start, length, prot, flags, fd, offset);
}
inline int DirectMunmap(void* start, size_t length) {
return munmap(start, length);
}
} // namespace base_internal
} // namespace absl
#endif // __linux__
#endif // ABSL_HAVE_MMAP
#endif // ABSL_BASE_INTERNAL_DIRECT_MMAP_H_

View File

@ -1,269 +0,0 @@
// Copyright 2017 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
//
// http://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.
//
#ifndef ABSL_BASE_INTERNAL_ENDIAN_H_
#define ABSL_BASE_INTERNAL_ENDIAN_H_
// The following guarantees declaration of the byte swap functions
#ifdef _MSC_VER
#include <stdlib.h> // NOLINT(build/include)
#elif defined(__APPLE__)
// Mac OS X / Darwin features
#include <libkern/OSByteOrder.h>
#elif defined(__FreeBSD__)
#include <sys/endian.h>
#elif defined(__GLIBC__)
#include <byteswap.h> // IWYU pragma: export
#endif
#include <cstdint>
#include "absl/base/config.h"
#include "absl/base/internal/unaligned_access.h"
#include "absl/base/port.h"
namespace absl {
// Use compiler byte-swapping intrinsics if they are available. 32-bit
// and 64-bit versions are available in Clang and GCC as of GCC 4.3.0.
// The 16-bit version is available in Clang and GCC only as of GCC 4.8.0.
// For simplicity, we enable them all only for GCC 4.8.0 or later.
#if defined(__clang__) || \
(defined(__GNUC__) && \
((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ >= 5))
inline uint64_t gbswap_64(uint64_t host_int) {
return __builtin_bswap64(host_int);
}
inline uint32_t gbswap_32(uint32_t host_int) {
return __builtin_bswap32(host_int);
}
inline uint16_t gbswap_16(uint16_t host_int) {
return __builtin_bswap16(host_int);
}
#elif defined(_MSC_VER)
inline uint64_t gbswap_64(uint64_t host_int) {
return _byteswap_uint64(host_int);
}
inline uint32_t gbswap_32(uint32_t host_int) {
return _byteswap_ulong(host_int);
}
inline uint16_t gbswap_16(uint16_t host_int) {
return _byteswap_ushort(host_int);
}
#elif defined(__APPLE__)
inline uint64_t gbswap_64(uint64_t host_int) { return OSSwapInt16(host_int); }
inline uint32_t gbswap_32(uint32_t host_int) { return OSSwapInt32(host_int); }
inline uint16_t gbswap_16(uint16_t host_int) { return OSSwapInt64(host_int); }
#else
inline uint64_t gbswap_64(uint64_t host_int) {
#if defined(__GNUC__) && defined(__x86_64__) && !defined(__APPLE__)
// Adapted from /usr/include/byteswap.h. Not available on Mac.
if (__builtin_constant_p(host_int)) {
return __bswap_constant_64(host_int);
} else {
register uint64_t result;
__asm__("bswap %0" : "=r"(result) : "0"(host_int));
return result;
}
#elif defined(__GLIBC__)
return bswap_64(host_int);
#else
return (((x & uint64_t{(0xFF}) << 56) |
((x & uint64_t{(0xFF00}) << 40) |
((x & uint64_t{(0xFF0000}) << 24) |
((x & uint64_t{(0xFF000000}) << 8) |
((x & uint64_t{(0xFF00000000}) >> 8) |
((x & uint64_t{(0xFF0000000000}) >> 24) |
((x & uint64_t{(0xFF000000000000}) >> 40) |
((x & uint64_t{(0xFF00000000000000}) >> 56));
#endif // bswap_64
}
inline uint32_t gbswap_32(uint32_t host_int) {
#if defined(__GLIBC__)
return bswap_32(host_int);
#else
return (((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) |
((x & 0xFF000000) >> 24));
#endif
}
inline uint16_t gbswap_16(uint16_t host_int) {
#if defined(__GLIBC__)
return bswap_16(host_int);
#else
return uint16_t{((x & 0xFF) << 8) | ((x & 0xFF00) >> 8)};
#endif
}
#endif // intrinics available
#ifdef ABSL_IS_LITTLE_ENDIAN
// Definitions for ntohl etc. that don't require us to include
// netinet/in.h. We wrap gbswap_32 and gbswap_16 in functions rather
// than just #defining them because in debug mode, gcc doesn't
// correctly handle the (rather involved) definitions of bswap_32.
// gcc guarantees that inline functions are as fast as macros, so
// this isn't a performance hit.
inline uint16_t ghtons(uint16_t x) { return gbswap_16(x); }
inline uint32_t ghtonl(uint32_t x) { return gbswap_32(x); }
inline uint64_t ghtonll(uint64_t x) { return gbswap_64(x); }
#elif defined ABSL_IS_BIG_ENDIAN
// These definitions are simpler on big-endian machines
// These are functions instead of macros to avoid self-assignment warnings
// on calls such as "i = ghtnol(i);". This also provides type checking.
inline uint16_t ghtons(uint16_t x) { return x; }
inline uint32_t ghtonl(uint32_t x) { return x; }
inline uint64_t ghtonll(uint64_t x) { return x; }
#else
#error \
"Unsupported byte order: Either ABSL_IS_BIG_ENDIAN or " \
"ABSL_IS_LITTLE_ENDIAN must be defined"
#endif // byte order
inline uint16_t gntohs(uint16_t x) { return ghtons(x); }
inline uint32_t gntohl(uint32_t x) { return ghtonl(x); }
inline uint64_t gntohll(uint64_t x) { return ghtonll(x); }
// Utilities to convert numbers between the current hosts's native byte
// order and little-endian byte order
//
// Load/Store methods are alignment safe
namespace little_endian {
// Conversion functions.
#ifdef ABSL_IS_LITTLE_ENDIAN
inline uint16_t FromHost16(uint16_t x) { return x; }
inline uint16_t ToHost16(uint16_t x) { return x; }
inline uint32_t FromHost32(uint32_t x) { return x; }
inline uint32_t ToHost32(uint32_t x) { return x; }
inline uint64_t FromHost64(uint64_t x) { return x; }
inline uint64_t ToHost64(uint64_t x) { return x; }
inline constexpr bool IsLittleEndian() { return true; }
#elif defined ABSL_IS_BIG_ENDIAN
inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); }
inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); }
inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); }
inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); }
inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); }
inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); }
inline constexpr bool IsLittleEndian() { return false; }
#endif /* ENDIAN */
// Functions to do unaligned loads and stores in little-endian order.
inline uint16_t Load16(const void *p) {
return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
}
inline void Store16(void *p, uint16_t v) {
ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
}
inline uint32_t Load32(const void *p) {
return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p));
}
inline void Store32(void *p, uint32_t v) {
ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
}
inline uint64_t Load64(const void *p) {
return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p));
}
inline void Store64(void *p, uint64_t v) {
ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
}
} // namespace little_endian
// Utilities to convert numbers between the current hosts's native byte
// order and big-endian byte order (same as network byte order)
//
// Load/Store methods are alignment safe
namespace big_endian {
#ifdef ABSL_IS_LITTLE_ENDIAN
inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); }
inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); }
inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); }
inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); }
inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); }
inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); }
inline constexpr bool IsLittleEndian() { return true; }
#elif defined ABSL_IS_BIG_ENDIAN
inline uint16_t FromHost16(uint16_t x) { return x; }
inline uint16_t ToHost16(uint16_t x) { return x; }
inline uint32_t FromHost32(uint32_t x) { return x; }
inline uint32_t ToHost32(uint32_t x) { return x; }
inline uint64_t FromHost64(uint64_t x) { return x; }
inline uint64_t ToHost64(uint64_t x) { return x; }
inline constexpr bool IsLittleEndian() { return false; }
#endif /* ENDIAN */
// Functions to do unaligned loads and stores in big-endian order.
inline uint16_t Load16(const void *p) {
return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
}
inline void Store16(void *p, uint16_t v) {
ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
}
inline uint32_t Load32(const void *p) {
return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p));
}
inline void Store32(void *p, uint32_t v) {
ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
}
inline uint64_t Load64(const void *p) {
return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p));
}
inline void Store64(void *p, uint64_t v) {
ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
}
} // namespace big_endian
} // namespace absl
#endif // ABSL_BASE_INTERNAL_ENDIAN_H_

View File

@ -1,279 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include "absl/base/internal/endian.h"
#include <algorithm>
#include <cstdint>
#include <limits>
#include <random>
#include <vector>
#include "gtest/gtest.h"
#include "absl/base/config.h"
namespace absl {
namespace {
const uint64_t kInitialNumber{0x0123456789abcdef};
const uint64_t k64Value{kInitialNumber};
const uint32_t k32Value{0x01234567};
const uint16_t k16Value{0x0123};
const int kNumValuesToTest = 1000000;
const int kRandomSeed = 12345;
#ifdef ABSL_IS_BIG_ENDIAN
const uint64_t kInitialInNetworkOrder{kInitialNumber};
const uint64_t k64ValueLE{0xefcdab8967452301};
const uint32_t k32ValueLE{0x67452301};
const uint16_t k16ValueLE{0x2301};
const uint8_t k8ValueLE{k8Value};
const uint64_t k64IValueLE{0xefcdab89674523a1};
const uint32_t k32IValueLE{0x67452391};
const uint16_t k16IValueLE{0x85ff};
const uint8_t k8IValueLE{0xff};
const uint64_t kDoubleValueLE{0x6e861bf0f9210940};
const uint32_t kFloatValueLE{0xd00f4940};
const uint8_t kBoolValueLE{0x1};
const uint64_t k64ValueBE{kInitialNumber};
const uint32_t k32ValueBE{k32Value};
const uint16_t k16ValueBE{k16Value};
const uint8_t k8ValueBE{k8Value};
const uint64_t k64IValueBE{0xa123456789abcdef};
const uint32_t k32IValueBE{0x91234567};
const uint16_t k16IValueBE{0xff85};
const uint8_t k8IValueBE{0xff};
const uint64_t kDoubleValueBE{0x400921f9f01b866e};
const uint32_t kFloatValueBE{0x40490fd0};
const uint8_t kBoolValueBE{0x1};
#elif defined ABSL_IS_LITTLE_ENDIAN
const uint64_t kInitialInNetworkOrder{0xefcdab8967452301};
const uint64_t k64ValueLE{kInitialNumber};
const uint32_t k32ValueLE{k32Value};
const uint16_t k16ValueLE{k16Value};
const uint64_t k64ValueBE{0xefcdab8967452301};
const uint32_t k32ValueBE{0x67452301};
const uint16_t k16ValueBE{0x2301};
#endif
template<typename T>
std::vector<T> GenerateAllValuesForType() {
std::vector<T> result;
T next = std::numeric_limits<T>::min();
while (true) {
result.push_back(next);
if (next == std::numeric_limits<T>::max()) {
return result;
}
++next;
}
}
template<typename T>
std::vector<T> GenerateRandomIntegers(size_t numValuesToTest) {
std::vector<T> result;
std::mt19937_64 rng(kRandomSeed);
for (size_t i = 0; i < numValuesToTest; ++i) {
result.push_back(rng());
}
return result;
}
void ManualByteSwap(char* bytes, int length) {
if (length == 1)
return;
EXPECT_EQ(0, length % 2);
for (int i = 0; i < length / 2; ++i) {
int j = (length - 1) - i;
using std::swap;
swap(bytes[i], bytes[j]);
}
}
template<typename T>
inline T UnalignedLoad(const char* p) {
static_assert(
sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8,
"Unexpected type size");
switch (sizeof(T)) {
case 1: return *reinterpret_cast<const T*>(p);
case 2:
return ABSL_INTERNAL_UNALIGNED_LOAD16(p);
case 4:
return ABSL_INTERNAL_UNALIGNED_LOAD32(p);
case 8:
return ABSL_INTERNAL_UNALIGNED_LOAD64(p);
default:
// Suppresses invalid "not all control paths return a value" on MSVC
return {};
}
}
template <typename T, typename ByteSwapper>
static void GBSwapHelper(const std::vector<T>& host_values_to_test,
const ByteSwapper& byte_swapper) {
// Test byte_swapper against a manual byte swap.
for (typename std::vector<T>::const_iterator it = host_values_to_test.begin();
it != host_values_to_test.end(); ++it) {
T host_value = *it;
char actual_value[sizeof(host_value)];
memcpy(actual_value, &host_value, sizeof(host_value));
byte_swapper(actual_value);
char expected_value[sizeof(host_value)];
memcpy(expected_value, &host_value, sizeof(host_value));
ManualByteSwap(expected_value, sizeof(host_value));
ASSERT_EQ(0, memcmp(actual_value, expected_value, sizeof(host_value)))
<< "Swap output for 0x" << std::hex << host_value << " does not match. "
<< "Expected: 0x" << UnalignedLoad<T>(expected_value) << "; "
<< "actual: 0x" << UnalignedLoad<T>(actual_value);
}
}
void Swap16(char* bytes) {
ABSL_INTERNAL_UNALIGNED_STORE16(
bytes, gbswap_16(ABSL_INTERNAL_UNALIGNED_LOAD16(bytes)));
}
void Swap32(char* bytes) {
ABSL_INTERNAL_UNALIGNED_STORE32(
bytes, gbswap_32(ABSL_INTERNAL_UNALIGNED_LOAD32(bytes)));
}
void Swap64(char* bytes) {
ABSL_INTERNAL_UNALIGNED_STORE64(
bytes, gbswap_64(ABSL_INTERNAL_UNALIGNED_LOAD64(bytes)));
}
TEST(EndianessTest, Uint16) {
GBSwapHelper(GenerateAllValuesForType<uint16_t>(), &Swap16);
}
TEST(EndianessTest, Uint32) {
GBSwapHelper(GenerateRandomIntegers<uint32_t>(kNumValuesToTest), &Swap32);
}
TEST(EndianessTest, Uint64) {
GBSwapHelper(GenerateRandomIntegers<uint64_t>(kNumValuesToTest), &Swap64);
}
TEST(EndianessTest, ghtonll_gntohll) {
// Test that absl::ghtonl compiles correctly
uint32_t test = 0x01234567;
EXPECT_EQ(absl::gntohl(absl::ghtonl(test)), test);
uint64_t comp = absl::ghtonll(kInitialNumber);
EXPECT_EQ(comp, kInitialInNetworkOrder);
comp = absl::gntohll(kInitialInNetworkOrder);
EXPECT_EQ(comp, kInitialNumber);
// Test that htonll and ntohll are each others' inverse functions on a
// somewhat assorted batch of numbers. 37 is chosen to not be anything
// particularly nice base 2.
uint64_t value = 1;
for (int i = 0; i < 100; ++i) {
comp = absl::ghtonll(absl::gntohll(value));
EXPECT_EQ(value, comp);
comp = absl::gntohll(absl::ghtonll(value));
EXPECT_EQ(value, comp);
value *= 37;
}
}
TEST(EndianessTest, little_endian) {
// Check little_endian uint16_t.
uint64_t comp = little_endian::FromHost16(k16Value);
EXPECT_EQ(comp, k16ValueLE);
comp = little_endian::ToHost16(k16ValueLE);
EXPECT_EQ(comp, k16Value);
// Check little_endian uint32_t.
comp = little_endian::FromHost32(k32Value);
EXPECT_EQ(comp, k32ValueLE);
comp = little_endian::ToHost32(k32ValueLE);
EXPECT_EQ(comp, k32Value);
// Check little_endian uint64_t.
comp = little_endian::FromHost64(k64Value);
EXPECT_EQ(comp, k64ValueLE);
comp = little_endian::ToHost64(k64ValueLE);
EXPECT_EQ(comp, k64Value);
// Check little-endian Load and store functions.
uint16_t u16Buf;
uint32_t u32Buf;
uint64_t u64Buf;
little_endian::Store16(&u16Buf, k16Value);
EXPECT_EQ(u16Buf, k16ValueLE);
comp = little_endian::Load16(&u16Buf);
EXPECT_EQ(comp, k16Value);
little_endian::Store32(&u32Buf, k32Value);
EXPECT_EQ(u32Buf, k32ValueLE);
comp = little_endian::Load32(&u32Buf);
EXPECT_EQ(comp, k32Value);
little_endian::Store64(&u64Buf, k64Value);
EXPECT_EQ(u64Buf, k64ValueLE);
comp = little_endian::Load64(&u64Buf);
EXPECT_EQ(comp, k64Value);
}
TEST(EndianessTest, big_endian) {
// Check big-endian Load and store functions.
uint16_t u16Buf;
uint32_t u32Buf;
uint64_t u64Buf;
unsigned char buffer[10];
big_endian::Store16(&u16Buf, k16Value);
EXPECT_EQ(u16Buf, k16ValueBE);
uint64_t comp = big_endian::Load16(&u16Buf);
EXPECT_EQ(comp, k16Value);
big_endian::Store32(&u32Buf, k32Value);
EXPECT_EQ(u32Buf, k32ValueBE);
comp = big_endian::Load32(&u32Buf);
EXPECT_EQ(comp, k32Value);
big_endian::Store64(&u64Buf, k64Value);
EXPECT_EQ(u64Buf, k64ValueBE);
comp = big_endian::Load64(&u64Buf);
EXPECT_EQ(comp, k64Value);
big_endian::Store16(buffer + 1, k16Value);
EXPECT_EQ(u16Buf, k16ValueBE);
comp = big_endian::Load16(buffer + 1);
EXPECT_EQ(comp, k16Value);
big_endian::Store32(buffer + 1, k32Value);
EXPECT_EQ(u32Buf, k32ValueBE);
comp = big_endian::Load32(buffer + 1);
EXPECT_EQ(comp, k32Value);
big_endian::Store64(buffer + 1, k64Value);
EXPECT_EQ(u64Buf, k64ValueBE);
comp = big_endian::Load64(buffer + 1);
EXPECT_EQ(comp, k64Value);
}
} // namespace
} // namespace absl

View File

@ -1,71 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include "absl/base/internal/exception_safety_testing.h"
#include "gtest/gtest.h"
#include "absl/meta/type_traits.h"
namespace testing {
exceptions_internal::NoThrowTag nothrow_ctor;
exceptions_internal::StrongGuaranteeTagType strong_guarantee;
namespace exceptions_internal {
int countdown = -1;
ConstructorTracker* ConstructorTracker::current_tracker_instance_ = nullptr;
void MaybeThrow(absl::string_view msg, bool throw_bad_alloc) {
if (countdown-- == 0) {
if (throw_bad_alloc) throw TestBadAllocException(msg);
throw TestException(msg);
}
}
testing::AssertionResult FailureMessage(const TestException& e,
int countdown) noexcept {
return testing::AssertionFailure() << "Exception thrown from " << e.what();
}
std::string GetSpecString(TypeSpec spec) {
std::string out;
absl::string_view sep;
const auto append = [&](absl::string_view s) {
absl::StrAppend(&out, sep, s);
sep = " | ";
};
if (static_cast<bool>(TypeSpec::kNoThrowCopy & spec)) {
append("kNoThrowCopy");
}
if (static_cast<bool>(TypeSpec::kNoThrowMove & spec)) {
append("kNoThrowMove");
}
if (static_cast<bool>(TypeSpec::kNoThrowNew & spec)) {
append("kNoThrowNew");
}
return out;
}
std::string GetSpecString(AllocSpec spec) {
return static_cast<bool>(AllocSpec::kNoThrowAllocate & spec)
? "kNoThrowAllocate"
: "";
}
} // namespace exceptions_internal
} // namespace testing

File diff suppressed because it is too large Load Diff

View File

@ -1,42 +0,0 @@
// Copyright 2017 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
//
// http://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.
// Testing utilities for ABSL types which throw exceptions.
#ifndef ABSL_BASE_INTERNAL_EXCEPTION_TESTING_H_
#define ABSL_BASE_INTERNAL_EXCEPTION_TESTING_H_
#include "gtest/gtest.h"
#include "absl/base/config.h"
// ABSL_BASE_INTERNAL_EXPECT_FAIL tests either for a specified thrown exception
// if exceptions are enabled, or for death with a specified text in the error
// message
#ifdef ABSL_HAVE_EXCEPTIONS
#define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \
EXPECT_THROW(expr, exception_t)
#elif defined(__ANDROID__)
// Android asserts do not log anywhere that gtest can currently inspect.
// So we expect exit, but cannot match the message.
#define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \
EXPECT_DEATH(expr, ".*")
#else
#define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \
EXPECT_DEATH(expr, text)
#endif
#endif // ABSL_BASE_INTERNAL_EXCEPTION_TESTING_H_

View File

@ -1,47 +0,0 @@
// Copyright 2018 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
//
// http://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.
#ifndef ABSL_BASE_INTERNAL_HIDE_PTR_H_
#define ABSL_BASE_INTERNAL_HIDE_PTR_H_
#include <cstdint>
namespace absl {
namespace base_internal {
// Arbitrary value with high bits set. Xor'ing with it is unlikely
// to map one valid pointer to another valid pointer.
constexpr uintptr_t HideMask() {
return (uintptr_t{0xF03A5F7BU} << (sizeof(uintptr_t) - 4) * 8) | 0xF03A5F7BU;
}
// Hide a pointer from the leak checker. For internal use only.
// Differs from absl::IgnoreLeak(ptr) in that absl::IgnoreLeak(ptr) causes ptr
// and all objects reachable from ptr to be ignored by the leak checker.
template <class T>
inline uintptr_t HidePtr(T* ptr) {
return reinterpret_cast<uintptr_t>(ptr) ^ HideMask();
}
// Return a pointer that has been hidden from the leak checker.
// For internal use only.
template <class T>
inline T* UnhidePtr(uintptr_t hidden) {
return reinterpret_cast<T*>(hidden ^ HideMask());
}
} // namespace base_internal
} // namespace absl
#endif // ABSL_BASE_INTERNAL_HIDE_PTR_H_

View File

@ -1,33 +0,0 @@
// Copyright 2017 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
//
// http://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.
//
#ifndef ABSL_BASE_INTERNAL_IDENTITY_H_
#define ABSL_BASE_INTERNAL_IDENTITY_H_
namespace absl {
namespace internal {
template <typename T>
struct identity {
typedef T type;
};
template <typename T>
using identity_t = typename identity<T>::type;
} // namespace internal
} // namespace absl
#endif // ABSL_BASE_INTERNAL_IDENTITY_H_

View File

@ -1,107 +0,0 @@
// Copyright 2017 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
//
// http://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.
#ifndef ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_
#define ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_
#include <type_traits>
#include "absl/base/internal/identity.h"
// File:
// This file define a macro that allows the creation of or emulation of C++17
// inline variables based on whether or not the feature is supported.
////////////////////////////////////////////////////////////////////////////////
// Macro: ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init)
//
// Description:
// Expands to the equivalent of an inline constexpr instance of the specified
// `type` and `name`, initialized to the value `init`. If the compiler being
// used is detected as supporting actual inline variables as a language
// feature, then the macro expands to an actual inline variable definition.
//
// Requires:
// `type` is a type that is usable in an extern variable declaration.
//
// Requires: `name` is a valid identifier
//
// Requires:
// `init` is an expression that can be used in the following definition:
// constexpr type name = init;
//
// Usage:
//
// // Equivalent to: `inline constexpr size_t variant_npos = -1;`
// ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, -1);
//
// Differences in implementation:
// For a direct, language-level inline variable, decltype(name) will be the
// type that was specified along with const qualification, whereas for
// emulated inline variables, decltype(name) may be different (in practice
// it will likely be a reference type).
////////////////////////////////////////////////////////////////////////////////
#ifdef __cpp_inline_variables
// Clang's -Wmissing-variable-declarations option erroneously warned that
// inline constexpr objects need to be pre-declared. This has now been fixed,
// but we will need to support this workaround for people building with older
// versions of clang.
//
// Bug: https://bugs.llvm.org/show_bug.cgi?id=35862
//
// Note:
// identity_t is used here so that the const and name are in the
// appropriate place for pointer types, reference types, function pointer
// types, etc..
#if defined(__clang__)
#define ABSL_INTERNAL_EXTERN_DECL(type, name) \
extern const ::absl::internal::identity_t<type> name;
#else // Otherwise, just define the macro to do nothing.
#define ABSL_INTERNAL_EXTERN_DECL(type, name)
#endif // defined(__clang__)
// See above comment at top of file for details.
#define ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init) \
ABSL_INTERNAL_EXTERN_DECL(type, name) \
inline constexpr ::absl::internal::identity_t<type> name = init
#else
// See above comment at top of file for details.
//
// Note:
// identity_t is used here so that the const and name are in the
// appropriate place for pointer types, reference types, function pointer
// types, etc..
#define ABSL_INTERNAL_INLINE_CONSTEXPR(var_type, name, init) \
template <class /*AbslInternalDummy*/ = void> \
struct AbslInternalInlineVariableHolder##name { \
static constexpr ::absl::internal::identity_t<var_type> kInstance = init; \
}; \
\
template <class AbslInternalDummy> \
constexpr ::absl::internal::identity_t<var_type> \
AbslInternalInlineVariableHolder##name<AbslInternalDummy>::kInstance; \
\
static constexpr const ::absl::internal::identity_t<var_type>& \
name = /* NOLINT */ \
AbslInternalInlineVariableHolder##name<>::kInstance; \
static_assert(sizeof(void (*)(decltype(name))) != 0, \
"Silence unused variable warnings.")
#endif // __cpp_inline_variables
#endif // ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_

View File

@ -1,44 +0,0 @@
// Copyright 2017 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
//
// http://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.
#ifndef ABSL_BASE_INLINE_VARIABLE_TESTING_H_
#define ABSL_BASE_INLINE_VARIABLE_TESTING_H_
#include "absl/base/internal/inline_variable.h"
namespace absl {
namespace inline_variable_testing_internal {
struct Foo {
int value = 5;
};
ABSL_INTERNAL_INLINE_CONSTEXPR(Foo, inline_variable_foo, {});
ABSL_INTERNAL_INLINE_CONSTEXPR(Foo, other_inline_variable_foo, {});
ABSL_INTERNAL_INLINE_CONSTEXPR(int, inline_variable_int, 5);
ABSL_INTERNAL_INLINE_CONSTEXPR(int, other_inline_variable_int, 5);
ABSL_INTERNAL_INLINE_CONSTEXPR(void(*)(), inline_variable_fun_ptr, nullptr);
const Foo& get_foo_a();
const Foo& get_foo_b();
const int& get_int_a();
const int& get_int_b();
} // namespace inline_variable_testing_internal
} // namespace absl
#endif // ABSL_BASE_INLINE_VARIABLE_TESTING_H_

View File

@ -1,188 +0,0 @@
// Copyright 2017 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
//
// http://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.
//
// absl::base_internal::Invoke(f, args...) is an implementation of
// INVOKE(f, args...) from section [func.require] of the C++ standard.
//
// [func.require]
// Define INVOKE (f, t1, t2, ..., tN) as follows:
// 1. (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T
// and t1 is an object of type T or a reference to an object of type T or a
// reference to an object of a type derived from T;
// 2. ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a
// class T and t1 is not one of the types described in the previous item;
// 3. t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is
// an object of type T or a reference to an object of type T or a reference
// to an object of a type derived from T;
// 4. (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1
// is not one of the types described in the previous item;
// 5. f(t1, t2, ..., tN) in all other cases.
//
// The implementation is SFINAE-friendly: substitution failure within Invoke()
// isn't an error.
#ifndef ABSL_BASE_INTERNAL_INVOKE_H_
#define ABSL_BASE_INTERNAL_INVOKE_H_
#include <algorithm>
#include <type_traits>
#include <utility>
// The following code is internal implementation detail. See the comment at the
// top of this file for the API documentation.
namespace absl {
namespace base_internal {
// The five classes below each implement one of the clauses from the definition
// of INVOKE. The inner class template Accept<F, Args...> checks whether the
// clause is applicable; static function template Invoke(f, args...) does the
// invocation.
//
// By separating the clause selection logic from invocation we make sure that
// Invoke() does exactly what the standard says.
template <typename Derived>
struct StrippedAccept {
template <typename... Args>
struct Accept : Derived::template AcceptImpl<typename std::remove_cv<
typename std::remove_reference<Args>::type>::type...> {};
};
// (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T
// and t1 is an object of type T or a reference to an object of type T or a
// reference to an object of a type derived from T.
struct MemFunAndRef : StrippedAccept<MemFunAndRef> {
template <typename... Args>
struct AcceptImpl : std::false_type {};
template <typename R, typename C, typename... Params, typename Obj,
typename... Args>
struct AcceptImpl<R (C::*)(Params...), Obj, Args...>
: std::is_base_of<C, Obj> {};
template <typename R, typename C, typename... Params, typename Obj,
typename... Args>
struct AcceptImpl<R (C::*)(Params...) const, Obj, Args...>
: std::is_base_of<C, Obj> {};
template <typename MemFun, typename Obj, typename... Args>
static decltype((std::declval<Obj>().*
std::declval<MemFun>())(std::declval<Args>()...))
Invoke(MemFun&& mem_fun, Obj&& obj, Args&&... args) {
return (std::forward<Obj>(obj).*
std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...);
}
};
// ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a
// class T and t1 is not one of the types described in the previous item.
struct MemFunAndPtr : StrippedAccept<MemFunAndPtr> {
template <typename... Args>
struct AcceptImpl : std::false_type {};
template <typename R, typename C, typename... Params, typename Ptr,
typename... Args>
struct AcceptImpl<R (C::*)(Params...), Ptr, Args...>
: std::integral_constant<bool, !std::is_base_of<C, Ptr>::value> {};
template <typename R, typename C, typename... Params, typename Ptr,
typename... Args>
struct AcceptImpl<R (C::*)(Params...) const, Ptr, Args...>
: std::integral_constant<bool, !std::is_base_of<C, Ptr>::value> {};
template <typename MemFun, typename Ptr, typename... Args>
static decltype(((*std::declval<Ptr>()).*
std::declval<MemFun>())(std::declval<Args>()...))
Invoke(MemFun&& mem_fun, Ptr&& ptr, Args&&... args) {
return ((*std::forward<Ptr>(ptr)).*
std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...);
}
};
// t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is
// an object of type T or a reference to an object of type T or a reference
// to an object of a type derived from T.
struct DataMemAndRef : StrippedAccept<DataMemAndRef> {
template <typename... Args>
struct AcceptImpl : std::false_type {};
template <typename R, typename C, typename Obj>
struct AcceptImpl<R C::*, Obj> : std::is_base_of<C, Obj> {};
template <typename DataMem, typename Ref>
static decltype(std::declval<Ref>().*std::declval<DataMem>()) Invoke(
DataMem&& data_mem, Ref&& ref) {
return std::forward<Ref>(ref).*std::forward<DataMem>(data_mem);
}
};
// (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1
// is not one of the types described in the previous item.
struct DataMemAndPtr : StrippedAccept<DataMemAndPtr> {
template <typename... Args>
struct AcceptImpl : std::false_type {};
template <typename R, typename C, typename Ptr>
struct AcceptImpl<R C::*, Ptr>
: std::integral_constant<bool, !std::is_base_of<C, Ptr>::value> {};
template <typename DataMem, typename Ptr>
static decltype((*std::declval<Ptr>()).*std::declval<DataMem>()) Invoke(
DataMem&& data_mem, Ptr&& ptr) {
return (*std::forward<Ptr>(ptr)).*std::forward<DataMem>(data_mem);
}
};
// f(t1, t2, ..., tN) in all other cases.
struct Callable {
// Callable doesn't have Accept because it's the last clause that gets picked
// when none of the previous clauses are applicable.
template <typename F, typename... Args>
static decltype(std::declval<F>()(std::declval<Args>()...)) Invoke(
F&& f, Args&&... args) {
return std::forward<F>(f)(std::forward<Args>(args)...);
}
};
// Resolves to the first matching clause.
template <typename... Args>
struct Invoker {
typedef typename std::conditional<
MemFunAndRef::Accept<Args...>::value, MemFunAndRef,
typename std::conditional<
MemFunAndPtr::Accept<Args...>::value, MemFunAndPtr,
typename std::conditional<
DataMemAndRef::Accept<Args...>::value, DataMemAndRef,
typename std::conditional<DataMemAndPtr::Accept<Args...>::value,
DataMemAndPtr, Callable>::type>::type>::
type>::type type;
};
// The result type of Invoke<F, Args...>.
template <typename F, typename... Args>
using InvokeT = decltype(Invoker<F, Args...>::type::Invoke(
std::declval<F>(), std::declval<Args>()...));
// Invoke(f, args...) is an implementation of INVOKE(f, args...) from section
// [func.require] of the C++ standard.
template <typename F, typename... Args>
InvokeT<F, Args...> Invoke(F&& f, Args&&... args) {
return Invoker<F, Args...>::type::Invoke(std::forward<F>(f),
std::forward<Args>(args)...);
}
} // namespace base_internal
} // namespace absl
#endif // ABSL_BASE_INTERNAL_INVOKE_H_

View File

@ -1,604 +0,0 @@
// Copyright 2017 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
//
// http://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.
// A low-level allocator that can be used by other low-level
// modules without introducing dependency cycles.
// This allocator is slow and wasteful of memory;
// it should not be used when performance is key.
#include "absl/base/internal/low_level_alloc.h"
#include <type_traits>
#include "absl/base/call_once.h"
#include "absl/base/config.h"
#include "absl/base/internal/direct_mmap.h"
#include "absl/base/internal/scheduling_mode.h"
#include "absl/base/macros.h"
#include "absl/base/thread_annotations.h"
// LowLevelAlloc requires that the platform support low-level
// allocation of virtual memory. Platforms lacking this cannot use
// LowLevelAlloc.
#ifndef ABSL_LOW_LEVEL_ALLOC_MISSING
#ifndef _WIN32
#include <pthread.h>
#include <signal.h>
#include <sys/mman.h>
#include <unistd.h>
#else
#include <windows.h>
#endif
#include <string.h>
#include <algorithm>
#include <atomic>
#include <cerrno>
#include <cstddef>
#include <new> // for placement-new
#include "absl/base/dynamic_annotations.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/spinlock.h"
// MAP_ANONYMOUS
#if defined(__APPLE__)
// For mmap, Linux defines both MAP_ANONYMOUS and MAP_ANON and says MAP_ANON is
// deprecated. In Darwin, MAP_ANON is all there is.
#if !defined MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif // !MAP_ANONYMOUS
#endif // __APPLE__
namespace absl {
namespace base_internal {
// A first-fit allocator with amortized logarithmic free() time.
// ---------------------------------------------------------------------------
static const int kMaxLevel = 30;
namespace {
// This struct describes one allocated block, or one free block.
struct AllocList {
struct Header {
// Size of entire region, including this field. Must be
// first. Valid in both allocated and unallocated blocks.
uintptr_t size;
// kMagicAllocated or kMagicUnallocated xor this.
uintptr_t magic;
// Pointer to parent arena.
LowLevelAlloc::Arena *arena;
// Aligns regions to 0 mod 2*sizeof(void*).
void *dummy_for_alignment;
} header;
// Next two fields: in unallocated blocks: freelist skiplist data
// in allocated blocks: overlaps with client data
// Levels in skiplist used.
int levels;
// Actually has levels elements. The AllocList node may not have room
// for all kMaxLevel entries. See max_fit in LLA_SkiplistLevels().
AllocList *next[kMaxLevel];
};
} // namespace
// ---------------------------------------------------------------------------
// A trivial skiplist implementation. This is used to keep the freelist
// in address order while taking only logarithmic time per insert and delete.
// An integer approximation of log2(size/base)
// Requires size >= base.
static int IntLog2(size_t size, size_t base) {
int result = 0;
for (size_t i = size; i > base; i >>= 1) { // i == floor(size/2**result)
result++;
}
// floor(size / 2**result) <= base < floor(size / 2**(result-1))
// => log2(size/(base+1)) <= result < 1+log2(size/base)
// => result ~= log2(size/base)
return result;
}
// Return a random integer n: p(n)=1/(2**n) if 1 <= n; p(n)=0 if n < 1.
static int Random(uint32_t *state) {
uint32_t r = *state;
int result = 1;
while ((((r = r*1103515245 + 12345) >> 30) & 1) == 0) {
result++;
}
*state = r;
return result;
}
// Return a number of skiplist levels for a node of size bytes, where
// base is the minimum node size. Compute level=log2(size / base)+n
// where n is 1 if random is false and otherwise a random number generated with
// the standard distribution for a skiplist: See Random() above.
// Bigger nodes tend to have more skiplist levels due to the log2(size / base)
// term, so first-fit searches touch fewer nodes. "level" is clipped so
// level<kMaxLevel and next[level-1] will fit in the node.
// 0 < LLA_SkiplistLevels(x,y,false) <= LLA_SkiplistLevels(x,y,true) < kMaxLevel
static int LLA_SkiplistLevels(size_t size, size_t base, uint32_t *random) {
// max_fit is the maximum number of levels that will fit in a node for the
// given size. We can't return more than max_fit, no matter what the
// random number generator says.
size_t max_fit = (size - offsetof(AllocList, next)) / sizeof(AllocList *);
int level = IntLog2(size, base) + (random != nullptr ? Random(random) : 1);
if (static_cast<size_t>(level) > max_fit) level = static_cast<int>(max_fit);
if (level > kMaxLevel-1) level = kMaxLevel - 1;
ABSL_RAW_CHECK(level >= 1, "block not big enough for even one level");
return level;
}
// Return "atleast", the first element of AllocList *head s.t. *atleast >= *e.
// For 0 <= i < head->levels, set prev[i] to "no_greater", where no_greater
// points to the last element at level i in the AllocList less than *e, or is
// head if no such element exists.
static AllocList *LLA_SkiplistSearch(AllocList *head,
AllocList *e, AllocList **prev) {
AllocList *p = head;
for (int level = head->levels - 1; level >= 0; level--) {
for (AllocList *n; (n = p->next[level]) != nullptr && n < e; p = n) {
}
prev[level] = p;
}
return (head->levels == 0) ? nullptr : prev[0]->next[0];
}
// Insert element *e into AllocList *head. Set prev[] as LLA_SkiplistSearch.
// Requires that e->levels be previously set by the caller (using
// LLA_SkiplistLevels())
static void LLA_SkiplistInsert(AllocList *head, AllocList *e,
AllocList **prev) {
LLA_SkiplistSearch(head, e, prev);
for (; head->levels < e->levels; head->levels++) { // extend prev pointers
prev[head->levels] = head; // to all *e's levels
}
for (int i = 0; i != e->levels; i++) { // add element to list
e->next[i] = prev[i]->next[i];
prev[i]->next[i] = e;
}
}
// Remove element *e from AllocList *head. Set prev[] as LLA_SkiplistSearch().
// Requires that e->levels be previous set by the caller (using
// LLA_SkiplistLevels())
static void LLA_SkiplistDelete(AllocList *head, AllocList *e,
AllocList **prev) {
AllocList *found = LLA_SkiplistSearch(head, e, prev);
ABSL_RAW_CHECK(e == found, "element not in freelist");
for (int i = 0; i != e->levels && prev[i]->next[i] == e; i++) {
prev[i]->next[i] = e->next[i];
}
while (head->levels > 0 && head->next[head->levels - 1] == nullptr) {
head->levels--; // reduce head->levels if level unused
}
}
// ---------------------------------------------------------------------------
// Arena implementation
// Metadata for an LowLevelAlloc arena instance.
struct LowLevelAlloc::Arena {
// Constructs an arena with the given LowLevelAlloc flags.
explicit Arena(uint32_t flags_value);
base_internal::SpinLock mu;
// Head of free list, sorted by address
AllocList freelist GUARDED_BY(mu);
// Count of allocated blocks
int32_t allocation_count GUARDED_BY(mu);
// flags passed to NewArena
const uint32_t flags;
// Result of getpagesize()
const size_t pagesize;
// Lowest power of two >= max(16, sizeof(AllocList))
const size_t roundup;
// Smallest allocation block size
const size_t min_size;
// PRNG state
uint32_t random GUARDED_BY(mu);
};
namespace {
using ArenaStorage = std::aligned_storage<sizeof(LowLevelAlloc::Arena),
alignof(LowLevelAlloc::Arena)>::type;
// Static storage space for the lazily-constructed, default global arena
// instances. We require this space because the whole point of LowLevelAlloc
// is to avoid relying on malloc/new.
ArenaStorage default_arena_storage;
ArenaStorage unhooked_arena_storage;
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
ArenaStorage unhooked_async_sig_safe_arena_storage;
#endif
// We must use LowLevelCallOnce here to construct the global arenas, rather than
// using function-level statics, to avoid recursively invoking the scheduler.
absl::once_flag create_globals_once;
void CreateGlobalArenas() {
new (&default_arena_storage)
LowLevelAlloc::Arena(LowLevelAlloc::kCallMallocHook);
new (&unhooked_arena_storage) LowLevelAlloc::Arena(0);
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
new (&unhooked_async_sig_safe_arena_storage)
LowLevelAlloc::Arena(LowLevelAlloc::kAsyncSignalSafe);
#endif
}
// Returns a global arena that does not call into hooks. Used by NewArena()
// when kCallMallocHook is not set.
LowLevelAlloc::Arena* UnhookedArena() {
base_internal::LowLevelCallOnce(&create_globals_once, CreateGlobalArenas);
return reinterpret_cast<LowLevelAlloc::Arena*>(&unhooked_arena_storage);
}
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
// Returns a global arena that is async-signal safe. Used by NewArena() when
// kAsyncSignalSafe is set.
LowLevelAlloc::Arena *UnhookedAsyncSigSafeArena() {
base_internal::LowLevelCallOnce(&create_globals_once, CreateGlobalArenas);
return reinterpret_cast<LowLevelAlloc::Arena *>(
&unhooked_async_sig_safe_arena_storage);
}
#endif
} // namespace
// Returns the default arena, as used by LowLevelAlloc::Alloc() and friends.
LowLevelAlloc::Arena *LowLevelAlloc::DefaultArena() {
base_internal::LowLevelCallOnce(&create_globals_once, CreateGlobalArenas);
return reinterpret_cast<LowLevelAlloc::Arena*>(&default_arena_storage);
}
// magic numbers to identify allocated and unallocated blocks
static const uintptr_t kMagicAllocated = 0x4c833e95U;
static const uintptr_t kMagicUnallocated = ~kMagicAllocated;
namespace {
class SCOPED_LOCKABLE ArenaLock {
public:
explicit ArenaLock(LowLevelAlloc::Arena *arena)
EXCLUSIVE_LOCK_FUNCTION(arena->mu)
: arena_(arena) {
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
sigset_t all;
sigfillset(&all);
mask_valid_ = pthread_sigmask(SIG_BLOCK, &all, &mask_) == 0;
}
#endif
arena_->mu.Lock();
}
~ArenaLock() { ABSL_RAW_CHECK(left_, "haven't left Arena region"); }
void Leave() UNLOCK_FUNCTION() {
arena_->mu.Unlock();
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
if (mask_valid_) {
pthread_sigmask(SIG_SETMASK, &mask_, nullptr);
}
#endif
left_ = true;
}
private:
bool left_ = false; // whether left region
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
bool mask_valid_ = false;
sigset_t mask_; // old mask of blocked signals
#endif
LowLevelAlloc::Arena *arena_;
ArenaLock(const ArenaLock &) = delete;
ArenaLock &operator=(const ArenaLock &) = delete;
};
} // namespace
// create an appropriate magic number for an object at "ptr"
// "magic" should be kMagicAllocated or kMagicUnallocated
inline static uintptr_t Magic(uintptr_t magic, AllocList::Header *ptr) {
return magic ^ reinterpret_cast<uintptr_t>(ptr);
}
namespace {
size_t GetPageSize() {
#ifdef _WIN32
SYSTEM_INFO system_info;
GetSystemInfo(&system_info);
return std::max(system_info.dwPageSize, system_info.dwAllocationGranularity);
#else
return getpagesize();
#endif
}
size_t RoundedUpBlockSize() {
// Round up block sizes to a power of two close to the header size.
size_t roundup = 16;
while (roundup < sizeof(AllocList::Header)) {
roundup += roundup;
}
return roundup;
}
} // namespace
LowLevelAlloc::Arena::Arena(uint32_t flags_value)
: mu(base_internal::SCHEDULE_KERNEL_ONLY),
allocation_count(0),
flags(flags_value),
pagesize(GetPageSize()),
roundup(RoundedUpBlockSize()),
min_size(2 * roundup),
random(0) {
freelist.header.size = 0;
freelist.header.magic =
Magic(kMagicUnallocated, &freelist.header);
freelist.header.arena = this;
freelist.levels = 0;
memset(freelist.next, 0, sizeof(freelist.next));
}
// L < meta_data_arena->mu
LowLevelAlloc::Arena *LowLevelAlloc::NewArena(int32_t flags) {
Arena *meta_data_arena = DefaultArena();
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
if ((flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
meta_data_arena = UnhookedAsyncSigSafeArena();
} else // NOLINT(readability/braces)
#endif
if ((flags & LowLevelAlloc::kCallMallocHook) == 0) {
meta_data_arena = UnhookedArena();
}
Arena *result =
new (AllocWithArena(sizeof (*result), meta_data_arena)) Arena(flags);
return result;
}
// L < arena->mu, L < arena->arena->mu
bool LowLevelAlloc::DeleteArena(Arena *arena) {
ABSL_RAW_CHECK(
arena != nullptr && arena != DefaultArena() && arena != UnhookedArena(),
"may not delete default arena");
ArenaLock section(arena);
if (arena->allocation_count != 0) {
section.Leave();
return false;
}
while (arena->freelist.next[0] != nullptr) {
AllocList *region = arena->freelist.next[0];
size_t size = region->header.size;
arena->freelist.next[0] = region->next[0];
ABSL_RAW_CHECK(
region->header.magic == Magic(kMagicUnallocated, &region->header),
"bad magic number in DeleteArena()");
ABSL_RAW_CHECK(region->header.arena == arena,
"bad arena pointer in DeleteArena()");
ABSL_RAW_CHECK(size % arena->pagesize == 0,
"empty arena has non-page-aligned block size");
ABSL_RAW_CHECK(reinterpret_cast<uintptr_t>(region) % arena->pagesize == 0,
"empty arena has non-page-aligned block");
int munmap_result;
#ifdef _WIN32
munmap_result = VirtualFree(region, 0, MEM_RELEASE);
ABSL_RAW_CHECK(munmap_result != 0,
"LowLevelAlloc::DeleteArena: VitualFree failed");
#else
if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) == 0) {
munmap_result = munmap(region, size);
} else {
munmap_result = base_internal::DirectMunmap(region, size);
}
if (munmap_result != 0) {
ABSL_RAW_LOG(FATAL, "LowLevelAlloc::DeleteArena: munmap failed: %d",
errno);
}
#endif
}
section.Leave();
arena->~Arena();
Free(arena);
return true;
}
// ---------------------------------------------------------------------------
// Addition, checking for overflow. The intent is to die if an external client
// manages to push through a request that would cause arithmetic to fail.
static inline uintptr_t CheckedAdd(uintptr_t a, uintptr_t b) {
uintptr_t sum = a + b;
ABSL_RAW_CHECK(sum >= a, "LowLevelAlloc arithmetic overflow");
return sum;
}
// Return value rounded up to next multiple of align.
// align must be a power of two.
static inline uintptr_t RoundUp(uintptr_t addr, uintptr_t align) {
return CheckedAdd(addr, align - 1) & ~(align - 1);
}
// Equivalent to "return prev->next[i]" but with sanity checking
// that the freelist is in the correct order, that it
// consists of regions marked "unallocated", and that no two regions
// are adjacent in memory (they should have been coalesced).
// L < arena->mu
static AllocList *Next(int i, AllocList *prev, LowLevelAlloc::Arena *arena) {
ABSL_RAW_CHECK(i < prev->levels, "too few levels in Next()");
AllocList *next = prev->next[i];
if (next != nullptr) {
ABSL_RAW_CHECK(
next->header.magic == Magic(kMagicUnallocated, &next->header),
"bad magic number in Next()");
ABSL_RAW_CHECK(next->header.arena == arena, "bad arena pointer in Next()");
if (prev != &arena->freelist) {
ABSL_RAW_CHECK(prev < next, "unordered freelist");
ABSL_RAW_CHECK(reinterpret_cast<char *>(prev) + prev->header.size <
reinterpret_cast<char *>(next),
"malformed freelist");
}
}
return next;
}
// Coalesce list item "a" with its successor if they are adjacent.
static void Coalesce(AllocList *a) {
AllocList *n = a->next[0];
if (n != nullptr && reinterpret_cast<char *>(a) + a->header.size ==
reinterpret_cast<char *>(n)) {
LowLevelAlloc::Arena *arena = a->header.arena;
a->header.size += n->header.size;
n->header.magic = 0;
n->header.arena = nullptr;
AllocList *prev[kMaxLevel];
LLA_SkiplistDelete(&arena->freelist, n, prev);
LLA_SkiplistDelete(&arena->freelist, a, prev);
a->levels = LLA_SkiplistLevels(a->header.size, arena->min_size,
&arena->random);
LLA_SkiplistInsert(&arena->freelist, a, prev);
}
}
// Adds block at location "v" to the free list
// L >= arena->mu
static void AddToFreelist(void *v, LowLevelAlloc::Arena *arena) {
AllocList *f = reinterpret_cast<AllocList *>(
reinterpret_cast<char *>(v) - sizeof (f->header));
ABSL_RAW_CHECK(f->header.magic == Magic(kMagicAllocated, &f->header),
"bad magic number in AddToFreelist()");
ABSL_RAW_CHECK(f->header.arena == arena,
"bad arena pointer in AddToFreelist()");
f->levels = LLA_SkiplistLevels(f->header.size, arena->min_size,
&arena->random);
AllocList *prev[kMaxLevel];
LLA_SkiplistInsert(&arena->freelist, f, prev);
f->header.magic = Magic(kMagicUnallocated, &f->header);
Coalesce(f); // maybe coalesce with successor
Coalesce(prev[0]); // maybe coalesce with predecessor
}
// Frees storage allocated by LowLevelAlloc::Alloc().
// L < arena->mu
void LowLevelAlloc::Free(void *v) {
if (v != nullptr) {
AllocList *f = reinterpret_cast<AllocList *>(
reinterpret_cast<char *>(v) - sizeof (f->header));
ABSL_RAW_CHECK(f->header.magic == Magic(kMagicAllocated, &f->header),
"bad magic number in Free()");
LowLevelAlloc::Arena *arena = f->header.arena;
ArenaLock section(arena);
AddToFreelist(v, arena);
ABSL_RAW_CHECK(arena->allocation_count > 0, "nothing in arena to free");
arena->allocation_count--;
section.Leave();
}
}
// allocates and returns a block of size bytes, to be freed with Free()
// L < arena->mu
static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) {
void *result = nullptr;
if (request != 0) {
AllocList *s; // will point to region that satisfies request
ArenaLock section(arena);
// round up with header
size_t req_rnd = RoundUp(CheckedAdd(request, sizeof (s->header)),
arena->roundup);
for (;;) { // loop until we find a suitable region
// find the minimum levels that a block of this size must have
int i = LLA_SkiplistLevels(req_rnd, arena->min_size, nullptr) - 1;
if (i < arena->freelist.levels) { // potential blocks exist
AllocList *before = &arena->freelist; // predecessor of s
while ((s = Next(i, before, arena)) != nullptr &&
s->header.size < req_rnd) {
before = s;
}
if (s != nullptr) { // we found a region
break;
}
}
// we unlock before mmap() both because mmap() may call a callback hook,
// and because it may be slow.
arena->mu.Unlock();
// mmap generous 64K chunks to decrease
// the chances/impact of fragmentation:
size_t new_pages_size = RoundUp(req_rnd, arena->pagesize * 16);
void *new_pages;
#ifdef _WIN32
new_pages = VirtualAlloc(0, new_pages_size,
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
ABSL_RAW_CHECK(new_pages != nullptr, "VirtualAlloc failed");
#else
if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
new_pages = base_internal::DirectMmap(nullptr, new_pages_size,
PROT_WRITE|PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
} else {
new_pages = mmap(nullptr, new_pages_size, PROT_WRITE | PROT_READ,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
}
if (new_pages == MAP_FAILED) {
ABSL_RAW_LOG(FATAL, "mmap error: %d", errno);
}
#endif
arena->mu.Lock();
s = reinterpret_cast<AllocList *>(new_pages);
s->header.size = new_pages_size;
// Pretend the block is allocated; call AddToFreelist() to free it.
s->header.magic = Magic(kMagicAllocated, &s->header);
s->header.arena = arena;
AddToFreelist(&s->levels, arena); // insert new region into free list
}
AllocList *prev[kMaxLevel];
LLA_SkiplistDelete(&arena->freelist, s, prev); // remove from free list
// s points to the first free region that's big enough
if (CheckedAdd(req_rnd, arena->min_size) <= s->header.size) {
// big enough to split
AllocList *n = reinterpret_cast<AllocList *>
(req_rnd + reinterpret_cast<char *>(s));
n->header.size = s->header.size - req_rnd;
n->header.magic = Magic(kMagicAllocated, &n->header);
n->header.arena = arena;
s->header.size = req_rnd;
AddToFreelist(&n->levels, arena);
}
s->header.magic = Magic(kMagicAllocated, &s->header);
ABSL_RAW_CHECK(s->header.arena == arena, "");
arena->allocation_count++;
section.Leave();
result = &s->levels;
}
ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(result, request);
return result;
}
void *LowLevelAlloc::Alloc(size_t request) {
void *result = DoAllocWithArena(request, DefaultArena());
return result;
}
void *LowLevelAlloc::AllocWithArena(size_t request, Arena *arena) {
ABSL_RAW_CHECK(arena != nullptr, "must pass a valid arena");
void *result = DoAllocWithArena(request, arena);
return result;
}
} // namespace base_internal
} // namespace absl
#endif // ABSL_LOW_LEVEL_ALLOC_MISSING

View File

@ -1,119 +0,0 @@
// Copyright 2017 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
//
// http://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.
//
#ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
#define ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
// A simple thread-safe memory allocator that does not depend on
// mutexes or thread-specific data. It is intended to be used
// sparingly, and only when malloc() would introduce an unwanted
// dependency, such as inside the heap-checker, or the Mutex
// implementation.
// IWYU pragma: private, include "base/low_level_alloc.h"
#include <sys/types.h>
#include <cstdint>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
// LowLevelAlloc requires that the platform support low-level
// allocation of virtual memory. Platforms lacking this cannot use
// LowLevelAlloc.
#ifdef ABSL_LOW_LEVEL_ALLOC_MISSING
#error ABSL_LOW_LEVEL_ALLOC_MISSING cannot be directly set
#elif !defined(ABSL_HAVE_MMAP) && !defined(_WIN32)
#define ABSL_LOW_LEVEL_ALLOC_MISSING 1
#endif
// Using LowLevelAlloc with kAsyncSignalSafe isn't supported on Windows.
#ifdef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
#error ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING cannot be directly set
#elif defined(_WIN32)
#define ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING 1
#endif
#include <cstddef>
#include "absl/base/port.h"
namespace absl {
namespace base_internal {
class LowLevelAlloc {
public:
struct Arena; // an arena from which memory may be allocated
// Returns a pointer to a block of at least "request" bytes
// that have been newly allocated from the specific arena.
// for Alloc() call the DefaultArena() is used.
// Returns 0 if passed request==0.
// Does not return 0 under other circumstances; it crashes if memory
// is not available.
static void *Alloc(size_t request) ABSL_ATTRIBUTE_SECTION(malloc_hook);
static void *AllocWithArena(size_t request, Arena *arena)
ABSL_ATTRIBUTE_SECTION(malloc_hook);
// Deallocates a region of memory that was previously allocated with
// Alloc(). Does nothing if passed 0. "s" must be either 0,
// or must have been returned from a call to Alloc() and not yet passed to
// Free() since that call to Alloc(). The space is returned to the arena
// from which it was allocated.
static void Free(void *s) ABSL_ATTRIBUTE_SECTION(malloc_hook);
// ABSL_ATTRIBUTE_SECTION(malloc_hook) for Alloc* and Free
// are to put all callers of MallocHook::Invoke* in this module
// into special section,
// so that MallocHook::GetCallerStackTrace can function accurately.
// Create a new arena.
// The root metadata for the new arena is allocated in the
// meta_data_arena; the DefaultArena() can be passed for meta_data_arena.
// These values may be ored into flags:
enum {
// Report calls to Alloc() and Free() via the MallocHook interface.
// Set in the DefaultArena.
kCallMallocHook = 0x0001,
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
// Make calls to Alloc(), Free() be async-signal-safe. Not set in
// DefaultArena(). Not supported on all platforms.
kAsyncSignalSafe = 0x0002,
#endif
};
// Construct a new arena. The allocation of the underlying metadata honors
// the provided flags. For example, the call NewArena(kAsyncSignalSafe)
// is itself async-signal-safe, as well as generatating an arena that provides
// async-signal-safe Alloc/Free.
static Arena *NewArena(int32_t flags);
// Destroys an arena allocated by NewArena and returns true,
// provided no allocated blocks remain in the arena.
// If allocated blocks remain in the arena, does nothing and
// returns false.
// It is illegal to attempt to destroy the DefaultArena().
static bool DeleteArena(Arena *arena);
// The default arena that always exists.
static Arena *DefaultArena();
private:
LowLevelAlloc(); // no instances
};
} // namespace base_internal
} // namespace absl
#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_

View File

@ -1,157 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include "absl/base/internal/low_level_alloc.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <thread> // NOLINT(build/c++11)
#include <unordered_map>
#include <utility>
namespace absl {
namespace base_internal {
namespace {
// This test doesn't use gtest since it needs to test that everything
// works before main().
#define TEST_ASSERT(x) \
if (!(x)) { \
printf("TEST_ASSERT(%s) FAILED ON LINE %d\n", #x, __LINE__); \
abort(); \
}
// a block of memory obtained from the allocator
struct BlockDesc {
char *ptr; // pointer to memory
int len; // number of bytes
int fill; // filled with data starting with this
};
// Check that the pattern placed in the block d
// by RandomizeBlockDesc is still there.
static void CheckBlockDesc(const BlockDesc &d) {
for (int i = 0; i != d.len; i++) {
TEST_ASSERT((d.ptr[i] & 0xff) == ((d.fill + i) & 0xff));
}
}
// Fill the block "*d" with a pattern
// starting with a random byte.
static void RandomizeBlockDesc(BlockDesc *d) {
d->fill = rand() & 0xff;
for (int i = 0; i != d->len; i++) {
d->ptr[i] = (d->fill + i) & 0xff;
}
}
// Use to indicate to the malloc hooks that
// this calls is from LowLevelAlloc.
static bool using_low_level_alloc = false;
// n times, toss a coin, and based on the outcome
// either allocate a new block or deallocate an old block.
// New blocks are placed in a std::unordered_map with a random key
// and initialized with RandomizeBlockDesc().
// If keys conflict, the older block is freed.
// Old blocks are always checked with CheckBlockDesc()
// before being freed. At the end of the run,
// all remaining allocated blocks are freed.
// If use_new_arena is true, use a fresh arena, and then delete it.
// If call_malloc_hook is true and user_arena is true,
// allocations and deallocations are reported via the MallocHook
// interface.
static void Test(bool use_new_arena, bool call_malloc_hook, int n) {
typedef std::unordered_map<int, BlockDesc> AllocMap;
AllocMap allocated;
AllocMap::iterator it;
BlockDesc block_desc;
int rnd;
LowLevelAlloc::Arena *arena = 0;
if (use_new_arena) {
int32_t flags = call_malloc_hook ? LowLevelAlloc::kCallMallocHook : 0;
arena = LowLevelAlloc::NewArena(flags);
}
for (int i = 0; i != n; i++) {
if (i != 0 && i % 10000 == 0) {
printf(".");
fflush(stdout);
}
switch (rand() & 1) { // toss a coin
case 0: // coin came up heads: add a block
using_low_level_alloc = true;
block_desc.len = rand() & 0x3fff;
block_desc.ptr =
reinterpret_cast<char *>(
arena == 0
? LowLevelAlloc::Alloc(block_desc.len)
: LowLevelAlloc::AllocWithArena(block_desc.len, arena));
using_low_level_alloc = false;
RandomizeBlockDesc(&block_desc);
rnd = rand();
it = allocated.find(rnd);
if (it != allocated.end()) {
CheckBlockDesc(it->second);
using_low_level_alloc = true;
LowLevelAlloc::Free(it->second.ptr);
using_low_level_alloc = false;
it->second = block_desc;
} else {
allocated[rnd] = block_desc;
}
break;
case 1: // coin came up tails: remove a block
it = allocated.begin();
if (it != allocated.end()) {
CheckBlockDesc(it->second);
using_low_level_alloc = true;
LowLevelAlloc::Free(it->second.ptr);
using_low_level_alloc = false;
allocated.erase(it);
}
break;
}
}
// remove all remaining blocks
while ((it = allocated.begin()) != allocated.end()) {
CheckBlockDesc(it->second);
using_low_level_alloc = true;
LowLevelAlloc::Free(it->second.ptr);
using_low_level_alloc = false;
allocated.erase(it);
}
if (use_new_arena) {
TEST_ASSERT(LowLevelAlloc::DeleteArena(arena));
}
}
// LowLevelAlloc is designed to be safe to call before main().
static struct BeforeMain {
BeforeMain() {
Test(false, false, 50000);
Test(true, false, 50000);
Test(true, true, 50000);
}
} before_main;
} // namespace
} // namespace base_internal
} // namespace absl
int main(int argc, char *argv[]) {
// The actual test runs in the global constructor of `before_main`.
printf("PASS\n");
return 0;
}

View File

@ -1,104 +0,0 @@
// Copyright 2017 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
//
// http://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.
//
// Core interfaces and definitions used by by low-level interfaces such as
// SpinLock.
#ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
#define ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
#include "absl/base/internal/scheduling_mode.h"
#include "absl/base/macros.h"
// The following two declarations exist so SchedulingGuard may friend them with
// the appropriate language linkage. These callbacks allow libc internals, such
// as function level statics, to schedule cooperatively when locking.
extern "C" bool __google_disable_rescheduling(void);
extern "C" void __google_enable_rescheduling(bool disable_result);
namespace absl {
namespace base_internal {
class SchedulingHelper; // To allow use of SchedulingGuard.
class SpinLock; // To allow use of SchedulingGuard.
// SchedulingGuard
// Provides guard semantics that may be used to disable cooperative rescheduling
// of the calling thread within specific program blocks. This is used to
// protect resources (e.g. low-level SpinLocks or Domain code) that cooperative
// scheduling depends on.
//
// Domain implementations capable of rescheduling in reaction to involuntary
// kernel thread actions (e.g blocking due to a pagefault or syscall) must
// guarantee that an annotated thread is not allowed to (cooperatively)
// reschedule until the annotated region is complete.
//
// It is an error to attempt to use a cooperatively scheduled resource (e.g.
// Mutex) within a rescheduling-disabled region.
//
// All methods are async-signal safe.
class SchedulingGuard {
public:
// Returns true iff the calling thread may be cooperatively rescheduled.
static bool ReschedulingIsAllowed();
private:
// Disable cooperative rescheduling of the calling thread. It may still
// initiate scheduling operations (e.g. wake-ups), however, it may not itself
// reschedule. Nestable. The returned result is opaque, clients should not
// attempt to interpret it.
// REQUIRES: Result must be passed to a pairing EnableScheduling().
static bool DisableRescheduling();
// Marks the end of a rescheduling disabled region, previously started by
// DisableRescheduling().
// REQUIRES: Pairs with innermost call (and result) of DisableRescheduling().
static void EnableRescheduling(bool disable_result);
// A scoped helper for {Disable, Enable}Rescheduling().
// REQUIRES: destructor must run in same thread as constructor.
struct ScopedDisable {
ScopedDisable() { disabled = SchedulingGuard::DisableRescheduling(); }
~ScopedDisable() { SchedulingGuard::EnableRescheduling(disabled); }
bool disabled;
};
// Access to SchedulingGuard is explicitly white-listed.
friend class SchedulingHelper;
friend class SpinLock;
SchedulingGuard(const SchedulingGuard&) = delete;
SchedulingGuard& operator=(const SchedulingGuard&) = delete;
};
//------------------------------------------------------------------------------
// End of public interfaces.
//------------------------------------------------------------------------------
inline bool SchedulingGuard::ReschedulingIsAllowed() {
return false;
}
inline bool SchedulingGuard::DisableRescheduling() {
return false;
}
inline void SchedulingGuard::EnableRescheduling(bool /* disable_result */) {
return;
}
} // namespace base_internal
} // namespace absl
#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_

View File

@ -1,48 +0,0 @@
// Copyright 2017 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
//
// http://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.
#ifndef ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_
#define ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_
// This header defines two macros:
// If the platform supports thread-local storage:
// ABSL_PER_THREAD_TLS_KEYWORD is the C keyword needed to declare a
// thread-local variable ABSL_PER_THREAD_TLS is 1
//
// Otherwise:
// ABSL_PER_THREAD_TLS_KEYWORD is empty
// ABSL_PER_THREAD_TLS is 0
//
// Microsoft C supports thread-local storage.
// GCC supports it if the appropriate version of glibc is available,
// which the programmer can indicate by defining ABSL_HAVE_TLS
#include "absl/base/port.h" // For ABSL_HAVE_TLS
#if defined(ABSL_PER_THREAD_TLS)
#error ABSL_PER_THREAD_TLS cannot be directly set
#elif defined(ABSL_PER_THREAD_TLS_KEYWORD)
#error ABSL_PER_THREAD_TLS_KEYWORD cannot be directly set
#elif defined(ABSL_HAVE_TLS)
#define ABSL_PER_THREAD_TLS_KEYWORD __thread
#define ABSL_PER_THREAD_TLS 1
#elif defined(_MSC_VER)
#define ABSL_PER_THREAD_TLS_KEYWORD __declspec(thread)
#define ABSL_PER_THREAD_TLS 1
#else
#define ABSL_PER_THREAD_TLS_KEYWORD
#define ABSL_PER_THREAD_TLS 0
#endif
#endif // ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_

View File

@ -1,33 +0,0 @@
// Copyright 2017 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
//
// http://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.
#ifndef ABSL_BASE_INTERNAL_PRETTY_FUNCTION_H_
#define ABSL_BASE_INTERNAL_PRETTY_FUNCTION_H_
// ABSL_PRETTY_FUNCTION
//
// In C++11, __func__ gives the undecorated name of the current function. That
// is, "main", not "int main()". Various compilers give extra macros to get the
// decorated function name, including return type and arguments, to
// differentiate between overload sets. ABSL_PRETTY_FUNCTION is a portable
// version of these macros which forwards to the correct macro on each compiler.
#if defined(_MSC_VER)
#define ABSL_PRETTY_FUNCTION __FUNCSIG__
#elif defined(__GNUC__)
#define ABSL_PRETTY_FUNCTION __PRETTY_FUNCTION__
#else
#error "Unsupported compiler"
#endif
#endif // ABSL_BASE_INTERNAL_PRETTY_FUNCTION_H_

View File

@ -1,218 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include "absl/base/internal/raw_logging.h"
#include <stddef.h>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/internal/atomic_hook.h"
#include "absl/base/log_severity.h"
// We know how to perform low-level writes to stderr in POSIX and Windows. For
// these platforms, we define the token ABSL_LOW_LEVEL_WRITE_SUPPORTED.
// Much of raw_logging.cc becomes a no-op when we can't output messages,
// although a FATAL ABSL_RAW_LOG message will still abort the process.
// ABSL_HAVE_POSIX_WRITE is defined when the platform provides posix write()
// (as from unistd.h)
//
// This preprocessor token is also defined in raw_io.cc. If you need to copy
// this, consider moving both to config.h instead.
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
defined(__Fuchsia__) || defined(__native_client__)
#include <unistd.h>
#define ABSL_HAVE_POSIX_WRITE 1
#define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1
#else
#undef ABSL_HAVE_POSIX_WRITE
#endif
// ABSL_HAVE_SYSCALL_WRITE is defined when the platform provides the syscall
// syscall(SYS_write, /*int*/ fd, /*char* */ buf, /*size_t*/ len);
// for low level operations that want to avoid libc.
#if (defined(__linux__) || defined(__FreeBSD__)) && !defined(__ANDROID__)
#include <sys/syscall.h>
#define ABSL_HAVE_SYSCALL_WRITE 1
#define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1
#else
#undef ABSL_HAVE_SYSCALL_WRITE
#endif
#ifdef _WIN32
#include <io.h>
#define ABSL_HAVE_RAW_IO 1
#define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1
#else
#undef ABSL_HAVE_RAW_IO
#endif
// TODO(gfalcon): We want raw-logging to work on as many platforms as possible.
// Explicitly #error out when not ABSL_LOW_LEVEL_WRITE_SUPPORTED, except for a
// whitelisted set of platforms for which we expect not to be able to raw log.
ABSL_CONST_INIT static absl::base_internal::AtomicHook<
absl::raw_logging_internal::LogPrefixHook> log_prefix_hook;
ABSL_CONST_INIT static absl::base_internal::AtomicHook<
absl::raw_logging_internal::AbortHook> abort_hook;
#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
static const char kTruncated[] = " ... (message truncated)\n";
// sprintf the format to the buffer, adjusting *buf and *size to reflect the
// consumed bytes, and return whether the message fit without truncation. If
// truncation occurred, if possible leave room in the buffer for the message
// kTruncated[].
inline static bool VADoRawLog(char** buf, int* size, const char* format,
va_list ap) ABSL_PRINTF_ATTRIBUTE(3, 0);
inline static bool VADoRawLog(char** buf, int* size,
const char* format, va_list ap) {
int n = vsnprintf(*buf, *size, format, ap);
bool result = true;
if (n < 0 || n > *size) {
result = false;
if (static_cast<size_t>(*size) > sizeof(kTruncated)) {
n = *size - sizeof(kTruncated); // room for truncation message
} else {
n = 0; // no room for truncation message
}
}
*size -= n;
*buf += n;
return result;
}
#endif // ABSL_LOW_LEVEL_WRITE_SUPPORTED
static constexpr int kLogBufSize = 3000;
namespace {
// CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths
// that invoke malloc() and getenv() that might acquire some locks.
// Helper for RawLog below.
// *DoRawLog writes to *buf of *size and move them past the written portion.
// It returns true iff there was no overflow or error.
bool DoRawLog(char** buf, int* size, const char* format, ...)
ABSL_PRINTF_ATTRIBUTE(3, 4);
bool DoRawLog(char** buf, int* size, const char* format, ...) {
va_list ap;
va_start(ap, format);
int n = vsnprintf(*buf, *size, format, ap);
va_end(ap);
if (n < 0 || n > *size) return false;
*size -= n;
*buf += n;
return true;
}
void RawLogVA(absl::LogSeverity severity, const char* file, int line,
const char* format, va_list ap) ABSL_PRINTF_ATTRIBUTE(4, 0);
void RawLogVA(absl::LogSeverity severity, const char* file, int line,
const char* format, va_list ap) {
char buffer[kLogBufSize];
char* buf = buffer;
int size = sizeof(buffer);
#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
bool enabled = true;
#else
bool enabled = false;
#endif
#ifdef ABSL_MIN_LOG_LEVEL
if (static_cast<int>(severity) < ABSL_MIN_LOG_LEVEL &&
severity < absl::LogSeverity::kFatal) {
enabled = false;
}
#endif
auto log_prefix_hook_ptr = log_prefix_hook.Load();
if (log_prefix_hook_ptr) {
enabled = log_prefix_hook_ptr(severity, file, line, &buf, &size);
} else {
if (enabled) {
DoRawLog(&buf, &size, "[%s : %d] RAW: ", file, line);
}
}
const char* const prefix_end = buf;
#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
if (enabled) {
bool no_chop = VADoRawLog(&buf, &size, format, ap);
if (no_chop) {
DoRawLog(&buf, &size, "\n");
} else {
DoRawLog(&buf, &size, "%s", kTruncated);
}
absl::raw_logging_internal::SafeWriteToStderr(buffer, strlen(buffer));
}
#else
static_cast<void>(format);
static_cast<void>(ap);
#endif
// Abort the process after logging a FATAL message, even if the output itself
// was suppressed.
if (severity == absl::LogSeverity::kFatal) {
abort_hook(file, line, buffer, prefix_end, buffer + kLogBufSize);
abort();
}
}
} // namespace
namespace absl {
namespace raw_logging_internal {
void SafeWriteToStderr(const char *s, size_t len) {
#if defined(ABSL_HAVE_SYSCALL_WRITE)
syscall(SYS_write, STDERR_FILENO, s, len);
#elif defined(ABSL_HAVE_POSIX_WRITE)
write(STDERR_FILENO, s, len);
#elif defined(ABSL_HAVE_RAW_IO)
_write(/* stderr */ 2, s, len);
#else
// stderr logging unsupported on this platform
(void) s;
(void) len;
#endif
}
void RawLog(absl::LogSeverity severity, const char* file, int line,
const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5);
void RawLog(absl::LogSeverity severity, const char* file, int line,
const char* format, ...) {
va_list ap;
va_start(ap, format);
RawLogVA(severity, file, line, format, ap);
va_end(ap);
}
bool RawLoggingFullySupported() {
#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
return true;
#else // !ABSL_LOW_LEVEL_WRITE_SUPPORTED
return false;
#endif // !ABSL_LOW_LEVEL_WRITE_SUPPORTED
}
} // namespace raw_logging_internal
} // namespace absl

View File

@ -1,137 +0,0 @@
// Copyright 2017 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
//
// http://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.
//
// Thread-safe logging routines that do not allocate any memory or
// acquire any locks, and can therefore be used by low-level memory
// allocation, synchronization, and signal-handling code.
#ifndef ABSL_BASE_INTERNAL_RAW_LOGGING_H_
#define ABSL_BASE_INTERNAL_RAW_LOGGING_H_
#include "absl/base/attributes.h"
#include "absl/base/log_severity.h"
#include "absl/base/macros.h"
#include "absl/base/port.h"
// This is similar to LOG(severity) << format..., but
// * it is to be used ONLY by low-level modules that can't use normal LOG()
// * it is designed to be a low-level logger that does not allocate any
// memory and does not need any locks, hence:
// * it logs straight and ONLY to STDERR w/o buffering
// * it uses an explicit printf-format and arguments list
// * it will silently chop off really long message strings
// Usage example:
// ABSL_RAW_LOG(ERROR, "Failed foo with %i: %s", status, error);
// This will print an almost standard log line like this to stderr only:
// E0821 211317 file.cc:123] RAW: Failed foo with 22: bad_file
#define ABSL_RAW_LOG(severity, ...) \
do { \
constexpr const char* absl_raw_logging_internal_basename = \
::absl::raw_logging_internal::Basename(__FILE__, \
sizeof(__FILE__) - 1); \
::absl::raw_logging_internal::RawLog(ABSL_RAW_LOGGING_INTERNAL_##severity, \
absl_raw_logging_internal_basename, \
__LINE__, __VA_ARGS__); \
} while (0)
// Similar to CHECK(condition) << message, but for low-level modules:
// we use only ABSL_RAW_LOG that does not allocate memory.
// We do not want to provide args list here to encourage this usage:
// if (!cond) ABSL_RAW_LOG(FATAL, "foo ...", hard_to_compute_args);
// so that the args are not computed when not needed.
#define ABSL_RAW_CHECK(condition, message) \
do { \
if (ABSL_PREDICT_FALSE(!(condition))) { \
ABSL_RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \
} \
} while (0)
#define ABSL_RAW_LOGGING_INTERNAL_INFO ::absl::LogSeverity::kInfo
#define ABSL_RAW_LOGGING_INTERNAL_WARNING ::absl::LogSeverity::kWarning
#define ABSL_RAW_LOGGING_INTERNAL_ERROR ::absl::LogSeverity::kError
#define ABSL_RAW_LOGGING_INTERNAL_FATAL ::absl::LogSeverity::kFatal
#define ABSL_RAW_LOGGING_INTERNAL_LEVEL(severity) \
::absl::NormalizeLogSeverity(severity)
namespace absl {
namespace raw_logging_internal {
// Helper function to implement ABSL_RAW_LOG
// Logs format... at "severity" level, reporting it
// as called from file:line.
// This does not allocate memory or acquire locks.
void RawLog(absl::LogSeverity severity, const char* file, int line,
const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5);
// Writes the provided buffer directly to stderr, in a safe, low-level manner.
//
// In POSIX this means calling write(), which is async-signal safe and does
// not malloc. If the platform supports the SYS_write syscall, we invoke that
// directly to side-step any libc interception.
void SafeWriteToStderr(const char *s, size_t len);
// compile-time function to get the "base" filename, that is, the part of
// a filename after the last "/" or "\" path separator. The search starts at
// the end of the std::string; the second parameter is the length of the std::string.
constexpr const char* Basename(const char* fname, int offset) {
return offset == 0 || fname[offset - 1] == '/' || fname[offset - 1] == '\\'
? fname + offset
: Basename(fname, offset - 1);
}
// For testing only.
// Returns true if raw logging is fully supported. When it is not
// fully supported, no messages will be emitted, but a log at FATAL
// severity will cause an abort.
//
// TODO(gfalcon): Come up with a better name for this method.
bool RawLoggingFullySupported();
// Function type for a raw_logging customization hook for suppressing messages
// by severity, and for writing custom prefixes on non-suppressed messages.
//
// The installed hook is called for every raw log invocation. The message will
// be logged to stderr only if the hook returns true. FATAL errors will cause
// the process to abort, even if writing to stderr is suppressed. The hook is
// also provided with an output buffer, where it can write a custom log message
// prefix.
//
// The raw_logging system does not allocate memory or grab locks. User-provided
// hooks must avoid these operations, and must not throw exceptions.
//
// 'severity' is the severity level of the message being written.
// 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro
// was located.
// 'buffer' and 'buf_size' are pointers to the buffer and buffer size. If the
// hook writes a prefix, it must increment *buffer and decrement *buf_size
// accordingly.
using LogPrefixHook = bool (*)(absl::LogSeverity severity, const char* file,
int line, char** buffer, int* buf_size);
// Function type for a raw_logging customization hook called to abort a process
// when a FATAL message is logged. If the provided AbortHook() returns, the
// logging system will call abort().
//
// 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro
// was located.
// The null-terminated logged message lives in the buffer between 'buf_start'
// and 'buf_end'. 'prefix_end' points to the first non-prefix character of the
// buffer (as written by the LogPrefixHook.)
using AbortHook = void (*)(const char* file, int line, const char* buf_start,
const char* prefix_end, const char* buf_end);
} // namespace raw_logging_internal
} // namespace absl
#endif // ABSL_BASE_INTERNAL_RAW_LOGGING_H_

View File

@ -1,54 +0,0 @@
// Copyright 2017 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
//
// http://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.
//
// Core interfaces and definitions used by by low-level interfaces such as
// SpinLock.
#ifndef ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
#define ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
namespace absl {
namespace base_internal {
// Used to describe how a thread may be scheduled. Typically associated with
// the declaration of a resource supporting synchronized access.
//
// SCHEDULE_COOPERATIVE_AND_KERNEL:
// Specifies that when waiting, a cooperative thread (e.g. a Fiber) may
// reschedule (using base::scheduling semantics); allowing other cooperative
// threads to proceed.
//
// SCHEDULE_KERNEL_ONLY: (Also described as "non-cooperative")
// Specifies that no cooperative scheduling semantics may be used, even if the
// current thread is itself cooperatively scheduled. This means that
// cooperative threads will NOT allow other cooperative threads to execute in
// their place while waiting for a resource of this type. Host operating system
// semantics (e.g. a futex) may still be used.
//
// When optional, clients should strongly prefer SCHEDULE_COOPERATIVE_AND_KERNEL
// by default. SCHEDULE_KERNEL_ONLY should only be used for resources on which
// base::scheduling (e.g. the implementation of a Scheduler) may depend.
//
// NOTE: Cooperative resources may not be nested below non-cooperative ones.
// This means that it is invalid to to acquire a SCHEDULE_COOPERATIVE_AND_KERNEL
// resource if a SCHEDULE_KERNEL_ONLY resource is already held.
enum SchedulingMode {
SCHEDULE_KERNEL_ONLY = 0, // Allow scheduling only the host OS.
SCHEDULE_COOPERATIVE_AND_KERNEL, // Also allow cooperative scheduling.
};
} // namespace base_internal
} // namespace absl
#endif // ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_

View File

@ -1,228 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include "absl/base/internal/spinlock.h"
#include <algorithm>
#include <atomic>
#include <limits>
#include "absl/base/attributes.h"
#include "absl/base/internal/atomic_hook.h"
#include "absl/base/internal/cycleclock.h"
#include "absl/base/internal/spinlock_wait.h"
#include "absl/base/internal/sysinfo.h" /* For NumCPUs() */
#include "absl/base/call_once.h"
// Description of lock-word:
// 31..00: [............................3][2][1][0]
//
// [0]: kSpinLockHeld
// [1]: kSpinLockCooperative
// [2]: kSpinLockDisabledScheduling
// [31..3]: ONLY kSpinLockSleeper OR
// Wait time in cycles >> PROFILE_TIMESTAMP_SHIFT
//
// Detailed descriptions:
//
// Bit [0]: The lock is considered held iff kSpinLockHeld is set.
//
// Bit [1]: Eligible waiters (e.g. Fibers) may co-operatively reschedule when
// contended iff kSpinLockCooperative is set.
//
// Bit [2]: This bit is exclusive from bit [1]. It is used only by a
// non-cooperative lock. When set, indicates that scheduling was
// successfully disabled when the lock was acquired. May be unset,
// even if non-cooperative, if a ThreadIdentity did not yet exist at
// time of acquisition.
//
// Bit [3]: If this is the only upper bit ([31..3]) set then this lock was
// acquired without contention, however, at least one waiter exists.
//
// Otherwise, bits [31..3] represent the time spent by the current lock
// holder to acquire the lock. There may be outstanding waiter(s).
namespace absl {
namespace base_internal {
ABSL_CONST_INIT static base_internal::AtomicHook<void (*)(const void *lock,
int64_t wait_cycles)>
submit_profile_data;
void RegisterSpinLockProfiler(void (*fn)(const void *contendedlock,
int64_t wait_cycles)) {
submit_profile_data.Store(fn);
}
// Uncommon constructors.
SpinLock::SpinLock(base_internal::SchedulingMode mode)
: lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
}
SpinLock::SpinLock(base_internal::LinkerInitialized,
base_internal::SchedulingMode mode) {
ABSL_TSAN_MUTEX_CREATE(this, 0);
if (IsCooperative(mode)) {
InitLinkerInitializedAndCooperative();
}
// Otherwise, lockword_ is already initialized.
}
// Static (linker initialized) spinlocks always start life as functional
// non-cooperative locks. When their static constructor does run, it will call
// this initializer to augment the lockword with the cooperative bit. By
// actually taking the lock when we do this we avoid the need for an atomic
// operation in the regular unlock path.
//
// SlowLock() must be careful to re-test for this bit so that any outstanding
// waiters may be upgraded to cooperative status.
void SpinLock::InitLinkerInitializedAndCooperative() {
Lock();
lockword_.fetch_or(kSpinLockCooperative, std::memory_order_relaxed);
Unlock();
}
// Monitor the lock to see if its value changes within some time period
// (adaptive_spin_count loop iterations). A timestamp indicating
// when the thread initially started waiting for the lock is passed in via
// the initial_wait_timestamp value. The total wait time in cycles for the
// lock is returned in the wait_cycles parameter. The last value read
// from the lock is returned from the method.
uint32_t SpinLock::SpinLoop(int64_t initial_wait_timestamp,
uint32_t *wait_cycles) {
// We are already in the slow path of SpinLock, initialize the
// adaptive_spin_count here.
ABSL_CONST_INIT static absl::once_flag init_adaptive_spin_count;
ABSL_CONST_INIT static int adaptive_spin_count = 0;
base_internal::LowLevelCallOnce(&init_adaptive_spin_count, []() {
adaptive_spin_count = base_internal::NumCPUs() > 1 ? 1000 : 1;
});
int c = adaptive_spin_count;
uint32_t lock_value;
do {
lock_value = lockword_.load(std::memory_order_relaxed);
} while ((lock_value & kSpinLockHeld) != 0 && --c > 0);
uint32_t spin_loop_wait_cycles =
EncodeWaitCycles(initial_wait_timestamp, CycleClock::Now());
*wait_cycles = spin_loop_wait_cycles;
return TryLockInternal(lock_value, spin_loop_wait_cycles);
}
void SpinLock::SlowLock() {
// The lock was not obtained initially, so this thread needs to wait for
// it. Record the current timestamp in the local variable wait_start_time
// so the total wait time can be stored in the lockword once this thread
// obtains the lock.
int64_t wait_start_time = CycleClock::Now();
uint32_t wait_cycles;
uint32_t lock_value = SpinLoop(wait_start_time, &wait_cycles);
int lock_wait_call_count = 0;
while ((lock_value & kSpinLockHeld) != 0) {
// If the lock is currently held, but not marked as having a sleeper, mark
// it as having a sleeper.
if ((lock_value & kWaitTimeMask) == 0) {
// Here, just "mark" that the thread is going to sleep. Don't store the
// lock wait time in the lock as that will cause the current lock
// owner to think it experienced contention.
if (lockword_.compare_exchange_strong(
lock_value, lock_value | kSpinLockSleeper,
std::memory_order_acquire, std::memory_order_relaxed)) {
// Successfully transitioned to kSpinLockSleeper. Pass
// kSpinLockSleeper to the SpinLockWait routine to properly indicate
// the last lock_value observed.
lock_value |= kSpinLockSleeper;
} else if ((lock_value & kSpinLockHeld) == 0) {
// Lock is free again, so try and acquire it before sleeping. The
// new lock state will be the number of cycles this thread waited if
// this thread obtains the lock.
lock_value = TryLockInternal(lock_value, wait_cycles);
continue; // Skip the delay at the end of the loop.
}
}
base_internal::SchedulingMode scheduling_mode;
if ((lock_value & kSpinLockCooperative) != 0) {
scheduling_mode = base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
} else {
scheduling_mode = base_internal::SCHEDULE_KERNEL_ONLY;
}
// SpinLockDelay() calls into fiber scheduler, we need to see
// synchronization there to avoid false positives.
ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0);
// Wait for an OS specific delay.
base_internal::SpinLockDelay(&lockword_, lock_value, ++lock_wait_call_count,
scheduling_mode);
ABSL_TSAN_MUTEX_POST_DIVERT(this, 0);
// Spin again after returning from the wait routine to give this thread
// some chance of obtaining the lock.
lock_value = SpinLoop(wait_start_time, &wait_cycles);
}
}
void SpinLock::SlowUnlock(uint32_t lock_value) {
base_internal::SpinLockWake(&lockword_,
false); // wake waiter if necessary
// If our acquisition was contended, collect contentionz profile info. We
// reserve a unitary wait time to represent that a waiter exists without our
// own acquisition having been contended.
if ((lock_value & kWaitTimeMask) != kSpinLockSleeper) {
const uint64_t wait_cycles = DecodeWaitCycles(lock_value);
ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0);
submit_profile_data(this, wait_cycles);
ABSL_TSAN_MUTEX_POST_DIVERT(this, 0);
}
}
// We use the upper 29 bits of the lock word to store the time spent waiting to
// acquire this lock. This is reported by contentionz profiling. Since the
// lower bits of the cycle counter wrap very quickly on high-frequency
// processors we divide to reduce the granularity to 2^PROFILE_TIMESTAMP_SHIFT
// sized units. On a 4Ghz machine this will lose track of wait times greater
// than (2^29/4 Ghz)*128 =~ 17.2 seconds. Such waits should be extremely rare.
enum { PROFILE_TIMESTAMP_SHIFT = 7 };
enum { LOCKWORD_RESERVED_SHIFT = 3 }; // We currently reserve the lower 3 bits.
uint32_t SpinLock::EncodeWaitCycles(int64_t wait_start_time,
int64_t wait_end_time) {
static const int64_t kMaxWaitTime =
std::numeric_limits<uint32_t>::max() >> LOCKWORD_RESERVED_SHIFT;
int64_t scaled_wait_time =
(wait_end_time - wait_start_time) >> PROFILE_TIMESTAMP_SHIFT;
// Return a representation of the time spent waiting that can be stored in
// the lock word's upper bits. bit_cast is required as Atomic32 is signed.
const uint32_t clamped = static_cast<uint32_t>(
std::min(scaled_wait_time, kMaxWaitTime) << LOCKWORD_RESERVED_SHIFT);
// bump up value if necessary to avoid returning kSpinLockSleeper.
const uint32_t after_spinlock_sleeper =
kSpinLockSleeper + (1 << LOCKWORD_RESERVED_SHIFT);
return clamped == kSpinLockSleeper ? after_spinlock_sleeper : clamped;
}
uint64_t SpinLock::DecodeWaitCycles(uint32_t lock_value) {
// Cast to uint32_t first to ensure bits [63:32] are cleared.
const uint64_t scaled_wait_time =
static_cast<uint32_t>(lock_value & kWaitTimeMask);
return scaled_wait_time
<< (PROFILE_TIMESTAMP_SHIFT - LOCKWORD_RESERVED_SHIFT);
}
} // namespace base_internal
} // namespace absl

View File

@ -1,239 +0,0 @@
//
// Copyright 2017 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
//
// http://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.
//
// Most users requiring mutual exclusion should use Mutex.
// SpinLock is provided for use in three situations:
// - for use in code that Mutex itself depends on
// - to get a faster fast-path release under low contention (without an
// atomic read-modify-write) In return, SpinLock has worse behaviour under
// contention, which is why Mutex is preferred in most situations.
// - for async signal safety (see below)
// SpinLock is async signal safe. If a spinlock is used within a signal
// handler, all code that acquires the lock must ensure that the signal cannot
// arrive while they are holding the lock. Typically, this is done by blocking
// the signal.
#ifndef ABSL_BASE_INTERNAL_SPINLOCK_H_
#define ABSL_BASE_INTERNAL_SPINLOCK_H_
#include <stdint.h>
#include <sys/types.h>
#include <atomic>
#include "absl/base/attributes.h"
#include "absl/base/dynamic_annotations.h"
#include "absl/base/internal/low_level_scheduling.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/scheduling_mode.h"
#include "absl/base/internal/tsan_mutex_interface.h"
#include "absl/base/macros.h"
#include "absl/base/port.h"
#include "absl/base/thread_annotations.h"
namespace absl {
namespace base_internal {
class LOCKABLE SpinLock {
public:
SpinLock() : lockword_(kSpinLockCooperative) {
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
}
// Special constructor for use with static SpinLock objects. E.g.,
//
// static SpinLock lock(base_internal::kLinkerInitialized);
//
// When intialized using this constructor, we depend on the fact
// that the linker has already initialized the memory appropriately.
// A SpinLock constructed like this can be freely used from global
// initializers without worrying about the order in which global
// initializers run.
explicit SpinLock(base_internal::LinkerInitialized) {
// Does nothing; lockword_ is already initialized
ABSL_TSAN_MUTEX_CREATE(this, 0);
}
// Constructors that allow non-cooperative spinlocks to be created for use
// inside thread schedulers. Normal clients should not use these.
explicit SpinLock(base_internal::SchedulingMode mode);
SpinLock(base_internal::LinkerInitialized,
base_internal::SchedulingMode mode);
~SpinLock() { ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); }
// Acquire this SpinLock.
inline void Lock() EXCLUSIVE_LOCK_FUNCTION() {
ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
if (!TryLockImpl()) {
SlowLock();
}
ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0);
}
// Try to acquire this SpinLock without blocking and return true if the
// acquisition was successful. If the lock was not acquired, false is
// returned. If this SpinLock is free at the time of the call, TryLock
// will return true with high probability.
inline bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock);
bool res = TryLockImpl();
ABSL_TSAN_MUTEX_POST_LOCK(
this, __tsan_mutex_try_lock | (res ? 0 : __tsan_mutex_try_lock_failed),
0);
return res;
}
// Release this SpinLock, which must be held by the calling thread.
inline void Unlock() UNLOCK_FUNCTION() {
ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0);
uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
lockword_.store(lock_value & kSpinLockCooperative,
std::memory_order_release);
if ((lock_value & kSpinLockDisabledScheduling) != 0) {
base_internal::SchedulingGuard::EnableRescheduling(true);
}
if ((lock_value & kWaitTimeMask) != 0) {
// Collect contentionz profile info, and speed the wakeup of any waiter.
// The wait_cycles value indicates how long this thread spent waiting
// for the lock.
SlowUnlock(lock_value);
}
ABSL_TSAN_MUTEX_POST_UNLOCK(this, 0);
}
// Determine if the lock is held. When the lock is held by the invoking
// thread, true will always be returned. Intended to be used as
// CHECK(lock.IsHeld()).
inline bool IsHeld() const {
return (lockword_.load(std::memory_order_relaxed) & kSpinLockHeld) != 0;
}
protected:
// These should not be exported except for testing.
// Store number of cycles between wait_start_time and wait_end_time in a
// lock value.
static uint32_t EncodeWaitCycles(int64_t wait_start_time,
int64_t wait_end_time);
// Extract number of wait cycles in a lock value.
static uint64_t DecodeWaitCycles(uint32_t lock_value);
// Provide access to protected method above. Use for testing only.
friend struct SpinLockTest;
private:
// lockword_ is used to store the following:
//
// bit[0] encodes whether a lock is being held.
// bit[1] encodes whether a lock uses cooperative scheduling.
// bit[2] encodes whether a lock disables scheduling.
// bit[3:31] encodes time a lock spent on waiting as a 29-bit unsigned int.
enum { kSpinLockHeld = 1 };
enum { kSpinLockCooperative = 2 };
enum { kSpinLockDisabledScheduling = 4 };
enum { kSpinLockSleeper = 8 };
enum { kWaitTimeMask = // Includes kSpinLockSleeper.
~(kSpinLockHeld | kSpinLockCooperative | kSpinLockDisabledScheduling) };
// Returns true if the provided scheduling mode is cooperative.
static constexpr bool IsCooperative(
base_internal::SchedulingMode scheduling_mode) {
return scheduling_mode == base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
}
uint32_t TryLockInternal(uint32_t lock_value, uint32_t wait_cycles);
void InitLinkerInitializedAndCooperative();
void SlowLock() ABSL_ATTRIBUTE_COLD;
void SlowUnlock(uint32_t lock_value) ABSL_ATTRIBUTE_COLD;
uint32_t SpinLoop(int64_t initial_wait_timestamp, uint32_t* wait_cycles);
inline bool TryLockImpl() {
uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
return (TryLockInternal(lock_value, 0) & kSpinLockHeld) == 0;
}
std::atomic<uint32_t> lockword_;
SpinLock(const SpinLock&) = delete;
SpinLock& operator=(const SpinLock&) = delete;
};
// Corresponding locker object that arranges to acquire a spinlock for
// the duration of a C++ scope.
class SCOPED_LOCKABLE SpinLockHolder {
public:
inline explicit SpinLockHolder(SpinLock* l) EXCLUSIVE_LOCK_FUNCTION(l)
: lock_(l) {
l->Lock();
}
inline ~SpinLockHolder() UNLOCK_FUNCTION() { lock_->Unlock(); }
SpinLockHolder(const SpinLockHolder&) = delete;
SpinLockHolder& operator=(const SpinLockHolder&) = delete;
private:
SpinLock* lock_;
};
// Register a hook for profiling support.
//
// The function pointer registered here will be called whenever a spinlock is
// contended. The callback is given an opaque handle to the contended spinlock
// and the number of wait cycles. This is thread-safe, but only a single
// profiler can be registered. It is an error to call this function multiple
// times with different arguments.
void RegisterSpinLockProfiler(void (*fn)(const void* lock,
int64_t wait_cycles));
//------------------------------------------------------------------------------
// Public interface ends here.
//------------------------------------------------------------------------------
// If (result & kSpinLockHeld) == 0, then *this was successfully locked.
// Otherwise, returns last observed value for lockword_.
inline uint32_t SpinLock::TryLockInternal(uint32_t lock_value,
uint32_t wait_cycles) {
if ((lock_value & kSpinLockHeld) != 0) {
return lock_value;
}
uint32_t sched_disabled_bit = 0;
if ((lock_value & kSpinLockCooperative) == 0) {
// For non-cooperative locks we must make sure we mark ourselves as
// non-reschedulable before we attempt to CompareAndSwap.
if (base_internal::SchedulingGuard::DisableRescheduling()) {
sched_disabled_bit = kSpinLockDisabledScheduling;
}
}
if (lockword_.compare_exchange_strong(
lock_value,
kSpinLockHeld | lock_value | wait_cycles | sched_disabled_bit,
std::memory_order_acquire, std::memory_order_relaxed)) {
} else {
base_internal::SchedulingGuard::EnableRescheduling(sched_disabled_bit != 0);
}
return lock_value;
}
} // namespace base_internal
} // namespace absl
#endif // ABSL_BASE_INTERNAL_SPINLOCK_H_

View File

@ -1,35 +0,0 @@
// Copyright 2017 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
//
// http://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.
//
// This file is an Akaros-specific part of spinlock_wait.cc
#include <atomic>
#include "absl/base/internal/scheduling_mode.h"
extern "C" {
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */,
int /* loop */, absl::base_internal::SchedulingMode /* mode */) {
// In Akaros, one must take care not to call anything that could cause a
// malloc(), a blocking system call, or a uthread_yield() while holding a
// spinlock. Our callers assume will not call into libraries or other
// arbitrary code.
}
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(
std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
} // extern "C"

View File

@ -1,46 +0,0 @@
// Copyright 2017 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
//
// http://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.
//
// This file is a Posix-specific part of spinlock_wait.cc
#include <sched.h>
#include <atomic>
#include <ctime>
#include <cerrno>
#include "absl/base/internal/scheduling_mode.h"
#include "absl/base/port.h"
extern "C" {
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, int loop,
absl::base_internal::SchedulingMode /* mode */) {
int save_errno = errno;
if (loop == 0) {
} else if (loop == 1) {
sched_yield();
} else {
struct timespec tm;
tm.tv_sec = 0;
tm.tv_nsec = absl::base_internal::SpinLockSuggestedDelayNS(loop);
nanosleep(&tm, nullptr);
}
errno = save_errno;
}
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(
std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
} // extern "C"

View File

@ -1,79 +0,0 @@
// Copyright 2017 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
//
// http://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.
// The OS-specific header included below must provide two calls:
// base::subtle::SpinLockDelay() and base::subtle::SpinLockWake().
// See spinlock_wait.h for the specs.
#include <atomic>
#include <cstdint>
#include "absl/base/internal/spinlock_wait.h"
#if defined(_WIN32)
#include "absl/base/internal/spinlock_win32.inc"
#elif defined(__akaros__)
#include "absl/base/internal/spinlock_akaros.inc"
#else
#include "absl/base/internal/spinlock_posix.inc"
#endif
namespace absl {
namespace base_internal {
// See spinlock_wait.h for spec.
uint32_t SpinLockWait(std::atomic<uint32_t> *w, int n,
const SpinLockWaitTransition trans[],
base_internal::SchedulingMode scheduling_mode) {
for (int loop = 0; ; loop++) {
uint32_t v = w->load(std::memory_order_acquire);
int i;
for (i = 0; i != n && v != trans[i].from; i++) {
}
if (i == n) {
SpinLockDelay(w, v, loop, scheduling_mode); // no matching transition
} else if (trans[i].to == v || // null transition
w->compare_exchange_strong(v, trans[i].to,
std::memory_order_acquire,
std::memory_order_relaxed)) {
if (trans[i].done) return v;
}
}
}
static std::atomic<uint64_t> delay_rand;
// Return a suggested delay in nanoseconds for iteration number "loop"
int SpinLockSuggestedDelayNS(int loop) {
// Weak pseudo-random number generator to get some spread between threads
// when many are spinning.
uint64_t r = delay_rand.load(std::memory_order_relaxed);
r = 0x5deece66dLL * r + 0xb; // numbers from nrand48()
delay_rand.store(r, std::memory_order_relaxed);
r <<= 16; // 48-bit random number now in top 48-bits.
if (loop < 0 || loop > 32) { // limit loop to 0..32
loop = 32;
}
// loop>>3 cannot exceed 4 because loop cannot exceed 32.
// Select top 20..24 bits of lower 48 bits,
// giving approximately 0ms to 16ms.
// Mean is exponential in loop for first 32 iterations, then 8ms.
// The futex path multiplies this by 16, since we expect explicit wakeups
// almost always on that path.
return static_cast<int>(r >> (44 - (loop >> 3)));
}
} // namespace base_internal
} // namespace absl

View File

@ -1,91 +0,0 @@
// Copyright 2017 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
//
// http://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.
#ifndef ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_
#define ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_
// Operations to make atomic transitions on a word, and to allow
// waiting for those transitions to become possible.
#include <stdint.h>
#include <atomic>
#include "absl/base/internal/scheduling_mode.h"
namespace absl {
namespace base_internal {
// SpinLockWait() waits until it can perform one of several transitions from
// "from" to "to". It returns when it performs a transition where done==true.
struct SpinLockWaitTransition {
uint32_t from;
uint32_t to;
bool done;
};
// Wait until *w can transition from trans[i].from to trans[i].to for some i
// satisfying 0<=i<n && trans[i].done, atomically make the transition,
// then return the old value of *w. Make any other atomic transitions
// where !trans[i].done, but continue waiting.
uint32_t SpinLockWait(std::atomic<uint32_t> *w, int n,
const SpinLockWaitTransition trans[],
SchedulingMode scheduling_mode);
// If possible, wake some thread that has called SpinLockDelay(w, ...). If
// "all" is true, wake all such threads. This call is a hint, and on some
// systems it may be a no-op; threads calling SpinLockDelay() will always wake
// eventually even if SpinLockWake() is never called.
void SpinLockWake(std::atomic<uint32_t> *w, bool all);
// Wait for an appropriate spin delay on iteration "loop" of a
// spin loop on location *w, whose previously observed value was "value".
// SpinLockDelay() may do nothing, may yield the CPU, may sleep a clock tick,
// or may wait for a delay that can be truncated by a call to SpinLockWake(w).
// In all cases, it must return in bounded time even if SpinLockWake() is not
// called.
void SpinLockDelay(std::atomic<uint32_t> *w, uint32_t value, int loop,
base_internal::SchedulingMode scheduling_mode);
// Helper used by AbslInternalSpinLockDelay.
// Returns a suggested delay in nanoseconds for iteration number "loop".
int SpinLockSuggestedDelayNS(int loop);
} // namespace base_internal
} // namespace absl
// In some build configurations we pass --detect-odr-violations to the
// gold linker. This causes it to flag weak symbol overrides as ODR
// violations. Because ODR only applies to C++ and not C,
// --detect-odr-violations ignores symbols not mangled with C++ names.
// By changing our extension points to be extern "C", we dodge this
// check.
extern "C" {
void AbslInternalSpinLockWake(std::atomic<uint32_t> *w, bool all);
void AbslInternalSpinLockDelay(
std::atomic<uint32_t> *w, uint32_t value, int loop,
absl::base_internal::SchedulingMode scheduling_mode);
}
inline void absl::base_internal::SpinLockWake(std::atomic<uint32_t> *w,
bool all) {
AbslInternalSpinLockWake(w, all);
}
inline void absl::base_internal::SpinLockDelay(
std::atomic<uint32_t> *w, uint32_t value, int loop,
absl::base_internal::SchedulingMode scheduling_mode) {
AbslInternalSpinLockDelay(w, value, loop, scheduling_mode);
}
#endif // ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_

View File

@ -1,37 +0,0 @@
// Copyright 2017 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
//
// http://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.
//
// This file is a Win32-specific part of spinlock_wait.cc
#include <windows.h>
#include <atomic>
#include "absl/base/internal/scheduling_mode.h"
extern "C" {
void AbslInternalSpinLockDelay(std::atomic<uint32_t>* /* lock_word */,
uint32_t /* value */, int loop,
absl::base_internal::SchedulingMode /* mode */) {
if (loop == 0) {
} else if (loop == 1) {
Sleep(0);
} else {
Sleep(absl::base_internal::SpinLockSuggestedDelayNS(loop) / 1000000);
}
}
void AbslInternalSpinLockWake(std::atomic<uint32_t>* /* lock_word */,
bool /* all */) {}
} // extern "C"

View File

@ -1,404 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include "absl/base/internal/sysinfo.h"
#include "absl/base/attributes.h"
#ifdef _WIN32
#include <shlwapi.h>
#include <windows.h>
#else
#include <fcntl.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#endif
#ifdef __linux__
#include <sys/syscall.h>
#endif
#if defined(__APPLE__) || defined(__FreeBSD__)
#include <sys/sysctl.h>
#endif
#if defined(__myriad2__)
#include <rtems.h>
#endif
#include <string.h>
#include <cassert>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <limits>
#include <thread> // NOLINT(build/c++11)
#include <utility>
#include <vector>
#include "absl/base/call_once.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/spinlock.h"
#include "absl/base/internal/unscaledcycleclock.h"
namespace absl {
namespace base_internal {
static once_flag init_system_info_once;
static int num_cpus = 0;
static double nominal_cpu_frequency = 1.0; // 0.0 might be dangerous.
static int GetNumCPUs() {
#if defined(__myriad2__)
return 1;
#else
// Other possibilities:
// - Read /sys/devices/system/cpu/online and use cpumask_parse()
// - sysconf(_SC_NPROCESSORS_ONLN)
return std::thread::hardware_concurrency();
#endif
}
#if defined(_WIN32)
static double GetNominalCPUFrequency() {
DWORD data;
DWORD data_size = sizeof(data);
#pragma comment(lib, "shlwapi.lib") // For SHGetValue().
if (SUCCEEDED(
SHGetValueA(HKEY_LOCAL_MACHINE,
"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
"~MHz", nullptr, &data, &data_size))) {
return data * 1e6; // Value is MHz.
}
return 1.0;
}
#elif defined(CTL_HW) && defined(HW_CPU_FREQ)
static double GetNominalCPUFrequency() {
unsigned freq;
size_t size = sizeof(freq);
int mib[2] = {CTL_HW, HW_CPU_FREQ};
if (sysctl(mib, 2, &freq, &size, nullptr, 0) == 0) {
return static_cast<double>(freq);
}
return 1.0;
}
#else
// Helper function for reading a long from a file. Returns true if successful
// and the memory location pointed to by value is set to the value read.
static bool ReadLongFromFile(const char *file, long *value) {
bool ret = false;
int fd = open(file, O_RDONLY);
if (fd != -1) {
char line[1024];
char *err;
memset(line, '\0', sizeof(line));
int len = read(fd, line, sizeof(line) - 1);
if (len <= 0) {
ret = false;
} else {
const long temp_value = strtol(line, &err, 10);
if (line[0] != '\0' && (*err == '\n' || *err == '\0')) {
*value = temp_value;
ret = true;
}
}
close(fd);
}
return ret;
}
#if defined(ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY)
// Reads a monotonic time source and returns a value in
// nanoseconds. The returned value uses an arbitrary epoch, not the
// Unix epoch.
static int64_t ReadMonotonicClockNanos() {
struct timespec t;
#ifdef CLOCK_MONOTONIC_RAW
int rc = clock_gettime(CLOCK_MONOTONIC_RAW, &t);
#else
int rc = clock_gettime(CLOCK_MONOTONIC, &t);
#endif
if (rc != 0) {
perror("clock_gettime() failed");
abort();
}
return int64_t{t.tv_sec} * 1000000000 + t.tv_nsec;
}
class UnscaledCycleClockWrapperForInitializeFrequency {
public:
static int64_t Now() { return base_internal::UnscaledCycleClock::Now(); }
};
struct TimeTscPair {
int64_t time; // From ReadMonotonicClockNanos().
int64_t tsc; // From UnscaledCycleClock::Now().
};
// Returns a pair of values (monotonic kernel time, TSC ticks) that
// approximately correspond to each other. This is accomplished by
// doing several reads and picking the reading with the lowest
// latency. This approach is used to minimize the probability that
// our thread was preempted between clock reads.
static TimeTscPair GetTimeTscPair() {
int64_t best_latency = std::numeric_limits<int64_t>::max();
TimeTscPair best;
for (int i = 0; i < 10; ++i) {
int64_t t0 = ReadMonotonicClockNanos();
int64_t tsc = UnscaledCycleClockWrapperForInitializeFrequency::Now();
int64_t t1 = ReadMonotonicClockNanos();
int64_t latency = t1 - t0;
if (latency < best_latency) {
best_latency = latency;
best.time = t0;
best.tsc = tsc;
}
}
return best;
}
// Measures and returns the TSC frequency by taking a pair of
// measurements approximately `sleep_nanoseconds` apart.
static double MeasureTscFrequencyWithSleep(int sleep_nanoseconds) {
auto t0 = GetTimeTscPair();
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = sleep_nanoseconds;
while (nanosleep(&ts, &ts) != 0 && errno == EINTR) {}
auto t1 = GetTimeTscPair();
double elapsed_ticks = t1.tsc - t0.tsc;
double elapsed_time = (t1.time - t0.time) * 1e-9;
return elapsed_ticks / elapsed_time;
}
// Measures and returns the TSC frequency by calling
// MeasureTscFrequencyWithSleep(), doubling the sleep interval until the
// frequency measurement stabilizes.
static double MeasureTscFrequency() {
double last_measurement = -1.0;
int sleep_nanoseconds = 1000000; // 1 millisecond.
for (int i = 0; i < 8; ++i) {
double measurement = MeasureTscFrequencyWithSleep(sleep_nanoseconds);
if (measurement * 0.99 < last_measurement &&
last_measurement < measurement * 1.01) {
// Use the current measurement if it is within 1% of the
// previous measurement.
return measurement;
}
last_measurement = measurement;
sleep_nanoseconds *= 2;
}
return last_measurement;
}
#endif // ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
static double GetNominalCPUFrequency() {
long freq = 0;
// Google's production kernel has a patch to export the TSC
// frequency through sysfs. If the kernel is exporting the TSC
// frequency use that. There are issues where cpuinfo_max_freq
// cannot be relied on because the BIOS may be exporting an invalid
// p-state (on x86) or p-states may be used to put the processor in
// a new mode (turbo mode). Essentially, those frequencies cannot
// always be relied upon. The same reasons apply to /proc/cpuinfo as
// well.
if (ReadLongFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz", &freq)) {
return freq * 1e3; // Value is kHz.
}
#if defined(ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY)
// On these platforms, the TSC frequency is the nominal CPU
// frequency. But without having the kernel export it directly
// though /sys/devices/system/cpu/cpu0/tsc_freq_khz, there is no
// other way to reliably get the TSC frequency, so we have to
// measure it ourselves. Some CPUs abuse cpuinfo_max_freq by
// exporting "fake" frequencies for implementing new features. For
// example, Intel's turbo mode is enabled by exposing a p-state
// value with a higher frequency than that of the real TSC
// rate. Because of this, we prefer to measure the TSC rate
// ourselves on i386 and x86-64.
return MeasureTscFrequency();
#else
// If CPU scaling is in effect, we want to use the *maximum*
// frequency, not whatever CPU speed some random processor happens
// to be using now.
if (ReadLongFromFile("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq",
&freq)) {
return freq * 1e3; // Value is kHz.
}
return 1.0;
#endif // !ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
}
#endif
// InitializeSystemInfo() may be called before main() and before
// malloc is properly initialized, therefore this must not allocate
// memory.
static void InitializeSystemInfo() {
num_cpus = GetNumCPUs();
nominal_cpu_frequency = GetNominalCPUFrequency();
}
int NumCPUs() {
base_internal::LowLevelCallOnce(&init_system_info_once, InitializeSystemInfo);
return num_cpus;
}
double NominalCPUFrequency() {
base_internal::LowLevelCallOnce(&init_system_info_once, InitializeSystemInfo);
return nominal_cpu_frequency;
}
#if defined(_WIN32)
pid_t GetTID() {
return GetCurrentThreadId();
}
#elif defined(__linux__)
#ifndef SYS_gettid
#define SYS_gettid __NR_gettid
#endif
pid_t GetTID() {
return syscall(SYS_gettid);
}
#elif defined(__akaros__)
pid_t GetTID() {
// Akaros has a concept of "vcore context", which is the state the program
// is forced into when we need to make a user-level scheduling decision, or
// run a signal handler. This is analogous to the interrupt context that a
// CPU might enter if it encounters some kind of exception.
//
// There is no current thread context in vcore context, but we need to give
// a reasonable answer if asked for a thread ID (e.g., in a signal handler).
// Thread 0 always exists, so if we are in vcore context, we return that.
//
// Otherwise, we know (since we are using pthreads) that the uthread struct
// current_uthread is pointing to is the first element of a
// struct pthread_tcb, so we extract and return the thread ID from that.
//
// TODO(dcross): Akaros anticipates moving the thread ID to the uthread
// structure at some point. We should modify this code to remove the cast
// when that happens.
if (in_vcore_context())
return 0;
return reinterpret_cast<struct pthread_tcb *>(current_uthread)->id;
}
#elif defined(__myriad2__)
pid_t GetTID() {
uint32_t tid;
rtems_task_ident(RTEMS_SELF, 0, &tid);
return tid;
}
#else
// Fallback implementation of GetTID using pthread_getspecific.
static once_flag tid_once;
static pthread_key_t tid_key;
static absl::base_internal::SpinLock tid_lock(
absl::base_internal::kLinkerInitialized);
// We set a bit per thread in this array to indicate that an ID is in
// use. ID 0 is unused because it is the default value returned by
// pthread_getspecific().
static std::vector<uint32_t>* tid_array GUARDED_BY(tid_lock) = nullptr;
static constexpr int kBitsPerWord = 32; // tid_array is uint32_t.
// Returns the TID to tid_array.
static void FreeTID(void *v) {
intptr_t tid = reinterpret_cast<intptr_t>(v);
int word = tid / kBitsPerWord;
uint32_t mask = ~(1u << (tid % kBitsPerWord));
absl::base_internal::SpinLockHolder lock(&tid_lock);
assert(0 <= word && static_cast<size_t>(word) < tid_array->size());
(*tid_array)[word] &= mask;
}
static void InitGetTID() {
if (pthread_key_create(&tid_key, FreeTID) != 0) {
// The logging system calls GetTID() so it can't be used here.
perror("pthread_key_create failed");
abort();
}
// Initialize tid_array.
absl::base_internal::SpinLockHolder lock(&tid_lock);
tid_array = new std::vector<uint32_t>(1);
(*tid_array)[0] = 1; // ID 0 is never-allocated.
}
// Return a per-thread small integer ID from pthread's thread-specific data.
pid_t GetTID() {
absl::call_once(tid_once, InitGetTID);
intptr_t tid = reinterpret_cast<intptr_t>(pthread_getspecific(tid_key));
if (tid != 0) {
return tid;
}
int bit; // tid_array[word] = 1u << bit;
size_t word;
{
// Search for the first unused ID.
absl::base_internal::SpinLockHolder lock(&tid_lock);
// First search for a word in the array that is not all ones.
word = 0;
while (word < tid_array->size() && ~(*tid_array)[word] == 0) {
++word;
}
if (word == tid_array->size()) {
tid_array->push_back(0); // No space left, add kBitsPerWord more IDs.
}
// Search for a zero bit in the word.
bit = 0;
while (bit < kBitsPerWord && (((*tid_array)[word] >> bit) & 1) != 0) {
++bit;
}
tid = (word * kBitsPerWord) + bit;
(*tid_array)[word] |= 1u << bit; // Mark the TID as allocated.
}
if (pthread_setspecific(tid_key, reinterpret_cast<void *>(tid)) != 0) {
perror("pthread_setspecific failed");
abort();
}
return static_cast<pid_t>(tid);
}
#endif
} // namespace base_internal
} // namespace absl

View File

@ -1,63 +0,0 @@
// Copyright 2017 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
//
// http://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.
//
// This file includes routines to find out characteristics
// of the machine a program is running on. It is undoubtedly
// system-dependent.
// Functions listed here that accept a pid_t as an argument act on the
// current process if the pid_t argument is 0
// All functions here are thread-hostile due to file caching unless
// commented otherwise.
#ifndef ABSL_BASE_INTERNAL_SYSINFO_H_
#define ABSL_BASE_INTERNAL_SYSINFO_H_
#ifndef _WIN32
#include <sys/types.h>
#else
#include <intsafe.h>
#endif
#include "absl/base/port.h"
namespace absl {
namespace base_internal {
// Nominal core processor cycles per second of each processor. This is _not_
// necessarily the frequency of the CycleClock counter (see cycleclock.h)
// Thread-safe.
double NominalCPUFrequency();
// Number of logical processors (hyperthreads) in system. Thread-safe.
int NumCPUs();
// Return the thread id of the current thread, as told by the system.
// No two currently-live threads implemented by the OS shall have the same ID.
// Thread ids of exited threads may be reused. Multiple user-level threads
// may have the same thread ID if multiplexed on the same OS thread.
//
// On Linux, you may send a signal to the resulting ID with kill(). However,
// it is recommended for portability that you use pthread_kill() instead.
#ifdef _WIN32
// On Windows, process id and thread id are of the same type according to
// the return types of GetProcessId() and GetThreadId() are both DWORD.
using pid_t = DWORD;
#endif
pid_t GetTID();
} // namespace base_internal
} // namespace absl
#endif // ABSL_BASE_INTERNAL_SYSINFO_H_

View File

@ -1,98 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include "absl/base/internal/sysinfo.h"
#ifndef _WIN32
#include <sys/types.h>
#include <unistd.h>
#endif
#include <thread> // NOLINT(build/c++11)
#include <unordered_set>
#include <vector>
#include "gtest/gtest.h"
#include "absl/synchronization/barrier.h"
#include "absl/synchronization/mutex.h"
namespace absl {
namespace base_internal {
namespace {
TEST(SysinfoTest, NumCPUs) {
EXPECT_NE(NumCPUs(), 0)
<< "NumCPUs() should not have the default value of 0";
}
TEST(SysinfoTest, NominalCPUFrequency) {
#if !(defined(__aarch64__) && defined(__linux__))
EXPECT_GE(NominalCPUFrequency(), 1000.0)
<< "NominalCPUFrequency() did not return a reasonable value";
#else
// TODO(absl-team): Aarch64 cannot read the CPU frequency from sysfs, so we
// get back 1.0. Fix once the value is available.
EXPECT_EQ(NominalCPUFrequency(), 1.0)
<< "CPU frequency detection was fixed! Please update unittest.";
#endif
}
TEST(SysinfoTest, GetTID) {
EXPECT_EQ(GetTID(), GetTID()); // Basic compile and equality test.
#ifdef __native_client__
// Native Client has a race condition bug that leads to memory
// exaustion when repeatedly creating and joining threads.
// https://bugs.chromium.org/p/nativeclient/issues/detail?id=1027
return;
#endif
// Test that TIDs are unique to each thread.
// Uses a few loops to exercise implementations that reallocate IDs.
for (int i = 0; i < 32; ++i) {
constexpr int kNumThreads = 64;
Barrier all_threads_done(kNumThreads);
std::vector<std::thread> threads;
Mutex mutex;
std::unordered_set<pid_t> tids;
for (int j = 0; j < kNumThreads; ++j) {
threads.push_back(std::thread([&]() {
pid_t id = GetTID();
{
MutexLock lock(&mutex);
ASSERT_TRUE(tids.find(id) == tids.end());
tids.insert(id);
}
// We can't simply join the threads here. The threads need to
// be alive otherwise the TID might have been reallocated to
// another live thread.
all_threads_done.Block();
}));
}
for (auto& thread : threads) {
thread.join();
}
}
}
#ifdef __linux__
TEST(SysinfoTest, LinuxGetTID) {
// On Linux, for the main thread, GetTID()==getpid() is guaranteed by the API.
EXPECT_EQ(GetTID(), getpid());
}
#endif
} // namespace
} // namespace base_internal
} // namespace absl

View File

@ -1,123 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include "absl/base/internal/thread_identity.h"
#ifndef _WIN32
#include <pthread.h>
#include <signal.h>
#endif
#include <atomic>
#include <cassert>
#include <memory>
#include "absl/base/call_once.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/spinlock.h"
namespace absl {
namespace base_internal {
#if ABSL_THREAD_IDENTITY_MODE != ABSL_THREAD_IDENTITY_MODE_USE_CPP11
namespace {
// Used to co-ordinate one-time creation of our pthread_key
absl::once_flag init_thread_identity_key_once;
pthread_key_t thread_identity_pthread_key;
std::atomic<bool> pthread_key_initialized(false);
void AllocateThreadIdentityKey(ThreadIdentityReclaimerFunction reclaimer) {
pthread_key_create(&thread_identity_pthread_key, reclaimer);
pthread_key_initialized.store(true, std::memory_order_release);
}
} // namespace
#endif
#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
// The actual TLS storage for a thread's currently associated ThreadIdentity.
// This is referenced by inline accessors in the header.
// "protected" visibility ensures that if multiple instances of Abseil code
// exist within a process (via dlopen() or similar), references to
// thread_identity_ptr from each instance of the code will refer to
// *different* instances of this ptr.
#ifdef __GNUC__
__attribute__((visibility("protected")))
#endif // __GNUC__
ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr;
#endif // TLS or CPP11
void SetCurrentThreadIdentity(
ThreadIdentity* identity, ThreadIdentityReclaimerFunction reclaimer) {
assert(CurrentThreadIdentityIfPresent() == nullptr);
// Associate our destructor.
// NOTE: This call to pthread_setspecific is currently the only immovable
// barrier to CurrentThreadIdentity() always being async signal safe.
#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
// NOTE: Not async-safe. But can be open-coded.
absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey,
reclaimer);
// We must mask signals around the call to setspecific as with current glibc,
// a concurrent getspecific (needed for GetCurrentThreadIdentityIfPresent())
// may zero our value.
//
// While not officially async-signal safe, getspecific within a signal handler
// is otherwise OK.
sigset_t all_signals;
sigset_t curr_signals;
sigfillset(&all_signals);
pthread_sigmask(SIG_SETMASK, &all_signals, &curr_signals);
pthread_setspecific(thread_identity_pthread_key,
reinterpret_cast<void*>(identity));
pthread_sigmask(SIG_SETMASK, &curr_signals, nullptr);
#elif ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS
// NOTE: Not async-safe. But can be open-coded.
absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey,
reclaimer);
pthread_setspecific(thread_identity_pthread_key,
reinterpret_cast<void*>(identity));
thread_identity_ptr = identity;
#elif ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
thread_local std::unique_ptr<ThreadIdentity, ThreadIdentityReclaimerFunction>
holder(identity, reclaimer);
thread_identity_ptr = identity;
#else
#error Unimplemented ABSL_THREAD_IDENTITY_MODE
#endif
}
void ClearCurrentThreadIdentity() {
#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
thread_identity_ptr = nullptr;
#elif ABSL_THREAD_IDENTITY_MODE == \
ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
// pthread_setspecific expected to clear value on destruction
assert(CurrentThreadIdentityIfPresent() == nullptr);
#endif
}
#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
ThreadIdentity* CurrentThreadIdentityIfPresent() {
bool initialized = pthread_key_initialized.load(std::memory_order_acquire);
if (!initialized) {
return nullptr;
}
return reinterpret_cast<ThreadIdentity*>(
pthread_getspecific(thread_identity_pthread_key));
}
#endif
} // namespace base_internal
} // namespace absl

View File

@ -1,240 +0,0 @@
// Copyright 2017 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
//
// http://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.
//
// Each active thread has an ThreadIdentity that may represent the thread in
// various level interfaces. ThreadIdentity objects are never deallocated.
// When a thread terminates, its ThreadIdentity object may be reused for a
// thread created later.
#ifndef ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
#define ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
#ifndef _WIN32
#include <pthread.h>
// Defines __GOOGLE_GRTE_VERSION__ (via glibc-specific features.h) when
// supported.
#include <unistd.h>
#endif
#include <atomic>
#include <cstdint>
#include "absl/base/internal/per_thread_tls.h"
namespace absl {
struct SynchLocksHeld;
struct SynchWaitParams;
namespace base_internal {
class SpinLock;
struct ThreadIdentity;
// Used by the implementation of base::Mutex and base::CondVar.
struct PerThreadSynch {
// The internal representation of base::Mutex and base::CondVar rely
// on the alignment of PerThreadSynch. Both store the address of the
// PerThreadSynch in the high-order bits of their internal state,
// which means the low kLowZeroBits of the address of PerThreadSynch
// must be zero.
static constexpr int kLowZeroBits = 8;
static constexpr int kAlignment = 1 << kLowZeroBits;
// Returns the associated ThreadIdentity.
// This can be implemented as a cast because we guarantee
// PerThreadSynch is the first element of ThreadIdentity.
ThreadIdentity* thread_identity() {
return reinterpret_cast<ThreadIdentity*>(this);
}
PerThreadSynch *next; // Circular waiter queue; initialized to 0.
PerThreadSynch *skip; // If non-zero, all entries in Mutex queue
// up to and including "skip" have same
// condition as this, and will be woken later
bool may_skip; // if false while on mutex queue, a mutex unlocker
// is using this PerThreadSynch as a terminator. Its
// skip field must not be filled in because the loop
// might then skip over the terminator.
// The wait parameters of the current wait. waitp is null if the
// thread is not waiting. Transitions from null to non-null must
// occur before the enqueue commit point (state = kQueued in
// Enqueue() and CondVarEnqueue()). Transitions from non-null to
// null must occur after the wait is finished (state = kAvailable in
// Mutex::Block() and CondVar::WaitCommon()). This field may be
// changed only by the thread that describes this PerThreadSynch. A
// special case is Fer(), which calls Enqueue() on another thread,
// but with an identical SynchWaitParams pointer, thus leaving the
// pointer unchanged.
SynchWaitParams *waitp;
bool suppress_fatal_errors; // If true, try to proceed even in the face of
// broken invariants. This is used within fatal
// signal handlers to improve the chances of
// debug logging information being output
// successfully.
intptr_t readers; // Number of readers in mutex.
int priority; // Priority of thread (updated every so often).
// When priority will next be read (cycles).
int64_t next_priority_read_cycles;
// State values:
// kAvailable: This PerThreadSynch is available.
// kQueued: This PerThreadSynch is unavailable, it's currently queued on a
// Mutex or CondVar waistlist.
//
// Transitions from kQueued to kAvailable require a release
// barrier. This is needed as a waiter may use "state" to
// independently observe that it's no longer queued.
//
// Transitions from kAvailable to kQueued require no barrier, they
// are externally ordered by the Mutex.
enum State {
kAvailable,
kQueued
};
std::atomic<State> state;
bool maybe_unlocking; // Valid at head of Mutex waiter queue;
// true if UnlockSlow could be searching
// for a waiter to wake. Used for an optimization
// in Enqueue(). true is always a valid value.
// Can be reset to false when the unlocker or any
// writer releases the lock, or a reader fully releases
// the lock. It may not be set to false by a reader
// that decrements the count to non-zero.
// protected by mutex spinlock
bool wake; // This thread is to be woken from a Mutex.
// If "x" is on a waiter list for a mutex, "x->cond_waiter" is true iff the
// waiter is waiting on the mutex as part of a CV Wait or Mutex Await.
//
// The value of "x->cond_waiter" is meaningless if "x" is not on a
// Mutex waiter list.
bool cond_waiter;
// Locks held; used during deadlock detection.
// Allocated in Synch_GetAllLocks() and freed in ReclaimThreadIdentity().
SynchLocksHeld *all_locks;
};
struct ThreadIdentity {
// Must be the first member. The Mutex implementation requires that
// the PerThreadSynch object associated with each thread is
// PerThreadSynch::kAlignment aligned. We provide this alignment on
// ThreadIdentity itself.
PerThreadSynch per_thread_synch;
// Private: Reserved for absl::synchronization_internal::Waiter.
struct WaiterState {
char data[128];
} waiter_state;
// Used by PerThreadSem::{Get,Set}ThreadBlockedCounter().
std::atomic<int>* blocked_count_ptr;
// The following variables are mostly read/written just by the
// thread itself. The only exception is that these are read by
// a ticker thread as a hint.
std::atomic<int> ticker; // Tick counter, incremented once per second.
std::atomic<int> wait_start; // Ticker value when thread started waiting.
std::atomic<bool> is_idle; // Has thread become idle yet?
ThreadIdentity* next;
};
// Returns the ThreadIdentity object representing the calling thread; guaranteed
// to be unique for its lifetime. The returned object will remain valid for the
// program's lifetime; although it may be re-assigned to a subsequent thread.
// If one does not exist, return nullptr instead.
//
// Does not malloc(*), and is async-signal safe.
// [*] Technically pthread_setspecific() does malloc on first use; however this
// is handled internally within tcmalloc's initialization already.
//
// New ThreadIdentity objects can be constructed and associated with a thread
// by calling GetOrCreateCurrentThreadIdentity() in per-thread-sem.h.
ThreadIdentity* CurrentThreadIdentityIfPresent();
using ThreadIdentityReclaimerFunction = void (*)(void*);
// Sets the current thread identity to the given value. 'reclaimer' is a
// pointer to the global function for cleaning up instances on thread
// destruction.
void SetCurrentThreadIdentity(ThreadIdentity* identity,
ThreadIdentityReclaimerFunction reclaimer);
// Removes the currently associated ThreadIdentity from the running thread.
// This must be called from inside the ThreadIdentityReclaimerFunction, and only
// from that function.
void ClearCurrentThreadIdentity();
// May be chosen at compile time via: -DABSL_FORCE_THREAD_IDENTITY_MODE=<mode
// index>
#ifdef ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
#error ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC cannot be direcly set
#else
#define ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC 0
#endif
#ifdef ABSL_THREAD_IDENTITY_MODE_USE_TLS
#error ABSL_THREAD_IDENTITY_MODE_USE_TLS cannot be direcly set
#else
#define ABSL_THREAD_IDENTITY_MODE_USE_TLS 1
#endif
#ifdef ABSL_THREAD_IDENTITY_MODE_USE_CPP11
#error ABSL_THREAD_IDENTITY_MODE_USE_CPP11 cannot be direcly set
#else
#define ABSL_THREAD_IDENTITY_MODE_USE_CPP11 2
#endif
#ifdef ABSL_THREAD_IDENTITY_MODE
#error ABSL_THREAD_IDENTITY_MODE cannot be direcly set
#elif defined(ABSL_FORCE_THREAD_IDENTITY_MODE)
#define ABSL_THREAD_IDENTITY_MODE ABSL_FORCE_THREAD_IDENTITY_MODE
#elif defined(_WIN32)
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \
(__GOOGLE_GRTE_VERSION__ >= 20140228L)
// Support for async-safe TLS was specifically added in GRTEv4. It's not
// present in the upstream eglibc.
// Note: Current default for production systems.
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_TLS
#else
#define ABSL_THREAD_IDENTITY_MODE \
ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
#endif
#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
extern ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr;
inline ThreadIdentity* CurrentThreadIdentityIfPresent() {
return thread_identity_ptr;
}
#elif ABSL_THREAD_IDENTITY_MODE != \
ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
#error Unknown ABSL_THREAD_IDENTITY_MODE
#endif
} // namespace base_internal
} // namespace absl
#endif // ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_

View File

@ -1,38 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include "benchmark/benchmark.h"
#include "absl/base/internal/thread_identity.h"
#include "absl/synchronization/internal/create_thread_identity.h"
#include "absl/synchronization/internal/per_thread_sem.h"
namespace {
void BM_SafeCurrentThreadIdentity(benchmark::State& state) {
for (auto _ : state) {
benchmark::DoNotOptimize(
absl::synchronization_internal::GetOrCreateCurrentThreadIdentity());
}
}
BENCHMARK(BM_SafeCurrentThreadIdentity);
void BM_UnsafeCurrentThreadIdentity(benchmark::State& state) {
for (auto _ : state) {
benchmark::DoNotOptimize(
absl::base_internal::CurrentThreadIdentityIfPresent());
}
}
BENCHMARK(BM_UnsafeCurrentThreadIdentity);
} // namespace

View File

@ -1,126 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include "absl/base/internal/thread_identity.h"
#include <thread> // NOLINT(build/c++11)
#include <vector>
#include "gtest/gtest.h"
#include "absl/base/attributes.h"
#include "absl/base/internal/spinlock.h"
#include "absl/base/macros.h"
#include "absl/synchronization/internal/per_thread_sem.h"
#include "absl/synchronization/mutex.h"
namespace absl {
namespace base_internal {
namespace {
// protects num_identities_reused
static absl::base_internal::SpinLock map_lock(
absl::base_internal::kLinkerInitialized);
static int num_identities_reused;
static const void* const kCheckNoIdentity = reinterpret_cast<void*>(1);
static void TestThreadIdentityCurrent(const void* assert_no_identity) {
ThreadIdentity* identity;
// We have to test this conditionally, because if the test framework relies
// on Abseil, then some previous action may have already allocated an
// identity.
if (assert_no_identity == kCheckNoIdentity) {
identity = CurrentThreadIdentityIfPresent();
EXPECT_TRUE(identity == nullptr);
}
identity = synchronization_internal::GetOrCreateCurrentThreadIdentity();
EXPECT_TRUE(identity != nullptr);
ThreadIdentity* identity_no_init;
identity_no_init = CurrentThreadIdentityIfPresent();
EXPECT_TRUE(identity == identity_no_init);
// Check that per_thread_synch is correctly aligned.
EXPECT_EQ(0, reinterpret_cast<intptr_t>(&identity->per_thread_synch) %
PerThreadSynch::kAlignment);
EXPECT_EQ(identity, identity->per_thread_synch.thread_identity());
absl::base_internal::SpinLockHolder l(&map_lock);
num_identities_reused++;
}
TEST(ThreadIdentityTest, BasicIdentityWorks) {
// This tests for the main() thread.
TestThreadIdentityCurrent(nullptr);
}
TEST(ThreadIdentityTest, BasicIdentityWorksThreaded) {
// Now try the same basic test with multiple threads being created and
// destroyed. This makes sure that:
// - New threads are created without a ThreadIdentity.
// - We re-allocate ThreadIdentity objects from the free-list.
// - If a thread implementation chooses to recycle threads, that
// correct re-initialization occurs.
static const int kNumLoops = 3;
static const int kNumThreads = 400;
for (int iter = 0; iter < kNumLoops; iter++) {
std::vector<std::thread> threads;
for (int i = 0; i < kNumThreads; ++i) {
threads.push_back(
std::thread(TestThreadIdentityCurrent, kCheckNoIdentity));
}
for (auto& thread : threads) {
thread.join();
}
}
// We should have recycled ThreadIdentity objects above; while (external)
// library threads allocating their own identities may preclude some
// reuse, we should have sufficient repetitions to exclude this.
EXPECT_LT(kNumThreads, num_identities_reused);
}
TEST(ThreadIdentityTest, ReusedThreadIdentityMutexTest) {
// This test repeatly creates and joins a series of threads, each of
// which acquires and releases shared Mutex locks. This verifies
// Mutex operations work correctly under a reused
// ThreadIdentity. Note that the most likely failure mode of this
// test is a crash or deadlock.
static const int kNumLoops = 10;
static const int kNumThreads = 12;
static const int kNumMutexes = 3;
static const int kNumLockLoops = 5;
Mutex mutexes[kNumMutexes];
for (int iter = 0; iter < kNumLoops; ++iter) {
std::vector<std::thread> threads;
for (int thread = 0; thread < kNumThreads; ++thread) {
threads.push_back(std::thread([&]() {
for (int l = 0; l < kNumLockLoops; ++l) {
for (int m = 0; m < kNumMutexes; ++m) {
MutexLock lock(&mutexes[m]);
}
}
}));
}
for (auto& thread : threads) {
thread.join();
}
}
}
} // namespace
} // namespace base_internal
} // namespace absl

View File

@ -1,106 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include "absl/base/internal/throw_delegate.h"
#include <cstdlib>
#include <functional>
#include <new>
#include <stdexcept>
#include "absl/base/config.h"
#include "absl/base/internal/raw_logging.h"
namespace absl {
namespace base_internal {
namespace {
template <typename T>
[[noreturn]] void Throw(const T& error) {
#ifdef ABSL_HAVE_EXCEPTIONS
throw error;
#else
ABSL_RAW_LOG(ERROR, "%s", error.what());
abort();
#endif
}
} // namespace
void ThrowStdLogicError(const std::string& what_arg) {
Throw(std::logic_error(what_arg));
}
void ThrowStdLogicError(const char* what_arg) {
Throw(std::logic_error(what_arg));
}
void ThrowStdInvalidArgument(const std::string& what_arg) {
Throw(std::invalid_argument(what_arg));
}
void ThrowStdInvalidArgument(const char* what_arg) {
Throw(std::invalid_argument(what_arg));
}
void ThrowStdDomainError(const std::string& what_arg) {
Throw(std::domain_error(what_arg));
}
void ThrowStdDomainError(const char* what_arg) {
Throw(std::domain_error(what_arg));
}
void ThrowStdLengthError(const std::string& what_arg) {
Throw(std::length_error(what_arg));
}
void ThrowStdLengthError(const char* what_arg) {
Throw(std::length_error(what_arg));
}
void ThrowStdOutOfRange(const std::string& what_arg) {
Throw(std::out_of_range(what_arg));
}
void ThrowStdOutOfRange(const char* what_arg) {
Throw(std::out_of_range(what_arg));
}
void ThrowStdRuntimeError(const std::string& what_arg) {
Throw(std::runtime_error(what_arg));
}
void ThrowStdRuntimeError(const char* what_arg) {
Throw(std::runtime_error(what_arg));
}
void ThrowStdRangeError(const std::string& what_arg) {
Throw(std::range_error(what_arg));
}
void ThrowStdRangeError(const char* what_arg) {
Throw(std::range_error(what_arg));
}
void ThrowStdOverflowError(const std::string& what_arg) {
Throw(std::overflow_error(what_arg));
}
void ThrowStdOverflowError(const char* what_arg) {
Throw(std::overflow_error(what_arg));
}
void ThrowStdUnderflowError(const std::string& what_arg) {
Throw(std::underflow_error(what_arg));
}
void ThrowStdUnderflowError(const char* what_arg) {
Throw(std::underflow_error(what_arg));
}
void ThrowStdBadFunctionCall() { Throw(std::bad_function_call()); }
void ThrowStdBadAlloc() { Throw(std::bad_alloc()); }
} // namespace base_internal
} // namespace absl

View File

@ -1,71 +0,0 @@
//
// Copyright 2017 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
//
// http://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.
//
#ifndef ABSL_BASE_INTERNAL_THROW_DELEGATE_H_
#define ABSL_BASE_INTERNAL_THROW_DELEGATE_H_
#include <string>
namespace absl {
namespace base_internal {
// Helper functions that allow throwing exceptions consistently from anywhere.
// The main use case is for header-based libraries (eg templates), as they will
// be built by many different targets with their own compiler options.
// In particular, this will allow a safe way to throw exceptions even if the
// caller is compiled with -fno-exceptions. This is intended for implementing
// things like map<>::at(), which the standard documents as throwing an
// exception on error.
//
// Using other techniques like #if tricks could lead to ODR violations.
//
// You shouldn't use it unless you're writing code that you know will be built
// both with and without exceptions and you need to conform to an interface
// that uses exceptions.
[[noreturn]] void ThrowStdLogicError(const std::string& what_arg);
[[noreturn]] void ThrowStdLogicError(const char* what_arg);
[[noreturn]] void ThrowStdInvalidArgument(const std::string& what_arg);
[[noreturn]] void ThrowStdInvalidArgument(const char* what_arg);
[[noreturn]] void ThrowStdDomainError(const std::string& what_arg);
[[noreturn]] void ThrowStdDomainError(const char* what_arg);
[[noreturn]] void ThrowStdLengthError(const std::string& what_arg);
[[noreturn]] void ThrowStdLengthError(const char* what_arg);
[[noreturn]] void ThrowStdOutOfRange(const std::string& what_arg);
[[noreturn]] void ThrowStdOutOfRange(const char* what_arg);
[[noreturn]] void ThrowStdRuntimeError(const std::string& what_arg);
[[noreturn]] void ThrowStdRuntimeError(const char* what_arg);
[[noreturn]] void ThrowStdRangeError(const std::string& what_arg);
[[noreturn]] void ThrowStdRangeError(const char* what_arg);
[[noreturn]] void ThrowStdOverflowError(const std::string& what_arg);
[[noreturn]] void ThrowStdOverflowError(const char* what_arg);
[[noreturn]] void ThrowStdUnderflowError(const std::string& what_arg);
[[noreturn]] void ThrowStdUnderflowError(const char* what_arg);
[[noreturn]] void ThrowStdBadFunctionCall();
[[noreturn]] void ThrowStdBadAlloc();
// ThrowStdBadArrayNewLength() cannot be consistently supported because
// std::bad_array_new_length is missing in libstdc++ until 4.9.0.
// https://gcc.gnu.org/onlinedocs/gcc-4.8.3/libstdc++/api/a01379_source.html
// https://gcc.gnu.org/onlinedocs/gcc-4.9.0/libstdc++/api/a01327_source.html
// libcxx (as of 3.2) and msvc (as of 2015) both have it.
// [[noreturn]] void ThrowStdBadArrayNewLength();
} // namespace base_internal
} // namespace absl
#endif // ABSL_BASE_INTERNAL_THROW_DELEGATE_H_

View File

@ -1,66 +0,0 @@
// Copyright 2017 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
//
// http://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.
//
// This file is intended solely for spinlock.h.
// It provides ThreadSanitizer annotations for custom mutexes.
// See <sanitizer/tsan_interface.h> for meaning of these annotations.
#ifndef ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
#define ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
// ABSL_INTERNAL_HAVE_TSAN_INTERFACE
// Macro intended only for internal use.
//
// Checks whether LLVM Thread Sanitizer interfaces are available.
// First made available in LLVM 5.0 (Sep 2017).
#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
#error "ABSL_INTERNAL_HAVE_TSAN_INTERFACE cannot be directly set."
#endif
#if defined(THREAD_SANITIZER) && defined(__has_include)
#if __has_include(<sanitizer/tsan_interface.h>)
#define ABSL_INTERNAL_HAVE_TSAN_INTERFACE 1
#endif
#endif
#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
#include <sanitizer/tsan_interface.h>
#define ABSL_TSAN_MUTEX_CREATE __tsan_mutex_create
#define ABSL_TSAN_MUTEX_DESTROY __tsan_mutex_destroy
#define ABSL_TSAN_MUTEX_PRE_LOCK __tsan_mutex_pre_lock
#define ABSL_TSAN_MUTEX_POST_LOCK __tsan_mutex_post_lock
#define ABSL_TSAN_MUTEX_PRE_UNLOCK __tsan_mutex_pre_unlock
#define ABSL_TSAN_MUTEX_POST_UNLOCK __tsan_mutex_post_unlock
#define ABSL_TSAN_MUTEX_PRE_SIGNAL __tsan_mutex_pre_signal
#define ABSL_TSAN_MUTEX_POST_SIGNAL __tsan_mutex_post_signal
#define ABSL_TSAN_MUTEX_PRE_DIVERT __tsan_mutex_pre_divert
#define ABSL_TSAN_MUTEX_POST_DIVERT __tsan_mutex_post_divert
#else
#define ABSL_TSAN_MUTEX_CREATE(...)
#define ABSL_TSAN_MUTEX_DESTROY(...)
#define ABSL_TSAN_MUTEX_PRE_LOCK(...)
#define ABSL_TSAN_MUTEX_POST_LOCK(...)
#define ABSL_TSAN_MUTEX_PRE_UNLOCK(...)
#define ABSL_TSAN_MUTEX_POST_UNLOCK(...)
#define ABSL_TSAN_MUTEX_PRE_SIGNAL(...)
#define ABSL_TSAN_MUTEX_POST_SIGNAL(...)
#define ABSL_TSAN_MUTEX_PRE_DIVERT(...)
#define ABSL_TSAN_MUTEX_POST_DIVERT(...)
#endif
#endif // ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_

View File

@ -1,256 +0,0 @@
//
// Copyright 2017 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
//
// http://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.
//
#ifndef ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
#define ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
#include <string.h>
#include <cstdint>
#include "absl/base/attributes.h"
// unaligned APIs
// Portable handling of unaligned loads, stores, and copies.
// On some platforms, like ARM, the copy functions can be more efficient
// then a load and a store.
//
// It is possible to implement all of these these using constant-length memcpy
// calls, which is portable and will usually be inlined into simple loads and
// stores if the architecture supports it. However, such inlining usually
// happens in a pass that's quite late in compilation, which means the resulting
// loads and stores cannot participate in many other optimizations, leading to
// overall worse code.
// The unaligned API is C++ only. The declarations use C++ features
// (namespaces, inline) which are absent or incompatible in C.
#if defined(__cplusplus)
#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||\
defined(MEMORY_SANITIZER)
// Consider we have an unaligned load/store of 4 bytes from address 0x...05.
// AddressSanitizer will treat it as a 3-byte access to the range 05:07 and
// will miss a bug if 08 is the first unaddressable byte.
// ThreadSanitizer will also treat this as a 3-byte access to 05:07 and will
// miss a race between this access and some other accesses to 08.
// MemorySanitizer will correctly propagate the shadow on unaligned stores
// and correctly report bugs on unaligned loads, but it may not properly
// update and report the origin of the uninitialized memory.
// For all three tools, replacing an unaligned access with a tool-specific
// callback solves the problem.
// Make sure uint16_t/uint32_t/uint64_t are defined.
#include <stdint.h>
extern "C" {
uint16_t __sanitizer_unaligned_load16(const void *p);
uint32_t __sanitizer_unaligned_load32(const void *p);
uint64_t __sanitizer_unaligned_load64(const void *p);
void __sanitizer_unaligned_store16(void *p, uint16_t v);
void __sanitizer_unaligned_store32(void *p, uint32_t v);
void __sanitizer_unaligned_store64(void *p, uint64_t v);
} // extern "C"
namespace absl {
inline uint16_t UnalignedLoad16(const void *p) {
return __sanitizer_unaligned_load16(p);
}
inline uint32_t UnalignedLoad32(const void *p) {
return __sanitizer_unaligned_load32(p);
}
inline uint64_t UnalignedLoad64(const void *p) {
return __sanitizer_unaligned_load64(p);
}
inline void UnalignedStore16(void *p, uint16_t v) {
__sanitizer_unaligned_store16(p, v);
}
inline void UnalignedStore32(void *p, uint32_t v) {
__sanitizer_unaligned_store32(p, v);
}
inline void UnalignedStore64(void *p, uint64_t v) {
__sanitizer_unaligned_store64(p, v);
}
} // namespace absl
#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) (absl::UnalignedLoad16(_p))
#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) (absl::UnalignedLoad32(_p))
#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) (absl::UnalignedLoad64(_p))
#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
(absl::UnalignedStore16(_p, _val))
#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
(absl::UnalignedStore32(_p, _val))
#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
(absl::UnalignedStore64(_p, _val))
#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \
defined(_M_IX86) || defined(__ppc__) || defined(__PPC__) || \
defined(__ppc64__) || defined(__PPC64__)
// x86 and x86-64 can perform unaligned loads/stores directly;
// modern PowerPC hardware can also do unaligned integer loads and stores;
// but note: the FPU still sends unaligned loads and stores to a trap handler!
#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
(*reinterpret_cast<const uint16_t *>(_p))
#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \
(*reinterpret_cast<const uint32_t *>(_p))
#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \
(*reinterpret_cast<const uint64_t *>(_p))
#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
(*reinterpret_cast<uint16_t *>(_p) = (_val))
#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
(*reinterpret_cast<uint32_t *>(_p) = (_val))
#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
(*reinterpret_cast<uint64_t *>(_p) = (_val))
#elif defined(__arm__) && \
!defined(__ARM_ARCH_5__) && \
!defined(__ARM_ARCH_5T__) && \
!defined(__ARM_ARCH_5TE__) && \
!defined(__ARM_ARCH_5TEJ__) && \
!defined(__ARM_ARCH_6__) && \
!defined(__ARM_ARCH_6J__) && \
!defined(__ARM_ARCH_6K__) && \
!defined(__ARM_ARCH_6Z__) && \
!defined(__ARM_ARCH_6ZK__) && \
!defined(__ARM_ARCH_6T2__)
// ARMv7 and newer support native unaligned accesses, but only of 16-bit
// and 32-bit values (not 64-bit); older versions either raise a fatal signal,
// do an unaligned read and rotate the words around a bit, or do the reads very
// slowly (trip through kernel mode). There's no simple #define that says just
// "ARMv7 or higher", so we have to filter away all ARMv5 and ARMv6
// sub-architectures. Newer gcc (>= 4.6) set an __ARM_FEATURE_ALIGNED #define,
// so in time, maybe we can move on to that.
//
// This is a mess, but there's not much we can do about it.
//
// To further complicate matters, only LDR instructions (single reads) are
// allowed to be unaligned, not LDRD (two reads) or LDM (many reads). Unless we
// explicitly tell the compiler that these accesses can be unaligned, it can and
// will combine accesses. On armcc, the way to signal this is done by accessing
// through the type (uint32_t __packed *), but GCC has no such attribute
// (it ignores __attribute__((packed)) on individual variables). However,
// we can tell it that a _struct_ is unaligned, which has the same effect,
// so we do that.
namespace absl {
namespace internal {
struct Unaligned16Struct {
uint16_t value;
uint8_t dummy; // To make the size non-power-of-two.
} ABSL_ATTRIBUTE_PACKED;
struct Unaligned32Struct {
uint32_t value;
uint8_t dummy; // To make the size non-power-of-two.
} ABSL_ATTRIBUTE_PACKED;
} // namespace internal
} // namespace absl
#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
((reinterpret_cast<const ::absl::internal::Unaligned16Struct *>(_p))->value)
#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \
((reinterpret_cast<const ::absl::internal::Unaligned32Struct *>(_p))->value)
#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
((reinterpret_cast< ::absl::internal::Unaligned16Struct *>(_p))->value = \
(_val))
#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
((reinterpret_cast< ::absl::internal::Unaligned32Struct *>(_p))->value = \
(_val))
namespace absl {
inline uint64_t UnalignedLoad64(const void *p) {
uint64_t t;
memcpy(&t, p, sizeof t);
return t;
}
inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
} // namespace absl
#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) (absl::UnalignedLoad64(_p))
#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
(absl::UnalignedStore64(_p, _val))
#else
// ABSL_INTERNAL_NEED_ALIGNED_LOADS is defined when the underlying platform
// doesn't support unaligned access.
#define ABSL_INTERNAL_NEED_ALIGNED_LOADS
// These functions are provided for architectures that don't support
// unaligned loads and stores.
namespace absl {
inline uint16_t UnalignedLoad16(const void *p) {
uint16_t t;
memcpy(&t, p, sizeof t);
return t;
}
inline uint32_t UnalignedLoad32(const void *p) {
uint32_t t;
memcpy(&t, p, sizeof t);
return t;
}
inline uint64_t UnalignedLoad64(const void *p) {
uint64_t t;
memcpy(&t, p, sizeof t);
return t;
}
inline void UnalignedStore16(void *p, uint16_t v) { memcpy(p, &v, sizeof v); }
inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); }
inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
} // namespace absl
#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) (absl::UnalignedLoad16(_p))
#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) (absl::UnalignedLoad32(_p))
#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) (absl::UnalignedLoad64(_p))
#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
(absl::UnalignedStore16(_p, _val))
#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
(absl::UnalignedStore32(_p, _val))
#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
(absl::UnalignedStore64(_p, _val))
#endif
#endif // defined(__cplusplus), end of unaligned API
#endif // ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_

View File

@ -1,101 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include "absl/base/internal/unscaledcycleclock.h"
#if ABSL_USE_UNSCALED_CYCLECLOCK
#if defined(_WIN32)
#include <intrin.h>
#endif
#if defined(__powerpc__) || defined(__ppc__)
#include <sys/platform/ppc.h>
#endif
#include "absl/base/internal/sysinfo.h"
namespace absl {
namespace base_internal {
#if defined(__i386__)
int64_t UnscaledCycleClock::Now() {
int64_t ret;
__asm__ volatile("rdtsc" : "=A"(ret));
return ret;
}
double UnscaledCycleClock::Frequency() {
return base_internal::NominalCPUFrequency();
}
#elif defined(__x86_64__)
int64_t UnscaledCycleClock::Now() {
uint64_t low, high;
__asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
return (high << 32) | low;
}
double UnscaledCycleClock::Frequency() {
return base_internal::NominalCPUFrequency();
}
#elif defined(__powerpc__) || defined(__ppc__)
int64_t UnscaledCycleClock::Now() {
return __ppc_get_timebase();
}
double UnscaledCycleClock::Frequency() {
return __ppc_get_timebase_freq();
}
#elif defined(__aarch64__)
// System timer of ARMv8 runs at a different frequency than the CPU's.
// The frequency is fixed, typically in the range 1-50MHz. It can be
// read at CNTFRQ special register. We assume the OS has set up
// the virtual timer properly.
int64_t UnscaledCycleClock::Now() {
int64_t virtual_timer_value;
asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
return virtual_timer_value;
}
double UnscaledCycleClock::Frequency() {
uint64_t aarch64_timer_frequency;
asm volatile("mrs %0, cntfrq_el0" : "=r"(aarch64_timer_frequency));
return aarch64_timer_frequency;
}
#elif defined(_M_IX86) || defined(_M_X64)
#pragma intrinsic(__rdtsc)
int64_t UnscaledCycleClock::Now() {
return __rdtsc();
}
double UnscaledCycleClock::Frequency() {
return base_internal::NominalCPUFrequency();
}
#endif
} // namespace base_internal
} // namespace absl
#endif // ABSL_USE_UNSCALED_CYCLECLOCK

View File

@ -1,119 +0,0 @@
// Copyright 2017 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
//
// http://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.
//
// UnscaledCycleClock
// An UnscaledCycleClock yields the value and frequency of a cycle counter
// that increments at a rate that is approximately constant.
// This class is for internal / whitelisted use only, you should consider
// using CycleClock instead.
//
// Notes:
// The cycle counter frequency is not necessarily the core clock frequency.
// That is, CycleCounter cycles are not necessarily "CPU cycles".
//
// An arbitrary offset may have been added to the counter at power on.
//
// On some platforms, the rate and offset of the counter may differ
// slightly when read from different CPUs of a multiprocessor. Usually,
// we try to ensure that the operating system adjusts values periodically
// so that values agree approximately. If you need stronger guarantees,
// consider using alternate interfaces.
//
// The CPU is not required to maintain the ordering of a cycle counter read
// with respect to surrounding instructions.
#ifndef ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_
#define ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_
#include <cstdint>
#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif
#include "absl/base/port.h"
// The following platforms have an implementation of a hardware counter.
#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
defined(__powerpc__) || defined(__ppc__) || \
defined(_M_IX86) || defined(_M_X64)
#define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 1
#else
#define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 0
#endif
// The following platforms often disable access to the hardware
// counter (through a sandbox) even if the underlying hardware has a
// usable counter. The CycleTimer interface also requires a *scaled*
// CycleClock that runs at atleast 1 MHz. We've found some Android
// ARM64 devices where this is not the case, so we disable it by
// default on Android ARM64.
#if defined(__native_client__) || TARGET_OS_IPHONE || \
(defined(__ANDROID__) && defined(__aarch64__))
#define ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT 0
#else
#define ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT 1
#endif
// UnscaledCycleClock is an optional internal feature.
// Use "#if ABSL_USE_UNSCALED_CYCLECLOCK" to test for its presence.
// Can be overridden at compile-time via -DABSL_USE_UNSCALED_CYCLECLOCK=0|1
#if !defined(ABSL_USE_UNSCALED_CYCLECLOCK)
#define ABSL_USE_UNSCALED_CYCLECLOCK \
(ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION && \
ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT)
#endif
#if ABSL_USE_UNSCALED_CYCLECLOCK
// This macro can be used to test if UnscaledCycleClock::Frequency()
// is NominalCPUFrequency() on a particular platform.
#if (defined(__i386__) || defined(__x86_64__) || \
defined(_M_IX86) || defined(_M_X64))
#define ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
#endif
namespace absl {
namespace time_internal {
class UnscaledCycleClockWrapperForGetCurrentTime;
} // namespace time_internal
namespace base_internal {
class CycleClock;
class UnscaledCycleClockWrapperForInitializeFrequency;
class UnscaledCycleClock {
private:
UnscaledCycleClock() = delete;
// Return the value of a cycle counter that counts at a rate that is
// approximately constant.
static int64_t Now();
// Return the how much UnscaledCycleClock::Now() increases per second.
// This is not necessarily the core CPU clock frequency.
// It may be the nominal value report by the kernel, rather than a measured
// value.
static double Frequency();
// Whitelisted friends.
friend class base_internal::CycleClock;
friend class time_internal::UnscaledCycleClockWrapperForGetCurrentTime;
friend class base_internal::UnscaledCycleClockWrapperForInitializeFrequency;
};
} // namespace base_internal
} // namespace absl
#endif // ABSL_USE_UNSCALED_CYCLECLOCK
#endif // ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_

View File

@ -1,200 +0,0 @@
// Copyright 2017 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
//
// http://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.
#include "absl/base/internal/invoke.h"
#include <functional>
#include <memory>
#include <string>
#include <utility>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
namespace absl {
namespace base_internal {
namespace {
int Function(int a, int b) { return a - b; }
int Sink(std::unique_ptr<int> p) {
return *p;
}
std::unique_ptr<int> Factory(int n) {
return make_unique<int>(n);
}
void NoOp() {}
struct ConstFunctor {
int operator()(int a, int b) const { return a - b; }
};
struct MutableFunctor {
int operator()(int a, int b) { return a - b; }
};
struct EphemeralFunctor {
int operator()(int a, int b) && { return a - b; }
};
struct OverloadedFunctor {
template <typename... Args>
std::string operator()(const Args&... args) & {
return StrCat("&", args...);
}
template <typename... Args>
std::string operator()(const Args&... args) const& {
return StrCat("const&", args...);
}
template <typename... Args>
std::string operator()(const Args&... args) && {
return StrCat("&&", args...);
}
};
struct Class {
int Method(int a, int b) { return a - b; }
int ConstMethod(int a, int b) const { return a - b; }
int member;
};
struct FlipFlop {
int ConstMethod() const { return member; }
FlipFlop operator*() const { return {-member}; }
int member;
};
// CallMaybeWithArg(f) resolves either to Invoke(f) or Invoke(f, 42), depending
// on which one is valid.
template <typename F>
decltype(Invoke(std::declval<const F&>())) CallMaybeWithArg(const F& f) {
return Invoke(f);
}
template <typename F>
decltype(Invoke(std::declval<const F&>(), 42)) CallMaybeWithArg(const F& f) {
return Invoke(f, 42);
}
TEST(InvokeTest, Function) {
EXPECT_EQ(1, Invoke(Function, 3, 2));
EXPECT_EQ(1, Invoke(&Function, 3, 2));
}
TEST(InvokeTest, NonCopyableArgument) {
EXPECT_EQ(42, Invoke(Sink, make_unique<int>(42)));
}
TEST(InvokeTest, NonCopyableResult) {
EXPECT_THAT(Invoke(Factory, 42), ::testing::Pointee(42));
}
TEST(InvokeTest, VoidResult) {
Invoke(NoOp);
}
TEST(InvokeTest, ConstFunctor) {
EXPECT_EQ(1, Invoke(ConstFunctor(), 3, 2));
}
TEST(InvokeTest, MutableFunctor) {
MutableFunctor f;
EXPECT_EQ(1, Invoke(f, 3, 2));
EXPECT_EQ(1, Invoke(MutableFunctor(), 3, 2));
}
TEST(InvokeTest, EphemeralFunctor) {
EphemeralFunctor f;
EXPECT_EQ(1, Invoke(std::move(f), 3, 2));
EXPECT_EQ(1, Invoke(EphemeralFunctor(), 3, 2));
}
TEST(InvokeTest, OverloadedFunctor) {
OverloadedFunctor f;
const OverloadedFunctor& cf = f;
EXPECT_EQ("&", Invoke(f));
EXPECT_EQ("& 42", Invoke(f, " 42"));
EXPECT_EQ("const&", Invoke(cf));
EXPECT_EQ("const& 42", Invoke(cf, " 42"));
EXPECT_EQ("&&", Invoke(std::move(f)));
EXPECT_EQ("&& 42", Invoke(std::move(f), " 42"));
}
TEST(InvokeTest, ReferenceWrapper) {
ConstFunctor cf;
MutableFunctor mf;
EXPECT_EQ(1, Invoke(std::cref(cf), 3, 2));
EXPECT_EQ(1, Invoke(std::ref(cf), 3, 2));
EXPECT_EQ(1, Invoke(std::ref(mf), 3, 2));
}
TEST(InvokeTest, MemberFunction) {
std::unique_ptr<Class> p(new Class);
std::unique_ptr<const Class> cp(new Class);
EXPECT_EQ(1, Invoke(&Class::Method, p, 3, 2));
EXPECT_EQ(1, Invoke(&Class::Method, p.get(), 3, 2));
EXPECT_EQ(1, Invoke(&Class::ConstMethod, p, 3, 2));
EXPECT_EQ(1, Invoke(&Class::ConstMethod, p.get(), 3, 2));
EXPECT_EQ(1, Invoke(&Class::ConstMethod, *p, 3, 2));
EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp, 3, 2));
EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp.get(), 3, 2));
EXPECT_EQ(1, Invoke(&Class::ConstMethod, *cp, 3, 2));
EXPECT_EQ(1, Invoke(&Class::Method, make_unique<Class>(), 3, 2));
EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique<Class>(), 3, 2));
EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique<const Class>(), 3, 2));
}
TEST(InvokeTest, DataMember) {
std::unique_ptr<Class> p(new Class{42});
std::unique_ptr<const Class> cp(new Class{42});
EXPECT_EQ(42, Invoke(&Class::member, p));
EXPECT_EQ(42, Invoke(&Class::member, *p));
EXPECT_EQ(42, Invoke(&Class::member, p.get()));
Invoke(&Class::member, p) = 42;
Invoke(&Class::member, p.get()) = 42;
EXPECT_EQ(42, Invoke(&Class::member, cp));
EXPECT_EQ(42, Invoke(&Class::member, *cp));
EXPECT_EQ(42, Invoke(&Class::member, cp.get()));
}
TEST(InvokeTest, FlipFlop) {
FlipFlop obj = {42};
// This call could resolve to (obj.*&FlipFlop::ConstMethod)() or
// ((*obj).*&FlipFlop::ConstMethod)(). We verify that it's the former.
EXPECT_EQ(42, Invoke(&FlipFlop::ConstMethod, obj));
EXPECT_EQ(42, Invoke(&FlipFlop::member, obj));
}
TEST(InvokeTest, SfinaeFriendly) {
CallMaybeWithArg(NoOp);
EXPECT_THAT(CallMaybeWithArg(Factory), ::testing::Pointee(42));
}
} // namespace
} // namespace base_internal
} // namespace absl

View File

@ -1,67 +0,0 @@
// Copyright 2017 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
//
// http://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.
//
#ifndef ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
#define ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
#include <array>
#include "absl/base/attributes.h"
namespace absl {
// Four severity levels are defined. Logging APIs should terminate the program
// when a message is logged at severity `kFatal`; the other levels have no
// special semantics.
enum class LogSeverity : int {
kInfo = 0,
kWarning = 1,
kError = 2,
kFatal = 3,
};
// Returns an iterable of all standard `absl::LogSeverity` values, ordered from
// least to most severe.
constexpr std::array<absl::LogSeverity, 4> LogSeverities() {
return {{absl::LogSeverity::kInfo, absl::LogSeverity::kWarning,
absl::LogSeverity::kError, absl::LogSeverity::kFatal}};
}
// Returns the all-caps std::string representation (e.g. "INFO") of the specified
// severity level if it is one of the normal levels and "UNKNOWN" otherwise.
constexpr const char* LogSeverityName(absl::LogSeverity s) {
return s == absl::LogSeverity::kInfo
? "INFO"
: s == absl::LogSeverity::kWarning
? "WARNING"
: s == absl::LogSeverity::kError
? "ERROR"
: s == absl::LogSeverity::kFatal ? "FATAL" : "UNKNOWN";
}
// Values less than `kInfo` normalize to `kInfo`; values greater than `kFatal`
// normalize to `kError` (**NOT** `kFatal`).
constexpr absl::LogSeverity NormalizeLogSeverity(absl::LogSeverity s) {
return s < absl::LogSeverity::kInfo
? absl::LogSeverity::kInfo
: s > absl::LogSeverity::kFatal ? absl::LogSeverity::kError : s;
}
constexpr absl::LogSeverity NormalizeLogSeverity(int s) {
return NormalizeLogSeverity(static_cast<absl::LogSeverity>(s));
}
} // namespace absl
#endif // ABSL_BASE_INTERNAL_LOG_SEVERITY_H_

View File

@ -1,202 +0,0 @@
//
// Copyright 2017 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
//
// http://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.
//
// -----------------------------------------------------------------------------
// File: macros.h
// -----------------------------------------------------------------------------
//
// This header file defines the set of language macros used within Abseil code.
// For the set of macros used to determine supported compilers and platforms,
// see absl/base/config.h instead.
//
// This code is compiled directly on many platforms, including client
// platforms like Windows, Mac, and embedded systems. Before making
// any changes here, make sure that you're not breaking any platforms.
//
#ifndef ABSL_BASE_MACROS_H_
#define ABSL_BASE_MACROS_H_
#include <cassert>
#include <cstddef>
#include "absl/base/port.h"
// ABSL_ARRAYSIZE()
//
// Returns the number of elements in an array as a compile-time constant, which
// can be used in defining new arrays. If you use this macro on a pointer by
// mistake, you will get a compile-time error.
#define ABSL_ARRAYSIZE(array) \
(sizeof(::absl::macros_internal::ArraySizeHelper(array)))
namespace absl {
namespace macros_internal {
// Note: this internal template function declaration is used by ABSL_ARRAYSIZE.
// The function doesn't need a definition, as we only use its type.
template <typename T, size_t N>
auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
} // namespace macros_internal
} // namespace absl
// kLinkerInitialized
//
// An enum used only as a constructor argument to indicate that a variable has
// static storage duration, and that the constructor should do nothing to its
// state. Use of this macro indicates to the reader that it is legal to
// declare a static instance of the class, provided the constructor is given
// the absl::base_internal::kLinkerInitialized argument.
//
// Normally, it is unsafe to declare a static variable that has a constructor or
// a destructor because invocation order is undefined. However, if the type can
// be zero-initialized (which the loader does for static variables) into a valid
// state and the type's destructor does not affect storage, then a constructor
// for static initialization can be declared.
//
// Example:
// // Declaration
// explicit MyClass(absl::base_internal:LinkerInitialized x) {}
//
// // Invocation
// static MyClass my_global(absl::base_internal::kLinkerInitialized);
namespace absl {
namespace base_internal {
enum LinkerInitialized {
kLinkerInitialized = 0,
};
} // namespace base_internal
} // namespace absl
// ABSL_FALLTHROUGH_INTENDED
//
// Annotates implicit fall-through between switch labels, allowing a case to
// indicate intentional fallthrough and turn off warnings about any lack of a
// `break` statement. The ABSL_FALLTHROUGH_INTENDED macro should be followed by
// a semicolon and can be used in most places where `break` can, provided that
// no statements exist between it and the next switch label.
//
// Example:
//
// switch (x) {
// case 40:
// case 41:
// if (truth_is_out_there) {
// ++x;
// ABSL_FALLTHROUGH_INTENDED; // Use instead of/along with annotations
// // in comments
// } else {
// return x;
// }
// case 42:
// ...
//
// Notes: when compiled with clang in C++11 mode, the ABSL_FALLTHROUGH_INTENDED
// macro is expanded to the [[clang::fallthrough]] attribute, which is analysed
// when performing switch labels fall-through diagnostic
// (`-Wimplicit-fallthrough`). See clang documentation on language extensions
// for details:
// http://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough
//
// When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro
// has no effect on diagnostics. In any case this macro has no effect on runtime
// behavior and performance of code.
#ifdef ABSL_FALLTHROUGH_INTENDED
#error "ABSL_FALLTHROUGH_INTENDED should not be defined."
#endif
// TODO(zhangxy): Use c++17 standard [[fallthrough]] macro, when supported.
#if defined(__clang__) && defined(__has_warning)
#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
#define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]]
#endif
#elif defined(__GNUC__) && __GNUC__ >= 7
#define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]]
#endif
#ifndef ABSL_FALLTHROUGH_INTENDED
#define ABSL_FALLTHROUGH_INTENDED \
do { \
} while (0)
#endif
// ABSL_DEPRECATED()
//
// Marks a deprecated class, struct, enum, function, method and variable
// declarations. The macro argument is used as a custom diagnostic message (e.g.
// suggestion of a better alternative).
//
// Example:
//
// class ABSL_DEPRECATED("Use Bar instead") Foo {...};
// ABSL_DEPRECATED("Use Baz instead") void Bar() {...}
//
// Every usage of a deprecated entity will trigger a warning when compiled with
// clang's `-Wdeprecated-declarations` option. This option is turned off by
// default, but the warnings will be reported by clang-tidy.
#if defined(__clang__) && __cplusplus >= 201103L
#define ABSL_DEPRECATED(message) __attribute__((deprecated(message)))
#endif
#ifndef ABSL_DEPRECATED
#define ABSL_DEPRECATED(message)
#endif
// ABSL_BAD_CALL_IF()
//
// Used on a function overload to trap bad calls: any call that matches the
// overload will cause a compile-time error. This macro uses a clang-specific
// "enable_if" attribute, as described at
// http://clang.llvm.org/docs/AttributeReference.html#enable-if
//
// Overloads which use this macro should be bracketed by
// `#ifdef ABSL_BAD_CALL_IF`.
//
// Example:
//
// int isdigit(int c);
// #ifdef ABSL_BAD_CALL_IF
// int isdigit(int c)
// ABSL_BAD_CALL_IF(c <= -1 || c > 255,
// "'c' must have the value of an unsigned char or EOF");
// #endif // ABSL_BAD_CALL_IF
#if defined(__clang__)
# if __has_attribute(enable_if)
# define ABSL_BAD_CALL_IF(expr, msg) \
__attribute__((enable_if(expr, "Bad call trap"), unavailable(msg)))
# endif
#endif
// ABSL_ASSERT()
//
// In C++11, `assert` can't be used portably within constexpr functions.
// ABSL_ASSERT functions as a runtime assert but works in C++11 constexpr
// functions. Example:
//
// constexpr double Divide(double a, double b) {
// return ABSL_ASSERT(b != 0), a / b;
// }
//
// This macro is inspired by
// https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/
#if defined(NDEBUG)
#define ABSL_ASSERT(expr) (false ? (void)(expr) : (void)0)
#else
#define ABSL_ASSERT(expr) \
(ABSL_PREDICT_TRUE((expr)) ? (void)0 \
: [] { assert(false && #expr); }()) // NOLINT
#endif
#endif // ABSL_BASE_MACROS_H_

Some files were not shown because too many files have changed in this diff Show More