aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar misterg <misterg@google.com>2017-09-19 16:54:40 -0400
committerGravatar misterg <misterg@google.com>2017-09-19 16:54:40 -0400
commitc2e754829628d1e9b7a16b3389cfdace76950fdf (patch)
tree5a7f056f44e27c30e10025113b644f0b3b5801fc
Initial Commit
-rw-r--r--ABSEIL_ISSUE_TEMPLATE.md22
-rw-r--r--AUTHORS6
-rw-r--r--CONTRIBUTING.md90
-rw-r--r--LICENSE204
-rw-r--r--README.md89
-rw-r--r--WORKSPACE22
-rw-r--r--absl/BUILD.bazel62
-rw-r--r--absl/algorithm/BUILD.bazel69
-rw-r--r--absl/algorithm/algorithm.h138
-rw-r--r--absl/algorithm/algorithm_test.cc182
-rw-r--r--absl/algorithm/container.h1652
-rw-r--r--absl/algorithm/container_test.cc1010
-rw-r--r--absl/base/BUILD.bazel369
-rw-r--r--absl/base/attributes.h469
-rw-r--r--absl/base/bit_cast_test.cc107
-rw-r--r--absl/base/call_once.h210
-rw-r--r--absl/base/call_once_test.cc102
-rw-r--r--absl/base/casts.h141
-rw-r--r--absl/base/config.h367
-rw-r--r--absl/base/config_test.cc45
-rw-r--r--absl/base/dynamic_annotations.cc129
-rw-r--r--absl/base/dynamic_annotations.h409
-rw-r--r--absl/base/internal/atomic_hook.h122
-rw-r--r--absl/base/internal/cycleclock.cc81
-rw-r--r--absl/base/internal/cycleclock.h77
-rw-r--r--absl/base/internal/endian.h267
-rw-r--r--absl/base/internal/endian_test.cc281
-rw-r--r--absl/base/internal/exception_testing.h24
-rw-r--r--absl/base/internal/identity.h33
-rw-r--r--absl/base/internal/invoke.h188
-rw-r--r--absl/base/internal/log_severity.cc15
-rw-r--r--absl/base/internal/log_severity.h52
-rw-r--r--absl/base/internal/low_level_alloc.cc598
-rw-r--r--absl/base/internal/low_level_alloc.h120
-rw-r--r--absl/base/internal/low_level_alloc_test.cc203
-rw-r--r--absl/base/internal/low_level_scheduling.h104
-rw-r--r--absl/base/internal/malloc_extension.cc197
-rw-r--r--absl/base/internal/malloc_extension.h424
-rw-r--r--absl/base/internal/malloc_extension_c.h75
-rw-r--r--absl/base/internal/malloc_extension_test.cc102
-rw-r--r--absl/base/internal/malloc_hook.cc611
-rw-r--r--absl/base/internal/malloc_hook.h333
-rw-r--r--absl/base/internal/malloc_hook_c.h131
-rw-r--r--absl/base/internal/malloc_hook_invoke.h198
-rw-r--r--absl/base/internal/malloc_hook_mmap_linux.inc236
-rw-r--r--absl/base/internal/per_thread_tls.h48
-rw-r--r--absl/base/internal/raw_logging.cc225
-rw-r--r--absl/base/internal/raw_logging.h129
-rw-r--r--absl/base/internal/scheduling_mode.h54
-rw-r--r--absl/base/internal/spinlock.cc243
-rw-r--r--absl/base/internal/spinlock.h227
-rw-r--r--absl/base/internal/spinlock_posix.inc46
-rw-r--r--absl/base/internal/spinlock_wait.cc77
-rw-r--r--absl/base/internal/spinlock_wait.h94
-rw-r--r--absl/base/internal/spinlock_win32.inc37
-rw-r--r--absl/base/internal/sysinfo.cc370
-rw-r--r--absl/base/internal/sysinfo.h64
-rw-r--r--absl/base/internal/sysinfo_test.cc99
-rw-r--r--absl/base/internal/thread_identity.cc126
-rw-r--r--absl/base/internal/thread_identity.h240
-rw-r--r--absl/base/internal/thread_identity_test.cc124
-rw-r--r--absl/base/internal/throw_delegate.cc106
-rw-r--r--absl/base/internal/throw_delegate.h71
-rw-r--r--absl/base/internal/tsan_mutex_interface.h51
-rw-r--r--absl/base/internal/unaligned_access.h256
-rw-r--r--absl/base/internal/unscaledcycleclock.cc101
-rw-r--r--absl/base/internal/unscaledcycleclock.h118
-rw-r--r--absl/base/invoke_test.cc199
-rw-r--r--absl/base/macros.h201
-rw-r--r--absl/base/optimization.h164
-rw-r--r--absl/base/policy_checks.h99
-rw-r--r--absl/base/port.h26
-rw-r--r--absl/base/raw_logging_test.cc50
-rw-r--r--absl/base/spinlock_test_common.cc265
-rw-r--r--absl/base/thread_annotations.h247
-rw-r--r--absl/base/throw_delegate_test.cc95
-rw-r--r--absl/container/BUILD.bazel124
-rw-r--r--absl/container/fixed_array.h493
-rw-r--r--absl/container/fixed_array_test.cc621
-rw-r--r--absl/container/inlined_vector.h1330
-rw-r--r--absl/container/inlined_vector_test.cc1593
-rw-r--r--absl/container/internal/test_instance_tracker.cc26
-rw-r--r--absl/container/internal/test_instance_tracker.h220
-rw-r--r--absl/container/internal/test_instance_tracker_test.cc160
-rw-r--r--absl/copts.bzl138
-rw-r--r--absl/debugging/BUILD.bazel170
-rw-r--r--absl/debugging/internal/address_is_readable.cc134
-rw-r--r--absl/debugging/internal/address_is_readable.h29
-rw-r--r--absl/debugging/internal/elf_mem_image.cc397
-rw-r--r--absl/debugging/internal/elf_mem_image.h125
-rw-r--r--absl/debugging/internal/stacktrace_aarch64-inl.inc181
-rw-r--r--absl/debugging/internal/stacktrace_arm-inl.inc115
-rw-r--r--absl/debugging/internal/stacktrace_config.h76
-rw-r--r--absl/debugging/internal/stacktrace_generic-inl.inc51
-rw-r--r--absl/debugging/internal/stacktrace_libunwind-inl.inc128
-rw-r--r--absl/debugging/internal/stacktrace_powerpc-inl.inc234
-rw-r--r--absl/debugging/internal/stacktrace_unimplemented-inl.inc14
-rw-r--r--absl/debugging/internal/stacktrace_win32-inl.inc75
-rw-r--r--absl/debugging/internal/stacktrace_x86-inl.inc327
-rw-r--r--absl/debugging/internal/vdso_support.cc177
-rw-r--r--absl/debugging/internal/vdso_support.h155
-rw-r--r--absl/debugging/leak_check.cc35
-rw-r--r--absl/debugging/leak_check.h111
-rw-r--r--absl/debugging/leak_check_disable.cc20
-rw-r--r--absl/debugging/leak_check_fail_test.cc41
-rw-r--r--absl/debugging/leak_check_test.cc41
-rw-r--r--absl/debugging/stacktrace.cc133
-rw-r--r--absl/debugging/stacktrace.h160
-rw-r--r--absl/memory/BUILD.bazel47
-rw-r--r--absl/memory/README.md22
-rw-r--r--absl/memory/memory.h622
-rw-r--r--absl/memory/memory_test.cc590
-rw-r--r--absl/meta/BUILD.bazel29
-rw-r--r--absl/meta/type_traits.h314
-rw-r--r--absl/meta/type_traits_test.cc640
-rw-r--r--absl/numeric/BUILD.bazel39
-rw-r--r--absl/numeric/int128.cc200
-rw-r--r--absl/numeric/int128.h651
-rw-r--r--absl/numeric/int128_have_intrinsic.inc3
-rw-r--r--absl/numeric/int128_no_intrinsic.inc3
-rw-r--r--absl/numeric/int128_test.cc492
-rw-r--r--absl/strings/BUILD.bazel293
-rw-r--r--absl/strings/README.md87
-rw-r--r--absl/strings/ascii.cc198
-rw-r--r--absl/strings/ascii.h239
-rw-r--r--absl/strings/ascii_ctype.h66
-rw-r--r--absl/strings/ascii_test.cc354
-rw-r--r--absl/strings/escaping.cc1093
-rw-r--r--absl/strings/escaping.h158
-rw-r--r--absl/strings/escaping_test.cc638
-rw-r--r--absl/strings/internal/char_map.h154
-rw-r--r--absl/strings/internal/char_map_test.cc172
-rw-r--r--absl/strings/internal/escaping_test_common.inc113
-rw-r--r--absl/strings/internal/fastmem.h215
-rw-r--r--absl/strings/internal/fastmem_test.cc453
-rw-r--r--absl/strings/internal/memutil.cc110
-rw-r--r--absl/strings/internal/memutil.h146
-rw-r--r--absl/strings/internal/memutil_test.cc180
-rw-r--r--absl/strings/internal/numbers_test_common.inc166
-rw-r--r--absl/strings/internal/ostringstream.h97
-rw-r--r--absl/strings/internal/ostringstream_test.cc103
-rw-r--r--absl/strings/internal/resize_uninitialized.h69
-rw-r--r--absl/strings/internal/resize_uninitialized_test.cc68
-rw-r--r--absl/strings/internal/str_join_internal.h314
-rw-r--r--absl/strings/internal/str_split_internal.h439
-rw-r--r--absl/strings/internal/utf8.cc51
-rw-r--r--absl/strings/internal/utf8.h52
-rw-r--r--absl/strings/internal/utf8_test.cc58
-rw-r--r--absl/strings/match.cc40
-rw-r--r--absl/strings/match.h81
-rw-r--r--absl/strings/match_test.cc99
-rw-r--r--absl/strings/numbers.cc1288
-rw-r--r--absl/strings/numbers.h173
-rw-r--r--absl/strings/numbers_test.cc1186
-rw-r--r--absl/strings/str_cat.cc208
-rw-r--r--absl/strings/str_cat.h348
-rw-r--r--absl/strings/str_cat_test.cc462
-rw-r--r--absl/strings/str_join.h288
-rw-r--r--absl/strings/str_join_test.cc474
-rw-r--r--absl/strings/str_replace.cc79
-rw-r--r--absl/strings/str_replace.h213
-rw-r--r--absl/strings/str_replace_test.cc340
-rw-r--r--absl/strings/str_split.cc133
-rw-r--r--absl/strings/str_split.h511
-rw-r--r--absl/strings/str_split_test.cc896
-rw-r--r--absl/strings/string_view.cc248
-rw-r--r--absl/strings/string_view.h572
-rw-r--r--absl/strings/string_view_test.cc1097
-rw-r--r--absl/strings/strip.cc269
-rw-r--r--absl/strings/strip.h89
-rw-r--r--absl/strings/strip_test.cc119
-rw-r--r--absl/strings/substitute.cc117
-rw-r--r--absl/strings/substitute.h674
-rw-r--r--absl/strings/substitute_test.cc168
-rw-r--r--absl/strings/testdata/getline-1.txt3
-rw-r--r--absl/strings/testdata/getline-2.txt1
-rw-r--r--absl/synchronization/BUILD.bazel178
-rw-r--r--absl/synchronization/barrier.cc50
-rw-r--r--absl/synchronization/barrier.h77
-rw-r--r--absl/synchronization/blocking_counter.cc53
-rw-r--r--absl/synchronization/blocking_counter.h96
-rw-r--r--absl/synchronization/blocking_counter_test.cc67
-rw-r--r--absl/synchronization/internal/create_thread_identity.cc110
-rw-r--r--absl/synchronization/internal/create_thread_identity.h53
-rw-r--r--absl/synchronization/internal/graphcycles.cc709
-rw-r--r--absl/synchronization/internal/graphcycles.h136
-rw-r--r--absl/synchronization/internal/graphcycles_test.cc471
-rw-r--r--absl/synchronization/internal/kernel_timeout.h147
-rw-r--r--absl/synchronization/internal/mutex_nonprod.cc311
-rw-r--r--absl/synchronization/internal/mutex_nonprod.inc256
-rw-r--r--absl/synchronization/internal/per_thread_sem.cc106
-rw-r--r--absl/synchronization/internal/per_thread_sem.h107
-rw-r--r--absl/synchronization/internal/per_thread_sem_test.cc246
-rw-r--r--absl/synchronization/internal/thread_pool.h90
-rw-r--r--absl/synchronization/internal/waiter.cc394
-rw-r--r--absl/synchronization/internal/waiter.h138
-rw-r--r--absl/synchronization/mutex.cc2680
-rw-r--r--absl/synchronization/mutex.h1013
-rw-r--r--absl/synchronization/mutex_test.cc1538
-rw-r--r--absl/synchronization/notification.cc84
-rw-r--r--absl/synchronization/notification.h112
-rw-r--r--absl/synchronization/notification_test.cc124
-rw-r--r--absl/test_dependencies.bzl40
-rw-r--r--absl/time/BUILD.bazel112
-rw-r--r--absl/time/clock.cc547
-rw-r--r--absl/time/clock.h72
-rw-r--r--absl/time/clock_test.cc70
-rw-r--r--absl/time/duration.cc864
-rw-r--r--absl/time/duration_test.cc1530
-rw-r--r--absl/time/format.cc140
-rw-r--r--absl/time/format_test.cc430
-rw-r--r--absl/time/internal/get_current_time_ios.inc80
-rw-r--r--absl/time/internal/get_current_time_posix.inc22
-rw-r--r--absl/time/internal/get_current_time_windows.inc17
-rw-r--r--absl/time/internal/test_util.cc112
-rw-r--r--absl/time/internal/test_util.h49
-rw-r--r--absl/time/internal/zoneinfo.inc729
-rw-r--r--absl/time/time.cc370
-rw-r--r--absl/time/time.h1181
-rw-r--r--absl/time/time_norm_test.cc306
-rw-r--r--absl/time/time_test.cc1027
-rw-r--r--absl/time/time_zone_test.cc95
-rw-r--r--absl/types/BUILD.bazel178
-rw-r--r--absl/types/any.h539
-rw-r--r--absl/types/any_test.cc713
-rw-r--r--absl/types/bad_any_cast.cc40
-rw-r--r--absl/types/bad_any_cast.h44
-rw-r--r--absl/types/bad_optional_access.cc42
-rw-r--r--absl/types/bad_optional_access.h37
-rw-r--r--absl/types/optional.cc24
-rw-r--r--absl/types/optional.h1092
-rw-r--r--absl/types/optional_test.cc1539
-rw-r--r--absl/types/span.h738
-rw-r--r--absl/types/span_test.cc783
-rw-r--r--absl/utility/BUILD.bazel34
-rw-r--r--absl/utility/utility.cc27
-rw-r--r--absl/utility/utility.h177
-rw-r--r--absl/utility/utility_test.cc163
238 files changed, 65475 insertions, 0 deletions
diff --git a/ABSEIL_ISSUE_TEMPLATE.md b/ABSEIL_ISSUE_TEMPLATE.md
new file mode 100644
index 0000000..585cdc3
--- /dev/null
+++ b/ABSEIL_ISSUE_TEMPLATE.md
@@ -0,0 +1,22 @@
+Please submit a new Abseil Issue using the tempate 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."]
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..976d31d
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,6 @@
+# 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.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..c9c89bb
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,90 @@
+# 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. 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.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..fef7d96
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,204 @@
+
+ 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.
+
+ \ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0301f61
--- /dev/null
+++ b/README.md
@@ -0,0 +1,89 @@
+# 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)
+- [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.
+
+## Codemap
+
+Abseil contains the following C++ library components:
+
+* [`base`](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`](algorithm/)
+ <br /> The `algorithm` library contains additions to the C++ `<algorithm>`
+ library and container-based versions of such algorithms.
+* [`container`](container)
+ <br /> The `container` library contains additional STL-style containers.
+* [`debugging`](debugging)
+ <br /> The `debugging` library contains code useful for enabling leak
+ checks. Future updates will add stacktrace and symbolization utilities.
+* [`memory`](memory)
+ <br /> The `memory` library contains C++11-compatible versions of
+ `std::make_unique()` and related memory management facilities.
+* [`meta`](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`](numeric)
+ <br /> The `numeric` library contains C++11-compatible 128-bit integers.
+* [`strings`](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`](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`](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`](types)
+ <br /> The `types` library contains non-container utility types, like a
+ C++11-compatible version of `absl::optional`.
+
+## 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/about/intro)
+* Read [Why Adopt Abseil](http://abseil.io/about/philosophy) to understand our
+ design philosophy.
+* Peruse our [Abseil Project Contract](http://abseil.io/about/contract) to
+ understand both what we promise to you, and what we expect of you in return.
+
+## Disclaimer
+
+* This is not an official Google product.
diff --git a/WORKSPACE b/WORKSPACE
new file mode 100644
index 0000000..7d8efc7
--- /dev/null
+++ b/WORKSPACE
@@ -0,0 +1,22 @@
+workspace(name = "com_google_absl")
+# GoogleTest/GoogleMock framework. Used by most unit-tests.
+http_archive(
+ name = "com_google_googletest",
+ urls = ["https://github.com/google/googletest/archive/master.zip"],
+ strip_prefix = "googletest-master",
+)
+
+# CCTZ (Time-zone framework).
+# TODO(b/63158562): Make test and benchmark targets from here build.
+http_archive(
+ name = "com_googlesource_code_cctz",
+ urls = ["https://github.com/google/cctz/archive/master.zip"],
+ strip_prefix = "cctz-master",
+)
+
+# RE2 regular-expression framework. Used by some unit-tests.
+http_archive(
+ name = "com_googlesource_code_re2",
+ urls = ["https://github.com/google/re2/archive/master.zip"],
+ strip_prefix = "re2-master",
+)
diff --git a/absl/BUILD.bazel b/absl/BUILD.bazel
new file mode 100644
index 0000000..42c107d
--- /dev/null
+++ b/absl/BUILD.bazel
@@ -0,0 +1,62 @@
+#
+# 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",
+ },
+)
+
+config_setting(
+ name = "hybrid_compiler",
+ values = {
+ "compiler": "hybrid",
+ },
+)
+
+config_setting(
+ name = "llvm_warnings",
+ values = {
+ "define": "ABSL_LLVM_WARNINGS=1",
+ },
+)
+
+# following configs are based on mapping defined in: https://git.io/v5Ijz
+config_setting(
+ name = "ios",
+ values = {
+ "cpu": "darwin",
+ },
+)
+
+config_setting(
+ name = "windows",
+ values = {
+ "cpu": "x64_windows_msvc",
+ },
+)
+
+config_setting(
+ name = "ppc",
+ values = {
+ "cpu": "ppc",
+ },
+)
diff --git a/absl/algorithm/BUILD.bazel b/absl/algorithm/BUILD.bazel
new file mode 100644
index 0000000..5890bf1
--- /dev/null
+++ b/absl/algorithm/BUILD.bazel
@@ -0,0 +1,69 @@
+#
+# 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",
+)
+load(
+ "//absl:test_dependencies.bzl",
+ "GUNIT_MAIN_DEPS_SELECTOR",
+)
+
+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"] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+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",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
diff --git a/absl/algorithm/algorithm.h b/absl/algorithm/algorithm.h
new file mode 100644
index 0000000..341b68b
--- /dev/null
+++ b/absl/algorithm/algorithm.h
@@ -0,0 +1,138 @@
+// 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));
+}
+
+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_
diff --git a/absl/algorithm/algorithm_test.cc b/absl/algorithm/algorithm_test.cc
new file mode 100644
index 0000000..e4322bc
--- /dev/null
+++ b/absl/algorithm/algorithm_test.cc
@@ -0,0 +1,182 @@
+// 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
diff --git a/absl/algorithm/container.h b/absl/algorithm/container.h
new file mode 100644
index 0000000..dbdc5c8
--- /dev/null
+++ b/absl/algorithm/container.h
@@ -0,0 +1,1652 @@
+// 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: container.h
+// -----------------------------------------------------------------------------
+//
+// This header file provides Container-based versions of algorithmic functions
+// within the C++ standard library. The following standard library sets of
+// functions are covered within this file:
+//
+// * Algorithmic <iterator> functions
+// * Algorithmic <numeric> functions
+// * <algorithm> functions
+//
+// The standard library functions operate on iterator ranges; the functions
+// within this API operate on containers, though many return iterator ranges.
+//
+// All functions within this API are named with a `c_` prefix. Calls such as
+// `absl::c_xx(container, ...) are equivalent to std:: functions such as
+// `std::xx(std::begin(cont), std::end(cont), ...)`. Functions that act on
+// iterators but not conceptually on iterator ranges (e.g. `std::iter_swap`)
+// have no equivalent here.
+//
+// For template parameter and variable naming, `C` indicates the container type
+// to which the function is applied, `Pred` indicates the predicate object type
+// to be used by the function and `T` indicates the applicable element type.
+//
+
+#ifndef ABSL_ALGORITHM_CONTAINER_H_
+#define ABSL_ALGORITHM_CONTAINER_H_
+
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <numeric>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "absl/algorithm/algorithm.h"
+#include "absl/base/macros.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+
+namespace container_algorithm_internal {
+
+// NOTE: it is important to defer to ADL lookup for building with C++ modules,
+// especially for headers like <valarray> which are not visible from this file
+// but specialize std::begin and std::end.
+using std::begin;
+using std::end;
+
+// The type of the iterator given by begin(c) (possibly std::begin(c)).
+// ContainerIter<const vector<T>> gives vector<T>::const_iterator,
+// while ContainerIter<vector<T>> gives vector<T>::iterator.
+template <typename C>
+using ContainerIter = decltype(begin(std::declval<C&>()));
+
+template <typename C>
+using ContainerDifferenceType =
+ decltype(std::distance(std::declval<ContainerIter<C>>(),
+ std::declval<ContainerIter<C>>()));
+
+template <typename C>
+using ContainerPointerType =
+ typename std::iterator_traits<ContainerIter<C>>::pointer;
+
+// container_algorithm_internal::c_begin and
+// container_algorithm_internal::c_end are abbreviations for proper ADL
+// lookup of std::begin and std::end, i.e.
+// using std::begin;
+// using std::end;
+// std::foo(begin(c), end(c);
+// becomes
+// std::foo(container_algorithm_internal::begin(c),
+// container_algorithm_internal::end(c));
+// These are meant for internal use only.
+
+template <typename C>
+ContainerIter<C> c_begin(C& c) { return begin(c); }
+
+template <typename C>
+ContainerIter<C> c_end(C& c) { return end(c); }
+
+} // namespace container_algorithm_internal
+
+// PUBLIC API
+
+//------------------------------------------------------------------------------
+// Abseil algorithm.h functions
+//------------------------------------------------------------------------------
+
+// c_linear_search()
+//
+// Container-based version of absl::linear_search() for performing a linear
+// search within a container.
+template <typename C, typename EqualityComparable>
+bool c_linear_search(const C& c, EqualityComparable&& value) {
+ return linear_search(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<EqualityComparable>(value));
+}
+
+//------------------------------------------------------------------------------
+// <iterator> algorithms
+//------------------------------------------------------------------------------
+
+// c_distance()
+//
+// Container-based version of the <iterator> `std::distance()` function to
+// return the number of elements within a container.
+template <typename C>
+container_algorithm_internal::ContainerDifferenceType<const C> c_distance(
+ const C& c) {
+ return std::distance(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Non-modifying sequence operations
+//------------------------------------------------------------------------------
+
+// c_all_of()
+//
+// Container-based version of the <algorithm> `std::all_of()` function to
+// test a condition on all elements within a container.
+template <typename C, typename Pred>
+bool c_all_of(const C& c, Pred&& pred) {
+ return std::all_of(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<Pred>(pred));
+}
+
+// c_any_of()
+//
+// Container-based version of the <algorithm> `std::any_of()` function to
+// test if any element in a container fulfills a condition.
+template <typename C, typename Pred>
+bool c_any_of(const C& c, Pred&& pred) {
+ return std::any_of(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<Pred>(pred));
+}
+
+// c_none_of()
+//
+// Container-based version of the <algorithm> `std::none_of()` function to
+// test if no elements in a container fulfil a condition.
+template <typename C, typename Pred>
+bool c_none_of(const C& c, Pred&& pred) {
+ return std::none_of(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<Pred>(pred));
+}
+
+// c_for_each()
+//
+// Container-based version of the <algorithm> `std::for_each()` function to
+// apply a function to a container's elements.
+template <typename C, typename Function>
+decay_t<Function> c_for_each(C&& c, Function&& f) {
+ return std::for_each(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<Function>(f));
+}
+
+// c_find()
+//
+// Container-based version of the <algorithm> `std::find()` function to find
+// the first element containing the passed value within a container value.
+template <typename C, typename T>
+container_algorithm_internal::ContainerIter<C> c_find(C& c, T&& value) {
+ return std::find(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<T>(value));
+}
+
+// c_find_if()
+//
+// Container-based version of the <algorithm> `std::find_if()` function to find
+// the first element in a container matching the given condition.
+template <typename C, typename Pred>
+container_algorithm_internal::ContainerIter<C> c_find_if(C& c, Pred&& pred) {
+ return std::find_if(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<Pred>(pred));
+}
+
+// c_find_if_not()
+//
+// Container-based version of the <algorithm> `std::find_if_not()` function to
+// find the first element in a container not matching the given condition.
+template <typename C, typename Pred>
+container_algorithm_internal::ContainerIter<C> c_find_if_not(C& c,
+ Pred&& pred) {
+ return std::find_if_not(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<Pred>(pred));
+}
+
+// c_find_end()
+//
+// Container-based version of the <algorithm> `std::find_end()` function to
+// find the last subsequence within a container.
+template <typename Sequence1, typename Sequence2>
+container_algorithm_internal::ContainerIter<Sequence1> c_find_end(
+ Sequence1& sequence, Sequence2& subsequence) {
+ return std::find_end(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ container_algorithm_internal::c_begin(subsequence),
+ container_algorithm_internal::c_end(subsequence));
+}
+
+// Overload of c_find_end() for using a predicate evaluation other than `==` as
+// the function's test condition.
+template <typename Sequence1, typename Sequence2, typename BinaryPredicate>
+container_algorithm_internal::ContainerIter<Sequence1> c_find_end(
+ Sequence1& sequence, Sequence2& subsequence, BinaryPredicate&& pred) {
+ return std::find_end(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ container_algorithm_internal::c_begin(subsequence),
+ container_algorithm_internal::c_end(subsequence),
+ std::forward<BinaryPredicate>(pred));
+}
+
+// c_find_first_of()
+//
+// Container-based version of the <algorithm> `std::find_first_of()` function to
+// find the first elements in an ordered set within a container.
+template <typename C1, typename C2>
+container_algorithm_internal::ContainerIter<C1> c_find_first_of(C1& container,
+ C2& options) {
+ return std::find_first_of(container_algorithm_internal::c_begin(container),
+ container_algorithm_internal::c_end(container),
+ container_algorithm_internal::c_begin(options),
+ container_algorithm_internal::c_end(options));
+}
+
+// Overload of c_find_first_of() for using a predicate evaluation other than
+// `==` as the function's test condition.
+template <typename C1, typename C2, typename BinaryPredicate>
+container_algorithm_internal::ContainerIter<C1> c_find_first_of(
+ C1& container, C2& options, BinaryPredicate&& pred) {
+ return std::find_first_of(container_algorithm_internal::c_begin(container),
+ container_algorithm_internal::c_end(container),
+ container_algorithm_internal::c_begin(options),
+ container_algorithm_internal::c_end(options),
+ std::forward<BinaryPredicate>(pred));
+}
+
+// c_adjacent_find()
+//
+// Container-based version of the <algorithm> `std::adjacent_find()` function to
+// find equal adjacent elements within a container.
+template <typename Sequence>
+container_algorithm_internal::ContainerIter<Sequence> c_adjacent_find(
+ Sequence& sequence) {
+ return std::adjacent_find(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_adjacent_find() for using a predicate evaluation other than
+// `==` as the function's test condition.
+template <typename Sequence, typename BinaryPredicate>
+container_algorithm_internal::ContainerIter<Sequence> c_adjacent_find(
+ Sequence& sequence, BinaryPredicate&& pred) {
+ return std::adjacent_find(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ std::forward<BinaryPredicate>(pred));
+}
+
+// c_count()
+//
+// Container-based version of the <algorithm> `std::count()` function to count
+// values that match within a container.
+template <typename C, typename T>
+container_algorithm_internal::ContainerDifferenceType<const C> c_count(
+ const C& c, T&& value) {
+ return std::count(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<T>(value));
+}
+
+// c_count_if()
+//
+// Container-based version of the <algorithm> `std::count_if()` function to
+// count values matching a condition within a container.
+template <typename C, typename Pred>
+container_algorithm_internal::ContainerDifferenceType<const C> c_count_if(
+ const C& c, Pred&& pred) {
+ return std::count_if(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<Pred>(pred));
+}
+
+// c_mismatch()
+//
+// Container-based version of the <algorithm> `std::mismatchf()` function to
+// return the first element where two ordered containers differ.
+template <typename C1, typename C2>
+std::pair<container_algorithm_internal::ContainerIter<C1>,
+ container_algorithm_internal::ContainerIter<C2>>
+c_mismatch(C1& c1, C2& c2) {
+ return std::mismatch(container_algorithm_internal::c_begin(c1),
+ container_algorithm_internal::c_end(c1),
+ container_algorithm_internal::c_begin(c2));
+}
+
+// Overload of c_mismatch() for using a predicate evaluation other than `==` as
+// the function's test condition.
+template <typename C1, typename C2, typename BinaryPredicate>
+std::pair<container_algorithm_internal::ContainerIter<C1>,
+ container_algorithm_internal::ContainerIter<C2>>
+c_mismatch(C1& c1, C2& c2, BinaryPredicate&& pred) {
+ return std::mismatch(container_algorithm_internal::c_begin(c1),
+ container_algorithm_internal::c_end(c1),
+ container_algorithm_internal::c_begin(c2),
+ std::forward<BinaryPredicate>(pred));
+}
+
+// c_equal()
+//
+// Container-based version of the <algorithm> `std::equal()` function to
+// test whether two containers are equal.
+//
+// NOTE: the semantics of c_equal() are slightly different than those of
+// equal(): while the latter iterates over the second container only up to the
+// size of the first container, c_equal() also checks whether the container
+// sizes are equal. This better matches expectations about c_equal() based on
+// its signature.
+//
+// Example:
+// vector v1 = <1, 2, 3>;
+// vector v2 = <1, 2, 3, 4>;
+// equal(std::begin(v1), std::end(v1), std::begin(v2)) returns true
+// c_equal(v1, v2) returns false
+
+template <typename C1, typename C2>
+bool c_equal(const C1& c1, const C2& c2) {
+ return ((c1.size() == c2.size()) &&
+ std::equal(container_algorithm_internal::c_begin(c1),
+ container_algorithm_internal::c_end(c1),
+ container_algorithm_internal::c_begin(c2)));
+}
+
+// Overload of c_equal() for using a predicate evaluation other than `==` as
+// the function's test condition.
+template <typename C1, typename C2, typename BinaryPredicate>
+bool c_equal(const C1& c1, const C2& c2, BinaryPredicate&& pred) {
+ return ((c1.size() == c2.size()) &&
+ std::equal(container_algorithm_internal::c_begin(c1),
+ container_algorithm_internal::c_end(c1),
+ container_algorithm_internal::c_begin(c2),
+ std::forward<BinaryPredicate>(pred)));
+}
+
+// c_is_permutation()
+//
+// Container-based version of the <algorithm> `std::is_permutation()` function
+// to test whether a container is a permutation of another.
+template <typename C1, typename C2>
+bool c_is_permutation(const C1& c1, const C2& c2) {
+ using std::begin;
+ using std::end;
+ return c1.size() == c2.size() &&
+ std::is_permutation(begin(c1), end(c1), begin(c2));
+}
+
+// Overload of c_is_permutation() for using a predicate evaluation other than
+// `==` as the function's test condition.
+template <typename C1, typename C2, typename BinaryPredicate>
+bool c_is_permutation(const C1& c1, const C2& c2, BinaryPredicate&& pred) {
+ using std::begin;
+ using std::end;
+ return c1.size() == c2.size() &&
+ std::is_permutation(begin(c1), end(c1), begin(c2),
+ std::forward<BinaryPredicate>(pred));
+}
+
+// c_search()
+//
+// Container-based version of the <algorithm> `std::search()` function to search
+// a container for a subsequence.
+template <typename Sequence1, typename Sequence2>
+container_algorithm_internal::ContainerIter<Sequence1> c_search(
+ Sequence1& sequence, Sequence2& subsequence) {
+ return std::search(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ container_algorithm_internal::c_begin(subsequence),
+ container_algorithm_internal::c_end(subsequence));
+}
+
+// Overload of c_search() for using a predicate evaluation other than
+// `==` as the function's test condition.
+template <typename Sequence1, typename Sequence2, typename BinaryPredicate>
+container_algorithm_internal::ContainerIter<Sequence1> c_search(
+ Sequence1& sequence, Sequence2& subsequence, BinaryPredicate&& pred) {
+ return std::search(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ container_algorithm_internal::c_begin(subsequence),
+ container_algorithm_internal::c_end(subsequence),
+ std::forward<BinaryPredicate>(pred));
+}
+
+// c_search_n()
+//
+// Container-based version of the <algorithm> `std::search_n()` function to
+// search a container for the first sequence of N elements.
+template <typename Sequence, typename Size, typename T>
+container_algorithm_internal::ContainerIter<Sequence> c_search_n(
+ Sequence& sequence, Size count, T&& value) {
+ return std::search_n(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence), count,
+ std::forward<T>(value));
+}
+
+// Overload of c_search_n() for using a predicate evaluation other than
+// `==` as the function's test condition.
+template <typename Sequence, typename Size, typename T,
+ typename BinaryPredicate>
+container_algorithm_internal::ContainerIter<Sequence> c_search_n(
+ Sequence& sequence, Size count, T&& value, BinaryPredicate&& pred) {
+ return std::search_n(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence), count,
+ std::forward<T>(value),
+ std::forward<BinaryPredicate>(pred));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Modifying sequence operations
+//------------------------------------------------------------------------------
+
+// c_copy()
+//
+// Container-based version of the <algorithm> `std::copy()` function to copy a
+// container's elements into an iterator.
+template <typename InputSequence, typename OutputIterator>
+OutputIterator c_copy(const InputSequence& input, OutputIterator output) {
+ return std::copy(container_algorithm_internal::c_begin(input),
+ container_algorithm_internal::c_end(input), output);
+}
+
+// c_copy_n()
+//
+// Container-based version of the <algorithm> `std::copy_n()` function to copy a
+// container's first N elements into an iterator.
+template <typename C, typename Size, typename OutputIterator>
+OutputIterator c_copy_n(const C& input, Size n, OutputIterator output) {
+ return std::copy_n(container_algorithm_internal::c_begin(input), n, output);
+}
+
+// c_copy_if()
+//
+// Container-based version of the <algorithm> `std::copy_if()` function to copy
+// a container's elements satisfying some condition into an iterator.
+template <typename InputSequence, typename OutputIterator, typename Pred>
+OutputIterator c_copy_if(const InputSequence& input, OutputIterator output,
+ Pred&& pred) {
+ return std::copy_if(container_algorithm_internal::c_begin(input),
+ container_algorithm_internal::c_end(input), output,
+ std::forward<Pred>(pred));
+}
+
+// c_copy_backward()
+//
+// Container-based version of the <algorithm> `std::copy_backward()` function to
+// copy a container's elements in reverse order into an iterator.
+template <typename C, typename BidirectionalIterator>
+BidirectionalIterator c_copy_backward(const C& src,
+ BidirectionalIterator dest) {
+ return std::copy_backward(container_algorithm_internal::c_begin(src),
+ container_algorithm_internal::c_end(src), dest);
+}
+
+// c_move()
+//
+// Container-based version of the <algorithm> `std::move()` function to move
+// a container's elements into an iterator.
+template <typename C, typename OutputIterator>
+OutputIterator c_move(C& src, OutputIterator dest) {
+ return std::move(container_algorithm_internal::c_begin(src),
+ container_algorithm_internal::c_end(src), dest);
+}
+
+// c_move_backward()
+//
+// Container-based version of the <algorithm> `std::move_backward()` function to
+// move a container's elements into an iterator in reverse order.
+template <typename C, typename BidirectionalIterator>
+BidirectionalIterator c_move_backward(C& src, BidirectionalIterator dest) {
+ return std::move_backward(container_algorithm_internal::c_begin(src),
+ container_algorithm_internal::c_end(src), dest);
+}
+
+// c_swap_ranges()
+//
+// Container-based version of the <algorithm> `std::swap_ranges()` function to
+// swap a container's elements with another container's elements.
+template <typename C1, typename C2>
+container_algorithm_internal::ContainerIter<C2> c_swap_ranges(C1& c1, C2& c2) {
+ return std::swap_ranges(container_algorithm_internal::c_begin(c1),
+ container_algorithm_internal::c_end(c1),
+ container_algorithm_internal::c_begin(c2));
+}
+
+// c_transform()
+//
+// Container-based version of the <algorithm> `std::transform()` function to
+// transform a container's elements using the unary operation, storing the
+// result in an iterator pointing to the last transformed element in the output
+// range.
+template <typename InputSequence, typename OutputIterator, typename UnaryOp>
+OutputIterator c_transform(const InputSequence& input, OutputIterator output,
+ UnaryOp&& unary_op) {
+ return std::transform(container_algorithm_internal::c_begin(input),
+ container_algorithm_internal::c_end(input), output,
+ std::forward<UnaryOp>(unary_op));
+}
+
+// Overload of c_transform() for performing a transformation using a binary
+// predicate.
+template <typename InputSequence1, typename InputSequence2,
+ typename OutputIterator, typename BinaryOp>
+OutputIterator c_transform(const InputSequence1& input1,
+ const InputSequence2& input2, OutputIterator output,
+ BinaryOp&& binary_op) {
+ return std::transform(container_algorithm_internal::c_begin(input1),
+ container_algorithm_internal::c_end(input1),
+ container_algorithm_internal::c_begin(input2), output,
+ std::forward<BinaryOp>(binary_op));
+}
+
+// c_replace()
+//
+// Container-based version of the <algorithm> `std::replace()` function to
+// replace a container's elements of some value with a new value. The container
+// is modified in place.
+template <typename Sequence, typename T>
+void c_replace(Sequence& sequence, const T& old_value, const T& new_value) {
+ std::replace(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence), old_value,
+ new_value);
+}
+
+// c_replace_if()
+//
+// Container-based version of the <algorithm> `std::replace_if()` function to
+// replace a container's elements of some value with a new value based on some
+// condition. The container is modified in place.
+template <typename C, typename Pred, typename T>
+void c_replace_if(C& c, Pred&& pred, T&& new_value) {
+ std::replace_if(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<Pred>(pred), std::forward<T>(new_value));
+}
+
+// c_replace_copy()
+//
+// Container-based version of the <algorithm> `std::replace_copy()` function to
+// replace a container's elements of some value with a new value and return the
+// results within an iterator.
+template <typename C, typename OutputIterator, typename T>
+OutputIterator c_replace_copy(const C& c, OutputIterator result, T&& old_value,
+ T&& new_value) {
+ return std::replace_copy(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c), result,
+ std::forward<T>(old_value),
+ std::forward<T>(new_value));
+}
+
+// c_replace_copy_if()
+//
+// Container-based version of the <algorithm> `std::replace_copy_if()` function
+// to replace a container's elements of some value with a new value based on
+// some condition, and return the results within an iterator.
+template <typename C, typename OutputIterator, typename Pred, typename T>
+OutputIterator c_replace_copy_if(const C& c, OutputIterator result, Pred&& pred,
+ T&& new_value) {
+ return std::replace_copy_if(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c), result,
+ std::forward<Pred>(pred),
+ std::forward<T>(new_value));
+}
+
+// c_fill()
+//
+// Container-based version of the <algorithm> `std::fill()` function to fill a
+// container with some value.
+template <typename C, typename T>
+void c_fill(C& c, T&& value) {
+ std::fill(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c), std::forward<T>(value));
+}
+
+// c_fill_n()
+//
+// Container-based version of the <algorithm> `std::fill_n()` function to fill
+// the first N elements in a container with some value.
+template <typename C, typename Size, typename T>
+void c_fill_n(C& c, Size n, T&& value) {
+ std::fill_n(container_algorithm_internal::c_begin(c), n,
+ std::forward<T>(value));
+}
+
+// c_generate()
+//
+// Container-based version of the <algorithm> `std::generate()` function to
+// assign a container's elements to the values provided by the given generator.
+template <typename C, typename Generator>
+void c_generate(C& c, Generator&& gen) {
+ std::generate(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<Generator>(gen));
+}
+
+// c_generate_n()
+//
+// Container-based version of the <algorithm> `std::generate_n()` function to
+// assign a container's first N elements to the values provided by the given
+// generator.
+template <typename C, typename Size, typename Generator>
+container_algorithm_internal::ContainerIter<C> c_generate_n(C& c, Size n,
+ Generator&& gen) {
+ return std::generate_n(container_algorithm_internal::c_begin(c), n,
+ std::forward<Generator>(gen));
+}
+
+// Note: `c_xx()` <algorithm> container versions for `remove()`, `remove_if()`,
+// and `unique()` are omitted, because it's not clear whether or not such
+// functions should call erase their supplied sequences afterwards. Either
+// behavior would be surprising for a different set of users.
+//
+
+// c_remove_copy()
+//
+// Container-based version of the <algorithm> `std::remove_copy()` function to
+// copy a container's elements while removing any elements matching the given
+// `value`.
+template <typename C, typename OutputIterator, typename T>
+OutputIterator c_remove_copy(const C& c, OutputIterator result, T&& value) {
+ return std::remove_copy(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c), result,
+ std::forward<T>(value));
+}
+
+// c_remove_copy_if()
+//
+// Container-based version of the <algorithm> `std::remove_copy_if()` function
+// to copy a container's elements while removing any elements matching the given
+// condition.
+template <typename C, typename OutputIterator, typename Pred>
+OutputIterator c_remove_copy_if(const C& c, OutputIterator result,
+ Pred&& pred) {
+ return std::remove_copy_if(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c), result,
+ std::forward<Pred>(pred));
+}
+
+// c_unique_copy()
+//
+// Container-based version of the <algorithm> `std::unique_copy()` function to
+// copy a container's elements while removing any elements containing duplicate
+// values.
+template <typename C, typename OutputIterator>
+OutputIterator c_unique_copy(const C& c, OutputIterator result) {
+ return std::unique_copy(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c), result);
+}
+
+// Overload of c_unique_copy() for using a predicate evaluation other than
+// `==` for comparing uniqueness of the element values.
+template <typename C, typename OutputIterator, typename BinaryPredicate>
+OutputIterator c_unique_copy(const C& c, OutputIterator result,
+ BinaryPredicate&& pred) {
+ return std::unique_copy(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c), result,
+ std::forward<BinaryPredicate>(pred));
+}
+
+// c_reverse()
+//
+// Container-based version of the <algorithm> `std::reverse()` function to
+// reverse a container's elements.
+template <typename Sequence>
+void c_reverse(Sequence& sequence) {
+ std::reverse(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence));
+}
+
+// c_reverse_copy()
+//
+// Container-based version of the <algorithm> `std::reverse()` function to
+// reverse a container's elements and write them to an iterator range.
+template <typename C, typename OutputIterator>
+OutputIterator c_reverse_copy(const C& sequence, OutputIterator result) {
+ return std::reverse_copy(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ result);
+}
+
+// c_rotate()
+//
+// Container-based version of the <algorithm> `std::rotate()` function to
+// shift a container's elements leftward such that the `middle` element becomes
+// the first element in the container.
+template <typename C,
+ typename Iterator = container_algorithm_internal::ContainerIter<C>>
+Iterator c_rotate(C& sequence, Iterator middle) {
+ return absl::rotate(container_algorithm_internal::c_begin(sequence), middle,
+ container_algorithm_internal::c_end(sequence));
+}
+
+// c_rotate_copy()
+//
+// Container-based version of the <algorithm> `std::rotate_copy()` function to
+// shift a container's elements leftward such that the `middle` element becomes
+// the first element in a new iterator range.
+template <typename C, typename OutputIterator>
+OutputIterator c_rotate_copy(
+ const C& sequence,
+ container_algorithm_internal::ContainerIter<const C> middle,
+ OutputIterator result) {
+ return std::rotate_copy(container_algorithm_internal::c_begin(sequence),
+ middle, container_algorithm_internal::c_end(sequence),
+ result);
+}
+
+// c_shuffle()
+//
+// Container-based version of the <algorithm> `std::shuffle()` function to
+// randomly shuffle elements within the container using a `gen()` uniform random
+// number generator.
+template <typename RandomAccessContainer, typename UniformRandomBitGenerator>
+void c_shuffle(RandomAccessContainer& c, UniformRandomBitGenerator&& gen) {
+ std::shuffle(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<UniformRandomBitGenerator>(gen));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Partition functions
+//------------------------------------------------------------------------------
+
+// c_is_partitioned()
+//
+// Container-based version of the <algorithm> `std::is_partitioned()` function
+// to test whether all elements in the container for which `pred` returns `true`
+// precede those for which `pred` is `false`.
+template <typename C, typename Pred>
+bool c_is_partitioned(const C& c, Pred&& pred) {
+ return std::is_partitioned(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<Pred>(pred));
+}
+
+// c_partition()
+//
+// Container-based version of the <algorithm> `std::partition()` function
+// to rearrange all elements in a container in such a way that all elements for
+// which `pred` returns `true` precede all those for which it returns `false`,
+// returning an iterator to the first element of the second group.
+template <typename C, typename Pred>
+container_algorithm_internal::ContainerIter<C> c_partition(C& c, Pred&& pred) {
+ return std::partition(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<Pred>(pred));
+}
+
+// c_stable_partition()
+//
+// Container-based version of the <algorithm> `std::stable_partition()` function
+// to rearrange all elements in a container in such a way that all elements for
+// which `pred` returns `true` precede all those for which it returns `false`,
+// preserving the relative ordering between the two groups. The function returns
+// an iterator to the first element of the second group.
+template <typename C, typename Pred>
+container_algorithm_internal::ContainerIter<C> c_stable_partition(C& c,
+ Pred&& pred) {
+ return std::stable_partition(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<Pred>(pred));
+}
+
+// c_partition_copy()
+//
+// Container-based version of the <algorithm> `std::partition_copy()` function
+// to partition a container's elements and return them into two iterators: one
+// for which `pred` returns `true`, and one for which `pred` returns `false.`
+
+template <typename C, typename OutputIterator1, typename OutputIterator2,
+ typename Pred>
+std::pair<OutputIterator1, OutputIterator2> c_partition_copy(
+ const C& c, OutputIterator1 out_true, OutputIterator2 out_false,
+ Pred&& pred) {
+ return std::partition_copy(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c), out_true,
+ out_false, std::forward<Pred>(pred));
+}
+
+// c_partition_point()
+//
+// Container-based version of the <algorithm> `std::partition_point()` function
+// to return the first element of an already partitioned container for which
+// the given `pred` is not `true`.
+template <typename C, typename Pred>
+container_algorithm_internal::ContainerIter<C> c_partition_point(C& c,
+ Pred&& pred) {
+ return std::partition_point(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<Pred>(pred));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Sorting functions
+//------------------------------------------------------------------------------
+
+// c_sort()
+//
+// Container-based version of the <algorithm> `std::sort()` function
+// to sort elements in ascending order of their values.
+template <typename C>
+void c_sort(C& c) {
+ std::sort(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c));
+}
+
+// Overload of c_sort() for performing a `comp` comparison other than the
+// default `operator<`.
+template <typename C, typename Compare>
+void c_sort(C& c, Compare&& comp) {
+ std::sort(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<Compare>(comp));
+}
+
+// c_stable_sort()
+//
+// Container-based version of the <algorithm> `std::stable_sort()` function
+// to sort elements in ascending order of their values, preserving the order
+// of equivalents.
+template <typename C>
+void c_stable_sort(C& c) {
+ std::stable_sort(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c));
+}
+
+// Overload of c_stable_sort() for performing a `comp` comparison other than the
+// default `operator<`.
+template <typename C, typename Compare>
+void c_stable_sort(C& c, Compare&& comp) {
+ std::stable_sort(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<Compare>(comp));
+}
+
+// c_is_sorted()
+//
+// Container-based version of the <algorithm> `std::is_sorted()` function
+// to evaluate whethr the given containter is sorted in ascending order.
+template <typename C>
+bool c_is_sorted(const C& c) {
+ return std::is_sorted(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c));
+}
+
+// c_is_sorted() overload for performing a `comp` comparison other than the
+// default `operator<`.
+template <typename C, typename Compare>
+bool c_is_sorted(const C& c, Compare&& comp) {
+ return std::is_sorted(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<Compare>(comp));
+}
+
+// c_partial_sort()
+//
+// Container-based version of the <algorithm> `std::partial_sort()` function
+// to rearrange elements within a container such that elements before `middle`
+// are sorted in ascending order.
+template <typename RandomAccessContainer>
+void c_partial_sort(
+ RandomAccessContainer& sequence,
+ container_algorithm_internal::ContainerIter<RandomAccessContainer> middle) {
+ std::partial_sort(container_algorithm_internal::c_begin(sequence), middle,
+ container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_partial_sort() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename RandomAccessContainer, typename Compare>
+void c_partial_sort(
+ RandomAccessContainer& sequence,
+ container_algorithm_internal::ContainerIter<RandomAccessContainer> middle,
+ Compare&& comp) {
+ std::partial_sort(container_algorithm_internal::c_begin(sequence), middle,
+ container_algorithm_internal::c_end(sequence),
+ std::forward<Compare>(comp));
+}
+
+// c_partial_sort_copy()
+//
+// Container-based version of the <algorithm> `std::partial_sort_copy()`
+// function to sort elements within a container such that elements before
+// `middle` are sorted in ascending order, and return the result within an
+// iterator.
+template <typename C, typename RandomAccessContainer>
+container_algorithm_internal::ContainerIter<RandomAccessContainer>
+c_partial_sort_copy(const C& sequence, RandomAccessContainer& result) {
+ return std::partial_sort_copy(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ container_algorithm_internal::c_begin(result),
+ container_algorithm_internal::c_end(result));
+}
+
+// Overload of c_partial_sort_copy() for performing a `comp` comparison other
+// than the default `operator<`.
+template <typename C, typename RandomAccessContainer, typename Compare>
+container_algorithm_internal::ContainerIter<RandomAccessContainer>
+c_partial_sort_copy(const C& sequence, RandomAccessContainer& result,
+ Compare&& comp) {
+ return std::partial_sort_copy(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ container_algorithm_internal::c_begin(result),
+ container_algorithm_internal::c_end(result),
+ std::forward<Compare>(comp));
+}
+
+// c_is_sorted_until()
+//
+// Container-based version of the <algorithm> `std::is_sorted_until()` function
+// to return the first element within a container that is not sorted in
+// ascending order as an iterator.
+template <typename C>
+container_algorithm_internal::ContainerIter<C> c_is_sorted_until(C& c) {
+ return std::is_sorted_until(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c));
+}
+
+// Overload of c_is_sorted_until() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename C, typename Compare>
+container_algorithm_internal::ContainerIter<C> c_is_sorted_until(
+ C& c, Compare&& comp) {
+ return std::is_sorted_until(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<Compare>(comp));
+}
+
+// c_nth_element()
+//
+// Container-based version of the <algorithm> `std::nth_element()` function
+// to rearrange the elements within a container such that the `nth` element
+// would be in that position in an ordered sequence; other elements may be in
+// any order, except that all preceding `nth` will be less than that element,
+// and all following `nth` will be greater than that element.
+template <typename RandomAccessContainer>
+void c_nth_element(
+ RandomAccessContainer& sequence,
+ container_algorithm_internal::ContainerIter<RandomAccessContainer> nth) {
+ std::nth_element(container_algorithm_internal::c_begin(sequence), nth,
+ container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_nth_element() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename RandomAccessContainer, typename Compare>
+void c_nth_element(
+ RandomAccessContainer& sequence,
+ container_algorithm_internal::ContainerIter<RandomAccessContainer> nth,
+ Compare&& comp) {
+ std::nth_element(container_algorithm_internal::c_begin(sequence), nth,
+ container_algorithm_internal::c_end(sequence),
+ std::forward<Compare>(comp));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Binary Search
+//------------------------------------------------------------------------------
+
+// c_lower_bound()
+//
+// Container-based version of the <algorithm> `std::lower_bound()` function
+// to return an iterator pointing to the first element in a sorted container
+// which does not compare less than `value`.
+template <typename Sequence, typename T>
+container_algorithm_internal::ContainerIter<Sequence> c_lower_bound(
+ Sequence& sequence, T&& value) {
+ return std::lower_bound(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ std::forward<T>(value));
+}
+
+// Overload of c_lower_bound() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename Sequence, typename T, typename Compare>
+container_algorithm_internal::ContainerIter<Sequence> c_lower_bound(
+ Sequence& sequence, T&& value, Compare&& comp) {
+ return std::lower_bound(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ std::forward<T>(value), std::forward<Compare>(comp));
+}
+
+// c_upper_bound()
+//
+// Container-based version of the <algorithm> `std::upper_bound()` function
+// to return an iterator pointing to the first element in a sorted container
+// which is greater than `value`.
+template <typename Sequence, typename T>
+container_algorithm_internal::ContainerIter<Sequence> c_upper_bound(
+ Sequence& sequence, T&& value) {
+ return std::upper_bound(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ std::forward<T>(value));
+}
+
+// Overload of c_upper_bound() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename Sequence, typename T, typename Compare>
+container_algorithm_internal::ContainerIter<Sequence> c_upper_bound(
+ Sequence& sequence, T&& value, Compare&& comp) {
+ return std::upper_bound(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ std::forward<T>(value), std::forward<Compare>(comp));
+}
+
+// c_equal_range()
+//
+// Container-based version of the <algorithm> `std::equal_range()` function
+// to return an iterator pair pointing to the first and last elements in a
+// sorted container which compare equal to `value`.
+template <typename Sequence, typename T>
+std::pair<container_algorithm_internal::ContainerIter<Sequence>,
+ container_algorithm_internal::ContainerIter<Sequence>>
+c_equal_range(Sequence& sequence, T&& value) {
+ return std::equal_range(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ std::forward<T>(value));
+}
+
+// Overload of c_equal_range() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename Sequence, typename T, typename Compare>
+std::pair<container_algorithm_internal::ContainerIter<Sequence>,
+ container_algorithm_internal::ContainerIter<Sequence>>
+c_equal_range(Sequence& sequence, T&& value, Compare&& comp) {
+ return std::equal_range(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ std::forward<T>(value), std::forward<Compare>(comp));
+}
+
+// c_binary_search()
+//
+// Container-based version of the <algorithm> `std::binary_search()` function
+// to test if any element in the sorted container contains a value equivalent to
+// 'value'.
+template <typename Sequence, typename T>
+bool c_binary_search(Sequence&& sequence, T&& value) {
+ return std::binary_search(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ std::forward<T>(value));
+}
+
+// Overload of c_binary_search() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename Sequence, typename T, typename Compare>
+bool c_binary_search(Sequence&& sequence, T&& value, Compare&& comp) {
+ return std::binary_search(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ std::forward<T>(value),
+ std::forward<Compare>(comp));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Merge functions
+//------------------------------------------------------------------------------
+
+// c_merge()
+//
+// Container-based version of the <algorithm> `std::merge()` function
+// to merge two sorted containers into a single sorted iterator.
+template <typename C1, typename C2, typename OutputIterator>
+OutputIterator c_merge(const C1& c1, const C2& c2, OutputIterator result) {
+ return std::merge(container_algorithm_internal::c_begin(c1),
+ container_algorithm_internal::c_end(c1),
+ container_algorithm_internal::c_begin(c2),
+ container_algorithm_internal::c_end(c2), result);
+}
+
+// Overload of c_merge() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename C1, typename C2, typename OutputIterator, typename Compare>
+OutputIterator c_merge(const C1& c1, const C2& c2, OutputIterator result,
+ Compare&& comp) {
+ return std::merge(container_algorithm_internal::c_begin(c1),
+ container_algorithm_internal::c_end(c1),
+ container_algorithm_internal::c_begin(c2),
+ container_algorithm_internal::c_end(c2), result,
+ std::forward<Compare>(comp));
+}
+
+// c_inplace_merge()
+//
+// Container-based version of the <algorithm> `std::inplace_merge()` function
+// to merge a supplied iterator `middle` into a container.
+template <typename C>
+void c_inplace_merge(C& c,
+ container_algorithm_internal::ContainerIter<C> middle) {
+ std::inplace_merge(container_algorithm_internal::c_begin(c), middle,
+ container_algorithm_internal::c_end(c));
+}
+
+// Overload of c_inplace_merge() for performing a merge using a `comp` other
+// than `operator<`.
+template <typename C, typename Compare>
+void c_inplace_merge(C& c,
+ container_algorithm_internal::ContainerIter<C> middle,
+ Compare&& comp) {
+ std::inplace_merge(container_algorithm_internal::c_begin(c), middle,
+ container_algorithm_internal::c_end(c),
+ std::forward<Compare>(comp));
+}
+
+// c_includes()
+//
+// Container-based version of the <algorithm> `std::includes()` function
+// to test whether a sorted container `c1` entirely contains another sorted
+// container `c2`.
+template <typename C1, typename C2>
+bool c_includes(const C1& c1, const C2& c2) {
+ return std::includes(container_algorithm_internal::c_begin(c1),
+ container_algorithm_internal::c_end(c1),
+ container_algorithm_internal::c_begin(c2),
+ container_algorithm_internal::c_end(c2));
+}
+
+// Overload of c_includes() for performing a merge using a `comp` other than
+// `operator<`.
+template <typename C1, typename C2, typename Compare>
+bool c_includes(const C1& c1, const C2& c2, Compare&& comp) {
+ return std::includes(container_algorithm_internal::c_begin(c1),
+ container_algorithm_internal::c_end(c1),
+ container_algorithm_internal::c_begin(c2),
+ container_algorithm_internal::c_end(c2),
+ std::forward<Compare>(comp));
+}
+
+// c_set_union()
+//
+// Container-based version of the <algorithm> `std::set_union()` function
+// to return an iterator containing the union of two containers; duplicate
+// values are not copied into the output.
+template <typename C1, typename C2, typename OutputIterator>
+OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output) {
+ return std::set_union(container_algorithm_internal::c_begin(c1),
+ container_algorithm_internal::c_end(c1),
+ container_algorithm_internal::c_begin(c2),
+ container_algorithm_internal::c_end(c2), output);
+}
+
+// Overload of c_set_union() for performing a merge using a `comp` other than
+// `operator<`.
+template <typename C1, typename C2, typename OutputIterator, typename Compare>
+OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output,
+ Compare&& comp) {
+ return std::set_union(container_algorithm_internal::c_begin(c1),
+ container_algorithm_internal::c_end(c1),
+ container_algorithm_internal::c_begin(c2),
+ container_algorithm_internal::c_end(c2), output,
+ std::forward<Compare>(comp));
+}
+
+// c_set_intersection()
+//
+// Container-based version of the <algorithm> `std::set_intersection()` function
+// to return an iterator containing the intersection of two containers.
+template <typename C1, typename C2, typename OutputIterator>
+OutputIterator c_set_intersection(const C1& c1, const C2& c2,
+ OutputIterator output) {
+ return std::set_intersection(container_algorithm_internal::c_begin(c1),
+ container_algorithm_internal::c_end(c1),
+ container_algorithm_internal::c_begin(c2),
+ container_algorithm_internal::c_end(c2), output);
+}
+
+// Overload of c_set_intersection() for performing a merge using a `comp` other
+// than `operator<`.
+template <typename C1, typename C2, typename OutputIterator, typename Compare>
+OutputIterator c_set_intersection(const C1& c1, const C2& c2,
+ OutputIterator output, Compare&& comp) {
+ return std::set_intersection(container_algorithm_internal::c_begin(c1),
+ container_algorithm_internal::c_end(c1),
+ container_algorithm_internal::c_begin(c2),
+ container_algorithm_internal::c_end(c2), output,
+ std::forward<Compare>(comp));
+}
+
+// c_set_difference()
+//
+// Container-based version of the <algorithm> `std::set_difference()` function
+// to return an iterator containing elements present in the first container but
+// not in the second.
+template <typename C1, typename C2, typename OutputIterator>
+OutputIterator c_set_difference(const C1& c1, const C2& c2,
+ OutputIterator output) {
+ return std::set_difference(container_algorithm_internal::c_begin(c1),
+ container_algorithm_internal::c_end(c1),
+ container_algorithm_internal::c_begin(c2),
+ container_algorithm_internal::c_end(c2), output);
+}
+
+// Overload of c_set_difference() for performing a merge using a `comp` other
+// than `operator<`.
+template <typename C1, typename C2, typename OutputIterator, typename Compare>
+OutputIterator c_set_difference(const C1& c1, const C2& c2,
+ OutputIterator output, Compare&& comp) {
+ return std::set_difference(container_algorithm_internal::c_begin(c1),
+ container_algorithm_internal::c_end(c1),
+ container_algorithm_internal::c_begin(c2),
+ container_algorithm_internal::c_end(c2), output,
+ std::forward<Compare>(comp));
+}
+
+// c_set_symmetric_difference()
+//
+// Container-based version of the <algorithm> `std::set_symmetric_difference()`
+// function to return an iterator containing elements present in either one
+// container or the other, but not both.
+template <typename C1, typename C2, typename OutputIterator>
+OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2,
+ OutputIterator output) {
+ return std::set_symmetric_difference(
+ container_algorithm_internal::c_begin(c1),
+ container_algorithm_internal::c_end(c1),
+ container_algorithm_internal::c_begin(c2),
+ container_algorithm_internal::c_end(c2), output);
+}
+
+// Overload of c_set_symmetric_difference() for performing a merge using a
+// `comp` other than `operator<`.
+template <typename C1, typename C2, typename OutputIterator, typename Compare>
+OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2,
+ OutputIterator output,
+ Compare&& comp) {
+ return std::set_symmetric_difference(
+ container_algorithm_internal::c_begin(c1),
+ container_algorithm_internal::c_end(c1),
+ container_algorithm_internal::c_begin(c2),
+ container_algorithm_internal::c_end(c2), output,
+ std::forward<Compare>(comp));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Heap functions
+//------------------------------------------------------------------------------
+
+// c_push_heap()
+//
+// Container-based version of the <algorithm> `std::push_heap()` function
+// to push a value onto a container heap.
+template <typename RandomAccessContainer>
+void c_push_heap(RandomAccessContainer& sequence) {
+ std::push_heap(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_push_heap() for performing a push operation on a heap using a
+// `comp` other than `operator<`.
+template <typename RandomAccessContainer, typename Compare>
+void c_push_heap(RandomAccessContainer& sequence, Compare&& comp) {
+ std::push_heap(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ std::forward<Compare>(comp));
+}
+
+// c_pop_heap()
+//
+// Container-based version of the <algorithm> `std::pop_heap()` function
+// to pop a value from a heap container.
+template <typename RandomAccessContainer>
+void c_pop_heap(RandomAccessContainer& sequence) {
+ std::pop_heap(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_pop_heap() for performing a pop operation on a heap using a
+// `comp` other than `operator<`.
+template <typename RandomAccessContainer, typename Compare>
+void c_pop_heap(RandomAccessContainer& sequence, Compare&& comp) {
+ std::pop_heap(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ std::forward<Compare>(comp));
+}
+
+// c_make_heap()
+//
+// Container-based version of the <algorithm> `std::make_heap()` function
+// to make a container a heap.
+template <typename RandomAccessContainer>
+void c_make_heap(RandomAccessContainer& sequence) {
+ std::make_heap(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_make_heap() for performing heap comparisons using a
+// `comp` other than `operator<`
+template <typename RandomAccessContainer, typename Compare>
+void c_make_heap(RandomAccessContainer& sequence, Compare&& comp) {
+ std::make_heap(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ std::forward<Compare>(comp));
+}
+
+// c_sort_heap()
+//
+// Container-based version of the <algorithm> `std::sort_heap()` function
+// to sort a heap into ascending order (after which it is no longer a heap).
+template <typename RandomAccessContainer>
+void c_sort_heap(RandomAccessContainer& sequence) {
+ std::sort_heap(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_sort_heap() for performing heap comparisons using a
+// `comp` other than `operator<`
+template <typename RandomAccessContainer, typename Compare>
+void c_sort_heap(RandomAccessContainer& sequence, Compare&& comp) {
+ std::sort_heap(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ std::forward<Compare>(comp));
+}
+
+// c_is_heap()
+//
+// Container-based version of the <algorithm> `std::is_heap()` function
+// to check whether the given container is a heap.
+template <typename RandomAccessContainer>
+bool c_is_heap(const RandomAccessContainer& sequence) {
+ return std::is_heap(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_is_heap() for performing heap comparisons using a
+// `comp` other than `operator<`
+template <typename RandomAccessContainer, typename Compare>
+bool c_is_heap(const RandomAccessContainer& sequence, Compare&& comp) {
+ return std::is_heap(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ std::forward<Compare>(comp));
+}
+
+// c_is_heap_until()
+//
+// Container-based version of the <algorithm> `std::is_heap_until()` function
+// to find the first element in a given container which is not in heap order.
+template <typename RandomAccessContainer>
+container_algorithm_internal::ContainerIter<RandomAccessContainer>
+c_is_heap_until(RandomAccessContainer& sequence) {
+ return std::is_heap_until(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_is_heap_until() for performing heap comparisons using a
+// `comp` other than `operator<`
+template <typename RandomAccessContainer, typename Compare>
+container_algorithm_internal::ContainerIter<RandomAccessContainer>
+c_is_heap_until(RandomAccessContainer& sequence, Compare&& comp) {
+ return std::is_heap_until(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ std::forward<Compare>(comp));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Min/max
+//------------------------------------------------------------------------------
+
+// c_min_element()
+//
+// Container-based version of the <algorithm> `std::min_element()` function
+// to return an iterator pointing to the element with the smallest value, using
+// `operator<` to make the comparisons.
+template <typename Sequence>
+container_algorithm_internal::ContainerIter<Sequence> c_min_element(
+ Sequence& sequence) {
+ return std::min_element(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_min_element() for performing a `comp` comparison other than
+// `operator<`.
+template <typename Sequence, typename Compare>
+container_algorithm_internal::ContainerIter<Sequence> c_min_element(
+ Sequence& sequence, Compare&& comp) {
+ return std::min_element(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ std::forward<Compare>(comp));
+}
+
+// c_max_element()
+//
+// Container-based version of the <algorithm> `std::max_element()` function
+// to return an iterator pointing to the element with the largest value, using
+// `operator<` to make the comparisons.
+template <typename Sequence>
+container_algorithm_internal::ContainerIter<Sequence> c_max_element(
+ Sequence& sequence) {
+ return std::max_element(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_max_element() for performing a `comp` comparison other than
+// `operator<`.
+template <typename Sequence, typename Compare>
+container_algorithm_internal::ContainerIter<Sequence> c_max_element(
+ Sequence& sequence, Compare&& comp) {
+ return std::max_element(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ std::forward<Compare>(comp));
+}
+
+// c_minmax_element()
+//
+// Container-based version of the <algorithm> `std::minmax_element()` function
+// to return a pair of iterators pointing to the elements containing the
+// smallest and largest values, respectively, using `operator<` to make the
+// comparisons.
+template <typename C>
+std::pair<container_algorithm_internal::ContainerIter<C>,
+ container_algorithm_internal::ContainerIter<C>>
+c_minmax_element(C& c) {
+ return std::minmax_element(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c));
+}
+
+// Overload of c_minmax_element() for performing `comp` comparisons other than
+// `operator<`.
+template <typename C, typename Compare>
+std::pair<container_algorithm_internal::ContainerIter<C>,
+ container_algorithm_internal::ContainerIter<C>>
+c_minmax_element(C& c, Compare&& comp) {
+ return std::minmax_element(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<Compare>(comp));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Lexicographical Comparisons
+//------------------------------------------------------------------------------
+
+// c_lexicographical_compare()
+//
+// Container-based version of the <algorithm> `std::lexicographical_compare()`
+// function to lexicographically compare (e.g. sort words alphabetically) two
+// container sequences. The comparison is performed using `operator<`. Note
+// that capital letters ("A-Z") have ASCII values less than lowercase letters
+// ("a-z").
+template <typename Sequence1, typename Sequence2>
+bool c_lexicographical_compare(Sequence1&& sequence1, Sequence2&& sequence2) {
+ return std::lexicographical_compare(
+ container_algorithm_internal::c_begin(sequence1),
+ container_algorithm_internal::c_end(sequence1),
+ container_algorithm_internal::c_begin(sequence2),
+ container_algorithm_internal::c_end(sequence2));
+}
+
+// Overload of c_lexicographical_compare() for performing a lexicographical
+// comparison using a `comp` operator instead of `operator<`.
+template <typename Sequence1, typename Sequence2, typename Compare>
+bool c_lexicographical_compare(Sequence1&& sequence1, Sequence2&& sequence2,
+ Compare&& comp) {
+ return std::lexicographical_compare(
+ container_algorithm_internal::c_begin(sequence1),
+ container_algorithm_internal::c_end(sequence1),
+ container_algorithm_internal::c_begin(sequence2),
+ container_algorithm_internal::c_end(sequence2),
+ std::forward<Compare>(comp));
+}
+
+// c_next_permutation()
+//
+// Container-based version of the <algorithm> `std::next_permutation()` function
+// to rearrange a container's elements into the next lexicographically greater
+// permutation.
+template <typename C>
+bool c_next_permutation(C& c) {
+ return std::next_permutation(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c));
+}
+
+// Overload of c_next_permutation() for performing a lexicographical
+// comparison using a `comp` operator instead of `operator<`.
+template <typename C, typename Compare>
+bool c_next_permutation(C& c, Compare&& comp) {
+ return std::next_permutation(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<Compare>(comp));
+}
+
+// c_prev_permutation()
+//
+// Container-based version of the <algorithm> `std::prev_permutation()` function
+// to rearrange a container's elements into the next lexicographically lesser
+// permutation.
+template <typename C>
+bool c_prev_permutation(C& c) {
+ return std::prev_permutation(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c));
+}
+
+// Overload of c_prev_permutation() for performing a lexicographical
+// comparison using a `comp` operator instead of `operator<`.
+template <typename C, typename Compare>
+bool c_prev_permutation(C& c, Compare&& comp) {
+ return std::prev_permutation(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<Compare>(comp));
+}
+
+//------------------------------------------------------------------------------
+// <numeric> algorithms
+//------------------------------------------------------------------------------
+
+// c_iota()
+//
+// Container-based version of the <algorithm> `std::iota()` function
+// to compute successive values of `value`, as if incremented with `++value`
+// after each element is written. and write them to the container.
+template <typename Sequence, typename T>
+void c_iota(Sequence& sequence, T&& value) {
+ std::iota(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ std::forward<T>(value));
+}
+// c_accumulate()
+//
+// Container-based version of the <algorithm> `std::accumulate()` function
+// to accumulate the element values of a container to `init` and return that
+// accumulation by value.
+//
+// Note: Due to a language technicality this function has return type
+// absl::decay_t<T>. As a user of this function you can casually read
+// this as "returns T by value" and assume it does the right thing.
+template <typename Sequence, typename T>
+decay_t<T> c_accumulate(const Sequence& sequence, T&& init) {
+ return std::accumulate(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ std::forward<T>(init));
+}
+
+// Overload of c_accumulate() for using a binary operations other than
+// addition for computing the accumulation.
+template <typename Sequence, typename T, typename BinaryOp>
+decay_t<T> c_accumulate(const Sequence& sequence, T&& init,
+ BinaryOp&& binary_op) {
+ return std::accumulate(container_algorithm_internal::c_begin(sequence),
+ container_algorithm_internal::c_end(sequence),
+ std::forward<T>(init),
+ std::forward<BinaryOp>(binary_op));
+}
+
+// c_inner_product()
+//
+// Container-based version of the <algorithm> `std::inner_product()` function
+// to compute the cumulative inner product of container element pairs.
+//
+// Note: Due to a language technicality this function has return type
+// absl::decay_t<T>. As a user of this function you can casually read
+// this as "returns T by value" and assume it does the right thing.
+template <typename Sequence1, typename Sequence2, typename T>
+decay_t<T> c_inner_product(const Sequence1& factors1, const Sequence2& factors2,
+ T&& sum) {
+ return std::inner_product(container_algorithm_internal::c_begin(factors1),
+ container_algorithm_internal::c_end(factors1),
+ container_algorithm_internal::c_begin(factors2),
+ std::forward<T>(sum));
+}
+
+// Overload of c_inner_product() for using binary operations other than
+// `operator+` (for computing the accumlation) and `operator*` (for computing
+// the product between the two container's element pair).
+template <typename Sequence1, typename Sequence2, typename T,
+ typename BinaryOp1, typename BinaryOp2>
+decay_t<T> c_inner_product(const Sequence1& factors1, const Sequence2& factors2,
+ T&& sum, BinaryOp1&& op1, BinaryOp2&& op2) {
+ return std::inner_product(container_algorithm_internal::c_begin(factors1),
+ container_algorithm_internal::c_end(factors1),
+ container_algorithm_internal::c_begin(factors2),
+ std::forward<T>(sum), std::forward<BinaryOp1>(op1),
+ std::forward<BinaryOp2>(op2));
+}
+
+// c_adjacent_difference()
+//
+// Container-based version of the <algorithm> `std::adjacent_difference()`
+// function to compute the difference between each element and the one preceding
+// it and write it to an iterator.
+template <typename InputSequence, typename OutputIt>
+OutputIt c_adjacent_difference(const InputSequence& input,
+ OutputIt output_first) {
+ return std::adjacent_difference(container_algorithm_internal::c_begin(input),
+ container_algorithm_internal::c_end(input),
+ output_first);
+}
+
+// Overload of c_adjacent_difference() for using a binary operation other than
+// subtraction to compute the adjacent difference.
+template <typename InputSequence, typename OutputIt, typename BinaryOp>
+OutputIt c_adjacent_difference(const InputSequence& input,
+ OutputIt output_first, BinaryOp&& op) {
+ return std::adjacent_difference(container_algorithm_internal::c_begin(input),
+ container_algorithm_internal::c_end(input),
+ output_first, std::forward<BinaryOp>(op));
+}
+
+// c_partial_sum()
+//
+// Container-based version of the <algorithm> `std::partial_sum()` function
+// to compute the partial sum of the elements in a sequence and write them
+// to an iterator. The partial sum is the sum of all element values so far in
+// the sequence.
+template <typename InputSequence, typename OutputIt>
+OutputIt c_partial_sum(const InputSequence& input, OutputIt output_first) {
+ return std::partial_sum(container_algorithm_internal::c_begin(input),
+ container_algorithm_internal::c_end(input),
+ output_first);
+}
+
+// Overload of c_partial_sum() for using a binary operation other than addition
+// to compute the "partial sum".
+template <typename InputSequence, typename OutputIt, typename BinaryOp>
+OutputIt c_partial_sum(const InputSequence& input, OutputIt output_first,
+ BinaryOp&& op) {
+ return std::partial_sum(container_algorithm_internal::c_begin(input),
+ container_algorithm_internal::c_end(input),
+ output_first, std::forward<BinaryOp>(op));
+}
+
+} // namespace absl
+
+#endif // ABSL_ALGORITHM_CONTAINER_H_
diff --git a/absl/algorithm/container_test.cc b/absl/algorithm/container_test.cc
new file mode 100644
index 0000000..093b281
--- /dev/null
+++ b/absl/algorithm/container_test.cc
@@ -0,0 +1,1010 @@
+// 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, MoveBackward) {
+ std::vector<std::unique_ptr<int>> actual;
+ actual.emplace_back(absl::make_unique<int>(1));
+ actual.emplace_back(absl::make_unique<int>(2));
+ actual.emplace_back(absl::make_unique<int>(3));
+ actual.emplace_back(absl::make_unique<int>(4));
+ actual.emplace_back(absl::make_unique<int>(5));
+ auto subrange = absl::MakeSpan(actual.data(), 3);
+ absl::c_move_backward(subrange, actual.end());
+ EXPECT_THAT(actual, ElementsAre(IsNull(), IsNull(), Pointee(1), Pointee(2),
+ Pointee(3)));
+}
+
+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
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
new file mode 100644
index 0000000..87a6d3e
--- /dev/null
+++ b/absl/base/BUILD.bazel
@@ -0,0 +1,369 @@
+#
+# 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",
+)
+load(
+ "//absl:test_dependencies.bzl",
+ "GUNIT_MAIN_DEPS_SELECTOR",
+ "GUNIT_MAIN_NO_LEAK_CHECK_DEPS_SELECTOR",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"]) # Apache 2.0
+
+# Some header files in //base are directly exported for unusual use cases,
+# and the ABSL versions must also be exported for those users.
+
+exports_files(["thread_annotations.h"])
+
+cc_library(
+ name = "spinlock_wait",
+ srcs = [
+ "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,
+ 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_extension",
+ srcs = ["internal/malloc_extension.cc"],
+ hdrs = [
+ "internal/malloc_extension.h",
+ "internal/malloc_extension_c.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ ":core_headers",
+ ":dynamic_annotations",
+ ],
+)
+
+# malloc_extension feels like it wants to be folded into this target, but
+# malloc_internal gets special build treatment to compile at -O3, so these
+# need to stay separate.
+cc_library(
+ name = "malloc_internal",
+ srcs = [
+ "internal/low_level_alloc.cc",
+ "internal/malloc_hook.cc",
+ "internal/malloc_hook_mmap_linux.inc",
+ ],
+ hdrs = [
+ "internal/low_level_alloc.h",
+ "internal/malloc_hook.h",
+ "internal/malloc_hook_c.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ textual_hdrs = [
+ "internal/malloc_hook_invoke.h",
+ ],
+ deps = [
+ ":base",
+ ":config",
+ ":core_headers",
+ ":dynamic_annotations",
+ ],
+)
+
+cc_library(
+ name = "base_internal",
+ hdrs = [
+ "internal/identity.h",
+ "internal/invoke.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+)
+
+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/log_severity.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",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ ":base_internal",
+ ":config",
+ ":core_headers",
+ ":dynamic_annotations",
+ ":spinlock_wait",
+ ],
+)
+
+cc_test(
+ name = "bit_cast_test",
+ size = "small",
+ srcs = [
+ "bit_cast_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":base",
+ ":core_headers",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_library(
+ name = "throw_delegate",
+ srcs = ["internal/throw_delegate.cc"],
+ hdrs = ["internal/throw_delegate.h"],
+ copts = ABSL_DEFAULT_COPTS + ABSL_EXCEPTIONS_FLAG,
+ features = [
+ "-use_header_modules", # b/33207452
+ ],
+ deps = [
+ ":base",
+ ":config",
+ ],
+)
+
+cc_test(
+ name = "throw_delegate_test",
+ srcs = ["throw_delegate_test.cc"],
+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+ deps = [
+ ":throw_delegate",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_library(
+ name = "exception_testing",
+ testonly = 1,
+ hdrs = ["internal/exception_testing.h"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":config",
+ "@com_google_googletest//:gtest",
+ ],
+)
+
+cc_test(
+ name = "invoke_test",
+ size = "small",
+ srcs = ["invoke_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":base_internal",
+ "//absl/strings",
+ "//absl/memory",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+# 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",
+ "//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",
+ "//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",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "config_test",
+ srcs = ["config_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":config",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "call_once_test",
+ srcs = ["call_once_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":base",
+ ":core_headers",
+ "//absl/synchronization",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+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",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+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",
+ "//absl/synchronization",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "malloc_extension_system_malloc_test",
+ size = "small",
+ srcs = ["internal/malloc_extension_test.cc"],
+ copts = select({
+ "//absl:windows": [
+ "/DABSL_MALLOC_EXTENSION_TEST_ALLOW_MISSING_EXTENSION=1",
+ ],
+ "//conditions:default": [
+ "-DABSL_MALLOC_EXTENSION_TEST_ALLOW_MISSING_EXTENSION=1",
+ ],
+ }) + ABSL_TEST_COPTS,
+ features = [
+ # This test can't be run under lsan because the test requires system
+ # malloc, and lsan provides a competing malloc implementation.
+ "-leak_sanitize",
+ ],
+ deps = [
+ ":malloc_extension",
+ ] + select(GUNIT_MAIN_NO_LEAK_CHECK_DEPS_SELECTOR),
+)
diff --git a/absl/base/attributes.h b/absl/base/attributes.h
new file mode 100644
index 0000000..5eecdab
--- /dev/null
+++ b/absl/base/attributes.h
@@ -0,0 +1,469 @@
+// 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.
+//
+// Various macros for C++ attributes
+// 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).
+//
+// For sanitizer-related attributes, define the following macros
+// using -D along with the given value for -fsanitize:
+// - ADDRESS_SANITIZER with -fsanitize=address (GCC 4.8+, Clang)
+// - MEMORY_SANITIZER with -fsanitize=memory (Clang)
+// - THREAD_SANITIZER with -fsanitize=thread (GCC 4.8+, Clang)
+// - UNDEFINED_BEHAVIOR_SANITIZER with -fsanitize=undefined (GCC 4.9+, Clang)
+// - CONTROL_FLOW_INTEGRITY with -fsanitize=cfi (Clang)
+// Since these are only supported by GCC and Clang now, 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 is a function-like feature checking macro.
+// It's a wrapper around __has_attribute, which is defined by GCC 5+ and Clang.
+// It 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 is 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
+// Tell the compiler to do 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>.
+//
+// N.B.: 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
+// For functions we want to force 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
+// Prevent 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
+// For weak functions
+#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
+// Tell the compiler either that a particular function parameter
+// should be a non-null pointer, or 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.
+//
+// /* 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
+// Tell 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
+// Tell 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
+// Tell 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 is similar to the ADDRESS_SANITIZER attribute above, but deals with
+// initializedness 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
+// Tell ThreadSanitizer to not instrument a given function.
+// If you are adding this attribute, please cc dynamic-tools@ on the cl.
+// 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
+// Tell UndefinedSanitizer to ignore a given function. Useful for cases
+// where certain behavior (eg. devision 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
+// Tell 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_SECTION
+// 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
+//
+// Tell 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 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
+// Tell 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
+//
+// 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
+
+// Return 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
+// Tell 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:
+//
+// 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
+// Tell 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, e.g.:
+// 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
+// Prevent 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
+// Tell 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
+// Prevent 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_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".
+//
+// Sample usage:
+//
+// ABSL_CONST_INIT static MyType 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) (b/36288871)
+#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_
diff --git a/absl/base/bit_cast_test.cc b/absl/base/bit_cast_test.cc
new file mode 100644
index 0000000..8cd878d
--- /dev/null
+++ b/absl/base/bit_cast_test.cc
@@ -0,0 +1,107 @@
+// 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
diff --git a/absl/base/call_once.h b/absl/base/call_once.h
new file mode 100644
index 0000000..478a41c
--- /dev/null
+++ b/absl/base/call_once.h
@@ -0,0 +1,210 @@
+// 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 <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/spinlock_wait.h"
+
+namespace absl {
+
+class once_flag;
+
+namespace base_internal {
+// Implementation detail.
+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,
+ kOnceDone = 0x3F2D8AB0,
+};
+
+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: %d. Either the control word "
+ "has non-static storage duration (where GoogleOnceDynamic might "
+ "be appropriate), or there's been a memory corruption.",
+ old_control);
+ }
+ }
+#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_
diff --git a/absl/base/call_once_test.cc b/absl/base/call_once_test.cc
new file mode 100644
index 0000000..de23543
--- /dev/null
+++ b/absl/base/call_once_test.cc
@@ -0,0 +1,102 @@
+// 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 <atomic>
+#include <thread>
+
+#include "absl/base/thread_annotations.h"
+#include "absl/synchronization/mutex.h"
+#include "gtest/gtest.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
diff --git a/absl/base/casts.h b/absl/base/casts.h
new file mode 100644
index 0000000..2a0adc2
--- /dev/null
+++ b/absl/base/casts.h
@@ -0,0 +1,141 @@
+//
+// 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 `implict_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 is 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 implementating 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_
diff --git a/absl/base/config.h b/absl/base/config.h
new file mode 100644
index 0000000..cf47f84
--- /dev/null
+++ b/absl/base/config.h
@@ -0,0 +1,367 @@
+//
+// 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
+
+#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
+
+// 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.
+#if defined(__ANDROID__) && defined(__clang__)
+#if __has_include(<android/ndk-version.h>)
+#include <android/ndk-version.h>
+#endif
+// 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(__NDK_MAJOR__) && defined(__NDK_MINOR__) && \
+ ((__NDK_MAJOR__ < 12) || ((__NDK_MAJOR__ == 12) && (__NDK_MINOR__ < 1)))
+#undef ABSL_HAVE_TLS
+#endif
+#endif // defined(__ANDROID__) && defined(__clang__)
+
+// 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.
+//
+// Notes: Clang implements the `thread_local` keyword but Xcode did not support
+// the implementation until Xcode 8.
+#ifdef ABSL_HAVE_THREAD_LOCAL
+#error ABSL_HAVE_THREAD_LOCAL cannot be directly set
+#elif !defined(__apple_build_version__) || __apple_build_version__ >= 8000042
+#define ABSL_HAVE_THREAD_LOCAL 1
+#endif
+
+// ABSL_HAVE_INTRINSIC_INT128
+//
+// Checks whether the __int128 compiler extension for a 128-bit integral type is
+// supported.
+//
+// Notes: __SIZEOF_INT128__ is defined by Clang and GCC when __int128 is
+// supported, except on ppc64 and aarch64 where __int128 exists but has exhibits
+// a sporadic compiler crashing bug. Nvidia's 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(__clang__) && defined(__SIZEOF_INT128__) && \
+ !defined(__ppc64__) && !defined(__aarch64__)) || \
+ (defined(__CUDACC__) && defined(__SIZEOF_INT128__) && \
+ __CUDACC_VER__ >= 70000) || \
+ (!defined(__clang__) && !defined(__CUDACC__) && defined(__GNUC__) && \
+ defined(__SIZEOF_INT128__))
+#define ABSL_HAVE_INTRINSIC_INT128 1
+#endif
+
+// 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__
+// Fuschia __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(__ros__) || \
+ defined(__native_client__) || defined(__asmjs__) || 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(__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
+// explicity 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 availble 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_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
+
+#endif // ABSL_BASE_CONFIG_H_
diff --git a/absl/base/config_test.cc b/absl/base/config_test.cc
new file mode 100644
index 0000000..578bb81
--- /dev/null
+++ b/absl/base/config_test.cc
@@ -0,0 +1,45 @@
+// 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 "gmock/gmock.h"
+#include "gtest/gtest.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
+}
+
+} // namespace
diff --git a/absl/base/dynamic_annotations.cc b/absl/base/dynamic_annotations.cc
new file mode 100644
index 0000000..08c27e5
--- /dev/null
+++ b/absl/base/dynamic_annotations.cc
@@ -0,0 +1,129 @@
+// 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
+ DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL = 1
+ and provides its own definitions of the functions. */
+
+#ifndef DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL
+# define 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 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 AnnotateRWLockCreate(const char *, int,
+ const volatile void *){}
+void AnnotateRWLockDestroy(const char *, int,
+ const volatile void *){}
+void AnnotateRWLockAcquired(const char *, int,
+ const volatile void *, long){}
+void AnnotateRWLockReleased(const char *, int,
+ const volatile void *, long){}
+void AnnotateBenignRace(const char *, int,
+ const volatile void *,
+ const char *){}
+void AnnotateBenignRaceSized(const char *, int,
+ const volatile void *,
+ size_t,
+ const char *) {}
+void AnnotateThreadName(const char *, int,
+ const char *){}
+void AnnotateIgnoreReadsBegin(const char *, int){}
+void AnnotateIgnoreReadsEnd(const char *, int){}
+void AnnotateIgnoreWritesBegin(const char *, int){}
+void AnnotateIgnoreWritesEnd(const char *, int){}
+void AnnotateEnableRaceDetection(const char *, int, int){}
+void AnnotateMemoryIsInitialized(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 AnnotateMemoryIsUninitialized(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 GetRunningOnValgrind(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 RunningOnValgrind(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. */
+ ANNOTATE_BENIGN_RACE(&running_on_valgrind, "safe hack");
+ if (local_running_on_valgrind == -1)
+ running_on_valgrind = local_running_on_valgrind = GetRunningOnValgrind();
+ return local_running_on_valgrind;
+}
+
+/* See the comments in dynamic_annotations.h */
+double ValgrindSlowdown(void) {
+ /* Same initialization hack as in RunningOnValgrind(). */
+ static volatile double slowdown = 0.0;
+ double local_slowdown = slowdown;
+ ANNOTATE_BENIGN_RACE(&slowdown, "safe hack");
+ if (RunningOnValgrind() == 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 /* DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 */
diff --git a/absl/base/dynamic_annotations.h b/absl/base/dynamic_annotations.h
new file mode 100644
index 0000000..b9c015b
--- /dev/null
+++ b/absl/base/dynamic_annotations.h
@@ -0,0 +1,409 @@
+/*
+ * 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., 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 DYNAMIC_ANNOTATIONS_ENABLED
+# define DYNAMIC_ANNOTATIONS_ENABLED 0
+#endif
+
+#if defined(__native_client__)
+ #include "nacl/dynamic_annotations.h"
+
+ // Stub out the macros missing from the NaCl version.
+ #ifndef ANNOTATE_CONTIGUOUS_CONTAINER
+ #define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid)
+ #endif
+ #ifndef ANNOTATE_RWLOCK_CREATE_STATIC
+ #define ANNOTATE_RWLOCK_CREATE_STATIC(lock)
+ #endif
+ #ifndef ADDRESS_SANITIZER_REDZONE
+ #define ADDRESS_SANITIZER_REDZONE(name)
+ #endif
+ #ifndef ANNOTATE_MEMORY_IS_UNINITIALIZED
+ #define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size)
+ #endif
+
+#else /* !__native_client__ */
+
+#if 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 ANNOTATE_BENIGN_RACE_STATIC. */
+ #define ANNOTATE_BENIGN_RACE(pointer, description) \
+ AnnotateBenignRaceSized(__FILE__, __LINE__, pointer, \
+ sizeof(*(pointer)), description)
+
+ /* Same as ANNOTATE_BENIGN_RACE(address, description), but applies to
+ the memory range [address, address+size). */
+ #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
+ AnnotateBenignRaceSized(__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 ANNOTATE_ENABLE_RACE_DETECTION(enable) \
+ AnnotateEnableRaceDetection(__FILE__, __LINE__, enable)
+
+ /* -------------------------------------------------------------
+ Annotations useful for debugging. */
+
+ /* Report the current thread name to a race detector. */
+ #define ANNOTATE_THREAD_NAME(name) \
+ AnnotateThreadName(__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 ANNOTATE_RWLOCK_CREATE(lock) \
+ AnnotateRWLockCreate(__FILE__, __LINE__, lock)
+
+ /* Report that a linker initialized lock has been created at address "lock".
+ */
+#ifdef THREAD_SANITIZER
+ #define ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
+ AnnotateRWLockCreateStatic(__FILE__, __LINE__, lock)
+#else
+ #define ANNOTATE_RWLOCK_CREATE_STATIC(lock) ANNOTATE_RWLOCK_CREATE(lock)
+#endif
+
+ /* Report that the lock at address "lock" is about to be destroyed. */
+ #define ANNOTATE_RWLOCK_DESTROY(lock) \
+ AnnotateRWLockDestroy(__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 ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \
+ AnnotateRWLockAcquired(__FILE__, __LINE__, lock, is_w)
+
+ /* Report that the lock at address "lock" is about to be released. */
+ #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
+ AnnotateRWLockReleased(__FILE__, __LINE__, lock, is_w)
+
+#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */
+
+ #define ANNOTATE_RWLOCK_CREATE(lock) /* empty */
+ #define ANNOTATE_RWLOCK_CREATE_STATIC(lock) /* empty */
+ #define ANNOTATE_RWLOCK_DESTROY(lock) /* empty */
+ #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) /* empty */
+ #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) /* empty */
+ #define ANNOTATE_BENIGN_RACE(address, description) /* empty */
+ #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */
+ #define ANNOTATE_THREAD_NAME(name) /* empty */
+ #define ANNOTATE_ENABLE_RACE_DETECTION(enable) /* empty */
+
+#endif /* DYNAMIC_ANNOTATIONS_ENABLED */
+
+/* These annotations are also made available to LLVM's Memory Sanitizer */
+#if DYNAMIC_ANNOTATIONS_ENABLED == 1 || defined(MEMORY_SANITIZER)
+ #define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
+ AnnotateMemoryIsInitialized(__FILE__, __LINE__, address, size)
+
+ #define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
+ AnnotateMemoryIsUninitialized(__FILE__, __LINE__, address, size)
+#else
+ #define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) /* empty */
+ #define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) /* empty */
+#endif /* 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 DYNAMIC_ANNOTATIONS_ENABLED == 0
+ #define 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 ATTRIBUTE_IGNORE_READS_BEGIN \
+ __attribute((exclusive_lock_function("*")))
+ #define ATTRIBUTE_IGNORE_READS_END \
+ __attribute((unlock_function("*")))
+#else
+ #define ATTRIBUTE_IGNORE_READS_BEGIN /* empty */
+ #define ATTRIBUTE_IGNORE_READS_END /* empty */
+#endif /* defined(__clang__) && ... */
+
+#if (DYNAMIC_ANNOTATIONS_ENABLED != 0) || defined(ANNOTALYSIS_ENABLED)
+ #define ANNOTATIONS_ENABLED
+#endif
+
+#if (DYNAMIC_ANNOTATIONS_ENABLED != 0)
+
+ /* Request the analysis tool to ignore all reads in the current thread
+ until ANNOTATE_IGNORE_READS_END is called.
+ Useful to ignore intentional racey reads, while still checking
+ other reads and all writes.
+ See also ANNOTATE_UNPROTECTED_READ. */
+ #define ANNOTATE_IGNORE_READS_BEGIN() \
+ AnnotateIgnoreReadsBegin(__FILE__, __LINE__)
+
+ /* Stop ignoring reads. */
+ #define ANNOTATE_IGNORE_READS_END() \
+ AnnotateIgnoreReadsEnd(__FILE__, __LINE__)
+
+ /* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead. */
+ #define ANNOTATE_IGNORE_WRITES_BEGIN() \
+ AnnotateIgnoreWritesBegin(__FILE__, __LINE__)
+
+ /* Stop ignoring writes. */
+ #define ANNOTATE_IGNORE_WRITES_END() \
+ AnnotateIgnoreWritesEnd(__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(ANNOTALYSIS_ENABLED)
+
+ #define ANNOTATE_IGNORE_READS_BEGIN() \
+ StaticAnnotateIgnoreReadsBegin(__FILE__, __LINE__)
+
+ #define ANNOTATE_IGNORE_READS_END() \
+ StaticAnnotateIgnoreReadsEnd(__FILE__, __LINE__)
+
+ #define ANNOTATE_IGNORE_WRITES_BEGIN() \
+ StaticAnnotateIgnoreWritesBegin(__FILE__, __LINE__)
+
+ #define ANNOTATE_IGNORE_WRITES_END() \
+ StaticAnnotateIgnoreWritesEnd(__FILE__, __LINE__)
+
+#else
+ #define ANNOTATE_IGNORE_READS_BEGIN() /* empty */
+ #define ANNOTATE_IGNORE_READS_END() /* empty */
+ #define ANNOTATE_IGNORE_WRITES_BEGIN() /* empty */
+ #define ANNOTATE_IGNORE_WRITES_END() /* empty */
+#endif
+
+/* Implement the ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more
+ primitive annotations defined above. */
+#if defined(ANNOTATIONS_ENABLED)
+
+ /* Start ignoring all memory accesses (both reads and writes). */
+ #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
+ do { \
+ ANNOTATE_IGNORE_READS_BEGIN(); \
+ ANNOTATE_IGNORE_WRITES_BEGIN(); \
+ }while (0)
+
+ /* Stop ignoring both reads and writes. */
+ #define ANNOTATE_IGNORE_READS_AND_WRITES_END() \
+ do { \
+ ANNOTATE_IGNORE_WRITES_END(); \
+ ANNOTATE_IGNORE_READS_END(); \
+ }while (0)
+
+#else
+ #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() /* empty */
+ #define 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 AnnotateRWLockCreate(const char *file, int line,
+ const volatile void *lock);
+void AnnotateRWLockCreateStatic(const char *file, int line,
+ const volatile void *lock);
+void AnnotateRWLockDestroy(const char *file, int line,
+ const volatile void *lock);
+void AnnotateRWLockAcquired(const char *file, int line,
+ const volatile void *lock, long is_w); /* NOLINT */
+void AnnotateRWLockReleased(const char *file, int line,
+ const volatile void *lock, long is_w); /* NOLINT */
+void AnnotateBenignRace(const char *file, int line,
+ const volatile void *address,
+ const char *description);
+void AnnotateBenignRaceSized(const char *file, int line,
+ const volatile void *address,
+ size_t size,
+ const char *description);
+void AnnotateThreadName(const char *file, int line,
+ const char *name);
+void AnnotateEnableRaceDetection(const char *file, int line, int enable);
+void AnnotateMemoryIsInitialized(const char *file, int line,
+ const volatile void *mem, size_t size);
+void AnnotateMemoryIsUninitialized(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 AnnotateIgnoreReadsBegin(const char *file, int line)
+ ATTRIBUTE_IGNORE_READS_BEGIN;
+void AnnotateIgnoreReadsEnd(const char *file, int line)
+ ATTRIBUTE_IGNORE_READS_END;
+void AnnotateIgnoreWritesBegin(const char *file, int line);
+void AnnotateIgnoreWritesEnd(const char *file, int line);
+
+#if defined(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 INGORE_READS_AND_WRITES to work properly. */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+static inline void StaticAnnotateIgnoreReadsBegin(const char *file, int line)
+ ATTRIBUTE_IGNORE_READS_BEGIN { (void)file; (void)line; }
+static inline void StaticAnnotateIgnoreReadsEnd(const char *file, int line)
+ ATTRIBUTE_IGNORE_READS_END { (void)file; (void)line; }
+static inline void StaticAnnotateIgnoreWritesBegin(
+ const char *file, int line) { (void)file; (void)line; }
+static inline void StaticAnnotateIgnoreWritesEnd(
+ 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 RunningOnValgrind() and
+ change its return value.
+ */
+int RunningOnValgrind(void);
+
+/* ValgrindSlowdown returns:
+ * 1.0, if (RunningOnValgrind() == 0)
+ * 50.0, if (RunningOnValgrind() != 0 && getenv("VALGRIND_SLOWDOWN") == NULL)
+ * atof(getenv("VALGRIND_SLOWDOWN")) otherwise
+ This function can be used to scale timeout values:
+ EXAMPLE:
+ for (;;) {
+ DoExpensiveBackgroundTask();
+ SleepForSeconds(5 * ValgrindSlowdown());
+ }
+ */
+double ValgrindSlowdown(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
+
+ Instead of doing
+ ANNOTATE_IGNORE_READS_BEGIN();
+ ... = x;
+ ANNOTATE_IGNORE_READS_END();
+ one can use
+ ... = ANNOTATE_UNPROTECTED_READ(x); */
+#if defined(__cplusplus) && defined(ANNOTATIONS_ENABLED)
+template <typename T>
+inline T ANNOTATE_UNPROTECTED_READ(const volatile T &x) { /* NOLINT */
+ ANNOTATE_IGNORE_READS_BEGIN();
+ T res = x;
+ ANNOTATE_IGNORE_READS_END();
+ return res;
+ }
+#else
+ #define ANNOTATE_UNPROTECTED_READ(x) (x)
+#endif
+
+#if DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus)
+ /* Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable. */
+ #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \
+ namespace { \
+ class static_var ## _annotator { \
+ public: \
+ static_var ## _annotator() { \
+ ANNOTATE_BENIGN_RACE_SIZED(&static_var, \
+ sizeof(static_var), \
+ # static_var ": " description); \
+ } \
+ }; \
+ static static_var ## _annotator the ## static_var ## _annotator;\
+ } // namespace
+#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */
+ #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) /* empty */
+#endif /* 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 ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \
+ __sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid)
+#define ADDRESS_SANITIZER_REDZONE(name) \
+ struct { char x[8] __attribute__ ((aligned (8))); } name
+#else
+#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid)
+#define ADDRESS_SANITIZER_REDZONE(name)
+#endif // ADDRESS_SANITIZER
+
+/* Undefine the macros intended only in this file. */
+#undef ANNOTALYSIS_ENABLED
+#undef ANNOTATIONS_ENABLED
+#undef ATTRIBUTE_IGNORE_READS_BEGIN
+#undef ATTRIBUTE_IGNORE_READS_END
+
+#endif /* !__native_client__ */
+
+#endif /* ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ */
diff --git a/absl/base/internal/atomic_hook.h b/absl/base/internal/atomic_hook.h
new file mode 100644
index 0000000..8eee367
--- /dev/null
+++ b/absl/base/internal/atomic_hook.h
@@ -0,0 +1,122 @@
+// 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 <cassert>
+#include <atomic>
+#include <utility>
+
+namespace absl {
+namespace base_internal {
+
+// In current versions of MSVC (as of July 2017), a std::atomic<T> where T is a
+// pointer to function cannot be constant-initialized with an address constant
+// expression. That is, the following code does not compile:
+// void NoOp() {}
+// constexpr std::atomic<void(*)()> ptr(NoOp);
+//
+// This is the only compiler we support that seems to have this issue. We
+// conditionalize on MSVC here to use a fallback implementation. But we
+// should revisit this occasionally. If MSVC fixes this compiler bug, we
+// can then change this to be conditionalized on the value on _MSC_FULL_VER
+// instead.
+#ifdef _MSC_FULL_VER
+#define ABSL_HAVE_FUNCTION_ADDRESS_CONSTANT_EXPRESSION 0
+#else
+#define ABSL_HAVE_FUNCTION_ADDRESS_CONSTANT_EXPRESSION 1
+#endif
+
+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, or performs a no-op (and returns a default
+// constructed object) if no hook has been registered.
+//
+// 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...);
+
+ constexpr AtomicHook() : hook_(DummyFunction) {}
+
+ // 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) {
+ assert(fn);
+ FnPtr expected = DummyFunction;
+ hook_.compare_exchange_strong(expected, fn, std::memory_order_acq_rel,
+ std::memory_order_acquire);
+ // If the compare and exchange failed, make sure that's because hook_ was
+ // already set to `fn` by an earlier call. Any other state reflects an API
+ // violation (calling Store() multiple times with different values).
+ //
+ // Avoid ABSL_RAW_CHECK, since raw logging depends on AtomicHook.
+ assert(expected == DummyFunction || expected == fn);
+ }
+
+ // 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 {
+ FnPtr hook = hook_.load(std::memory_order_acquire);
+ if (ABSL_HAVE_FUNCTION_ADDRESS_CONSTANT_EXPRESSION || hook) {
+ return hook(std::forward<CallArgs>(args)...);
+ } else {
+ return ReturnType();
+ }
+ }
+
+ // 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 = hook_.load(std::memory_order_acquire);
+ return (ptr == DummyFunction) ? nullptr : ptr;
+ }
+
+ private:
+#if ABSL_HAVE_FUNCTION_ADDRESS_CONSTANT_EXPRESSION
+ static ReturnType DummyFunction(Args...) {
+ return ReturnType();
+ }
+#else
+ static constexpr FnPtr DummyFunction = nullptr;
+#endif
+
+ std::atomic<FnPtr> hook_;
+};
+
+#undef ABSL_HAVE_FUNCTION_ADDRESS_CONSTANT_EXPRESSION
+
+} // namespace base_internal
+} // namespace absl
+
+#endif // ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
diff --git a/absl/base/internal/cycleclock.cc b/absl/base/internal/cycleclock.cc
new file mode 100644
index 0000000..a742df0
--- /dev/null
+++ b/absl/base/internal/cycleclock.cc
@@ -0,0 +1,81 @@
+// 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
diff --git a/absl/base/internal/cycleclock.h b/absl/base/internal/cycleclock.h
new file mode 100644
index 0000000..60e9715
--- /dev/null
+++ b/absl/base/internal/cycleclock.h
@@ -0,0 +1,77 @@
+//
+// 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_
diff --git a/absl/base/internal/endian.h b/absl/base/internal/endian.h
new file mode 100644
index 0000000..602129e
--- /dev/null
+++ b/absl/base/internal/endian.h
@@ -0,0 +1,267 @@
+// 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(__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_
diff --git a/absl/base/internal/endian_test.cc b/absl/base/internal/endian_test.cc
new file mode 100644
index 0000000..6812214
--- /dev/null
+++ b/absl/base/internal/endian_test.cc
@@ -0,0 +1,281 @@
+// 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 <cstdio>
+#include <limits>
+#include <random>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/casts.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
diff --git a/absl/base/internal/exception_testing.h b/absl/base/internal/exception_testing.h
new file mode 100644
index 0000000..99a1073
--- /dev/null
+++ b/absl/base/internal/exception_testing.h
@@ -0,0 +1,24 @@
+// 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)
+
+#else
+
+#define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \
+ EXPECT_DEATH(expr, text)
+
+#endif
+
+#endif // ABSL_BASE_INTERNAL_EXCEPTION_TESTING_H_
diff --git a/absl/base/internal/identity.h b/absl/base/internal/identity.h
new file mode 100644
index 0000000..a6734b4
--- /dev/null
+++ b/absl/base/internal/identity.h
@@ -0,0 +1,33 @@
+// 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_
diff --git a/absl/base/internal/invoke.h b/absl/base/internal/invoke.h
new file mode 100644
index 0000000..8c3f4f6
--- /dev/null
+++ b/absl/base/internal/invoke.h
@@ -0,0 +1,188 @@
+// 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_
diff --git a/absl/base/internal/log_severity.cc b/absl/base/internal/log_severity.cc
new file mode 100644
index 0000000..430ac45
--- /dev/null
+++ b/absl/base/internal/log_severity.cc
@@ -0,0 +1,15 @@
+// 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/log_severity.h"
diff --git a/absl/base/internal/log_severity.h b/absl/base/internal/log_severity.h
new file mode 100644
index 0000000..deaf6a5
--- /dev/null
+++ b/absl/base/internal/log_severity.h
@@ -0,0 +1,52 @@
+// 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 "absl/base/attributes.h"
+
+namespace absl {
+
+enum class LogSeverity : int {
+ kInfo = 0,
+ kWarning = 1,
+ kError = 2,
+ kFatal = 3,
+};
+
+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";
+}
+
+// Note that out-of-range large severities 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_
diff --git a/absl/base/internal/low_level_alloc.cc b/absl/base/internal/low_level_alloc.cc
new file mode 100644
index 0000000..c55201b
--- /dev/null
+++ b/absl/base/internal/low_level_alloc.cc
@@ -0,0 +1,598 @@
+// 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/config.h"
+
+#include "absl/base/internal/low_level_alloc.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 <cstddef>
+#include <cerrno>
+#include <new> // for placement-new
+
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/malloc_hook.h"
+#include "absl/base/internal/malloc_hook_invoke.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
+
+struct LowLevelAlloc::Arena {
+ // This constructor does nothing, and relies on zero-initialization to get
+ // the proper initial state.
+ Arena() : mu(base_internal::kLinkerInitialized) {} // NOLINT
+ explicit Arena(int) // NOLINT(readability/casting)
+ : // Avoid recursive cooperative scheduling w/ kernel scheduling.
+ mu(base_internal::SCHEDULE_KERNEL_ONLY),
+ // Set pagesize to zero explicitly for non-static init.
+ pagesize(0),
+ random(0) {}
+
+ base_internal::SpinLock mu; // protects freelist, allocation_count,
+ // pagesize, roundup, min_size
+ AllocList freelist; // head of free list; sorted by addr (under mu)
+ int32_t allocation_count; // count of allocated blocks (under mu)
+ std::atomic<uint32_t> flags; // flags passed to NewArena (ro after init)
+ size_t pagesize; // ==getpagesize() (init under mu, then ro)
+ size_t roundup; // lowest 2^n >= max(16,sizeof (AllocList))
+ // (init under mu, then ro)
+ size_t min_size; // smallest allocation block size
+ // (init under mu, then ro)
+ uint32_t random; // PRNG state
+};
+
+// The default arena, which is used when 0 is passed instead of an Arena
+// pointer.
+static struct LowLevelAlloc::Arena default_arena; // NOLINT
+
+// Non-malloc-hooked arenas: used only to allocate metadata for arenas that
+// do not want malloc hook reporting, so that for them there's no malloc hook
+// reporting even during arena creation.
+static struct LowLevelAlloc::Arena unhooked_arena; // NOLINT
+
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+static struct LowLevelAlloc::Arena unhooked_async_sig_safe_arena; // NOLINT
+#endif
+
+// 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 == &unhooked_async_sig_safe_arena ||
+ (arena->flags.load(std::memory_order_relaxed) &
+ 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);
+}
+
+// Initialize the fields of an Arena
+static void ArenaInit(LowLevelAlloc::Arena *arena) {
+ if (arena->pagesize == 0) {
+#ifdef _WIN32
+ SYSTEM_INFO system_info;
+ GetSystemInfo(&system_info);
+ arena->pagesize = std::max(system_info.dwPageSize,
+ system_info.dwAllocationGranularity);
+#else
+ arena->pagesize = getpagesize();
+#endif
+ // Round up block sizes to a power of two close to the header size.
+ arena->roundup = 16;
+ while (arena->roundup < sizeof (arena->freelist.header)) {
+ arena->roundup += arena->roundup;
+ }
+ // Don't allocate blocks less than twice the roundup size to avoid tiny
+ // free blocks.
+ arena->min_size = 2 * arena->roundup;
+ arena->freelist.header.size = 0;
+ arena->freelist.header.magic =
+ Magic(kMagicUnallocated, &arena->freelist.header);
+ arena->freelist.header.arena = arena;
+ arena->freelist.levels = 0;
+ memset(arena->freelist.next, 0, sizeof (arena->freelist.next));
+ arena->allocation_count = 0;
+ if (arena == &default_arena) {
+ // Default arena should be hooked, e.g. for heap-checker to trace
+ // pointer chains through objects in the default arena.
+ arena->flags.store(LowLevelAlloc::kCallMallocHook,
+ std::memory_order_relaxed);
+ }
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+ else if (arena == // NOLINT(readability/braces)
+ &unhooked_async_sig_safe_arena) {
+ arena->flags.store(LowLevelAlloc::kAsyncSignalSafe,
+ std::memory_order_relaxed);
+ }
+#endif
+ else { // NOLINT(readability/braces)
+ // other arenas' flags may be overridden by client,
+ // but unhooked_arena will have 0 in 'flags'.
+ arena->flags.store(0, std::memory_order_relaxed);
+ }
+ }
+}
+
+// L < meta_data_arena->mu
+LowLevelAlloc::Arena *LowLevelAlloc::NewArena(int32_t flags,
+ Arena *meta_data_arena) {
+ ABSL_RAW_CHECK(meta_data_arena != nullptr, "must pass a valid arena");
+ if (meta_data_arena == &default_arena) {
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+ if ((flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
+ meta_data_arena = &unhooked_async_sig_safe_arena;
+ } else // NOLINT(readability/braces)
+#endif
+ if ((flags & LowLevelAlloc::kCallMallocHook) == 0) {
+ meta_data_arena = &unhooked_arena;
+ }
+ }
+ // Arena(0) uses the constructor for non-static contexts
+ Arena *result =
+ new (AllocWithArena(sizeof (*result), meta_data_arena)) Arena(0);
+ ArenaInit(result);
+ result->flags.store(flags, std::memory_order_relaxed);
+ return result;
+}
+
+// L < arena->mu, L < arena->arena->mu
+bool LowLevelAlloc::DeleteArena(Arena *arena) {
+ ABSL_RAW_CHECK(
+ arena != nullptr && arena != &default_arena && arena != &unhooked_arena,
+ "may not delete default arena");
+ ArenaLock section(arena);
+ bool empty = (arena->allocation_count == 0);
+ section.Leave();
+ if (empty) {
+ 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.load(std::memory_order_relaxed) &
+ LowLevelAlloc::kAsyncSignalSafe) == 0) {
+ munmap_result = munmap(region, size);
+ } else {
+ munmap_result = MallocHook::UnhookedMUnmap(region, size);
+ }
+ if (munmap_result != 0) {
+ ABSL_RAW_LOG(FATAL, "LowLevelAlloc::DeleteArena: munmap failed: %d",
+ errno);
+ }
+#endif
+ }
+ Free(arena);
+ }
+ return empty;
+}
+
+// ---------------------------------------------------------------------------
+
+// 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;
+ if ((arena->flags.load(std::memory_order_relaxed) & kCallMallocHook) != 0) {
+ MallocHook::InvokeDeleteHook(v);
+ }
+ 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);
+ ArenaInit(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.load(std::memory_order_relaxed) &
+ LowLevelAlloc::kAsyncSignalSafe) != 0) {
+ new_pages = MallocHook::UnhookedMMap(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;
+ }
+ ANNOTATE_MEMORY_IS_UNINITIALIZED(result, request);
+ return result;
+}
+
+void *LowLevelAlloc::Alloc(size_t request) {
+ void *result = DoAllocWithArena(request, &default_arena);
+ if ((default_arena.flags.load(std::memory_order_relaxed) &
+ kCallMallocHook) != 0) {
+ // this call must be directly in the user-called allocator function
+ // for MallocHook::GetCallerStackTrace to work properly
+ MallocHook::InvokeNewHook(result, request);
+ }
+ 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);
+ if ((arena->flags.load(std::memory_order_relaxed) & kCallMallocHook) != 0) {
+ // this call must be directly in the user-called allocator function
+ // for MallocHook::GetCallerStackTrace to work properly
+ MallocHook::InvokeNewHook(result, request);
+ }
+ return result;
+}
+
+LowLevelAlloc::Arena *LowLevelAlloc::DefaultArena() {
+ return &default_arena;
+}
+
+} // namespace base_internal
+} // namespace absl
+
+#endif // ABSL_LOW_LEVEL_ALLOC_MISSING
diff --git a/absl/base/internal/low_level_alloc.h b/absl/base/internal/low_level_alloc.h
new file mode 100644
index 0000000..d6eb813
--- /dev/null
+++ b/absl/base/internal/low_level_alloc.h
@@ -0,0 +1,120 @@
+// 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 <cstdint>
+
+#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
+
+ // When used with DefaultArena(), the NewArena() and DeleteArena() calls
+ // obey the flags given explicitly in the NewArena() call, even if those
+ // flags differ from the settings in DefaultArena(). So the call
+ // NewArena(kAsyncSignalSafe, DefaultArena()) is itself async-signal-safe,
+ // as well as generatating an arena that provides async-signal-safe
+ // Alloc/Free.
+ };
+ static Arena *NewArena(int32_t flags, Arena *meta_data_arena);
+
+ // 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_
diff --git a/absl/base/internal/low_level_alloc_test.cc b/absl/base/internal/low_level_alloc_test.cc
new file mode 100644
index 0000000..5f60c3d
--- /dev/null
+++ b/absl/base/internal/low_level_alloc_test.cc
@@ -0,0 +1,203 @@
+// 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 <stdio.h>
+#include <stdlib.h>
+#include <thread> // NOLINT(build/c++11)
+#include <unordered_map>
+
+#include "absl/base/internal/malloc_hook.h"
+
+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, LowLevelAlloc::DefaultArena());
+ }
+ 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));
+ }
+}
+
+// used for counting allocates and frees
+static int32_t allocates;
+static int32_t frees;
+
+// ignore uses of the allocator not triggered by our test
+static std::thread::id* test_tid;
+
+// called on each alloc if kCallMallocHook specified
+static void AllocHook(const void *p, size_t size) {
+ if (using_low_level_alloc) {
+ if (*test_tid == std::this_thread::get_id()) {
+ allocates++;
+ }
+ }
+}
+
+// called on each free if kCallMallocHook specified
+static void FreeHook(const void *p) {
+ if (using_low_level_alloc) {
+ if (*test_tid == std::this_thread::get_id()) {
+ frees++;
+ }
+ }
+}
+
+// LowLevelAlloc is designed to be safe to call before main().
+static struct BeforeMain {
+ BeforeMain() {
+ test_tid = new std::thread::id(std::this_thread::get_id());
+ TEST_ASSERT(MallocHook::AddNewHook(&AllocHook));
+ TEST_ASSERT(MallocHook::AddDeleteHook(&FreeHook));
+ TEST_ASSERT(allocates == 0);
+ TEST_ASSERT(frees == 0);
+ Test(false, false, 50000);
+ TEST_ASSERT(allocates != 0); // default arena calls hooks
+ TEST_ASSERT(frees != 0);
+ for (int i = 0; i != 16; i++) {
+ bool call_hooks = ((i & 1) == 1);
+ allocates = 0;
+ frees = 0;
+ Test(true, call_hooks, 15000);
+ if (call_hooks) {
+ TEST_ASSERT(allocates > 5000); // arena calls hooks
+ TEST_ASSERT(frees > 5000);
+ } else {
+ TEST_ASSERT(allocates == 0); // arena doesn't call hooks
+ TEST_ASSERT(frees == 0);
+ }
+ }
+ TEST_ASSERT(MallocHook::RemoveNewHook(&AllocHook));
+ TEST_ASSERT(MallocHook::RemoveDeleteHook(&FreeHook));
+ }
+} 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;
+}
diff --git a/absl/base/internal/low_level_scheduling.h b/absl/base/internal/low_level_scheduling.h
new file mode 100644
index 0000000..b950107
--- /dev/null
+++ b/absl/base/internal/low_level_scheduling.h
@@ -0,0 +1,104 @@
+// 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 //base 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 SpinLock; // To allow use of SchedulingGuard.
+class SchedulingHelper; // 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_
diff --git a/absl/base/internal/malloc_extension.cc b/absl/base/internal/malloc_extension.cc
new file mode 100644
index 0000000..daf4bc3
--- /dev/null
+++ b/absl/base/internal/malloc_extension.cc
@@ -0,0 +1,197 @@
+// 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/malloc_extension.h"
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <atomic>
+#include <string>
+
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/malloc_extension_c.h"
+#include "absl/base/port.h"
+
+namespace absl {
+namespace base_internal {
+
+// SysAllocator implementation
+SysAllocator::~SysAllocator() {}
+void SysAllocator::GetStats(char* buffer, int) { buffer[0] = 0; }
+
+// Default implementation -- does nothing
+MallocExtension::~MallocExtension() { }
+bool MallocExtension::VerifyAllMemory() { return true; }
+bool MallocExtension::VerifyNewMemory(const void*) { return true; }
+bool MallocExtension::VerifyArrayNewMemory(const void*) { return true; }
+bool MallocExtension::VerifyMallocMemory(const void*) { return true; }
+
+bool MallocExtension::GetNumericProperty(const char*, size_t*) {
+ return false;
+}
+
+bool MallocExtension::SetNumericProperty(const char*, size_t) {
+ return false;
+}
+
+void MallocExtension::GetStats(char* buffer, int length) {
+ assert(length > 0);
+ static_cast<void>(length);
+ buffer[0] = '\0';
+}
+
+bool MallocExtension::MallocMemoryStats(int* blocks, size_t* total,
+ int histogram[kMallocHistogramSize]) {
+ *blocks = 0;
+ *total = 0;
+ memset(histogram, 0, sizeof(*histogram) * kMallocHistogramSize);
+ return true;
+}
+
+void MallocExtension::MarkThreadIdle() {
+ // Default implementation does nothing
+}
+
+void MallocExtension::MarkThreadBusy() {
+ // Default implementation does nothing
+}
+
+SysAllocator* MallocExtension::GetSystemAllocator() {
+ return nullptr;
+}
+
+void MallocExtension::SetSystemAllocator(SysAllocator*) {
+ // Default implementation does nothing
+}
+
+void MallocExtension::ReleaseToSystem(size_t) {
+ // Default implementation does nothing
+}
+
+void MallocExtension::ReleaseFreeMemory() {
+ ReleaseToSystem(static_cast<size_t>(-1)); // SIZE_T_MAX
+}
+
+void MallocExtension::SetMemoryReleaseRate(double) {
+ // Default implementation does nothing
+}
+
+double MallocExtension::GetMemoryReleaseRate() {
+ return -1.0;
+}
+
+size_t MallocExtension::GetEstimatedAllocatedSize(size_t size) {
+ return size;
+}
+
+size_t MallocExtension::GetAllocatedSize(const void* p) {
+ assert(GetOwnership(p) != kNotOwned);
+ static_cast<void>(p);
+ return 0;
+}
+
+MallocExtension::Ownership MallocExtension::GetOwnership(const void*) {
+ return kUnknownOwnership;
+}
+
+void MallocExtension::GetProperties(MallocExtension::StatLevel,
+ std::map<std::string, Property>* result) {
+ result->clear();
+}
+
+size_t MallocExtension::ReleaseCPUMemory(int) {
+ return 0;
+}
+
+// The current malloc extension object.
+
+std::atomic<MallocExtension*> MallocExtension::current_instance_;
+
+MallocExtension* MallocExtension::InitModule() {
+ MallocExtension* ext = new MallocExtension;
+ current_instance_.store(ext, std::memory_order_release);
+ return ext;
+}
+
+void MallocExtension::Register(MallocExtension* implementation) {
+ InitModuleOnce();
+ // When running under valgrind, our custom malloc is replaced with
+ // valgrind's one and malloc extensions will not work. (Note:
+ // callers should be responsible for checking that they are the
+ // malloc that is really being run, before calling Register. This
+ // is just here as an extra sanity check.)
+ // Under compiler-based ThreadSanitizer RunningOnValgrind() returns true,
+ // but we still want to use malloc extensions.
+#ifndef THREAD_SANITIZER
+ if (RunningOnValgrind()) {
+ return;
+ }
+#endif // #ifndef THREAD_SANITIZER
+ current_instance_.store(implementation, std::memory_order_release);
+}
+void MallocExtension::GetHeapSample(MallocExtensionWriter*) {}
+
+void MallocExtension::GetHeapGrowthStacks(MallocExtensionWriter*) {}
+
+void MallocExtension::GetFragmentationProfile(MallocExtensionWriter*) {}
+
+} // namespace base_internal
+} // namespace absl
+
+// These are C shims that work on the current instance.
+
+#define C_SHIM(fn, retval, paramlist, arglist) \
+ extern "C" retval MallocExtension_##fn paramlist { \
+ return absl::base_internal::MallocExtension::instance()->fn arglist; \
+ }
+
+C_SHIM(VerifyAllMemory, int, (void), ());
+C_SHIM(VerifyNewMemory, int, (const void* p), (p));
+C_SHIM(VerifyArrayNewMemory, int, (const void* p), (p));
+C_SHIM(VerifyMallocMemory, int, (const void* p), (p));
+C_SHIM(
+ MallocMemoryStats, int,
+ (int* blocks, size_t* total,
+ int histogram[absl::base_internal::MallocExtension::kMallocHistogramSize]),
+ (blocks, total, histogram));
+
+C_SHIM(GetStats, void,
+ (char* buffer, int buffer_length), (buffer, buffer_length));
+C_SHIM(GetNumericProperty, int,
+ (const char* property, size_t* value), (property, value));
+C_SHIM(SetNumericProperty, int,
+ (const char* property, size_t value), (property, value));
+
+C_SHIM(MarkThreadIdle, void, (void), ());
+C_SHIM(MarkThreadBusy, void, (void), ());
+C_SHIM(ReleaseFreeMemory, void, (void), ());
+C_SHIM(ReleaseToSystem, void, (size_t num_bytes), (num_bytes));
+C_SHIM(GetEstimatedAllocatedSize, size_t, (size_t size), (size));
+C_SHIM(GetAllocatedSize, size_t, (const void* p), (p));
+
+// Can't use the shim here because of the need to translate the enums.
+extern "C"
+MallocExtension_Ownership MallocExtension_GetOwnership(const void* p) {
+ return static_cast<MallocExtension_Ownership>(
+ absl::base_internal::MallocExtension::instance()->GetOwnership(p));
+}
+
+// Default implementation just returns size. The expectation is that
+// the linked-in malloc implementation might provide an override of
+// this weak function with a better implementation.
+ABSL_ATTRIBUTE_WEAK ABSL_ATTRIBUTE_NOINLINE size_t nallocx(size_t size, int) {
+ return size;
+}
diff --git a/absl/base/internal/malloc_extension.h b/absl/base/internal/malloc_extension.h
new file mode 100644
index 0000000..dee4116
--- /dev/null
+++ b/absl/base/internal/malloc_extension.h
@@ -0,0 +1,424 @@
+//
+// 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.
+//
+
+// Extra extensions exported by some malloc implementations. These
+// extensions are accessed through a virtual base class so an
+// application can link against a malloc that does not implement these
+// extensions, and it will get default versions that do nothing.
+//
+// NOTE FOR C USERS: If you wish to use this functionality from within
+// a C program, see malloc_extension_c.h.
+
+#ifndef ABSL_BASE_INTERNAL_MALLOC_EXTENSION_H_
+#define ABSL_BASE_INTERNAL_MALLOC_EXTENSION_H_
+
+#include <atomic>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string>
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+namespace absl {
+namespace base_internal {
+
+class MallocExtensionWriter;
+
+// Interface to a pluggable system allocator.
+class SysAllocator {
+ public:
+ SysAllocator() {
+ }
+ virtual ~SysAllocator();
+
+ // Allocates "size"-byte of memory from system aligned with "alignment".
+ // Returns null if failed. Otherwise, the returned pointer p up to and
+ // including (p + actual_size -1) have been allocated.
+ virtual void* Alloc(size_t size, size_t *actual_size, size_t alignment) = 0;
+
+ // Get a human-readable description of the current state of the
+ // allocator. The state is stored as a null-terminated std::string in
+ // a prefix of buffer.
+ virtual void GetStats(char* buffer, int length);
+};
+
+// The default implementations of the following routines do nothing.
+// All implementations should be thread-safe; the current ones
+// (DebugMallocImplementation and TCMallocImplementation) are.
+class MallocExtension {
+ public:
+ virtual ~MallocExtension();
+
+ // Verifies that all blocks are valid. Returns true if all are; dumps
+ // core otherwise. A no-op except in debug mode. Even in debug mode,
+ // they may not do any checking except with certain malloc
+ // implementations. Thread-safe.
+ virtual bool VerifyAllMemory();
+
+ // Verifies that p was returned by new, has not been deleted, and is
+ // valid. Returns true if p is good; dumps core otherwise. A no-op
+ // except in debug mode. Even in debug mode, may not do any checking
+ // except with certain malloc implementations. Thread-safe.
+ virtual bool VerifyNewMemory(const void* p);
+
+ // Verifies that p was returned by new[], has not been deleted, and is
+ // valid. Returns true if p is good; dumps core otherwise. A no-op
+ // except in debug mode. Even in debug mode, may not do any checking
+ // except with certain malloc implementations. Thread-safe.
+ virtual bool VerifyArrayNewMemory(const void* p);
+
+ // Verifies that p was returned by malloc, has not been freed, and is
+ // valid. Returns true if p is good; dumps core otherwise. A no-op
+ // except in debug mode. Even in debug mode, may not do any checking
+ // except with certain malloc implementations. Thread-safe.
+ virtual bool VerifyMallocMemory(const void* p);
+
+ // If statistics collection is enabled, sets *blocks to be the number of
+ // currently allocated blocks, sets *total to be the total size allocated
+ // over all blocks, sets histogram[n] to be the number of blocks with
+ // size between 2^n-1 and 2^(n+1), and returns true. Returns false, and
+ // does not change *blocks, *total, or *histogram, if statistics
+ // collection is disabled.
+ //
+ // Note that these statistics reflect memory allocated by new, new[],
+ // malloc(), and realloc(), but not mmap(). They may be larger (if not
+ // all pages have been written to) or smaller (if pages have been
+ // allocated by mmap()) than the total RSS size. They will always be
+ // smaller than the total virtual memory size.
+ static constexpr int kMallocHistogramSize = 64;
+ virtual bool MallocMemoryStats(int* blocks, size_t* total,
+ int histogram[kMallocHistogramSize]);
+
+ // Get a human readable description of the current state of the malloc
+ // data structures. The state is stored as a null-terminated std::string
+ // in a prefix of "buffer[0,buffer_length-1]".
+ // REQUIRES: buffer_length > 0.
+ virtual void GetStats(char* buffer, int buffer_length);
+
+ // Outputs to "writer" a sample of live objects and the stack traces
+ // that allocated these objects. The output can be passed to pprof.
+ virtual void GetHeapSample(MallocExtensionWriter* writer);
+
+ // Outputs to "writer" the stack traces that caused growth in the
+ // address space size. The output can be passed to "pprof".
+ virtual void GetHeapGrowthStacks(MallocExtensionWriter* writer);
+
+ // Outputs to "writer" a fragmentation profile. The output can be
+ // passed to "pprof". In particular, the result is a list of
+ // <n,total,stacktrace> tuples that says that "total" bytes in "n"
+ // objects are currently unusable because of fragmentation caused by
+ // an allocation with the specified "stacktrace".
+ virtual void GetFragmentationProfile(MallocExtensionWriter* writer);
+
+ // -------------------------------------------------------------------
+ // Control operations for getting and setting malloc implementation
+ // specific parameters. Some currently useful properties:
+ //
+ // generic
+ // -------
+ // "generic.current_allocated_bytes"
+ // Number of bytes currently allocated by application
+ // This property is not writable.
+ //
+ // "generic.heap_size"
+ // Number of bytes in the heap ==
+ // current_allocated_bytes +
+ // fragmentation +
+ // freed memory regions
+ // This property is not writable.
+ //
+ // tcmalloc
+ // --------
+ // "tcmalloc.max_total_thread_cache_bytes"
+ // Upper limit on total number of bytes stored across all
+ // per-thread caches. Default: 16MB.
+ //
+ // "tcmalloc.current_total_thread_cache_bytes"
+ // Number of bytes used across all thread caches.
+ // This property is not writable.
+ //
+ // "tcmalloc.pageheap_free_bytes"
+ // Number of bytes in free, mapped pages in page heap. These
+ // bytes can be used to fulfill allocation requests. They
+ // always count towards virtual memory usage, and unless the
+ // underlying memory is swapped out by the OS, they also count
+ // towards physical memory usage. This property is not writable.
+ //
+ // "tcmalloc.pageheap_unmapped_bytes"
+ // Number of bytes in free, unmapped pages in page heap.
+ // These are bytes that have been released back to the OS,
+ // possibly by one of the MallocExtension "Release" calls.
+ // They can be used to fulfill allocation requests, but
+ // typically incur a page fault. They always count towards
+ // virtual memory usage, and depending on the OS, typically
+ // do not count towards physical memory usage. This property
+ // is not writable.
+ //
+ // "tcmalloc.per_cpu_caches_active"
+ // Whether tcmalloc is using per-CPU caches (1 or 0 respectively).
+ // This property is not writable.
+ // -------------------------------------------------------------------
+
+ // Get the named "property"'s value. Returns true if the property
+ // is known. Returns false if the property is not a valid property
+ // name for the current malloc implementation.
+ // REQUIRES: property != null; value != null
+ virtual bool GetNumericProperty(const char* property, size_t* value);
+
+ // Set the named "property"'s value. Returns true if the property
+ // is known and writable. Returns false if the property is not a
+ // valid property name for the current malloc implementation, or
+ // is not writable.
+ // REQUIRES: property != null
+ virtual bool SetNumericProperty(const char* property, size_t value);
+
+ // Mark the current thread as "idle". This routine may optionally
+ // be called by threads as a hint to the malloc implementation that
+ // any thread-specific resources should be released. Note: this may
+ // be an expensive routine, so it should not be called too often.
+ //
+ // Also, if the code that calls this routine will go to sleep for
+ // a while, it should take care to not allocate anything between
+ // the call to this routine and the beginning of the sleep.
+ //
+ // Most malloc implementations ignore this routine.
+ virtual void MarkThreadIdle();
+
+ // Mark the current thread as "busy". This routine should be
+ // called after MarkThreadIdle() if the thread will now do more
+ // work. If this method is not called, performance may suffer.
+ //
+ // Most malloc implementations ignore this routine.
+ virtual void MarkThreadBusy();
+
+ // Attempt to free any resources associated with cpu <cpu> (in the sense
+ // of only being usable from that CPU.) Returns the number of bytes
+ // previously assigned to "cpu" that were freed. Safe to call from
+ // any processor, not just <cpu>.
+ //
+ // Most malloc implementations ignore this routine (known exceptions:
+ // tcmalloc with --tcmalloc_per_cpu_caches=true.)
+ virtual size_t ReleaseCPUMemory(int cpu);
+
+ // Gets the system allocator used by the malloc extension instance. Returns
+ // null for malloc implementations that do not support pluggable system
+ // allocators.
+ virtual SysAllocator* GetSystemAllocator();
+
+ // Sets the system allocator to the specified.
+ //
+ // Users could register their own system allocators for malloc implementation
+ // that supports pluggable system allocators, such as TCMalloc, by doing:
+ // alloc = new MyOwnSysAllocator();
+ // MallocExtension::instance()->SetSystemAllocator(alloc);
+ // It's up to users whether to fall back (recommended) to the default
+ // system allocator (use GetSystemAllocator() above) or not. The caller is
+ // responsible to any necessary locking.
+ // See tcmalloc/system-alloc.h for the interface and
+ // tcmalloc/memfs_malloc.cc for the examples.
+ //
+ // It's a no-op for malloc implementations that do not support pluggable
+ // system allocators.
+ virtual void SetSystemAllocator(SysAllocator *a);
+
+ // Try to release num_bytes of free memory back to the operating
+ // system for reuse. Use this extension with caution -- to get this
+ // memory back may require faulting pages back in by the OS, and
+ // that may be slow. (Currently only implemented in tcmalloc.)
+ virtual void ReleaseToSystem(size_t num_bytes);
+
+ // Same as ReleaseToSystem() but release as much memory as possible.
+ virtual void ReleaseFreeMemory();
+
+ // Sets the rate at which we release unused memory to the system.
+ // Zero means we never release memory back to the system. Increase
+ // this flag to return memory faster; decrease it to return memory
+ // slower. Reasonable rates are in the range [0,10]. (Currently
+ // only implemented in tcmalloc).
+ virtual void SetMemoryReleaseRate(double rate);
+
+ // Gets the release rate. Returns a value < 0 if unknown.
+ virtual double GetMemoryReleaseRate();
+
+ // Returns the estimated number of bytes that will be allocated for
+ // a request of "size" bytes. This is an estimate: an allocation of
+ // SIZE bytes may reserve more bytes, but will never reserve less.
+ // (Currently only implemented in tcmalloc, other implementations
+ // always return SIZE.)
+ // This is equivalent to malloc_good_size() in OS X.
+ virtual size_t GetEstimatedAllocatedSize(size_t size);
+
+ // Returns the actual number N of bytes reserved by tcmalloc for the
+ // pointer p. This number may be equal to or greater than the
+ // number of bytes requested when p was allocated.
+ //
+ // This routine is just useful for statistics collection. The
+ // client must *not* read or write from the extra bytes that are
+ // indicated by this call.
+ //
+ // Example, suppose the client gets memory by calling
+ // p = malloc(10)
+ // and GetAllocatedSize(p) returns 16. The client must only use the
+ // first 10 bytes p[0..9], and not attempt to read or write p[10..15].
+ //
+ // p must have been allocated by this malloc implementation, must
+ // not be an interior pointer -- that is, must be exactly the
+ // pointer returned to by malloc() et al., not some offset from that
+ // -- and should not have been freed yet. p may be null.
+ // (Currently only implemented in tcmalloc; other implementations
+ // will return 0.)
+ virtual size_t GetAllocatedSize(const void* p);
+
+ // Returns kOwned if this malloc implementation allocated the memory
+ // pointed to by p, or kNotOwned if some other malloc implementation
+ // allocated it or p is null. May also return kUnknownOwnership if
+ // the malloc implementation does not keep track of ownership.
+ // REQUIRES: p must be a value returned from a previous call to
+ // malloc(), calloc(), realloc(), memalign(), posix_memalign(),
+ // valloc(), pvalloc(), new, or new[], and must refer to memory that
+ // is currently allocated (so, for instance, you should not pass in
+ // a pointer after having called free() on it).
+ enum Ownership {
+ // NOTE: Enum values MUST be kept in sync with the version in
+ // malloc_extension_c.h
+ kUnknownOwnership = 0,
+ kOwned,
+ kNotOwned
+ };
+ virtual Ownership GetOwnership(const void* p);
+
+ // The current malloc implementation. Always non-null.
+ static MallocExtension* instance() {
+ InitModuleOnce();
+ return current_instance_.load(std::memory_order_acquire);
+ }
+
+ // Change the malloc implementation. Typically called by the
+ // malloc implementation during initialization.
+ static void Register(MallocExtension* implementation);
+
+ // Type used by GetProperties. See comment on GetProperties.
+ struct Property {
+ size_t value;
+ // Stores breakdown of the property value bucketed by object size.
+ struct Bucket {
+ size_t min_object_size;
+ size_t max_object_size;
+ size_t size;
+ };
+ // Empty unless detailed info was asked for and this type has buckets
+ std::vector<Bucket> buckets;
+ };
+
+ // Type used by GetProperties. See comment on GetProperties.
+ enum StatLevel { kSummary, kDetailed };
+
+ // Stores in *result detailed statistics about the malloc
+ // implementation. *result will be a map keyed by the name of
+ // the statistic. Each statistic has at least a "value" field.
+ //
+ // Some statistics may also contain an array of buckets if
+ // level==kDetailed and the "value" can be subdivided
+ // into different buckets for different object sizes. If
+ // such detailed statistics are not available, Property::buckets
+ // will be empty. Otherwise Property::buckets will contain
+ // potentially many entries. For each bucket b, b.value
+ // will count the value contributed by objects in the range
+ // [b.min_object_size, b.max_object_size].
+ //
+ // Common across malloc implementations:
+ // generic.bytes_in_use_by_app -- Bytes currently in use by application
+ // generic.physical_memory_used -- Overall (including malloc internals)
+ // generic.virtual_memory_used -- Overall (including malloc internals)
+ //
+ // Tcmalloc specific properties
+ // tcmalloc.cpu_free -- Bytes in per-cpu free-lists
+ // tcmalloc.thread_cache_free -- Bytes in per-thread free-lists
+ // tcmalloc.transfer_cache -- Bytes in cross-thread transfer caches
+ // tcmalloc.central_cache_free -- Bytes in central cache
+ // tcmalloc.page_heap_free -- Bytes in page heap
+ // tcmalloc.page_heap_unmapped -- Bytes in page heap (no backing phys. mem)
+ // tcmalloc.metadata_bytes -- Used by internal data structures
+ // tcmalloc.thread_cache_count -- Number of thread caches in use
+ //
+ // Debug allocator
+ // debug.free_queue -- Recently freed objects
+ virtual void GetProperties(StatLevel level,
+ std::map<std::string, Property>* result);
+ private:
+ static MallocExtension* InitModule();
+
+ static void InitModuleOnce() {
+ // Pointer stored here so heap leak checker will consider the default
+ // instance reachable, even if current_instance_ is later overridden by
+ // MallocExtension::Register().
+ ABSL_ATTRIBUTE_UNUSED static MallocExtension* default_instance =
+ InitModule();
+ }
+
+ static std::atomic<MallocExtension*> current_instance_;
+};
+
+// Base class than can handle output generated by GetHeapSample() and
+// GetHeapGrowthStacks(). Use the available subclass or roll your
+// own. Useful if you want explicit control over the type of output
+// buffer used (e.g. IOBuffer, Cord, etc.)
+class MallocExtensionWriter {
+ public:
+ virtual ~MallocExtensionWriter() {}
+ virtual void Write(const char* buf, int len) = 0;
+ protected:
+ MallocExtensionWriter() {}
+ MallocExtensionWriter(const MallocExtensionWriter&) = delete;
+ MallocExtensionWriter& operator=(const MallocExtensionWriter&) = delete;
+};
+
+// A subclass that writes to the std::string "out". NOTE: The generated
+// data is *appended* to "*out". I.e., the old contents of "*out" are
+// preserved.
+class StringMallocExtensionWriter : public MallocExtensionWriter {
+ public:
+ explicit StringMallocExtensionWriter(std::string* out) : out_(out) {}
+ virtual void Write(const char* buf, int len) {
+ out_->append(buf, len);
+ }
+
+ private:
+ std::string* const out_;
+ StringMallocExtensionWriter(const StringMallocExtensionWriter&) = delete;
+ StringMallocExtensionWriter& operator=(const StringMallocExtensionWriter&) =
+ delete;
+};
+
+} // namespace base_internal
+} // namespace absl
+
+// The nallocx function allocates no memory, but it performs the same size
+// computation as the malloc function, and returns the real size of the
+// allocation that would result from the equivalent malloc function call.
+// Default weak implementation returns size unchanged, but tcmalloc overrides it
+// and returns rounded up size. See the following link for details:
+// http://www.unix.com/man-page/freebsd/3/nallocx/
+extern "C" size_t nallocx(size_t size, int flags);
+
+#ifndef MALLOCX_LG_ALIGN
+#define MALLOCX_LG_ALIGN(la) (la)
+#endif
+
+#endif // ABSL_BASE_INTERNAL_MALLOC_EXTENSION_H_
diff --git a/absl/base/internal/malloc_extension_c.h b/absl/base/internal/malloc_extension_c.h
new file mode 100644
index 0000000..5afc84a
--- /dev/null
+++ b/absl/base/internal/malloc_extension_c.h
@@ -0,0 +1,75 @@
+/*
+ * 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.
+
+ * C shims for the C++ malloc_extension.h. See malloc_extension.h for
+ * details. Note these C shims always work on
+ * MallocExtension::instance(); it is not possible to have more than
+ * one MallocExtension object in C applications.
+ */
+
+#ifndef ABSL_BASE_INTERNAL_MALLOC_EXTENSION_C_H_
+#define ABSL_BASE_INTERNAL_MALLOC_EXTENSION_C_H_
+
+#include <stddef.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define kMallocExtensionHistogramSize 64
+
+int MallocExtension_VerifyAllMemory(void);
+int MallocExtension_VerifyNewMemory(const void* p);
+int MallocExtension_VerifyArrayNewMemory(const void* p);
+int MallocExtension_VerifyMallocMemory(const void* p);
+int MallocExtension_MallocMemoryStats(int* blocks, size_t* total,
+ int histogram[kMallocExtensionHistogramSize]);
+
+void MallocExtension_GetStats(char* buffer, int buffer_length);
+
+/* TODO(csilvers): write a C version of these routines, that perhaps
+ * takes a function ptr and a void *.
+ */
+/* void MallocExtension_GetHeapSample(MallocExtensionWriter* result); */
+/* void MallocExtension_GetHeapGrowthStacks(MallocExtensionWriter* result); */
+
+int MallocExtension_GetNumericProperty(const char* property, size_t* value);
+int MallocExtension_SetNumericProperty(const char* property, size_t value);
+void MallocExtension_MarkThreadIdle(void);
+void MallocExtension_MarkThreadBusy(void);
+void MallocExtension_ReleaseToSystem(size_t num_bytes);
+void MallocExtension_ReleaseFreeMemory(void);
+size_t MallocExtension_GetEstimatedAllocatedSize(size_t size);
+size_t MallocExtension_GetAllocatedSize(const void* p);
+
+/*
+ * NOTE: These enum values MUST be kept in sync with the version in
+ * malloc_extension.h
+ */
+typedef enum {
+ MallocExtension_kUnknownOwnership = 0,
+ MallocExtension_kOwned,
+ MallocExtension_kNotOwned
+} MallocExtension_Ownership;
+
+MallocExtension_Ownership MallocExtension_GetOwnership(const void* p);
+
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* ABSL_BASE_INTERNAL_MALLOC_EXTENSION_C_H_ */
diff --git a/absl/base/internal/malloc_extension_test.cc b/absl/base/internal/malloc_extension_test.cc
new file mode 100644
index 0000000..246875a
--- /dev/null
+++ b/absl/base/internal/malloc_extension_test.cc
@@ -0,0 +1,102 @@
+/*
+ * 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 <algorithm>
+#include <cstdlib>
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/malloc_extension.h"
+#include "absl/base/internal/malloc_extension_c.h"
+
+namespace absl {
+namespace base_internal {
+namespace {
+
+TEST(MallocExtension, MallocExtension) {
+ void* a = malloc(1000);
+
+ size_t cxx_bytes_used, c_bytes_used;
+ if (!MallocExtension::instance()->GetNumericProperty(
+ "generic.current_allocated_bytes", &cxx_bytes_used)) {
+ EXPECT_TRUE(ABSL_MALLOC_EXTENSION_TEST_ALLOW_MISSING_EXTENSION);
+ } else {
+ ASSERT_TRUE(MallocExtension::instance()->GetNumericProperty(
+ "generic.current_allocated_bytes", &cxx_bytes_used));
+ ASSERT_TRUE(MallocExtension_GetNumericProperty(
+ "generic.current_allocated_bytes", &c_bytes_used));
+#ifndef MEMORY_SANITIZER
+ EXPECT_GT(cxx_bytes_used, 1000);
+ EXPECT_GT(c_bytes_used, 1000);
+#endif
+
+ EXPECT_TRUE(MallocExtension::instance()->VerifyAllMemory());
+ EXPECT_TRUE(MallocExtension_VerifyAllMemory());
+
+ EXPECT_EQ(MallocExtension::kOwned,
+ MallocExtension::instance()->GetOwnership(a));
+ // TODO(csilvers): this relies on undocumented behavior that
+ // GetOwnership works on stack-allocated variables. Use a better test.
+ EXPECT_EQ(MallocExtension::kNotOwned,
+ MallocExtension::instance()->GetOwnership(&cxx_bytes_used));
+ EXPECT_EQ(MallocExtension::kNotOwned,
+ MallocExtension::instance()->GetOwnership(nullptr));
+ EXPECT_GE(MallocExtension::instance()->GetAllocatedSize(a), 1000);
+ // This is just a sanity check. If we allocated too much, tcmalloc is
+ // broken
+ EXPECT_LE(MallocExtension::instance()->GetAllocatedSize(a), 5000);
+ EXPECT_GE(MallocExtension::instance()->GetEstimatedAllocatedSize(1000),
+ 1000);
+ for (int i = 0; i < 10; ++i) {
+ void* p = malloc(i);
+ EXPECT_GE(MallocExtension::instance()->GetAllocatedSize(p),
+ MallocExtension::instance()->GetEstimatedAllocatedSize(i));
+ free(p);
+ }
+
+ // Check the c-shim version too.
+ EXPECT_EQ(MallocExtension_kOwned, MallocExtension_GetOwnership(a));
+ EXPECT_EQ(MallocExtension_kNotOwned,
+ MallocExtension_GetOwnership(&cxx_bytes_used));
+ EXPECT_EQ(MallocExtension_kNotOwned, MallocExtension_GetOwnership(nullptr));
+ EXPECT_GE(MallocExtension_GetAllocatedSize(a), 1000);
+ EXPECT_LE(MallocExtension_GetAllocatedSize(a), 5000);
+ EXPECT_GE(MallocExtension_GetEstimatedAllocatedSize(1000), 1000);
+ }
+
+ free(a);
+}
+
+// Verify that the .cc file and .h file have the same enum values.
+TEST(GetOwnership, EnumValuesEqualForCAndCXX) {
+ EXPECT_EQ(static_cast<int>(MallocExtension::kUnknownOwnership),
+ static_cast<int>(MallocExtension_kUnknownOwnership));
+ EXPECT_EQ(static_cast<int>(MallocExtension::kOwned),
+ static_cast<int>(MallocExtension_kOwned));
+ EXPECT_EQ(static_cast<int>(MallocExtension::kNotOwned),
+ static_cast<int>(MallocExtension_kNotOwned));
+}
+
+TEST(nallocx, SaneBehavior) {
+ for (size_t size = 0; size < 64 * 1024; ++size) {
+ size_t alloc_size = nallocx(size, 0);
+ EXPECT_LE(size, alloc_size) << "size is " << size;
+ EXPECT_LE(alloc_size, std::max(size + 100, 2 * size)) << "size is " << size;
+ }
+}
+
+} // namespace
+} // namespace base_internal
+} // namespace absl
diff --git a/absl/base/internal/malloc_hook.cc b/absl/base/internal/malloc_hook.cc
new file mode 100644
index 0000000..d5d227a
--- /dev/null
+++ b/absl/base/internal/malloc_hook.cc
@@ -0,0 +1,611 @@
+// 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"
+
+#if ABSL_HAVE_MMAP
+// Disable the glibc prototype of mremap(), as older versions of the
+// system headers define this function with only four arguments,
+// whereas newer versions allow an optional fifth argument:
+#define mremap glibc_mremap
+#include <sys/mman.h>
+#undef mremap
+#endif
+
+#include <cstddef>
+#include <cstdint>
+#include <algorithm>
+
+#include "absl/base/call_once.h"
+#include "absl/base/casts.h"
+#include "absl/base/internal/malloc_hook.h"
+#include "absl/base/internal/malloc_hook_invoke.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/spinlock.h"
+
+// __THROW is defined in glibc systems. It means, counter-intuitively,
+// "This function will never throw an exception." It's an optional
+// optimization tool, but we may need to use it to match glibc prototypes.
+#ifndef __THROW // I guess we're not on a glibc system
+# define __THROW // __THROW is just an optimization, so ok to make it ""
+#endif
+
+namespace absl {
+namespace base_internal {
+namespace {
+
+void RemoveInitialHooksAndCallInitializers(); // below.
+
+absl::once_flag once;
+
+// These hooks are installed in MallocHook as the only initial hooks. The first
+// hook that is called will run RemoveInitialHooksAndCallInitializers (see the
+// definition below) and then redispatch to any malloc hooks installed by
+// RemoveInitialHooksAndCallInitializers.
+//
+// Note(llib): there is a possibility of a race in the event that there are
+// multiple threads running before the first allocation. This is pretty
+// difficult to achieve, but if it is then multiple threads may concurrently do
+// allocations. The first caller will call
+// RemoveInitialHooksAndCallInitializers via one of the initial hooks. A
+// concurrent allocation may, depending on timing either:
+// * still have its initial malloc hook installed, run that and block on waiting
+// for the first caller to finish its call to
+// RemoveInitialHooksAndCallInitializers, and proceed normally.
+// * occur some time during the RemoveInitialHooksAndCallInitializers call, at
+// which point there could be no initial hooks and the subsequent hooks that
+// are about to be set up by RemoveInitialHooksAndCallInitializers haven't
+// been installed yet. I think the worst we can get is that some allocations
+// will not get reported to some hooks set by the initializers called from
+// RemoveInitialHooksAndCallInitializers.
+
+void InitialNewHook(const void* ptr, size_t size) {
+ absl::call_once(once, RemoveInitialHooksAndCallInitializers);
+ MallocHook::InvokeNewHook(ptr, size);
+}
+
+void InitialPreMMapHook(const void* start,
+ size_t size,
+ int protection,
+ int flags,
+ int fd,
+ off_t offset) {
+ absl::call_once(once, RemoveInitialHooksAndCallInitializers);
+ MallocHook::InvokePreMmapHook(start, size, protection, flags, fd, offset);
+}
+
+void InitialPreSbrkHook(ptrdiff_t increment) {
+ absl::call_once(once, RemoveInitialHooksAndCallInitializers);
+ MallocHook::InvokePreSbrkHook(increment);
+}
+
+// This function is called at most once by one of the above initial malloc
+// hooks. It removes all initial hooks and initializes all other clients that
+// want to get control at the very first memory allocation. The initializers
+// may assume that the initial malloc hooks have been removed. The initializers
+// may set up malloc hooks and allocate memory.
+void RemoveInitialHooksAndCallInitializers() {
+ ABSL_RAW_CHECK(MallocHook::RemoveNewHook(&InitialNewHook), "");
+ ABSL_RAW_CHECK(MallocHook::RemovePreMmapHook(&InitialPreMMapHook), "");
+ ABSL_RAW_CHECK(MallocHook::RemovePreSbrkHook(&InitialPreSbrkHook), "");
+}
+
+} // namespace
+} // namespace base_internal
+} // namespace absl
+
+namespace absl {
+namespace base_internal {
+
+// This lock is shared between all implementations of HookList::Add & Remove.
+// The potential for contention is very small. This needs to be a SpinLock and
+// not a Mutex since it's possible for Mutex locking to allocate memory (e.g.,
+// per-thread allocation in debug builds), which could cause infinite recursion.
+static absl::base_internal::SpinLock hooklist_spinlock(
+ absl::base_internal::kLinkerInitialized);
+
+template <typename T>
+bool HookList<T>::Add(T value_as_t) {
+ if (value_as_t == T()) {
+ return false;
+ }
+ absl::base_internal::SpinLockHolder l(&hooklist_spinlock);
+ // Find the first slot in data that is 0.
+ int index = 0;
+ while ((index < kHookListMaxValues) &&
+ (priv_data[index].load(std::memory_order_relaxed) != 0)) {
+ ++index;
+ }
+ if (index == kHookListMaxValues) {
+ return false;
+ }
+ int prev_num_hooks = priv_end.load(std::memory_order_acquire);
+ priv_data[index].store(reinterpret_cast<intptr_t>(value_as_t),
+ std::memory_order_release);
+ if (prev_num_hooks <= index) {
+ priv_end.store(index + 1, std::memory_order_release);
+ }
+ return true;
+}
+
+template <typename T>
+bool HookList<T>::Remove(T value_as_t) {
+ if (value_as_t == T()) {
+ return false;
+ }
+ absl::base_internal::SpinLockHolder l(&hooklist_spinlock);
+ int hooks_end = priv_end.load(std::memory_order_acquire);
+ int index = 0;
+ while (index < hooks_end &&
+ value_as_t != reinterpret_cast<T>(
+ priv_data[index].load(std::memory_order_acquire))) {
+ ++index;
+ }
+ if (index == hooks_end) {
+ return false;
+ }
+ priv_data[index].store(0, std::memory_order_release);
+ if (hooks_end == index + 1) {
+ // Adjust hooks_end down to the lowest possible value.
+ hooks_end = index;
+ while ((hooks_end > 0) &&
+ (priv_data[hooks_end - 1].load(std::memory_order_acquire) == 0)) {
+ --hooks_end;
+ }
+ priv_end.store(hooks_end, std::memory_order_release);
+ }
+ return true;
+}
+
+template <typename T>
+int HookList<T>::Traverse(T* output_array, int n) const {
+ int hooks_end = priv_end.load(std::memory_order_acquire);
+ int actual_hooks_end = 0;
+ for (int i = 0; i < hooks_end && n > 0; ++i) {
+ T data = reinterpret_cast<T>(priv_data[i].load(std::memory_order_acquire));
+ if (data != T()) {
+ *output_array++ = data;
+ ++actual_hooks_end;
+ --n;
+ }
+ }
+ return actual_hooks_end;
+}
+
+// Initialize a HookList (optionally with the given initial_value in index 0).
+#define INIT_HOOK_LIST { {0}, {{}} }
+#define INIT_HOOK_LIST_WITH_VALUE(initial_value) \
+ { {1}, { {reinterpret_cast<intptr_t>(initial_value)} } }
+
+// Explicit instantiation for malloc_hook_test.cc. This ensures all the methods
+// are instantiated.
+template struct HookList<MallocHook::NewHook>;
+
+HookList<MallocHook::NewHook> new_hooks_ =
+ INIT_HOOK_LIST_WITH_VALUE(&InitialNewHook);
+HookList<MallocHook::DeleteHook> delete_hooks_ = INIT_HOOK_LIST;
+HookList<MallocHook::SampledNewHook> sampled_new_hooks_ = INIT_HOOK_LIST;
+HookList<MallocHook::SampledDeleteHook> sampled_delete_hooks_ = INIT_HOOK_LIST;
+HookList<MallocHook::PreMmapHook> premmap_hooks_ =
+ INIT_HOOK_LIST_WITH_VALUE(&InitialPreMMapHook);
+HookList<MallocHook::MmapHook> mmap_hooks_ = INIT_HOOK_LIST;
+HookList<MallocHook::MunmapHook> munmap_hooks_ = INIT_HOOK_LIST;
+HookList<MallocHook::MremapHook> mremap_hooks_ = INIT_HOOK_LIST;
+HookList<MallocHook::PreSbrkHook> presbrk_hooks_ =
+ INIT_HOOK_LIST_WITH_VALUE(InitialPreSbrkHook);
+HookList<MallocHook::SbrkHook> sbrk_hooks_ = INIT_HOOK_LIST;
+
+// These lists contain either 0 or 1 hooks.
+HookList<MallocHook::MmapReplacement> mmap_replacement_ = INIT_HOOK_LIST;
+HookList<MallocHook::MunmapReplacement> munmap_replacement_ = INIT_HOOK_LIST;
+
+#undef INIT_HOOK_LIST_WITH_VALUE
+#undef INIT_HOOK_LIST
+
+} // namespace base_internal
+} // namespace absl
+
+// These are available as C bindings as well as C++, hence their
+// definition outside the MallocHook class.
+extern "C"
+int MallocHook_AddNewHook(MallocHook_NewHook hook) {
+ return absl::base_internal::new_hooks_.Add(hook);
+}
+
+extern "C"
+int MallocHook_RemoveNewHook(MallocHook_NewHook hook) {
+ return absl::base_internal::new_hooks_.Remove(hook);
+}
+
+extern "C"
+int MallocHook_AddDeleteHook(MallocHook_DeleteHook hook) {
+ return absl::base_internal::delete_hooks_.Add(hook);
+}
+
+extern "C"
+int MallocHook_RemoveDeleteHook(MallocHook_DeleteHook hook) {
+ return absl::base_internal::delete_hooks_.Remove(hook);
+}
+
+extern "C" int MallocHook_AddSampledNewHook(MallocHook_SampledNewHook hook) {
+ return absl::base_internal::sampled_new_hooks_.Add(hook);
+}
+
+extern "C" int MallocHook_RemoveSampledNewHook(MallocHook_SampledNewHook hook) {
+ return absl::base_internal::sampled_new_hooks_.Remove(hook);
+}
+
+extern "C" int MallocHook_AddSampledDeleteHook(
+ MallocHook_SampledDeleteHook hook) {
+ return absl::base_internal::sampled_delete_hooks_.Add(hook);
+}
+
+extern "C" int MallocHook_RemoveSampledDeleteHook(
+ MallocHook_SampledDeleteHook hook) {
+ return absl::base_internal::sampled_delete_hooks_.Remove(hook);
+}
+
+extern "C"
+int MallocHook_AddPreMmapHook(MallocHook_PreMmapHook hook) {
+ return absl::base_internal::premmap_hooks_.Add(hook);
+}
+
+extern "C"
+int MallocHook_RemovePreMmapHook(MallocHook_PreMmapHook hook) {
+ return absl::base_internal::premmap_hooks_.Remove(hook);
+}
+
+extern "C"
+int MallocHook_SetMmapReplacement(MallocHook_MmapReplacement hook) {
+ // NOTE this is a best effort CHECK. Concurrent sets could succeed since
+ // this test is outside of the Add spin lock.
+ ABSL_RAW_CHECK(absl::base_internal::mmap_replacement_.empty(),
+ "Only one MMapReplacement is allowed.");
+ return absl::base_internal::mmap_replacement_.Add(hook);
+}
+
+extern "C"
+int MallocHook_RemoveMmapReplacement(MallocHook_MmapReplacement hook) {
+ return absl::base_internal::mmap_replacement_.Remove(hook);
+}
+
+extern "C"
+int MallocHook_AddMmapHook(MallocHook_MmapHook hook) {
+ return absl::base_internal::mmap_hooks_.Add(hook);
+}
+
+extern "C"
+int MallocHook_RemoveMmapHook(MallocHook_MmapHook hook) {
+ return absl::base_internal::mmap_hooks_.Remove(hook);
+}
+
+extern "C"
+int MallocHook_AddMunmapHook(MallocHook_MunmapHook hook) {
+ return absl::base_internal::munmap_hooks_.Add(hook);
+}
+
+extern "C"
+int MallocHook_RemoveMunmapHook(MallocHook_MunmapHook hook) {
+ return absl::base_internal::munmap_hooks_.Remove(hook);
+}
+
+extern "C"
+int MallocHook_SetMunmapReplacement(MallocHook_MunmapReplacement hook) {
+ // NOTE this is a best effort CHECK. Concurrent sets could succeed since
+ // this test is outside of the Add spin lock.
+ ABSL_RAW_CHECK(absl::base_internal::munmap_replacement_.empty(),
+ "Only one MunmapReplacement is allowed.");
+ return absl::base_internal::munmap_replacement_.Add(hook);
+}
+
+extern "C"
+int MallocHook_RemoveMunmapReplacement(MallocHook_MunmapReplacement hook) {
+ return absl::base_internal::munmap_replacement_.Remove(hook);
+}
+
+extern "C"
+int MallocHook_AddMremapHook(MallocHook_MremapHook hook) {
+ return absl::base_internal::mremap_hooks_.Add(hook);
+}
+
+extern "C"
+int MallocHook_RemoveMremapHook(MallocHook_MremapHook hook) {
+ return absl::base_internal::mremap_hooks_.Remove(hook);
+}
+
+extern "C"
+int MallocHook_AddPreSbrkHook(MallocHook_PreSbrkHook hook) {
+ return absl::base_internal::presbrk_hooks_.Add(hook);
+}
+
+extern "C"
+int MallocHook_RemovePreSbrkHook(MallocHook_PreSbrkHook hook) {
+ return absl::base_internal::presbrk_hooks_.Remove(hook);
+}
+
+extern "C"
+int MallocHook_AddSbrkHook(MallocHook_SbrkHook hook) {
+ return absl::base_internal::sbrk_hooks_.Add(hook);
+}
+
+extern "C"
+int MallocHook_RemoveSbrkHook(MallocHook_SbrkHook hook) {
+ return absl::base_internal::sbrk_hooks_.Remove(hook);
+}
+
+namespace absl {
+namespace base_internal {
+
+// Note: embedding the function calls inside the traversal of HookList would be
+// very confusing, as it is legal for a hook to remove itself and add other
+// hooks. Doing traversal first, and then calling the hooks ensures we only
+// call the hooks registered at the start.
+#define INVOKE_HOOKS(HookType, hook_list, args) \
+ do { \
+ HookType hooks[kHookListMaxValues]; \
+ int num_hooks = hook_list.Traverse(hooks, kHookListMaxValues); \
+ for (int i = 0; i < num_hooks; ++i) { \
+ (*hooks[i]) args; \
+ } \
+ } while (0)
+
+// There should only be one replacement. Return the result of the first
+// one, or false if there is none.
+#define INVOKE_REPLACEMENT(HookType, hook_list, args) \
+ do { \
+ HookType hooks[kHookListMaxValues]; \
+ int num_hooks = hook_list.Traverse(hooks, kHookListMaxValues); \
+ return (num_hooks > 0 && (*hooks[0])args); \
+ } while (0)
+
+void MallocHook::InvokeNewHookSlow(const void* ptr, size_t size) {
+ INVOKE_HOOKS(NewHook, new_hooks_, (ptr, size));
+}
+
+void MallocHook::InvokeDeleteHookSlow(const void* ptr) {
+ INVOKE_HOOKS(DeleteHook, delete_hooks_, (ptr));
+}
+
+void MallocHook::InvokeSampledNewHookSlow(const SampledAlloc* sampled_alloc) {
+ INVOKE_HOOKS(SampledNewHook, sampled_new_hooks_, (sampled_alloc));
+}
+
+void MallocHook::InvokeSampledDeleteHookSlow(AllocHandle handle) {
+ INVOKE_HOOKS(SampledDeleteHook, sampled_delete_hooks_, (handle));
+}
+
+void MallocHook::InvokePreMmapHookSlow(const void* start,
+ size_t size,
+ int protection,
+ int flags,
+ int fd,
+ off_t offset) {
+ INVOKE_HOOKS(PreMmapHook, premmap_hooks_, (start, size, protection, flags, fd,
+ offset));
+}
+
+void MallocHook::InvokeMmapHookSlow(const void* result,
+ const void* start,
+ size_t size,
+ int protection,
+ int flags,
+ int fd,
+ off_t offset) {
+ INVOKE_HOOKS(MmapHook, mmap_hooks_, (result, start, size, protection, flags,
+ fd, offset));
+}
+
+bool MallocHook::InvokeMmapReplacementSlow(const void* start,
+ size_t size,
+ int protection,
+ int flags,
+ int fd,
+ off_t offset,
+ void** result) {
+ INVOKE_REPLACEMENT(MmapReplacement, mmap_replacement_,
+ (start, size, protection, flags, fd, offset, result));
+}
+
+void MallocHook::InvokeMunmapHookSlow(const void* start, size_t size) {
+ INVOKE_HOOKS(MunmapHook, munmap_hooks_, (start, size));
+}
+
+bool MallocHook::InvokeMunmapReplacementSlow(const void* start,
+ size_t size,
+ int* result) {
+ INVOKE_REPLACEMENT(MunmapReplacement, munmap_replacement_,
+ (start, size, result));
+}
+
+void MallocHook::InvokeMremapHookSlow(const void* result,
+ const void* old_addr,
+ size_t old_size,
+ size_t new_size,
+ int flags,
+ const void* new_addr) {
+ INVOKE_HOOKS(MremapHook, mremap_hooks_, (result, old_addr, old_size, new_size,
+ flags, new_addr));
+}
+
+void MallocHook::InvokePreSbrkHookSlow(ptrdiff_t increment) {
+ INVOKE_HOOKS(PreSbrkHook, presbrk_hooks_, (increment));
+}
+
+void MallocHook::InvokeSbrkHookSlow(const void* result, ptrdiff_t increment) {
+ INVOKE_HOOKS(SbrkHook, sbrk_hooks_, (result, increment));
+}
+
+#undef INVOKE_HOOKS
+#undef INVOKE_REPLACEMENT
+
+} // namespace base_internal
+} // namespace absl
+
+ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(google_malloc);
+ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(google_malloc);
+// actual functions are in debugallocation.cc or tcmalloc.cc
+ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(malloc_hook);
+ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(malloc_hook);
+// actual functions are in this file, malloc_hook.cc, and low_level_alloc.cc
+ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(blink_malloc);
+ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(blink_malloc);
+// actual functions are in third_party/blink_headless/.../{PartitionAlloc,
+// FastMalloc}.cpp.
+
+#define ADDR_IN_ATTRIBUTE_SECTION(addr, name) \
+ (reinterpret_cast<uintptr_t>(ABSL_ATTRIBUTE_SECTION_START(name)) <= \
+ reinterpret_cast<uintptr_t>(addr) && \
+ reinterpret_cast<uintptr_t>(addr) < \
+ reinterpret_cast<uintptr_t>(ABSL_ATTRIBUTE_SECTION_STOP(name)))
+
+// Return true iff 'caller' is a return address within a function
+// that calls one of our hooks via MallocHook:Invoke*.
+// A helper for GetCallerStackTrace.
+static inline bool InHookCaller(const void* caller) {
+ return ADDR_IN_ATTRIBUTE_SECTION(caller, google_malloc) ||
+ ADDR_IN_ATTRIBUTE_SECTION(caller, malloc_hook) ||
+ ADDR_IN_ATTRIBUTE_SECTION(caller, blink_malloc);
+ // We can use one section for everything except tcmalloc_or_debug
+ // due to its special linkage mode, which prevents merging of the sections.
+}
+
+#undef ADDR_IN_ATTRIBUTE_SECTION
+
+static absl::once_flag in_hook_caller_once;
+
+static void InitializeInHookCaller() {
+ ABSL_INIT_ATTRIBUTE_SECTION_VARS(google_malloc);
+ if (ABSL_ATTRIBUTE_SECTION_START(google_malloc) ==
+ ABSL_ATTRIBUTE_SECTION_STOP(google_malloc)) {
+ ABSL_RAW_LOG(ERROR,
+ "google_malloc section is missing, "
+ "thus InHookCaller is broken!");
+ }
+ ABSL_INIT_ATTRIBUTE_SECTION_VARS(malloc_hook);
+ if (ABSL_ATTRIBUTE_SECTION_START(malloc_hook) ==
+ ABSL_ATTRIBUTE_SECTION_STOP(malloc_hook)) {
+ ABSL_RAW_LOG(ERROR,
+ "malloc_hook section is missing, "
+ "thus InHookCaller is broken!");
+ }
+ ABSL_INIT_ATTRIBUTE_SECTION_VARS(blink_malloc);
+ // The blink_malloc section is only expected to be present in binaries
+ // linking against the blink rendering engine in third_party/blink_headless.
+}
+
+// We can improve behavior/compactness of this function
+// if we pass a generic test function (with a generic arg)
+// into the implementations for get_stack_trace_fn instead of the skip_count.
+extern "C" int MallocHook_GetCallerStackTrace(
+ void** result, int max_depth, int skip_count,
+ MallocHook_GetStackTraceFn get_stack_trace_fn) {
+ if (!ABSL_HAVE_ATTRIBUTE_SECTION) {
+ // Fall back to get_stack_trace_fn and good old but fragile frame skip
+ // counts.
+ // Note: this path is inaccurate when a hook is not called directly by an
+ // allocation function but is daisy-chained through another hook,
+ // search for MallocHook::(Get|Set|Invoke)* to find such cases.
+#ifdef NDEBUG
+ return get_stack_trace_fn(result, max_depth, skip_count);
+#else
+ return get_stack_trace_fn(result, max_depth, skip_count + 1);
+#endif
+ // due to -foptimize-sibling-calls in opt mode
+ // there's no need for extra frame skip here then
+ }
+ absl::call_once(in_hook_caller_once, InitializeInHookCaller);
+ // MallocHook caller determination via InHookCaller works, use it:
+ static const int kMaxSkip = 32 + 6 + 3;
+ // Constant tuned to do just one get_stack_trace_fn call below in practice
+ // and not get many frames that we don't actually need:
+ // currently max passed max_depth is 32,
+ // max passed/needed skip_count is 6
+ // and 3 is to account for some hook daisy chaining.
+ static const int kStackSize = kMaxSkip + 1;
+ void* stack[kStackSize];
+ int depth =
+ get_stack_trace_fn(stack, kStackSize, 1); // skip this function frame
+ if (depth == 0)
+ // silently propagate cases when get_stack_trace_fn does not work
+ return 0;
+ for (int i = depth - 1; i >= 0; --i) { // stack[0] is our immediate caller
+ if (InHookCaller(stack[i])) {
+ i += 1; // skip hook caller frame
+ depth -= i; // correct depth
+ if (depth > max_depth) depth = max_depth;
+ std::copy(stack + i, stack + i + depth, result);
+ if (depth < max_depth && depth + i == kStackSize) {
+ // get frames for the missing depth
+ depth += get_stack_trace_fn(result + depth, max_depth - depth,
+ 1 + kStackSize);
+ }
+ return depth;
+ }
+ }
+ ABSL_RAW_LOG(WARNING,
+ "Hooked allocator frame not found, returning empty trace");
+ // If this happens try increasing kMaxSkip
+ // or else something must be wrong with InHookCaller,
+ // e.g. for every section used in InHookCaller
+ // all functions in that section must be inside the same library.
+ return 0;
+}
+
+// On systems where we know how, we override mmap/munmap/mremap/sbrk
+// to provide support for calling the related hooks (in addition,
+// of course, to doing what these functions normally do).
+
+// The ABSL_MALLOC_HOOK_MMAP_DISABLE macro disables mmap/munmap interceptors.
+// Dynamic tools that intercept mmap/munmap can't be linked together with
+// malloc_hook interceptors. We disable the malloc_hook interceptors for the
+// widely-used dynamic tools, i.e. ThreadSanitizer and MemorySanitizer, but
+// still allow users to disable this in special cases that can't be easily
+// detected during compilation, via -DABSL_MALLOC_HOOK_MMAP_DISABLE or #define
+// ABSL_MALLOC_HOOK_MMAP_DISABLE.
+// TODO(b/62370839): Remove MALLOC_HOOK_MMAP_DISABLE in CROSSTOOL for tsan and
+// msan config; Replace MALLOC_HOOK_MMAP_DISABLE with
+// ABSL_MALLOC_HOOK_MMAP_DISABLE for other special cases.
+#if !defined(THREAD_SANITIZER) && !defined(MEMORY_SANITIZER) && \
+ !defined(ABSL_MALLOC_HOOK_MMAP_DISABLE) && defined(__linux__)
+#include "absl/base/internal/malloc_hook_mmap_linux.inc"
+
+#elif ABSL_HAVE_MMAP
+
+namespace absl {
+namespace base_internal {
+
+// static
+void* MallocHook::UnhookedMMap(void* start, size_t size, int protection,
+ int flags, int fd, off_t offset) {
+ void* result;
+ if (!MallocHook::InvokeMmapReplacement(
+ start, size, protection, flags, fd, offset, &result)) {
+ result = mmap(start, size, protection, flags, fd, offset);
+ }
+ return result;
+}
+
+// static
+int MallocHook::UnhookedMUnmap(void* start, size_t size) {
+ int result;
+ if (!MallocHook::InvokeMunmapReplacement(start, size, &result)) {
+ result = munmap(start, size);
+ }
+ return result;
+}
+
+} // namespace base_internal
+} // namespace absl
+
+#endif
diff --git a/absl/base/internal/malloc_hook.h b/absl/base/internal/malloc_hook.h
new file mode 100644
index 0000000..ed5cf2e
--- /dev/null
+++ b/absl/base/internal/malloc_hook.h
@@ -0,0 +1,333 @@
+//
+// 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.
+//
+
+// Some of our malloc implementations can invoke the following hooks whenever
+// memory is allocated or deallocated. MallocHook is thread-safe, and things
+// you do before calling AddFooHook(MyHook) are visible to any resulting calls
+// to MyHook. Hooks must be thread-safe. If you write:
+//
+// CHECK(MallocHook::AddNewHook(&MyNewHook));
+//
+// MyNewHook will be invoked in subsequent calls in the current thread, but
+// there are no guarantees on when it might be invoked in other threads.
+//
+// There are a limited number of slots available for each hook type. Add*Hook
+// will return false if there are no slots available. Remove*Hook will return
+// false if the given hook was not already installed.
+//
+// The order in which individual hooks are called in Invoke*Hook is undefined.
+//
+// It is safe for a hook to remove itself within Invoke*Hook and add other
+// hooks. Any hooks added inside a hook invocation (for the same hook type)
+// will not be invoked for the current invocation.
+//
+// One important user of these hooks is the heap profiler.
+//
+// CAVEAT: If you add new MallocHook::Invoke* calls then those calls must be
+// directly in the code of the (de)allocation function that is provided to the
+// user and that function must have an ABSL_ATTRIBUTE_SECTION(malloc_hook)
+// attribute.
+//
+// Note: the Invoke*Hook() functions are defined in malloc_hook-inl.h. If you
+// need to invoke a hook (which you shouldn't unless you're part of tcmalloc),
+// be sure to #include malloc_hook-inl.h in addition to malloc_hook.h.
+//
+// NOTE FOR C USERS: If you want to use malloc_hook functionality from
+// a C program, #include malloc_hook_c.h instead of this file.
+//
+// IWYU pragma: private, include "base/malloc_hook.h"
+
+#ifndef ABSL_BASE_INTERNAL_MALLOC_HOOK_H_
+#define ABSL_BASE_INTERNAL_MALLOC_HOOK_H_
+
+#include <sys/types.h>
+#include <cstddef>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/malloc_hook_c.h"
+#include "absl/base/port.h"
+
+namespace absl {
+namespace base_internal {
+
+// Note: malloc_hook_c.h defines MallocHook_*Hook and
+// MallocHook_{Add,Remove}*Hook. The version of these inside the MallocHook
+// class are defined in terms of the malloc_hook_c version. See malloc_hook_c.h
+// for details of these types/functions.
+
+class MallocHook {
+ public:
+ // The NewHook is invoked whenever an object is being allocated.
+ // Object pointer and size are passed in.
+ // It may be passed null pointer if the allocator returned null.
+ typedef MallocHook_NewHook NewHook;
+ inline static bool AddNewHook(NewHook hook) {
+ return MallocHook_AddNewHook(hook);
+ }
+ inline static bool RemoveNewHook(NewHook hook) {
+ return MallocHook_RemoveNewHook(hook);
+ }
+ inline static void InvokeNewHook(const void* ptr, size_t size);
+
+ // The DeleteHook is invoked whenever an object is being deallocated.
+ // Object pointer is passed in.
+ // It may be passed null pointer if the caller is trying to delete null.
+ typedef MallocHook_DeleteHook DeleteHook;
+ inline static bool AddDeleteHook(DeleteHook hook) {
+ return MallocHook_AddDeleteHook(hook);
+ }
+ inline static bool RemoveDeleteHook(DeleteHook hook) {
+ return MallocHook_RemoveDeleteHook(hook);
+ }
+ inline static void InvokeDeleteHook(const void* ptr);
+
+ // The SampledNewHook is invoked for some subset of object allocations
+ // according to the sampling policy of an allocator such as tcmalloc.
+ // SampledAlloc has the following fields:
+ // * AllocHandle handle: to be set to an effectively unique value (in this
+ // process) by allocator.
+ // * size_t allocated_size: space actually used by allocator to host
+ // the object.
+ // * int stack_depth and const void* stack: invocation stack for
+ // the allocation.
+ // The allocator invoking the hook should record the handle value and later
+ // call InvokeSampledDeleteHook() with that value.
+ typedef MallocHook_SampledNewHook SampledNewHook;
+ typedef MallocHook_SampledAlloc SampledAlloc;
+ inline static bool AddSampledNewHook(SampledNewHook hook) {
+ return MallocHook_AddSampledNewHook(hook);
+ }
+ inline static bool RemoveSampledNewHook(SampledNewHook hook) {
+ return MallocHook_RemoveSampledNewHook(hook);
+ }
+ inline static void InvokeSampledNewHook(const SampledAlloc* sampled_alloc);
+
+ // The SampledDeleteHook is invoked whenever an object previously chosen
+ // by an allocator for sampling is being deallocated.
+ // The handle identifying the object --as previously chosen by
+ // InvokeSampledNewHook()-- is passed in.
+ typedef MallocHook_SampledDeleteHook SampledDeleteHook;
+ typedef MallocHook_AllocHandle AllocHandle;
+ inline static bool AddSampledDeleteHook(SampledDeleteHook hook) {
+ return MallocHook_AddSampledDeleteHook(hook);
+ }
+ inline static bool RemoveSampledDeleteHook(SampledDeleteHook hook) {
+ return MallocHook_RemoveSampledDeleteHook(hook);
+ }
+ inline static void InvokeSampledDeleteHook(AllocHandle handle);
+
+ // The PreMmapHook is invoked with mmap's or mmap64's arguments just
+ // before the mmap/mmap64 call is actually made. Such a hook may be useful
+ // in memory limited contexts, to catch allocations that will exceed
+ // a memory limit, and take outside actions to increase that limit.
+ typedef MallocHook_PreMmapHook PreMmapHook;
+ inline static bool AddPreMmapHook(PreMmapHook hook) {
+ return MallocHook_AddPreMmapHook(hook);
+ }
+ inline static bool RemovePreMmapHook(PreMmapHook hook) {
+ return MallocHook_RemovePreMmapHook(hook);
+ }
+ inline static void InvokePreMmapHook(const void* start,
+ size_t size,
+ int protection,
+ int flags,
+ int fd,
+ off_t offset);
+
+ // The MmapReplacement is invoked with mmap's arguments and place to put the
+ // result into after the PreMmapHook but before the mmap/mmap64 call is
+ // actually made.
+ // The MmapReplacement should return true if it handled the call, or false
+ // if it is still necessary to call mmap/mmap64.
+ // This should be used only by experts, and users must be be
+ // extremely careful to avoid recursive calls to mmap. The replacement
+ // should be async signal safe.
+ // Only one MmapReplacement is supported. After setting an MmapReplacement
+ // you must call RemoveMmapReplacement before calling SetMmapReplacement
+ // again.
+ typedef MallocHook_MmapReplacement MmapReplacement;
+ inline static bool SetMmapReplacement(MmapReplacement hook) {
+ return MallocHook_SetMmapReplacement(hook);
+ }
+ inline static bool RemoveMmapReplacement(MmapReplacement hook) {
+ return MallocHook_RemoveMmapReplacement(hook);
+ }
+ inline static bool InvokeMmapReplacement(const void* start,
+ size_t size,
+ int protection,
+ int flags,
+ int fd,
+ off_t offset,
+ void** result);
+
+
+ // The MmapHook is invoked with mmap's return value and arguments whenever
+ // a region of memory has been just mapped.
+ // It may be passed MAP_FAILED if the mmap failed.
+ typedef MallocHook_MmapHook MmapHook;
+ inline static bool AddMmapHook(MmapHook hook) {
+ return MallocHook_AddMmapHook(hook);
+ }
+ inline static bool RemoveMmapHook(MmapHook hook) {
+ return MallocHook_RemoveMmapHook(hook);
+ }
+ inline static void InvokeMmapHook(const void* result,
+ const void* start,
+ size_t size,
+ int protection,
+ int flags,
+ int fd,
+ off_t offset);
+
+ // The MunmapReplacement is invoked with munmap's arguments and place to put
+ // the result into just before the munmap call is actually made.
+ // The MunmapReplacement should return true if it handled the call, or false
+ // if it is still necessary to call munmap.
+ // This should be used only by experts. The replacement should be
+ // async signal safe.
+ // Only one MunmapReplacement is supported. After setting an
+ // MunmapReplacement you must call RemoveMunmapReplacement before
+ // calling SetMunmapReplacement again.
+ typedef MallocHook_MunmapReplacement MunmapReplacement;
+ inline static bool SetMunmapReplacement(MunmapReplacement hook) {
+ return MallocHook_SetMunmapReplacement(hook);
+ }
+ inline static bool RemoveMunmapReplacement(MunmapReplacement hook) {
+ return MallocHook_RemoveMunmapReplacement(hook);
+ }
+ inline static bool InvokeMunmapReplacement(const void* start,
+ size_t size,
+ int* result);
+
+ // The MunmapHook is invoked with munmap's arguments just before the munmap
+ // call is actually made.
+ // TODO(maxim): Rename this to PreMunmapHook for consistency with PreMmapHook
+ // and PreSbrkHook.
+ typedef MallocHook_MunmapHook MunmapHook;
+ inline static bool AddMunmapHook(MunmapHook hook) {
+ return MallocHook_AddMunmapHook(hook);
+ }
+ inline static bool RemoveMunmapHook(MunmapHook hook) {
+ return MallocHook_RemoveMunmapHook(hook);
+ }
+ inline static void InvokeMunmapHook(const void* start, size_t size);
+
+ // The MremapHook is invoked with mremap's return value and arguments
+ // whenever a region of memory has been just remapped.
+ typedef MallocHook_MremapHook MremapHook;
+ inline static bool AddMremapHook(MremapHook hook) {
+ return MallocHook_AddMremapHook(hook);
+ }
+ inline static bool RemoveMremapHook(MremapHook hook) {
+ return MallocHook_RemoveMremapHook(hook);
+ }
+ inline static void InvokeMremapHook(const void* result,
+ const void* old_addr,
+ size_t old_size,
+ size_t new_size,
+ int flags,
+ const void* new_addr);
+
+ // The PreSbrkHook is invoked with sbrk's argument just before sbrk is called
+ // -- except when the increment is 0. This is because sbrk(0) is often called
+ // to get the top of the memory stack, and is not actually a
+ // memory-allocation call. It may be useful in memory-limited contexts,
+ // to catch allocations that will exceed the limit and take outside
+ // actions to increase such a limit.
+ typedef MallocHook_PreSbrkHook PreSbrkHook;
+ inline static bool AddPreSbrkHook(PreSbrkHook hook) {
+ return MallocHook_AddPreSbrkHook(hook);
+ }
+ inline static bool RemovePreSbrkHook(PreSbrkHook hook) {
+ return MallocHook_RemovePreSbrkHook(hook);
+ }
+ inline static void InvokePreSbrkHook(ptrdiff_t increment);
+
+ // The SbrkHook is invoked with sbrk's result and argument whenever sbrk
+ // has just executed -- except when the increment is 0.
+ // This is because sbrk(0) is often called to get the top of the memory stack,
+ // and is not actually a memory-allocation call.
+ typedef MallocHook_SbrkHook SbrkHook;
+ inline static bool AddSbrkHook(SbrkHook hook) {
+ return MallocHook_AddSbrkHook(hook);
+ }
+ inline static bool RemoveSbrkHook(SbrkHook hook) {
+ return MallocHook_RemoveSbrkHook(hook);
+ }
+ inline static void InvokeSbrkHook(const void* result, ptrdiff_t increment);
+
+ // Pointer to a absl::GetStackTrace implementation, following the API in
+ // base/stacktrace.h.
+ using GetStackTraceFn = int (*)(void**, int, int);
+
+ // Get the current stack trace. Try to skip all routines up to and
+ // including the caller of MallocHook::Invoke*.
+ // Use "skip_count" (similarly to absl::GetStackTrace from stacktrace.h)
+ // as a hint about how many routines to skip if better information
+ // is not available.
+ // Stack trace is filled into *result up to the size of max_depth.
+ // The actual number of stack frames filled is returned.
+ inline static int GetCallerStackTrace(void** result, int max_depth,
+ int skip_count,
+ GetStackTraceFn get_stack_trace_fn) {
+ return MallocHook_GetCallerStackTrace(result, max_depth, skip_count,
+ get_stack_trace_fn);
+ }
+
+#if ABSL_HAVE_MMAP
+ // Unhooked versions of mmap() and munmap(). These should be used
+ // only by experts, since they bypass heapchecking, etc.
+ // Note: These do not run hooks, but they still use the MmapReplacement
+ // and MunmapReplacement.
+ static void* UnhookedMMap(void* start, size_t size, int protection, int flags,
+ int fd, off_t offset);
+ static int UnhookedMUnmap(void* start, size_t size);
+#endif
+
+ private:
+ // Slow path versions of Invoke*Hook.
+ static void InvokeNewHookSlow(const void* ptr,
+ size_t size) ABSL_ATTRIBUTE_COLD;
+ static void InvokeDeleteHookSlow(const void* ptr) ABSL_ATTRIBUTE_COLD;
+ static void InvokeSampledNewHookSlow(const SampledAlloc* sampled_alloc)
+ ABSL_ATTRIBUTE_COLD;
+ static void InvokeSampledDeleteHookSlow(AllocHandle handle)
+ ABSL_ATTRIBUTE_COLD;
+ static void InvokePreMmapHookSlow(const void* start, size_t size,
+ int protection, int flags, int fd,
+ off_t offset) ABSL_ATTRIBUTE_COLD;
+ static void InvokeMmapHookSlow(const void* result, const void* start,
+ size_t size, int protection, int flags, int fd,
+ off_t offset) ABSL_ATTRIBUTE_COLD;
+ static bool InvokeMmapReplacementSlow(const void* start, size_t size,
+ int protection, int flags, int fd,
+ off_t offset,
+ void** result) ABSL_ATTRIBUTE_COLD;
+ static void InvokeMunmapHookSlow(const void* ptr,
+ size_t size) ABSL_ATTRIBUTE_COLD;
+ static bool InvokeMunmapReplacementSlow(const void* ptr, size_t size,
+ int* result) ABSL_ATTRIBUTE_COLD;
+ static void InvokeMremapHookSlow(const void* result, const void* old_addr,
+ size_t old_size, size_t new_size, int flags,
+ const void* new_addr) ABSL_ATTRIBUTE_COLD;
+ static void InvokePreSbrkHookSlow(ptrdiff_t increment) ABSL_ATTRIBUTE_COLD;
+ static void InvokeSbrkHookSlow(const void* result,
+ ptrdiff_t increment) ABSL_ATTRIBUTE_COLD;
+};
+
+} // namespace base_internal
+} // namespace absl
+#endif // ABSL_BASE_INTERNAL_MALLOC_HOOK_H_
diff --git a/absl/base/internal/malloc_hook_c.h b/absl/base/internal/malloc_hook_c.h
new file mode 100644
index 0000000..03b84ca
--- /dev/null
+++ b/absl/base/internal/malloc_hook_c.h
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+/*
+ * C shims for the C++ malloc_hook.h. See malloc_hook.h for details
+ * on how to use these.
+ */
+#ifndef ABSL_BASE_INTERNAL_MALLOC_HOOK_C_H_
+#define ABSL_BASE_INTERNAL_MALLOC_HOOK_C_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Get the current stack trace. Try to skip all routines up to and
+ * including the caller of MallocHook::Invoke*.
+ * Use "skip_count" (similarly to absl::GetStackTrace from stacktrace.h)
+ * as a hint about how many routines to skip if better information
+ * is not available.
+ */
+typedef int (*MallocHook_GetStackTraceFn)(void**, int, int);
+int MallocHook_GetCallerStackTrace(void** result, int max_depth, int skip_count,
+ MallocHook_GetStackTraceFn fn);
+
+/* All the MallocHook_{Add,Remove}*Hook functions below return 1 on success
+ * and 0 on failure.
+ */
+
+typedef void (*MallocHook_NewHook)(const void* ptr, size_t size);
+int MallocHook_AddNewHook(MallocHook_NewHook hook);
+int MallocHook_RemoveNewHook(MallocHook_NewHook hook);
+
+typedef void (*MallocHook_DeleteHook)(const void* ptr);
+int MallocHook_AddDeleteHook(MallocHook_DeleteHook hook);
+int MallocHook_RemoveDeleteHook(MallocHook_DeleteHook hook);
+
+typedef int64_t MallocHook_AllocHandle;
+typedef struct {
+ /* See malloc_hook.h for documentation for this struct. */
+ MallocHook_AllocHandle handle;
+ size_t allocated_size;
+ int stack_depth;
+ const void* stack;
+} MallocHook_SampledAlloc;
+typedef void (*MallocHook_SampledNewHook)(
+ const MallocHook_SampledAlloc* sampled_alloc);
+int MallocHook_AddSampledNewHook(MallocHook_SampledNewHook hook);
+int MallocHook_RemoveSampledNewHook(MallocHook_SampledNewHook hook);
+
+typedef void (*MallocHook_SampledDeleteHook)(MallocHook_AllocHandle handle);
+int MallocHook_AddSampledDeleteHook(MallocHook_SampledDeleteHook hook);
+int MallocHook_RemoveSampledDeleteHook(MallocHook_SampledDeleteHook hook);
+
+typedef void (*MallocHook_PreMmapHook)(const void *start,
+ size_t size,
+ int protection,
+ int flags,
+ int fd,
+ off_t offset);
+int MallocHook_AddPreMmapHook(MallocHook_PreMmapHook hook);
+int MallocHook_RemovePreMmapHook(MallocHook_PreMmapHook hook);
+
+typedef void (*MallocHook_MmapHook)(const void* result,
+ const void* start,
+ size_t size,
+ int protection,
+ int flags,
+ int fd,
+ off_t offset);
+int MallocHook_AddMmapHook(MallocHook_MmapHook hook);
+int MallocHook_RemoveMmapHook(MallocHook_MmapHook hook);
+
+typedef int (*MallocHook_MmapReplacement)(const void* start,
+ size_t size,
+ int protection,
+ int flags,
+ int fd,
+ off_t offset,
+ void** result);
+int MallocHook_SetMmapReplacement(MallocHook_MmapReplacement hook);
+int MallocHook_RemoveMmapReplacement(MallocHook_MmapReplacement hook);
+
+typedef void (*MallocHook_MunmapHook)(const void* start, size_t size);
+int MallocHook_AddMunmapHook(MallocHook_MunmapHook hook);
+int MallocHook_RemoveMunmapHook(MallocHook_MunmapHook hook);
+
+typedef int (*MallocHook_MunmapReplacement)(const void* start,
+ size_t size,
+ int* result);
+int MallocHook_SetMunmapReplacement(MallocHook_MunmapReplacement hook);
+int MallocHook_RemoveMunmapReplacement(MallocHook_MunmapReplacement hook);
+
+typedef void (*MallocHook_MremapHook)(const void* result,
+ const void* old_addr,
+ size_t old_size,
+ size_t new_size,
+ int flags,
+ const void* new_addr);
+int MallocHook_AddMremapHook(MallocHook_MremapHook hook);
+int MallocHook_RemoveMremapHook(MallocHook_MremapHook hook);
+
+typedef void (*MallocHook_PreSbrkHook)(ptrdiff_t increment);
+int MallocHook_AddPreSbrkHook(MallocHook_PreSbrkHook hook);
+int MallocHook_RemovePreSbrkHook(MallocHook_PreSbrkHook hook);
+
+typedef void (*MallocHook_SbrkHook)(const void* result, ptrdiff_t increment);
+int MallocHook_AddSbrkHook(MallocHook_SbrkHook hook);
+int MallocHook_RemoveSbrkHook(MallocHook_SbrkHook hook);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* ABSL_BASE_INTERNAL_MALLOC_HOOK_C_H_ */
diff --git a/absl/base/internal/malloc_hook_invoke.h b/absl/base/internal/malloc_hook_invoke.h
new file mode 100644
index 0000000..c08220c
--- /dev/null
+++ b/absl/base/internal/malloc_hook_invoke.h
@@ -0,0 +1,198 @@
+//
+// 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 has the implementation details of malloc_hook that are needed
+// to use malloc-hook inside the tcmalloc system. It does not hold
+// any of the client-facing calls that are used to add new hooks.
+//
+// IWYU pragma: private, include "base/malloc_hook-inl.h"
+
+#ifndef ABSL_BASE_INTERNAL_MALLOC_HOOK_INVOKE_H_
+#define ABSL_BASE_INTERNAL_MALLOC_HOOK_INVOKE_H_
+
+#include <sys/types.h>
+#include <atomic>
+#include <cstddef>
+
+#include "absl/base/internal/malloc_hook.h"
+
+namespace absl {
+namespace base_internal {
+
+// Maximum of 7 hooks means that HookList is 8 words.
+static constexpr int kHookListMaxValues = 7;
+
+// HookList: a class that provides synchronized insertions and removals and
+// lockless traversal. Most of the implementation is in malloc_hook.cc.
+template <typename T>
+struct HookList {
+ static_assert(sizeof(T) <= sizeof(intptr_t), "T_should_fit_in_intptr_t");
+
+ // Adds value to the list. Note that duplicates are allowed. Thread-safe and
+ // blocking (acquires hooklist_spinlock). Returns true on success; false
+ // otherwise (failures include invalid value and no space left).
+ bool Add(T value);
+
+ // Removes the first entry matching value from the list. Thread-safe and
+ // blocking (acquires hooklist_spinlock). Returns true on success; false
+ // otherwise (failures include invalid value and no value found).
+ bool Remove(T value);
+
+ // Store up to n values of the list in output_array, and return the number of
+ // elements stored. Thread-safe and non-blocking. This is fast (one memory
+ // access) if the list is empty.
+ int Traverse(T* output_array, int n) const;
+
+ // Fast inline implementation for fast path of Invoke*Hook.
+ bool empty() const {
+ // empty() is only used as an optimization to determine if we should call
+ // Traverse which has proper acquire loads. Memory reordering around a
+ // call to empty will either lead to an unnecessary Traverse call, or will
+ // miss invoking hooks, neither of which is a problem.
+ return priv_end.load(std::memory_order_relaxed) == 0;
+ }
+
+ // This internal data is not private so that the class is an aggregate and can
+ // be initialized by the linker. Don't access this directly. Use the
+ // INIT_HOOK_LIST macro in malloc_hook.cc.
+
+ // One more than the index of the last valid element in priv_data. During
+ // 'Remove' this may be past the last valid element in priv_data, but
+ // subsequent values will be 0.
+ std::atomic<int> priv_end;
+ std::atomic<intptr_t> priv_data[kHookListMaxValues];
+};
+
+extern template struct HookList<MallocHook::NewHook>;
+
+extern HookList<MallocHook::NewHook> new_hooks_;
+extern HookList<MallocHook::DeleteHook> delete_hooks_;
+extern HookList<MallocHook::SampledNewHook> sampled_new_hooks_;
+extern HookList<MallocHook::SampledDeleteHook> sampled_delete_hooks_;
+extern HookList<MallocHook::PreMmapHook> premmap_hooks_;
+extern HookList<MallocHook::MmapHook> mmap_hooks_;
+extern HookList<MallocHook::MmapReplacement> mmap_replacement_;
+extern HookList<MallocHook::MunmapHook> munmap_hooks_;
+extern HookList<MallocHook::MunmapReplacement> munmap_replacement_;
+extern HookList<MallocHook::MremapHook> mremap_hooks_;
+extern HookList<MallocHook::PreSbrkHook> presbrk_hooks_;
+extern HookList<MallocHook::SbrkHook> sbrk_hooks_;
+
+inline void MallocHook::InvokeNewHook(const void* ptr, size_t size) {
+ if (!absl::base_internal::new_hooks_.empty()) {
+ InvokeNewHookSlow(ptr, size);
+ }
+}
+
+inline void MallocHook::InvokeDeleteHook(const void* ptr) {
+ if (!absl::base_internal::delete_hooks_.empty()) {
+ InvokeDeleteHookSlow(ptr);
+ }
+}
+
+inline void MallocHook::InvokeSampledNewHook(
+ const SampledAlloc* sampled_alloc) {
+ if (!absl::base_internal::sampled_new_hooks_.empty()) {
+ InvokeSampledNewHookSlow(sampled_alloc);
+ }
+}
+
+inline void MallocHook::InvokeSampledDeleteHook(AllocHandle handle) {
+ if (!absl::base_internal::sampled_delete_hooks_.empty()) {
+ InvokeSampledDeleteHookSlow(handle);
+ }
+}
+
+inline void MallocHook::InvokePreMmapHook(const void* start,
+ size_t size,
+ int protection,
+ int flags,
+ int fd,
+ off_t offset) {
+ if (!absl::base_internal::premmap_hooks_.empty()) {
+ InvokePreMmapHookSlow(start, size, protection, flags, fd, offset);
+ }
+}
+
+inline void MallocHook::InvokeMmapHook(const void* result,
+ const void* start,
+ size_t size,
+ int protection,
+ int flags,
+ int fd,
+ off_t offset) {
+ if (!absl::base_internal::mmap_hooks_.empty()) {
+ InvokeMmapHookSlow(result, start, size, protection, flags, fd, offset);
+ }
+}
+
+inline bool MallocHook::InvokeMmapReplacement(const void* start,
+ size_t size,
+ int protection,
+ int flags,
+ int fd,
+ off_t offset,
+ void** result) {
+ if (!absl::base_internal::mmap_replacement_.empty()) {
+ return InvokeMmapReplacementSlow(start, size,
+ protection, flags,
+ fd, offset,
+ result);
+ }
+ return false;
+}
+
+inline void MallocHook::InvokeMunmapHook(const void* start, size_t size) {
+ if (!absl::base_internal::munmap_hooks_.empty()) {
+ InvokeMunmapHookSlow(start, size);
+ }
+}
+
+inline bool MallocHook::InvokeMunmapReplacement(
+ const void* start, size_t size, int* result) {
+ if (!absl::base_internal::mmap_replacement_.empty()) {
+ return InvokeMunmapReplacementSlow(start, size, result);
+ }
+ return false;
+}
+
+inline void MallocHook::InvokeMremapHook(const void* result,
+ const void* old_addr,
+ size_t old_size,
+ size_t new_size,
+ int flags,
+ const void* new_addr) {
+ if (!absl::base_internal::mremap_hooks_.empty()) {
+ InvokeMremapHookSlow(result, old_addr, old_size, new_size, flags, new_addr);
+ }
+}
+
+inline void MallocHook::InvokePreSbrkHook(ptrdiff_t increment) {
+ if (!absl::base_internal::presbrk_hooks_.empty() && increment != 0) {
+ InvokePreSbrkHookSlow(increment);
+ }
+}
+
+inline void MallocHook::InvokeSbrkHook(const void* result,
+ ptrdiff_t increment) {
+ if (!absl::base_internal::sbrk_hooks_.empty() && increment != 0) {
+ InvokeSbrkHookSlow(result, increment);
+ }
+}
+
+} // namespace base_internal
+} // namespace absl
+#endif // ABSL_BASE_INTERNAL_MALLOC_HOOK_INVOKE_H_
diff --git a/absl/base/internal/malloc_hook_mmap_linux.inc b/absl/base/internal/malloc_hook_mmap_linux.inc
new file mode 100644
index 0000000..059ded5
--- /dev/null
+++ b/absl/base/internal/malloc_hook_mmap_linux.inc
@@ -0,0 +1,236 @@
+// 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 define mmap() and mmap64(), which somewhat reimplements libc's mmap
+// syscall stubs. Unfortunately libc only exports the stubs via weak symbols
+// (which we're overriding with our mmap64() and mmap() wrappers) so we can't
+// just call through to them.
+
+#ifndef __linux__
+# error Should only be including malloc_hook_mmap_linux.h on linux systems.
+#endif
+
+#include <sys/mman.h>
+#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, SYS_munmap, and SYS_mremap are not defined in Android.
+#ifdef __BIONIC__
+extern "C" void *__mmap2(void *, size_t, int, int, int, long);
+#if defined(__NR_mmap) && !defined(SYS_mmap)
+#define SYS_mmap __NR_mmap
+#endif
+#ifndef SYS_munmap
+#define SYS_munmap __NR_munmap
+#endif
+#ifndef SYS_mremap
+#define SYS_mremap __NR_mremap
+#endif
+#endif // __BIONIC__
+
+// Platform specific logic extracted from
+// https://chromium.googlesource.com/linux-syscall-support/+/master/linux_syscall_support.h
+static inline void* do_mmap64(void* start, size_t length, int prot,
+ int flags, int fd, off64_t offset) __THROW {
+#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
+}
+
+// We use do_mmap64 abstraction to put MallocHook::InvokeMmapHook
+// calls right into mmap and mmap64, so that the stack frames in the caller's
+// stack are at the same offsets for all the calls of memory allocating
+// functions.
+
+// Put all callers of MallocHook::Invoke* in this module into
+// malloc_hook section,
+// so that MallocHook::GetCallerStackTrace can function accurately:
+
+// Make sure mmap doesn't get #define'd away by <sys/mman.h>
+# undef mmap
+
+extern "C" {
+ABSL_ATTRIBUTE_SECTION(malloc_hook)
+void* mmap64(void* start, size_t length, int prot, int flags, int fd,
+ off64_t offset) __THROW;
+ABSL_ATTRIBUTE_SECTION(malloc_hook)
+void* mmap(void* start, size_t length, int prot, int flags, int fd,
+ off_t offset) __THROW;
+ABSL_ATTRIBUTE_SECTION(malloc_hook)
+int munmap(void* start, size_t length) __THROW;
+ABSL_ATTRIBUTE_SECTION(malloc_hook)
+void* mremap(void* old_addr, size_t old_size, size_t new_size, int flags,
+ ...) __THROW;
+ABSL_ATTRIBUTE_SECTION(malloc_hook) void* sbrk(ptrdiff_t increment) __THROW;
+}
+
+extern "C" void* mmap64(void *start, size_t length, int prot, int flags,
+ int fd, off64_t offset) __THROW {
+ absl::base_internal::MallocHook::InvokePreMmapHook(start, length, prot, flags,
+ fd, offset);
+ void *result;
+ if (!absl::base_internal::MallocHook::InvokeMmapReplacement(
+ start, length, prot, flags, fd, offset, &result)) {
+ result = do_mmap64(start, length, prot, flags, fd, offset);
+ }
+ absl::base_internal::MallocHook::InvokeMmapHook(result, start, length, prot,
+ flags, fd, offset);
+ return result;
+}
+
+# if !defined(__USE_FILE_OFFSET64) || !defined(__REDIRECT_NTH)
+
+extern "C" void* mmap(void *start, size_t length, int prot, int flags,
+ int fd, off_t offset) __THROW {
+ absl::base_internal::MallocHook::InvokePreMmapHook(start, length, prot, flags,
+ fd, offset);
+ void *result;
+ if (!absl::base_internal::MallocHook::InvokeMmapReplacement(
+ start, length, prot, flags, fd, offset, &result)) {
+ result = do_mmap64(start, length, prot, flags, fd,
+ static_cast<size_t>(offset)); // avoid sign extension
+ }
+ absl::base_internal::MallocHook::InvokeMmapHook(result, start, length, prot,
+ flags, fd, offset);
+ return result;
+}
+
+# endif // !defined(__USE_FILE_OFFSET64) || !defined(__REDIRECT_NTH)
+
+extern "C" int munmap(void* start, size_t length) __THROW {
+ absl::base_internal::MallocHook::InvokeMunmapHook(start, length);
+ int result;
+ if (!absl::base_internal::MallocHook::InvokeMunmapReplacement(start, length,
+ &result)) {
+ result = syscall(SYS_munmap, start, length);
+ }
+ return result;
+}
+
+extern "C" void* mremap(void* old_addr, size_t old_size, size_t new_size,
+ int flags, ...) __THROW {
+ va_list ap;
+ va_start(ap, flags);
+ void *new_address = va_arg(ap, void *);
+ va_end(ap);
+ void* result = reinterpret_cast<void*>(
+ syscall(SYS_mremap, old_addr, old_size, new_size, flags, new_address));
+ absl::base_internal::MallocHook::InvokeMremapHook(
+ result, old_addr, old_size, new_size, flags, new_address);
+ return result;
+}
+
+// sbrk cannot be intercepted on Android as there is no mechanism to
+// invoke the original sbrk (since there is no __sbrk as with glibc).
+#if !defined(__BIONIC__)
+// libc's version:
+extern "C" void* __sbrk(ptrdiff_t increment);
+
+extern "C" void* sbrk(ptrdiff_t increment) __THROW {
+ absl::base_internal::MallocHook::InvokePreSbrkHook(increment);
+ void *result = __sbrk(increment);
+ absl::base_internal::MallocHook::InvokeSbrkHook(result, increment);
+ return result;
+}
+#endif // !defined(__BIONIC__)
+
+namespace absl {
+namespace base_internal {
+
+/*static*/void* MallocHook::UnhookedMMap(void *start, size_t length, int prot,
+ int flags, int fd, off_t offset) {
+ void* result;
+ if (!MallocHook::InvokeMmapReplacement(
+ start, length, prot, flags, fd, offset, &result)) {
+ result = do_mmap64(start, length, prot, flags, fd, offset);
+ }
+ return result;
+}
+
+/*static*/int MallocHook::UnhookedMUnmap(void *start, size_t length) {
+ int result;
+ if (!MallocHook::InvokeMunmapReplacement(start, length, &result)) {
+ result = syscall(SYS_munmap, start, length);
+ }
+ return result;
+}
+
+} // namespace base_internal
+} // namespace absl
diff --git a/absl/base/internal/per_thread_tls.h b/absl/base/internal/per_thread_tls.h
new file mode 100644
index 0000000..7397451
--- /dev/null
+++ b/absl/base/internal/per_thread_tls.h
@@ -0,0 +1,48 @@
+// 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 programme 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_
diff --git a/absl/base/internal/raw_logging.cc b/absl/base/internal/raw_logging.cc
new file mode 100644
index 0000000..d197d44
--- /dev/null
+++ b/absl/base/internal/raw_logging.cc
@@ -0,0 +1,225 @@
+// 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 <atomic>
+#include <cassert>
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/atomic_hook.h"
+#include "absl/base/internal/log_severity.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/port.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(__Fuchsia__) || \
+ defined(__GENCLAVE__)
+#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(__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) {
+ 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 absl {
+namespace raw_logging_internal {
+void SafeWriteToStderr(const char *s, size_t len);
+} // namespace raw_logging_internal
+} // namespace absl
+
+namespace {
+
+// CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths
+// that invoke malloc() and getenv() that might acquire some locks.
+// If this becomes a problem we should reimplement a subset of vsnprintf
+// that does not need locks and malloc.
+// E.g. google3/third_party/clearsilver/core/util/snprintf.c
+// looks like such a reimplementation.
+
+// 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) {
+ 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 {
+
+// 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) {
+#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, ...) {
+ 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
diff --git a/absl/base/internal/raw_logging.h b/absl/base/internal/raw_logging.h
new file mode 100644
index 0000000..47cf437
--- /dev/null
+++ b/absl/base/internal/raw_logging.h
@@ -0,0 +1,129 @@
+// 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/internal/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);
+
+// 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_
diff --git a/absl/base/internal/scheduling_mode.h b/absl/base/internal/scheduling_mode.h
new file mode 100644
index 0000000..b7560f3
--- /dev/null
+++ b/absl/base/internal/scheduling_mode.h
@@ -0,0 +1,54 @@
+// 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 //base 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_
diff --git a/absl/base/internal/spinlock.cc b/absl/base/internal/spinlock.cc
new file mode 100644
index 0000000..6257bfc
--- /dev/null
+++ b/absl/base/internal/spinlock.cc
@@ -0,0 +1,243 @@
+// 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 "absl/base/casts.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() */
+
+// 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 {
+
+static int adaptive_spin_count = 0;
+
+namespace {
+struct SpinLock_InitHelper {
+ SpinLock_InitHelper() {
+ // On multi-cpu machines, spin for longer before yielding
+ // the processor or sleeping. Reduces idle time significantly.
+ if (base_internal::NumCPUs() > 1) {
+ adaptive_spin_count = 1000;
+ }
+ }
+};
+
+// Hook into global constructor execution:
+// We do not do adaptive spinning before that,
+// but nothing lock-intensive should be going on at that time.
+static SpinLock_InitHelper init_helper;
+
+ABSL_CONST_INIT static base_internal::AtomicHook<void (*)(const void *lock,
+ int64_t wait_cycles)>
+ submit_profile_data;
+
+} // namespace
+
+void RegisterSpinLockProfiler(void (*fn)(const void *contendedlock,
+ int64_t wait_cycles)) {
+ submit_profile_data.Store(fn);
+}
+
+static inline bool IsCooperative(
+ base_internal::SchedulingMode scheduling_mode) {
+ return scheduling_mode == base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
+}
+
+// Uncommon constructors.
+SpinLock::SpinLock(base_internal::SchedulingMode mode)
+ : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {
+ ABSL_TSAN_MUTEX_CREATE(this, 0);
+}
+
+SpinLock::SpinLock(base_internal::LinkerInitialized,
+ base_internal::SchedulingMode mode) {
+ ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_linker_init);
+ 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) {
+ 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
diff --git a/absl/base/internal/spinlock.h b/absl/base/internal/spinlock.h
new file mode 100644
index 0000000..fa64ba6
--- /dev/null
+++ b/absl/base/internal/spinlock.h
@@ -0,0 +1,227 @@
+//
+// 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 <atomic>
+
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/low_level_scheduling.h"
+#include "absl/base/internal/tsan_mutex_interface.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, 0);
+ }
+
+ // 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, __tsan_mutex_linker_init);
+ }
+
+ // 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, 0); }
+
+ // 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) };
+
+ 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);
+ }
+
+ return lock_value;
+}
+
+} // namespace base_internal
+} // namespace absl
+
+#endif // ABSL_BASE_INTERNAL_SPINLOCK_H_
diff --git a/absl/base/internal/spinlock_posix.inc b/absl/base/internal/spinlock_posix.inc
new file mode 100644
index 0000000..0098c1c
--- /dev/null
+++ b/absl/base/internal/spinlock_posix.inc
@@ -0,0 +1,46 @@
+// 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"
diff --git a/absl/base/internal/spinlock_wait.cc b/absl/base/internal/spinlock_wait.cc
new file mode 100644
index 0000000..0fd3628
--- /dev/null
+++ b/absl/base/internal/spinlock_wait.cc
@@ -0,0 +1,77 @@
+// 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"
+#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 r >> (44 - (loop >> 3));
+}
+
+} // namespace base_internal
+} // namespace absl
diff --git a/absl/base/internal/spinlock_wait.h b/absl/base/internal/spinlock_wait.h
new file mode 100644
index 0000000..5432c1c
--- /dev/null
+++ b/absl/base/internal/spinlock_wait.h
@@ -0,0 +1,94 @@
+// 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.
+
+// This file is used internally in spinlock.cc and once.cc, and a few other
+// places listing in //base:spinlock_wait_users. If you need to use it outside
+// of //base, please request permission to be added to that list.
+
+#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,
+ base_internal::SchedulingMode scheduling_mode) {
+ AbslInternalSpinLockDelay(w, value, loop, scheduling_mode);
+}
+
+#endif // ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_
diff --git a/absl/base/internal/spinlock_win32.inc b/absl/base/internal/spinlock_win32.inc
new file mode 100644
index 0000000..32c8fc0
--- /dev/null
+++ b/absl/base/internal/spinlock_win32.inc
@@ -0,0 +1,37 @@
+// 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"
diff --git a/absl/base/internal/sysinfo.cc b/absl/base/internal/sysinfo.cc
new file mode 100644
index 0000000..11863ea
--- /dev/null
+++ b/absl/base/internal/sysinfo.cc
@@ -0,0 +1,370 @@
+// 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"
+
+#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
+
+#ifdef __APPLE__
+#include <sys/sysctl.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"
+#include "absl/base/thread_annotations.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__) || defined(__GENCLAVE__)
+ // TODO(b/28296132): Calling std::thread::hardware_concurrency() induces a
+ // link error on myriad2 builds.
+ // TODO(b/62709537): Support std::thread::hardware_concurrency() in gEnclalve.
+ 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);
+}
+
+#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
diff --git a/absl/base/internal/sysinfo.h b/absl/base/internal/sysinfo.h
new file mode 100644
index 0000000..f21de14
--- /dev/null
+++ b/absl/base/internal/sysinfo.h
@@ -0,0 +1,64 @@
+// 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. See
+// //base/cpuid/cpuid.h for more CPU-related info. 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_
diff --git a/absl/base/internal/sysinfo_test.cc b/absl/base/internal/sysinfo_test.cc
new file mode 100644
index 0000000..4c7d66b
--- /dev/null
+++ b/absl/base/internal/sysinfo_test.cc
@@ -0,0 +1,99 @@
+// 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(b/37919252): 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 and "
+ "b/37919252";
+#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
diff --git a/absl/base/internal/thread_identity.cc b/absl/base/internal/thread_identity.cc
new file mode 100644
index 0000000..ee96a58
--- /dev/null
+++ b/absl/base/internal/thread_identity.cc
@@ -0,0 +1,126 @@
+// 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 copies of //base exist in a
+// process (via dlopen() or similar), references to
+// thread_identity_ptr from each copy of the code will refer to
+// *different* instances of this ptr. See extensive discussion of this choice
+// in cl/90634708
+// TODO(ahh): hard deprecate multiple copies of //base; remove this.
+#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);
+ // b/18366710:
+ // 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
diff --git a/absl/base/internal/thread_identity.h b/absl/base/internal/thread_identity.h
new file mode 100644
index 0000000..914d5da
--- /dev/null
+++ b/absl/base/internal/thread_identity.h
@@ -0,0 +1,240 @@
+// 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
+ // upto 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_
diff --git a/absl/base/internal/thread_identity_test.cc b/absl/base/internal/thread_identity_test.cc
new file mode 100644
index 0000000..a2b053d
--- /dev/null
+++ b/absl/base/internal/thread_identity_test.cc
@@ -0,0 +1,124 @@
+// 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/internal/spinlock.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
diff --git a/absl/base/internal/throw_delegate.cc b/absl/base/internal/throw_delegate.cc
new file mode 100644
index 0000000..46dc573
--- /dev/null
+++ b/absl/base/internal/throw_delegate.cc
@@ -0,0 +1,106 @@
+// 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
diff --git a/absl/base/internal/throw_delegate.h b/absl/base/internal/throw_delegate.h
new file mode 100644
index 0000000..70e2d77
--- /dev/null
+++ b/absl/base/internal/throw_delegate.h
@@ -0,0 +1,71 @@
+//
+// 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_
diff --git a/absl/base/internal/tsan_mutex_interface.h b/absl/base/internal/tsan_mutex_interface.h
new file mode 100644
index 0000000..a1303e6
--- /dev/null
+++ b/absl/base/internal/tsan_mutex_interface.h
@@ -0,0 +1,51 @@
+// 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_
+
+#ifdef THREAD_SANITIZER
+#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_
diff --git a/absl/base/internal/unaligned_access.h b/absl/base/internal/unaligned_access.h
new file mode 100644
index 0000000..ea30829
--- /dev/null
+++ b/absl/base/internal/unaligned_access.h
@@ -0,0 +1,256 @@
+//
+// 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_
diff --git a/absl/base/internal/unscaledcycleclock.cc b/absl/base/internal/unscaledcycleclock.cc
new file mode 100644
index 0000000..a12d68b
--- /dev/null
+++ b/absl/base/internal/unscaledcycleclock.cc
@@ -0,0 +1,101 @@
+// 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
diff --git a/absl/base/internal/unscaledcycleclock.h b/absl/base/internal/unscaledcycleclock.h
new file mode 100644
index 0000000..ddf6a5e
--- /dev/null
+++ b/absl/base/internal/unscaledcycleclock.h
@@ -0,0 +1,118 @@
+// 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_
diff --git a/absl/base/invoke_test.cc b/absl/base/invoke_test.cc
new file mode 100644
index 0000000..2bbfc47
--- /dev/null
+++ b/absl/base/invoke_test.cc
@@ -0,0 +1,199 @@
+// 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 "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
diff --git a/absl/base/macros.h b/absl/base/macros.h
new file mode 100644
index 0000000..259970f
--- /dev/null
+++ b/absl/base/macros.h
@@ -0,0 +1,201 @@
+//
+// 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 <cstddef>
+
+#include "absl/base/port.h"
+
+// ABSL_ARRAYSIZE()
+//
+// Returns the # 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.
+//
+// Note: this template function declaration is used in defining arraysize.
+// Note that the function doesn't need an implementation, as we only
+// use its type.
+namespace absl {
+namespace macros_internal {
+template <typename T, size_t N>
+char (&ArraySizeHelper(T (&array)[N]))[N];
+} // namespace macros_internal
+} // namespace absl
+#define ABSL_ARRAYSIZE(array) \
+ (sizeof(::absl::macros_internal::ArraySizeHelper(array)))
+
+// 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 go/clang-tidy.
+#if defined(__clang__) && __cplusplus >= 201103L && defined(__has_warning)
+#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); }())
+#endif
+
+#endif // ABSL_BASE_MACROS_H_
diff --git a/absl/base/optimization.h b/absl/base/optimization.h
new file mode 100644
index 0000000..db8beaf
--- /dev/null
+++ b/absl/base/optimization.h
@@ -0,0 +1,164 @@
+//
+// 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: optimization.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines portable macros for performance optimization.
+
+#ifndef ABSL_BASE_OPTIMIZATION_H_
+#define ABSL_BASE_OPTIMIZATION_H_
+
+#include "absl/base/config.h"
+
+// ABSL_BLOCK_TAIL_CALL_OPTIMIZATION
+//
+// Instructs the compiler to avoid optimizing tail-call recursion. Use of this
+// macro is useful when you wish to preserve the existing function order within
+// a stack trace for logging, debugging, or profiling purposes.
+//
+// Example:
+//
+// int f() {
+// int result = g();
+// ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
+// return result;
+// }
+#if defined(__pnacl__)
+#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
+#elif defined(__clang__)
+// Clang will not tail call given inline volatile assembly.
+#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
+#elif defined(__GNUC__)
+// GCC will not tail call given inline volatile assembly.
+#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
+#elif defined(_MSC_VER)
+// The __nop() intrinsic blocks the optimisation.
+#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __nop()
+#else
+#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
+#endif
+
+// ABSL_CACHELINE_SIZE
+//
+// Explicitly defines the size of the L1 cache for purposes of alignment.
+// Setting the cacheline size allows you to specify that certain objects be
+// aligned on a cacheline boundary with `ABSL_CACHELINE_ALIGNED` declarations.
+// (See below.)
+//
+// NOTE: this macro should be replaced with the following C++17 features, when
+// those are generally available:
+//
+// * `std::hardware_constructive_interference_size`
+// * `std::hardware_destructive_interference_size`
+//
+// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
+// for more information.
+#if defined(__GNUC__)
+// Cache line alignment
+#if defined(__i386__) || defined(__x86_64__)
+#define ABSL_CACHELINE_SIZE 64
+#elif defined(__powerpc64__)
+#define ABSL_CACHELINE_SIZE 128
+#elif defined(__aarch64__)
+// We would need to read special register ctr_el0 to find out L1 dcache size.
+// This value is a good estimate based on a real aarch64 machine.
+#define ABSL_CACHELINE_SIZE 64
+#elif defined(__arm__)
+// Cache line sizes for ARM: These values are not strictly correct since
+// cache line sizes depend on implementations, not architectures. There
+// are even implementations with cache line sizes configurable at boot
+// time.
+#if defined(__ARM_ARCH_5T__)
+#define ABSL_CACHELINE_SIZE 32
+#elif defined(__ARM_ARCH_7A__)
+#define ABSL_CACHELINE_SIZE 64
+#endif
+#endif
+
+#ifndef ABSL_CACHELINE_SIZE
+// A reasonable default guess. Note that overestimates tend to waste more
+// space, while underestimates tend to waste more time.
+#define ABSL_CACHELINE_SIZE 64
+#endif
+
+// ABSL_CACHELINE_ALIGNED
+//
+// Indicates that the declared object be cache aligned using
+// `ABSL_CACHELINE_SIZE` (see above). Cacheline aligning objects allows you to
+// load a set of related objects in the L1 cache for performance improvements.
+// Cacheline aligning objects properly allows constructive memory sharing and
+// prevents destructive (or "false") memory sharing.
+//
+// NOTE: this macro should be replaced with usage of `alignas()` using
+// `std::hardware_constructive_interference_size` and/or
+// `std::hardware_destructive_interference_size` when available within C++17.
+//
+// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
+// for more information.
+//
+// On some compilers, `ABSL_CACHELINE_ALIGNED` expands to
+// `__attribute__((aligned(ABSL_CACHELINE_SIZE)))`. For compilers where this is
+// not known to work, the macro expands to nothing.
+//
+// No further guarantees are made here. The result of applying the macro
+// to variables and types is always implementation-defined.
+//
+// WARNING: It is easy to use this attribute incorrectly, even to the point
+// of causing bugs that are difficult to diagnose, crash, etc. It does not
+// of itself guarantee that objects are aligned to a cache line.
+//
+// Recommendations:
+//
+// 1) Consult compiler documentation; this comment is not kept in sync as
+// toolchains evolve.
+// 2) Verify your use has the intended effect. This often requires inspecting
+// the generated machine code.
+// 3) Prefer applying this attribute to individual variables. Avoid
+// applying it to types. This tends to localize the effect.
+#define ABSL_CACHELINE_ALIGNED __attribute__((aligned(ABSL_CACHELINE_SIZE)))
+
+#else // not GCC
+#define ABSL_CACHELINE_SIZE 64
+#define ABSL_CACHELINE_ALIGNED
+#endif
+
+// ABSL_PREDICT_TRUE, ABSL_PREDICT_FALSE
+//
+// Enables the compiler to prioritize compilation using static analysis for
+// likely paths within a boolean branch.
+//
+// Example:
+//
+// if (ABSL_PREDICT_TRUE(expression)) {
+// return result; // Faster if more likely
+// } else {
+// return 0;
+// }
+//
+// Compilers can use the information that a certain branch is not likely to be
+// taken (for instance, a CHECK failure) to optimize for the common case in
+// the absence of better information (ie. compiling gcc with `-fprofile-arcs`).
+#if ABSL_HAVE_BUILTIN(__builtin_expect) || \
+ (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_PREDICT_FALSE(x) (__builtin_expect(x, 0))
+#define ABSL_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
+#else
+#define ABSL_PREDICT_FALSE(x) x
+#define ABSL_PREDICT_TRUE(x) x
+#endif
+
+#endif // ABSL_BASE_OPTIMIZATION_H_
diff --git a/absl/base/policy_checks.h b/absl/base/policy_checks.h
new file mode 100644
index 0000000..17c05c1
--- /dev/null
+++ b/absl/base/policy_checks.h
@@ -0,0 +1,99 @@
+// 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: policy_checks.h
+// -----------------------------------------------------------------------------
+//
+// This header enforces a minimum set of policies at build time, such as the
+// supported compiler and library versions. Unsupported configurations are
+// reported with `#error`. This enforcement is best effort, so successfully
+// compiling this header does not guarantee a supported configuration.
+
+#ifndef ABSL_BASE_POLICY_CHECKS_H_
+#define ABSL_BASE_POLICY_CHECKS_H_
+
+// Included for the __GLIBC_PREREQ macro used below.
+#include <limits.h>
+
+// Included for the _STLPORT_VERSION macro used below.
+#if defined(__cplusplus)
+#include <cstddef>
+#endif
+
+// -----------------------------------------------------------------------------
+// Operating System Check
+// -----------------------------------------------------------------------------
+
+#if defined(__CYGWIN__)
+#error "Cygwin is not supported."
+#endif
+
+// -----------------------------------------------------------------------------
+// Compiler Check
+// -----------------------------------------------------------------------------
+
+// We support MSVC++ 14.0 update 2 and later.
+// This minimum will go up.
+#if defined(_MSC_FULL_VER) && _MSC_FULL_VER < 190023918
+#error "This package requires Visual Studio 2015 Update 2 or higher"
+#endif
+
+// We support gcc 4.7 and later.
+// This minimum will go up.
+#if defined(__GNUC__) && !defined(__clang__)
+#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7)
+#error "This package requires gcc 4.7 or higher"
+#endif
+#endif
+
+// We support Apple Xcode clang 4.2.1 (version 421.11.65) and later.
+// This corresponds to Apple Xcode version 4.5.
+// This minimum will go up.
+#if defined(__apple_build_version__) && __apple_build_version__ < 4211165
+#error "This package requires __apple_build_version__ of 4211165 or higher"
+#endif
+
+// -----------------------------------------------------------------------------
+// C++ Version Check
+// -----------------------------------------------------------------------------
+
+// Enforce C++11 as the minimum. Note that Visual Studio has not
+// advanced __cplusplus despite being good enough for our purposes, so
+// so we exempt it from the check.
+#if defined(__cplusplus) && !defined(_MSC_VER)
+#if __cplusplus < 201103L
+#error "C++ versions less than C++11 are not supported."
+#endif
+#endif
+
+// -----------------------------------------------------------------------------
+// Standard Library Check
+// -----------------------------------------------------------------------------
+
+// We have chosen glibc 2.12 as the minimum as it was tagged for release
+// in May, 2010 and includes some functionality used in Google software
+// (for instance pthread_setname_np):
+// https://sourceware.org/ml/libc-alpha/2010-05/msg00000.html
+#ifdef __GLIBC_PREREQ
+#if !__GLIBC_PREREQ(2, 12)
+#error "Minimum required version of glibc is 2.12."
+#endif
+#endif
+
+#if defined(_STLPORT_VERSION)
+#error "STLPort is not supported."
+#endif
+
+#endif // ABSL_BASE_POLICY_CHECKS_H_
diff --git a/absl/base/port.h b/absl/base/port.h
new file mode 100644
index 0000000..1c67257
--- /dev/null
+++ b/absl/base/port.h
@@ -0,0 +1,26 @@
+// 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 files is a forwarding header for other headers containing various
+// portability macros and functions.
+// This file is used for both C and C++!
+
+#ifndef ABSL_BASE_PORT_H_
+#define ABSL_BASE_PORT_H_
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/optimization.h"
+
+#endif // ABSL_BASE_PORT_H_
diff --git a/absl/base/raw_logging_test.cc b/absl/base/raw_logging_test.cc
new file mode 100644
index 0000000..dae4b35
--- /dev/null
+++ b/absl/base/raw_logging_test.cc
@@ -0,0 +1,50 @@
+// 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 test serves primarily as a compilation test for base/raw_logging.h.
+// Raw logging testing is covered by logging_unittest.cc, which is not as
+// portable as this test.
+
+#include "absl/base/internal/raw_logging.h"
+
+#include "gtest/gtest.h"
+
+namespace {
+
+TEST(RawLoggingCompilationTest, Log) {
+ ABSL_RAW_LOG(INFO, "RAW INFO: %d", 1);
+ ABSL_RAW_LOG(ERROR, "RAW ERROR: %d", 1);
+}
+
+TEST(RawLoggingCompilationTest, PassingCheck) {
+ ABSL_RAW_CHECK(true, "RAW CHECK");
+}
+
+// Not all platforms support output from raw log, so we don't verify any
+// particular output for RAW check failures (expecting the empty std::string
+// accomplishes this). This test is primarily a compilation test, but we
+// are verifying process death when EXPECT_DEATH works for a platform.
+const char kExpectedDeathOutput[] = "";
+
+TEST(RawLoggingDeathTest, FailingCheck) {
+ EXPECT_DEATH_IF_SUPPORTED(ABSL_RAW_CHECK(1 == 0, "explanation"),
+ kExpectedDeathOutput);
+}
+
+TEST(RawLoggingDeathTest, LogFatal) {
+ EXPECT_DEATH_IF_SUPPORTED(ABSL_RAW_LOG(FATAL, "my dog has fleas"),
+ kExpectedDeathOutput);
+}
+
+} // namespace
diff --git a/absl/base/spinlock_test_common.cc b/absl/base/spinlock_test_common.cc
new file mode 100644
index 0000000..b1212ea
--- /dev/null
+++ b/absl/base/spinlock_test_common.cc
@@ -0,0 +1,265 @@
+// 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 bunch of threads repeatedly hash an array of ints protected by a
+// spinlock. If the spinlock is working properly, all elements of the
+// array should be equal at the end of the test.
+
+#include <cstdint>
+#include <limits>
+#include <random>
+#include <thread> // NOLINT(build/c++11)
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/low_level_scheduling.h"
+#include "absl/base/internal/spinlock.h"
+#include "absl/base/internal/sysinfo.h"
+#include "absl/synchronization/blocking_counter.h"
+#include "absl/synchronization/notification.h"
+
+constexpr int32_t kNumThreads = 10;
+constexpr int32_t kIters = 1000;
+
+namespace absl {
+namespace base_internal {
+
+// This is defined outside of anonymous namespace so that it can be
+// a friend of SpinLock to access protected methods for testing.
+struct SpinLockTest {
+ static uint32_t EncodeWaitCycles(int64_t wait_start_time,
+ int64_t wait_end_time) {
+ return SpinLock::EncodeWaitCycles(wait_start_time, wait_end_time);
+ }
+ static uint64_t DecodeWaitCycles(uint32_t lock_value) {
+ return SpinLock::DecodeWaitCycles(lock_value);
+ }
+};
+
+namespace {
+
+static constexpr int kArrayLength = 10;
+static uint32_t values[kArrayLength];
+
+static SpinLock static_spinlock(base_internal::kLinkerInitialized);
+static SpinLock static_cooperative_spinlock(
+ base_internal::kLinkerInitialized,
+ base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL);
+static SpinLock static_noncooperative_spinlock(
+ base_internal::kLinkerInitialized, base_internal::SCHEDULE_KERNEL_ONLY);
+
+// Simple integer hash function based on the public domain lookup2 hash.
+// http://burtleburtle.net/bob/c/lookup2.c
+static uint32_t Hash32(uint32_t a, uint32_t c) {
+ uint32_t b = 0x9e3779b9UL; // The golden ratio; an arbitrary value.
+ a -= b; a -= c; a ^= (c >> 13);
+ b -= c; b -= a; b ^= (a << 8);
+ c -= a; c -= b; c ^= (b >> 13);
+ a -= b; a -= c; a ^= (c >> 12);
+ b -= c; b -= a; b ^= (a << 16);
+ c -= a; c -= b; c ^= (b >> 5);
+ a -= b; a -= c; a ^= (c >> 3);
+ b -= c; b -= a; b ^= (a << 10);
+ c -= a; c -= b; c ^= (b >> 15);
+ return c;
+}
+
+static void TestFunction(int thread_salt, SpinLock* spinlock) {
+ for (int i = 0; i < kIters; i++) {
+ SpinLockHolder h(spinlock);
+ for (int j = 0; j < kArrayLength; j++) {
+ const int index = (j + thread_salt) % kArrayLength;
+ values[index] = Hash32(values[index], thread_salt);
+ std::this_thread::yield();
+ }
+ }
+}
+
+static void ThreadedTest(SpinLock* spinlock) {
+ std::vector<std::thread> threads;
+ for (int i = 0; i < kNumThreads; ++i) {
+ threads.push_back(std::thread(TestFunction, i, spinlock));
+ }
+ for (auto& thread : threads) {
+ thread.join();
+ }
+
+ SpinLockHolder h(spinlock);
+ for (int i = 1; i < kArrayLength; i++) {
+ EXPECT_EQ(values[0], values[i]);
+ }
+}
+
+TEST(SpinLock, StackNonCooperativeDisablesScheduling) {
+ SpinLock spinlock(base_internal::SCHEDULE_KERNEL_ONLY);
+ spinlock.Lock();
+ EXPECT_FALSE(base_internal::SchedulingGuard::ReschedulingIsAllowed());
+ spinlock.Unlock();
+}
+
+TEST(SpinLock, StaticNonCooperativeDisablesScheduling) {
+ static_noncooperative_spinlock.Lock();
+ EXPECT_FALSE(base_internal::SchedulingGuard::ReschedulingIsAllowed());
+ static_noncooperative_spinlock.Unlock();
+}
+
+TEST(SpinLock, WaitCyclesEncoding) {
+ // These are implementation details not exported by SpinLock.
+ const int kProfileTimestampShift = 7;
+ const int kLockwordReservedShift = 3;
+ const uint32_t kSpinLockSleeper = 8;
+
+ // We should be able to encode up to (1^kMaxCycleBits - 1) without clamping
+ // but the lower kProfileTimestampShift will be dropped.
+ const int kMaxCyclesShift =
+ 32 - kLockwordReservedShift + kProfileTimestampShift;
+ const uint64_t kMaxCycles = (int64_t{1} << kMaxCyclesShift) - 1;
+
+ // These bits should be zero after encoding.
+ const uint32_t kLockwordReservedMask = (1 << kLockwordReservedShift) - 1;
+
+ // These bits are dropped when wait cycles are encoded.
+ const uint64_t kProfileTimestampMask = (1 << kProfileTimestampShift) - 1;
+
+ // Test a bunch of random values
+ std::default_random_engine generator;
+ // Shift to avoid overflow below.
+ std::uniform_int_distribution<uint64_t> time_distribution(
+ 0, std::numeric_limits<uint64_t>::max() >> 4);
+ std::uniform_int_distribution<uint64_t> cycle_distribution(0, kMaxCycles);
+
+ for (int i = 0; i < 100; i++) {
+ int64_t start_time = time_distribution(generator);
+ int64_t cycles = cycle_distribution(generator);
+ int64_t end_time = start_time + cycles;
+ uint32_t lock_value = SpinLockTest::EncodeWaitCycles(start_time, end_time);
+ EXPECT_EQ(0, lock_value & kLockwordReservedMask);
+ uint64_t decoded = SpinLockTest::DecodeWaitCycles(lock_value);
+ EXPECT_EQ(0, decoded & kProfileTimestampMask);
+ EXPECT_EQ(cycles & ~kProfileTimestampMask, decoded);
+ }
+
+ // Test corner cases
+ int64_t start_time = time_distribution(generator);
+ EXPECT_EQ(0, SpinLockTest::EncodeWaitCycles(start_time, start_time));
+ EXPECT_EQ(0, SpinLockTest::DecodeWaitCycles(0));
+ EXPECT_EQ(0, SpinLockTest::DecodeWaitCycles(kLockwordReservedMask));
+ EXPECT_EQ(kMaxCycles & ~kProfileTimestampMask,
+ SpinLockTest::DecodeWaitCycles(~kLockwordReservedMask));
+
+ // Check that we cannot produce kSpinLockSleeper during encoding.
+ int64_t sleeper_cycles =
+ kSpinLockSleeper << (kProfileTimestampShift - kLockwordReservedShift);
+ uint32_t sleeper_value =
+ SpinLockTest::EncodeWaitCycles(start_time, start_time + sleeper_cycles);
+ EXPECT_NE(sleeper_value, kSpinLockSleeper);
+
+ // Test clamping
+ uint32_t max_value =
+ SpinLockTest::EncodeWaitCycles(start_time, start_time + kMaxCycles);
+ uint64_t max_value_decoded = SpinLockTest::DecodeWaitCycles(max_value);
+ uint64_t expected_max_value_decoded = kMaxCycles & ~kProfileTimestampMask;
+ EXPECT_EQ(expected_max_value_decoded, max_value_decoded);
+
+ const int64_t step = (1 << kProfileTimestampShift);
+ uint32_t after_max_value =
+ SpinLockTest::EncodeWaitCycles(start_time, start_time + kMaxCycles + step);
+ uint64_t after_max_value_decoded =
+ SpinLockTest::DecodeWaitCycles(after_max_value);
+ EXPECT_EQ(expected_max_value_decoded, after_max_value_decoded);
+
+ uint32_t before_max_value = SpinLockTest::EncodeWaitCycles(
+ start_time, start_time + kMaxCycles - step);
+ uint64_t before_max_value_decoded =
+ SpinLockTest::DecodeWaitCycles(before_max_value);
+ EXPECT_GT(expected_max_value_decoded, before_max_value_decoded);
+}
+
+TEST(SpinLockWithThreads, StaticSpinLock) {
+ ThreadedTest(&static_spinlock);
+}
+
+TEST(SpinLockWithThreads, StackSpinLock) {
+ SpinLock spinlock;
+ ThreadedTest(&spinlock);
+}
+
+TEST(SpinLockWithThreads, StackCooperativeSpinLock) {
+ SpinLock spinlock(base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL);
+ ThreadedTest(&spinlock);
+}
+
+TEST(SpinLockWithThreads, StackNonCooperativeSpinLock) {
+ SpinLock spinlock(base_internal::SCHEDULE_KERNEL_ONLY);
+ ThreadedTest(&spinlock);
+}
+
+TEST(SpinLockWithThreads, StaticCooperativeSpinLock) {
+ ThreadedTest(&static_cooperative_spinlock);
+}
+
+TEST(SpinLockWithThreads, StaticNonCooperativeSpinLock) {
+ ThreadedTest(&static_noncooperative_spinlock);
+}
+
+TEST(SpinLockWithThreads, DoesNotDeadlock) {
+ struct Helper {
+ static void NotifyThenLock(Notification* locked, SpinLock* spinlock,
+ BlockingCounter* b) {
+ locked->WaitForNotification(); // Wait for LockThenWait() to hold "s".
+ b->DecrementCount();
+ SpinLockHolder l(spinlock);
+ }
+
+ static void LockThenWait(Notification* locked, SpinLock* spinlock,
+ BlockingCounter* b) {
+ SpinLockHolder l(spinlock);
+ locked->Notify();
+ b->Wait();
+ }
+
+ static void DeadlockTest(SpinLock* spinlock, int num_spinners) {
+ Notification locked;
+ BlockingCounter counter(num_spinners);
+ std::vector<std::thread> threads;
+
+ threads.push_back(
+ std::thread(Helper::LockThenWait, &locked, spinlock, &counter));
+ for (int i = 0; i < num_spinners; ++i) {
+ threads.push_back(
+ std::thread(Helper::NotifyThenLock, &locked, spinlock, &counter));
+ }
+
+ for (auto& thread : threads) {
+ thread.join();
+ }
+ }
+ };
+
+ SpinLock stack_cooperative_spinlock(
+ base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL);
+ SpinLock stack_noncooperative_spinlock(base_internal::SCHEDULE_KERNEL_ONLY);
+ Helper::DeadlockTest(&stack_cooperative_spinlock,
+ base_internal::NumCPUs() * 2);
+ Helper::DeadlockTest(&stack_noncooperative_spinlock,
+ base_internal::NumCPUs() * 2);
+ Helper::DeadlockTest(&static_cooperative_spinlock,
+ base_internal::NumCPUs() * 2);
+ Helper::DeadlockTest(&static_noncooperative_spinlock,
+ base_internal::NumCPUs() * 2);
+}
+
+} // namespace
+} // namespace base_internal
+} // namespace absl
diff --git a/absl/base/thread_annotations.h b/absl/base/thread_annotations.h
new file mode 100644
index 0000000..025a854
--- /dev/null
+++ b/absl/base/thread_annotations.h
@@ -0,0 +1,247 @@
+// 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: thread_annotations.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains macro definitions for thread safety annotations
+// that allow developers to document the locking policies of multi-threaded
+// code. The annotations can also help program analysis tools to identify
+// potential thread safety issues.
+//
+//
+// These annotations are implemented using compiler attributes. Using the macros
+// defined here instead of raw attributes allow for portability and future
+// compatibility.
+//
+// When referring to mutexes in the arguments of the attributes, you should
+// use variable names or more complex expressions (e.g. my_object->mutex_)
+// that evaluate to a concrete mutex object whenever possible. If the mutex
+// you want to refer to is not in scope, you may use a member pointer
+// (e.g. &MyClass::mutex_) to refer to a mutex in some (unknown) object.
+//
+
+#ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_
+#define ABSL_BASE_THREAD_ANNOTATIONS_H_
+#if defined(__clang__)
+#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
+#else
+#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
+#endif
+
+// GUARDED_BY()
+//
+// Documents if a shared variable/field needs to be protected by a mutex.
+// GUARDED_BY() allows the user to specify a particular mutex that should be
+// held when accessing the annotated variable.
+//
+// Example:
+//
+// Mutex mu;
+// int p1 GUARDED_BY(mu);
+#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
+#define GUARDED_VAR THREAD_ANNOTATION_ATTRIBUTE__(guarded)
+
+// PT_GUARDED_BY()
+//
+// Documents if the memory location pointed to by a pointer should be guarded
+// by a mutex when dereferencing the pointer.
+//
+// Example:
+// Mutex mu;
+// int *p1 PT_GUARDED_BY(mu);
+//
+// Note that a pointer variable to a shared memory location could itself be a
+// shared variable.
+//
+// Example:
+//
+// // `q`, guarded by `mu1`, points to a shared memory location that is
+// // guarded by `mu2`:
+// int *q GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
+#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
+#define PT_GUARDED_VAR THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded)
+
+// ACQUIRED_AFTER() / ACQUIRED_BEFORE()
+//
+// Documents the acquisition order between locks that can be held
+// simultaneously by a thread. For any two locks that need to be annotated
+// to establish an acquisition order, only one of them needs the annotation.
+// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER
+// and ACQUIRED_BEFORE.)
+//
+// Example:
+//
+// Mutex m1;
+// Mutex m2 ACQUIRED_AFTER(m1);
+#define ACQUIRED_AFTER(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
+
+#define ACQUIRED_BEFORE(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
+
+// EXCLUSIVE_LOCKS_REQUIRED() / SHARED_LOCKS_REQUIRED()
+//
+// Documents a function that expects a mutex to be held prior to entry.
+// The mutex is expected to be held both on entry to, and exit from, the
+// function.
+//
+// Example:
+//
+// Mutex mu1, mu2;
+// int a GUARDED_BY(mu1);
+// int b GUARDED_BY(mu2);
+//
+// void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... };
+#define EXCLUSIVE_LOCKS_REQUIRED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
+
+#define SHARED_LOCKS_REQUIRED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
+
+// LOCKS_EXCLUDED()
+//
+// Documents the locks acquired in the body of the function. These locks
+// cannot be held when calling this function (as Abseil's `Mutex` locks are
+// non-reentrant).
+#define LOCKS_EXCLUDED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
+
+// LOCK_RETURNED()
+//
+// Documents a function that returns a mutex without acquiring it. For example,
+// a public getter method that returns a pointer to a private mutex should
+// be annotated with LOCK_RETURNED.
+#define LOCK_RETURNED(x) \
+ THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
+
+// LOCKABLE
+//
+// Documents if a class/type is a lockable type (such as the `Mutex` class).
+#define LOCKABLE \
+ THREAD_ANNOTATION_ATTRIBUTE__(lockable)
+
+// SCOPED_LOCKABLE
+//
+// Documents if a class does RAII locking (such as the `MutexLock` class).
+// The constructor should use `LOCK_FUNCTION()` to specify the mutex that is
+// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no
+// arguments; the analysis will assume that the destructor unlocks whatever the
+// constructor locked.
+#define SCOPED_LOCKABLE \
+ THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+
+// EXCLUSIVE_LOCK_FUNCTION()
+//
+// Documents functions that acquire a lock in the body of a function, and do
+// not release it.
+#define EXCLUSIVE_LOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
+
+// SHARED_LOCK_FUNCTION()
+//
+// Documents functions that acquire a shared (reader) lock in the body of a
+// function, and do not release it.
+#define SHARED_LOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
+
+// UNLOCK_FUNCTION()
+//
+// Documents functions that expect a lock to be held on entry to the function,
+// and release it in the body of the function.
+#define UNLOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
+
+// EXCLUSIVE_TRYLOCK_FUNCTION() / SHARED_TRYLOCK_FUNCTION()
+//
+// Documents functions that try to acquire a lock, and return success or failure
+// (or a non-boolean value that can be interpreted as a boolean).
+// The first argument should be `true` for functions that return `true` on
+// success, or `false` for functions that return `false` on success. The second
+// argument specifies the mutex that is locked on success. If unspecified, this
+// mutex is assumed to be `this`.
+#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
+
+#define SHARED_TRYLOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
+
+// ASSERT_EXCLUSIVE_LOCK() / ASSERT_SHARED_LOCK()
+//
+// Documents functions that dynamically check to see if a lock is held, and fail
+// if it is not held.
+#define ASSERT_EXCLUSIVE_LOCK(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__))
+
+#define ASSERT_SHARED_LOCK(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__))
+
+// NO_THREAD_SAFETY_ANALYSIS
+//
+// Turns off thread safety checking within the body of a particular function.
+// This annotation is used to mark functions that are known to be correct, but
+// the locking behavior is more complicated than the analyzer can handle.
+#define NO_THREAD_SAFETY_ANALYSIS \
+ THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
+
+//------------------------------------------------------------------------------
+// Tool-Supplied Annotations
+//------------------------------------------------------------------------------
+
+// TS_UNCHECKED should be placed around lock expressions that are not valid
+// C++ syntax, but which are present for documentation purposes. These
+// annotations will be ignored by the analysis.
+#define TS_UNCHECKED(x) ""
+
+// TS_FIXME is used to mark lock expressions that are not valid C++ syntax.
+// It is used by automated tools to mark and disable invalid expressions.
+// The annotation should either be fixed, or changed to TS_UNCHECKED.
+#define TS_FIXME(x) ""
+
+// Like NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body of
+// a particular function. However, this attribute is used to mark functions
+// that are incorrect and need to be fixed. It is used by automated tools to
+// avoid breaking the build when the analysis is updated.
+// Code owners are expected to eventually fix the routine.
+#define NO_THREAD_SAFETY_ANALYSIS_FIXME NO_THREAD_SAFETY_ANALYSIS
+
+// Similar to NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a GUARDED_BY
+// annotation that needs to be fixed, because it is producing thread safety
+// warning. It disables the GUARDED_BY.
+#define GUARDED_BY_FIXME(x)
+
+// Disables warnings for a single read operation. This can be used to avoid
+// warnings when it is known that the read is not actually involved in a race,
+// but the compiler cannot confirm that.
+#define TS_UNCHECKED_READ(x) thread_safety_analysis::ts_unchecked_read(x)
+
+
+namespace thread_safety_analysis {
+
+// Takes a reference to a guarded data member, and returns an unguarded
+// reference.
+template <typename T>
+inline const T& ts_unchecked_read(const T& v) NO_THREAD_SAFETY_ANALYSIS {
+ return v;
+}
+
+template <typename T>
+inline T& ts_unchecked_read(T& v) NO_THREAD_SAFETY_ANALYSIS {
+ return v;
+}
+
+} // namespace thread_safety_analysis
+
+#endif // ABSL_BASE_THREAD_ANNOTATIONS_H_
diff --git a/absl/base/throw_delegate_test.cc b/absl/base/throw_delegate_test.cc
new file mode 100644
index 0000000..f949445
--- /dev/null
+++ b/absl/base/throw_delegate_test.cc
@@ -0,0 +1,95 @@
+// 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 <functional>
+#include <new>
+#include <stdexcept>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace {
+
+using absl::base_internal::ThrowStdLogicError;
+using absl::base_internal::ThrowStdInvalidArgument;
+using absl::base_internal::ThrowStdDomainError;
+using absl::base_internal::ThrowStdLengthError;
+using absl::base_internal::ThrowStdOutOfRange;
+using absl::base_internal::ThrowStdRuntimeError;
+using absl::base_internal::ThrowStdRangeError;
+using absl::base_internal::ThrowStdOverflowError;
+using absl::base_internal::ThrowStdUnderflowError;
+using absl::base_internal::ThrowStdBadFunctionCall;
+using absl::base_internal::ThrowStdBadAlloc;
+
+constexpr const char* what_arg = "The quick brown fox jumps over the lazy dog";
+
+template <typename E>
+void ExpectThrowChar(void (*f)(const char*)) {
+ try {
+ f(what_arg);
+ FAIL() << "Didn't throw";
+ } catch (const E& e) {
+ EXPECT_STREQ(e.what(), what_arg);
+ }
+}
+
+template <typename E>
+void ExpectThrowString(void (*f)(const std::string&)) {
+ try {
+ f(what_arg);
+ FAIL() << "Didn't throw";
+ } catch (const E& e) {
+ EXPECT_STREQ(e.what(), what_arg);
+ }
+}
+
+template <typename E>
+void ExpectThrowNoWhat(void (*f)()) {
+ try {
+ f();
+ FAIL() << "Didn't throw";
+ } catch (const E& e) {
+ }
+}
+
+TEST(ThrowHelper, Test) {
+ // Not using EXPECT_THROW because we want to check the .what() message too.
+ ExpectThrowChar<std::logic_error>(ThrowStdLogicError);
+ ExpectThrowChar<std::invalid_argument>(ThrowStdInvalidArgument);
+ ExpectThrowChar<std::domain_error>(ThrowStdDomainError);
+ ExpectThrowChar<std::length_error>(ThrowStdLengthError);
+ ExpectThrowChar<std::out_of_range>(ThrowStdOutOfRange);
+ ExpectThrowChar<std::runtime_error>(ThrowStdRuntimeError);
+ ExpectThrowChar<std::range_error>(ThrowStdRangeError);
+ ExpectThrowChar<std::overflow_error>(ThrowStdOverflowError);
+ ExpectThrowChar<std::underflow_error>(ThrowStdUnderflowError);
+
+ ExpectThrowString<std::logic_error>(ThrowStdLogicError);
+ ExpectThrowString<std::invalid_argument>(ThrowStdInvalidArgument);
+ ExpectThrowString<std::domain_error>(ThrowStdDomainError);
+ ExpectThrowString<std::length_error>(ThrowStdLengthError);
+ ExpectThrowString<std::out_of_range>(ThrowStdOutOfRange);
+ ExpectThrowString<std::runtime_error>(ThrowStdRuntimeError);
+ ExpectThrowString<std::range_error>(ThrowStdRangeError);
+ ExpectThrowString<std::overflow_error>(ThrowStdOverflowError);
+ ExpectThrowString<std::underflow_error>(ThrowStdUnderflowError);
+
+ ExpectThrowNoWhat<std::bad_function_call>(ThrowStdBadFunctionCall);
+ ExpectThrowNoWhat<std::bad_alloc>(ThrowStdBadAlloc);
+}
+
+} // namespace
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel
new file mode 100644
index 0000000..625cef1
--- /dev/null
+++ b/absl/container/BUILD.bazel
@@ -0,0 +1,124 @@
+#
+# 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",
+)
+load(
+ "//absl:test_dependencies.bzl",
+ "GUNIT_MAIN_DEPS_SELECTOR",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"]) # Apache 2.0
+
+cc_library(
+ name = "fixed_array",
+ hdrs = ["fixed_array.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ "//absl/algorithm",
+ "//absl/base:core_headers",
+ "//absl/base:dynamic_annotations",
+ "//absl/base:throw_delegate",
+ ],
+)
+
+cc_test(
+ name = "fixed_array_test",
+ srcs = ["fixed_array_test.cc"],
+ copts = ABSL_TEST_COPTS + ["-fexceptions"],
+ deps = [
+ ":fixed_array",
+ "//absl/base:core_headers",
+ "//absl/base:exception_testing",
+ "//absl/memory",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "fixed_array_test_noexceptions",
+ srcs = ["fixed_array_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":fixed_array",
+ "//absl/base:core_headers",
+ "//absl/base:exception_testing",
+ "//absl/memory",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_library(
+ name = "inlined_vector",
+ hdrs = ["inlined_vector.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ "//absl/algorithm",
+ "//absl/base:core_headers",
+ "//absl/base:throw_delegate",
+ "//absl/memory",
+ ],
+)
+
+cc_test(
+ name = "inlined_vector_test",
+ srcs = ["inlined_vector_test.cc"],
+ copts = ABSL_TEST_COPTS + ["-fexceptions"],
+ deps = [
+ ":inlined_vector",
+ ":test_instance_tracker",
+ "//absl/base",
+ "//absl/base:core_headers",
+ "//absl/base:exception_testing",
+ "//absl/memory",
+ "//absl/strings",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "inlined_vector_test_noexceptions",
+ srcs = ["inlined_vector_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":inlined_vector",
+ ":test_instance_tracker",
+ "//absl/base",
+ "//absl/base:core_headers",
+ "//absl/base:exception_testing",
+ "//absl/memory",
+ "//absl/strings",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_library(
+ name = "test_instance_tracker",
+ testonly = 1,
+ srcs = ["internal/test_instance_tracker.cc"],
+ hdrs = ["internal/test_instance_tracker.h"],
+ copts = ABSL_DEFAULT_COPTS,
+)
+
+cc_test(
+ name = "test_instance_tracker_test",
+ srcs = ["internal/test_instance_tracker_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":test_instance_tracker",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
diff --git a/absl/container/fixed_array.h b/absl/container/fixed_array.h
new file mode 100644
index 0000000..20bde27
--- /dev/null
+++ b/absl/container/fixed_array.h
@@ -0,0 +1,493 @@
+// 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: fixed_array.h
+// -----------------------------------------------------------------------------
+//
+// A `FixedArray<T>` represents a non-resizable array of `T` where the length of
+// the array can be determined at run-time. It is a good replacement for
+// non-standard and deprecated uses of `alloca()` and variable length arrays
+// within the GCC extension. (See
+// https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html).
+//
+// `FixedArray` allocates small arrays inline, keeping performance fast by
+// avoiding heap operations. It also helps reduce the chances of
+// accidentally overflowing your stack if large input is passed to
+// your function.
+
+#ifndef ABSL_CONTAINER_FIXED_ARRAY_H_
+#define ABSL_CONTAINER_FIXED_ARRAY_H_
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <cstddef>
+#include <initializer_list>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <new>
+#include <type_traits>
+
+#include "absl/algorithm/algorithm.h"
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/base/macros.h"
+#include "absl/base/optimization.h"
+#include "absl/base/port.h"
+
+namespace absl {
+
+constexpr static auto kFixedArrayUseDefault = static_cast<size_t>(-1);
+
+// -----------------------------------------------------------------------------
+// FixedArray
+// -----------------------------------------------------------------------------
+//
+// A `FixedArray` provides a run-time fixed-size array, allocating small arrays
+// inline for efficiency and correctness.
+//
+// Most users should not specify an `inline_elements` argument and let
+// `FixedArray<>` automatically determine the number of elements
+// to store inline based on `sizeof(T)`. If `inline_elements` is specified, the
+// `FixedArray<>` implementation will inline arrays of
+// length <= `inline_elements`.
+//
+// Note that a `FixedArray` constructed with a `size_type` argument will
+// default-initialize its values by leaving trivially constructible types
+// uninitialized (e.g. int, int[4], double), and others default-constructed.
+// This matches the behavior of c-style arrays and `std::array`, but not
+// `std::vector`.
+//
+// Note that `FixedArray` does not provide a public allocator; if it requires a
+// heap allocation, it will do so with global `::operator new[]()` and
+// `::operator delete[]()`, even if T provides class-scope overrides for these
+// operators.
+template <typename T, size_t inlined = kFixedArrayUseDefault>
+class FixedArray {
+ static constexpr size_t kInlineBytesDefault = 256;
+
+ // std::iterator_traits isn't guaranteed to be SFINAE-friendly until C++17,
+ // but this seems to be mostly pedantic.
+ template <typename Iter>
+ using EnableIfForwardIterator = typename std::enable_if<
+ std::is_convertible<
+ typename std::iterator_traits<Iter>::iterator_category,
+ std::forward_iterator_tag>::value,
+ int>::type;
+
+ public:
+ // For playing nicely with stl:
+ using value_type = T;
+ using iterator = T*;
+ using const_iterator = const T*;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ using reference = T&;
+ using const_reference = const T&;
+ using pointer = T*;
+ using const_pointer = const T*;
+ using difference_type = ptrdiff_t;
+ using size_type = size_t;
+
+ static constexpr size_type inline_elements =
+ inlined == kFixedArrayUseDefault
+ ? kInlineBytesDefault / sizeof(value_type)
+ : inlined;
+
+ // Creates an array object that can store `n` elements.
+ // Note that trivially constructible elements will be uninitialized.
+ explicit FixedArray(size_type n) : rep_(n) {}
+
+ // Creates an array initialized with `n` copies of `val`.
+ FixedArray(size_type n, const value_type& val) : rep_(n, val) {}
+
+ // Creates an array initialized with the elements from the input
+ // range. The array's size will always be `std::distance(first, last)`.
+ // REQUIRES: Iter must be a forward_iterator or better.
+ template <typename Iter, EnableIfForwardIterator<Iter> = 0>
+ FixedArray(Iter first, Iter last) : rep_(first, last) {}
+
+ // Create the array from an initializer_list.
+ FixedArray(std::initializer_list<T> init_list)
+ : FixedArray(init_list.begin(), init_list.end()) {}
+
+ ~FixedArray() {}
+
+ // Copy and move construction and assignment are deleted because (1) you can't
+ // copy or move an array, (2) assignment breaks the invariant that the size of
+ // a `FixedArray` never changes, and (3) there's no clear answer as to what
+ // should happen to a moved-from `FixedArray`.
+ FixedArray(const FixedArray&) = delete;
+ void operator=(const FixedArray&) = delete;
+
+ // FixedArray::size()
+ //
+ // Returns the length of the fixed array.
+ size_type size() const { return rep_.size(); }
+
+ // FixedArray::max_size()
+ //
+ // Returns the largest possible value of `std::distance(begin(), end())` for a
+ // `FixedArray<T>`. This is equivalent to the most possible addressable bytes
+ // over the number of bytes taken by T.
+ constexpr size_type max_size() const {
+ return std::numeric_limits<difference_type>::max() / sizeof(value_type);
+ }
+
+ // FixedArray::empty()
+ //
+ // Returns whether or not the fixed array is empty.
+ bool empty() const { return size() == 0; }
+
+ // FixedArray::memsize()
+ //
+ // Returns the memory size of the fixed array in bytes.
+ size_t memsize() const { return size() * sizeof(value_type); }
+
+ // FixedArray::data()
+ //
+ // Returns a const T* pointer to elements of the `FixedArray`. This pointer
+ // can be used to access (but not modify) the contained elements.
+ const_pointer data() const { return AsValue(rep_.begin()); }
+
+ // Overload of FixedArray::data() to return a T* pointer to elements of the
+ // fixed array. This pointer can be used to access and modify the contained
+ // elements.
+ pointer data() { return AsValue(rep_.begin()); }
+ // FixedArray::operator[]
+ //
+ // Returns a reference the ith element of the fixed array.
+ // REQUIRES: 0 <= i < size()
+ reference operator[](size_type i) {
+ assert(i < size());
+ return data()[i];
+ }
+
+ // Overload of FixedArray::operator()[] to return a const reference to the
+ // ith element of the fixed array.
+ // REQUIRES: 0 <= i < size()
+ const_reference operator[](size_type i) const {
+ assert(i < size());
+ return data()[i];
+ }
+
+ // FixedArray::at
+ //
+ // Bounds-checked access. Returns a reference to the ith element of the
+ // fiexed array, or throws std::out_of_range
+ reference at(size_type i) {
+ if (ABSL_PREDICT_FALSE(i >= size())) {
+ base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
+ }
+ return data()[i];
+ }
+
+ // Overload of FixedArray::at() to return a const reference to the ith element
+ // of the fixed array.
+ const_reference at(size_type i) const {
+ if (i >= size()) {
+ base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
+ }
+ return data()[i];
+ }
+
+ // FixedArray::front()
+ //
+ // Returns a reference to the first element of the fixed array.
+ reference front() { return *begin(); }
+
+ // Overload of FixedArray::front() to return a reference to the first element
+ // of a fixed array of const values.
+ const_reference front() const { return *begin(); }
+
+ // FixedArray::back()
+ //
+ // Returns a reference to the last element of the fixed array.
+ reference back() { return *(end() - 1); }
+
+ // Overload of FixedArray::back() to return a reference to the last element
+ // of a fixed array of const values.
+ const_reference back() const { return *(end() - 1); }
+
+ // FixedArray::begin()
+ //
+ // Returns an iterator to the beginning of the fixed array.
+ iterator begin() { return data(); }
+
+ // Overload of FixedArray::begin() to return a const iterator to the
+ // beginning of the fixed array.
+ const_iterator begin() const { return data(); }
+
+ // FixedArray::cbegin()
+ //
+ // Returns a const iterator to the beginning of the fixed array.
+ const_iterator cbegin() const { return begin(); }
+
+ // FixedArray::end()
+ //
+ // Returns an iterator to the end of the fixed array.
+ iterator end() { return data() + size(); }
+
+ // Overload of FixedArray::end() to return a const iterator to the end of the
+ // fixed array.
+ const_iterator end() const { return data() + size(); }
+
+ // FixedArray::cend()
+ //
+ // Returns a const iterator to the end of the fixed array.
+ const_iterator cend() const { return end(); }
+
+ // FixedArray::rbegin()
+ //
+ // Returns a reverse iterator from the end of the fixed array.
+ reverse_iterator rbegin() { return reverse_iterator(end()); }
+
+ // Overload of FixedArray::rbegin() to return a const reverse iterator from
+ // the end of the fixed array.
+ const_reverse_iterator rbegin() const {
+ return const_reverse_iterator(end());
+ }
+
+ // FixedArray::crbegin()
+ //
+ // Returns a const reverse iterator from the end of the fixed array.
+ const_reverse_iterator crbegin() const { return rbegin(); }
+
+ // FixedArray::rend()
+ //
+ // Returns a reverse iterator from the beginning of the fixed array.
+ reverse_iterator rend() { return reverse_iterator(begin()); }
+
+ // Overload of FixedArray::rend() for returning a const reverse iterator
+ // from the beginning of the fixed array.
+ const_reverse_iterator rend() const {
+ return const_reverse_iterator(begin());
+ }
+
+ // FixedArray::crend()
+ //
+ // Returns a reverse iterator from the beginning of the fixed array.
+ const_reverse_iterator crend() const { return rend(); }
+
+ // FixedArray::fill()
+ //
+ // Assigns the given `value` to all elements in the fixed array.
+ void fill(const T& value) { std::fill(begin(), end(), value); }
+
+ // Relational operators. Equality operators are elementwise using
+ // `operator==`, while order operators order FixedArrays lexicographically.
+ friend bool operator==(const FixedArray& lhs, const FixedArray& rhs) {
+ return absl::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+ }
+
+ friend bool operator!=(const FixedArray& lhs, const FixedArray& rhs) {
+ return !(lhs == rhs);
+ }
+
+ friend bool operator<(const FixedArray& lhs, const FixedArray& rhs) {
+ return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
+ rhs.end());
+ }
+
+ friend bool operator>(const FixedArray& lhs, const FixedArray& rhs) {
+ return rhs < lhs;
+ }
+
+ friend bool operator<=(const FixedArray& lhs, const FixedArray& rhs) {
+ return !(rhs < lhs);
+ }
+
+ friend bool operator>=(const FixedArray& lhs, const FixedArray& rhs) {
+ return !(lhs < rhs);
+ }
+
+ private:
+ // HolderTraits
+ //
+ // Wrapper to hold elements of type T for the case where T is an array type.
+ // If 'T' is an array type, HolderTraits::type is a struct with a 'T v;'.
+ // Otherwise, HolderTraits::type is simply 'T'.
+ //
+ // Maintainer's Note: The simpler solution would be to simply wrap T in a
+ // struct whether it's an array or not: 'struct Holder { T v; };', but
+ // that causes some paranoid diagnostics to misfire about uses of data(),
+ // believing that 'data()' (aka '&rep_.begin().v') is a pointer to a single
+ // element, rather than the packed array that it really is.
+ // e.g.:
+ //
+ // FixedArray<char> buf(1);
+ // sprintf(buf.data(), "foo");
+ //
+ // error: call to int __builtin___sprintf_chk(etc...)
+ // will always overflow destination buffer [-Werror]
+ //
+ class HolderTraits {
+ template <typename U>
+ struct SelectImpl {
+ using type = U;
+ static pointer AsValue(type* p) { return p; }
+ };
+
+ // Partial specialization for elements of array type.
+ template <typename U, size_t N>
+ struct SelectImpl<U[N]> {
+ struct Holder { U v[N]; };
+ using type = Holder;
+ static pointer AsValue(type* p) { return &p->v; }
+ };
+ using Impl = SelectImpl<value_type>;
+
+ public:
+ using type = typename Impl::type;
+
+ static pointer AsValue(type *p) { return Impl::AsValue(p); }
+
+ // TODO(billydonahue): fix the type aliasing violation
+ // this assertion hints at.
+ static_assert(sizeof(type) == sizeof(value_type),
+ "Holder must be same size as value_type");
+ };
+
+ using Holder = typename HolderTraits::type;
+ static pointer AsValue(Holder *p) { return HolderTraits::AsValue(p); }
+
+ // InlineSpace
+ //
+ // Allocate some space, not an array of elements of type T, so that we can
+ // skip calling the T constructors and destructors for space we never use.
+ // How many elements should we store inline?
+ // a. If not specified, use a default of kInlineBytesDefault bytes (This is
+ // currently 256 bytes, which seems small enough to not cause stack overflow
+ // or unnecessary stack pollution, while still allowing stack allocation for
+ // reasonably long character arrays).
+ // b. Never use 0 length arrays (not ISO C++)
+ //
+ template <size_type N, typename = void>
+ class InlineSpace {
+ public:
+ Holder* data() { return reinterpret_cast<Holder*>(space_.data()); }
+ void AnnotateConstruct(size_t n) const { Annotate(n, true); }
+ void AnnotateDestruct(size_t n) const { Annotate(n, false); }
+
+ private:
+#ifndef ADDRESS_SANITIZER
+ void Annotate(size_t, bool) const { }
+#else
+ void Annotate(size_t n, bool creating) const {
+ if (!n) return;
+ const void* bot = &left_redzone_;
+ const void* beg = space_.data();
+ const void* end = space_.data() + n;
+ const void* top = &right_redzone_ + 1;
+ // args: (beg, end, old_mid, new_mid)
+ if (creating) {
+ ANNOTATE_CONTIGUOUS_CONTAINER(beg, top, top, end);
+ ANNOTATE_CONTIGUOUS_CONTAINER(bot, beg, beg, bot);
+ } else {
+ ANNOTATE_CONTIGUOUS_CONTAINER(beg, top, end, top);
+ ANNOTATE_CONTIGUOUS_CONTAINER(bot, beg, bot, beg);
+ }
+ }
+#endif // ADDRESS_SANITIZER
+
+ using Buffer =
+ typename std::aligned_storage<sizeof(Holder), alignof(Holder)>::type;
+
+ ADDRESS_SANITIZER_REDZONE(left_redzone_);
+ std::array<Buffer, N> space_;
+ ADDRESS_SANITIZER_REDZONE(right_redzone_);
+ };
+
+ // specialization when N = 0.
+ template <typename U>
+ class InlineSpace<0, U> {
+ public:
+ Holder* data() { return nullptr; }
+ void AnnotateConstruct(size_t) const {}
+ void AnnotateDestruct(size_t) const {}
+ };
+
+ // Rep
+ //
+ // A const Rep object holds FixedArray's size and data pointer.
+ //
+ class Rep : public InlineSpace<inline_elements> {
+ public:
+ Rep(size_type n, const value_type& val) : n_(n), p_(MakeHolder(n)) {
+ std::uninitialized_fill_n(p_, n, val);
+ }
+
+ explicit Rep(size_type n) : n_(n), p_(MakeHolder(n)) {
+ // Loop optimizes to nothing for trivially constructible T.
+ for (Holder* p = p_; p != p_ + n; ++p)
+ // Note: no parens: default init only.
+ // Also note '::' to avoid Holder class placement new operator.
+ ::new (static_cast<void*>(p)) Holder;
+ }
+
+ template <typename Iter>
+ Rep(Iter first, Iter last)
+ : n_(std::distance(first, last)), p_(MakeHolder(n_)) {
+ std::uninitialized_copy(first, last, AsValue(p_));
+ }
+
+ ~Rep() {
+ // Destruction must be in reverse order.
+ // Loop optimizes to nothing for trivially destructible T.
+ for (Holder* p = end(); p != begin();) (--p)->~Holder();
+ if (IsAllocated(size())) {
+ ::operator delete[](begin());
+ } else {
+ this->AnnotateDestruct(size());
+ }
+ }
+ Holder* begin() const { return p_; }
+ Holder* end() const { return p_ + n_; }
+ size_type size() const { return n_; }
+
+ private:
+ Holder* MakeHolder(size_type n) {
+ if (IsAllocated(n)) {
+ return Allocate(n);
+ } else {
+ this->AnnotateConstruct(n);
+ return this->data();
+ }
+ }
+
+ Holder* Allocate(size_type n) {
+ return static_cast<Holder*>(::operator new[](n * sizeof(Holder)));
+ }
+
+ bool IsAllocated(size_type n) const { return n > inline_elements; }
+
+ const size_type n_;
+ Holder* const p_;
+ };
+
+
+ // Data members
+ Rep rep_;
+};
+
+template <typename T, size_t N>
+constexpr size_t FixedArray<T, N>::inline_elements;
+
+template <typename T, size_t N>
+constexpr size_t FixedArray<T, N>::kInlineBytesDefault;
+
+} // namespace absl
+#endif // ABSL_CONTAINER_FIXED_ARRAY_H_
diff --git a/absl/container/fixed_array_test.cc b/absl/container/fixed_array_test.cc
new file mode 100644
index 0000000..9e88eab
--- /dev/null
+++ b/absl/container/fixed_array_test.cc
@@ -0,0 +1,621 @@
+// 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/container/fixed_array.h"
+
+#include <stdio.h>
+#include <list>
+#include <memory>
+#include <numeric>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/exception_testing.h"
+#include "absl/memory/memory.h"
+
+namespace {
+
+// Helper routine to determine if a absl::FixedArray used stack allocation.
+template <typename ArrayType>
+static bool IsOnStack(const ArrayType& a) {
+ return a.size() <= ArrayType::inline_elements;
+}
+
+class ConstructionTester {
+ public:
+ ConstructionTester()
+ : self_ptr_(this),
+ value_(0) {
+ constructions++;
+ }
+ ~ConstructionTester() {
+ assert(self_ptr_ == this);
+ self_ptr_ = nullptr;
+ destructions++;
+ }
+
+ // These are incremented as elements are constructed and destructed so we can
+ // be sure all elements are properly cleaned up.
+ static int constructions;
+ static int destructions;
+
+ void CheckConstructed() {
+ assert(self_ptr_ == this);
+ }
+
+ void set(int value) { value_ = value; }
+ int get() { return value_; }
+
+ private:
+ // self_ptr_ should always point to 'this' -- that's how we can be sure the
+ // constructor has been called.
+ ConstructionTester* self_ptr_;
+ int value_;
+};
+
+int ConstructionTester::constructions = 0;
+int ConstructionTester::destructions = 0;
+
+// ThreeInts will initialize its three ints to the value stored in
+// ThreeInts::counter. The constructor increments counter so that each object
+// in an array of ThreeInts will have different values.
+class ThreeInts {
+ public:
+ ThreeInts() {
+ x_ = counter;
+ y_ = counter;
+ z_ = counter;
+ ++counter;
+ }
+
+ static int counter;
+
+ int x_, y_, z_;
+};
+
+int ThreeInts::counter = 0;
+
+TEST(FixedArrayTest, SmallObjects) {
+ // Small object arrays
+ {
+ // Short arrays should be on the stack
+ absl::FixedArray<int> array(4);
+ EXPECT_TRUE(IsOnStack(array));
+ }
+
+ {
+ // Large arrays should be on the heap
+ absl::FixedArray<int> array(1048576);
+ EXPECT_FALSE(IsOnStack(array));
+ }
+
+ {
+ // Arrays of <= default size should be on the stack
+ absl::FixedArray<int, 100> array(100);
+ EXPECT_TRUE(IsOnStack(array));
+ }
+
+ {
+ // Arrays of > default size should be on the stack
+ absl::FixedArray<int, 100> array(101);
+ EXPECT_FALSE(IsOnStack(array));
+ }
+
+ {
+ // Arrays with different size elements should use approximately
+ // same amount of stack space
+ absl::FixedArray<int> array1(0);
+ absl::FixedArray<char> array2(0);
+ EXPECT_LE(sizeof(array1), sizeof(array2)+100);
+ EXPECT_LE(sizeof(array2), sizeof(array1)+100);
+ }
+
+ {
+ // Ensure that vectors are properly constructed inside a fixed array.
+ absl::FixedArray<std::vector<int> > array(2);
+ EXPECT_EQ(0, array[0].size());
+ EXPECT_EQ(0, array[1].size());
+ }
+
+ {
+ // Regardless of absl::FixedArray implementation, check that a type with a
+ // low alignment requirement and a non power-of-two size is initialized
+ // correctly.
+ ThreeInts::counter = 1;
+ absl::FixedArray<ThreeInts> array(2);
+ EXPECT_EQ(1, array[0].x_);
+ EXPECT_EQ(1, array[0].y_);
+ EXPECT_EQ(1, array[0].z_);
+ EXPECT_EQ(2, array[1].x_);
+ EXPECT_EQ(2, array[1].y_);
+ EXPECT_EQ(2, array[1].z_);
+ }
+}
+
+TEST(FixedArrayTest, AtThrows) {
+ absl::FixedArray<int> a = {1, 2, 3};
+ EXPECT_EQ(a.at(2), 3);
+ ABSL_BASE_INTERNAL_EXPECT_FAIL(a.at(3), std::out_of_range,
+ "failed bounds check");
+}
+
+TEST(FixedArrayRelationalsTest, EqualArrays) {
+ for (int i = 0; i < 10; ++i) {
+ absl::FixedArray<int, 5> a1(i);
+ std::iota(a1.begin(), a1.end(), 0);
+ absl::FixedArray<int, 5> a2(a1.begin(), a1.end());
+
+ EXPECT_TRUE(a1 == a2);
+ EXPECT_FALSE(a1 != a2);
+ EXPECT_TRUE(a2 == a1);
+ EXPECT_FALSE(a2 != a1);
+ EXPECT_FALSE(a1 < a2);
+ EXPECT_FALSE(a1 > a2);
+ EXPECT_FALSE(a2 < a1);
+ EXPECT_FALSE(a2 > a1);
+ EXPECT_TRUE(a1 <= a2);
+ EXPECT_TRUE(a1 >= a2);
+ EXPECT_TRUE(a2 <= a1);
+ EXPECT_TRUE(a2 >= a1);
+ }
+}
+
+TEST(FixedArrayRelationalsTest, UnequalArrays) {
+ for (int i = 1; i < 10; ++i) {
+ absl::FixedArray<int, 5> a1(i);
+ std::iota(a1.begin(), a1.end(), 0);
+ absl::FixedArray<int, 5> a2(a1.begin(), a1.end());
+ --a2[i / 2];
+
+ EXPECT_FALSE(a1 == a2);
+ EXPECT_TRUE(a1 != a2);
+ EXPECT_FALSE(a2 == a1);
+ EXPECT_TRUE(a2 != a1);
+ EXPECT_FALSE(a1 < a2);
+ EXPECT_TRUE(a1 > a2);
+ EXPECT_TRUE(a2 < a1);
+ EXPECT_FALSE(a2 > a1);
+ EXPECT_FALSE(a1 <= a2);
+ EXPECT_TRUE(a1 >= a2);
+ EXPECT_TRUE(a2 <= a1);
+ EXPECT_FALSE(a2 >= a1);
+ }
+}
+
+template <int stack_elements>
+static void TestArray(int n) {
+ SCOPED_TRACE(n);
+ SCOPED_TRACE(stack_elements);
+ ConstructionTester::constructions = 0;
+ ConstructionTester::destructions = 0;
+ {
+ absl::FixedArray<ConstructionTester, stack_elements> array(n);
+
+ EXPECT_THAT(array.size(), n);
+ EXPECT_THAT(array.memsize(), sizeof(ConstructionTester) * n);
+ EXPECT_THAT(array.begin() + n, array.end());
+
+ // Check that all elements were constructed
+ for (int i = 0; i < n; i++) {
+ array[i].CheckConstructed();
+ }
+ // Check that no other elements were constructed
+ EXPECT_THAT(ConstructionTester::constructions, n);
+
+ // Test operator[]
+ for (int i = 0; i < n; i++) {
+ array[i].set(i);
+ }
+ for (int i = 0; i < n; i++) {
+ EXPECT_THAT(array[i].get(), i);
+ EXPECT_THAT(array.data()[i].get(), i);
+ }
+
+ // Test data()
+ for (int i = 0; i < n; i++) {
+ array.data()[i].set(i + 1);
+ }
+ for (int i = 0; i < n; i++) {
+ EXPECT_THAT(array[i].get(), i+1);
+ EXPECT_THAT(array.data()[i].get(), i+1);
+ }
+ } // Close scope containing 'array'.
+
+ // Check that all constructed elements were destructed.
+ EXPECT_EQ(ConstructionTester::constructions,
+ ConstructionTester::destructions);
+}
+
+template <int elements_per_inner_array, int inline_elements>
+static void TestArrayOfArrays(int n) {
+ SCOPED_TRACE(n);
+ SCOPED_TRACE(inline_elements);
+ SCOPED_TRACE(elements_per_inner_array);
+ ConstructionTester::constructions = 0;
+ ConstructionTester::destructions = 0;
+ {
+ using InnerArray = ConstructionTester[elements_per_inner_array];
+ // Heap-allocate the FixedArray to avoid blowing the stack frame.
+ auto array_ptr =
+ absl::make_unique<absl::FixedArray<InnerArray, inline_elements>>(n);
+ auto& array = *array_ptr;
+
+ ASSERT_EQ(array.size(), n);
+ ASSERT_EQ(array.memsize(),
+ sizeof(ConstructionTester) * elements_per_inner_array * n);
+ ASSERT_EQ(array.begin() + n, array.end());
+
+ // Check that all elements were constructed
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < elements_per_inner_array; j++) {
+ (array[i])[j].CheckConstructed();
+ }
+ }
+ // Check that no other elements were constructed
+ ASSERT_EQ(ConstructionTester::constructions, n * elements_per_inner_array);
+
+ // Test operator[]
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < elements_per_inner_array; j++) {
+ (array[i])[j].set(i * elements_per_inner_array + j);
+ }
+ }
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < elements_per_inner_array; j++) {
+ ASSERT_EQ((array[i])[j].get(), i * elements_per_inner_array + j);
+ ASSERT_EQ((array.data()[i])[j].get(), i * elements_per_inner_array + j);
+ }
+ }
+
+ // Test data()
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < elements_per_inner_array; j++) {
+ (array.data()[i])[j].set((i + 1) * elements_per_inner_array + j);
+ }
+ }
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < elements_per_inner_array; j++) {
+ ASSERT_EQ((array[i])[j].get(),
+ (i + 1) * elements_per_inner_array + j);
+ ASSERT_EQ((array.data()[i])[j].get(),
+ (i + 1) * elements_per_inner_array + j);
+ }
+ }
+ } // Close scope containing 'array'.
+
+ // Check that all constructed elements were destructed.
+ EXPECT_EQ(ConstructionTester::constructions,
+ ConstructionTester::destructions);
+}
+
+TEST(IteratorConstructorTest, NonInline) {
+ int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 };
+ absl::FixedArray<int, ABSL_ARRAYSIZE(kInput) - 1> const fixed(
+ kInput, kInput + ABSL_ARRAYSIZE(kInput));
+ ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size());
+ for (size_t i = 0; i < ABSL_ARRAYSIZE(kInput); ++i) {
+ ASSERT_EQ(kInput[i], fixed[i]);
+ }
+}
+
+TEST(IteratorConstructorTest, Inline) {
+ int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 };
+ absl::FixedArray<int, ABSL_ARRAYSIZE(kInput)> const fixed(
+ kInput, kInput + ABSL_ARRAYSIZE(kInput));
+ ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size());
+ for (size_t i = 0; i < ABSL_ARRAYSIZE(kInput); ++i) {
+ ASSERT_EQ(kInput[i], fixed[i]);
+ }
+}
+
+TEST(IteratorConstructorTest, NonPod) {
+ char const* kInput[] =
+ { "red", "orange", "yellow", "green", "blue", "indigo", "violet" };
+ absl::FixedArray<std::string> const fixed(kInput, kInput + ABSL_ARRAYSIZE(kInput));
+ ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size());
+ for (size_t i = 0; i < ABSL_ARRAYSIZE(kInput); ++i) {
+ ASSERT_EQ(kInput[i], fixed[i]);
+ }
+}
+
+TEST(IteratorConstructorTest, FromEmptyVector) {
+ std::vector<int> const empty;
+ absl::FixedArray<int> const fixed(empty.begin(), empty.end());
+ EXPECT_EQ(0, fixed.size());
+ EXPECT_EQ(empty.size(), fixed.size());
+}
+
+TEST(IteratorConstructorTest, FromNonEmptyVector) {
+ int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 };
+ std::vector<int> const items(kInput, kInput + ABSL_ARRAYSIZE(kInput));
+ absl::FixedArray<int> const fixed(items.begin(), items.end());
+ ASSERT_EQ(items.size(), fixed.size());
+ for (size_t i = 0; i < items.size(); ++i) {
+ ASSERT_EQ(items[i], fixed[i]);
+ }
+}
+
+TEST(IteratorConstructorTest, FromBidirectionalIteratorRange) {
+ int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 };
+ std::list<int> const items(kInput, kInput + ABSL_ARRAYSIZE(kInput));
+ absl::FixedArray<int> const fixed(items.begin(), items.end());
+ EXPECT_THAT(fixed, testing::ElementsAreArray(kInput));
+}
+
+TEST(InitListConstructorTest, InitListConstruction) {
+ absl::FixedArray<int> fixed = {1, 2, 3};
+ EXPECT_THAT(fixed, testing::ElementsAreArray({1, 2, 3}));
+}
+
+TEST(FillConstructorTest, NonEmptyArrays) {
+ absl::FixedArray<int> stack_array(4, 1);
+ EXPECT_THAT(stack_array, testing::ElementsAreArray({1, 1, 1, 1}));
+
+ absl::FixedArray<int, 0> heap_array(4, 1);
+ EXPECT_THAT(stack_array, testing::ElementsAreArray({1, 1, 1, 1}));
+}
+
+TEST(FillConstructorTest, EmptyArray) {
+ absl::FixedArray<int> empty_fill(0, 1);
+ absl::FixedArray<int> empty_size(0);
+ EXPECT_EQ(empty_fill, empty_size);
+}
+
+TEST(FillConstructorTest, NotTriviallyCopyable) {
+ std::string str = "abcd";
+ absl::FixedArray<std::string> strings = {str, str, str, str};
+
+ absl::FixedArray<std::string> array(4, str);
+ EXPECT_EQ(array, strings);
+}
+
+TEST(FillConstructorTest, Disambiguation) {
+ absl::FixedArray<size_t> a(1, 2);
+ EXPECT_THAT(a, testing::ElementsAre(2));
+}
+
+TEST(FixedArrayTest, ManySizedArrays) {
+ std::vector<int> sizes;
+ for (int i = 1; i < 100; i++) sizes.push_back(i);
+ for (int i = 100; i <= 1000; i += 100) sizes.push_back(i);
+ for (int n : sizes) {
+ TestArray<0>(n);
+ TestArray<1>(n);
+ TestArray<64>(n);
+ TestArray<1000>(n);
+ }
+}
+
+TEST(FixedArrayTest, ManySizedArraysOfArraysOf1) {
+ for (int n = 1; n < 1000; n++) {
+ ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 0>(n)));
+ ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 1>(n)));
+ ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 64>(n)));
+ ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 1000>(n)));
+ }
+}
+
+TEST(FixedArrayTest, ManySizedArraysOfArraysOf2) {
+ for (int n = 1; n < 1000; n++) {
+ TestArrayOfArrays<2, 0>(n);
+ TestArrayOfArrays<2, 1>(n);
+ TestArrayOfArrays<2, 64>(n);
+ TestArrayOfArrays<2, 1000>(n);
+ }
+}
+
+// If value_type is put inside of a struct container,
+// we might evoke this error in a hardened build unless data() is carefully
+// written, so check on that.
+// error: call to int __builtin___sprintf_chk(etc...)
+// will always overflow destination buffer [-Werror]
+TEST(FixedArrayTest, AvoidParanoidDiagnostics) {
+ absl::FixedArray<char, 32> buf(32);
+ sprintf(buf.data(), "foo"); // NOLINT(runtime/printf)
+}
+
+TEST(FixedArrayTest, TooBigInlinedSpace) {
+ struct TooBig {
+ char c[1 << 20];
+ }; // too big for even one on the stack
+
+ // Simulate the data members of absl::FixedArray, a pointer and a size_t.
+ struct Data {
+ TooBig* p;
+ size_t size;
+ };
+
+ // Make sure TooBig objects are not inlined for 0 or default size.
+ static_assert(sizeof(absl::FixedArray<TooBig, 0>) == sizeof(Data),
+ "0-sized absl::FixedArray should have same size as Data.");
+ static_assert(alignof(absl::FixedArray<TooBig, 0>) == alignof(Data),
+ "0-sized absl::FixedArray should have same alignment as Data.");
+ static_assert(sizeof(absl::FixedArray<TooBig>) == sizeof(Data),
+ "default-sized absl::FixedArray should have same size as Data");
+ static_assert(
+ alignof(absl::FixedArray<TooBig>) == alignof(Data),
+ "default-sized absl::FixedArray should have same alignment as Data.");
+}
+
+// PickyDelete EXPECTs its class-scope deallocation funcs are unused.
+struct PickyDelete {
+ PickyDelete() {}
+ ~PickyDelete() {}
+ void operator delete(void* p) {
+ EXPECT_TRUE(false) << __FUNCTION__;
+ ::operator delete(p);
+ }
+ void operator delete[](void* p) {
+ EXPECT_TRUE(false) << __FUNCTION__;
+ ::operator delete[](p);
+ }
+};
+
+TEST(FixedArrayTest, UsesGlobalAlloc) { absl::FixedArray<PickyDelete, 0> a(5); }
+
+TEST(FixedArrayTest, Data) {
+ static const int kInput[] = { 2, 3, 5, 7, 11, 13, 17 };
+ absl::FixedArray<int> fa(std::begin(kInput), std::end(kInput));
+ EXPECT_EQ(fa.data(), &*fa.begin());
+ EXPECT_EQ(fa.data(), &fa[0]);
+
+ const absl::FixedArray<int>& cfa = fa;
+ EXPECT_EQ(cfa.data(), &*cfa.begin());
+ EXPECT_EQ(cfa.data(), &cfa[0]);
+}
+
+TEST(FixedArrayTest, Empty) {
+ absl::FixedArray<int> empty(0);
+ absl::FixedArray<int> inline_filled(1);
+ absl::FixedArray<int, 0> heap_filled(1);
+ EXPECT_TRUE(empty.empty());
+ EXPECT_FALSE(inline_filled.empty());
+ EXPECT_FALSE(heap_filled.empty());
+}
+
+TEST(FixedArrayTest, FrontAndBack) {
+ absl::FixedArray<int, 3 * sizeof(int)> inlined = {1, 2, 3};
+ EXPECT_EQ(inlined.front(), 1);
+ EXPECT_EQ(inlined.back(), 3);
+
+ absl::FixedArray<int, 0> allocated = {1, 2, 3};
+ EXPECT_EQ(allocated.front(), 1);
+ EXPECT_EQ(allocated.back(), 3);
+
+ absl::FixedArray<int> one_element = {1};
+ EXPECT_EQ(one_element.front(), one_element.back());
+}
+
+TEST(FixedArrayTest, ReverseIteratorInlined) {
+ absl::FixedArray<int, 5 * sizeof(int)> a = {0, 1, 2, 3, 4};
+
+ int counter = 5;
+ for (absl::FixedArray<int>::reverse_iterator iter = a.rbegin();
+ iter != a.rend(); ++iter) {
+ counter--;
+ EXPECT_EQ(counter, *iter);
+ }
+ EXPECT_EQ(counter, 0);
+
+ counter = 5;
+ for (absl::FixedArray<int>::const_reverse_iterator iter = a.rbegin();
+ iter != a.rend(); ++iter) {
+ counter--;
+ EXPECT_EQ(counter, *iter);
+ }
+ EXPECT_EQ(counter, 0);
+
+ counter = 5;
+ for (auto iter = a.crbegin(); iter != a.crend(); ++iter) {
+ counter--;
+ EXPECT_EQ(counter, *iter);
+ }
+ EXPECT_EQ(counter, 0);
+}
+
+TEST(FixedArrayTest, ReverseIteratorAllocated) {
+ absl::FixedArray<int, 0> a = {0, 1, 2, 3, 4};
+
+ int counter = 5;
+ for (absl::FixedArray<int>::reverse_iterator iter = a.rbegin();
+ iter != a.rend(); ++iter) {
+ counter--;
+ EXPECT_EQ(counter, *iter);
+ }
+ EXPECT_EQ(counter, 0);
+
+ counter = 5;
+ for (absl::FixedArray<int>::const_reverse_iterator iter = a.rbegin();
+ iter != a.rend(); ++iter) {
+ counter--;
+ EXPECT_EQ(counter, *iter);
+ }
+ EXPECT_EQ(counter, 0);
+
+ counter = 5;
+ for (auto iter = a.crbegin(); iter != a.crend(); ++iter) {
+ counter--;
+ EXPECT_EQ(counter, *iter);
+ }
+ EXPECT_EQ(counter, 0);
+}
+
+TEST(FixedArrayTest, Fill) {
+ absl::FixedArray<int, 5 * sizeof(int)> inlined(5);
+ int fill_val = 42;
+ inlined.fill(fill_val);
+ for (int i : inlined) EXPECT_EQ(i, fill_val);
+
+ absl::FixedArray<int, 0> allocated(5);
+ allocated.fill(fill_val);
+ for (int i : allocated) EXPECT_EQ(i, fill_val);
+
+ // It doesn't do anything, just make sure this compiles.
+ absl::FixedArray<int> empty(0);
+ empty.fill(fill_val);
+}
+
+#ifdef ADDRESS_SANITIZER
+TEST(FixedArrayTest, AddressSanitizerAnnotations1) {
+ absl::FixedArray<int, 32> a(10);
+ int *raw = a.data();
+ raw[0] = 0;
+ raw[9] = 0;
+ EXPECT_DEATH(raw[-2] = 0, "container-overflow");
+ EXPECT_DEATH(raw[-1] = 0, "container-overflow");
+ EXPECT_DEATH(raw[10] = 0, "container-overflow");
+ EXPECT_DEATH(raw[31] = 0, "container-overflow");
+}
+
+TEST(FixedArrayTest, AddressSanitizerAnnotations2) {
+ absl::FixedArray<char, 17> a(12);
+ char *raw = a.data();
+ raw[0] = 0;
+ raw[11] = 0;
+ EXPECT_DEATH(raw[-7] = 0, "container-overflow");
+ EXPECT_DEATH(raw[-1] = 0, "container-overflow");
+ EXPECT_DEATH(raw[12] = 0, "container-overflow");
+ EXPECT_DEATH(raw[17] = 0, "container-overflow");
+}
+
+TEST(FixedArrayTest, AddressSanitizerAnnotations3) {
+ absl::FixedArray<uint64_t, 20> a(20);
+ uint64_t *raw = a.data();
+ raw[0] = 0;
+ raw[19] = 0;
+ EXPECT_DEATH(raw[-1] = 0, "container-overflow");
+ EXPECT_DEATH(raw[20] = 0, "container-overflow");
+}
+
+TEST(FixedArrayTest, AddressSanitizerAnnotations4) {
+ absl::FixedArray<ThreeInts> a(10);
+ ThreeInts *raw = a.data();
+ raw[0] = ThreeInts();
+ raw[9] = ThreeInts();
+ // Note: raw[-1] is pointing to 12 bytes before the container range. However,
+ // there is only a 8-byte red zone before the container range, so we only
+ // access the last 4 bytes of the struct to make sure it stays within the red
+ // zone.
+ EXPECT_DEATH(raw[-1].z_ = 0, "container-overflow");
+ EXPECT_DEATH(raw[10] = ThreeInts(), "container-overflow");
+ // The actual size of storage is kDefaultBytes=256, 21*12 = 252,
+ // so reading raw[21] should still trigger the correct warning.
+ EXPECT_DEATH(raw[21] = ThreeInts(), "container-overflow");
+}
+#endif // ADDRESS_SANITIZER
+
+} // namespace
diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h
new file mode 100644
index 0000000..f060f5c
--- /dev/null
+++ b/absl/container/inlined_vector.h
@@ -0,0 +1,1330 @@
+// 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: inlined_vector.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains the declaration and definition of an "inlined
+// vector" which behaves in an equivalent fashion to a `std::vector`, except
+// that storage for small sequences of the vector are provided inline without
+// requiring any heap allocation.
+
+// An `absl::InlinedVector<T,N>` specifies the size N at which to inline as one
+// of its template parameters. Vectors of length <= N are provided inline.
+// Typically N is very small (e.g., 4) so that sequences that are expected to be
+// short do not require allocations.
+
+// An `absl::InlinedVector` does not usually require a specific allocator; if
+// the inlined vector grows beyond its initial constraints, it will need to
+// allocate (as any normal `std::vector` would) and it will generally use the
+// default allocator in that case; optionally, a custom allocator may be
+// specified using an `absl::InlinedVector<T,N,A>` construction.
+
+#ifndef ABSL_CONTAINER_INLINED_VECTOR_H_
+#define ABSL_CONTAINER_INLINED_VECTOR_H_
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <initializer_list>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "absl/algorithm/algorithm.h"
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/base/optimization.h"
+#include "absl/base/port.h"
+#include "absl/memory/memory.h"
+
+namespace absl {
+
+// -----------------------------------------------------------------------------
+// InlinedVector
+// -----------------------------------------------------------------------------
+//
+// An `absl::InlinedVector` is designed to be a drop-in replacement for
+// `std::vector` for use cases where the vector's size is sufficiently small
+// that it can be inlined. If the inlined vector does grow beyond its estimated
+// size, it will trigger an initial allocation on the heap, and will behave as a
+// `std:vector`. The API of the `absl::InlinedVector` within this file is
+// designed to cover the same API footprint as covered by `std::vector`.
+template <typename T, size_t N, typename A = std::allocator<T> >
+class InlinedVector {
+ using AllocatorTraits = std::allocator_traits<A>;
+
+ public:
+ using allocator_type = A;
+ using value_type = typename allocator_type::value_type;
+ using pointer = typename allocator_type::pointer;
+ using const_pointer = typename allocator_type::const_pointer;
+ using reference = typename allocator_type::reference;
+ using const_reference = typename allocator_type::const_reference;
+ using size_type = typename allocator_type::size_type;
+ using difference_type = typename allocator_type::difference_type;
+ using iterator = pointer;
+ using const_iterator = const_pointer;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ InlinedVector() noexcept(noexcept(allocator_type()))
+ : allocator_and_tag_(allocator_type()) {}
+
+ explicit InlinedVector(const allocator_type& alloc) noexcept
+ : allocator_and_tag_(alloc) {}
+
+ // Create a vector with n copies of value_type().
+ explicit InlinedVector(size_type n) : allocator_and_tag_(allocator_type()) {
+ InitAssign(n);
+ }
+
+ // Create a vector with n copies of elem
+ InlinedVector(size_type n, const value_type& elem,
+ const allocator_type& alloc = allocator_type())
+ : allocator_and_tag_(alloc) {
+ InitAssign(n, elem);
+ }
+
+ // Create and initialize with the elements [first .. last).
+ // The unused enable_if argument restricts this constructor so that it is
+ // elided when value_type is an integral type. This prevents ambiguous
+ // interpretation between a call to this constructor with two integral
+ // arguments and a call to the preceding (n, elem) constructor.
+ template <typename InputIterator>
+ InlinedVector(
+ InputIterator first, InputIterator last,
+ const allocator_type& alloc = allocator_type(),
+ typename std::enable_if<!std::is_integral<InputIterator>::value>::type* =
+ nullptr)
+ : allocator_and_tag_(alloc) {
+ AppendRange(first, last);
+ }
+
+ InlinedVector(std::initializer_list<value_type> init,
+ const allocator_type& alloc = allocator_type())
+ : allocator_and_tag_(alloc) {
+ AppendRange(init.begin(), init.end());
+ }
+
+ InlinedVector(const InlinedVector& v);
+ InlinedVector(const InlinedVector& v, const allocator_type& alloc);
+
+ InlinedVector(InlinedVector&& v) noexcept(
+ absl::allocator_is_nothrow<allocator_type>::value ||
+ std::is_nothrow_move_constructible<value_type>::value);
+ InlinedVector(InlinedVector&& v, const allocator_type& alloc) noexcept(
+ absl::allocator_is_nothrow<allocator_type>::value);
+
+ ~InlinedVector() { clear(); }
+
+ InlinedVector& operator=(const InlinedVector& v) {
+ // Optimized to avoid reallocation.
+ // Prefer reassignment to copy construction for elements.
+ if (size() < v.size()) { // grow
+ reserve(v.size());
+ std::copy(v.begin(), v.begin() + size(), begin());
+ std::copy(v.begin() + size(), v.end(), std::back_inserter(*this));
+ } else { // maybe shrink
+ erase(begin() + v.size(), end());
+ std::copy(v.begin(), v.end(), begin());
+ }
+ return *this;
+ }
+
+ InlinedVector& operator=(InlinedVector&& v) {
+ if (this == &v) {
+ return *this;
+ }
+ if (v.allocated()) {
+ clear();
+ tag().set_allocated_size(v.size());
+ init_allocation(v.allocation());
+ v.tag() = Tag();
+ } else {
+ if (allocated()) clear();
+ // Both are inlined now.
+ if (size() < v.size()) {
+ auto mid = std::make_move_iterator(v.begin() + size());
+ std::copy(std::make_move_iterator(v.begin()), mid, begin());
+ UninitializedCopy(mid, std::make_move_iterator(v.end()), end());
+ } else {
+ auto new_end = std::copy(std::make_move_iterator(v.begin()),
+ std::make_move_iterator(v.end()), begin());
+ Destroy(new_end, end());
+ }
+ tag().set_inline_size(v.size());
+ }
+ return *this;
+ }
+
+ InlinedVector& operator=(std::initializer_list<value_type> init) {
+ AssignRange(init.begin(), init.end());
+ return *this;
+ }
+
+ // InlinedVector::assign()
+ //
+ // Replaces the contents of the inlined vector with copies of those in the
+ // iterator range [first, last).
+ template <typename InputIterator>
+ void assign(
+ InputIterator first, InputIterator last,
+ typename std::enable_if<!std::is_integral<InputIterator>::value>::type* =
+ nullptr) {
+ AssignRange(first, last);
+ }
+
+ // Overload of `InlinedVector::assign()` to take values from elements of an
+ // initializer list
+ void assign(std::initializer_list<value_type> init) {
+ AssignRange(init.begin(), init.end());
+ }
+
+ // Overload of `InlinedVector::assign()` to replace the first `n` elements of
+ // the inlined vector with `elem` values.
+ void assign(size_type n, const value_type& elem) {
+ if (n <= size()) { // Possibly shrink
+ std::fill_n(begin(), n, elem);
+ erase(begin() + n, end());
+ return;
+ }
+ // Grow
+ reserve(n);
+ std::fill_n(begin(), size(), elem);
+ if (allocated()) {
+ UninitializedFill(allocated_space() + size(), allocated_space() + n,
+ elem);
+ tag().set_allocated_size(n);
+ } else {
+ UninitializedFill(inlined_space() + size(), inlined_space() + n, elem);
+ tag().set_inline_size(n);
+ }
+ }
+
+ // InlinedVector::size()
+ //
+ // Returns the number of elements in the inlined vector.
+ size_type size() const noexcept { return tag().size(); }
+
+ // InlinedVector::empty()
+ //
+ // Checks if the inlined vector has no elements.
+ bool empty() const noexcept { return (size() == 0); }
+
+ // InlinedVector::capacity()
+ //
+ // Returns the number of elements that can be stored in an inlined vector
+ // without requiring a reallocation of underlying memory. Note that for
+ // most inlined vectors, `capacity()` should equal its initial size `N`; for
+ // inlined vectors which exceed this capacity, they will no longer be inlined,
+ // and `capacity()` will equal its capacity on the allocated heap.
+ size_type capacity() const noexcept {
+ return allocated() ? allocation().capacity() : N;
+ }
+
+ // InlinedVector::max_size()
+ //
+ // Returns the maximum number of elements the vector can hold.
+ size_type max_size() const noexcept {
+ // One bit of the size storage is used to indicate whether the inlined
+ // vector is allocated; as a result, the maximum size of the container that
+ // we can express is half of the max for our size type.
+ return std::numeric_limits<size_type>::max() / 2;
+ }
+
+ // InlinedVector::data()
+ //
+ // Returns a const T* pointer to elements of the inlined vector. This pointer
+ // can be used to access (but not modify) the contained elements.
+ // Only results within the range `[0,size())` are defined.
+ const_pointer data() const noexcept {
+ return allocated() ? allocated_space() : inlined_space();
+ }
+
+ // Overload of InlinedVector::data() to return a T* pointer to elements of the
+ // inlined vector. This pointer can be used to access and modify the contained
+ // elements.
+ pointer data() noexcept {
+ return allocated() ? allocated_space() : inlined_space();
+ }
+
+ // InlinedVector::clear()
+ //
+ // Removes all elements from the inlined vector.
+ void clear() noexcept {
+ size_type s = size();
+ if (allocated()) {
+ Destroy(allocated_space(), allocated_space() + s);
+ allocation().Dealloc(allocator());
+ } else if (s != 0) { // do nothing for empty vectors
+ Destroy(inlined_space(), inlined_space() + s);
+ }
+ tag() = Tag();
+ }
+
+ // InlinedVector::at()
+ //
+ // Returns the ith element of an inlined vector.
+ const value_type& at(size_type i) const {
+ if (ABSL_PREDICT_FALSE(i >= size())) {
+ base_internal::ThrowStdOutOfRange(
+ "InlinedVector::at failed bounds check");
+ }
+ return data()[i];
+ }
+
+ // InlinedVector::operator[]
+ //
+ // Returns the ith element of an inlined vector using the array operator.
+ const value_type& operator[](size_type i) const {
+ assert(i < size());
+ return data()[i];
+ }
+
+ // Overload of InlinedVector::at() to return the ith element of an inlined
+ // vector.
+ value_type& at(size_type i) {
+ if (i >= size()) {
+ base_internal::ThrowStdOutOfRange(
+ "InlinedVector::at failed bounds check");
+ }
+ return data()[i];
+ }
+
+ // Overload of InlinedVector::operator[] to return the ith element of an
+ // inlined vector.
+ value_type& operator[](size_type i) {
+ assert(i < size());
+ return data()[i];
+ }
+
+ // InlinedVector::back()
+ //
+ // Returns a reference to the last element of an inlined vector.
+ value_type& back() {
+ assert(!empty());
+ return at(size() - 1);
+ }
+
+ // Overload of InlinedVector::back() returns a reference to the last element
+ // of an inlined vector of const values.
+ const value_type& back() const {
+ assert(!empty());
+ return at(size() - 1);
+ }
+
+ // InlinedVector::front()
+ //
+ // Returns a reference to the first element of an inlined vector.
+ value_type& front() {
+ assert(!empty());
+ return at(0);
+ }
+
+ // Overload of InlinedVector::front() returns a reference to the first element
+ // of an inlined vector of const values.
+ const value_type& front() const {
+ assert(!empty());
+ return at(0);
+ }
+
+ // InlinedVector::emplace_back()
+ //
+ // Constructs and appends an object to the inlined vector.
+ template <typename... Args>
+ void emplace_back(Args&&... args) {
+ size_type s = size();
+ assert(s <= capacity());
+ if (ABSL_PREDICT_FALSE(s == capacity())) {
+ GrowAndEmplaceBack(std::forward<Args>(args)...);
+ return;
+ }
+ assert(s < capacity());
+
+ value_type* space;
+ if (allocated()) {
+ tag().set_allocated_size(s + 1);
+ space = allocated_space();
+ } else {
+ tag().set_inline_size(s + 1);
+ space = inlined_space();
+ }
+ Construct(space + s, std::forward<Args>(args)...);
+ }
+
+ // InlinedVector::push_back()
+ //
+ // Appends a const element to the inlined vector.
+ void push_back(const value_type& t) { emplace_back(t); }
+
+ // Overload of InlinedVector::push_back() to append a move-only element to the
+ // inlined vector.
+ void push_back(value_type&& t) { emplace_back(std::move(t)); }
+
+ // InlinedVector::pop_back()
+ //
+ // Removes the last element (which is destroyed) in the inlined vector.
+ void pop_back() {
+ assert(!empty());
+ size_type s = size();
+ if (allocated()) {
+ Destroy(allocated_space() + s - 1, allocated_space() + s);
+ tag().set_allocated_size(s - 1);
+ } else {
+ Destroy(inlined_space() + s - 1, inlined_space() + s);
+ tag().set_inline_size(s - 1);
+ }
+ }
+
+ // InlinedVector::resize()
+ //
+ // Resizes the inlined vector to contain `n` elements. If `n` is smaller than
+ // the inlined vector's current size, extra elements are destroyed. If `n` is
+ // larger than the initial size, new elements are value-initialized.
+ void resize(size_type n);
+
+ // Overload of InlinedVector::resize() to resize the inlined vector to contain
+ // `n` elements. If `n` is larger than the current size, enough copies of
+ // `elem` are appended to increase its size to `n`.
+ void resize(size_type n, const value_type& elem);
+
+ // InlinedVector::begin()
+ //
+ // Returns an iterator to the beginning of the inlined vector.
+ iterator begin() noexcept { return data(); }
+
+ // Overload of InlinedVector::begin() for returning a const iterator to the
+ // beginning of the inlined vector.
+ const_iterator begin() const noexcept { return data(); }
+
+ // InlinedVector::cbegin()
+ //
+ // Returns a const iterator to the beginning of the inlined vector.
+ const_iterator cbegin() const noexcept { return begin(); }
+
+ // InlinedVector::end()
+ //
+ // Returns an iterator to the end of the inlined vector.
+ iterator end() noexcept { return data() + size(); }
+
+ // Overload of InlinedVector::end() for returning a const iterator to the end
+ // of the inlined vector.
+ const_iterator end() const noexcept { return data() + size(); }
+
+ // InlinedVector::cend()
+ //
+ // Returns a const iterator to the end of the inlined vector.
+ const_iterator cend() const noexcept { return end(); }
+
+ // InlinedVector::rbegin()
+ //
+ // Returns a reverse iterator from the end of the inlined vector.
+ reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
+
+ // Overload of InlinedVector::rbegin() for returning a const reverse iterator
+ // from the end of the inlined vector.
+ const_reverse_iterator rbegin() const noexcept {
+ return const_reverse_iterator(end());
+ }
+
+ // InlinedVector::crbegin()
+ //
+ // Returns a const reverse iterator from the end of the inlined vector.
+ const_reverse_iterator crbegin() const noexcept { return rbegin(); }
+
+ // InlinedVector::rend()
+ //
+ // Returns a reverse iterator from the beginning of the inlined vector.
+ reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
+
+ // Overload of InlinedVector::rend() for returning a const reverse iterator
+ // from the beginning of the inlined vector.
+ const_reverse_iterator rend() const noexcept {
+ return const_reverse_iterator(begin());
+ }
+
+ // InlinedVector::crend()
+ //
+ // Returns a reverse iterator from the beginning of the inlined vector.
+ const_reverse_iterator crend() const noexcept { return rend(); }
+
+ // InlinedVector::emplace()
+ //
+ // Constructs and inserts an object to the inlined vector at the given
+ // `position`, returning an iterator pointing to the newly emplaced element.
+ template <typename... Args>
+ iterator emplace(const_iterator position, Args&&... args);
+
+ // InlinedVector::insert()
+ //
+ // Inserts an element of the specified value at `position`, returning an
+ // iterator pointing to the newly inserted element.
+ iterator insert(const_iterator position, const value_type& v) {
+ return emplace(position, v);
+ }
+
+ // Overload of InlinedVector::insert() for inserting an element of the
+ // specified rvalue, returning an iterator pointing to the newly inserted
+ // element.
+ iterator insert(const_iterator position, value_type&& v) {
+ return emplace(position, std::move(v));
+ }
+
+ // Overload of InlinedVector::insert() for inserting `n` elements of the
+ // specified value at `position`, returning an iterator pointing to the first
+ // of the newly inserted elements.
+ iterator insert(const_iterator position, size_type n, const value_type& v) {
+ return InsertWithCount(position, n, v);
+ }
+
+ // Overload of `InlinedVector::insert()` to disambiguate the two
+ // three-argument overloads of `insert()`, returning an iterator pointing to
+ // the first of the newly inserted elements.
+ template <typename InputIterator,
+ typename = typename std::enable_if<std::is_convertible<
+ typename std::iterator_traits<InputIterator>::iterator_category,
+ std::input_iterator_tag>::value>::type>
+ iterator insert(const_iterator position, InputIterator first,
+ InputIterator last) {
+ using IterType =
+ typename std::iterator_traits<InputIterator>::iterator_category;
+ return InsertWithRange(position, first, last, IterType());
+ }
+
+ // Overload of InlinedVector::insert() for inserting a list of elements at
+ // `position`, returning an iterator pointing to the first of the newly
+ // inserted elements.
+ iterator insert(const_iterator position,
+ std::initializer_list<value_type> init) {
+ return insert(position, init.begin(), init.end());
+ }
+
+ // InlinedVector::erase()
+ //
+ // Erases the element at `position` of the inlined vector, returning an
+ // iterator pointing to the following element or the container's end if the
+ // last element was erased.
+ iterator erase(const_iterator position) {
+ assert(position >= begin());
+ assert(position < end());
+
+ iterator pos = const_cast<iterator>(position);
+ std::move(pos + 1, end(), pos);
+ pop_back();
+ return pos;
+ }
+
+ // Overload of InlinedVector::erase() for erasing all elements in the
+ // iteraror range [first, last) in the inlined vector, returning an iterator
+ // pointing to the first element following the range erased, or the
+ // container's end if range included the container's last element.
+ iterator erase(const_iterator first, const_iterator last);
+
+ // InlinedVector::reserve()
+ //
+ // Enlarges the underlying representation of the inlined vector so it can hold
+ // at least `n` elements. This method does not change `size()` or the actual
+ // contents of the vector.
+ //
+ // Note that if `n` does not exceed the inlined vector's initial size `N`,
+ // `reserve()` will have no effect; if it does exceed its initial size,
+ // `reserve()` will trigger an initial allocation and move the inlined vector
+ // onto the heap. If the vector already exists on the heap and the requested
+ // size exceeds it, a reallocation will be performed.
+ void reserve(size_type n) {
+ if (n > capacity()) {
+ // Make room for new elements
+ EnlargeBy(n - size());
+ }
+ }
+
+ // InlinedVector::swap()
+ //
+ // Swaps the contents of this inlined vector with the contents of `other`.
+ void swap(InlinedVector& other);
+
+ // InlinedVector::get_allocator()
+ //
+ // Returns the allocator of this inlined vector.
+ allocator_type get_allocator() const { return allocator(); }
+
+ private:
+ static_assert(N > 0, "inlined vector with nonpositive size");
+
+ // It holds whether the vector is allocated or not in the lowest bit.
+ // The size is held in the high bits:
+ // size_ = (size << 1) | is_allocated;
+ class Tag {
+ public:
+ Tag() : size_(0) {}
+ size_type size() const { return size_ >> 1; }
+ void add_size(size_type n) { size_ += n << 1; }
+ void set_inline_size(size_type n) { size_ = n << 1; }
+ void set_allocated_size(size_type n) { size_ = (n << 1) | 1; }
+ bool allocated() const { return size_ & 1; }
+
+ private:
+ size_type size_;
+ };
+
+ // Derives from allocator_type to use the empty base class optimization.
+ // If the allocator_type is stateless, we can 'store'
+ // our instance of it for free.
+ class AllocatorAndTag : private allocator_type {
+ public:
+ explicit AllocatorAndTag(const allocator_type& a, Tag t = Tag())
+ : allocator_type(a), tag_(t) {
+ }
+ Tag& tag() { return tag_; }
+ const Tag& tag() const { return tag_; }
+ allocator_type& allocator() { return *this; }
+ const allocator_type& allocator() const { return *this; }
+ private:
+ Tag tag_;
+ };
+
+ class Allocation {
+ public:
+ Allocation(allocator_type& a, // NOLINT(runtime/references)
+ size_type capacity)
+ : capacity_(capacity),
+ buffer_(AllocatorTraits::allocate(a, capacity_)) {}
+
+ void Dealloc(allocator_type& a) { // NOLINT(runtime/references)
+ AllocatorTraits::deallocate(a, buffer(), capacity());
+ }
+
+ size_type capacity() const { return capacity_; }
+ const value_type* buffer() const { return buffer_; }
+ value_type* buffer() { return buffer_; }
+
+ private:
+ size_type capacity_;
+ value_type* buffer_;
+ };
+
+ const Tag& tag() const { return allocator_and_tag_.tag(); }
+ Tag& tag() { return allocator_and_tag_.tag(); }
+
+ Allocation& allocation() {
+ return reinterpret_cast<Allocation&>(rep_.allocation_storage.allocation);
+ }
+ const Allocation& allocation() const {
+ return reinterpret_cast<const Allocation&>(
+ rep_.allocation_storage.allocation);
+ }
+ void init_allocation(const Allocation& allocation) {
+ new (&rep_.allocation_storage.allocation) Allocation(allocation);
+ }
+
+ value_type* inlined_space() {
+ return reinterpret_cast<value_type*>(&rep_.inlined_storage.inlined);
+ }
+ const value_type* inlined_space() const {
+ return reinterpret_cast<const value_type*>(&rep_.inlined_storage.inlined);
+ }
+
+ value_type* allocated_space() {
+ return allocation().buffer();
+ }
+ const value_type* allocated_space() const {
+ return allocation().buffer();
+ }
+
+ const allocator_type& allocator() const {
+ return allocator_and_tag_.allocator();
+ }
+ allocator_type& allocator() {
+ return allocator_and_tag_.allocator();
+ }
+
+ bool allocated() const { return tag().allocated(); }
+
+ // Enlarge the underlying representation so we can store size_ + delta elems.
+ // The size is not changed, and any newly added memory is not initialized.
+ void EnlargeBy(size_type delta);
+
+ // Shift all elements from position to end() n places to the right.
+ // If the vector needs to be enlarged, memory will be allocated.
+ // Returns iterators pointing to the start of the previously-initialized
+ // portion and the start of the uninitialized portion of the created gap.
+ // The number of initialized spots is pair.second - pair.first;
+ // the number of raw spots is n - (pair.second - pair.first).
+ std::pair<iterator, iterator> ShiftRight(const_iterator position,
+ size_type n);
+
+ void ResetAllocation(Allocation new_allocation, size_type new_size) {
+ if (allocated()) {
+ Destroy(allocated_space(), allocated_space() + size());
+ assert(begin() == allocated_space());
+ allocation().Dealloc(allocator());
+ allocation() = new_allocation;
+ } else {
+ Destroy(inlined_space(), inlined_space() + size());
+ init_allocation(new_allocation); // bug: only init once
+ }
+ tag().set_allocated_size(new_size);
+ }
+
+ template <typename... Args>
+ void GrowAndEmplaceBack(Args&&... args) {
+ assert(size() == capacity());
+ const size_type s = size();
+
+ Allocation new_allocation(allocator(), 2 * capacity());
+
+ Construct(new_allocation.buffer() + s, std::forward<Args>(args)...);
+ UninitializedCopy(std::make_move_iterator(data()),
+ std::make_move_iterator(data() + s),
+ new_allocation.buffer());
+
+ ResetAllocation(new_allocation, s + 1);
+ }
+
+ void InitAssign(size_type n);
+ void InitAssign(size_type n, const value_type& t);
+
+ template <typename... Args>
+ void Construct(pointer p, Args&&... args) {
+ AllocatorTraits::construct(allocator(), p, std::forward<Args>(args)...);
+ }
+
+ template <typename Iter>
+ void UninitializedCopy(Iter src, Iter src_last, value_type* dst) {
+ for (; src != src_last; ++dst, ++src) Construct(dst, *src);
+ }
+
+ template <typename... Args>
+ void UninitializedFill(value_type* dst, value_type* dst_last,
+ const Args&... args) {
+ for (; dst != dst_last; ++dst) Construct(dst, args...);
+ }
+
+ // Destroy [ptr, ptr_last) in place.
+ void Destroy(value_type* ptr, value_type* ptr_last);
+
+ template <typename Iter>
+ void AppendRange(Iter first, Iter last, std::input_iterator_tag) {
+ std::copy(first, last, std::back_inserter(*this));
+ }
+
+ // Faster path for forward iterators.
+ template <typename Iter>
+ void AppendRange(Iter first, Iter last, std::forward_iterator_tag);
+
+ template <typename Iter>
+ void AppendRange(Iter first, Iter last) {
+ using IterTag = typename std::iterator_traits<Iter>::iterator_category;
+ AppendRange(first, last, IterTag());
+ }
+
+ template <typename Iter>
+ void AssignRange(Iter first, Iter last, std::input_iterator_tag);
+
+ // Faster path for forward iterators.
+ template <typename Iter>
+ void AssignRange(Iter first, Iter last, std::forward_iterator_tag);
+
+ template <typename Iter>
+ void AssignRange(Iter first, Iter last) {
+ using IterTag = typename std::iterator_traits<Iter>::iterator_category;
+ AssignRange(first, last, IterTag());
+ }
+
+ iterator InsertWithCount(const_iterator position, size_type n,
+ const value_type& v);
+
+ template <typename InputIter>
+ iterator InsertWithRange(const_iterator position, InputIter first,
+ InputIter last, std::input_iterator_tag);
+ template <typename ForwardIter>
+ iterator InsertWithRange(const_iterator position, ForwardIter first,
+ ForwardIter last, std::forward_iterator_tag);
+
+ AllocatorAndTag allocator_and_tag_;
+
+ // Either the inlined or allocated representation
+ union Rep {
+ // Use struct to perform indirection that solves a bizarre compilation
+ // error on Visual Studio (all known versions).
+ struct {
+ typename std::aligned_storage<sizeof(value_type),
+ alignof(value_type)>::type inlined[N];
+ } inlined_storage;
+ struct {
+ typename std::aligned_storage<sizeof(Allocation),
+ alignof(Allocation)>::type allocation;
+ } allocation_storage;
+ } rep_;
+};
+
+// -----------------------------------------------------------------------------
+// InlinedVector Non-Member Functions
+// -----------------------------------------------------------------------------
+
+// swap()
+//
+// Swaps the contents of two inlined vectors. This convenience function
+// simply calls InlinedVector::swap(other_inlined_vector).
+template <typename T, size_t N, typename A>
+void swap(InlinedVector<T, N, A>& a,
+ InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) {
+ a.swap(b);
+}
+
+// operator==()
+//
+// Tests the equivalency of the contents of two inlined vectors.
+template <typename T, size_t N, typename A>
+bool operator==(const InlinedVector<T, N, A>& a,
+ const InlinedVector<T, N, A>& b) {
+ return absl::equal(a.begin(), a.end(), b.begin(), b.end());
+}
+
+// operator!=()
+//
+// Tests the inequality of the contents of two inlined vectors.
+template <typename T, size_t N, typename A>
+bool operator!=(const InlinedVector<T, N, A>& a,
+ const InlinedVector<T, N, A>& b) {
+ return !(a == b);
+}
+
+// operator<()
+//
+// Tests whether the contents of one inlined vector are less than the contents
+// of another through a lexicographical comparison operation.
+template <typename T, size_t N, typename A>
+bool operator<(const InlinedVector<T, N, A>& a,
+ const InlinedVector<T, N, A>& b) {
+ return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
+}
+
+// operator>()
+//
+// Tests whether the contents of one inlined vector are greater than the
+// contents of another through a lexicographical comparison operation.
+template <typename T, size_t N, typename A>
+bool operator>(const InlinedVector<T, N, A>& a,
+ const InlinedVector<T, N, A>& b) {
+ return b < a;
+}
+
+// operator<=()
+//
+// Tests whether the contents of one inlined vector are less than or equal to
+// the contents of another through a lexicographical comparison operation.
+template <typename T, size_t N, typename A>
+bool operator<=(const InlinedVector<T, N, A>& a,
+ const InlinedVector<T, N, A>& b) {
+ return !(b < a);
+}
+
+// operator>=()
+//
+// Tests whether the contents of one inlined vector are greater than or equal to
+// the contents of another through a lexicographical comparison operation.
+template <typename T, size_t N, typename A>
+bool operator>=(const InlinedVector<T, N, A>& a,
+ const InlinedVector<T, N, A>& b) {
+ return !(a < b);
+}
+
+// -----------------------------------------------------------------------------
+// Implementation of InlinedVector
+// -----------------------------------------------------------------------------
+//
+// Do not depend on any implementation details below this line.
+
+template <typename T, size_t N, typename A>
+InlinedVector<T, N, A>::InlinedVector(const InlinedVector& v)
+ : allocator_and_tag_(v.allocator()) {
+ reserve(v.size());
+ if (allocated()) {
+ UninitializedCopy(v.begin(), v.end(), allocated_space());
+ tag().set_allocated_size(v.size());
+ } else {
+ UninitializedCopy(v.begin(), v.end(), inlined_space());
+ tag().set_inline_size(v.size());
+ }
+}
+
+template <typename T, size_t N, typename A>
+InlinedVector<T, N, A>::InlinedVector(const InlinedVector& v,
+ const allocator_type& alloc)
+ : allocator_and_tag_(alloc) {
+ reserve(v.size());
+ if (allocated()) {
+ UninitializedCopy(v.begin(), v.end(), allocated_space());
+ tag().set_allocated_size(v.size());
+ } else {
+ UninitializedCopy(v.begin(), v.end(), inlined_space());
+ tag().set_inline_size(v.size());
+ }
+}
+
+template <typename T, size_t N, typename A>
+InlinedVector<T, N, A>::InlinedVector(InlinedVector&& v) noexcept(
+ absl::allocator_is_nothrow<allocator_type>::value ||
+ std::is_nothrow_move_constructible<value_type>::value)
+ : allocator_and_tag_(v.allocator_and_tag_) {
+ if (v.allocated()) {
+ // We can just steal the underlying buffer from the source.
+ // That leaves the source empty, so we clear its size.
+ init_allocation(v.allocation());
+ v.tag() = Tag();
+ } else {
+ UninitializedCopy(std::make_move_iterator(v.inlined_space()),
+ std::make_move_iterator(v.inlined_space() + v.size()),
+ inlined_space());
+ }
+}
+
+template <typename T, size_t N, typename A>
+InlinedVector<T, N, A>::InlinedVector(
+ InlinedVector&& v,
+ const allocator_type&
+ alloc) noexcept(absl::allocator_is_nothrow<allocator_type>::value)
+ : allocator_and_tag_(alloc) {
+ if (v.allocated()) {
+ if (alloc == v.allocator()) {
+ // We can just steal the allocation from the source.
+ tag() = v.tag();
+ init_allocation(v.allocation());
+ v.tag() = Tag();
+ } else {
+ // We need to use our own allocator
+ reserve(v.size());
+ UninitializedCopy(std::make_move_iterator(v.begin()),
+ std::make_move_iterator(v.end()), allocated_space());
+ tag().set_allocated_size(v.size());
+ }
+ } else {
+ UninitializedCopy(std::make_move_iterator(v.inlined_space()),
+ std::make_move_iterator(v.inlined_space() + v.size()),
+ inlined_space());
+ tag().set_inline_size(v.size());
+ }
+}
+
+template <typename T, size_t N, typename A>
+void InlinedVector<T, N, A>::InitAssign(size_type n, const value_type& t) {
+ if (n > static_cast<size_type>(N)) {
+ Allocation new_allocation(allocator(), n);
+ init_allocation(new_allocation);
+ UninitializedFill(allocated_space(), allocated_space() + n, t);
+ tag().set_allocated_size(n);
+ } else {
+ UninitializedFill(inlined_space(), inlined_space() + n, t);
+ tag().set_inline_size(n);
+ }
+}
+
+template <typename T, size_t N, typename A>
+void InlinedVector<T, N, A>::InitAssign(size_type n) {
+ if (n > static_cast<size_type>(N)) {
+ Allocation new_allocation(allocator(), n);
+ init_allocation(new_allocation);
+ UninitializedFill(allocated_space(), allocated_space() + n);
+ tag().set_allocated_size(n);
+ } else {
+ UninitializedFill(inlined_space(), inlined_space() + n);
+ tag().set_inline_size(n);
+ }
+}
+
+template <typename T, size_t N, typename A>
+void InlinedVector<T, N, A>::resize(size_type n) {
+ size_type s = size();
+ if (n < s) {
+ erase(begin() + n, end());
+ return;
+ }
+ reserve(n);
+ assert(capacity() >= n);
+
+ // Fill new space with elements constructed in-place.
+ if (allocated()) {
+ UninitializedFill(allocated_space() + s, allocated_space() + n);
+ tag().set_allocated_size(n);
+ } else {
+ UninitializedFill(inlined_space() + s, inlined_space() + n);
+ tag().set_inline_size(n);
+ }
+}
+
+template <typename T, size_t N, typename A>
+void InlinedVector<T, N, A>::resize(size_type n, const value_type& elem) {
+ size_type s = size();
+ if (n < s) {
+ erase(begin() + n, end());
+ return;
+ }
+ reserve(n);
+ assert(capacity() >= n);
+
+ // Fill new space with copies of 'elem'.
+ if (allocated()) {
+ UninitializedFill(allocated_space() + s, allocated_space() + n, elem);
+ tag().set_allocated_size(n);
+ } else {
+ UninitializedFill(inlined_space() + s, inlined_space() + n, elem);
+ tag().set_inline_size(n);
+ }
+}
+
+template <typename T, size_t N, typename A>
+template <typename... Args>
+typename InlinedVector<T, N, A>::iterator InlinedVector<T, N, A>::emplace(
+ const_iterator position, Args&&... args) {
+ assert(position >= begin());
+ assert(position <= end());
+ if (position == end()) {
+ emplace_back(std::forward<Args>(args)...);
+ return end() - 1;
+ }
+ size_type s = size();
+ size_type idx = std::distance(cbegin(), position);
+ if (s == capacity()) {
+ EnlargeBy(1);
+ }
+ assert(s < capacity());
+ iterator pos = begin() + idx; // Set 'pos' to a post-enlarge iterator.
+
+ pointer space;
+ if (allocated()) {
+ tag().set_allocated_size(s + 1);
+ space = allocated_space();
+ } else {
+ tag().set_inline_size(s + 1);
+ space = inlined_space();
+ }
+ Construct(space + s, std::move(space[s - 1]));
+ std::move_backward(pos, space + s - 1, space + s);
+ Destroy(pos, pos + 1);
+ Construct(pos, std::forward<Args>(args)...);
+
+ return pos;
+}
+
+template <typename T, size_t N, typename A>
+typename InlinedVector<T, N, A>::iterator InlinedVector<T, N, A>::erase(
+ const_iterator first, const_iterator last) {
+ assert(begin() <= first);
+ assert(first <= last);
+ assert(last <= end());
+
+ iterator range_start = const_cast<iterator>(first);
+ iterator range_end = const_cast<iterator>(last);
+
+ size_type s = size();
+ ptrdiff_t erase_gap = std::distance(range_start, range_end);
+ if (erase_gap > 0) {
+ pointer space;
+ if (allocated()) {
+ space = allocated_space();
+ tag().set_allocated_size(s - erase_gap);
+ } else {
+ space = inlined_space();
+ tag().set_inline_size(s - erase_gap);
+ }
+ std::move(range_end, space + s, range_start);
+ Destroy(space + s - erase_gap, space + s);
+ }
+ return range_start;
+}
+
+template <typename T, size_t N, typename A>
+void InlinedVector<T, N, A>::swap(InlinedVector& other) {
+ using std::swap; // Augment ADL with std::swap.
+ if (&other == this) {
+ return;
+ }
+ if (allocated() && other.allocated()) {
+ // Both out of line, so just swap the tag, allocation, and allocator.
+ swap(tag(), other.tag());
+ swap(allocation(), other.allocation());
+ swap(allocator(), other.allocator());
+ return;
+ }
+ if (!allocated() && !other.allocated()) {
+ // Both inlined: swap up to smaller size, then move remaining elements.
+ InlinedVector* a = this;
+ InlinedVector* b = &other;
+ if (size() < other.size()) {
+ swap(a, b);
+ }
+
+ const size_type a_size = a->size();
+ const size_type b_size = b->size();
+ assert(a_size >= b_size);
+ // 'a' is larger. Swap the elements up to the smaller array size.
+ std::swap_ranges(a->inlined_space(),
+ a->inlined_space() + b_size,
+ b->inlined_space());
+
+ // Move the remaining elements: A[b_size,a_size) -> B[b_size,a_size)
+ b->UninitializedCopy(a->inlined_space() + b_size,
+ a->inlined_space() + a_size,
+ b->inlined_space() + b_size);
+ a->Destroy(a->inlined_space() + b_size, a->inlined_space() + a_size);
+
+ swap(a->tag(), b->tag());
+ swap(a->allocator(), b->allocator());
+ assert(b->size() == a_size);
+ assert(a->size() == b_size);
+ return;
+ }
+ // One is out of line, one is inline.
+ // We first move the elements from the inlined vector into the
+ // inlined space in the other vector. We then put the other vector's
+ // pointer/capacity into the originally inlined vector and swap
+ // the tags.
+ InlinedVector* a = this;
+ InlinedVector* b = &other;
+ if (a->allocated()) {
+ swap(a, b);
+ }
+ assert(!a->allocated());
+ assert(b->allocated());
+ const size_type a_size = a->size();
+ const size_type b_size = b->size();
+ // In an optimized build, b_size would be unused.
+ (void)b_size;
+
+ // Made Local copies of size(), don't need tag() accurate anymore
+ swap(a->tag(), b->tag());
+
+ // Copy b_allocation out before b's union gets clobbered by inline_space.
+ Allocation b_allocation = b->allocation();
+
+ b->UninitializedCopy(a->inlined_space(), a->inlined_space() + a_size,
+ b->inlined_space());
+ a->Destroy(a->inlined_space(), a->inlined_space() + a_size);
+
+ a->allocation() = b_allocation;
+
+ if (a->allocator() != b->allocator()) {
+ swap(a->allocator(), b->allocator());
+ }
+
+ assert(b->size() == a_size);
+ assert(a->size() == b_size);
+}
+
+template <typename T, size_t N, typename A>
+void InlinedVector<T, N, A>::EnlargeBy(size_type delta) {
+ const size_type s = size();
+ assert(s <= capacity());
+
+ size_type target = std::max(static_cast<size_type>(N), s + delta);
+
+ // Compute new capacity by repeatedly doubling current capacity
+ // TODO(psrc): Check and avoid overflow?
+ size_type new_capacity = capacity();
+ while (new_capacity < target) {
+ new_capacity <<= 1;
+ }
+
+ Allocation new_allocation(allocator(), new_capacity);
+
+ UninitializedCopy(std::make_move_iterator(data()),
+ std::make_move_iterator(data() + s),
+ new_allocation.buffer());
+
+ ResetAllocation(new_allocation, s);
+}
+
+template <typename T, size_t N, typename A>
+auto InlinedVector<T, N, A>::ShiftRight(const_iterator position, size_type n)
+ -> std::pair<iterator, iterator> {
+ iterator start_used = const_cast<iterator>(position);
+ iterator start_raw = const_cast<iterator>(position);
+ size_type s = size();
+ size_type required_size = s + n;
+
+ if (required_size > capacity()) {
+ // Compute new capacity by repeatedly doubling current capacity
+ size_type new_capacity = capacity();
+ while (new_capacity < required_size) {
+ new_capacity <<= 1;
+ }
+ // Move everyone into the new allocation, leaving a gap of n for the
+ // requested shift.
+ Allocation new_allocation(allocator(), new_capacity);
+ size_type index = position - begin();
+ UninitializedCopy(std::make_move_iterator(data()),
+ std::make_move_iterator(data() + index),
+ new_allocation.buffer());
+ UninitializedCopy(std::make_move_iterator(data() + index),
+ std::make_move_iterator(data() + s),
+ new_allocation.buffer() + index + n);
+ ResetAllocation(new_allocation, s);
+
+ // New allocation means our iterator is invalid, so we'll recalculate.
+ // Since the entire gap is in new space, there's no used space to reuse.
+ start_raw = begin() + index;
+ start_used = start_raw;
+ } else {
+ // If we had enough space, it's a two-part move. Elements going into
+ // previously-unoccupied space need an UninitializedCopy. Elements
+ // going into a previously-occupied space are just a move.
+ iterator pos = const_cast<iterator>(position);
+ iterator raw_space = end();
+ size_type slots_in_used_space = raw_space - pos;
+ size_type new_elements_in_used_space = std::min(n, slots_in_used_space);
+ size_type new_elements_in_raw_space = n - new_elements_in_used_space;
+ size_type old_elements_in_used_space =
+ slots_in_used_space - new_elements_in_used_space;
+
+ UninitializedCopy(std::make_move_iterator(pos + old_elements_in_used_space),
+ std::make_move_iterator(raw_space),
+ raw_space + new_elements_in_raw_space);
+ std::move_backward(pos, pos + old_elements_in_used_space, raw_space);
+
+ // If the gap is entirely in raw space, the used space starts where the raw
+ // space starts, leaving no elements in used space. If the gap is entirely
+ // in used space, the raw space starts at the end of the gap, leaving all
+ // elements accounted for within the used space.
+ start_used = pos;
+ start_raw = pos + new_elements_in_used_space;
+ }
+ return std::make_pair(start_used, start_raw);
+}
+
+template <typename T, size_t N, typename A>
+void InlinedVector<T, N, A>::Destroy(value_type* ptr, value_type* ptr_last) {
+ for (value_type* p = ptr; p != ptr_last; ++p) {
+ AllocatorTraits::destroy(allocator(), p);
+ }
+
+ // Overwrite unused memory with 0xab so we can catch uninitialized usage.
+ // Cast to void* to tell the compiler that we don't care that we might be
+ // scribbling on a vtable pointer.
+#ifndef NDEBUG
+ if (ptr != ptr_last) {
+ memset(reinterpret_cast<void*>(ptr), 0xab,
+ sizeof(*ptr) * (ptr_last - ptr));
+ }
+#endif
+}
+
+template <typename T, size_t N, typename A>
+template <typename Iter>
+void InlinedVector<T, N, A>::AppendRange(Iter first, Iter last,
+ std::forward_iterator_tag) {
+ using Length = typename std::iterator_traits<Iter>::difference_type;
+ Length length = std::distance(first, last);
+ reserve(size() + length);
+ if (allocated()) {
+ UninitializedCopy(first, last, allocated_space() + size());
+ tag().set_allocated_size(size() + length);
+ } else {
+ UninitializedCopy(first, last, inlined_space() + size());
+ tag().set_inline_size(size() + length);
+ }
+}
+
+template <typename T, size_t N, typename A>
+template <typename Iter>
+void InlinedVector<T, N, A>::AssignRange(Iter first, Iter last,
+ std::input_iterator_tag) {
+ // Optimized to avoid reallocation.
+ // Prefer reassignment to copy construction for elements.
+ iterator out = begin();
+ for ( ; first != last && out != end(); ++first, ++out)
+ *out = *first;
+ erase(out, end());
+ std::copy(first, last, std::back_inserter(*this));
+}
+
+template <typename T, size_t N, typename A>
+template <typename Iter>
+void InlinedVector<T, N, A>::AssignRange(Iter first, Iter last,
+ std::forward_iterator_tag) {
+ using Length = typename std::iterator_traits<Iter>::difference_type;
+ Length length = std::distance(first, last);
+ // Prefer reassignment to copy construction for elements.
+ if (static_cast<size_type>(length) <= size()) {
+ erase(std::copy(first, last, begin()), end());
+ return;
+ }
+ reserve(length);
+ iterator out = begin();
+ for (; out != end(); ++first, ++out) *out = *first;
+ if (allocated()) {
+ UninitializedCopy(first, last, out);
+ tag().set_allocated_size(length);
+ } else {
+ UninitializedCopy(first, last, out);
+ tag().set_inline_size(length);
+ }
+}
+
+template <typename T, size_t N, typename A>
+auto InlinedVector<T, N, A>::InsertWithCount(const_iterator position,
+ size_type n, const value_type& v)
+ -> iterator {
+ assert(position >= begin() && position <= end());
+ if (n == 0) return const_cast<iterator>(position);
+ std::pair<iterator, iterator> it_pair = ShiftRight(position, n);
+ std::fill(it_pair.first, it_pair.second, v);
+ UninitializedFill(it_pair.second, it_pair.first + n, v);
+ tag().add_size(n);
+ return it_pair.first;
+}
+
+template <typename T, size_t N, typename A>
+template <typename InputIter>
+auto InlinedVector<T, N, A>::InsertWithRange(const_iterator position,
+ InputIter first, InputIter last,
+ std::input_iterator_tag)
+ -> iterator {
+ assert(position >= begin() && position <= end());
+ size_type index = position - cbegin();
+ size_type i = index;
+ while (first != last) insert(begin() + i++, *first++);
+ return begin() + index;
+}
+
+// Overload of InlinedVector::InsertWithRange()
+template <typename T, size_t N, typename A>
+template <typename ForwardIter>
+auto InlinedVector<T, N, A>::InsertWithRange(const_iterator position,
+ ForwardIter first,
+ ForwardIter last,
+ std::forward_iterator_tag)
+ -> iterator {
+ assert(position >= begin() && position <= end());
+ if (first == last) {
+ return const_cast<iterator>(position);
+ }
+ using Length = typename std::iterator_traits<ForwardIter>::difference_type;
+ Length n = std::distance(first, last);
+ std::pair<iterator, iterator> it_pair = ShiftRight(position, n);
+ size_type used_spots = it_pair.second - it_pair.first;
+ ForwardIter open_spot = std::next(first, used_spots);
+ std::copy(first, open_spot, it_pair.first);
+ UninitializedCopy(open_spot, last, it_pair.second);
+ tag().add_size(n);
+ return it_pair.first;
+}
+
+} // namespace absl
+
+#endif // ABSL_CONTAINER_INLINED_VECTOR_H_
diff --git a/absl/container/inlined_vector_test.cc b/absl/container/inlined_vector_test.cc
new file mode 100644
index 0000000..c559a9a
--- /dev/null
+++ b/absl/container/inlined_vector_test.cc
@@ -0,0 +1,1593 @@
+// 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/container/inlined_vector.h"
+
+#include <forward_list>
+#include <list>
+#include <memory>
+#include <scoped_allocator>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+#include "absl/base/internal/exception_testing.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
+#include "absl/container/internal/test_instance_tracker.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/str_cat.h"
+
+namespace {
+
+using absl::test_internal::CopyableMovableInstance;
+using absl::test_internal::CopyableOnlyInstance;
+using absl::test_internal::InstanceTracker;
+using testing::AllOf;
+using testing::Each;
+using testing::ElementsAre;
+using testing::ElementsAreArray;
+using testing::Eq;
+using testing::Gt;
+using testing::PrintToString;
+
+using IntVec = absl::InlinedVector<int, 8>;
+
+MATCHER_P(SizeIs, n, "") {
+ return testing::ExplainMatchResult(n, arg.size(), result_listener);
+}
+
+MATCHER_P(CapacityIs, n, "") {
+ return testing::ExplainMatchResult(n, arg.capacity(), result_listener);
+}
+
+MATCHER_P(ValueIs, e, "") {
+ return testing::ExplainMatchResult(e, arg.value(), result_listener);
+}
+
+// TODO(bsamwel): Add support for movable-only types.
+
+// Test fixture for typed tests on BaseCountedInstance derived classes, see
+// test_instance_tracker.h.
+template <typename T>
+class InstanceTest : public ::testing::Test {};
+TYPED_TEST_CASE_P(InstanceTest);
+
+// A simple reference counted class to make sure that the proper elements are
+// destroyed in the erase(begin, end) test.
+class RefCounted {
+ public:
+ RefCounted(int value, int* count) : value_(value), count_(count) {
+ Ref();
+ }
+
+ RefCounted(const RefCounted& v)
+ : value_(v.value_), count_(v.count_) {
+ Ref();
+ }
+
+ ~RefCounted() {
+ Unref();
+ count_ = nullptr;
+ }
+
+ friend void swap(RefCounted& a, RefCounted& b) {
+ using std::swap;
+ swap(a.value_, b.value_);
+ swap(a.count_, b.count_);
+ }
+
+ RefCounted& operator=(RefCounted v) {
+ using std::swap;
+ swap(*this, v);
+ return *this;
+ }
+
+ void Ref() const {
+ ABSL_RAW_CHECK(count_ != nullptr, "");
+ ++(*count_);
+ }
+
+ void Unref() const {
+ --(*count_);
+ ABSL_RAW_CHECK(*count_ >= 0, "");
+ }
+
+ int value_;
+ int* count_;
+};
+
+using RefCountedVec = absl::InlinedVector<RefCounted, 8>;
+
+// A class with a vtable pointer
+class Dynamic {
+ public:
+ virtual ~Dynamic() {}
+};
+
+using DynamicVec = absl::InlinedVector<Dynamic, 8>;
+
+// Append 0..len-1 to *v
+template <typename Container>
+static void Fill(Container* v, int len, int offset = 0) {
+ for (int i = 0; i < len; i++) {
+ v->push_back(i + offset);
+ }
+}
+
+static IntVec Fill(int len, int offset = 0) {
+ IntVec v;
+ Fill(&v, len, offset);
+ return v;
+}
+
+// This is a stateful allocator, but the state lives outside of the
+// allocator (in whatever test is using the allocator). This is odd
+// but helps in tests where the allocator is propagated into nested
+// containers - that chain of allocators uses the same state and is
+// thus easier to query for aggregate allocation information.
+template <typename T>
+class CountingAllocator : public std::allocator<T> {
+ public:
+ using Alloc = std::allocator<T>;
+ using pointer = typename Alloc::pointer;
+ using size_type = typename Alloc::size_type;
+
+ CountingAllocator() : bytes_used_(nullptr) {}
+ explicit CountingAllocator(int64_t* b) : bytes_used_(b) {}
+
+ template <typename U>
+ CountingAllocator(const CountingAllocator<U>& x)
+ : Alloc(x), bytes_used_(x.bytes_used_) {}
+
+ pointer allocate(size_type n,
+ std::allocator<void>::const_pointer hint = nullptr) {
+ assert(bytes_used_ != nullptr);
+ *bytes_used_ += n * sizeof(T);
+ return Alloc::allocate(n, hint);
+ }
+
+ void deallocate(pointer p, size_type n) {
+ Alloc::deallocate(p, n);
+ assert(bytes_used_ != nullptr);
+ *bytes_used_ -= n * sizeof(T);
+ }
+
+ template<typename U>
+ class rebind {
+ public:
+ using other = CountingAllocator<U>;
+ };
+
+ friend bool operator==(const CountingAllocator& a,
+ const CountingAllocator& b) {
+ return a.bytes_used_ == b.bytes_used_;
+ }
+
+ friend bool operator!=(const CountingAllocator& a,
+ const CountingAllocator& b) {
+ return !(a == b);
+ }
+
+ int64_t* bytes_used_;
+};
+
+TEST(IntVec, SimpleOps) {
+ for (int len = 0; len < 20; len++) {
+ IntVec v;
+ const IntVec& cv = v; // const alias
+
+ Fill(&v, len);
+ EXPECT_EQ(len, v.size());
+ EXPECT_LE(len, v.capacity());
+
+ for (int i = 0; i < len; i++) {
+ EXPECT_EQ(i, v[i]);
+ EXPECT_EQ(i, v.at(i));
+ }
+ EXPECT_EQ(v.begin(), v.data());
+ EXPECT_EQ(cv.begin(), cv.data());
+
+ int counter = 0;
+ for (IntVec::iterator iter = v.begin(); iter != v.end(); ++iter) {
+ EXPECT_EQ(counter, *iter);
+ counter++;
+ }
+ EXPECT_EQ(counter, len);
+
+ counter = 0;
+ for (IntVec::const_iterator iter = v.begin(); iter != v.end(); ++iter) {
+ EXPECT_EQ(counter, *iter);
+ counter++;
+ }
+ EXPECT_EQ(counter, len);
+
+ counter = 0;
+ for (IntVec::const_iterator iter = v.cbegin(); iter != v.cend(); ++iter) {
+ EXPECT_EQ(counter, *iter);
+ counter++;
+ }
+ EXPECT_EQ(counter, len);
+
+ if (len > 0) {
+ EXPECT_EQ(0, v.front());
+ EXPECT_EQ(len - 1, v.back());
+ v.pop_back();
+ EXPECT_EQ(len - 1, v.size());
+ for (int i = 0; i < v.size(); ++i) {
+ EXPECT_EQ(i, v[i]);
+ EXPECT_EQ(i, v.at(i));
+ }
+ }
+ }
+}
+
+TEST(IntVec, AtThrows) {
+ IntVec v = {1, 2, 3};
+ EXPECT_EQ(v.at(2), 3);
+ ABSL_BASE_INTERNAL_EXPECT_FAIL(v.at(3), std::out_of_range,
+ "failed bounds check");
+}
+
+TEST(IntVec, ReverseIterator) {
+ for (int len = 0; len < 20; len++) {
+ IntVec v;
+ Fill(&v, len);
+
+ int counter = len;
+ for (IntVec::reverse_iterator iter = v.rbegin(); iter != v.rend(); ++iter) {
+ counter--;
+ EXPECT_EQ(counter, *iter);
+ }
+ EXPECT_EQ(counter, 0);
+
+ counter = len;
+ for (IntVec::const_reverse_iterator iter = v.rbegin(); iter != v.rend();
+ ++iter) {
+ counter--;
+ EXPECT_EQ(counter, *iter);
+ }
+ EXPECT_EQ(counter, 0);
+
+ counter = len;
+ for (IntVec::const_reverse_iterator iter = v.crbegin(); iter != v.crend();
+ ++iter) {
+ counter--;
+ EXPECT_EQ(counter, *iter);
+ }
+ EXPECT_EQ(counter, 0);
+ }
+}
+
+TEST(IntVec, Erase) {
+ for (int len = 1; len < 20; len++) {
+ for (int i = 0; i < len; ++i) {
+ IntVec v;
+ Fill(&v, len);
+ v.erase(v.begin() + i);
+ EXPECT_EQ(len - 1, v.size());
+ for (int j = 0; j < i; ++j) {
+ EXPECT_EQ(j, v[j]);
+ }
+ for (int j = i; j < len - 1; ++j) {
+ EXPECT_EQ(j + 1, v[j]);
+ }
+ }
+ }
+}
+
+// At the end of this test loop, the elements between [erase_begin, erase_end)
+// should have reference counts == 0, and all others elements should have
+// reference counts == 1.
+TEST(RefCountedVec, EraseBeginEnd) {
+ for (int len = 1; len < 20; ++len) {
+ for (int erase_begin = 0; erase_begin < len; ++erase_begin) {
+ for (int erase_end = erase_begin; erase_end <= len; ++erase_end) {
+ std::vector<int> counts(len, 0);
+ RefCountedVec v;
+ for (int i = 0; i < len; ++i) {
+ v.push_back(RefCounted(i, &counts[i]));
+ }
+
+ int erase_len = erase_end - erase_begin;
+
+ v.erase(v.begin() + erase_begin, v.begin() + erase_end);
+
+ EXPECT_EQ(len - erase_len, v.size());
+
+ // Check the elements before the first element erased.
+ for (int i = 0; i < erase_begin; ++i) {
+ EXPECT_EQ(i, v[i].value_);
+ }
+
+ // Check the elements after the first element erased.
+ for (int i = erase_begin; i < v.size(); ++i) {
+ EXPECT_EQ(i + erase_len, v[i].value_);
+ }
+
+ // Check that the elements at the beginning are preserved.
+ for (int i = 0; i < erase_begin; ++i) {
+ EXPECT_EQ(1, counts[i]);
+ }
+
+ // Check that the erased elements are destroyed
+ for (int i = erase_begin; i < erase_end; ++i) {
+ EXPECT_EQ(0, counts[i]);
+ }
+
+ // Check that the elements at the end are preserved.
+ for (int i = erase_end; i< len; ++i) {
+ EXPECT_EQ(1, counts[i]);
+ }
+ }
+ }
+ }
+}
+
+struct NoDefaultCtor {
+ explicit NoDefaultCtor(int) {}
+};
+struct NoCopy {
+ NoCopy() {}
+ NoCopy(const NoCopy&) = delete;
+};
+struct NoAssign {
+ NoAssign() {}
+ NoAssign& operator=(const NoAssign&) = delete;
+};
+struct MoveOnly {
+ MoveOnly() {}
+ MoveOnly(MoveOnly&&) = default;
+ MoveOnly& operator=(MoveOnly&&) = default;
+};
+TEST(InlinedVectorTest, NoDefaultCtor) {
+ absl::InlinedVector<NoDefaultCtor, 1> v(10, NoDefaultCtor(2));
+ (void)v;
+}
+TEST(InlinedVectorTest, NoCopy) {
+ absl::InlinedVector<NoCopy, 1> v(10);
+ (void)v;
+}
+TEST(InlinedVectorTest, NoAssign) {
+ absl::InlinedVector<NoAssign, 1> v(10);
+ (void)v;
+}
+TEST(InlinedVectorTest, MoveOnly) {
+ absl::InlinedVector<MoveOnly, 2> v;
+ v.push_back(MoveOnly{});
+ v.push_back(MoveOnly{});
+ v.push_back(MoveOnly{});
+ v.erase(v.begin());
+ v.push_back(MoveOnly{});
+ v.erase(v.begin(), v.begin() + 1);
+ v.insert(v.begin(), MoveOnly{});
+ v.emplace(v.begin());
+ v.emplace(v.begin(), MoveOnly{});
+}
+TEST(InlinedVectorTest, Noexcept) {
+ EXPECT_TRUE(std::is_nothrow_move_constructible<IntVec>::value);
+ EXPECT_TRUE((std::is_nothrow_move_constructible<
+ absl::InlinedVector<MoveOnly, 2>>::value));
+
+ struct MoveCanThrow {
+ MoveCanThrow(MoveCanThrow&&) {}
+ };
+ EXPECT_EQ(absl::default_allocator_is_nothrow::value,
+ (std::is_nothrow_move_constructible<
+ absl::InlinedVector<MoveCanThrow, 2>>::value));
+}
+
+
+TEST(IntVec, Insert) {
+ for (int len = 0; len < 20; len++) {
+ for (int pos = 0; pos <= len; pos++) {
+ {
+ // Single element
+ std::vector<int> std_v;
+ Fill(&std_v, len);
+ IntVec v;
+ Fill(&v, len);
+
+ std_v.insert(std_v.begin() + pos, 9999);
+ IntVec::iterator it = v.insert(v.cbegin() + pos, 9999);
+ EXPECT_THAT(v, ElementsAreArray(std_v));
+ EXPECT_EQ(it, v.cbegin() + pos);
+ }
+ {
+ // n elements
+ std::vector<int> std_v;
+ Fill(&std_v, len);
+ IntVec v;
+ Fill(&v, len);
+
+ IntVec::size_type n = 5;
+ std_v.insert(std_v.begin() + pos, n, 9999);
+ IntVec::iterator it = v.insert(v.cbegin() + pos, n, 9999);
+ EXPECT_THAT(v, ElementsAreArray(std_v));
+ EXPECT_EQ(it, v.cbegin() + pos);
+ }
+ {
+ // Iterator range (random access iterator)
+ std::vector<int> std_v;
+ Fill(&std_v, len);
+ IntVec v;
+ Fill(&v, len);
+
+ const std::vector<int> input = {9999, 8888, 7777};
+ std_v.insert(std_v.begin() + pos, input.cbegin(), input.cend());
+ IntVec::iterator it =
+ v.insert(v.cbegin() + pos, input.cbegin(), input.cend());
+ EXPECT_THAT(v, ElementsAreArray(std_v));
+ EXPECT_EQ(it, v.cbegin() + pos);
+ }
+ {
+ // Iterator range (forward iterator)
+ std::vector<int> std_v;
+ Fill(&std_v, len);
+ IntVec v;
+ Fill(&v, len);
+
+ const std::forward_list<int> input = {9999, 8888, 7777};
+ std_v.insert(std_v.begin() + pos, input.cbegin(), input.cend());
+ IntVec::iterator it =
+ v.insert(v.cbegin() + pos, input.cbegin(), input.cend());
+ EXPECT_THAT(v, ElementsAreArray(std_v));
+ EXPECT_EQ(it, v.cbegin() + pos);
+ }
+ {
+ // Iterator range (input iterator)
+ std::vector<int> std_v;
+ Fill(&std_v, len);
+ IntVec v;
+ Fill(&v, len);
+
+ std_v.insert(std_v.begin() + pos, {9999, 8888, 7777});
+ std::istringstream input("9999 8888 7777");
+ IntVec::iterator it =
+ v.insert(v.cbegin() + pos, std::istream_iterator<int>(input),
+ std::istream_iterator<int>());
+ EXPECT_THAT(v, ElementsAreArray(std_v));
+ EXPECT_EQ(it, v.cbegin() + pos);
+ }
+ {
+ // Initializer list
+ std::vector<int> std_v;
+ Fill(&std_v, len);
+ IntVec v;
+ Fill(&v, len);
+
+ std_v.insert(std_v.begin() + pos, {9999, 8888});
+ IntVec::iterator it = v.insert(v.cbegin() + pos, {9999, 8888});
+ EXPECT_THAT(v, ElementsAreArray(std_v));
+ EXPECT_EQ(it, v.cbegin() + pos);
+ }
+ }
+ }
+}
+
+TEST(RefCountedVec, InsertConstructorDestructor) {
+ // Make sure the proper construction/destruction happen during insert
+ // operations.
+ for (int len = 0; len < 20; len++) {
+ SCOPED_TRACE(len);
+ for (int pos = 0; pos <= len; pos++) {
+ SCOPED_TRACE(pos);
+ std::vector<int> counts(len, 0);
+ int inserted_count = 0;
+ RefCountedVec v;
+ for (int i = 0; i < len; ++i) {
+ SCOPED_TRACE(i);
+ v.push_back(RefCounted(i, &counts[i]));
+ }
+
+ EXPECT_THAT(counts, Each(Eq(1)));
+
+ RefCounted insert_element(9999, &inserted_count);
+ EXPECT_EQ(1, inserted_count);
+ v.insert(v.begin() + pos, insert_element);
+ EXPECT_EQ(2, inserted_count);
+ // Check that the elements at the end are preserved.
+ EXPECT_THAT(counts, Each(Eq(1)));
+ EXPECT_EQ(2, inserted_count);
+ }
+ }
+}
+
+TEST(IntVec, Resize) {
+ for (int len = 0; len < 20; len++) {
+ IntVec v;
+ Fill(&v, len);
+
+ // Try resizing up and down by k elements
+ static const int kResizeElem = 1000000;
+ for (int k = 0; k < 10; k++) {
+ // Enlarging resize
+ v.resize(len+k, kResizeElem);
+ EXPECT_EQ(len+k, v.size());
+ EXPECT_LE(len+k, v.capacity());
+ for (int i = 0; i < len+k; i++) {
+ if (i < len) {
+ EXPECT_EQ(i, v[i]);
+ } else {
+ EXPECT_EQ(kResizeElem, v[i]);
+ }
+ }
+
+ // Shrinking resize
+ v.resize(len, kResizeElem);
+ EXPECT_EQ(len, v.size());
+ EXPECT_LE(len, v.capacity());
+ for (int i = 0; i < len; i++) {
+ EXPECT_EQ(i, v[i]);
+ }
+ }
+ }
+}
+
+TEST(IntVec, InitWithLength) {
+ for (int len = 0; len < 20; len++) {
+ IntVec v(len, 7);
+ EXPECT_EQ(len, v.size());
+ EXPECT_LE(len, v.capacity());
+ for (int i = 0; i < len; i++) {
+ EXPECT_EQ(7, v[i]);
+ }
+ }
+}
+
+TEST(IntVec, CopyConstructorAndAssignment) {
+ for (int len = 0; len < 20; len++) {
+ IntVec v;
+ Fill(&v, len);
+ EXPECT_EQ(len, v.size());
+ EXPECT_LE(len, v.capacity());
+
+ IntVec v2(v);
+ EXPECT_TRUE(v == v2) << PrintToString(v) << PrintToString(v2);
+
+ for (int start_len = 0; start_len < 20; start_len++) {
+ IntVec v3;
+ Fill(&v3, start_len, 99); // Add dummy elements that should go away
+ v3 = v;
+ EXPECT_TRUE(v == v3) << PrintToString(v) << PrintToString(v3);
+ }
+ }
+}
+
+TEST(IntVec, MoveConstructorAndAssignment) {
+ for (int len = 0; len < 20; len++) {
+ IntVec v_in;
+ const int inlined_capacity = v_in.capacity();
+ Fill(&v_in, len);
+ EXPECT_EQ(len, v_in.size());
+ EXPECT_LE(len, v_in.capacity());
+
+ {
+ IntVec v_temp(v_in);
+ auto* old_data = v_temp.data();
+ IntVec v_out(std::move(v_temp));
+ EXPECT_TRUE(v_in == v_out) << PrintToString(v_in) << PrintToString(v_out);
+ if (v_in.size() > inlined_capacity) {
+ // Allocation is moved as a whole, data stays in place.
+ EXPECT_TRUE(v_out.data() == old_data);
+ } else {
+ EXPECT_FALSE(v_out.data() == old_data);
+ }
+ }
+ for (int start_len = 0; start_len < 20; start_len++) {
+ IntVec v_out;
+ Fill(&v_out, start_len, 99); // Add dummy elements that should go away
+ IntVec v_temp(v_in);
+ auto* old_data = v_temp.data();
+ v_out = std::move(v_temp);
+ EXPECT_TRUE(v_in == v_out) << PrintToString(v_in) << PrintToString(v_out);
+ if (v_in.size() > inlined_capacity) {
+ // Allocation is moved as a whole, data stays in place.
+ EXPECT_TRUE(v_out.data() == old_data);
+ } else {
+ EXPECT_FALSE(v_out.data() == old_data);
+ }
+ }
+ }
+}
+
+TEST(OverheadTest, Storage) {
+ // Check for size overhead.
+ // In particular, ensure that std::allocator doesn't cost anything to store.
+ // The union should be absorbing some of the allocation bookkeeping overhead
+ // in the larger vectors, leaving only the size_ field as overhead.
+ EXPECT_EQ(2 * sizeof(int*),
+ sizeof(absl::InlinedVector<int*, 1>) - 1 * sizeof(int*));
+ EXPECT_EQ(1 * sizeof(int*),
+ sizeof(absl::InlinedVector<int*, 2>) - 2 * sizeof(int*));
+ EXPECT_EQ(1 * sizeof(int*),
+ sizeof(absl::InlinedVector<int*, 3>) - 3 * sizeof(int*));
+ EXPECT_EQ(1 * sizeof(int*),
+ sizeof(absl::InlinedVector<int*, 4>) - 4 * sizeof(int*));
+ EXPECT_EQ(1 * sizeof(int*),
+ sizeof(absl::InlinedVector<int*, 5>) - 5 * sizeof(int*));
+ EXPECT_EQ(1 * sizeof(int*),
+ sizeof(absl::InlinedVector<int*, 6>) - 6 * sizeof(int*));
+ EXPECT_EQ(1 * sizeof(int*),
+ sizeof(absl::InlinedVector<int*, 7>) - 7 * sizeof(int*));
+ EXPECT_EQ(1 * sizeof(int*),
+ sizeof(absl::InlinedVector<int*, 8>) - 8 * sizeof(int*));
+}
+
+TEST(IntVec, Clear) {
+ for (int len = 0; len < 20; len++) {
+ SCOPED_TRACE(len);
+ IntVec v;
+ Fill(&v, len);
+ v.clear();
+ EXPECT_EQ(0, v.size());
+ EXPECT_EQ(v.begin(), v.end());
+ }
+}
+
+TEST(IntVec, Reserve) {
+ for (int len = 0; len < 20; len++) {
+ IntVec v;
+ Fill(&v, len);
+
+ for (int newlen = 0; newlen < 100; newlen++) {
+ const int* start_rep = v.data();
+ v.reserve(newlen);
+ const int* final_rep = v.data();
+ if (newlen <= len) {
+ EXPECT_EQ(start_rep, final_rep);
+ }
+ EXPECT_LE(newlen, v.capacity());
+
+ // Filling up to newlen should not change rep
+ while (v.size() < newlen) {
+ v.push_back(0);
+ }
+ EXPECT_EQ(final_rep, v.data());
+ }
+ }
+}
+
+TEST(StringVec, SelfRefPushBack) {
+ std::vector<std::string> std_v;
+ absl::InlinedVector<std::string, 4> v;
+ const std::string s = "A quite long std::string to ensure heap.";
+ std_v.push_back(s);
+ v.push_back(s);
+ for (int i = 0; i < 20; ++i) {
+ EXPECT_THAT(v, ElementsAreArray(std_v));
+
+ v.push_back(v.back());
+ std_v.push_back(std_v.back());
+ }
+ EXPECT_THAT(v, ElementsAreArray(std_v));
+}
+
+TEST(StringVec, SelfRefPushBackWithMove) {
+ std::vector<std::string> std_v;
+ absl::InlinedVector<std::string, 4> v;
+ const std::string s = "A quite long std::string to ensure heap.";
+ std_v.push_back(s);
+ v.push_back(s);
+ for (int i = 0; i < 20; ++i) {
+ EXPECT_EQ(v.back(), std_v.back());
+
+ v.push_back(std::move(v.back()));
+ std_v.push_back(std::move(std_v.back()));
+ }
+ EXPECT_EQ(v.back(), std_v.back());
+}
+
+TEST(StringVec, SelfMove) {
+ const std::string s = "A quite long std::string to ensure heap.";
+ for (int len = 0; len < 20; len++) {
+ SCOPED_TRACE(len);
+ absl::InlinedVector<std::string, 8> v;
+ for (int i = 0; i < len; ++i) {
+ SCOPED_TRACE(i);
+ v.push_back(s);
+ }
+ // Indirection necessary to avoid compiler warning.
+ v = std::move(*(&v));
+ // Ensure that the inlined vector is still in a valid state by copying it.
+ // We don't expect specific contents since a self-move results in an
+ // unspecified valid state.
+ std::vector<std::string> copy(v.begin(), v.end());
+ }
+}
+
+TEST(IntVec, Swap) {
+ for (int l1 = 0; l1 < 20; l1++) {
+ SCOPED_TRACE(l1);
+ for (int l2 = 0; l2 < 20; l2++) {
+ SCOPED_TRACE(l2);
+ IntVec a = Fill(l1, 0);
+ IntVec b = Fill(l2, 100);
+ {
+ using std::swap;
+ swap(a, b);
+ }
+ EXPECT_EQ(l1, b.size());
+ EXPECT_EQ(l2, a.size());
+ for (int i = 0; i < l1; i++) {
+ SCOPED_TRACE(i);
+ EXPECT_EQ(i, b[i]);
+ }
+ for (int i = 0; i < l2; i++) {
+ SCOPED_TRACE(i);
+ EXPECT_EQ(100 + i, a[i]);
+ }
+ }
+ }
+}
+
+TYPED_TEST_P(InstanceTest, Swap) {
+ using Instance = TypeParam;
+ using InstanceVec = absl::InlinedVector<Instance, 8>;
+ for (int l1 = 0; l1 < 20; l1++) {
+ SCOPED_TRACE(l1);
+ for (int l2 = 0; l2 < 20; l2++) {
+ SCOPED_TRACE(l2);
+ InstanceTracker tracker;
+ InstanceVec a, b;
+ const size_t inlined_capacity = a.capacity();
+ for (int i = 0; i < l1; i++) a.push_back(Instance(i));
+ for (int i = 0; i < l2; i++) b.push_back(Instance(100+i));
+ EXPECT_EQ(tracker.instances(), l1 + l2);
+ tracker.ResetCopiesMovesSwaps();
+ {
+ using std::swap;
+ swap(a, b);
+ }
+ EXPECT_EQ(tracker.instances(), l1 + l2);
+ if (a.size() > inlined_capacity && b.size() > inlined_capacity) {
+ EXPECT_EQ(tracker.swaps(), 0); // Allocations are swapped.
+ EXPECT_EQ(tracker.moves(), 0);
+ } else if (a.size() <= inlined_capacity && b.size() <= inlined_capacity) {
+ EXPECT_EQ(tracker.swaps(), std::min(l1, l2));
+ // TODO(bsamwel): This should use moves when the type is movable.
+ EXPECT_EQ(tracker.copies(), std::max(l1, l2) - std::min(l1, l2));
+ } else {
+ // One is allocated and the other isn't. The allocation is transferred
+ // without copying elements, and the inlined instances are copied/moved.
+ EXPECT_EQ(tracker.swaps(), 0);
+ // TODO(bsamwel): This should use moves when the type is movable.
+ EXPECT_EQ(tracker.copies(), std::min(l1, l2));
+ }
+
+ EXPECT_EQ(l1, b.size());
+ EXPECT_EQ(l2, a.size());
+ for (int i = 0; i < l1; i++) {
+ EXPECT_EQ(i, b[i].value());
+ }
+ for (int i = 0; i < l2; i++) {
+ EXPECT_EQ(100 + i, a[i].value());
+ }
+ }
+ }
+}
+
+TEST(IntVec, EqualAndNotEqual) {
+ IntVec a, b;
+ EXPECT_TRUE(a == b);
+ EXPECT_FALSE(a != b);
+
+ a.push_back(3);
+ EXPECT_FALSE(a == b);
+ EXPECT_TRUE(a != b);
+
+ b.push_back(3);
+ EXPECT_TRUE(a == b);
+ EXPECT_FALSE(a != b);
+
+ b.push_back(7);
+ EXPECT_FALSE(a == b);
+ EXPECT_TRUE(a != b);
+
+ a.push_back(6);
+ EXPECT_FALSE(a == b);
+ EXPECT_TRUE(a != b);
+
+ a.clear();
+ b.clear();
+ for (int i = 0; i < 100; i++) {
+ a.push_back(i);
+ b.push_back(i);
+ EXPECT_TRUE(a == b);
+ EXPECT_FALSE(a != b);
+
+ b[i] = b[i] + 1;
+ EXPECT_FALSE(a == b);
+ EXPECT_TRUE(a != b);
+
+ b[i] = b[i] - 1; // Back to before
+ EXPECT_TRUE(a == b);
+ EXPECT_FALSE(a != b);
+ }
+}
+
+TEST(IntVec, RelationalOps) {
+ IntVec a, b;
+ EXPECT_FALSE(a < b);
+ EXPECT_FALSE(b < a);
+ EXPECT_FALSE(a > b);
+ EXPECT_FALSE(b > a);
+ EXPECT_TRUE(a <= b);
+ EXPECT_TRUE(b <= a);
+ EXPECT_TRUE(a >= b);
+ EXPECT_TRUE(b >= a);
+ b.push_back(3);
+ EXPECT_TRUE(a < b);
+ EXPECT_FALSE(b < a);
+ EXPECT_FALSE(a > b);
+ EXPECT_TRUE(b > a);
+ EXPECT_TRUE(a <= b);
+ EXPECT_FALSE(b <= a);
+ EXPECT_FALSE(a >= b);
+ EXPECT_TRUE(b >= a);
+}
+
+TYPED_TEST_P(InstanceTest, CountConstructorsDestructors) {
+ using Instance = TypeParam;
+ using InstanceVec = absl::InlinedVector<Instance, 8>;
+ InstanceTracker tracker;
+ for (int len = 0; len < 20; len++) {
+ SCOPED_TRACE(len);
+ tracker.ResetCopiesMovesSwaps();
+
+ InstanceVec v;
+ const size_t inlined_capacity = v.capacity();
+ for (int i = 0; i < len; i++) {
+ v.push_back(Instance(i));
+ }
+ EXPECT_EQ(tracker.instances(), len);
+ EXPECT_GE(tracker.copies() + tracker.moves(),
+ len); // More due to reallocation.
+ tracker.ResetCopiesMovesSwaps();
+
+ // Enlarging resize() must construct some objects
+ tracker.ResetCopiesMovesSwaps();
+ v.resize(len + 10, Instance(100));
+ EXPECT_EQ(tracker.instances(), len + 10);
+ if (len <= inlined_capacity && len + 10 > inlined_capacity) {
+ EXPECT_EQ(tracker.copies() + tracker.moves(), 10 + len);
+ } else {
+ // Only specify a minimum number of copies + moves. We don't want to
+ // depend on the reallocation policy here.
+ EXPECT_GE(tracker.copies() + tracker.moves(),
+ 10); // More due to reallocation.
+ }
+
+ // Shrinking resize() must destroy some objects
+ tracker.ResetCopiesMovesSwaps();
+ v.resize(len, Instance(100));
+ EXPECT_EQ(tracker.instances(), len);
+ EXPECT_EQ(tracker.copies(), 0);
+ EXPECT_EQ(tracker.moves(), 0);
+
+ // reserve() must not increase the number of initialized objects
+ SCOPED_TRACE("reserve");
+ v.reserve(len+1000);
+ EXPECT_EQ(tracker.instances(), len);
+ EXPECT_EQ(tracker.copies() + tracker.moves(), len);
+
+ // pop_back() and erase() must destroy one object
+ if (len > 0) {
+ tracker.ResetCopiesMovesSwaps();
+ v.pop_back();
+ EXPECT_EQ(tracker.instances(), len - 1);
+ EXPECT_EQ(tracker.copies(), 0);
+ EXPECT_EQ(tracker.moves(), 0);
+
+ if (!v.empty()) {
+ tracker.ResetCopiesMovesSwaps();
+ v.erase(v.begin());
+ EXPECT_EQ(tracker.instances(), len - 2);
+ EXPECT_EQ(tracker.copies() + tracker.moves(), len - 2);
+ }
+ }
+
+ tracker.ResetCopiesMovesSwaps();
+ int instances_before_empty_erase = tracker.instances();
+ v.erase(v.begin(), v.begin());
+ EXPECT_EQ(tracker.instances(), instances_before_empty_erase);
+ EXPECT_EQ(tracker.copies() + tracker.moves(), 0);
+ }
+}
+
+TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnCopyConstruction) {
+ using Instance = TypeParam;
+ using InstanceVec = absl::InlinedVector<Instance, 8>;
+ InstanceTracker tracker;
+ for (int len = 0; len < 20; len++) {
+ SCOPED_TRACE(len);
+ tracker.ResetCopiesMovesSwaps();
+
+ InstanceVec v;
+ for (int i = 0; i < len; i++) {
+ v.push_back(Instance(i));
+ }
+ EXPECT_EQ(tracker.instances(), len);
+ EXPECT_GE(tracker.copies() + tracker.moves(),
+ len); // More due to reallocation.
+ tracker.ResetCopiesMovesSwaps();
+ { // Copy constructor should create 'len' more instances.
+ InstanceVec v_copy(v);
+ EXPECT_EQ(tracker.instances(), len + len);
+ EXPECT_EQ(tracker.copies(), len);
+ EXPECT_EQ(tracker.moves(), 0);
+ }
+ EXPECT_EQ(tracker.instances(), len);
+ }
+}
+
+TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnMoveConstruction) {
+ using Instance = TypeParam;
+ using InstanceVec = absl::InlinedVector<Instance, 8>;
+ InstanceTracker tracker;
+ for (int len = 0; len < 20; len++) {
+ SCOPED_TRACE(len);
+ tracker.ResetCopiesMovesSwaps();
+
+ InstanceVec v;
+ const size_t inlined_capacity = v.capacity();
+ for (int i = 0; i < len; i++) {
+ v.push_back(Instance(i));
+ }
+ EXPECT_EQ(tracker.instances(), len);
+ EXPECT_GE(tracker.copies() + tracker.moves(),
+ len); // More due to reallocation.
+ tracker.ResetCopiesMovesSwaps();
+ {
+ InstanceVec v_copy(std::move(v));
+ if (len > inlined_capacity) {
+ // Allocation is moved as a whole.
+ EXPECT_EQ(tracker.instances(), len);
+ EXPECT_EQ(tracker.live_instances(), len);
+ // Tests an implementation detail, don't rely on this in your code.
+ EXPECT_EQ(v.size(), 0); // NOLINT misc-use-after-move
+ EXPECT_EQ(tracker.copies(), 0);
+ EXPECT_EQ(tracker.moves(), 0);
+ } else {
+ EXPECT_EQ(tracker.instances(), len + len);
+ if (Instance::supports_move()) {
+ EXPECT_EQ(tracker.live_instances(), len);
+ EXPECT_EQ(tracker.copies(), 0);
+ EXPECT_EQ(tracker.moves(), len);
+ } else {
+ EXPECT_EQ(tracker.live_instances(), len + len);
+ EXPECT_EQ(tracker.copies(), len);
+ EXPECT_EQ(tracker.moves(), 0);
+ }
+ }
+ EXPECT_EQ(tracker.swaps(), 0);
+ }
+ }
+}
+
+TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnAssignment) {
+ using Instance = TypeParam;
+ using InstanceVec = absl::InlinedVector<Instance, 8>;
+ InstanceTracker tracker;
+ for (int len = 0; len < 20; len++) {
+ SCOPED_TRACE(len);
+ for (int longorshort = 0; longorshort <= 1; ++longorshort) {
+ SCOPED_TRACE(longorshort);
+ tracker.ResetCopiesMovesSwaps();
+
+ InstanceVec longer, shorter;
+ for (int i = 0; i < len; i++) {
+ longer.push_back(Instance(i));
+ shorter.push_back(Instance(i));
+ }
+ longer.push_back(Instance(len));
+ EXPECT_EQ(tracker.instances(), len + len + 1);
+ EXPECT_GE(tracker.copies() + tracker.moves(),
+ len + len + 1); // More due to reallocation.
+
+ tracker.ResetCopiesMovesSwaps();
+ if (longorshort) {
+ shorter = longer;
+ EXPECT_EQ(tracker.instances(), (len + 1) + (len + 1));
+ EXPECT_GE(tracker.copies() + tracker.moves(),
+ len + 1); // More due to reallocation.
+ } else {
+ longer = shorter;
+ EXPECT_EQ(tracker.instances(), len + len);
+ EXPECT_EQ(tracker.copies() + tracker.moves(), len);
+ }
+ }
+ }
+}
+
+TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnMoveAssignment) {
+ using Instance = TypeParam;
+ using InstanceVec = absl::InlinedVector<Instance, 8>;
+ InstanceTracker tracker;
+ for (int len = 0; len < 20; len++) {
+ SCOPED_TRACE(len);
+ for (int longorshort = 0; longorshort <= 1; ++longorshort) {
+ SCOPED_TRACE(longorshort);
+ tracker.ResetCopiesMovesSwaps();
+
+ InstanceVec longer, shorter;
+ const int inlined_capacity = longer.capacity();
+ for (int i = 0; i < len; i++) {
+ longer.push_back(Instance(i));
+ shorter.push_back(Instance(i));
+ }
+ longer.push_back(Instance(len));
+ EXPECT_EQ(tracker.instances(), len + len + 1);
+ EXPECT_GE(tracker.copies() + tracker.moves(),
+ len + len + 1); // More due to reallocation.
+
+ tracker.ResetCopiesMovesSwaps();
+ int src_len;
+ if (longorshort) {
+ src_len = len + 1;
+ shorter = std::move(longer);
+ } else {
+ src_len = len;
+ longer = std::move(shorter);
+ }
+ if (src_len > inlined_capacity) {
+ // Allocation moved as a whole.
+ EXPECT_EQ(tracker.instances(), src_len);
+ EXPECT_EQ(tracker.live_instances(), src_len);
+ EXPECT_EQ(tracker.copies(), 0);
+ EXPECT_EQ(tracker.moves(), 0);
+ } else {
+ // Elements are all copied.
+ EXPECT_EQ(tracker.instances(), src_len + src_len);
+ if (Instance::supports_move()) {
+ EXPECT_EQ(tracker.copies(), 0);
+ EXPECT_EQ(tracker.moves(), src_len);
+ EXPECT_EQ(tracker.live_instances(), src_len);
+ } else {
+ EXPECT_EQ(tracker.copies(), src_len);
+ EXPECT_EQ(tracker.moves(), 0);
+ EXPECT_EQ(tracker.live_instances(), src_len + src_len);
+ }
+ }
+ EXPECT_EQ(tracker.swaps(), 0);
+ }
+ }
+}
+
+TEST(CountElemAssign, SimpleTypeWithInlineBacking) {
+ for (size_t original_size = 0; original_size <= 5; ++original_size) {
+ SCOPED_TRACE(original_size);
+ // Original contents are [12345, 12345, ...]
+ std::vector<int> original_contents(original_size, 12345);
+
+ absl::InlinedVector<int, 2> v(original_contents.begin(),
+ original_contents.end());
+ v.assign(2, 123);
+ EXPECT_THAT(v, AllOf(SizeIs(2), ElementsAre(123, 123)));
+ if (original_size <= 2) {
+ // If the original had inline backing, it should stay inline.
+ EXPECT_EQ(2, v.capacity());
+ }
+ }
+}
+
+TEST(CountElemAssign, SimpleTypeWithAllocation) {
+ for (size_t original_size = 0; original_size <= 5; ++original_size) {
+ SCOPED_TRACE(original_size);
+ // Original contents are [12345, 12345, ...]
+ std::vector<int> original_contents(original_size, 12345);
+
+ absl::InlinedVector<int, 2> v(original_contents.begin(),
+ original_contents.end());
+ v.assign(3, 123);
+ EXPECT_THAT(v, AllOf(SizeIs(3), ElementsAre(123, 123, 123)));
+ EXPECT_LE(v.size(), v.capacity());
+ }
+}
+
+TYPED_TEST_P(InstanceTest, CountElemAssignInlineBacking) {
+ using Instance = TypeParam;
+ for (size_t original_size = 0; original_size <= 5; ++original_size) {
+ SCOPED_TRACE(original_size);
+ // Original contents are [12345, 12345, ...]
+ std::vector<Instance> original_contents(original_size, Instance(12345));
+
+ absl::InlinedVector<Instance, 2> v(original_contents.begin(),
+ original_contents.end());
+ v.assign(2, Instance(123));
+ EXPECT_THAT(v, AllOf(SizeIs(2), ElementsAre(ValueIs(123), ValueIs(123))));
+ if (original_size <= 2) {
+ // If the original had inline backing, it should stay inline.
+ EXPECT_EQ(2, v.capacity());
+ }
+ }
+}
+
+template <typename Instance>
+void InstanceCountElemAssignWithAllocationTest() {
+ for (size_t original_size = 0; original_size <= 5; ++original_size) {
+ SCOPED_TRACE(original_size);
+ // Original contents are [12345, 12345, ...]
+ std::vector<Instance> original_contents(original_size, Instance(12345));
+
+ absl::InlinedVector<Instance, 2> v(original_contents.begin(),
+ original_contents.end());
+ v.assign(3, Instance(123));
+ EXPECT_THAT(v,
+ AllOf(SizeIs(3),
+ ElementsAre(ValueIs(123), ValueIs(123), ValueIs(123))));
+ EXPECT_LE(v.size(), v.capacity());
+ }
+}
+TEST(CountElemAssign, WithAllocationCopyableInstance) {
+ InstanceCountElemAssignWithAllocationTest<CopyableOnlyInstance>();
+}
+TEST(CountElemAssign, WithAllocationCopyableMovableInstance) {
+ InstanceCountElemAssignWithAllocationTest<CopyableMovableInstance>();
+}
+
+TEST(RangedConstructor, SimpleType) {
+ std::vector<int> source_v = {4, 5, 6};
+ // First try to fit in inline backing
+ absl::InlinedVector<int, 4> v(source_v.begin(), source_v.end());
+ EXPECT_EQ(3, v.size());
+ EXPECT_EQ(4, v.capacity()); // Indication that we're still on inlined storage
+ EXPECT_EQ(4, v[0]);
+ EXPECT_EQ(5, v[1]);
+ EXPECT_EQ(6, v[2]);
+
+ // Now, force a re-allocate
+ absl::InlinedVector<int, 2> realloc_v(source_v.begin(), source_v.end());
+ EXPECT_EQ(3, realloc_v.size());
+ EXPECT_LT(2, realloc_v.capacity());
+ EXPECT_EQ(4, realloc_v[0]);
+ EXPECT_EQ(5, realloc_v[1]);
+ EXPECT_EQ(6, realloc_v[2]);
+}
+
+// Test for ranged constructors using Instance as the element type and
+// SourceContainer as the source container type.
+template <typename Instance, typename SourceContainer, int inlined_capacity>
+void InstanceRangedConstructorTestForContainer() {
+ InstanceTracker tracker;
+ SourceContainer source_v = {Instance(0), Instance(1)};
+ tracker.ResetCopiesMovesSwaps();
+ absl::InlinedVector<Instance, inlined_capacity> v(source_v.begin(),
+ source_v.end());
+ EXPECT_EQ(2, v.size());
+ EXPECT_LT(1, v.capacity());
+ EXPECT_EQ(0, v[0].value());
+ EXPECT_EQ(1, v[1].value());
+ EXPECT_EQ(tracker.copies(), 2);
+ EXPECT_EQ(tracker.moves(), 0);
+}
+
+template <typename Instance, int inlined_capacity>
+void InstanceRangedConstructorTestWithCapacity() {
+ // Test with const and non-const, random access and non-random-access sources.
+ // TODO(bsamwel): Test with an input iterator source.
+ {
+ SCOPED_TRACE("std::list");
+ InstanceRangedConstructorTestForContainer<Instance, std::list<Instance>,
+ inlined_capacity>();
+ {
+ SCOPED_TRACE("const std::list");
+ InstanceRangedConstructorTestForContainer<
+ Instance, const std::list<Instance>, inlined_capacity>();
+ }
+ {
+ SCOPED_TRACE("std::vector");
+ InstanceRangedConstructorTestForContainer<Instance, std::vector<Instance>,
+ inlined_capacity>();
+ }
+ {
+ SCOPED_TRACE("const std::vector");
+ InstanceRangedConstructorTestForContainer<
+ Instance, const std::vector<Instance>, inlined_capacity>();
+ }
+ }
+}
+
+TYPED_TEST_P(InstanceTest, RangedConstructor) {
+ using Instance = TypeParam;
+ SCOPED_TRACE("capacity=1");
+ InstanceRangedConstructorTestWithCapacity<Instance, 1>();
+ SCOPED_TRACE("capacity=2");
+ InstanceRangedConstructorTestWithCapacity<Instance, 2>();
+}
+
+TEST(RangedConstructor, ElementsAreConstructed) {
+ std::vector<std::string> source_v = {"cat", "dog"};
+
+ // Force expansion and re-allocation of v. Ensures that when the vector is
+ // expanded that new elements are constructed.
+ absl::InlinedVector<std::string, 1> v(source_v.begin(), source_v.end());
+ EXPECT_EQ("cat", v[0]);
+ EXPECT_EQ("dog", v[1]);
+}
+
+TEST(RangedAssign, SimpleType) {
+ // Test for all combinations of original sizes (empty and non-empty inline,
+ // and out of line) and target sizes.
+ for (size_t original_size = 0; original_size <= 5; ++original_size) {
+ SCOPED_TRACE(original_size);
+ // Original contents are [12345, 12345, ...]
+ std::vector<int> original_contents(original_size, 12345);
+
+ for (size_t target_size = 0; target_size <= 5; ++target_size) {
+ SCOPED_TRACE(target_size);
+
+ // New contents are [3, 4, ...]
+ std::vector<int> new_contents;
+ for (size_t i = 0; i < target_size; ++i) {
+ new_contents.push_back(i + 3);
+ }
+
+ absl::InlinedVector<int, 3> v(original_contents.begin(),
+ original_contents.end());
+ v.assign(new_contents.begin(), new_contents.end());
+
+ EXPECT_EQ(new_contents.size(), v.size());
+ EXPECT_LE(new_contents.size(), v.capacity());
+ if (target_size <= 3 && original_size <= 3) {
+ // Storage should stay inline when target size is small.
+ EXPECT_EQ(3, v.capacity());
+ }
+ EXPECT_THAT(v, ElementsAreArray(new_contents));
+ }
+ }
+}
+
+// Returns true if lhs and rhs have the same value.
+template <typename Instance>
+static bool InstanceValuesEqual(const Instance& lhs, const Instance& rhs) {
+ return lhs.value() == rhs.value();
+}
+
+// Test for ranged assign() using Instance as the element type and
+// SourceContainer as the source container type.
+template <typename Instance, typename SourceContainer>
+void InstanceRangedAssignTestForContainer() {
+ // Test for all combinations of original sizes (empty and non-empty inline,
+ // and out of line) and target sizes.
+ for (size_t original_size = 0; original_size <= 5; ++original_size) {
+ SCOPED_TRACE(original_size);
+ // Original contents are [12345, 12345, ...]
+ std::vector<Instance> original_contents(original_size, Instance(12345));
+
+ for (size_t target_size = 0; target_size <= 5; ++target_size) {
+ SCOPED_TRACE(target_size);
+
+ // New contents are [3, 4, ...]
+ // Generate data using a non-const container, because SourceContainer
+ // itself may be const.
+ // TODO(bsamwel): Test with an input iterator.
+ std::vector<Instance> new_contents_in;
+ for (size_t i = 0; i < target_size; ++i) {
+ new_contents_in.push_back(Instance(i + 3));
+ }
+ SourceContainer new_contents(new_contents_in.begin(),
+ new_contents_in.end());
+
+ absl::InlinedVector<Instance, 3> v(original_contents.begin(),
+ original_contents.end());
+ v.assign(new_contents.begin(), new_contents.end());
+
+ EXPECT_EQ(new_contents.size(), v.size());
+ EXPECT_LE(new_contents.size(), v.capacity());
+ if (target_size <= 3 && original_size <= 3) {
+ // Storage should stay inline when target size is small.
+ EXPECT_EQ(3, v.capacity());
+ }
+ EXPECT_TRUE(std::equal(v.begin(), v.end(), new_contents.begin(),
+ InstanceValuesEqual<Instance>));
+ }
+ }
+}
+
+TYPED_TEST_P(InstanceTest, RangedAssign) {
+ using Instance = TypeParam;
+ // Test with const and non-const, random access and non-random-access sources.
+ // TODO(bsamwel): Test with an input iterator source.
+ SCOPED_TRACE("std::list");
+ InstanceRangedAssignTestForContainer<Instance, std::list<Instance>>();
+ SCOPED_TRACE("const std::list");
+ InstanceRangedAssignTestForContainer<Instance, const std::list<Instance>>();
+ SCOPED_TRACE("std::vector");
+ InstanceRangedAssignTestForContainer<Instance, std::vector<Instance>>();
+ SCOPED_TRACE("const std::vector");
+ InstanceRangedAssignTestForContainer<Instance, const std::vector<Instance>>();
+}
+
+TEST(InitializerListConstructor, SimpleTypeWithInlineBacking) {
+ EXPECT_THAT((absl::InlinedVector<int, 4>{4, 5, 6}),
+ AllOf(SizeIs(3), CapacityIs(4), ElementsAre(4, 5, 6)));
+}
+
+TEST(InitializerListConstructor, SimpleTypeWithReallocationRequired) {
+ EXPECT_THAT((absl::InlinedVector<int, 2>{4, 5, 6}),
+ AllOf(SizeIs(3), CapacityIs(Gt(2)), ElementsAre(4, 5, 6)));
+}
+
+TEST(InitializerListConstructor, DisparateTypesInList) {
+ EXPECT_THAT((absl::InlinedVector<int, 2>{-7, 8ULL}), ElementsAre(-7, 8));
+
+ EXPECT_THAT((absl::InlinedVector<std::string, 2>{"foo", std::string("bar")}),
+ ElementsAre("foo", "bar"));
+}
+
+TEST(InitializerListConstructor, ComplexTypeWithInlineBacking) {
+ EXPECT_THAT((absl::InlinedVector<CopyableMovableInstance, 1>{
+ CopyableMovableInstance(0)}),
+ AllOf(SizeIs(1), CapacityIs(1), ElementsAre(ValueIs(0))));
+}
+
+TEST(InitializerListConstructor, ComplexTypeWithReallocationRequired) {
+ EXPECT_THAT(
+ (absl::InlinedVector<CopyableMovableInstance, 1>{
+ CopyableMovableInstance(0), CopyableMovableInstance(1)}),
+ AllOf(SizeIs(2), CapacityIs(Gt(1)), ElementsAre(ValueIs(0), ValueIs(1))));
+}
+
+TEST(InitializerListAssign, SimpleTypeFitsInlineBacking) {
+ for (size_t original_size = 0; original_size <= 4; ++original_size) {
+ SCOPED_TRACE(original_size);
+
+ absl::InlinedVector<int, 2> v1(original_size, 12345);
+ const size_t original_capacity_v1 = v1.capacity();
+ v1.assign({3});
+ EXPECT_THAT(
+ v1, AllOf(SizeIs(1), CapacityIs(original_capacity_v1), ElementsAre(3)));
+
+ absl::InlinedVector<int, 2> v2(original_size, 12345);
+ const size_t original_capacity_v2 = v2.capacity();
+ v2 = {3};
+ EXPECT_THAT(
+ v2, AllOf(SizeIs(1), CapacityIs(original_capacity_v2), ElementsAre(3)));
+ }
+}
+
+TEST(InitializerListAssign, SimpleTypeDoesNotFitInlineBacking) {
+ for (size_t original_size = 0; original_size <= 4; ++original_size) {
+ SCOPED_TRACE(original_size);
+ absl::InlinedVector<int, 2> v1(original_size, 12345);
+ v1.assign({3, 4, 5});
+ EXPECT_THAT(v1, AllOf(SizeIs(3), ElementsAre(3, 4, 5)));
+ EXPECT_LE(3, v1.capacity());
+
+ absl::InlinedVector<int, 2> v2(original_size, 12345);
+ v2 = {3, 4, 5};
+ EXPECT_THAT(v2, AllOf(SizeIs(3), ElementsAre(3, 4, 5)));
+ EXPECT_LE(3, v2.capacity());
+ }
+}
+
+TEST(InitializerListAssign, DisparateTypesInList) {
+ absl::InlinedVector<int, 2> v_int1;
+ v_int1.assign({-7, 8ULL});
+ EXPECT_THAT(v_int1, ElementsAre(-7, 8));
+
+ absl::InlinedVector<int, 2> v_int2;
+ v_int2 = {-7, 8ULL};
+ EXPECT_THAT(v_int2, ElementsAre(-7, 8));
+
+ absl::InlinedVector<std::string, 2> v_string1;
+ v_string1.assign({"foo", std::string("bar")});
+ EXPECT_THAT(v_string1, ElementsAre("foo", "bar"));
+
+ absl::InlinedVector<std::string, 2> v_string2;
+ v_string2 = {"foo", std::string("bar")};
+ EXPECT_THAT(v_string2, ElementsAre("foo", "bar"));
+}
+
+TYPED_TEST_P(InstanceTest, InitializerListAssign) {
+ using Instance = TypeParam;
+ for (size_t original_size = 0; original_size <= 4; ++original_size) {
+ SCOPED_TRACE(original_size);
+ absl::InlinedVector<Instance, 2> v(original_size, Instance(12345));
+ const size_t original_capacity = v.capacity();
+ v.assign({Instance(3)});
+ EXPECT_THAT(v, AllOf(SizeIs(1), CapacityIs(original_capacity),
+ ElementsAre(ValueIs(3))));
+ }
+ for (size_t original_size = 0; original_size <= 4; ++original_size) {
+ SCOPED_TRACE(original_size);
+ absl::InlinedVector<Instance, 2> v(original_size, Instance(12345));
+ v.assign({Instance(3), Instance(4), Instance(5)});
+ EXPECT_THAT(v, AllOf(SizeIs(3),
+ ElementsAre(ValueIs(3), ValueIs(4), ValueIs(5))));
+ EXPECT_LE(3, v.capacity());
+ }
+}
+
+REGISTER_TYPED_TEST_CASE_P(InstanceTest, Swap, CountConstructorsDestructors,
+ CountConstructorsDestructorsOnCopyConstruction,
+ CountConstructorsDestructorsOnMoveConstruction,
+ CountConstructorsDestructorsOnAssignment,
+ CountConstructorsDestructorsOnMoveAssignment,
+ CountElemAssignInlineBacking, RangedConstructor,
+ RangedAssign, InitializerListAssign);
+
+using InstanceTypes =
+ ::testing::Types<CopyableOnlyInstance, CopyableMovableInstance>;
+INSTANTIATE_TYPED_TEST_CASE_P(InstanceTestOnTypes, InstanceTest, InstanceTypes);
+
+TEST(DynamicVec, DynamicVecCompiles) {
+ DynamicVec v;
+ (void)v;
+}
+
+TEST(AllocatorSupportTest, Constructors) {
+ using MyAlloc = CountingAllocator<int>;
+ using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
+ const int ia[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+ int64_t allocated = 0;
+ MyAlloc alloc(&allocated);
+ { AllocVec ABSL_ATTRIBUTE_UNUSED v; }
+ { AllocVec ABSL_ATTRIBUTE_UNUSED v(alloc); }
+ { AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + ABSL_ARRAYSIZE(ia), alloc); }
+ { AllocVec ABSL_ATTRIBUTE_UNUSED v({1, 2, 3}, alloc); }
+
+ AllocVec v2;
+ { AllocVec ABSL_ATTRIBUTE_UNUSED v(v2, alloc); }
+ { AllocVec ABSL_ATTRIBUTE_UNUSED v(std::move(v2), alloc); }
+}
+
+TEST(AllocatorSupportTest, CountAllocations) {
+ using MyAlloc = CountingAllocator<int>;
+ using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
+ const int ia[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+ int64_t allocated = 0;
+ MyAlloc alloc(&allocated);
+ {
+ AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + 4, alloc);
+ EXPECT_THAT(allocated, 0);
+ }
+ EXPECT_THAT(allocated, 0);
+ {
+ AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + ABSL_ARRAYSIZE(ia), alloc);
+ EXPECT_THAT(allocated, v.size() * sizeof(int));
+ }
+ EXPECT_THAT(allocated, 0);
+ {
+ AllocVec v(4, 1, alloc);
+ EXPECT_THAT(allocated, 0);
+
+ int64_t allocated2 = 0;
+ MyAlloc alloc2(&allocated2);
+ AllocVec v2(v, alloc2);
+ EXPECT_THAT(allocated2, 0);
+
+ int64_t allocated3 = 0;
+ MyAlloc alloc3(&allocated3);
+ AllocVec v3(std::move(v), alloc3);
+ EXPECT_THAT(allocated3, 0);
+ }
+ EXPECT_THAT(allocated, 0);
+ {
+ AllocVec v(8, 2, alloc);
+ EXPECT_THAT(allocated, v.size() * sizeof(int));
+
+ int64_t allocated2 = 0;
+ MyAlloc alloc2(&allocated2);
+ AllocVec v2(v, alloc2);
+ EXPECT_THAT(allocated2, v2.size() * sizeof(int));
+
+ int64_t allocated3 = 0;
+ MyAlloc alloc3(&allocated3);
+ AllocVec v3(std::move(v), alloc3);
+ EXPECT_THAT(allocated3, v3.size() * sizeof(int));
+ }
+}
+
+TEST(AllocatorSupportTest, SwapBothAllocated) {
+ using MyAlloc = CountingAllocator<int>;
+ using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
+ int64_t allocated1 = 0;
+ int64_t allocated2 = 0;
+ {
+ const int ia1[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+ const int ia2[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
+ MyAlloc a1(&allocated1);
+ MyAlloc a2(&allocated2);
+ AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1);
+ AllocVec v2(ia2, ia2 + ABSL_ARRAYSIZE(ia2), a2);
+ EXPECT_LT(v1.capacity(), v2.capacity());
+ EXPECT_THAT(allocated1, v1.capacity() * sizeof(int));
+ EXPECT_THAT(allocated2, v2.capacity() * sizeof(int));
+ v1.swap(v2);
+ EXPECT_THAT(v1, ElementsAreArray(ia2));
+ EXPECT_THAT(v2, ElementsAreArray(ia1));
+ EXPECT_THAT(allocated1, v2.capacity() * sizeof(int));
+ EXPECT_THAT(allocated2, v1.capacity() * sizeof(int));
+ }
+ EXPECT_THAT(allocated1, 0);
+ EXPECT_THAT(allocated2, 0);
+}
+
+TEST(AllocatorSupportTest, SwapOneAllocated) {
+ using MyAlloc = CountingAllocator<int>;
+ using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
+ int64_t allocated1 = 0;
+ int64_t allocated2 = 0;
+ {
+ const int ia1[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+ const int ia2[] = { 0, 1, 2, 3 };
+ MyAlloc a1(&allocated1);
+ MyAlloc a2(&allocated2);
+ AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1);
+ AllocVec v2(ia2, ia2 + ABSL_ARRAYSIZE(ia2), a2);
+ EXPECT_THAT(allocated1, v1.capacity() * sizeof(int));
+ EXPECT_THAT(allocated2, 0);
+ v1.swap(v2);
+ EXPECT_THAT(v1, ElementsAreArray(ia2));
+ EXPECT_THAT(v2, ElementsAreArray(ia1));
+ EXPECT_THAT(allocated1, v2.capacity() * sizeof(int));
+ EXPECT_THAT(allocated2, 0);
+ EXPECT_TRUE(v2.get_allocator() == a1);
+ EXPECT_TRUE(v1.get_allocator() == a2);
+ }
+ EXPECT_THAT(allocated1, 0);
+ EXPECT_THAT(allocated2, 0);
+}
+
+TEST(AllocatorSupportTest, ScopedAllocatorWorks) {
+ using StdVector = std::vector<int, CountingAllocator<int>>;
+ using MyAlloc =
+ std::scoped_allocator_adaptor<CountingAllocator<StdVector>>;
+ using AllocVec = absl::InlinedVector<StdVector, 4, MyAlloc>;
+
+ int64_t allocated = 0;
+ AllocVec vec(MyAlloc{CountingAllocator<StdVector>{&allocated}});
+ EXPECT_EQ(allocated, 0);
+
+ // This default constructs a vector<int>, but the allocator should pass itself
+ // into the vector<int>.
+ // The absl::InlinedVector does not allocate any memory.
+ // The vector<int> does not allocate any memory.
+ vec.resize(1);
+ EXPECT_EQ(allocated, 0);
+
+ // We make vector<int> allocate memory.
+ // It must go through the allocator even though we didn't construct the
+ // vector directly.
+ vec[0].push_back(1);
+ EXPECT_EQ(allocated, sizeof(int) * 1);
+
+ // Another allocating vector.
+ vec.push_back(vec[0]);
+ EXPECT_EQ(allocated, sizeof(int) * 2);
+
+ // Overflow the inlined memory.
+ // The absl::InlinedVector will now allocate.
+ vec.resize(5);
+ EXPECT_EQ(allocated, sizeof(int) * 2 + sizeof(StdVector) * 8);
+
+ // Adding one more in external mode should also work.
+ vec.push_back(vec[0]);
+ EXPECT_EQ(allocated, sizeof(int) * 3 + sizeof(StdVector) * 8);
+
+ // And extending these should still work.
+ vec[0].push_back(1);
+ EXPECT_EQ(allocated, sizeof(int) * 4 + sizeof(StdVector) * 8);
+
+ vec.clear();
+ EXPECT_EQ(allocated, 0);
+}
+
+} // anonymous namespace
diff --git a/absl/container/internal/test_instance_tracker.cc b/absl/container/internal/test_instance_tracker.cc
new file mode 100644
index 0000000..fe00aca
--- /dev/null
+++ b/absl/container/internal/test_instance_tracker.cc
@@ -0,0 +1,26 @@
+// 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/container/internal/test_instance_tracker.h"
+
+namespace absl {
+namespace test_internal {
+int BaseCountedInstance::num_instances_ = 0;
+int BaseCountedInstance::num_live_instances_ = 0;
+int BaseCountedInstance::num_moves_ = 0;
+int BaseCountedInstance::num_copies_ = 0;
+int BaseCountedInstance::num_swaps_ = 0;
+
+} // namespace test_internal
+} // namespace absl
diff --git a/absl/container/internal/test_instance_tracker.h b/absl/container/internal/test_instance_tracker.h
new file mode 100644
index 0000000..cf8f3a5
--- /dev/null
+++ b/absl/container/internal/test_instance_tracker.h
@@ -0,0 +1,220 @@
+// 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_CONTAINER_INTERNAL_TEST_INSTANCE_TRACKER_H_
+#define ABSL_CONTAINER_INTERNAL_TEST_INSTANCE_TRACKER_H_
+
+#include <cstdlib>
+#include <ostream>
+
+namespace absl {
+namespace test_internal {
+
+// A type that counts number of occurences of the type, the live occurrences of
+// the type, as well as the number of copies, moves, and swaps that have
+// occurred on the type. This is used as a base class for the copyable,
+// copyable+movable, and movable types below that are used in actual tests. Use
+// InstanceTracker in tests to track the number of instances.
+class BaseCountedInstance {
+ public:
+ explicit BaseCountedInstance(int x) : value_(x) {
+ ++num_instances_;
+ ++num_live_instances_;
+ }
+ BaseCountedInstance(const BaseCountedInstance& x)
+ : value_(x.value_), is_live_(x.is_live_) {
+ ++num_instances_;
+ if (is_live_) ++num_live_instances_;
+ ++num_copies_;
+ }
+ BaseCountedInstance(BaseCountedInstance&& x)
+ : value_(x.value_), is_live_(x.is_live_) {
+ x.is_live_ = false;
+ ++num_instances_;
+ ++num_moves_;
+ }
+ ~BaseCountedInstance() {
+ --num_instances_;
+ if (is_live_) --num_live_instances_;
+ }
+
+ BaseCountedInstance& operator=(const BaseCountedInstance& x) {
+ value_ = x.value_;
+ if (is_live_) --num_live_instances_;
+ is_live_ = x.is_live_;
+ if (is_live_) ++num_live_instances_;
+ ++num_copies_;
+ return *this;
+ }
+ BaseCountedInstance& operator=(BaseCountedInstance&& x) {
+ value_ = x.value_;
+ if (is_live_) --num_live_instances_;
+ is_live_ = x.is_live_;
+ x.is_live_ = false;
+ ++num_moves_;
+ return *this;
+ }
+
+ int value() const {
+ if (!is_live_) std::abort();
+ return value_;
+ }
+
+ friend std::ostream& operator<<(std::ostream& o,
+ const BaseCountedInstance& v) {
+ return o << "[value:" << v.value() << "]";
+ }
+
+ // Implementation of efficient swap() that counts swaps.
+ static void SwapImpl(
+ BaseCountedInstance& lhs, // NOLINT(runtime/references)
+ BaseCountedInstance& rhs) { // NOLINT(runtime/references)
+ using std::swap;
+ swap(lhs.value_, rhs.value_);
+ swap(lhs.is_live_, rhs.is_live_);
+ ++BaseCountedInstance::num_swaps_;
+ }
+
+ private:
+ friend class InstanceTracker;
+
+ int value_;
+
+ // Indicates if the value is live, ie it hasn't been moved away from.
+ bool is_live_ = true;
+
+ // Number of instances.
+ static int num_instances_;
+
+ // Number of live instances (those that have not been moved away from.)
+ static int num_live_instances_;
+
+ // Number of times that BaseCountedInstance objects were moved.
+ static int num_moves_;
+
+ // Number of times that BaseCountedInstance objects were copied.
+ static int num_copies_;
+
+ // Number of times that BaseCountedInstance objects were swapped.
+ static int num_swaps_;
+};
+
+// Helper to track the BaseCountedInstance instance counters. Expects that the
+// number of instances and live_instances are the same when it is constructed
+// and when it is destructed.
+class InstanceTracker {
+ public:
+ InstanceTracker()
+ : start_instances_(BaseCountedInstance::num_instances_),
+ start_live_instances_(BaseCountedInstance::num_live_instances_) {
+ ResetCopiesMovesSwaps();
+ }
+ ~InstanceTracker() {
+ if (instances() != 0) std::abort();
+ if (live_instances() != 0) std::abort();
+ }
+
+ // Returns the number of BaseCountedInstance instances both containing valid
+ // values and those moved away from compared to when the InstanceTracker was
+ // constructed
+ int instances() const {
+ return BaseCountedInstance::num_instances_ - start_instances_;
+ }
+
+ // Returns the number of live BaseCountedInstance instances compared to when
+ // the InstanceTracker was constructed
+ int live_instances() const {
+ return BaseCountedInstance::num_live_instances_ - start_live_instances_;
+ }
+
+ // Returns the number of moves on BaseCountedInstance objects since
+ // construction or since the last call to ResetCopiesMovesSwaps().
+ int moves() const { return BaseCountedInstance::num_moves_ - start_moves_; }
+
+ // Returns the number of copies on BaseCountedInstance objects since
+ // construction or the last call to ResetCopiesMovesSwaps().
+ int copies() const {
+ return BaseCountedInstance::num_copies_ - start_copies_;
+ }
+
+ // Returns the number of swaps on BaseCountedInstance objects since
+ // construction or the last call to ResetCopiesMovesSwaps().
+ int swaps() const { return BaseCountedInstance::num_swaps_ - start_swaps_; }
+
+ // Resets the base values for moves, copies and swaps to the current values,
+ // so that subsequent Get*() calls for moves, copies and swaps will compare to
+ // the situation at the point of this call.
+ void ResetCopiesMovesSwaps() {
+ start_moves_ = BaseCountedInstance::num_moves_;
+ start_copies_ = BaseCountedInstance::num_copies_;
+ start_swaps_ = BaseCountedInstance::num_swaps_;
+ }
+
+ private:
+ int start_instances_;
+ int start_live_instances_;
+ int start_moves_;
+ int start_copies_;
+ int start_swaps_;
+};
+
+// Copyable, not movable.
+class CopyableOnlyInstance : public BaseCountedInstance {
+ public:
+ explicit CopyableOnlyInstance(int x) : BaseCountedInstance(x) {}
+ CopyableOnlyInstance(const CopyableOnlyInstance& rhs) = default;
+ CopyableOnlyInstance& operator=(const CopyableOnlyInstance& rhs) = default;
+
+ friend void swap(CopyableOnlyInstance& lhs, CopyableOnlyInstance& rhs) {
+ BaseCountedInstance::SwapImpl(lhs, rhs);
+ }
+
+ static bool supports_move() { return false; }
+};
+
+// Copyable and movable.
+class CopyableMovableInstance : public BaseCountedInstance {
+ public:
+ explicit CopyableMovableInstance(int x) : BaseCountedInstance(x) {}
+ CopyableMovableInstance(const CopyableMovableInstance& rhs) = default;
+ CopyableMovableInstance(CopyableMovableInstance&& rhs) = default;
+ CopyableMovableInstance& operator=(const CopyableMovableInstance& rhs) =
+ default;
+ CopyableMovableInstance& operator=(CopyableMovableInstance&& rhs) = default;
+
+ friend void swap(CopyableMovableInstance& lhs, CopyableMovableInstance& rhs) {
+ BaseCountedInstance::SwapImpl(lhs, rhs);
+ }
+
+ static bool supports_move() { return true; }
+};
+
+// Only movable, not default-constructible.
+class MovableOnlyInstance : public BaseCountedInstance {
+ public:
+ explicit MovableOnlyInstance(int x) : BaseCountedInstance(x) {}
+ MovableOnlyInstance(MovableOnlyInstance&& other) = default;
+ MovableOnlyInstance& operator=(MovableOnlyInstance&& other) = default;
+
+ friend void swap(MovableOnlyInstance& lhs, MovableOnlyInstance& rhs) {
+ BaseCountedInstance::SwapImpl(lhs, rhs);
+ }
+
+ static bool supports_move() { return true; }
+};
+
+} // namespace test_internal
+} // namespace absl
+
+#endif // ABSL_CONTAINER_INTERNAL_TEST_INSTANCE_TRACKER_H_
diff --git a/absl/container/internal/test_instance_tracker_test.cc b/absl/container/internal/test_instance_tracker_test.cc
new file mode 100644
index 0000000..9efb677
--- /dev/null
+++ b/absl/container/internal/test_instance_tracker_test.cc
@@ -0,0 +1,160 @@
+// 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/container/internal/test_instance_tracker.h"
+
+#include "gtest/gtest.h"
+
+namespace {
+
+using absl::test_internal::CopyableMovableInstance;
+using absl::test_internal::CopyableOnlyInstance;
+using absl::test_internal::InstanceTracker;
+using absl::test_internal::MovableOnlyInstance;
+
+TEST(TestInstanceTracker, CopyableMovable) {
+ InstanceTracker tracker;
+ CopyableMovableInstance src(1);
+ EXPECT_EQ(1, src.value()) << src;
+ CopyableMovableInstance copy(src);
+ CopyableMovableInstance move(std::move(src));
+ EXPECT_EQ(1, tracker.copies());
+ EXPECT_EQ(1, tracker.moves());
+ EXPECT_EQ(0, tracker.swaps());
+ EXPECT_EQ(3, tracker.instances());
+ EXPECT_EQ(2, tracker.live_instances());
+ tracker.ResetCopiesMovesSwaps();
+
+ CopyableMovableInstance copy_assign(1);
+ copy_assign = copy;
+ CopyableMovableInstance move_assign(1);
+ move_assign = std::move(move);
+ EXPECT_EQ(1, tracker.copies());
+ EXPECT_EQ(1, tracker.moves());
+ EXPECT_EQ(0, tracker.swaps());
+ EXPECT_EQ(5, tracker.instances());
+ EXPECT_EQ(3, tracker.live_instances());
+ tracker.ResetCopiesMovesSwaps();
+
+ {
+ using std::swap;
+ swap(move_assign, copy);
+ swap(copy, move_assign);
+ EXPECT_EQ(2, tracker.swaps());
+ EXPECT_EQ(0, tracker.copies());
+ EXPECT_EQ(0, tracker.moves());
+ EXPECT_EQ(5, tracker.instances());
+ EXPECT_EQ(3, tracker.live_instances());
+ }
+}
+
+TEST(TestInstanceTracker, CopyableOnly) {
+ InstanceTracker tracker;
+ CopyableOnlyInstance src(1);
+ EXPECT_EQ(1, src.value()) << src;
+ CopyableOnlyInstance copy(src);
+ CopyableOnlyInstance copy2(std::move(src)); // NOLINT
+ EXPECT_EQ(2, tracker.copies());
+ EXPECT_EQ(0, tracker.moves());
+ EXPECT_EQ(3, tracker.instances());
+ EXPECT_EQ(3, tracker.live_instances());
+ tracker.ResetCopiesMovesSwaps();
+
+ CopyableOnlyInstance copy_assign(1);
+ copy_assign = copy;
+ CopyableOnlyInstance copy_assign2(1);
+ copy_assign2 = std::move(copy2); // NOLINT
+ EXPECT_EQ(2, tracker.copies());
+ EXPECT_EQ(0, tracker.moves());
+ EXPECT_EQ(5, tracker.instances());
+ EXPECT_EQ(5, tracker.live_instances());
+ tracker.ResetCopiesMovesSwaps();
+
+ {
+ using std::swap;
+ swap(src, copy);
+ swap(copy, src);
+ EXPECT_EQ(2, tracker.swaps());
+ EXPECT_EQ(0, tracker.copies());
+ EXPECT_EQ(0, tracker.moves());
+ EXPECT_EQ(5, tracker.instances());
+ EXPECT_EQ(5, tracker.live_instances());
+ }
+}
+
+TEST(TestInstanceTracker, MovableOnly) {
+ InstanceTracker tracker;
+ MovableOnlyInstance src(1);
+ EXPECT_EQ(1, src.value()) << src;
+ MovableOnlyInstance move(std::move(src));
+ MovableOnlyInstance move_assign(2);
+ move_assign = std::move(move);
+ EXPECT_EQ(3, tracker.instances());
+ EXPECT_EQ(1, tracker.live_instances());
+ EXPECT_EQ(2, tracker.moves());
+ EXPECT_EQ(0, tracker.copies());
+ tracker.ResetCopiesMovesSwaps();
+
+ {
+ using std::swap;
+ MovableOnlyInstance other(2);
+ swap(move_assign, other);
+ swap(other, move_assign);
+ EXPECT_EQ(2, tracker.swaps());
+ EXPECT_EQ(0, tracker.copies());
+ EXPECT_EQ(0, tracker.moves());
+ EXPECT_EQ(4, tracker.instances());
+ EXPECT_EQ(2, tracker.live_instances());
+ }
+}
+
+TEST(TestInstanceTracker, ExistingInstances) {
+ CopyableMovableInstance uncounted_instance(1);
+ CopyableMovableInstance uncounted_live_instance(
+ std::move(uncounted_instance));
+ InstanceTracker tracker;
+ EXPECT_EQ(0, tracker.instances());
+ EXPECT_EQ(0, tracker.live_instances());
+ EXPECT_EQ(0, tracker.copies());
+ {
+ CopyableMovableInstance instance1(1);
+ EXPECT_EQ(1, tracker.instances());
+ EXPECT_EQ(1, tracker.live_instances());
+ EXPECT_EQ(0, tracker.copies());
+ EXPECT_EQ(0, tracker.moves());
+ {
+ InstanceTracker tracker2;
+ CopyableMovableInstance instance2(instance1);
+ CopyableMovableInstance instance3(std::move(instance2));
+ EXPECT_EQ(3, tracker.instances());
+ EXPECT_EQ(2, tracker.live_instances());
+ EXPECT_EQ(1, tracker.copies());
+ EXPECT_EQ(1, tracker.moves());
+ EXPECT_EQ(2, tracker2.instances());
+ EXPECT_EQ(1, tracker2.live_instances());
+ EXPECT_EQ(1, tracker2.copies());
+ EXPECT_EQ(1, tracker2.moves());
+ }
+ EXPECT_EQ(1, tracker.instances());
+ EXPECT_EQ(1, tracker.live_instances());
+ EXPECT_EQ(1, tracker.copies());
+ EXPECT_EQ(1, tracker.moves());
+ }
+ EXPECT_EQ(0, tracker.instances());
+ EXPECT_EQ(0, tracker.live_instances());
+ EXPECT_EQ(1, tracker.copies());
+ EXPECT_EQ(1, tracker.moves());
+}
+
+} // namespace
diff --git a/absl/copts.bzl b/absl/copts.bzl
new file mode 100644
index 0000000..68aafd5
--- /dev/null
+++ b/absl/copts.bzl
@@ -0,0 +1,138 @@
+"""absl specific copts.
+
+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.
+"""
+GCC_FLAGS = [
+ "-Wall",
+ "-Wextra",
+ "-Wcast-qual",
+ "-Wconversion-null",
+ "-Wmissing-declarations",
+ "-Woverlength-strings",
+ "-Wpointer-arith",
+ "-Wunused-local-typedefs",
+ "-Wunused-result",
+ "-Wvarargs",
+ "-Wvla", # variable-length array
+ "-Wwrite-strings",
+]
+
+GCC_TEST_FLAGS = [
+ "-Wno-conversion-null",
+ "-Wno-missing-declarations",
+ "-Wno-sign-compare",
+ "-Wno-unused-function",
+ "-Wno-unused-parameter",
+ "-Wno-unused-private-field",
+]
+
+LLVM_FLAGS = [
+ "-Wall",
+ "-Wextra",
+ "-Weverything",
+ "-Wno-c++98-compat-pedantic",
+ "-Wno-comma",
+ "-Wno-conversion",
+ "-Wno-disabled-macro-expansion",
+ "-Wno-documentation",
+ "-Wno-documentation-unknown-command",
+ "-Wno-double-promotion",
+ "-Wno-exit-time-destructors",
+ "-Wno-extra-semi",
+ "-Wno-float-conversion",
+ "-Wno-float-equal",
+ "-Wno-format-nonliteral",
+ "-Wno-gcc-compat",
+ "-Wno-global-constructors",
+ "-Wno-google3-inheriting-constructor",
+ "-Wno-google3-lambda-expression",
+ "-Wno-google3-rvalue-reference",
+ "-Wno-google3-trailing-return-type",
+ "-Wno-nested-anon-types",
+ "-Wno-non-modular-include-in-module",
+ "-Wno-old-style-cast",
+ "-Wno-packed",
+ "-Wno-padded",
+ "-Wno-range-loop-analysis",
+ "-Wno-reserved-id-macro",
+ "-Wno-shorten-64-to-32",
+ "-Wno-sign-conversion",
+ "-Wno-switch-enum",
+ "-Wno-thread-safety-negative",
+ "-Wno-undef",
+ "-Wno-unused-macros",
+ "-Wno-weak-vtables",
+ # flags below are also controled by -Wconversion which is disabled
+ "-Wbitfield-enum-conversion",
+ "-Wbool-conversion",
+ "-Wconstant-conversion",
+ "-Wenum-conversion",
+ "-Wint-conversion",
+ "-Wliteral-conversion",
+ "-Wnon-literal-null-conversion",
+ "-Wnull-conversion",
+ "-Wobjc-literal-conversion",
+ "-Wstring-conversion",
+]
+
+LLVM_TEST_FLAGS = [
+ "-Wno-c99-extensions",
+ "-Wno-missing-noreturn",
+ "-Wno-missing-prototypes",
+ "-Wno-null-conversion",
+ "-Wno-shadow",
+ "-Wno-shift-sign-overflow",
+ "-Wno-sign-compare",
+ "-Wno-unused-function",
+ "-Wno-unused-member-function",
+ "-Wno-unused-parameter",
+ "-Wno-unused-private-field",
+ "-Wno-unused-template",
+ "-Wno-used-but-marked-unused",
+ "-Wno-zero-as-null-pointer-constant",
+]
+
+MSVC_FLAGS = [
+ "/W3",
+ "/WX",
+ "/wd4005", # macro-redifinition
+ "/wd4068", # unknown pragma
+ "/wd4244", # conversion from 'type1' to 'type2', possible loss of data
+ "/wd4267", # conversion from 'size_t' to 'type', possible loss of data
+ "/wd4800", # forcing value to bool 'true' or 'false' (performance warning)
+ "/DWIN32_LEAN_AND_MEAN", # Don't bloat namespace with incompatible winsock versions.
+]
+
+MSVC_TEST_FLAGS = [
+ "/wd4018", # signed/unsigned mismatch
+ "/wd4101", # unreferenced local variable
+ "/wd4503", # decorated name length exceeded, name was truncated
+]
+
+def _qualify_flags(scope, flags):
+ return [scope + x for x in flags]
+
+HYBRID_FLAGS = _qualify_flags("-Xgcc-only=", GCC_FLAGS) + _qualify_flags("-Xclang-only=", LLVM_FLAGS)
+HYBRID_TEST_FLAGS = _qualify_flags("-Xgcc-only=", GCC_TEST_FLAGS) + _qualify_flags("-Xclang-only=", LLVM_TEST_FLAGS)
+
+# /Wall with msvc includes unhelpful warnings such as C4711, C4710, ...
+ABSL_DEFAULT_COPTS = select({
+ "//absl:windows": MSVC_FLAGS,
+ "//absl:llvm_warnings": LLVM_FLAGS,
+ "//conditions:default": GCC_FLAGS,
+})
+
+# in absence of modules (--compiler=gcc or -c opt), cc_tests leak their copts
+# to their (included header) dependencies and fail to build outside absl
+ABSL_TEST_COPTS = ABSL_DEFAULT_COPTS + select({
+ "//absl:windows": MSVC_TEST_FLAGS,
+ "//absl:llvm_warnings": LLVM_TEST_FLAGS,
+ "//conditions:default": GCC_TEST_FLAGS,
+})
+
+ABSL_EXCEPTIONS_FLAG = select({
+ "//absl:windows": ["/U_HAS_EXCEPTIONS", "/D_HAS_EXCEPTIONS=1", "/EHsc"],
+ "//conditions:default": ["-fexceptions"],
+})
diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel
new file mode 100644
index 0000000..84acf9f
--- /dev/null
+++ b/absl/debugging/BUILD.bazel
@@ -0,0 +1,170 @@
+#
+# 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",
+)
+
+package(
+ default_visibility = ["//visibility:public"],
+)
+
+licenses(["notice"]) # Apache 2.0
+
+cc_library(
+ name = "stacktrace",
+ srcs = [
+ "stacktrace.cc",
+ ],
+ hdrs = ["stacktrace.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ ":debugging_internal",
+ "//absl/base",
+ "//absl/base:core_headers",
+ ],
+)
+
+cc_library(
+ name = "debugging_internal",
+ srcs = [
+ "internal/address_is_readable.cc",
+ "internal/elf_mem_image.cc",
+ "internal/vdso_support.cc",
+ ],
+ hdrs = [
+ "internal/address_is_readable.h",
+ "internal/elf_mem_image.h",
+ "internal/stacktrace_aarch64-inl.inc",
+ "internal/stacktrace_arm-inl.inc",
+ "internal/stacktrace_config.h",
+ "internal/stacktrace_generic-inl.inc",
+ "internal/stacktrace_libunwind-inl.inc",
+ "internal/stacktrace_powerpc-inl.inc",
+ "internal/stacktrace_unimplemented-inl.inc",
+ "internal/stacktrace_win32-inl.inc",
+ "internal/stacktrace_x86-inl.inc",
+ "internal/vdso_support.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ "//absl/base",
+ "//absl/base:dynamic_annotations",
+ "//absl/base:core_headers",
+ ],
+)
+
+cc_library(
+ name = "leak_check",
+ srcs = select({
+ # The leak checking interface depends on weak function
+ # declarations that may not necessarily have definitions.
+ # Windows doesn't support this, and ios requires
+ # guaranteed definitions for weak symbols.
+ "//absl:ios": [],
+ "//absl:windows": [],
+ "//conditions:default": [
+ "leak_check.cc",
+ ],
+ }),
+ hdrs = select({
+ "//absl:ios": [],
+ "//absl:windows": [],
+ "//conditions:default": ["leak_check.h"],
+ }),
+ deps = ["//absl/base:core_headers"],
+)
+
+# Adding a dependency to leak_check_disable will disable
+# sanitizer leak checking (asan/lsan) in a test without
+# the need to mess around with build features.
+cc_library(
+ name = "leak_check_disable",
+ srcs = ["leak_check_disable.cc"],
+ linkstatic = 1,
+ alwayslink = 1,
+)
+
+# These targets exists for use in tests only, explicitly configuring the
+# LEAK_SANITIZER macro. It must be linked with -fsanitize=leak for lsan.
+ABSL_LSAN_LINKOPTS = select({
+ "//absl:llvm_compiler": ["-fsanitize=leak"],
+ "//conditions:default": [],
+})
+
+cc_library(
+ name = "leak_check_api_enabled_for_testing",
+ testonly = 1,
+ srcs = ["leak_check.cc"],
+ hdrs = ["leak_check.h"],
+ copts = select({
+ "//absl:llvm_compiler": ["-DLEAK_SANITIZER"],
+ "//conditions:default": [],
+ }),
+ visibility = ["//visibility:private"],
+)
+
+cc_library(
+ name = "leak_check_api_disabled_for_testing",
+ testonly = 1,
+ srcs = ["leak_check.cc"],
+ hdrs = ["leak_check.h"],
+ copts = ["-ULEAK_SANITIZER"],
+ visibility = ["//visibility:private"],
+)
+
+cc_test(
+ name = "leak_check_test",
+ srcs = ["leak_check_test.cc"],
+ copts = select({
+ "//absl:llvm_compiler": ["-DABSL_EXPECT_LEAK_SANITIZER"],
+ "//conditions:default": [],
+ }),
+ linkopts = ABSL_LSAN_LINKOPTS,
+ deps = [
+ ":leak_check_api_enabled_for_testing",
+ "//absl/base",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "leak_check_no_lsan_test",
+ srcs = ["leak_check_test.cc"],
+ copts = ["-UABSL_EXPECT_LEAK_SANITIZER"],
+ deps = [
+ ":leak_check_api_disabled_for_testing",
+ "//absl/base", # for raw_logging
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+# Test that leak checking is skipped when lsan is enabled but
+# ":leak_check_disable" is linked in.
+#
+# This test should fail in the absence of a dependency on ":leak_check_disable"
+cc_test(
+ name = "disabled_leak_check_test",
+ srcs = ["leak_check_fail_test.cc"],
+ linkopts = ABSL_LSAN_LINKOPTS,
+ deps = [
+ ":leak_check_api_enabled_for_testing",
+ ":leak_check_disable",
+ "//absl/base",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/absl/debugging/internal/address_is_readable.cc b/absl/debugging/internal/address_is_readable.cc
new file mode 100644
index 0000000..037ea54
--- /dev/null
+++ b/absl/debugging/internal/address_is_readable.cc
@@ -0,0 +1,134 @@
+// 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.
+
+// base::AddressIsReadable() probes an address to see whether it is readable,
+// without faulting.
+
+#include "absl/debugging/internal/address_is_readable.h"
+
+#if !defined(__linux__) || defined(__ANDROID__)
+
+namespace absl {
+namespace debug_internal {
+
+// On platforms other than Linux, just return true.
+bool AddressIsReadable(const void* /* addr */) { return true; }
+
+} // namespace debug_internal
+} // namespace absl
+
+#else
+
+#include <fcntl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include <atomic>
+#include <cerrno>
+#include <cstdint>
+
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+namespace debug_internal {
+
+// Pack a pid and two file descriptors into a 64-bit word,
+// using 16, 24, and 24 bits for each respectively.
+static uint64_t Pack(uint64_t pid, uint64_t read_fd, uint64_t write_fd) {
+ ABSL_RAW_CHECK((read_fd >> 24) == 0 && (write_fd >> 24) == 0,
+ "fd out of range");
+ return (pid << 48) | ((read_fd & 0xffffff) << 24) | (write_fd & 0xffffff);
+}
+
+// Unpack x into a pid and two file descriptors, where x was created with
+// Pack().
+static void Unpack(uint64_t x, int *pid, int *read_fd, int *write_fd) {
+ *pid = x >> 48;
+ *read_fd = (x >> 24) & 0xffffff;
+ *write_fd = x & 0xffffff;
+}
+
+// Return whether the byte at *addr is readable, without faulting.
+// Save and restores errno. Returns true on systems where
+// unimplemented.
+// This is a namespace-scoped variable for correct zero-initialization.
+static std::atomic<uint64_t> pid_and_fds; // initially 0, an invalid pid.
+bool AddressIsReadable(const void *addr) {
+ int save_errno = errno;
+ // We test whether a byte is readable by using write(). Normally, this would
+ // be done via a cached file descriptor to /dev/null, but linux fails to
+ // check whether the byte is readable when the destination is /dev/null, so
+ // we use a cached pipe. We store the pid of the process that created the
+ // pipe to handle the case where a process forks, and the child closes all
+ // the file descriptors and then calls this routine. This is not perfect:
+ // the child could use the routine, then close all file descriptors and then
+ // use this routine again. But the likely use of this routine is when
+ // crashing, to test the validity of pages when dumping the stack. Beware
+ // that we may leak file descriptors, but we're unlikely to leak many.
+ int bytes_written;
+ int current_pid = getpid() & 0xffff; // we use only the low order 16 bits
+ do { // until we do not get EBADF trying to use file descriptors
+ int pid;
+ int read_fd;
+ int write_fd;
+ uint64_t local_pid_and_fds = pid_and_fds.load(std::memory_order_relaxed);
+ Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd);
+ while (current_pid != pid) {
+ int p[2];
+ // new pipe
+ if (pipe(p) != 0) {
+ ABSL_RAW_LOG(FATAL, "Failed to create pipe, errno=%d", errno);
+ }
+ fcntl(p[0], F_SETFD, FD_CLOEXEC);
+ fcntl(p[1], F_SETFD, FD_CLOEXEC);
+ uint64_t new_pid_and_fds = Pack(current_pid, p[0], p[1]);
+ if (pid_and_fds.compare_exchange_strong(
+ local_pid_and_fds, new_pid_and_fds, std::memory_order_relaxed,
+ std::memory_order_relaxed)) {
+ local_pid_and_fds = new_pid_and_fds; // fds exposed to other threads
+ } else { // fds not exposed to other threads; we can close them.
+ close(p[0]);
+ close(p[1]);
+ local_pid_and_fds = pid_and_fds.load(std::memory_order_relaxed);
+ }
+ Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd);
+ }
+ errno = 0;
+ // Use syscall(SYS_write, ...) instead of write() to prevent ASAN
+ // and other checkers from complaining about accesses to arbitrary
+ // memory.
+ do {
+ bytes_written = syscall(SYS_write, write_fd, addr, 1);
+ } while (bytes_written == -1 && errno == EINTR);
+ if (bytes_written == 1) { // remove the byte from the pipe
+ char c;
+ while (read(read_fd, &c, 1) == -1 && errno == EINTR) {
+ }
+ }
+ if (errno == EBADF) { // Descriptors invalid.
+ // If pid_and_fds contains the problematic file descriptors we just used,
+ // this call will forget them, and the loop will try again.
+ pid_and_fds.compare_exchange_strong(local_pid_and_fds, 0,
+ std::memory_order_relaxed,
+ std::memory_order_relaxed);
+ }
+ } while (errno == EBADF);
+ errno = save_errno;
+ return bytes_written == 1;
+}
+
+} // namespace debug_internal
+} // namespace absl
+
+#endif
diff --git a/absl/debugging/internal/address_is_readable.h b/absl/debugging/internal/address_is_readable.h
new file mode 100644
index 0000000..a8b3292
--- /dev/null
+++ b/absl/debugging/internal/address_is_readable.h
@@ -0,0 +1,29 @@
+// 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_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
+#define ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
+
+namespace absl {
+namespace debug_internal {
+
+// Return whether the byte at *addr is readable, without faulting.
+// Save and restores errno.
+bool AddressIsReadable(const void *addr);
+
+} // namespace debug_internal
+} // namespace absl
+
+#endif // ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
diff --git a/absl/debugging/internal/elf_mem_image.cc b/absl/debugging/internal/elf_mem_image.cc
new file mode 100644
index 0000000..f6c6bc0
--- /dev/null
+++ b/absl/debugging/internal/elf_mem_image.cc
@@ -0,0 +1,397 @@
+// 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.
+
+// Allow dynamic symbol lookup in an in-memory Elf image.
+//
+
+#include "absl/debugging/internal/elf_mem_image.h"
+
+#ifdef ABSL_HAVE_ELF_MEM_IMAGE // defined in elf_mem_image.h
+
+#include <string.h>
+#include <cassert>
+#include <cstddef>
+#include "absl/base/internal/raw_logging.h"
+
+// From binutils/include/elf/common.h (this doesn't appear to be documented
+// anywhere else).
+//
+// /* This flag appears in a Versym structure. It means that the symbol
+// is hidden, and is only visible with an explicit version number.
+// This is a GNU extension. */
+// #define VERSYM_HIDDEN 0x8000
+//
+// /* This is the mask for the rest of the Versym information. */
+// #define VERSYM_VERSION 0x7fff
+
+#define VERSYM_VERSION 0x7fff
+
+namespace absl {
+namespace debug_internal {
+
+namespace {
+
+#if __WORDSIZE == 32
+const int kElfClass = ELFCLASS32;
+int ElfBind(const ElfW(Sym) *symbol) { return ELF32_ST_BIND(symbol->st_info); }
+int ElfType(const ElfW(Sym) *symbol) { return ELF32_ST_TYPE(symbol->st_info); }
+#elif __WORDSIZE == 64
+const int kElfClass = ELFCLASS64;
+int ElfBind(const ElfW(Sym) *symbol) { return ELF64_ST_BIND(symbol->st_info); }
+int ElfType(const ElfW(Sym) *symbol) { return ELF64_ST_TYPE(symbol->st_info); }
+#else
+const int kElfClass = -1;
+int ElfBind(const ElfW(Sym) *) {
+ ABSL_RAW_LOG(FATAL, "Unexpected word size");
+ return 0;
+}
+int ElfType(const ElfW(Sym) *) {
+ ABSL_RAW_LOG(FATAL, "Unexpected word size");
+ return 0;
+}
+#endif
+
+// Extract an element from one of the ELF tables, cast it to desired type.
+// This is just a simple arithmetic and a glorified cast.
+// Callers are responsible for bounds checking.
+template <typename T>
+const T *GetTableElement(const ElfW(Ehdr) * ehdr, ElfW(Off) table_offset,
+ ElfW(Word) element_size, size_t index) {
+ return reinterpret_cast<const T*>(reinterpret_cast<const char *>(ehdr)
+ + table_offset
+ + index * element_size);
+}
+
+} // namespace
+
+const void *const ElfMemImage::kInvalidBase =
+ reinterpret_cast<const void *>(~0L);
+
+ElfMemImage::ElfMemImage(const void *base) {
+ ABSL_RAW_CHECK(base != kInvalidBase, "bad pointer");
+ Init(base);
+}
+
+int ElfMemImage::GetNumSymbols() const {
+ if (!hash_) {
+ return 0;
+ }
+ // See http://www.caldera.com/developers/gabi/latest/ch5.dynamic.html#hash
+ return hash_[1];
+}
+
+const ElfW(Sym) *ElfMemImage::GetDynsym(int index) const {
+ ABSL_RAW_CHECK(index < GetNumSymbols(), "index out of range");
+ return dynsym_ + index;
+}
+
+const ElfW(Versym) *ElfMemImage::GetVersym(int index) const {
+ ABSL_RAW_CHECK(index < GetNumSymbols(), "index out of range");
+ return versym_ + index;
+}
+
+const ElfW(Phdr) *ElfMemImage::GetPhdr(int index) const {
+ ABSL_RAW_CHECK(index < ehdr_->e_phnum, "index out of range");
+ return GetTableElement<ElfW(Phdr)>(ehdr_,
+ ehdr_->e_phoff,
+ ehdr_->e_phentsize,
+ index);
+}
+
+const char *ElfMemImage::GetDynstr(ElfW(Word) offset) const {
+ ABSL_RAW_CHECK(offset < strsize_, "offset out of range");
+ return dynstr_ + offset;
+}
+
+const void *ElfMemImage::GetSymAddr(const ElfW(Sym) *sym) const {
+ if (sym->st_shndx == SHN_UNDEF || sym->st_shndx >= SHN_LORESERVE) {
+ // Symbol corresponds to "special" (e.g. SHN_ABS) section.
+ return reinterpret_cast<const void *>(sym->st_value);
+ }
+ ABSL_RAW_CHECK(link_base_ < sym->st_value, "symbol out of range");
+ return GetTableElement<char>(ehdr_, 0, 1, sym->st_value) - link_base_;
+}
+
+const ElfW(Verdef) *ElfMemImage::GetVerdef(int index) const {
+ ABSL_RAW_CHECK(0 <= index && static_cast<size_t>(index) <= verdefnum_,
+ "index out of range");
+ const ElfW(Verdef) *version_definition = verdef_;
+ while (version_definition->vd_ndx < index && version_definition->vd_next) {
+ const char *const version_definition_as_char =
+ reinterpret_cast<const char *>(version_definition);
+ version_definition =
+ reinterpret_cast<const ElfW(Verdef) *>(version_definition_as_char +
+ version_definition->vd_next);
+ }
+ return version_definition->vd_ndx == index ? version_definition : nullptr;
+}
+
+const ElfW(Verdaux) *ElfMemImage::GetVerdefAux(
+ const ElfW(Verdef) *verdef) const {
+ return reinterpret_cast<const ElfW(Verdaux) *>(verdef+1);
+}
+
+const char *ElfMemImage::GetVerstr(ElfW(Word) offset) const {
+ ABSL_RAW_CHECK(offset < strsize_, "offset out of range");
+ return dynstr_ + offset;
+}
+
+void ElfMemImage::Init(const void *base) {
+ ehdr_ = nullptr;
+ dynsym_ = nullptr;
+ dynstr_ = nullptr;
+ versym_ = nullptr;
+ verdef_ = nullptr;
+ hash_ = nullptr;
+ strsize_ = 0;
+ verdefnum_ = 0;
+ link_base_ = ~0L; // Sentinel: PT_LOAD .p_vaddr can't possibly be this.
+ if (!base) {
+ return;
+ }
+ const intptr_t base_as_uintptr_t = reinterpret_cast<uintptr_t>(base);
+ // Fake VDSO has low bit set.
+ const bool fake_vdso = ((base_as_uintptr_t & 1) != 0);
+ base = reinterpret_cast<const void *>(base_as_uintptr_t & ~1);
+ const char *const base_as_char = reinterpret_cast<const char *>(base);
+ if (base_as_char[EI_MAG0] != ELFMAG0 || base_as_char[EI_MAG1] != ELFMAG1 ||
+ base_as_char[EI_MAG2] != ELFMAG2 || base_as_char[EI_MAG3] != ELFMAG3) {
+ assert(false);
+ return;
+ }
+ int elf_class = base_as_char[EI_CLASS];
+ if (elf_class != kElfClass) {
+ assert(false);
+ return;
+ }
+ switch (base_as_char[EI_DATA]) {
+ case ELFDATA2LSB: {
+ if (__LITTLE_ENDIAN != __BYTE_ORDER) {
+ assert(false);
+ return;
+ }
+ break;
+ }
+ case ELFDATA2MSB: {
+ if (__BIG_ENDIAN != __BYTE_ORDER) {
+ assert(false);
+ return;
+ }
+ break;
+ }
+ default: {
+ assert(false);
+ return;
+ }
+ }
+
+ ehdr_ = reinterpret_cast<const ElfW(Ehdr) *>(base);
+ const ElfW(Phdr) *dynamic_program_header = nullptr;
+ for (int i = 0; i < ehdr_->e_phnum; ++i) {
+ const ElfW(Phdr) *const program_header = GetPhdr(i);
+ switch (program_header->p_type) {
+ case PT_LOAD:
+ if (!~link_base_) {
+ link_base_ = program_header->p_vaddr;
+ }
+ break;
+ case PT_DYNAMIC:
+ dynamic_program_header = program_header;
+ break;
+ }
+ }
+ if (!~link_base_ || !dynamic_program_header) {
+ assert(false);
+ // Mark this image as not present. Can not recur infinitely.
+ Init(nullptr);
+ return;
+ }
+ ptrdiff_t relocation =
+ base_as_char - reinterpret_cast<const char *>(link_base_);
+ ElfW(Dyn) *dynamic_entry =
+ reinterpret_cast<ElfW(Dyn) *>(dynamic_program_header->p_vaddr +
+ relocation);
+ for (; dynamic_entry->d_tag != DT_NULL; ++dynamic_entry) {
+ ElfW(Xword) value = dynamic_entry->d_un.d_val;
+ if (fake_vdso) {
+ // A complication: in the real VDSO, dynamic entries are not relocated
+ // (it wasn't loaded by a dynamic loader). But when testing with a
+ // "fake" dlopen()ed vdso library, the loader relocates some (but
+ // not all!) of them before we get here.
+ if (dynamic_entry->d_tag == DT_VERDEF) {
+ // The only dynamic entry (of the ones we care about) libc-2.3.6
+ // loader doesn't relocate.
+ value += relocation;
+ }
+ } else {
+ // Real VDSO. Everything needs to be relocated.
+ value += relocation;
+ }
+ switch (dynamic_entry->d_tag) {
+ case DT_HASH:
+ hash_ = reinterpret_cast<ElfW(Word) *>(value);
+ break;
+ case DT_SYMTAB:
+ dynsym_ = reinterpret_cast<ElfW(Sym) *>(value);
+ break;
+ case DT_STRTAB:
+ dynstr_ = reinterpret_cast<const char *>(value);
+ break;
+ case DT_VERSYM:
+ versym_ = reinterpret_cast<ElfW(Versym) *>(value);
+ break;
+ case DT_VERDEF:
+ verdef_ = reinterpret_cast<ElfW(Verdef) *>(value);
+ break;
+ case DT_VERDEFNUM:
+ verdefnum_ = dynamic_entry->d_un.d_val;
+ break;
+ case DT_STRSZ:
+ strsize_ = dynamic_entry->d_un.d_val;
+ break;
+ default:
+ // Unrecognized entries explicitly ignored.
+ break;
+ }
+ }
+ if (!hash_ || !dynsym_ || !dynstr_ || !versym_ ||
+ !verdef_ || !verdefnum_ || !strsize_) {
+ assert(false); // invalid VDSO
+ // Mark this image as not present. Can not recur infinitely.
+ Init(nullptr);
+ return;
+ }
+}
+
+bool ElfMemImage::LookupSymbol(const char *name,
+ const char *version,
+ int type,
+ SymbolInfo *info_out) const {
+ for (const SymbolInfo& info : *this) {
+ if (strcmp(info.name, name) == 0 && strcmp(info.version, version) == 0 &&
+ ElfType(info.symbol) == type) {
+ if (info_out) {
+ *info_out = info;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ElfMemImage::LookupSymbolByAddress(const void *address,
+ SymbolInfo *info_out) const {
+ for (const SymbolInfo& info : *this) {
+ const char *const symbol_start =
+ reinterpret_cast<const char *>(info.address);
+ const char *const symbol_end = symbol_start + info.symbol->st_size;
+ if (symbol_start <= address && address < symbol_end) {
+ if (info_out) {
+ // Client wants to know details for that symbol (the usual case).
+ if (ElfBind(info.symbol) == STB_GLOBAL) {
+ // Strong symbol; just return it.
+ *info_out = info;
+ return true;
+ } else {
+ // Weak or local. Record it, but keep looking for a strong one.
+ *info_out = info;
+ }
+ } else {
+ // Client only cares if there is an overlapping symbol.
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+ElfMemImage::SymbolIterator::SymbolIterator(const void *const image, int index)
+ : index_(index), image_(image) {
+}
+
+const ElfMemImage::SymbolInfo *ElfMemImage::SymbolIterator::operator->() const {
+ return &info_;
+}
+
+const ElfMemImage::SymbolInfo& ElfMemImage::SymbolIterator::operator*() const {
+ return info_;
+}
+
+bool ElfMemImage::SymbolIterator::operator==(const SymbolIterator &rhs) const {
+ return this->image_ == rhs.image_ && this->index_ == rhs.index_;
+}
+
+bool ElfMemImage::SymbolIterator::operator!=(const SymbolIterator &rhs) const {
+ return !(*this == rhs);
+}
+
+ElfMemImage::SymbolIterator &ElfMemImage::SymbolIterator::operator++() {
+ this->Update(1);
+ return *this;
+}
+
+ElfMemImage::SymbolIterator ElfMemImage::begin() const {
+ SymbolIterator it(this, 0);
+ it.Update(0);
+ return it;
+}
+
+ElfMemImage::SymbolIterator ElfMemImage::end() const {
+ return SymbolIterator(this, GetNumSymbols());
+}
+
+void ElfMemImage::SymbolIterator::Update(int increment) {
+ const ElfMemImage *image = reinterpret_cast<const ElfMemImage *>(image_);
+ ABSL_RAW_CHECK(image->IsPresent() || increment == 0, "");
+ if (!image->IsPresent()) {
+ return;
+ }
+ index_ += increment;
+ if (index_ >= image->GetNumSymbols()) {
+ index_ = image->GetNumSymbols();
+ return;
+ }
+ const ElfW(Sym) *symbol = image->GetDynsym(index_);
+ const ElfW(Versym) *version_symbol = image->GetVersym(index_);
+ ABSL_RAW_CHECK(symbol && version_symbol, "");
+ const char *const symbol_name = image->GetDynstr(symbol->st_name);
+ const ElfW(Versym) version_index = version_symbol[0] & VERSYM_VERSION;
+ const ElfW(Verdef) *version_definition = nullptr;
+ const char *version_name = "";
+ if (symbol->st_shndx == SHN_UNDEF) {
+ // Undefined symbols reference DT_VERNEED, not DT_VERDEF, and
+ // version_index could well be greater than verdefnum_, so calling
+ // GetVerdef(version_index) may trigger assertion.
+ } else {
+ version_definition = image->GetVerdef(version_index);
+ }
+ if (version_definition) {
+ // I am expecting 1 or 2 auxiliary entries: 1 for the version itself,
+ // optional 2nd if the version has a parent.
+ ABSL_RAW_CHECK(
+ version_definition->vd_cnt == 1 || version_definition->vd_cnt == 2,
+ "wrong number of entries");
+ const ElfW(Verdaux) *version_aux = image->GetVerdefAux(version_definition);
+ version_name = image->GetVerstr(version_aux->vda_name);
+ }
+ info_.name = symbol_name;
+ info_.version = version_name;
+ info_.address = image->GetSymAddr(symbol);
+ info_.symbol = symbol;
+}
+
+} // namespace debug_internal
+} // namespace absl
+
+#endif // ABSL_HAVE_ELF_MEM_IMAGE
diff --git a/absl/debugging/internal/elf_mem_image.h b/absl/debugging/internal/elf_mem_image.h
new file mode 100644
index 0000000..7f3dbb9
--- /dev/null
+++ b/absl/debugging/internal/elf_mem_image.h
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+// Allow dynamic symbol lookup for in-memory Elf images.
+
+#ifndef ABSL_DEBUGGING_INTERNAL_ELF_MEM_IMAGE_H_
+#define ABSL_DEBUGGING_INTERNAL_ELF_MEM_IMAGE_H_
+
+// Including this will define the __GLIBC__ macro if glibc is being
+// used.
+#include <climits>
+
+// Maybe one day we can rewrite this file not to require the elf
+// symbol extensions in glibc, but for right now we need them.
+#ifdef ABSL_HAVE_ELF_MEM_IMAGE
+#error ABSL_HAVE_ELF_MEM_IMAGE cannot be directly set
+#endif
+
+#if defined(__ELF__) && defined(__GLIBC__) && !defined(__native_client__) && \
+ !defined(__asmjs__)
+#define ABSL_HAVE_ELF_MEM_IMAGE 1
+#endif
+
+#if ABSL_HAVE_ELF_MEM_IMAGE
+
+#include <link.h> // for ElfW
+
+namespace absl {
+namespace debug_internal {
+
+// An in-memory ELF image (may not exist on disk).
+class ElfMemImage {
+ public:
+ // Sentinel: there could never be an elf image at this address.
+ static const void *const kInvalidBase;
+
+ // Information about a single vdso symbol.
+ // All pointers are into .dynsym, .dynstr, or .text of the VDSO.
+ // Do not free() them or modify through them.
+ struct SymbolInfo {
+ const char *name; // E.g. "__vdso_getcpu"
+ const char *version; // E.g. "LINUX_2.6", could be ""
+ // for unversioned symbol.
+ const void *address; // Relocated symbol address.
+ const ElfW(Sym) *symbol; // Symbol in the dynamic symbol table.
+ };
+
+ // Supports iteration over all dynamic symbols.
+ class SymbolIterator {
+ public:
+ friend class ElfMemImage;
+ const SymbolInfo *operator->() const;
+ const SymbolInfo &operator*() const;
+ SymbolIterator& operator++();
+ bool operator!=(const SymbolIterator &rhs) const;
+ bool operator==(const SymbolIterator &rhs) const;
+ private:
+ SymbolIterator(const void *const image, int index);
+ void Update(int incr);
+ SymbolInfo info_;
+ int index_;
+ const void *const image_;
+ };
+
+
+ explicit ElfMemImage(const void *base);
+ void Init(const void *base);
+ bool IsPresent() const { return ehdr_ != nullptr; }
+ const ElfW(Phdr)* GetPhdr(int index) const;
+ const ElfW(Sym)* GetDynsym(int index) const;
+ const ElfW(Versym)* GetVersym(int index) const;
+ const ElfW(Verdef)* GetVerdef(int index) const;
+ const ElfW(Verdaux)* GetVerdefAux(const ElfW(Verdef) *verdef) const;
+ const char* GetDynstr(ElfW(Word) offset) const;
+ const void* GetSymAddr(const ElfW(Sym) *sym) const;
+ const char* GetVerstr(ElfW(Word) offset) const;
+ int GetNumSymbols() const;
+
+ SymbolIterator begin() const;
+ SymbolIterator end() const;
+
+ // Look up versioned dynamic symbol in the image.
+ // Returns false if image is not present, or doesn't contain given
+ // symbol/version/type combination.
+ // If info_out is non-null, additional details are filled in.
+ bool LookupSymbol(const char *name, const char *version,
+ int symbol_type, SymbolInfo *info_out) const;
+
+ // Find info about symbol (if any) which overlaps given address.
+ // Returns true if symbol was found; false if image isn't present
+ // or doesn't have a symbol overlapping given address.
+ // If info_out is non-null, additional details are filled in.
+ bool LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const;
+
+ private:
+ const ElfW(Ehdr) *ehdr_;
+ const ElfW(Sym) *dynsym_;
+ const ElfW(Versym) *versym_;
+ const ElfW(Verdef) *verdef_;
+ const ElfW(Word) *hash_;
+ const char *dynstr_;
+ size_t strsize_;
+ size_t verdefnum_;
+ ElfW(Addr) link_base_; // Link-time base (p_vaddr of first PT_LOAD).
+};
+
+} // namespace debug_internal
+} // namespace absl
+
+#endif // ABSL_HAVE_ELF_MEM_IMAGE
+
+#endif // ABSL_DEBUGGING_INTERNAL_ELF_MEM_IMAGE_H_
diff --git a/absl/debugging/internal/stacktrace_aarch64-inl.inc b/absl/debugging/internal/stacktrace_aarch64-inl.inc
new file mode 100644
index 0000000..c125ea2
--- /dev/null
+++ b/absl/debugging/internal/stacktrace_aarch64-inl.inc
@@ -0,0 +1,181 @@
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_AARCH64_INL_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_AARCH64_INL_H_
+
+// Generate stack tracer for aarch64
+
+#if defined(__linux__)
+#include <sys/mman.h>
+#include <ucontext.h>
+#include <unistd.h>
+#endif
+
+#include <atomic>
+#include <cassert>
+#include <cstdint>
+#include <iostream>
+
+#include "absl/debugging/internal/address_is_readable.h"
+#include "absl/debugging/internal/vdso_support.h" // a no-op on non-elf or non-glibc systems
+#include "absl/debugging/stacktrace.h"
+
+static const uintptr_t kUnknownFrameSize = 0;
+
+#if defined(__linux__)
+// Returns the address of the VDSO __kernel_rt_sigreturn function, if present.
+static const unsigned char* GetKernelRtSigreturnAddress() {
+ constexpr uintptr_t kImpossibleAddress = 1;
+ static std::atomic<uintptr_t> memoized{kImpossibleAddress};
+ uintptr_t address = memoized.load(std::memory_order_relaxed);
+ if (address != kImpossibleAddress) {
+ return reinterpret_cast<const unsigned char*>(address);
+ }
+
+ address = reinterpret_cast<uintptr_t>(nullptr);
+
+#ifdef ABSL_HAVE_VDSO_SUPPORT
+ absl::debug_internal::VDSOSupport vdso;
+ if (vdso.IsPresent()) {
+ absl::debug_internal::VDSOSupport::SymbolInfo symbol_info;
+ if (!vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.6.39", STT_FUNC,
+ &symbol_info) ||
+ symbol_info.address == nullptr) {
+ // Unexpected: VDSO is present, yet the expected symbol is missing
+ // or null.
+ assert(false && "VDSO is present, but doesn't have expected symbol");
+ } else {
+ if (reinterpret_cast<uintptr_t>(symbol_info.address) !=
+ kImpossibleAddress) {
+ address = reinterpret_cast<uintptr_t>(symbol_info.address);
+ } else {
+ assert(false && "VDSO returned invalid address");
+ }
+ }
+ }
+#endif
+
+ memoized.store(address, std::memory_order_relaxed);
+ return reinterpret_cast<const unsigned char*>(address);
+}
+#endif // __linux__
+
+// Compute the size of a stack frame in [low..high). We assume that
+// low < high. Return size of kUnknownFrameSize.
+template<typename T>
+static inline uintptr_t ComputeStackFrameSize(const T* low,
+ const T* high) {
+ const char* low_char_ptr = reinterpret_cast<const char *>(low);
+ const char* high_char_ptr = reinterpret_cast<const char *>(high);
+ return low < high ? high_char_ptr - low_char_ptr : kUnknownFrameSize;
+}
+
+// Given a pointer to a stack frame, locate and return the calling
+// stackframe, or return null if no stackframe can be found. Perform sanity
+// checks (the strictness of which is controlled by the boolean parameter
+// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
+template<bool STRICT_UNWINDING, bool WITH_CONTEXT>
+static void **NextStackFrame(void **old_frame_pointer, const void *uc) {
+ void **new_frame_pointer = reinterpret_cast<void**>(*old_frame_pointer);
+ bool check_frame_size = true;
+
+#if defined(__linux__)
+ if (WITH_CONTEXT && uc != nullptr) {
+ // Check to see if next frame's return address is __kernel_rt_sigreturn.
+ if (old_frame_pointer[1] == GetKernelRtSigreturnAddress()) {
+ const ucontext_t *ucv = static_cast<const ucontext_t *>(uc);
+ // old_frame_pointer[0] is not suitable for unwinding, look at
+ // ucontext to discover frame pointer before signal.
+ void **const pre_signal_frame_pointer =
+ reinterpret_cast<void **>(ucv->uc_mcontext.regs[29]);
+
+ // Check that alleged frame pointer is actually readable. This is to
+ // prevent "double fault" in case we hit the first fault due to e.g.
+ // stack corruption.
+ if (!absl::debug_internal::AddressIsReadable(
+ pre_signal_frame_pointer))
+ return nullptr;
+
+ // Alleged frame pointer is readable, use it for further unwinding.
+ new_frame_pointer = pre_signal_frame_pointer;
+
+ // Skip frame size check if we return from a signal. We may be using a
+ // an alternate stack for signals.
+ check_frame_size = false;
+ }
+ }
+#endif
+
+ // aarch64 ABI requires stack pointer to be 16-byte-aligned.
+ if ((reinterpret_cast<uintptr_t>(new_frame_pointer) & 15) != 0)
+ return nullptr;
+
+ // Check frame size. In strict mode, we assume frames to be under
+ // 100,000 bytes. In non-strict mode, we relax the limit to 1MB.
+ if (check_frame_size) {
+ const uintptr_t max_size = STRICT_UNWINDING ? 100000 : 1000000;
+ const uintptr_t frame_size =
+ ComputeStackFrameSize(old_frame_pointer, new_frame_pointer);
+ if (frame_size == kUnknownFrameSize || frame_size > max_size)
+ return nullptr;
+ }
+
+ return new_frame_pointer;
+}
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
+ const void *ucp, int *min_dropped_frames) {
+#ifdef __GNUC__
+ void **frame_pointer = reinterpret_cast<void**>(__builtin_frame_address(0));
+#else
+# error reading stack point not yet supported on this platform.
+#endif
+
+ skip_count++; // Skip the frame for this function.
+ int n = 0;
+
+ // The frame pointer points to low address of a frame. The first 64-bit
+ // word of a frame points to the next frame up the call chain, which normally
+ // is just after the high address of the current frame. The second word of
+ // a frame contains return adress of to the caller. To find a pc value
+ // associated with the current frame, we need to go down a level in the call
+ // chain. So we remember return the address of the last frame seen. This
+ // does not work for the first stack frame, which belongs to UnwindImp() but
+ // we skip the frame for UnwindImp() anyway.
+ void* prev_return_address = nullptr;
+
+ while (frame_pointer && n < max_depth) {
+ // The absl::GetStackFrames routine is called when we are in some
+ // informational context (the failure signal handler for example).
+ // Use the non-strict unwinding rules to produce a stack trace
+ // that is as complete as possible (even if it contains a few bogus
+ // entries in some rare cases).
+ void **next_frame_pointer =
+ NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(frame_pointer, ucp);
+
+ if (skip_count > 0) {
+ skip_count--;
+ } else {
+ result[n] = prev_return_address;
+ if (IS_STACK_FRAMES) {
+ sizes[n] = ComputeStackFrameSize(frame_pointer, next_frame_pointer);
+ }
+ n++;
+ }
+ prev_return_address = frame_pointer[1];
+ frame_pointer = next_frame_pointer;
+ }
+ if (min_dropped_frames != nullptr) {
+ // Implementation detail: we clamp the max of frames we are willing to
+ // count, so as not to spend too much time in the loop below.
+ const int kMaxUnwind = 200;
+ int j = 0;
+ for (; frame_pointer != nullptr && j < kMaxUnwind; j++) {
+ frame_pointer =
+ NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(frame_pointer, ucp);
+ }
+ *min_dropped_frames = j;
+ }
+ return n;
+}
+
+#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_AARCH64_INL_H_
diff --git a/absl/debugging/internal/stacktrace_arm-inl.inc b/absl/debugging/internal/stacktrace_arm-inl.inc
new file mode 100644
index 0000000..566b6d3
--- /dev/null
+++ b/absl/debugging/internal/stacktrace_arm-inl.inc
@@ -0,0 +1,115 @@
+// Copyright 2011 and onwards Google Inc.
+// All rights reserved.
+//
+// Author: Doug Kwan
+// This is inspired by Craig Silverstein's PowerPC stacktrace code.
+//
+
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_
+
+#include <cstdint>
+
+#include "absl/debugging/stacktrace.h"
+
+// WARNING:
+// This only works if all your code is in either ARM or THUMB mode. With
+// interworking, the frame pointer of the caller can either be in r11 (ARM
+// mode) or r7 (THUMB mode). A callee only saves the frame pointer of its
+// mode in a fixed location on its stack frame. If the caller is a different
+// mode, there is no easy way to find the frame pointer. It can either be
+// still in the designated register or saved on stack along with other callee
+// saved registers.
+
+// Given a pointer to a stack frame, locate and return the calling
+// stackframe, or return nullptr if no stackframe can be found. Perform sanity
+// checks (the strictness of which is controlled by the boolean parameter
+// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
+template<bool STRICT_UNWINDING>
+static void **NextStackFrame(void **old_sp) {
+ void **new_sp = (void**) old_sp[-1];
+
+ // Check that the transition from frame pointer old_sp to frame
+ // pointer new_sp isn't clearly bogus
+ if (STRICT_UNWINDING) {
+ // With the stack growing downwards, older stack frame must be
+ // at a greater address that the current one.
+ if (new_sp <= old_sp) return nullptr;
+ // Assume stack frames larger than 100,000 bytes are bogus.
+ if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return nullptr;
+ } else {
+ // In the non-strict mode, allow discontiguous stack frames.
+ // (alternate-signal-stacks for example).
+ if (new_sp == old_sp) return nullptr;
+ // And allow frames upto about 1MB.
+ if ((new_sp > old_sp)
+ && ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return nullptr;
+ }
+ if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return nullptr;
+ return new_sp;
+}
+
+// This ensures that absl::GetStackTrace sets up the Link Register properly.
+#ifdef __GNUC__
+void StacktraceArmDummyFunction() __attribute__((noinline));
+void StacktraceArmDummyFunction() { __asm__ volatile(""); }
+#else
+# error StacktraceArmDummyFunction() needs to be ported to this platform.
+#endif
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
+ const void * /* ucp */, int *min_dropped_frames) {
+#ifdef __GNUC__
+ void **sp = reinterpret_cast<void**>(__builtin_frame_address(0));
+#else
+# error reading stack point not yet supported on this platform.
+#endif
+
+ // On ARM, the return address is stored in the link register (r14).
+ // This is not saved on the stack frame of a leaf function. To
+ // simplify code that reads return addresses, we call a dummy
+ // function so that the return address of this function is also
+ // stored in the stack frame. This works at least for gcc.
+ StacktraceArmDummyFunction();
+
+ int n = 0;
+ while (sp && n < max_depth) {
+ // The absl::GetStackFrames routine is called when we are in some
+ // informational context (the failure signal handler for example).
+ // Use the non-strict unwinding rules to produce a stack trace
+ // that is as complete as possible (even if it contains a few bogus
+ // entries in some rare cases).
+ void **next_sp = NextStackFrame<!IS_STACK_FRAMES>(sp);
+
+ if (skip_count > 0) {
+ skip_count--;
+ } else {
+ result[n] = *sp;
+
+ if (IS_STACK_FRAMES) {
+ if (next_sp > sp) {
+ sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp;
+ } else {
+ // A frame-size of 0 is used to indicate unknown frame size.
+ sizes[n] = 0;
+ }
+ }
+ n++;
+ }
+ sp = next_sp;
+ }
+ if (min_dropped_frames != nullptr) {
+ // Implementation detail: we clamp the max of frames we are willing to
+ // count, so as not to spend too much time in the loop below.
+ const int kMaxUnwind = 200;
+ int j = 0;
+ for (; sp != nullptr && j < kMaxUnwind; j++) {
+ sp = NextStackFrame<!IS_STACK_FRAMES>(sp);
+ }
+ *min_dropped_frames = j;
+ }
+ return n;
+}
+
+#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_
diff --git a/absl/debugging/internal/stacktrace_config.h b/absl/debugging/internal/stacktrace_config.h
new file mode 100644
index 0000000..c0df5bb
--- /dev/null
+++ b/absl/debugging/internal/stacktrace_config.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+
+ * Defines ABSL_STACKTRACE_INL_HEADER to the *-inl.h containing
+ * actual unwinder implementation.
+ * This header is "private" to stacktrace.cc.
+ * DO NOT include it into any other files.
+*/
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
+
+// First, test platforms which only support a stub.
+#if ABSL_STACKTRACE_INL_HEADER
+#error ABSL_STACKTRACE_INL_HEADER cannot be directly set
+#elif defined(__native_client__) || defined(__APPLE__) || \
+ defined(__ANDROID__) || defined(__myriad2__) || defined(__asmjs__) || \
+ defined(__Fuchsia__) || defined(__GENCLAVE__) || \
+ defined(GOOGLE_UNSUPPORTED_OS_HERCULES)
+#define ABSL_STACKTRACE_INL_HEADER \
+ "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
+
+// Next, test for Mips and Windows.
+// TODO(marmstrong): http://b/21334018: Mips case, remove the check for
+// ABSL_STACKTRACE_INL_HEADER.
+#elif defined(__mips__) && !defined(ABSL_STACKTRACE_INL_HEADER)
+#define ABSL_STACKTRACE_INL_HEADER \
+ "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
+#elif defined(_WIN32) // windows
+#define ABSL_STACKTRACE_INL_HEADER \
+ "absl/debugging/internal/stacktrace_win32-inl.inc"
+
+// Finally, test NO_FRAME_POINTER.
+#elif !defined(NO_FRAME_POINTER)
+# if defined(__i386__) || defined(__x86_64__)
+#define ABSL_STACKTRACE_INL_HEADER \
+ "absl/debugging/internal/stacktrace_x86-inl.inc"
+# elif defined(__ppc__) || defined(__PPC__)
+#define ABSL_STACKTRACE_INL_HEADER \
+ "absl/debugging/internal/stacktrace_powerpc-inl.inc"
+# elif defined(__aarch64__)
+#define ABSL_STACKTRACE_INL_HEADER \
+ "absl/debugging/internal/stacktrace_aarch64-inl.inc"
+# elif defined(__arm__)
+#define ABSL_STACKTRACE_INL_HEADER \
+ "absl/debugging/internal/stacktrace_arm-inl.inc"
+# endif
+#else // defined(NO_FRAME_POINTER)
+# if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
+#define ABSL_STACKTRACE_INL_HEADER \
+ "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
+# elif defined(__ppc__) || defined(__PPC__)
+// Use glibc's backtrace.
+#define ABSL_STACKTRACE_INL_HEADER \
+ "absl/debugging/internal/stacktrace_generic-inl.inc"
+# elif defined(__arm__)
+# error stacktrace without frame pointer is not supported on ARM
+# endif
+#endif // NO_FRAME_POINTER
+
+#if !defined(ABSL_STACKTRACE_INL_HEADER)
+#error Not supported yet
+#endif
+
+#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
diff --git a/absl/debugging/internal/stacktrace_generic-inl.inc b/absl/debugging/internal/stacktrace_generic-inl.inc
new file mode 100644
index 0000000..de4881e
--- /dev/null
+++ b/absl/debugging/internal/stacktrace_generic-inl.inc
@@ -0,0 +1,51 @@
+// Copyright 2000 - 2007 Google Inc.
+// All rights reserved.
+//
+// Author: Sanjay Ghemawat
+//
+// Portable implementation - just use glibc
+//
+// Note: The glibc implementation may cause a call to malloc.
+// This can cause a deadlock in HeapProfiler.
+
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_
+
+#include <execinfo.h>
+#include <cstring>
+
+#include "absl/debugging/stacktrace.h"
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
+ const void *ucp, int *min_dropped_frames) {
+ static const int kStackLength = 64;
+ void * stack[kStackLength];
+ int size;
+
+ size = backtrace(stack, kStackLength);
+ skip_count++; // we want to skip the current frame as well
+ int result_count = size - skip_count;
+ if (result_count < 0)
+ result_count = 0;
+ if (result_count > max_depth)
+ result_count = max_depth;
+ for (int i = 0; i < result_count; i++)
+ result[i] = stack[i + skip_count];
+
+ if (IS_STACK_FRAMES) {
+ // No implementation for finding out the stack frame sizes yet.
+ memset(sizes, 0, sizeof(*sizes) * result_count);
+ }
+ if (min_dropped_frames != nullptr) {
+ if (size - skip_count - max_depth > 0) {
+ *min_dropped_frames = size - skip_count - max_depth;
+ } else {
+ *min_dropped_frames = 0;
+ }
+ }
+
+ return result_count;
+}
+
+#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_
diff --git a/absl/debugging/internal/stacktrace_libunwind-inl.inc b/absl/debugging/internal/stacktrace_libunwind-inl.inc
new file mode 100644
index 0000000..e9c2d26
--- /dev/null
+++ b/absl/debugging/internal/stacktrace_libunwind-inl.inc
@@ -0,0 +1,128 @@
+// 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_DEBUGGING_INTERNAL_STACKTRACE_LIBUNWIND_INL_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_LIBUNWIND_INL_H_
+
+// We only need local unwinder.
+#define UNW_LOCAL_ONLY
+
+extern "C" {
+#include "third_party/libunwind/include/libunwind.h"
+}
+#include "absl/debugging/stacktrace.h"
+
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/raw_logging.h"
+
+// Sometimes, we can try to get a stack trace from within a stack
+// trace, because we don't block signals inside libunwind (which would be too
+// expensive: the two extra system calls per stack trace do matter here).
+// That can cause a self-deadlock (as in http://b/5722312).
+// Protect against such reentrant call by failing to get a stack trace.
+//
+// We use __thread here because the code here is extremely low level -- it is
+// called while collecting stack traces from within malloc and mmap, and thus
+// can not call anything which might call malloc or mmap itself.
+// In particular, using PerThread or STATIC_THREAD_LOCAL_POD
+// here will cause infinite recursion for at least dbg/piii builds with
+// crosstool-v12.
+static __thread int recursive;
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
+ const void *, int *min_dropped_frames) {
+ if (recursive) {
+ return 0;
+ }
+ ++recursive;
+
+ int n = 0;
+ if (IS_STACK_FRAMES) {
+ void *ip;
+ unw_cursor_t cursor;
+ unw_context_t uc;
+ unw_word_t sp = 0, next_sp = 0;
+
+ unw_getcontext(&uc);
+ ABSL_RAW_CHECK(unw_init_local(&cursor, &uc) >= 0, "unw_init_local failed");
+ skip_count++; // Do not include current frame
+
+ while (skip_count--) {
+ if (unw_step(&cursor) <= 0) {
+ goto out;
+ }
+ if (unw_get_reg(&cursor, UNW_REG_SP, &next_sp)) {
+ goto out;
+ }
+ }
+
+ while (n < max_depth) {
+ if (unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t *) &ip) < 0) {
+ break;
+ }
+ sizes[n] = 0;
+ result[n++] = ip;
+ if (unw_step(&cursor) <= 0) {
+ break;
+ }
+ sp = next_sp;
+ if (unw_get_reg(&cursor, UNW_REG_SP, &next_sp) , 0) {
+ break;
+ }
+ sizes[n - 1] = next_sp - sp;
+ }
+ if (min_dropped_frames != nullptr) {
+ // Implementation detail: we clamp the max of frames we are willing to
+ // count, so as not to spend too much time in the loop below.
+ const int kMaxUnwind = 200;
+ int j = 0;
+ for (; j < kMaxUnwind; j++) {
+ if (unw_step(&cursor) < 0) {
+ break;
+ }
+ }
+ *min_dropped_frames = j;
+ }
+ } else {
+ skip_count++; // Do not include current frame.
+ void **result_all = reinterpret_cast<void**>(
+ alloca(sizeof(void*) * (max_depth + skip_count)));
+ int rc = unw_backtrace(result_all, max_depth + skip_count);
+
+ if (rc > 0) {
+ // Tell MSan that result_all has been initialized. b/34965936.
+ ANNOTATE_MEMORY_IS_INITIALIZED(result_all, rc * sizeof(void*));
+ }
+
+ if (rc > skip_count) {
+ memcpy(result, &result_all[skip_count],
+ sizeof(void*) * (rc - skip_count));
+ n = rc - skip_count;
+ } else {
+ n = 0;
+ }
+
+ if (min_dropped_frames != nullptr) {
+ // Not implemented.
+ *min_dropped_frames = 0;
+ }
+ }
+
+ out:
+ --recursive;
+ return n;
+}
+
+#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_LIBUNWIND_INL_H_
diff --git a/absl/debugging/internal/stacktrace_powerpc-inl.inc b/absl/debugging/internal/stacktrace_powerpc-inl.inc
new file mode 100644
index 0000000..0628b28
--- /dev/null
+++ b/absl/debugging/internal/stacktrace_powerpc-inl.inc
@@ -0,0 +1,234 @@
+// 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.
+//
+// Produce stack trace. I'm guessing (hoping!) the code is much like
+// for x86. For apple machines, at least, it seems to be; see
+// http://developer.apple.com/documentation/mac/runtimehtml/RTArch-59.html
+// http://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html#STACK
+// Linux has similar code: http://patchwork.ozlabs.org/linuxppc/patch?id=8882
+
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_POWERPC_INL_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_POWERPC_INL_H_
+
+#if defined(__linux__)
+#include <asm/ptrace.h> // for PT_NIP.
+#include <ucontext.h> // for ucontext_t
+#endif
+
+#include <unistd.h>
+#include <cassert>
+#include <cstdint>
+#include <cstdio>
+
+#include "absl/base/port.h"
+#include "absl/debugging/stacktrace.h"
+#include "absl/debugging/internal/address_is_readable.h"
+#include "absl/debugging/internal/vdso_support.h" // a no-op on non-elf or non-glibc systems
+
+// Given a stack pointer, return the saved link register value.
+// Note that this is the link register for a callee.
+static inline void *StacktracePowerPCGetLR(void **sp) {
+ // PowerPC has 3 main ABIs, which say where in the stack the
+ // Link Register is. For DARWIN and AIX (used by apple and
+ // linux ppc64), it's in sp[2]. For SYSV (used by linux ppc),
+ // it's in sp[1].
+#if defined(_CALL_AIX) || defined(_CALL_DARWIN)
+ return *(sp+2);
+#elif defined(_CALL_SYSV)
+ return *(sp+1);
+#elif defined(__APPLE__) || (defined(__linux__) && defined(__PPC64__))
+ // This check is in case the compiler doesn't define _CALL_AIX/etc.
+ return *(sp+2);
+#elif defined(__linux)
+ // This check is in case the compiler doesn't define _CALL_SYSV.
+ return *(sp+1);
+#else
+#error Need to specify the PPC ABI for your archiecture.
+#endif
+}
+
+// Given a pointer to a stack frame, locate and return the calling
+// stackframe, or return null if no stackframe can be found. Perform sanity
+// checks (the strictness of which is controlled by the boolean parameter
+// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
+template<bool STRICT_UNWINDING, bool IS_WITH_CONTEXT>
+ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack.
+static void **NextStackFrame(void **old_sp, const void *uc) {
+ void **new_sp = (void **) *old_sp;
+ enum { kStackAlignment = 16 };
+
+ // Check that the transition from frame pointer old_sp to frame
+ // pointer new_sp isn't clearly bogus
+ if (STRICT_UNWINDING) {
+ // With the stack growing downwards, older stack frame must be
+ // at a greater address that the current one.
+ if (new_sp <= old_sp) return nullptr;
+ // Assume stack frames larger than 100,000 bytes are bogus.
+ if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return nullptr;
+ } else {
+ // In the non-strict mode, allow discontiguous stack frames.
+ // (alternate-signal-stacks for example).
+ if (new_sp == old_sp) return nullptr;
+ // And allow frames upto about 1MB.
+ if ((new_sp > old_sp)
+ && ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return nullptr;
+ }
+ if ((uintptr_t)new_sp % kStackAlignment != 0) return nullptr;
+
+#if defined(__linux__)
+ enum StackTraceKernelSymbolStatus {
+ kNotInitialized = 0, kAddressValid, kAddressInvalid };
+
+ if (IS_WITH_CONTEXT && uc != nullptr) {
+ static StackTraceKernelSymbolStatus kernel_symbol_status =
+ kNotInitialized; // Sentinel: not computed yet.
+ // Initialize with sentinel value: __kernel_rt_sigtramp_rt64 can not
+ // possibly be there.
+ static const unsigned char *kernel_sigtramp_rt64_address = nullptr;
+ if (kernel_symbol_status == kNotInitialized) {
+ absl::debug_internal::VDSOSupport vdso;
+ if (vdso.IsPresent()) {
+ absl::debug_internal::VDSOSupport::SymbolInfo
+ sigtramp_rt64_symbol_info;
+ if (!vdso.LookupSymbol(
+ "__kernel_sigtramp_rt64", "LINUX_2.6.15",
+ absl::debug_internal::VDSOSupport::kVDSOSymbolType,
+ &sigtramp_rt64_symbol_info) ||
+ sigtramp_rt64_symbol_info.address == nullptr) {
+ // Unexpected: VDSO is present, yet the expected symbol is missing
+ // or null.
+ assert(false && "VDSO is present, but doesn't have expected symbol");
+ kernel_symbol_status = kAddressInvalid;
+ } else {
+ kernel_sigtramp_rt64_address =
+ reinterpret_cast<const unsigned char *>(
+ sigtramp_rt64_symbol_info.address);
+ kernel_symbol_status = kAddressValid;
+ }
+ } else {
+ kernel_symbol_status = kAddressInvalid;
+ }
+ }
+
+ if (new_sp != nullptr &&
+ kernel_symbol_status == kAddressValid &&
+ StacktracePowerPCGetLR(new_sp) == kernel_sigtramp_rt64_address) {
+ const ucontext_t* signal_context =
+ reinterpret_cast<const ucontext_t*>(uc);
+ void **const sp_before_signal =
+ reinterpret_cast<void**>(signal_context->uc_mcontext.gp_regs[PT_R1]);
+ // Check that alleged sp before signal is nonnull and is reasonably
+ // aligned.
+ if (sp_before_signal != nullptr &&
+ ((uintptr_t)sp_before_signal % kStackAlignment) == 0) {
+ // Check that alleged stack pointer is actually readable. This is to
+ // prevent a "double fault" in case we hit the first fault due to e.g.
+ // a stack corruption.
+ if (absl::debug_internal::AddressIsReadable(sp_before_signal)) {
+ // Alleged stack pointer is readable, use it for further unwinding.
+ new_sp = sp_before_signal;
+ }
+ }
+ }
+ }
+#endif
+
+ return new_sp;
+}
+
+// This ensures that absl::GetStackTrace sets up the Link Register properly.
+void StacktracePowerPCDummyFunction() __attribute__((noinline));
+void StacktracePowerPCDummyFunction() { __asm__ volatile(""); }
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack.
+static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
+ const void *ucp, int *min_dropped_frames) {
+ void **sp;
+ // Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther)
+ // and Darwin 8.8.1 (Tiger) use as 1.38. This means we have to use a
+ // different asm syntax. I don't know quite the best way to discriminate
+ // systems using the old as from the new one; I've gone with __APPLE__.
+#ifdef __APPLE__
+ __asm__ volatile ("mr %0,r1" : "=r" (sp));
+#else
+ __asm__ volatile ("mr %0,1" : "=r" (sp));
+#endif
+
+ // On PowerPC, the "Link Register" or "Link Record" (LR), is a stack
+ // entry that holds the return address of the subroutine call (what
+ // instruction we run after our function finishes). This is the
+ // same as the stack-pointer of our parent routine, which is what we
+ // want here. While the compiler will always(?) set up LR for
+ // subroutine calls, it may not for leaf functions (such as this one).
+ // This routine forces the compiler (at least gcc) to push it anyway.
+ StacktracePowerPCDummyFunction();
+
+ // The LR save area is used by the callee, so the top entry is bogus.
+ skip_count++;
+
+ int n = 0;
+
+ // Unlike ABIs of X86 and ARM, PowerPC ABIs say that return address (in
+ // the link register) of a function call is stored in the caller's stack
+ // frame instead of the callee's. When we look for the return address
+ // associated with a stack frame, we need to make sure that there is a
+ // caller frame before it. So we call NextStackFrame before entering the
+ // loop below and check next_sp instead of sp for loop termination.
+ // The outermost frame is set up by runtimes and it does not have a
+ // caller frame, so it is skipped.
+
+ // The absl::GetStackFrames routine is called when we are in some
+ // informational context (the failure signal handler for example).
+ // Use the non-strict unwinding rules to produce a stack trace
+ // that is as complete as possible (even if it contains a few
+ // bogus entries in some rare cases).
+ void **next_sp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(sp, ucp);
+
+ while (next_sp && n < max_depth) {
+ if (skip_count > 0) {
+ skip_count--;
+ } else {
+ result[n] = StacktracePowerPCGetLR(sp);
+ if (IS_STACK_FRAMES) {
+ if (next_sp > sp) {
+ sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp;
+ } else {
+ // A frame-size of 0 is used to indicate unknown frame size.
+ sizes[n] = 0;
+ }
+ }
+ n++;
+ }
+
+ sp = next_sp;
+ next_sp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(sp, ucp);
+ }
+
+ if (min_dropped_frames != nullptr) {
+ // Implementation detail: we clamp the max of frames we are willing to
+ // count, so as not to spend too much time in the loop below.
+ const int kMaxUnwind = 1000;
+ int j = 0;
+ for (; next_sp != nullptr && j < kMaxUnwind; j++) {
+ next_sp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(next_sp, ucp);
+ }
+ *min_dropped_frames = j;
+ }
+ return n;
+}
+
+#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_POWERPC_INL_H_
diff --git a/absl/debugging/internal/stacktrace_unimplemented-inl.inc b/absl/debugging/internal/stacktrace_unimplemented-inl.inc
new file mode 100644
index 0000000..a66be77
--- /dev/null
+++ b/absl/debugging/internal/stacktrace_unimplemented-inl.inc
@@ -0,0 +1,14 @@
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_UNIMPLEMENTED_INL_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_UNIMPLEMENTED_INL_H_
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+static int UnwindImpl(void** /* result */, int* /* sizes */,
+ int /* max_depth */, int /* skip_count */,
+ const void* /* ucp */, int *min_dropped_frames) {
+ if (min_dropped_frames != nullptr) {
+ *min_dropped_frames = 0;
+ }
+ return 0;
+}
+
+#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_UNIMPLEMENTED_INL_H_
diff --git a/absl/debugging/internal/stacktrace_win32-inl.inc b/absl/debugging/internal/stacktrace_win32-inl.inc
new file mode 100644
index 0000000..4c7f855
--- /dev/null
+++ b/absl/debugging/internal/stacktrace_win32-inl.inc
@@ -0,0 +1,75 @@
+// 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.
+//
+// Produces a stack trace for Windows. Normally, one could use
+// stacktrace_x86-inl.h or stacktrace_x86_64-inl.h -- and indeed, that
+// should work for binaries compiled using MSVC in "debug" mode.
+// However, in "release" mode, Windows uses frame-pointer
+// optimization, which makes getting a stack trace very difficult.
+//
+// There are several approaches one can take. One is to use Windows
+// intrinsics like StackWalk64. These can work, but have restrictions
+// on how successful they can be. Another attempt is to write a
+// version of stacktrace_x86-inl.h that has heuristic support for
+// dealing with FPO, similar to what WinDbg does (see
+// http://www.nynaeve.net/?p=97). There are (non-working) examples of
+// these approaches, complete with TODOs, in stacktrace_win32-inl.h#1
+//
+// The solution we've ended up doing is to call the undocumented
+// windows function RtlCaptureStackBackTrace, which probably doesn't
+// work with FPO but at least is fast, and doesn't require a symbol
+// server.
+//
+// This code is inspired by a patch from David Vitek:
+// http://code.google.com/p/google-perftools/issues/detail?id=83
+
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_
+
+#include <windows.h> // for GetProcAddress and GetModuleHandle
+#include <cassert>
+
+typedef USHORT NTAPI RtlCaptureStackBackTrace_Function(
+ IN ULONG frames_to_skip,
+ IN ULONG frames_to_capture,
+ OUT PVOID *backtrace,
+ OUT PULONG backtrace_hash);
+
+// Load the function we need at static init time, where we don't have
+// to worry about someone else holding the loader's lock.
+static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn =
+ (RtlCaptureStackBackTrace_Function*)
+ GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace");
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
+ const void *ucp, int *min_dropped_frames) {
+ int n = 0;
+ if (!RtlCaptureStackBackTrace_fn) {
+ // can't find a stacktrace with no function to call
+ } else {
+ n = (int)RtlCaptureStackBackTrace_fn(skip_count + 2, max_depth, result, 0);
+ }
+ if (IS_STACK_FRAMES) {
+ // No implementation for finding out the stack frame sizes yet.
+ memset(sizes, 0, sizeof(*sizes) * n);
+ }
+ if (min_dropped_frames != nullptr) {
+ // Not implemented.
+ *min_dropped_frames = 0;
+ }
+ return n;
+}
+
+#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_
diff --git a/absl/debugging/internal/stacktrace_x86-inl.inc b/absl/debugging/internal/stacktrace_x86-inl.inc
new file mode 100644
index 0000000..6e1af01
--- /dev/null
+++ b/absl/debugging/internal/stacktrace_x86-inl.inc
@@ -0,0 +1,327 @@
+// 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.
+//
+// Produce stack trace
+
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_X86_INL_INC_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_X86_INL_INC_
+
+#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__))
+#include <ucontext.h> // for ucontext_t
+#endif
+
+#if !defined(_WIN32)
+#include <unistd.h>
+#endif
+
+#include <cassert>
+#include <cstdint>
+
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/debugging/internal/address_is_readable.h"
+#include "absl/debugging/internal/vdso_support.h" // a no-op on non-elf or non-glibc systems
+#include "absl/debugging/stacktrace.h"
+#include "absl/base/internal/raw_logging.h"
+
+#if defined(__linux__) && defined(__i386__)
+// Count "push %reg" instructions in VDSO __kernel_vsyscall(),
+// preceeding "syscall" or "sysenter".
+// If __kernel_vsyscall uses frame pointer, answer 0.
+//
+// kMaxBytes tells how many instruction bytes of __kernel_vsyscall
+// to analyze before giving up. Up to kMaxBytes+1 bytes of
+// instructions could be accessed.
+//
+// Here are known __kernel_vsyscall instruction sequences:
+//
+// SYSENTER (linux-2.6.26/arch/x86/vdso/vdso32/sysenter.S).
+// Used on Intel.
+// 0xffffe400 <__kernel_vsyscall+0>: push %ecx
+// 0xffffe401 <__kernel_vsyscall+1>: push %edx
+// 0xffffe402 <__kernel_vsyscall+2>: push %ebp
+// 0xffffe403 <__kernel_vsyscall+3>: mov %esp,%ebp
+// 0xffffe405 <__kernel_vsyscall+5>: sysenter
+//
+// SYSCALL (see linux-2.6.26/arch/x86/vdso/vdso32/syscall.S).
+// Used on AMD.
+// 0xffffe400 <__kernel_vsyscall+0>: push %ebp
+// 0xffffe401 <__kernel_vsyscall+1>: mov %ecx,%ebp
+// 0xffffe403 <__kernel_vsyscall+3>: syscall
+//
+
+// The sequence below isn't actually expected in Google fleet,
+// here only for completeness. Remove this comment from OSS release.
+
+// i386 (see linux-2.6.26/arch/x86/vdso/vdso32/int80.S)
+// 0xffffe400 <__kernel_vsyscall+0>: int $0x80
+// 0xffffe401 <__kernel_vsyscall+1>: ret
+//
+static const int kMaxBytes = 10;
+
+// We use assert()s instead of DCHECK()s -- this is too low level
+// for DCHECK().
+
+static int CountPushInstructions(const unsigned char *const addr) {
+ int result = 0;
+ for (int i = 0; i < kMaxBytes; ++i) {
+ if (addr[i] == 0x89) {
+ // "mov reg,reg"
+ if (addr[i + 1] == 0xE5) {
+ // Found "mov %esp,%ebp".
+ return 0;
+ }
+ ++i; // Skip register encoding byte.
+ } else if (addr[i] == 0x0F &&
+ (addr[i + 1] == 0x34 || addr[i + 1] == 0x05)) {
+ // Found "sysenter" or "syscall".
+ return result;
+ } else if ((addr[i] & 0xF0) == 0x50) {
+ // Found "push %reg".
+ ++result;
+ } else if (addr[i] == 0xCD && addr[i + 1] == 0x80) {
+ // Found "int $0x80"
+ assert(result == 0);
+ return 0;
+ } else {
+ // Unexpected instruction.
+ assert(false && "unexpected instruction in __kernel_vsyscall");
+ return 0;
+ }
+ }
+ // Unexpected: didn't find SYSENTER or SYSCALL in
+ // [__kernel_vsyscall, __kernel_vsyscall + kMaxBytes) interval.
+ assert(false && "did not find SYSENTER or SYSCALL in __kernel_vsyscall");
+ return 0;
+}
+#endif
+
+// Assume stack frames larger than 100,000 bytes are bogus.
+static const int kMaxFrameBytes = 100000;
+
+// Returns the stack frame pointer from signal context, 0 if unknown.
+// vuc is a ucontext_t *. We use void* to avoid the use
+// of ucontext_t on non-POSIX systems.
+static uintptr_t GetFP(const void *vuc) {
+#if defined(__linux__)
+ if (vuc != nullptr) {
+ auto *uc = reinterpret_cast<const ucontext_t *>(vuc);
+#if defined(__i386__)
+ const auto bp = uc->uc_mcontext.gregs[REG_EBP];
+ const auto sp = uc->uc_mcontext.gregs[REG_ESP];
+#elif defined(__x86_64__)
+ const auto bp = uc->uc_mcontext.gregs[REG_RBP];
+ const auto sp = uc->uc_mcontext.gregs[REG_RSP];
+#else
+ const uintptr_t bp = 0;
+ const uintptr_t sp = 0;
+#endif
+ // Sanity-check that the base pointer is valid. It should be as long as
+ // SHRINK_WRAP_FRAME_POINTER is not set, but it's possible that some code in
+ // the process is compiled with --copt=-fomit-frame-pointer or
+ // --copt=-momit-leaf-frame-pointer.
+ //
+ // TODO(bcmills): -momit-leaf-frame-pointer is currently the default
+ // behavior when building with clang. Talk to the C++ toolchain team about
+ // fixing that.
+ if (bp >= sp && bp - sp <= kMaxFrameBytes) return bp;
+
+ // If bp isn't a plausible frame pointer, return the stack pointer instead.
+ // If we're lucky, it points to the start of a stack frame; otherwise, we'll
+ // get one frame of garbage in the stack trace and fail the sanity check on
+ // the next iteration.
+ return sp;
+ }
+#endif
+ return 0;
+}
+
+// Given a pointer to a stack frame, locate and return the calling
+// stackframe, or return null if no stackframe can be found. Perform sanity
+// checks (the strictness of which is controlled by the boolean parameter
+// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
+template <bool STRICT_UNWINDING, bool WITH_CONTEXT>
+ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack.
+static void **NextStackFrame(void **old_fp, const void *uc) {
+ void **new_fp = (void **)*old_fp;
+
+#if defined(__linux__) && defined(__i386__)
+ if (WITH_CONTEXT && uc != nullptr) {
+ // How many "push %reg" instructions are there at __kernel_vsyscall?
+ // This is constant for a given kernel and processor, so compute
+ // it only once.
+ static int num_push_instructions = -1; // Sentinel: not computed yet.
+ // Initialize with sentinel value: __kernel_rt_sigreturn can not possibly
+ // be there.
+ static const unsigned char *kernel_rt_sigreturn_address = nullptr;
+ static const unsigned char *kernel_vsyscall_address = nullptr;
+ if (num_push_instructions == -1) {
+ absl::debug_internal::VDSOSupport vdso;
+ if (vdso.IsPresent()) {
+ absl::debug_internal::VDSOSupport::SymbolInfo
+ rt_sigreturn_symbol_info;
+ absl::debug_internal::VDSOSupport::SymbolInfo vsyscall_symbol_info;
+ if (!vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.5", STT_FUNC,
+ &rt_sigreturn_symbol_info) ||
+ !vdso.LookupSymbol("__kernel_vsyscall", "LINUX_2.5", STT_FUNC,
+ &vsyscall_symbol_info) ||
+ rt_sigreturn_symbol_info.address == nullptr ||
+ vsyscall_symbol_info.address == nullptr) {
+ // Unexpected: 32-bit VDSO is present, yet one of the expected
+ // symbols is missing or null.
+ assert(false && "VDSO is present, but doesn't have expected symbols");
+ num_push_instructions = 0;
+ } else {
+ kernel_rt_sigreturn_address =
+ reinterpret_cast<const unsigned char *>(
+ rt_sigreturn_symbol_info.address);
+ kernel_vsyscall_address =
+ reinterpret_cast<const unsigned char *>(
+ vsyscall_symbol_info.address);
+ num_push_instructions =
+ CountPushInstructions(kernel_vsyscall_address);
+ }
+ } else {
+ num_push_instructions = 0;
+ }
+ }
+ if (num_push_instructions != 0 && kernel_rt_sigreturn_address != nullptr &&
+ old_fp[1] == kernel_rt_sigreturn_address) {
+ const ucontext_t *ucv = static_cast<const ucontext_t *>(uc);
+ // This kernel does not use frame pointer in its VDSO code,
+ // and so %ebp is not suitable for unwinding.
+ void **const reg_ebp =
+ reinterpret_cast<void **>(ucv->uc_mcontext.gregs[REG_EBP]);
+ const unsigned char *const reg_eip =
+ reinterpret_cast<unsigned char *>(ucv->uc_mcontext.gregs[REG_EIP]);
+ if (new_fp == reg_ebp && kernel_vsyscall_address <= reg_eip &&
+ reg_eip - kernel_vsyscall_address < kMaxBytes) {
+ // We "stepped up" to __kernel_vsyscall, but %ebp is not usable.
+ // Restore from 'ucv' instead.
+ void **const reg_esp =
+ reinterpret_cast<void **>(ucv->uc_mcontext.gregs[REG_ESP]);
+ // Check that alleged %esp is not null and is reasonably aligned.
+ if (reg_esp &&
+ ((uintptr_t)reg_esp & (sizeof(reg_esp) - 1)) == 0) {
+ // Check that alleged %esp is actually readable. This is to prevent
+ // "double fault" in case we hit the first fault due to e.g. stack
+ // corruption.
+ void *const reg_esp2 = reg_esp[num_push_instructions - 1];
+ if (absl::debug_internal::AddressIsReadable(reg_esp2)) {
+ // Alleged %esp is readable, use it for further unwinding.
+ new_fp = reinterpret_cast<void **>(reg_esp2);
+ }
+ }
+ }
+ }
+ }
+#endif
+
+ const uintptr_t old_fp_u = reinterpret_cast<uintptr_t>(old_fp);
+ const uintptr_t new_fp_u = reinterpret_cast<uintptr_t>(new_fp);
+
+ // Check that the transition from frame pointer old_fp to frame
+ // pointer new_fp isn't clearly bogus. Skip the checks if new_fp
+ // matches the signal context, so that we don't skip out early when
+ // using an alternate signal stack.
+ //
+ // TODO(bcmills): The GetFP call should be completely unnecessary when
+ // SHRINK_WRAP_FRAME_POINTER is set (because we should be back in the thread's
+ // stack by this point), but it is empirically still needed (e.g. when the
+ // stack includes a call to abort). unw_get_reg returns UNW_EBADREG for some
+ // frames. Figure out why GetValidFrameAddr and/or libunwind isn't doing what
+ // it's supposed to.
+ if (STRICT_UNWINDING &&
+ (!WITH_CONTEXT || uc == nullptr || new_fp_u != GetFP(uc))) {
+ // With the stack growing downwards, older stack frame must be
+ // at a greater address that the current one.
+ if (new_fp_u <= old_fp_u) return nullptr;
+ if (new_fp_u - old_fp_u > kMaxFrameBytes) return nullptr;
+ } else {
+ if (new_fp == nullptr) return nullptr; // skip AddressIsReadable() below
+ // In the non-strict mode, allow discontiguous stack frames.
+ // (alternate-signal-stacks for example).
+ if (new_fp == old_fp) return nullptr;
+ }
+
+ if (new_fp_u & (sizeof(void *) - 1)) return nullptr;
+#ifdef __i386__
+ // On 32-bit machines, the stack pointer can be very close to
+ // 0xffffffff, so we explicitly check for a pointer into the
+ // last two pages in the address space
+ if (new_fp_u >= 0xffffe000) return nullptr;
+#endif
+#if !defined(_WIN32)
+ if (!STRICT_UNWINDING) {
+ // Lax sanity checks cause a crash in 32-bit tcmalloc/crash_reason_test
+ // on AMD-based machines with VDSO-enabled kernels.
+ // Make an extra sanity check to insure new_fp is readable.
+ // Note: NextStackFrame<false>() is only called while the program
+ // is already on its last leg, so it's ok to be slow here.
+
+ if (!absl::debug_internal::AddressIsReadable(new_fp)) {
+ return nullptr;
+ }
+ }
+#endif
+ return new_fp;
+}
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack.
+ABSL_ATTRIBUTE_NOINLINE
+static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count,
+ const void *ucp, int *min_dropped_frames) {
+ int n = 0;
+ void **fp = reinterpret_cast<void **>(__builtin_frame_address(0));
+
+ while (fp && n < max_depth) {
+ if (*(fp + 1) == reinterpret_cast<void *>(0)) {
+ // In 64-bit code, we often see a frame that
+ // points to itself and has a return address of 0.
+ break;
+ }
+ void **next_fp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(fp, ucp);
+ if (skip_count > 0) {
+ skip_count--;
+ } else {
+ result[n] = *(fp + 1);
+ if (IS_STACK_FRAMES) {
+ if (next_fp > fp) {
+ sizes[n] = (uintptr_t)next_fp - (uintptr_t)fp;
+ } else {
+ // A frame-size of 0 is used to indicate unknown frame size.
+ sizes[n] = 0;
+ }
+ }
+ n++;
+ }
+ fp = next_fp;
+ }
+ if (min_dropped_frames != nullptr) {
+ // Implementation detail: we clamp the max of frames we are willing to
+ // count, so as not to spend too much time in the loop below.
+ const int kMaxUnwind = 1000;
+ int j = 0;
+ for (; fp != nullptr && j < kMaxUnwind; j++) {
+ fp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(fp, ucp);
+ }
+ *min_dropped_frames = j;
+ }
+ return n;
+}
+
+#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_X86_INL_INC_
diff --git a/absl/debugging/internal/vdso_support.cc b/absl/debugging/internal/vdso_support.cc
new file mode 100644
index 0000000..5026e1c
--- /dev/null
+++ b/absl/debugging/internal/vdso_support.cc
@@ -0,0 +1,177 @@
+// 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.
+
+// Allow dynamic symbol lookup in the kernel VDSO page.
+//
+// VDSOSupport -- a class representing kernel VDSO (if present).
+
+#include "absl/debugging/internal/vdso_support.h"
+
+#ifdef ABSL_HAVE_VDSO_SUPPORT // defined in vdso_support.h
+
+#include <fcntl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/port.h"
+
+#ifndef AT_SYSINFO_EHDR
+#define AT_SYSINFO_EHDR 33 // for crosstoolv10
+#endif
+
+namespace absl {
+namespace debug_internal {
+
+std::atomic<const void *> VDSOSupport::vdso_base_(
+ debug_internal::ElfMemImage::kInvalidBase);
+std::atomic<VDSOSupport::GetCpuFn> VDSOSupport::getcpu_fn_(&InitAndGetCPU);
+VDSOSupport::VDSOSupport()
+ // If vdso_base_ is still set to kInvalidBase, we got here
+ // before VDSOSupport::Init has been called. Call it now.
+ : image_(vdso_base_.load(std::memory_order_relaxed) ==
+ debug_internal::ElfMemImage::kInvalidBase
+ ? Init()
+ : vdso_base_.load(std::memory_order_relaxed)) {}
+
+// NOTE: we can't use GoogleOnceInit() below, because we can be
+// called by tcmalloc, and none of the *once* stuff may be functional yet.
+//
+// In addition, we hope that the VDSOSupportHelper constructor
+// causes this code to run before there are any threads, and before
+// InitGoogle() has executed any chroot or setuid calls.
+//
+// Finally, even if there is a race here, it is harmless, because
+// the operation should be idempotent.
+const void *VDSOSupport::Init() {
+ if (vdso_base_.load(std::memory_order_relaxed) ==
+ debug_internal::ElfMemImage::kInvalidBase) {
+ {
+ // Valgrind zaps AT_SYSINFO_EHDR and friends from the auxv[]
+ // on stack, and so glibc works as if VDSO was not present.
+ // But going directly to kernel via /proc/self/auxv below bypasses
+ // Valgrind zapping. So we check for Valgrind separately.
+ if (RunningOnValgrind()) {
+ vdso_base_.store(nullptr, std::memory_order_relaxed);
+ getcpu_fn_.store(&GetCPUViaSyscall, std::memory_order_relaxed);
+ return nullptr;
+ }
+ int fd = open("/proc/self/auxv", O_RDONLY);
+ if (fd == -1) {
+ // Kernel too old to have a VDSO.
+ vdso_base_.store(nullptr, std::memory_order_relaxed);
+ getcpu_fn_.store(&GetCPUViaSyscall, std::memory_order_relaxed);
+ return nullptr;
+ }
+ ElfW(auxv_t) aux;
+ while (read(fd, &aux, sizeof(aux)) == sizeof(aux)) {
+ if (aux.a_type == AT_SYSINFO_EHDR) {
+ vdso_base_.store(reinterpret_cast<void *>(aux.a_un.a_val),
+ std::memory_order_relaxed);
+ break;
+ }
+ }
+ close(fd);
+ }
+ if (vdso_base_.load(std::memory_order_relaxed) ==
+ debug_internal::ElfMemImage::kInvalidBase) {
+ // Didn't find AT_SYSINFO_EHDR in auxv[].
+ vdso_base_.store(nullptr, std::memory_order_relaxed);
+ }
+ }
+ GetCpuFn fn = &GetCPUViaSyscall; // default if VDSO not present.
+ if (vdso_base_.load(std::memory_order_relaxed)) {
+ VDSOSupport vdso;
+ SymbolInfo info;
+ if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) {
+ fn = reinterpret_cast<GetCpuFn>(const_cast<void *>(info.address));
+ }
+ }
+ // Subtle: this code runs outside of any locks; prevent compiler
+ // from assigning to getcpu_fn_ more than once.
+ getcpu_fn_.store(fn, std::memory_order_relaxed);
+ return vdso_base_.load(std::memory_order_relaxed);
+}
+
+const void *VDSOSupport::SetBase(const void *base) {
+ ABSL_RAW_CHECK(base != debug_internal::ElfMemImage::kInvalidBase,
+ "internal error");
+ const void *old_base = vdso_base_.load(std::memory_order_relaxed);
+ vdso_base_.store(base, std::memory_order_relaxed);
+ image_.Init(base);
+ // Also reset getcpu_fn_, so GetCPU could be tested with simulated VDSO.
+ getcpu_fn_.store(&InitAndGetCPU, std::memory_order_relaxed);
+ return old_base;
+}
+
+bool VDSOSupport::LookupSymbol(const char *name,
+ const char *version,
+ int type,
+ SymbolInfo *info) const {
+ return image_.LookupSymbol(name, version, type, info);
+}
+
+bool VDSOSupport::LookupSymbolByAddress(const void *address,
+ SymbolInfo *info_out) const {
+ return image_.LookupSymbolByAddress(address, info_out);
+}
+
+// NOLINT on 'long' because this routine mimics kernel api.
+long VDSOSupport::GetCPUViaSyscall(unsigned *cpu, // NOLINT(runtime/int)
+ void *, void *) {
+#ifdef SYS_getcpu
+ return syscall(SYS_getcpu, cpu, nullptr, nullptr);
+#else
+ // x86_64 never implemented sys_getcpu(), except as a VDSO call.
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+// Use fast __vdso_getcpu if available.
+long VDSOSupport::InitAndGetCPU(unsigned *cpu, // NOLINT(runtime/int)
+ void *x, void *y) {
+ Init();
+ GetCpuFn fn = getcpu_fn_.load(std::memory_order_relaxed);
+ ABSL_RAW_CHECK(fn != &InitAndGetCPU, "Init() did not set getcpu_fn_");
+ return (*fn)(cpu, x, y);
+}
+
+// This function must be very fast, and may be called from very
+// low level (e.g. tcmalloc). Hence I avoid things like
+// GoogleOnceInit() and ::operator new.
+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
+int GetCPU() {
+ unsigned cpu;
+ int ret_code = (*VDSOSupport::getcpu_fn_)(&cpu, nullptr, nullptr);
+ return ret_code == 0 ? cpu : ret_code;
+}
+
+// We need to make sure VDSOSupport::Init() is called before
+// InitGoogle() does any setuid or chroot calls. If VDSOSupport
+// is used in any global constructor, this will happen, since
+// VDSOSupport's constructor calls Init. But if not, we need to
+// ensure it here, with a global constructor of our own. This
+// is an allowed exception to the normal rule against non-trivial
+// global constructors.
+static class VDSOInitHelper {
+ public:
+ VDSOInitHelper() { VDSOSupport::Init(); }
+} vdso_init_helper;
+
+} // namespace debug_internal
+} // namespace absl
+
+#endif // ABSL_HAVE_VDSO_SUPPORT
diff --git a/absl/debugging/internal/vdso_support.h b/absl/debugging/internal/vdso_support.h
new file mode 100644
index 0000000..a6a7a17
--- /dev/null
+++ b/absl/debugging/internal/vdso_support.h
@@ -0,0 +1,155 @@
+//
+// 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.
+//
+
+// Allow dynamic symbol lookup in the kernel VDSO page.
+//
+// VDSO stands for "Virtual Dynamic Shared Object" -- a page of
+// executable code, which looks like a shared library, but doesn't
+// necessarily exist anywhere on disk, and which gets mmap()ed into
+// every process by kernels which support VDSO, such as 2.6.x for 32-bit
+// executables, and 2.6.24 and above for 64-bit executables.
+//
+// More details could be found here:
+// http://www.trilithium.com/johan/2005/08/linux-gate/
+//
+// VDSOSupport -- a class representing kernel VDSO (if present).
+//
+// Example usage:
+// VDSOSupport vdso;
+// VDSOSupport::SymbolInfo info;
+// typedef (*FN)(unsigned *, void *, void *);
+// FN fn = nullptr;
+// if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) {
+// fn = reinterpret_cast<FN>(info.address);
+// }
+
+#ifndef ABSL_DEBUGGING_INTERNAL_VDSO_SUPPORT_H_
+#define ABSL_DEBUGGING_INTERNAL_VDSO_SUPPORT_H_
+
+#include <atomic>
+
+#include "absl/debugging/internal/elf_mem_image.h"
+
+#ifdef ABSL_HAVE_ELF_MEM_IMAGE
+
+#ifdef ABSL_HAVE_VDSO_SUPPORT
+#error ABSL_HAVE_VDSO_SUPPORT cannot be directly set
+#else
+#define ABSL_HAVE_VDSO_SUPPORT 1
+#endif
+
+namespace absl {
+namespace debug_internal {
+
+// NOTE: this class may be used from within tcmalloc, and can not
+// use any memory allocation routines.
+class VDSOSupport {
+ public:
+ VDSOSupport();
+
+ typedef ElfMemImage::SymbolInfo SymbolInfo;
+ typedef ElfMemImage::SymbolIterator SymbolIterator;
+
+ // On PowerPC64 VDSO symbols can either be of type STT_FUNC or STT_NOTYPE
+ // depending on how the kernel is built. The kernel is normally built with
+ // STT_NOTYPE type VDSO symbols. Let's make things simpler first by using a
+ // compile-time constant.
+#ifdef __powerpc64__
+ enum { kVDSOSymbolType = STT_NOTYPE };
+#else
+ enum { kVDSOSymbolType = STT_FUNC };
+#endif
+
+ // Answers whether we have a vdso at all.
+ bool IsPresent() const { return image_.IsPresent(); }
+
+ // Allow to iterate over all VDSO symbols.
+ SymbolIterator begin() const { return image_.begin(); }
+ SymbolIterator end() const { return image_.end(); }
+
+ // Look up versioned dynamic symbol in the kernel VDSO.
+ // Returns false if VDSO is not present, or doesn't contain given
+ // symbol/version/type combination.
+ // If info_out != nullptr, additional details are filled in.
+ bool LookupSymbol(const char *name, const char *version,
+ int symbol_type, SymbolInfo *info_out) const;
+
+ // Find info about symbol (if any) which overlaps given address.
+ // Returns true if symbol was found; false if VDSO isn't present
+ // or doesn't have a symbol overlapping given address.
+ // If info_out != nullptr, additional details are filled in.
+ bool LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const;
+
+ // Used only for testing. Replace real VDSO base with a mock.
+ // Returns previous value of vdso_base_. After you are done testing,
+ // you are expected to call SetBase() with previous value, in order to
+ // reset state to the way it was.
+ const void *SetBase(const void *s);
+
+ // Computes vdso_base_ and returns it. Should be called as early as
+ // possible; before any thread creation, chroot or setuid.
+ static const void *Init();
+
+ private:
+ // image_ represents VDSO ELF image in memory.
+ // image_.ehdr_ == nullptr implies there is no VDSO.
+ ElfMemImage image_;
+
+ // Cached value of auxv AT_SYSINFO_EHDR, computed once.
+ // This is a tri-state:
+ // kInvalidBase => value hasn't been determined yet.
+ // 0 => there is no VDSO.
+ // else => vma of VDSO Elf{32,64}_Ehdr.
+ //
+ // When testing with mock VDSO, low bit is set.
+ // The low bit is always available because vdso_base_ is
+ // page-aligned.
+ static std::atomic<const void *> vdso_base_;
+
+ // NOLINT on 'long' because these routines mimic kernel api.
+ // The 'cache' parameter may be used by some versions of the kernel,
+ // and should be nullptr or point to a static buffer containing at
+ // least two 'long's.
+ static long InitAndGetCPU(unsigned *cpu, void *cache, // NOLINT 'long'.
+ void *unused);
+ static long GetCPUViaSyscall(unsigned *cpu, void *cache, // NOLINT 'long'.
+ void *unused);
+ typedef long (*GetCpuFn)(unsigned *cpu, void *cache, // NOLINT 'long'.
+ void *unused);
+
+ // This function pointer may point to InitAndGetCPU,
+ // GetCPUViaSyscall, or __vdso_getcpu at different stages of initialization.
+ static std::atomic<GetCpuFn> getcpu_fn_;
+
+ friend int GetCPU(void); // Needs access to getcpu_fn_.
+
+ VDSOSupport(const VDSOSupport&) = delete;
+ VDSOSupport& operator=(const VDSOSupport&) = delete;
+};
+
+// Same as sched_getcpu() on later glibc versions.
+// Return current CPU, using (fast) __vdso_getcpu@LINUX_2.6 if present,
+// otherwise use syscall(SYS_getcpu,...).
+// May return -1 with errno == ENOSYS if the kernel doesn't
+// support SYS_getcpu.
+int GetCPU();
+
+} // namespace debug_internal
+} // namespace absl
+
+#endif // ABSL_HAVE_ELF_MEM_IMAGE
+
+#endif // ABSL_DEBUGGING_INTERNAL_VDSO_SUPPORT_H_
diff --git a/absl/debugging/leak_check.cc b/absl/debugging/leak_check.cc
new file mode 100644
index 0000000..30e7e8a
--- /dev/null
+++ b/absl/debugging/leak_check.cc
@@ -0,0 +1,35 @@
+// Wrappers around lsan_interface functions.
+// When lsan is not linked in, these functions are not available,
+// therefore Abseil code which depends on these functions is conditioned on the
+// definition of LEAK_SANITIZER.
+#include "absl/debugging/leak_check.h"
+
+#ifndef LEAK_SANITIZER
+
+namespace absl {
+bool HaveLeakSanitizer() { return false; }
+void DoIgnoreLeak(const void*) { }
+void RegisterLivePointers(const void*, size_t) { }
+void UnRegisterLivePointers(const void*, size_t) { }
+LeakCheckDisabler::LeakCheckDisabler() { }
+LeakCheckDisabler::~LeakCheckDisabler() { }
+} // namespace absl
+
+#else
+
+#include <sanitizer/lsan_interface.h>
+
+namespace absl {
+bool HaveLeakSanitizer() { return true; }
+void DoIgnoreLeak(const void* ptr) { __lsan_ignore_object(ptr); }
+void RegisterLivePointers(const void* ptr, size_t size) {
+ __lsan_register_root_region(ptr, size);
+}
+void UnRegisterLivePointers(const void* ptr, size_t size) {
+ __lsan_unregister_root_region(ptr, size);
+}
+LeakCheckDisabler::LeakCheckDisabler() { __lsan_disable(); }
+LeakCheckDisabler::~LeakCheckDisabler() { __lsan_enable(); }
+} // namespace absl
+
+#endif // LEAK_SANITIZER
diff --git a/absl/debugging/leak_check.h b/absl/debugging/leak_check.h
new file mode 100644
index 0000000..f67fe88
--- /dev/null
+++ b/absl/debugging/leak_check.h
@@ -0,0 +1,111 @@
+//
+// 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: leak_check.h
+// -----------------------------------------------------------------------------
+//
+// This package contains functions that affect leak checking behavior within
+// targets built with the LeakSanitizer (LSan), a memory leak detector that is
+// integrated within the AddressSanitizer (ASan) as an additional component, or
+// which can be used standalone. LSan and ASan are included or can be provided
+// as additional components for most compilers such as Clang, gcc and MSVC.
+// Note: this leak checking API is not yet supported in MSVC.
+// Leak checking is enabled by default in all ASan builds.
+//
+// See https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer
+//
+// -----------------------------------------------------------------------------
+#ifndef ABSL_DEBUGGING_LEAK_CHECK_H_
+#define ABSL_DEBUGGING_LEAK_CHECK_H_
+
+#include <cstddef>
+
+namespace absl {
+
+// HaveLeakSanitizer()
+//
+// Returns true if a leak-checking sanitizer (either ASan or standalone LSan) is
+// currently built into this target.
+bool HaveLeakSanitizer();
+
+// DoIgnoreLeak()
+//
+// Implements `IgnoreLeak()` below. This function should usually
+// not be called directly; calling `IgnoreLeak()` is preferred.
+void DoIgnoreLeak(const void* ptr);
+
+// IgnoreLeak()
+//
+// Instruct the leak sanitizer to ignore leak warnings on the object referenced
+// by the passed pointer, as well as all heap objects transitively referenced
+// by it. The passed object pointer can point to either the beginning of the
+// object or anywhere within it.
+//
+// Example:
+//
+// static T* obj = IgnoreLeak(new T(...));
+//
+// If the passed `ptr` does not point to an actively allocated object at the
+// time `IgnoreLeak()` is called, the call is a no-op; if it is actively
+// allocated, the object must not get deallocated later.
+//
+template <typename T>
+T* IgnoreLeak(T* ptr) {
+ DoIgnoreLeak(ptr);
+ return ptr;
+}
+
+// LeakCheckDisabler
+//
+// This helper class indicates that any heap allocations done in the code block
+// covered by the scoped object, which should be allocated on the stack, will
+// not be reported as leaks. Leak check disabling will occur within the code
+// block and any nested function calls within the code block.
+//
+// Example:
+//
+// void Foo() {
+// LeakCheckDisabler disabler;
+// ... code that allocates objects whose leaks should be ignored ...
+// }
+//
+// REQUIRES: Destructor runs in same thread as constructor
+class LeakCheckDisabler {
+ public:
+ LeakCheckDisabler();
+ LeakCheckDisabler(const LeakCheckDisabler&) = delete;
+ LeakCheckDisabler& operator=(const LeakCheckDisabler&) = delete;
+ ~LeakCheckDisabler();
+};
+
+// RegisterLivePointers()
+//
+// Registers `ptr[0,size-1]` as pointers to memory that is still actively being
+// referenced and for which leak checking should be ignored. This function is
+// useful if you store pointers in mapped memory, for memory ranges that we know
+// are correct but for which normal analysis would flag as leaked code.
+void RegisterLivePointers(const void* ptr, size_t size);
+
+// UnRegisterLivePointers()
+//
+// Deregisters the pointers previously marked as active in
+// `RegisterLivePointers()`, enabling leak checking of those pointers.
+void UnRegisterLivePointers(const void* ptr, size_t size);
+
+} // namespace absl
+
+#endif // ABSL_DEBUGGING_LEAK_CHECK_H_
diff --git a/absl/debugging/leak_check_disable.cc b/absl/debugging/leak_check_disable.cc
new file mode 100644
index 0000000..df22c1c
--- /dev/null
+++ b/absl/debugging/leak_check_disable.cc
@@ -0,0 +1,20 @@
+// 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.
+
+// Disable LeakSanitizer when this file is linked in.
+// This function overrides __lsan_is_turned_off from sanitizer/lsan_interface.h
+extern "C" int __lsan_is_turned_off();
+extern "C" int __lsan_is_turned_off() {
+ return 1;
+}
diff --git a/absl/debugging/leak_check_fail_test.cc b/absl/debugging/leak_check_fail_test.cc
new file mode 100644
index 0000000..bf541fe
--- /dev/null
+++ b/absl/debugging/leak_check_fail_test.cc
@@ -0,0 +1,41 @@
+// 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 <memory>
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/debugging/leak_check.h"
+
+namespace {
+
+TEST(LeakCheckTest, LeakMemory) {
+ // This test is expected to cause lsan failures on program exit. Therefore the
+ // test will be run only by leak_check_test.sh, which will verify a
+ // failed exit code.
+
+ char* foo = strdup("lsan should complain about this leaked string");
+ ABSL_RAW_LOG(INFO, "Should detect leaked std::string %s", foo);
+}
+
+TEST(LeakCheckTest, LeakMemoryAfterDisablerScope) {
+ // This test is expected to cause lsan failures on program exit. Therefore the
+ // test will be run only by external_leak_check_test.sh, which will verify a
+ // failed exit code.
+ { absl::LeakCheckDisabler disabler; }
+ char* foo = strdup("lsan should also complain about this leaked string");
+ ABSL_RAW_LOG(INFO, "Re-enabled leak detection.Should detect leaked std::string %s",
+ foo);
+}
+
+} // namespace
diff --git a/absl/debugging/leak_check_test.cc b/absl/debugging/leak_check_test.cc
new file mode 100644
index 0000000..27ca2d1
--- /dev/null
+++ b/absl/debugging/leak_check_test.cc
@@ -0,0 +1,41 @@
+// 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 <memory>
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/debugging/leak_check.h"
+
+namespace {
+
+TEST(LeakCheckTest, DetectLeakSanitizer) {
+#ifdef ABSL_EXPECT_LEAK_SANITIZER
+ EXPECT_TRUE(absl::HaveLeakSanitizer());
+#else
+ EXPECT_FALSE(absl::HaveLeakSanitizer());
+#endif
+}
+
+TEST(LeakCheckTest, IgnoreLeakSuppressesLeakedMemoryErrors) {
+ auto foo = absl::IgnoreLeak(new std::string("some ignored leaked string"));
+ ABSL_RAW_LOG(INFO, "Ignoring leaked std::string %s", foo->c_str());
+}
+
+TEST(LeakCheckTest, LeakCheckDisablerIgnoresLeak) {
+ absl::LeakCheckDisabler disabler;
+ auto foo = new std::string("some std::string leaked while checks are disabled");
+ ABSL_RAW_LOG(INFO, "Ignoring leaked std::string %s", foo->c_str());
+}
+
+} // namespace
diff --git a/absl/debugging/stacktrace.cc b/absl/debugging/stacktrace.cc
new file mode 100644
index 0000000..6c16904
--- /dev/null
+++ b/absl/debugging/stacktrace.cc
@@ -0,0 +1,133 @@
+// 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.
+
+// Produce stack trace.
+//
+// There are three different ways we can try to get the stack trace:
+//
+// 1) Our hand-coded stack-unwinder. This depends on a certain stack
+// layout, which is used by gcc (and those systems using a
+// gcc-compatible ABI) on x86 systems, at least since gcc 2.95.
+// It uses the frame pointer to do its work.
+//
+// 2) The libunwind library. This is still in development, and as a
+// separate library adds a new dependency, but doesn't need a frame
+// pointer. It also doesn't call malloc.
+//
+// 3) The gdb unwinder -- also the one used by the c++ exception code.
+// It's obviously well-tested, but has a fatal flaw: it can call
+// malloc() from the unwinder. This is a problem because we're
+// trying to use the unwinder to instrument malloc().
+//
+// Note: if you add a new implementation here, make sure it works
+// correctly when absl::GetStackTrace() is called with max_depth == 0.
+// Some code may do that.
+
+#include "absl/debugging/stacktrace.h"
+
+#include <atomic>
+
+#include "absl/base/port.h"
+#include "absl/debugging/internal/stacktrace_config.h"
+
+#if defined(ABSL_STACKTRACE_INL_HEADER)
+#include ABSL_STACKTRACE_INL_HEADER
+#else
+# error Cannot calculate stack trace: will need to write for your environment
+# include "absl/debugging/internal/stacktrace_x86-inl.inc"
+# include "absl/debugging/internal/stacktrace_win32-inl.inc"
+# include "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
+# include "absl/debugging/internal/stacktrace_libunwind-inl.inc"
+# include "absl/debugging/internal/stacktrace_generic-inl.inc"
+# include "absl/debugging/internal/stacktrace_powerpc-inl.inc"
+# include "absl/debugging/internal/stacktrace_arm-inl.inc"
+# include "absl/debugging/internal/stacktrace_aarch64-inl.inc"
+#endif
+
+namespace absl {
+namespace {
+
+typedef int (*Unwinder)(void**, int*, int, int, const void*, int*);
+std::atomic<Unwinder> custom;
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Unwind(void** result, int* sizes,
+ int max_depth, int skip_count,
+ const void* uc,
+ int* min_dropped_frames) {
+ Unwinder f = &UnwindImpl<IS_STACK_FRAMES, IS_WITH_CONTEXT>;
+ Unwinder g = custom.load(std::memory_order_acquire);
+ if (g != nullptr) f = g;
+
+ // Add 1 to skip count for the unwinder function itself
+ int size = (*f)(result, sizes, max_depth, skip_count + 1, uc,
+ min_dropped_frames);
+ // To disable tail call to (*f)(...)
+ ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
+ return size;
+}
+
+} // anonymous namespace
+
+int GetStackFrames(void** result, int* sizes, int max_depth, int skip_count) {
+ return Unwind<true, false>(result, sizes, max_depth, skip_count, nullptr,
+ nullptr);
+}
+
+int GetStackFramesWithContext(void** result, int* sizes, int max_depth,
+ int skip_count, const void* uc,
+ int* min_dropped_frames) {
+ return Unwind<true, true>(result, sizes, max_depth, skip_count, uc,
+ min_dropped_frames);
+}
+
+int GetStackTrace(void** result, int max_depth, int skip_count) {
+ return Unwind<false, false>(result, nullptr, max_depth, skip_count, nullptr,
+ nullptr);
+}
+
+int GetStackTraceWithContext(void** result, int max_depth, int skip_count,
+ const void* uc, int* min_dropped_frames) {
+ return Unwind<false, true>(result, nullptr, max_depth, skip_count, uc,
+ min_dropped_frames);
+}
+
+void SetStackUnwinder(Unwinder w) {
+ custom.store(w, std::memory_order_release);
+}
+
+int DefaultStackUnwinder(void** pcs, int* sizes, int depth, int skip,
+ const void* uc, int* min_dropped_frames) {
+ skip++; // For this function
+ Unwinder f = nullptr;
+ if (sizes == nullptr) {
+ if (uc == nullptr) {
+ f = &UnwindImpl<false, false>;
+ } else {
+ f = &UnwindImpl<false, true>;
+ }
+ } else {
+ if (uc == nullptr) {
+ f = &UnwindImpl<true, false>;
+ } else {
+ f = &UnwindImpl<true, true>;
+ }
+ }
+ volatile int x = 0;
+ int n = (*f)(pcs, sizes, depth, skip, uc, min_dropped_frames);
+ x = 1; (void) x; // To disable tail call to (*f)(...)
+ return n;
+}
+
+} // namespace absl
diff --git a/absl/debugging/stacktrace.h b/absl/debugging/stacktrace.h
new file mode 100644
index 0000000..0aab574
--- /dev/null
+++ b/absl/debugging/stacktrace.h
@@ -0,0 +1,160 @@
+//
+// 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.
+//
+
+// Routines to extract the current stack trace. These functions are
+// thread-safe and async-signal-safe.
+// Note that stack trace functionality is platform dependent and requires
+// additional support from the compiler/build system in many cases. (That is,
+// this generally only works on platforms/builds that have been specifically
+// configured to support it.)
+
+#ifndef ABSL_DEBUGGING_STACKTRACE_H_
+#define ABSL_DEBUGGING_STACKTRACE_H_
+
+namespace absl {
+
+// Skips the most recent "skip_count" stack frames (also skips the
+// frame generated for the "absl::GetStackFrames" routine itself), and then
+// records the pc values for up to the next "max_depth" frames in
+// "result", and the corresponding stack frame sizes in "sizes".
+// Returns the number of values recorded in "result"/"sizes".
+//
+// Example:
+// main() { foo(); }
+// foo() { bar(); }
+// bar() {
+// void* result[10];
+// int sizes[10];
+// int depth = absl::GetStackFrames(result, sizes, 10, 1);
+// }
+//
+// The absl::GetStackFrames call will skip the frame for "bar". It will
+// return 2 and will produce pc values that map to the following
+// procedures:
+// result[0] foo
+// result[1] main
+// (Actually, there may be a few more entries after "main" to account for
+// startup procedures.)
+// And corresponding stack frame sizes will also be recorded:
+// sizes[0] 16
+// sizes[1] 16
+// (Stack frame sizes of 16 above are just for illustration purposes.)
+// Stack frame sizes of 0 or less indicate that those frame sizes couldn't
+// be identified.
+//
+// This routine may return fewer stack frame entries than are
+// available. Also note that "result" and "sizes" must both be non-null.
+extern int GetStackFrames(void** result, int* sizes, int max_depth,
+ int skip_count);
+
+// Same as above, but to be used from a signal handler. The "uc" parameter
+// should be the pointer to ucontext_t which was passed as the 3rd parameter
+// to sa_sigaction signal handler. It may help the unwinder to get a
+// better stack trace under certain conditions. The "uc" may safely be null.
+//
+// If min_dropped_frames is not null, stores in *min_dropped_frames a
+// lower bound on the number of dropped stack frames. The stored value is
+// guaranteed to be >= 0. The number of real stack frames is guaranteed to
+// be >= skip_count + max_depth + *min_dropped_frames.
+extern int GetStackFramesWithContext(void** result, int* sizes, int max_depth,
+ int skip_count, const void* uc,
+ int* min_dropped_frames);
+
+// This is similar to the absl::GetStackFrames routine, except that it returns
+// the stack trace only, and not the stack frame sizes as well.
+// Example:
+// main() { foo(); }
+// foo() { bar(); }
+// bar() {
+// void* result[10];
+// int depth = absl::GetStackTrace(result, 10, 1);
+// }
+//
+// This produces:
+// result[0] foo
+// result[1] main
+// .... ...
+//
+// "result" must not be null.
+extern int GetStackTrace(void** result, int max_depth, int skip_count);
+
+// Same as above, but to be used from a signal handler. The "uc" parameter
+// should be the pointer to ucontext_t which was passed as the 3rd parameter
+// to sa_sigaction signal handler. It may help the unwinder to get a
+// better stack trace under certain conditions. The "uc" may safely be null.
+//
+// If min_dropped_frames is not null, stores in *min_dropped_frames a
+// lower bound on the number of dropped stack frames. The stored value is
+// guaranteed to be >= 0. The number of real stack frames is guaranteed to
+// be >= skip_count + max_depth + *min_dropped_frames.
+extern int GetStackTraceWithContext(void** result, int max_depth,
+ int skip_count, const void* uc,
+ int* min_dropped_frames);
+
+// Call this to provide a custom function for unwinding stack frames
+// that will be used every time someone invokes one of the static
+// GetStack{Frames,Trace}{,WithContext}() functions above.
+//
+// The arguments passed to the unwinder function will match the
+// arguments passed to absl::GetStackFramesWithContext() except that sizes
+// will be non-null iff the caller is interested in frame sizes.
+//
+// If unwinder is null, we revert to the default stack-tracing behavior.
+//
+// ****************************************************************
+// WARNINGS
+//
+// absl::SetStackUnwinder is not suitable for general purpose use. It is
+// provided for custom runtimes.
+// Some things to watch out for when calling absl::SetStackUnwinder:
+//
+// (a) The unwinder may be called from within signal handlers and
+// therefore must be async-signal-safe.
+//
+// (b) Even after a custom stack unwinder has been unregistered, other
+// threads may still be in the process of using that unwinder.
+// Therefore do not clean up any state that may be needed by an old
+// unwinder.
+// ****************************************************************
+extern void SetStackUnwinder(int (*unwinder)(void** pcs, int* sizes,
+ int max_depth, int skip_count,
+ const void* uc,
+ int* min_dropped_frames));
+
+// Function that exposes built-in stack-unwinding behavior, ignoring
+// any calls to absl::SetStackUnwinder().
+//
+// pcs must NOT be null.
+//
+// sizes may be null.
+// uc may be null.
+// min_dropped_frames may be null.
+//
+// The semantics are the same as the corresponding GetStack*() function in the
+// case where absl::SetStackUnwinder() was never called. Equivalents are:
+//
+// null sizes | non-nullptr sizes
+// |==========================================================|
+// null uc | GetStackTrace() | GetStackFrames() |
+// non-null uc | GetStackTraceWithContext() | GetStackFramesWithContext() |
+// |==========================================================|
+extern int DefaultStackUnwinder(void** pcs, int* sizes, int max_depth,
+ int skip_count, const void* uc,
+ int* min_dropped_frames);
+
+} // namespace absl
+
+#endif // ABSL_DEBUGGING_STACKTRACE_H_
diff --git a/absl/memory/BUILD.bazel b/absl/memory/BUILD.bazel
new file mode 100644
index 0000000..91fc55f
--- /dev/null
+++ b/absl/memory/BUILD.bazel
@@ -0,0 +1,47 @@
+#
+# 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",
+)
+load(
+ "//absl:test_dependencies.bzl",
+ "GUNIT_MAIN_DEPS_SELECTOR",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"]) # Apache 2.0
+
+cc_library(
+ name = "memory",
+ hdrs = ["memory.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = ["//absl/meta:type_traits"],
+)
+
+cc_test(
+ name = "memory_test",
+ srcs = ["memory_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":memory",
+ "//absl/base",
+ "//absl/base:core_headers",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
diff --git a/absl/memory/README.md b/absl/memory/README.md
new file mode 100644
index 0000000..72eddd9
--- /dev/null
+++ b/absl/memory/README.md
@@ -0,0 +1,22 @@
+# ABSL Memory
+
+This directory contains packages related to abstractions for managing memory
+within objects.
+
+## Library Listing
+
+Only one library target exists within this directory at this time:
+
+* **memory** (`//absl/memory:memory`) provides classes and
+ utility functions for managing memory associated with pointers.
+
+
+## Memory Library File Listing
+
+The following header files are directly included within the
+`absl::memory` library:
+
+### Smart Pointer Management
+
+* `memory.h`
+ <br/>Pointer memory management abstractions for handling unique pointers
diff --git a/absl/memory/memory.h b/absl/memory/memory.h
new file mode 100644
index 0000000..c679960
--- /dev/null
+++ b/absl/memory/memory.h
@@ -0,0 +1,622 @@
+// 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: memory.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains utility functions for managing the creation and
+// conversion of smart pointers. This file is an extension to the C++
+// standard <memory> library header file.
+
+#ifndef ABSL_MEMORY_MEMORY_H_
+#define ABSL_MEMORY_MEMORY_H_
+
+#include <cstddef>
+#include <limits>
+#include <memory>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+
+// -----------------------------------------------------------------------------
+// Function Template: WrapUnique()
+// -----------------------------------------------------------------------------
+//
+// Transfers ownership of a raw pointer to a `std::unique_ptr`. The returned
+// value is a `std::unique_ptr` of deduced type.
+//
+// Example:
+// X* NewX(int, int);
+// auto x = WrapUnique(NewX(1, 2)); // 'x' is std::unique_ptr<X>.
+//
+// `absl::WrapUnique` is useful for capturing the output of a raw pointer
+// factory. However, prefer 'absl::make_unique<T>(args...) over
+// 'absl::WrapUnique(new T(args...))'.
+//
+// auto x = WrapUnique(new X(1, 2)); // works, but nonideal.
+// auto x = make_unique<X>(1, 2); // safer, standard, avoids raw 'new'.
+//
+// Note that `absl::WrapUnique(p)` is valid only if `delete p` is a valid
+// expression. In particular, `absl::WrapUnique()` cannot wrap pointers to
+// arrays, functions or void, and it must not be used to capture pointers
+// obtained from array-new expressions (even though that would compile!).
+template <typename T>
+std::unique_ptr<T> WrapUnique(T* ptr) {
+ static_assert(!std::is_array<T>::value, "array types are unsupported");
+ static_assert(std::is_object<T>::value, "non-object types are unsupported");
+ return std::unique_ptr<T>(ptr);
+}
+
+namespace memory_internal {
+
+// Traits to select proper overload and return type for `absl::make_unique<>`.
+template <typename T>
+struct MakeUniqueResult {
+ using scalar = std::unique_ptr<T>;
+};
+template <typename T>
+struct MakeUniqueResult<T[]> {
+ using array = std::unique_ptr<T[]>;
+};
+template <typename T, size_t N>
+struct MakeUniqueResult<T[N]> {
+ using invalid = void;
+};
+
+} // namespace memory_internal
+
+// -----------------------------------------------------------------------------
+// Function Template: make_unique<T>()
+// -----------------------------------------------------------------------------
+//
+// Creates a `std::unique_ptr<>`, while avoiding issues creating temporaries
+// during the construction process. `absl::make_unique<>` also avoids redundant
+// type declarations, by avoiding the need to explicitly use the `new` operator.
+//
+// This implementation of `absl::make_unique<>` is designed for C++11 code and
+// will be replaced in C++14 by the equivalent `std::make_unique<>` abstraction.
+// `absl::make_unique<>` is designed to be 100% compatible with
+// `std::make_unique<>` so that the eventual migration will involve a simple
+// rename operation.
+//
+// For more background on why `std::unique_ptr<T>(new T(a,b))` is problematic,
+// see Herb Sutter's explanation on
+// (Exception-Safe Function Calls)[http://herbsutter.com/gotw/_102/].
+// (In general, reviewers should treat `new T(a,b)` with scrutiny.)
+//
+// Example usage:
+//
+// auto p = make_unique<X>(args...); // 'p' is a std::unique_ptr<X>
+// auto pa = make_unique<X[]>(5); // 'pa' is a std::unique_ptr<X[]>
+//
+// Three overloads of `absl::make_unique` are required:
+//
+// - For non-array T:
+//
+// Allocates a T with `new T(std::forward<Args> args...)`,
+// forwarding all `args` to T's constructor.
+// Returns a `std::unique_ptr<T>` owning that object.
+//
+// - For an array of unknown bounds T[]:
+//
+// `absl::make_unique<>` will allocate an array T of type U[] with
+// `new U[n]()` and return a `std::unique_ptr<U[]>` owning that array.
+//
+// Note that 'U[n]()' is different from 'U[n]', and elements will be
+// value-initialized. Note as well that `std::unique_ptr` will perform its
+// own destruction of the array elements upon leaving scope, even though
+// the array [] does not have a default destructor.
+//
+// NOTE: an array of unknown bounds T[] may still be (and often will be)
+// initialized to have a size, and will still use this overload. E.g:
+//
+// auto my_array = absl::make_unique<int[]>(10);
+//
+// - For an array of known bounds T[N]:
+//
+// `absl::make_unique<>` is deleted (like with `std::make_unique<>`) as
+// this overload is not useful.
+//
+// NOTE: an array of known bounds T[N] is not considered a useful
+// construction, and may cause undefined behavior in templates. E.g:
+//
+// auto my_array = absl::make_unique<int[10]>();
+//
+// In those cases, of course, you can still use the overload above and
+// simply initialize it to its desired size:
+//
+// auto my_array = absl::make_unique<int[]>(10);
+
+// `absl::make_unique` overload for non-array types.
+template <typename T, typename... Args>
+typename memory_internal::MakeUniqueResult<T>::scalar make_unique(
+ Args&&... args) {
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
+
+// `absl::make_unique` overload for an array T[] of unknown bounds.
+// The array allocation needs to use the `new T[size]` form and cannot take
+// element constructor arguments. The `std::unique_ptr` will manage destructing
+// these array elements.
+template <typename T>
+typename memory_internal::MakeUniqueResult<T>::array make_unique(size_t n) {
+ return std::unique_ptr<T>(new typename absl::remove_extent_t<T>[n]());
+}
+
+// `absl::make_unique` overload for an array T[N] of known bounds.
+// This construction will be rejected.
+template <typename T, typename... Args>
+typename memory_internal::MakeUniqueResult<T>::invalid make_unique(
+ Args&&... /* args */) = delete;
+
+// -----------------------------------------------------------------------------
+// Function Template: RawPtr()
+// -----------------------------------------------------------------------------
+//
+// Extracts the raw pointer from a pointer-like 'ptr'. `absl::RawPtr` is useful
+// within templates that need to handle a complement of raw pointers,
+// `std::nullptr_t`, and smart pointers.
+template <typename T>
+auto RawPtr(T&& ptr) -> decltype(&*ptr) {
+ // ptr is a forwarding reference to support Ts with non-const operators.
+ return (ptr != nullptr) ? &*ptr : nullptr;
+}
+inline std::nullptr_t RawPtr(std::nullptr_t) { return nullptr; }
+
+// -----------------------------------------------------------------------------
+// Function Template: ShareUniquePtr()
+// -----------------------------------------------------------------------------
+//
+// Transforms a `std::unique_ptr` rvalue into a `std::shared_ptr`. The returned
+// value is a `std::shared_ptr` of deduced type and ownership is transferred to
+// the shared pointer.
+//
+// Example:
+//
+// auto up = absl::make_unique<int>(10);
+// auto sp = absl::ShareUniquePtr(std::move(up)); // shared_ptr<int>
+// CHECK_EQ(*sp, 10);
+// CHECK(up == nullptr);
+//
+// Note that this conversion is correct even when T is an array type, although
+// the resulting shared pointer may not be very useful.
+//
+// Implements the resolution of [LWG 2415](http://wg21.link/lwg2415), by which a
+// null shared pointer does not attempt to call the deleter.
+template <typename T, typename D>
+std::shared_ptr<T> ShareUniquePtr(std::unique_ptr<T, D>&& ptr) {
+ return ptr ? std::shared_ptr<T>(std::move(ptr)) : std::shared_ptr<T>();
+}
+
+// -----------------------------------------------------------------------------
+// Function Template: WeakenPtr()
+// -----------------------------------------------------------------------------
+//
+// Creates a weak pointer associated with a given shared pointer. The returned
+// value is a `std::weak_ptr` of deduced type.
+//
+// Example:
+//
+// auto sp = std::make_shared<int>(10);
+// auto wp = absl::WeakenPtr(sp);
+// CHECK_EQ(sp.get(), wp.lock().get());
+// sp.reset();
+// CHECK(wp.lock() == nullptr);
+//
+template <typename T>
+std::weak_ptr<T> WeakenPtr(const std::shared_ptr<T>& ptr) {
+ return std::weak_ptr<T>(ptr);
+}
+
+namespace memory_internal {
+
+// ExtractOr<E, O, D>::type evaluates to E<O> if possible. Otherwise, D.
+template <template <typename> class Extract, typename Obj, typename Default,
+ typename>
+struct ExtractOr {
+ using type = Default;
+};
+
+template <template <typename> class Extract, typename Obj, typename Default>
+struct ExtractOr<Extract, Obj, Default, void_t<Extract<Obj>>> {
+ using type = Extract<Obj>;
+};
+
+template <template <typename> class Extract, typename Obj, typename Default>
+using ExtractOrT = typename ExtractOr<Extract, Obj, Default, void>::type;
+
+// Extractors for the features of allocators.
+template <typename T>
+using GetPointer = typename T::pointer;
+
+template <typename T>
+using GetConstPointer = typename T::const_pointer;
+
+template <typename T>
+using GetVoidPointer = typename T::void_pointer;
+
+template <typename T>
+using GetConstVoidPointer = typename T::const_void_pointer;
+
+template <typename T>
+using GetDifferenceType = typename T::difference_type;
+
+template <typename T>
+using GetSizeType = typename T::size_type;
+
+template <typename T>
+using GetPropagateOnContainerCopyAssignment =
+ typename T::propagate_on_container_copy_assignment;
+
+template <typename T>
+using GetPropagateOnContainerMoveAssignment =
+ typename T::propagate_on_container_move_assignment;
+
+template <typename T>
+using GetPropagateOnContainerSwap = typename T::propagate_on_container_swap;
+
+template <typename T>
+using GetIsAlwaysEqual = typename T::is_always_equal;
+
+template <typename T>
+struct GetFirstArg;
+
+template <template <typename...> class Class, typename T, typename... Args>
+struct GetFirstArg<Class<T, Args...>> {
+ using type = T;
+};
+
+template <typename Ptr, typename = void>
+struct ElementType {
+ using type = typename GetFirstArg<Ptr>::type;
+};
+
+template <typename T>
+struct ElementType<T, void_t<typename T::element_type>> {
+ using type = typename T::element_type;
+};
+
+template <typename T, typename U>
+struct RebindFirstArg;
+
+template <template <typename...> class Class, typename T, typename... Args,
+ typename U>
+struct RebindFirstArg<Class<T, Args...>, U> {
+ using type = Class<U, Args...>;
+};
+
+template <typename T, typename U, typename = void>
+struct RebindPtr {
+ using type = typename RebindFirstArg<T, U>::type;
+};
+
+template <typename T, typename U>
+struct RebindPtr<T, U, void_t<typename T::template rebind<U>>> {
+ using type = typename T::template rebind<U>;
+};
+
+template <typename T, typename U, typename = void>
+struct RebindAlloc {
+ using type = typename RebindFirstArg<T, U>::type;
+};
+
+template <typename T, typename U>
+struct RebindAlloc<T, U, void_t<typename T::template rebind<U>::other>> {
+ using type = typename T::template rebind<U>::other;
+};
+
+} // namespace memory_internal
+
+// -----------------------------------------------------------------------------
+// Class Template: pointer_traits
+// -----------------------------------------------------------------------------
+//
+// An implementation of C++11's std::pointer_traits.
+//
+// Provided for portability on toolchains that have a working C++11 compiler,
+// but the standard library is lacking in C++11 support. For example, some
+// version of the Android NDK.
+//
+
+template <typename Ptr>
+struct pointer_traits {
+ using pointer = Ptr;
+
+ // element_type:
+ // Ptr::element_type if present. Otherwise T if Ptr is a template
+ // instantiation Template<T, Args...>
+ using element_type = typename memory_internal::ElementType<Ptr>::type;
+
+ // difference_type:
+ // Ptr::difference_type if present, otherwise std::ptrdiff_t
+ using difference_type =
+ memory_internal::ExtractOrT<memory_internal::GetDifferenceType, Ptr,
+ std::ptrdiff_t>;
+
+ // rebind:
+ // Ptr::rebind<U> if exists, otherwise Template<U, Args...> if Ptr is a
+ // template instantiation Template<T, Args...>
+ template <typename U>
+ using rebind = typename memory_internal::RebindPtr<Ptr, U>::type;
+
+ // pointer_to:
+ // Calls Ptr::pointer_to(r)
+ static pointer pointer_to(element_type& r) { // NOLINT(runtime/references)
+ return Ptr::pointer_to(r);
+ }
+};
+
+// Specialization for T*.
+template <typename T>
+struct pointer_traits<T*> {
+ using pointer = T*;
+ using element_type = T;
+ using difference_type = std::ptrdiff_t;
+
+ template <typename U>
+ using rebind = U*;
+
+ // pointer_to:
+ // Calls std::addressof(r)
+ static pointer pointer_to(
+ element_type& r) noexcept { // NOLINT(runtime/references)
+ return std::addressof(r);
+ }
+};
+
+// -----------------------------------------------------------------------------
+// Class Template: allocator_traits
+// -----------------------------------------------------------------------------
+//
+// A C++11 compatible implementation of C++17's std::allocator_traits.
+//
+template <typename Alloc>
+struct allocator_traits {
+ using allocator_type = Alloc;
+
+ // value_type:
+ // Alloc::value_type
+ using value_type = typename Alloc::value_type;
+
+ // pointer:
+ // Alloc::pointer if present, otherwise value_type*
+ using pointer = memory_internal::ExtractOrT<memory_internal::GetPointer,
+ Alloc, value_type*>;
+
+ // const_pointer:
+ // Alloc::const_pointer if present, otherwise
+ // absl::pointer_traits<pointer>::rebind<const value_type>
+ using const_pointer =
+ memory_internal::ExtractOrT<memory_internal::GetConstPointer, Alloc,
+ typename absl::pointer_traits<pointer>::
+ template rebind<const value_type>>;
+
+ // void_pointer:
+ // Alloc::void_pointer if present, otherwise
+ // absl::pointer_traits<pointer>::rebind<void>
+ using void_pointer = memory_internal::ExtractOrT<
+ memory_internal::GetVoidPointer, Alloc,
+ typename absl::pointer_traits<pointer>::template rebind<void>>;
+
+ // const_void_pointer:
+ // Alloc::const_void_pointer if present, otherwise
+ // absl::pointer_traits<pointer>::rebind<const void>
+ using const_void_pointer = memory_internal::ExtractOrT<
+ memory_internal::GetConstVoidPointer, Alloc,
+ typename absl::pointer_traits<pointer>::template rebind<const void>>;
+
+ // difference_type:
+ // Alloc::difference_type if present, otherwise
+ // absl::pointer_traits<pointer>::difference_type
+ using difference_type = memory_internal::ExtractOrT<
+ memory_internal::GetDifferenceType, Alloc,
+ typename absl::pointer_traits<pointer>::difference_type>;
+
+ // size_type:
+ // Alloc::size_type if present, otherwise
+ // std::make_unsigned<difference_type>::type
+ using size_type = memory_internal::ExtractOrT<
+ memory_internal::GetSizeType, Alloc,
+ typename std::make_unsigned<difference_type>::type>;
+
+ // propagate_on_container_copy_assignment:
+ // Alloc::propagate_on_container_copy_assignment if present, otherwise
+ // std::false_type
+ using propagate_on_container_copy_assignment = memory_internal::ExtractOrT<
+ memory_internal::GetPropagateOnContainerCopyAssignment, Alloc,
+ std::false_type>;
+
+ // propagate_on_container_move_assignment:
+ // Alloc::propagate_on_container_move_assignment if present, otherwise
+ // std::false_type
+ using propagate_on_container_move_assignment = memory_internal::ExtractOrT<
+ memory_internal::GetPropagateOnContainerMoveAssignment, Alloc,
+ std::false_type>;
+
+ // propagate_on_container_swap:
+ // Alloc::propagate_on_container_swap if present, otherwise std::false_type
+ using propagate_on_container_swap =
+ memory_internal::ExtractOrT<memory_internal::GetPropagateOnContainerSwap,
+ Alloc, std::false_type>;
+
+ // is_always_equal:
+ // Alloc::is_always_equal if present, otherwise std::is_empty<Alloc>::type
+ using is_always_equal =
+ memory_internal::ExtractOrT<memory_internal::GetIsAlwaysEqual, Alloc,
+ typename std::is_empty<Alloc>::type>;
+
+ // rebind_alloc:
+ // Alloc::rebind<T>::other if present, otherwise Alloc<T, Args> if this Alloc
+ // is Alloc<U, Args>
+ template <typename T>
+ using rebind_alloc = typename memory_internal::RebindAlloc<Alloc, T>::type;
+
+ // rebind_traits:
+ // absl::allocator_traits<rebind_alloc<T>>
+ template <typename T>
+ using rebind_traits = absl::allocator_traits<rebind_alloc<T>>;
+
+ // allocate(Alloc& a, size_type n):
+ // Calls a.allocate(n)
+ static pointer allocate(Alloc& a, // NOLINT(runtime/references)
+ size_type n) {
+ return a.allocate(n);
+ }
+
+ // allocate(Alloc& a, size_type n, const_void_pointer hint):
+ // Calls a.allocate(n, hint) if possible.
+ // If not possible, calls a.allocate(n)
+ static pointer allocate(Alloc& a, size_type n, // NOLINT(runtime/references)
+ const_void_pointer hint) {
+ return allocate_impl(0, a, n, hint);
+ }
+
+ // deallocate(Alloc& a, pointer p, size_type n):
+ // Calls a.deallocate(p, n)
+ static void deallocate(Alloc& a, pointer p, // NOLINT(runtime/references)
+ size_type n) {
+ a.deallocate(p, n);
+ }
+
+ // construct(Alloc& a, T* p, Args&&... args):
+ // Calls a.construct(p, std::forward<Args>(args)...) if possible.
+ // If not possible, calls
+ // ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...)
+ template <typename T, typename... Args>
+ static void construct(Alloc& a, T* p, // NOLINT(runtime/references)
+ Args&&... args) {
+ construct_impl(0, a, p, std::forward<Args>(args)...);
+ }
+
+ // destroy(Alloc& a, T* p):
+ // Calls a.destroy(p) if possible. If not possible, calls p->~T().
+ template <typename T>
+ static void destroy(Alloc& a, T* p) { // NOLINT(runtime/references)
+ destroy_impl(0, a, p);
+ }
+
+ // max_size(const Alloc& a):
+ // Returns a.max_size() if possible. If not possible, returns
+ // std::numeric_limits<size_type>::max() / sizeof(value_type)
+ static size_type max_size(const Alloc& a) { return max_size_impl(0, a); }
+
+ // select_on_container_copy_construction(const Alloc& a):
+ // Returns a.select_on_container_copy_construction() if possible.
+ // If not possible, returns a.
+ static Alloc select_on_container_copy_construction(const Alloc& a) {
+ return select_on_container_copy_construction_impl(0, a);
+ }
+
+ private:
+ template <typename A>
+ static auto allocate_impl(int, A& a, // NOLINT(runtime/references)
+ size_type n, const_void_pointer hint)
+ -> decltype(a.allocate(n, hint)) {
+ return a.allocate(n, hint);
+ }
+ static pointer allocate_impl(char, Alloc& a, // NOLINT(runtime/references)
+ size_type n, const_void_pointer) {
+ return a.allocate(n);
+ }
+
+ template <typename A, typename... Args>
+ static auto construct_impl(int, A& a, // NOLINT(runtime/references)
+ Args&&... args)
+ -> decltype(a.construct(std::forward<Args>(args)...)) {
+ a.construct(std::forward<Args>(args)...);
+ }
+
+ template <typename T, typename... Args>
+ static void construct_impl(char, Alloc&, T* p, Args&&... args) {
+ ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
+ }
+
+ template <typename A, typename T>
+ static auto destroy_impl(int, A& a, // NOLINT(runtime/references)
+ T* p) -> decltype(a.destroy(p)) {
+ a.destroy(p);
+ }
+ template <typename T>
+ static void destroy_impl(char, Alloc&, T* p) {
+ p->~T();
+ }
+
+ template <typename A>
+ static auto max_size_impl(int, const A& a) -> decltype(a.max_size()) {
+ return a.max_size();
+ }
+ static size_type max_size_impl(char, const Alloc&) {
+ return std::numeric_limits<size_type>::max() / sizeof(value_type);
+ }
+
+ template <typename A>
+ static auto select_on_container_copy_construction_impl(int, const A& a)
+ -> decltype(a.select_on_container_copy_construction()) {
+ return a.select_on_container_copy_construction();
+ }
+ static Alloc select_on_container_copy_construction_impl(char,
+ const Alloc& a) {
+ return a;
+ }
+};
+
+namespace memory_internal {
+
+// This template alias transforms Alloc::is_nothrow into a metafunction with
+// Alloc as a parameter so it can be used with ExtractOrT<>.
+template <typename Alloc>
+using GetIsNothrow = typename Alloc::is_nothrow;
+
+} // namespace memory_internal
+
+// ABSL_ALLOCATOR_NOTHROW is a build time configuration macro for user to
+// specify whether the default allocation function can throw or never throws.
+// If the allocation function never throws, user should define it to a non-zero
+// value (e.g. via `-DABSL_ALLOCATOR_NOTHROW`).
+// If the allocation function can throw, user should leave it undefined or
+// define it to zero.
+//
+// allocator_is_nothrow<Alloc> is a traits class that derives from
+// Alloc::is_nothrow if present, otherwise std::false_type. It's specialized
+// for Alloc = std::allocator<T> for any type T according to the state of
+// ABSL_ALLOCATOR_NOTHROW.
+//
+// default_allocator_is_nothrow is a class that derives from std::true_type
+// when the default allocator (global operator new) never throws, and
+// std::false_type when it can throw. It is a convenience shorthand for writing
+// allocator_is_nothrow<std::allocator<T>> (T can be any type).
+// NOTE: allocator_is_nothrow<std::allocator<T>> is guaranteed to derive from
+// the same type for all T, because users should specialize neither
+// allocator_is_nothrow nor std::allocator.
+template <typename Alloc>
+struct allocator_is_nothrow
+ : memory_internal::ExtractOrT<memory_internal::GetIsNothrow, Alloc,
+ std::false_type> {};
+
+#if ABSL_ALLOCATOR_NOTHROW
+template <typename T>
+struct allocator_is_nothrow<std::allocator<T>> : std::true_type {};
+struct default_allocator_is_nothrow : std::true_type {};
+#else
+struct default_allocator_is_nothrow : std::false_type {};
+#endif
+
+} // namespace absl
+
+#endif // ABSL_MEMORY_MEMORY_H_
diff --git a/absl/memory/memory_test.cc b/absl/memory/memory_test.cc
new file mode 100644
index 0000000..8a5f552
--- /dev/null
+++ b/absl/memory/memory_test.cc
@@ -0,0 +1,590 @@
+// 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.
+
+// Tests for pointer utilities.
+
+#include "absl/memory/memory.h"
+
+#include <sys/types.h>
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace {
+
+using ::testing::ElementsAre;
+using ::testing::Return;
+
+// This class creates observable behavior to verify that a destructor has
+// been called, via the instance_count variable.
+class DestructorVerifier {
+ public:
+ DestructorVerifier() { ++instance_count_; }
+ DestructorVerifier(const DestructorVerifier&) = delete;
+ DestructorVerifier& operator=(const DestructorVerifier&) = delete;
+ ~DestructorVerifier() { --instance_count_; }
+
+ // The number of instances of this class currently active.
+ static int instance_count() { return instance_count_; }
+
+ private:
+ // The number of instances of this class currently active.
+ static int instance_count_;
+};
+
+int DestructorVerifier::instance_count_ = 0;
+
+TEST(WrapUniqueTest, WrapUnique) {
+ // Test that the unique_ptr is constructed properly by verifying that the
+ // destructor for its payload gets called at the proper time.
+ {
+ auto dv = new DestructorVerifier;
+ EXPECT_EQ(1, DestructorVerifier::instance_count());
+ std::unique_ptr<DestructorVerifier> ptr = absl::WrapUnique(dv);
+ EXPECT_EQ(1, DestructorVerifier::instance_count());
+ }
+ EXPECT_EQ(0, DestructorVerifier::instance_count());
+}
+TEST(MakeUniqueTest, Basic) {
+ std::unique_ptr<std::string> p = absl::make_unique<std::string>();
+ EXPECT_EQ("", *p);
+ p = absl::make_unique<std::string>("hi");
+ EXPECT_EQ("hi", *p);
+}
+
+struct MoveOnly {
+ MoveOnly() = default;
+ explicit MoveOnly(int i1) : ip1{new int{i1}} {}
+ MoveOnly(int i1, int i2) : ip1{new int{i1}}, ip2{new int{i2}} {}
+ std::unique_ptr<int> ip1;
+ std::unique_ptr<int> ip2;
+};
+
+struct AcceptMoveOnly {
+ explicit AcceptMoveOnly(MoveOnly m) : m_(std::move(m)) {}
+ MoveOnly m_;
+};
+
+TEST(MakeUniqueTest, MoveOnlyTypeAndValue) {
+ using ExpectedType = std::unique_ptr<MoveOnly>;
+ {
+ auto p = absl::make_unique<MoveOnly>();
+ static_assert(std::is_same<decltype(p), ExpectedType>::value,
+ "unexpected return type");
+ EXPECT_TRUE(!p->ip1);
+ EXPECT_TRUE(!p->ip2);
+ }
+ {
+ auto p = absl::make_unique<MoveOnly>(1);
+ static_assert(std::is_same<decltype(p), ExpectedType>::value,
+ "unexpected return type");
+ EXPECT_TRUE(p->ip1 && *p->ip1 == 1);
+ EXPECT_TRUE(!p->ip2);
+ }
+ {
+ auto p = absl::make_unique<MoveOnly>(1, 2);
+ static_assert(std::is_same<decltype(p), ExpectedType>::value,
+ "unexpected return type");
+ EXPECT_TRUE(p->ip1 && *p->ip1 == 1);
+ EXPECT_TRUE(p->ip2 && *p->ip2 == 2);
+ }
+}
+
+TEST(MakeUniqueTest, AcceptMoveOnly) {
+ auto p = absl::make_unique<AcceptMoveOnly>(MoveOnly());
+ p = std::unique_ptr<AcceptMoveOnly>(new AcceptMoveOnly(MoveOnly()));
+}
+
+struct ArrayWatch {
+ void* operator new[](size_t n) {
+ allocs().push_back(n);
+ return ::operator new[](n);
+ }
+ void operator delete[](void* p) {
+ return ::operator delete[](p);
+ }
+ static std::vector<size_t>& allocs() {
+ static auto& v = *new std::vector<size_t>;
+ return v;
+ }
+};
+
+TEST(Make_UniqueTest, Array) {
+ // Ensure state is clean before we start so that these tests
+ // are order-agnostic.
+ ArrayWatch::allocs().clear();
+
+ auto p = absl::make_unique<ArrayWatch[]>(5);
+ static_assert(std::is_same<decltype(p),
+ std::unique_ptr<ArrayWatch[]>>::value,
+ "unexpected return type");
+ EXPECT_THAT(ArrayWatch::allocs(), ElementsAre(5 * sizeof(ArrayWatch)));
+}
+
+#if 0
+// TODO(billydonahue): Make a proper NC test.
+// These tests shouldn't compile.
+TEST(MakeUniqueTestNC, AcceptMoveOnlyLvalue) {
+ auto m = MoveOnly();
+ auto p = absl::make_unique<AcceptMoveOnly>(m);
+}
+TEST(MakeUniqueTestNC, KnownBoundArray) {
+ auto p = absl::make_unique<ArrayWatch[5]>();
+}
+#endif
+
+TEST(RawPtrTest, RawPointer) {
+ int i = 5;
+ EXPECT_EQ(&i, absl::RawPtr(&i));
+}
+
+TEST(RawPtrTest, SmartPointer) {
+ int* o = new int(5);
+ std::unique_ptr<int> p(o);
+ EXPECT_EQ(o, absl::RawPtr(p));
+}
+
+class IntPointerNonConstDeref {
+ public:
+ explicit IntPointerNonConstDeref(int* p) : p_(p) {}
+ friend bool operator!=(const IntPointerNonConstDeref& a, std::nullptr_t) {
+ return a.p_ != nullptr;
+ }
+ int& operator*() { return *p_; }
+
+ private:
+ std::unique_ptr<int> p_;
+};
+
+TEST(RawPtrTest, SmartPointerNonConstDereference) {
+ int* o = new int(5);
+ IntPointerNonConstDeref p(o);
+ EXPECT_EQ(o, absl::RawPtr(p));
+}
+
+TEST(RawPtrTest, NullValuedRawPointer) {
+ int* p = nullptr;
+ EXPECT_EQ(nullptr, absl::RawPtr(p));
+}
+
+TEST(RawPtrTest, NullValuedSmartPointer) {
+ std::unique_ptr<int> p;
+ EXPECT_EQ(nullptr, absl::RawPtr(p));
+}
+
+TEST(RawPtrTest, Nullptr) {
+ auto p = absl::RawPtr(nullptr);
+ EXPECT_TRUE((std::is_same<std::nullptr_t, decltype(p)>::value));
+ EXPECT_EQ(nullptr, p);
+}
+
+TEST(RawPtrTest, Null) {
+ auto p = absl::RawPtr(nullptr);
+ EXPECT_TRUE((std::is_same<std::nullptr_t, decltype(p)>::value));
+ EXPECT_EQ(nullptr, p);
+}
+
+TEST(RawPtrTest, Zero) {
+ auto p = absl::RawPtr(nullptr);
+ EXPECT_TRUE((std::is_same<std::nullptr_t, decltype(p)>::value));
+ EXPECT_EQ(nullptr, p);
+}
+
+TEST(ShareUniquePtrTest, Share) {
+ auto up = absl::make_unique<int>();
+ int* rp = up.get();
+ auto sp = absl::ShareUniquePtr(std::move(up));
+ EXPECT_EQ(sp.get(), rp);
+}
+
+TEST(ShareUniquePtrTest, ShareNull) {
+ struct NeverDie {
+ using pointer = void*;
+ void operator()(pointer) {
+ ASSERT_TRUE(false) << "Deleter should not have been called.";
+ }
+ };
+
+ std::unique_ptr<void, NeverDie> up;
+ auto sp = absl::ShareUniquePtr(std::move(up));
+}
+
+TEST(WeakenPtrTest, Weak) {
+ auto sp = std::make_shared<int>();
+ auto wp = absl::WeakenPtr(sp);
+ EXPECT_EQ(sp.get(), wp.lock().get());
+ sp.reset();
+ EXPECT_TRUE(wp.expired());
+}
+
+// Should not compile.
+/*
+TEST(RawPtrTest, NotAPointer) {
+ absl::RawPtr(1.5);
+}
+*/
+
+template <typename T>
+struct SmartPointer {
+ using difference_type = char;
+};
+
+struct PointerWith {
+ using element_type = int32_t;
+ using difference_type = int16_t;
+ template <typename U>
+ using rebind = SmartPointer<U>;
+
+ static PointerWith pointer_to(
+ element_type& r) { // NOLINT(runtime/references)
+ return PointerWith{&r};
+ }
+
+ element_type* ptr;
+};
+
+template <typename... Args>
+struct PointerWithout {};
+
+TEST(PointerTraits, Types) {
+ using TraitsWith = absl::pointer_traits<PointerWith>;
+ EXPECT_TRUE((std::is_same<TraitsWith::pointer, PointerWith>::value));
+ EXPECT_TRUE((std::is_same<TraitsWith::element_type, int32_t>::value));
+ EXPECT_TRUE((std::is_same<TraitsWith::difference_type, int16_t>::value));
+ EXPECT_TRUE((
+ std::is_same<TraitsWith::rebind<int64_t>, SmartPointer<int64_t>>::value));
+
+ using TraitsWithout = absl::pointer_traits<PointerWithout<double, int>>;
+ EXPECT_TRUE((std::is_same<TraitsWithout::pointer,
+ PointerWithout<double, int>>::value));
+ EXPECT_TRUE((std::is_same<TraitsWithout::element_type, double>::value));
+ EXPECT_TRUE(
+ (std::is_same<TraitsWithout ::difference_type, std::ptrdiff_t>::value));
+ EXPECT_TRUE((std::is_same<TraitsWithout::rebind<int64_t>,
+ PointerWithout<int64_t, int>>::value));
+
+ using TraitsRawPtr = absl::pointer_traits<char*>;
+ EXPECT_TRUE((std::is_same<TraitsRawPtr::pointer, char*>::value));
+ EXPECT_TRUE((std::is_same<TraitsRawPtr::element_type, char>::value));
+ EXPECT_TRUE(
+ (std::is_same<TraitsRawPtr::difference_type, std::ptrdiff_t>::value));
+ EXPECT_TRUE((std::is_same<TraitsRawPtr::rebind<int64_t>, int64_t*>::value));
+}
+
+TEST(PointerTraits, Functions) {
+ int i;
+ EXPECT_EQ(&i, absl::pointer_traits<PointerWith>::pointer_to(i).ptr);
+ EXPECT_EQ(&i, absl::pointer_traits<int*>::pointer_to(i));
+}
+
+TEST(AllocatorTraits, Typedefs) {
+ struct A {
+ struct value_type {};
+ };
+ EXPECT_TRUE((
+ std::is_same<A,
+ typename absl::allocator_traits<A>::allocator_type>::value));
+ EXPECT_TRUE(
+ (std::is_same<A::value_type,
+ typename absl::allocator_traits<A>::value_type>::value));
+
+ struct X {};
+ struct HasPointer {
+ using value_type = X;
+ using pointer = SmartPointer<X>;
+ };
+ EXPECT_TRUE((std::is_same<SmartPointer<X>, typename absl::allocator_traits<
+ HasPointer>::pointer>::value));
+ EXPECT_TRUE(
+ (std::is_same<A::value_type*,
+ typename absl::allocator_traits<A>::pointer>::value));
+
+ EXPECT_TRUE(
+ (std::is_same<
+ SmartPointer<const X>,
+ typename absl::allocator_traits<HasPointer>::const_pointer>::value));
+ EXPECT_TRUE(
+ (std::is_same<const A::value_type*,
+ typename absl::allocator_traits<A>::const_pointer>::value));
+
+ struct HasVoidPointer {
+ using value_type = X;
+ struct void_pointer {};
+ };
+
+ EXPECT_TRUE((std::is_same<HasVoidPointer::void_pointer,
+ typename absl::allocator_traits<
+ HasVoidPointer>::void_pointer>::value));
+ EXPECT_TRUE(
+ (std::is_same<SmartPointer<void>, typename absl::allocator_traits<
+ HasPointer>::void_pointer>::value));
+
+ struct HasConstVoidPointer {
+ using value_type = X;
+ struct const_void_pointer {};
+ };
+
+ EXPECT_TRUE(
+ (std::is_same<HasConstVoidPointer::const_void_pointer,
+ typename absl::allocator_traits<
+ HasConstVoidPointer>::const_void_pointer>::value));
+ EXPECT_TRUE((std::is_same<SmartPointer<const void>,
+ typename absl::allocator_traits<
+ HasPointer>::const_void_pointer>::value));
+
+ struct HasDifferenceType {
+ using value_type = X;
+ using difference_type = int;
+ };
+ EXPECT_TRUE(
+ (std::is_same<int, typename absl::allocator_traits<
+ HasDifferenceType>::difference_type>::value));
+ EXPECT_TRUE((std::is_same<char, typename absl::allocator_traits<
+ HasPointer>::difference_type>::value));
+
+ struct HasSizeType {
+ using value_type = X;
+ using size_type = unsigned int;
+ };
+ EXPECT_TRUE((std::is_same<unsigned int, typename absl::allocator_traits<
+ HasSizeType>::size_type>::value));
+ EXPECT_TRUE((std::is_same<unsigned char, typename absl::allocator_traits<
+ HasPointer>::size_type>::value));
+
+ struct HasPropagateOnCopy {
+ using value_type = X;
+ struct propagate_on_container_copy_assignment {};
+ };
+
+ EXPECT_TRUE(
+ (std::is_same<HasPropagateOnCopy::propagate_on_container_copy_assignment,
+ typename absl::allocator_traits<HasPropagateOnCopy>::
+ propagate_on_container_copy_assignment>::value));
+ EXPECT_TRUE(
+ (std::is_same<std::false_type,
+ typename absl::allocator_traits<
+ A>::propagate_on_container_copy_assignment>::value));
+
+ struct HasPropagateOnMove {
+ using value_type = X;
+ struct propagate_on_container_move_assignment {};
+ };
+
+ EXPECT_TRUE(
+ (std::is_same<HasPropagateOnMove::propagate_on_container_move_assignment,
+ typename absl::allocator_traits<HasPropagateOnMove>::
+ propagate_on_container_move_assignment>::value));
+ EXPECT_TRUE(
+ (std::is_same<std::false_type,
+ typename absl::allocator_traits<
+ A>::propagate_on_container_move_assignment>::value));
+
+ struct HasPropagateOnSwap {
+ using value_type = X;
+ struct propagate_on_container_swap {};
+ };
+
+ EXPECT_TRUE(
+ (std::is_same<HasPropagateOnSwap::propagate_on_container_swap,
+ typename absl::allocator_traits<HasPropagateOnSwap>::
+ propagate_on_container_swap>::value));
+ EXPECT_TRUE(
+ (std::is_same<std::false_type, typename absl::allocator_traits<A>::
+ propagate_on_container_swap>::value));
+
+ struct HasIsAlwaysEqual {
+ using value_type = X;
+ struct is_always_equal {};
+ };
+
+ EXPECT_TRUE((std::is_same<HasIsAlwaysEqual::is_always_equal,
+ typename absl::allocator_traits<
+ HasIsAlwaysEqual>::is_always_equal>::value));
+ EXPECT_TRUE((std::is_same<std::true_type, typename absl::allocator_traits<
+ A>::is_always_equal>::value));
+ struct NonEmpty {
+ using value_type = X;
+ int i;
+ };
+ EXPECT_TRUE(
+ (std::is_same<std::false_type,
+ absl::allocator_traits<NonEmpty>::is_always_equal>::value));
+}
+
+template <typename T>
+struct Rebound {};
+
+struct AllocWithRebind {
+ using value_type = int;
+ template <typename T>
+ struct rebind {
+ using other = Rebound<T>;
+ };
+};
+
+template <typename T, typename U>
+struct AllocWithoutRebind {
+ using value_type = int;
+};
+
+TEST(AllocatorTraits, Rebind) {
+ EXPECT_TRUE(
+ (std::is_same<Rebound<int>,
+ typename absl::allocator_traits<
+ AllocWithRebind>::template rebind_alloc<int>>::value));
+ EXPECT_TRUE(
+ (std::is_same<absl::allocator_traits<Rebound<int>>,
+ typename absl::allocator_traits<
+ AllocWithRebind>::template rebind_traits<int>>::value));
+
+ EXPECT_TRUE(
+ (std::is_same<AllocWithoutRebind<double, char>,
+ typename absl::allocator_traits<AllocWithoutRebind<
+ int, char>>::template rebind_alloc<double>>::value));
+ EXPECT_TRUE(
+ (std::is_same<absl::allocator_traits<AllocWithoutRebind<double, char>>,
+ typename absl::allocator_traits<AllocWithoutRebind<
+ int, char>>::template rebind_traits<double>>::value));
+}
+
+struct TestValue {
+ TestValue() {}
+ explicit TestValue(int* trace) : trace(trace) { ++*trace; }
+ ~TestValue() {
+ if (trace) --*trace;
+ }
+ int* trace = nullptr;
+};
+
+struct MinimalMockAllocator {
+ MinimalMockAllocator() : value(0) {}
+ explicit MinimalMockAllocator(int value) : value(value) {}
+ MinimalMockAllocator(const MinimalMockAllocator& other)
+ : value(other.value) {}
+ using value_type = TestValue;
+ MOCK_METHOD1(allocate, value_type*(size_t));
+ MOCK_METHOD2(deallocate, void(value_type*, size_t));
+
+ int value;
+};
+
+TEST(AllocatorTraits, FunctionsMinimal) {
+ int trace = 0;
+ int hint;
+ TestValue x(&trace);
+ MinimalMockAllocator mock;
+ using Traits = absl::allocator_traits<MinimalMockAllocator>;
+ EXPECT_CALL(mock, allocate(7)).WillRepeatedly(Return(&x));
+ EXPECT_CALL(mock, deallocate(&x, 7));
+
+ EXPECT_EQ(&x, Traits::allocate(mock, 7));
+ Traits::allocate(mock, 7, static_cast<const void*>(&hint));
+ EXPECT_EQ(&x, Traits::allocate(mock, 7, static_cast<const void*>(&hint)));
+ Traits::deallocate(mock, &x, 7);
+
+ EXPECT_EQ(1, trace);
+ Traits::construct(mock, &x, &trace);
+ EXPECT_EQ(2, trace);
+ Traits::destroy(mock, &x);
+ EXPECT_EQ(1, trace);
+
+ EXPECT_EQ(std::numeric_limits<size_t>::max() / sizeof(TestValue),
+ Traits::max_size(mock));
+
+ EXPECT_EQ(0, mock.value);
+ EXPECT_EQ(0, Traits::select_on_container_copy_construction(mock).value);
+}
+
+struct FullMockAllocator {
+ FullMockAllocator() : value(0) {}
+ explicit FullMockAllocator(int value) : value(value) {}
+ FullMockAllocator(const FullMockAllocator& other) : value(other.value) {}
+ using value_type = TestValue;
+ MOCK_METHOD1(allocate, value_type*(size_t));
+ MOCK_METHOD2(allocate, value_type*(size_t, const void*));
+ MOCK_METHOD2(construct, void(value_type*, int*));
+ MOCK_METHOD1(destroy, void(value_type*));
+ MOCK_CONST_METHOD0(max_size, size_t());
+ MOCK_CONST_METHOD0(select_on_container_copy_construction,
+ FullMockAllocator());
+
+ int value;
+};
+
+TEST(AllocatorTraits, FunctionsFull) {
+ int trace = 0;
+ int hint;
+ TestValue x(&trace), y;
+ FullMockAllocator mock;
+ using Traits = absl::allocator_traits<FullMockAllocator>;
+ EXPECT_CALL(mock, allocate(7)).WillRepeatedly(Return(&x));
+ EXPECT_CALL(mock, allocate(13, &hint)).WillRepeatedly(Return(&y));
+ EXPECT_CALL(mock, construct(&x, &trace));
+ EXPECT_CALL(mock, destroy(&x));
+ EXPECT_CALL(mock, max_size()).WillRepeatedly(Return(17));
+ EXPECT_CALL(mock, select_on_container_copy_construction())
+ .WillRepeatedly(Return(FullMockAllocator(23)));
+
+ EXPECT_EQ(&x, Traits::allocate(mock, 7));
+ EXPECT_EQ(&y, Traits::allocate(mock, 13, static_cast<const void*>(&hint)));
+
+ EXPECT_EQ(1, trace);
+ Traits::construct(mock, &x, &trace);
+ EXPECT_EQ(1, trace);
+ Traits::destroy(mock, &x);
+ EXPECT_EQ(1, trace);
+
+ EXPECT_EQ(17, Traits::max_size(mock));
+
+ EXPECT_EQ(0, mock.value);
+ EXPECT_EQ(23, Traits::select_on_container_copy_construction(mock).value);
+}
+
+TEST(AllocatorNoThrowTest, DefaultAllocator) {
+#if ABSL_ALLOCATOR_NOTHROW
+ EXPECT_TRUE(absl::default_allocator_is_nothrow::value);
+#else
+ EXPECT_FALSE(absl::default_allocator_is_nothrow::value);
+#endif
+}
+
+TEST(AllocatorNoThrowTest, StdAllocator) {
+#if ABSL_ALLOCATOR_NOTHROW
+ EXPECT_TRUE(absl::allocator_is_nothrow<std::allocator<int>>::value);
+#else
+ EXPECT_FALSE(absl::allocator_is_nothrow<std::allocator<int>>::value);
+#endif
+}
+
+TEST(AllocatorNoThrowTest, CustomAllocator) {
+ struct NoThrowAllocator {
+ using is_nothrow = std::true_type;
+ };
+ struct CanThrowAllocator {
+ using is_nothrow = std::false_type;
+ };
+ struct UnspecifiedAllocator {
+ };
+ EXPECT_TRUE(absl::allocator_is_nothrow<NoThrowAllocator>::value);
+ EXPECT_FALSE(absl::allocator_is_nothrow<CanThrowAllocator>::value);
+ EXPECT_FALSE(absl::allocator_is_nothrow<UnspecifiedAllocator>::value);
+}
+
+} // namespace
diff --git a/absl/meta/BUILD.bazel b/absl/meta/BUILD.bazel
new file mode 100644
index 0000000..872751e
--- /dev/null
+++ b/absl/meta/BUILD.bazel
@@ -0,0 +1,29 @@
+load(
+ "//absl:copts.bzl",
+ "ABSL_DEFAULT_COPTS",
+ "ABSL_TEST_COPTS",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["unencumbered"]) # Owned by Google
+
+cc_library(
+ name = "type_traits",
+ hdrs = ["type_traits.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ "//absl/base:config",
+ ],
+)
+
+cc_test(
+ name = "type_traits_test",
+ srcs = ["type_traits_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":type_traits",
+ "//absl/base:core_headers",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h
new file mode 100644
index 0000000..779afd2
--- /dev/null
+++ b/absl/meta/type_traits.h
@@ -0,0 +1,314 @@
+//
+// 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.
+//
+// -----------------------------------------------------------------------------
+// type_traits.h
+// -----------------------------------------------------------------------------
+//
+// This file contains C++11-compatible versions of standard <type_traits> API
+// functions for determining the characteristics of types. Such traits can
+// support type inference, classification, and transformation, as well as
+// make it easier to write templates based on generic type behavior.
+//
+// See http://en.cppreference.com/w/cpp/header/type_traits
+//
+// WARNING: use of many of the constructs in this header will count as "complex
+// template metaprogramming", so before proceeding, please carefully consider
+// https://google.github.io/styleguide/cppguide.html#Template_metaprogramming
+//
+// WARNING: using template metaprogramming to detect or depend on API
+// features is brittle and not guaranteed. Neither the standard library nor
+// Abseil provides any guarantee that APIs are stable in the face of template
+// metaprogramming. Use with caution.
+#ifndef ABSL_META_TYPE_TRAITS_H_
+#define ABSL_META_TYPE_TRAITS_H_
+
+#include <type_traits>
+
+#include "absl/base/config.h"
+
+namespace absl {
+
+namespace type_traits_internal {
+template <typename... Ts>
+struct VoidTImpl {
+ using type = void;
+};
+
+// This trick to retrieve a default alignment is necessary for our
+// implementation of aligned_storage_t to be consistent with any implementation
+// of std::aligned_storage.
+template <size_t Len, typename T = std::aligned_storage<Len>>
+struct default_alignment_of_aligned_storage;
+
+template <size_t Len, size_t Align>
+struct default_alignment_of_aligned_storage<Len,
+ std::aligned_storage<Len, Align>> {
+ static constexpr size_t value = Align;
+};
+
+} // namespace type_traits_internal
+
+// void_t()
+//
+// Ignores the type of any its arguments and returns `void`. In general, this
+// metafunction allows you to create a general case that maps to `void` while
+// allowing specializations that map to specific types.
+//
+// This metafunction is designed to be a drop-in replacement for the C++17
+// `std::void_t` metafunction.
+//
+// NOTE: `absl::void_t` does not use the standard-specified implementation so
+// that it can remain compatibile with gcc < 5.1. This can introduce slightly
+// different behavior, such as when ordering partial specializations.
+template <typename... Ts>
+using void_t = typename type_traits_internal::VoidTImpl<Ts...>::type;
+
+// conjunction
+//
+// Performs a compile-time logical AND operation on the passed types (which
+// must have `::value` members convertible to `bool`. Short-circuits if it
+// encounters any `false` members (and does not compare the `::value` members
+// of any remaining arguments).
+//
+// This metafunction is designed to be a drop-in replacement for the C++17
+// `std::conjunction` metafunction.
+template <typename... Ts>
+struct conjunction;
+
+template <typename T, typename... Ts>
+struct conjunction<T, Ts...>
+ : std::conditional<T::value, conjunction<Ts...>, T>::type {};
+
+template <typename T>
+struct conjunction<T> : T {};
+
+template <>
+struct conjunction<> : std::true_type {};
+
+// disjunction
+//
+// Performs a compile-time logical OR operation on the passed types (which
+// must have `::value` members convertible to `bool`. Short-circuits if it
+// encounters any `true` members (and does not compare the `::value` members
+// of any remaining arguments).
+//
+// This metafunction is designed to be a drop-in replacement for the C++17
+// `std::disjunction` metafunction.
+template <typename... Ts>
+struct disjunction;
+
+template <typename T, typename... Ts>
+struct disjunction<T, Ts...> :
+ std::conditional<T::value, T, disjunction<Ts...>>::type {};
+
+template <typename T>
+struct disjunction<T> : T {};
+
+template <>
+struct disjunction<> : std::false_type {};
+
+// negation
+//
+// Performs a compile-time logical NOT operation on the passed type (which
+// must have `::value` members convertible to `bool`.
+//
+// This metafunction is designed to be a drop-in replacement for the C++17
+// `std::negation` metafunction.
+template <typename T>
+struct negation : std::integral_constant<bool, !T::value> {};
+
+// is_trivially_destructible()
+//
+// Determines whether the passed type `T` is trivially destructable.
+//
+// This metafunction is designed to be a drop-in replacement for the C++17
+// `std::is_trivially_destructible()` metafunction.
+//
+// NOTE: the extensions (__has_trivial_xxx) are implemented in gcc (version >=
+// 4.3) and clang. Since we are supporting libstdc++ > 4.7, they should always
+// be present. These extensions are documented at
+// https://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html#Type-Traits.
+template <typename T>
+struct is_trivially_destructible
+ : std::integral_constant<bool, __has_trivial_destructor(T) &&
+ std::is_destructible<T>::value> {
+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
+ static_assert(std::is_trivially_destructible<T>::value ==
+ is_trivially_destructible::value,
+ "Not compliant with std::is_trivially_destructible");
+#endif // ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
+};
+
+// is_trivially_default_constructible()
+//
+// Determines whether the passed type `T` is trivially default constructible.
+//
+// This metafunction is designed to be a drop-in replacement for the C++17
+// `std::is_trivially_default_constructible()` metafunction.
+//
+// NOTE: according to the C++ standard, Section: 20.15.4.3 [meta.unary.prop]
+// "The predicate condition for a template specialization is_constructible<T,
+// Args...> shall be satisfied if and only if the following variable
+// definition would be well-formed for some invented variable t:
+//
+// T t(declval<Args>()...);
+//
+// is_trivially_constructible<T, Args...> additionally requires that the
+// variable definition does not call any operation that is not trivial.
+// For the purposes of this check, the call to std::declval is considered
+// trivial."
+//
+// Notes from http://en.cppreference.com/w/cpp/types/is_constructible:
+// In many implementations, is_nothrow_constructible also checks if the
+// destructor throws because it is effectively noexcept(T(arg)). Same
+// applies to is_trivially_constructible, which, in these implementations, also
+// requires that the destructor is trivial.
+// GCC bug 51452: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51452
+// LWG issue 2116: http://cplusplus.github.io/LWG/lwg-active.html#2116.
+//
+// "T obj();" need to be well-formed and not call any non-trivial operation.
+// Nontrivally destructible types will cause the expression to be nontrivial.
+template <typename T>
+struct is_trivially_default_constructible
+ : std::integral_constant<bool,
+ __has_trivial_constructor(T) &&
+ std::is_default_constructible<T>::value &&
+ is_trivially_destructible<T>::value> {
+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+ static_assert(std::is_trivially_default_constructible<T>::value ==
+ is_trivially_default_constructible::value,
+ "Not compliant with std::is_trivially_default_constructible");
+#endif // ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+};
+
+// is_trivially_copy_constructible()
+//
+// Determines whether the passed type `T` is trivially copy constructible.
+//
+// This metafunction is designed to be a drop-in replacement for the C++17
+// `std::is_trivially_copy_constructible()` metafunction.
+//
+// NOTE: `T obj(declval<const T&>());` needs to be well-formed and not call any
+// nontrivial operation. Nontrivally destructible types will cause the
+// expression to be nontrivial.
+template <typename T>
+struct is_trivially_copy_constructible
+ : std::integral_constant<bool, __has_trivial_copy(T) &&
+ std::is_copy_constructible<T>::value &&
+ is_trivially_destructible<T>::value> {
+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+ static_assert(std::is_trivially_copy_constructible<T>::value ==
+ is_trivially_copy_constructible::value,
+ "Not compliant with std::is_trivially_copy_constructible");
+#endif // ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+};
+
+// is_trivially_copy_assignable()
+//
+// Determines whether the passed type `T` is trivially copy assignable.
+//
+// This metafunction is designed to be a drop-in replacement for the C++17
+// `std::is_trivially_copy_assignable()` metafunction.
+//
+// NOTE: `is_assignable<T, U>::value` is `true` if the expression
+// `declval<T>() = declval<U>()` is well-formed when treated as an unevaluated
+// operand. `is_trivially_assignable<T, U>` requires the assignment to call no
+// operation that is not trivial. `is_trivially_copy_assignable<T>` is simply
+// `is_trivially_assignable<T, const T&>`.
+template <typename T>
+struct is_trivially_copy_assignable
+ : std::integral_constant<bool, __has_trivial_assign(T) &&
+ std::is_copy_assignable<T>::value> {
+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
+ static_assert(std::is_trivially_copy_assignable<T>::value ==
+ is_trivially_copy_assignable::value,
+ "Not compliant with std::is_trivially_copy_assignable");
+#endif // ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
+};
+
+// -----------------------------------------------------------------------------
+// C++14 "_t" trait aliases
+// -----------------------------------------------------------------------------
+
+template <typename T>
+using remove_cv_t = typename std::remove_cv<T>::type;
+
+template <typename T>
+using remove_const_t = typename std::remove_const<T>::type;
+
+template <typename T>
+using remove_volatile_t = typename std::remove_volatile<T>::type;
+
+template <typename T>
+using add_cv_t = typename std::add_cv<T>::type;
+
+template <typename T>
+using add_const_t = typename std::add_const<T>::type;
+
+template <typename T>
+using add_volatile_t = typename std::add_volatile<T>::type;
+
+template <typename T>
+using remove_reference_t = typename std::remove_reference<T>::type;
+
+template <typename T>
+using add_lvalue_reference_t = typename std::add_lvalue_reference<T>::type;
+
+template <typename T>
+using add_rvalue_reference_t = typename std::add_rvalue_reference<T>::type;
+
+template <typename T>
+using remove_pointer_t = typename std::remove_pointer<T>::type;
+
+template <typename T>
+using add_pointer_t = typename std::add_pointer<T>::type;
+
+template <typename T>
+using make_signed_t = typename std::make_signed<T>::type;
+
+template <typename T>
+using make_unsigned_t = typename std::make_unsigned<T>::type;
+
+template <typename T>
+using remove_extent_t = typename std::remove_extent<T>::type;
+
+template <typename T>
+using remove_all_extents_t = typename std::remove_all_extents<T>::type;
+
+template <size_t Len, size_t Align = type_traits_internal::
+ default_alignment_of_aligned_storage<Len>::value>
+using aligned_storage_t = typename std::aligned_storage<Len, Align>::type;
+
+template <typename T>
+using decay_t = typename std::decay<T>::type;
+
+template <bool B, typename T = void>
+using enable_if_t = typename std::enable_if<B, T>::type;
+
+template <bool B, typename T, typename F>
+using conditional_t = typename std::conditional<B, T, F>::type;
+
+template <typename... T>
+using common_type_t = typename std::common_type<T...>::type;
+
+template <typename T>
+using underlying_type_t = typename std::underlying_type<T>::type;
+
+template <typename T>
+using result_of_t = typename std::result_of<T>::type;
+
+} // namespace absl
+#endif // ABSL_META_TYPE_TRAITS_H_
diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc
new file mode 100644
index 0000000..54dcc8f
--- /dev/null
+++ b/absl/meta/type_traits_test.cc
@@ -0,0 +1,640 @@
+// 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/meta/type_traits.h"
+
+#include <cstdint>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace {
+
+using ::testing::StaticAssertTypeEq;
+
+struct Dummy {};
+
+TEST(VoidTTest, BasicUsage) {
+ StaticAssertTypeEq<void, absl::void_t<Dummy>>();
+ StaticAssertTypeEq<void, absl::void_t<Dummy, Dummy, Dummy>>();
+}
+
+TEST(ConjunctionTest, BasicBooleanLogic) {
+ EXPECT_TRUE(absl::conjunction<>::value);
+ EXPECT_TRUE(absl::conjunction<std::true_type>::value);
+ EXPECT_TRUE((absl::conjunction<std::true_type, std::true_type>::value));
+ EXPECT_FALSE((absl::conjunction<std::true_type, std::false_type>::value));
+ EXPECT_FALSE((absl::conjunction<std::false_type, std::true_type>::value));
+ EXPECT_FALSE((absl::conjunction<std::false_type, std::false_type>::value));
+}
+
+struct MyTrueType {
+ static constexpr bool value = true;
+};
+
+struct MyFalseType {
+ static constexpr bool value = false;
+};
+
+TEST(ConjunctionTest, ShortCircuiting) {
+ EXPECT_FALSE(
+ (absl::conjunction<std::true_type, std::false_type, Dummy>::value));
+ EXPECT_TRUE((std::is_base_of<MyFalseType,
+ absl::conjunction<std::true_type, MyFalseType,
+ std::false_type>>::value));
+ EXPECT_TRUE(
+ (std::is_base_of<MyTrueType,
+ absl::conjunction<std::true_type, MyTrueType>>::value));
+}
+
+TEST(DisjunctionTest, BasicBooleanLogic) {
+ EXPECT_FALSE(absl::disjunction<>::value);
+ EXPECT_FALSE(absl::disjunction<std::false_type>::value);
+ EXPECT_TRUE((absl::disjunction<std::true_type, std::true_type>::value));
+ EXPECT_TRUE((absl::disjunction<std::true_type, std::false_type>::value));
+ EXPECT_TRUE((absl::disjunction<std::false_type, std::true_type>::value));
+ EXPECT_FALSE((absl::disjunction<std::false_type, std::false_type>::value));
+}
+
+TEST(DisjunctionTest, ShortCircuiting) {
+ EXPECT_TRUE(
+ (absl::disjunction<std::false_type, std::true_type, Dummy>::value));
+ EXPECT_TRUE((
+ std::is_base_of<MyTrueType, absl::disjunction<std::false_type, MyTrueType,
+ std::true_type>>::value));
+ EXPECT_TRUE((
+ std::is_base_of<MyFalseType,
+ absl::disjunction<std::false_type, MyFalseType>>::value));
+}
+
+TEST(NegationTest, BasicBooleanLogic) {
+ EXPECT_FALSE(absl::negation<std::true_type>::value);
+ EXPECT_FALSE(absl::negation<MyTrueType>::value);
+ EXPECT_TRUE(absl::negation<std::false_type>::value);
+ EXPECT_TRUE(absl::negation<MyFalseType>::value);
+}
+
+// all member functions are trivial
+class Trivial {
+ int n_;
+};
+
+class TrivialDefaultCtor {
+ public:
+ TrivialDefaultCtor() = default;
+ explicit TrivialDefaultCtor(int n) : n_(n) {}
+
+ private:
+ int n_;
+};
+
+class TrivialCopyCtor {
+ public:
+ explicit TrivialCopyCtor(int n) : n_(n) {}
+ TrivialCopyCtor(const TrivialCopyCtor&) = default;
+ TrivialCopyCtor& operator=(const TrivialCopyCtor& t) {
+ n_ = t.n_;
+ return *this;
+ }
+
+ private:
+ int n_;
+};
+
+class TrivialCopyAssign {
+ public:
+ explicit TrivialCopyAssign(int n) : n_(n) {}
+ TrivialCopyAssign(const TrivialCopyAssign& t) : n_(t.n_) {}
+ TrivialCopyAssign& operator=(const TrivialCopyAssign& t) = default;
+ ~TrivialCopyAssign() {} // can have non trivial destructor
+ private:
+ int n_;
+};
+
+struct NonTrivialDestructor {
+ ~NonTrivialDestructor() {}
+};
+
+struct TrivialDestructor {
+ ~TrivialDestructor() = default;
+};
+
+struct NonCopyable {
+ NonCopyable() = default;
+ NonCopyable(const NonCopyable&) = delete;
+ NonCopyable& operator=(const NonCopyable&) = delete;
+};
+
+class Base {
+ public:
+ virtual ~Base() {}
+};
+
+// In GCC/Clang, std::is_trivially_constructible requires that the destructor is
+// trivial. However, MSVC doesn't require that. This results in different
+// behavior when checking is_trivially_constructible on any type with nontrivial
+// destructor. Since absl::is_trivially_default_constructible and
+// absl::is_trivially_copy_constructible both follows Clang/GCC's interpretation
+// and check is_trivially_destructible, it results in inconsistency with
+// std::is_trivially_xxx_constructible on MSVC. This macro is used to work
+// around this issue in test. In practice, a trivially constructible type
+// should also be trivially destructible.
+// GCC bug 51452: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51452
+// LWG issue 2116: http://cplusplus.github.io/LWG/lwg-active.html#2116.
+#ifdef _MSC_VER
+#define ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE
+#endif
+
+TEST(TypeTraitsTest, TestTrivialDefaultCtor) {
+ // arithmetic types and pointers have trivial default constructors.
+ EXPECT_TRUE(absl::is_trivially_default_constructible<bool>::value);
+ EXPECT_TRUE(absl::is_trivially_default_constructible<char>::value);
+ EXPECT_TRUE(absl::is_trivially_default_constructible<unsigned char>::value);
+ EXPECT_TRUE(absl::is_trivially_default_constructible<signed char>::value);
+ EXPECT_TRUE(absl::is_trivially_default_constructible<wchar_t>::value);
+ EXPECT_TRUE(absl::is_trivially_default_constructible<int>::value);
+ EXPECT_TRUE(absl::is_trivially_default_constructible<unsigned int>::value);
+ EXPECT_TRUE(absl::is_trivially_default_constructible<int16_t>::value);
+ EXPECT_TRUE(absl::is_trivially_default_constructible<uint16_t>::value);
+ EXPECT_TRUE(absl::is_trivially_default_constructible<int64_t>::value);
+ EXPECT_TRUE(absl::is_trivially_default_constructible<uint64_t>::value);
+ EXPECT_TRUE(absl::is_trivially_default_constructible<float>::value);
+ EXPECT_TRUE(absl::is_trivially_default_constructible<double>::value);
+ EXPECT_TRUE(absl::is_trivially_default_constructible<long double>::value);
+ EXPECT_TRUE(absl::is_trivially_default_constructible<std::string*>::value);
+ EXPECT_TRUE(absl::is_trivially_default_constructible<Trivial*>::value);
+ EXPECT_TRUE(
+ absl::is_trivially_default_constructible<const TrivialCopyCtor*>::value);
+ EXPECT_TRUE(
+ absl::is_trivially_default_constructible<TrivialCopyCtor**>::value);
+
+ // types with compiler generated default ctors
+ EXPECT_TRUE(absl::is_trivially_default_constructible<Trivial>::value);
+ EXPECT_TRUE(
+ absl::is_trivially_default_constructible<TrivialDefaultCtor>::value);
+
+#ifndef ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE
+ // types with non trivial destructor are non trivial
+ EXPECT_FALSE(
+ absl::is_trivially_default_constructible<NonTrivialDestructor>::value);
+#endif
+
+ // types with vtables
+ EXPECT_FALSE(absl::is_trivially_default_constructible<Base>::value);
+
+ // Verify that arrays of such types are trivially default constructible
+ typedef int int10[10];
+ EXPECT_TRUE(absl::is_trivially_default_constructible<int10>::value);
+ typedef Trivial Trivial10[10];
+ EXPECT_TRUE(absl::is_trivially_default_constructible<Trivial10>::value);
+ typedef Trivial TrivialDefaultCtor10[10];
+ EXPECT_TRUE(
+ absl::is_trivially_default_constructible<TrivialDefaultCtor10>::value);
+
+ // Verify that std::pair has non-trivial constructors.
+ EXPECT_FALSE(
+ (absl::is_trivially_default_constructible<std::pair<int, char*>>::value));
+
+ // Verify that types without trivial constructors are
+ // correctly marked as such.
+ EXPECT_FALSE(absl::is_trivially_default_constructible<std::string>::value);
+ EXPECT_FALSE(
+ absl::is_trivially_default_constructible<std::vector<int>>::value);
+}
+
+TEST(TypeTraitsTest, TestTrivialCopyCtor) {
+ // Verify that arithmetic types and pointers have trivial copy
+ // constructors.
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<bool>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<char>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<unsigned char>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<signed char>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<wchar_t>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<int>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<unsigned int>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<int16_t>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<uint16_t>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<int64_t>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<uint64_t>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<float>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<double>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<long double>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<std::string*>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<Trivial*>::value);
+ EXPECT_TRUE(
+ absl::is_trivially_copy_constructible<const TrivialCopyCtor*>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<TrivialCopyCtor**>::value);
+
+ // types with compiler generated copy ctors
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<Trivial>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<TrivialCopyCtor>::value);
+
+#ifndef ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE
+ // type with non-trivial destructor are non-trivial copy construbtible
+ EXPECT_FALSE(
+ absl::is_trivially_copy_constructible<NonTrivialDestructor>::value);
+#endif
+
+ // types with vtables
+ EXPECT_FALSE(absl::is_trivially_copy_constructible<Base>::value);
+
+ // Verify that std pair of such types is trivially copy constructible
+ EXPECT_TRUE(
+ (absl::is_trivially_copy_constructible<std::pair<int, char*>>::value));
+ EXPECT_TRUE(
+ (absl::is_trivially_copy_constructible<std::pair<int, Trivial>>::value));
+ EXPECT_TRUE((absl::is_trivially_copy_constructible<
+ std::pair<int, TrivialCopyCtor>>::value));
+
+ // Verify that arrays are not
+ typedef int int10[10];
+ EXPECT_FALSE(absl::is_trivially_copy_constructible<int10>::value);
+
+ // Verify that pairs of types without trivial copy constructors
+ // are not marked as trivial.
+ EXPECT_FALSE((absl::is_trivially_copy_constructible<
+ std::pair<int, std::string>>::value));
+ EXPECT_FALSE((absl::is_trivially_copy_constructible<
+ std::pair<std::string, int>>::value));
+
+ // Verify that types without trivial copy constructors are
+ // correctly marked as such.
+ EXPECT_FALSE(absl::is_trivially_copy_constructible<std::string>::value);
+ EXPECT_FALSE(absl::is_trivially_copy_constructible<std::vector<int>>::value);
+
+ // types with deleted copy constructors are not copy constructible
+ EXPECT_FALSE(absl::is_trivially_copy_constructible<NonCopyable>::value);
+}
+
+TEST(TypeTraitsTest, TestTrivialCopyAssign) {
+ // Verify that arithmetic types and pointers have trivial copy
+ // constructors.
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<bool>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<char>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<unsigned char>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<signed char>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<wchar_t>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<int>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<unsigned int>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<int16_t>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<uint16_t>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<int64_t>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<uint64_t>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<float>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<double>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<long double>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<std::string*>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<Trivial*>::value);
+ EXPECT_TRUE(
+ absl::is_trivially_copy_assignable<const TrivialCopyCtor*>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<TrivialCopyCtor**>::value);
+
+ // const qualified types are not assignable
+ EXPECT_FALSE(absl::is_trivially_copy_assignable<const int>::value);
+
+ // types with compiler generated copy assignment
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<Trivial>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<TrivialCopyAssign>::value);
+
+ // types with vtables
+ EXPECT_FALSE(absl::is_trivially_copy_assignable<Base>::value);
+
+ // Verify that arrays are not trivially copy assignable
+ typedef int int10[10];
+ EXPECT_FALSE(absl::is_trivially_copy_assignable<int10>::value);
+
+ // Verify that std::pair is not trivially assignable
+ EXPECT_FALSE(
+ (absl::is_trivially_copy_assignable<std::pair<int, char*>>::value));
+
+ // Verify that types without trivial copy constructors are
+ // correctly marked as such.
+ EXPECT_FALSE(absl::is_trivially_copy_assignable<std::string>::value);
+ EXPECT_FALSE(absl::is_trivially_copy_assignable<std::vector<int>>::value);
+
+ // types with deleted copy assignment are not copy assignable
+ EXPECT_FALSE(absl::is_trivially_copy_assignable<NonCopyable>::value);
+}
+
+TEST(TypeTraitsTest, TestTrivialDestructor) {
+ // Verify that arithmetic types and pointers have trivial copy
+ // constructors.
+ EXPECT_TRUE(absl::is_trivially_destructible<bool>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<char>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<unsigned char>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<signed char>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<wchar_t>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<int>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<unsigned int>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<int16_t>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<uint16_t>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<int64_t>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<uint64_t>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<float>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<double>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<long double>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<std::string*>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<Trivial*>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<const TrivialCopyCtor*>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<TrivialCopyCtor**>::value);
+
+ // classes with destructors
+ EXPECT_TRUE(absl::is_trivially_destructible<Trivial>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<TrivialDestructor>::value);
+ EXPECT_FALSE(absl::is_trivially_destructible<NonTrivialDestructor>::value);
+
+ // std::pair of such types is trivial
+ EXPECT_TRUE((absl::is_trivially_destructible<std::pair<int, int>>::value));
+ EXPECT_TRUE((absl::is_trivially_destructible<
+ std::pair<Trivial, TrivialDestructor>>::value));
+
+ // array of such types is trivial
+ typedef int int10[10];
+ EXPECT_TRUE(absl::is_trivially_destructible<int10>::value);
+ typedef TrivialDestructor TrivialDestructor10[10];
+ EXPECT_TRUE(absl::is_trivially_destructible<TrivialDestructor10>::value);
+ typedef NonTrivialDestructor NonTrivialDestructor10[10];
+ EXPECT_FALSE(absl::is_trivially_destructible<NonTrivialDestructor10>::value);
+}
+
+#define ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(trait_name, ...) \
+ EXPECT_TRUE((std::is_same<typename std::trait_name<__VA_ARGS__>::type, \
+ absl::trait_name##_t<__VA_ARGS__>>::value))
+
+TEST(TypeTraitsTest, TestRemoveCVAliases) {
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_cv, int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_cv, const int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_cv, volatile int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_cv, const volatile int);
+
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_const, int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_const, const int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_const, volatile int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_const, const volatile int);
+
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_volatile, int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_volatile, const int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_volatile, volatile int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_volatile, const volatile int);
+}
+
+TEST(TypeTraitsTest, TestAddCVAliases) {
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_cv, int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_cv, const int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_cv, volatile int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_cv, const volatile int);
+
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_const, int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_const, const int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_const, volatile int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_const, const volatile int);
+
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_volatile, int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_volatile, const int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_volatile, volatile int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_volatile, const volatile int);
+}
+
+TEST(TypeTraitsTest, TestReferenceAliases) {
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, volatile int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, int&);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, volatile int&);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, int&&);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, volatile int&&);
+
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, volatile int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, int&);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, volatile int&);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, int&&);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, volatile int&&);
+
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, volatile int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, int&);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, volatile int&);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, int&&);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, volatile int&&);
+}
+
+TEST(TypeTraitsTest, TestPointerAliases) {
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_pointer, int*);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_pointer, volatile int*);
+
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_pointer, int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_pointer, volatile int);
+}
+
+TEST(TypeTraitsTest, TestSignednessAliases) {
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_signed, int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_signed, volatile int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_signed, unsigned);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_signed, volatile unsigned);
+
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_unsigned, int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_unsigned, volatile int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_unsigned, unsigned);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_unsigned, volatile unsigned);
+}
+
+TEST(TypeTraitsTest, TestExtentAliases) {
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_extent, int[]);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_extent, int[1]);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_extent, int[1][1]);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_extent, int[][1]);
+
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_all_extents, int[]);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_all_extents, int[1]);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_all_extents, int[1][1]);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_all_extents, int[][1]);
+}
+
+TEST(TypeTraitsTest, TestAlignedStorageAlias) {
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 1);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 2);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 3);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 4);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 5);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 6);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 7);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 8);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 9);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 10);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 11);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 12);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 13);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 14);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 15);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 16);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 17);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 18);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 19);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 20);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 21);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 22);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 23);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 24);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 25);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 26);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 27);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 28);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 29);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 30);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 31);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 32);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 33);
+
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 1, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 2, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 3, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 4, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 5, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 6, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 7, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 8, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 9, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 10, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 11, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 12, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 13, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 14, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 15, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 16, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 17, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 18, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 19, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 20, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 21, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 22, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 23, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 24, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 25, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 26, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 27, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 28, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 29, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 30, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 31, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 32, 128);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 33, 128);
+}
+
+TEST(TypeTraitsTest, TestDecay) {
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, volatile int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const volatile int);
+
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int&);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const int&);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, volatile int&);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const volatile int&);
+
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int&);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const int&);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, volatile int&);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const volatile int&);
+
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int[1]);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int[1][1]);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int[][1]);
+
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int());
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int(float));
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int(char, ...));
+}
+
+struct TypeA {};
+struct TypeB {};
+struct TypeC {};
+struct TypeD {};
+
+template <typename T>
+struct Wrap {};
+
+enum class TypeEnum { A, B, C, D };
+
+struct GetTypeT {
+ template <typename T,
+ absl::enable_if_t<std::is_same<T, TypeA>::value, int> = 0>
+ TypeEnum operator()(Wrap<T>) const {
+ return TypeEnum::A;
+ }
+
+ template <typename T,
+ absl::enable_if_t<std::is_same<T, TypeB>::value, int> = 0>
+ TypeEnum operator()(Wrap<T>) const {
+ return TypeEnum::B;
+ }
+
+ template <typename T,
+ absl::enable_if_t<std::is_same<T, TypeC>::value, int> = 0>
+ TypeEnum operator()(Wrap<T>) const {
+ return TypeEnum::C;
+ }
+
+ // NOTE: TypeD is intentionally not handled
+} constexpr GetType = {};
+
+TEST(TypeTraitsTest, TestEnableIf) {
+ EXPECT_EQ(TypeEnum::A, GetType(Wrap<TypeA>()));
+ EXPECT_EQ(TypeEnum::B, GetType(Wrap<TypeB>()));
+ EXPECT_EQ(TypeEnum::C, GetType(Wrap<TypeC>()));
+}
+
+TEST(TypeTraitsTest, TestConditional) {
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(conditional, true, int, char);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(conditional, false, int, char);
+}
+
+// TODO(calabrese) Check with specialized std::common_type
+TEST(TypeTraitsTest, TestCommonType) {
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int, char);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int, char, int);
+
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int&);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int, char&);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int, char, int&);
+}
+
+TEST(TypeTraitsTest, TestUnderlyingType) {
+ enum class enum_char : char {};
+ enum class enum_long_long : long long {}; // NOLINT(runtime/int)
+
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(underlying_type, enum_char);
+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(underlying_type, enum_long_long);
+}
+
+struct GetTypeExtT {
+ template <typename T>
+ absl::result_of_t<const GetTypeT&(T)> operator()(T&& arg) const {
+ return GetType(std::forward<T>(arg));
+ }
+
+ TypeEnum operator()(Wrap<TypeD>) const { return TypeEnum::D; }
+} constexpr GetTypeExt = {};
+
+TEST(TypeTraitsTest, TestResultOf) {
+ EXPECT_EQ(TypeEnum::A, GetTypeExt(Wrap<TypeA>()));
+ EXPECT_EQ(TypeEnum::B, GetTypeExt(Wrap<TypeB>()));
+ EXPECT_EQ(TypeEnum::C, GetTypeExt(Wrap<TypeC>()));
+ EXPECT_EQ(TypeEnum::D, GetTypeExt(Wrap<TypeD>()));
+}
+
+} // namespace
diff --git a/absl/numeric/BUILD.bazel b/absl/numeric/BUILD.bazel
new file mode 100644
index 0000000..2c80db3
--- /dev/null
+++ b/absl/numeric/BUILD.bazel
@@ -0,0 +1,39 @@
+load(
+ "//absl:copts.bzl",
+ "ABSL_DEFAULT_COPTS",
+ "ABSL_TEST_COPTS",
+)
+load(
+ "//absl:test_dependencies.bzl",
+ "GUNIT_MAIN_DEPS_SELECTOR",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["unencumbered"]) # Owned by Google
+
+cc_library(
+ name = "int128",
+ srcs = ["int128.cc"],
+ hdrs = ["int128.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ ],
+)
+
+cc_test(
+ name = "int128_test",
+ size = "small",
+ srcs = [
+ "int128_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":int128",
+ "//absl/base",
+ "//absl/base:core_headers",
+ "//absl/meta:type_traits",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
diff --git a/absl/numeric/int128.cc b/absl/numeric/int128.cc
new file mode 100644
index 0000000..184041f
--- /dev/null
+++ b/absl/numeric/int128.cc
@@ -0,0 +1,200 @@
+// 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/numeric/int128.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <iomanip>
+#include <iostream> // NOLINT(readability/streams)
+#include <sstream>
+
+namespace absl {
+
+const uint128 kuint128max = MakeUint128(std::numeric_limits<uint64_t>::max(),
+ std::numeric_limits<uint64_t>::max());
+
+namespace {
+
+// Returns the 0-based position of the last set bit (i.e., most significant bit)
+// in the given uint64_t. The argument may not be 0.
+//
+// For example:
+// Given: 5 (decimal) == 101 (binary)
+// Returns: 2
+#define STEP(T, n, pos, sh) \
+ do { \
+ if ((n) >= (static_cast<T>(1) << (sh))) { \
+ (n) = (n) >> (sh); \
+ (pos) |= (sh); \
+ } \
+ } while (0)
+static inline int Fls64(uint64_t n) {
+ assert(n != 0);
+ int pos = 0;
+ STEP(uint64_t, n, pos, 0x20);
+ uint32_t n32 = static_cast<uint32_t>(n);
+ STEP(uint32_t, n32, pos, 0x10);
+ STEP(uint32_t, n32, pos, 0x08);
+ STEP(uint32_t, n32, pos, 0x04);
+ return pos + ((uint64_t{0x3333333322221100} >> (n32 << 2)) & 0x3);
+}
+#undef STEP
+
+// Like Fls64() above, but returns the 0-based position of the last set bit
+// (i.e., most significant bit) in the given uint128. The argument may not be 0.
+static inline int Fls128(uint128 n) {
+ if (uint64_t hi = Uint128High64(n)) {
+ return Fls64(hi) + 64;
+ }
+ return Fls64(Uint128Low64(n));
+}
+
+// Long division/modulo for uint128 implemented using the shift-subtract
+// division algorithm adapted from:
+// http://stackoverflow.com/questions/5386377/division-without-using
+void DivModImpl(uint128 dividend, uint128 divisor, uint128* quotient_ret,
+ uint128* remainder_ret) {
+ assert(divisor != 0);
+
+ if (divisor > dividend) {
+ *quotient_ret = 0;
+ *remainder_ret = dividend;
+ return;
+ }
+
+ if (divisor == dividend) {
+ *quotient_ret = 1;
+ *remainder_ret = 0;
+ return;
+ }
+
+ uint128 denominator = divisor;
+ uint128 quotient = 0;
+
+ // Left aligns the MSB of the denominator and the dividend.
+ const int shift = Fls128(dividend) - Fls128(denominator);
+ denominator <<= shift;
+
+ // Uses shift-subtract algorithm to divide dividend by denominator. The
+ // remainder will be left in dividend.
+ for (int i = 0; i <= shift; ++i) {
+ quotient <<= 1;
+ if (dividend >= denominator) {
+ dividend -= denominator;
+ quotient |= 1;
+ }
+ denominator >>= 1;
+ }
+
+ *quotient_ret = quotient;
+ *remainder_ret = dividend;
+}
+
+template <typename T>
+uint128 Initialize128FromFloat(T v) {
+ // Rounding behavior is towards zero, same as for built-in types.
+
+ // Undefined behavior if v is NaN or cannot fit into uint128.
+ assert(!std::isnan(v) && v > -1 && v < std::ldexp(static_cast<T>(1), 128));
+
+ if (v >= std::ldexp(static_cast<T>(1), 64)) {
+ uint64_t hi = static_cast<uint64_t>(std::ldexp(v, -64));
+ uint64_t lo = static_cast<uint64_t>(v - std::ldexp(static_cast<T>(hi), 64));
+ return MakeUint128(hi, lo);
+ }
+
+ return MakeUint128(0, static_cast<uint64_t>(v));
+}
+} // namespace
+
+uint128::uint128(float v) : uint128(Initialize128FromFloat(v)) {}
+uint128::uint128(double v) : uint128(Initialize128FromFloat(v)) {}
+uint128::uint128(long double v) : uint128(Initialize128FromFloat(v)) {}
+
+uint128& uint128::operator/=(const uint128& divisor) {
+ uint128 quotient = 0;
+ uint128 remainder = 0;
+ DivModImpl(*this, divisor, &quotient, &remainder);
+ *this = quotient;
+ return *this;
+}
+uint128& uint128::operator%=(const uint128& divisor) {
+ uint128 quotient = 0;
+ uint128 remainder = 0;
+ DivModImpl(*this, divisor, &quotient, &remainder);
+ *this = remainder;
+ return *this;
+}
+
+std::ostream& operator<<(std::ostream& o, const uint128& b) {
+ std::ios_base::fmtflags flags = o.flags();
+
+ // Select a divisor which is the largest power of the base < 2^64.
+ uint128 div;
+ int div_base_log;
+ switch (flags & std::ios::basefield) {
+ case std::ios::hex:
+ div = 0x1000000000000000; // 16^15
+ div_base_log = 15;
+ break;
+ case std::ios::oct:
+ div = 01000000000000000000000; // 8^21
+ div_base_log = 21;
+ break;
+ default: // std::ios::dec
+ div = 10000000000000000000u; // 10^19
+ div_base_log = 19;
+ break;
+ }
+
+ // Now piece together the uint128 representation from three chunks of
+ // the original value, each less than "div" and therefore representable
+ // as a uint64_t.
+ std::ostringstream os;
+ std::ios_base::fmtflags copy_mask =
+ std::ios::basefield | std::ios::showbase | std::ios::uppercase;
+ os.setf(flags & copy_mask, copy_mask);
+ uint128 high = b;
+ uint128 low;
+ DivModImpl(high, div, &high, &low);
+ uint128 mid;
+ DivModImpl(high, div, &high, &mid);
+ if (Uint128Low64(high) != 0) {
+ os << Uint128Low64(high);
+ os << std::noshowbase << std::setfill('0') << std::setw(div_base_log);
+ os << Uint128Low64(mid);
+ os << std::setw(div_base_log);
+ } else if (Uint128Low64(mid) != 0) {
+ os << Uint128Low64(mid);
+ os << std::noshowbase << std::setfill('0') << std::setw(div_base_log);
+ }
+ os << Uint128Low64(low);
+ std::string rep = os.str();
+
+ // Add the requisite padding.
+ std::streamsize width = o.width(0);
+ if (static_cast<size_t>(width) > rep.size()) {
+ if ((flags & std::ios::adjustfield) == std::ios::left) {
+ rep.append(width - rep.size(), o.fill());
+ } else {
+ rep.insert(0, width - rep.size(), o.fill());
+ }
+ }
+
+ // Stream the final representation in a single "<<" call.
+ return o << rep;
+}
+
+} // namespace absl
diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h
new file mode 100644
index 0000000..72be806
--- /dev/null
+++ b/absl/numeric/int128.h
@@ -0,0 +1,651 @@
+//
+// 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: int128.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines 128-bit integer types. Currently, this file defines
+// `uint128`, an unsigned 128-bit integer; a signed 128-bit integer is
+// forthcoming.
+
+#ifndef ABSL_NUMERIC_INT128_H_
+#define ABSL_NUMERIC_INT128_H_
+
+#include <cassert>
+#include <cmath>
+#include <cstdint>
+#include <cstring>
+#include <iosfwd>
+#include <limits>
+
+#include "absl/base/config.h"
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+
+namespace absl {
+
+// uint128
+//
+// An unsigned 128-bit integer type. The API is meant to mimic an intrinsic type
+// as closely as is practical, including exhibiting undefined behavior in
+// analogous cases (e.g. division by zero). This type is intended to be a
+// drop-in replacement once C++ supports an intrinsic `uint128_t` type; when
+// that occurs, existing uses of `uint128` will continue to work using that new
+// type.
+//
+// Note: code written with this type will continue to compile once `unint128_t`
+// is introduced, provided the replacement helper functions
+// `Uint128(Low|High)64()` and `MakeUint128()` are made.
+//
+// A `uint128` supports the following:
+//
+// * Implicit construction from integral types
+// * Explicit conversion to integral types
+//
+// Additionally, if your compiler supports `__int128`, `uint128` is
+// interoperable with that type. (Abseil checks for this compatibility through
+// the `ABSL_HAVE_INTRINSIC_INT128` macro.)
+//
+// However, a `uint128` differs from intrinsic integral types in the following
+// ways:
+//
+// * Errors on implicit conversions that does not preserve value (such as
+// loss of precision when converting to float values).
+// * Requires explicit construction from and conversion to floating point
+// types.
+// * Conversion to integral types requires an explicit static_cast() to
+// mimic use of the `-Wnarrowing` compiler flag.
+//
+// Example:
+//
+// float y = kuint128max; // Error. uint128 cannot be implicitly converted
+// // to float.
+//
+// uint128 v;
+// uint64_t i = v // Error
+// uint64_t i = static_cast<uint64_t>(v) // OK
+//
+// NOTE: the alignment requirement of `uint128` is due to change, so users
+// should take care to avoid depending on the current 8 byte alignment.
+// TODO(strel) Remove alignment note above once alignof(uint128) becomes 16.
+class uint128 {
+ public:
+ uint128() = default;
+
+ // Constructors from arithmetic types
+ constexpr uint128(int v); // NOLINT(runtime/explicit)
+ constexpr uint128(unsigned int v); // NOLINT(runtime/explicit)
+ constexpr uint128(long v); // NOLINT(runtime/int)
+ constexpr uint128(unsigned long v); // NOLINT(runtime/int)
+ constexpr uint128(long long v); // NOLINT(runtime/int)
+ constexpr uint128(unsigned long long v); // NOLINT(runtime/int)
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+ constexpr uint128(__int128 v); // NOLINT(runtime/explicit)
+ constexpr uint128(unsigned __int128 v); // NOLINT(runtime/explicit)
+#endif // ABSL_HAVE_INTRINSIC_INT128
+ explicit uint128(float v); // NOLINT(runtime/explicit)
+ explicit uint128(double v); // NOLINT(runtime/explicit)
+ explicit uint128(long double v); // NOLINT(runtime/explicit)
+
+ // Assignment operators from arithmetic types
+ uint128& operator=(int v);
+ uint128& operator=(unsigned int v);
+ uint128& operator=(long v); // NOLINT(runtime/int)
+ uint128& operator=(unsigned long v); // NOLINT(runtime/int)
+ uint128& operator=(long long v); // NOLINT(runtime/int)
+ uint128& operator=(unsigned long long v); // NOLINT(runtime/int)
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+ uint128& operator=(__int128 v);
+ uint128& operator=(unsigned __int128 v);
+#endif // ABSL_HAVE_INTRINSIC_INT128
+
+ // Conversion operators to other arithmetic types
+ constexpr explicit operator bool() const;
+ constexpr explicit operator char() const;
+ constexpr explicit operator signed char() const;
+ constexpr explicit operator unsigned char() const;
+ constexpr explicit operator char16_t() const;
+ constexpr explicit operator char32_t() const;
+ constexpr explicit operator wchar_t() const;
+ constexpr explicit operator short() const; // NOLINT(runtime/int)
+ // NOLINTNEXTLINE(runtime/int)
+ constexpr explicit operator unsigned short() const;
+ constexpr explicit operator int() const;
+ constexpr explicit operator unsigned int() const;
+ constexpr explicit operator long() const; // NOLINT(runtime/int)
+ // NOLINTNEXTLINE(runtime/int)
+ constexpr explicit operator unsigned long() const;
+ // NOLINTNEXTLINE(runtime/int)
+ constexpr explicit operator long long() const;
+ // NOLINTNEXTLINE(runtime/int)
+ constexpr explicit operator unsigned long long() const;
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+ constexpr explicit operator __int128() const;
+ constexpr explicit operator unsigned __int128() const;
+#endif // ABSL_HAVE_INTRINSIC_INT128
+ explicit operator float() const;
+ explicit operator double() const;
+ explicit operator long double() const;
+
+ // Trivial copy constructor, assignment operator and destructor.
+
+ // Arithmetic operators.
+ uint128& operator+=(const uint128& other);
+ uint128& operator-=(const uint128& other);
+ uint128& operator*=(const uint128& other);
+ // Long division/modulo for uint128.
+ uint128& operator/=(const uint128& other);
+ uint128& operator%=(const uint128& other);
+ uint128 operator++(int);
+ uint128 operator--(int);
+ uint128& operator<<=(int);
+ uint128& operator>>=(int);
+ uint128& operator&=(const uint128& other);
+ uint128& operator|=(const uint128& other);
+ uint128& operator^=(const uint128& other);
+ uint128& operator++();
+ uint128& operator--();
+
+ // Uint128Low64()
+ //
+ // Returns the lower 64-bit value of a `uint128` value.
+ friend uint64_t Uint128Low64(const uint128& v);
+
+ // Uint128High64()
+ //
+ // Returns the higher 64-bit value of a `uint128` value.
+ friend uint64_t Uint128High64(const uint128& v);
+
+ // MakeUInt128()
+ //
+ // Constructs a `uint128` numeric value from two 64-bit unsigned integers.
+ // Note that this factory function is the only way to construct a `uint128`
+ // from integer values greater than 2^64.
+ //
+ // Example:
+ //
+ // absl::uint128 big = absl::MakeUint128(1, 0);
+ friend constexpr uint128 MakeUint128(uint64_t top, uint64_t bottom);
+
+ private:
+ constexpr uint128(uint64_t top, uint64_t bottom);
+
+ // TODO(strel) Update implementation to use __int128 once all users of
+ // uint128 are fixed to not depend on alignof(uint128) == 8. Also add
+ // alignas(16) to class definition to keep alignment consistent across
+ // platforms.
+#if defined(ABSL_IS_LITTLE_ENDIAN)
+ uint64_t lo_;
+ uint64_t hi_;
+#elif defined(ABSL_IS_BIG_ENDIAN)
+ uint64_t hi_;
+ uint64_t lo_;
+#else // byte order
+#error "Unsupported byte order: must be little-endian or big-endian."
+#endif // byte order
+};
+
+extern const uint128 kuint128max;
+
+// allow uint128 to be logged
+extern std::ostream& operator<<(std::ostream& o, const uint128& b);
+
+// TODO(strel) add operator>>(std::istream&, uint128&)
+
+// Methods to access low and high pieces of 128-bit value.
+uint64_t Uint128Low64(const uint128& v);
+uint64_t Uint128High64(const uint128& v);
+
+// TODO(b/31950287): Implement signed 128-bit type
+
+// --------------------------------------------------------------------------
+// Implementation details follow
+// --------------------------------------------------------------------------
+
+inline constexpr uint128 MakeUint128(uint64_t top, uint64_t bottom) {
+ return uint128(top, bottom);
+}
+
+// Assignment from integer types.
+
+inline uint128& uint128::operator=(int v) {
+ return *this = uint128(v);
+}
+
+inline uint128& uint128::operator=(unsigned int v) {
+ return *this = uint128(v);
+}
+
+inline uint128& uint128::operator=(long v) { // NOLINT(runtime/int)
+ return *this = uint128(v);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+inline uint128& uint128::operator=(unsigned long v) {
+ return *this = uint128(v);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+inline uint128& uint128::operator=(long long v) {
+ return *this = uint128(v);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+inline uint128& uint128::operator=(unsigned long long v) {
+ return *this = uint128(v);
+}
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+inline uint128& uint128::operator=(__int128 v) {
+ return *this = uint128(v);
+}
+
+inline uint128& uint128::operator=(unsigned __int128 v) {
+ return *this = uint128(v);
+}
+#endif // ABSL_HAVE_INTRINSIC_INT128
+
+// Shift and arithmetic operators.
+
+inline uint128 operator<<(const uint128& lhs, int amount) {
+ return uint128(lhs) <<= amount;
+}
+
+inline uint128 operator>>(const uint128& lhs, int amount) {
+ return uint128(lhs) >>= amount;
+}
+
+inline uint128 operator+(const uint128& lhs, const uint128& rhs) {
+ return uint128(lhs) += rhs;
+}
+
+inline uint128 operator-(const uint128& lhs, const uint128& rhs) {
+ return uint128(lhs) -= rhs;
+}
+
+inline uint128 operator*(const uint128& lhs, const uint128& rhs) {
+ return uint128(lhs) *= rhs;
+}
+
+inline uint128 operator/(const uint128& lhs, const uint128& rhs) {
+ return uint128(lhs) /= rhs;
+}
+
+inline uint128 operator%(const uint128& lhs, const uint128& rhs) {
+ return uint128(lhs) %= rhs;
+}
+
+inline uint64_t Uint128Low64(const uint128& v) { return v.lo_; }
+
+inline uint64_t Uint128High64(const uint128& v) { return v.hi_; }
+
+// Constructors from integer types.
+
+#if defined(ABSL_IS_LITTLE_ENDIAN)
+
+inline constexpr uint128::uint128(uint64_t top, uint64_t bottom)
+ : lo_(bottom), hi_(top) {}
+
+inline constexpr uint128::uint128(int v)
+ : lo_(v), hi_(v < 0 ? std::numeric_limits<uint64_t>::max() : 0) {}
+inline constexpr uint128::uint128(long v) // NOLINT(runtime/int)
+ : lo_(v), hi_(v < 0 ? std::numeric_limits<uint64_t>::max() : 0) {}
+inline constexpr uint128::uint128(long long v) // NOLINT(runtime/int)
+ : lo_(v), hi_(v < 0 ? std::numeric_limits<uint64_t>::max() : 0) {}
+
+inline constexpr uint128::uint128(unsigned int v) : lo_(v), hi_(0) {}
+// NOLINTNEXTLINE(runtime/int)
+inline constexpr uint128::uint128(unsigned long v) : lo_(v), hi_(0) {}
+// NOLINTNEXTLINE(runtime/int)
+inline constexpr uint128::uint128(unsigned long long v)
+ : lo_(v), hi_(0) {}
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+inline constexpr uint128::uint128(__int128 v)
+ : lo_(static_cast<uint64_t>(v & ~uint64_t{0})),
+ hi_(static_cast<uint64_t>(static_cast<unsigned __int128>(v) >> 64)) {}
+inline constexpr uint128::uint128(unsigned __int128 v)
+ : lo_(static_cast<uint64_t>(v & ~uint64_t{0})),
+ hi_(static_cast<uint64_t>(v >> 64)) {}
+#endif // ABSL_HAVE_INTRINSIC_INT128
+
+#elif defined(ABSL_IS_BIG_ENDIAN)
+
+inline constexpr uint128::uint128(uint64_t top, uint64_t bottom)
+ : hi_(top), lo_(bottom) {}
+
+inline constexpr uint128::uint128(int v)
+ : hi_(v < 0 ? std::numeric_limits<uint64_t>::max() : 0), lo_(v) {}
+inline constexpr uint128::uint128(long v) // NOLINT(runtime/int)
+ : hi_(v < 0 ? std::numeric_limits<uint64_t>::max() : 0), lo_(v) {}
+inline constexpr uint128::uint128(long long v) // NOLINT(runtime/int)
+ : hi_(v < 0 ? std::numeric_limits<uint64_t>::max() : 0), lo_(v) {}
+
+inline constexpr uint128::uint128(unsigned int v) : hi_(0), lo_(v) {}
+// NOLINTNEXTLINE(runtime/int)
+inline constexpr uint128::uint128(unsigned long v) : hi_(0), lo_(v) {}
+// NOLINTNEXTLINE(runtime/int)
+inline constexpr uint128::uint128(unsigned long long v)
+ : hi_(0), lo_(v) {}
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+inline constexpr uint128::uint128(__int128 v)
+ : hi_(static_cast<uint64_t>(static_cast<unsigned __int128>(v) >> 64)),
+ lo_(static_cast<uint64_t>(v & ~uint64_t{0})) {}
+inline constexpr uint128::uint128(unsigned __int128 v)
+ : hi_(static_cast<uint64_t>(v >> 64)),
+ lo_(static_cast<uint64_t>(v & ~uint64_t{0})) {}
+#endif // ABSL_HAVE_INTRINSIC_INT128
+
+#else // byte order
+#error "Unsupported byte order: must be little-endian or big-endian."
+#endif // byte order
+
+// Conversion operators to integer types.
+
+inline constexpr uint128::operator bool() const {
+ return lo_ || hi_;
+}
+
+inline constexpr uint128::operator char() const {
+ return static_cast<char>(lo_);
+}
+
+inline constexpr uint128::operator signed char() const {
+ return static_cast<signed char>(lo_);
+}
+
+inline constexpr uint128::operator unsigned char() const {
+ return static_cast<unsigned char>(lo_);
+}
+
+inline constexpr uint128::operator char16_t() const {
+ return static_cast<char16_t>(lo_);
+}
+
+inline constexpr uint128::operator char32_t() const {
+ return static_cast<char32_t>(lo_);
+}
+
+inline constexpr uint128::operator wchar_t() const {
+ return static_cast<wchar_t>(lo_);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+inline constexpr uint128::operator short() const {
+ return static_cast<short>(lo_); // NOLINT(runtime/int)
+}
+
+// NOLINTNEXTLINE(runtime/int)
+inline constexpr uint128::operator unsigned short() const {
+ return static_cast<unsigned short>(lo_); // NOLINT(runtime/int)
+}
+
+inline constexpr uint128::operator int() const {
+ return static_cast<int>(lo_);
+}
+
+inline constexpr uint128::operator unsigned int() const {
+ return static_cast<unsigned int>(lo_);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+inline constexpr uint128::operator long() const {
+ return static_cast<long>(lo_); // NOLINT(runtime/int)
+}
+
+// NOLINTNEXTLINE(runtime/int)
+inline constexpr uint128::operator unsigned long() const {
+ return static_cast<unsigned long>(lo_); // NOLINT(runtime/int)
+}
+
+// NOLINTNEXTLINE(runtime/int)
+inline constexpr uint128::operator long long() const {
+ return static_cast<long long>(lo_); // NOLINT(runtime/int)
+}
+
+// NOLINTNEXTLINE(runtime/int)
+inline constexpr uint128::operator unsigned long long() const {
+ return static_cast<unsigned long long>(lo_); // NOLINT(runtime/int)
+}
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+inline constexpr uint128::operator __int128() const {
+ return (static_cast<__int128>(hi_) << 64) + lo_;
+}
+
+inline constexpr uint128::operator unsigned __int128() const {
+ return (static_cast<unsigned __int128>(hi_) << 64) + lo_;
+}
+#endif // ABSL_HAVE_INTRINSIC_INT128
+
+// Conversion operators to floating point types.
+
+inline uint128::operator float() const {
+ return static_cast<float>(lo_) + std::ldexp(static_cast<float>(hi_), 64);
+}
+
+inline uint128::operator double() const {
+ return static_cast<double>(lo_) + std::ldexp(static_cast<double>(hi_), 64);
+}
+
+inline uint128::operator long double() const {
+ return static_cast<long double>(lo_) +
+ std::ldexp(static_cast<long double>(hi_), 64);
+}
+
+// Comparison operators.
+
+inline bool operator==(const uint128& lhs, const uint128& rhs) {
+ return (Uint128Low64(lhs) == Uint128Low64(rhs) &&
+ Uint128High64(lhs) == Uint128High64(rhs));
+}
+
+inline bool operator!=(const uint128& lhs, const uint128& rhs) {
+ return !(lhs == rhs);
+}
+
+inline bool operator<(const uint128& lhs, const uint128& rhs) {
+ return (Uint128High64(lhs) == Uint128High64(rhs))
+ ? (Uint128Low64(lhs) < Uint128Low64(rhs))
+ : (Uint128High64(lhs) < Uint128High64(rhs));
+}
+
+inline bool operator>(const uint128& lhs, const uint128& rhs) {
+ return (Uint128High64(lhs) == Uint128High64(rhs))
+ ? (Uint128Low64(lhs) > Uint128Low64(rhs))
+ : (Uint128High64(lhs) > Uint128High64(rhs));
+}
+
+inline bool operator<=(const uint128& lhs, const uint128& rhs) {
+ return (Uint128High64(lhs) == Uint128High64(rhs))
+ ? (Uint128Low64(lhs) <= Uint128Low64(rhs))
+ : (Uint128High64(lhs) <= Uint128High64(rhs));
+}
+
+inline bool operator>=(const uint128& lhs, const uint128& rhs) {
+ return (Uint128High64(lhs) == Uint128High64(rhs))
+ ? (Uint128Low64(lhs) >= Uint128Low64(rhs))
+ : (Uint128High64(lhs) >= Uint128High64(rhs));
+}
+
+// Unary operators.
+
+inline uint128 operator-(const uint128& val) {
+ const uint64_t hi_flip = ~Uint128High64(val);
+ const uint64_t lo_flip = ~Uint128Low64(val);
+ const uint64_t lo_add = lo_flip + 1;
+ if (lo_add < lo_flip) {
+ return MakeUint128(hi_flip + 1, lo_add);
+ }
+ return MakeUint128(hi_flip, lo_add);
+}
+
+inline bool operator!(const uint128& val) {
+ return !Uint128High64(val) && !Uint128Low64(val);
+}
+
+// Logical operators.
+
+inline uint128 operator~(const uint128& val) {
+ return MakeUint128(~Uint128High64(val), ~Uint128Low64(val));
+}
+
+inline uint128 operator|(const uint128& lhs, const uint128& rhs) {
+ return MakeUint128(Uint128High64(lhs) | Uint128High64(rhs),
+ Uint128Low64(lhs) | Uint128Low64(rhs));
+}
+
+inline uint128 operator&(const uint128& lhs, const uint128& rhs) {
+ return MakeUint128(Uint128High64(lhs) & Uint128High64(rhs),
+ Uint128Low64(lhs) & Uint128Low64(rhs));
+}
+
+inline uint128 operator^(const uint128& lhs, const uint128& rhs) {
+ return MakeUint128(Uint128High64(lhs) ^ Uint128High64(rhs),
+ Uint128Low64(lhs) ^ Uint128Low64(rhs));
+}
+
+inline uint128& uint128::operator|=(const uint128& other) {
+ hi_ |= other.hi_;
+ lo_ |= other.lo_;
+ return *this;
+}
+
+inline uint128& uint128::operator&=(const uint128& other) {
+ hi_ &= other.hi_;
+ lo_ &= other.lo_;
+ return *this;
+}
+
+inline uint128& uint128::operator^=(const uint128& other) {
+ hi_ ^= other.hi_;
+ lo_ ^= other.lo_;
+ return *this;
+}
+
+// Shift and arithmetic assign operators.
+
+inline uint128& uint128::operator<<=(int amount) {
+ // Shifts of >= 128 are undefined.
+ assert(amount < 128);
+
+ // uint64_t shifts of >= 64 are undefined, so we will need some
+ // special-casing.
+ if (amount < 64) {
+ if (amount != 0) {
+ hi_ = (hi_ << amount) | (lo_ >> (64 - amount));
+ lo_ = lo_ << amount;
+ }
+ } else {
+ hi_ = lo_ << (amount - 64);
+ lo_ = 0;
+ }
+ return *this;
+}
+
+inline uint128& uint128::operator>>=(int amount) {
+ // Shifts of >= 128 are undefined.
+ assert(amount < 128);
+
+ // uint64_t shifts of >= 64 are undefined, so we will need some
+ // special-casing.
+ if (amount < 64) {
+ if (amount != 0) {
+ lo_ = (lo_ >> amount) | (hi_ << (64 - amount));
+ hi_ = hi_ >> amount;
+ }
+ } else {
+ lo_ = hi_ >> (amount - 64);
+ hi_ = 0;
+ }
+ return *this;
+}
+
+inline uint128& uint128::operator+=(const uint128& other) {
+ hi_ += other.hi_;
+ uint64_t lolo = lo_ + other.lo_;
+ if (lolo < lo_)
+ ++hi_;
+ lo_ = lolo;
+ return *this;
+}
+
+inline uint128& uint128::operator-=(const uint128& other) {
+ hi_ -= other.hi_;
+ if (other.lo_ > lo_) --hi_;
+ lo_ -= other.lo_;
+ return *this;
+}
+
+inline uint128& uint128::operator*=(const uint128& other) {
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+ // TODO(strel) Remove once alignment issues are resolved and unsigned __int128
+ // can be used for uint128 storage.
+ *this = static_cast<unsigned __int128>(*this) *
+ static_cast<unsigned __int128>(other);
+ return *this;
+#else // ABSL_HAVE_INTRINSIC128
+ uint64_t a96 = hi_ >> 32;
+ uint64_t a64 = hi_ & 0xffffffff;
+ uint64_t a32 = lo_ >> 32;
+ uint64_t a00 = lo_ & 0xffffffff;
+ uint64_t b96 = other.hi_ >> 32;
+ uint64_t b64 = other.hi_ & 0xffffffff;
+ uint64_t b32 = other.lo_ >> 32;
+ uint64_t b00 = other.lo_ & 0xffffffff;
+ // multiply [a96 .. a00] x [b96 .. b00]
+ // terms higher than c96 disappear off the high side
+ // terms c96 and c64 are safe to ignore carry bit
+ uint64_t c96 = a96 * b00 + a64 * b32 + a32 * b64 + a00 * b96;
+ uint64_t c64 = a64 * b00 + a32 * b32 + a00 * b64;
+ this->hi_ = (c96 << 32) + c64;
+ this->lo_ = 0;
+ // add terms after this one at a time to capture carry
+ *this += uint128(a32 * b00) << 32;
+ *this += uint128(a00 * b32) << 32;
+ *this += a00 * b00;
+ return *this;
+#endif // ABSL_HAVE_INTRINSIC128
+}
+
+// Increment/decrement operators.
+
+inline uint128 uint128::operator++(int) {
+ uint128 tmp(*this);
+ *this += 1;
+ return tmp;
+}
+
+inline uint128 uint128::operator--(int) {
+ uint128 tmp(*this);
+ *this -= 1;
+ return tmp;
+}
+
+inline uint128& uint128::operator++() {
+ *this += 1;
+ return *this;
+}
+
+inline uint128& uint128::operator--() {
+ *this -= 1;
+ return *this;
+}
+
+} // namespace absl
+
+#endif // ABSL_NUMERIC_INT128_H_
diff --git a/absl/numeric/int128_have_intrinsic.inc b/absl/numeric/int128_have_intrinsic.inc
new file mode 100644
index 0000000..bb6491e
--- /dev/null
+++ b/absl/numeric/int128_have_intrinsic.inc
@@ -0,0 +1,3 @@
+// This file will contain :int128 implementation details that depend on internal
+// representation when ABSL_HAVE_INTRINSIC_INT128 is defined. This file will be
+// included by int128.h. \ No newline at end of file
diff --git a/absl/numeric/int128_no_intrinsic.inc b/absl/numeric/int128_no_intrinsic.inc
new file mode 100644
index 0000000..2dbff2b
--- /dev/null
+++ b/absl/numeric/int128_no_intrinsic.inc
@@ -0,0 +1,3 @@
+// This file will contain :int128 implementation details that depend on internal
+// representation when ABSL_HAVE_INTRINSIC_INT128 is *not* defined. This file
+// will be included by int128.h.
diff --git a/absl/numeric/int128_test.cc b/absl/numeric/int128_test.cc
new file mode 100644
index 0000000..c8aabeb
--- /dev/null
+++ b/absl/numeric/int128_test.cc
@@ -0,0 +1,492 @@
+// 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/numeric/int128.h"
+
+#include <algorithm>
+#include <limits>
+#include <random>
+#include <sstream>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/cycleclock.h"
+#include "absl/meta/type_traits.h"
+
+#if defined(_MSC_VER) && _MSC_VER == 1900
+// Disable "unary minus operator applied to unsigned type" warnings in Microsoft
+// Visual C++ 14 (2015).
+#pragma warning(disable:4146)
+#endif
+
+namespace {
+
+template <typename T>
+class Uint128IntegerTraitsTest : public ::testing::Test {};
+typedef ::testing::Types<bool, char, signed char, unsigned char, char16_t,
+ char32_t, wchar_t,
+ short, // NOLINT(runtime/int)
+ unsigned short, // NOLINT(runtime/int)
+ int, unsigned int,
+ long, // NOLINT(runtime/int)
+ unsigned long, // NOLINT(runtime/int)
+ long long, // NOLINT(runtime/int)
+ unsigned long long> // NOLINT(runtime/int)
+ IntegerTypes;
+
+template <typename T>
+class Uint128FloatTraitsTest : public ::testing::Test {};
+typedef ::testing::Types<float, double, long double> FloatingPointTypes;
+
+TYPED_TEST_CASE(Uint128IntegerTraitsTest, IntegerTypes);
+
+TYPED_TEST(Uint128IntegerTraitsTest, ConstructAssignTest) {
+ static_assert(std::is_constructible<absl::uint128, TypeParam>::value,
+ "absl::uint128 must be constructible from TypeParam");
+ static_assert(std::is_assignable<absl::uint128&, TypeParam>::value,
+ "absl::uint128 must be assignable from TypeParam");
+ static_assert(!std::is_assignable<TypeParam&, absl::uint128>::value,
+ "TypeParam must not be assignable from absl::uint128");
+}
+
+TYPED_TEST_CASE(Uint128FloatTraitsTest, FloatingPointTypes);
+
+TYPED_TEST(Uint128FloatTraitsTest, ConstructAssignTest) {
+ static_assert(std::is_constructible<absl::uint128, TypeParam>::value,
+ "absl::uint128 must be constructible from TypeParam");
+ static_assert(!std::is_assignable<absl::uint128&, TypeParam>::value,
+ "absl::uint128 must not be assignable from TypeParam");
+ static_assert(!std::is_assignable<TypeParam&, absl::uint128>::value,
+ "TypeParam must not be assignable from absl::uint128");
+}
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+// These type traits done separately as TYPED_TEST requires typeinfo, and not
+// all platforms have this for __int128 even though they define the type.
+TEST(Uint128, IntrinsicTypeTraitsTest) {
+ static_assert(std::is_constructible<absl::uint128, __int128>::value,
+ "absl::uint128 must be constructible from __int128");
+ static_assert(std::is_assignable<absl::uint128&, __int128>::value,
+ "absl::uint128 must be assignable from __int128");
+ static_assert(!std::is_assignable<__int128&, absl::uint128>::value,
+ "__int128 must not be assignable from absl::uint128");
+
+ static_assert(std::is_constructible<absl::uint128, unsigned __int128>::value,
+ "absl::uint128 must be constructible from unsigned __int128");
+ static_assert(std::is_assignable<absl::uint128&, unsigned __int128>::value,
+ "absl::uint128 must be assignable from unsigned __int128");
+ static_assert(!std::is_assignable<unsigned __int128&, absl::uint128>::value,
+ "unsigned __int128 must not be assignable from absl::uint128");
+}
+#endif // ABSL_HAVE_INTRINSIC_INT128
+
+TEST(Uint128, AllTests) {
+ absl::uint128 zero = 0;
+ absl::uint128 one = 1;
+ absl::uint128 one_2arg = absl::MakeUint128(0, 1);
+ absl::uint128 two = 2;
+ absl::uint128 three = 3;
+ absl::uint128 big = absl::MakeUint128(2000, 2);
+ absl::uint128 big_minus_one = absl::MakeUint128(2000, 1);
+ absl::uint128 bigger = absl::MakeUint128(2001, 1);
+ absl::uint128 biggest = absl::kuint128max;
+ absl::uint128 high_low = absl::MakeUint128(1, 0);
+ absl::uint128 low_high =
+ absl::MakeUint128(0, std::numeric_limits<uint64_t>::max());
+ EXPECT_LT(one, two);
+ EXPECT_GT(two, one);
+ EXPECT_LT(one, big);
+ EXPECT_LT(one, big);
+ EXPECT_EQ(one, one_2arg);
+ EXPECT_NE(one, two);
+ EXPECT_GT(big, one);
+ EXPECT_GE(big, two);
+ EXPECT_GE(big, big_minus_one);
+ EXPECT_GT(big, big_minus_one);
+ EXPECT_LT(big_minus_one, big);
+ EXPECT_LE(big_minus_one, big);
+ EXPECT_NE(big_minus_one, big);
+ EXPECT_LT(big, biggest);
+ EXPECT_LE(big, biggest);
+ EXPECT_GT(biggest, big);
+ EXPECT_GE(biggest, big);
+ EXPECT_EQ(big, ~~big);
+ EXPECT_EQ(one, one | one);
+ EXPECT_EQ(big, big | big);
+ EXPECT_EQ(one, one | zero);
+ EXPECT_EQ(one, one & one);
+ EXPECT_EQ(big, big & big);
+ EXPECT_EQ(zero, one & zero);
+ EXPECT_EQ(zero, big & ~big);
+ EXPECT_EQ(zero, one ^ one);
+ EXPECT_EQ(zero, big ^ big);
+ EXPECT_EQ(one, one ^ zero);
+
+ // Shift operators.
+ EXPECT_EQ(big, big << 0);
+ EXPECT_EQ(big, big >> 0);
+ EXPECT_GT(big << 1, big);
+ EXPECT_LT(big >> 1, big);
+ EXPECT_EQ(big, (big << 10) >> 10);
+ EXPECT_EQ(big, (big >> 1) << 1);
+ EXPECT_EQ(one, (one << 80) >> 80);
+ EXPECT_EQ(zero, (one >> 80) << 80);
+
+ // Shift assignments.
+ absl::uint128 big_copy = big;
+ EXPECT_EQ(big << 0, big_copy <<= 0);
+ big_copy = big;
+ EXPECT_EQ(big >> 0, big_copy >>= 0);
+ big_copy = big;
+ EXPECT_EQ(big << 1, big_copy <<= 1);
+ big_copy = big;
+ EXPECT_EQ(big >> 1, big_copy >>= 1);
+ big_copy = big;
+ EXPECT_EQ(big << 10, big_copy <<= 10);
+ big_copy = big;
+ EXPECT_EQ(big >> 10, big_copy >>= 10);
+ big_copy = big;
+ EXPECT_EQ(big << 64, big_copy <<= 64);
+ big_copy = big;
+ EXPECT_EQ(big >> 64, big_copy >>= 64);
+ big_copy = big;
+ EXPECT_EQ(big << 73, big_copy <<= 73);
+ big_copy = big;
+ EXPECT_EQ(big >> 73, big_copy >>= 73);
+
+ EXPECT_EQ(Uint128High64(biggest), std::numeric_limits<uint64_t>::max());
+ EXPECT_EQ(Uint128Low64(biggest), std::numeric_limits<uint64_t>::max());
+ EXPECT_EQ(zero + one, one);
+ EXPECT_EQ(one + one, two);
+ EXPECT_EQ(big_minus_one + one, big);
+ EXPECT_EQ(one - one, zero);
+ EXPECT_EQ(one - zero, one);
+ EXPECT_EQ(zero - one, biggest);
+ EXPECT_EQ(big - big, zero);
+ EXPECT_EQ(big - one, big_minus_one);
+ EXPECT_EQ(big + std::numeric_limits<uint64_t>::max(), bigger);
+ EXPECT_EQ(biggest + 1, zero);
+ EXPECT_EQ(zero - 1, biggest);
+ EXPECT_EQ(high_low - one, low_high);
+ EXPECT_EQ(low_high + one, high_low);
+ EXPECT_EQ(Uint128High64((absl::uint128(1) << 64) - 1), 0);
+ EXPECT_EQ(Uint128Low64((absl::uint128(1) << 64) - 1),
+ std::numeric_limits<uint64_t>::max());
+ EXPECT_TRUE(!!one);
+ EXPECT_TRUE(!!high_low);
+ EXPECT_FALSE(!!zero);
+ EXPECT_FALSE(!one);
+ EXPECT_FALSE(!high_low);
+ EXPECT_TRUE(!zero);
+ EXPECT_TRUE(zero == 0); // NOLINT(readability/check)
+ EXPECT_FALSE(zero != 0); // NOLINT(readability/check)
+ EXPECT_FALSE(one == 0); // NOLINT(readability/check)
+ EXPECT_TRUE(one != 0); // NOLINT(readability/check)
+ EXPECT_FALSE(high_low == 0); // NOLINT(readability/check)
+ EXPECT_TRUE(high_low != 0); // NOLINT(readability/check)
+
+ absl::uint128 test = zero;
+ EXPECT_EQ(++test, one);
+ EXPECT_EQ(test, one);
+ EXPECT_EQ(test++, one);
+ EXPECT_EQ(test, two);
+ EXPECT_EQ(test -= 2, zero);
+ EXPECT_EQ(test, zero);
+ EXPECT_EQ(test += 2, two);
+ EXPECT_EQ(test, two);
+ EXPECT_EQ(--test, one);
+ EXPECT_EQ(test, one);
+ EXPECT_EQ(test--, one);
+ EXPECT_EQ(test, zero);
+ EXPECT_EQ(test |= three, three);
+ EXPECT_EQ(test &= one, one);
+ EXPECT_EQ(test ^= three, two);
+ EXPECT_EQ(test >>= 1, one);
+ EXPECT_EQ(test <<= 1, two);
+
+ EXPECT_EQ(big, -(-big));
+ EXPECT_EQ(two, -((-one) - 1));
+ EXPECT_EQ(absl::kuint128max, -one);
+ EXPECT_EQ(zero, -zero);
+}
+
+TEST(Uint128, ConversionTests) {
+ EXPECT_TRUE(absl::MakeUint128(1, 0));
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+ unsigned __int128 intrinsic =
+ (static_cast<unsigned __int128>(0x3a5b76c209de76f6) << 64) +
+ 0x1f25e1d63a2b46c5;
+ absl::uint128 custom =
+ absl::MakeUint128(0x3a5b76c209de76f6, 0x1f25e1d63a2b46c5);
+
+ EXPECT_EQ(custom, absl::uint128(intrinsic));
+ EXPECT_EQ(custom, absl::uint128(static_cast<__int128>(intrinsic)));
+ EXPECT_EQ(intrinsic, static_cast<unsigned __int128>(custom));
+ EXPECT_EQ(intrinsic, static_cast<__int128>(custom));
+#endif // ABSL_HAVE_INTRINSIC_INT128
+
+ // verify that an integer greater than 2**64 that can be stored precisely
+ // inside a double is converted to a absl::uint128 without loss of
+ // information.
+ double precise_double = 0x530e * std::pow(2.0, 64.0) + 0xda74000000000000;
+ absl::uint128 from_precise_double(precise_double);
+ absl::uint128 from_precise_ints =
+ absl::MakeUint128(0x530e, 0xda74000000000000);
+ EXPECT_EQ(from_precise_double, from_precise_ints);
+ EXPECT_DOUBLE_EQ(static_cast<double>(from_precise_ints), precise_double);
+
+ double approx_double = 0xffffeeeeddddcccc * std::pow(2.0, 64.0) +
+ 0xbbbbaaaa99998888;
+ absl::uint128 from_approx_double(approx_double);
+ EXPECT_DOUBLE_EQ(static_cast<double>(from_approx_double), approx_double);
+
+ double round_to_zero = 0.7;
+ double round_to_five = 5.8;
+ double round_to_nine = 9.3;
+ EXPECT_EQ(static_cast<absl::uint128>(round_to_zero), 0);
+ EXPECT_EQ(static_cast<absl::uint128>(round_to_five), 5);
+ EXPECT_EQ(static_cast<absl::uint128>(round_to_nine), 9);
+}
+
+TEST(Uint128, OperatorAssignReturnRef) {
+ absl::uint128 v(1);
+ (v += 4) -= 3;
+ EXPECT_EQ(2, v);
+}
+
+TEST(Uint128, Multiply) {
+ absl::uint128 a, b, c;
+
+ // Zero test.
+ a = 0;
+ b = 0;
+ c = a * b;
+ EXPECT_EQ(0, c);
+
+ // Max carries.
+ a = absl::uint128(0) - 1;
+ b = absl::uint128(0) - 1;
+ c = a * b;
+ EXPECT_EQ(1, c);
+
+ // Self-operation with max carries.
+ c = absl::uint128(0) - 1;
+ c *= c;
+ EXPECT_EQ(1, c);
+
+ // 1-bit x 1-bit.
+ for (int i = 0; i < 64; ++i) {
+ for (int j = 0; j < 64; ++j) {
+ a = absl::uint128(1) << i;
+ b = absl::uint128(1) << j;
+ c = a * b;
+ EXPECT_EQ(absl::uint128(1) << (i + j), c);
+ }
+ }
+
+ // Verified with dc.
+ a = absl::MakeUint128(0xffffeeeeddddcccc, 0xbbbbaaaa99998888);
+ b = absl::MakeUint128(0x7777666655554444, 0x3333222211110000);
+ c = a * b;
+ EXPECT_EQ(absl::MakeUint128(0x530EDA741C71D4C3, 0xBF25975319080000), c);
+ EXPECT_EQ(0, c - b * a);
+ EXPECT_EQ(a*a - b*b, (a+b) * (a-b));
+
+ // Verified with dc.
+ a = absl::MakeUint128(0x0123456789abcdef, 0xfedcba9876543210);
+ b = absl::MakeUint128(0x02468ace13579bdf, 0xfdb97531eca86420);
+ c = a * b;
+ EXPECT_EQ(absl::MakeUint128(0x97a87f4f261ba3f2, 0x342d0bbf48948200), c);
+ EXPECT_EQ(0, c - b * a);
+ EXPECT_EQ(a*a - b*b, (a+b) * (a-b));
+}
+
+TEST(Uint128, AliasTests) {
+ absl::uint128 x1 = absl::MakeUint128(1, 2);
+ absl::uint128 x2 = absl::MakeUint128(2, 4);
+ x1 += x1;
+ EXPECT_EQ(x2, x1);
+
+ absl::uint128 x3 = absl::MakeUint128(1, static_cast<uint64_t>(1) << 63);
+ absl::uint128 x4 = absl::MakeUint128(3, 0);
+ x3 += x3;
+ EXPECT_EQ(x4, x3);
+}
+
+TEST(Uint128, DivideAndMod) {
+ using std::swap;
+
+ // a := q * b + r
+ absl::uint128 a, b, q, r;
+
+ // Zero test.
+ a = 0;
+ b = 123;
+ q = a / b;
+ r = a % b;
+ EXPECT_EQ(0, q);
+ EXPECT_EQ(0, r);
+
+ a = absl::MakeUint128(0x530eda741c71d4c3, 0xbf25975319080000);
+ q = absl::MakeUint128(0x4de2cab081, 0x14c34ab4676e4bab);
+ b = absl::uint128(0x1110001);
+ r = absl::uint128(0x3eb455);
+ ASSERT_EQ(a, q * b + r); // Sanity-check.
+
+ absl::uint128 result_q, result_r;
+ result_q = a / b;
+ result_r = a % b;
+ EXPECT_EQ(q, result_q);
+ EXPECT_EQ(r, result_r);
+
+ // Try the other way around.
+ swap(q, b);
+ result_q = a / b;
+ result_r = a % b;
+ EXPECT_EQ(q, result_q);
+ EXPECT_EQ(r, result_r);
+ // Restore.
+ swap(b, q);
+
+ // Dividend < divisor; result should be q:0 r:<dividend>.
+ swap(a, b);
+ result_q = a / b;
+ result_r = a % b;
+ EXPECT_EQ(0, result_q);
+ EXPECT_EQ(a, result_r);
+ // Try the other way around.
+ swap(a, q);
+ result_q = a / b;
+ result_r = a % b;
+ EXPECT_EQ(0, result_q);
+ EXPECT_EQ(a, result_r);
+ // Restore.
+ swap(q, a);
+ swap(b, a);
+
+ // Try a large remainder.
+ b = a / 2 + 1;
+ absl::uint128 expected_r =
+ absl::MakeUint128(0x29876d3a0e38ea61, 0xdf92cba98c83ffff);
+ // Sanity checks.
+ ASSERT_EQ(a / 2 - 1, expected_r);
+ ASSERT_EQ(a, b + expected_r);
+ result_q = a / b;
+ result_r = a % b;
+ EXPECT_EQ(1, result_q);
+ EXPECT_EQ(expected_r, result_r);
+}
+
+TEST(Uint128, DivideAndModRandomInputs) {
+ const int kNumIters = 1 << 18;
+ std::minstd_rand random(testing::UnitTest::GetInstance()->random_seed());
+ std::uniform_int_distribution<uint64_t> uniform_uint64;
+ for (int i = 0; i < kNumIters; ++i) {
+ const absl::uint128 a =
+ absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
+ const absl::uint128 b =
+ absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
+ if (b == 0) {
+ continue; // Avoid a div-by-zero.
+ }
+ const absl::uint128 q = a / b;
+ const absl::uint128 r = a % b;
+ ASSERT_EQ(a, b * q + r);
+ }
+}
+
+TEST(Uint128, ConstexprTest) {
+ constexpr absl::uint128 zero = absl::uint128();
+ constexpr absl::uint128 one = 1;
+ constexpr absl::uint128 minus_two = -2;
+ EXPECT_EQ(zero, absl::uint128(0));
+ EXPECT_EQ(one, absl::uint128(1));
+ EXPECT_EQ(minus_two, absl::MakeUint128(-1, -2));
+}
+
+TEST(Uint128, Traits) {
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<absl::uint128>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<absl::uint128>::value);
+ EXPECT_TRUE(std::is_trivially_destructible<absl::uint128>::value);
+}
+
+TEST(Uint128, OStream) {
+ struct {
+ absl::uint128 val;
+ std::ios_base::fmtflags flags;
+ std::streamsize width;
+ char fill;
+ const char* rep;
+ } cases[] = {
+ // zero with different bases
+ {absl::uint128(0), std::ios::dec, 0, '_', "0"},
+ {absl::uint128(0), std::ios::oct, 0, '_', "0"},
+ {absl::uint128(0), std::ios::hex, 0, '_', "0"},
+ // crossover between lo_ and hi_
+ {absl::MakeUint128(0, -1), std::ios::dec, 0, '_', "18446744073709551615"},
+ {absl::MakeUint128(0, -1), std::ios::oct, 0, '_',
+ "1777777777777777777777"},
+ {absl::MakeUint128(0, -1), std::ios::hex, 0, '_', "ffffffffffffffff"},
+ {absl::MakeUint128(1, 0), std::ios::dec, 0, '_', "18446744073709551616"},
+ {absl::MakeUint128(1, 0), std::ios::oct, 0, '_',
+ "2000000000000000000000"},
+ {absl::MakeUint128(1, 0), std::ios::hex, 0, '_', "10000000000000000"},
+ // just the top bit
+ {absl::MakeUint128(0x8000000000000000, 0), std::ios::dec, 0, '_',
+ "170141183460469231731687303715884105728"},
+ {absl::MakeUint128(0x8000000000000000, 0), std::ios::oct, 0, '_',
+ "2000000000000000000000000000000000000000000"},
+ {absl::MakeUint128(0x8000000000000000, 0), std::ios::hex, 0, '_',
+ "80000000000000000000000000000000"},
+ // maximum absl::uint128 value
+ {absl::MakeUint128(-1, -1), std::ios::dec, 0, '_',
+ "340282366920938463463374607431768211455"},
+ {absl::MakeUint128(-1, -1), std::ios::oct, 0, '_',
+ "3777777777777777777777777777777777777777777"},
+ {absl::MakeUint128(-1, -1), std::ios::hex, 0, '_',
+ "ffffffffffffffffffffffffffffffff"},
+ // uppercase
+ {absl::MakeUint128(-1, -1), std::ios::hex | std::ios::uppercase, 0, '_',
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"},
+ // showbase
+ {absl::uint128(1), std::ios::dec | std::ios::showbase, 0, '_', "1"},
+ {absl::uint128(1), std::ios::oct | std::ios::showbase, 0, '_', "01"},
+ {absl::uint128(1), std::ios::hex | std::ios::showbase, 0, '_', "0x1"},
+ // showbase does nothing on zero
+ {absl::uint128(0), std::ios::dec | std::ios::showbase, 0, '_', "0"},
+ {absl::uint128(0), std::ios::oct | std::ios::showbase, 0, '_', "0"},
+ {absl::uint128(0), std::ios::hex | std::ios::showbase, 0, '_', "0"},
+ // showpos does nothing on unsigned types
+ {absl::uint128(1), std::ios::dec | std::ios::showpos, 0, '_', "1"},
+ // padding
+ {absl::uint128(9), std::ios::dec, 6, '_', "_____9"},
+ {absl::uint128(12345), std::ios::dec, 6, '_', "_12345"},
+ // left adjustment
+ {absl::uint128(9), std::ios::dec | std::ios::left, 6, '_', "9_____"},
+ {absl::uint128(12345), std::ios::dec | std::ios::left, 6, '_', "12345_"},
+ };
+ for (const auto& test_case : cases) {
+ std::ostringstream os;
+ os.flags(test_case.flags);
+ os.width(test_case.width);
+ os.fill(test_case.fill);
+ os << test_case.val;
+ EXPECT_EQ(test_case.rep, os.str());
+ }
+}
+
+} // namespace
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel
new file mode 100644
index 0000000..070721c
--- /dev/null
+++ b/absl/strings/BUILD.bazel
@@ -0,0 +1,293 @@
+#
+# 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.
+#
+# -*- mode: python; -*-
+# Libraries in this low-level package may not depend on libraries in packages
+# that are not low level. For more information, including how to submit
+# changes to this file, see http://www/eng/howto/build-monitors.html
+
+load(
+ "//absl:test_dependencies.bzl",
+ "GUNIT_MAIN_DEPS_SELECTOR",
+ "GUNIT_DEPS_SELECTOR",
+)
+load(
+ "//absl:copts.bzl",
+ "ABSL_DEFAULT_COPTS",
+ "ABSL_TEST_COPTS",
+ "ABSL_EXCEPTIONS_FLAG",
+)
+
+package(
+ default_visibility = ["//visibility:public"],
+ features = [
+ "parse_headers",
+ "header_modules",
+ ],
+)
+
+licenses(["notice"]) # Apache 2.0
+
+cc_library(
+ name = "strings",
+ srcs = [
+ "ascii.cc",
+ "escaping.cc",
+ "internal/memutil.cc",
+ "internal/memutil.h",
+ "internal/str_join_internal.h",
+ "internal/str_split_internal.h",
+ "match.cc",
+ "numbers.cc",
+ "str_cat.cc",
+ "str_replace.cc",
+ "str_split.cc",
+ "string_view.cc",
+ "substitute.cc",
+ ],
+ hdrs = [
+ "ascii.h",
+ "escaping.h",
+ "match.h",
+ "numbers.h",
+ "str_cat.h",
+ "str_join.h",
+ "str_replace.h",
+ "str_split.h",
+ "string_view.h",
+ "strip.h",
+ "substitute.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ ":internal",
+ "//absl/base",
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ "//absl/base:endian",
+ "//absl/base:throw_delegate",
+ "//absl/memory",
+ "//absl/meta:type_traits",
+ "//absl/numeric:int128",
+ ],
+)
+
+cc_library(
+ name = "internal",
+ srcs = [
+ "internal/utf8.cc",
+ ],
+ hdrs = [
+ "internal/char_map.h",
+ "internal/fastmem.h",
+ "internal/ostringstream.h",
+ "internal/resize_uninitialized.h",
+ "internal/utf8.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ "//absl/base:core_headers",
+ "//absl/base:endian",
+ "//absl/meta:type_traits",
+ ],
+)
+
+cc_test(
+ name = "match_test",
+ size = "small",
+ srcs = ["match_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [":strings"] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "escaping_test",
+ size = "small",
+ srcs = [
+ "escaping_test.cc",
+ "internal/escaping_test_common.inc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":strings",
+ "//absl/base:core_headers",
+ "//absl/container:fixed_array",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "ascii_test",
+ size = "small",
+ srcs = ["ascii_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":strings",
+ "//absl/base:core_headers",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "memutil_test",
+ size = "small",
+ srcs = [
+ "internal/memutil.h",
+ "internal/memutil_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":strings",
+ "//absl/base:core_headers",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "utf8_test",
+ size = "small",
+ srcs = [
+ "internal/utf8_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":strings",
+ ":internal",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "string_view_test",
+ size = "small",
+ srcs = ["string_view_test.cc"],
+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+ deps = [
+ ":strings",
+ "//absl/base:core_headers",
+ "//absl/base:config",
+ "//absl/base:dynamic_annotations",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "substitute_test",
+ size = "small",
+ srcs = ["substitute_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":strings",
+ "//absl/base:core_headers",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "str_replace_test",
+ size = "small",
+ srcs = ["str_replace_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":strings",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "str_split_test",
+ srcs = ["str_split_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":strings",
+ "//absl/base:core_headers",
+ "//absl/base:dynamic_annotations",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "ostringstream_test",
+ size = "small",
+ srcs = ["internal/ostringstream_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":internal",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "resize_uninitialized_test",
+ size = "small",
+ srcs = [
+ "internal/resize_uninitialized.h",
+ "internal/resize_uninitialized_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ "//absl/base:core_headers",
+ "//absl/meta:type_traits",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "str_join_test",
+ size = "small",
+ srcs = ["str_join_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":strings",
+ "//absl/base:core_headers",
+ "//absl/memory",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "str_cat_test",
+ size = "small",
+ srcs = ["str_cat_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":strings",
+ "//absl/base:core_headers",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "numbers_test",
+ size = "small",
+ srcs = [
+ "internal/numbers_test_common.inc",
+ "numbers_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ tags = [
+ "no_test_loonix",
+ ],
+ deps = [
+ ":strings",
+ "//absl/base",
+ "//absl/base:core_headers",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "strip_test",
+ size = "small",
+ srcs = ["strip_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [":strings"] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "char_map_test",
+ srcs = ["internal/char_map_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":internal",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
diff --git a/absl/strings/README.md b/absl/strings/README.md
new file mode 100644
index 0000000..d5320eb
--- /dev/null
+++ b/absl/strings/README.md
@@ -0,0 +1,87 @@
+# ABSL Strings
+
+This directory contains packages related to std::string operations and std::string
+alternatives (such as character-agnostic byte manipulation packages).
+
+## Library Listing
+
+Two library targets are available within this directory:
+
+* **strings** (`//absl/strings:strings`) provides classes and
+ utility functions for manipulating and comparing strings, converting other
+ types (such as integers) into strings, or evaluating strings for other usages
+ (such as tokenization).
+
+* **cord** (`//absl/strings:cord`) provides classes and utility
+ functions for manipulating `Cord` elements. A `Cord` is a sequence of
+ characters that internally uses a tree structure to store their data,
+ avoiding the need for long regions of contiguous memory, and allows memory
+ sharing, sub-std::string copy-on-write, and a host of other advanced std::string
+ features.
+
+## Strings Library File Listing
+
+The following header files are directly included within the
+`absl::strings` library.
+
+## Alternate std::string-like Classes
+
+* `bytestream.h`
+ <br/>Abstraction of std::string for I/O
+* `string_view.h`
+ <br/>Pointer to part or all of another std::string
+
+## Formatting and Parsing
+
+* `numbers.h`
+ <br/>Converter between strings and numbers. Prefer `str_cat.h` for numbers
+ to strings
+
+## Operations on Characters
+
+* `ascii_ctype.h`
+ <br/>Char classifiers like &lt;ctype.h&gt; but faster
+* `charset.h`
+ <br/>Bitmap from unsigned char -&gt; bool
+
+## Operations on Strings
+
+* `case.h`
+ <br/>Case-changers
+* `escaping.h`
+ <br/>Escapers and unescapers
+* `str_join.h`
+ <br/>Joiner functions using a delimiter
+* `str_split.h`
+ <br/>Split functions
+* `str_cat.h`
+ <br/>Concatenators and appenders
+* `string_view_utils.h`
+ <br>Utility functions for strings
+* `strip.h`
+ <br/>Character removal functions
+* `substitute.h`
+ <br/>Printf-like typesafe formatter
+
+## Miscellaneous
+
+* `util.h`
+ <br/>Grab bag of useful std::string functions
+
+
+## Cord Library File Listing
+
+The following header files are directly included within the
+`absl::strings::cord` library:
+
+## The `Cord` Class
+
+* `cord.h`
+ <br/>A std::string built from a tree of shareable nodes
+
+## Operations on Cords
+
+* `cord_cat.h`
+ <br/>Concatenator functions for cords
+* `cord_util.h`
+ <br/>Utility functions for cords
diff --git a/absl/strings/ascii.cc b/absl/strings/ascii.cc
new file mode 100644
index 0000000..c9481e8
--- /dev/null
+++ b/absl/strings/ascii.cc
@@ -0,0 +1,198 @@
+// 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/strings/ascii.h"
+
+namespace absl {
+namespace ascii_internal {
+
+// # Table generated by this Python code (bit 0x02 is currently unused):
+// TODO(mbar) Move Python code for generation of table to BUILD and link here.
+
+// NOTE: The kAsciiPropertyBits table used within this code was generated by
+// Python code of the following form. (Bit 0x02 is currently unused and
+// available.)
+//
+// def Hex2(n):
+// return '0x' + hex(n/16)[2:] + hex(n%16)[2:]
+// def IsPunct(ch):
+// return (ord(ch) >= 32 and ord(ch) < 127 and
+// not ch.isspace() and not ch.isalnum())
+// def IsBlank(ch):
+// return ch in ' \t'
+// def IsCntrl(ch):
+// return ord(ch) < 32 or ord(ch) == 127
+// def IsXDigit(ch):
+// return ch.isdigit() or ch.lower() in 'abcdef'
+// for i in range(128):
+// ch = chr(i)
+// mask = ((ch.isalpha() and 0x01 or 0) |
+// (ch.isalnum() and 0x04 or 0) |
+// (ch.isspace() and 0x08 or 0) |
+// (IsPunct(ch) and 0x10 or 0) |
+// (IsBlank(ch) and 0x20 or 0) |
+// (IsCntrl(ch) and 0x40 or 0) |
+// (IsXDigit(ch) and 0x80 or 0))
+// print Hex2(mask) + ',',
+// if i % 16 == 7:
+// print ' //', Hex2(i & 0x78)
+// elif i % 16 == 15:
+// print
+
+// clang-format off
+// Array of bitfields holding character information. Each bit value corresponds
+// to a particular character feature. For readability, and because the value
+// of these bits is tightly coupled to this implementation, the individual bits
+// are not named. Note that bitfields for all characters above ASCII 127 are
+// zero-initialized.
+const unsigned char kPropertyBits[256] = {
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x00
+ 0x40, 0x68, 0x48, 0x48, 0x48, 0x48, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x10
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, // 0x20
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, // 0x30
+ 0x84, 0x84, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x40
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x50
+ 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x60
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x70
+ 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x40,
+};
+
+// Array of characters for the ascii_tolower() function. For values 'A'
+// through 'Z', return the lower-case character; otherwise, return the
+// identity of the passed character.
+const char kToLower[256] = {
+ '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
+ '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
+ '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
+ '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
+ '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
+ '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
+ '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
+ '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
+ '\x40', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
+ '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67',
+ '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f',
+ '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77',
+ '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f',
+ '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87',
+ '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f',
+ '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97',
+ '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f',
+ '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7',
+ '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf',
+ '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7',
+ '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf',
+ '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7',
+ '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf',
+ '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7',
+ '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf',
+ '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7',
+ '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef',
+ '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf7',
+ '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff',
+};
+
+// Array of characters for the ascii_toupper() function. For values 'a'
+// through 'z', return the upper-case character; otherwise, return the
+// identity of the passed character.
+const char kToUpper[256] = {
+ '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
+ '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
+ '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
+ '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
+ '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
+ '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
+ '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
+ '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
+ '\x40', '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47',
+ '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f',
+ '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57',
+ '\x58', '\x59', '\x5a', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
+ '\x60', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f',
+ '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87',
+ '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f',
+ '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97',
+ '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f',
+ '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7',
+ '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf',
+ '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7',
+ '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf',
+ '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7',
+ '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf',
+ '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7',
+ '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf',
+ '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7',
+ '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef',
+ '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf7',
+ '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff',
+};
+// clang-format on
+
+} // namespace ascii_internal
+
+void AsciiStrToLower(std::string* s) {
+ for (auto& ch : *s) {
+ ch = absl::ascii_tolower(ch);
+ }
+}
+
+void AsciiStrToUpper(std::string* s) {
+ for (auto& ch : *s) {
+ ch = absl::ascii_toupper(ch);
+ }
+}
+
+void RemoveExtraAsciiWhitespace(std::string* str) {
+ auto stripped = StripAsciiWhitespace(*str);
+
+ if (stripped.empty()) {
+ str->clear();
+ return;
+ }
+
+ auto input_it = stripped.begin();
+ auto input_end = stripped.end();
+ auto output_it = &(*str)[0];
+ bool is_ws = false;
+
+ for (; input_it < input_end; ++input_it) {
+ if (is_ws) {
+ // Consecutive whitespace? Keep only the last.
+ is_ws = absl::ascii_isspace(*input_it);
+ if (is_ws) --output_it;
+ } else {
+ is_ws = absl::ascii_isspace(*input_it);
+ }
+
+ *output_it = *input_it;
+ ++output_it;
+ }
+
+ str->erase(output_it - &(*str)[0]);
+}
+
+} // namespace absl
diff --git a/absl/strings/ascii.h b/absl/strings/ascii.h
new file mode 100644
index 0000000..fc2bb33
--- /dev/null
+++ b/absl/strings/ascii.h
@@ -0,0 +1,239 @@
+//
+// 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: ascii.h
+// -----------------------------------------------------------------------------
+//
+// This package contains functions operating on characters and strings
+// restricted to standard ASCII. These include character classification
+// functions analogous to those found in the ANSI C Standard Library <ctype.h>
+// header file.
+//
+// C++ implementations provide <ctype.h> functionality based on their
+// C environment locale. In general, reliance on such a locale is not ideal, as
+// the locale standard is problematic (and may not return invariant information
+// for the same character set, for example). These `ascii_*()` functions are
+// hard-wired for standard ASCII, much faster, and guaranteed to behave
+// consistently. They will never be overloaded, nor will their function
+// signature change.
+//
+// `ascii_isalnum()`, `ascii_isalpha()`, `ascii_isascii()`, `ascii_isblank()`,
+// `ascii_iscntrl()`, `ascii_isdigit()`, `ascii_isgraph()`, `ascii_islower()`,
+// `ascii_isprint()`, `ascii_ispunct()`, `ascii_isspace()`, `ascii_isupper()`,
+// `ascii_isxdigit()`
+// Analagous to the <ctype.h> functions with similar names, these
+// functions take an unsigned char and return a bool, based on whether the
+// character matches the condition specified.
+//
+// If the input character has a numerical value greater than 127, these
+// functions return `false`.
+//
+// `ascii_tolower()`, `ascii_toupper()`
+// Analagous to the <ctype.h> functions with similar names, these functions
+// take an unsigned char and return a char.
+//
+// If the input character is not an ASCII {lower,upper}-case letter (including
+// numerical values greater than 127) then the functions return the same value
+// as the input character.
+
+#ifndef ABSL_STRINGS_ASCII_H_
+#define ABSL_STRINGS_ASCII_H_
+
+#include <algorithm>
+#include <string>
+
+#include "absl/base/attributes.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+namespace ascii_internal {
+
+// Declaration for an array of bitfields holding character information.
+extern const unsigned char kPropertyBits[256];
+
+// Declaration for the array of characters to upper-case characters.
+extern const char kToUpper[256];
+
+// Declaration for the array of characters to lower-case characters.
+extern const char kToLower[256];
+
+} // namespace ascii_internal
+
+// ascii_isalpha()
+//
+// Determines whether the given character is an alphabetic character.
+inline bool ascii_isalpha(unsigned char c) {
+ return (ascii_internal::kPropertyBits[c] & 0x01) != 0;
+}
+
+// ascii_isalnum()
+//
+// Determines whether the given character is an alphanumeric character.
+inline bool ascii_isalnum(unsigned char c) {
+ return (ascii_internal::kPropertyBits[c] & 0x04) != 0;
+}
+
+// ascii_isspace()
+//
+// Determines whether the given character is a whitespace character (space,
+// tab, vertical tab, formfeed, linefeed, or carriage return).
+inline bool ascii_isspace(unsigned char c) {
+ return (ascii_internal::kPropertyBits[c] & 0x08) != 0;
+}
+
+// ascii_ispunct()
+//
+// Determines whether the given character is a punctuation character.
+inline bool ascii_ispunct(unsigned char c) {
+ return (ascii_internal::kPropertyBits[c] & 0x10) != 0;
+}
+
+// ascii_isblank()
+//
+// Determines whether the given character is a blank character (tab or space).
+inline bool ascii_isblank(unsigned char c) {
+ return (ascii_internal::kPropertyBits[c] & 0x20) != 0;
+}
+
+// ascii_iscntrl()
+//
+// Determines whether the given character is a control character.
+inline bool ascii_iscntrl(unsigned char c) {
+ return (ascii_internal::kPropertyBits[c] & 0x40) != 0;
+}
+
+// ascii_isxdigit()
+//
+// Determines whether the given character can be represented as a hexadecimal
+// digit character (i.e. {0-9} or {A-F}).
+inline bool ascii_isxdigit(unsigned char c) {
+ return (ascii_internal::kPropertyBits[c] & 0x80) != 0;
+}
+
+// ascii_isdigit()
+//
+// Determines whether the given character can be represented as a decimal
+// digit character (i.e. {0-9}).
+inline bool ascii_isdigit(unsigned char c) { return c >= '0' && c <= '9'; }
+
+// ascii_isprint()
+//
+// Determines whether the given character is printable, including whitespace.
+inline bool ascii_isprint(unsigned char c) { return c >= 32 && c < 127; }
+
+// ascii_isgraph()
+//
+// Determines whether the given character has a graphical representation.
+inline bool ascii_isgraph(unsigned char c) { return c > 32 && c < 127; }
+
+// ascii_isupper()
+//
+// Determines whether the given character is uppercase.
+inline bool ascii_isupper(unsigned char c) { return c >= 'A' && c <= 'Z'; }
+
+// ascii_islower()
+//
+// Determines whether the given character is lowercase.
+inline bool ascii_islower(unsigned char c) { return c >= 'a' && c <= 'z'; }
+
+// ascii_isascii()
+//
+// Determines whether the given character is ASCII.
+inline bool ascii_isascii(unsigned char c) { return c < 128; }
+
+// ascii_tolower()
+//
+// Returns an ASCII character, converting to lowercase if uppercase is
+// passed. Note that character values > 127 are simply returned.
+inline char ascii_tolower(unsigned char c) {
+ return ascii_internal::kToLower[c];
+}
+
+// Converts the characters in `s` to lowercase, changing the contents of `s`.
+void AsciiStrToLower(std::string* s);
+
+// Creates a lowercase std::string from a given absl::string_view.
+ABSL_MUST_USE_RESULT inline std::string AsciiStrToLower(absl::string_view s) {
+ std::string result(s);
+ absl::AsciiStrToLower(&result);
+ return result;
+}
+
+// ascii_toupper()
+//
+// Returns the ASCII character, converting to upper-case if lower-case is
+// passed. Note that characters values > 127 are simply returned.
+inline char ascii_toupper(unsigned char c) {
+ return ascii_internal::kToUpper[c];
+}
+
+// Converts the characters in `s` to uppercase, changing the contents of `s`.
+void AsciiStrToUpper(std::string* s);
+
+// Creates an uppercase std::string from a given absl::string_view.
+ABSL_MUST_USE_RESULT inline std::string AsciiStrToUpper(absl::string_view s) {
+ std::string result(s);
+ absl::AsciiStrToUpper(&result);
+ return result;
+}
+
+// Returns absl::string_view with whitespace stripped from the beginning of the
+// given string_view.
+ABSL_MUST_USE_RESULT inline absl::string_view StripLeadingAsciiWhitespace(
+ absl::string_view str) {
+ auto it = std::find_if_not(str.begin(), str.end(), absl::ascii_isspace);
+ return absl::string_view(it, str.end() - it);
+}
+
+// Strips in place whitespace from the beginning of the given std::string.
+inline void StripLeadingAsciiWhitespace(std::string* str) {
+ auto it = std::find_if_not(str->begin(), str->end(), absl::ascii_isspace);
+ str->erase(str->begin(), it);
+}
+
+// Returns absl::string_view with whitespace stripped from the end of the given
+// string_view.
+ABSL_MUST_USE_RESULT inline absl::string_view StripTrailingAsciiWhitespace(
+ absl::string_view str) {
+ auto it = std::find_if_not(str.rbegin(), str.rend(), absl::ascii_isspace);
+ return absl::string_view(str.begin(), str.rend() - it);
+}
+
+// Strips in place whitespace from the end of the given std::string
+inline void StripTrailingAsciiWhitespace(std::string* str) {
+ auto it = std::find_if_not(str->rbegin(), str->rend(), absl::ascii_isspace);
+ str->erase(str->rend() - it);
+}
+
+// Returns absl::string_view with whitespace stripped from both ends of the
+// given string_view.
+ABSL_MUST_USE_RESULT inline absl::string_view StripAsciiWhitespace(
+ absl::string_view str) {
+ return StripTrailingAsciiWhitespace(StripLeadingAsciiWhitespace(str));
+}
+
+// Strips in place whitespace from both ends of the given std::string
+inline void StripAsciiWhitespace(std::string* str) {
+ StripTrailingAsciiWhitespace(str);
+ StripLeadingAsciiWhitespace(str);
+}
+
+// Removes leading, trailing, and consecutive internal whitespace.
+void RemoveExtraAsciiWhitespace(std::string*);
+
+} // namespace absl
+
+#endif // ABSL_STRINGS_ASCII_H_
diff --git a/absl/strings/ascii_ctype.h b/absl/strings/ascii_ctype.h
new file mode 100644
index 0000000..e1ba9e2
--- /dev/null
+++ b/absl/strings/ascii_ctype.h
@@ -0,0 +1,66 @@
+// 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_STRINGS_ASCII_CTYPE_H_
+#define ABSL_STRINGS_ASCII_CTYPE_H_
+
+#include "absl/strings/ascii.h"
+
+inline bool ascii_isalpha(unsigned char c) {
+ return absl::ascii_isalpha(c);
+}
+inline bool ascii_isalnum(unsigned char c) {
+ return absl::ascii_isalnum(c);
+}
+inline bool ascii_isspace(unsigned char c) {
+ return absl::ascii_isspace(c);
+}
+inline bool ascii_ispunct(unsigned char c) {
+ return absl::ascii_ispunct(c);
+}
+inline bool ascii_isblank(unsigned char c) {
+ return absl::ascii_isblank(c);
+}
+inline bool ascii_iscntrl(unsigned char c) {
+ return absl::ascii_iscntrl(c);
+}
+inline bool ascii_isxdigit(unsigned char c) {
+ return absl::ascii_isxdigit(c);
+}
+inline bool ascii_isdigit(unsigned char c) {
+ return absl::ascii_isdigit(c);
+}
+inline bool ascii_isprint(unsigned char c) {
+ return absl::ascii_isprint(c);
+}
+inline bool ascii_isgraph(unsigned char c) {
+ return absl::ascii_isgraph(c);
+}
+inline bool ascii_isupper(unsigned char c) {
+ return absl::ascii_isupper(c);
+}
+inline bool ascii_islower(unsigned char c) {
+ return absl::ascii_islower(c);
+}
+inline bool ascii_isascii(unsigned char c) {
+ return absl::ascii_isascii(c);
+}
+inline char ascii_tolower(unsigned char c) {
+ return absl::ascii_tolower(c);
+}
+inline char ascii_toupper(unsigned char c) {
+ return absl::ascii_toupper(c);
+}
+
+#endif // ABSL_STRINGS_ASCII_CTYPE_H_
diff --git a/absl/strings/ascii_test.cc b/absl/strings/ascii_test.cc
new file mode 100644
index 0000000..97f3601
--- /dev/null
+++ b/absl/strings/ascii_test.cc
@@ -0,0 +1,354 @@
+// 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/strings/ascii.h"
+
+#include <cctype>
+#include <clocale>
+#include <cstring>
+#include <string>
+
+#include "gtest/gtest.h"
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+
+namespace {
+
+TEST(AsciiIsFoo, All) {
+ for (int i = 0; i < 256; i++) {
+ if ((i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z'))
+ EXPECT_TRUE(absl::ascii_isalpha(i)) << ": failed on " << i;
+ else
+ EXPECT_TRUE(!absl::ascii_isalpha(i)) << ": failed on " << i;
+ }
+ for (int i = 0; i < 256; i++) {
+ if ((i >= '0' && i <= '9'))
+ EXPECT_TRUE(absl::ascii_isdigit(i)) << ": failed on " << i;
+ else
+ EXPECT_TRUE(!absl::ascii_isdigit(i)) << ": failed on " << i;
+ }
+ for (int i = 0; i < 256; i++) {
+ if (absl::ascii_isalpha(i) || absl::ascii_isdigit(i))
+ EXPECT_TRUE(absl::ascii_isalnum(i)) << ": failed on " << i;
+ else
+ EXPECT_TRUE(!absl::ascii_isalnum(i)) << ": failed on " << i;
+ }
+ for (int i = 0; i < 256; i++) {
+ if (i != '\0' && strchr(" \r\n\t\v\f", i))
+ EXPECT_TRUE(absl::ascii_isspace(i)) << ": failed on " << i;
+ else
+ EXPECT_TRUE(!absl::ascii_isspace(i)) << ": failed on " << i;
+ }
+ for (int i = 0; i < 256; i++) {
+ if (i >= 32 && i < 127)
+ EXPECT_TRUE(absl::ascii_isprint(i)) << ": failed on " << i;
+ else
+ EXPECT_TRUE(!absl::ascii_isprint(i)) << ": failed on " << i;
+ }
+ for (int i = 0; i < 256; i++) {
+ if (absl::ascii_isprint(i) && !absl::ascii_isspace(i) &&
+ !absl::ascii_isalnum(i))
+ EXPECT_TRUE(absl::ascii_ispunct(i)) << ": failed on " << i;
+ else
+ EXPECT_TRUE(!absl::ascii_ispunct(i)) << ": failed on " << i;
+ }
+ for (int i = 0; i < 256; i++) {
+ if (i == ' ' || i == '\t')
+ EXPECT_TRUE(absl::ascii_isblank(i)) << ": failed on " << i;
+ else
+ EXPECT_TRUE(!absl::ascii_isblank(i)) << ": failed on " << i;
+ }
+ for (int i = 0; i < 256; i++) {
+ if (i < 32 || i == 127)
+ EXPECT_TRUE(absl::ascii_iscntrl(i)) << ": failed on " << i;
+ else
+ EXPECT_TRUE(!absl::ascii_iscntrl(i)) << ": failed on " << i;
+ }
+ for (int i = 0; i < 256; i++) {
+ if (absl::ascii_isdigit(i) || (i >= 'A' && i <= 'F') ||
+ (i >= 'a' && i <= 'f'))
+ EXPECT_TRUE(absl::ascii_isxdigit(i)) << ": failed on " << i;
+ else
+ EXPECT_TRUE(!absl::ascii_isxdigit(i)) << ": failed on " << i;
+ }
+ for (int i = 0; i < 256; i++) {
+ if (i > 32 && i < 127)
+ EXPECT_TRUE(absl::ascii_isgraph(i)) << ": failed on " << i;
+ else
+ EXPECT_TRUE(!absl::ascii_isgraph(i)) << ": failed on " << i;
+ }
+ for (int i = 0; i < 256; i++) {
+ if (i >= 'A' && i <= 'Z')
+ EXPECT_TRUE(absl::ascii_isupper(i)) << ": failed on " << i;
+ else
+ EXPECT_TRUE(!absl::ascii_isupper(i)) << ": failed on " << i;
+ }
+ for (int i = 0; i < 256; i++) {
+ if (i >= 'a' && i <= 'z')
+ EXPECT_TRUE(absl::ascii_islower(i)) << ": failed on " << i;
+ else
+ EXPECT_TRUE(!absl::ascii_islower(i)) << ": failed on " << i;
+ }
+ for (int i = 0; i < 128; i++) {
+ EXPECT_TRUE(absl::ascii_isascii(i)) << ": failed on " << i;
+ }
+ for (int i = 128; i < 256; i++) {
+ EXPECT_TRUE(!absl::ascii_isascii(i)) << ": failed on " << i;
+ }
+
+ // The official is* functions don't accept negative signed chars, but
+ // our absl::ascii_is* functions do.
+ for (int i = 0; i < 256; i++) {
+ signed char sc = static_cast<signed char>(static_cast<unsigned char>(i));
+ EXPECT_EQ(absl::ascii_isalpha(i), absl::ascii_isalpha(sc)) << i;
+ EXPECT_EQ(absl::ascii_isdigit(i), absl::ascii_isdigit(sc)) << i;
+ EXPECT_EQ(absl::ascii_isalnum(i), absl::ascii_isalnum(sc)) << i;
+ EXPECT_EQ(absl::ascii_isspace(i), absl::ascii_isspace(sc)) << i;
+ EXPECT_EQ(absl::ascii_ispunct(i), absl::ascii_ispunct(sc)) << i;
+ EXPECT_EQ(absl::ascii_isblank(i), absl::ascii_isblank(sc)) << i;
+ EXPECT_EQ(absl::ascii_iscntrl(i), absl::ascii_iscntrl(sc)) << i;
+ EXPECT_EQ(absl::ascii_isxdigit(i), absl::ascii_isxdigit(sc)) << i;
+ EXPECT_EQ(absl::ascii_isprint(i), absl::ascii_isprint(sc)) << i;
+ EXPECT_EQ(absl::ascii_isgraph(i), absl::ascii_isgraph(sc)) << i;
+ EXPECT_EQ(absl::ascii_isupper(i), absl::ascii_isupper(sc)) << i;
+ EXPECT_EQ(absl::ascii_islower(i), absl::ascii_islower(sc)) << i;
+ EXPECT_EQ(absl::ascii_isascii(i), absl::ascii_isascii(sc)) << i;
+ }
+}
+
+// Checks that absl::ascii_isfoo returns the same value as isfoo in the C
+// locale.
+TEST(AsciiIsFoo, SameAsIsFoo) {
+ // temporarily change locale to C. It should already be C, but just for safety
+ std::string old_locale = setlocale(LC_CTYPE, nullptr);
+ ASSERT_TRUE(setlocale(LC_CTYPE, "C"));
+
+ for (int i = 0; i < 256; i++) {
+ EXPECT_EQ(isalpha(i) != 0, absl::ascii_isalpha(i)) << i;
+ EXPECT_EQ(isdigit(i) != 0, absl::ascii_isdigit(i)) << i;
+ EXPECT_EQ(isalnum(i) != 0, absl::ascii_isalnum(i)) << i;
+ EXPECT_EQ(isspace(i) != 0, absl::ascii_isspace(i)) << i;
+ EXPECT_EQ(ispunct(i) != 0, absl::ascii_ispunct(i)) << i;
+ EXPECT_EQ(isblank(i) != 0, absl::ascii_isblank(i)) << i;
+ EXPECT_EQ(iscntrl(i) != 0, absl::ascii_iscntrl(i)) << i;
+ EXPECT_EQ(isxdigit(i) != 0, absl::ascii_isxdigit(i)) << i;
+ EXPECT_EQ(isprint(i) != 0, absl::ascii_isprint(i)) << i;
+ EXPECT_EQ(isgraph(i) != 0, absl::ascii_isgraph(i)) << i;
+ EXPECT_EQ(isupper(i) != 0, absl::ascii_isupper(i)) << i;
+ EXPECT_EQ(islower(i) != 0, absl::ascii_islower(i)) << i;
+ EXPECT_EQ(isascii(i) != 0, absl::ascii_isascii(i)) << i;
+ }
+
+ // restore the old locale.
+ ASSERT_TRUE(setlocale(LC_CTYPE, old_locale.c_str()));
+}
+
+TEST(AsciiToFoo, All) {
+ // temporarily change locale to C. It should already be C, but just for safety
+ std::string old_locale = setlocale(LC_CTYPE, nullptr);
+ ASSERT_TRUE(setlocale(LC_CTYPE, "C"));
+
+ for (int i = 0; i < 256; i++) {
+ if (absl::ascii_islower(i))
+ EXPECT_EQ(absl::ascii_toupper(i), 'A' + (i - 'a')) << i;
+ else
+ EXPECT_EQ(absl::ascii_toupper(i), static_cast<char>(i)) << i;
+
+ if (absl::ascii_isupper(i))
+ EXPECT_EQ(absl::ascii_tolower(i), 'a' + (i - 'A')) << i;
+ else
+ EXPECT_EQ(absl::ascii_tolower(i), static_cast<char>(i)) << i;
+
+ // These CHECKs only hold in a C locale.
+ EXPECT_EQ(static_cast<char>(tolower(i)), absl::ascii_tolower(i)) << i;
+ EXPECT_EQ(static_cast<char>(toupper(i)), absl::ascii_toupper(i)) << i;
+
+ // The official to* functions don't accept negative signed chars, but
+ // our absl::ascii_to* functions do.
+ signed char sc = static_cast<signed char>(static_cast<unsigned char>(i));
+ EXPECT_EQ(absl::ascii_tolower(i), absl::ascii_tolower(sc)) << i;
+ EXPECT_EQ(absl::ascii_toupper(i), absl::ascii_toupper(sc)) << i;
+ }
+
+ // restore the old locale.
+ ASSERT_TRUE(setlocale(LC_CTYPE, old_locale.c_str()));
+}
+
+TEST(AsciiStrTo, Lower) {
+ const char buf[] = "ABCDEF";
+ const std::string str("GHIJKL");
+ const std::string str2("MNOPQR");
+ const absl::string_view sp(str2);
+
+ EXPECT_EQ("abcdef", absl::AsciiStrToLower(buf));
+ EXPECT_EQ("ghijkl", absl::AsciiStrToLower(str));
+ EXPECT_EQ("mnopqr", absl::AsciiStrToLower(sp));
+
+ char mutable_buf[] = "Mutable";
+ std::transform(mutable_buf, mutable_buf + strlen(mutable_buf),
+ mutable_buf, absl::ascii_tolower);
+ EXPECT_STREQ("mutable", mutable_buf);
+}
+
+TEST(AsciiStrTo, Upper) {
+ const char buf[] = "abcdef";
+ const std::string str("ghijkl");
+ const std::string str2("mnopqr");
+ const absl::string_view sp(str2);
+
+ EXPECT_EQ("ABCDEF", absl::AsciiStrToUpper(buf));
+ EXPECT_EQ("GHIJKL", absl::AsciiStrToUpper(str));
+ EXPECT_EQ("MNOPQR", absl::AsciiStrToUpper(sp));
+
+ char mutable_buf[] = "Mutable";
+ std::transform(mutable_buf, mutable_buf + strlen(mutable_buf),
+ mutable_buf, absl::ascii_toupper);
+ EXPECT_STREQ("MUTABLE", mutable_buf);
+}
+
+TEST(StripLeadingAsciiWhitespace, FromStringView) {
+ EXPECT_EQ(absl::string_view{},
+ absl::StripLeadingAsciiWhitespace(absl::string_view{}));
+ EXPECT_EQ("foo", absl::StripLeadingAsciiWhitespace({"foo"}));
+ EXPECT_EQ("foo", absl::StripLeadingAsciiWhitespace({"\t \n\f\r\n\vfoo"}));
+ EXPECT_EQ("foo foo\n ",
+ absl::StripLeadingAsciiWhitespace({"\t \n\f\r\n\vfoo foo\n "}));
+ EXPECT_EQ(absl::string_view{}, absl::StripLeadingAsciiWhitespace(
+ {"\t \n\f\r\v\n\t \n\f\r\v\n"}));
+}
+
+TEST(StripLeadingAsciiWhitespace, InPlace) {
+ std::string str;
+
+ absl::StripLeadingAsciiWhitespace(&str);
+ EXPECT_EQ("", str);
+
+ str = "foo";
+ absl::StripLeadingAsciiWhitespace(&str);
+ EXPECT_EQ("foo", str);
+
+ str = "\t \n\f\r\n\vfoo";
+ absl::StripLeadingAsciiWhitespace(&str);
+ EXPECT_EQ("foo", str);
+
+ str = "\t \n\f\r\n\vfoo foo\n ";
+ absl::StripLeadingAsciiWhitespace(&str);
+ EXPECT_EQ("foo foo\n ", str);
+
+ str = "\t \n\f\r\v\n\t \n\f\r\v\n";
+ absl::StripLeadingAsciiWhitespace(&str);
+ EXPECT_EQ(absl::string_view{}, str);
+}
+
+TEST(StripTrailingAsciiWhitespace, FromStringView) {
+ EXPECT_EQ(absl::string_view{},
+ absl::StripTrailingAsciiWhitespace(absl::string_view{}));
+ EXPECT_EQ("foo", absl::StripTrailingAsciiWhitespace({"foo"}));
+ EXPECT_EQ("foo", absl::StripTrailingAsciiWhitespace({"foo\t \n\f\r\n\v"}));
+ EXPECT_EQ(" \nfoo foo",
+ absl::StripTrailingAsciiWhitespace({" \nfoo foo\t \n\f\r\n\v"}));
+ EXPECT_EQ(absl::string_view{}, absl::StripTrailingAsciiWhitespace(
+ {"\t \n\f\r\v\n\t \n\f\r\v\n"}));
+}
+
+TEST(StripTrailingAsciiWhitespace, InPlace) {
+ std::string str;
+
+ absl::StripTrailingAsciiWhitespace(&str);
+ EXPECT_EQ("", str);
+
+ str = "foo";
+ absl::StripTrailingAsciiWhitespace(&str);
+ EXPECT_EQ("foo", str);
+
+ str = "foo\t \n\f\r\n\v";
+ absl::StripTrailingAsciiWhitespace(&str);
+ EXPECT_EQ("foo", str);
+
+ str = " \nfoo foo\t \n\f\r\n\v";
+ absl::StripTrailingAsciiWhitespace(&str);
+ EXPECT_EQ(" \nfoo foo", str);
+
+ str = "\t \n\f\r\v\n\t \n\f\r\v\n";
+ absl::StripTrailingAsciiWhitespace(&str);
+ EXPECT_EQ(absl::string_view{}, str);
+}
+
+TEST(StripAsciiWhitespace, FromStringView) {
+ EXPECT_EQ(absl::string_view{},
+ absl::StripAsciiWhitespace(absl::string_view{}));
+ EXPECT_EQ("foo", absl::StripAsciiWhitespace({"foo"}));
+ EXPECT_EQ("foo",
+ absl::StripAsciiWhitespace({"\t \n\f\r\n\vfoo\t \n\f\r\n\v"}));
+ EXPECT_EQ("foo foo", absl::StripAsciiWhitespace(
+ {"\t \n\f\r\n\vfoo foo\t \n\f\r\n\v"}));
+ EXPECT_EQ(absl::string_view{},
+ absl::StripAsciiWhitespace({"\t \n\f\r\v\n\t \n\f\r\v\n"}));
+}
+
+TEST(StripAsciiWhitespace, InPlace) {
+ std::string str;
+
+ absl::StripAsciiWhitespace(&str);
+ EXPECT_EQ("", str);
+
+ str = "foo";
+ absl::StripAsciiWhitespace(&str);
+ EXPECT_EQ("foo", str);
+
+ str = "\t \n\f\r\n\vfoo\t \n\f\r\n\v";
+ absl::StripAsciiWhitespace(&str);
+ EXPECT_EQ("foo", str);
+
+ str = "\t \n\f\r\n\vfoo foo\t \n\f\r\n\v";
+ absl::StripAsciiWhitespace(&str);
+ EXPECT_EQ("foo foo", str);
+
+ str = "\t \n\f\r\v\n\t \n\f\r\v\n";
+ absl::StripAsciiWhitespace(&str);
+ EXPECT_EQ(absl::string_view{}, str);
+}
+
+TEST(RemoveExtraAsciiWhitespace, InPlace) {
+ const char* inputs[] = {"No extra space",
+ " Leading whitespace",
+ "Trailing whitespace ",
+ " Leading and trailing ",
+ " Whitespace \t in\v middle ",
+ "'Eeeeep! \n Newlines!\n",
+ "nospaces",
+ "",
+ "\n\t a\t\n\nb \t\n"};
+
+ const char* outputs[] = {
+ "No extra space",
+ "Leading whitespace",
+ "Trailing whitespace",
+ "Leading and trailing",
+ "Whitespace in middle",
+ "'Eeeeep! Newlines!",
+ "nospaces",
+ "",
+ "a\nb",
+ };
+ const int NUM_TESTS = ABSL_ARRAYSIZE(inputs);
+
+ for (int i = 0; i < NUM_TESTS; i++) {
+ std::string s(inputs[i]);
+ absl::RemoveExtraAsciiWhitespace(&s);
+ EXPECT_EQ(outputs[i], s);
+ }
+}
+
+} // namespace
diff --git a/absl/strings/escaping.cc b/absl/strings/escaping.cc
new file mode 100644
index 0000000..f157605
--- /dev/null
+++ b/absl/strings/escaping.cc
@@ -0,0 +1,1093 @@
+// 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/strings/escaping.h"
+
+#include <cassert>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+#include <limits>
+#include <string>
+#include <vector>
+
+#include "absl/base/internal/endian.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/unaligned_access.h"
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/strings/internal/char_map.h"
+#include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/internal/utf8.h"
+#include "absl/strings/str_join.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+namespace {
+
+// Digit conversion.
+constexpr char kHexChar[] = "0123456789abcdef";
+
+constexpr char kHexTable[513] =
+ "000102030405060708090a0b0c0d0e0f"
+ "101112131415161718191a1b1c1d1e1f"
+ "202122232425262728292a2b2c2d2e2f"
+ "303132333435363738393a3b3c3d3e3f"
+ "404142434445464748494a4b4c4d4e4f"
+ "505152535455565758595a5b5c5d5e5f"
+ "606162636465666768696a6b6c6d6e6f"
+ "707172737475767778797a7b7c7d7e7f"
+ "808182838485868788898a8b8c8d8e8f"
+ "909192939495969798999a9b9c9d9e9f"
+ "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
+ "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
+ "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
+ "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
+ "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
+ "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
+
+// These are used for the leave_nulls_escaped argument to CUnescapeInternal().
+constexpr bool kUnescapeNulls = false;
+
+inline bool is_octal_digit(char c) { return ('0' <= c) && (c <= '7'); }
+
+inline int hex_digit_to_int(char c) {
+ static_assert('0' == 0x30 && 'A' == 0x41 && 'a' == 0x61,
+ "Character set must be ASCII.");
+ assert(absl::ascii_isxdigit(c));
+ int x = static_cast<unsigned char>(c);
+ if (x > '9') {
+ x += 9;
+ }
+ return x & 0xf;
+}
+
+// ----------------------------------------------------------------------
+// CUnescapeInternal()
+// Implements both CUnescape() and CUnescapeForNullTerminatedString().
+//
+// Unescapes C escape sequences and is the reverse of CEscape().
+//
+// If 'source' is valid, stores the unescaped std::string and its size in
+// 'dest' and 'dest_len' respectively, and returns true. Otherwise
+// returns false and optionally stores the error description in
+// 'error'. Set 'error' to nullptr to disable error reporting.
+//
+// 'dest' should point to a buffer that is at least as big as 'source'.
+// 'source' and 'dest' may be the same.
+//
+// NOTE: any changes to this function must also be reflected in the older
+// UnescapeCEscapeSequences().
+// ----------------------------------------------------------------------
+bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped,
+ char* dest, ptrdiff_t* dest_len, std::string* error) {
+ char* d = dest;
+ const char* p = source.data();
+ const char* end = source.end();
+ const char* last_byte = end - 1;
+
+ // Small optimization for case where source = dest and there's no escaping
+ while (p == d && p < end && *p != '\\') p++, d++;
+
+ while (p < end) {
+ if (*p != '\\') {
+ *d++ = *p++;
+ } else {
+ if (++p > last_byte) { // skip past the '\\'
+ if (error) *error = "String cannot end with \\";
+ return false;
+ }
+ switch (*p) {
+ case 'a': *d++ = '\a'; break;
+ case 'b': *d++ = '\b'; break;
+ case 'f': *d++ = '\f'; break;
+ case 'n': *d++ = '\n'; break;
+ case 'r': *d++ = '\r'; break;
+ case 't': *d++ = '\t'; break;
+ case 'v': *d++ = '\v'; break;
+ case '\\': *d++ = '\\'; break;
+ case '?': *d++ = '\?'; break; // \? Who knew?
+ case '\'': *d++ = '\''; break;
+ case '"': *d++ = '\"'; break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7': {
+ // octal digit: 1 to 3 digits
+ const char* octal_start = p;
+ unsigned int ch = *p - '0';
+ if (p < last_byte && is_octal_digit(p[1])) ch = ch * 8 + *++p - '0';
+ if (p < last_byte && is_octal_digit(p[1]))
+ ch = ch * 8 + *++p - '0'; // now points at last digit
+ if (ch > 0xff) {
+ if (error) {
+ *error = "Value of \\" +
+ std::string(octal_start, p + 1 - octal_start) +
+ " exceeds 0xff";
+ }
+ return false;
+ }
+ if ((ch == 0) && leave_nulls_escaped) {
+ // Copy the escape sequence for the null character
+ const ptrdiff_t octal_size = p + 1 - octal_start;
+ *d++ = '\\';
+ memcpy(d, octal_start, octal_size);
+ d += octal_size;
+ break;
+ }
+ *d++ = ch;
+ break;
+ }
+ case 'x':
+ case 'X': {
+ if (p >= last_byte) {
+ if (error) *error = "String cannot end with \\x";
+ return false;
+ } else if (!absl::ascii_isxdigit(p[1])) {
+ if (error) *error = "\\x cannot be followed by a non-hex digit";
+ return false;
+ }
+ unsigned int ch = 0;
+ const char* hex_start = p;
+ while (p < last_byte && absl::ascii_isxdigit(p[1]))
+ // Arbitrarily many hex digits
+ ch = (ch << 4) + hex_digit_to_int(*++p);
+ if (ch > 0xFF) {
+ if (error) {
+ *error = "Value of \\" + std::string(hex_start, p + 1 - hex_start) +
+ " exceeds 0xff";
+ }
+ return false;
+ }
+ if ((ch == 0) && leave_nulls_escaped) {
+ // Copy the escape sequence for the null character
+ const ptrdiff_t hex_size = p + 1 - hex_start;
+ *d++ = '\\';
+ memcpy(d, hex_start, hex_size);
+ d += hex_size;
+ break;
+ }
+ *d++ = ch;
+ break;
+ }
+ case 'u': {
+ // \uhhhh => convert 4 hex digits to UTF-8
+ char32_t rune = 0;
+ const char* hex_start = p;
+ if (p + 4 >= end) {
+ if (error) {
+ *error = "\\u must be followed by 4 hex digits: \\" +
+ std::string(hex_start, p + 1 - hex_start);
+ }
+ return false;
+ }
+ for (int i = 0; i < 4; ++i) {
+ // Look one char ahead.
+ if (absl::ascii_isxdigit(p[1])) {
+ rune = (rune << 4) + hex_digit_to_int(*++p); // Advance p.
+ } else {
+ if (error) {
+ *error = "\\u must be followed by 4 hex digits: \\" +
+ std::string(hex_start, p + 1 - hex_start);
+ }
+ return false;
+ }
+ }
+ if ((rune == 0) && leave_nulls_escaped) {
+ // Copy the escape sequence for the null character
+ *d++ = '\\';
+ memcpy(d, hex_start, 5); // u0000
+ d += 5;
+ break;
+ }
+ d += strings_internal::EncodeUTF8Char(d, rune);
+ break;
+ }
+ case 'U': {
+ // \Uhhhhhhhh => convert 8 hex digits to UTF-8
+ char32_t rune = 0;
+ const char* hex_start = p;
+ if (p + 8 >= end) {
+ if (error) {
+ *error = "\\U must be followed by 8 hex digits: \\" +
+ std::string(hex_start, p + 1 - hex_start);
+ }
+ return false;
+ }
+ for (int i = 0; i < 8; ++i) {
+ // Look one char ahead.
+ if (absl::ascii_isxdigit(p[1])) {
+ // Don't change rune until we're sure this
+ // is within the Unicode limit, but do advance p.
+ uint32_t newrune = (rune << 4) + hex_digit_to_int(*++p);
+ if (newrune > 0x10FFFF) {
+ if (error) {
+ *error = "Value of \\" +
+ std::string(hex_start, p + 1 - hex_start) +
+ " exceeds Unicode limit (0x10FFFF)";
+ }
+ return false;
+ } else {
+ rune = newrune;
+ }
+ } else {
+ if (error) {
+ *error = "\\U must be followed by 8 hex digits: \\" +
+ std::string(hex_start, p + 1 - hex_start);
+ }
+ return false;
+ }
+ }
+ if ((rune == 0) && leave_nulls_escaped) {
+ // Copy the escape sequence for the null character
+ *d++ = '\\';
+ memcpy(d, hex_start, 9); // U00000000
+ d += 9;
+ break;
+ }
+ d += strings_internal::EncodeUTF8Char(d, rune);
+ break;
+ }
+ default: {
+ if (error) *error = std::string("Unknown escape sequence: \\") + *p;
+ return false;
+ }
+ }
+ p++; // read past letter we escaped
+ }
+ }
+ *dest_len = d - dest;
+ return true;
+}
+
+// ----------------------------------------------------------------------
+// CUnescapeInternal()
+//
+// Same as above but uses a C++ std::string for output. 'source' and 'dest'
+// may be the same.
+// ----------------------------------------------------------------------
+bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped,
+ std::string* dest, std::string* error) {
+ strings_internal::STLStringResizeUninitialized(dest, source.size());
+
+ ptrdiff_t dest_size;
+ if (!CUnescapeInternal(source,
+ leave_nulls_escaped,
+ const_cast<char*>(dest->data()),
+ &dest_size,
+ error)) {
+ return false;
+ }
+ dest->erase(dest_size);
+ return true;
+}
+
+// ----------------------------------------------------------------------
+// CEscape()
+// CHexEscape()
+// Utf8SafeCEscape()
+// Utf8SafeCHexEscape()
+// Escapes 'src' using C-style escape sequences. This is useful for
+// preparing query flags. The 'Hex' version uses hexadecimal rather than
+// octal sequences. The 'Utf8Safe' version does not touch UTF-8 bytes.
+//
+// Escaped chars: \n, \r, \t, ", ', \, and !absl::ascii_isprint().
+// ----------------------------------------------------------------------
+std::string CEscapeInternal(absl::string_view src, bool use_hex, bool utf8_safe) {
+ std::string dest;
+ bool last_hex_escape = false; // true if last output char was \xNN.
+
+ for (unsigned char c : src) {
+ bool is_hex_escape = false;
+ switch (c) {
+ case '\n': dest.append("\\" "n"); break;
+ case '\r': dest.append("\\" "r"); break;
+ case '\t': dest.append("\\" "t"); break;
+ case '\"': dest.append("\\" "\""); break;
+ case '\'': dest.append("\\" "'"); break;
+ case '\\': dest.append("\\" "\\"); break;
+ default:
+ // Note that if we emit \xNN and the src character after that is a hex
+ // digit then that digit must be escaped too to prevent it being
+ // interpreted as part of the character code by C.
+ if ((!utf8_safe || c < 0x80) &&
+ (!absl::ascii_isprint(c) ||
+ (last_hex_escape && absl::ascii_isxdigit(c)))) {
+ if (use_hex) {
+ dest.append("\\" "x");
+ dest.push_back(kHexChar[c / 16]);
+ dest.push_back(kHexChar[c % 16]);
+ is_hex_escape = true;
+ } else {
+ dest.append("\\");
+ dest.push_back(kHexChar[c / 64]);
+ dest.push_back(kHexChar[(c % 64) / 8]);
+ dest.push_back(kHexChar[c % 8]);
+ }
+ } else {
+ dest.push_back(c);
+ break;
+ }
+ }
+ last_hex_escape = is_hex_escape;
+ }
+
+ return dest;
+}
+
+// Calculates the length of the C-style escaped version of 'src'.
+// Assumes that non-printable characters are escaped using octal sequences, and
+// that UTF-8 bytes are not handled specially.
+inline size_t CEscapedLength(absl::string_view src) {
+ /* clang-format off */
+ constexpr char c_escaped_len[256] = {
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 4, 4, 2, 4, 4, // \t, \n, \r
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // ", '
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // '0'..'9'
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'A'..'O'
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, // 'P'..'Z', '\'
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'a'..'o'
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, // 'p'..'z', DEL
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ };
+ /* clang-format on */
+
+ size_t escaped_len = 0;
+ for (unsigned char c : src) escaped_len += c_escaped_len[c];
+ return escaped_len;
+}
+
+void CEscapeAndAppendInternal(absl::string_view src, std::string* dest) {
+ size_t escaped_len = CEscapedLength(src);
+ if (escaped_len == src.size()) {
+ dest->append(src.data(), src.size());
+ return;
+ }
+
+ size_t cur_dest_len = dest->size();
+ strings_internal::STLStringResizeUninitialized(dest,
+ cur_dest_len + escaped_len);
+ char* append_ptr = &(*dest)[cur_dest_len];
+
+ for (unsigned char c : src) {
+ switch (c) {
+ case '\n':
+ *append_ptr++ = '\\';
+ *append_ptr++ = 'n';
+ break;
+ case '\r':
+ *append_ptr++ = '\\';
+ *append_ptr++ = 'r';
+ break;
+ case '\t':
+ *append_ptr++ = '\\';
+ *append_ptr++ = 't';
+ break;
+ case '\"':
+ *append_ptr++ = '\\';
+ *append_ptr++ = '\"';
+ break;
+ case '\'':
+ *append_ptr++ = '\\';
+ *append_ptr++ = '\'';
+ break;
+ case '\\':
+ *append_ptr++ = '\\';
+ *append_ptr++ = '\\';
+ break;
+ default:
+ if (!absl::ascii_isprint(c)) {
+ *append_ptr++ = '\\';
+ *append_ptr++ = '0' + c / 64;
+ *append_ptr++ = '0' + (c % 64) / 8;
+ *append_ptr++ = '0' + c % 8;
+ } else {
+ *append_ptr++ = c;
+ }
+ break;
+ }
+ }
+}
+
+bool Base64UnescapeInternal(const char* src_param, size_t szsrc, char* dest,
+ size_t szdest, const signed char* unbase64,
+ size_t* len) {
+ static const char kPad64Equals = '=';
+ static const char kPad64Dot = '.';
+
+ size_t destidx = 0;
+ int decode = 0;
+ int state = 0;
+ unsigned int ch = 0;
+ unsigned int temp = 0;
+
+ // If "char" is signed by default, using *src as an array index results in
+ // accessing negative array elements. Treat the input as a pointer to
+ // unsigned char to avoid this.
+ const unsigned char* src = reinterpret_cast<const unsigned char*>(src_param);
+
+ // The GET_INPUT macro gets the next input character, skipping
+ // over any whitespace, and stopping when we reach the end of the
+ // std::string or when we read any non-data character. The arguments are
+ // an arbitrary identifier (used as a label for goto) and the number
+ // of data bytes that must remain in the input to avoid aborting the
+ // loop.
+#define GET_INPUT(label, remain) \
+ label: \
+ --szsrc; \
+ ch = *src++; \
+ decode = unbase64[ch]; \
+ if (decode < 0) { \
+ if (absl::ascii_isspace(ch) && szsrc >= remain) goto label; \
+ state = 4 - remain; \
+ break; \
+ }
+
+ // if dest is null, we're just checking to see if it's legal input
+ // rather than producing output. (I suspect this could just be done
+ // with a regexp...). We duplicate the loop so this test can be
+ // outside it instead of in every iteration.
+
+ if (dest) {
+ // This loop consumes 4 input bytes and produces 3 output bytes
+ // per iteration. We can't know at the start that there is enough
+ // data left in the std::string for a full iteration, so the loop may
+ // break out in the middle; if so 'state' will be set to the
+ // number of input bytes read.
+
+ while (szsrc >= 4) {
+ // We'll start by optimistically assuming that the next four
+ // bytes of the std::string (src[0..3]) are four good data bytes
+ // (that is, no nulls, whitespace, padding chars, or illegal
+ // chars). We need to test src[0..2] for nulls individually
+ // before constructing temp to preserve the property that we
+ // never read past a null in the std::string (no matter how long
+ // szsrc claims the std::string is).
+
+ if (!src[0] || !src[1] || !src[2] ||
+ ((temp = ((unsigned(unbase64[src[0]]) << 18) |
+ (unsigned(unbase64[src[1]]) << 12) |
+ (unsigned(unbase64[src[2]]) << 6) |
+ (unsigned(unbase64[src[3]])))) &
+ 0x80000000)) {
+ // Iff any of those four characters was bad (null, illegal,
+ // whitespace, padding), then temp's high bit will be set
+ // (because unbase64[] is -1 for all bad characters).
+ //
+ // We'll back up and resort to the slower decoder, which knows
+ // how to handle those cases.
+
+ GET_INPUT(first, 4);
+ temp = decode;
+ GET_INPUT(second, 3);
+ temp = (temp << 6) | decode;
+ GET_INPUT(third, 2);
+ temp = (temp << 6) | decode;
+ GET_INPUT(fourth, 1);
+ temp = (temp << 6) | decode;
+ } else {
+ // We really did have four good data bytes, so advance four
+ // characters in the std::string.
+
+ szsrc -= 4;
+ src += 4;
+ }
+
+ // temp has 24 bits of input, so write that out as three bytes.
+
+ if (destidx + 3 > szdest) return false;
+ dest[destidx + 2] = temp;
+ temp >>= 8;
+ dest[destidx + 1] = temp;
+ temp >>= 8;
+ dest[destidx] = temp;
+ destidx += 3;
+ }
+ } else {
+ while (szsrc >= 4) {
+ if (!src[0] || !src[1] || !src[2] ||
+ ((temp = ((unsigned(unbase64[src[0]]) << 18) |
+ (unsigned(unbase64[src[1]]) << 12) |
+ (unsigned(unbase64[src[2]]) << 6) |
+ (unsigned(unbase64[src[3]])))) &
+ 0x80000000)) {
+ GET_INPUT(first_no_dest, 4);
+ GET_INPUT(second_no_dest, 3);
+ GET_INPUT(third_no_dest, 2);
+ GET_INPUT(fourth_no_dest, 1);
+ } else {
+ szsrc -= 4;
+ src += 4;
+ }
+ destidx += 3;
+ }
+ }
+
+#undef GET_INPUT
+
+ // if the loop terminated because we read a bad character, return
+ // now.
+ if (decode < 0 && ch != kPad64Equals && ch != kPad64Dot &&
+ !absl::ascii_isspace(ch))
+ return false;
+
+ if (ch == kPad64Equals || ch == kPad64Dot) {
+ // if we stopped by hitting an '=' or '.', un-read that character -- we'll
+ // look at it again when we count to check for the proper number of
+ // equals signs at the end.
+ ++szsrc;
+ --src;
+ } else {
+ // This loop consumes 1 input byte per iteration. It's used to
+ // clean up the 0-3 input bytes remaining when the first, faster
+ // loop finishes. 'temp' contains the data from 'state' input
+ // characters read by the first loop.
+ while (szsrc > 0) {
+ --szsrc;
+ ch = *src++;
+ decode = unbase64[ch];
+ if (decode < 0) {
+ if (absl::ascii_isspace(ch)) {
+ continue;
+ } else if (ch == kPad64Equals || ch == kPad64Dot) {
+ // back up one character; we'll read it again when we check
+ // for the correct number of pad characters at the end.
+ ++szsrc;
+ --src;
+ break;
+ } else {
+ return false;
+ }
+ }
+
+ // Each input character gives us six bits of output.
+ temp = (temp << 6) | decode;
+ ++state;
+ if (state == 4) {
+ // If we've accumulated 24 bits of output, write that out as
+ // three bytes.
+ if (dest) {
+ if (destidx + 3 > szdest) return false;
+ dest[destidx + 2] = temp;
+ temp >>= 8;
+ dest[destidx + 1] = temp;
+ temp >>= 8;
+ dest[destidx] = temp;
+ }
+ destidx += 3;
+ state = 0;
+ temp = 0;
+ }
+ }
+ }
+
+ // Process the leftover data contained in 'temp' at the end of the input.
+ int expected_equals = 0;
+ switch (state) {
+ case 0:
+ // Nothing left over; output is a multiple of 3 bytes.
+ break;
+
+ case 1:
+ // Bad input; we have 6 bits left over.
+ return false;
+
+ case 2:
+ // Produce one more output byte from the 12 input bits we have left.
+ if (dest) {
+ if (destidx + 1 > szdest) return false;
+ temp >>= 4;
+ dest[destidx] = temp;
+ }
+ ++destidx;
+ expected_equals = 2;
+ break;
+
+ case 3:
+ // Produce two more output bytes from the 18 input bits we have left.
+ if (dest) {
+ if (destidx + 2 > szdest) return false;
+ temp >>= 2;
+ dest[destidx + 1] = temp;
+ temp >>= 8;
+ dest[destidx] = temp;
+ }
+ destidx += 2;
+ expected_equals = 1;
+ break;
+
+ default:
+ // state should have no other values at this point.
+ ABSL_RAW_LOG(FATAL, "This can't happen; base64 decoder state = %d",
+ state);
+ }
+
+ // The remainder of the std::string should be all whitespace, mixed with
+ // exactly 0 equals signs, or exactly 'expected_equals' equals
+ // signs. (Always accepting 0 equals signs is an Abseil extension
+ // not covered in the RFC, as is accepting dot as the pad character.)
+
+ int equals = 0;
+ while (szsrc > 0) {
+ if (*src == kPad64Equals || *src == kPad64Dot)
+ ++equals;
+ else if (!absl::ascii_isspace(*src))
+ return false;
+ --szsrc;
+ ++src;
+ }
+
+ const bool ok = (equals == 0 || equals == expected_equals);
+ if (ok) *len = destidx;
+ return ok;
+}
+
+// The arrays below were generated by the following code
+// #include <sys/time.h>
+// #include <stdlib.h>
+// #include <std::string.h>
+// main()
+// {
+// static const char Base64[] =
+// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+// char* pos;
+// int idx, i, j;
+// printf(" ");
+// for (i = 0; i < 255; i += 8) {
+// for (j = i; j < i + 8; j++) {
+// pos = strchr(Base64, j);
+// if ((pos == nullptr) || (j == 0))
+// idx = -1;
+// else
+// idx = pos - Base64;
+// if (idx == -1)
+// printf(" %2d, ", idx);
+// else
+// printf(" %2d/*%c*/,", idx, j);
+// }
+// printf("\n ");
+// }
+// }
+//
+// where the value of "Base64[]" was replaced by one of the base-64 conversion
+// tables from the functions below.
+/* clang-format off */
+constexpr signed char kUnBase64[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 62/*+*/, -1, -1, -1, 63/*/ */,
+ 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+ 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1,
+ -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
+ 07/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+ 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+ 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, -1,
+ -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+ 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+ 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+ 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+constexpr signed char kUnWebSafeBase64[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 62/*-*/, -1, -1,
+ 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+ 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1,
+ -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
+ 07/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+ 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+ 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, 63/*_*/,
+ -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+ 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+ 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+ 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1
+};
+/* clang-format on */
+
+size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding) {
+ // Base64 encodes three bytes of input at a time. If the input is not
+ // divisible by three, we pad as appropriate.
+ //
+ // (from http://tools.ietf.org/html/rfc3548)
+ // Special processing is performed if fewer than 24 bits are available
+ // at the end of the data being encoded. A full encoding quantum is
+ // always completed at the end of a quantity. When fewer than 24 input
+ // bits are available in an input group, zero bits are added (on the
+ // right) to form an integral number of 6-bit groups. Padding at the
+ // end of the data is performed using the '=' character. Since all base
+ // 64 input is an integral number of octets, only the following cases
+ // can arise:
+
+ // Base64 encodes each three bytes of input into four bytes of output.
+ size_t len = (input_len / 3) * 4;
+
+ if (input_len % 3 == 0) {
+ // (from http://tools.ietf.org/html/rfc3548)
+ // (1) the final quantum of encoding input is an integral multiple of 24
+ // bits; here, the final unit of encoded output will be an integral
+ // multiple of 4 characters with no "=" padding,
+ } else if (input_len % 3 == 1) {
+ // (from http://tools.ietf.org/html/rfc3548)
+ // (2) the final quantum of encoding input is exactly 8 bits; here, the
+ // final unit of encoded output will be two characters followed by two
+ // "=" padding characters, or
+ len += 2;
+ if (do_padding) {
+ len += 2;
+ }
+ } else { // (input_len % 3 == 2)
+ // (from http://tools.ietf.org/html/rfc3548)
+ // (3) the final quantum of encoding input is exactly 16 bits; here, the
+ // final unit of encoded output will be three characters followed by one
+ // "=" padding character.
+ len += 3;
+ if (do_padding) {
+ len += 1;
+ }
+ }
+
+ assert(len >= input_len); // make sure we didn't overflow
+ return len;
+}
+
+size_t Base64EscapeInternal(const unsigned char* src, size_t szsrc, char* dest,
+ size_t szdest, const char* base64,
+ bool do_padding) {
+ static const char kPad64 = '=';
+
+ if (szsrc * 4 > szdest * 3) return 0;
+
+ char* cur_dest = dest;
+ const unsigned char* cur_src = src;
+
+ char* const limit_dest = dest + szdest;
+ const unsigned char* const limit_src = src + szsrc;
+
+ // Three bytes of data encodes to four characters of cyphertext.
+ // So we can pump through three-byte chunks atomically.
+ if (szsrc >= 3) { // "limit_src - 3" is UB if szsrc < 3
+ while (cur_src < limit_src - 3) { // as long as we have >= 32 bits
+ uint32_t in = absl::big_endian::Load32(cur_src) >> 8;
+
+ cur_dest[0] = base64[in >> 18];
+ in &= 0x3FFFF;
+ cur_dest[1] = base64[in >> 12];
+ in &= 0xFFF;
+ cur_dest[2] = base64[in >> 6];
+ in &= 0x3F;
+ cur_dest[3] = base64[in];
+
+ cur_dest += 4;
+ cur_src += 3;
+ }
+ }
+ // To save time, we didn't update szdest or szsrc in the loop. So do it now.
+ szdest = limit_dest - cur_dest;
+ szsrc = limit_src - cur_src;
+
+ /* now deal with the tail (<=3 bytes) */
+ switch (szsrc) {
+ case 0:
+ // Nothing left; nothing more to do.
+ break;
+ case 1: {
+ // One byte left: this encodes to two characters, and (optionally)
+ // two pad characters to round out the four-character cypherblock.
+ if (szdest < 2) return 0;
+ uint32_t in = cur_src[0];
+ cur_dest[0] = base64[in >> 2];
+ in &= 0x3;
+ cur_dest[1] = base64[in << 4];
+ cur_dest += 2;
+ szdest -= 2;
+ if (do_padding) {
+ if (szdest < 2) return 0;
+ cur_dest[0] = kPad64;
+ cur_dest[1] = kPad64;
+ cur_dest += 2;
+ szdest -= 2;
+ }
+ break;
+ }
+ case 2: {
+ // Two bytes left: this encodes to three characters, and (optionally)
+ // one pad character to round out the four-character cypherblock.
+ if (szdest < 3) return 0;
+ uint32_t in = absl::big_endian::Load16(cur_src);
+ cur_dest[0] = base64[in >> 10];
+ in &= 0x3FF;
+ cur_dest[1] = base64[in >> 4];
+ in &= 0x00F;
+ cur_dest[2] = base64[in << 2];
+ cur_dest += 3;
+ szdest -= 3;
+ if (do_padding) {
+ if (szdest < 1) return 0;
+ cur_dest[0] = kPad64;
+ cur_dest += 1;
+ szdest -= 1;
+ }
+ break;
+ }
+ case 3: {
+ // Three bytes left: same as in the big loop above. We can't do this in
+ // the loop because the loop above always reads 4 bytes, and the fourth
+ // byte is past the end of the input.
+ if (szdest < 4) return 0;
+ uint32_t in = (cur_src[0] << 16) + absl::big_endian::Load16(cur_src + 1);
+ cur_dest[0] = base64[in >> 18];
+ in &= 0x3FFFF;
+ cur_dest[1] = base64[in >> 12];
+ in &= 0xFFF;
+ cur_dest[2] = base64[in >> 6];
+ in &= 0x3F;
+ cur_dest[3] = base64[in];
+ cur_dest += 4;
+ szdest -= 4;
+ break;
+ }
+ default:
+ // Should not be reached: blocks of 4 bytes are handled
+ // in the while loop before this switch statement.
+ ABSL_RAW_LOG(FATAL, "Logic problem? szsrc = %zu", szsrc);
+ break;
+ }
+ return (cur_dest - dest);
+}
+
+constexpr char kBase64Chars[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+constexpr char kWebSafeBase64Chars[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+void Base64EscapeInternal(const unsigned char* src, size_t szsrc, std::string* dest,
+ bool do_padding, const char* base64_chars) {
+ const size_t calc_escaped_size =
+ CalculateBase64EscapedLenInternal(szsrc, do_padding);
+ strings_internal::STLStringResizeUninitialized(dest, calc_escaped_size);
+
+ const size_t escaped_len = Base64EscapeInternal(
+ src, szsrc, &(*dest)[0], dest->size(), base64_chars, do_padding);
+ assert(calc_escaped_size == escaped_len);
+ dest->erase(escaped_len);
+}
+
+bool Base64UnescapeInternal(const char* src, size_t slen, std::string* dest,
+ const signed char* unbase64) {
+ // Determine the size of the output std::string. Base64 encodes every 3 bytes into
+ // 4 characters. any leftover chars are added directly for good measure.
+ // This is documented in the base64 RFC: http://tools.ietf.org/html/rfc3548
+ const size_t dest_len = 3 * (slen / 4) + (slen % 4);
+
+ strings_internal::STLStringResizeUninitialized(dest, dest_len);
+
+ // We are getting the destination buffer by getting the beginning of the
+ // std::string and converting it into a char *.
+ size_t len;
+ const bool ok =
+ Base64UnescapeInternal(src, slen, &(*dest)[0], dest_len, unbase64, &len);
+ if (!ok) {
+ dest->clear();
+ return false;
+ }
+
+ // could be shorter if there was padding
+ assert(len <= dest_len);
+ dest->erase(len);
+
+ return true;
+}
+
+/* clang-format off */
+constexpr char kHexValue[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // '0'..'9'
+ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'A'..'F'
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'a'..'f'
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+/* clang-format on */
+
+// This is a templated function so that T can be either a char*
+// or a std::string. This works because we use the [] operator to access
+// individual characters at a time.
+template <typename T>
+void HexStringToBytesInternal(const char* from, T to, ptrdiff_t num) {
+ for (int i = 0; i < num; i++) {
+ to[i] = (kHexValue[from[i * 2] & 0xFF] << 4) +
+ (kHexValue[from[i * 2 + 1] & 0xFF]);
+ }
+}
+
+// This is a templated function so that T can be either a char* or a std::string.
+template <typename T>
+void BytesToHexStringInternal(const unsigned char* src, T dest, ptrdiff_t num) {
+ auto dest_ptr = &dest[0];
+ for (auto src_ptr = src; src_ptr != (src + num); ++src_ptr, dest_ptr += 2) {
+ const char* hex_p = &kHexTable[*src_ptr * 2];
+ std::copy(hex_p, hex_p + 2, dest_ptr);
+ }
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------
+// CUnescape()
+//
+// See CUnescapeInternal() for implementation details.
+// ----------------------------------------------------------------------
+bool CUnescape(absl::string_view source, std::string* dest, std::string* error) {
+ return CUnescapeInternal(source, kUnescapeNulls, dest, error);
+}
+
+std::string CEscape(absl::string_view src) {
+ std::string dest;
+ CEscapeAndAppendInternal(src, &dest);
+ return dest;
+}
+
+std::string CHexEscape(absl::string_view src) {
+ return CEscapeInternal(src, true, false);
+}
+
+std::string Utf8SafeCEscape(absl::string_view src) {
+ return CEscapeInternal(src, false, true);
+}
+
+std::string Utf8SafeCHexEscape(absl::string_view src) {
+ return CEscapeInternal(src, true, true);
+}
+
+// ----------------------------------------------------------------------
+// ptrdiff_t Base64Unescape() - base64 decoder
+// ptrdiff_t Base64Escape() - base64 encoder
+// ptrdiff_t WebSafeBase64Unescape() - Google's variation of base64 decoder
+// ptrdiff_t WebSafeBase64Escape() - Google's variation of base64 encoder
+//
+// Check out
+// http://tools.ietf.org/html/rfc2045 for formal description, but what we
+// care about is that...
+// Take the encoded stuff in groups of 4 characters and turn each
+// character into a code 0 to 63 thus:
+// A-Z map to 0 to 25
+// a-z map to 26 to 51
+// 0-9 map to 52 to 61
+// +(- for WebSafe) maps to 62
+// /(_ for WebSafe) maps to 63
+// There will be four numbers, all less than 64 which can be represented
+// by a 6 digit binary number (aaaaaa, bbbbbb, cccccc, dddddd respectively).
+// Arrange the 6 digit binary numbers into three bytes as such:
+// aaaaaabb bbbbcccc ccdddddd
+// Equals signs (one or two) are used at the end of the encoded block to
+// indicate that the text was not an integer multiple of three bytes long.
+// ----------------------------------------------------------------------
+
+bool Base64Unescape(absl::string_view src, std::string* dest) {
+ return Base64UnescapeInternal(src.data(), src.size(), dest, kUnBase64);
+}
+
+bool WebSafeBase64Unescape(absl::string_view src, std::string* dest) {
+ return Base64UnescapeInternal(src.data(), src.size(), dest, kUnWebSafeBase64);
+}
+
+void Base64Escape(absl::string_view src, std::string* dest) {
+ Base64EscapeInternal(reinterpret_cast<const unsigned char*>(src.data()),
+ src.size(), dest, true, kBase64Chars);
+}
+
+void WebSafeBase64Escape(absl::string_view src, std::string* dest) {
+ Base64EscapeInternal(reinterpret_cast<const unsigned char*>(src.data()),
+ src.size(), dest, false, kWebSafeBase64Chars);
+}
+
+std::string HexStringToBytes(absl::string_view from) {
+ std::string result;
+ const auto num = from.size() / 2;
+ strings_internal::STLStringResizeUninitialized(&result, num);
+ absl::HexStringToBytesInternal<std::string&>(from.data(), result, num);
+ return result;
+}
+
+std::string BytesToHexString(absl::string_view from) {
+ std::string result;
+ strings_internal::STLStringResizeUninitialized(&result, 2 * from.size());
+ absl::BytesToHexStringInternal<std::string&>(
+ reinterpret_cast<const unsigned char*>(from.data()), result, from.size());
+ return result;
+}
+
+} // namespace absl
diff --git a/absl/strings/escaping.h b/absl/strings/escaping.h
new file mode 100644
index 0000000..05327e7
--- /dev/null
+++ b/absl/strings/escaping.h
@@ -0,0 +1,158 @@
+//
+// 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: escaping.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains std::string utilities involved in escaping and
+// unescaping strings in various ways.
+//
+
+#ifndef ABSL_STRINGS_ESCAPING_H_
+#define ABSL_STRINGS_ESCAPING_H_
+
+#include <cstddef>
+#include <string>
+#include <vector>
+
+#include "absl/base/macros.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/str_join.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+
+// CUnescape()
+//
+// Unescapes a `source` std::string and copies it into `dest`, rewriting C-style
+// escape sequences (http://en.cppreference.com/w/cpp/language/escape) into
+// their proper code point equivalents, returning `true` if successful.
+//
+// The following unescape sequences can be handled:
+//
+// * ASCII escape sequences ('\n','\r','\\', etc.) to their ASCII equivalents
+// * Octal escape sequences ('\nnn') to byte nnn. The unescaped value must
+// resolve to a single byte or an error will occur. E.g. values greater than
+// 0xff will produce an error.
+// * Hexadecimal escape sequences ('\xnn') to byte nn. While an arbitrary
+// number of following digits are allowed, the unescaped value must resolve
+// to a single byte or an error will occur. E.g. '\x0045' is equivalent to
+// '\x45', but '\x1234' will produce an error.
+// * Unicode escape sequences ('\unnnn' for exactly four hex digits or
+// '\Unnnnnnnn' for exactly eight hex digits, which will be encoded in
+// UTF-8. (E.g., `\u2019` unescapes to the three bytes 0xE2, 0x80, and
+// 0x99).
+//
+//
+// If any errors are encountered, this function returns `false` and stores the
+// first encountered error in `error`. To disable error reporting, set `error`
+// to `nullptr` or use the overload with no error reporting below.
+//
+// Example:
+//
+// std::string s = "foo\\rbar\\nbaz\\t";
+// std::string unescaped_s = absl::CUnescape(s);
+// EXPECT_EQ(unescaped_s, "foo\rbar\nbaz\t");
+bool CUnescape(absl::string_view source, std::string* dest, std::string* error);
+
+// Overload of `CUnescape()` with no error reporting.
+inline bool CUnescape(absl::string_view source, std::string* dest) {
+ return CUnescape(source, dest, nullptr);
+}
+
+// CEscape()
+//
+// Escapes a 'src' std::string using C-style escapes sequences
+// (http://en.cppreference.com/w/cpp/language/escape), escaping other
+// non-printable/non-whitespace bytes as octal sequences (e.g. "\377").
+//
+// Example:
+//
+// std::string s = "foo\rbar\tbaz\010\011\012\013\014\x0d\n";
+// std::string escaped_s = absl::CEscape(s);
+// EXPECT_EQ(escaped_s, "foo\\rbar\\tbaz\\010\\t\\n\\013\\014\\r\\n");
+std::string CEscape(absl::string_view src);
+
+// CHexEscape()
+//
+// Escapes a 'src' std::string using C-style escape sequences, escaping
+// other non-printable/non-whitespace bytes as hexadecimal sequences (e.g.
+// "\xFF").
+//
+// Example:
+//
+// std::string s = "foo\rbar\tbaz\010\011\012\013\014\x0d\n";
+// std::string escaped_s = absl::CHexEscape(s);
+// EXPECT_EQ(escaped_s, "foo\\rbar\\tbaz\\x08\\t\\n\\x0b\\x0c\\r\\n");
+std::string CHexEscape(absl::string_view src);
+
+// Utf8SafeCEscape()
+//
+// Escapes a 'src' std::string using C-style escape sequences, escaping bytes as
+// octal sequences, and passing through UTF-8 characters without conversion.
+// I.e., when encountering any bytes with their high bit set, this function
+// will not escape those values, whether or not they are valid UTF-8.
+std::string Utf8SafeCEscape(absl::string_view src);
+
+// Utf8SafeCHexEscape()
+//
+// Escapes a 'src' std::string using C-style escape sequences, escaping bytes as
+// hexidecimal sequences, and passing through UTF-8 characters without
+// conversion.
+std::string Utf8SafeCHexEscape(absl::string_view src);
+
+// Base64Unescape()
+//
+// Converts a `src` std::string encoded in Base64 to its binary equivalent, writing
+// it to a `dest` buffer, returning `true` on success. If `src` contains invalid
+// characters, `dest` is cleared and returns `false`.
+bool Base64Unescape(absl::string_view src, std::string* dest);
+
+// WebSafeBase64Unescape(absl::string_view, std::string*)
+//
+// Converts a `src` std::string encoded in Base64 to its binary equivalent, writing
+// it to a `dest` buffer, but using '-' instead of '+', and '_' instead of '/'.
+// If `src` contains invalid characters, `dest` is cleared and returns `false`.
+bool WebSafeBase64Unescape(absl::string_view src, std::string* dest);
+
+// Base64Escape()
+//
+// Encodes a `src` std::string into a `dest` buffer using base64 encoding, with
+// padding characters. This function conforms with RFC 4648 section 4 (base64).
+void Base64Escape(absl::string_view src, std::string* dest);
+
+// WebSafeBase64Escape()
+//
+// Encodes a `src` std::string into a `dest` buffer using uses '-' instead of '+' and
+// '_' instead of '/', and without padding. This function conforms with RFC 4648
+// section 5 (base64url).
+void WebSafeBase64Escape(absl::string_view src, std::string* dest);
+
+// HexStringToBytes()
+//
+// Converts an ASCII hex std::string into bytes, returning binary data of length
+// `from.size()/2`.
+std::string HexStringToBytes(absl::string_view from);
+
+// BytesToHexString()
+//
+// Converts binary data into an ASCII text std::string, returing a std::string of size
+// `2*from.size()`.
+std::string BytesToHexString(absl::string_view from);
+
+} // namespace absl
+
+#endif // ABSL_STRINGS_ESCAPING_H_
diff --git a/absl/strings/escaping_test.cc b/absl/strings/escaping_test.cc
new file mode 100644
index 0000000..d464051
--- /dev/null
+++ b/absl/strings/escaping_test.cc
@@ -0,0 +1,638 @@
+// 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/strings/escaping.h"
+
+#include <array>
+#include <cstdio>
+#include <cstring>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/macros.h"
+#include "absl/container/fixed_array.h"
+#include "absl/strings/str_cat.h"
+
+#include "absl/strings/internal/escaping_test_common.inc"
+
+namespace {
+
+struct epair {
+ std::string escaped;
+ std::string unescaped;
+};
+
+TEST(CEscape, EscapeAndUnescape) {
+ const std::string inputs[] = {
+ std::string("foo\nxx\r\b\0023"),
+ std::string(""),
+ std::string("abc"),
+ std::string("\1chad_rules"),
+ std::string("\1arnar_drools"),
+ std::string("xxxx\r\t'\"\\"),
+ std::string("\0xx\0", 4),
+ std::string("\x01\x31"),
+ std::string("abc\xb\x42\141bc"),
+ std::string("123\1\x31\x32\x33"),
+ std::string("\xc1\xca\x1b\x62\x19o\xcc\x04"),
+ std::string("\\\"\xe8\xb0\xb7\xe6\xad\x8c\\\" is Google\\\'s Chinese name"),
+ };
+ // Do this twice, once for octal escapes and once for hex escapes.
+ for (int kind = 0; kind < 4; kind++) {
+ for (const std::string& original : inputs) {
+ std::string escaped;
+ switch (kind) {
+ case 0:
+ escaped = absl::CEscape(original);
+ break;
+ case 1:
+ escaped = absl::CHexEscape(original);
+ break;
+ case 2:
+ escaped = absl::Utf8SafeCEscape(original);
+ break;
+ case 3:
+ escaped = absl::Utf8SafeCHexEscape(original);
+ break;
+ }
+ std::string unescaped_str;
+ EXPECT_TRUE(absl::CUnescape(escaped, &unescaped_str));
+ EXPECT_EQ(unescaped_str, original);
+
+ // Check in-place unescaping
+ std::string s = escaped;
+ EXPECT_TRUE(absl::CUnescape(s, &s));
+ ASSERT_EQ(s, original);
+ }
+ }
+ // Check that all possible two character strings can be escaped then
+ // unescaped successfully.
+ for (int char0 = 0; char0 < 256; char0++) {
+ for (int char1 = 0; char1 < 256; char1++) {
+ char chars[2];
+ chars[0] = char0;
+ chars[1] = char1;
+ std::string s(chars, 2);
+ std::string escaped = absl::CHexEscape(s);
+ std::string unescaped;
+ EXPECT_TRUE(absl::CUnescape(escaped, &unescaped));
+ EXPECT_EQ(s, unescaped);
+ }
+ }
+}
+
+TEST(CEscape, BasicEscaping) {
+ epair oct_values[] = {
+ {"foo\\rbar\\nbaz\\t", "foo\rbar\nbaz\t"},
+ {"\\'full of \\\"sound\\\" and \\\"fury\\\"\\'",
+ "'full of \"sound\" and \"fury\"'"},
+ {"signi\\\\fying\\\\ nothing\\\\", "signi\\fying\\ nothing\\"},
+ {"\\010\\t\\n\\013\\014\\r", "\010\011\012\013\014\015"}
+ };
+ epair hex_values[] = {
+ {"ubik\\rubik\\nubik\\t", "ubik\rubik\nubik\t"},
+ {"I\\\'ve just seen a \\\"face\\\"",
+ "I've just seen a \"face\""},
+ {"hel\\\\ter\\\\skel\\\\ter\\\\", "hel\\ter\\skel\\ter\\"},
+ {"\\x08\\t\\n\\x0b\\x0c\\r", "\010\011\012\013\014\015"}
+ };
+ epair utf8_oct_values[] = {
+ {"\xe8\xb0\xb7\xe6\xad\x8c\\r\xe8\xb0\xb7\xe6\xad\x8c\\nbaz\\t",
+ "\xe8\xb0\xb7\xe6\xad\x8c\r\xe8\xb0\xb7\xe6\xad\x8c\nbaz\t"},
+ {"\\\"\xe8\xb0\xb7\xe6\xad\x8c\\\" is Google\\\'s Chinese name",
+ "\"\xe8\xb0\xb7\xe6\xad\x8c\" is Google\'s Chinese name"},
+ {"\xe3\x83\xa1\xe3\x83\xbc\xe3\x83\xab\\\\are\\\\Japanese\\\\chars\\\\",
+ "\xe3\x83\xa1\xe3\x83\xbc\xe3\x83\xab\\are\\Japanese\\chars\\"},
+ {"\xed\x81\xac\xeb\xa1\xac\\010\\t\\n\\013\\014\\r",
+ "\xed\x81\xac\xeb\xa1\xac\010\011\012\013\014\015"}
+ };
+ epair utf8_hex_values[] = {
+ {"\x20\xe4\xbd\xa0\\t\xe5\xa5\xbd,\\r!\\n",
+ "\x20\xe4\xbd\xa0\t\xe5\xa5\xbd,\r!\n"},
+ {"\xe8\xa9\xa6\xe9\xa8\x93\\\' means \\\"test\\\"",
+ "\xe8\xa9\xa6\xe9\xa8\x93\' means \"test\""},
+ {"\\\\\xe6\x88\x91\\\\:\\\\\xe6\x9d\xa8\xe6\xac\xa2\\\\",
+ "\\\xe6\x88\x91\\:\\\xe6\x9d\xa8\xe6\xac\xa2\\"},
+ {"\xed\x81\xac\xeb\xa1\xac\\x08\\t\\n\\x0b\\x0c\\r",
+ "\xed\x81\xac\xeb\xa1\xac\010\011\012\013\014\015"}
+ };
+
+ for (const epair& val : oct_values) {
+ std::string escaped = absl::CEscape(val.unescaped);
+ EXPECT_EQ(escaped, val.escaped);
+ }
+ for (const epair& val : hex_values) {
+ std::string escaped = absl::CHexEscape(val.unescaped);
+ EXPECT_EQ(escaped, val.escaped);
+ }
+ for (const epair& val : utf8_oct_values) {
+ std::string escaped = absl::Utf8SafeCEscape(val.unescaped);
+ EXPECT_EQ(escaped, val.escaped);
+ }
+ for (const epair& val : utf8_hex_values) {
+ std::string escaped = absl::Utf8SafeCHexEscape(val.unescaped);
+ EXPECT_EQ(escaped, val.escaped);
+ }
+}
+
+TEST(Unescape, BasicFunction) {
+ epair tests[] =
+ {{"\\u0030", "0"},
+ {"\\u00A3", "\xC2\xA3"},
+ {"\\u22FD", "\xE2\x8B\xBD"},
+ {"\\U00010000", "\xF0\x90\x80\x80"},
+ {"\\U0010FFFD", "\xF4\x8F\xBF\xBD"}};
+ for (const epair& val : tests) {
+ std::string out;
+ EXPECT_TRUE(absl::CUnescape(val.escaped, &out));
+ EXPECT_EQ(out, val.unescaped);
+ }
+ std::string bad[] =
+ {"\\u1", // too short
+ "\\U1", // too short
+ "\\Uffffff",
+ "\\777", // exceeds 0xff
+ "\\xABCD"}; // exceeds 0xff
+ for (const std::string& e : bad) {
+ std::string error;
+ std::string out;
+ EXPECT_FALSE(absl::CUnescape(e, &out, &error));
+ EXPECT_FALSE(error.empty());
+ }
+}
+
+class CUnescapeTest : public testing::Test {
+ protected:
+ static const char kStringWithMultipleOctalNulls[];
+ static const char kStringWithMultipleHexNulls[];
+ static const char kStringWithMultipleUnicodeNulls[];
+
+ std::string result_string_;
+};
+
+const char CUnescapeTest::kStringWithMultipleOctalNulls[] =
+ "\\0\\n" // null escape \0 plus newline
+ "0\\n" // just a number 0 (not a null escape) plus newline
+ "\\00\\12" // null escape \00 plus octal newline code
+ "\\000"; // null escape \000
+
+// This has the same ingredients as kStringWithMultipleOctalNulls
+// but with \x hex escapes instead of octal escapes.
+const char CUnescapeTest::kStringWithMultipleHexNulls[] =
+ "\\x0\\n"
+ "0\\n"
+ "\\x00\\xa"
+ "\\x000";
+
+const char CUnescapeTest::kStringWithMultipleUnicodeNulls[] =
+ "\\u0000\\n" // short-form (4-digit) null escape plus newline
+ "0\\n" // just a number 0 (not a null escape) plus newline
+ "\\U00000000"; // long-form (8-digit) null escape
+
+TEST_F(CUnescapeTest, Unescapes1CharOctalNull) {
+ std::string original_string = "\\0";
+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+ EXPECT_EQ(std::string("\0", 1), result_string_);
+}
+
+TEST_F(CUnescapeTest, Unescapes2CharOctalNull) {
+ std::string original_string = "\\00";
+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+ EXPECT_EQ(std::string("\0", 1), result_string_);
+}
+
+TEST_F(CUnescapeTest, Unescapes3CharOctalNull) {
+ std::string original_string = "\\000";
+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+ EXPECT_EQ(std::string("\0", 1), result_string_);
+}
+
+TEST_F(CUnescapeTest, Unescapes1CharHexNull) {
+ std::string original_string = "\\x0";
+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+ EXPECT_EQ(std::string("\0", 1), result_string_);
+}
+
+TEST_F(CUnescapeTest, Unescapes2CharHexNull) {
+ std::string original_string = "\\x00";
+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+ EXPECT_EQ(std::string("\0", 1), result_string_);
+}
+
+TEST_F(CUnescapeTest, Unescapes3CharHexNull) {
+ std::string original_string = "\\x000";
+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+ EXPECT_EQ(std::string("\0", 1), result_string_);
+}
+
+TEST_F(CUnescapeTest, Unescapes4CharUnicodeNull) {
+ std::string original_string = "\\u0000";
+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+ EXPECT_EQ(std::string("\0", 1), result_string_);
+}
+
+TEST_F(CUnescapeTest, Unescapes8CharUnicodeNull) {
+ std::string original_string = "\\U00000000";
+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+ EXPECT_EQ(std::string("\0", 1), result_string_);
+}
+
+TEST_F(CUnescapeTest, UnescapesMultipleOctalNulls) {
+ std::string original_string(kStringWithMultipleOctalNulls);
+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+ // All escapes, including newlines and null escapes, should have been
+ // converted to the equivalent characters.
+ EXPECT_EQ(std::string("\0\n"
+ "0\n"
+ "\0\n"
+ "\0", 7), result_string_);
+}
+
+
+TEST_F(CUnescapeTest, UnescapesMultipleHexNulls) {
+ std::string original_string(kStringWithMultipleHexNulls);
+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+ EXPECT_EQ(std::string("\0\n"
+ "0\n"
+ "\0\n"
+ "\0", 7), result_string_);
+}
+
+TEST_F(CUnescapeTest, UnescapesMultipleUnicodeNulls) {
+ std::string original_string(kStringWithMultipleUnicodeNulls);
+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
+ EXPECT_EQ(std::string("\0\n"
+ "0\n"
+ "\0", 5), result_string_);
+}
+
+static struct {
+ absl::string_view plaintext;
+ absl::string_view cyphertext;
+} const base64_tests[] = {
+ // Empty std::string.
+ {{"", 0}, {"", 0}},
+ {{nullptr, 0},
+ {"", 0}}, // if length is zero, plaintext ptr must be ignored!
+
+ // Basic bit patterns;
+ // values obtained with "echo -n '...' | uuencode -m test"
+
+ {{"\000", 1}, "AA=="},
+ {{"\001", 1}, "AQ=="},
+ {{"\002", 1}, "Ag=="},
+ {{"\004", 1}, "BA=="},
+ {{"\010", 1}, "CA=="},
+ {{"\020", 1}, "EA=="},
+ {{"\040", 1}, "IA=="},
+ {{"\100", 1}, "QA=="},
+ {{"\200", 1}, "gA=="},
+
+ {{"\377", 1}, "/w=="},
+ {{"\376", 1}, "/g=="},
+ {{"\375", 1}, "/Q=="},
+ {{"\373", 1}, "+w=="},
+ {{"\367", 1}, "9w=="},
+ {{"\357", 1}, "7w=="},
+ {{"\337", 1}, "3w=="},
+ {{"\277", 1}, "vw=="},
+ {{"\177", 1}, "fw=="},
+ {{"\000\000", 2}, "AAA="},
+ {{"\000\001", 2}, "AAE="},
+ {{"\000\002", 2}, "AAI="},
+ {{"\000\004", 2}, "AAQ="},
+ {{"\000\010", 2}, "AAg="},
+ {{"\000\020", 2}, "ABA="},
+ {{"\000\040", 2}, "ACA="},
+ {{"\000\100", 2}, "AEA="},
+ {{"\000\200", 2}, "AIA="},
+ {{"\001\000", 2}, "AQA="},
+ {{"\002\000", 2}, "AgA="},
+ {{"\004\000", 2}, "BAA="},
+ {{"\010\000", 2}, "CAA="},
+ {{"\020\000", 2}, "EAA="},
+ {{"\040\000", 2}, "IAA="},
+ {{"\100\000", 2}, "QAA="},
+ {{"\200\000", 2}, "gAA="},
+
+ {{"\377\377", 2}, "//8="},
+ {{"\377\376", 2}, "//4="},
+ {{"\377\375", 2}, "//0="},
+ {{"\377\373", 2}, "//s="},
+ {{"\377\367", 2}, "//c="},
+ {{"\377\357", 2}, "/+8="},
+ {{"\377\337", 2}, "/98="},
+ {{"\377\277", 2}, "/78="},
+ {{"\377\177", 2}, "/38="},
+ {{"\376\377", 2}, "/v8="},
+ {{"\375\377", 2}, "/f8="},
+ {{"\373\377", 2}, "+/8="},
+ {{"\367\377", 2}, "9/8="},
+ {{"\357\377", 2}, "7/8="},
+ {{"\337\377", 2}, "3/8="},
+ {{"\277\377", 2}, "v/8="},
+ {{"\177\377", 2}, "f/8="},
+
+ {{"\000\000\000", 3}, "AAAA"},
+ {{"\000\000\001", 3}, "AAAB"},
+ {{"\000\000\002", 3}, "AAAC"},
+ {{"\000\000\004", 3}, "AAAE"},
+ {{"\000\000\010", 3}, "AAAI"},
+ {{"\000\000\020", 3}, "AAAQ"},
+ {{"\000\000\040", 3}, "AAAg"},
+ {{"\000\000\100", 3}, "AABA"},
+ {{"\000\000\200", 3}, "AACA"},
+ {{"\000\001\000", 3}, "AAEA"},
+ {{"\000\002\000", 3}, "AAIA"},
+ {{"\000\004\000", 3}, "AAQA"},
+ {{"\000\010\000", 3}, "AAgA"},
+ {{"\000\020\000", 3}, "ABAA"},
+ {{"\000\040\000", 3}, "ACAA"},
+ {{"\000\100\000", 3}, "AEAA"},
+ {{"\000\200\000", 3}, "AIAA"},
+ {{"\001\000\000", 3}, "AQAA"},
+ {{"\002\000\000", 3}, "AgAA"},
+ {{"\004\000\000", 3}, "BAAA"},
+ {{"\010\000\000", 3}, "CAAA"},
+ {{"\020\000\000", 3}, "EAAA"},
+ {{"\040\000\000", 3}, "IAAA"},
+ {{"\100\000\000", 3}, "QAAA"},
+ {{"\200\000\000", 3}, "gAAA"},
+
+ {{"\377\377\377", 3}, "////"},
+ {{"\377\377\376", 3}, "///+"},
+ {{"\377\377\375", 3}, "///9"},
+ {{"\377\377\373", 3}, "///7"},
+ {{"\377\377\367", 3}, "///3"},
+ {{"\377\377\357", 3}, "///v"},
+ {{"\377\377\337", 3}, "///f"},
+ {{"\377\377\277", 3}, "//+/"},
+ {{"\377\377\177", 3}, "//9/"},
+ {{"\377\376\377", 3}, "//7/"},
+ {{"\377\375\377", 3}, "//3/"},
+ {{"\377\373\377", 3}, "//v/"},
+ {{"\377\367\377", 3}, "//f/"},
+ {{"\377\357\377", 3}, "/+//"},
+ {{"\377\337\377", 3}, "/9//"},
+ {{"\377\277\377", 3}, "/7//"},
+ {{"\377\177\377", 3}, "/3//"},
+ {{"\376\377\377", 3}, "/v//"},
+ {{"\375\377\377", 3}, "/f//"},
+ {{"\373\377\377", 3}, "+///"},
+ {{"\367\377\377", 3}, "9///"},
+ {{"\357\377\377", 3}, "7///"},
+ {{"\337\377\377", 3}, "3///"},
+ {{"\277\377\377", 3}, "v///"},
+ {{"\177\377\377", 3}, "f///"},
+
+ // Random numbers: values obtained with
+ //
+ // #! /bin/bash
+ // dd bs=$1 count=1 if=/dev/random of=/tmp/bar.random
+ // od -N $1 -t o1 /tmp/bar.random
+ // uuencode -m test < /tmp/bar.random
+ //
+ // where $1 is the number of bytes (2, 3)
+
+ {{"\243\361", 2}, "o/E="},
+ {{"\024\167", 2}, "FHc="},
+ {{"\313\252", 2}, "y6o="},
+ {{"\046\041", 2}, "JiE="},
+ {{"\145\236", 2}, "ZZ4="},
+ {{"\254\325", 2}, "rNU="},
+ {{"\061\330", 2}, "Mdg="},
+ {{"\245\032", 2}, "pRo="},
+ {{"\006\000", 2}, "BgA="},
+ {{"\375\131", 2}, "/Vk="},
+ {{"\303\210", 2}, "w4g="},
+ {{"\040\037", 2}, "IB8="},
+ {{"\261\372", 2}, "sfo="},
+ {{"\335\014", 2}, "3Qw="},
+ {{"\233\217", 2}, "m48="},
+ {{"\373\056", 2}, "+y4="},
+ {{"\247\232", 2}, "p5o="},
+ {{"\107\053", 2}, "Rys="},
+ {{"\204\077", 2}, "hD8="},
+ {{"\276\211", 2}, "vok="},
+ {{"\313\110", 2}, "y0g="},
+ {{"\363\376", 2}, "8/4="},
+ {{"\251\234", 2}, "qZw="},
+ {{"\103\262", 2}, "Q7I="},
+ {{"\142\312", 2}, "Yso="},
+ {{"\067\211", 2}, "N4k="},
+ {{"\220\001", 2}, "kAE="},
+ {{"\152\240", 2}, "aqA="},
+ {{"\367\061", 2}, "9zE="},
+ {{"\133\255", 2}, "W60="},
+ {{"\176\035", 2}, "fh0="},
+ {{"\032\231", 2}, "Gpk="},
+
+ {{"\013\007\144", 3}, "Cwdk"},
+ {{"\030\112\106", 3}, "GEpG"},
+ {{"\047\325\046", 3}, "J9Um"},
+ {{"\310\160\022", 3}, "yHAS"},
+ {{"\131\100\237", 3}, "WUCf"},
+ {{"\064\342\134", 3}, "NOJc"},
+ {{"\010\177\004", 3}, "CH8E"},
+ {{"\345\147\205", 3}, "5WeF"},
+ {{"\300\343\360", 3}, "wOPw"},
+ {{"\061\240\201", 3}, "MaCB"},
+ {{"\225\333\044", 3}, "ldsk"},
+ {{"\215\137\352", 3}, "jV/q"},
+ {{"\371\147\160", 3}, "+Wdw"},
+ {{"\030\320\051", 3}, "GNAp"},
+ {{"\044\174\241", 3}, "JHyh"},
+ {{"\260\127\037", 3}, "sFcf"},
+ {{"\111\045\033", 3}, "SSUb"},
+ {{"\202\114\107", 3}, "gkxH"},
+ {{"\057\371\042", 3}, "L/ki"},
+ {{"\223\247\244", 3}, "k6ek"},
+ {{"\047\216\144", 3}, "J45k"},
+ {{"\203\070\327", 3}, "gzjX"},
+ {{"\247\140\072", 3}, "p2A6"},
+ {{"\124\115\116", 3}, "VE1O"},
+ {{"\157\162\050", 3}, "b3Io"},
+ {{"\357\223\004", 3}, "75ME"},
+ {{"\052\117\156", 3}, "Kk9u"},
+ {{"\347\154\000", 3}, "52wA"},
+ {{"\303\012\142", 3}, "wwpi"},
+ {{"\060\035\362", 3}, "MB3y"},
+ {{"\130\226\361", 3}, "WJbx"},
+ {{"\173\013\071", 3}, "ews5"},
+ {{"\336\004\027", 3}, "3gQX"},
+ {{"\357\366\234", 3}, "7/ac"},
+ {{"\353\304\111", 3}, "68RJ"},
+ {{"\024\264\131", 3}, "FLRZ"},
+ {{"\075\114\251", 3}, "PUyp"},
+ {{"\315\031\225", 3}, "zRmV"},
+ {{"\154\201\276", 3}, "bIG+"},
+ {{"\200\066\072", 3}, "gDY6"},
+ {{"\142\350\267", 3}, "Yui3"},
+ {{"\033\000\166", 3}, "GwB2"},
+ {{"\210\055\077", 3}, "iC0/"},
+ {{"\341\037\124", 3}, "4R9U"},
+ {{"\161\103\152", 3}, "cUNq"},
+ {{"\270\142\131", 3}, "uGJZ"},
+ {{"\337\076\074", 3}, "3z48"},
+ {{"\375\106\362", 3}, "/Uby"},
+ {{"\227\301\127", 3}, "l8FX"},
+ {{"\340\002\234", 3}, "4AKc"},
+ {{"\121\064\033", 3}, "UTQb"},
+ {{"\157\134\143", 3}, "b1xj"},
+ {{"\247\055\327", 3}, "py3X"},
+ {{"\340\142\005", 3}, "4GIF"},
+ {{"\060\260\143", 3}, "MLBj"},
+ {{"\075\203\170", 3}, "PYN4"},
+ {{"\143\160\016", 3}, "Y3AO"},
+ {{"\313\013\063", 3}, "ywsz"},
+ {{"\174\236\135", 3}, "fJ5d"},
+ {{"\103\047\026", 3}, "QycW"},
+ {{"\365\005\343", 3}, "9QXj"},
+ {{"\271\160\223", 3}, "uXCT"},
+ {{"\362\255\172", 3}, "8q16"},
+ {{"\113\012\015", 3}, "SwoN"},
+
+ // various lengths, generated by this python script:
+ //
+ // from std::string import lowercase as lc
+ // for i in range(27):
+ // print '{ %2d, "%s",%s "%s" },' % (i, lc[:i], ' ' * (26-i),
+ // lc[:i].encode('base64').strip())
+
+ {{"", 0}, {"", 0}},
+ {"a", "YQ=="},
+ {"ab", "YWI="},
+ {"abc", "YWJj"},
+ {"abcd", "YWJjZA=="},
+ {"abcde", "YWJjZGU="},
+ {"abcdef", "YWJjZGVm"},
+ {"abcdefg", "YWJjZGVmZw=="},
+ {"abcdefgh", "YWJjZGVmZ2g="},
+ {"abcdefghi", "YWJjZGVmZ2hp"},
+ {"abcdefghij", "YWJjZGVmZ2hpag=="},
+ {"abcdefghijk", "YWJjZGVmZ2hpams="},
+ {"abcdefghijkl", "YWJjZGVmZ2hpamts"},
+ {"abcdefghijklm", "YWJjZGVmZ2hpamtsbQ=="},
+ {"abcdefghijklmn", "YWJjZGVmZ2hpamtsbW4="},
+ {"abcdefghijklmno", "YWJjZGVmZ2hpamtsbW5v"},
+ {"abcdefghijklmnop", "YWJjZGVmZ2hpamtsbW5vcA=="},
+ {"abcdefghijklmnopq", "YWJjZGVmZ2hpamtsbW5vcHE="},
+ {"abcdefghijklmnopqr", "YWJjZGVmZ2hpamtsbW5vcHFy"},
+ {"abcdefghijklmnopqrs", "YWJjZGVmZ2hpamtsbW5vcHFycw=="},
+ {"abcdefghijklmnopqrst", "YWJjZGVmZ2hpamtsbW5vcHFyc3Q="},
+ {"abcdefghijklmnopqrstu", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1"},
+ {"abcdefghijklmnopqrstuv", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dg=="},
+ {"abcdefghijklmnopqrstuvw", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnc="},
+ {"abcdefghijklmnopqrstuvwx", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4"},
+ {"abcdefghijklmnopqrstuvwxy", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eQ=="},
+ {"abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo="},
+};
+
+TEST(Base64, EscapeAndUnescape) {
+ // Check the short strings; this tests the math (and boundaries)
+ for (const auto& tc : base64_tests) {
+ std::string encoded("this junk should be ignored");
+ absl::Base64Escape(tc.plaintext, &encoded);
+ EXPECT_EQ(encoded, tc.cyphertext);
+
+ std::string decoded("this junk should be ignored");
+ EXPECT_TRUE(absl::Base64Unescape(encoded, &decoded));
+ EXPECT_EQ(decoded, tc.plaintext);
+
+ std::string websafe(tc.cyphertext);
+ for (int c = 0; c < websafe.size(); ++c) {
+ if ('+' == websafe[c]) websafe[c] = '-';
+ if ('/' == websafe[c]) websafe[c] = '_';
+ if ('=' == websafe[c]) {
+ websafe.resize(c);
+ break;
+ }
+ }
+
+ encoded = "this junk should be ignored";
+ absl::WebSafeBase64Escape(tc.plaintext, &encoded);
+ EXPECT_EQ(encoded, websafe);
+
+ // Let's try the std::string version of the decoder
+ decoded = "this junk should be ignored";
+ EXPECT_TRUE(absl::WebSafeBase64Unescape(websafe, &decoded));
+ EXPECT_EQ(decoded, tc.plaintext);
+ }
+
+ // Now try the long strings, this tests the streaming
+ for (const auto& tc : base64_strings) {
+ std::string buffer;
+ absl::WebSafeBase64Escape(tc.plaintext, &buffer);
+ EXPECT_EQ(tc.cyphertext, buffer);
+ }
+
+ // Verify the behavior when decoding bad data
+ {
+ absl::string_view data_set[] = {"ab-/", absl::string_view("\0bcd", 4),
+ absl::string_view("abc.\0", 5)};
+ for (absl::string_view bad_data : data_set) {
+ std::string buf;
+ EXPECT_FALSE(absl::Base64Unescape(bad_data, &buf));
+ EXPECT_FALSE(absl::WebSafeBase64Unescape(bad_data, &buf));
+ EXPECT_TRUE(buf.empty());
+ }
+ }
+}
+
+TEST(Base64, DISABLED_HugeData) {
+ const size_t kSize = size_t(3) * 1000 * 1000 * 1000;
+ static_assert(kSize % 3 == 0, "kSize must be divisible by 3");
+ const std::string huge(kSize, 'x');
+
+ std::string escaped;
+ absl::Base64Escape(huge, &escaped);
+
+ // Generates the std::string that should match a base64 encoded "xxx..." std::string.
+ // "xxx" in base64 is "eHh4".
+ std::string expected_encoding;
+ expected_encoding.reserve(kSize / 3 * 4);
+ for (size_t i = 0; i < kSize / 3; ++i) {
+ expected_encoding.append("eHh4");
+ }
+ EXPECT_EQ(expected_encoding, escaped);
+
+ std::string unescaped;
+ EXPECT_TRUE(absl::Base64Unescape(escaped, &unescaped));
+ EXPECT_EQ(huge, unescaped);
+}
+
+TEST(HexAndBack, HexStringToBytes_and_BytesToHexString) {
+ std::string hex_mixed = "0123456789abcdefABCDEF";
+ std::string bytes_expected = "\x01\x23\x45\x67\x89\xab\xcd\xef\xAB\xCD\xEF";
+ std::string hex_only_lower = "0123456789abcdefabcdef";
+
+ std::string bytes_result = absl::HexStringToBytes(hex_mixed);
+ EXPECT_EQ(bytes_expected, bytes_result);
+
+ std::string prefix_valid = hex_mixed + "?";
+ std::string prefix_valid_result = absl::HexStringToBytes(
+ absl::string_view(prefix_valid.data(), prefix_valid.size() - 1));
+ EXPECT_EQ(bytes_expected, prefix_valid_result);
+
+ std::string infix_valid = "?" + hex_mixed + "???";
+ std::string infix_valid_result = absl::HexStringToBytes(
+ absl::string_view(infix_valid.data() + 1, hex_mixed.size()));
+ EXPECT_EQ(bytes_expected, infix_valid_result);
+
+ std::string hex_result = absl::BytesToHexString(bytes_expected);
+ EXPECT_EQ(hex_only_lower, hex_result);
+}
+
+} // namespace
diff --git a/absl/strings/internal/char_map.h b/absl/strings/internal/char_map.h
new file mode 100644
index 0000000..8d92963
--- /dev/null
+++ b/absl/strings/internal/char_map.h
@@ -0,0 +1,154 @@
+// 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.
+//
+// Character Map Class
+//
+// A fast, bit-vector map for 8-bit unsigned characters.
+// This class is useful for non-character purposes as well.
+
+#ifndef ABSL_STRINGS_INTERNAL_CHAR_MAP_H_
+#define ABSL_STRINGS_INTERNAL_CHAR_MAP_H_
+
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+
+namespace absl {
+namespace strings_internal {
+
+class Charmap {
+ public:
+ constexpr Charmap() : m_() {}
+
+ // Initializes with a given char*. Note that NUL is not treated as
+ // a terminator, but rather a char to be flicked.
+ Charmap(const char* str, int len) : m_() {
+ while (len--) SetChar(*str++);
+ }
+
+ // Initializes with a given char*. NUL is treated as a terminator
+ // and will not be in the charmap.
+ explicit Charmap(const char* str) : m_() {
+ while (*str) SetChar(*str++);
+ }
+
+ constexpr bool contains(unsigned char c) const {
+ return (m_[c / 64] >> (c % 64)) & 0x1;
+ }
+
+ // Returns true if and only if a character exists in both maps.
+ bool IntersectsWith(const Charmap& c) const {
+ for (size_t i = 0; i < ABSL_ARRAYSIZE(m_); ++i) {
+ if ((m_[i] & c.m_[i]) != 0) return true;
+ }
+ return false;
+ }
+
+ bool IsZero() const {
+ for (uint64_t c : m_) {
+ if (c != 0) return false;
+ }
+ return true;
+ }
+
+ // Containing only a single specified char.
+ static constexpr Charmap Char(char x) {
+ return Charmap(CharMaskForWord(x, 0), CharMaskForWord(x, 1),
+ CharMaskForWord(x, 2), CharMaskForWord(x, 3));
+ }
+
+ // Containing all the chars in the C-std::string 's'.
+ // Note that this is expensively recursive because of the C++11 constexpr
+ // formulation. Use only in constexpr initializers.
+ static constexpr Charmap FromString(const char* s) {
+ return *s == 0 ? Charmap() : (Char(*s) | FromString(s + 1));
+ }
+
+ // Containing all the chars in the closed interval [lo,hi].
+ static constexpr Charmap Range(char lo, char hi) {
+ return Charmap(RangeForWord(lo, hi, 0), RangeForWord(lo, hi, 1),
+ RangeForWord(lo, hi, 2), RangeForWord(lo, hi, 3));
+ }
+
+ friend constexpr Charmap operator&(const Charmap& a, const Charmap& b) {
+ return Charmap(a.m_[0] & b.m_[0], a.m_[1] & b.m_[1], a.m_[2] & b.m_[2],
+ a.m_[3] & b.m_[3]);
+ }
+
+ friend constexpr Charmap operator|(const Charmap& a, const Charmap& b) {
+ return Charmap(a.m_[0] | b.m_[0], a.m_[1] | b.m_[1], a.m_[2] | b.m_[2],
+ a.m_[3] | b.m_[3]);
+ }
+
+ friend constexpr Charmap operator~(const Charmap& a) {
+ return Charmap(~a.m_[0], ~a.m_[1], ~a.m_[2], ~a.m_[3]);
+ }
+
+ private:
+ constexpr Charmap(uint64_t b0, uint64_t b1, uint64_t b2, uint64_t b3)
+ : m_{b0, b1, b2, b3} {}
+
+ static constexpr uint64_t RangeForWord(unsigned char lo, unsigned char hi,
+ uint64_t word) {
+ return OpenRangeFromZeroForWord(hi + 1, word) &
+ ~OpenRangeFromZeroForWord(lo, word);
+ }
+
+ // All the chars in the specified word of the range [0, upper).
+ static constexpr uint64_t OpenRangeFromZeroForWord(uint64_t upper,
+ uint64_t word) {
+ return (upper <= 64 * word)
+ ? 0
+ : (upper >= 64 * (word + 1))
+ ? ~static_cast<uint64_t>(0)
+ : (~static_cast<uint64_t>(0) >> (64 - upper % 64));
+ }
+
+ static constexpr uint64_t CharMaskForWord(unsigned char x, uint64_t word) {
+ return (x / 64 == word) ? (static_cast<uint64_t>(1) << (x % 64)) : 0;
+ }
+
+ private:
+ void SetChar(unsigned char c) {
+ m_[c / 64] |= static_cast<uint64_t>(1) << (c % 64);
+ }
+
+ uint64_t m_[4];
+};
+
+// Mirror the char-classifying predicates in <cctype>
+constexpr Charmap UpperCharmap() { return Charmap::Range('A', 'Z'); }
+constexpr Charmap LowerCharmap() { return Charmap::Range('a', 'z'); }
+constexpr Charmap DigitCharmap() { return Charmap::Range('0', '9'); }
+constexpr Charmap AlphaCharmap() { return LowerCharmap() | UpperCharmap(); }
+constexpr Charmap AlnumCharmap() { return DigitCharmap() | AlphaCharmap(); }
+constexpr Charmap XDigitCharmap() {
+ return DigitCharmap() | Charmap::Range('A', 'F') | Charmap::Range('a', 'f');
+}
+constexpr Charmap PrintCharmap() { return Charmap::Range(0x20, 0x7e); }
+constexpr Charmap SpaceCharmap() { return Charmap::FromString("\t\n\v\f\r "); }
+constexpr Charmap CntrlCharmap() {
+ return Charmap::Range(0, 0x7f) & ~PrintCharmap();
+}
+constexpr Charmap BlankCharmap() { return Charmap::FromString("\t "); }
+constexpr Charmap GraphCharmap() { return PrintCharmap() & ~SpaceCharmap(); }
+constexpr Charmap PunctCharmap() { return GraphCharmap() & ~AlnumCharmap(); }
+
+} // namespace strings_internal
+} // namespace absl
+
+#endif // ABSL_STRINGS_INTERNAL_CHAR_MAP_H_
diff --git a/absl/strings/internal/char_map_test.cc b/absl/strings/internal/char_map_test.cc
new file mode 100644
index 0000000..2167be9
--- /dev/null
+++ b/absl/strings/internal/char_map_test.cc
@@ -0,0 +1,172 @@
+// 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/strings/internal/char_map.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <cctype>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace {
+
+constexpr absl::strings_internal::Charmap everything_map =
+ ~absl::strings_internal::Charmap();
+constexpr absl::strings_internal::Charmap nothing_map{};
+
+TEST(Charmap, AllTests) {
+ const absl::strings_internal::Charmap also_nothing_map("", 0);
+ ASSERT_TRUE(everything_map.contains('\0'));
+ ASSERT_TRUE(!nothing_map.contains('\0'));
+ ASSERT_TRUE(!also_nothing_map.contains('\0'));
+ for (unsigned char ch = 1; ch != 0; ++ch) {
+ ASSERT_TRUE(everything_map.contains(ch));
+ ASSERT_TRUE(!nothing_map.contains(ch));
+ ASSERT_TRUE(!also_nothing_map.contains(ch));
+ }
+
+ const absl::strings_internal::Charmap symbols("&@#@^!@?", 5);
+ ASSERT_TRUE(symbols.contains('&'));
+ ASSERT_TRUE(symbols.contains('@'));
+ ASSERT_TRUE(symbols.contains('#'));
+ ASSERT_TRUE(symbols.contains('^'));
+ ASSERT_TRUE(!symbols.contains('!'));
+ ASSERT_TRUE(!symbols.contains('?'));
+ int cnt = 0;
+ for (unsigned char ch = 1; ch != 0; ++ch)
+ cnt += symbols.contains(ch);
+ ASSERT_EQ(cnt, 4);
+
+ const absl::strings_internal::Charmap lets("^abcde", 3);
+ const absl::strings_internal::Charmap lets2("fghij\0klmnop", 10);
+ const absl::strings_internal::Charmap lets3("fghij\0klmnop");
+ ASSERT_TRUE(lets2.contains('k'));
+ ASSERT_TRUE(!lets3.contains('k'));
+
+ ASSERT_TRUE(symbols.IntersectsWith(lets));
+ ASSERT_TRUE(!lets2.IntersectsWith(lets));
+ ASSERT_TRUE(lets.IntersectsWith(symbols));
+ ASSERT_TRUE(!lets.IntersectsWith(lets2));
+
+ ASSERT_TRUE(nothing_map.IsZero());
+ ASSERT_TRUE(!lets.IsZero());
+}
+
+namespace {
+std::string Members(const absl::strings_internal::Charmap& m) {
+ std::string r;
+ for (size_t i = 0; i < 256; ++i)
+ if (m.contains(i)) r.push_back(i);
+ return r;
+}
+
+std::string ClosedRangeString(unsigned char lo, unsigned char hi) {
+ // Don't depend on lo<hi. Just increment until lo==hi.
+ std::string s;
+ while (true) {
+ s.push_back(lo);
+ if (lo == hi) break;
+ ++lo;
+ }
+ return s;
+}
+
+} // namespace
+
+TEST(Charmap, Constexpr) {
+ constexpr absl::strings_internal::Charmap kEmpty = nothing_map;
+ EXPECT_THAT(Members(kEmpty), "");
+ constexpr absl::strings_internal::Charmap kA =
+ absl::strings_internal::Charmap::Char('A');
+ EXPECT_THAT(Members(kA), "A");
+ constexpr absl::strings_internal::Charmap kAZ =
+ absl::strings_internal::Charmap::Range('A', 'Z');
+ EXPECT_THAT(Members(kAZ), "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ constexpr absl::strings_internal::Charmap kIdentifier =
+ absl::strings_internal::Charmap::Range('0', '9') |
+ absl::strings_internal::Charmap::Range('A', 'Z') |
+ absl::strings_internal::Charmap::Range('a', 'z') |
+ absl::strings_internal::Charmap::Char('_');
+ EXPECT_THAT(Members(kIdentifier),
+ "0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "_"
+ "abcdefghijklmnopqrstuvwxyz");
+ constexpr absl::strings_internal::Charmap kAll = everything_map;
+ for (size_t i = 0; i < 256; ++i) {
+ EXPECT_TRUE(kAll.contains(i)) << i;
+ }
+ constexpr absl::strings_internal::Charmap kHello =
+ absl::strings_internal::Charmap::FromString("Hello, world!");
+ EXPECT_THAT(Members(kHello), " !,Hdelorw");
+
+ // test negation and intersection
+ constexpr absl::strings_internal::Charmap kABC =
+ absl::strings_internal::Charmap::Range('A', 'Z') &
+ ~absl::strings_internal::Charmap::Range('D', 'Z');
+ EXPECT_THAT(Members(kABC), "ABC");
+}
+
+TEST(Charmap, Range) {
+ // Exhaustive testing takes too long, so test some of the boundaries that
+ // are perhaps going to cause trouble.
+ std::vector<size_t> poi = {0, 1, 2, 3, 4, 7, 8, 9, 15,
+ 16, 17, 30, 31, 32, 33, 63, 64, 65,
+ 127, 128, 129, 223, 224, 225, 254, 255};
+ for (auto lo = poi.begin(); lo != poi.end(); ++lo) {
+ SCOPED_TRACE(*lo);
+ for (auto hi = lo; hi != poi.end(); ++hi) {
+ SCOPED_TRACE(*hi);
+ EXPECT_THAT(Members(absl::strings_internal::Charmap::Range(*lo, *hi)),
+ ClosedRangeString(*lo, *hi));
+ }
+ }
+}
+
+bool AsBool(int x) { return static_cast<bool>(x); }
+
+TEST(CharmapCtype, Match) {
+ for (int c = 0; c < 256; ++c) {
+ SCOPED_TRACE(c);
+ SCOPED_TRACE(static_cast<char>(c));
+ EXPECT_EQ(AsBool(std::isupper(c)),
+ absl::strings_internal::UpperCharmap().contains(c));
+ EXPECT_EQ(AsBool(std::islower(c)),
+ absl::strings_internal::LowerCharmap().contains(c));
+ EXPECT_EQ(AsBool(std::isdigit(c)),
+ absl::strings_internal::DigitCharmap().contains(c));
+ EXPECT_EQ(AsBool(std::isalpha(c)),
+ absl::strings_internal::AlphaCharmap().contains(c));
+ EXPECT_EQ(AsBool(std::isalnum(c)),
+ absl::strings_internal::AlnumCharmap().contains(c));
+ EXPECT_EQ(AsBool(std::isxdigit(c)),
+ absl::strings_internal::XDigitCharmap().contains(c));
+ EXPECT_EQ(AsBool(std::isprint(c)),
+ absl::strings_internal::PrintCharmap().contains(c));
+ EXPECT_EQ(AsBool(std::isspace(c)),
+ absl::strings_internal::SpaceCharmap().contains(c));
+ EXPECT_EQ(AsBool(std::iscntrl(c)),
+ absl::strings_internal::CntrlCharmap().contains(c));
+ EXPECT_EQ(AsBool(std::isblank(c)),
+ absl::strings_internal::BlankCharmap().contains(c));
+ EXPECT_EQ(AsBool(std::isgraph(c)),
+ absl::strings_internal::GraphCharmap().contains(c));
+ EXPECT_EQ(AsBool(std::ispunct(c)),
+ absl::strings_internal::PunctCharmap().contains(c));
+ }
+}
+
+} // namespace
diff --git a/absl/strings/internal/escaping_test_common.inc b/absl/strings/internal/escaping_test_common.inc
new file mode 100644
index 0000000..6f29140
--- /dev/null
+++ b/absl/strings/internal/escaping_test_common.inc
@@ -0,0 +1,113 @@
+// 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 test contains common things needed by both escaping_test.cc and
+// escaping_benchmark.cc.
+
+namespace {
+
+struct {
+ absl::string_view plaintext;
+ absl::string_view cyphertext;
+} const base64_strings[] = {
+ // Some google quotes
+ // Cyphertext created with "uuencode (GNU sharutils) 4.6.3"
+ // (Note that we're testing the websafe encoding, though, so if
+ // you add messages, be sure to run "tr -- '+/' '-_'" on the output)
+ { "I was always good at math and science, and I never realized "
+ "that was unusual or somehow undesirable. So one of the things "
+ "I care a lot about is helping to remove that stigma, "
+ "to show girls that you can be feminine, you can like the things "
+ "that girls like, but you can also be really good at technology. "
+ "You can be really good at building things."
+ " - Marissa Meyer, Newsweek, 2010-12-22" "\n",
+
+ "SSB3YXMgYWx3YXlzIGdvb2QgYXQgbWF0aCBhbmQgc2NpZW5jZSwgYW5kIEkg"
+ "bmV2ZXIgcmVhbGl6ZWQgdGhhdCB3YXMgdW51c3VhbCBvciBzb21laG93IHVu"
+ "ZGVzaXJhYmxlLiBTbyBvbmUgb2YgdGhlIHRoaW5ncyBJIGNhcmUgYSBsb3Qg"
+ "YWJvdXQgaXMgaGVscGluZyB0byByZW1vdmUgdGhhdCBzdGlnbWEsIHRvIHNo"
+ "b3cgZ2lybHMgdGhhdCB5b3UgY2FuIGJlIGZlbWluaW5lLCB5b3UgY2FuIGxp"
+ "a2UgdGhlIHRoaW5ncyB0aGF0IGdpcmxzIGxpa2UsIGJ1dCB5b3UgY2FuIGFs"
+ "c28gYmUgcmVhbGx5IGdvb2QgYXQgdGVjaG5vbG9neS4gWW91IGNhbiBiZSBy"
+ "ZWFsbHkgZ29vZCBhdCBidWlsZGluZyB0aGluZ3MuIC0gTWFyaXNzYSBNZXll"
+ "ciwgTmV3c3dlZWssIDIwMTAtMTItMjIK" },
+
+ { "Typical first year for a new cluster: "
+ "~0.5 overheating "
+ "~1 PDU failure "
+ "~1 rack-move "
+ "~1 network rewiring "
+ "~20 rack failures "
+ "~5 racks go wonky "
+ "~8 network maintenances "
+ "~12 router reloads "
+ "~3 router failures "
+ "~dozens of minor 30-second blips for dns "
+ "~1000 individual machine failures "
+ "~thousands of hard drive failures "
+ "slow disks, bad memory, misconfigured machines, flaky machines, etc."
+ " - Jeff Dean, The Joys of Real Hardware" "\n",
+
+ "VHlwaWNhbCBmaXJzdCB5ZWFyIGZvciBhIG5ldyBjbHVzdGVyOiB-MC41IG92"
+ "ZXJoZWF0aW5nIH4xIFBEVSBmYWlsdXJlIH4xIHJhY2stbW92ZSB-MSBuZXR3"
+ "b3JrIHJld2lyaW5nIH4yMCByYWNrIGZhaWx1cmVzIH41IHJhY2tzIGdvIHdv"
+ "bmt5IH44IG5ldHdvcmsgbWFpbnRlbmFuY2VzIH4xMiByb3V0ZXIgcmVsb2Fk"
+ "cyB-MyByb3V0ZXIgZmFpbHVyZXMgfmRvemVucyBvZiBtaW5vciAzMC1zZWNv"
+ "bmQgYmxpcHMgZm9yIGRucyB-MTAwMCBpbmRpdmlkdWFsIG1hY2hpbmUgZmFp"
+ "bHVyZXMgfnRob3VzYW5kcyBvZiBoYXJkIGRyaXZlIGZhaWx1cmVzIHNsb3cg"
+ "ZGlza3MsIGJhZCBtZW1vcnksIG1pc2NvbmZpZ3VyZWQgbWFjaGluZXMsIGZs"
+ "YWt5IG1hY2hpbmVzLCBldGMuIC0gSmVmZiBEZWFuLCBUaGUgSm95cyBvZiBS"
+ "ZWFsIEhhcmR3YXJlCg" },
+
+ { "I'm the head of the webspam team at Google. "
+ "That means that if you type your name into Google and get porn back, "
+ "it's my fault. Unless you're a porn star, in which case porn is a "
+ "completely reasonable response."
+ " - Matt Cutts, Google Plus" "\n",
+
+ "SSdtIHRoZSBoZWFkIG9mIHRoZSB3ZWJzcGFtIHRlYW0gYXQgR29vZ2xlLiAg"
+ "VGhhdCBtZWFucyB0aGF0IGlmIHlvdSB0eXBlIHlvdXIgbmFtZSBpbnRvIEdv"
+ "b2dsZSBhbmQgZ2V0IHBvcm4gYmFjaywgaXQncyBteSBmYXVsdC4gVW5sZXNz"
+ "IHlvdSdyZSBhIHBvcm4gc3RhciwgaW4gd2hpY2ggY2FzZSBwb3JuIGlzIGEg"
+ "Y29tcGxldGVseSByZWFzb25hYmxlIHJlc3BvbnNlLiAtIE1hdHQgQ3V0dHMs"
+ "IEdvb2dsZSBQbHVzCg" },
+
+ { "It will still be a long time before machines approach human intelligence. "
+ "But luckily, machines don't actually have to be intelligent; "
+ "they just have to fake it. Access to a wealth of information, "
+ "combined with a rudimentary decision-making capacity, "
+ "can often be almost as useful. Of course, the results are better yet "
+ "when coupled with intelligence. A reference librarian with access to "
+ "a good search engine is a formidable tool."
+ " - Craig Silverstein, Siemens Pictures of the Future, Spring 2004" "\n",
+
+ "SXQgd2lsbCBzdGlsbCBiZSBhIGxvbmcgdGltZSBiZWZvcmUgbWFjaGluZXMg"
+ "YXBwcm9hY2ggaHVtYW4gaW50ZWxsaWdlbmNlLiBCdXQgbHVja2lseSwgbWFj"
+ "aGluZXMgZG9uJ3QgYWN0dWFsbHkgaGF2ZSB0byBiZSBpbnRlbGxpZ2VudDsg"
+ "dGhleSBqdXN0IGhhdmUgdG8gZmFrZSBpdC4gQWNjZXNzIHRvIGEgd2VhbHRo"
+ "IG9mIGluZm9ybWF0aW9uLCBjb21iaW5lZCB3aXRoIGEgcnVkaW1lbnRhcnkg"
+ "ZGVjaXNpb24tbWFraW5nIGNhcGFjaXR5LCBjYW4gb2Z0ZW4gYmUgYWxtb3N0"
+ "IGFzIHVzZWZ1bC4gT2YgY291cnNlLCB0aGUgcmVzdWx0cyBhcmUgYmV0dGVy"
+ "IHlldCB3aGVuIGNvdXBsZWQgd2l0aCBpbnRlbGxpZ2VuY2UuIEEgcmVmZXJl"
+ "bmNlIGxpYnJhcmlhbiB3aXRoIGFjY2VzcyB0byBhIGdvb2Qgc2VhcmNoIGVu"
+ "Z2luZSBpcyBhIGZvcm1pZGFibGUgdG9vbC4gLSBDcmFpZyBTaWx2ZXJzdGVp"
+ "biwgU2llbWVucyBQaWN0dXJlcyBvZiB0aGUgRnV0dXJlLCBTcHJpbmcgMjAw"
+ "NAo" },
+
+ // Degenerate edge case
+ { "",
+ "" },
+};
+
+} // namespace
diff --git a/absl/strings/internal/fastmem.h b/absl/strings/internal/fastmem.h
new file mode 100644
index 0000000..9989b12
--- /dev/null
+++ b/absl/strings/internal/fastmem.h
@@ -0,0 +1,215 @@
+// 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.
+//
+// Fast memory copying and comparison routines.
+// strings::fastmemcmp_inlined() replaces memcmp()
+// strings::memcpy_inlined() replaces memcpy()
+// strings::memeq(a, b, n) replaces memcmp(a, b, n) == 0
+//
+// strings::*_inlined() routines are inline versions of the
+// routines exported by this module. Sometimes using the inlined
+// versions is faster. Measure before using the inlined versions.
+//
+
+#ifndef ABSL_STRINGS_INTERNAL_FASTMEM_H_
+#define ABSL_STRINGS_INTERNAL_FASTMEM_H_
+
+#ifdef __SSE4_1__
+#include <immintrin.h>
+#endif
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+
+#include "absl/base/internal/unaligned_access.h"
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+
+namespace absl {
+namespace strings_internal {
+
+// Return true if the n bytes at a equal the n bytes at b.
+// The regions are allowed to overlap.
+//
+// The performance is similar to the performance of memcmp(), but faster for
+// moderately-sized inputs, or inputs that share a common prefix and differ
+// somewhere in their last 8 bytes. Further optimizations can be added later
+// if it makes sense to do so. Alternatively, if the compiler & runtime improve
+// to eliminate the need for this, we can remove it.
+inline bool memeq(const char* a, const char* b, size_t n) {
+ size_t n_rounded_down = n & ~static_cast<size_t>(7);
+ if (ABSL_PREDICT_FALSE(n_rounded_down == 0)) { // n <= 7
+ return memcmp(a, b, n) == 0;
+ }
+ // n >= 8
+ {
+ uint64_t u =
+ ABSL_INTERNAL_UNALIGNED_LOAD64(a) ^ ABSL_INTERNAL_UNALIGNED_LOAD64(b);
+ uint64_t v = ABSL_INTERNAL_UNALIGNED_LOAD64(a + n - 8) ^
+ ABSL_INTERNAL_UNALIGNED_LOAD64(b + n - 8);
+ if ((u | v) != 0) { // The first or last 8 bytes differ.
+ return false;
+ }
+ }
+ // The next line forces n to be a multiple of 8.
+ n = n_rounded_down;
+ if (n >= 80) {
+ // In 2013 or later, this should be fast on long strings.
+ return memcmp(a, b, n) == 0;
+ }
+ // Now force n to be a multiple of 16. Arguably, a "switch" would be smart
+ // here, but there's a difficult-to-evaluate code size vs. speed issue. The
+ // current approach often re-compares some bytes (worst case is if n initially
+ // was 16, 32, 48, or 64), but is fairly short.
+ size_t e = n & 8;
+ a += e;
+ b += e;
+ n -= e;
+ // n is now in {0, 16, 32, ...}. Process 0 or more 16-byte chunks.
+ while (n > 0) {
+#ifdef __SSE4_1__
+ __m128i u =
+ _mm_xor_si128(_mm_loadu_si128(reinterpret_cast<const __m128i*>(a)),
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(b)));
+ if (!_mm_test_all_zeros(u, u)) {
+ return false;
+ }
+#else
+ uint64_t x =
+ ABSL_INTERNAL_UNALIGNED_LOAD64(a) ^ ABSL_INTERNAL_UNALIGNED_LOAD64(b);
+ uint64_t y = ABSL_INTERNAL_UNALIGNED_LOAD64(a + 8) ^
+ ABSL_INTERNAL_UNALIGNED_LOAD64(b + 8);
+ if ((x | y) != 0) {
+ return false;
+ }
+#endif
+ a += 16;
+ b += 16;
+ n -= 16;
+ }
+ return true;
+}
+
+inline int fastmemcmp_inlined(const void* va, const void* vb, size_t n) {
+ const unsigned char* pa = static_cast<const unsigned char*>(va);
+ const unsigned char* pb = static_cast<const unsigned char*>(vb);
+ switch (n) {
+ default:
+ return memcmp(va, vb, n);
+ case 7:
+ if (*pa != *pb) return *pa < *pb ? -1 : +1;
+ ++pa;
+ ++pb;
+ ABSL_FALLTHROUGH_INTENDED;
+ case 6:
+ if (*pa != *pb) return *pa < *pb ? -1 : +1;
+ ++pa;
+ ++pb;
+ ABSL_FALLTHROUGH_INTENDED;
+ case 5:
+ if (*pa != *pb) return *pa < *pb ? -1 : +1;
+ ++pa;
+ ++pb;
+ ABSL_FALLTHROUGH_INTENDED;
+ case 4:
+ if (*pa != *pb) return *pa < *pb ? -1 : +1;
+ ++pa;
+ ++pb;
+ ABSL_FALLTHROUGH_INTENDED;
+ case 3:
+ if (*pa != *pb) return *pa < *pb ? -1 : +1;
+ ++pa;
+ ++pb;
+ ABSL_FALLTHROUGH_INTENDED;
+ case 2:
+ if (*pa != *pb) return *pa < *pb ? -1 : +1;
+ ++pa;
+ ++pb;
+ ABSL_FALLTHROUGH_INTENDED;
+ case 1:
+ if (*pa != *pb) return *pa < *pb ? -1 : +1;
+ ABSL_FALLTHROUGH_INTENDED;
+ case 0:
+ break;
+ }
+ return 0;
+}
+
+// The standard memcpy operation is slow for variable small sizes.
+// This implementation inlines the optimal realization for sizes 1 to 16.
+// To avoid code bloat don't use it in case of not performance-critical spots,
+// nor when you don't expect very frequent values of size <= 16.
+inline void memcpy_inlined(char* dst, const char* src, size_t size) {
+ // Compiler inlines code with minimal amount of data movement when third
+ // parameter of memcpy is a constant.
+ switch (size) {
+ case 1:
+ memcpy(dst, src, 1);
+ break;
+ case 2:
+ memcpy(dst, src, 2);
+ break;
+ case 3:
+ memcpy(dst, src, 3);
+ break;
+ case 4:
+ memcpy(dst, src, 4);
+ break;
+ case 5:
+ memcpy(dst, src, 5);
+ break;
+ case 6:
+ memcpy(dst, src, 6);
+ break;
+ case 7:
+ memcpy(dst, src, 7);
+ break;
+ case 8:
+ memcpy(dst, src, 8);
+ break;
+ case 9:
+ memcpy(dst, src, 9);
+ break;
+ case 10:
+ memcpy(dst, src, 10);
+ break;
+ case 11:
+ memcpy(dst, src, 11);
+ break;
+ case 12:
+ memcpy(dst, src, 12);
+ break;
+ case 13:
+ memcpy(dst, src, 13);
+ break;
+ case 14:
+ memcpy(dst, src, 14);
+ break;
+ case 15:
+ memcpy(dst, src, 15);
+ break;
+ case 16:
+ memcpy(dst, src, 16);
+ break;
+ default:
+ memcpy(dst, src, size);
+ break;
+ }
+}
+
+} // namespace strings_internal
+} // namespace absl
+
+#endif // ABSL_STRINGS_INTERNAL_FASTMEM_H_
diff --git a/absl/strings/internal/fastmem_test.cc b/absl/strings/internal/fastmem_test.cc
new file mode 100644
index 0000000..7c670f9
--- /dev/null
+++ b/absl/strings/internal/fastmem_test.cc
@@ -0,0 +1,453 @@
+// 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/strings/internal/fastmem.h"
+
+#include <memory>
+#include <random>
+#include <string>
+
+#include "base/init_google.h"
+#include "base/logging.h"
+#include "testing/base/public/benchmark.h"
+#include "gtest/gtest.h"
+
+namespace {
+
+using RandomEngine = std::minstd_rand0;
+
+void VerifyResults(const int r1, const int r2, const std::string& a,
+ const std::string& b) {
+ CHECK_EQ(a.size(), b.size());
+ if (r1 == 0) {
+ EXPECT_EQ(r2, 0) << a << " " << b;
+ } else if (r1 > 0) {
+ EXPECT_GT(r2, 0) << a << " " << b;
+ } else {
+ EXPECT_LT(r2, 0) << a << " " << b;
+ }
+ if ((r1 == 0) == (r2 == 0)) {
+ EXPECT_EQ(r1 == 0,
+ absl::strings_internal::memeq(a.data(), b.data(), a.size()))
+ << r1 << " " << a << " " << b;
+ }
+}
+
+// Check correctness against glibc's memcmp implementation
+void CheckSingle(const std::string& a, const std::string& b) {
+ CHECK_EQ(a.size(), b.size());
+ const int r1 = memcmp(a.data(), b.data(), a.size());
+ const int r2 =
+ absl::strings_internal::fastmemcmp_inlined(a.data(), b.data(), a.size());
+ VerifyResults(r1, r2, a, b);
+}
+
+void GenerateString(size_t len, std::string* s) {
+ s->clear();
+ for (int i = 0; i < len; i++) {
+ *s += ('a' + (i % 26));
+ }
+}
+
+void CheckCompare(const std::string& a, const std::string& b) {
+ CheckSingle(a, b);
+ for (int common = 0; common <= 32; common++) {
+ std::string extra;
+ GenerateString(common, &extra);
+ CheckSingle(extra + a, extra + b);
+ CheckSingle(a + extra, b + extra);
+ for (char c1 = 'a'; c1 <= 'c'; c1++) {
+ for (char c2 = 'a'; c2 <= 'c'; c2++) {
+ CheckSingle(extra + c1 + a, extra + c2 + b);
+ }
+ }
+ }
+}
+
+TEST(FastCompare, Misc) {
+ CheckCompare("", "");
+
+ CheckCompare("a", "a");
+ CheckCompare("ab", "ab");
+ CheckCompare("abc", "abc");
+ CheckCompare("abcd", "abcd");
+ CheckCompare("abcde", "abcde");
+
+ CheckCompare("a", "x");
+ CheckCompare("ab", "xb");
+ CheckCompare("abc", "xbc");
+ CheckCompare("abcd", "xbcd");
+ CheckCompare("abcde", "xbcde");
+
+ CheckCompare("x", "a");
+ CheckCompare("xb", "ab");
+ CheckCompare("xbc", "abc");
+ CheckCompare("xbcd", "abcd");
+ CheckCompare("xbcde", "abcde");
+
+ CheckCompare("a", "x");
+ CheckCompare("ab", "ax");
+ CheckCompare("abc", "abx");
+ CheckCompare("abcd", "abcx");
+ CheckCompare("abcde", "abcdx");
+
+ CheckCompare("x", "a");
+ CheckCompare("ax", "ab");
+ CheckCompare("abx", "abc");
+ CheckCompare("abcx", "abcd");
+ CheckCompare("abcdx", "abcde");
+
+ for (int len = 0; len < 1000; len++) {
+ std::string p(len, 'z');
+ CheckCompare(p + "x", p + "a");
+ CheckCompare(p + "ax", p + "ab");
+ CheckCompare(p + "abx", p + "abc");
+ CheckCompare(p + "abcx", p + "abcd");
+ CheckCompare(p + "abcdx", p + "abcde");
+ }
+}
+
+TEST(FastCompare, TrailingByte) {
+ for (int i = 0; i < 256; i++) {
+ for (int j = 0; j < 256; j++) {
+ std::string a(1, i);
+ std::string b(1, j);
+ CheckSingle(a, b);
+ }
+ }
+}
+
+// Check correctness of memcpy_inlined.
+void CheckSingleMemcpyInlined(const std::string& a) {
+ std::unique_ptr<char[]> destination(new char[a.size() + 2]);
+ destination[0] = 'x';
+ destination[a.size() + 1] = 'x';
+ absl::strings_internal::memcpy_inlined(destination.get() + 1, a.data(),
+ a.size());
+ CHECK_EQ('x', destination[0]);
+ CHECK_EQ('x', destination[a.size() + 1]);
+ CHECK_EQ(0, memcmp(a.data(), destination.get() + 1, a.size()));
+}
+
+TEST(MemCpyInlined, Misc) {
+ CheckSingleMemcpyInlined("");
+ CheckSingleMemcpyInlined("0");
+ CheckSingleMemcpyInlined("012");
+ CheckSingleMemcpyInlined("0123");
+ CheckSingleMemcpyInlined("01234");
+ CheckSingleMemcpyInlined("012345");
+ CheckSingleMemcpyInlined("0123456");
+ CheckSingleMemcpyInlined("01234567");
+ CheckSingleMemcpyInlined("012345678");
+ CheckSingleMemcpyInlined("0123456789");
+ CheckSingleMemcpyInlined("0123456789a");
+ CheckSingleMemcpyInlined("0123456789ab");
+ CheckSingleMemcpyInlined("0123456789abc");
+ CheckSingleMemcpyInlined("0123456789abcd");
+ CheckSingleMemcpyInlined("0123456789abcde");
+ CheckSingleMemcpyInlined("0123456789abcdef");
+ CheckSingleMemcpyInlined("0123456789abcdefg");
+}
+
+template <typename Function>
+inline void CopyLoop(benchmark::State& state, int size, Function func) {
+ char* src = new char[size];
+ char* dst = new char[size];
+ memset(src, 'x', size);
+ memset(dst, 'y', size);
+ for (auto _ : state) {
+ func(dst, src, size);
+ }
+ state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) * size);
+ CHECK_EQ(dst[0], 'x');
+ delete[] src;
+ delete[] dst;
+}
+
+void BM_memcpy(benchmark::State& state) {
+ CopyLoop(state, state.range(0), memcpy);
+}
+BENCHMARK(BM_memcpy)->DenseRange(1, 18)->Range(32, 8 << 20);
+
+void BM_memcpy_inlined(benchmark::State& state) {
+ CopyLoop(state, state.range(0), absl::strings_internal::memcpy_inlined);
+}
+BENCHMARK(BM_memcpy_inlined)->DenseRange(1, 18)->Range(32, 8 << 20);
+
+// unaligned memcpy
+void BM_unaligned_memcpy(benchmark::State& state) {
+ const int n = state.range(0);
+ const int kMaxOffset = 32;
+ char* src = new char[n + kMaxOffset];
+ char* dst = new char[n + kMaxOffset];
+ memset(src, 'x', n + kMaxOffset);
+ int r = 0, i = 0;
+ for (auto _ : state) {
+ memcpy(dst + (i % kMaxOffset), src + ((i + 5) % kMaxOffset), n);
+ r += dst[0];
+ ++i;
+ }
+ state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) * n);
+ delete[] src;
+ delete[] dst;
+ benchmark::DoNotOptimize(r);
+}
+BENCHMARK(BM_unaligned_memcpy)->DenseRange(1, 18)->Range(32, 8 << 20);
+
+// memmove worst case: heavy overlap, but not always by the same amount.
+// Also, the source and destination will often be unaligned.
+void BM_memmove_worst_case(benchmark::State& state) {
+ const int n = state.range(0);
+ const int32_t kDeterministicSeed = 301;
+ const int kMaxOffset = 32;
+ char* src = new char[n + kMaxOffset];
+ memset(src, 'x', n + kMaxOffset);
+ size_t offsets[64];
+ RandomEngine rng(kDeterministicSeed);
+ std::uniform_int_distribution<size_t> random_to_max_offset(0, kMaxOffset);
+ for (size_t& offset : offsets) {
+ offset = random_to_max_offset(rng);
+ }
+ int r = 0, i = 0;
+ for (auto _ : state) {
+ memmove(src + offsets[i], src + offsets[i + 1], n);
+ r += src[0];
+ i = (i + 2) % arraysize(offsets);
+ }
+ state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) * n);
+ delete[] src;
+ benchmark::DoNotOptimize(r);
+}
+BENCHMARK(BM_memmove_worst_case)->DenseRange(1, 18)->Range(32, 8 << 20);
+
+// memmove cache-friendly: aligned and overlapping with 4k
+// between the source and destination addresses.
+void BM_memmove_cache_friendly(benchmark::State& state) {
+ const int n = state.range(0);
+ char* src = new char[n + 4096];
+ memset(src, 'x', n);
+ int r = 0;
+ while (state.KeepRunningBatch(2)) { // count each memmove as an iteration
+ memmove(src + 4096, src, n);
+ memmove(src, src + 4096, n);
+ r += src[0];
+ }
+ state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) * n);
+ delete[] src;
+ benchmark::DoNotOptimize(r);
+}
+BENCHMARK(BM_memmove_cache_friendly)
+ ->Arg(5 * 1024)
+ ->Arg(10 * 1024)
+ ->Range(16 << 10, 8 << 20);
+
+// memmove best(?) case: aligned and non-overlapping.
+void BM_memmove_aligned_non_overlapping(benchmark::State& state) {
+ CopyLoop(state, state.range(0), memmove);
+}
+BENCHMARK(BM_memmove_aligned_non_overlapping)
+ ->DenseRange(1, 18)
+ ->Range(32, 8 << 20);
+
+// memset speed
+void BM_memset(benchmark::State& state) {
+ const int n = state.range(0);
+ char* dst = new char[n];
+ int r = 0;
+ for (auto _ : state) {
+ memset(dst, 'x', n);
+ r += dst[0];
+ }
+ state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) * n);
+ delete[] dst;
+ benchmark::DoNotOptimize(r);
+}
+BENCHMARK(BM_memset)->Range(8, 4096 << 10);
+
+// Bandwidth (vectorization?) test: the ideal generated code will be limited
+// by memory bandwidth. Even so-so generated code will max out memory bandwidth
+// on some machines.
+void BM_membandwidth(benchmark::State& state) {
+ const int n = state.range(0);
+ CHECK_EQ(n % 32, 0); // We will read 32 bytes per iter.
+ char* dst = new char[n];
+ int r = 0;
+ for (auto _ : state) {
+ const uint32_t* p = reinterpret_cast<uint32_t*>(dst);
+ const uint32_t* limit = reinterpret_cast<uint32_t*>(dst + n);
+ uint32_t x = 0;
+ while (p < limit) {
+ x += p[0];
+ x += p[1];
+ x += p[2];
+ x += p[3];
+ x += p[4];
+ x += p[5];
+ x += p[6];
+ x += p[7];
+ p += 8;
+ }
+ r += x;
+ }
+ state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) * n);
+ delete[] dst;
+ benchmark::DoNotOptimize(r);
+}
+BENCHMARK(BM_membandwidth)->Range(32, 16384 << 10);
+
+// Helper for benchmarks. Repeatedly compares two strings that are
+// either equal or different only in one character. If test_equal_strings
+// is false then position_to_modify determines where the difference will be.
+template <typename Function>
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline void StringCompareLoop(
+ benchmark::State& state, bool test_equal_strings,
+ std::string::size_type position_to_modify, int size, Function func) {
+ const int kIterMult = 4; // Iteration multiplier for better timing resolution
+ CHECK_GT(size, 0);
+ const bool position_to_modify_is_valid =
+ position_to_modify != std::string::npos && position_to_modify < size;
+ CHECK_NE(position_to_modify_is_valid, test_equal_strings);
+ if (!position_to_modify_is_valid) {
+ position_to_modify = 0;
+ }
+ std::string sa(size, 'a');
+ std::string sb = sa;
+ char last = sa[size - 1];
+ int num = 0;
+ for (auto _ : state) {
+ for (int i = 0; i < kIterMult; ++i) {
+ sb[position_to_modify] = test_equal_strings ? last : last ^ 1;
+ num += func(sa, sb);
+ }
+ }
+ state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) * size);
+ benchmark::DoNotOptimize(num);
+}
+
+// Helper for benchmarks. Repeatedly compares two memory regions that are
+// either equal or different only in their final character.
+template <typename Function>
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline void CompareLoop(benchmark::State& state,
+ bool test_equal_strings,
+ int size, Function func) {
+ const int kIterMult = 4; // Iteration multiplier for better timing resolution
+ CHECK_GT(size, 0);
+ char* data = static_cast<char*>(malloc(size * 2));
+ memset(data, 'a', size * 2);
+ char* a = data;
+ char* b = data + size;
+ char last = a[size - 1];
+ int num = 0;
+ for (auto _ : state) {
+ for (int i = 0; i < kIterMult; ++i) {
+ b[size - 1] = test_equal_strings ? last : last ^ 1;
+ num += func(a, b, size);
+ }
+ }
+ state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) * size);
+ benchmark::DoNotOptimize(num);
+ free(data);
+}
+
+void BM_memcmp(benchmark::State& state) {
+ CompareLoop(state, false, state.range(0), memcmp);
+}
+BENCHMARK(BM_memcmp)->DenseRange(1, 9)->Range(32, 8 << 20);
+
+void BM_fastmemcmp_inlined(benchmark::State& state) {
+ CompareLoop(state, false, state.range(0),
+ absl::strings_internal::fastmemcmp_inlined);
+}
+BENCHMARK(BM_fastmemcmp_inlined)->DenseRange(1, 9)->Range(32, 8 << 20);
+
+void BM_memeq(benchmark::State& state) {
+ CompareLoop(state, false, state.range(0), absl::strings_internal::memeq);
+}
+BENCHMARK(BM_memeq)->DenseRange(1, 9)->Range(32, 8 << 20);
+
+void BM_memeq_equal(benchmark::State& state) {
+ CompareLoop(state, true, state.range(0), absl::strings_internal::memeq);
+}
+BENCHMARK(BM_memeq_equal)->DenseRange(1, 9)->Range(32, 8 << 20);
+
+bool StringLess(const std::string& x, const std::string& y) { return x < y; }
+bool StringEqual(const std::string& x, const std::string& y) { return x == y; }
+bool StdEqual(const std::string& x, const std::string& y) {
+ return x.size() == y.size() &&
+ std::equal(x.data(), x.data() + x.size(), y.data());
+}
+
+// Benchmark for x < y, where x and y are strings that differ in only their
+// final char. That should be more-or-less the worst case for <.
+void BM_string_less(benchmark::State& state) {
+ StringCompareLoop(state, false, state.range(0) - 1, state.range(0),
+ StringLess);
+}
+BENCHMARK(BM_string_less)->DenseRange(1, 9)->Range(32, 1 << 20);
+
+// Benchmark for x < y, where x and y are strings that differ in only their
+// first char. That should be more-or-less the best case for <.
+void BM_string_less_easy(benchmark::State& state) {
+ StringCompareLoop(state, false, 0, state.range(0), StringLess);
+}
+BENCHMARK(BM_string_less_easy)->DenseRange(1, 9)->Range(32, 1 << 20);
+
+void BM_string_equal(benchmark::State& state) {
+ StringCompareLoop(state, false, state.range(0) - 1, state.range(0),
+ StringEqual);
+}
+BENCHMARK(BM_string_equal)->DenseRange(1, 9)->Range(32, 1 << 20);
+
+void BM_string_equal_equal(benchmark::State& state) {
+ StringCompareLoop(state, true, std::string::npos, state.range(0), StringEqual);
+}
+BENCHMARK(BM_string_equal_equal)->DenseRange(1, 9)->Range(32, 1 << 20);
+
+void BM_std_equal(benchmark::State& state) {
+ StringCompareLoop(state, false, state.range(0) - 1, state.range(0), StdEqual);
+}
+BENCHMARK(BM_std_equal)->DenseRange(1, 9)->Range(32, 1 << 20);
+
+void BM_std_equal_equal(benchmark::State& state) {
+ StringCompareLoop(state, true, std::string::npos, state.range(0), StdEqual);
+}
+BENCHMARK(BM_std_equal_equal)->DenseRange(1, 9)->Range(32, 1 << 20);
+
+void BM_string_equal_unequal_lengths(benchmark::State& state) {
+ const int size = state.range(0);
+ std::string a(size, 'a');
+ std::string b(size + 1, 'a');
+ int count = 0;
+ for (auto _ : state) {
+ b[size - 1] = 'a';
+ count += (a == b);
+ }
+ benchmark::DoNotOptimize(count);
+}
+BENCHMARK(BM_string_equal_unequal_lengths)->Arg(1)->Arg(1 << 20);
+
+void BM_stdstring_equal_unequal_lengths(benchmark::State& state) {
+ const int size = state.range(0);
+ std::string a(size, 'a');
+ std::string b(size + 1, 'a');
+ int count = 0;
+ for (auto _ : state) {
+ b[size - 1] = 'a';
+ count += (a == b);
+ }
+ benchmark::DoNotOptimize(count);
+}
+BENCHMARK(BM_stdstring_equal_unequal_lengths)->Arg(1)->Arg(1 << 20);
+
+} // namespace
diff --git a/absl/strings/internal/memutil.cc b/absl/strings/internal/memutil.cc
new file mode 100644
index 0000000..a0de70d
--- /dev/null
+++ b/absl/strings/internal/memutil.cc
@@ -0,0 +1,110 @@
+// 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/strings/internal/memutil.h"
+
+#include <cstdlib>
+
+namespace absl {
+namespace strings_internal {
+
+int memcasecmp(const char* s1, const char* s2, size_t len) {
+ const unsigned char* us1 = reinterpret_cast<const unsigned char*>(s1);
+ const unsigned char* us2 = reinterpret_cast<const unsigned char*>(s2);
+
+ for (size_t i = 0; i < len; i++) {
+ const int diff =
+ int{static_cast<unsigned char>(absl::ascii_tolower(us1[i]))} -
+ int{static_cast<unsigned char>(absl::ascii_tolower(us2[i]))};
+ if (diff != 0) return diff;
+ }
+ return 0;
+}
+
+char* memdup(const char* s, size_t slen) {
+ void* copy;
+ if ((copy = malloc(slen)) == nullptr) return nullptr;
+ memcpy(copy, s, slen);
+ return reinterpret_cast<char*>(copy);
+}
+
+char* memrchr(const char* s, int c, size_t slen) {
+ for (const char* e = s + slen - 1; e >= s; e--) {
+ if (*e == c) return const_cast<char*>(e);
+ }
+ return nullptr;
+}
+
+size_t memspn(const char* s, size_t slen, const char* accept) {
+ const char* p = s;
+ const char* spanp;
+ char c, sc;
+
+cont:
+ c = *p++;
+ if (slen-- == 0) return p - 1 - s;
+ for (spanp = accept; (sc = *spanp++) != '\0';)
+ if (sc == c) goto cont;
+ return p - 1 - s;
+}
+
+size_t memcspn(const char* s, size_t slen, const char* reject) {
+ const char* p = s;
+ const char* spanp;
+ char c, sc;
+
+ while (slen-- != 0) {
+ c = *p++;
+ for (spanp = reject; (sc = *spanp++) != '\0';)
+ if (sc == c) return p - 1 - s;
+ }
+ return p - s;
+}
+
+char* mempbrk(const char* s, size_t slen, const char* accept) {
+ const char* scanp;
+ int sc;
+
+ for (; slen; ++s, --slen) {
+ for (scanp = accept; (sc = *scanp++) != '\0';)
+ if (sc == *s) return const_cast<char*>(s);
+ }
+ return nullptr;
+}
+
+// This is significantly faster for case-sensitive matches with very
+// few possible matches. See unit test for benchmarks.
+const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle,
+ size_t neelen) {
+ if (0 == neelen) {
+ return phaystack; // even if haylen is 0
+ }
+ if (haylen < neelen) return nullptr;
+
+ const char* match;
+ const char* hayend = phaystack + haylen - neelen + 1;
+ // A static cast is used here to work around the fact that memchr returns
+ // a void* on Posix-compliant systems and const void* on Windows.
+ while ((match = static_cast<const char*>(
+ memchr(phaystack, pneedle[0], hayend - phaystack)))) {
+ if (memcmp(match, pneedle, neelen) == 0)
+ return match;
+ else
+ phaystack = match + 1;
+ }
+ return nullptr;
+}
+
+} // namespace strings_internal
+} // namespace absl
diff --git a/absl/strings/internal/memutil.h b/absl/strings/internal/memutil.h
new file mode 100644
index 0000000..a6f1c69
--- /dev/null
+++ b/absl/strings/internal/memutil.h
@@ -0,0 +1,146 @@
+//
+// 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.
+//
+
+// These routines provide mem versions of standard C std::string routines,
+// such as strpbrk. They function exactly the same as the str versions,
+// so if you wonder what they are, replace the word "mem" by
+// "str" and check out the man page. I could return void*, as the
+// strutil.h mem*() routines tend to do, but I return char* instead
+// since this is by far the most common way these functions are called.
+//
+// The difference between the mem and str versions is the mem version
+// takes a pointer and a length, rather than a '\0'-terminated std::string.
+// The memcase* routines defined here assume the locale is "C"
+// (they use absl::ascii_tolower instead of tolower).
+//
+// These routines are based on the BSD library.
+//
+// Here's a list of routines from std::string.h, and their mem analogues.
+// Functions in lowercase are defined in std::string.h; those in UPPERCASE
+// are defined here:
+//
+// strlen --
+// strcat strncat MEMCAT
+// strcpy strncpy memcpy
+// -- memccpy (very cool function, btw)
+// -- memmove
+// -- memset
+// strcmp strncmp memcmp
+// strcasecmp strncasecmp MEMCASECMP
+// strchr memchr
+// strcoll --
+// strxfrm --
+// strdup strndup MEMDUP
+// strrchr MEMRCHR
+// strspn MEMSPN
+// strcspn MEMCSPN
+// strpbrk MEMPBRK
+// strstr MEMSTR MEMMEM
+// (g)strcasestr MEMCASESTR MEMCASEMEM
+// strtok --
+// strprefix MEMPREFIX (strprefix is from strutil.h)
+// strcaseprefix MEMCASEPREFIX (strcaseprefix is from strutil.h)
+// strsuffix MEMSUFFIX (strsuffix is from strutil.h)
+// strcasesuffix MEMCASESUFFIX (strcasesuffix is from strutil.h)
+// -- MEMIS
+// -- MEMCASEIS
+// strcount MEMCOUNT (strcount is from strutil.h)
+
+#ifndef ABSL_STRINGS_INTERNAL_MEMUTIL_H_
+#define ABSL_STRINGS_INTERNAL_MEMUTIL_H_
+
+#include <cstddef>
+#include <cstring>
+
+#include "absl/base/port.h" // disable some warnings on Windows
+#include "absl/strings/ascii.h" // for absl::ascii_tolower
+
+namespace absl {
+namespace strings_internal {
+
+inline char* memcat(char* dest, size_t destlen, const char* src,
+ size_t srclen) {
+ return reinterpret_cast<char*>(memcpy(dest + destlen, src, srclen));
+}
+
+int memcasecmp(const char* s1, const char* s2, size_t len);
+char* memdup(const char* s, size_t slen);
+char* memrchr(const char* s, int c, size_t slen);
+size_t memspn(const char* s, size_t slen, const char* accept);
+size_t memcspn(const char* s, size_t slen, const char* reject);
+char* mempbrk(const char* s, size_t slen, const char* accept);
+
+// This is for internal use only. Don't call this directly
+template <bool case_sensitive>
+const char* int_memmatch(const char* haystack, size_t haylen,
+ const char* needle, size_t neelen) {
+ if (0 == neelen) {
+ return haystack; // even if haylen is 0
+ }
+ const char* hayend = haystack + haylen;
+ const char* needlestart = needle;
+ const char* needleend = needlestart + neelen;
+
+ for (; haystack < hayend; ++haystack) {
+ char hay = case_sensitive
+ ? *haystack
+ : absl::ascii_tolower(static_cast<unsigned char>(*haystack));
+ char nee = case_sensitive
+ ? *needle
+ : absl::ascii_tolower(static_cast<unsigned char>(*needle));
+ if (hay == nee) {
+ if (++needle == needleend) {
+ return haystack + 1 - neelen;
+ }
+ } else if (needle != needlestart) {
+ // must back up haystack in case a prefix matched (find "aab" in "aaab")
+ haystack -= needle - needlestart; // for loop will advance one more
+ needle = needlestart;
+ }
+ }
+ return nullptr;
+}
+
+// These are the guys you can call directly
+inline const char* memstr(const char* phaystack, size_t haylen,
+ const char* pneedle) {
+ return int_memmatch<true>(phaystack, haylen, pneedle, strlen(pneedle));
+}
+
+inline const char* memcasestr(const char* phaystack, size_t haylen,
+ const char* pneedle) {
+ return int_memmatch<false>(phaystack, haylen, pneedle, strlen(pneedle));
+}
+
+inline const char* memmem(const char* phaystack, size_t haylen,
+ const char* pneedle, size_t needlelen) {
+ return int_memmatch<true>(phaystack, haylen, pneedle, needlelen);
+}
+
+inline const char* memcasemem(const char* phaystack, size_t haylen,
+ const char* pneedle, size_t needlelen) {
+ return int_memmatch<false>(phaystack, haylen, pneedle, needlelen);
+}
+
+// This is significantly faster for case-sensitive matches with very
+// few possible matches. See unit test for benchmarks.
+const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle,
+ size_t neelen);
+
+} // namespace strings_internal
+} // namespace absl
+
+#endif // ABSL_STRINGS_INTERNAL_MEMUTIL_H_
diff --git a/absl/strings/internal/memutil_test.cc b/absl/strings/internal/memutil_test.cc
new file mode 100644
index 0000000..1ff60f2
--- /dev/null
+++ b/absl/strings/internal/memutil_test.cc
@@ -0,0 +1,180 @@
+// 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 memutil.cc
+
+#include "absl/strings/internal/memutil.h"
+
+#include <algorithm>
+#include <cstdlib>
+
+#include "gtest/gtest.h"
+#include "absl/strings/ascii.h"
+
+namespace {
+
+static char* memcasechr(const char* s, int c, size_t slen) {
+ c = absl::ascii_tolower(c);
+ for (; slen; ++s, --slen) {
+ if (absl::ascii_tolower(*s) == c) return const_cast<char*>(s);
+ }
+ return nullptr;
+}
+
+static const char* memcasematch(const char* phaystack, size_t haylen,
+ const char* pneedle, size_t neelen) {
+ if (0 == neelen) {
+ return phaystack; // even if haylen is 0
+ }
+ if (haylen < neelen) return nullptr;
+
+ const char* match;
+ const char* hayend = phaystack + haylen - neelen + 1;
+ while ((match = static_cast<char*>(
+ memcasechr(phaystack, pneedle[0], hayend - phaystack)))) {
+ if (absl::strings_internal::memcasecmp(match, pneedle, neelen) == 0)
+ return match;
+ else
+ phaystack = match + 1;
+ }
+ return nullptr;
+}
+
+TEST(MemUtilTest, AllTests) {
+ // check memutil functions
+ char a[1000];
+ absl::strings_internal::memcat(a, 0, "hello", sizeof("hello") - 1);
+ absl::strings_internal::memcat(a, 5, " there", sizeof(" there") - 1);
+
+ EXPECT_EQ(absl::strings_internal::memcasecmp(a, "heLLO there",
+ sizeof("hello there") - 1),
+ 0);
+ EXPECT_EQ(absl::strings_internal::memcasecmp(a, "heLLO therf",
+ sizeof("hello there") - 1),
+ -1);
+ EXPECT_EQ(absl::strings_internal::memcasecmp(a, "heLLO therf",
+ sizeof("hello there") - 2),
+ 0);
+ EXPECT_EQ(absl::strings_internal::memcasecmp(a, "whatever", 0), 0);
+
+ char* p = absl::strings_internal::memdup("hello", 5);
+ free(p);
+
+ p = absl::strings_internal::memrchr("hello there", 'e',
+ sizeof("hello there") - 1);
+ EXPECT_TRUE(p && p[-1] == 'r');
+ p = absl::strings_internal::memrchr("hello there", 'e',
+ sizeof("hello there") - 2);
+ EXPECT_TRUE(p && p[-1] == 'h');
+ p = absl::strings_internal::memrchr("hello there", 'u',
+ sizeof("hello there") - 1);
+ EXPECT_TRUE(p == nullptr);
+
+ int len = absl::strings_internal::memspn("hello there",
+ sizeof("hello there") - 1, "hole");
+ EXPECT_EQ(len, sizeof("hello") - 1);
+ len = absl::strings_internal::memspn("hello there", sizeof("hello there") - 1,
+ "u");
+ EXPECT_EQ(len, 0);
+ len = absl::strings_internal::memspn("hello there", sizeof("hello there") - 1,
+ "");
+ EXPECT_EQ(len, 0);
+ len = absl::strings_internal::memspn("hello there", sizeof("hello there") - 1,
+ "trole h");
+ EXPECT_EQ(len, sizeof("hello there") - 1);
+ len = absl::strings_internal::memspn("hello there!",
+ sizeof("hello there!") - 1, "trole h");
+ EXPECT_EQ(len, sizeof("hello there") - 1);
+ len = absl::strings_internal::memspn("hello there!",
+ sizeof("hello there!") - 2, "trole h!");
+ EXPECT_EQ(len, sizeof("hello there!") - 2);
+
+ len = absl::strings_internal::memcspn("hello there",
+ sizeof("hello there") - 1, "leho");
+ EXPECT_EQ(len, 0);
+ len = absl::strings_internal::memcspn("hello there",
+ sizeof("hello there") - 1, "u");
+ EXPECT_EQ(len, sizeof("hello there") - 1);
+ len = absl::strings_internal::memcspn("hello there",
+ sizeof("hello there") - 1, "");
+ EXPECT_EQ(len, sizeof("hello there") - 1);
+ len = absl::strings_internal::memcspn("hello there",
+ sizeof("hello there") - 1, " ");
+ EXPECT_EQ(len, 5);
+
+ p = absl::strings_internal::mempbrk("hello there", sizeof("hello there") - 1,
+ "leho");
+ EXPECT_TRUE(p && p[1] == 'e' && p[2] == 'l');
+ p = absl::strings_internal::mempbrk("hello there", sizeof("hello there") - 1,
+ "nu");
+ EXPECT_TRUE(p == nullptr);
+ p = absl::strings_internal::mempbrk("hello there!",
+ sizeof("hello there!") - 2, "!");
+ EXPECT_TRUE(p == nullptr);
+ p = absl::strings_internal::mempbrk("hello there", sizeof("hello there") - 1,
+ " t ");
+ EXPECT_TRUE(p && p[-1] == 'o' && p[1] == 't');
+
+ {
+ const char kHaystack[] = "0123456789";
+ EXPECT_EQ(absl::strings_internal::memmem(kHaystack, 0, "", 0), kHaystack);
+ EXPECT_EQ(absl::strings_internal::memmem(kHaystack, 10, "012", 3),
+ kHaystack);
+ EXPECT_EQ(absl::strings_internal::memmem(kHaystack, 10, "0xx", 1),
+ kHaystack);
+ EXPECT_EQ(absl::strings_internal::memmem(kHaystack, 10, "789", 3),
+ kHaystack + 7);
+ EXPECT_EQ(absl::strings_internal::memmem(kHaystack, 10, "9xx", 1),
+ kHaystack + 9);
+ EXPECT_TRUE(absl::strings_internal::memmem(kHaystack, 10, "9xx", 3) ==
+ nullptr);
+ EXPECT_TRUE(absl::strings_internal::memmem(kHaystack, 10, "xxx", 1) ==
+ nullptr);
+ }
+ {
+ const char kHaystack[] = "aBcDeFgHiJ";
+ EXPECT_EQ(absl::strings_internal::memcasemem(kHaystack, 0, "", 0),
+ kHaystack);
+ EXPECT_EQ(absl::strings_internal::memcasemem(kHaystack, 10, "Abc", 3),
+ kHaystack);
+ EXPECT_EQ(absl::strings_internal::memcasemem(kHaystack, 10, "Axx", 1),
+ kHaystack);
+ EXPECT_EQ(absl::strings_internal::memcasemem(kHaystack, 10, "hIj", 3),
+ kHaystack + 7);
+ EXPECT_EQ(absl::strings_internal::memcasemem(kHaystack, 10, "jxx", 1),
+ kHaystack + 9);
+ EXPECT_TRUE(absl::strings_internal::memcasemem(kHaystack, 10, "jxx", 3) ==
+ nullptr);
+ EXPECT_TRUE(absl::strings_internal::memcasemem(kHaystack, 10, "xxx", 1) ==
+ nullptr);
+ }
+ {
+ const char kHaystack[] = "0123456789";
+ EXPECT_EQ(absl::strings_internal::memmatch(kHaystack, 0, "", 0), kHaystack);
+ EXPECT_EQ(absl::strings_internal::memmatch(kHaystack, 10, "012", 3),
+ kHaystack);
+ EXPECT_EQ(absl::strings_internal::memmatch(kHaystack, 10, "0xx", 1),
+ kHaystack);
+ EXPECT_EQ(absl::strings_internal::memmatch(kHaystack, 10, "789", 3),
+ kHaystack + 7);
+ EXPECT_EQ(absl::strings_internal::memmatch(kHaystack, 10, "9xx", 1),
+ kHaystack + 9);
+ EXPECT_TRUE(absl::strings_internal::memmatch(kHaystack, 10, "9xx", 3) ==
+ nullptr);
+ EXPECT_TRUE(absl::strings_internal::memmatch(kHaystack, 10, "xxx", 1) ==
+ nullptr);
+ }
+}
+
+} // namespace
diff --git a/absl/strings/internal/numbers_test_common.inc b/absl/strings/internal/numbers_test_common.inc
new file mode 100644
index 0000000..e165b3b
--- /dev/null
+++ b/absl/strings/internal/numbers_test_common.inc
@@ -0,0 +1,166 @@
+// 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 contains common things needed by numbers_test.cc,
+// numbers_legacy_test.cc and numbers_benchmark.cc.
+
+namespace {
+
+// Previously documented minimum buffer sizes for Fast*ToBuffer functions.
+// NOTE(edk): These should be deleted and uses replaced with kFastToBufferSize
+// once existing code has been fixed to use kFastToBufferSize.
+enum {
+ kFastInt32ToBufferSize = 12,
+ kFastInt64ToBufferSize = 22,
+ kFastUInt32ToBufferSize = 12,
+ kFastUInt64ToBufferSize = 22
+};
+
+template <typename IntType>
+bool Itoa(IntType value, int base, std::string* destination) {
+ destination->clear();
+ if (base <= 1 || base > 36) {
+ return false;
+ }
+
+ if (value == 0) {
+ destination->push_back('0');
+ return true;
+ }
+
+ bool negative = value < 0;
+ while (value != 0) {
+ const IntType next_value = value / base;
+ // Can't use std::abs here because of problems when IntType is unsigned.
+ int remainder = value > next_value * base ? value - next_value * base
+ : next_value * base - value;
+ char c = remainder < 10 ? '0' + remainder : 'A' + remainder - 10;
+ destination->insert(0, 1, c);
+ value = next_value;
+ }
+
+ if (negative) {
+ destination->insert(0, 1, '-');
+ }
+ return true;
+}
+
+struct uint32_test_case {
+ const char* str;
+ bool expect_ok;
+ int base; // base to pass to the conversion function
+ uint32_t expected;
+} const strtouint32_test_cases[] = {
+ {"0xffffffff", true, 16, std::numeric_limits<uint32_t>::max()},
+ {"0x34234324", true, 16, 0x34234324},
+ {"34234324", true, 16, 0x34234324},
+ {"0", true, 16, 0},
+ {" \t\n 0xffffffff", true, 16, std::numeric_limits<uint32_t>::max()},
+ {" \f\v 46", true, 10, 46}, // must accept weird whitespace
+ {" \t\n 72717222", true, 8, 072717222},
+ {" \t\n 072717222", true, 8, 072717222},
+ {" \t\n 072717228", false, 8, 07271722},
+ {"0", true, 0, 0},
+
+ // Base-10 version.
+ {"34234324", true, 0, 34234324},
+ {"4294967295", true, 0, std::numeric_limits<uint32_t>::max()},
+ {"34234324 \n\t", true, 10, 34234324},
+
+ // Unusual base
+ {"0", true, 3, 0},
+ {"2", true, 3, 2},
+ {"11", true, 3, 4},
+
+ // Invalid uints.
+ {"", false, 0, 0},
+ {" ", false, 0, 0},
+ {"abc", false, 0, 0}, // would be valid hex, but prefix is missing
+ {"34234324a", false, 0, 34234324},
+ {"34234.3", false, 0, 34234},
+ {"-1", false, 0, 0},
+ {" -123", false, 0, 0},
+ {" \t\n -123", false, 0, 0},
+
+ // Out of bounds.
+ {"4294967296", false, 0, std::numeric_limits<uint32_t>::max()},
+ {"0x100000000", false, 0, std::numeric_limits<uint32_t>::max()},
+ {nullptr, false, 0, 0},
+};
+
+struct uint64_test_case {
+ const char* str;
+ bool expect_ok;
+ int base;
+ uint64_t expected;
+} const strtouint64_test_cases[] = {
+ {"0x3423432448783446", true, 16, int64_t{0x3423432448783446}},
+ {"3423432448783446", true, 16, int64_t{0x3423432448783446}},
+
+ {"0", true, 16, 0},
+ {"000", true, 0, 0},
+ {"0", true, 0, 0},
+ {" \t\n 0xffffffffffffffff", true, 16,
+ std::numeric_limits<uint64_t>::max()},
+
+ {"012345670123456701234", true, 8, int64_t{012345670123456701234}},
+ {"12345670123456701234", true, 8, int64_t{012345670123456701234}},
+
+ {"12845670123456701234", false, 8, 0},
+
+ // Base-10 version.
+ {"34234324487834466", true, 0, int64_t{34234324487834466}},
+
+ {" \t\n 18446744073709551615", true, 0,
+ std::numeric_limits<uint64_t>::max()},
+
+ {"34234324487834466 \n\t ", true, 0, int64_t{34234324487834466}},
+
+ {" \f\v 46", true, 10, 46}, // must accept weird whitespace
+
+ // Unusual base
+ {"0", true, 3, 0},
+ {"2", true, 3, 2},
+ {"11", true, 3, 4},
+
+ {"0", true, 0, 0},
+
+ // Invalid uints.
+ {"", false, 0, 0},
+ {" ", false, 0, 0},
+ {"abc", false, 0, 0},
+ {"34234324487834466a", false, 0, 0},
+ {"34234487834466.3", false, 0, 0},
+ {"-1", false, 0, 0},
+ {" -123", false, 0, 0},
+ {" \t\n -123", false, 0, 0},
+
+ // Out of bounds.
+ {"18446744073709551616", false, 10, 0},
+ {"18446744073709551616", false, 0, 0},
+ {"0x10000000000000000", false, 16, std::numeric_limits<uint64_t>::max()},
+ {"0X10000000000000000", false, 16,
+ std::numeric_limits<uint64_t>::max()}, // 0X versus 0x.
+ {"0x10000000000000000", false, 0, std::numeric_limits<uint64_t>::max()},
+ {"0X10000000000000000", false, 0,
+ std::numeric_limits<uint64_t>::max()}, // 0X versus 0x.
+
+ {"0x1234", true, 16, 0x1234},
+
+ // Base-10 std::string version.
+ {"1234", true, 0, 1234},
+ {nullptr, false, 0, 0},
+};
+
+} // namespace
diff --git a/absl/strings/internal/ostringstream.h b/absl/strings/internal/ostringstream.h
new file mode 100644
index 0000000..017632a
--- /dev/null
+++ b/absl/strings/internal/ostringstream.h
@@ -0,0 +1,97 @@
+// 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_STRINGS_INTERNAL_OSTRINGSTREAM_H_
+#define ABSL_STRINGS_INTERNAL_OSTRINGSTREAM_H_
+
+#include <cassert>
+#include <ostream>
+#include <streambuf>
+#include <string>
+
+#include "absl/base/port.h"
+
+namespace absl {
+namespace strings_internal {
+
+// The same as std::ostringstream but appends to a user-specified std::string,
+// and is faster. It is ~70% faster to create, ~50% faster to write to, and
+// completely free to extract the result std::string.
+//
+// std::string s;
+// OStringStream strm(&s);
+// strm << 42 << ' ' << 3.14; // appends to `s`
+//
+// The stream object doesn't have to be named. Starting from C++11 operator<<
+// works with rvalues of std::ostream.
+//
+// std::string s;
+// OStringStream(&s) << 42 << ' ' << 3.14; // appends to `s`
+//
+// OStringStream is faster to create than std::ostringstream but it's still
+// relatively slow. Avoid creating multiple streams where a single stream will
+// do.
+//
+// Creates unnecessary instances of OStringStream: slow.
+//
+// std::string s;
+// OStringStream(&s) << 42;
+// OStringStream(&s) << ' ';
+// OStringStream(&s) << 3.14;
+//
+// Creates a single instance of OStringStream and reuses it: fast.
+//
+// std::string s;
+// OStringStream strm(&s);
+// strm << 42;
+// strm << ' ';
+// strm << 3.14;
+//
+// Note: flush() has no effect. No reason to call it.
+class OStringStream : private std::basic_streambuf<char>, public std::ostream {
+ public:
+ // The argument can be null, in which case you'll need to call str(p) with a
+ // non-null argument before you can write to the stream.
+ //
+ // The destructor of OStringStream doesn't use the std::string. It's OK to destroy
+ // the std::string before the stream.
+ explicit OStringStream(std::string* s) : std::ostream(this), s_(s) {}
+
+ std::string* str() { return s_; }
+ const std::string* str() const { return s_; }
+ void str(std::string* s) { s_ = s; }
+
+ private:
+ using Buf = std::basic_streambuf<char>;
+
+ Buf::int_type overflow(int c = Buf::traits_type::eof()) override {
+ assert(s_);
+ if (!Buf::traits_type::eq_int_type(c, Buf::traits_type::eof()))
+ s_->push_back(static_cast<char>(c));
+ return 1;
+ }
+
+ std::streamsize xsputn(const char* s, std::streamsize n) override {
+ assert(s_);
+ s_->append(s, n);
+ return n;
+ }
+
+ std::string* s_;
+};
+
+} // namespace strings_internal
+} // namespace absl
+
+#endif // ABSL_STRINGS_INTERNAL_OSTRINGSTREAM_H_
diff --git a/absl/strings/internal/ostringstream_test.cc b/absl/strings/internal/ostringstream_test.cc
new file mode 100644
index 0000000..0047ec8
--- /dev/null
+++ b/absl/strings/internal/ostringstream_test.cc
@@ -0,0 +1,103 @@
+// 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/strings/internal/ostringstream.h"
+
+#include <memory>
+#include <ostream>
+#include <sstream>
+#include <string>
+#include <type_traits>
+
+#include "gtest/gtest.h"
+
+namespace {
+
+TEST(OStringStream, IsOStream) {
+ static_assert(
+ std::is_base_of<std::ostream, absl::strings_internal::OStringStream>(),
+ "");
+}
+
+TEST(OStringStream, ConstructDestroy) {
+ {
+ absl::strings_internal::OStringStream strm(nullptr);
+ EXPECT_EQ(nullptr, strm.str());
+ }
+ {
+ std::string s = "abc";
+ {
+ absl::strings_internal::OStringStream strm(&s);
+ EXPECT_EQ(&s, strm.str());
+ }
+ EXPECT_EQ("abc", s);
+ }
+ {
+ std::unique_ptr<std::string> s(new std::string);
+ absl::strings_internal::OStringStream strm(s.get());
+ s.reset();
+ }
+}
+
+TEST(OStringStream, Str) {
+ std::string s1;
+ absl::strings_internal::OStringStream strm(&s1);
+ const absl::strings_internal::OStringStream& c_strm(strm);
+
+ static_assert(std::is_same<decltype(strm.str()), std::string*>(), "");
+ static_assert(std::is_same<decltype(c_strm.str()), const std::string*>(), "");
+
+ EXPECT_EQ(&s1, strm.str());
+ EXPECT_EQ(&s1, c_strm.str());
+
+ strm.str(&s1);
+ EXPECT_EQ(&s1, strm.str());
+ EXPECT_EQ(&s1, c_strm.str());
+
+ std::string s2;
+ strm.str(&s2);
+ EXPECT_EQ(&s2, strm.str());
+ EXPECT_EQ(&s2, c_strm.str());
+
+ strm.str(nullptr);
+ EXPECT_EQ(nullptr, strm.str());
+ EXPECT_EQ(nullptr, c_strm.str());
+}
+
+TEST(OStreamStream, WriteToLValue) {
+ std::string s = "abc";
+ {
+ absl::strings_internal::OStringStream strm(&s);
+ EXPECT_EQ("abc", s);
+ strm << "";
+ EXPECT_EQ("abc", s);
+ strm << 42;
+ EXPECT_EQ("abc42", s);
+ strm << 'x' << 'y';
+ EXPECT_EQ("abc42xy", s);
+ }
+ EXPECT_EQ("abc42xy", s);
+}
+
+TEST(OStreamStream, WriteToRValue) {
+ std::string s = "abc";
+ absl::strings_internal::OStringStream(&s) << "";
+ EXPECT_EQ("abc", s);
+ absl::strings_internal::OStringStream(&s) << 42;
+ EXPECT_EQ("abc42", s);
+ absl::strings_internal::OStringStream(&s) << 'x' << 'y';
+ EXPECT_EQ("abc42xy", s);
+}
+
+} // namespace
diff --git a/absl/strings/internal/resize_uninitialized.h b/absl/strings/internal/resize_uninitialized.h
new file mode 100644
index 0000000..0157ca0
--- /dev/null
+++ b/absl/strings/internal/resize_uninitialized.h
@@ -0,0 +1,69 @@
+//
+// 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_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_
+#define ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_
+
+#include <string>
+#include <utility>
+
+#include "absl/base/port.h"
+#include "absl/meta/type_traits.h" // for void_t
+
+namespace absl {
+namespace strings_internal {
+
+// Is a subclass of true_type or false_type, depending on whether or not
+// T has a resize_uninitialized member.
+template <typename T, typename = void>
+struct HasResizeUninitialized : std::false_type {};
+template <typename T>
+struct HasResizeUninitialized<
+ T, absl::void_t<decltype(std::declval<T>().resize_uninitialized(237))>>
+ : std::true_type {};
+
+template <typename string_type>
+void ResizeUninit(string_type* s, size_t new_size, std::true_type) {
+ s->resize_uninitialized(new_size);
+}
+template <typename string_type>
+void ResizeUninit(string_type* s, size_t new_size, std::false_type) {
+ s->resize(new_size);
+}
+
+// Returns true if the std::string implementation supports a resize where
+// the new characters added to the std::string are left untouched.
+//
+// (A better name might be "STLStringSupportsUninitializedResize", alluding to
+// the previous function.)
+template <typename string_type>
+inline constexpr bool STLStringSupportsNontrashingResize(string_type*) {
+ return HasResizeUninitialized<string_type>();
+}
+
+// Like str->resize(new_size), except any new characters added to "*str" as a
+// result of resizing may be left uninitialized, rather than being filled with
+// '0' bytes. Typically used when code is then going to overwrite the backing
+// store of the std::string with known data. Uses a Google extension to std::string.
+template <typename string_type, typename = void>
+inline void STLStringResizeUninitialized(string_type* s, size_t new_size) {
+ ResizeUninit(s, new_size, HasResizeUninitialized<string_type>());
+}
+
+} // namespace strings_internal
+} // namespace absl
+
+#endif // ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_
diff --git a/absl/strings/internal/resize_uninitialized_test.cc b/absl/strings/internal/resize_uninitialized_test.cc
new file mode 100644
index 0000000..ad282ef
--- /dev/null
+++ b/absl/strings/internal/resize_uninitialized_test.cc
@@ -0,0 +1,68 @@
+// 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/strings/internal/resize_uninitialized.h"
+
+#include "gtest/gtest.h"
+
+namespace {
+
+int resize_call_count = 0;
+
+struct resizable_string {
+ void resize(size_t) { resize_call_count += 1; }
+};
+
+int resize_uninitialized_call_count = 0;
+
+struct resize_uninitializable_string {
+ void resize(size_t) { resize_call_count += 1; }
+ void resize_uninitialized(size_t) { resize_uninitialized_call_count += 1; }
+};
+
+TEST(ResizeUninit, WithAndWithout) {
+ resize_call_count = 0;
+ resize_uninitialized_call_count = 0;
+ {
+ resizable_string rs;
+
+ EXPECT_EQ(resize_call_count, 0);
+ EXPECT_EQ(resize_uninitialized_call_count, 0);
+ EXPECT_FALSE(
+ absl::strings_internal::STLStringSupportsNontrashingResize(&rs));
+ EXPECT_EQ(resize_call_count, 0);
+ EXPECT_EQ(resize_uninitialized_call_count, 0);
+ absl::strings_internal::STLStringResizeUninitialized(&rs, 237);
+ EXPECT_EQ(resize_call_count, 1);
+ EXPECT_EQ(resize_uninitialized_call_count, 0);
+ }
+
+ resize_call_count = 0;
+ resize_uninitialized_call_count = 0;
+ {
+ resize_uninitializable_string rus;
+
+ EXPECT_EQ(resize_call_count, 0);
+ EXPECT_EQ(resize_uninitialized_call_count, 0);
+ EXPECT_TRUE(
+ absl::strings_internal::STLStringSupportsNontrashingResize(&rus));
+ EXPECT_EQ(resize_call_count, 0);
+ EXPECT_EQ(resize_uninitialized_call_count, 0);
+ absl::strings_internal::STLStringResizeUninitialized(&rus, 237);
+ EXPECT_EQ(resize_call_count, 0);
+ EXPECT_EQ(resize_uninitialized_call_count, 1);
+ }
+}
+
+} // namespace
diff --git a/absl/strings/internal/str_join_internal.h b/absl/strings/internal/str_join_internal.h
new file mode 100644
index 0000000..e73f1dd
--- /dev/null
+++ b/absl/strings/internal/str_join_internal.h
@@ -0,0 +1,314 @@
+//
+// 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 declares INTERNAL parts of the Join API that are inlined/templated
+// or otherwise need to be available at compile time. The main abstractions
+// defined in this file are:
+//
+// - A handful of default Formatters
+// - JoinAlgorithm() overloads
+// - JoinRange() overloads
+// - JoinTuple()
+//
+// DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including
+// absl/strings/str_join.h
+//
+// IWYU pragma: private, include "absl/strings/str_join.h"
+
+#ifndef ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_
+#define ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_
+
+#include <cassert>
+#include <iterator>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "absl/strings/internal/ostringstream.h"
+#include "absl/strings/str_cat.h"
+
+namespace absl {
+namespace strings_internal {
+
+//
+// Formatter objects
+//
+// The following are implementation classes for standard Formatter objects. The
+// factory functions that users will call to create and use these formatters are
+// defined and documented in strings/join.h.
+//
+
+// The default formatter. Converts alpha-numeric types to strings.
+struct AlphaNumFormatterImpl {
+ // This template is needed in order to support passing in a dereferenced
+ // vector<bool>::iterator
+ template <typename T>
+ void operator()(std::string* out, const T& t) const {
+ StrAppend(out, AlphaNum(t));
+ }
+
+ void operator()(std::string* out, const AlphaNum& t) const {
+ StrAppend(out, t);
+ }
+};
+
+// A type that's used to overload the JoinAlgorithm() function (defined below)
+// for ranges that do not require additional formatting (e.g., a range of
+// strings).
+
+struct NoFormatter : public AlphaNumFormatterImpl {};
+
+// Formats types to strings using the << operator.
+class StreamFormatterImpl {
+ public:
+ // The method isn't const because it mutates state. Making it const will
+ // render StreamFormatterImpl thread-hostile.
+ template <typename T>
+ void operator()(std::string* out, const T& t) {
+ // The stream is created lazily to avoid paying the relatively high cost
+ // of its construction when joining an empty range.
+ if (strm_) {
+ strm_->clear(); // clear the bad, fail and eof bits in case they were set
+ strm_->str(out);
+ } else {
+ strm_.reset(new strings_internal::OStringStream(out));
+ }
+ *strm_ << t;
+ }
+
+ private:
+ std::unique_ptr<strings_internal::OStringStream> strm_;
+};
+
+// Formats a std::pair<>. The 'first' member is formatted using f1_ and the
+// 'second' member is formatted using f2_. sep_ is the separator.
+template <typename F1, typename F2>
+class PairFormatterImpl {
+ public:
+ PairFormatterImpl(F1 f1, absl::string_view sep, F2 f2)
+ : f1_(std::move(f1)), sep_(sep), f2_(std::move(f2)) {}
+
+ template <typename T>
+ void operator()(std::string* out, const T& p) {
+ f1_(out, p.first);
+ out->append(sep_);
+ f2_(out, p.second);
+ }
+
+ template <typename T>
+ void operator()(std::string* out, const T& p) const {
+ f1_(out, p.first);
+ out->append(sep_);
+ f2_(out, p.second);
+ }
+
+ private:
+ F1 f1_;
+ std::string sep_;
+ F2 f2_;
+};
+
+// Wraps another formatter and dereferences the argument to operator() then
+// passes the dereferenced argument to the wrapped formatter. This can be
+// useful, for example, to join a std::vector<int*>.
+template <typename Formatter>
+class DereferenceFormatterImpl {
+ public:
+ DereferenceFormatterImpl() : f_() {}
+ explicit DereferenceFormatterImpl(Formatter&& f)
+ : f_(std::forward<Formatter>(f)) {}
+
+ template <typename T>
+ void operator()(std::string* out, const T& t) {
+ f_(out, *t);
+ }
+
+ template <typename T>
+ void operator()(std::string* out, const T& t) const {
+ f_(out, *t);
+ }
+
+ private:
+ Formatter f_;
+};
+
+// DefaultFormatter<T> is a traits class that selects a default Formatter to use
+// for the given type T. The ::Type member names the Formatter to use. This is
+// used by the strings::Join() functions that do NOT take a Formatter argument,
+// in which case a default Formatter must be chosen.
+//
+// AlphaNumFormatterImpl is the default in the base template, followed by
+// specializations for other types.
+template <typename ValueType>
+struct DefaultFormatter {
+ typedef AlphaNumFormatterImpl Type;
+};
+template <>
+struct DefaultFormatter<const char*> {
+ typedef AlphaNumFormatterImpl Type;
+};
+template <>
+struct DefaultFormatter<char*> {
+ typedef AlphaNumFormatterImpl Type;
+};
+template <>
+struct DefaultFormatter<std::string> {
+ typedef NoFormatter Type;
+};
+template <>
+struct DefaultFormatter<absl::string_view> {
+ typedef NoFormatter Type;
+};
+template <typename ValueType>
+struct DefaultFormatter<ValueType*> {
+ typedef DereferenceFormatterImpl<typename DefaultFormatter<ValueType>::Type>
+ Type;
+};
+
+template <typename ValueType>
+struct DefaultFormatter<std::unique_ptr<ValueType>>
+ : public DefaultFormatter<ValueType*> {};
+
+//
+// JoinAlgorithm() functions
+//
+
+// The main joining algorithm. This simply joins the elements in the given
+// iterator range, each separated by the given separator, into an output std::string,
+// and formats each element using the provided Formatter object.
+template <typename Iterator, typename Formatter>
+std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s,
+ Formatter&& f) {
+ std::string result;
+ absl::string_view sep("");
+ for (Iterator it = start; it != end; ++it) {
+ result.append(sep.data(), sep.size());
+ f(&result, *it);
+ sep = s;
+ }
+ return result;
+}
+
+// No-op placeholder for input iterators which can not be iterated over.
+template <typename Iterator>
+size_t GetResultSize(Iterator, Iterator, size_t, std::input_iterator_tag) {
+ return 0;
+}
+
+// Calculates space to reserve, if the iterator supports multiple passes.
+template <typename Iterator>
+size_t GetResultSize(Iterator it, Iterator end, size_t separator_size,
+ std::forward_iterator_tag) {
+ assert(it != end);
+ size_t length = it->size();
+ while (++it != end) {
+ length += separator_size;
+ length += it->size();
+ }
+ return length;
+}
+
+// A joining algorithm that's optimized for an iterator range of std::string-like
+// objects that do not need any additional formatting. This is to optimize the
+// common case of joining, say, a std::vector<std::string> or a
+// std::vector<absl::string_view>.
+//
+// This is an overload of the previous JoinAlgorithm() function. Here the
+// Formatter argument is of type NoFormatter. Since NoFormatter is an internal
+// type, this overload is only invoked when strings::Join() is called with a
+// range of std::string-like objects (e.g., std::string, absl::string_view), and an
+// explicit Formatter argument was NOT specified.
+//
+// The optimization is that the needed space will be reserved in the output
+// std::string to avoid the need to resize while appending. To do this, the iterator
+// range will be traversed twice: once to calculate the total needed size, and
+// then again to copy the elements and delimiters to the output std::string.
+template <typename Iterator>
+std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s,
+ NoFormatter) {
+ std::string result;
+ if (start != end) {
+ typename std::iterator_traits<Iterator>::iterator_category iterator_tag;
+ result.reserve(GetResultSize(start, end, s.size(), iterator_tag));
+
+ // Joins strings
+ absl::string_view sep("", 0);
+ for (Iterator it = start; it != end; ++it) {
+ result.append(sep.data(), sep.size());
+ result.append(it->data(), it->size());
+ sep = s;
+ }
+ }
+
+ return result;
+}
+
+// JoinTupleLoop implements a loop over the elements of a std::tuple, which
+// are heterogeneous. The primary template matches the tuple interior case. It
+// continues the iteration after appending a separator (for nonzero indices)
+// and formatting an element of the tuple. The specialization for the I=N case
+// matches the end-of-tuple, and terminates the iteration.
+template <size_t I, size_t N>
+struct JoinTupleLoop {
+ template <typename Tup, typename Formatter>
+ void operator()(std::string* out, const Tup& tup, absl::string_view sep,
+ Formatter&& fmt) {
+ if (I > 0) out->append(sep.data(), sep.size());
+ fmt(out, std::get<I>(tup));
+ JoinTupleLoop<I + 1, N>()(out, tup, sep, fmt);
+ }
+};
+template <size_t N>
+struct JoinTupleLoop<N, N> {
+ template <typename Tup, typename Formatter>
+ void operator()(std::string*, const Tup&, absl::string_view, Formatter&&) {}
+};
+
+template <typename... T, typename Formatter>
+std::string JoinAlgorithm(const std::tuple<T...>& tup, absl::string_view sep,
+ Formatter&& fmt) {
+ std::string result;
+ JoinTupleLoop<0, sizeof...(T)>()(&result, tup, sep, fmt);
+ return result;
+}
+
+template <typename Iterator>
+std::string JoinRange(Iterator first, Iterator last, absl::string_view separator) {
+ // No formatter was explicitly given, so a default must be chosen.
+ typedef typename std::iterator_traits<Iterator>::value_type ValueType;
+ typedef typename DefaultFormatter<ValueType>::Type Formatter;
+ return JoinAlgorithm(first, last, separator, Formatter());
+}
+
+template <typename Range, typename Formatter>
+std::string JoinRange(const Range& range, absl::string_view separator,
+ Formatter&& fmt) {
+ using std::begin;
+ using std::end;
+ return JoinAlgorithm(begin(range), end(range), separator, fmt);
+}
+
+template <typename Range>
+std::string JoinRange(const Range& range, absl::string_view separator) {
+ using std::begin;
+ using std::end;
+ return JoinRange(begin(range), end(range), separator);
+}
+
+} // namespace strings_internal
+} // namespace absl
+
+#endif // ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_
diff --git a/absl/strings/internal/str_split_internal.h b/absl/strings/internal/str_split_internal.h
new file mode 100644
index 0000000..dc31a8e
--- /dev/null
+++ b/absl/strings/internal/str_split_internal.h
@@ -0,0 +1,439 @@
+// 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 declares INTERNAL parts of the Split API that are inline/templated
+// or otherwise need to be available at compile time. The main abstractions
+// defined in here are
+//
+// - ConvertibleToStringView
+// - SplitIterator<>
+// - Splitter<>
+//
+// DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including
+// absl/strings/str_split.h.
+//
+// IWYU pragma: private, include "absl/strings/str_split.h"
+
+#ifndef ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_
+#define ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_
+
+#ifdef _GLIBCXX_DEBUG
+#include <glibcxx_debug_traits.h>
+#endif // _GLIBCXX_DEBUG
+
+#include <array>
+#include <initializer_list>
+#include <iterator>
+#include <map>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/meta/type_traits.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+namespace strings_internal {
+
+#ifdef _GLIBCXX_DEBUG
+using ::glibcxx_debug_traits::IsStrictlyDebugWrapperBase;
+#else // _GLIBCXX_DEBUG
+template <typename T> struct IsStrictlyDebugWrapperBase : std::false_type {};
+#endif // _GLIBCXX_DEBUG
+
+// This class is implicitly constructible from everything that absl::string_view
+// is implicitly constructible from. If it's constructed from a temporary
+// std::string, the data is moved into a data member so its lifetime matches that of
+// the ConvertibleToStringView instance.
+class ConvertibleToStringView {
+ public:
+ ConvertibleToStringView(const char* s) // NOLINT(runtime/explicit)
+ : value_(s) {}
+ ConvertibleToStringView(char* s) : value_(s) {} // NOLINT(runtime/explicit)
+ ConvertibleToStringView(absl::string_view s) // NOLINT(runtime/explicit)
+ : value_(s) {}
+ ConvertibleToStringView(const std::string& s) // NOLINT(runtime/explicit)
+ : value_(s) {}
+
+ // Matches rvalue strings and moves their data to a member.
+ConvertibleToStringView(std::string&& s) // NOLINT(runtime/explicit)
+ : copy_(std::move(s)), value_(copy_) {}
+
+ ConvertibleToStringView(const ConvertibleToStringView& other)
+ : copy_(other.copy_),
+ value_(other.IsSelfReferential() ? copy_ : other.value_) {}
+
+ ConvertibleToStringView(ConvertibleToStringView&& other) {
+ StealMembers(std::move(other));
+ }
+
+ ConvertibleToStringView& operator=(ConvertibleToStringView other) {
+ StealMembers(std::move(other));
+ return *this;
+ }
+
+ absl::string_view value() const { return value_; }
+
+ private:
+ // Returns true if ctsp's value refers to its internal copy_ member.
+ bool IsSelfReferential() const { return value_.data() == copy_.data(); }
+
+ void StealMembers(ConvertibleToStringView&& other) {
+ if (other.IsSelfReferential()) {
+ copy_ = std::move(other.copy_);
+ value_ = copy_;
+ other.value_ = other.copy_;
+ } else {
+ value_ = other.value_;
+ }
+ }
+
+ // Holds the data moved from temporary std::string arguments. Declared first so
+ // that 'value' can refer to 'copy_'.
+ std::string copy_;
+ absl::string_view value_;
+};
+
+// An iterator that enumerates the parts of a std::string from a Splitter. The text
+// to be split, the Delimiter, and the Predicate are all taken from the given
+// Splitter object. Iterators may only be compared if they refer to the same
+// Splitter instance.
+//
+// This class is NOT part of the public splitting API.
+template <typename Splitter>
+class SplitIterator {
+ public:
+ using iterator_category = std::input_iterator_tag;
+ using value_type = absl::string_view;
+ using difference_type = ptrdiff_t;
+ using pointer = const value_type*;
+ using reference = const value_type&;
+
+ enum State { kInitState, kLastState, kEndState };
+ SplitIterator(State state, const Splitter* splitter)
+ : pos_(0),
+ state_(state),
+ splitter_(splitter),
+ delimiter_(splitter->delimiter()),
+ predicate_(splitter->predicate()) {
+ // Hack to maintain backward compatibility. This one block makes it so an
+ // empty absl::string_view whose .data() happens to be nullptr behaves
+ // *differently* from an otherwise empty absl::string_view whose .data() is
+ // not nullptr. This is an undesirable difference in general, but this
+ // behavior is maintained to avoid breaking existing code that happens to
+ // depend on this old behavior/bug. Perhaps it will be fixed one day. The
+ // difference in behavior is as follows:
+ // Split(absl::string_view(""), '-'); // {""}
+ // Split(absl::string_view(), '-'); // {}
+ if (splitter_->text().data() == nullptr) {
+ state_ = kEndState;
+ pos_ = splitter_->text().size();
+ return;
+ }
+
+ if (state_ == kEndState) {
+ pos_ = splitter_->text().size();
+ } else {
+ ++(*this);
+ }
+ }
+
+ bool at_end() const { return state_ == kEndState; }
+
+ reference operator*() const { return curr_; }
+ pointer operator->() const { return &curr_; }
+
+ SplitIterator& operator++() {
+ do {
+ if (state_ == kLastState) {
+ state_ = kEndState;
+ return *this;
+ }
+ const absl::string_view text = splitter_->text();
+ const absl::string_view d = delimiter_.Find(text, pos_);
+ if (d.data() == text.end()) state_ = kLastState;
+ curr_ = text.substr(pos_, d.data() - (text.data() + pos_));
+ pos_ += curr_.size() + d.size();
+ } while (!predicate_(curr_));
+ return *this;
+ }
+
+ SplitIterator operator++(int) {
+ SplitIterator old(*this);
+ ++(*this);
+ return old;
+ }
+
+ friend bool operator==(const SplitIterator& a, const SplitIterator& b) {
+ return a.state_ == b.state_ && a.pos_ == b.pos_;
+ }
+
+ friend bool operator!=(const SplitIterator& a, const SplitIterator& b) {
+ return !(a == b);
+ }
+
+ private:
+ size_t pos_;
+ State state_;
+ absl::string_view curr_;
+ const Splitter* splitter_;
+ typename Splitter::DelimiterType delimiter_;
+ typename Splitter::PredicateType predicate_;
+};
+
+// HasMappedType<T>::value is true iff there exists a type T::mapped_type.
+template <typename T, typename = void>
+struct HasMappedType : std::false_type {};
+template <typename T>
+struct HasMappedType<T, absl::void_t<typename T::mapped_type>>
+ : std::true_type {};
+
+// HasValueType<T>::value is true iff there exists a type T::value_type.
+template <typename T, typename = void>
+struct HasValueType : std::false_type {};
+template <typename T>
+struct HasValueType<T, absl::void_t<typename T::value_type>> : std::true_type {
+};
+
+// HasConstIterator<T>::value is true iff there exists a type T::const_iterator.
+template <typename T, typename = void>
+struct HasConstIterator : std::false_type {};
+template <typename T>
+struct HasConstIterator<T, absl::void_t<typename T::const_iterator>>
+ : std::true_type {};
+
+// IsInitializerList<T>::value is true iff T is an std::initializer_list. More
+// details below in Splitter<> where this is used.
+std::false_type IsInitializerListDispatch(...); // default: No
+template <typename T>
+std::true_type IsInitializerListDispatch(std::initializer_list<T>*);
+template <typename T>
+struct IsInitializerList
+ : decltype(IsInitializerListDispatch(static_cast<T*>(nullptr))) {};
+
+// A SplitterIsConvertibleTo<C>::type alias exists iff the specified condition
+// is true for type 'C'.
+//
+// Restricts conversion to container-like types (by testing for the presence of
+// a const_iterator member type) and also to disable conversion to an
+// std::initializer_list (which also has a const_iterator). Otherwise, code
+// compiled in C++11 will get an error due to ambiguous conversion paths (in
+// C++11 std::vector<T>::operator= is overloaded to take either a std::vector<T>
+// or an std::initializer_list<T>).
+template <typename C>
+struct SplitterIsConvertibleTo
+ : std::enable_if<
+ !IsStrictlyDebugWrapperBase<C>::value &&
+ !IsInitializerList<C>::value &&
+ HasValueType<C>::value &&
+ HasConstIterator<C>::value> {};
+
+// This class implements the range that is returned by absl::StrSplit(). This
+// class has templated conversion operators that allow it to be implicitly
+// converted to a variety of types that the caller may have specified on the
+// left-hand side of an assignment.
+//
+// The main interface for interacting with this class is through its implicit
+// conversion operators. However, this class may also be used like a container
+// in that it has .begin() and .end() member functions. It may also be used
+// within a range-for loop.
+//
+// Output containers can be collections of any type that is constructible from
+// an absl::string_view.
+//
+// An Predicate functor may be supplied. This predicate will be used to filter
+// the split strings: only strings for which the predicate returns true will be
+// kept. A Predicate object is any unary functor that takes an absl::string_view
+// and returns bool.
+template <typename Delimiter, typename Predicate>
+class Splitter {
+ public:
+ using DelimiterType = Delimiter;
+ using PredicateType = Predicate;
+ using const_iterator = strings_internal::SplitIterator<Splitter>;
+ using value_type = typename std::iterator_traits<const_iterator>::value_type;
+
+ Splitter(ConvertibleToStringView input_text, Delimiter d, Predicate p)
+ : text_(std::move(input_text)),
+ delimiter_(std::move(d)),
+ predicate_(std::move(p)) {}
+
+ absl::string_view text() const { return text_.value(); }
+ const Delimiter& delimiter() const { return delimiter_; }
+ const Predicate& predicate() const { return predicate_; }
+
+ // Range functions that iterate the split substrings as absl::string_view
+ // objects. These methods enable a Splitter to be used in a range-based for
+ // loop.
+ const_iterator begin() const { return {const_iterator::kInitState, this}; }
+ const_iterator end() const { return {const_iterator::kEndState, this}; }
+
+ // An implicit conversion operator that is restricted to only those containers
+ // that the splitter is convertible to.
+ template <typename Container,
+ typename OnlyIf = typename SplitterIsConvertibleTo<Container>::type>
+ operator Container() const { // NOLINT(runtime/explicit)
+ return ConvertToContainer<Container, typename Container::value_type,
+ HasMappedType<Container>::value>()(*this);
+ }
+
+ // Returns a pair with its .first and .second members set to the first two
+ // strings returned by the begin() iterator. Either/both of .first and .second
+ // will be constructed with empty strings if the iterator doesn't have a
+ // corresponding value.
+ template <typename First, typename Second>
+ operator std::pair<First, Second>() const { // NOLINT(runtime/explicit)
+ absl::string_view first, second;
+ auto it = begin();
+ if (it != end()) {
+ first = *it;
+ if (++it != end()) {
+ second = *it;
+ }
+ }
+ return {First(first), Second(second)};
+ }
+
+ private:
+ // ConvertToContainer is a functor converting a Splitter to the requested
+ // Container of ValueType. It is specialized below to optimize splitting to
+ // certain combinations of Container and ValueType.
+ //
+ // This base template handles the generic case of storing the split results in
+ // the requested non-map-like container and converting the split substrings to
+ // the requested type.
+ template <typename Container, typename ValueType, bool is_map = false>
+ struct ConvertToContainer {
+ Container operator()(const Splitter& splitter) const {
+ Container c;
+ auto it = std::inserter(c, c.end());
+ for (const auto sp : splitter) {
+ *it++ = ValueType(sp);
+ }
+ return c;
+ }
+ };
+
+ // Partial specialization for a std::vector<absl::string_view>.
+ //
+ // Optimized for the common case of splitting to a
+ // std::vector<absl::string_view>. In this case we first split the results to
+ // a small array of absl::string_view on the stack, to reduce reallocations.
+ template <typename A>
+ struct ConvertToContainer<std::vector<absl::string_view, A>,
+ absl::string_view, false> {
+ std::vector<absl::string_view, A> operator()(
+ const Splitter& splitter) const {
+ struct raw_view {
+ const char* data;
+ size_t size;
+ operator absl::string_view() const { // NOLINT(runtime/explicit)
+ return {data, size};
+ }
+ };
+ std::vector<absl::string_view, A> v;
+ std::array<raw_view, 16> ar;
+ for (auto it = splitter.begin(); !it.at_end();) {
+ size_t index = 0;
+ do {
+ ar[index].data = it->data();
+ ar[index].size = it->size();
+ ++it;
+ } while (++index != ar.size() && !it.at_end());
+ v.insert(v.end(), ar.begin(), ar.begin() + index);
+ }
+ return v;
+ }
+ };
+
+ // Partial specialization for a std::vector<std::string>.
+ //
+ // Optimized for the common case of splitting to a std::vector<std::string>. In
+ // this case we first split the results to a std::vector<absl::string_view> so
+ // the returned std::vector<std::string> can have space reserved to avoid std::string
+ // moves.
+ template <typename A>
+ struct ConvertToContainer<std::vector<std::string, A>, std::string, false> {
+ std::vector<std::string, A> operator()(const Splitter& splitter) const {
+ const std::vector<absl::string_view> v = splitter;
+ return std::vector<std::string, A>(v.begin(), v.end());
+ }
+ };
+
+ // Partial specialization for containers of pairs (e.g., maps).
+ //
+ // The algorithm is to insert a new pair into the map for each even-numbered
+ // item, with the even-numbered item as the key with a default-constructed
+ // value. Each odd-numbered item will then be assigned to the last pair's
+ // value.
+ template <typename Container, typename First, typename Second>
+ struct ConvertToContainer<Container, std::pair<const First, Second>, true> {
+ Container operator()(const Splitter& splitter) const {
+ Container m;
+ typename Container::iterator it;
+ bool insert = true;
+ for (const auto sp : splitter) {
+ if (insert) {
+ it = Inserter<Container>::Insert(&m, First(sp), Second());
+ } else {
+ it->second = Second(sp);
+ }
+ insert = !insert;
+ }
+ return m;
+ }
+
+ // Inserts the key and value into the given map, returning an iterator to
+ // the inserted item. Specialized for std::map and std::multimap to use
+ // emplace() and adapt emplace()'s return value.
+ template <typename Map>
+ struct Inserter {
+ using M = Map;
+ template <typename... Args>
+ static typename M::iterator Insert(M* m, Args&&... args) {
+ return m->insert(std::make_pair(std::forward<Args>(args)...)).first;
+ }
+ };
+
+ template <typename... Ts>
+ struct Inserter<std::map<Ts...>> {
+ using M = std::map<Ts...>;
+ template <typename... Args>
+ static typename M::iterator Insert(M* m, Args&&... args) {
+ return m->emplace(std::make_pair(std::forward<Args>(args)...)).first;
+ }
+ };
+
+ template <typename... Ts>
+ struct Inserter<std::multimap<Ts...>> {
+ using M = std::multimap<Ts...>;
+ template <typename... Args>
+ static typename M::iterator Insert(M* m, Args&&... args) {
+ return m->emplace(std::make_pair(std::forward<Args>(args)...));
+ }
+ };
+ };
+
+ ConvertibleToStringView text_;
+ Delimiter delimiter_;
+ Predicate predicate_;
+};
+
+} // namespace strings_internal
+} // namespace absl
+
+#endif // ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_
diff --git a/absl/strings/internal/utf8.cc b/absl/strings/internal/utf8.cc
new file mode 100644
index 0000000..2415c2c
--- /dev/null
+++ b/absl/strings/internal/utf8.cc
@@ -0,0 +1,51 @@
+// 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.
+
+// UTF8 utilities, implemented to reduce dependencies.
+
+#include "absl/strings/internal/utf8.h"
+
+namespace absl {
+namespace strings_internal {
+
+size_t EncodeUTF8Char(char *buffer, char32_t utf8_char) {
+ if (utf8_char <= 0x7F) {
+ *buffer = static_cast<char>(utf8_char);
+ return 1;
+ } else if (utf8_char <= 0x7FF) {
+ buffer[1] = 0x80 | (utf8_char & 0x3F);
+ utf8_char >>= 6;
+ buffer[0] = 0xC0 | utf8_char;
+ return 2;
+ } else if (utf8_char <= 0xFFFF) {
+ buffer[2] = 0x80 | (utf8_char & 0x3F);
+ utf8_char >>= 6;
+ buffer[1] = 0x80 | (utf8_char & 0x3F);
+ utf8_char >>= 6;
+ buffer[0] = 0xE0 | utf8_char;
+ return 3;
+ } else {
+ buffer[3] = 0x80 | (utf8_char & 0x3F);
+ utf8_char >>= 6;
+ buffer[2] = 0x80 | (utf8_char & 0x3F);
+ utf8_char >>= 6;
+ buffer[1] = 0x80 | (utf8_char & 0x3F);
+ utf8_char >>= 6;
+ buffer[0] = 0xF0 | utf8_char;
+ return 4;
+ }
+}
+
+} // namespace strings_internal
+} // namespace absl
diff --git a/absl/strings/internal/utf8.h b/absl/strings/internal/utf8.h
new file mode 100644
index 0000000..705eea7
--- /dev/null
+++ b/absl/strings/internal/utf8.h
@@ -0,0 +1,52 @@
+// 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.
+//
+// UTF8 utilities, implemented to reduce dependencies.
+//
+// If you need Unicode specific processing (for example being aware of
+// Unicode character boundaries, or knowledge of Unicode casing rules,
+// or various forms of equivalence and normalization), take a look at
+// files in i18n/utf8.
+
+#ifndef ABSL_STRINGS_INTERNAL_UTF8_H_
+#define ABSL_STRINGS_INTERNAL_UTF8_H_
+
+#include <cstddef>
+#include <cstdint>
+
+
+namespace absl {
+namespace strings_internal {
+
+// For Unicode code points 0 through 0x10FFFF, EncodeUTF8Char writes
+// out the UTF-8 encoding into buffer, and returns the number of chars
+// it wrote.
+//
+// As described in https://tools.ietf.org/html/rfc3629#section-3 , the encodings
+// are:
+// 00 - 7F : 0xxxxxxx
+// 80 - 7FF : 110xxxxx 10xxxxxx
+// 800 - FFFF : 1110xxxx 10xxxxxx 10xxxxxx
+// 10000 - 10FFFF : 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+//
+// Values greater than 0x10FFFF are not supported and may or may not write
+// characters into buffer, however never will more than kMaxEncodedUTF8Size
+// bytes be written, regardless of the value of utf8_char.
+enum { kMaxEncodedUTF8Size = 4 };
+size_t EncodeUTF8Char(char *buffer, char32_t utf8_char);
+
+} // namespace strings_internal
+} // namespace absl
+
+#endif // ABSL_STRINGS_INTERNAL_UTF8_H_
diff --git a/absl/strings/internal/utf8_test.cc b/absl/strings/internal/utf8_test.cc
new file mode 100644
index 0000000..4d43742
--- /dev/null
+++ b/absl/strings/internal/utf8_test.cc
@@ -0,0 +1,58 @@
+// 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/strings/internal/utf8.h"
+
+#include <cctype>
+#include <cstdlib>
+#include <cstring>
+#include <cstdint>
+
+#include "gtest/gtest.h"
+
+namespace {
+
+TEST(EncodeUTF8Char, BasicFunction) {
+ std::pair<char32_t, std::string> tests[] = {{0x0030, u8"\u0030"},
+ {0x00A3, u8"\u00A3"},
+ {0x00010000, u8"\U00010000"},
+ {0x0000FFFF, u8"\U0000FFFF"},
+ {0x0010FFFD, u8"\U0010FFFD"}};
+ for (auto &test : tests) {
+ char buf0[7] = {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'};
+ char buf1[7] = {'\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF'};
+ char *buf0_written =
+ &buf0[absl::strings_internal::EncodeUTF8Char(buf0, test.first)];
+ char *buf1_written =
+ &buf1[absl::strings_internal::EncodeUTF8Char(buf1, test.first)];
+ int apparent_length = 7;
+ while (buf0[apparent_length - 1] == '\x00' &&
+ buf1[apparent_length - 1] == '\xFF') {
+ if (--apparent_length == 0) break;
+ }
+ EXPECT_EQ(apparent_length, buf0_written - buf0);
+ EXPECT_EQ(apparent_length, buf1_written - buf1);
+ EXPECT_EQ(apparent_length, test.second.length());
+ EXPECT_EQ(std::string(buf0, apparent_length), test.second);
+ EXPECT_EQ(std::string(buf1, apparent_length), test.second);
+ }
+ char buf[32] = "Don't Tread On Me";
+ EXPECT_LE(absl::strings_internal::EncodeUTF8Char(buf, 0x00110000),
+ absl::strings_internal::kMaxEncodedUTF8Size);
+ char buf2[32] = "Negative is invalid but sane";
+ EXPECT_LE(absl::strings_internal::EncodeUTF8Char(buf2, -1),
+ absl::strings_internal::kMaxEncodedUTF8Size);
+}
+
+} // namespace
diff --git a/absl/strings/match.cc b/absl/strings/match.cc
new file mode 100644
index 0000000..53881bd
--- /dev/null
+++ b/absl/strings/match.cc
@@ -0,0 +1,40 @@
+// 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/strings/match.h"
+
+#include "absl/strings/internal/memutil.h"
+
+namespace absl {
+
+namespace {
+bool CaseEqual(absl::string_view piece1, absl::string_view piece2) {
+ return (piece1.size() == piece2.size() &&
+ 0 == strings_internal::memcasecmp(piece1.data(), piece2.data(),
+ piece1.size()));
+ // memcasecmp uses ascii_tolower().
+}
+} // namespace
+
+bool StartsWithIgnoreCase(absl::string_view text, absl::string_view preffix) {
+ return (text.size() >= preffix.size()) &&
+ CaseEqual(text.substr(0, preffix.size()), preffix);
+}
+
+bool EndsWithIgnoreCase(absl::string_view text, absl::string_view suffix) {
+ return (text.size() >= suffix.size()) &&
+ CaseEqual(text.substr(text.size() - suffix.size()), suffix);
+}
+
+} // namespace absl
diff --git a/absl/strings/match.h b/absl/strings/match.h
new file mode 100644
index 0000000..4a5d1c0
--- /dev/null
+++ b/absl/strings/match.h
@@ -0,0 +1,81 @@
+//
+// 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: match.h
+// -----------------------------------------------------------------------------
+//
+// This file contains simple utilities for performing std::string matching checks.
+// All of these function parameters are specified as `absl::string_view`,
+// meaning that these functions can accept `std::string`, `absl::string_view` or
+// nul-terminated C-style strings.
+//
+// Examples:
+// std::string s = "foo";
+// absl::string_view sv = "f";
+// EXPECT_TRUE(absl::StrContains(s, sv));
+//
+// Note: The order of parameters in these functions is designed to mimic the
+// order an equivalent member function would exhibit;
+// e.g. `s.Contains(x)` ==> `absl::StrContains(s, x).
+#ifndef ABSL_STRINGS_MATCH_H_
+#define ABSL_STRINGS_MATCH_H_
+
+#include <cstring>
+
+#include "absl/strings/string_view.h"
+
+namespace absl {
+
+// StrContains()
+//
+// Returns whether a given std::string `s` contains the substring `x`.
+inline bool StrContains(absl::string_view s, absl::string_view x) {
+ return static_cast<absl::string_view::size_type>(s.find(x, 0)) != s.npos;
+}
+
+// StartsWith()
+//
+// Returns whether a given std::string `s` begins with `x`.
+inline bool StartsWith(absl::string_view s, absl::string_view x) {
+ return x.empty() ||
+ (s.size() >= x.size() && memcmp(s.data(), x.data(), x.size()) == 0);
+}
+
+// EndsWith()
+//
+// Returns whether a given std::string `s` ends `x`.
+inline bool EndsWith(absl::string_view s, absl::string_view x) {
+ return x.empty() ||
+ (s.size() >= x.size() &&
+ memcmp(s.data() + (s.size() - x.size()), x.data(), x.size()) == 0);
+}
+
+// StartsWithIgnoreCase()
+//
+// Returns whether a given std::string `text` starts with `starts_with`, ignoring
+// case in the comparison.
+bool StartsWithIgnoreCase(absl::string_view text,
+ absl::string_view starts_with);
+
+// EndsWithIgnoreCase()
+//
+// Returns whether a given std::string `text` ends with `ends_with`, ignoring case
+// in the comparison.
+bool EndsWithIgnoreCase(absl::string_view text, absl::string_view ends_with);
+
+} // namespace absl
+
+#endif // ABSL_STRINGS_MATCH_H_
diff --git a/absl/strings/match_test.cc b/absl/strings/match_test.cc
new file mode 100644
index 0000000..d194f0e
--- /dev/null
+++ b/absl/strings/match_test.cc
@@ -0,0 +1,99 @@
+// 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/strings/match.h"
+
+#include "gtest/gtest.h"
+
+namespace {
+
+TEST(MatchTest, StartsWith) {
+ const std::string s1("123" "\0" "456", 7);
+ const absl::string_view a("foobar");
+ const absl::string_view b(s1);
+ const absl::string_view e;
+ EXPECT_TRUE(absl::StartsWith(a, a));
+ EXPECT_TRUE(absl::StartsWith(a, "foo"));
+ EXPECT_TRUE(absl::StartsWith(a, e));
+ EXPECT_TRUE(absl::StartsWith(b, s1));
+ EXPECT_TRUE(absl::StartsWith(b, b));
+ EXPECT_TRUE(absl::StartsWith(b, e));
+ EXPECT_TRUE(absl::StartsWith(e, ""));
+ EXPECT_FALSE(absl::StartsWith(a, b));
+ EXPECT_FALSE(absl::StartsWith(b, a));
+ EXPECT_FALSE(absl::StartsWith(e, a));
+}
+
+TEST(MatchTest, EndsWith) {
+ const std::string s1("123" "\0" "456", 7);
+ const absl::string_view a("foobar");
+ const absl::string_view b(s1);
+ const absl::string_view e;
+ EXPECT_TRUE(absl::EndsWith(a, a));
+ EXPECT_TRUE(absl::EndsWith(a, "bar"));
+ EXPECT_TRUE(absl::EndsWith(a, e));
+ EXPECT_TRUE(absl::EndsWith(b, s1));
+ EXPECT_TRUE(absl::EndsWith(b, b));
+ EXPECT_TRUE(absl::EndsWith(b, e));
+ EXPECT_TRUE(absl::EndsWith(e, ""));
+ EXPECT_FALSE(absl::EndsWith(a, b));
+ EXPECT_FALSE(absl::EndsWith(b, a));
+ EXPECT_FALSE(absl::EndsWith(e, a));
+}
+
+TEST(MatchTest, Contains) {
+ absl::string_view a("abcdefg");
+ absl::string_view b("abcd");
+ absl::string_view c("efg");
+ absl::string_view d("gh");
+ EXPECT_TRUE(absl::StrContains(a, a));
+ EXPECT_TRUE(absl::StrContains(a, b));
+ EXPECT_TRUE(absl::StrContains(a, c));
+ EXPECT_FALSE(absl::StrContains(a, d));
+ EXPECT_TRUE(absl::StrContains("", ""));
+ EXPECT_TRUE(absl::StrContains("abc", ""));
+ EXPECT_FALSE(absl::StrContains("", "a"));
+}
+
+TEST(MatchTest, ContainsNull) {
+ const std::string s = "foo";
+ const char* cs = "foo";
+ const absl::string_view sv("foo");
+ const absl::string_view sv2("foo\0bar", 4);
+ EXPECT_EQ(s, "foo");
+ EXPECT_EQ(sv, "foo");
+ EXPECT_NE(sv2, "foo");
+ EXPECT_TRUE(absl::EndsWith(s, sv));
+ EXPECT_TRUE(absl::StartsWith(cs, sv));
+ EXPECT_TRUE(absl::StrContains(cs, sv));
+ EXPECT_FALSE(absl::StrContains(cs, sv2));
+}
+
+TEST(MatchTest, StartsWithIgnoreCase) {
+ EXPECT_TRUE(absl::StartsWithIgnoreCase("foo", "foo"));
+ EXPECT_TRUE(absl::StartsWithIgnoreCase("foo", "Fo"));
+ EXPECT_TRUE(absl::StartsWithIgnoreCase("foo", ""));
+ EXPECT_FALSE(absl::StartsWithIgnoreCase("foo", "fooo"));
+ EXPECT_FALSE(absl::StartsWithIgnoreCase("", "fo"));
+}
+
+TEST(MatchTest, EndsWithIgnoreCase) {
+ EXPECT_TRUE(absl::EndsWithIgnoreCase("foo", "foo"));
+ EXPECT_TRUE(absl::EndsWithIgnoreCase("foo", "Oo"));
+ EXPECT_TRUE(absl::EndsWithIgnoreCase("foo", ""));
+ EXPECT_FALSE(absl::EndsWithIgnoreCase("foo", "fooo"));
+ EXPECT_FALSE(absl::EndsWithIgnoreCase("", "fo"));
+}
+
+} // namespace
diff --git a/absl/strings/numbers.cc b/absl/strings/numbers.cc
new file mode 100644
index 0000000..3b093b9
--- /dev/null
+++ b/absl/strings/numbers.cc
@@ -0,0 +1,1288 @@
+// This file contains std::string processing functions related to
+// numeric values.
+
+#include "absl/strings/numbers.h"
+
+#include <cassert>
+#include <cctype>
+#include <cfloat> // for DBL_DIG and FLT_DIG
+#include <cmath> // for HUGE_VAL
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <limits>
+#include <memory>
+#include <string>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/numeric/int128.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/internal/memutil.h"
+#include "absl/strings/str_cat.h"
+
+namespace absl {
+
+bool SimpleAtof(absl::string_view str, float* value) {
+ *value = 0.0;
+ if (str.empty()) return false;
+ char buf[32];
+ std::unique_ptr<char[]> bigbuf;
+ char* ptr = buf;
+ if (str.size() > sizeof(buf) - 1) {
+ bigbuf.reset(new char[str.size() + 1]);
+ ptr = bigbuf.get();
+ }
+ memcpy(ptr, str.data(), str.size());
+ ptr[str.size()] = '\0';
+
+ char* endptr;
+ *value = strtof(ptr, &endptr);
+ if (endptr != ptr) {
+ while (absl::ascii_isspace(*endptr)) ++endptr;
+ }
+ // Ignore range errors from strtod/strtof.
+ // The values it returns on underflow and
+ // overflow are the right fallback in a
+ // robust setting.
+ return *ptr != '\0' && *endptr == '\0';
+}
+
+bool SimpleAtod(absl::string_view str, double* value) {
+ *value = 0.0;
+ if (str.empty()) return false;
+ char buf[32];
+ std::unique_ptr<char[]> bigbuf;
+ char* ptr = buf;
+ if (str.size() > sizeof(buf) - 1) {
+ bigbuf.reset(new char[str.size() + 1]);
+ ptr = bigbuf.get();
+ }
+ memcpy(ptr, str.data(), str.size());
+ ptr[str.size()] = '\0';
+
+ char* endptr;
+ *value = strtod(ptr, &endptr);
+ if (endptr != ptr) {
+ while (absl::ascii_isspace(*endptr)) ++endptr;
+ }
+ // Ignore range errors from strtod. The values it
+ // returns on underflow and overflow are the right
+ // fallback in a robust setting.
+ return *ptr != '\0' && *endptr == '\0';
+}
+
+namespace {
+
+// TODO(rogeeff): replace with the real released thing once we figure out what
+// it is.
+inline bool CaseEqual(absl::string_view piece1, absl::string_view piece2) {
+ return (piece1.size() == piece2.size() &&
+ 0 == strings_internal::memcasecmp(piece1.data(), piece2.data(),
+ piece1.size()));
+}
+
+// Writes a two-character representation of 'i' to 'buf'. 'i' must be in the
+// range 0 <= i < 100, and buf must have space for two characters. Example:
+// char buf[2];
+// PutTwoDigits(42, buf);
+// // buf[0] == '4'
+// // buf[1] == '2'
+inline void PutTwoDigits(size_t i, char* buf) {
+ static const char two_ASCII_digits[100][2] = {
+ {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'},
+ {'0', '5'}, {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'},
+ {'1', '0'}, {'1', '1'}, {'1', '2'}, {'1', '3'}, {'1', '4'},
+ {'1', '5'}, {'1', '6'}, {'1', '7'}, {'1', '8'}, {'1', '9'},
+ {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'}, {'2', '4'},
+ {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'},
+ {'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'},
+ {'3', '5'}, {'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'},
+ {'4', '0'}, {'4', '1'}, {'4', '2'}, {'4', '3'}, {'4', '4'},
+ {'4', '5'}, {'4', '6'}, {'4', '7'}, {'4', '8'}, {'4', '9'},
+ {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'}, {'5', '4'},
+ {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'},
+ {'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'},
+ {'6', '5'}, {'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'},
+ {'7', '0'}, {'7', '1'}, {'7', '2'}, {'7', '3'}, {'7', '4'},
+ {'7', '5'}, {'7', '6'}, {'7', '7'}, {'7', '8'}, {'7', '9'},
+ {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'}, {'8', '4'},
+ {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'},
+ {'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'},
+ {'9', '5'}, {'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}
+ };
+ assert(i < 100);
+ memcpy(buf, two_ASCII_digits[i], 2);
+}
+
+} // namespace
+
+bool SimpleAtob(absl::string_view str, bool* value) {
+ ABSL_RAW_CHECK(value != nullptr, "Output pointer must not be nullptr.");
+ if (CaseEqual(str, "true") || CaseEqual(str, "t") ||
+ CaseEqual(str, "yes") || CaseEqual(str, "y") ||
+ CaseEqual(str, "1")) {
+ *value = true;
+ return true;
+ }
+ if (CaseEqual(str, "false") || CaseEqual(str, "f") ||
+ CaseEqual(str, "no") || CaseEqual(str, "n") ||
+ CaseEqual(str, "0")) {
+ *value = false;
+ return true;
+ }
+ return false;
+}
+
+// ----------------------------------------------------------------------
+// FastInt32ToBuffer()
+// FastUInt32ToBuffer()
+// FastInt64ToBuffer()
+// FastUInt64ToBuffer()
+//
+// Like the Fast*ToBuffer() functions above, these are intended for speed.
+// Unlike the Fast*ToBuffer() functions, however, these functions write
+// their output to the beginning of the buffer (hence the name, as the
+// output is left-aligned). The caller is responsible for ensuring that
+// the buffer has enough space to hold the output.
+//
+// Returns a pointer to the end of the std::string (i.e. the null character
+// terminating the std::string).
+// ----------------------------------------------------------------------
+
+namespace {
+
+// Used to optimize printing a decimal number's final digit.
+const char one_ASCII_final_digits[10][2] {
+ {'0', 0}, {'1', 0}, {'2', 0}, {'3', 0}, {'4', 0},
+ {'5', 0}, {'6', 0}, {'7', 0}, {'8', 0}, {'9', 0},
+};
+
+} // namespace
+
+char* numbers_internal::FastUInt32ToBuffer(uint32_t i, char* buffer) {
+ uint32_t digits;
+ // The idea of this implementation is to trim the number of divides to as few
+ // as possible, and also reducing memory stores and branches, by going in
+ // steps of two digits at a time rather than one whenever possible.
+ // The huge-number case is first, in the hopes that the compiler will output
+ // that case in one branch-free block of code, and only output conditional
+ // branches into it from below.
+ if (i >= 1000000000) { // >= 1,000,000,000
+ digits = i / 100000000; // 100,000,000
+ i -= digits * 100000000;
+ PutTwoDigits(digits, buffer);
+ buffer += 2;
+ lt100_000_000:
+ digits = i / 1000000; // 1,000,000
+ i -= digits * 1000000;
+ PutTwoDigits(digits, buffer);
+ buffer += 2;
+ lt1_000_000:
+ digits = i / 10000; // 10,000
+ i -= digits * 10000;
+ PutTwoDigits(digits, buffer);
+ buffer += 2;
+ lt10_000:
+ digits = i / 100;
+ i -= digits * 100;
+ PutTwoDigits(digits, buffer);
+ buffer += 2;
+ lt100:
+ digits = i;
+ PutTwoDigits(digits, buffer);
+ buffer += 2;
+ *buffer = 0;
+ return buffer;
+ }
+
+ if (i < 100) {
+ digits = i;
+ if (i >= 10) goto lt100;
+ memcpy(buffer, one_ASCII_final_digits[i], 2);
+ return buffer + 1;
+ }
+ if (i < 10000) { // 10,000
+ if (i >= 1000) goto lt10_000;
+ digits = i / 100;
+ i -= digits * 100;
+ *buffer++ = '0' + digits;
+ goto lt100;
+ }
+ if (i < 1000000) { // 1,000,000
+ if (i >= 100000) goto lt1_000_000;
+ digits = i / 10000; // 10,000
+ i -= digits * 10000;
+ *buffer++ = '0' + digits;
+ goto lt10_000;
+ }
+ if (i < 100000000) { // 100,000,000
+ if (i >= 10000000) goto lt100_000_000;
+ digits = i / 1000000; // 1,000,000
+ i -= digits * 1000000;
+ *buffer++ = '0' + digits;
+ goto lt1_000_000;
+ }
+ // we already know that i < 1,000,000,000
+ digits = i / 100000000; // 100,000,000
+ i -= digits * 100000000;
+ *buffer++ = '0' + digits;
+ goto lt100_000_000;
+}
+
+char* numbers_internal::FastInt32ToBuffer(int32_t i, char* buffer) {
+ uint32_t u = i;
+ if (i < 0) {
+ *buffer++ = '-';
+ // We need to do the negation in modular (i.e., "unsigned")
+ // arithmetic; MSVC++ apprently warns for plain "-u", so
+ // we write the equivalent expression "0 - u" instead.
+ u = 0 - u;
+ }
+ return numbers_internal::FastUInt32ToBuffer(u, buffer);
+}
+
+char* numbers_internal::FastUInt64ToBuffer(uint64_t i, char* buffer) {
+ uint32_t u32 = static_cast<uint32_t>(i);
+ if (u32 == i) return numbers_internal::FastUInt32ToBuffer(u32, buffer);
+
+ // Here we know i has at least 10 decimal digits.
+ uint64_t top_1to11 = i / 1000000000;
+ u32 = static_cast<uint32_t>(i - top_1to11 * 1000000000);
+ uint32_t top_1to11_32 = static_cast<uint32_t>(top_1to11);
+
+ if (top_1to11_32 == top_1to11) {
+ buffer = numbers_internal::FastUInt32ToBuffer(top_1to11_32, buffer);
+ } else {
+ // top_1to11 has more than 32 bits too; print it in two steps.
+ uint32_t top_8to9 = static_cast<uint32_t>(top_1to11 / 100);
+ uint32_t mid_2 = static_cast<uint32_t>(top_1to11 - top_8to9 * 100);
+ buffer = numbers_internal::FastUInt32ToBuffer(top_8to9, buffer);
+ PutTwoDigits(mid_2, buffer);
+ buffer += 2;
+ }
+
+ // We have only 9 digits now, again the maximum uint32_t can handle fully.
+ uint32_t digits = u32 / 10000000; // 10,000,000
+ u32 -= digits * 10000000;
+ PutTwoDigits(digits, buffer);
+ buffer += 2;
+ digits = u32 / 100000; // 100,000
+ u32 -= digits * 100000;
+ PutTwoDigits(digits, buffer);
+ buffer += 2;
+ digits = u32 / 1000; // 1,000
+ u32 -= digits * 1000;
+ PutTwoDigits(digits, buffer);
+ buffer += 2;
+ digits = u32 / 10;
+ u32 -= digits * 10;
+ PutTwoDigits(digits, buffer);
+ buffer += 2;
+ memcpy(buffer, one_ASCII_final_digits[u32], 2);
+ return buffer + 1;
+}
+
+char* numbers_internal::FastInt64ToBuffer(int64_t i, char* buffer) {
+ uint64_t u = i;
+ if (i < 0) {
+ *buffer++ = '-';
+ u = 0 - u;
+ }
+ return numbers_internal::FastUInt64ToBuffer(u, buffer);
+}
+
+// Although DBL_DIG is typically 15, DBL_MAX is normally represented with 17
+// digits of precision. When converted to a std::string value with fewer digits
+// of precision using strtod(), the result can be bigger than DBL_MAX due to
+// a rounding error. Converting this value back to a double will produce an
+// Inf which will trigger a SIGFPE if FP exceptions are enabled. We skip
+// the precision check for sufficiently large values to avoid the SIGFPE.
+static const double kDoublePrecisionCheckMax = DBL_MAX / 1.000000000000001;
+
+char* numbers_internal::RoundTripDoubleToBuffer(double d, char* buffer) {
+ // DBL_DIG is 15 for IEEE-754 doubles, which are used on almost all
+ // platforms these days. Just in case some system exists where DBL_DIG
+ // is significantly larger -- and risks overflowing our buffer -- we have
+ // this assert.
+ static_assert(DBL_DIG < 20, "DBL_DIG is too big");
+
+ bool full_precision_needed = true;
+ if (std::abs(d) <= kDoublePrecisionCheckMax) {
+ int snprintf_result = snprintf(buffer, numbers_internal::kFastToBufferSize,
+ "%.*g", DBL_DIG, d);
+
+ // The snprintf should never overflow because the buffer is significantly
+ // larger than the precision we asked for.
+ assert(snprintf_result > 0 &&
+ snprintf_result < numbers_internal::kFastToBufferSize);
+ (void)snprintf_result;
+
+ full_precision_needed = strtod(buffer, nullptr) != d;
+ }
+
+ if (full_precision_needed) {
+ int snprintf_result = snprintf(buffer, numbers_internal::kFastToBufferSize,
+ "%.*g", DBL_DIG + 2, d);
+
+ // Should never overflow; see above.
+ assert(snprintf_result > 0 &&
+ snprintf_result < numbers_internal::kFastToBufferSize);
+ (void)snprintf_result;
+ }
+ return buffer;
+}
+// This table is used to quickly calculate the base-ten exponent of a given
+// float, and then to provide a multiplier to bring that number into the
+// range 1-999,999,999, that is, into uint32_t range. Finally, the exp
+// std::string is made available so there is one less int-to-std::string conversion
+// to be done.
+
+struct Spec {
+ double min_range;
+ double multiplier;
+ const char expstr[5];
+};
+const Spec neg_exp_table[] = {
+ {1.4e-45f, 1e+55, "e-45"}, //
+ {1e-44f, 1e+54, "e-44"}, //
+ {1e-43f, 1e+53, "e-43"}, //
+ {1e-42f, 1e+52, "e-42"}, //
+ {1e-41f, 1e+51, "e-41"}, //
+ {1e-40f, 1e+50, "e-40"}, //
+ {1e-39f, 1e+49, "e-39"}, //
+ {1e-38f, 1e+48, "e-38"}, //
+ {1e-37f, 1e+47, "e-37"}, //
+ {1e-36f, 1e+46, "e-36"}, //
+ {1e-35f, 1e+45, "e-35"}, //
+ {1e-34f, 1e+44, "e-34"}, //
+ {1e-33f, 1e+43, "e-33"}, //
+ {1e-32f, 1e+42, "e-32"}, //
+ {1e-31f, 1e+41, "e-31"}, //
+ {1e-30f, 1e+40, "e-30"}, //
+ {1e-29f, 1e+39, "e-29"}, //
+ {1e-28f, 1e+38, "e-28"}, //
+ {1e-27f, 1e+37, "e-27"}, //
+ {1e-26f, 1e+36, "e-26"}, //
+ {1e-25f, 1e+35, "e-25"}, //
+ {1e-24f, 1e+34, "e-24"}, //
+ {1e-23f, 1e+33, "e-23"}, //
+ {1e-22f, 1e+32, "e-22"}, //
+ {1e-21f, 1e+31, "e-21"}, //
+ {1e-20f, 1e+30, "e-20"}, //
+ {1e-19f, 1e+29, "e-19"}, //
+ {1e-18f, 1e+28, "e-18"}, //
+ {1e-17f, 1e+27, "e-17"}, //
+ {1e-16f, 1e+26, "e-16"}, //
+ {1e-15f, 1e+25, "e-15"}, //
+ {1e-14f, 1e+24, "e-14"}, //
+ {1e-13f, 1e+23, "e-13"}, //
+ {1e-12f, 1e+22, "e-12"}, //
+ {1e-11f, 1e+21, "e-11"}, //
+ {1e-10f, 1e+20, "e-10"}, //
+ {1e-09f, 1e+19, "e-09"}, //
+ {1e-08f, 1e+18, "e-08"}, //
+ {1e-07f, 1e+17, "e-07"}, //
+ {1e-06f, 1e+16, "e-06"}, //
+ {1e-05f, 1e+15, "e-05"}, //
+ {1e-04f, 1e+14, "e-04"}, //
+};
+
+const Spec pos_exp_table[] = {
+ {1e+08f, 1e+02, "e+08"}, //
+ {1e+09f, 1e+01, "e+09"}, //
+ {1e+10f, 1e+00, "e+10"}, //
+ {1e+11f, 1e-01, "e+11"}, //
+ {1e+12f, 1e-02, "e+12"}, //
+ {1e+13f, 1e-03, "e+13"}, //
+ {1e+14f, 1e-04, "e+14"}, //
+ {1e+15f, 1e-05, "e+15"}, //
+ {1e+16f, 1e-06, "e+16"}, //
+ {1e+17f, 1e-07, "e+17"}, //
+ {1e+18f, 1e-08, "e+18"}, //
+ {1e+19f, 1e-09, "e+19"}, //
+ {1e+20f, 1e-10, "e+20"}, //
+ {1e+21f, 1e-11, "e+21"}, //
+ {1e+22f, 1e-12, "e+22"}, //
+ {1e+23f, 1e-13, "e+23"}, //
+ {1e+24f, 1e-14, "e+24"}, //
+ {1e+25f, 1e-15, "e+25"}, //
+ {1e+26f, 1e-16, "e+26"}, //
+ {1e+27f, 1e-17, "e+27"}, //
+ {1e+28f, 1e-18, "e+28"}, //
+ {1e+29f, 1e-19, "e+29"}, //
+ {1e+30f, 1e-20, "e+30"}, //
+ {1e+31f, 1e-21, "e+31"}, //
+ {1e+32f, 1e-22, "e+32"}, //
+ {1e+33f, 1e-23, "e+33"}, //
+ {1e+34f, 1e-24, "e+34"}, //
+ {1e+35f, 1e-25, "e+35"}, //
+ {1e+36f, 1e-26, "e+36"}, //
+ {1e+37f, 1e-27, "e+37"}, //
+ {1e+38f, 1e-28, "e+38"}, //
+ {1e+39, 1e-29, "e+39"}, //
+};
+
+struct ExpCompare {
+ bool operator()(const Spec& spec, double d) const {
+ return spec.min_range < d;
+ }
+};
+
+// Utility routine(s) for RoundTripFloatToBuffer:
+// OutputNecessaryDigits takes two 11-digit numbers, whose integer portion
+// represents the fractional part of a floating-point number, and outputs a
+// number that is in-between them, with the fewest digits possible. For
+// instance, given 12345678900 and 12345876900, it would output "0123457".
+// When there are multiple final digits that would satisfy this requirement,
+// this routine attempts to use a digit that would represent the average of
+// lower_double and upper_double.
+//
+// Although the routine works using integers, all callers use doubles, so
+// for their convenience this routine accepts doubles.
+static char* OutputNecessaryDigits(double lower_double, double upper_double,
+ char* out) {
+ assert(lower_double > 0);
+ assert(lower_double < upper_double - 10);
+ assert(upper_double < 100000000000.0);
+
+ // Narrow the range a bit; without this bias, an input of lower=87654320010.0
+ // and upper=87654320100.0 would produce an output of 876543201
+ //
+ // We do this in three steps: first, we lower the upper bound and truncate it
+ // to an integer. Then, we increase the lower bound by exactly the amount we
+ // just decreased the upper bound by - at that point, the midpoint is exactly
+ // where it used to be. Then we truncate the lower bound.
+
+ uint64_t upper64 = upper_double - (1.0 / 1024);
+ double shrink = upper_double - upper64;
+ uint64_t lower64 = lower_double + shrink;
+
+ // Theory of operation: we convert the lower number to ascii representation,
+ // two digits at a time. As we go, we remove the same digits from the upper
+ // number. When we see the upper number does not share those same digits, we
+ // know we can stop converting. When we stop, the last digit we output is
+ // taken from the average of upper and lower values, rounded up.
+ char buf[2];
+ uint32_t lodigits =
+ static_cast<uint32_t>(lower64 / 1000000000); // 1,000,000,000
+ uint64_t mul64 = lodigits * uint64_t{1000000000};
+
+ PutTwoDigits(lodigits, out);
+ out += 2;
+ if (upper64 - mul64 >= 1000000000) { // digit mismatch!
+ PutTwoDigits(upper64 / 1000000000, buf);
+ if (out[-2] != buf[0]) {
+ out[-2] = '0' + (upper64 + lower64 + 10000000000) / 20000000000;
+ --out;
+ } else {
+ PutTwoDigits((upper64 + lower64 + 1000000000) / 2000000000, out - 2);
+ }
+ *out = '\0';
+ return out;
+ }
+ uint32_t lower = static_cast<uint32_t>(lower64 - mul64);
+ uint32_t upper = static_cast<uint32_t>(upper64 - mul64);
+
+ lodigits = lower / 10000000; // 10,000,000
+ uint32_t mul = lodigits * 10000000;
+ PutTwoDigits(lodigits, out);
+ out += 2;
+ if (upper - mul >= 10000000) { // digit mismatch!
+ PutTwoDigits(upper / 10000000, buf);
+ if (out[-2] != buf[0]) {
+ out[-2] = '0' + (upper + lower + 100000000) / 200000000;
+ --out;
+ } else {
+ PutTwoDigits((upper + lower + 10000000) / 20000000, out - 2);
+ }
+ *out = '\0';
+ return out;
+ }
+ lower -= mul;
+ upper -= mul;
+
+ lodigits = lower / 100000; // 100,000
+ mul = lodigits * 100000;
+ PutTwoDigits(lodigits, out);
+ out += 2;
+ if (upper - mul >= 100000) { // digit mismatch!
+ PutTwoDigits(upper / 100000, buf);
+ if (out[-2] != buf[0]) {
+ out[-2] = '0' + (upper + lower + 1000000) / 2000000;
+ --out;
+ } else {
+ PutTwoDigits((upper + lower + 100000) / 200000, out - 2);
+ }
+ *out = '\0';
+ return out;
+ }
+ lower -= mul;
+ upper -= mul;
+
+ lodigits = lower / 1000;
+ mul = lodigits * 1000;
+ PutTwoDigits(lodigits, out);
+ out += 2;
+ if (upper - mul >= 1000) { // digit mismatch!
+ PutTwoDigits(upper / 1000, buf);
+ if (out[-2] != buf[0]) {
+ out[-2] = '0' + (upper + lower + 10000) / 20000;
+ --out;
+ } else {
+ PutTwoDigits((upper + lower + 1000) / 2000, out - 2);
+ }
+ *out = '\0';
+ return out;
+ }
+ lower -= mul;
+ upper -= mul;
+
+ PutTwoDigits(lower / 10, out);
+ out += 2;
+ PutTwoDigits(upper / 10, buf);
+ if (out[-2] != buf[0]) {
+ out[-2] = '0' + (upper + lower + 100) / 200;
+ --out;
+ } else {
+ PutTwoDigits((upper + lower + 10) / 20, out - 2);
+ }
+ *out = '\0';
+ return out;
+}
+
+// RoundTripFloatToBuffer converts the given float into a std::string which, if
+// passed to strtof, will produce the exact same original float. It does this
+// by computing the range of possible doubles which map to the given float, and
+// then examining the digits of the doubles in that range. If all the doubles
+// in the range start with "2.37", then clearly our float does, too. As soon as
+// they diverge, only one more digit is needed.
+char* numbers_internal::RoundTripFloatToBuffer(float f, char* buffer) {
+ static_assert(std::numeric_limits<float>::is_iec559,
+ "IEEE-754/IEC-559 support only");
+
+ char* out = buffer; // we write data to out, incrementing as we go, but
+ // FloatToBuffer always returns the address of the buffer
+ // passed in.
+
+ if (std::isnan(f)) {
+ strcpy(out, "nan"); // NOLINT(runtime/printf)
+ return buffer;
+ }
+ if (f == 0) { // +0 and -0 are handled here
+ if (std::signbit(f)) {
+ strcpy(out, "-0"); // NOLINT(runtime/printf)
+ } else {
+ strcpy(out, "0"); // NOLINT(runtime/printf)
+ }
+ return buffer;
+ }
+ if (f < 0) {
+ *out++ = '-';
+ f = -f;
+ }
+ if (std::isinf(f)) {
+ strcpy(out, "inf"); // NOLINT(runtime/printf)
+ return buffer;
+ }
+
+ double next_lower = nextafterf(f, 0.0f);
+ // For all doubles in the range lower_bound < f < upper_bound, the
+ // nearest float is f.
+ double lower_bound = (f + next_lower) * 0.5;
+ double upper_bound = f + (f - lower_bound);
+ // Note: because std::nextafter is slow, we calculate upper_bound
+ // assuming that it is the same distance from f as lower_bound is.
+ // For exact powers of two, upper_bound is actually twice as far
+ // from f as lower_bound is, but this turns out not to matter.
+
+ // Most callers pass floats that are either 0 or within the
+ // range 0.0001 through 100,000,000, so handle those first,
+ // since they don't need exponential notation.
+ const Spec* spec = nullptr;
+ if (f < 1.0) {
+ if (f >= 0.0001f) {
+ // for fractional values, we set up the multiplier at the same
+ // time as we output the leading "0." / "0.0" / "0.00" / "0.000"
+ double multiplier = 1e+11;
+ *out++ = '0';
+ *out++ = '.';
+ if (f < 0.1f) {
+ multiplier = 1e+12;
+ *out++ = '0';
+ if (f < 0.01f) {
+ multiplier = 1e+13;
+ *out++ = '0';
+ if (f < 0.001f) {
+ multiplier = 1e+14;
+ *out++ = '0';
+ }
+ }
+ }
+ OutputNecessaryDigits(lower_bound * multiplier, upper_bound * multiplier,
+ out);
+ return buffer;
+ }
+ spec = std::lower_bound(std::begin(neg_exp_table), std::end(neg_exp_table),
+ double{f}, ExpCompare());
+ if (spec == std::end(neg_exp_table)) --spec;
+ } else if (f < 1e8) {
+ // Handling non-exponential format greater than 1.0 is similar to the above,
+ // but instead of 0.0 / 0.00 / 0.000, the prefix is simply the truncated
+ // integer part of f.
+ int32_t as_int = f;
+ out = numbers_internal::FastUInt32ToBuffer(as_int, out);
+ // Easy: if the integer part is within (lower_bound, upper_bound), then we
+ // are already done.
+ if (as_int > lower_bound && as_int < upper_bound) {
+ return buffer;
+ }
+ *out++ = '.';
+ OutputNecessaryDigits((lower_bound - as_int) * 1e11,
+ (upper_bound - as_int) * 1e11, out);
+ return buffer;
+ } else {
+ spec = std::lower_bound(std::begin(pos_exp_table),
+ std::end(pos_exp_table),
+ double{f}, ExpCompare());
+ if (spec == std::end(pos_exp_table)) --spec;
+ }
+ // Exponential notation from here on. "spec" was computed using lower_bound,
+ // which means it's the first spec from the table where min_range is greater
+ // or equal to f.
+ // Unfortunately that's not quite what we want; we want a min_range that is
+ // less or equal. So first thing, if it was greater, back up one entry.
+ if (spec->min_range > f) --spec;
+
+ // The digits might be "237000123", but we want "2.37000123",
+ // so we output the digits one character later, and then move the first
+ // digit back so we can stick the "." in.
+ char* start = out;
+ out = OutputNecessaryDigits(lower_bound * spec->multiplier,
+ upper_bound * spec->multiplier, start + 1);
+ start[0] = start[1];
+ start[1] = '.';
+
+ // If it turns out there was only one digit output, then back up over the '.'
+ if (out == &start[2]) --out;
+
+ // Now add the "e+NN" part.
+ memcpy(out, spec->expstr, 4);
+ out[4] = '\0';
+ return buffer;
+}
+
+// Returns the number of leading 0 bits in a 64-bit value.
+// TODO(jorg): Replace with builtin_clzll if available.
+// Are we shipping util/bits in absl?
+static inline int CountLeadingZeros64(uint64_t n) {
+ int zeroes = 60;
+ if (n >> 32) zeroes -= 32, n >>= 32;
+ if (n >> 16) zeroes -= 16, n >>= 16;
+ if (n >> 8) zeroes -= 8, n >>= 8;
+ if (n >> 4) zeroes -= 4, n >>= 4;
+ return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0\0"[n] + zeroes;
+}
+
+// Given a 128-bit number expressed as a pair of uint64_t, high half first,
+// return that number multiplied by the given 32-bit value. If the result is
+// too large to fit in a 128-bit number, divide it by 2 until it fits.
+static std::pair<uint64_t, uint64_t> Mul32(std::pair<uint64_t, uint64_t> num,
+ uint32_t mul) {
+ uint64_t bits0_31 = num.second & 0xFFFFFFFF;
+ uint64_t bits32_63 = num.second >> 32;
+ uint64_t bits64_95 = num.first & 0xFFFFFFFF;
+ uint64_t bits96_127 = num.first >> 32;
+
+ // The picture so far: each of these 64-bit values has only the lower 32 bits
+ // filled in.
+ // bits96_127: [ 00000000 xxxxxxxx ]
+ // bits64_95: [ 00000000 xxxxxxxx ]
+ // bits32_63: [ 00000000 xxxxxxxx ]
+ // bits0_31: [ 00000000 xxxxxxxx ]
+
+ bits0_31 *= mul;
+ bits32_63 *= mul;
+ bits64_95 *= mul;
+ bits96_127 *= mul;
+
+ // Now the top halves may also have value, though all 64 of their bits will
+ // never be set at the same time, since they are a result of a 32x32 bit
+ // multiply. This makes the carry calculation slightly easier.
+ // bits96_127: [ mmmmmmmm | mmmmmmmm ]
+ // bits64_95: [ | mmmmmmmm mmmmmmmm | ]
+ // bits32_63: | [ mmmmmmmm | mmmmmmmm ]
+ // bits0_31: | [ | mmmmmmmm mmmmmmmm ]
+ // eventually: [ bits128_up | ...bits64_127.... | ..bits0_63... ]
+
+ uint64_t bits0_63 = bits0_31 + (bits32_63 << 32);
+ uint64_t bits64_127 = bits64_95 + (bits96_127 << 32) + (bits32_63 >> 32) +
+ (bits0_63 < bits0_31);
+ uint64_t bits128_up = (bits96_127 >> 32) + (bits64_127 < bits64_95);
+ if (bits128_up == 0) return {bits64_127, bits0_63};
+
+ int shift = 64 - CountLeadingZeros64(bits128_up);
+ uint64_t lo = (bits0_63 >> shift) + (bits64_127 << (64 - shift));
+ uint64_t hi = (bits64_127 >> shift) + (bits128_up << (64 - shift));
+ return {hi, lo};
+}
+
+// Compute num * 5 ^ expfive, and return the first 128 bits of the result,
+// where the first bit is always a one. So PowFive(1, 0) starts 0b100000,
+// PowFive(1, 1) starts 0b101000, PowFive(1, 2) starts 0b110010, etc.
+static std::pair<uint64_t, uint64_t> PowFive(uint64_t num, int expfive) {
+ std::pair<uint64_t, uint64_t> result = {num, 0};
+ while (expfive >= 13) {
+ // 5^13 is the highest power of five that will fit in a 32-bit integer.
+ result = Mul32(result, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5);
+ expfive -= 13;
+ }
+ constexpr int powers_of_five[13] = {
+ 1,
+ 5,
+ 5 * 5,
+ 5 * 5 * 5,
+ 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5};
+ result = Mul32(result, powers_of_five[expfive & 15]);
+ int shift = CountLeadingZeros64(result.first);
+ if (shift != 0) {
+ result.first = (result.first << shift) + (result.second >> (64 - shift));
+ result.second = (result.second << shift);
+ }
+ return result;
+}
+
+struct ExpDigits {
+ int32_t exponent;
+ char digits[6];
+};
+
+// SplitToSix converts value, a positive double-precision floating-point number,
+// into a base-10 exponent and 6 ASCII digits, where the first digit is never
+// zero. For example, SplitToSix(1) returns an exponent of zero and a digits
+// array of {'1', '0', '0', '0', '0', '0'}. If value is exactly halfway between
+// two possible representations, e.g. value = 100000.5, then "round to even" is
+// performed.
+static ExpDigits SplitToSix(const double value) {
+ ExpDigits exp_dig;
+ int exp = 5;
+ double d = value;
+ // First step: calculate a close approximation of the output, where the
+ // value d will be between 100,000 and 999,999, representing the digits
+ // in the output ASCII array, and exp is the base-10 exponent. It would be
+ // faster to use a table here, and to look up the base-2 exponent of value,
+ // however value is an IEEE-754 64-bit number, so the table would have 2,000
+ // entries, which is not cache-friendly.
+ if (d >= 999999.5) {
+ if (d >= 1e+261) exp += 256, d *= 1e-256;
+ if (d >= 1e+133) exp += 128, d *= 1e-128;
+ if (d >= 1e+69) exp += 64, d *= 1e-64;
+ if (d >= 1e+37) exp += 32, d *= 1e-32;
+ if (d >= 1e+21) exp += 16, d *= 1e-16;
+ if (d >= 1e+13) exp += 8, d *= 1e-8;
+ if (d >= 1e+9) exp += 4, d *= 1e-4;
+ if (d >= 1e+7) exp += 2, d *= 1e-2;
+ if (d >= 1e+6) exp += 1, d *= 1e-1;
+ } else {
+ if (d < 1e-250) exp -= 256, d *= 1e256;
+ if (d < 1e-122) exp -= 128, d *= 1e128;
+ if (d < 1e-58) exp -= 64, d *= 1e64;
+ if (d < 1e-26) exp -= 32, d *= 1e32;
+ if (d < 1e-10) exp -= 16, d *= 1e16;
+ if (d < 1e-2) exp -= 8, d *= 1e8;
+ if (d < 1e+2) exp -= 4, d *= 1e4;
+ if (d < 1e+4) exp -= 2, d *= 1e2;
+ if (d < 1e+5) exp -= 1, d *= 1e1;
+ }
+ // At this point, d is in the range [99999.5..999999.5) and exp is in the
+ // range [-324..308]. Since we need to round d up, we want to add a half
+ // and truncate.
+ // However, the technique above may have lost some precision, due to its
+ // repeated multiplication by constants that each may be off by half a bit
+ // of precision. This only matters if we're close to the edge though.
+ // Since we'd like to know if the fractional part of d is close to a half,
+ // we multiply it by 65536 and see if the fractional part is close to 32768.
+ // (The number doesn't have to be a power of two,but powers of two are faster)
+ uint64_t d64k = d * 65536;
+ int dddddd; // A 6-digit decimal integer.
+ if ((d64k % 65536) == 32767 || (d64k % 65536) == 32768) {
+ // OK, it's fairly likely that precision was lost above, which is
+ // not a surprise given only 52 mantissa bits are available. Therefore
+ // redo the calculation using 128-bit numbers. (64 bits are not enough).
+
+ // Start out with digits rounded down; maybe add one below.
+ dddddd = static_cast<int>(d64k / 65536);
+
+ // mantissa is a 64-bit integer representing M.mmm... * 2^63. The actual
+ // value we're representing, of course, is M.mmm... * 2^exp2.
+ int exp2;
+ double m = std::frexp(value, &exp2);
+ uint64_t mantissa = m * (32768.0 * 65536.0 * 65536.0 * 65536.0);
+ // std::frexp returns an m value in the range [0.5, 1.0), however we
+ // can't multiply it by 2^64 and convert to an integer because some FPUs
+ // throw an exception when converting an number higher than 2^63 into an
+ // integer - even an unsigned 64-bit integer! Fortunately it doesn't matter
+ // since m only has 52 significant bits anyway.
+ mantissa <<= 1;
+ exp2 -= 64; // not needed, but nice for debugging
+
+ // OK, we are here to compare:
+ // (dddddd + 0.5) * 10^(exp-5) vs. mantissa * 2^exp2
+ // so we can round up dddddd if appropriate. Those values span the full
+ // range of 600 orders of magnitude of IEE 64-bit floating-point.
+ // Fortunately, we already know they are very close, so we don't need to
+ // track the base-2 exponent of both sides. This greatly simplifies the
+ // the math since the 2^exp2 calculation is unnecessary and the power-of-10
+ // calculation can become a power-of-5 instead.
+
+ std::pair<uint64_t, uint64_t> edge, val;
+ if (exp >= 6) {
+ // Compare (dddddd + 0.5) * 5 ^ (exp - 5) to mantissa
+ // Since we're tossing powers of two, 2 * dddddd + 1 is the
+ // same as dddddd + 0.5
+ edge = PowFive(2 * dddddd + 1, exp - 5);
+
+ val.first = mantissa;
+ val.second = 0;
+ } else {
+ // We can't compare (dddddd + 0.5) * 5 ^ (exp - 5) to mantissa as we did
+ // above because (exp - 5) is negative. So we compare (dddddd + 0.5) to
+ // mantissa * 5 ^ (5 - exp)
+ edge = PowFive(2 * dddddd + 1, 0);
+
+ val = PowFive(mantissa, 5 - exp);
+ }
+ // printf("exp=%d %016lx %016lx vs %016lx %016lx\n", exp, val.first,
+ // val.second, edge.first, edge.second);
+ if (val > edge) {
+ dddddd++;
+ } else if (val == edge) {
+ dddddd += (dddddd & 1);
+ }
+ } else {
+ // Here, we are not close to the edge.
+ dddddd = static_cast<int>((d64k + 32768) / 65536);
+ }
+ if (dddddd == 1000000) {
+ dddddd = 100000;
+ exp += 1;
+ }
+ exp_dig.exponent = exp;
+
+ int two_digits = dddddd / 10000;
+ dddddd -= two_digits * 10000;
+ PutTwoDigits(two_digits, &exp_dig.digits[0]);
+
+ two_digits = dddddd / 100;
+ dddddd -= two_digits * 100;
+ PutTwoDigits(two_digits, &exp_dig.digits[2]);
+
+ PutTwoDigits(dddddd, &exp_dig.digits[4]);
+ return exp_dig;
+}
+
+// Helper function for fast formatting of floating-point.
+// The result is the same as "%g", a.k.a. "%.6g".
+size_t numbers_internal::SixDigitsToBuffer(double d, char* const buffer) {
+ static_assert(std::numeric_limits<float>::is_iec559,
+ "IEEE-754/IEC-559 support only");
+
+ char* out = buffer; // we write data to out, incrementing as we go, but
+ // FloatToBuffer always returns the address of the buffer
+ // passed in.
+
+ if (std::isnan(d)) {
+ strcpy(out, "nan"); // NOLINT(runtime/printf)
+ return 3;
+ }
+ if (d == 0) { // +0 and -0 are handled here
+ if (std::signbit(d)) *out++ = '-';
+ *out++ = '0';
+ *out = 0;
+ return out - buffer;
+ }
+ if (d < 0) {
+ *out++ = '-';
+ d = -d;
+ }
+ if (std::isinf(d)) {
+ strcpy(out, "inf"); // NOLINT(runtime/printf)
+ return out + 3 - buffer;
+ }
+
+ auto exp_dig = SplitToSix(d);
+ int exp = exp_dig.exponent;
+ const char* digits = exp_dig.digits;
+ out[0] = '0';
+ out[1] = '.';
+ switch (exp) {
+ case 5:
+ memcpy(out, &digits[0], 6), out += 6;
+ *out = 0;
+ return out - buffer;
+ case 4:
+ memcpy(out, &digits[0], 5), out += 5;
+ if (digits[5] != '0') {
+ *out++ = '.';
+ *out++ = digits[5];
+ }
+ *out = 0;
+ return out - buffer;
+ case 3:
+ memcpy(out, &digits[0], 4), out += 4;
+ if ((digits[5] | digits[4]) != '0') {
+ *out++ = '.';
+ *out++ = digits[4];
+ if (digits[5] != '0') *out++ = digits[5];
+ }
+ *out = 0;
+ return out - buffer;
+ case 2:
+ memcpy(out, &digits[0], 3), out += 3;
+ *out++ = '.';
+ memcpy(out, &digits[3], 3);
+ out += 3;
+ while (out[-1] == '0') --out;
+ if (out[-1] == '.') --out;
+ *out = 0;
+ return out - buffer;
+ case 1:
+ memcpy(out, &digits[0], 2), out += 2;
+ *out++ = '.';
+ memcpy(out, &digits[2], 4);
+ out += 4;
+ while (out[-1] == '0') --out;
+ if (out[-1] == '.') --out;
+ *out = 0;
+ return out - buffer;
+ case 0:
+ memcpy(out, &digits[0], 1), out += 1;
+ *out++ = '.';
+ memcpy(out, &digits[1], 5);
+ out += 5;
+ while (out[-1] == '0') --out;
+ if (out[-1] == '.') --out;
+ *out = 0;
+ return out - buffer;
+ case -4:
+ out[2] = '0';
+ ++out;
+ ABSL_FALLTHROUGH_INTENDED;
+ case -3:
+ out[2] = '0';
+ ++out;
+ ABSL_FALLTHROUGH_INTENDED;
+ case -2:
+ out[2] = '0';
+ ++out;
+ ABSL_FALLTHROUGH_INTENDED;
+ case -1:
+ out += 2;
+ memcpy(out, &digits[0], 6);
+ out += 6;
+ while (out[-1] == '0') --out;
+ *out = 0;
+ return out - buffer;
+ }
+ assert(exp < -4 || exp >= 6);
+ out[0] = digits[0];
+ assert(out[1] == '.');
+ out += 2;
+ memcpy(out, &digits[1], 5), out += 5;
+ while (out[-1] == '0') --out;
+ if (out[-1] == '.') --out;
+ *out++ = 'e';
+ if (exp > 0) {
+ *out++ = '+';
+ } else {
+ *out++ = '-';
+ exp = -exp;
+ }
+ if (exp > 99) {
+ int dig1 = exp / 100;
+ exp -= dig1 * 100;
+ *out++ = '0' + dig1;
+ }
+ PutTwoDigits(exp, out);
+ out += 2;
+ *out = 0;
+ return out - buffer;
+}
+
+namespace {
+// Represents integer values of digits.
+// Uses 36 to indicate an invalid character since we support
+// bases up to 36.
+static const int8_t kAsciiToInt[256] = {
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, // 16 36s.
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 36, 36, 36, 36, 36, 36, 36, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 36, 36, 36, 36, 36, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36};
+
+// Parse the sign and optional hex or oct prefix in text.
+inline bool safe_parse_sign_and_base(absl::string_view* text /*inout*/,
+ int* base_ptr /*inout*/,
+ bool* negative_ptr /*output*/) {
+ if (text->data() == nullptr) {
+ return false;
+ }
+
+ const char* start = text->data();
+ const char* end = start + text->size();
+ int base = *base_ptr;
+
+ // Consume whitespace.
+ while (start < end && absl::ascii_isspace(start[0])) {
+ ++start;
+ }
+ while (start < end && absl::ascii_isspace(end[-1])) {
+ --end;
+ }
+ if (start >= end) {
+ return false;
+ }
+
+ // Consume sign.
+ *negative_ptr = (start[0] == '-');
+ if (*negative_ptr || start[0] == '+') {
+ ++start;
+ if (start >= end) {
+ return false;
+ }
+ }
+
+ // Consume base-dependent prefix.
+ // base 0: "0x" -> base 16, "0" -> base 8, default -> base 10
+ // base 16: "0x" -> base 16
+ // Also validate the base.
+ if (base == 0) {
+ if (end - start >= 2 && start[0] == '0' &&
+ (start[1] == 'x' || start[1] == 'X')) {
+ base = 16;
+ start += 2;
+ if (start >= end) {
+ // "0x" with no digits after is invalid.
+ return false;
+ }
+ } else if (end - start >= 1 && start[0] == '0') {
+ base = 8;
+ start += 1;
+ } else {
+ base = 10;
+ }
+ } else if (base == 16) {
+ if (end - start >= 2 && start[0] == '0' &&
+ (start[1] == 'x' || start[1] == 'X')) {
+ start += 2;
+ if (start >= end) {
+ // "0x" with no digits after is invalid.
+ return false;
+ }
+ }
+ } else if (base >= 2 && base <= 36) {
+ // okay
+ } else {
+ return false;
+ }
+ *text = absl::string_view(start, end - start);
+ *base_ptr = base;
+ return true;
+}
+
+// Consume digits.
+//
+// The classic loop:
+//
+// for each digit
+// value = value * base + digit
+// value *= sign
+//
+// The classic loop needs overflow checking. It also fails on the most
+// negative integer, -2147483648 in 32-bit two's complement representation.
+//
+// My improved loop:
+//
+// if (!negative)
+// for each digit
+// value = value * base
+// value = value + digit
+// else
+// for each digit
+// value = value * base
+// value = value - digit
+//
+// Overflow checking becomes simple.
+
+// Lookup tables per IntType:
+// vmax/base and vmin/base are precomputed because division costs at least 8ns.
+// TODO(junyer): Doing this per base instead (i.e. an array of structs, not a
+// struct of arrays) would probably be better in terms of d-cache for the most
+// commonly used bases.
+template <typename IntType>
+struct LookupTables {
+ static const IntType kVmaxOverBase[];
+ static const IntType kVminOverBase[];
+};
+
+// An array initializer macro for X/base where base in [0, 36].
+// However, note that lookups for base in [0, 1] should never happen because
+// base has been validated to be in [2, 36] by safe_parse_sign_and_base().
+#define X_OVER_BASE_INITIALIZER(X) \
+ { \
+ 0, 0, X / 2, X / 3, X / 4, X / 5, X / 6, X / 7, X / 8, X / 9, X / 10, \
+ X / 11, X / 12, X / 13, X / 14, X / 15, X / 16, X / 17, X / 18, \
+ X / 19, X / 20, X / 21, X / 22, X / 23, X / 24, X / 25, X / 26, \
+ X / 27, X / 28, X / 29, X / 30, X / 31, X / 32, X / 33, X / 34, \
+ X / 35, X / 36, \
+ }
+
+template <typename IntType>
+const IntType LookupTables<IntType>::kVmaxOverBase[] =
+ X_OVER_BASE_INITIALIZER(std::numeric_limits<IntType>::max());
+
+template <typename IntType>
+const IntType LookupTables<IntType>::kVminOverBase[] =
+ X_OVER_BASE_INITIALIZER(std::numeric_limits<IntType>::min());
+
+#undef X_OVER_BASE_INITIALIZER
+
+template <typename IntType>
+inline bool safe_parse_positive_int(absl::string_view text, int base,
+ IntType* value_p) {
+ IntType value = 0;
+ const IntType vmax = std::numeric_limits<IntType>::max();
+ assert(vmax > 0);
+ assert(base >= 0);
+ assert(vmax >= static_cast<IntType>(base));
+ const IntType vmax_over_base = LookupTables<IntType>::kVmaxOverBase[base];
+ const char* start = text.data();
+ const char* end = start + text.size();
+ // loop over digits
+ for (; start < end; ++start) {
+ unsigned char c = static_cast<unsigned char>(start[0]);
+ int digit = kAsciiToInt[c];
+ if (digit >= base) {
+ *value_p = value;
+ return false;
+ }
+ if (value > vmax_over_base) {
+ *value_p = vmax;
+ return false;
+ }
+ value *= base;
+ if (value > vmax - digit) {
+ *value_p = vmax;
+ return false;
+ }
+ value += digit;
+ }
+ *value_p = value;
+ return true;
+}
+
+template <typename IntType>
+inline bool safe_parse_negative_int(absl::string_view text, int base,
+ IntType* value_p) {
+ IntType value = 0;
+ const IntType vmin = std::numeric_limits<IntType>::min();
+ assert(vmin < 0);
+ assert(vmin <= 0 - base);
+ IntType vmin_over_base = LookupTables<IntType>::kVminOverBase[base];
+ // 2003 c++ standard [expr.mul]
+ // "... the sign of the remainder is implementation-defined."
+ // Although (vmin/base)*base + vmin%base is always vmin.
+ // 2011 c++ standard tightens the spec but we cannot rely on it.
+ // TODO(junyer): Handle this in the lookup table generation.
+ if (vmin % base > 0) {
+ vmin_over_base += 1;
+ }
+ const char* start = text.data();
+ const char* end = start + text.size();
+ // loop over digits
+ for (; start < end; ++start) {
+ unsigned char c = static_cast<unsigned char>(start[0]);
+ int digit = kAsciiToInt[c];
+ if (digit >= base) {
+ *value_p = value;
+ return false;
+ }
+ if (value < vmin_over_base) {
+ *value_p = vmin;
+ return false;
+ }
+ value *= base;
+ if (value < vmin + digit) {
+ *value_p = vmin;
+ return false;
+ }
+ value -= digit;
+ }
+ *value_p = value;
+ return true;
+}
+
+// Input format based on POSIX.1-2008 strtol
+// http://pubs.opengroup.org/onlinepubs/9699919799/functions/strtol.html
+template <typename IntType>
+inline bool safe_int_internal(absl::string_view text, IntType* value_p,
+ int base) {
+ *value_p = 0;
+ bool negative;
+ if (!safe_parse_sign_and_base(&text, &base, &negative)) {
+ return false;
+ }
+ if (!negative) {
+ return safe_parse_positive_int(text, base, value_p);
+ } else {
+ return safe_parse_negative_int(text, base, value_p);
+ }
+}
+
+template <typename IntType>
+inline bool safe_uint_internal(absl::string_view text, IntType* value_p,
+ int base) {
+ *value_p = 0;
+ bool negative;
+ if (!safe_parse_sign_and_base(&text, &base, &negative) || negative) {
+ return false;
+ }
+ return safe_parse_positive_int(text, base, value_p);
+}
+} // anonymous namespace
+
+namespace numbers_internal {
+bool safe_strto32_base(absl::string_view text, int32_t* value, int base) {
+ return safe_int_internal<int32_t>(text, value, base);
+}
+
+bool safe_strto64_base(absl::string_view text, int64_t* value, int base) {
+ return safe_int_internal<int64_t>(text, value, base);
+}
+
+bool safe_strtou32_base(absl::string_view text, uint32_t* value, int base) {
+ return safe_uint_internal<uint32_t>(text, value, base);
+}
+
+bool safe_strtou64_base(absl::string_view text, uint64_t* value, int base) {
+ return safe_uint_internal<uint64_t>(text, value, base);
+}
+} // namespace numbers_internal
+
+} // namespace absl
diff --git a/absl/strings/numbers.h b/absl/strings/numbers.h
new file mode 100644
index 0000000..f17dc97
--- /dev/null
+++ b/absl/strings/numbers.h
@@ -0,0 +1,173 @@
+//
+// 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: numbers.h
+// -----------------------------------------------------------------------------
+//
+// This package contains functions for converting strings to numbers. For
+// converting numbers to strings, use `StrCat()` or `StrAppend()` in str_cat.h,
+// which automatically detect and convert most number values appropriately.
+
+#ifndef ABSL_STRINGS_NUMBERS_H_
+#define ABSL_STRINGS_NUMBERS_H_
+
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <limits>
+#include <string>
+#include <type_traits>
+
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/numeric/int128.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+
+// SimpleAtoi()
+//
+// Converts the given std::string into an integer value, returning `true` if
+// successful. The std::string must reflect a base-10 integer (optionally followed or
+// preceded by ASCII whitespace) whose value falls within the range of the
+// integer type,
+template <typename int_type>
+ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view s, int_type* out);
+
+// SimpleAtof()
+//
+// Converts the given std::string (optionally followed or preceded by ASCII
+// whitespace) into a float, which may be rounded on overflow or underflow.
+ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str, float* value);
+
+// SimpleAtod()
+//
+// Converts the given std::string (optionally followed or preceded by ASCII
+// whitespace) into a double, which may be rounded on overflow or underflow.
+ABSL_MUST_USE_RESULT bool SimpleAtod(absl::string_view str, double* value);
+
+// SimpleAtob()
+//
+// Converts the given std::string into into a boolean, returning `true` if
+// successful. The following case-insensitive strings are interpreted as boolean
+// `true`: "true", "t", "yes", "y", "1". The following case-insensitive strings
+// are interpreted as boolean `false`: "false", "f", "no", "n", "0".
+ABSL_MUST_USE_RESULT bool SimpleAtob(absl::string_view str, bool* value);
+
+} // namespace absl
+
+// End of public API. Implementation details follow.
+
+namespace absl {
+namespace numbers_internal {
+
+// safe_strto?() functions for implementing SimpleAtoi()
+bool safe_strto32_base(absl::string_view text, int32_t* value, int base);
+bool safe_strto64_base(absl::string_view text, int64_t* value, int base);
+bool safe_strtou32_base(absl::string_view text, uint32_t* value, int base);
+bool safe_strtou64_base(absl::string_view text, uint64_t* value, int base);
+
+// These functions are intended for speed. All functions take an output buffer
+// as an argument and return a pointer to the last byte they wrote, which is the
+// terminating '\0'. At most `kFastToBufferSize` bytes are written.
+char* FastInt32ToBuffer(int32_t i, char* buffer);
+char* FastUInt32ToBuffer(uint32_t i, char* buffer);
+char* FastInt64ToBuffer(int64_t i, char* buffer);
+char* FastUInt64ToBuffer(uint64_t i, char* buffer);
+
+static const int kFastToBufferSize = 32;
+static const int kSixDigitsToBufferSize = 16;
+
+char* RoundTripDoubleToBuffer(double d, char* buffer);
+char* RoundTripFloatToBuffer(float f, char* buffer);
+
+// Helper function for fast formatting of floating-point values.
+// The result is the same as printf's "%g", a.k.a. "%.6g"; that is, six
+// significant digits are returned, trailing zeros are removed, and numbers
+// outside the range 0.0001-999999 are output using scientific notation
+// (1.23456e+06). This routine is heavily optimized.
+// Required buffer size is `kSixDigitsToBufferSize`.
+size_t SixDigitsToBuffer(double d, char* buffer);
+
+template <typename int_type>
+char* FastIntToBuffer(int_type i, char* buffer) {
+ static_assert(sizeof(i) <= 64 / 8,
+ "FastIntToBuffer works only with 64-bit-or-less integers.");
+ // TODO(jorg): This signed-ness check is used because it works correctly
+ // with enums, and it also serves to check that int_type is not a pointer.
+ // If one day something like std::is_signed<enum E> works, switch to it.
+ if (static_cast<int_type>(1) - 2 < 0) { // Signed
+ if (sizeof(i) > 32 / 8) { // 33-bit to 64-bit
+ return numbers_internal::FastInt64ToBuffer(i, buffer);
+ } else { // 32-bit or less
+ return numbers_internal::FastInt32ToBuffer(i, buffer);
+ }
+ } else { // Unsigned
+ if (sizeof(i) > 32 / 8) { // 33-bit to 64-bit
+ return numbers_internal::FastUInt64ToBuffer(i, buffer);
+ } else { // 32-bit or less
+ return numbers_internal::FastUInt32ToBuffer(i, buffer);
+ }
+ }
+}
+
+} // namespace numbers_internal
+
+// SimpleAtoi()
+//
+// Converts a std::string to an integer, using `safe_strto?()` functions for actual
+// parsing, returning `true` if successful. The `safe_strto?()` functions apply
+// strict checking; the std::string must be a base-10 integer, optionally followed or
+// preceded by ASCII whitespace, with a value in the range of the corresponding
+// integer type.
+template <typename int_type>
+ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view s, int_type* out) {
+ static_assert(sizeof(*out) == 4 || sizeof(*out) == 8,
+ "SimpleAtoi works only with 32-bit or 64-bit integers.");
+ static_assert(!std::is_floating_point<int_type>::value,
+ "Use SimpleAtof or SimpleAtod instead.");
+ bool parsed;
+ // TODO(jorg): This signed-ness check is used because it works correctly
+ // with enums, and it also serves to check that int_type is not a pointer.
+ // If one day something like std::is_signed<enum E> works, switch to it.
+ if (static_cast<int_type>(1) - 2 < 0) { // Signed
+ if (sizeof(*out) == 64 / 8) { // 64-bit
+ int64_t val;
+ parsed = numbers_internal::safe_strto64_base(s, &val, 10);
+ *out = static_cast<int_type>(val);
+ } else { // 32-bit
+ int32_t val;
+ parsed = numbers_internal::safe_strto32_base(s, &val, 10);
+ *out = static_cast<int_type>(val);
+ }
+ } else { // Unsigned
+ if (sizeof(*out) == 64 / 8) { // 64-bit
+ uint64_t val;
+ parsed = numbers_internal::safe_strtou64_base(s, &val, 10);
+ *out = static_cast<int_type>(val);
+ } else { // 32-bit
+ uint32_t val;
+ parsed = numbers_internal::safe_strtou32_base(s, &val, 10);
+ *out = static_cast<int_type>(val);
+ }
+ }
+ return parsed;
+}
+
+} // namespace absl
+
+#endif // ABSL_STRINGS_NUMBERS_H_
diff --git a/absl/strings/numbers_test.cc b/absl/strings/numbers_test.cc
new file mode 100644
index 0000000..9b74d67
--- /dev/null
+++ b/absl/strings/numbers_test.cc
@@ -0,0 +1,1186 @@
+// This file tests std::string processing functions related to numeric values.
+
+#include "absl/strings/numbers.h"
+
+#include <sys/types.h>
+#include <algorithm>
+#include <cctype>
+#include <cfenv> // NOLINT(build/c++11)
+#include <cfloat>
+#include <cinttypes>
+#include <climits>
+#include <cmath>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <limits>
+#include <numeric>
+#include <random>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/port.h"
+#include "absl/strings/str_cat.h"
+
+#include "absl/strings/internal/numbers_test_common.inc"
+
+namespace {
+
+using absl::numbers_internal::FastInt32ToBuffer;
+using absl::numbers_internal::FastInt64ToBuffer;
+using absl::numbers_internal::FastUInt32ToBuffer;
+using absl::numbers_internal::FastUInt64ToBuffer;
+using absl::numbers_internal::kFastToBufferSize;
+using absl::numbers_internal::kSixDigitsToBufferSize;
+using absl::numbers_internal::safe_strto32_base;
+using absl::numbers_internal::safe_strto64_base;
+using absl::numbers_internal::safe_strtou32_base;
+using absl::numbers_internal::safe_strtou64_base;
+using absl::numbers_internal::RoundTripFloatToBuffer;
+using absl::numbers_internal::SixDigitsToBuffer;
+using absl::SimpleAtoi;
+using testing::Eq;
+using testing::MatchesRegex;
+
+// Number of floats to test with.
+// 10,000,000 is a reasonable default for a test that only takes a few seconds.
+// 1,000,000,000+ triggers checking for all possible mantissa values for
+// double-precision tests. 2,000,000,000+ triggers checking for every possible
+// single-precision float.
+#ifdef _MSC_VER
+// Use a smaller number on MSVC to avoid test time out (1 min)
+const int kFloatNumCases = 5000000;
+#else
+const int kFloatNumCases = 10000000;
+#endif
+
+// This is a slow, brute-force routine to compute the exact base-10
+// representation of a double-precision floating-point number. It
+// is useful for debugging only.
+std::string PerfectDtoa(double d) {
+ if (d == 0) return "0";
+ if (d < 0) return "-" + PerfectDtoa(-d);
+
+ // Basic theory: decompose d into mantissa and exp, where
+ // d = mantissa * 2^exp, and exp is as close to zero as possible.
+ int64_t mantissa, exp = 0;
+ while (d >= 1ULL << 63) ++exp, d *= 0.5;
+ while ((mantissa = d) != d) --exp, d *= 2.0;
+
+ // Then convert mantissa to ASCII, and either double it (if
+ // exp > 0) or halve it (if exp < 0) repeatedly. "halve it"
+ // in this case means multiplying it by five and dividing by 10.
+ constexpr int maxlen = 1100; // worst case is actually 1030 or so.
+ char buf[maxlen + 5];
+ for (int64_t num = mantissa, pos = maxlen; --pos >= 0;) {
+ buf[pos] = '0' + (num % 10);
+ num /= 10;
+ }
+ char* begin = &buf[0];
+ char* end = buf + maxlen;
+ for (int i = 0; i != exp; i += (exp > 0) ? 1 : -1) {
+ int carry = 0;
+ for (char* p = end; --p != begin;) {
+ int dig = *p - '0';
+ dig = dig * (exp > 0 ? 2 : 5) + carry;
+ carry = dig / 10;
+ dig %= 10;
+ *p = '0' + dig;
+ }
+ }
+ if (exp < 0) {
+ // "dividing by 10" above means we have to add the decimal point.
+ memmove(end + 1 + exp, end + exp, 1 - exp);
+ end[exp] = '.';
+ ++end;
+ }
+ while (*begin == '0' && begin[1] != '.') ++begin;
+ return {begin, end};
+}
+
+TEST(ToString, PerfectDtoa) {
+ EXPECT_THAT(PerfectDtoa(1), Eq("1"));
+ EXPECT_THAT(PerfectDtoa(0.1),
+ Eq("0.1000000000000000055511151231257827021181583404541015625"));
+ EXPECT_THAT(PerfectDtoa(1e24), Eq("999999999999999983222784"));
+ EXPECT_THAT(PerfectDtoa(5e-324), MatchesRegex("0.0000.*625"));
+ for (int i = 0; i < 100; ++i) {
+ for (double multiplier :
+ {1e-300, 1e-200, 1e-100, 0.1, 1.0, 10.0, 1e100, 1e300}) {
+ double d = multiplier * i;
+ std::string s = PerfectDtoa(d);
+ EXPECT_EQ(d, strtod(s.c_str(), nullptr));
+ }
+ }
+}
+
+void CheckInt32(int32_t x) {
+ char buffer[kFastInt32ToBufferSize];
+ char* actual = FastInt32ToBuffer(x, buffer);
+ std::string expected = std::to_string(x);
+ ASSERT_TRUE(expected == actual)
+ << "Expected \"" << expected << "\", Actual \"" << actual << "\", Input "
+ << x;
+}
+
+void CheckInt64(int64_t x) {
+ char buffer[kFastInt64ToBufferSize + 3];
+ buffer[0] = '*';
+ buffer[23] = '*';
+ buffer[24] = '*';
+ char* actual = FastInt64ToBuffer(x, &buffer[1]);
+ std::string expected = std::to_string(x);
+ ASSERT_TRUE(expected == actual)
+ << "Expected \"" << expected << "\", Actual \"" << actual << "\", Input "
+ << x;
+ ASSERT_EQ(buffer[0], '*');
+ ASSERT_EQ(buffer[23], '*');
+ ASSERT_EQ(buffer[24], '*');
+}
+
+void CheckUInt32(uint32_t x) {
+ char buffer[kFastUInt64ToBufferSize];
+ char* actual = FastUInt32ToBuffer(x, buffer);
+ std::string expected = std::to_string(x);
+ ASSERT_TRUE(expected == actual)
+ << "Expected \"" << expected << "\", Actual \"" << actual << "\", Input "
+ << x;
+}
+
+void CheckUInt64(uint64_t x) {
+ char buffer[kFastUInt64ToBufferSize + 1];
+ char* actual = FastUInt64ToBuffer(x, &buffer[1]);
+ std::string expected = std::to_string(x);
+ ASSERT_TRUE(expected == actual)
+ << "Expected \"" << expected << "\", Actual \"" << actual << "\", Input "
+ << x;
+}
+
+void CheckHex64(uint64_t v) {
+ char expected[kFastUInt64ToBufferSize];
+ std::string actual = absl::StrCat(absl::Hex(v, absl::kZeroPad16));
+ snprintf(expected, sizeof(expected), "%016" PRIx64, static_cast<uint64_t>(v));
+ ASSERT_TRUE(expected == actual)
+ << "Expected \"" << expected << "\", Actual \"" << actual << "\"";
+}
+
+void TestFastPrints() {
+ for (int i = -100; i <= 100; i++) {
+ CheckInt32(i);
+ CheckInt64(i);
+ }
+ for (int i = 0; i <= 100; i++) {
+ CheckUInt32(i);
+ CheckUInt64(i);
+ }
+ // Test min int to make sure that works
+ CheckInt32(INT_MIN);
+ CheckInt32(INT_MAX);
+ CheckInt64(LONG_MIN);
+ CheckInt64(uint64_t{1000000000});
+ CheckInt64(uint64_t{9999999999});
+ CheckInt64(uint64_t{100000000000000});
+ CheckInt64(uint64_t{999999999999999});
+ CheckInt64(uint64_t{1000000000000000000});
+ CheckInt64(uint64_t{1199999999999999999});
+ CheckInt64(int64_t{-700000000000000000});
+ CheckInt64(LONG_MAX);
+ CheckUInt32(std::numeric_limits<uint32_t>::max());
+ CheckUInt64(uint64_t{1000000000});
+ CheckUInt64(uint64_t{9999999999});
+ CheckUInt64(uint64_t{100000000000000});
+ CheckUInt64(uint64_t{999999999999999});
+ CheckUInt64(uint64_t{1000000000000000000});
+ CheckUInt64(uint64_t{1199999999999999999});
+ CheckUInt64(std::numeric_limits<uint64_t>::max());
+
+ for (int i = 0; i < 10000; i++) {
+ CheckHex64(i);
+ }
+ CheckHex64(uint64_t{0x123456789abcdef0});
+}
+
+template <typename int_type, typename in_val_type>
+void VerifySimpleAtoiGood(in_val_type in_value, int_type exp_value) {
+ std::string s = absl::StrCat(in_value);
+ int_type x = static_cast<int_type>(~exp_value);
+ EXPECT_TRUE(SimpleAtoi(s, &x))
+ << "in_value=" << in_value << " s=" << s << " x=" << x;
+ EXPECT_EQ(exp_value, x);
+ x = static_cast<int_type>(~exp_value);
+ EXPECT_TRUE(SimpleAtoi(s.c_str(), &x));
+ EXPECT_EQ(exp_value, x);
+}
+
+template <typename int_type, typename in_val_type>
+void VerifySimpleAtoiBad(in_val_type in_value) {
+ std::string s = absl::StrCat(in_value);
+ int_type x;
+ EXPECT_FALSE(SimpleAtoi(s, &x));
+ EXPECT_FALSE(SimpleAtoi(s.c_str(), &x));
+}
+
+TEST(NumbersTest, Atoi) {
+ // SimpleAtoi(absl::string_view, int32_t)
+ VerifySimpleAtoiGood<int32_t>(0, 0);
+ VerifySimpleAtoiGood<int32_t>(42, 42);
+ VerifySimpleAtoiGood<int32_t>(-42, -42);
+
+ VerifySimpleAtoiGood<int32_t>(std::numeric_limits<int32_t>::min(),
+ std::numeric_limits<int32_t>::min());
+ VerifySimpleAtoiGood<int32_t>(std::numeric_limits<int32_t>::max(),
+ std::numeric_limits<int32_t>::max());
+
+ // SimpleAtoi(absl::string_view, uint32_t)
+ VerifySimpleAtoiGood<uint32_t>(0, 0);
+ VerifySimpleAtoiGood<uint32_t>(42, 42);
+ VerifySimpleAtoiBad<uint32_t>(-42);
+
+ VerifySimpleAtoiBad<uint32_t>(std::numeric_limits<int32_t>::min());
+ VerifySimpleAtoiGood<uint32_t>(std::numeric_limits<int32_t>::max(),
+ std::numeric_limits<int32_t>::max());
+ VerifySimpleAtoiGood<uint32_t>(std::numeric_limits<uint32_t>::max(),
+ std::numeric_limits<uint32_t>::max());
+ VerifySimpleAtoiBad<uint32_t>(std::numeric_limits<int64_t>::min());
+ VerifySimpleAtoiBad<uint32_t>(std::numeric_limits<int64_t>::max());
+ VerifySimpleAtoiBad<uint32_t>(std::numeric_limits<uint64_t>::max());
+
+ // SimpleAtoi(absl::string_view, int64_t)
+ VerifySimpleAtoiGood<int64_t>(0, 0);
+ VerifySimpleAtoiGood<int64_t>(42, 42);
+ VerifySimpleAtoiGood<int64_t>(-42, -42);
+
+ VerifySimpleAtoiGood<int64_t>(std::numeric_limits<int32_t>::min(),
+ std::numeric_limits<int32_t>::min());
+ VerifySimpleAtoiGood<int64_t>(std::numeric_limits<int32_t>::max(),
+ std::numeric_limits<int32_t>::max());
+ VerifySimpleAtoiGood<int64_t>(std::numeric_limits<uint32_t>::max(),
+ std::numeric_limits<uint32_t>::max());
+ VerifySimpleAtoiGood<int64_t>(std::numeric_limits<int64_t>::min(),
+ std::numeric_limits<int64_t>::min());
+ VerifySimpleAtoiGood<int64_t>(std::numeric_limits<int64_t>::max(),
+ std::numeric_limits<int64_t>::max());
+ VerifySimpleAtoiBad<int64_t>(std::numeric_limits<uint64_t>::max());
+
+ // SimpleAtoi(absl::string_view, uint64_t)
+ VerifySimpleAtoiGood<uint64_t>(0, 0);
+ VerifySimpleAtoiGood<uint64_t>(42, 42);
+ VerifySimpleAtoiBad<uint64_t>(-42);
+
+ VerifySimpleAtoiBad<uint64_t>(std::numeric_limits<int32_t>::min());
+ VerifySimpleAtoiGood<uint64_t>(std::numeric_limits<int32_t>::max(),
+ std::numeric_limits<int32_t>::max());
+ VerifySimpleAtoiGood<uint64_t>(std::numeric_limits<uint32_t>::max(),
+ std::numeric_limits<uint32_t>::max());
+ VerifySimpleAtoiBad<uint64_t>(std::numeric_limits<int64_t>::min());
+ VerifySimpleAtoiGood<uint64_t>(std::numeric_limits<int64_t>::max(),
+ std::numeric_limits<int64_t>::max());
+ VerifySimpleAtoiGood<uint64_t>(std::numeric_limits<uint64_t>::max(),
+ std::numeric_limits<uint64_t>::max());
+
+ // Some other types
+ VerifySimpleAtoiGood<int>(-42, -42);
+ VerifySimpleAtoiGood<int32_t>(-42, -42);
+ VerifySimpleAtoiGood<uint32_t>(42, 42);
+ VerifySimpleAtoiGood<unsigned int>(42, 42);
+ VerifySimpleAtoiGood<int64_t>(-42, -42);
+ VerifySimpleAtoiGood<long>(-42, -42); // NOLINT(runtime/int)
+ VerifySimpleAtoiGood<uint64_t>(42, 42);
+ VerifySimpleAtoiGood<size_t>(42, 42);
+ VerifySimpleAtoiGood<std::string::size_type>(42, 42);
+}
+
+TEST(NumbersTest, Atoenum) {
+ enum E01 {
+ E01_zero = 0,
+ E01_one = 1,
+ };
+
+ VerifySimpleAtoiGood<E01>(E01_zero, E01_zero);
+ VerifySimpleAtoiGood<E01>(E01_one, E01_one);
+
+ enum E_101 {
+ E_101_minusone = -1,
+ E_101_zero = 0,
+ E_101_one = 1,
+ };
+
+ VerifySimpleAtoiGood<E_101>(E_101_minusone, E_101_minusone);
+ VerifySimpleAtoiGood<E_101>(E_101_zero, E_101_zero);
+ VerifySimpleAtoiGood<E_101>(E_101_one, E_101_one);
+
+ enum E_bigint {
+ E_bigint_zero = 0,
+ E_bigint_one = 1,
+ E_bigint_max31 = static_cast<int32_t>(0x7FFFFFFF),
+ };
+
+ VerifySimpleAtoiGood<E_bigint>(E_bigint_zero, E_bigint_zero);
+ VerifySimpleAtoiGood<E_bigint>(E_bigint_one, E_bigint_one);
+ VerifySimpleAtoiGood<E_bigint>(E_bigint_max31, E_bigint_max31);
+
+ enum E_fullint {
+ E_fullint_zero = 0,
+ E_fullint_one = 1,
+ E_fullint_max31 = static_cast<int32_t>(0x7FFFFFFF),
+ E_fullint_min32 = INT32_MIN,
+ };
+
+ VerifySimpleAtoiGood<E_fullint>(E_fullint_zero, E_fullint_zero);
+ VerifySimpleAtoiGood<E_fullint>(E_fullint_one, E_fullint_one);
+ VerifySimpleAtoiGood<E_fullint>(E_fullint_max31, E_fullint_max31);
+ VerifySimpleAtoiGood<E_fullint>(E_fullint_min32, E_fullint_min32);
+
+ enum E_biguint {
+ E_biguint_zero = 0,
+ E_biguint_one = 1,
+ E_biguint_max31 = static_cast<uint32_t>(0x7FFFFFFF),
+ E_biguint_max32 = static_cast<uint32_t>(0xFFFFFFFF),
+ };
+
+ VerifySimpleAtoiGood<E_biguint>(E_biguint_zero, E_biguint_zero);
+ VerifySimpleAtoiGood<E_biguint>(E_biguint_one, E_biguint_one);
+ VerifySimpleAtoiGood<E_biguint>(E_biguint_max31, E_biguint_max31);
+ VerifySimpleAtoiGood<E_biguint>(E_biguint_max32, E_biguint_max32);
+}
+
+TEST(stringtest, safe_strto32_base) {
+ int32_t value;
+ EXPECT_TRUE(safe_strto32_base("0x34234324", &value, 16));
+ EXPECT_EQ(0x34234324, value);
+
+ EXPECT_TRUE(safe_strto32_base("0X34234324", &value, 16));
+ EXPECT_EQ(0x34234324, value);
+
+ EXPECT_TRUE(safe_strto32_base("34234324", &value, 16));
+ EXPECT_EQ(0x34234324, value);
+
+ EXPECT_TRUE(safe_strto32_base("0", &value, 16));
+ EXPECT_EQ(0, value);
+
+ EXPECT_TRUE(safe_strto32_base(" \t\n -0x34234324", &value, 16));
+ EXPECT_EQ(-0x34234324, value);
+
+ EXPECT_TRUE(safe_strto32_base(" \t\n -34234324", &value, 16));
+ EXPECT_EQ(-0x34234324, value);
+
+ EXPECT_TRUE(safe_strto32_base("7654321", &value, 8));
+ EXPECT_EQ(07654321, value);
+
+ EXPECT_TRUE(safe_strto32_base("-01234", &value, 8));
+ EXPECT_EQ(-01234, value);
+
+ EXPECT_FALSE(safe_strto32_base("1834", &value, 8));
+
+ // Autodetect base.
+ EXPECT_TRUE(safe_strto32_base("0", &value, 0));
+ EXPECT_EQ(0, value);
+
+ EXPECT_TRUE(safe_strto32_base("077", &value, 0));
+ EXPECT_EQ(077, value); // Octal interpretation
+
+ // Leading zero indicates octal, but then followed by invalid digit.
+ EXPECT_FALSE(safe_strto32_base("088", &value, 0));
+
+ // Leading 0x indicated hex, but then followed by invalid digit.
+ EXPECT_FALSE(safe_strto32_base("0xG", &value, 0));
+
+ // Base-10 version.
+ EXPECT_TRUE(safe_strto32_base("34234324", &value, 10));
+ EXPECT_EQ(34234324, value);
+
+ EXPECT_TRUE(safe_strto32_base("0", &value, 10));
+ EXPECT_EQ(0, value);
+
+ EXPECT_TRUE(safe_strto32_base(" \t\n -34234324", &value, 10));
+ EXPECT_EQ(-34234324, value);
+
+ EXPECT_TRUE(safe_strto32_base("34234324 \n\t ", &value, 10));
+ EXPECT_EQ(34234324, value);
+
+ // Invalid ints.
+ EXPECT_FALSE(safe_strto32_base("", &value, 10));
+ EXPECT_FALSE(safe_strto32_base(" ", &value, 10));
+ EXPECT_FALSE(safe_strto32_base("abc", &value, 10));
+ EXPECT_FALSE(safe_strto32_base("34234324a", &value, 10));
+ EXPECT_FALSE(safe_strto32_base("34234.3", &value, 10));
+
+ // Out of bounds.
+ EXPECT_FALSE(safe_strto32_base("2147483648", &value, 10));
+ EXPECT_FALSE(safe_strto32_base("-2147483649", &value, 10));
+
+ // String version.
+ EXPECT_TRUE(safe_strto32_base(std::string("0x1234"), &value, 16));
+ EXPECT_EQ(0x1234, value);
+
+ // Base-10 std::string version.
+ EXPECT_TRUE(safe_strto32_base("1234", &value, 10));
+ EXPECT_EQ(1234, value);
+}
+
+TEST(stringtest, safe_strto32_range) {
+ // These tests verify underflow/overflow behaviour.
+ int32_t value;
+ EXPECT_FALSE(safe_strto32_base("2147483648", &value, 10));
+ EXPECT_EQ(std::numeric_limits<int32_t>::max(), value);
+
+ EXPECT_TRUE(safe_strto32_base("-2147483648", &value, 10));
+ EXPECT_EQ(std::numeric_limits<int32_t>::min(), value);
+
+ EXPECT_FALSE(safe_strto32_base("-2147483649", &value, 10));
+ EXPECT_EQ(std::numeric_limits<int32_t>::min(), value);
+}
+
+TEST(stringtest, safe_strto64_range) {
+ // These tests verify underflow/overflow behaviour.
+ int64_t value;
+ EXPECT_FALSE(safe_strto64_base("9223372036854775808", &value, 10));
+ EXPECT_EQ(std::numeric_limits<int64_t>::max(), value);
+
+ EXPECT_TRUE(safe_strto64_base("-9223372036854775808", &value, 10));
+ EXPECT_EQ(std::numeric_limits<int64_t>::min(), value);
+
+ EXPECT_FALSE(safe_strto64_base("-9223372036854775809", &value, 10));
+ EXPECT_EQ(std::numeric_limits<int64_t>::min(), value);
+}
+
+TEST(stringtest, safe_strto32_leading_substring) {
+ // These tests verify this comment in numbers.h:
+ // On error, returns false, and sets *value to: [...]
+ // conversion of leading substring if available ("123@@@" -> 123)
+ // 0 if no leading substring available
+ int32_t value;
+ EXPECT_FALSE(safe_strto32_base("04069@@@", &value, 10));
+ EXPECT_EQ(4069, value);
+
+ EXPECT_FALSE(safe_strto32_base("04069@@@", &value, 8));
+ EXPECT_EQ(0406, value);
+
+ EXPECT_FALSE(safe_strto32_base("04069balloons", &value, 10));
+ EXPECT_EQ(4069, value);
+
+ EXPECT_FALSE(safe_strto32_base("04069balloons", &value, 16));
+ EXPECT_EQ(0x4069ba, value);
+
+ EXPECT_FALSE(safe_strto32_base("@@@", &value, 10));
+ EXPECT_EQ(0, value); // there was no leading substring
+}
+
+TEST(stringtest, safe_strto64_leading_substring) {
+ // These tests verify this comment in numbers.h:
+ // On error, returns false, and sets *value to: [...]
+ // conversion of leading substring if available ("123@@@" -> 123)
+ // 0 if no leading substring available
+ int64_t value;
+ EXPECT_FALSE(safe_strto64_base("04069@@@", &value, 10));
+ EXPECT_EQ(4069, value);
+
+ EXPECT_FALSE(safe_strto64_base("04069@@@", &value, 8));
+ EXPECT_EQ(0406, value);
+
+ EXPECT_FALSE(safe_strto64_base("04069balloons", &value, 10));
+ EXPECT_EQ(4069, value);
+
+ EXPECT_FALSE(safe_strto64_base("04069balloons", &value, 16));
+ EXPECT_EQ(0x4069ba, value);
+
+ EXPECT_FALSE(safe_strto64_base("@@@", &value, 10));
+ EXPECT_EQ(0, value); // there was no leading substring
+}
+
+TEST(stringtest, safe_strto64_base) {
+ int64_t value;
+ EXPECT_TRUE(safe_strto64_base("0x3423432448783446", &value, 16));
+ EXPECT_EQ(int64_t{0x3423432448783446}, value);
+
+ EXPECT_TRUE(safe_strto64_base("3423432448783446", &value, 16));
+ EXPECT_EQ(int64_t{0x3423432448783446}, value);
+
+ EXPECT_TRUE(safe_strto64_base("0", &value, 16));
+ EXPECT_EQ(0, value);
+
+ EXPECT_TRUE(safe_strto64_base(" \t\n -0x3423432448783446", &value, 16));
+ EXPECT_EQ(int64_t{-0x3423432448783446}, value);
+
+ EXPECT_TRUE(safe_strto64_base(" \t\n -3423432448783446", &value, 16));
+ EXPECT_EQ(int64_t{-0x3423432448783446}, value);
+
+ EXPECT_TRUE(safe_strto64_base("123456701234567012", &value, 8));
+ EXPECT_EQ(int64_t{0123456701234567012}, value);
+
+ EXPECT_TRUE(safe_strto64_base("-017777777777777", &value, 8));
+ EXPECT_EQ(int64_t{-017777777777777}, value);
+
+ EXPECT_FALSE(safe_strto64_base("19777777777777", &value, 8));
+
+ // Autodetect base.
+ EXPECT_TRUE(safe_strto64_base("0", &value, 0));
+ EXPECT_EQ(0, value);
+
+ EXPECT_TRUE(safe_strto64_base("077", &value, 0));
+ EXPECT_EQ(077, value); // Octal interpretation
+
+ // Leading zero indicates octal, but then followed by invalid digit.
+ EXPECT_FALSE(safe_strto64_base("088", &value, 0));
+
+ // Leading 0x indicated hex, but then followed by invalid digit.
+ EXPECT_FALSE(safe_strto64_base("0xG", &value, 0));
+
+ // Base-10 version.
+ EXPECT_TRUE(safe_strto64_base("34234324487834466", &value, 10));
+ EXPECT_EQ(int64_t{34234324487834466}, value);
+
+ EXPECT_TRUE(safe_strto64_base("0", &value, 10));
+ EXPECT_EQ(0, value);
+
+ EXPECT_TRUE(safe_strto64_base(" \t\n -34234324487834466", &value, 10));
+ EXPECT_EQ(int64_t{-34234324487834466}, value);
+
+ EXPECT_TRUE(safe_strto64_base("34234324487834466 \n\t ", &value, 10));
+ EXPECT_EQ(int64_t{34234324487834466}, value);
+
+ // Invalid ints.
+ EXPECT_FALSE(safe_strto64_base("", &value, 10));
+ EXPECT_FALSE(safe_strto64_base(" ", &value, 10));
+ EXPECT_FALSE(safe_strto64_base("abc", &value, 10));
+ EXPECT_FALSE(safe_strto64_base("34234324487834466a", &value, 10));
+ EXPECT_FALSE(safe_strto64_base("34234487834466.3", &value, 10));
+
+ // Out of bounds.
+ EXPECT_FALSE(safe_strto64_base("9223372036854775808", &value, 10));
+ EXPECT_FALSE(safe_strto64_base("-9223372036854775809", &value, 10));
+
+ // String version.
+ EXPECT_TRUE(safe_strto64_base(std::string("0x1234"), &value, 16));
+ EXPECT_EQ(0x1234, value);
+
+ // Base-10 std::string version.
+ EXPECT_TRUE(safe_strto64_base("1234", &value, 10));
+ EXPECT_EQ(1234, value);
+}
+
+const size_t kNumRandomTests = 10000;
+
+template <typename IntType>
+void test_random_integer_parse_base(bool (*parse_func)(absl::string_view,
+ IntType* value,
+ int base)) {
+ using RandomEngine = std::minstd_rand0;
+ std::random_device rd;
+ RandomEngine rng(rd());
+ std::uniform_int_distribution<IntType> random_int(
+ std::numeric_limits<IntType>::min());
+ std::uniform_int_distribution<int> random_base(2, 35);
+ for (size_t i = 0; i < kNumRandomTests; i++) {
+ IntType value = random_int(rng);
+ int base = random_base(rng);
+ std::string str_value;
+ EXPECT_TRUE(Itoa<IntType>(value, base, &str_value));
+ IntType parsed_value;
+
+ // Test successful parse
+ EXPECT_TRUE(parse_func(str_value, &parsed_value, base));
+ EXPECT_EQ(parsed_value, value);
+
+ // Test overflow
+ EXPECT_FALSE(
+ parse_func(absl::StrCat(std::numeric_limits<IntType>::max(), value),
+ &parsed_value, base));
+
+ // Test underflow
+ if (std::numeric_limits<IntType>::min() < 0) {
+ EXPECT_FALSE(
+ parse_func(absl::StrCat(std::numeric_limits<IntType>::min(), value),
+ &parsed_value, base));
+ } else {
+ EXPECT_FALSE(parse_func(absl::StrCat("-", value), &parsed_value, base));
+ }
+ }
+}
+
+TEST(stringtest, safe_strto32_random) {
+ test_random_integer_parse_base<int32_t>(&safe_strto32_base);
+}
+TEST(stringtest, safe_strto64_random) {
+ test_random_integer_parse_base<int64_t>(&safe_strto64_base);
+}
+TEST(stringtest, safe_strtou32_random) {
+ test_random_integer_parse_base<uint32_t>(&safe_strtou32_base);
+}
+TEST(stringtest, safe_strtou64_random) {
+ test_random_integer_parse_base<uint64_t>(&safe_strtou64_base);
+}
+
+TEST(stringtest, safe_strtou32_base) {
+ for (int i = 0; strtouint32_test_cases[i].str != nullptr; ++i) {
+ const auto& e = strtouint32_test_cases[i];
+ uint32_t value;
+ EXPECT_EQ(e.expect_ok, safe_strtou32_base(e.str, &value, e.base))
+ << "str=\"" << e.str << "\" base=" << e.base;
+ if (e.expect_ok) {
+ EXPECT_EQ(e.expected, value) << "i=" << i << " str=\"" << e.str
+ << "\" base=" << e.base;
+ }
+ }
+}
+
+TEST(stringtest, safe_strtou32_base_length_delimited) {
+ for (int i = 0; strtouint32_test_cases[i].str != nullptr; ++i) {
+ const auto& e = strtouint32_test_cases[i];
+ std::string tmp(e.str);
+ tmp.append("12"); // Adds garbage at the end.
+
+ uint32_t value;
+ EXPECT_EQ(e.expect_ok,
+ safe_strtou32_base(absl::string_view(tmp.data(), strlen(e.str)),
+ &value, e.base))
+ << "str=\"" << e.str << "\" base=" << e.base;
+ if (e.expect_ok) {
+ EXPECT_EQ(e.expected, value) << "i=" << i << " str=" << e.str
+ << " base=" << e.base;
+ }
+ }
+}
+
+TEST(stringtest, safe_strtou64_base) {
+ for (int i = 0; strtouint64_test_cases[i].str != nullptr; ++i) {
+ const auto& e = strtouint64_test_cases[i];
+ uint64_t value;
+ EXPECT_EQ(e.expect_ok, safe_strtou64_base(e.str, &value, e.base))
+ << "str=\"" << e.str << "\" base=" << e.base;
+ if (e.expect_ok) {
+ EXPECT_EQ(e.expected, value) << "str=" << e.str << " base=" << e.base;
+ }
+ }
+}
+
+TEST(stringtest, safe_strtou64_base_length_delimited) {
+ for (int i = 0; strtouint64_test_cases[i].str != nullptr; ++i) {
+ const auto& e = strtouint64_test_cases[i];
+ std::string tmp(e.str);
+ tmp.append("12"); // Adds garbage at the end.
+
+ uint64_t value;
+ EXPECT_EQ(e.expect_ok,
+ safe_strtou64_base(absl::string_view(tmp.data(), strlen(e.str)),
+ &value, e.base))
+ << "str=\"" << e.str << "\" base=" << e.base;
+ if (e.expect_ok) {
+ EXPECT_EQ(e.expected, value) << "str=\"" << e.str << "\" base=" << e.base;
+ }
+ }
+}
+
+// feenableexcept() and fedisableexcept() are missing on Mac OS X, MSVC.
+#if defined(_MSC_VER) || defined(__APPLE__)
+#define ABSL_MISSING_FEENABLEEXCEPT 1
+#define ABSL_MISSING_FEDISABLEEXCEPT 1
+#endif
+
+class SimpleDtoaTest : public testing::Test {
+ protected:
+ void SetUp() override {
+ // Store the current floating point env & clear away any pending exceptions.
+ feholdexcept(&fp_env_);
+#ifndef ABSL_MISSING_FEENABLEEXCEPT
+ // Turn on floating point exceptions.
+ feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
+#endif
+ }
+
+ void TearDown() override {
+ // Restore the floating point environment to the original state.
+ // In theory fedisableexcept is unnecessary; fesetenv will also do it.
+ // In practice, our toolchains have subtle bugs.
+#ifndef ABSL_MISSING_FEDISABLEEXCEPT
+ fedisableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
+#endif
+ fesetenv(&fp_env_);
+ }
+
+ std::string ToNineDigits(double value) {
+ char buffer[kFastToBufferSize]; // more than enough for %.9g
+ snprintf(buffer, sizeof(buffer), "%.9g", value);
+ return buffer;
+ }
+
+ fenv_t fp_env_;
+};
+
+// Run the given runnable functor for "cases" test cases, chosen over the
+// available range of float. pi and e and 1/e are seeded, and then all
+// available integer powers of 2 and 10 are multiplied against them. In
+// addition to trying all those values, we try the next higher and next lower
+// float, and then we add additional test cases evenly distributed between them.
+// Each test case is passed to runnable as both a positive and negative value.
+template <typename R>
+void ExhaustiveFloat(uint32_t cases, R&& runnable) {
+ runnable(0.0f);
+ runnable(-0.0f);
+ if (cases >= 2e9) { // more than 2 billion? Might as well run them all.
+ for (float f = 0; f < std::numeric_limits<float>::max(); ) {
+ f = nextafterf(f, std::numeric_limits<float>::max());
+ runnable(-f);
+ runnable(f);
+ }
+ return;
+ }
+ std::set<float> floats = {3.4028234e38f};
+ for (float f : {1.0, 3.14159265, 2.718281828, 1 / 2.718281828}) {
+ for (float testf = f; testf != 0; testf *= 0.1f) floats.insert(testf);
+ for (float testf = f; testf != 0; testf *= 0.5f) floats.insert(testf);
+ for (float testf = f; testf < 3e38f / 2; testf *= 2.0f)
+ floats.insert(testf);
+ for (float testf = f; testf < 3e38f / 10; testf *= 10) floats.insert(testf);
+ }
+
+ float last = *floats.begin();
+
+ runnable(last);
+ runnable(-last);
+ int iters_per_float = cases / floats.size();
+ if (iters_per_float == 0) iters_per_float = 1;
+ for (float f : floats) {
+ if (f == last) continue;
+ float testf = nextafter(last, std::numeric_limits<float>::max());
+ runnable(testf);
+ runnable(-testf);
+ last = testf;
+ if (f == last) continue;
+ double step = (double{f} - last) / iters_per_float;
+ for (double d = last + step; d < f; d += step) {
+ testf = d;
+ if (testf != last) {
+ runnable(testf);
+ runnable(-testf);
+ last = testf;
+ }
+ }
+ testf = nextafter(f, 0.0f);
+ if (testf > last) {
+ runnable(testf);
+ runnable(-testf);
+ last = testf;
+ }
+ if (f != last) {
+ runnable(f);
+ runnable(-f);
+ last = f;
+ }
+ }
+}
+
+TEST_F(SimpleDtoaTest, ExhaustiveFloatToBuffer) {
+ uint64_t test_count = 0;
+ std::vector<float> mismatches;
+ ExhaustiveFloat(kFloatNumCases, [&](float f) {
+ if (f != f) return; // rule out NaNs
+ ++test_count;
+ char fastbuf[kFastToBufferSize];
+ RoundTripFloatToBuffer(f, fastbuf);
+ float round_trip = strtof(fastbuf, nullptr);
+ if (f != round_trip) {
+ mismatches.push_back(f);
+ if (mismatches.size() < 10) {
+ ABSL_RAW_LOG(ERROR, "%s",
+ absl::StrCat("Round-trip failure with float. ", "f=", f,
+ "=", ToNineDigits(f), " fast=", fastbuf,
+ " strtof=", ToNineDigits(round_trip))
+ .c_str());
+ }
+ }
+ });
+ if (!mismatches.empty()) {
+ EXPECT_EQ(mismatches.size(), 0);
+ for (size_t i = 0; i < mismatches.size(); ++i) {
+ if (i > 100) i = mismatches.size() - 1;
+ float f = mismatches[i];
+ std::string msg =
+ absl::StrCat("Mismatch #", i, " f=", f, " (", ToNineDigits(f), ")");
+ char buf[kFastToBufferSize];
+ absl::StrAppend(&msg, " fast='", RoundTripFloatToBuffer(f, buf), "'");
+ float rt = strtof(buf, nullptr);
+ absl::StrAppend(&msg, " rt=", ToNineDigits(rt));
+ ABSL_RAW_LOG(ERROR, "%s", msg.c_str());
+ }
+ }
+}
+
+TEST_F(SimpleDtoaTest, ExhaustiveDoubleToSixDigits) {
+ uint64_t test_count = 0;
+ std::vector<double> mismatches;
+ auto checker = [&](double d) {
+ if (d != d) return; // rule out NaNs
+ ++test_count;
+ char sixdigitsbuf[kSixDigitsToBufferSize] = {0};
+ SixDigitsToBuffer(d, sixdigitsbuf);
+ char snprintfbuf[kSixDigitsToBufferSize] = {0};
+ snprintf(snprintfbuf, kSixDigitsToBufferSize, "%g", d);
+ if (strcmp(sixdigitsbuf, snprintfbuf) != 0) {
+ mismatches.push_back(d);
+ if (mismatches.size() < 10) {
+ ABSL_RAW_LOG(ERROR, "%s",
+ absl::StrCat("Six-digit failure with double. ", "d=", d,
+ "=", d, " sixdigits=", sixdigitsbuf,
+ " printf(%g)=", snprintfbuf)
+ .c_str());
+ }
+ }
+ };
+ // Some quick sanity checks...
+ checker(5e-324);
+ checker(1e-308);
+ checker(1.0);
+ checker(1.000005);
+ checker(1.7976931348623157e308);
+ checker(0.00390625);
+#ifndef _MSC_VER
+ // on MSVC, snprintf() rounds it to 0.00195313. SixDigitsToBuffer() rounds it
+ // to 0.00195312 (round half to even).
+ checker(0.001953125);
+#endif
+ checker(0.005859375);
+ // Some cases where the rounding is very very close
+ checker(1.089095e-15);
+ checker(3.274195e-55);
+ checker(6.534355e-146);
+ checker(2.920845e+234);
+
+ if (mismatches.empty()) {
+ test_count = 0;
+ ExhaustiveFloat(kFloatNumCases, checker);
+
+ test_count = 0;
+ std::vector<int> digit_testcases{
+ 100000, 100001, 100002, 100005, 100010, 100020, 100050, 100100, // misc
+ 195312, 195313, // 1.953125 is a case where we round down, just barely.
+ 200000, 500000, 800000, // misc mid-range cases
+ 585937, 585938, // 5.859375 is a case where we round up, just barely.
+ 900000, 990000, 999000, 999900, 999990, 999996, 999997, 999998, 999999};
+ if (kFloatNumCases >= 1e9) {
+ // If at least 1 billion test cases were requested, user wants an
+ // exhaustive test. So let's test all mantissas, too.
+ constexpr int min_mantissa = 100000, max_mantissa = 999999;
+ digit_testcases.resize(max_mantissa - min_mantissa + 1);
+ std::iota(digit_testcases.begin(), digit_testcases.end(), min_mantissa);
+ }
+
+ for (int exponent = -324; exponent <= 308; ++exponent) {
+ double powten = pow(10.0, exponent);
+ if (powten == 0) powten = 5e-324;
+ if (kFloatNumCases >= 1e9) {
+ // The exhaustive test takes a very long time, so log progress.
+ char buf[kSixDigitsToBufferSize];
+ ABSL_RAW_LOG(
+ INFO, "%s",
+ absl::StrCat("Exp ", exponent, " powten=", powten, "(",
+ powten, ") (",
+ std::string(buf, SixDigitsToBuffer(powten, buf)), ")")
+ .c_str());
+ }
+ for (int digits : digit_testcases) {
+ if (exponent == 308 && digits >= 179769) break; // don't overflow!
+ double digiform = (digits + 0.5) * 0.00001;
+ double testval = digiform * powten;
+ double pretestval = nextafter(testval, 0);
+ double posttestval = nextafter(testval, 1.7976931348623157e308);
+ checker(testval);
+ checker(pretestval);
+ checker(posttestval);
+ }
+ }
+ } else {
+ EXPECT_EQ(mismatches.size(), 0);
+ for (size_t i = 0; i < mismatches.size(); ++i) {
+ if (i > 100) i = mismatches.size() - 1;
+ double d = mismatches[i];
+ char sixdigitsbuf[kSixDigitsToBufferSize] = {0};
+ SixDigitsToBuffer(d, sixdigitsbuf);
+ char snprintfbuf[kSixDigitsToBufferSize] = {0};
+ snprintf(snprintfbuf, kSixDigitsToBufferSize, "%g", d);
+ double before = nextafter(d, 0.0);
+ double after = nextafter(d, 1.7976931348623157e308);
+ char b1[32], b2[kSixDigitsToBufferSize];
+ ABSL_RAW_LOG(
+ ERROR, "%s",
+ absl::StrCat(
+ "Mismatch #", i, " d=", d, " (", ToNineDigits(d), ")",
+ " sixdigits='", sixdigitsbuf, "'", " snprintf='", snprintfbuf,
+ "'", " Before.=", PerfectDtoa(before), " ",
+ (SixDigitsToBuffer(before, b2), b2),
+ " vs snprintf=", (snprintf(b1, sizeof(b1), "%g", before), b1),
+ " Perfect=", PerfectDtoa(d), " ", (SixDigitsToBuffer(d, b2), b2),
+ " vs snprintf=", (snprintf(b1, sizeof(b1), "%g", d), b1),
+ " After.=.", PerfectDtoa(after), " ",
+ (SixDigitsToBuffer(after, b2), b2),
+ " vs snprintf=", (snprintf(b1, sizeof(b1), "%g", after), b1))
+ .c_str());
+ }
+ }
+}
+
+TEST(StrToInt32, Partial) {
+ struct Int32TestLine {
+ std::string input;
+ bool status;
+ int32_t value;
+ };
+ const int32_t int32_min = std::numeric_limits<int32_t>::min();
+ const int32_t int32_max = std::numeric_limits<int32_t>::max();
+ Int32TestLine int32_test_line[] = {
+ {"", false, 0},
+ {" ", false, 0},
+ {"-", false, 0},
+ {"123@@@", false, 123},
+ {absl::StrCat(int32_min, int32_max), false, int32_min},
+ {absl::StrCat(int32_max, int32_max), false, int32_max},
+ };
+
+ for (const Int32TestLine& test_line : int32_test_line) {
+ int32_t value = -2;
+ bool status = safe_strto32_base(test_line.input, &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ value = -2;
+ status = safe_strto32_base(test_line.input, &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ value = -2;
+ status = safe_strto32_base(absl::string_view(test_line.input), &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ }
+}
+
+TEST(StrToUint32, Partial) {
+ struct Uint32TestLine {
+ std::string input;
+ bool status;
+ uint32_t value;
+ };
+ const uint32_t uint32_max = std::numeric_limits<uint32_t>::max();
+ Uint32TestLine uint32_test_line[] = {
+ {"", false, 0},
+ {" ", false, 0},
+ {"-", false, 0},
+ {"123@@@", false, 123},
+ {absl::StrCat(uint32_max, uint32_max), false, uint32_max},
+ };
+
+ for (const Uint32TestLine& test_line : uint32_test_line) {
+ uint32_t value = 2;
+ bool status = safe_strtou32_base(test_line.input, &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ value = 2;
+ status = safe_strtou32_base(test_line.input, &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ value = 2;
+ status = safe_strtou32_base(absl::string_view(test_line.input), &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ }
+}
+
+TEST(StrToInt64, Partial) {
+ struct Int64TestLine {
+ std::string input;
+ bool status;
+ int64_t value;
+ };
+ const int64_t int64_min = std::numeric_limits<int64_t>::min();
+ const int64_t int64_max = std::numeric_limits<int64_t>::max();
+ Int64TestLine int64_test_line[] = {
+ {"", false, 0},
+ {" ", false, 0},
+ {"-", false, 0},
+ {"123@@@", false, 123},
+ {absl::StrCat(int64_min, int64_max), false, int64_min},
+ {absl::StrCat(int64_max, int64_max), false, int64_max},
+ };
+
+ for (const Int64TestLine& test_line : int64_test_line) {
+ int64_t value = -2;
+ bool status = safe_strto64_base(test_line.input, &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ value = -2;
+ status = safe_strto64_base(test_line.input, &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ value = -2;
+ status = safe_strto64_base(absl::string_view(test_line.input), &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ }
+}
+
+TEST(StrToUint64, Partial) {
+ struct Uint64TestLine {
+ std::string input;
+ bool status;
+ uint64_t value;
+ };
+ const uint64_t uint64_max = std::numeric_limits<uint64_t>::max();
+ Uint64TestLine uint64_test_line[] = {
+ {"", false, 0},
+ {" ", false, 0},
+ {"-", false, 0},
+ {"123@@@", false, 123},
+ {absl::StrCat(uint64_max, uint64_max), false, uint64_max},
+ };
+
+ for (const Uint64TestLine& test_line : uint64_test_line) {
+ uint64_t value = 2;
+ bool status = safe_strtou64_base(test_line.input, &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ value = 2;
+ status = safe_strtou64_base(test_line.input, &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ value = 2;
+ status = safe_strtou64_base(absl::string_view(test_line.input), &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ }
+}
+
+TEST(StrToInt32Base, PrefixOnly) {
+ struct Int32TestLine {
+ std::string input;
+ bool status;
+ int32_t value;
+ };
+ Int32TestLine int32_test_line[] = {
+ { "", false, 0 },
+ { "-", false, 0 },
+ { "-0", true, 0 },
+ { "0", true, 0 },
+ { "0x", false, 0 },
+ { "-0x", false, 0 },
+ };
+ const int base_array[] = { 0, 2, 8, 10, 16 };
+
+ for (const Int32TestLine& line : int32_test_line) {
+ for (const int base : base_array) {
+ int32_t value = 2;
+ bool status = safe_strto32_base(line.input.c_str(), &value, base);
+ EXPECT_EQ(line.status, status) << line.input << " " << base;
+ EXPECT_EQ(line.value, value) << line.input << " " << base;
+ value = 2;
+ status = safe_strto32_base(line.input, &value, base);
+ EXPECT_EQ(line.status, status) << line.input << " " << base;
+ EXPECT_EQ(line.value, value) << line.input << " " << base;
+ value = 2;
+ status = safe_strto32_base(absl::string_view(line.input), &value, base);
+ EXPECT_EQ(line.status, status) << line.input << " " << base;
+ EXPECT_EQ(line.value, value) << line.input << " " << base;
+ }
+ }
+}
+
+TEST(StrToUint32Base, PrefixOnly) {
+ struct Uint32TestLine {
+ std::string input;
+ bool status;
+ uint32_t value;
+ };
+ Uint32TestLine uint32_test_line[] = {
+ { "", false, 0 },
+ { "0", true, 0 },
+ { "0x", false, 0 },
+ };
+ const int base_array[] = { 0, 2, 8, 10, 16 };
+
+ for (const Uint32TestLine& line : uint32_test_line) {
+ for (const int base : base_array) {
+ uint32_t value = 2;
+ bool status = safe_strtou32_base(line.input.c_str(), &value, base);
+ EXPECT_EQ(line.status, status) << line.input << " " << base;
+ EXPECT_EQ(line.value, value) << line.input << " " << base;
+ value = 2;
+ status = safe_strtou32_base(line.input, &value, base);
+ EXPECT_EQ(line.status, status) << line.input << " " << base;
+ EXPECT_EQ(line.value, value) << line.input << " " << base;
+ value = 2;
+ status = safe_strtou32_base(absl::string_view(line.input), &value, base);
+ EXPECT_EQ(line.status, status) << line.input << " " << base;
+ EXPECT_EQ(line.value, value) << line.input << " " << base;
+ }
+ }
+}
+
+TEST(StrToInt64Base, PrefixOnly) {
+ struct Int64TestLine {
+ std::string input;
+ bool status;
+ int64_t value;
+ };
+ Int64TestLine int64_test_line[] = {
+ { "", false, 0 },
+ { "-", false, 0 },
+ { "-0", true, 0 },
+ { "0", true, 0 },
+ { "0x", false, 0 },
+ { "-0x", false, 0 },
+ };
+ const int base_array[] = { 0, 2, 8, 10, 16 };
+
+ for (const Int64TestLine& line : int64_test_line) {
+ for (const int base : base_array) {
+ int64_t value = 2;
+ bool status = safe_strto64_base(line.input.c_str(), &value, base);
+ EXPECT_EQ(line.status, status) << line.input << " " << base;
+ EXPECT_EQ(line.value, value) << line.input << " " << base;
+ value = 2;
+ status = safe_strto64_base(line.input, &value, base);
+ EXPECT_EQ(line.status, status) << line.input << " " << base;
+ EXPECT_EQ(line.value, value) << line.input << " " << base;
+ value = 2;
+ status = safe_strto64_base(absl::string_view(line.input), &value, base);
+ EXPECT_EQ(line.status, status) << line.input << " " << base;
+ EXPECT_EQ(line.value, value) << line.input << " " << base;
+ }
+ }
+}
+
+TEST(StrToUint64Base, PrefixOnly) {
+ struct Uint64TestLine {
+ std::string input;
+ bool status;
+ uint64_t value;
+ };
+ Uint64TestLine uint64_test_line[] = {
+ { "", false, 0 },
+ { "0", true, 0 },
+ { "0x", false, 0 },
+ };
+ const int base_array[] = { 0, 2, 8, 10, 16 };
+
+ for (const Uint64TestLine& line : uint64_test_line) {
+ for (const int base : base_array) {
+ uint64_t value = 2;
+ bool status = safe_strtou64_base(line.input.c_str(), &value, base);
+ EXPECT_EQ(line.status, status) << line.input << " " << base;
+ EXPECT_EQ(line.value, value) << line.input << " " << base;
+ value = 2;
+ status = safe_strtou64_base(line.input, &value, base);
+ EXPECT_EQ(line.status, status) << line.input << " " << base;
+ EXPECT_EQ(line.value, value) << line.input << " " << base;
+ value = 2;
+ status = safe_strtou64_base(absl::string_view(line.input), &value, base);
+ EXPECT_EQ(line.status, status) << line.input << " " << base;
+ EXPECT_EQ(line.value, value) << line.input << " " << base;
+ }
+ }
+}
+
+} // namespace
diff --git a/absl/strings/str_cat.cc b/absl/strings/str_cat.cc
new file mode 100644
index 0000000..0c75655
--- /dev/null
+++ b/absl/strings/str_cat.cc
@@ -0,0 +1,208 @@
+// 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/strings/str_cat.h"
+
+#include <cstdarg>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+
+#include "absl/strings/ascii.h"
+#include "absl/strings/internal/resize_uninitialized.h"
+
+namespace absl {
+
+AlphaNum::AlphaNum(Hex hex) {
+ char* const end = &digits_[numbers_internal::kFastToBufferSize];
+ char* writer = end;
+ uint64_t value = hex.value;
+ static const char hexdigits[] = "0123456789abcdef";
+ do {
+ *--writer = hexdigits[value & 0xF];
+ value >>= 4;
+ } while (value != 0);
+
+ char* beg;
+ if (end - writer < hex.width) {
+ beg = end - hex.width;
+ std::fill_n(beg, writer - beg, hex.fill);
+ } else {
+ beg = writer;
+ }
+
+ piece_ = absl::string_view(beg, end - beg);
+}
+
+// ----------------------------------------------------------------------
+// StrCat()
+// This merges the given strings or integers, with no delimiter. This
+// is designed to be the fastest possible way to construct a std::string out
+// of a mix of raw C strings, StringPieces, strings, and integer values.
+// ----------------------------------------------------------------------
+
+// Append is merely a version of memcpy that returns the address of the byte
+// after the area just overwritten.
+static char* Append(char* out, const AlphaNum& x) {
+ // memcpy is allowed to overwrite arbitrary memory, so doing this after the
+ // call would force an extra fetch of x.size().
+ char* after = out + x.size();
+ memcpy(out, x.data(), x.size());
+ return after;
+}
+
+std::string StrCat(const AlphaNum& a, const AlphaNum& b) {
+ std::string result;
+ absl::strings_internal::STLStringResizeUninitialized(&result,
+ a.size() + b.size());
+ char* const begin = &*result.begin();
+ char* out = begin;
+ out = Append(out, a);
+ out = Append(out, b);
+ assert(out == begin + result.size());
+ return result;
+}
+
+std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) {
+ std::string result;
+ strings_internal::STLStringResizeUninitialized(
+ &result, a.size() + b.size() + c.size());
+ char* const begin = &*result.begin();
+ char* out = begin;
+ out = Append(out, a);
+ out = Append(out, b);
+ out = Append(out, c);
+ assert(out == begin + result.size());
+ return result;
+}
+
+std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c,
+ const AlphaNum& d) {
+ std::string result;
+ strings_internal::STLStringResizeUninitialized(
+ &result, a.size() + b.size() + c.size() + d.size());
+ char* const begin = &*result.begin();
+ char* out = begin;
+ out = Append(out, a);
+ out = Append(out, b);
+ out = Append(out, c);
+ out = Append(out, d);
+ assert(out == begin + result.size());
+ return result;
+}
+
+namespace strings_internal {
+
+// Do not call directly - these are not part of the public API.
+std::string CatPieces(std::initializer_list<absl::string_view> pieces) {
+ std::string result;
+ size_t total_size = 0;
+ for (const absl::string_view piece : pieces) total_size += piece.size();
+ strings_internal::STLStringResizeUninitialized(&result, total_size);
+
+ char* const begin = &*result.begin();
+ char* out = begin;
+ for (const absl::string_view piece : pieces) {
+ const size_t this_size = piece.size();
+ memcpy(out, piece.data(), this_size);
+ out += this_size;
+ }
+ assert(out == begin + result.size());
+ return result;
+}
+
+// It's possible to call StrAppend with an absl::string_view that is itself a
+// fragment of the std::string we're appending to. However the results of this are
+// random. Therefore, check for this in debug mode. Use unsigned math so we
+// only have to do one comparison. Note, there's an exception case: appending an
+// empty std::string is always allowed.
+#define ASSERT_NO_OVERLAP(dest, src) \
+ assert(((src).size() == 0) || \
+ (uintptr_t((src).data() - (dest).data()) > uintptr_t((dest).size())))
+
+void AppendPieces(std::string* dest,
+ std::initializer_list<absl::string_view> pieces) {
+ size_t old_size = dest->size();
+ size_t total_size = old_size;
+ for (const absl::string_view piece : pieces) {
+ ASSERT_NO_OVERLAP(*dest, piece);
+ total_size += piece.size();
+ }
+ strings_internal::STLStringResizeUninitialized(dest, total_size);
+
+ char* const begin = &*dest->begin();
+ char* out = begin + old_size;
+ for (const absl::string_view piece : pieces) {
+ const size_t this_size = piece.size();
+ memcpy(out, piece.data(), this_size);
+ out += this_size;
+ }
+ assert(out == begin + dest->size());
+}
+
+} // namespace strings_internal
+
+void StrAppend(std::string* dest, const AlphaNum& a) {
+ ASSERT_NO_OVERLAP(*dest, a);
+ dest->append(a.data(), a.size());
+}
+
+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b) {
+ ASSERT_NO_OVERLAP(*dest, a);
+ ASSERT_NO_OVERLAP(*dest, b);
+ std::string::size_type old_size = dest->size();
+ strings_internal::STLStringResizeUninitialized(
+ dest, old_size + a.size() + b.size());
+ char* const begin = &*dest->begin();
+ char* out = begin + old_size;
+ out = Append(out, a);
+ out = Append(out, b);
+ assert(out == begin + dest->size());
+}
+
+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
+ const AlphaNum& c) {
+ ASSERT_NO_OVERLAP(*dest, a);
+ ASSERT_NO_OVERLAP(*dest, b);
+ ASSERT_NO_OVERLAP(*dest, c);
+ std::string::size_type old_size = dest->size();
+ strings_internal::STLStringResizeUninitialized(
+ dest, old_size + a.size() + b.size() + c.size());
+ char* const begin = &*dest->begin();
+ char* out = begin + old_size;
+ out = Append(out, a);
+ out = Append(out, b);
+ out = Append(out, c);
+ assert(out == begin + dest->size());
+}
+
+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
+ const AlphaNum& c, const AlphaNum& d) {
+ ASSERT_NO_OVERLAP(*dest, a);
+ ASSERT_NO_OVERLAP(*dest, b);
+ ASSERT_NO_OVERLAP(*dest, c);
+ ASSERT_NO_OVERLAP(*dest, d);
+ std::string::size_type old_size = dest->size();
+ strings_internal::STLStringResizeUninitialized(
+ dest, old_size + a.size() + b.size() + c.size() + d.size());
+ char* const begin = &*dest->begin();
+ char* out = begin + old_size;
+ out = Append(out, a);
+ out = Append(out, b);
+ out = Append(out, c);
+ out = Append(out, d);
+ assert(out == begin + dest->size());
+}
+
+} // namespace absl
diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h
new file mode 100644
index 0000000..5b4c9ba
--- /dev/null
+++ b/absl/strings/str_cat.h
@@ -0,0 +1,348 @@
+//
+// 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: str_cat.h
+// -----------------------------------------------------------------------------
+//
+// This package contains functions for efficiently concatenating and appending
+// strings: `StrCat()` and `StrAppend()`. Most of the work within these routines
+// is actually handled through use of a special AlphaNum type, which was
+// designed to be used as a parameter type that efficiently manages conversion
+// to strings and avoids copies in the above operations.
+//
+// Any routine accepting either a std::string or a number may accept `AlphaNum`.
+// The basic idea is that by accepting a `const AlphaNum &` as an argument
+// to your function, your callers will automagically convert bools, integers,
+// and floating point values to strings for you.
+//
+// NOTE: Use of `AlphaNum` outside of the //absl/strings package is unsupported
+// except for the specific case of function parameters of type `AlphaNum` or
+// `const AlphaNum &`. In particular, instantiating `AlphaNum` directly as a
+// stack variable is not supported.
+//
+// Conversion from 8-bit values is not accepted because, if it were, then an
+// attempt to pass ':' instead of ":" might result in a 58 ending up in your
+// result.
+//
+// Bools convert to "0" or "1".
+//
+// Floating point numbers are formatted with six-digit precision, which is
+// the default for "std::cout <<" or printf "%g" (the same as "%.6g").
+//
+//
+// You can convert to hexadecimal output rather than decimal output using the
+// `Hex` type contained here. To do so, pass `Hex(my_int)` as a parameter to
+// `StrCat()` or `StrAppend()`. You may specify a minimum hex field width using
+// a `PadSpec` enum, so the equivalent of `StringPrintf("%04x", my_int)` is
+// `absl::StrCat(absl::Hex(my_int, absl::kZeroPad4))`.
+//
+// -----------------------------------------------------------------------------
+
+#ifndef ABSL_STRINGS_STR_CAT_H_
+#define ABSL_STRINGS_STR_CAT_H_
+
+#include <array>
+#include <cstdint>
+#include <string>
+#include <type_traits>
+
+#include "absl/base/port.h"
+#include "absl/strings/numbers.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+
+namespace strings_internal {
+// AlphaNumBuffer allows a way to pass a std::string to StrCat without having to do
+// memory allocation. It is simply a pair of a fixed-size character array, and
+// a size. Please don't use outside of absl, yet.
+template <size_t max_size>
+struct AlphaNumBuffer {
+ std::array<char, max_size> data;
+ size_t size;
+};
+
+} // namespace strings_internal
+
+// Enum that specifies the number of significant digits to return in a `Hex`
+// conversion and fill character to use. A `kZeroPad2` value, for example, would
+// produce hexadecimal strings such as "0A","0F" and 'kSpacePad5' value would
+// produce hexadecimal strings such as " A"," F".
+enum PadSpec {
+ kNoPad = 1,
+ kZeroPad2,
+ kZeroPad3,
+ kZeroPad4,
+ kZeroPad5,
+ kZeroPad6,
+ kZeroPad7,
+ kZeroPad8,
+ kZeroPad9,
+ kZeroPad10,
+ kZeroPad11,
+ kZeroPad12,
+ kZeroPad13,
+ kZeroPad14,
+ kZeroPad15,
+ kZeroPad16,
+
+ kSpacePad2 = kZeroPad2 + 64,
+ kSpacePad3,
+ kSpacePad4,
+ kSpacePad5,
+ kSpacePad6,
+ kSpacePad7,
+ kSpacePad8,
+ kSpacePad9,
+ kSpacePad10,
+ kSpacePad11,
+ kSpacePad12,
+ kSpacePad13,
+ kSpacePad14,
+ kSpacePad15,
+ kSpacePad16,
+};
+
+// -----------------------------------------------------------------------------
+// Hex
+// -----------------------------------------------------------------------------
+//
+// `Hex` stores a set of hexadecimal std::string conversion parameters for use
+// within `AlphaNum` std::string conversions.
+struct Hex {
+ uint64_t value;
+ uint8_t width;
+ char fill;
+
+ template <typename Int>
+ explicit Hex(Int v, PadSpec spec = absl::kNoPad,
+ typename std::enable_if<sizeof(Int) == 1>::type* = nullptr)
+ : Hex(spec, static_cast<uint8_t>(v)) {}
+ template <typename Int>
+ explicit Hex(Int v, PadSpec spec = absl::kNoPad,
+ typename std::enable_if<sizeof(Int) == 2>::type* = nullptr)
+ : Hex(spec, static_cast<uint16_t>(v)) {}
+ template <typename Int>
+ explicit Hex(Int v, PadSpec spec = absl::kNoPad,
+ typename std::enable_if<sizeof(Int) == 4>::type* = nullptr)
+ : Hex(spec, static_cast<uint32_t>(v)) {}
+ template <typename Int>
+ explicit Hex(Int v, PadSpec spec = absl::kNoPad,
+ typename std::enable_if<sizeof(Int) == 8>::type* = nullptr)
+ : Hex(spec, static_cast<uint64_t>(v)) {}
+
+ private:
+ Hex(PadSpec spec, uint64_t v)
+ : value(v),
+ width(spec == absl::kNoPad
+ ? 1
+ : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2
+ : spec - absl::kZeroPad2 + 2),
+ fill(spec >= absl::kSpacePad2 ? ' ' : '0') {}
+};
+
+// -----------------------------------------------------------------------------
+// AlphaNum
+// -----------------------------------------------------------------------------
+//
+// The `AlphaNum` class acts as the main parameter type for `StrCat()` and
+// `StrAppend()`, providing efficient conversion of numeric, boolean, and
+// hexadecimal values (through the `Hex` type) into strings.
+
+class AlphaNum {
+ public:
+ // No bool ctor -- bools convert to an integral type.
+ // A bool ctor would also convert incoming pointers (bletch).
+
+ AlphaNum(int x) // NOLINT(runtime/explicit)
+ : piece_(digits_,
+ numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
+ AlphaNum(unsigned int x) // NOLINT(runtime/explicit)
+ : piece_(digits_,
+ numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
+ AlphaNum(long x) // NOLINT(*)
+ : piece_(digits_,
+ numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
+ AlphaNum(unsigned long x) // NOLINT(*)
+ : piece_(digits_,
+ numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
+ AlphaNum(long long x) // NOLINT(*)
+ : piece_(digits_,
+ numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
+ AlphaNum(unsigned long long x) // NOLINT(*)
+ : piece_(digits_,
+ numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
+
+ AlphaNum(float f) // NOLINT(runtime/explicit)
+ : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {}
+ AlphaNum(double f) // NOLINT(runtime/explicit)
+ : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {}
+
+ AlphaNum(Hex hex); // NOLINT(runtime/explicit)
+
+ template <size_t size>
+ AlphaNum( // NOLINT(runtime/explicit)
+ const strings_internal::AlphaNumBuffer<size>& buf)
+ : piece_(&buf.data[0], buf.size) {}
+
+ AlphaNum(const char* c_str) : piece_(c_str) {} // NOLINT(runtime/explicit)
+ AlphaNum(absl::string_view pc) : piece_(pc) {} // NOLINT(runtime/explicit)
+ template <typename Allocator>
+ AlphaNum( // NOLINT(runtime/explicit)
+ const std::basic_string<char, std::char_traits<char>, Allocator>& str)
+ : piece_(str) {}
+
+ // Use std::string literals ":" instead of character literals ':'.
+ AlphaNum(char c) = delete; // NOLINT(runtime/explicit)
+
+ AlphaNum(const AlphaNum&) = delete;
+ AlphaNum& operator=(const AlphaNum&) = delete;
+
+ absl::string_view::size_type size() const { return piece_.size(); }
+ const char* data() const { return piece_.data(); }
+ absl::string_view Piece() const { return piece_; }
+
+ // Normal enums are already handled by the integer formatters.
+ // This overload matches only scoped enums.
+ template <typename T,
+ typename = typename std::enable_if<
+ std::is_enum<T>{} && !std::is_convertible<T, int>{}>::type>
+ AlphaNum(T e) // NOLINT(runtime/explicit)
+ : AlphaNum(static_cast<typename std::underlying_type<T>::type>(e)) {}
+
+ private:
+ absl::string_view piece_;
+ char digits_[numbers_internal::kFastToBufferSize];
+};
+
+// -----------------------------------------------------------------------------
+// StrCat()
+// -----------------------------------------------------------------------------
+//
+// Merges given strings or numbers, using no delimiter(s).
+//
+// `StrCat()` is designed to be the fastest possible way to construct a std::string
+// out of a mix of raw C strings, string_views, strings, bool values,
+// and numeric values.
+//
+// Don't use `StrCat()` for user-visible strings. The localization process
+// works poorly on strings built up out of fragments.
+//
+// For clarity and performance, don't use `StrCat()` when appending to a
+// std::string. Use `StrAppend()` instead. In particular, avoid using any of these
+// (anti-)patterns:
+//
+// str.append(StrCat(...))
+// str += StrCat(...)
+// str = StrCat(str, ...)
+//
+// The last case is the worst, with a potential to change a loop
+// from a linear time operation with O(1) dynamic allocations into a
+// quadratic time operation with O(n) dynamic allocations.
+//
+// See `StrAppend()` below for more information.
+
+namespace strings_internal {
+
+// Do not call directly - this is not part of the public API.
+std::string CatPieces(std::initializer_list<absl::string_view> pieces);
+void AppendPieces(std::string* dest,
+ std::initializer_list<absl::string_view> pieces);
+
+} // namespace strings_internal
+
+ABSL_MUST_USE_RESULT inline std::string StrCat() { return std::string(); }
+
+ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a) {
+ return std::string(a.data(), a.size());
+}
+
+ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b);
+ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+ const AlphaNum& c);
+ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+ const AlphaNum& c, const AlphaNum& d);
+
+// Support 5 or more arguments
+template <typename... AV>
+ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+ const AlphaNum& c, const AlphaNum& d,
+ const AlphaNum& e,
+ const AV&... args) {
+ return strings_internal::CatPieces(
+ {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(),
+ static_cast<const AlphaNum&>(args).Piece()...});
+}
+
+// -----------------------------------------------------------------------------
+// StrAppend()
+// -----------------------------------------------------------------------------
+//
+// Appends a std::string or set of strings to an existing std::string, in a similar
+// fashion to `StrCat()`.
+//
+// WARNING: `StrAppend(&str, a, b, c, ...)` requires that none of the
+// a, b, c, parameters be a reference into str. For speed, `StrAppend()` does
+// not try to check each of its input arguments to be sure that they are not
+// a subset of the std::string being appended to. That is, while this will work:
+//
+// std::string s = "foo";
+// s += s;
+//
+// This output is undefined:
+//
+// std::string s = "foo";
+// StrAppend(&s, s);
+//
+// This output is undefined as well, since `absl::string_view` does not own its
+// data:
+//
+// std::string s = "foobar";
+// absl::string_view p = s;
+// StrAppend(&s, p);
+
+inline void StrAppend(std::string*) {}
+void StrAppend(std::string* dest, const AlphaNum& a);
+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b);
+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
+ const AlphaNum& c);
+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
+ const AlphaNum& c, const AlphaNum& d);
+
+// Support 5 or more arguments
+template <typename... AV>
+inline void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
+ const AlphaNum& c, const AlphaNum& d, const AlphaNum& e,
+ const AV&... args) {
+ strings_internal::AppendPieces(
+ dest, {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(),
+ static_cast<const AlphaNum&>(args).Piece()...});
+}
+
+// Helper function for the future StrCat default floating-point format, %.6g
+// This is fast.
+inline strings_internal::AlphaNumBuffer<
+ numbers_internal::kSixDigitsToBufferSize>
+SixDigits(double d) {
+ strings_internal::AlphaNumBuffer<numbers_internal::kSixDigitsToBufferSize>
+ result;
+ result.size = numbers_internal::SixDigitsToBuffer(d, &result.data[0]);
+ return result;
+}
+
+} // namespace absl
+
+#endif // ABSL_STRINGS_STR_CAT_H_
diff --git a/absl/strings/str_cat_test.cc b/absl/strings/str_cat_test.cc
new file mode 100644
index 0000000..293d194
--- /dev/null
+++ b/absl/strings/str_cat_test.cc
@@ -0,0 +1,462 @@
+// 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 tests for all str_cat.h functions
+
+#include "absl/strings/str_cat.h"
+
+#include <cstdint>
+#include <string>
+
+#include "gtest/gtest.h"
+#include "absl/strings/substitute.h"
+
+namespace {
+
+// Test absl::StrCat of ints and longs of various sizes and signdedness.
+TEST(StrCat, Ints) {
+ const short s = -1; // NOLINT(runtime/int)
+ const uint16_t us = 2;
+ const int i = -3;
+ const unsigned int ui = 4;
+ const long l = -5; // NOLINT(runtime/int)
+ const unsigned long ul = 6; // NOLINT(runtime/int)
+ const long long ll = -7; // NOLINT(runtime/int)
+ const unsigned long long ull = 8; // NOLINT(runtime/int)
+ const ptrdiff_t ptrdiff = -9;
+ const size_t size = 10;
+ const intptr_t intptr = -12;
+ const uintptr_t uintptr = 13;
+ std::string answer;
+ answer = absl::StrCat(s, us);
+ EXPECT_EQ(answer, "-12");
+ answer = absl::StrCat(i, ui);
+ EXPECT_EQ(answer, "-34");
+ answer = absl::StrCat(l, ul);
+ EXPECT_EQ(answer, "-56");
+ answer = absl::StrCat(ll, ull);
+ EXPECT_EQ(answer, "-78");
+ answer = absl::StrCat(ptrdiff, size);
+ EXPECT_EQ(answer, "-910");
+ answer = absl::StrCat(ptrdiff, intptr);
+ EXPECT_EQ(answer, "-9-12");
+ answer = absl::StrCat(uintptr, 0);
+ EXPECT_EQ(answer, "130");
+}
+
+TEST(StrCat, Enums) {
+ enum SmallNumbers { One = 1, Ten = 10 } e = Ten;
+ EXPECT_EQ("10", absl::StrCat(e));
+ EXPECT_EQ("-5", absl::StrCat(SmallNumbers(-5)));
+
+ enum class Option { Boxers = 1, Briefs = -1 };
+
+ EXPECT_EQ("-1", absl::StrCat(Option::Briefs));
+
+ enum class Airplane : uint64_t {
+ Airbus = 1,
+ Boeing = 1000,
+ Canary = 10000000000 // too big for "int"
+ };
+
+ EXPECT_EQ("10000000000", absl::StrCat(Airplane::Canary));
+
+ enum class TwoGig : int32_t {
+ TwoToTheZero = 1,
+ TwoToTheSixteenth = 1 << 16,
+ TwoToTheThirtyFirst = INT32_MIN
+ };
+ EXPECT_EQ("65536", absl::StrCat(TwoGig::TwoToTheSixteenth));
+ EXPECT_EQ("-2147483648", absl::StrCat(TwoGig::TwoToTheThirtyFirst));
+ EXPECT_EQ("-1", absl::StrCat(static_cast<TwoGig>(-1)));
+
+ enum class FourGig : uint32_t {
+ TwoToTheZero = 1,
+ TwoToTheSixteenth = 1 << 16,
+ TwoToTheThirtyFirst = 1U << 31 // too big for "int"
+ };
+ EXPECT_EQ("65536", absl::StrCat(FourGig::TwoToTheSixteenth));
+ EXPECT_EQ("2147483648", absl::StrCat(FourGig::TwoToTheThirtyFirst));
+ EXPECT_EQ("4294967295", absl::StrCat(static_cast<FourGig>(-1)));
+
+ EXPECT_EQ("10000000000", absl::StrCat(Airplane::Canary));
+}
+
+TEST(StrCat, Basics) {
+ std::string result;
+
+ std::string strs[] = {
+ "Hello",
+ "Cruel",
+ "World"
+ };
+
+ std::string stdstrs[] = {
+ "std::Hello",
+ "std::Cruel",
+ "std::World"
+ };
+
+ absl::string_view pieces[] = {"Hello", "Cruel", "World"};
+
+ const char* c_strs[] = {
+ "Hello",
+ "Cruel",
+ "World"
+ };
+
+ int32_t i32s[] = {'H', 'C', 'W'};
+ uint64_t ui64s[] = {12345678910LL, 10987654321LL};
+
+ EXPECT_EQ(absl::StrCat(), "");
+
+ result = absl::StrCat(false, true, 2, 3);
+ EXPECT_EQ(result, "0123");
+
+ result = absl::StrCat(-1);
+ EXPECT_EQ(result, "-1");
+
+ result = absl::StrCat(absl::SixDigits(0.5));
+ EXPECT_EQ(result, "0.5");
+
+ result = absl::StrCat(strs[1], pieces[2]);
+ EXPECT_EQ(result, "CruelWorld");
+
+ result = absl::StrCat(stdstrs[1], " ", stdstrs[2]);
+ EXPECT_EQ(result, "std::Cruel std::World");
+
+ result = absl::StrCat(strs[0], ", ", pieces[2]);
+ EXPECT_EQ(result, "Hello, World");
+
+ result = absl::StrCat(strs[0], ", ", strs[1], " ", strs[2], "!");
+ EXPECT_EQ(result, "Hello, Cruel World!");
+
+ result = absl::StrCat(pieces[0], ", ", pieces[1], " ", pieces[2]);
+ EXPECT_EQ(result, "Hello, Cruel World");
+
+ result = absl::StrCat(c_strs[0], ", ", c_strs[1], " ", c_strs[2]);
+ EXPECT_EQ(result, "Hello, Cruel World");
+
+ result = absl::StrCat("ASCII ", i32s[0], ", ", i32s[1], " ", i32s[2], "!");
+ EXPECT_EQ(result, "ASCII 72, 67 87!");
+
+ result = absl::StrCat(ui64s[0], ", ", ui64s[1], "!");
+ EXPECT_EQ(result, "12345678910, 10987654321!");
+
+ std::string one = "1"; // Actually, it's the size of this std::string that we want; a
+ // 64-bit build distinguishes between size_t and uint64_t,
+ // even though they're both unsigned 64-bit values.
+ result = absl::StrCat("And a ", one.size(), " and a ",
+ &result[2] - &result[0], " and a ", one, " 2 3 4", "!");
+ EXPECT_EQ(result, "And a 1 and a 2 and a 1 2 3 4!");
+
+ // result = absl::StrCat("Single chars won't compile", '!');
+ // result = absl::StrCat("Neither will nullptrs", nullptr);
+ result =
+ absl::StrCat("To output a char by ASCII/numeric value, use +: ", '!' + 0);
+ EXPECT_EQ(result, "To output a char by ASCII/numeric value, use +: 33");
+
+ float f = 100000.5;
+ result = absl::StrCat("A hundred K and a half is ", absl::SixDigits(f));
+ EXPECT_EQ(result, "A hundred K and a half is 100000");
+
+ f = 100001.5;
+ result =
+ absl::StrCat("A hundred K and one and a half is ", absl::SixDigits(f));
+ EXPECT_EQ(result, "A hundred K and one and a half is 100002");
+
+ double d = 100000.5;
+ d *= d;
+ result =
+ absl::StrCat("A hundred K and a half squared is ", absl::SixDigits(d));
+ EXPECT_EQ(result, "A hundred K and a half squared is 1.00001e+10");
+
+ result = absl::StrCat(1, 2, 333, 4444, 55555, 666666, 7777777, 88888888,
+ 999999999);
+ EXPECT_EQ(result, "12333444455555666666777777788888888999999999");
+}
+
+// A minimal allocator that uses malloc().
+template <typename T>
+struct Mallocator {
+ typedef T value_type;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+
+ size_type max_size() const {
+ return size_t(std::numeric_limits<size_type>::max()) / sizeof(value_type);
+ }
+ template <typename U>
+ struct rebind {
+ typedef Mallocator<U> other;
+ };
+ Mallocator() = default;
+
+ T* allocate(size_t n) { return static_cast<T*>(std::malloc(n * sizeof(T))); }
+ void deallocate(T* p, size_t) { std::free(p); }
+};
+template <typename T, typename U>
+bool operator==(const Mallocator<T>&, const Mallocator<U>&) {
+ return true;
+}
+template <typename T, typename U>
+bool operator!=(const Mallocator<T>&, const Mallocator<U>&) {
+ return false;
+}
+
+TEST(StrCat, CustomAllocator) {
+ using mstring =
+ std::basic_string<char, std::char_traits<char>, Mallocator<char>>;
+ const mstring str1("PARACHUTE OFF A BLIMP INTO MOSCONE!!");
+
+ const mstring str2("Read this book about coffee tables");
+
+ std::string result = absl::StrCat(str1, str2);
+ EXPECT_EQ(result,
+ "PARACHUTE OFF A BLIMP INTO MOSCONE!!"
+ "Read this book about coffee tables");
+}
+
+TEST(StrCat, MaxArgs) {
+ std::string result;
+ // Test 10 up to 26 arguments, the current maximum
+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a");
+ EXPECT_EQ(result, "123456789a");
+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b");
+ EXPECT_EQ(result, "123456789ab");
+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c");
+ EXPECT_EQ(result, "123456789abc");
+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d");
+ EXPECT_EQ(result, "123456789abcd");
+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e");
+ EXPECT_EQ(result, "123456789abcde");
+ result =
+ absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f");
+ EXPECT_EQ(result, "123456789abcdef");
+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+ "g");
+ EXPECT_EQ(result, "123456789abcdefg");
+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+ "g", "h");
+ EXPECT_EQ(result, "123456789abcdefgh");
+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+ "g", "h", "i");
+ EXPECT_EQ(result, "123456789abcdefghi");
+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+ "g", "h", "i", "j");
+ EXPECT_EQ(result, "123456789abcdefghij");
+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+ "g", "h", "i", "j", "k");
+ EXPECT_EQ(result, "123456789abcdefghijk");
+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+ "g", "h", "i", "j", "k", "l");
+ EXPECT_EQ(result, "123456789abcdefghijkl");
+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+ "g", "h", "i", "j", "k", "l", "m");
+ EXPECT_EQ(result, "123456789abcdefghijklm");
+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+ "g", "h", "i", "j", "k", "l", "m", "n");
+ EXPECT_EQ(result, "123456789abcdefghijklmn");
+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+ "g", "h", "i", "j", "k", "l", "m", "n", "o");
+ EXPECT_EQ(result, "123456789abcdefghijklmno");
+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+ "g", "h", "i", "j", "k", "l", "m", "n", "o", "p");
+ EXPECT_EQ(result, "123456789abcdefghijklmnop");
+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f",
+ "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q");
+ EXPECT_EQ(result, "123456789abcdefghijklmnopq");
+ // No limit thanks to C++11's variadic templates
+ result = absl::StrCat(
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "a", "b", "c", "d", "e", "f", "g", "h",
+ "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w",
+ "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L",
+ "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z");
+ EXPECT_EQ(result,
+ "12345678910abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+}
+
+TEST(StrAppend, Basics) {
+ std::string result = "existing text";
+
+ std::string strs[] = {
+ "Hello",
+ "Cruel",
+ "World"
+ };
+
+ absl::string_view pieces[] = {"Hello", "Cruel", "World"};
+
+ const char* c_strs[] = {
+ "Hello",
+ "Cruel",
+ "World"
+ };
+
+ int32_t i32s[] = {'H', 'C', 'W'};
+ uint64_t ui64s[] = {12345678910LL, 10987654321LL};
+
+ std::string::size_type old_size = result.size();
+ absl::StrAppend(&result);
+ EXPECT_EQ(result.size(), old_size);
+
+ old_size = result.size();
+ absl::StrAppend(&result, strs[0]);
+ EXPECT_EQ(result.substr(old_size), "Hello");
+
+ old_size = result.size();
+ absl::StrAppend(&result, strs[1], pieces[2]);
+ EXPECT_EQ(result.substr(old_size), "CruelWorld");
+
+ old_size = result.size();
+ absl::StrAppend(&result, strs[0], ", ", pieces[2]);
+ EXPECT_EQ(result.substr(old_size), "Hello, World");
+
+ old_size = result.size();
+ absl::StrAppend(&result, strs[0], ", ", strs[1], " ", strs[2], "!");
+ EXPECT_EQ(result.substr(old_size), "Hello, Cruel World!");
+
+ old_size = result.size();
+ absl::StrAppend(&result, pieces[0], ", ", pieces[1], " ", pieces[2]);
+ EXPECT_EQ(result.substr(old_size), "Hello, Cruel World");
+
+ old_size = result.size();
+ absl::StrAppend(&result, c_strs[0], ", ", c_strs[1], " ", c_strs[2]);
+ EXPECT_EQ(result.substr(old_size), "Hello, Cruel World");
+
+ old_size = result.size();
+ absl::StrAppend(&result, "ASCII ", i32s[0], ", ", i32s[1], " ", i32s[2], "!");
+ EXPECT_EQ(result.substr(old_size), "ASCII 72, 67 87!");
+
+ old_size = result.size();
+ absl::StrAppend(&result, ui64s[0], ", ", ui64s[1], "!");
+ EXPECT_EQ(result.substr(old_size), "12345678910, 10987654321!");
+
+ std::string one = "1"; // Actually, it's the size of this std::string that we want; a
+ // 64-bit build distinguishes between size_t and uint64_t,
+ // even though they're both unsigned 64-bit values.
+ old_size = result.size();
+ absl::StrAppend(&result, "And a ", one.size(), " and a ",
+ &result[2] - &result[0], " and a ", one, " 2 3 4", "!");
+ EXPECT_EQ(result.substr(old_size), "And a 1 and a 2 and a 1 2 3 4!");
+
+ // result = absl::StrCat("Single chars won't compile", '!');
+ // result = absl::StrCat("Neither will nullptrs", nullptr);
+ old_size = result.size();
+ absl::StrAppend(&result,
+ "To output a char by ASCII/numeric value, use +: ", '!' + 0);
+ EXPECT_EQ(result.substr(old_size),
+ "To output a char by ASCII/numeric value, use +: 33");
+
+ // Test 9 arguments, the old maximum
+ old_size = result.size();
+ absl::StrAppend(&result, 1, 22, 333, 4444, 55555, 666666, 7777777, 88888888,
+ 9);
+ EXPECT_EQ(result.substr(old_size), "1223334444555556666667777777888888889");
+
+ // No limit thanks to C++11's variadic templates
+ old_size = result.size();
+ absl::StrAppend(
+ &result, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, //
+ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", //
+ "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", //
+ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", //
+ "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", //
+ "No limit thanks to C++11's variadic templates");
+ EXPECT_EQ(result.substr(old_size),
+ "12345678910abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "No limit thanks to C++11's variadic templates");
+}
+
+#ifdef GTEST_HAS_DEATH_TEST
+TEST(StrAppend, Death) {
+ std::string s = "self";
+ // on linux it's "assertion", on mac it's "Assertion",
+ // on chromiumos it's "Assertion ... failed".
+ EXPECT_DEBUG_DEATH(absl::StrAppend(&s, s.c_str() + 1), "ssertion.*failed");
+ EXPECT_DEBUG_DEATH(absl::StrAppend(&s, s), "ssertion.*failed");
+}
+#endif // GTEST_HAS_DEATH_TEST
+
+TEST(StrAppend, EmptyString) {
+ std::string s = "";
+ absl::StrAppend(&s, s);
+ EXPECT_EQ(s, "");
+}
+
+template <typename IntType>
+void CheckHex(IntType v, const char* nopad_format, const char* zeropad_format,
+ const char* spacepad_format) {
+ char expected[256];
+
+ std::string actual = absl::StrCat(absl::Hex(v, absl::kNoPad));
+ snprintf(expected, sizeof(expected), nopad_format, v);
+ EXPECT_EQ(expected, actual) << " decimal value " << v;
+
+ for (int spec = absl::kZeroPad2; spec <= absl::kZeroPad16; ++spec) {
+ std::string actual =
+ absl::StrCat(absl::Hex(v, static_cast<absl::PadSpec>(spec)));
+ snprintf(expected, sizeof(expected), zeropad_format,
+ spec - absl::kZeroPad2 + 2, v);
+ EXPECT_EQ(expected, actual) << " decimal value " << v;
+ }
+
+ for (int spec = absl::kSpacePad2; spec <= absl::kSpacePad16; ++spec) {
+ std::string actual =
+ absl::StrCat(absl::Hex(v, static_cast<absl::PadSpec>(spec)));
+ snprintf(expected, sizeof(expected), spacepad_format,
+ spec - absl::kSpacePad2 + 2, v);
+ EXPECT_EQ(expected, actual) << " decimal value " << v;
+ }
+}
+
+void CheckHex64(uint64_t v) {
+ unsigned long long llv = v; // NOLINT(runtime/int)
+
+ CheckHex(llv, "%llx", "%0*llx", "%*llx");
+}
+
+template <typename Int32Type>
+void CheckHex32(Int32Type v) {
+ CheckHex(v, "%x", "%0*x", "%*x");
+}
+
+void TestFastPrints() {
+ // Test min int to make sure that works
+ for (int i = 0; i < 10000; i++) {
+ CheckHex64(i);
+ CheckHex32(static_cast<uint32_t>(i));
+ CheckHex32(i);
+ CheckHex32(-i);
+ }
+
+ CheckHex64(uint64_t{0x123456789abcdef0});
+ CheckHex32(0x12345678U);
+
+ int8_t minus_one_8bit = -1;
+ EXPECT_EQ("ff", absl::StrCat(absl::Hex(minus_one_8bit)));
+
+ int16_t minus_one_16bit = -1;
+ EXPECT_EQ("ffff", absl::StrCat(absl::Hex(minus_one_16bit)));
+}
+
+TEST(Numbers, TestFunctionsMovedOverFromNumbersMain) {
+ TestFastPrints();
+}
+
+} // namespace
diff --git a/absl/strings/str_join.h b/absl/strings/str_join.h
new file mode 100644
index 0000000..82a3cac
--- /dev/null
+++ b/absl/strings/str_join.h
@@ -0,0 +1,288 @@
+//
+// 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: str_join.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains functions for joining a range of elements and
+// returning the result as a std::string. StrJoin operations are specified by passing
+// a range, a separator std::string to use between the elements joined, and an
+// optional Formatter responsible for converting each argument in the range to a
+// std::string. If omitted, a default `AlphaNumFormatter()` is called on the elements
+// to be joined, using the same formatting that `absl::StrCat()` uses. This
+// package defines a number of default formatters, and you can define your own
+// implementations.
+//
+// Ranges are specified by passing a container with `std::begin()` and
+// `std::end()` iterators, container-specific `begin()` and `end()` iterators, a
+// brace-initialized `std::initializer_list`, or a `std::tuple` of heterogeneous
+// objects. The separator std::string is specified as an `absl::string_view`.
+//
+// Because the default formatter uses the `absl::AlphaNum` class,
+// `absl::StrJoin()`, like `absl::StrCat()`, will work out-of-the-box on
+// collections of strings, ints, floats, doubles, etc.
+//
+// Example:
+//
+// std::vector<std::string> v = {"foo", "bar", "baz"};
+// std::string s = absl::StrJoin(v, "-");
+// EXPECT_EQ("foo-bar-baz", s);
+//
+// See comments on the `absl::StrJoin()` function for more examples.
+
+#ifndef ABSL_STRINGS_STR_JOIN_H_
+#define ABSL_STRINGS_STR_JOIN_H_
+
+#include <cstdio>
+#include <cstring>
+#include <initializer_list>
+#include <iterator>
+#include <string>
+#include <tuple>
+#include <utility>
+
+#include "absl/base/macros.h"
+#include "absl/strings/internal/str_join_internal.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+
+// -----------------------------------------------------------------------------
+// Concept: Formatter
+// -----------------------------------------------------------------------------
+//
+// A Formatter is a function object that is responsible for formatting its
+// argument as a std::string and appending it to a given output std::string. Formatters
+// may be implemented as function objects, lambdas, or normal functions. You may
+// provide your own Formatter to enable `absl::StrJoin()` to work with arbitrary
+// types.
+//
+// The following is an example of a custom Formatter that simply uses
+// `std::to_string()` to format an integer as a std::string.
+//
+// struct MyFormatter {
+// void operator()(std::string* out, int i) const {
+// out->append(std::to_string(i));
+// }
+// };
+//
+// You would use the above formatter by passing an instance of it as the final
+// argument to `absl::StrJoin()`:
+//
+// std::vector<int> v = {1, 2, 3, 4};
+// std::string s = absl::StrJoin(v, "-", MyFormatter());
+// EXPECT_EQ("1-2-3-4", s);
+//
+// The following standard formatters are provided within this file:
+//
+// - `AlphaNumFormatter()` (the default)
+// - `StreamFormatter()`
+// - `PairFormatter()`
+// - `DereferenceFormatter()`
+
+// AlphaNumFormatter()
+//
+// Default formatter used if none is specified. Uses `absl::AlphaNum` to convert
+// numeric arguments to strings.
+inline strings_internal::AlphaNumFormatterImpl AlphaNumFormatter() {
+ return strings_internal::AlphaNumFormatterImpl();
+}
+
+// StreamFormatter()
+//
+// Formats its argument using the << operator.
+inline strings_internal::StreamFormatterImpl StreamFormatter() {
+ return strings_internal::StreamFormatterImpl();
+}
+
+// Function Template: PairFormatter(Formatter, absl::string_view, Formatter)
+//
+// Formats a `std::pair` by putting a given separator between the pair's
+// `.first` and `.second` members. This formatter allows you to specify
+// custom Formatters for both the first and second member of each pair.
+template <typename FirstFormatter, typename SecondFormatter>
+inline strings_internal::PairFormatterImpl<FirstFormatter, SecondFormatter>
+PairFormatter(FirstFormatter f1, absl::string_view sep, SecondFormatter f2) {
+ return strings_internal::PairFormatterImpl<FirstFormatter, SecondFormatter>(
+ std::move(f1), sep, std::move(f2));
+}
+
+// Function overload of PairFormatter() for using a default
+// `AlphaNumFormatter()` for each Formatter in the pair.
+inline strings_internal::PairFormatterImpl<
+ strings_internal::AlphaNumFormatterImpl,
+ strings_internal::AlphaNumFormatterImpl>
+PairFormatter(absl::string_view sep) {
+ return PairFormatter(AlphaNumFormatter(), sep, AlphaNumFormatter());
+}
+
+// Function Template: DereferenceFormatter(Formatter)
+//
+// Formats its argument by dereferencing it and then applying the given
+// formatter. This formatter is useful for formatting a container of
+// pointer-to-T. This pattern often shows up when joining repeated fields in
+// protocol buffers.
+template <typename Formatter>
+strings_internal::DereferenceFormatterImpl<Formatter> DereferenceFormatter(
+ Formatter&& f) {
+ return strings_internal::DereferenceFormatterImpl<Formatter>(
+ std::forward<Formatter>(f));
+}
+
+// Function overload of `DererefenceFormatter()` for using a default
+// `AlphaNumFormatter()`.
+inline strings_internal::DereferenceFormatterImpl<
+ strings_internal::AlphaNumFormatterImpl>
+DereferenceFormatter() {
+ return strings_internal::DereferenceFormatterImpl<
+ strings_internal::AlphaNumFormatterImpl>(AlphaNumFormatter());
+}
+
+// -----------------------------------------------------------------------------
+// StrJoin()
+// -----------------------------------------------------------------------------
+//
+// Joins a range of elements and returns the result as a std::string.
+// `absl::StrJoin()` takes a range, a separator std::string to use between the
+// elements joined, and an optional Formatter responsible for converting each
+// argument in the range to a std::string.
+//
+// If omitted, the default `AlphaNumFormatter()` is called on the elements to be
+// joined.
+//
+// Example 1:
+// // Joins a collection of strings. This pattern also works with a collection
+// // of `asbl::string_view` or even `const char*`.
+// std::vector<std::string> v = {"foo", "bar", "baz"};
+// std::string s = absl::StrJoin(v, "-");
+// EXPECT_EQ("foo-bar-baz", s);
+//
+// Example 2:
+// // Joins the values in the given `std::initializer_list<>` specified using
+// // brace initialization. This pattern also works with an initializer_list
+// // of ints or `absl::string_view` -- any `AlphaNum`-compatible type.
+// std::string s = absl::StrJoin({"foo", "bar", "baz"}, "-");
+// EXPECT_EQ("foo-bar-baz", s);
+//
+// Example 3:
+// // Joins a collection of ints. This pattern also works with floats,
+// // doubles, int64s -- any `StrCat()`-compatible type.
+// std::vector<int> v = {1, 2, 3, -4};
+// std::string s = absl::StrJoin(v, "-");
+// EXPECT_EQ("1-2-3--4", s);
+//
+// Example 4:
+// // Joins a collection of pointer-to-int. By default, pointers are
+// // dereferenced and the pointee is formatted using the default format for
+// // that type; such dereferencing occurs for all levels of indirection, so
+// // this pattern works just as well for `std::vector<int**>` as for
+// // `std::vector<int*>`.
+// int x = 1, y = 2, z = 3;
+// std::vector<int*> v = {&x, &y, &z};
+// std::string s = absl::StrJoin(v, "-");
+// EXPECT_EQ("1-2-3", s);
+//
+// Example 5:
+// // Dereferencing of `std::unique_ptr<>` is also supported:
+// std::vector<std::unique_ptr<int>> v
+// v.emplace_back(new int(1));
+// v.emplace_back(new int(2));
+// v.emplace_back(new int(3));
+// std::string s = absl::StrJoin(v, "-");
+// EXPECT_EQ("1-2-3", s);
+//
+// Example 6:
+// // Joins a `std::map`, with each key-value pair separated by an equals
+// // sign. This pattern would also work with, say, a
+// // `std::vector<std::pair<>>`.
+// std::map<std::string, int> m = {
+// std::make_pair("a", 1),
+// std::make_pair("b", 2),
+// std::make_pair("c", 3)};
+// std::string s = absl::StrJoin(m, ",", strings::PairFormatter("="));
+// EXPECT_EQ("a=1,b=2,c=3", s);
+//
+// Example 7:
+// // These examples show how `absl::StrJoin()` handles a few common edge
+// // cases:
+// std::vector<std::string> v_empty;
+// EXPECT_EQ("", absl::StrJoin(v_empty, "-"));
+//
+// std::vector<std::string> v_one_item = {"foo"};
+// EXPECT_EQ("foo", absl::StrJoin(v_one_item, "-"));
+//
+// std::vector<std::string> v_empty_string = {""};
+// EXPECT_EQ("", absl::StrJoin(v_empty_string, "-"));
+//
+// std::vector<std::string> v_one_item_empty_string = {"a", ""};
+// EXPECT_EQ("a-", absl::StrJoin(v_one_item_empty_string, "-"));
+//
+// std::vector<std::string> v_two_empty_string = {"", ""};
+// EXPECT_EQ("-", absl::StrJoin(v_two_empty_string, "-"));
+//
+// Example 8:
+// // Joins a `std::tuple<T...>` of heterogeneous types, converting each to
+// // a std::string using the `absl::AlphaNum` class.
+// std::string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-");
+// EXPECT_EQ("123-abc-0.456", s);
+
+template <typename Iterator, typename Formatter>
+std::string StrJoin(Iterator start, Iterator end, absl::string_view sep,
+ Formatter&& fmt) {
+ return strings_internal::JoinAlgorithm(start, end, sep, fmt);
+}
+
+template <typename Range, typename Formatter>
+std::string StrJoin(const Range& range, absl::string_view separator,
+ Formatter&& fmt) {
+ return strings_internal::JoinRange(range, separator, fmt);
+}
+
+template <typename T, typename Formatter>
+std::string StrJoin(std::initializer_list<T> il, absl::string_view separator,
+ Formatter&& fmt) {
+ return strings_internal::JoinRange(il, separator, fmt);
+}
+
+template <typename... T, typename Formatter>
+std::string StrJoin(const std::tuple<T...>& value, absl::string_view separator,
+ Formatter&& fmt) {
+ return strings_internal::JoinAlgorithm(value, separator, fmt);
+}
+
+template <typename Iterator>
+std::string StrJoin(Iterator start, Iterator end, absl::string_view separator) {
+ return strings_internal::JoinRange(start, end, separator);
+}
+
+template <typename Range>
+std::string StrJoin(const Range& range, absl::string_view separator) {
+ return strings_internal::JoinRange(range, separator);
+}
+
+template <typename T>
+std::string StrJoin(std::initializer_list<T> il, absl::string_view separator) {
+ return strings_internal::JoinRange(il, separator);
+}
+
+template <typename... T>
+std::string StrJoin(const std::tuple<T...>& value, absl::string_view separator) {
+ return strings_internal::JoinAlgorithm(value, separator, AlphaNumFormatter());
+}
+
+} // namespace absl
+
+#endif // ABSL_STRINGS_STR_JOIN_H_
diff --git a/absl/strings/str_join_test.cc b/absl/strings/str_join_test.cc
new file mode 100644
index 0000000..7c2ed09
--- /dev/null
+++ b/absl/strings/str_join_test.cc
@@ -0,0 +1,474 @@
+// 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 tests for all join.h functions
+
+#include "absl/strings/str_join.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <initializer_list>
+#include <map>
+#include <ostream>
+#include <random>
+#include <set>
+#include <tuple>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_split.h"
+
+namespace {
+
+TEST(StrJoin, APIExamples) {
+ {
+ // Collection of strings
+ std::vector<std::string> v = {"foo", "bar", "baz"};
+ EXPECT_EQ("foo-bar-baz", absl::StrJoin(v, "-"));
+ }
+
+ {
+ // Collection of absl::string_view
+ std::vector<absl::string_view> v = {"foo", "bar", "baz"};
+ EXPECT_EQ("foo-bar-baz", absl::StrJoin(v, "-"));
+ }
+
+ {
+ // Collection of const char*
+ std::vector<const char*> v = {"foo", "bar", "baz"};
+ EXPECT_EQ("foo-bar-baz", absl::StrJoin(v, "-"));
+ }
+
+ {
+ // Collection of non-const char*
+ std::string a = "foo", b = "bar", c = "baz";
+ std::vector<char*> v = {&a[0], &b[0], &c[0]};
+ EXPECT_EQ("foo-bar-baz", absl::StrJoin(v, "-"));
+ }
+
+ {
+ // Collection of ints
+ std::vector<int> v = {1, 2, 3, -4};
+ EXPECT_EQ("1-2-3--4", absl::StrJoin(v, "-"));
+ }
+
+ {
+ // Literals passed as a std::initializer_list
+ std::string s = absl::StrJoin({"a", "b", "c"}, "-");
+ EXPECT_EQ("a-b-c", s);
+ }
+ {
+ // Join a std::tuple<T...>.
+ std::string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-");
+ EXPECT_EQ("123-abc-0.456", s);
+ }
+
+ {
+ // Collection of unique_ptrs
+ std::vector<std::unique_ptr<int>> v;
+ v.emplace_back(new int(1));
+ v.emplace_back(new int(2));
+ v.emplace_back(new int(3));
+ EXPECT_EQ("1-2-3", absl::StrJoin(v, "-"));
+ }
+
+ {
+ // Array of ints
+ const int a[] = {1, 2, 3, -4};
+ EXPECT_EQ("1-2-3--4", absl::StrJoin(a, a + ABSL_ARRAYSIZE(a), "-"));
+ }
+
+ {
+ // Collection of pointers
+ int x = 1, y = 2, z = 3;
+ std::vector<int*> v = {&x, &y, &z};
+ EXPECT_EQ("1-2-3", absl::StrJoin(v, "-"));
+ }
+
+ {
+ // Collection of pointers to pointers
+ int x = 1, y = 2, z = 3;
+ int *px = &x, *py = &y, *pz = &z;
+ std::vector<int**> v = {&px, &py, &pz};
+ EXPECT_EQ("1-2-3", absl::StrJoin(v, "-"));
+ }
+
+ {
+ // Collection of pointers to std::string
+ std::string a("a"), b("b");
+ std::vector<std::string*> v = {&a, &b};
+ EXPECT_EQ("a-b", absl::StrJoin(v, "-"));
+ }
+
+ {
+ // A std::map, which is a collection of std::pair<>s.
+ std::map<std::string, int> m = { {"a", 1}, {"b", 2}, {"c", 3} };
+ EXPECT_EQ("a=1,b=2,c=3", absl::StrJoin(m, ",", absl::PairFormatter("=")));
+ }
+
+ {
+ // Shows absl::StrSplit and absl::StrJoin working together. This example is
+ // equivalent to s/=/-/g.
+ const std::string s = "a=b=c=d";
+ EXPECT_EQ("a-b-c-d", absl::StrJoin(absl::StrSplit(s, "="), "-"));
+ }
+
+ //
+ // A few examples of edge cases
+ //
+
+ {
+ // Empty range yields an empty std::string.
+ std::vector<std::string> v;
+ EXPECT_EQ("", absl::StrJoin(v, "-"));
+ }
+
+ {
+ // A range of 1 element gives a std::string with that element but no separator.
+ std::vector<std::string> v = {"foo"};
+ EXPECT_EQ("foo", absl::StrJoin(v, "-"));
+ }
+
+ {
+ // A range with a single empty std::string element
+ std::vector<std::string> v = {""};
+ EXPECT_EQ("", absl::StrJoin(v, "-"));
+ }
+
+ {
+ // A range with 2 elements, one of which is an empty std::string
+ std::vector<std::string> v = {"a", ""};
+ EXPECT_EQ("a-", absl::StrJoin(v, "-"));
+ }
+
+ {
+ // A range with 2 empty elements.
+ std::vector<std::string> v = {"", ""};
+ EXPECT_EQ("-", absl::StrJoin(v, "-"));
+ }
+
+ {
+ // A std::vector of bool.
+ std::vector<bool> v = {true, false, true};
+ EXPECT_EQ("1-0-1", absl::StrJoin(v, "-"));
+ }
+}
+
+TEST(StrJoin, CustomFormatter) {
+ std::vector<std::string> v{"One", "Two", "Three"};
+ {
+ std::string joined = absl::StrJoin(v, "", [](std::string* out, const std::string& in) {
+ absl::StrAppend(out, "(", in, ")");
+ });
+ EXPECT_EQ("(One)(Two)(Three)", joined);
+ }
+ {
+ class ImmovableFormatter {
+ public:
+ void operator()(std::string* out, const std::string& in) {
+ absl::StrAppend(out, "(", in, ")");
+ }
+ ImmovableFormatter() {}
+ ImmovableFormatter(const ImmovableFormatter&) = delete;
+ };
+ EXPECT_EQ("(One)(Two)(Three)", absl::StrJoin(v, "", ImmovableFormatter()));
+ }
+ {
+ class OverloadedFormatter {
+ public:
+ void operator()(std::string* out, const std::string& in) {
+ absl::StrAppend(out, "(", in, ")");
+ }
+ void operator()(std::string* out, const std::string& in) const {
+ absl::StrAppend(out, "[", in, "]");
+ }
+ };
+ EXPECT_EQ("(One)(Two)(Three)", absl::StrJoin(v, "", OverloadedFormatter()));
+ const OverloadedFormatter fmt = {};
+ EXPECT_EQ("[One][Two][Three]", absl::StrJoin(v, "", fmt));
+ }
+}
+
+//
+// Tests the Formatters
+//
+
+TEST(AlphaNumFormatter, FormatterAPI) {
+ // Not an exhaustive test. See strings/strcat_test.h for the exhaustive test
+ // of what AlphaNum can convert.
+ auto f = absl::AlphaNumFormatter();
+ std::string s;
+ f(&s, "Testing: ");
+ f(&s, static_cast<int>(1));
+ f(&s, static_cast<int16_t>(2));
+ f(&s, static_cast<int64_t>(3));
+ f(&s, static_cast<float>(4));
+ f(&s, static_cast<double>(5));
+ f(&s, static_cast<unsigned>(6));
+ f(&s, static_cast<size_t>(7));
+ f(&s, absl::string_view(" OK"));
+ EXPECT_EQ("Testing: 1234567 OK", s);
+}
+
+// Make sure people who are mistakenly using std::vector<bool> even though
+// they're not memory-constrained can use absl::AlphaNumFormatter().
+TEST(AlphaNumFormatter, VectorOfBool) {
+ auto f = absl::AlphaNumFormatter();
+ std::string s;
+ std::vector<bool> v = {true, false, true};
+ f(&s, *v.cbegin());
+ f(&s, *v.begin());
+ f(&s, v[1]);
+ EXPECT_EQ("110", s);
+}
+
+TEST(AlphaNumFormatter, AlphaNum) {
+ auto f = absl::AlphaNumFormatter();
+ std::string s;
+ f(&s, absl::AlphaNum("hello"));
+ EXPECT_EQ("hello", s);
+}
+
+struct StreamableType {
+ std::string contents;
+};
+inline std::ostream& operator<<(std::ostream& os, const StreamableType& t) {
+ os << "Streamable:" << t.contents;
+ return os;
+}
+
+TEST(StreamFormatter, FormatterAPI) {
+ auto f = absl::StreamFormatter();
+ std::string s;
+ f(&s, "Testing: ");
+ f(&s, static_cast<int>(1));
+ f(&s, static_cast<int16_t>(2));
+ f(&s, static_cast<int64_t>(3));
+ f(&s, static_cast<float>(4));
+ f(&s, static_cast<double>(5));
+ f(&s, static_cast<unsigned>(6));
+ f(&s, static_cast<size_t>(7));
+ f(&s, absl::string_view(" OK "));
+ StreamableType streamable = {"object"};
+ f(&s, streamable);
+ EXPECT_EQ("Testing: 1234567 OK Streamable:object", s);
+}
+
+// A dummy formatter that wraps each element in parens. Used in some tests
+// below.
+struct TestingParenFormatter {
+ template <typename T>
+ void operator()(std::string* s, const T& t) {
+ absl::StrAppend(s, "(", t, ")");
+ }
+};
+
+TEST(PairFormatter, FormatterAPI) {
+ {
+ // Tests default PairFormatter(sep) that uses AlphaNumFormatter for the
+ // 'first' and 'second' members.
+ const auto f = absl::PairFormatter("=");
+ std::string s;
+ f(&s, std::make_pair("a", "b"));
+ f(&s, std::make_pair(1, 2));
+ EXPECT_EQ("a=b1=2", s);
+ }
+
+ {
+ // Tests using a custom formatter for the 'first' and 'second' members.
+ auto f = absl::PairFormatter(TestingParenFormatter(), "=",
+ TestingParenFormatter());
+ std::string s;
+ f(&s, std::make_pair("a", "b"));
+ f(&s, std::make_pair(1, 2));
+ EXPECT_EQ("(a)=(b)(1)=(2)", s);
+ }
+}
+
+TEST(DereferenceFormatter, FormatterAPI) {
+ {
+ // Tests wrapping the default AlphaNumFormatter.
+ const absl::strings_internal::DereferenceFormatterImpl<
+ absl::strings_internal::AlphaNumFormatterImpl>
+ f;
+ int x = 1, y = 2, z = 3;
+ std::string s;
+ f(&s, &x);
+ f(&s, &y);
+ f(&s, &z);
+ EXPECT_EQ("123", s);
+ }
+
+ {
+ // Tests wrapping std::string's default formatter.
+ absl::strings_internal::DereferenceFormatterImpl<
+ absl::strings_internal::DefaultFormatter<std::string>::Type>
+ f;
+
+ std::string x = "x";
+ std::string y = "y";
+ std::string z = "z";
+ std::string s;
+ f(&s, &x);
+ f(&s, &y);
+ f(&s, &z);
+ EXPECT_EQ(s, "xyz");
+ }
+
+ {
+ // Tests wrapping a custom formatter.
+ auto f = absl::DereferenceFormatter(TestingParenFormatter());
+ int x = 1, y = 2, z = 3;
+ std::string s;
+ f(&s, &x);
+ f(&s, &y);
+ f(&s, &z);
+ EXPECT_EQ("(1)(2)(3)", s);
+ }
+
+ {
+ absl::strings_internal::DereferenceFormatterImpl<
+ absl::strings_internal::AlphaNumFormatterImpl>
+ f;
+ auto x = std::unique_ptr<int>(new int(1));
+ auto y = std::unique_ptr<int>(new int(2));
+ auto z = std::unique_ptr<int>(new int(3));
+ std::string s;
+ f(&s, x);
+ f(&s, y);
+ f(&s, z);
+ EXPECT_EQ("123", s);
+ }
+}
+
+//
+// Tests the interfaces for the 4 public Join function overloads. The semantics
+// of the algorithm is covered in the above APIExamples test.
+//
+TEST(StrJoin, PublicAPIOverloads) {
+ std::vector<std::string> v = {"a", "b", "c"};
+
+ // Iterators + formatter
+ EXPECT_EQ("a-b-c",
+ absl::StrJoin(v.begin(), v.end(), "-", absl::AlphaNumFormatter()));
+ // Range + formatter
+ EXPECT_EQ("a-b-c", absl::StrJoin(v, "-", absl::AlphaNumFormatter()));
+ // Iterators, no formatter
+ EXPECT_EQ("a-b-c", absl::StrJoin(v.begin(), v.end(), "-"));
+ // Range, no formatter
+ EXPECT_EQ("a-b-c", absl::StrJoin(v, "-"));
+}
+
+TEST(StrJoin, Array) {
+ const absl::string_view a[] = {"a", "b", "c"};
+ EXPECT_EQ("a-b-c", absl::StrJoin(a, "-"));
+}
+
+TEST(StrJoin, InitializerList) {
+ { EXPECT_EQ("a-b-c", absl::StrJoin({"a", "b", "c"}, "-")); }
+
+ {
+ auto a = {"a", "b", "c"};
+ EXPECT_EQ("a-b-c", absl::StrJoin(a, "-"));
+ }
+
+ {
+ std::initializer_list<const char*> a = {"a", "b", "c"};
+ EXPECT_EQ("a-b-c", absl::StrJoin(a, "-"));
+ }
+
+ {
+ std::initializer_list<std::string> a = {"a", "b", "c"};
+ EXPECT_EQ("a-b-c", absl::StrJoin(a, "-"));
+ }
+
+ {
+ std::initializer_list<absl::string_view> a = {"a", "b", "c"};
+ EXPECT_EQ("a-b-c", absl::StrJoin(a, "-"));
+ }
+
+ {
+ // Tests initializer_list with a non-default formatter
+ auto a = {"a", "b", "c"};
+ TestingParenFormatter f;
+ EXPECT_EQ("(a)-(b)-(c)", absl::StrJoin(a, "-", f));
+ }
+
+ {
+ // initializer_list of ints
+ EXPECT_EQ("1-2-3", absl::StrJoin({1, 2, 3}, "-"));
+ }
+
+ {
+ // Tests initializer_list of ints with a non-default formatter
+ auto a = {1, 2, 3};
+ TestingParenFormatter f;
+ EXPECT_EQ("(1)-(2)-(3)", absl::StrJoin(a, "-", f));
+ }
+}
+
+TEST(StrJoin, Tuple) {
+ EXPECT_EQ("", absl::StrJoin(std::make_tuple(), "-"));
+ EXPECT_EQ("hello", absl::StrJoin(std::make_tuple("hello"), "-"));
+
+ int x(10);
+ std::string y("hello");
+ double z(3.14);
+ EXPECT_EQ("10-hello-3.14", absl::StrJoin(std::make_tuple(x, y, z), "-"));
+
+ // Faster! Faster!!
+ EXPECT_EQ("10-hello-3.14",
+ absl::StrJoin(std::make_tuple(x, std::cref(y), z), "-"));
+
+ struct TestFormatter {
+ char buffer[128];
+ void operator()(std::string* out, int v) {
+ snprintf(buffer, sizeof(buffer), "%#.8x", v);
+ out->append(buffer);
+ }
+ void operator()(std::string* out, double v) {
+ snprintf(buffer, sizeof(buffer), "%#.0f", v);
+ out->append(buffer);
+ }
+ void operator()(std::string* out, const std::string& v) {
+ snprintf(buffer, sizeof(buffer), "%.4s", v.c_str());
+ out->append(buffer);
+ }
+ };
+ EXPECT_EQ("0x0000000a-hell-3.",
+ absl::StrJoin(std::make_tuple(x, y, z), "-", TestFormatter()));
+ EXPECT_EQ(
+ "0x0000000a-hell-3.",
+ absl::StrJoin(std::make_tuple(x, std::cref(y), z), "-", TestFormatter()));
+ EXPECT_EQ("0x0000000a-hell-3.",
+ absl::StrJoin(std::make_tuple(&x, &y, &z), "-",
+ absl::DereferenceFormatter(TestFormatter())));
+ EXPECT_EQ("0x0000000a-hell-3.",
+ absl::StrJoin(std::make_tuple(absl::make_unique<int>(x),
+ absl::make_unique<std::string>(y),
+ absl::make_unique<double>(z)),
+ "-", absl::DereferenceFormatter(TestFormatter())));
+ EXPECT_EQ("0x0000000a-hell-3.",
+ absl::StrJoin(std::make_tuple(absl::make_unique<int>(x), &y, &z),
+ "-", absl::DereferenceFormatter(TestFormatter())));
+}
+
+} // namespace
diff --git a/absl/strings/str_replace.cc b/absl/strings/str_replace.cc
new file mode 100644
index 0000000..69efa35
--- /dev/null
+++ b/absl/strings/str_replace.cc
@@ -0,0 +1,79 @@
+// 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/strings/str_replace.h"
+
+#include "absl/strings/str_cat.h"
+
+namespace absl {
+namespace strings_internal {
+
+using FixedMapping =
+ std::initializer_list<std::pair<absl::string_view, absl::string_view>>;
+
+// Applies the ViableSubstitutions in subs_ptr to the absl::string_view s, and
+// stores the result in *result_ptr. Returns the number of substitutions that
+// occurred.
+int ApplySubstitutions(
+ absl::string_view s,
+ std::vector<strings_internal::ViableSubstitution>* subs_ptr,
+ std::string* result_ptr) {
+ auto& subs = *subs_ptr;
+ int substitutions = 0;
+ size_t pos = 0;
+ while (!subs.empty()) {
+ auto& sub = subs.back();
+ if (sub.offset >= pos) {
+ if (pos <= s.size()) {
+ StrAppend(result_ptr, s.substr(pos, sub.offset - pos), sub.replacement);
+ }
+ pos = sub.offset + sub.old.size();
+ substitutions += 1;
+ }
+ sub.offset = s.find(sub.old, pos);
+ if (sub.offset == s.npos) {
+ subs.pop_back();
+ } else {
+ // Insertion sort to ensure the last ViableSubstitution continues to be
+ // before all the others.
+ size_t index = subs.size();
+ while (--index && subs[index - 1].OccursBefore(subs[index])) {
+ std::swap(subs[index], subs[index - 1]);
+ }
+ }
+ }
+ result_ptr->append(s.data() + pos, s.size() - pos);
+ return substitutions;
+}
+
+} // namespace strings_internal
+
+// We can implement this in terms of the generic StrReplaceAll, but
+// we must specify the template overload because C++ cannot deduce the type
+// of an initializer_list parameter to a function, and also if we don't specify
+// the type, we just call ourselves.
+//
+// Note that we implement them here, rather than in the header, so that they
+// aren't inlined.
+
+std::string StrReplaceAll(absl::string_view s,
+ strings_internal::FixedMapping replacements) {
+ return StrReplaceAll<strings_internal::FixedMapping>(s, replacements);
+}
+
+int StrReplaceAll(strings_internal::FixedMapping replacements, std::string* target) {
+ return StrReplaceAll<strings_internal::FixedMapping>(replacements, target);
+}
+
+} // namespace absl
diff --git a/absl/strings/str_replace.h b/absl/strings/str_replace.h
new file mode 100644
index 0000000..f4d9bb9
--- /dev/null
+++ b/absl/strings/str_replace.h
@@ -0,0 +1,213 @@
+//
+// 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: str_replace.h
+// -----------------------------------------------------------------------------
+//
+// This file defines `absl::StrReplaceAll()`, a general-purpose std::string
+// replacement function designed for large, arbitrary text substitutions,
+// especially on strings which you are receiving from some other system for
+// further processing (e.g. processing regular expressions, escaping HTML
+// entities, etc. `StrReplaceAll` is designed to be efficient even when only
+// one substitution is being performed, or when substitution is rare.
+//
+// If the std::string being modified is known at compile-time, and the substitutions
+// vary, `absl::Substitute()` may be a better choice.
+//
+// Example:
+//
+// std::string html_escaped = absl::StrReplaceAll(user_input, {
+// {"&", "&amp;"},
+// {"<", "&lt;"},
+// {">", "&gt;"},
+// {"\"", "&quot;"},
+// {"'", "&#39;"}});
+#ifndef ABSL_STRINGS_STR_REPLACE_H_
+#define ABSL_STRINGS_STR_REPLACE_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/base/attributes.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+
+// StrReplaceAll()
+//
+// Replaces character sequences within a given std::string with replacements provided
+// within an initializer list of key/value pairs. Candidate replacements are
+// considered in order as they occur within the std::string, with earlier matches
+// taking precedence, and longer matches taking precedence for candidates
+// starting at the same position in the std::string. Once a substitution is made, the
+// replaced text is not considered for any further substitutions.
+//
+// Example:
+//
+// std::string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!",
+// {{"$count", absl::StrCat(5)},
+// {"$who", "Bob"},
+// {"#Noun", "Apples"}});
+// EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
+ABSL_MUST_USE_RESULT std::string StrReplaceAll(
+ absl::string_view s,
+ std::initializer_list<std::pair<absl::string_view, absl::string_view>>
+ replacements);
+
+// Overload of `StrReplaceAll()` to accept a container of key/value replacement
+// pairs (typically either an associative map or a `std::vector` of `std::pair`
+// elements). A vector of pairs is generally more efficient.
+//
+// Examples:
+//
+// std::map<const absl::string_view, const absl::string_view> replacements;
+// replacements["$who"] = "Bob";
+// replacements["$count"] = "5";
+// replacements["#Noun"] = "Apples";
+// std::string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!",
+// replacements);
+// EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
+//
+// // A std::vector of std::pair elements can be more efficient.
+// std::vector<std::pair<const absl::string_view, std::string>> replacements;
+// replacements.push_back({"&", "&amp;"});
+// replacements.push_back({"<", "&lt;"});
+// replacements.push_back({">", "&gt;"});
+// std::string s = absl::StrReplaceAll("if (ptr < &foo)",
+// replacements);
+// EXPECT_EQ("if (ptr &lt; &amp;foo)", s);
+template <typename StrToStrMapping>
+std::string StrReplaceAll(absl::string_view s, const StrToStrMapping& replacements);
+
+// Overload of `StrReplaceAll()` to replace character sequences within a given
+// output std::string *in place* with replacements provided within an initializer
+// list of key/value pairs, returning the number of substitutions that occurred.
+//
+// Example:
+//
+// std::string s = std::string("$who bought $count #Noun. Thanks $who!");
+// int count;
+// count = absl::StrReplaceAll({{"$count", absl::StrCat(5)},
+// {"$who", "Bob"},
+// {"#Noun", "Apples"}}, &s);
+// EXPECT_EQ(count, 4);
+// EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
+int StrReplaceAll(
+ std::initializer_list<std::pair<absl::string_view, absl::string_view>>
+ replacements,
+ std::string* target);
+
+// Overload of `StrReplaceAll()` to replace patterns within a given output
+// std::string *in place* with replacements provided within a container of key/value
+// pairs.
+//
+// Example:
+//
+// std::string s = std::string("if (ptr < &foo)");
+// int count = absl::StrReplaceAll({{"&", "&amp;"},
+// {"<", "&lt;"},
+// {">", "&gt;"}}, &s);
+// EXPECT_EQ(count, 2);
+// EXPECT_EQ("if (ptr &lt; &amp;foo)", s);
+template <typename StrToStrMapping>
+int StrReplaceAll(const StrToStrMapping& replacements, std::string* target);
+
+// Implementation details only, past this point.
+namespace strings_internal {
+
+struct ViableSubstitution {
+ absl::string_view old;
+ absl::string_view replacement;
+ size_t offset;
+
+ ViableSubstitution(absl::string_view old_str,
+ absl::string_view replacement_str, size_t offset_val)
+ : old(old_str), replacement(replacement_str), offset(offset_val) {}
+
+ // One substitution occurs "before" another (takes priority) if either
+ // it has the lowest offset, or it has the same offset but a larger size.
+ bool OccursBefore(const ViableSubstitution& y) const {
+ if (offset != y.offset) return offset < y.offset;
+ return old.size() > y.old.size();
+ }
+};
+
+// Build a vector of ViableSubstitutions based on the given list of
+// replacements. subs can be implemented as a priority_queue. However, it turns
+// out that most callers have small enough a list of substitutions that the
+// overhead of such a queue isn't worth it.
+template <typename StrToStrMapping>
+std::vector<ViableSubstitution> FindSubstitutions(
+ absl::string_view s, const StrToStrMapping& replacements) {
+ std::vector<ViableSubstitution> subs;
+ subs.reserve(replacements.size());
+
+ for (const auto& rep : replacements) {
+ using std::get;
+ absl::string_view old(get<0>(rep));
+
+ size_t pos = s.find(old);
+ if (pos == s.npos) continue;
+
+ // Ignore attempts to replace "". This condition is almost never true,
+ // but above condition is frequently true. That's why we test for this
+ // now and not before.
+ if (old.empty()) continue;
+
+ subs.emplace_back(old, get<1>(rep), pos);
+
+ // Insertion sort to ensure the last ViableSubstitution comes before
+ // all the others.
+ size_t index = subs.size();
+ while (--index && subs[index - 1].OccursBefore(subs[index])) {
+ std::swap(subs[index], subs[index - 1]);
+ }
+ }
+ return subs;
+}
+
+int ApplySubstitutions(absl::string_view s,
+ std::vector<ViableSubstitution>* subs_ptr,
+ std::string* result_ptr);
+
+} // namespace strings_internal
+
+template <typename StrToStrMapping>
+std::string StrReplaceAll(absl::string_view s, const StrToStrMapping& replacements) {
+ auto subs = strings_internal::FindSubstitutions(s, replacements);
+ std::string result;
+ result.reserve(s.size());
+ strings_internal::ApplySubstitutions(s, &subs, &result);
+ return result;
+}
+
+template <typename StrToStrMapping>
+int StrReplaceAll(const StrToStrMapping& replacements, std::string* target) {
+ auto subs = strings_internal::FindSubstitutions(*target, replacements);
+ if (subs.empty()) return 0;
+
+ std::string result;
+ result.reserve(target->size());
+ int substitutions =
+ strings_internal::ApplySubstitutions(*target, &subs, &result);
+ target->swap(result);
+ return substitutions;
+}
+
+} // namespace absl
+
+#endif // ABSL_STRINGS_STR_REPLACE_H_
diff --git a/absl/strings/str_replace_test.cc b/absl/strings/str_replace_test.cc
new file mode 100644
index 0000000..f49c7e1
--- /dev/null
+++ b/absl/strings/str_replace_test.cc
@@ -0,0 +1,340 @@
+// 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/strings/str_replace.h"
+
+#include <list>
+#include <tuple>
+
+#include "gtest/gtest.h"
+#include "absl/strings/str_split.h"
+#include "absl/strings/str_cat.h"
+
+TEST(StrReplaceAll, OneReplacement) {
+ std::string s;
+
+ // Empty std::string.
+ s = absl::StrReplaceAll(s, {{"", ""}});
+ EXPECT_EQ(s, "");
+ s = absl::StrReplaceAll(s, {{"x", ""}});
+ EXPECT_EQ(s, "");
+ s = absl::StrReplaceAll(s, {{"", "y"}});
+ EXPECT_EQ(s, "");
+ s = absl::StrReplaceAll(s, {{"x", "y"}});
+ EXPECT_EQ(s, "");
+
+ // Empty substring.
+ s = absl::StrReplaceAll("abc", {{"", ""}});
+ EXPECT_EQ(s, "abc");
+ s = absl::StrReplaceAll("abc", {{"", "y"}});
+ EXPECT_EQ(s, "abc");
+ s = absl::StrReplaceAll("abc", {{"x", ""}});
+ EXPECT_EQ(s, "abc");
+
+ // Substring not found.
+ s = absl::StrReplaceAll("abc", {{"xyz", "123"}});
+ EXPECT_EQ(s, "abc");
+
+ // Replace entire std::string.
+ s = absl::StrReplaceAll("abc", {{"abc", "xyz"}});
+ EXPECT_EQ(s, "xyz");
+
+ // Replace once at the start.
+ s = absl::StrReplaceAll("abc", {{"a", "x"}});
+ EXPECT_EQ(s, "xbc");
+
+ // Replace once in the middle.
+ s = absl::StrReplaceAll("abc", {{"b", "x"}});
+ EXPECT_EQ(s, "axc");
+
+ // Replace once at the end.
+ s = absl::StrReplaceAll("abc", {{"c", "x"}});
+ EXPECT_EQ(s, "abx");
+
+ // Replace multiple times with varying lengths of original/replacement.
+ s = absl::StrReplaceAll("ababa", {{"a", "xxx"}});
+ EXPECT_EQ(s, "xxxbxxxbxxx");
+
+ s = absl::StrReplaceAll("ababa", {{"b", "xxx"}});
+ EXPECT_EQ(s, "axxxaxxxa");
+
+ s = absl::StrReplaceAll("aaabaaabaaa", {{"aaa", "x"}});
+ EXPECT_EQ(s, "xbxbx");
+
+ s = absl::StrReplaceAll("abbbabbba", {{"bbb", "x"}});
+ EXPECT_EQ(s, "axaxa");
+
+ // Overlapping matches are replaced greedily.
+ s = absl::StrReplaceAll("aaa", {{"aa", "x"}});
+ EXPECT_EQ(s, "xa");
+
+ // The replacements are not recursive.
+ s = absl::StrReplaceAll("aaa", {{"aa", "a"}});
+ EXPECT_EQ(s, "aa");
+}
+
+TEST(StrReplaceAll, ManyReplacements) {
+ std::string s;
+
+ // Empty std::string.
+ s = absl::StrReplaceAll("", {{"", ""}, {"x", ""}, {"", "y"}, {"x", "y"}});
+ EXPECT_EQ(s, "");
+
+ // Empty substring.
+ s = absl::StrReplaceAll("abc", {{"", ""}, {"", "y"}, {"x", ""}});
+ EXPECT_EQ(s, "abc");
+
+ // Replace entire std::string, one char at a time
+ s = absl::StrReplaceAll("abc", {{"a", "x"}, {"b", "y"}, {"c", "z"}});
+ EXPECT_EQ(s, "xyz");
+ s = absl::StrReplaceAll("zxy", {{"z", "x"}, {"x", "y"}, {"y", "z"}});
+ EXPECT_EQ(s, "xyz");
+
+ // Replace once at the start (longer matches take precedence)
+ s = absl::StrReplaceAll("abc", {{"a", "x"}, {"ab", "xy"}, {"abc", "xyz"}});
+ EXPECT_EQ(s, "xyz");
+
+ // Replace once in the middle.
+ s = absl::StrReplaceAll(
+ "Abc!", {{"a", "x"}, {"ab", "xy"}, {"b", "y"}, {"bc", "yz"}, {"c", "z"}});
+ EXPECT_EQ(s, "Ayz!");
+
+ // Replace once at the end.
+ s = absl::StrReplaceAll(
+ "Abc!",
+ {{"a", "x"}, {"ab", "xy"}, {"b", "y"}, {"bc!", "yz?"}, {"c!", "z;"}});
+ EXPECT_EQ(s, "Ayz?");
+
+ // Replace multiple times with varying lengths of original/replacement.
+ s = absl::StrReplaceAll("ababa", {{"a", "xxx"}, {"b", "XXXX"}});
+ EXPECT_EQ(s, "xxxXXXXxxxXXXXxxx");
+
+ // Overlapping matches are replaced greedily.
+ s = absl::StrReplaceAll("aaa", {{"aa", "x"}, {"a", "X"}});
+ EXPECT_EQ(s, "xX");
+ s = absl::StrReplaceAll("aaa", {{"a", "X"}, {"aa", "x"}});
+ EXPECT_EQ(s, "xX");
+
+ // Two well-known sentences
+ s = absl::StrReplaceAll("the quick brown fox jumped over the lazy dogs",
+ {
+ {"brown", "box"},
+ {"dogs", "jugs"},
+ {"fox", "with"},
+ {"jumped", "five"},
+ {"over", "dozen"},
+ {"quick", "my"},
+ {"the", "pack"},
+ {"the lazy", "liquor"},
+ });
+ EXPECT_EQ(s, "pack my box with five dozen liquor jugs");
+}
+
+TEST(StrReplaceAll, ManyReplacementsInMap) {
+ std::map<const char *, const char *> replacements;
+ replacements["$who"] = "Bob";
+ replacements["$count"] = "5";
+ replacements["#Noun"] = "Apples";
+ std::string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!",
+ replacements);
+ EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
+}
+
+TEST(StrReplaceAll, ReplacementsInPlace) {
+ std::string s = std::string("$who bought $count #Noun. Thanks $who!");
+ int count;
+ count = absl::StrReplaceAll({{"$count", absl::StrCat(5)},
+ {"$who", "Bob"},
+ {"#Noun", "Apples"}}, &s);
+ EXPECT_EQ(count, 4);
+ EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
+}
+
+TEST(StrReplaceAll, ReplacementsInPlaceInMap) {
+ std::string s = std::string("$who bought $count #Noun. Thanks $who!");
+ std::map<absl::string_view, absl::string_view> replacements;
+ replacements["$who"] = "Bob";
+ replacements["$count"] = "5";
+ replacements["#Noun"] = "Apples";
+ int count;
+ count = absl::StrReplaceAll(replacements, &s);
+ EXPECT_EQ(count, 4);
+ EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
+}
+
+struct Cont {
+ Cont() {}
+ explicit Cont(absl::string_view src) : data(src) {}
+
+ absl::string_view data;
+};
+
+template <int index>
+absl::string_view get(const Cont& c) {
+ auto splitter = absl::StrSplit(c.data, ':');
+ auto it = splitter.begin();
+ for (int i = 0; i < index; ++i) ++it;
+
+ return *it;
+}
+
+TEST(StrReplaceAll, VariableNumber) {
+ std::string s;
+ {
+ std::vector<std::pair<std::string, std::string>> replacements;
+
+ s = "abc";
+ EXPECT_EQ(0, absl::StrReplaceAll(replacements, &s));
+ EXPECT_EQ("abc", s);
+
+ s = "abc";
+ replacements.push_back({"a", "A"});
+ EXPECT_EQ(1, absl::StrReplaceAll(replacements, &s));
+ EXPECT_EQ("Abc", s);
+
+ s = "abc";
+ replacements.push_back({"b", "B"});
+ EXPECT_EQ(2, absl::StrReplaceAll(replacements, &s));
+ EXPECT_EQ("ABc", s);
+
+ s = "abc";
+ replacements.push_back({"d", "D"});
+ EXPECT_EQ(2, absl::StrReplaceAll(replacements, &s));
+ EXPECT_EQ("ABc", s);
+
+ EXPECT_EQ("ABcABc", absl::StrReplaceAll("abcabc", replacements));
+ }
+
+ {
+ std::map<const char*, const char*> replacements;
+ replacements["aa"] = "x";
+ replacements["a"] = "X";
+ s = "aaa";
+ EXPECT_EQ(2, absl::StrReplaceAll(replacements, &s));
+ EXPECT_EQ("xX", s);
+
+ EXPECT_EQ("xxX", absl::StrReplaceAll("aaaaa", replacements));
+ }
+
+ {
+ std::list<std::pair<absl::string_view, absl::string_view>> replacements = {
+ {"a", "x"}, {"b", "y"}, {"c", "z"}};
+
+ std::string s = absl::StrReplaceAll("abc", replacements);
+ EXPECT_EQ(s, "xyz");
+ }
+
+ {
+ using X = std::tuple<absl::string_view, std::string, int>;
+ std::vector<X> replacements(3);
+ replacements[0] = X{"a", "x", 1};
+ replacements[1] = X{"b", "y", 0};
+ replacements[2] = X{"c", "z", -1};
+
+ std::string s = absl::StrReplaceAll("abc", replacements);
+ EXPECT_EQ(s, "xyz");
+ }
+
+ {
+ std::vector<Cont> replacements(3);
+ replacements[0] = Cont{"a:x"};
+ replacements[1] = Cont{"b:y"};
+ replacements[2] = Cont{"c:z"};
+
+ std::string s = absl::StrReplaceAll("abc", replacements);
+ EXPECT_EQ(s, "xyz");
+ }
+}
+
+// Same as above, but using the in-place variant of absl::StrReplaceAll,
+// that returns the # of replacements performed.
+TEST(StrReplaceAll, Inplace) {
+ std::string s;
+ int reps;
+
+ // Empty std::string.
+ s = "";
+ reps = absl::StrReplaceAll({{"", ""}, {"x", ""}, {"", "y"}, {"x", "y"}}, &s);
+ EXPECT_EQ(reps, 0);
+ EXPECT_EQ(s, "");
+
+ // Empty substring.
+ s = "abc";
+ reps = absl::StrReplaceAll({{"", ""}, {"", "y"}, {"x", ""}}, &s);
+ EXPECT_EQ(reps, 0);
+ EXPECT_EQ(s, "abc");
+
+ // Replace entire std::string, one char at a time
+ s = "abc";
+ reps = absl::StrReplaceAll({{"a", "x"}, {"b", "y"}, {"c", "z"}}, &s);
+ EXPECT_EQ(reps, 3);
+ EXPECT_EQ(s, "xyz");
+ s = "zxy";
+ reps = absl::StrReplaceAll({{"z", "x"}, {"x", "y"}, {"y", "z"}}, &s);
+ EXPECT_EQ(reps, 3);
+ EXPECT_EQ(s, "xyz");
+
+ // Replace once at the start (longer matches take precedence)
+ s = "abc";
+ reps = absl::StrReplaceAll({{"a", "x"}, {"ab", "xy"}, {"abc", "xyz"}}, &s);
+ EXPECT_EQ(reps, 1);
+ EXPECT_EQ(s, "xyz");
+
+ // Replace once in the middle.
+ s = "Abc!";
+ reps = absl::StrReplaceAll(
+ {{"a", "x"}, {"ab", "xy"}, {"b", "y"}, {"bc", "yz"}, {"c", "z"}}, &s);
+ EXPECT_EQ(reps, 1);
+ EXPECT_EQ(s, "Ayz!");
+
+ // Replace once at the end.
+ s = "Abc!";
+ reps = absl::StrReplaceAll(
+ {{"a", "x"}, {"ab", "xy"}, {"b", "y"}, {"bc!", "yz?"}, {"c!", "z;"}}, &s);
+ EXPECT_EQ(reps, 1);
+ EXPECT_EQ(s, "Ayz?");
+
+ // Replace multiple times with varying lengths of original/replacement.
+ s = "ababa";
+ reps = absl::StrReplaceAll({{"a", "xxx"}, {"b", "XXXX"}}, &s);
+ EXPECT_EQ(reps, 5);
+ EXPECT_EQ(s, "xxxXXXXxxxXXXXxxx");
+
+ // Overlapping matches are replaced greedily.
+ s = "aaa";
+ reps = absl::StrReplaceAll({{"aa", "x"}, {"a", "X"}}, &s);
+ EXPECT_EQ(reps, 2);
+ EXPECT_EQ(s, "xX");
+ s = "aaa";
+ reps = absl::StrReplaceAll({{"a", "X"}, {"aa", "x"}}, &s);
+ EXPECT_EQ(reps, 2);
+ EXPECT_EQ(s, "xX");
+
+ // Two well-known sentences
+ s = "the quick brown fox jumped over the lazy dogs";
+ reps = absl::StrReplaceAll(
+ {
+ {"brown", "box"},
+ {"dogs", "jugs"},
+ {"fox", "with"},
+ {"jumped", "five"},
+ {"over", "dozen"},
+ {"quick", "my"},
+ {"the", "pack"},
+ {"the lazy", "liquor"},
+ },
+ &s);
+ EXPECT_EQ(reps, 8);
+ EXPECT_EQ(s, "pack my box with five dozen liquor jugs");
+}
diff --git a/absl/strings/str_split.cc b/absl/strings/str_split.cc
new file mode 100644
index 0000000..910a67c
--- /dev/null
+++ b/absl/strings/str_split.cc
@@ -0,0 +1,133 @@
+// 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/strings/str_split.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
+#include <iterator>
+#include <limits>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/ascii.h"
+
+namespace absl {
+
+namespace {
+
+// This GenericFind() template function encapsulates the finding algorithm
+// shared between the ByString and ByAnyChar delimiters. The FindPolicy
+// template parameter allows each delimiter to customize the actual find
+// function to use and the length of the found delimiter. For example, the
+// Literal delimiter will ultimately use absl::string_view::find(), and the
+// AnyOf delimiter will use absl::string_view::find_first_of().
+template <typename FindPolicy>
+absl::string_view GenericFind(absl::string_view text,
+ absl::string_view delimiter, size_t pos,
+ FindPolicy find_policy) {
+ if (delimiter.empty() && text.length() > 0) {
+ // Special case for empty std::string delimiters: always return a zero-length
+ // absl::string_view referring to the item at position 1 past pos.
+ return absl::string_view(text.begin() + pos + 1, 0);
+ }
+ size_t found_pos = absl::string_view::npos;
+ absl::string_view found(text.end(), 0); // By default, not found
+ found_pos = find_policy.Find(text, delimiter, pos);
+ if (found_pos != absl::string_view::npos) {
+ found = absl::string_view(text.data() + found_pos,
+ find_policy.Length(delimiter));
+ }
+ return found;
+}
+
+// Finds using absl::string_view::find(), therefore the length of the found
+// delimiter is delimiter.length().
+struct LiteralPolicy {
+ size_t Find(absl::string_view text, absl::string_view delimiter, size_t pos) {
+ return text.find(delimiter, pos);
+ }
+ size_t Length(absl::string_view delimiter) { return delimiter.length(); }
+};
+
+// Finds using absl::string_view::find_first_of(), therefore the length of the
+// found delimiter is 1.
+struct AnyOfPolicy {
+ size_t Find(absl::string_view text, absl::string_view delimiter, size_t pos) {
+ return text.find_first_of(delimiter, pos);
+ }
+ size_t Length(absl::string_view /* delimiter */) { return 1; }
+};
+
+} // namespace
+
+//
+// ByString
+//
+
+ByString::ByString(absl::string_view sp) : delimiter_(sp) {}
+
+absl::string_view ByString::Find(absl::string_view text, size_t pos) const {
+ if (delimiter_.length() == 1) {
+ // Much faster to call find on a single character than on an
+ // absl::string_view.
+ size_t found_pos = text.find(delimiter_[0], pos);
+ if (found_pos == absl::string_view::npos)
+ return absl::string_view(text.end(), 0);
+ return text.substr(found_pos, 1);
+ }
+ return GenericFind(text, delimiter_, pos, LiteralPolicy());
+}
+
+//
+// ByChar
+//
+
+absl::string_view ByChar::Find(absl::string_view text, size_t pos) const {
+ size_t found_pos = text.find(c_, pos);
+ if (found_pos == absl::string_view::npos)
+ return absl::string_view(text.end(), 0);
+ return text.substr(found_pos, 1);
+}
+
+//
+// ByAnyChar
+//
+
+ByAnyChar::ByAnyChar(absl::string_view sp) : delimiters_(sp) {}
+
+absl::string_view ByAnyChar::Find(absl::string_view text, size_t pos) const {
+ return GenericFind(text, delimiters_, pos, AnyOfPolicy());
+}
+
+//
+// ByLength
+//
+ByLength::ByLength(ptrdiff_t length) : length_(length) {
+ ABSL_RAW_CHECK(length > 0, "");
+}
+
+absl::string_view ByLength::Find(absl::string_view text,
+ size_t pos) const {
+ pos = std::min(pos, text.size()); // truncate `pos`
+ absl::string_view substr = text.substr(pos);
+ // If the std::string is shorter than the chunk size we say we
+ // "can't find the delimiter" so this will be the last chunk.
+ if (substr.length() <= static_cast<size_t>(length_))
+ return absl::string_view(text.end(), 0);
+
+ return absl::string_view(substr.begin() + length_, 0);
+}
+
+} // namespace absl
diff --git a/absl/strings/str_split.h b/absl/strings/str_split.h
new file mode 100644
index 0000000..a7b48b1
--- /dev/null
+++ b/absl/strings/str_split.h
@@ -0,0 +1,511 @@
+//
+// 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: str_split.h
+// -----------------------------------------------------------------------------
+//
+// This file contains functions for splitting strings. It defines the main
+// `StrSplit()` function, several delimiters for determining the boundaries on
+// which to split the std::string, and predicates for filtering delimited results.
+// `StrSplit()` adapts the returned collection to the type specified by the
+// caller.
+//
+// Example:
+//
+// // Splits the given std::string on commas. Returns the results in a
+// // vector of strings.
+// std::vector<std::string> v = absl::StrSplit("a,b,c", ',');
+// // Can also use ","
+// // v[0] == "a", v[1] == "b", v[2] == "c"
+//
+// See StrSplit() below for more information.
+#ifndef ABSL_STRINGS_STR_SPLIT_H_
+#define ABSL_STRINGS_STR_SPLIT_H_
+
+#include <algorithm>
+#include <cstddef>
+#include <map>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/internal/str_split_internal.h"
+#include "absl/strings/string_view.h"
+#include "absl/strings/strip.h"
+
+namespace absl {
+
+//------------------------------------------------------------------------------
+// Delimiters
+//------------------------------------------------------------------------------
+//
+// `StrSplit()` uses delimiters to define the boundaries between elements in the
+// provided input. Several `Delimiter` types are defined below. If a std::string
+// (`const char*`, `std::string`, or `absl::string_view`) is passed in place of
+// an explicit `Delimiter` object, `StrSplit()` treats it the same way as if it
+// were passed a `ByString` delimiter.
+//
+// A `Delimiter` is an object with a `Find()` function that knows how to find
+// the first occurrence of itself in a given `absl::string_view`.
+//
+// The following `Delimiter` types are available for use within `StrSplit()`:
+//
+// - `ByString` (default for std::string arguments)
+// - `ByChar` (default for a char argument)
+// - `ByAnyChar`
+// - `ByLength`
+// - `MaxSplits`
+//
+//
+// A Delimiter's Find() member function will be passed the input text that is to
+// be split and the position to begin searching for the next delimiter in the
+// input text. The returned absl::string_view should refer to the next
+// occurrence (after pos) of the represented delimiter; this returned
+// absl::string_view represents the next location where the input std::string should
+// be broken. The returned absl::string_view may be zero-length if the Delimiter
+// does not represent a part of the std::string (e.g., a fixed-length delimiter). If
+// no delimiter is found in the given text, a zero-length absl::string_view
+// referring to text.end() should be returned (e.g.,
+// absl::string_view(text.end(), 0)). It is important that the returned
+// absl::string_view always be within the bounds of input text given as an
+// argument--it must not refer to a std::string that is physically located outside of
+// the given std::string.
+//
+// The following example is a simple Delimiter object that is created with a
+// single char and will look for that char in the text passed to the Find()
+// function:
+//
+// struct SimpleDelimiter {
+// const char c_;
+// explicit SimpleDelimiter(char c) : c_(c) {}
+// absl::string_view Find(absl::string_view text, size_t pos) {
+// auto found = text.find(c_, pos);
+// if (found == absl::string_view::npos)
+// return absl::string_view(text.end(), 0);
+//
+// return absl::string_view(text, found, 1);
+// }
+// };
+
+// ByString
+//
+// A sub-std::string delimiter. If `StrSplit()` is passed a std::string in place of a
+// `Delimiter` object, the std::string will be implicitly converted into a
+// `ByString` delimiter.
+//
+// Example:
+//
+// // Because a std::string literal is converted to an `absl::ByString`,
+// // the following two splits are equivalent.
+//
+// std::vector<std::string> v1 = absl::StrSplit("a, b, c", ", ");
+//
+// using absl::ByString;
+// std::vector<std::string> v2 = absl::StrSplit("a, b, c",
+// ByString(", "));
+// // v[0] == "a", v[1] == "b", v[3] == "c"
+class ByString {
+ public:
+ explicit ByString(absl::string_view sp);
+ absl::string_view Find(absl::string_view text, size_t pos) const;
+
+ private:
+ const std::string delimiter_;
+};
+
+// ByChar
+//
+// A single character delimiter. `ByChar` is functionally equivalent to a
+// 1-char std::string within a `ByString` delimiter, but slightly more
+// efficient.
+//
+// Example:
+//
+// // Because a char literal is converted to a absl::ByChar,
+// // the following two splits are equivalent.
+// std::vector<std::string> v1 = absl::StrSplit("a,b,c", ',');
+// using absl::ByChar;
+// std::vector<std::string> v2 = absl::StrSplit("a,b,c", ByChar(','));
+// // v[0] == "a", v[1] == "b", v[3] == "c"
+//
+// `ByChar` is also the default delimiter if a single character is given
+// as the delimiter to `StrSplit()`. For example, the following calls are
+// equivalent:
+//
+// std::vector<std::string> v = absl::StrSplit("a-b", '-');
+//
+// using absl::ByChar;
+// std::vector<std::string> v = absl::StrSplit("a-b", ByChar('-'));
+//
+class ByChar {
+ public:
+ explicit ByChar(char c) : c_(c) {}
+ absl::string_view Find(absl::string_view text, size_t pos) const;
+
+ private:
+ char c_;
+};
+
+// ByAnyChar
+//
+// A delimiter that will match any of the given byte-sized characters within
+// its provided std::string.
+//
+// Note: this delimiter works with single-byte std::string data, but does not work
+// with variable-width encodings, such as UTF-8.
+//
+// Example:
+//
+// using absl::ByAnyChar;
+// std::vector<std::string> v = absl::StrSplit("a,b=c", ByAnyChar(",="));
+// // v[0] == "a", v[1] == "b", v[3] == "c"
+//
+// If `ByAnyChar` is given the empty std::string, it behaves exactly like
+// `ByString` and matches each individual character in the input std::string.
+//
+class ByAnyChar {
+ public:
+ explicit ByAnyChar(absl::string_view sp);
+ absl::string_view Find(absl::string_view text, size_t pos) const;
+
+ private:
+ const std::string delimiters_;
+};
+
+// ByLength
+//
+// A delimiter for splitting into equal-length strings. The length argument to
+// the constructor must be greater than 0.
+//
+// Note: this delimiter works with single-byte std::string data, but does not work
+// with variable-width encodings, such as UTF-8.
+//
+// Example:
+//
+// using absl::ByLength;
+// std::vector<std::string> v = absl::StrSplit("123456789", ByLength(3));
+
+// // v[0] == "123", v[1] == "456", v[2] == "789"
+//
+// Note that the std::string does not have to be a multiple of the fixed split
+// length. In such a case, the last substring will be shorter.
+//
+// using absl::ByLength;
+// std::vector<std::string> v = absl::StrSplit("12345", ByLength(2));
+//
+// // v[0] == "12", v[1] == "35", v[2] == "5"
+class ByLength {
+ public:
+ explicit ByLength(ptrdiff_t length);
+ absl::string_view Find(absl::string_view text, size_t pos) const;
+
+ private:
+ const ptrdiff_t length_;
+};
+
+namespace strings_internal {
+
+// A traits-like metafunction for selecting the default Delimiter object type
+// for a particular Delimiter type. The base case simply exposes type Delimiter
+// itself as the delimiter's Type. However, there are specializations for
+// std::string-like objects that map them to the ByString delimiter object.
+// This allows functions like absl::StrSplit() and absl::MaxSplits() to accept
+// std::string-like objects (e.g., ',') as delimiter arguments but they will be
+// treated as if a ByString delimiter was given.
+template <typename Delimiter>
+struct SelectDelimiter {
+ using type = Delimiter;
+};
+
+template <>
+struct SelectDelimiter<char> {
+ using type = ByChar;
+};
+template <>
+struct SelectDelimiter<char*> {
+ using type = ByString;
+};
+template <>
+struct SelectDelimiter<const char*> {
+ using type = ByString;
+};
+template <>
+struct SelectDelimiter<absl::string_view> {
+ using type = ByString;
+};
+template <>
+struct SelectDelimiter<std::string> {
+ using type = ByString;
+};
+
+// Wraps another delimiter and sets a max number of matches for that delimiter.
+template <typename Delimiter>
+class MaxSplitsImpl {
+ public:
+ MaxSplitsImpl(Delimiter delimiter, int limit)
+ : delimiter_(delimiter), limit_(limit), count_(0) {}
+ absl::string_view Find(absl::string_view text, size_t pos) {
+ if (count_++ == limit_) {
+ return absl::string_view(text.end(), 0); // No more matches.
+ }
+ return delimiter_.Find(text, pos);
+ }
+
+ private:
+ Delimiter delimiter_;
+ const int limit_;
+ int count_;
+};
+
+} // namespace strings_internal
+
+// MaxSplits()
+//
+// A delimiter that limits the number of matches which can occur to the passed
+// `limit`. The last element in the returned collection will contain all
+// remaining unsplit pieces, which may contain instances of the delimiter.
+// The collection will contain at most `limit` + 1 elements.
+// Example:
+//
+// using absl::MaxSplits;
+// std::vector<std::string> v = absl::StrSplit("a,b,c", MaxSplits(',', 1));
+//
+// // v[0] == "a", v[1] == "b,c"
+template <typename Delimiter>
+inline strings_internal::MaxSplitsImpl<
+ typename strings_internal::SelectDelimiter<Delimiter>::type>
+MaxSplits(Delimiter delimiter, int limit) {
+ typedef
+ typename strings_internal::SelectDelimiter<Delimiter>::type DelimiterType;
+ return strings_internal::MaxSplitsImpl<DelimiterType>(
+ DelimiterType(delimiter), limit);
+}
+
+//------------------------------------------------------------------------------
+// Predicates
+//------------------------------------------------------------------------------
+//
+// Predicates filter the results of a `StrSplit()` by determining whether or not
+// a resultant element is included in the result set. A predicate may be passed
+// as an optional third argument to the `StrSplit()` function.
+//
+// Predicates are unary functions (or functors) that take a single
+// `absl::string_view` argument and return a bool indicating whether the
+// argument should be included (`true`) or excluded (`false`).
+//
+// Predicates are useful when filtering out empty substrings. By default, empty
+// substrings may be returned by `StrSplit()`, which is similar to the way split
+// functions work in other programming languages.
+
+// AllowEmpty()
+//
+// Always returns `true`, indicating that all strings--including empty
+// strings--should be included in the split output. This predicate is not
+// strictly needed because this is the default behavior of `StrSplit()`;
+// however, it might be useful at some call sites to make the intent explicit.
+//
+// Example:
+//
+// std::vector<std::string> v = absl::StrSplit(" a , ,,b,", ',', AllowEmpty());
+//
+// // v[0] == " a ", v[1] == " ", v[2] == "", v[3] = "b", v[4] == ""
+struct AllowEmpty {
+ bool operator()(absl::string_view) const { return true; }
+};
+
+// SkipEmpty()
+//
+// Returns `false` if the given `absl::string_view` is empty, indicating that
+// `StrSplit()` should omit the empty std::string.
+//
+// Example:
+//
+// std::vector<std::string> v = absl::StrSplit(",a,,b,", ',', SkipEmpty());
+//
+// // v[0] == "a", v[1] == "b"
+//
+// Note: `SkipEmpty()` does not consider a std::string containing only whitespace
+// to be empty. To skip such whitespace as well, use the `SkipWhitespace()`
+// predicate.
+struct SkipEmpty {
+ bool operator()(absl::string_view sp) const { return !sp.empty(); }
+};
+
+// SkipWhitespace()
+//
+// Returns `false` if the given `absl::string_view` is empty *or* contains only
+// whitespace, indicating that `StrSplit()` should omit the std::string.
+//
+// Example:
+//
+// std::vector<std::string> v = absl::StrSplit(" a , ,,b,",
+// ',', SkipWhitespace());
+// // v[0] == " a ", v[1] == "b"
+//
+// // SkipEmpty() would return whitespace elements
+// std::vector<std::string> v = absl::StrSplit(" a , ,,b,", ',', SkipEmpty());
+// // v[0] == " a ", v[1] == " ", v[2] == "b"
+struct SkipWhitespace {
+ bool operator()(absl::string_view sp) const {
+ sp = absl::StripAsciiWhitespace(sp);
+ return !sp.empty();
+ }
+};
+
+//------------------------------------------------------------------------------
+// StrSplit()
+//------------------------------------------------------------------------------
+
+// StrSplit()
+//
+// Splits a given `std::string` based on the provided `Delimiter` object,
+// returning the elements within the type specified by the caller. Optionally,
+// you may also pass a `Predicate` to `StrSplit()` indicating whether to include
+// or exclude the resulting element within the final result set. (See the
+// overviews for Delimiters and Predicates above.)
+//
+// Example:
+//
+// std::vector<std::string> v = absl::StrSplit("a,b,c,d", ',');
+// // v[0] == "a", v[1] == "b", v[2] == "c", v[3] == "d"
+//
+// You can also provide an explicit `Delimiter` object:
+//
+// Example:
+//
+// using absl::ByAnyChar;
+// std::vector<std::string> v = absl::StrSplit("a,b=c", ByAnyChar(",="));
+// // v[0] == "a", v[1] == "b", v[3] == "c"
+//
+// See above for more information on delimiters.
+//
+// By default, empty strings are included in the result set. You can optionally
+// include a third `Predicate` argument to apply a test for whether the
+// resultant element should be included in the result set:
+//
+// Example:
+//
+// std::vector<std::string> v = absl::StrSplit(" a , ,,b,",
+// ',', SkipWhitespace());
+// // v[0] == "a", v[1] == "b"
+//
+// See above for more information on predicates.
+//
+//------------------------------------------------------------------------------
+// StrSplit() Return Types
+//------------------------------------------------------------------------------
+//
+// The `StrSplit()` function adapts the returned collection to the collection
+// specified by the caller (e.g. `std::vector` above). The returned collections
+// may contain `string`, `absl::string_view` (in which case the original std::string
+// being split must ensure that it outlives the collection), or any object that
+// can be explicitly created from an `absl::string_view`. This behavior works
+// for:
+//
+// 1) All standard STL containers including `std::vector`, `std::list`,
+// `std::deque`, `std::set`,`std::multiset`, 'std::map`, and `std::multimap`
+// 2) `std::pair` (which is not actually a container). See below.
+//
+// Example:
+//
+// // The results are returned as `absl::string_view` objects. Note that we
+// // have to ensure that the input std::string outlives any results.
+// std::vector<absl::string_view> v = absl::StrSplit("a,b,c", ',');
+//
+// // Stores results in a std::set<std::string>, which also performs
+// // de-duplication and orders the elements in ascending order.
+// std::set<std::string> a = absl::StrSplit("b,a,c,a,b", ',');
+// // v[0] == "a", v[1] == "b", v[2] = "c"
+//
+// // `StrSplit()` can be used within a range-based for loop, in which case
+// // each element will be of type `absl::string_view`.
+// std::vector<std::string> v;
+// for (const auto sv : absl::StrSplit("a,b,c", ',')) {
+// if (sv != "b") v.emplace_back(sv);
+// }
+// // v[0] == "a", v[1] == "c"
+//
+// // Stores results in a map. The map implementation assumes that the input
+// // is provided as a series of key/value pairs. For example, the 0th element
+// // resulting from the split will be stored as a key to the 1st element. If
+// // an odd number of elements are resolved, the last element is paired with
+// // a default-constructed value (e.g., empty std::string).
+// std::map<std::string, std::string> m = absl::StrSplit("a,b,c", ',');
+// // m["a"] == "b", m["c"] == "" // last component value equals ""
+//
+// Splitting to `std::pair` is an interesting case because it can hold only two
+// elements and is not a collection type. When splitting to a `std::pair` the
+// first two split strings become the `std::pair` `.first` and `.second`
+// members, respectively. The remaining split substrings are discarded. If there
+// are less than two split substrings, the empty std::string is used for the
+// corresponding
+// `std::pair` member.
+//
+// Example:
+//
+// // Stores first two split strings as the members in a std::pair.
+// std::pair<std::string, std::string> p = absl::StrSplit("a,b,c", ',');
+// // p.first == "a", p.second == "b" // "c" is omitted.
+//
+// The `StrSplit()` function can be used multiple times to perform more
+// complicated splitting logic, such as intelligently parsing key-value pairs.
+//
+// Example:
+//
+// // The input std::string "a=b=c,d=e,f=,g" becomes
+// // { "a" => "b=c", "d" => "e", "f" => "", "g" => "" }
+// std::map<std::string, std::string> m;
+// for (absl::string_view sp : absl::StrSplit("a=b=c,d=e,f=,g", ',')) {
+// m.insert(absl::StrSplit(sp, absl::MaxSplits('=', 1)));
+// }
+// EXPECT_EQ("b=c", m.find("a")->second);
+// EXPECT_EQ("e", m.find("d")->second);
+// EXPECT_EQ("", m.find("f")->second);
+// EXPECT_EQ("", m.find("g")->second);
+//
+// WARNING: Due to a legacy bug that is maintained for backward compatibility,
+// splitting the following empty string_views produces different results:
+//
+// absl::StrSplit(absl::string_view(""), '-'); // {""}
+// absl::StrSplit(absl::string_view(), '-'); // {}, but should be {""}
+//
+// Try not to depend on this distinction because the bug may one day be fixed.
+template <typename Delimiter>
+strings_internal::Splitter<
+ typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty>
+StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d) {
+ using DelimiterType =
+ typename strings_internal::SelectDelimiter<Delimiter>::type;
+ return strings_internal::Splitter<DelimiterType, AllowEmpty>(
+ std::move(text), DelimiterType(d), AllowEmpty());
+}
+
+template <typename Delimiter, typename Predicate>
+strings_internal::Splitter<
+ typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate>
+StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d,
+ Predicate p) {
+ using DelimiterType =
+ typename strings_internal::SelectDelimiter<Delimiter>::type;
+ return strings_internal::Splitter<DelimiterType, Predicate>(
+ std::move(text), DelimiterType(d), std::move(p));
+}
+
+} // namespace absl
+
+#endif // ABSL_STRINGS_STR_SPLIT_H_
diff --git a/absl/strings/str_split_test.cc b/absl/strings/str_split_test.cc
new file mode 100644
index 0000000..a95a0fb
--- /dev/null
+++ b/absl/strings/str_split_test.cc
@@ -0,0 +1,896 @@
+// 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/strings/str_split.h"
+
+#include <climits>
+#include <cstdlib>
+#include <cstring>
+#include <deque>
+#include <limits>
+#include <list>
+#include <map>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/dynamic_annotations.h" // for RunningOnValgrind
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/strings/numbers.h"
+
+namespace {
+
+using ::testing::ElementsAre;
+using ::testing::Pair;
+using ::testing::UnorderedElementsAre;
+
+// This tests the overall split API, which is made up of the absl::StrSplit()
+// function and the Delimiter objects in the absl:: namespace.
+// This TEST macro is outside of any namespace to require full specification of
+// namespaces just like callers will need to use.
+TEST(Split, APIExamples) {
+ {
+ // Passes std::string delimiter. Assumes the default of Literal.
+ std::vector<std::string> v = absl::StrSplit("a,b,c", ',');
+ EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+
+ // Equivalent to...
+ using absl::ByString;
+ v = absl::StrSplit("a,b,c", ByString(","));
+ EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+
+ // Equivalent to...
+ EXPECT_THAT(absl::StrSplit("a,b,c", ByString(",")),
+ ElementsAre("a", "b", "c"));
+ }
+
+ {
+ // Same as above, but using a single character as the delimiter.
+ std::vector<std::string> v = absl::StrSplit("a,b,c", ',');
+ EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+
+ // Equivalent to...
+ using absl::ByChar;
+ v = absl::StrSplit("a,b,c", ByChar(','));
+ EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+ }
+
+ {
+ // Same as above, but using std::string
+ std::vector<std::string> v = absl::StrSplit("a,b,c", ',');
+ EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+
+ // Equivalent to...
+ using absl::ByChar;
+ v = absl::StrSplit("a,b,c", ByChar(','));
+ EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+ }
+
+ {
+ // Uses the Literal std::string "=>" as the delimiter.
+ const std::vector<std::string> v = absl::StrSplit("a=>b=>c", "=>");
+ EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+ }
+
+ {
+ // The substrings are returned as string_views, eliminating copying.
+ std::vector<absl::string_view> v = absl::StrSplit("a,b,c", ',');
+ EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+ }
+
+ {
+ // Leading and trailing empty substrings.
+ std::vector<std::string> v = absl::StrSplit(",a,b,c,", ',');
+ EXPECT_THAT(v, ElementsAre("", "a", "b", "c", ""));
+ }
+
+ {
+ // Splits on a delimiter that is not found.
+ std::vector<std::string> v = absl::StrSplit("abc", ',');
+ EXPECT_THAT(v, ElementsAre("abc"));
+ }
+
+ {
+ // Splits the input std::string into individual characters by using an empty
+ // std::string as the delimiter.
+ std::vector<std::string> v = absl::StrSplit("abc", "");
+ EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+ }
+
+ {
+ // Splits std::string data with embedded NUL characters, using NUL as the
+ // delimiter. A simple delimiter of "\0" doesn't work because strlen() will
+ // say that's the empty std::string when constructing the absl::string_view
+ // delimiter. Instead, a non-empty std::string containing NUL can be used as the
+ // delimiter.
+ std::string embedded_nulls("a\0b\0c", 5);
+ std::string null_delim("\0", 1);
+ std::vector<std::string> v = absl::StrSplit(embedded_nulls, null_delim);
+ EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+ }
+
+ {
+ // Stores first two split strings as the members in a std::pair.
+ std::pair<std::string, std::string> p = absl::StrSplit("a,b,c", ',');
+ EXPECT_EQ("a", p.first);
+ EXPECT_EQ("b", p.second);
+ // "c" is omitted because std::pair can hold only two elements.
+ }
+
+ {
+ // Results stored in std::set<std::string>
+ std::set<std::string> v = absl::StrSplit("a,b,c,a,b,c,a,b,c", ',');
+ EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+ }
+
+ {
+ // Uses a non-const char* delimiter.
+ char a[] = ",";
+ char* d = a + 0;
+ std::vector<std::string> v = absl::StrSplit("a,b,c", d);
+ EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+ }
+
+ {
+ // Results split using either of , or ;
+ using absl::ByAnyChar;
+ std::vector<std::string> v = absl::StrSplit("a,b;c", ByAnyChar(",;"));
+ EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+ }
+
+ {
+ // Uses the SkipWhitespace predicate.
+ using absl::SkipWhitespace;
+ std::vector<std::string> v = absl::StrSplit("a, ,,b,", ',', SkipWhitespace());
+ EXPECT_THAT(v, ElementsAre("a", "b"));
+ }
+
+ {
+ // Uses the ByLength delimiter.
+ using absl::ByLength;
+ std::vector<std::string> v = absl::StrSplit("abcdefg", ByLength(3));
+ EXPECT_THAT(v, ElementsAre("abc", "def", "g"));
+ }
+
+ {
+ // Results stored in a std::map.
+ std::map<std::string, std::string> m = absl::StrSplit("a,1,b,2,a,3", ',');
+ EXPECT_EQ(2, m.size());
+ EXPECT_EQ("3", m["a"]);
+ EXPECT_EQ("2", m["b"]);
+ }
+
+ {
+ // Results stored in a std::multimap.
+ std::multimap<std::string, std::string> m = absl::StrSplit("a,1,b,2,a,3", ',');
+ EXPECT_EQ(3, m.size());
+ auto it = m.find("a");
+ EXPECT_EQ("1", it->second);
+ ++it;
+ EXPECT_EQ("3", it->second);
+ it = m.find("b");
+ EXPECT_EQ("2", it->second);
+ }
+
+ {
+ // Demonstrates use in a range-based for loop in C++11.
+ std::string s = "x,x,x,x,x,x,x";
+ for (absl::string_view sp : absl::StrSplit(s, ',')) {
+ EXPECT_EQ("x", sp);
+ }
+ }
+
+ {
+ // Demonstrates use with a Predicate in a range-based for loop.
+ using absl::SkipWhitespace;
+ std::string s = " ,x,,x,,x,x,x,,";
+ for (absl::string_view sp : absl::StrSplit(s, ',', SkipWhitespace())) {
+ EXPECT_EQ("x", sp);
+ }
+ }
+
+ {
+ // Demonstrates a "smart" split to std::map using two separate calls to
+ // absl::StrSplit. One call to split the records, and another call to split
+ // the keys and values. This also uses the Limit delimiter so that the
+ // std::string "a=b=c" will split to "a" -> "b=c".
+ std::map<std::string, std::string> m;
+ for (absl::string_view sp : absl::StrSplit("a=b=c,d=e,f=,g", ',')) {
+ m.insert(absl::StrSplit(sp, absl::MaxSplits('=', 1)));
+ }
+ EXPECT_EQ("b=c", m.find("a")->second);
+ EXPECT_EQ("e", m.find("d")->second);
+ EXPECT_EQ("", m.find("f")->second);
+ EXPECT_EQ("", m.find("g")->second);
+ }
+}
+
+//
+// Tests for SplitIterator
+//
+
+TEST(SplitIterator, Basics) {
+ auto splitter = absl::StrSplit("a,b", ',');
+ auto it = splitter.begin();
+ auto end = splitter.end();
+
+ EXPECT_NE(it, end);
+ EXPECT_EQ("a", *it); // tests dereference
+ ++it; // tests preincrement
+ EXPECT_NE(it, end);
+ EXPECT_EQ("b", std::string(it->data(), it->size())); // tests dereference as ptr
+ it++; // tests postincrement
+ EXPECT_EQ(it, end);
+}
+
+// Simple Predicate to skip a particular std::string.
+class Skip {
+ public:
+ explicit Skip(const std::string& s) : s_(s) {}
+ bool operator()(absl::string_view sp) { return sp != s_; }
+
+ private:
+ std::string s_;
+};
+
+TEST(SplitIterator, Predicate) {
+ auto splitter = absl::StrSplit("a,b,c", ',', Skip("b"));
+ auto it = splitter.begin();
+ auto end = splitter.end();
+
+ EXPECT_NE(it, end);
+ EXPECT_EQ("a", *it); // tests dereference
+ ++it; // tests preincrement -- "b" should be skipped here.
+ EXPECT_NE(it, end);
+ EXPECT_EQ("c", std::string(it->data(), it->size())); // tests dereference as ptr
+ it++; // tests postincrement
+ EXPECT_EQ(it, end);
+}
+
+TEST(SplitIterator, EdgeCases) {
+ // Expected input and output, assuming a delimiter of ','
+ struct {
+ std::string in;
+ std::vector<std::string> expect;
+ } specs[] = {
+ {"", {""}},
+ {"foo", {"foo"}},
+ {",", {"", ""}},
+ {",foo", {"", "foo"}},
+ {"foo,", {"foo", ""}},
+ {",foo,", {"", "foo", ""}},
+ {"foo,bar", {"foo", "bar"}},
+ };
+
+ for (const auto& spec : specs) {
+ SCOPED_TRACE(spec.in);
+ auto splitter = absl::StrSplit(spec.in, ',');
+ auto it = splitter.begin();
+ auto end = splitter.end();
+ for (const auto& expected : spec.expect) {
+ EXPECT_NE(it, end);
+ EXPECT_EQ(expected, *it++);
+ }
+ EXPECT_EQ(it, end);
+ }
+}
+
+TEST(Splitter, Const) {
+ const auto splitter = absl::StrSplit("a,b,c", ',');
+ EXPECT_THAT(splitter, ElementsAre("a", "b", "c"));
+}
+
+TEST(Split, EmptyAndNull) {
+ // Attention: Splitting a null absl::string_view is different than splitting
+ // an empty absl::string_view even though both string_views are considered
+ // equal. This behavior is likely surprising and undesirable. However, to
+ // maintain backward compatibility, there is a small "hack" in
+ // str_split_internal.h that preserves this behavior. If that behavior is ever
+ // changed/fixed, this test will need to be updated.
+ EXPECT_THAT(absl::StrSplit(absl::string_view(""), '-'), ElementsAre(""));
+ EXPECT_THAT(absl::StrSplit(absl::string_view(), '-'), ElementsAre());
+}
+
+TEST(SplitIterator, EqualityAsEndCondition) {
+ auto splitter = absl::StrSplit("a,b,c", ',');
+ auto it = splitter.begin();
+ auto it2 = it;
+
+ // Increments it2 twice to point to "c" in the input text.
+ ++it2;
+ ++it2;
+ EXPECT_EQ("c", *it2);
+
+ // This test uses a non-end SplitIterator as the terminating condition in a
+ // for loop. This relies on SplitIterator equality for non-end SplitIterators
+ // working correctly. At this point it2 points to "c", and we use that as the
+ // "end" condition in this test.
+ std::vector<absl::string_view> v;
+ for (; it != it2; ++it) {
+ v.push_back(*it);
+ }
+ EXPECT_THAT(v, ElementsAre("a", "b"));
+}
+
+//
+// Tests for Splitter
+//
+
+TEST(Splitter, RangeIterators) {
+ auto splitter = absl::StrSplit("a,b,c", ',');
+ std::vector<absl::string_view> output;
+ for (const absl::string_view p : splitter) {
+ output.push_back(p);
+ }
+ EXPECT_THAT(output, ElementsAre("a", "b", "c"));
+}
+
+// Some template functions for use in testing conversion operators
+template <typename ContainerType, typename Splitter>
+void TestConversionOperator(const Splitter& splitter) {
+ ContainerType output = splitter;
+ EXPECT_THAT(output, UnorderedElementsAre("a", "b", "c", "d"));
+}
+
+template <typename MapType, typename Splitter>
+void TestMapConversionOperator(const Splitter& splitter) {
+ MapType m = splitter;
+ EXPECT_THAT(m, UnorderedElementsAre(Pair("a", "b"), Pair("c", "d")));
+}
+
+template <typename FirstType, typename SecondType, typename Splitter>
+void TestPairConversionOperator(const Splitter& splitter) {
+ std::pair<FirstType, SecondType> p = splitter;
+ EXPECT_EQ(p, (std::pair<FirstType, SecondType>("a", "b")));
+}
+
+TEST(Splitter, ConversionOperator) {
+ auto splitter = absl::StrSplit("a,b,c,d", ',');
+
+ TestConversionOperator<std::vector<absl::string_view>>(splitter);
+ TestConversionOperator<std::vector<std::string>>(splitter);
+ TestConversionOperator<std::list<absl::string_view>>(splitter);
+ TestConversionOperator<std::list<std::string>>(splitter);
+ TestConversionOperator<std::deque<absl::string_view>>(splitter);
+ TestConversionOperator<std::deque<std::string>>(splitter);
+ TestConversionOperator<std::set<absl::string_view>>(splitter);
+ TestConversionOperator<std::set<std::string>>(splitter);
+ TestConversionOperator<std::multiset<absl::string_view>>(splitter);
+ TestConversionOperator<std::multiset<std::string>>(splitter);
+ TestConversionOperator<std::unordered_set<std::string>>(splitter);
+
+ // Tests conversion to map-like objects.
+
+ TestMapConversionOperator<std::map<absl::string_view, absl::string_view>>(
+ splitter);
+ TestMapConversionOperator<std::map<absl::string_view, std::string>>(splitter);
+ TestMapConversionOperator<std::map<std::string, absl::string_view>>(splitter);
+ TestMapConversionOperator<std::map<std::string, std::string>>(splitter);
+ TestMapConversionOperator<
+ std::multimap<absl::string_view, absl::string_view>>(splitter);
+ TestMapConversionOperator<std::multimap<absl::string_view, std::string>>(splitter);
+ TestMapConversionOperator<std::multimap<std::string, absl::string_view>>(splitter);
+ TestMapConversionOperator<std::multimap<std::string, std::string>>(splitter);
+ TestMapConversionOperator<std::unordered_map<std::string, std::string>>(splitter);
+
+ // Tests conversion to std::pair
+
+ TestPairConversionOperator<absl::string_view, absl::string_view>(splitter);
+ TestPairConversionOperator<absl::string_view, std::string>(splitter);
+ TestPairConversionOperator<std::string, absl::string_view>(splitter);
+ TestPairConversionOperator<std::string, std::string>(splitter);
+}
+
+// A few additional tests for conversion to std::pair. This conversion is
+// different from others because a std::pair always has exactly two elements:
+// .first and .second. The split has to work even when the split has
+// less-than, equal-to, and more-than 2 strings.
+TEST(Splitter, ToPair) {
+ {
+ // Empty std::string
+ std::pair<std::string, std::string> p = absl::StrSplit("", ',');
+ EXPECT_EQ("", p.first);
+ EXPECT_EQ("", p.second);
+ }
+
+ {
+ // Only first
+ std::pair<std::string, std::string> p = absl::StrSplit("a", ',');
+ EXPECT_EQ("a", p.first);
+ EXPECT_EQ("", p.second);
+ }
+
+ {
+ // Only second
+ std::pair<std::string, std::string> p = absl::StrSplit(",b", ',');
+ EXPECT_EQ("", p.first);
+ EXPECT_EQ("b", p.second);
+ }
+
+ {
+ // First and second.
+ std::pair<std::string, std::string> p = absl::StrSplit("a,b", ',');
+ EXPECT_EQ("a", p.first);
+ EXPECT_EQ("b", p.second);
+ }
+
+ {
+ // First and second and then more stuff that will be ignored.
+ std::pair<std::string, std::string> p = absl::StrSplit("a,b,c", ',');
+ EXPECT_EQ("a", p.first);
+ EXPECT_EQ("b", p.second);
+ // "c" is omitted.
+ }
+}
+
+TEST(Splitter, Predicates) {
+ static const char kTestChars[] = ",a, ,b,";
+ using absl::AllowEmpty;
+ using absl::SkipEmpty;
+ using absl::SkipWhitespace;
+
+ {
+ // No predicate. Does not skip empties.
+ auto splitter = absl::StrSplit(kTestChars, ',');
+ std::vector<std::string> v = splitter;
+ EXPECT_THAT(v, ElementsAre("", "a", " ", "b", ""));
+ }
+
+ {
+ // Allows empty strings. Same behavior as no predicate at all.
+ auto splitter = absl::StrSplit(kTestChars, ',', AllowEmpty());
+ std::vector<std::string> v_allowempty = splitter;
+ EXPECT_THAT(v_allowempty, ElementsAre("", "a", " ", "b", ""));
+
+ // Ensures AllowEmpty equals the behavior with no predicate.
+ auto splitter_nopredicate = absl::StrSplit(kTestChars, ',');
+ std::vector<std::string> v_nopredicate = splitter_nopredicate;
+ EXPECT_EQ(v_allowempty, v_nopredicate);
+ }
+
+ {
+ // Skips empty strings.
+ auto splitter = absl::StrSplit(kTestChars, ',', SkipEmpty());
+ std::vector<std::string> v = splitter;
+ EXPECT_THAT(v, ElementsAre("a", " ", "b"));
+ }
+
+ {
+ // Skips empty and all-whitespace strings.
+ auto splitter = absl::StrSplit(kTestChars, ',', SkipWhitespace());
+ std::vector<std::string> v = splitter;
+ EXPECT_THAT(v, ElementsAre("a", "b"));
+ }
+}
+
+//
+// Tests for StrSplit()
+//
+
+TEST(Split, Basics) {
+ {
+ // Doesn't really do anything useful because the return value is ignored,
+ // but it should work.
+ absl::StrSplit("a,b,c", ',');
+ }
+
+ {
+ std::vector<absl::string_view> v = absl::StrSplit("a,b,c", ',');
+ EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+ }
+
+ {
+ std::vector<std::string> v = absl::StrSplit("a,b,c", ',');
+ EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+ }
+
+ {
+ // Ensures that assignment works. This requires a little extra work with
+ // C++11 because of overloads with initializer_list.
+ std::vector<std::string> v;
+ v = absl::StrSplit("a,b,c", ',');
+
+ EXPECT_THAT(v, ElementsAre("a", "b", "c"));
+ std::map<std::string, std::string> m;
+ m = absl::StrSplit("a,b,c", ',');
+ EXPECT_EQ(2, m.size());
+ std::unordered_map<std::string, std::string> hm;
+ hm = absl::StrSplit("a,b,c", ',');
+ EXPECT_EQ(2, hm.size());
+ }
+}
+
+absl::string_view ReturnStringView() { return "Hello World"; }
+const char* ReturnConstCharP() { return "Hello World"; }
+char* ReturnCharP() { return const_cast<char*>("Hello World"); }
+
+TEST(Split, AcceptsCertainTemporaries) {
+ std::vector<std::string> v;
+ v = absl::StrSplit(ReturnStringView(), ' ');
+ EXPECT_THAT(v, ElementsAre("Hello", "World"));
+ v = absl::StrSplit(ReturnConstCharP(), ' ');
+ EXPECT_THAT(v, ElementsAre("Hello", "World"));
+ v = absl::StrSplit(ReturnCharP(), ' ');
+ EXPECT_THAT(v, ElementsAre("Hello", "World"));
+}
+
+TEST(Split, Temporary) {
+ // Use a std::string longer than the small-std::string-optimization length, so that when
+ // the temporary is destroyed, if the splitter keeps a reference to the
+ // std::string's contents, it'll reference freed memory instead of just dead
+ // on-stack memory.
+ const char input[] = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u";
+ EXPECT_LT(sizeof(std::string), ABSL_ARRAYSIZE(input))
+ << "Input should be larger than fits on the stack.";
+
+ // This happens more often in C++11 as part of a range-based for loop.
+ auto splitter = absl::StrSplit(std::string(input), ',');
+ std::string expected = "a";
+ for (absl::string_view letter : splitter) {
+ EXPECT_EQ(expected, letter);
+ ++expected[0];
+ }
+ EXPECT_EQ("v", expected);
+
+ // This happens more often in C++11 as part of a range-based for loop.
+ auto std_splitter = absl::StrSplit(std::string(input), ',');
+ expected = "a";
+ for (absl::string_view letter : std_splitter) {
+ EXPECT_EQ(expected, letter);
+ ++expected[0];
+ }
+ EXPECT_EQ("v", expected);
+}
+
+template <typename T>
+static std::unique_ptr<T> CopyToHeap(const T& value) {
+ return std::unique_ptr<T>(new T(value));
+}
+
+TEST(Split, LvalueCaptureIsCopyable) {
+ std::string input = "a,b";
+ auto heap_splitter = CopyToHeap(absl::StrSplit(input, ','));
+ auto stack_splitter = *heap_splitter;
+ heap_splitter.reset();
+ std::vector<std::string> result = stack_splitter;
+ EXPECT_THAT(result, testing::ElementsAre("a", "b"));
+}
+
+TEST(Split, TemporaryCaptureIsCopyable) {
+ auto heap_splitter = CopyToHeap(absl::StrSplit(std::string("a,b"), ','));
+ auto stack_splitter = *heap_splitter;
+ heap_splitter.reset();
+ std::vector<std::string> result = stack_splitter;
+ EXPECT_THAT(result, testing::ElementsAre("a", "b"));
+}
+
+TEST(Split, SplitterIsCopyableAndMoveable) {
+ auto a = absl::StrSplit("foo", '-');
+
+ // Ensures that the following expressions compile.
+ auto b = a; // Copy construct
+ auto c = std::move(a); // Move construct
+ b = c; // Copy assign
+ c = std::move(b); // Move assign
+
+ EXPECT_THAT(c, ElementsAre("foo"));
+}
+
+TEST(Split, StringDelimiter) {
+ {
+ std::vector<absl::string_view> v = absl::StrSplit("a,b", ',');
+ EXPECT_THAT(v, ElementsAre("a", "b"));
+ }
+
+ {
+ std::vector<absl::string_view> v = absl::StrSplit("a,b", std::string(","));
+ EXPECT_THAT(v, ElementsAre("a", "b"));
+ }
+
+ {
+ std::vector<absl::string_view> v =
+ absl::StrSplit("a,b", absl::string_view(","));
+ EXPECT_THAT(v, ElementsAre("a", "b"));
+ }
+}
+
+TEST(Split, UTF8) {
+ // Tests splitting utf8 strings and utf8 delimiters.
+ {
+ // A utf8 input std::string with an ascii delimiter.
+ std::vector<absl::string_view> v = absl::StrSplit("a,κόσμε", ',');
+ EXPECT_THAT(v, ElementsAre("a", "κόσμε"));
+ }
+
+ {
+ // A utf8 input std::string and a utf8 delimiter.
+ std::vector<absl::string_view> v = absl::StrSplit("a,κόσμε,b", ",κόσμε,");
+ EXPECT_THAT(v, ElementsAre("a", "b"));
+ }
+
+ {
+ // A utf8 input std::string and ByAnyChar with ascii chars.
+ std::vector<absl::string_view> v =
+ absl::StrSplit("Foo hällo th丞re", absl::ByAnyChar(" \t"));
+ EXPECT_THAT(v, ElementsAre("Foo", "hällo", "th丞re"));
+ }
+}
+
+TEST(Split, EmptyStringDelimiter) {
+ {
+ std::vector<std::string> v = absl::StrSplit("", "");
+ EXPECT_THAT(v, ElementsAre(""));
+ }
+
+ {
+ std::vector<std::string> v = absl::StrSplit("a", "");
+ EXPECT_THAT(v, ElementsAre("a"));
+ }
+
+ {
+ std::vector<std::string> v = absl::StrSplit("ab", "");
+ EXPECT_THAT(v, ElementsAre("a", "b"));
+ }
+
+ {
+ std::vector<std::string> v = absl::StrSplit("a b", "");
+ EXPECT_THAT(v, ElementsAre("a", " ", "b"));
+ }
+}
+
+TEST(Split, SubstrDelimiter) {
+ std::vector<absl::string_view> results;
+ absl::string_view delim("//");
+
+ results = absl::StrSplit("", delim);
+ EXPECT_THAT(results, ElementsAre(""));
+
+ results = absl::StrSplit("//", delim);
+ EXPECT_THAT(results, ElementsAre("", ""));
+
+ results = absl::StrSplit("ab", delim);
+ EXPECT_THAT(results, ElementsAre("ab"));
+
+ results = absl::StrSplit("ab//", delim);
+ EXPECT_THAT(results, ElementsAre("ab", ""));
+
+ results = absl::StrSplit("ab/", delim);
+ EXPECT_THAT(results, ElementsAre("ab/"));
+
+ results = absl::StrSplit("a/b", delim);
+ EXPECT_THAT(results, ElementsAre("a/b"));
+
+ results = absl::StrSplit("a//b", delim);
+ EXPECT_THAT(results, ElementsAre("a", "b"));
+
+ results = absl::StrSplit("a///b", delim);
+ EXPECT_THAT(results, ElementsAre("a", "/b"));
+
+ results = absl::StrSplit("a////b", delim);
+ EXPECT_THAT(results, ElementsAre("a", "", "b"));
+}
+
+TEST(Split, EmptyResults) {
+ std::vector<absl::string_view> results;
+
+ results = absl::StrSplit("", '#');
+ EXPECT_THAT(results, ElementsAre(""));
+
+ results = absl::StrSplit("#", '#');
+ EXPECT_THAT(results, ElementsAre("", ""));
+
+ results = absl::StrSplit("#cd", '#');
+ EXPECT_THAT(results, ElementsAre("", "cd"));
+
+ results = absl::StrSplit("ab#cd#", '#');
+ EXPECT_THAT(results, ElementsAre("ab", "cd", ""));
+
+ results = absl::StrSplit("ab##cd", '#');
+ EXPECT_THAT(results, ElementsAre("ab", "", "cd"));
+
+ results = absl::StrSplit("ab##", '#');
+ EXPECT_THAT(results, ElementsAre("ab", "", ""));
+
+ results = absl::StrSplit("ab#ab#", '#');
+ EXPECT_THAT(results, ElementsAre("ab", "ab", ""));
+
+ results = absl::StrSplit("aaaa", 'a');
+ EXPECT_THAT(results, ElementsAre("", "", "", "", ""));
+
+ results = absl::StrSplit("", '#', absl::SkipEmpty());
+ EXPECT_THAT(results, ElementsAre());
+}
+
+template <typename Delimiter>
+static bool IsFoundAtStartingPos(absl::string_view text, Delimiter d,
+ size_t starting_pos, int expected_pos) {
+ absl::string_view found = d.Find(text, starting_pos);
+ return found.data() != text.end() &&
+ expected_pos == found.data() - text.data();
+}
+
+// Helper function for testing Delimiter objects. Returns true if the given
+// Delimiter is found in the given std::string at the given position. This function
+// tests two cases:
+// 1. The actual text given, staring at position 0
+// 2. The text given with leading padding that should be ignored
+template <typename Delimiter>
+static bool IsFoundAt(absl::string_view text, Delimiter d, int expected_pos) {
+ const std::string leading_text = ",x,y,z,";
+ return IsFoundAtStartingPos(text, d, 0, expected_pos) &&
+ IsFoundAtStartingPos(leading_text + std::string(text), d,
+ leading_text.length(),
+ expected_pos + leading_text.length());
+}
+
+//
+// Tests for Literal
+//
+
+// Tests using any delimiter that represents a single comma.
+template <typename Delimiter>
+void TestComma(Delimiter d) {
+ EXPECT_TRUE(IsFoundAt(",", d, 0));
+ EXPECT_TRUE(IsFoundAt("a,", d, 1));
+ EXPECT_TRUE(IsFoundAt(",b", d, 0));
+ EXPECT_TRUE(IsFoundAt("a,b", d, 1));
+ EXPECT_TRUE(IsFoundAt("a,b,", d, 1));
+ EXPECT_TRUE(IsFoundAt("a,b,c", d, 1));
+ EXPECT_FALSE(IsFoundAt("", d, -1));
+ EXPECT_FALSE(IsFoundAt(" ", d, -1));
+ EXPECT_FALSE(IsFoundAt("a", d, -1));
+ EXPECT_FALSE(IsFoundAt("a b c", d, -1));
+ EXPECT_FALSE(IsFoundAt("a;b;c", d, -1));
+ EXPECT_FALSE(IsFoundAt(";", d, -1));
+}
+
+TEST(Delimiter, Literal) {
+ using absl::ByString;
+ TestComma(ByString(","));
+
+ // Works as named variable.
+ ByString comma_string(",");
+ TestComma(comma_string);
+
+ // The first occurrence of empty std::string ("") in a std::string is at position 0.
+ // There is a test below that demonstrates this for absl::string_view::find().
+ // If the ByString delimiter returned position 0 for this, there would
+ // be an infinite loop in the SplitIterator code. To avoid this, empty std::string
+ // is a special case in that it always returns the item at position 1.
+ absl::string_view abc("abc");
+ EXPECT_EQ(0, abc.find("")); // "" is found at position 0
+ ByString empty("");
+ EXPECT_FALSE(IsFoundAt("", empty, 0));
+ EXPECT_FALSE(IsFoundAt("a", empty, 0));
+ EXPECT_TRUE(IsFoundAt("ab", empty, 1));
+ EXPECT_TRUE(IsFoundAt("abc", empty, 1));
+}
+
+TEST(Split, ByChar) {
+ using absl::ByChar;
+ TestComma(ByChar(','));
+
+ // Works as named variable.
+ ByChar comma_char(',');
+ TestComma(comma_char);
+}
+
+//
+// Tests for ByAnyChar
+//
+
+TEST(Delimiter, ByAnyChar) {
+ using absl::ByAnyChar;
+ ByAnyChar one_delim(",");
+ // Found
+ EXPECT_TRUE(IsFoundAt(",", one_delim, 0));
+ EXPECT_TRUE(IsFoundAt("a,", one_delim, 1));
+ EXPECT_TRUE(IsFoundAt("a,b", one_delim, 1));
+ EXPECT_TRUE(IsFoundAt(",b", one_delim, 0));
+ // Not found
+ EXPECT_FALSE(IsFoundAt("", one_delim, -1));
+ EXPECT_FALSE(IsFoundAt(" ", one_delim, -1));
+ EXPECT_FALSE(IsFoundAt("a", one_delim, -1));
+ EXPECT_FALSE(IsFoundAt("a;b;c", one_delim, -1));
+ EXPECT_FALSE(IsFoundAt(";", one_delim, -1));
+
+ ByAnyChar two_delims(",;");
+ // Found
+ EXPECT_TRUE(IsFoundAt(",", two_delims, 0));
+ EXPECT_TRUE(IsFoundAt(";", two_delims, 0));
+ EXPECT_TRUE(IsFoundAt(",;", two_delims, 0));
+ EXPECT_TRUE(IsFoundAt(";,", two_delims, 0));
+ EXPECT_TRUE(IsFoundAt(",;b", two_delims, 0));
+ EXPECT_TRUE(IsFoundAt(";,b", two_delims, 0));
+ EXPECT_TRUE(IsFoundAt("a;,", two_delims, 1));
+ EXPECT_TRUE(IsFoundAt("a,;", two_delims, 1));
+ EXPECT_TRUE(IsFoundAt("a;,b", two_delims, 1));
+ EXPECT_TRUE(IsFoundAt("a,;b", two_delims, 1));
+ // Not found
+ EXPECT_FALSE(IsFoundAt("", two_delims, -1));
+ EXPECT_FALSE(IsFoundAt(" ", two_delims, -1));
+ EXPECT_FALSE(IsFoundAt("a", two_delims, -1));
+ EXPECT_FALSE(IsFoundAt("a=b=c", two_delims, -1));
+ EXPECT_FALSE(IsFoundAt("=", two_delims, -1));
+
+ // ByAnyChar behaves just like ByString when given a delimiter of empty
+ // std::string. That is, it always returns a zero-length absl::string_view
+ // referring to the item at position 1, not position 0.
+ ByAnyChar empty("");
+ EXPECT_FALSE(IsFoundAt("", empty, 0));
+ EXPECT_FALSE(IsFoundAt("a", empty, 0));
+ EXPECT_TRUE(IsFoundAt("ab", empty, 1));
+ EXPECT_TRUE(IsFoundAt("abc", empty, 1));
+}
+
+//
+// Tests for ByLength
+//
+
+TEST(Delimiter, ByLength) {
+ using absl::ByLength;
+
+ ByLength four_char_delim(4);
+
+ // Found
+ EXPECT_TRUE(IsFoundAt("abcde", four_char_delim, 4));
+ EXPECT_TRUE(IsFoundAt("abcdefghijklmnopqrstuvwxyz", four_char_delim, 4));
+ EXPECT_TRUE(IsFoundAt("a b,c\nd", four_char_delim, 4));
+ // Not found
+ EXPECT_FALSE(IsFoundAt("", four_char_delim, 0));
+ EXPECT_FALSE(IsFoundAt("a", four_char_delim, 0));
+ EXPECT_FALSE(IsFoundAt("ab", four_char_delim, 0));
+ EXPECT_FALSE(IsFoundAt("abc", four_char_delim, 0));
+ EXPECT_FALSE(IsFoundAt("abcd", four_char_delim, 0));
+}
+
+// Allocates too much memory for TSan and MSan.
+#if !defined(THREAD_SANITIZER) && !defined(MEMORY_SANITIZER)
+TEST(Split, WorksWithLargeStrings) {
+ if (sizeof(size_t) > 4 && !RunningOnValgrind()) {
+ std::string s(1ULL << 31, 'x');
+ s.push_back('-'); // 2G + 1 byte
+ std::vector<absl::string_view> v = absl::StrSplit(s, '-');
+ EXPECT_EQ(2, v.size());
+ // The first element will contain 2G of 'x's.
+ // testing::StartsWith is too slow with a 2G std::string.
+ EXPECT_EQ('x', v[0][0]);
+ EXPECT_EQ('x', v[0][1]);
+ EXPECT_EQ('x', v[0][3]);
+ EXPECT_EQ("", v[1]);
+ }
+}
+#endif // THREAD_SANITIZER
+
+TEST(SplitInternalTest, TypeTraits) {
+ EXPECT_FALSE(absl::strings_internal::HasMappedType<int>::value);
+ EXPECT_TRUE(
+ (absl::strings_internal::HasMappedType<std::map<int, int>>::value));
+ EXPECT_FALSE(absl::strings_internal::HasValueType<int>::value);
+ EXPECT_TRUE(
+ (absl::strings_internal::HasValueType<std::map<int, int>>::value));
+ EXPECT_FALSE(absl::strings_internal::HasConstIterator<int>::value);
+ EXPECT_TRUE(
+ (absl::strings_internal::HasConstIterator<std::map<int, int>>::value));
+ EXPECT_FALSE(absl::strings_internal::IsInitializerList<int>::value);
+ EXPECT_TRUE((absl::strings_internal::IsInitializerList<
+ std::initializer_list<int>>::value));
+}
+
+} // namespace
diff --git a/absl/strings/string_view.cc b/absl/strings/string_view.cc
new file mode 100644
index 0000000..4d4ba6c
--- /dev/null
+++ b/absl/strings/string_view.cc
@@ -0,0 +1,248 @@
+// 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/strings/string_view.h"
+
+#ifndef ABSL_HAVE_STD_STRING_VIEW
+
+#include <algorithm>
+#include <climits>
+#include <cstring>
+#include <ostream>
+#include <string>
+
+#include "absl/strings/internal/memutil.h"
+#include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/match.h"
+
+namespace absl {
+
+namespace {
+void WritePadding(std::ostream& o, size_t pad) {
+ char fill_buf[32];
+ memset(fill_buf, o.fill(), sizeof(fill_buf));
+ while (pad) {
+ size_t n = std::min(pad, sizeof(fill_buf));
+ o.write(fill_buf, n);
+ pad -= n;
+ }
+}
+
+class LookupTable {
+ public:
+ // For each character in wanted, sets the index corresponding
+ // to the ASCII code of that character. This is used by
+ // the find_.*_of methods below to tell whether or not a character is in
+ // the lookup table in constant time.
+ explicit LookupTable(string_view wanted) {
+ for (char c : wanted) {
+ table_[Index(c)] = true;
+ }
+ }
+ bool operator[](char c) const { return table_[Index(c)]; }
+
+ private:
+ static unsigned char Index(char c) { return static_cast<unsigned char>(c); }
+ bool table_[UCHAR_MAX + 1] = {};
+};
+
+} // namespace
+
+std::ostream& operator<<(std::ostream& o, string_view piece) {
+ std::ostream::sentry sentry(o);
+ if (sentry) {
+ size_t lpad = 0;
+ size_t rpad = 0;
+ if (static_cast<size_t>(o.width()) > piece.size()) {
+ size_t pad = o.width() - piece.size();
+ if ((o.flags() & o.adjustfield) == o.left) {
+ rpad = pad;
+ } else {
+ lpad = pad;
+ }
+ }
+ if (lpad) WritePadding(o, lpad);
+ o.write(piece.data(), piece.size());
+ if (rpad) WritePadding(o, rpad);
+ o.width(0);
+ }
+ return o;
+}
+
+string_view::size_type string_view::copy(char* buf, size_type n,
+ size_type pos) const {
+ size_type ulen = length_;
+ assert(pos <= ulen);
+ size_type rlen = std::min(ulen - pos, n);
+ if (rlen > 0) {
+ const char* start = ptr_ + pos;
+ std::copy(start, start + rlen, buf);
+ }
+ return rlen;
+}
+
+string_view::size_type string_view::find(string_view s, size_type pos) const
+ noexcept {
+ if (empty() || pos > length_) {
+ if (empty() && pos == 0 && s.empty()) return 0;
+ return npos;
+ }
+ const char* result =
+ strings_internal::memmatch(ptr_ + pos, length_ - pos, s.ptr_, s.length_);
+ return result ? result - ptr_ : npos;
+}
+
+string_view::size_type string_view::find(char c, size_type pos) const noexcept {
+ if (empty() || pos >= length_) {
+ return npos;
+ }
+ const char* result =
+ static_cast<const char*>(memchr(ptr_ + pos, c, length_ - pos));
+ return result != nullptr ? result - ptr_ : npos;
+}
+
+string_view::size_type string_view::rfind(string_view s, size_type pos) const
+ noexcept {
+ if (length_ < s.length_) return npos;
+ if (s.empty()) return std::min(length_, pos);
+ const char* last = ptr_ + std::min(length_ - s.length_, pos) + s.length_;
+ const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_);
+ return result != last ? result - ptr_ : npos;
+}
+
+// Search range is [0..pos] inclusive. If pos == npos, search everything.
+string_view::size_type string_view::rfind(char c, size_type pos) const
+ noexcept {
+ // Note: memrchr() is not available on Windows.
+ if (empty()) return npos;
+ for (size_type i = std::min(pos, length_ - 1);; --i) {
+ if (ptr_[i] == c) {
+ return i;
+ }
+ if (i == 0) break;
+ }
+ return npos;
+}
+
+string_view::size_type string_view::find_first_of(string_view s,
+ size_type pos) const
+ noexcept {
+ if (empty() || s.empty()) {
+ return npos;
+ }
+ // Avoid the cost of LookupTable() for a single-character search.
+ if (s.length_ == 1) return find_first_of(s.ptr_[0], pos);
+ LookupTable tbl(s);
+ for (size_type i = pos; i < length_; ++i) {
+ if (tbl[ptr_[i]]) {
+ return i;
+ }
+ }
+ return npos;
+}
+
+string_view::size_type string_view::find_first_not_of(string_view s,
+ size_type pos) const
+ noexcept {
+ if (empty()) return npos;
+ // Avoid the cost of LookupTable() for a single-character search.
+ if (s.length_ == 1) return find_first_not_of(s.ptr_[0], pos);
+ LookupTable tbl(s);
+ for (size_type i = pos; i < length_; ++i) {
+ if (!tbl[ptr_[i]]) {
+ return i;
+ }
+ }
+ return npos;
+}
+
+string_view::size_type string_view::find_first_not_of(char c,
+ size_type pos) const
+ noexcept {
+ if (empty()) return npos;
+ for (; pos < length_; ++pos) {
+ if (ptr_[pos] != c) {
+ return pos;
+ }
+ }
+ return npos;
+}
+
+string_view::size_type string_view::find_last_of(string_view s,
+ size_type pos) const noexcept {
+ if (empty() || s.empty()) return npos;
+ // Avoid the cost of LookupTable() for a single-character search.
+ if (s.length_ == 1) return find_last_of(s.ptr_[0], pos);
+ LookupTable tbl(s);
+ for (size_type i = std::min(pos, length_ - 1);; --i) {
+ if (tbl[ptr_[i]]) {
+ return i;
+ }
+ if (i == 0) break;
+ }
+ return npos;
+}
+
+string_view::size_type string_view::find_last_not_of(string_view s,
+ size_type pos) const
+ noexcept {
+ if (empty()) return npos;
+ size_type i = std::min(pos, length_ - 1);
+ if (s.empty()) return i;
+ // Avoid the cost of LookupTable() for a single-character search.
+ if (s.length_ == 1) return find_last_not_of(s.ptr_[0], pos);
+ LookupTable tbl(s);
+ for (;; --i) {
+ if (!tbl[ptr_[i]]) {
+ return i;
+ }
+ if (i == 0) break;
+ }
+ return npos;
+}
+
+string_view::size_type string_view::find_last_not_of(char c,
+ size_type pos) const
+ noexcept {
+ if (empty()) return npos;
+ size_type i = std::min(pos, length_ - 1);
+ for (;; --i) {
+ if (ptr_[i] != c) {
+ return i;
+ }
+ if (i == 0) break;
+ }
+ return npos;
+}
+
+// MSVC has non-standard behavior that implicitly creates definitions for static
+// const members. These implicit definitions conflict with explicit out-of-class
+// member definitions that are required by the C++ standard, resulting in
+// LNK1169 "multiply defined" errors at link time. __declspec(selectany) asks
+// MSVC to choose only one definition for the symbol it decorates. See details
+// at http://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx
+#ifdef _MSC_VER
+#define ABSL_STRING_VIEW_SELECTANY __declspec(selectany)
+#else
+#define ABSL_STRING_VIEW_SELECTANY
+#endif
+
+ABSL_STRING_VIEW_SELECTANY
+constexpr string_view::size_type string_view::npos;
+ABSL_STRING_VIEW_SELECTANY
+constexpr string_view::size_type string_view::kMaxSize;
+
+} // namespace absl
+
+#endif // ABSL_HAVE_STD_STRING_VIEW
diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h
new file mode 100644
index 0000000..e2609f1
--- /dev/null
+++ b/absl/strings/string_view.h
@@ -0,0 +1,572 @@
+//
+// 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: string_view.h
+// -----------------------------------------------------------------------------
+//
+// This file contains the definition of the `absl::string_view` class. A
+// `string_view` points to a contiguous span of characters, often part or all of
+// another `std::string`, double-quoted std::string literal, character array, or even
+// another `string_view`.
+//
+// This `absl::string_view` abstraction is designed to be a drop-in
+// replacement for the C++17 `std::string_view` abstraction.
+#ifndef ABSL_STRINGS_STRING_VIEW_H_
+#define ABSL_STRINGS_STRING_VIEW_H_
+
+#include <algorithm>
+#include "absl/base/config.h"
+
+#ifdef ABSL_HAVE_STD_STRING_VIEW
+
+#include <string_view>
+
+namespace absl {
+using std::string_view;
+};
+
+#else // ABSL_HAVE_STD_STRING_VIEW
+
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <iosfwd>
+#include <iterator>
+#include <limits>
+#include <string>
+
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+
+namespace absl {
+
+// absl::string_view
+//
+// A `string_view` provides a lightweight view into the std::string data provided by
+// a `std::string`, double-quoted std::string literal, character array, or even
+// another `string_view`. A `string_view` does *not* own the std::string to which it
+// points, and that data cannot be modified through the view.
+//
+// You can use `string_view` as a function or method parameter anywhere a
+// parameter can receive a double-quoted std::string literal, `const char*`,
+// `std::string`, or another `absl::string_view` argument with no need to copy
+// the std::string data. Systematic use of `string_view` within function arguments
+// reduces data copies and `strlen()` calls.
+//
+// Because of its small size, prefer passing `string_view` by value:
+//
+// void MyFunction(absl::string_view arg);
+//
+// If circumstances require, you may also pass one by const reference:
+//
+// void MyFunction(const absl::string_view& arg); // not preferred
+//
+// Passing by value generates slightly smaller code for many architectures.
+//
+// In either case, the source data of the `string_view` must outlive the
+// `string_view` itself.
+//
+// A `string_view` is also suitable for local variables if you know that the
+// lifetime of the underlying object is longer than the lifetime of your
+// `string_view` variable. However, beware of binding a `string_view` to a
+// temporary value:
+//
+// // BAD use of string_view: lifetime problem
+// absl::string_view sv = obj.ReturnAString();
+//
+// // GOOD use of string_view: str outlives sv
+// std::string str = obj.ReturnAString();
+// absl::string_view sv = str;
+//
+// Due to lifetime issues, a `string_view` is sometimes a poor choice for a
+// return value and usually a poor choice for a data member. If you do use a
+// `string_view` this way, it is your responsibility to ensure that the object
+// pointed to by the `string_view` outlives the `string_view`.
+//
+// A `string_view` may represent a whole std::string or just part of a std::string. For
+// example, when splitting a std::string, `std::vector<absl::string_view>` is a
+// natural data type for the output.
+//
+//
+// When constructed from a source which is nul-terminated, the `string_view`
+// itself will not include the nul-terminator unless a specific size (including
+// the nul) is passed to the constructor. As a result, common idioms that work
+// on nul-terminated strings do not work on `string_view` objects. If you write
+// code that scans a `string_view`, you must check its length rather than test
+// for nul, for example. Note, however, that nuls may still be embedded within
+// a `string_view` explicitly.
+//
+// You may create a null `string_view` in two ways:
+//
+// absl::string_view sv();
+// absl::string_view sv(nullptr, 0);
+//
+// For the above, `sv.data() == nullptr`, `sv.length() == 0`, and
+// `sv.empty() == true`. Also, if you create a `string_view` with a non-null
+// pointer then `sv.data() != nullptr`. Thus, you can use `string_view()` to
+// signal an undefined value that is different from other `string_view` values
+// in a similar fashion to how `const char* p1 = nullptr;` is different from
+// `const char* p2 = "";`. However, in practice, it is not recommended to rely
+// on this behavior.
+//
+// Be careful not to confuse a null `string_view` with an empty one. A null
+// `string_view` is an empty `string_view`, but some empty `string_view`s are
+// not null. Prefer checking for emptiness over checking for null.
+//
+// There are many ways to create an empty string_view:
+//
+// const char* nullcp = nullptr;
+// // string_view.size() will return 0 in all cases.
+// absl::string_view();
+// absl::string_view(nullcp, 0);
+// absl::string_view("");
+// absl::string_view("", 0);
+// absl::string_view("abcdef", 0);
+// absl::string_view("abcdef" + 6, 0);
+//
+// All empty `string_view` objects whether null or not, are equal:
+//
+// absl::string_view() == absl::string_view("", 0)
+// absl::string_view(nullptr, 0) == absl:: string_view("abcdef"+6, 0)
+class string_view {
+ public:
+ using traits_type = std::char_traits<char>;
+ using value_type = char;
+ using pointer = char*;
+ using const_pointer = const char*;
+ using reference = char&;
+ using const_reference = const char&;
+ using const_iterator = const char*;
+ using iterator = const_iterator;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ using reverse_iterator = const_reverse_iterator;
+ using size_type = size_t;
+ using difference_type = std::ptrdiff_t;
+
+ static constexpr size_type npos = static_cast<size_type>(-1);
+
+ // Null `string_view` constructor
+ constexpr string_view() noexcept : ptr_(nullptr), length_(0) {}
+
+ // Implicit constructors
+
+ template <typename Allocator>
+ string_view( // NOLINT(runtime/explicit)
+ const std::basic_string<char, std::char_traits<char>, Allocator>&
+ str) noexcept
+ : ptr_(str.data()), length_(str.size()) {}
+
+ // Implicit constructor of a `string_view` from nul-terminated `str`. When
+ // accepting possibly null strings, use `absl::NullSafeStringView(str)`
+ // instead (see below).
+ constexpr string_view(const char* str) // NOLINT(runtime/explicit)
+ : ptr_(str), length_(StrLenInternal(str)) {}
+
+ // Implicit consructor of a `string_view` from a `const char*` and length
+ constexpr string_view(const char* data, size_type len)
+ : ptr_(data), length_(CheckLengthInternal(len)) {}
+
+ // NOTE(b/36227513): harmlessly omitted to work around gdb bug.
+ // constexpr string_view(const string_view&) noexcept = default;
+ // string_view& operator=(const string_view&) noexcept = default;
+
+ // Iterators
+
+ // string_view::begin()
+ //
+ // Returns an iterator pointing to the first character at the beginning of the
+ // `string_view`, or `end()` if the `string_view` is empty.
+ constexpr const_iterator begin() const noexcept { return ptr_; }
+
+ // string_view::end()
+ //
+ // Returns an iterator pointing just beyond the last character at the end of
+ // the `string_view`. This iterator acts as a placeholder; attempting to
+ // access it results in undefined behavior.
+ constexpr const_iterator end() const noexcept { return ptr_ + length_; }
+
+ // string_view::cbegin()
+ //
+ // Returns a const iterator pointing to the first character at the beginning
+ // of the `string_view`, or `end()` if the `string_view` is empty.
+ constexpr const_iterator cbegin() const noexcept { return begin(); }
+
+ // string_view::cend()
+ //
+ // Returns a const iterator pointing just beyond the last character at the end
+ // of the `string_view`. This pointer acts as a placeholder; attempting to
+ // access its element results in undefined behavior.
+ constexpr const_iterator cend() const noexcept { return end(); }
+
+ // string_view::rbegin()
+ //
+ // Returns a reverse iterator pointing to the last character at the end of the
+ // `string_view`, or `rend()` if the `string_view` is empty.
+ const_reverse_iterator rbegin() const noexcept {
+ return const_reverse_iterator(end());
+ }
+
+ // string_view::rend()
+ //
+ // Returns a reverse iterator pointing just before the first character at the
+ // beginning of the `string_view`. This pointer acts as a placeholder;
+ // attempting to access its element results in undefined behavior.
+ const_reverse_iterator rend() const noexcept {
+ return const_reverse_iterator(begin());
+ }
+
+ // string_view::crbegin()
+ //
+ // Returns a const reverse iterator pointing to the last character at the end
+ // of the `string_view`, or `crend()` if the `string_view` is empty.
+ const_reverse_iterator crbegin() const noexcept { return rbegin(); }
+
+ // string_view::crend()
+ //
+ // Returns a const reverse iterator pointing just before the first character
+ // at the beginning of the `string_view`. This pointer acts as a placeholder;
+ // attempting to access its element results in undefined behavior.
+ const_reverse_iterator crend() const noexcept { return rend(); }
+
+ // Capacity Utilities
+
+ // string_view::size()
+ //
+ // Returns the number of characters in the `string_view`.
+ constexpr size_type size() const noexcept {
+ return length_;
+ }
+
+ // string_view::length()
+ //
+ // Returns the number of characters in the `string_view`. Alias for `size()`.
+ constexpr size_type length() const noexcept { return size(); }
+
+ // string_view::max_size()
+ //
+ // Returns the maximum number of characters the `string_view` can hold.
+ constexpr size_type max_size() const noexcept { return kMaxSize; }
+
+ // string_view::empty()
+ //
+ // Checks if the `string_view` is empty (refers to no characters).
+ constexpr bool empty() const noexcept { return length_ == 0; }
+
+ // std::string:view::operator[]
+ //
+ // Returns the ith element of an `string_view` using the array operator.
+ // Note that this operator does not perform any bounds checking.
+ constexpr const_reference operator[](size_type i) const { return ptr_[i]; }
+
+ // string_view::front()
+ //
+ // Returns the first element of a `string_view`.
+ constexpr const_reference front() const { return ptr_[0]; }
+
+ // string_view::back()
+ //
+ // Returns the last element of a `string_view`.
+ constexpr const_reference back() const { return ptr_[size() - 1]; }
+
+ // string_view::data()
+ //
+ // Returns a pointer to the underlying character array (which is of course
+ // stored elsewhere). Note that `string_view::data()` may contain embedded nul
+ // characters, but the returned buffer may or may not be nul-terminated;
+ // therefore, do not pass `data()` to a routine that expects a nul-terminated
+ // std::string.
+ constexpr const_pointer data() const noexcept { return ptr_; }
+
+ // Modifiers
+
+ // string_view::remove_prefix()
+ //
+ // Removes the first `n` characters from the `string_view`, returning a
+ // pointer to the new first character. Note that the underlying std::string is not
+ // changed, only the view.
+ void remove_prefix(size_type n) {
+ assert(n <= length_);
+ ptr_ += n;
+ length_ -= n;
+ }
+
+ // string_view::remove_suffix()
+ //
+ // Removes the last `n` characters from the `string_view`. Note that the
+ // underlying std::string is not changed, only the view.
+ void remove_suffix(size_type n) {
+ assert(n <= length_);
+ length_ -= n;
+ }
+
+ // string_view::swap()
+ //
+ // Swaps this `string_view` with another `string_view`.
+ void swap(string_view& s) noexcept {
+ auto t = *this;
+ *this = s;
+ s = t;
+ }
+
+ // Explicit conversion operators
+
+ // Supports conversion to both `std::basic_string` where available.
+ template <typename A>
+ explicit operator std::basic_string<char, traits_type, A>() const {
+ if (!data()) return {};
+ return std::basic_string<char, traits_type, A>(data(), size());
+ }
+
+ // string_view::copy()
+ //
+ // Copies the contents of the `string_view` at offset `pos` and length `n`
+ // into `buf`.
+ size_type copy(char* buf, size_type n, size_type pos = 0) const;
+
+ // string_view::substr()
+ //
+ // Returns a "substring" of the `string_view` (at offset `post` and length
+ // `n`) as another std::string views. This function throws `std::out_of_bounds` if
+ // `pos > size'.
+ string_view substr(size_type pos, size_type n = npos) const {
+ if (ABSL_PREDICT_FALSE(pos > length_))
+ base_internal::ThrowStdOutOfRange("absl::string_view::substr");
+ n = std::min(n, length_ - pos);
+ return string_view(ptr_ + pos, n);
+ }
+
+ // string_view::compare()
+ //
+ // Performs a lexicographical comparison between the `string_view` and
+ // another `absl::string_view), returning -1 if `this` is less than, 0 if
+ // `this` is equal to, and 1 if `this` is greater than the passed std::string
+ // view. Note that in the case of data equality, a further comparison is made
+ // on the respective sizes of the two `string_view`s to determine which is
+ // smaller, equal, or greater.
+ int compare(string_view x) const noexcept {
+ auto min_length = std::min(length_, x.length_);
+ if (min_length > 0) {
+ int r = memcmp(ptr_, x.ptr_, min_length);
+ if (r < 0) return -1;
+ if (r > 0) return 1;
+ }
+ if (length_ < x.length_) return -1;
+ if (length_ > x.length_) return 1;
+ return 0;
+ }
+
+ // Overload of `string_view::compare()` for comparing a substring of the
+ // 'string_view` and another `absl::string_view`.
+ int compare(size_type pos1, size_type count1, string_view v) const {
+ return substr(pos1, count1).compare(v);
+ }
+
+ // Overload of `string_view::compare()` for comparing a substring of the
+ // `string_view` and a substring of another `absl::string_view`.
+ int compare(size_type pos1, size_type count1, string_view v, size_type pos2,
+ size_type count2) const {
+ return substr(pos1, count1).compare(v.substr(pos2, count2));
+ }
+
+ // Overload of `string_view::compare()` for comparing a `string_view` and a
+ // a different C-style std::string `s`.
+ int compare(const char* s) const { return compare(string_view(s)); }
+
+ // Overload of `string_view::compare()` for comparing a substring of the
+ // `string_view` and a different std::string C-style std::string `s`.
+ int compare(size_type pos1, size_type count1, const char* s) const {
+ return substr(pos1, count1).compare(string_view(s));
+ }
+
+ // Overload of `string_view::compare()` for comparing a substring of the
+ // `string_view` and a substring of a different C-style std::string `s`.
+ int compare(size_type pos1, size_type count1, const char* s,
+ size_type count2) const {
+ return substr(pos1, count1).compare(string_view(s, count2));
+ }
+
+ // Find Utilities
+
+ // string_view::find()
+ //
+ // Finds the first occurrence of the substring `s` within the `string_view`,
+ // returning the position of the first character's match, or `npos` if no
+ // match was found.
+ size_type find(string_view s, size_type pos = 0) const noexcept;
+
+ // Overload of `string_view::find()` for finding the given character `c`
+ // within the `string_view`.
+ size_type find(char c, size_type pos = 0) const noexcept;
+
+ // string_view::rfind()
+ //
+ // Finds the last occurrence of a substring `s` within the `string_view`,
+ // returning the position of the first character's match, or `npos` if no
+ // match was found.
+ size_type rfind(string_view s, size_type pos = npos) const
+ noexcept;
+
+ // Overload of `string_view::rfind()` for finding the given character `c`
+ // within the `string_view`.
+ size_type rfind(char c, size_type pos = npos) const noexcept;
+
+ // string_view::find_first_of()
+ //
+ // Finds the first occurrence of any of the characters in `s` within the
+ // `string_view`, returning the start position of the match, or `npos` if no
+ // match was found.
+ size_type find_first_of(string_view s, size_type pos = 0) const
+ noexcept;
+
+ // Overload of `string_view::find_first_of()` for finding a character `c`
+ // within the `string_view`.
+ size_type find_first_of(char c, size_type pos = 0) const
+ noexcept {
+ return find(c, pos);
+ }
+
+ // string_view::find_last_of()
+ //
+ // Finds the last occurrence of any of the characters in `s` within the
+ // `string_view`, returning the start position of the match, or `npos` if no
+ // match was found.
+ size_type find_last_of(string_view s, size_type pos = npos) const
+ noexcept;
+
+ // Overload of `string_view::find_last_of()` for finding a character `c`
+ // within the `string_view`.
+ size_type find_last_of(char c, size_type pos = npos) const
+ noexcept {
+ return rfind(c, pos);
+ }
+
+ // string_view::find_first_not_of()
+ //
+ // Finds the first occurrence of any of the characters not in `s` within the
+ // `string_view`, returning the start position of the first non-match, or
+ // `npos` if no non-match was found.
+ size_type find_first_not_of(string_view s, size_type pos = 0) const noexcept;
+
+ // Overload of `string_view::find_first_not_of()` for finding a character
+ // that is not `c` within the `string_view`.
+ size_type find_first_not_of(char c, size_type pos = 0) const noexcept;
+
+ // string_view::find_last_not_of()
+ //
+ // Finds the last occurrence of any of the characters not in `s` within the
+ // `string_view`, returning the start position of the last non-match, or
+ // `npos` if no non-match was found.
+ size_type find_last_not_of(string_view s,
+ size_type pos = npos) const noexcept;
+
+ // Overload of `string_view::find_last_not_of()` for finding a character
+ // that is not `c` within the `string_view`.
+ size_type find_last_not_of(char c, size_type pos = npos) const
+ noexcept;
+
+ private:
+ static constexpr size_type kMaxSize =
+ std::numeric_limits<size_type>::max() / 2 + 1;
+
+ static constexpr size_type StrLenInternal(const char* str) {
+ return str ?
+// check whether __builtin_strlen is provided by the compiler.
+// GCC doesn't have __has_builtin()
+// (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66970),
+// but has __builtin_strlen according to
+// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Other-Builtins.html.
+#if ABSL_HAVE_BUILTIN(__builtin_strlen) || \
+ (defined(__GNUC__) && !defined(__clang__))
+ __builtin_strlen(str)
+#else
+ strlen(str)
+#endif
+ : 0;
+ }
+
+ static constexpr size_type CheckLengthInternal(size_type len) {
+ return ABSL_ASSERT(len <= kMaxSize), len;
+ }
+
+ const char* ptr_;
+ size_type length_;
+};
+
+// This large function is defined inline so that in a fairly common case where
+// one of the arguments is a literal, the compiler can elide a lot of the
+// following comparisons.
+inline bool operator==(string_view x, string_view y) noexcept {
+ auto len = x.size();
+ if (len != y.size()) {
+ return false;
+ }
+ return x.data() == y.data() || len <= 0 ||
+ memcmp(x.data(), y.data(), len) == 0;
+}
+
+inline bool operator!=(string_view x, string_view y) noexcept {
+ return !(x == y);
+}
+
+inline bool operator<(string_view x, string_view y) noexcept {
+ auto min_size = std::min(x.size(), y.size());
+ const int r = min_size == 0 ? 0 : memcmp(x.data(), y.data(), min_size);
+ return (r < 0) || (r == 0 && x.size() < y.size());
+}
+
+inline bool operator>(string_view x, string_view y) noexcept { return y < x; }
+
+inline bool operator<=(string_view x, string_view y) noexcept {
+ return !(y < x);
+}
+
+inline bool operator>=(string_view x, string_view y) noexcept {
+ return !(x < y);
+}
+
+// IO Insertion Operator
+std::ostream& operator<<(std::ostream& o, string_view piece);
+
+} // namespace absl
+
+#endif // ABSL_HAVE_STD_STRING_VIEW
+
+namespace absl {
+
+// ClippedSubstr()
+//
+// Like `s.substr(pos, n)`, but clips `pos` to an upper bound of `s.size()`.
+// Provided because std::string_view::substr throws if `pos > size()`,
+// to support b/37991613.
+inline string_view ClippedSubstr(string_view s, size_t pos,
+ size_t n = string_view::npos) {
+ pos = std::min(pos, static_cast<size_t>(s.size()));
+ return s.substr(pos, n);
+}
+
+// NullSafeStringView()
+//
+// Creates an `absl::string_view` from a pointer `p` even if it's null-valued.
+// This function should be used where an `absl::string_view` can be created from
+// a possibly-null pointer.
+inline string_view NullSafeStringView(const char* p) {
+ return p ? string_view(p) : string_view();
+}
+
+} // namespace absl
+
+#endif // ABSL_STRINGS_STRING_VIEW_H_
diff --git a/absl/strings/string_view_test.cc b/absl/strings/string_view_test.cc
new file mode 100644
index 0000000..439d649
--- /dev/null
+++ b/absl/strings/string_view_test.cc
@@ -0,0 +1,1097 @@
+// 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/strings/string_view.h"
+
+#include <algorithm>
+#include <iomanip>
+#include <iterator>
+#include <map>
+#include <random>
+#include <sstream>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/port.h"
+
+namespace {
+
+// A minimal allocator that uses malloc().
+template <typename T>
+struct Mallocator {
+ typedef T value_type;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+
+ size_type max_size() const {
+ return size_t(std::numeric_limits<size_type>::max()) / sizeof(value_type);
+ }
+ template <typename U>
+ struct rebind {
+ typedef Mallocator<U> other;
+ };
+ Mallocator() = default;
+
+ T* allocate(size_t n) { return static_cast<T*>(std::malloc(n * sizeof(T))); }
+ void deallocate(T* p, size_t) { std::free(p); }
+};
+template <typename T, typename U>
+bool operator==(const Mallocator<T>&, const Mallocator<U>&) {
+ return true;
+}
+template <typename T, typename U>
+bool operator!=(const Mallocator<T>&, const Mallocator<U>&) {
+ return false;
+}
+
+TEST(StringViewTest, Ctor) {
+ {
+ // Null.
+ absl::string_view s10;
+ EXPECT_TRUE(s10.data() == nullptr);
+ EXPECT_EQ(0, s10.length());
+ }
+
+ {
+ // const char* without length.
+ const char* hello = "hello";
+ absl::string_view s20(hello);
+ EXPECT_TRUE(s20.data() == hello);
+ EXPECT_EQ(5, s20.length());
+
+ // const char* with length.
+ absl::string_view s21(hello, 4);
+ EXPECT_TRUE(s21.data() == hello);
+ EXPECT_EQ(4, s21.length());
+
+ // Not recommended, but valid C++
+ absl::string_view s22(hello, 6);
+ EXPECT_TRUE(s22.data() == hello);
+ EXPECT_EQ(6, s22.length());
+ }
+
+ {
+ // std::string.
+ std::string hola = "hola";
+ absl::string_view s30(hola);
+ EXPECT_TRUE(s30.data() == hola.data());
+ EXPECT_EQ(4, s30.length());
+
+ // std::string with embedded '\0'.
+ hola.push_back('\0');
+ hola.append("h2");
+ hola.push_back('\0');
+ absl::string_view s31(hola);
+ EXPECT_TRUE(s31.data() == hola.data());
+ EXPECT_EQ(8, s31.length());
+ }
+
+ {
+ using mstring =
+ std::basic_string<char, std::char_traits<char>, Mallocator<char>>;
+ mstring str1("BUNGIE-JUMPING!");
+ const mstring str2("SLEEPING!");
+
+ absl::string_view s1(str1);
+ s1.remove_prefix(strlen("BUNGIE-JUM"));
+
+ absl::string_view s2(str2);
+ s2.remove_prefix(strlen("SLEE"));
+
+ EXPECT_EQ(s1, s2);
+ EXPECT_EQ(s1, "PING!");
+ }
+
+ // TODO(mec): absl::string_view(const absl::string_view&);
+}
+
+TEST(StringViewTest, Swap) {
+ absl::string_view a("a");
+ absl::string_view b("bbb");
+ EXPECT_TRUE(noexcept(a.swap(b)));
+ a.swap(b);
+ EXPECT_EQ(a, "bbb");
+ EXPECT_EQ(b, "a");
+ a.swap(b);
+ EXPECT_EQ(a, "a");
+ EXPECT_EQ(b, "bbb");
+}
+
+TEST(StringViewTest, STLComparator) {
+ std::string s1("foo");
+ std::string s2("bar");
+ std::string s3("baz");
+
+ absl::string_view p1(s1);
+ absl::string_view p2(s2);
+ absl::string_view p3(s3);
+
+ typedef std::map<absl::string_view, int> TestMap;
+ TestMap map;
+
+ map.insert(std::make_pair(p1, 0));
+ map.insert(std::make_pair(p2, 1));
+ map.insert(std::make_pair(p3, 2));
+ EXPECT_EQ(map.size(), 3);
+
+ TestMap::const_iterator iter = map.begin();
+ EXPECT_EQ(iter->second, 1);
+ ++iter;
+ EXPECT_EQ(iter->second, 2);
+ ++iter;
+ EXPECT_EQ(iter->second, 0);
+ ++iter;
+ EXPECT_TRUE(iter == map.end());
+
+ TestMap::iterator new_iter = map.find("zot");
+ EXPECT_TRUE(new_iter == map.end());
+
+ new_iter = map.find("bar");
+ EXPECT_TRUE(new_iter != map.end());
+
+ map.erase(new_iter);
+ EXPECT_EQ(map.size(), 2);
+
+ iter = map.begin();
+ EXPECT_EQ(iter->second, 2);
+ ++iter;
+ EXPECT_EQ(iter->second, 0);
+ ++iter;
+ EXPECT_TRUE(iter == map.end());
+}
+
+#define COMPARE(result, op, x, y) \
+ EXPECT_EQ(result, absl::string_view((x)) op absl::string_view((y))); \
+ EXPECT_EQ(result, absl::string_view((x)).compare(absl::string_view((y))) op 0)
+
+TEST(StringViewTest, ComparisonOperators) {
+ COMPARE(true, ==, "", "");
+ COMPARE(true, ==, "", absl::string_view());
+ COMPARE(true, ==, absl::string_view(), "");
+ COMPARE(true, ==, "a", "a");
+ COMPARE(true, ==, "aa", "aa");
+ COMPARE(false, ==, "a", "");
+ COMPARE(false, ==, "", "a");
+ COMPARE(false, ==, "a", "b");
+ COMPARE(false, ==, "a", "aa");
+ COMPARE(false, ==, "aa", "a");
+
+ COMPARE(false, !=, "", "");
+ COMPARE(false, !=, "a", "a");
+ COMPARE(false, !=, "aa", "aa");
+ COMPARE(true, !=, "a", "");
+ COMPARE(true, !=, "", "a");
+ COMPARE(true, !=, "a", "b");
+ COMPARE(true, !=, "a", "aa");
+ COMPARE(true, !=, "aa", "a");
+
+ COMPARE(true, <, "a", "b");
+ COMPARE(true, <, "a", "aa");
+ COMPARE(true, <, "aa", "b");
+ COMPARE(true, <, "aa", "bb");
+ COMPARE(false, <, "a", "a");
+ COMPARE(false, <, "b", "a");
+ COMPARE(false, <, "aa", "a");
+ COMPARE(false, <, "b", "aa");
+ COMPARE(false, <, "bb", "aa");
+
+ COMPARE(true, <=, "a", "a");
+ COMPARE(true, <=, "a", "b");
+ COMPARE(true, <=, "a", "aa");
+ COMPARE(true, <=, "aa", "b");
+ COMPARE(true, <=, "aa", "bb");
+ COMPARE(false, <=, "b", "a");
+ COMPARE(false, <=, "aa", "a");
+ COMPARE(false, <=, "b", "aa");
+ COMPARE(false, <=, "bb", "aa");
+
+ COMPARE(false, >=, "a", "b");
+ COMPARE(false, >=, "a", "aa");
+ COMPARE(false, >=, "aa", "b");
+ COMPARE(false, >=, "aa", "bb");
+ COMPARE(true, >=, "a", "a");
+ COMPARE(true, >=, "b", "a");
+ COMPARE(true, >=, "aa", "a");
+ COMPARE(true, >=, "b", "aa");
+ COMPARE(true, >=, "bb", "aa");
+
+ COMPARE(false, >, "a", "a");
+ COMPARE(false, >, "a", "b");
+ COMPARE(false, >, "a", "aa");
+ COMPARE(false, >, "aa", "b");
+ COMPARE(false, >, "aa", "bb");
+ COMPARE(true, >, "b", "a");
+ COMPARE(true, >, "aa", "a");
+ COMPARE(true, >, "b", "aa");
+ COMPARE(true, >, "bb", "aa");
+}
+
+TEST(StringViewTest, ComparisonOperatorsByCharacterPosition) {
+ std::string x;
+ for (int i = 0; i < 256; i++) {
+ x += 'a';
+ std::string y = x;
+ COMPARE(true, ==, x, y);
+ for (int j = 0; j < i; j++) {
+ std::string z = x;
+ z[j] = 'b'; // Differs in position 'j'
+ COMPARE(false, ==, x, z);
+ COMPARE(true, <, x, z);
+ COMPARE(true, >, z, x);
+ if (j + 1 < i) {
+ z[j + 1] = 'A'; // Differs in position 'j+1' as well
+ COMPARE(false, ==, x, z);
+ COMPARE(true, <, x, z);
+ COMPARE(true, >, z, x);
+ z[j + 1] = 'z'; // Differs in position 'j+1' as well
+ COMPARE(false, ==, x, z);
+ COMPARE(true, <, x, z);
+ COMPARE(true, >, z, x);
+ }
+ }
+ }
+}
+#undef COMPARE
+
+// Sadly, our users often confuse std::string::npos with absl::string_view::npos;
+// So much so that we test here that they are the same. They need to
+// both be unsigned, and both be the maximum-valued integer of their type.
+
+template <typename T>
+struct is_type {
+ template <typename U>
+ static bool same(U) {
+ return false;
+ }
+ static bool same(T) { return true; }
+};
+
+TEST(StringViewTest, NposMatchesStdStringView) {
+ EXPECT_EQ(absl::string_view::npos, std::string::npos);
+
+ EXPECT_TRUE(is_type<size_t>::same(absl::string_view::npos));
+ EXPECT_FALSE(is_type<size_t>::same(""));
+
+ // Make sure absl::string_view::npos continues to be a header constant.
+ char test[absl::string_view::npos & 1] = {0};
+ EXPECT_EQ(0, test[0]);
+}
+
+TEST(StringViewTest, STL1) {
+ const absl::string_view a("abcdefghijklmnopqrstuvwxyz");
+ const absl::string_view b("abc");
+ const absl::string_view c("xyz");
+ const absl::string_view d("foobar");
+ const absl::string_view e;
+ std::string temp("123");
+ temp += '\0';
+ temp += "456";
+ const absl::string_view f(temp);
+
+ EXPECT_EQ(a[6], 'g');
+ EXPECT_EQ(b[0], 'a');
+ EXPECT_EQ(c[2], 'z');
+ EXPECT_EQ(f[3], '\0');
+ EXPECT_EQ(f[5], '5');
+
+ EXPECT_EQ(*d.data(), 'f');
+ EXPECT_EQ(d.data()[5], 'r');
+ EXPECT_TRUE(e.data() == nullptr);
+
+ EXPECT_EQ(*a.begin(), 'a');
+ EXPECT_EQ(*(b.begin() + 2), 'c');
+ EXPECT_EQ(*(c.end() - 1), 'z');
+
+ EXPECT_EQ(*a.rbegin(), 'z');
+ EXPECT_EQ(*(b.rbegin() + 2), 'a');
+ EXPECT_EQ(*(c.rend() - 1), 'x');
+ EXPECT_TRUE(a.rbegin() + 26 == a.rend());
+
+ EXPECT_EQ(a.size(), 26);
+ EXPECT_EQ(b.size(), 3);
+ EXPECT_EQ(c.size(), 3);
+ EXPECT_EQ(d.size(), 6);
+ EXPECT_EQ(e.size(), 0);
+ EXPECT_EQ(f.size(), 7);
+
+ EXPECT_TRUE(!d.empty());
+ EXPECT_TRUE(d.begin() != d.end());
+ EXPECT_TRUE(d.begin() + 6 == d.end());
+
+ EXPECT_TRUE(e.empty());
+ EXPECT_TRUE(e.begin() == e.end());
+
+ char buf[4] = { '%', '%', '%', '%' };
+ EXPECT_EQ(a.copy(buf, 4), 4);
+ EXPECT_EQ(buf[0], a[0]);
+ EXPECT_EQ(buf[1], a[1]);
+ EXPECT_EQ(buf[2], a[2]);
+ EXPECT_EQ(buf[3], a[3]);
+ EXPECT_EQ(a.copy(buf, 3, 7), 3);
+ EXPECT_EQ(buf[0], a[7]);
+ EXPECT_EQ(buf[1], a[8]);
+ EXPECT_EQ(buf[2], a[9]);
+ EXPECT_EQ(buf[3], a[3]);
+ EXPECT_EQ(c.copy(buf, 99), 3);
+ EXPECT_EQ(buf[0], c[0]);
+ EXPECT_EQ(buf[1], c[1]);
+ EXPECT_EQ(buf[2], c[2]);
+ EXPECT_EQ(buf[3], a[3]);
+}
+
+// Separated from STL1() because some compilers produce an overly
+// large stack frame for the combined function.
+TEST(StringViewTest, STL2) {
+ const absl::string_view a("abcdefghijklmnopqrstuvwxyz");
+ const absl::string_view b("abc");
+ const absl::string_view c("xyz");
+ absl::string_view d("foobar");
+ const absl::string_view e;
+ const absl::string_view f(
+ "123"
+ "\0"
+ "456",
+ 7);
+
+ d = absl::string_view();
+ EXPECT_EQ(d.size(), 0);
+ EXPECT_TRUE(d.empty());
+ EXPECT_TRUE(d.data() == nullptr);
+ EXPECT_TRUE(d.begin() == d.end());
+
+ EXPECT_EQ(a.find(b), 0);
+ EXPECT_EQ(a.find(b, 1), absl::string_view::npos);
+ EXPECT_EQ(a.find(c), 23);
+ EXPECT_EQ(a.find(c, 9), 23);
+ EXPECT_EQ(a.find(c, absl::string_view::npos), absl::string_view::npos);
+ EXPECT_EQ(b.find(c), absl::string_view::npos);
+ EXPECT_EQ(b.find(c, absl::string_view::npos), absl::string_view::npos);
+ EXPECT_EQ(a.find(d), 0);
+ EXPECT_EQ(a.find(e), 0);
+ EXPECT_EQ(a.find(d, 12), 12);
+ EXPECT_EQ(a.find(e, 17), 17);
+ absl::string_view g("xx not found bb");
+ EXPECT_EQ(a.find(g), absl::string_view::npos);
+ // empty std::string nonsense
+ EXPECT_EQ(d.find(b), absl::string_view::npos);
+ EXPECT_EQ(e.find(b), absl::string_view::npos);
+ EXPECT_EQ(d.find(b, 4), absl::string_view::npos);
+ EXPECT_EQ(e.find(b, 7), absl::string_view::npos);
+
+ size_t empty_search_pos = std::string().find(std::string());
+ EXPECT_EQ(d.find(d), empty_search_pos);
+ EXPECT_EQ(d.find(e), empty_search_pos);
+ EXPECT_EQ(e.find(d), empty_search_pos);
+ EXPECT_EQ(e.find(e), empty_search_pos);
+ EXPECT_EQ(d.find(d, 4), std::string().find(std::string(), 4));
+ EXPECT_EQ(d.find(e, 4), std::string().find(std::string(), 4));
+ EXPECT_EQ(e.find(d, 4), std::string().find(std::string(), 4));
+ EXPECT_EQ(e.find(e, 4), std::string().find(std::string(), 4));
+
+ EXPECT_EQ(a.find('a'), 0);
+ EXPECT_EQ(a.find('c'), 2);
+ EXPECT_EQ(a.find('z'), 25);
+ EXPECT_EQ(a.find('$'), absl::string_view::npos);
+ EXPECT_EQ(a.find('\0'), absl::string_view::npos);
+ EXPECT_EQ(f.find('\0'), 3);
+ EXPECT_EQ(f.find('3'), 2);
+ EXPECT_EQ(f.find('5'), 5);
+ EXPECT_EQ(g.find('o'), 4);
+ EXPECT_EQ(g.find('o', 4), 4);
+ EXPECT_EQ(g.find('o', 5), 8);
+ EXPECT_EQ(a.find('b', 5), absl::string_view::npos);
+ // empty std::string nonsense
+ EXPECT_EQ(d.find('\0'), absl::string_view::npos);
+ EXPECT_EQ(e.find('\0'), absl::string_view::npos);
+ EXPECT_EQ(d.find('\0', 4), absl::string_view::npos);
+ EXPECT_EQ(e.find('\0', 7), absl::string_view::npos);
+ EXPECT_EQ(d.find('x'), absl::string_view::npos);
+ EXPECT_EQ(e.find('x'), absl::string_view::npos);
+ EXPECT_EQ(d.find('x', 4), absl::string_view::npos);
+ EXPECT_EQ(e.find('x', 7), absl::string_view::npos);
+
+ EXPECT_EQ(a.rfind(b), 0);
+ EXPECT_EQ(a.rfind(b, 1), 0);
+ EXPECT_EQ(a.rfind(c), 23);
+ EXPECT_EQ(a.rfind(c, 22), absl::string_view::npos);
+ EXPECT_EQ(a.rfind(c, 1), absl::string_view::npos);
+ EXPECT_EQ(a.rfind(c, 0), absl::string_view::npos);
+ EXPECT_EQ(b.rfind(c), absl::string_view::npos);
+ EXPECT_EQ(b.rfind(c, 0), absl::string_view::npos);
+ EXPECT_EQ(a.rfind(d), std::string(a).rfind(std::string()));
+ EXPECT_EQ(a.rfind(e), std::string(a).rfind(std::string()));
+ EXPECT_EQ(a.rfind(d, 12), 12);
+ EXPECT_EQ(a.rfind(e, 17), 17);
+ EXPECT_EQ(a.rfind(g), absl::string_view::npos);
+ EXPECT_EQ(d.rfind(b), absl::string_view::npos);
+ EXPECT_EQ(e.rfind(b), absl::string_view::npos);
+ EXPECT_EQ(d.rfind(b, 4), absl::string_view::npos);
+ EXPECT_EQ(e.rfind(b, 7), absl::string_view::npos);
+ // empty std::string nonsense
+ EXPECT_EQ(d.rfind(d, 4), std::string().rfind(std::string()));
+ EXPECT_EQ(e.rfind(d, 7), std::string().rfind(std::string()));
+ EXPECT_EQ(d.rfind(e, 4), std::string().rfind(std::string()));
+ EXPECT_EQ(e.rfind(e, 7), std::string().rfind(std::string()));
+ EXPECT_EQ(d.rfind(d), std::string().rfind(std::string()));
+ EXPECT_EQ(e.rfind(d), std::string().rfind(std::string()));
+ EXPECT_EQ(d.rfind(e), std::string().rfind(std::string()));
+ EXPECT_EQ(e.rfind(e), std::string().rfind(std::string()));
+
+ EXPECT_EQ(g.rfind('o'), 8);
+ EXPECT_EQ(g.rfind('q'), absl::string_view::npos);
+ EXPECT_EQ(g.rfind('o', 8), 8);
+ EXPECT_EQ(g.rfind('o', 7), 4);
+ EXPECT_EQ(g.rfind('o', 3), absl::string_view::npos);
+ EXPECT_EQ(f.rfind('\0'), 3);
+ EXPECT_EQ(f.rfind('\0', 12), 3);
+ EXPECT_EQ(f.rfind('3'), 2);
+ EXPECT_EQ(f.rfind('5'), 5);
+ // empty std::string nonsense
+ EXPECT_EQ(d.rfind('o'), absl::string_view::npos);
+ EXPECT_EQ(e.rfind('o'), absl::string_view::npos);
+ EXPECT_EQ(d.rfind('o', 4), absl::string_view::npos);
+ EXPECT_EQ(e.rfind('o', 7), absl::string_view::npos);
+}
+
+// Continued from STL2
+TEST(StringViewTest, STL2FindFirst) {
+ const absl::string_view a("abcdefghijklmnopqrstuvwxyz");
+ const absl::string_view b("abc");
+ const absl::string_view c("xyz");
+ absl::string_view d("foobar");
+ const absl::string_view e;
+ const absl::string_view f(
+ "123"
+ "\0"
+ "456",
+ 7);
+ absl::string_view g("xx not found bb");
+
+ d = absl::string_view();
+ EXPECT_EQ(a.find_first_of(b), 0);
+ EXPECT_EQ(a.find_first_of(b, 0), 0);
+ EXPECT_EQ(a.find_first_of(b, 1), 1);
+ EXPECT_EQ(a.find_first_of(b, 2), 2);
+ EXPECT_EQ(a.find_first_of(b, 3), absl::string_view::npos);
+ EXPECT_EQ(a.find_first_of(c), 23);
+ EXPECT_EQ(a.find_first_of(c, 23), 23);
+ EXPECT_EQ(a.find_first_of(c, 24), 24);
+ EXPECT_EQ(a.find_first_of(c, 25), 25);
+ EXPECT_EQ(a.find_first_of(c, 26), absl::string_view::npos);
+ EXPECT_EQ(g.find_first_of(b), 13);
+ EXPECT_EQ(g.find_first_of(c), 0);
+ EXPECT_EQ(a.find_first_of(f), absl::string_view::npos);
+ EXPECT_EQ(f.find_first_of(a), absl::string_view::npos);
+ // empty std::string nonsense
+ EXPECT_EQ(a.find_first_of(d), absl::string_view::npos);
+ EXPECT_EQ(a.find_first_of(e), absl::string_view::npos);
+ EXPECT_EQ(d.find_first_of(b), absl::string_view::npos);
+ EXPECT_EQ(e.find_first_of(b), absl::string_view::npos);
+ EXPECT_EQ(d.find_first_of(d), absl::string_view::npos);
+ EXPECT_EQ(e.find_first_of(d), absl::string_view::npos);
+ EXPECT_EQ(d.find_first_of(e), absl::string_view::npos);
+ EXPECT_EQ(e.find_first_of(e), absl::string_view::npos);
+
+ EXPECT_EQ(a.find_first_not_of(b), 3);
+ EXPECT_EQ(a.find_first_not_of(c), 0);
+ EXPECT_EQ(b.find_first_not_of(a), absl::string_view::npos);
+ EXPECT_EQ(c.find_first_not_of(a), absl::string_view::npos);
+ EXPECT_EQ(f.find_first_not_of(a), 0);
+ EXPECT_EQ(a.find_first_not_of(f), 0);
+ EXPECT_EQ(a.find_first_not_of(d), 0);
+ EXPECT_EQ(a.find_first_not_of(e), 0);
+ // empty std::string nonsense
+ EXPECT_EQ(a.find_first_not_of(d), 0);
+ EXPECT_EQ(a.find_first_not_of(e), 0);
+ EXPECT_EQ(a.find_first_not_of(d, 1), 1);
+ EXPECT_EQ(a.find_first_not_of(e, 1), 1);
+ EXPECT_EQ(a.find_first_not_of(d, a.size() - 1), a.size() - 1);
+ EXPECT_EQ(a.find_first_not_of(e, a.size() - 1), a.size() - 1);
+ EXPECT_EQ(a.find_first_not_of(d, a.size()), absl::string_view::npos);
+ EXPECT_EQ(a.find_first_not_of(e, a.size()), absl::string_view::npos);
+ EXPECT_EQ(a.find_first_not_of(d, absl::string_view::npos),
+ absl::string_view::npos);
+ EXPECT_EQ(a.find_first_not_of(e, absl::string_view::npos),
+ absl::string_view::npos);
+ EXPECT_EQ(d.find_first_not_of(a), absl::string_view::npos);
+ EXPECT_EQ(e.find_first_not_of(a), absl::string_view::npos);
+ EXPECT_EQ(d.find_first_not_of(d), absl::string_view::npos);
+ EXPECT_EQ(e.find_first_not_of(d), absl::string_view::npos);
+ EXPECT_EQ(d.find_first_not_of(e), absl::string_view::npos);
+ EXPECT_EQ(e.find_first_not_of(e), absl::string_view::npos);
+
+ absl::string_view h("====");
+ EXPECT_EQ(h.find_first_not_of('='), absl::string_view::npos);
+ EXPECT_EQ(h.find_first_not_of('=', 3), absl::string_view::npos);
+ EXPECT_EQ(h.find_first_not_of('\0'), 0);
+ EXPECT_EQ(g.find_first_not_of('x'), 2);
+ EXPECT_EQ(f.find_first_not_of('\0'), 0);
+ EXPECT_EQ(f.find_first_not_of('\0', 3), 4);
+ EXPECT_EQ(f.find_first_not_of('\0', 2), 2);
+ // empty std::string nonsense
+ EXPECT_EQ(d.find_first_not_of('x'), absl::string_view::npos);
+ EXPECT_EQ(e.find_first_not_of('x'), absl::string_view::npos);
+ EXPECT_EQ(d.find_first_not_of('\0'), absl::string_view::npos);
+ EXPECT_EQ(e.find_first_not_of('\0'), absl::string_view::npos);
+}
+
+// Continued from STL2
+TEST(StringViewTest, STL2FindLast) {
+ const absl::string_view a("abcdefghijklmnopqrstuvwxyz");
+ const absl::string_view b("abc");
+ const absl::string_view c("xyz");
+ absl::string_view d("foobar");
+ const absl::string_view e;
+ const absl::string_view f(
+ "123"
+ "\0"
+ "456",
+ 7);
+ absl::string_view g("xx not found bb");
+ absl::string_view h("====");
+ absl::string_view i("56");
+
+ d = absl::string_view();
+ EXPECT_EQ(h.find_last_of(a), absl::string_view::npos);
+ EXPECT_EQ(g.find_last_of(a), g.size()-1);
+ EXPECT_EQ(a.find_last_of(b), 2);
+ EXPECT_EQ(a.find_last_of(c), a.size()-1);
+ EXPECT_EQ(f.find_last_of(i), 6);
+ EXPECT_EQ(a.find_last_of('a'), 0);
+ EXPECT_EQ(a.find_last_of('b'), 1);
+ EXPECT_EQ(a.find_last_of('z'), 25);
+ EXPECT_EQ(a.find_last_of('a', 5), 0);
+ EXPECT_EQ(a.find_last_of('b', 5), 1);
+ EXPECT_EQ(a.find_last_of('b', 0), absl::string_view::npos);
+ EXPECT_EQ(a.find_last_of('z', 25), 25);
+ EXPECT_EQ(a.find_last_of('z', 24), absl::string_view::npos);
+ EXPECT_EQ(f.find_last_of(i, 5), 5);
+ EXPECT_EQ(f.find_last_of(i, 6), 6);
+ EXPECT_EQ(f.find_last_of(a, 4), absl::string_view::npos);
+ // empty std::string nonsense
+ EXPECT_EQ(f.find_last_of(d), absl::string_view::npos);
+ EXPECT_EQ(f.find_last_of(e), absl::string_view::npos);
+ EXPECT_EQ(f.find_last_of(d, 4), absl::string_view::npos);
+ EXPECT_EQ(f.find_last_of(e, 4), absl::string_view::npos);
+ EXPECT_EQ(d.find_last_of(d), absl::string_view::npos);
+ EXPECT_EQ(d.find_last_of(e), absl::string_view::npos);
+ EXPECT_EQ(e.find_last_of(d), absl::string_view::npos);
+ EXPECT_EQ(e.find_last_of(e), absl::string_view::npos);
+ EXPECT_EQ(d.find_last_of(f), absl::string_view::npos);
+ EXPECT_EQ(e.find_last_of(f), absl::string_view::npos);
+ EXPECT_EQ(d.find_last_of(d, 4), absl::string_view::npos);
+ EXPECT_EQ(d.find_last_of(e, 4), absl::string_view::npos);
+ EXPECT_EQ(e.find_last_of(d, 4), absl::string_view::npos);
+ EXPECT_EQ(e.find_last_of(e, 4), absl::string_view::npos);
+ EXPECT_EQ(d.find_last_of(f, 4), absl::string_view::npos);
+ EXPECT_EQ(e.find_last_of(f, 4), absl::string_view::npos);
+
+ EXPECT_EQ(a.find_last_not_of(b), a.size()-1);
+ EXPECT_EQ(a.find_last_not_of(c), 22);
+ EXPECT_EQ(b.find_last_not_of(a), absl::string_view::npos);
+ EXPECT_EQ(b.find_last_not_of(b), absl::string_view::npos);
+ EXPECT_EQ(f.find_last_not_of(i), 4);
+ EXPECT_EQ(a.find_last_not_of(c, 24), 22);
+ EXPECT_EQ(a.find_last_not_of(b, 3), 3);
+ EXPECT_EQ(a.find_last_not_of(b, 2), absl::string_view::npos);
+ // empty std::string nonsense
+ EXPECT_EQ(f.find_last_not_of(d), f.size()-1);
+ EXPECT_EQ(f.find_last_not_of(e), f.size()-1);
+ EXPECT_EQ(f.find_last_not_of(d, 4), 4);
+ EXPECT_EQ(f.find_last_not_of(e, 4), 4);
+ EXPECT_EQ(d.find_last_not_of(d), absl::string_view::npos);
+ EXPECT_EQ(d.find_last_not_of(e), absl::string_view::npos);
+ EXPECT_EQ(e.find_last_not_of(d), absl::string_view::npos);
+ EXPECT_EQ(e.find_last_not_of(e), absl::string_view::npos);
+ EXPECT_EQ(d.find_last_not_of(f), absl::string_view::npos);
+ EXPECT_EQ(e.find_last_not_of(f), absl::string_view::npos);
+ EXPECT_EQ(d.find_last_not_of(d, 4), absl::string_view::npos);
+ EXPECT_EQ(d.find_last_not_of(e, 4), absl::string_view::npos);
+ EXPECT_EQ(e.find_last_not_of(d, 4), absl::string_view::npos);
+ EXPECT_EQ(e.find_last_not_of(e, 4), absl::string_view::npos);
+ EXPECT_EQ(d.find_last_not_of(f, 4), absl::string_view::npos);
+ EXPECT_EQ(e.find_last_not_of(f, 4), absl::string_view::npos);
+
+ EXPECT_EQ(h.find_last_not_of('x'), h.size() - 1);
+ EXPECT_EQ(h.find_last_not_of('='), absl::string_view::npos);
+ EXPECT_EQ(b.find_last_not_of('c'), 1);
+ EXPECT_EQ(h.find_last_not_of('x', 2), 2);
+ EXPECT_EQ(h.find_last_not_of('=', 2), absl::string_view::npos);
+ EXPECT_EQ(b.find_last_not_of('b', 1), 0);
+ // empty std::string nonsense
+ EXPECT_EQ(d.find_last_not_of('x'), absl::string_view::npos);
+ EXPECT_EQ(e.find_last_not_of('x'), absl::string_view::npos);
+ EXPECT_EQ(d.find_last_not_of('\0'), absl::string_view::npos);
+ EXPECT_EQ(e.find_last_not_of('\0'), absl::string_view::npos);
+}
+
+// Continued from STL2
+TEST(StringViewTest, STL2Substr) {
+ const absl::string_view a("abcdefghijklmnopqrstuvwxyz");
+ const absl::string_view b("abc");
+ const absl::string_view c("xyz");
+ absl::string_view d("foobar");
+ const absl::string_view e;
+
+ d = absl::string_view();
+ EXPECT_EQ(a.substr(0, 3), b);
+ EXPECT_EQ(a.substr(23), c);
+ EXPECT_EQ(a.substr(23, 3), c);
+ EXPECT_EQ(a.substr(23, 99), c);
+ EXPECT_EQ(a.substr(0), a);
+ EXPECT_EQ(a.substr(3, 2), "de");
+ // empty std::string nonsense
+ EXPECT_EQ(d.substr(0, 99), e);
+ // use of npos
+ EXPECT_EQ(a.substr(0, absl::string_view::npos), a);
+ EXPECT_EQ(a.substr(23, absl::string_view::npos), c);
+ // throw exception
+#ifdef ABSL_HAVE_EXCEPTIONS
+ EXPECT_THROW(a.substr(99, 2), std::out_of_range);
+#else
+ EXPECT_DEATH(a.substr(99, 2), "absl::string_view::substr");
+#endif
+}
+
+TEST(StringViewTest, TruncSubstr) {
+ const absl::string_view hi("hi");
+ EXPECT_EQ("", absl::ClippedSubstr(hi, 0, 0));
+ EXPECT_EQ("h", absl::ClippedSubstr(hi, 0, 1));
+ EXPECT_EQ("hi", absl::ClippedSubstr(hi, 0));
+ EXPECT_EQ("i", absl::ClippedSubstr(hi, 1));
+ EXPECT_EQ("", absl::ClippedSubstr(hi, 2));
+ EXPECT_EQ("", absl::ClippedSubstr(hi, 3)); // truncation
+ EXPECT_EQ("", absl::ClippedSubstr(hi, 3, 2)); // truncation
+}
+
+TEST(StringViewTest, UTF8) {
+ EXPECT_EQ(strlen("á"), absl::string_view("á á").find_first_of(" "));
+ EXPECT_EQ(strlen("á"), absl::string_view("á á").find_first_of(" \t"));
+}
+
+TEST(StringViewTest, FindConformance) {
+ struct {
+ std::string haystack;
+ std::string needle;
+ } specs[] = {
+ {"", ""},
+ {"", "a"},
+ {"a", ""},
+ {"a", "a"},
+ {"a", "b"},
+ {"aa", ""},
+ {"aa", "a"},
+ {"aa", "b"},
+ {"ab", "a"},
+ {"ab", "b"},
+ {"abcd", ""},
+ {"abcd", "a"},
+ {"abcd", "d"},
+ {"abcd", "ab"},
+ {"abcd", "bc"},
+ {"abcd", "cd"},
+ {"abcd", "abcd"},
+ };
+ for (const auto& s : specs) {
+ SCOPED_TRACE(s.haystack);
+ SCOPED_TRACE(s.needle);
+ std::string st = s.haystack;
+ absl::string_view sp = s.haystack;
+ for (size_t i = 0; i <= sp.size(); ++i) {
+ size_t pos = (i == sp.size()) ? absl::string_view::npos : i;
+ SCOPED_TRACE(pos);
+ EXPECT_EQ(sp.find(s.needle, pos),
+ st.find(s.needle, pos));
+ EXPECT_EQ(sp.rfind(s.needle, pos),
+ st.rfind(s.needle, pos));
+ EXPECT_EQ(sp.find_first_of(s.needle, pos),
+ st.find_first_of(s.needle, pos));
+ EXPECT_EQ(sp.find_first_not_of(s.needle, pos),
+ st.find_first_not_of(s.needle, pos));
+ EXPECT_EQ(sp.find_last_of(s.needle, pos),
+ st.find_last_of(s.needle, pos));
+ EXPECT_EQ(sp.find_last_not_of(s.needle, pos),
+ st.find_last_not_of(s.needle, pos));
+ }
+ }
+}
+
+TEST(StringViewTest, Remove) {
+ absl::string_view a("foobar");
+ std::string s1("123");
+ s1 += '\0';
+ s1 += "456";
+ absl::string_view b(s1);
+ absl::string_view e;
+ std::string s2;
+
+ // remove_prefix
+ absl::string_view c(a);
+ c.remove_prefix(3);
+ EXPECT_EQ(c, "bar");
+ c = a;
+ c.remove_prefix(0);
+ EXPECT_EQ(c, a);
+ c.remove_prefix(c.size());
+ EXPECT_EQ(c, e);
+
+ // remove_suffix
+ c = a;
+ c.remove_suffix(3);
+ EXPECT_EQ(c, "foo");
+ c = a;
+ c.remove_suffix(0);
+ EXPECT_EQ(c, a);
+ c.remove_suffix(c.size());
+ EXPECT_EQ(c, e);
+}
+
+TEST(StringViewTest, Set) {
+ absl::string_view a("foobar");
+ absl::string_view empty;
+ absl::string_view b;
+
+ // set
+ b = absl::string_view("foobar", 6);
+ EXPECT_EQ(b, a);
+ b = absl::string_view("foobar", 0);
+ EXPECT_EQ(b, empty);
+ b = absl::string_view("foobar", 7);
+ EXPECT_NE(b, a);
+
+ b = absl::string_view("foobar");
+ EXPECT_EQ(b, a);
+}
+
+TEST(StringViewTest, FrontBack) {
+ static const char arr[] = "abcd";
+ const absl::string_view csp(arr, 4);
+ EXPECT_EQ(&arr[0], &csp.front());
+ EXPECT_EQ(&arr[3], &csp.back());
+}
+
+TEST(StringViewTest, FrontBackSingleChar) {
+ static const char c = 'a';
+ const absl::string_view csp(&c, 1);
+ EXPECT_EQ(&c, &csp.front());
+ EXPECT_EQ(&c, &csp.back());
+}
+
+TEST(StringViewTest, NULLInput) {
+ absl::string_view s;
+ EXPECT_EQ(s.data(), nullptr);
+ EXPECT_EQ(s.size(), 0);
+
+ s = absl::string_view(nullptr);
+ EXPECT_EQ(s.data(), nullptr);
+ EXPECT_EQ(s.size(), 0);
+
+ // .ToString() on a absl::string_view with nullptr should produce the empty
+ // std::string.
+ EXPECT_EQ("", std::string(s));
+}
+
+TEST(StringViewTest, Comparisons2) {
+ // The `compare` member has 6 overloads (v: string_view, s: const char*):
+ // (1) compare(v)
+ // (2) compare(pos1, count1, v)
+ // (3) compare(pos1, count1, v, pos2, count2)
+ // (4) compare(s)
+ // (5) compare(pos1, count1, s)
+ // (6) compare(pos1, count1, s, count2)
+
+ absl::string_view abc("abcdefghijklmnopqrstuvwxyz");
+
+ // check comparison operations on strings longer than 4 bytes.
+ EXPECT_EQ(abc, absl::string_view("abcdefghijklmnopqrstuvwxyz"));
+ EXPECT_EQ(abc.compare(absl::string_view("abcdefghijklmnopqrstuvwxyz")), 0);
+
+ EXPECT_LT(abc, absl::string_view("abcdefghijklmnopqrstuvwxzz"));
+ EXPECT_LT(abc.compare(absl::string_view("abcdefghijklmnopqrstuvwxzz")), 0);
+
+ EXPECT_GT(abc, absl::string_view("abcdefghijklmnopqrstuvwxyy"));
+ EXPECT_GT(abc.compare(absl::string_view("abcdefghijklmnopqrstuvwxyy")), 0);
+
+ // The "substr" variants of `compare`.
+ absl::string_view digits("0123456789");
+ auto npos = absl::string_view::npos;
+
+ // Taking string_view
+ EXPECT_EQ(digits.compare(3, npos, absl::string_view("3456789")), 0); // 2
+ EXPECT_EQ(digits.compare(3, 4, absl::string_view("3456")), 0); // 2
+ EXPECT_EQ(digits.compare(10, 0, absl::string_view()), 0); // 2
+ EXPECT_EQ(digits.compare(3, 4, absl::string_view("0123456789"), 3, 4),
+ 0); // 3
+ EXPECT_LT(digits.compare(3, 4, absl::string_view("0123456789"), 3, 5),
+ 0); // 3
+ EXPECT_LT(digits.compare(0, npos, absl::string_view("0123456789"), 3, 5),
+ 0); // 3
+ // Taking const char*
+ EXPECT_EQ(digits.compare(3, 4, "3456"), 0); // 5
+ EXPECT_EQ(digits.compare(3, npos, "3456789"), 0); // 5
+ EXPECT_EQ(digits.compare(10, 0, ""), 0); // 5
+ EXPECT_EQ(digits.compare(3, 4, "0123456789", 3, 4), 0); // 6
+ EXPECT_LT(digits.compare(3, 4, "0123456789", 3, 5), 0); // 6
+ EXPECT_LT(digits.compare(0, npos, "0123456789", 3, 5), 0); // 6
+}
+
+struct MyCharAlloc : std::allocator<char> {};
+
+TEST(StringViewTest, ExplicitConversionOperator) {
+ absl::string_view sp = "hi";
+ EXPECT_EQ(sp, std::string(sp));
+}
+
+TEST(StringViewTest, NullSafeStringView) {
+ {
+ absl::string_view s = absl::NullSafeStringView(nullptr);
+ EXPECT_EQ(nullptr, s.data());
+ EXPECT_EQ(0, s.size());
+ EXPECT_EQ(absl::string_view(), s);
+ }
+ {
+ static const char kHi[] = "hi";
+ absl::string_view s = absl::NullSafeStringView(kHi);
+ EXPECT_EQ(kHi, s.data());
+ EXPECT_EQ(strlen(kHi), s.size());
+ EXPECT_EQ(absl::string_view("hi"), s);
+ }
+}
+
+TEST(StringViewTest, ConstexprCompiles) {
+ constexpr absl::string_view sp;
+ constexpr absl::string_view cstr(nullptr);
+ constexpr absl::string_view cstr_len("cstr", 4);
+
+#if defined(ABSL_HAVE_STD_STRING_VIEW)
+ // In libstdc++ (as of 7.2), `std::string_view::string_view(const char*)`
+ // calls `std::char_traits<char>::length(const char*)` to get the std::string
+ // length, but it is not marked constexpr yet. See GCC bug:
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78156
+ // Also, there is a LWG issue that adds constexpr to length() which was just
+ // resolved 2017-06-02. See
+ // http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2232
+ // TODO(zhangxy): Update the condition when libstdc++ adopts the constexpr
+ // length().
+#if !defined(__GLIBCXX__)
+#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR 1
+#endif // !__GLIBCXX__
+
+#else // ABSL_HAVE_STD_STRING_VIEW
+
+// This duplicates the check for __builtin_strlen in the header.
+#if ABSL_HAVE_BUILTIN(__builtin_strlen) || \
+ (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR 1
+#elif defined(__GNUC__) // GCC or clang
+#error GCC/clang should have constexpr string_view.
+#endif
+
+#endif // ABSL_HAVE_STD_STRING_VIEW
+
+#ifdef ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR
+ constexpr absl::string_view cstr_strlen("foo");
+ EXPECT_EQ(cstr_strlen.length(), 3);
+ constexpr absl::string_view cstr_strlen2 = "bar";
+ EXPECT_EQ(cstr_strlen2, "bar");
+#endif
+
+#if !defined(__clang__) || 3 < __clang_major__ || \
+ (3 == __clang_major__ && 4 < __clang_minor__)
+ // older clang versions (< 3.5) complain that:
+ // "cannot perform pointer arithmetic on null pointer"
+ constexpr absl::string_view::iterator const_begin_empty = sp.begin();
+ constexpr absl::string_view::iterator const_end_empty = sp.end();
+ EXPECT_EQ(const_begin_empty, const_end_empty);
+#endif
+
+ constexpr absl::string_view::iterator const_begin = cstr_len.begin();
+ constexpr absl::string_view::iterator const_end = cstr_len.end();
+ constexpr absl::string_view::size_type const_size = cstr_len.size();
+ constexpr absl::string_view::size_type const_length = cstr_len.length();
+ EXPECT_EQ(const_begin + const_size, const_end);
+ EXPECT_EQ(const_begin + const_length, const_end);
+
+ constexpr bool isempty = sp.empty();
+ EXPECT_TRUE(isempty);
+
+ constexpr const char c = cstr_len[2];
+ EXPECT_EQ(c, 't');
+
+ constexpr const char cfront = cstr_len.front();
+ constexpr const char cback = cstr_len.back();
+ EXPECT_EQ(cfront, 'c');
+ EXPECT_EQ(cback, 'r');
+
+ constexpr const char* np = sp.data();
+ constexpr const char* cstr_ptr = cstr_len.data();
+ EXPECT_EQ(np, nullptr);
+ EXPECT_NE(cstr_ptr, nullptr);
+
+ constexpr size_t sp_npos = sp.npos;
+ EXPECT_EQ(sp_npos, -1);
+}
+
+TEST(StringViewTest, Noexcept) {
+ EXPECT_TRUE((std::is_nothrow_constructible<absl::string_view,
+ const std::string&>::value));
+ EXPECT_TRUE(
+ (std::is_nothrow_constructible<absl::string_view, const std::string&>::value));
+ EXPECT_TRUE(std::is_nothrow_constructible<absl::string_view>::value);
+ constexpr absl::string_view sp;
+ EXPECT_TRUE(noexcept(sp.begin()));
+ EXPECT_TRUE(noexcept(sp.end()));
+ EXPECT_TRUE(noexcept(sp.cbegin()));
+ EXPECT_TRUE(noexcept(sp.cend()));
+ EXPECT_TRUE(noexcept(sp.rbegin()));
+ EXPECT_TRUE(noexcept(sp.rend()));
+ EXPECT_TRUE(noexcept(sp.crbegin()));
+ EXPECT_TRUE(noexcept(sp.crend()));
+ EXPECT_TRUE(noexcept(sp.size()));
+ EXPECT_TRUE(noexcept(sp.length()));
+ EXPECT_TRUE(noexcept(sp.empty()));
+ EXPECT_TRUE(noexcept(sp.data()));
+ EXPECT_TRUE(noexcept(sp.compare(sp)));
+ EXPECT_TRUE(noexcept(sp.find(sp)));
+ EXPECT_TRUE(noexcept(sp.find('f')));
+ EXPECT_TRUE(noexcept(sp.rfind(sp)));
+ EXPECT_TRUE(noexcept(sp.rfind('f')));
+ EXPECT_TRUE(noexcept(sp.find_first_of(sp)));
+ EXPECT_TRUE(noexcept(sp.find_first_of('f')));
+ EXPECT_TRUE(noexcept(sp.find_last_of(sp)));
+ EXPECT_TRUE(noexcept(sp.find_last_of('f')));
+ EXPECT_TRUE(noexcept(sp.find_first_not_of(sp)));
+ EXPECT_TRUE(noexcept(sp.find_first_not_of('f')));
+ EXPECT_TRUE(noexcept(sp.find_last_not_of(sp)));
+ EXPECT_TRUE(noexcept(sp.find_last_not_of('f')));
+}
+
+TEST(ComparisonOpsTest, StringCompareNotAmbiguous) {
+ EXPECT_EQ("hello", std::string("hello"));
+ EXPECT_LT("hello", std::string("world"));
+}
+
+TEST(ComparisonOpsTest, HeterogenousStringViewEquals) {
+ EXPECT_EQ(absl::string_view("hello"), std::string("hello"));
+ EXPECT_EQ("hello", absl::string_view("hello"));
+}
+
+TEST(FindOneCharTest, EdgeCases) {
+ absl::string_view a("xxyyyxx");
+
+ // Set a = "xyyyx".
+ a.remove_prefix(1);
+ a.remove_suffix(1);
+
+ EXPECT_EQ(0, a.find('x'));
+ EXPECT_EQ(0, a.find('x', 0));
+ EXPECT_EQ(4, a.find('x', 1));
+ EXPECT_EQ(4, a.find('x', 4));
+ EXPECT_EQ(absl::string_view::npos, a.find('x', 5));
+
+ EXPECT_EQ(4, a.rfind('x'));
+ EXPECT_EQ(4, a.rfind('x', 5));
+ EXPECT_EQ(4, a.rfind('x', 4));
+ EXPECT_EQ(0, a.rfind('x', 3));
+ EXPECT_EQ(0, a.rfind('x', 0));
+
+ // Set a = "yyy".
+ a.remove_prefix(1);
+ a.remove_suffix(1);
+
+ EXPECT_EQ(absl::string_view::npos, a.find('x'));
+ EXPECT_EQ(absl::string_view::npos, a.rfind('x'));
+}
+
+#ifndef THREAD_SANITIZER // Allocates too much memory for tsan.
+TEST(HugeStringView, TwoPointTwoGB) {
+ if (sizeof(size_t) <= 4 || RunningOnValgrind())
+ return;
+ // Try a huge std::string piece.
+ const size_t size = size_t{2200} * 1000 * 1000;
+ std::string s(size, 'a');
+ absl::string_view sp(s);
+ EXPECT_EQ(size, sp.length());
+ sp.remove_prefix(1);
+ EXPECT_EQ(size - 1, sp.length());
+ sp.remove_suffix(2);
+ EXPECT_EQ(size - 1 - 2, sp.length());
+}
+#endif // THREAD_SANITIZER
+
+#ifndef NDEBUG
+TEST(NonNegativeLenTest, NonNegativeLen) {
+ EXPECT_DEATH_IF_SUPPORTED(absl::string_view("xyz", -1), "len <= kMaxSize");
+}
+#endif // NDEBUG
+
+class StringViewStreamTest : public ::testing::Test {
+ public:
+ // Set negative 'width' for right justification.
+ template <typename T>
+ std::string Pad(const T& s, int width, char fill = 0) {
+ std::ostringstream oss;
+ if (fill != 0) {
+ oss << std::setfill(fill);
+ }
+ if (width < 0) {
+ width = -width;
+ oss << std::right;
+ }
+ oss << std::setw(width) << s;
+ return oss.str();
+ }
+};
+
+TEST_F(StringViewStreamTest, Padding) {
+ std::string s("hello");
+ absl::string_view sp(s);
+ for (int w = -64; w < 64; ++w) {
+ SCOPED_TRACE(w);
+ EXPECT_EQ(Pad(s, w), Pad(sp, w));
+ }
+ for (int w = -64; w < 64; ++w) {
+ SCOPED_TRACE(w);
+ EXPECT_EQ(Pad(s, w, '#'), Pad(sp, w, '#'));
+ }
+}
+
+TEST_F(StringViewStreamTest, ResetsWidth) {
+ // Width should reset after one formatted write.
+ // If we weren't resetting width after formatting the string_view,
+ // we'd have width=5 carrying over to the printing of the "]",
+ // creating "[###hi####]".
+ std::string s = "hi";
+ absl::string_view sp = s;
+ {
+ std::ostringstream oss;
+ oss << "[" << std::setfill('#') << std::setw(5) << s << "]";
+ ASSERT_EQ("[###hi]", oss.str());
+ }
+ {
+ std::ostringstream oss;
+ oss << "[" << std::setfill('#') << std::setw(5) << sp << "]";
+ EXPECT_EQ("[###hi]", oss.str());
+ }
+}
+
+} // namespace
diff --git a/absl/strings/strip.cc b/absl/strings/strip.cc
new file mode 100644
index 0000000..968c09c
--- /dev/null
+++ b/absl/strings/strip.cc
@@ -0,0 +1,269 @@
+// 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 contains functions that remove a defined part from the std::string,
+// i.e., strip the std::string.
+
+#include "absl/strings/strip.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+#include <string>
+
+#include "absl/strings/ascii.h"
+#include "absl/strings/string_view.h"
+
+// ----------------------------------------------------------------------
+// ReplaceCharacters
+// Replaces any occurrence of the character 'remove' (or the characters
+// in 'remove') with the character 'replace_with'.
+// ----------------------------------------------------------------------
+void ReplaceCharacters(char* str, size_t len, absl::string_view remove,
+ char replace_with) {
+ for (char* end = str + len; str != end; ++str) {
+ if (remove.find(*str) != absl::string_view::npos) {
+ *str = replace_with;
+ }
+ }
+}
+
+void ReplaceCharacters(std::string* s, absl::string_view remove, char replace_with) {
+ for (char& ch : *s) {
+ if (remove.find(ch) != absl::string_view::npos) {
+ ch = replace_with;
+ }
+ }
+}
+
+bool StripTrailingNewline(std::string* s) {
+ if (!s->empty() && (*s)[s->size() - 1] == '\n') {
+ if (s->size() > 1 && (*s)[s->size() - 2] == '\r')
+ s->resize(s->size() - 2);
+ else
+ s->resize(s->size() - 1);
+ return true;
+ }
+ return false;
+}
+
+// ----------------------------------------------------------------------
+// Misc. stripping routines
+// ----------------------------------------------------------------------
+void StripCurlyBraces(std::string* s) {
+ return StripBrackets('{', '}', s);
+}
+
+void StripBrackets(char left, char right, std::string* s) {
+ std::string::iterator opencurly = std::find(s->begin(), s->end(), left);
+ while (opencurly != s->end()) {
+ std::string::iterator closecurly = std::find(opencurly, s->end(), right);
+ if (closecurly == s->end()) return;
+ opencurly = s->erase(opencurly, closecurly + 1);
+ opencurly = std::find(opencurly, s->end(), left);
+ }
+}
+
+void StripMarkupTags(std::string* s) {
+ std::string::iterator output = std::find(s->begin(), s->end(), '<');
+ std::string::iterator input = output;
+ while (input != s->end()) {
+ if (*input == '<') {
+ input = std::find(input, s->end(), '>');
+ if (input == s->end()) break;
+ ++input;
+ } else {
+ *output++ = *input++;
+ }
+ }
+ s->resize(output - s->begin());
+}
+
+std::string OutputWithMarkupTagsStripped(const std::string& s) {
+ std::string result(s);
+ StripMarkupTags(&result);
+ return result;
+}
+
+ptrdiff_t TrimStringLeft(std::string* s, absl::string_view remove) {
+ size_t i = 0;
+ while (i < s->size() && memchr(remove.data(), (*s)[i], remove.size())) {
+ ++i;
+ }
+ if (i > 0) s->erase(0, i);
+ return i;
+}
+
+ptrdiff_t TrimStringRight(std::string* s, absl::string_view remove) {
+ size_t i = s->size(), trimmed = 0;
+ while (i > 0 && memchr(remove.data(), (*s)[i - 1], remove.size())) {
+ --i;
+ }
+ if (i < s->size()) {
+ trimmed = s->size() - i;
+ s->erase(i);
+ }
+ return trimmed;
+}
+
+// Unfortunately, absl::string_view does not have erase, so we've to replicate
+// the implementation with remove_prefix()/remove_suffix()
+ptrdiff_t TrimStringLeft(absl::string_view* s, absl::string_view remove) {
+ size_t i = 0;
+ while (i < s->size() && memchr(remove.data(), (*s)[i], remove.size())) {
+ ++i;
+ }
+ if (i > 0) s->remove_prefix(i);
+ return i;
+}
+
+ptrdiff_t TrimStringRight(absl::string_view* s, absl::string_view remove) {
+ size_t i = s->size(), trimmed = 0;
+ while (i > 0 && memchr(remove.data(), (*s)[i - 1], remove.size())) {
+ --i;
+ }
+ if (i < s->size()) {
+ trimmed = s->size() - i;
+ s->remove_suffix(trimmed);
+ }
+ return trimmed;
+}
+
+// ----------------------------------------------------------------------
+// Various removal routines
+// ----------------------------------------------------------------------
+ptrdiff_t strrm(char* str, char c) {
+ char* src;
+ char* dest;
+ for (src = dest = str; *src != '\0'; ++src)
+ if (*src != c) *(dest++) = *src;
+ *dest = '\0';
+ return dest - str;
+}
+
+ptrdiff_t memrm(char* str, ptrdiff_t strlen, char c) {
+ char* src;
+ char* dest;
+ for (src = dest = str; strlen-- > 0; ++src)
+ if (*src != c) *(dest++) = *src;
+ return dest - str;
+}
+
+ptrdiff_t strrmm(char* str, const char* chars) {
+ char* src;
+ char* dest;
+ for (src = dest = str; *src != '\0'; ++src) {
+ bool skip = false;
+ for (const char* c = chars; *c != '\0'; c++) {
+ if (*src == *c) {
+ skip = true;
+ break;
+ }
+ }
+ if (!skip) *(dest++) = *src;
+ }
+ *dest = '\0';
+ return dest - str;
+}
+
+ptrdiff_t strrmm(std::string* str, const std::string& chars) {
+ size_t str_len = str->length();
+ size_t in_index = str->find_first_of(chars);
+ if (in_index == std::string::npos) return str_len;
+
+ size_t out_index = in_index++;
+
+ while (in_index < str_len) {
+ char c = (*str)[in_index++];
+ if (chars.find(c) == std::string::npos) (*str)[out_index++] = c;
+ }
+
+ str->resize(out_index);
+ return out_index;
+}
+
+// ----------------------------------------------------------------------
+// StripDupCharacters
+// Replaces any repeated occurrence of the character 'dup_char'
+// with single occurrence. e.g.,
+// StripDupCharacters("a//b/c//d", '/', 0) => "a/b/c/d"
+// Return the number of characters removed
+// ----------------------------------------------------------------------
+ptrdiff_t StripDupCharacters(std::string* s, char dup_char, ptrdiff_t start_pos) {
+ if (start_pos < 0) start_pos = 0;
+
+ // remove dups by compaction in-place
+ ptrdiff_t input_pos = start_pos; // current reader position
+ ptrdiff_t output_pos = start_pos; // current writer position
+ const ptrdiff_t input_end = s->size();
+ while (input_pos < input_end) {
+ // keep current character
+ const char curr_char = (*s)[input_pos];
+ if (output_pos != input_pos) // must copy
+ (*s)[output_pos] = curr_char;
+ ++input_pos;
+ ++output_pos;
+
+ if (curr_char == dup_char) { // skip subsequent dups
+ while ((input_pos < input_end) && ((*s)[input_pos] == dup_char))
+ ++input_pos;
+ }
+ }
+ const ptrdiff_t num_deleted = input_pos - output_pos;
+ s->resize(s->size() - num_deleted);
+ return num_deleted;
+}
+
+// ----------------------------------------------------------------------
+// TrimRunsInString
+// Removes leading and trailing runs, and collapses middle
+// runs of a set of characters into a single character (the
+// first one specified in 'remove'). Useful for collapsing
+// runs of repeated delimiters, whitespace, etc. E.g.,
+// TrimRunsInString(&s, " :,()") removes leading and trailing
+// delimiter chars and collapses and converts internal runs
+// of delimiters to single ' ' characters, so, for example,
+// " a:(b):c " -> "a b c"
+// "first,last::(area)phone, ::zip" -> "first last area phone zip"
+// ----------------------------------------------------------------------
+void TrimRunsInString(std::string* s, absl::string_view remove) {
+ std::string::iterator dest = s->begin();
+ std::string::iterator src_end = s->end();
+ for (std::string::iterator src = s->begin(); src != src_end;) {
+ if (remove.find(*src) == absl::string_view::npos) {
+ *(dest++) = *(src++);
+ } else {
+ // Skip to the end of this run of chars that are in 'remove'.
+ for (++src; src != src_end; ++src) {
+ if (remove.find(*src) == absl::string_view::npos) {
+ if (dest != s->begin()) {
+ // This is an internal run; collapse it.
+ *(dest++) = remove[0];
+ }
+ *(dest++) = *(src++);
+ break;
+ }
+ }
+ }
+ }
+ s->erase(dest, src_end);
+}
+
+// ----------------------------------------------------------------------
+// RemoveNullsInString
+// Removes any internal \0 characters from the std::string.
+// ----------------------------------------------------------------------
+void RemoveNullsInString(std::string* s) {
+ s->erase(std::remove(s->begin(), s->end(), '\0'), s->end());
+}
diff --git a/absl/strings/strip.h b/absl/strings/strip.h
new file mode 100644
index 0000000..370f9e8
--- /dev/null
+++ b/absl/strings/strip.h
@@ -0,0 +1,89 @@
+//
+// 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: strip.h
+// -----------------------------------------------------------------------------
+//
+// This file contains various functions for stripping substrings from a std::string.
+#ifndef ABSL_STRINGS_STRIP_H_
+#define ABSL_STRINGS_STRIP_H_
+
+#include <cstddef>
+#include <string>
+
+#include "absl/base/macros.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/match.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+
+// ConsumePrefix()
+//
+// Strips the `expected` prefix from the start of the given std::string, returning
+// `true` if the strip operation succeeded or false otherwise.
+//
+// Example:
+//
+// absl::string_view input("abc");
+// EXPECT_TRUE(absl::ConsumePrefix(&input, "a"));
+// EXPECT_EQ(input, "bc");
+inline bool ConsumePrefix(absl::string_view* str, absl::string_view expected) {
+ if (!absl::StartsWith(*str, expected)) return false;
+ str->remove_prefix(expected.size());
+ return true;
+}
+// ConsumeSuffix()
+//
+// Strips the `expected` suffix from the end of the given std::string, returning
+// `true` if the strip operation succeeded or false otherwise.
+//
+// Example:
+//
+// absl::string_view input("abcdef");
+// EXPECT_TRUE(absl::ConsumeSuffix(&input, "def"));
+// EXPECT_EQ(input, "abc");
+inline bool ConsumeSuffix(absl::string_view* str, absl::string_view expected) {
+ if (!absl::EndsWith(*str, expected)) return false;
+ str->remove_suffix(expected.size());
+ return true;
+}
+
+// StripPrefix()
+//
+// Returns a view into the input std::string 'str' with the given 'prefix' removed,
+// but leaving the original std::string intact. If the prefix does not match at the
+// start of the std::string, returns the original std::string instead.
+inline absl::string_view StripPrefix(absl::string_view str,
+ absl::string_view prefix) {
+ if (absl::StartsWith(str, prefix)) str.remove_prefix(prefix.size());
+ return str;
+}
+
+// StripSuffix()
+//
+// Returns a view into the input std::string 'str' with the given 'suffix' removed,
+// but leaving the original std::string intact. If the suffix does not match at the
+// end of the std::string, returns the original std::string instead.
+inline absl::string_view StripSuffix(absl::string_view str,
+ absl::string_view suffix) {
+ if (absl::EndsWith(str, suffix)) str.remove_suffix(suffix.size());
+ return str;
+}
+
+} // namespace absl
+
+#endif // ABSL_STRINGS_STRIP_H_
diff --git a/absl/strings/strip_test.cc b/absl/strings/strip_test.cc
new file mode 100644
index 0000000..3c9e726
--- /dev/null
+++ b/absl/strings/strip_test.cc
@@ -0,0 +1,119 @@
+// 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 contains functions that remove a defined part from the std::string,
+// i.e., strip the std::string.
+
+#include "absl/strings/strip.h"
+
+#include <cassert>
+#include <cstdio>
+#include <cstring>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/strings/string_view.h"
+
+namespace {
+
+using testing::ElementsAre;
+using testing::IsEmpty;
+
+TEST(Strip, ConsumePrefixOneChar) {
+ absl::string_view input("abc");
+ EXPECT_TRUE(absl::ConsumePrefix(&input, "a"));
+ EXPECT_EQ(input, "bc");
+
+ EXPECT_FALSE(absl::ConsumePrefix(&input, "x"));
+ EXPECT_EQ(input, "bc");
+
+ EXPECT_TRUE(absl::ConsumePrefix(&input, "b"));
+ EXPECT_EQ(input, "c");
+
+ EXPECT_TRUE(absl::ConsumePrefix(&input, "c"));
+ EXPECT_EQ(input, "");
+
+ EXPECT_FALSE(absl::ConsumePrefix(&input, "a"));
+ EXPECT_EQ(input, "");
+}
+
+TEST(Strip, ConsumePrefix) {
+ absl::string_view input("abcdef");
+ EXPECT_FALSE(absl::ConsumePrefix(&input, "abcdefg"));
+ EXPECT_EQ(input, "abcdef");
+
+ EXPECT_FALSE(absl::ConsumePrefix(&input, "abce"));
+ EXPECT_EQ(input, "abcdef");
+
+ EXPECT_TRUE(absl::ConsumePrefix(&input, ""));
+ EXPECT_EQ(input, "abcdef");
+
+ EXPECT_FALSE(absl::ConsumePrefix(&input, "abcdeg"));
+ EXPECT_EQ(input, "abcdef");
+
+ EXPECT_TRUE(absl::ConsumePrefix(&input, "abcdef"));
+ EXPECT_EQ(input, "");
+
+ input = "abcdef";
+ EXPECT_TRUE(absl::ConsumePrefix(&input, "abcde"));
+ EXPECT_EQ(input, "f");
+}
+
+TEST(Strip, ConsumeSuffix) {
+ absl::string_view input("abcdef");
+ EXPECT_FALSE(absl::ConsumeSuffix(&input, "abcdefg"));
+ EXPECT_EQ(input, "abcdef");
+
+ EXPECT_TRUE(absl::ConsumeSuffix(&input, ""));
+ EXPECT_EQ(input, "abcdef");
+
+ EXPECT_TRUE(absl::ConsumeSuffix(&input, "def"));
+ EXPECT_EQ(input, "abc");
+
+ input = "abcdef";
+ EXPECT_FALSE(absl::ConsumeSuffix(&input, "abcdeg"));
+ EXPECT_EQ(input, "abcdef");
+
+ EXPECT_TRUE(absl::ConsumeSuffix(&input, "f"));
+ EXPECT_EQ(input, "abcde");
+
+ EXPECT_TRUE(absl::ConsumeSuffix(&input, "abcde"));
+ EXPECT_EQ(input, "");
+}
+
+TEST(Strip, StripPrefix) {
+ const absl::string_view null_str;
+
+ EXPECT_EQ(absl::StripPrefix("foobar", "foo"), "bar");
+ EXPECT_EQ(absl::StripPrefix("foobar", ""), "foobar");
+ EXPECT_EQ(absl::StripPrefix("foobar", null_str), "foobar");
+ EXPECT_EQ(absl::StripPrefix("foobar", "foobar"), "");
+ EXPECT_EQ(absl::StripPrefix("foobar", "bar"), "foobar");
+ EXPECT_EQ(absl::StripPrefix("foobar", "foobarr"), "foobar");
+ EXPECT_EQ(absl::StripPrefix("", ""), "");
+}
+
+TEST(Strip, StripSuffix) {
+ const absl::string_view null_str;
+
+ EXPECT_EQ(absl::StripSuffix("foobar", "bar"), "foo");
+ EXPECT_EQ(absl::StripSuffix("foobar", ""), "foobar");
+ EXPECT_EQ(absl::StripSuffix("foobar", null_str), "foobar");
+ EXPECT_EQ(absl::StripSuffix("foobar", "foobar"), "");
+ EXPECT_EQ(absl::StripSuffix("foobar", "foo"), "foobar");
+ EXPECT_EQ(absl::StripSuffix("foobar", "ffoobar"), "foobar");
+ EXPECT_EQ(absl::StripSuffix("", ""), "");
+}
+
+} // namespace
diff --git a/absl/strings/substitute.cc b/absl/strings/substitute.cc
new file mode 100644
index 0000000..f739f8c
--- /dev/null
+++ b/absl/strings/substitute.cc
@@ -0,0 +1,117 @@
+// 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/strings/substitute.h"
+
+#include <algorithm>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/escaping.h"
+#include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+namespace substitute_internal {
+
+void SubstituteAndAppendArray(std::string* output, absl::string_view format,
+ const absl::string_view* args_array,
+ size_t num_args) {
+ // Determine total size needed.
+ size_t size = 0;
+ for (size_t i = 0; i < format.size(); i++) {
+ if (format[i] == '$') {
+ if (i + 1 >= format.size()) {
+#ifndef NDEBUG
+ ABSL_RAW_LOG(FATAL,
+ "Invalid strings::Substitute() format std::string: \"%s\".",
+ absl::CEscape(format).c_str());
+#endif
+ return;
+ } else if (absl::ascii_isdigit(format[i + 1])) {
+ int index = format[i + 1] - '0';
+ if (static_cast<size_t>(index) >= num_args) {
+#ifndef NDEBUG
+ ABSL_RAW_LOG(
+ FATAL,
+ "Invalid strings::Substitute() format std::string: asked for \"$"
+ "%d\", but only %d args were given. Full format std::string was: "
+ "\"%s\".",
+ index, static_cast<int>(num_args), absl::CEscape(format).c_str());
+#endif
+ return;
+ }
+ size += args_array[index].size();
+ ++i; // Skip next char.
+ } else if (format[i + 1] == '$') {
+ ++size;
+ ++i; // Skip next char.
+ } else {
+#ifndef NDEBUG
+ ABSL_RAW_LOG(FATAL,
+ "Invalid strings::Substitute() format std::string: \"%s\".",
+ absl::CEscape(format).c_str());
+#endif
+ return;
+ }
+ } else {
+ ++size;
+ }
+ }
+
+ if (size == 0) return;
+
+ // Build the std::string.
+ size_t original_size = output->size();
+ strings_internal::STLStringResizeUninitialized(output, original_size + size);
+ char* target = &(*output)[original_size];
+ for (size_t i = 0; i < format.size(); i++) {
+ if (format[i] == '$') {
+ if (absl::ascii_isdigit(format[i + 1])) {
+ const absl::string_view src = args_array[format[i + 1] - '0'];
+ target = std::copy(src.begin(), src.end(), target);
+ ++i; // Skip next char.
+ } else if (format[i + 1] == '$') {
+ *target++ = '$';
+ ++i; // Skip next char.
+ }
+ } else {
+ *target++ = format[i];
+ }
+ }
+
+ assert(target == output->data() + output->size());
+}
+
+Arg::Arg(const void* value) {
+ static_assert(sizeof(scratch_) >= sizeof(value) * 2 + 2,
+ "fix sizeof(scratch_)");
+ if (value == nullptr) {
+ piece_ = "NULL";
+ } else {
+ char* ptr = scratch_ + sizeof(scratch_);
+ uintptr_t num = reinterpret_cast<uintptr_t>(value);
+ static const char kHexDigits[] = "0123456789abcdef";
+ do {
+ *--ptr = kHexDigits[num & 0xf];
+ num >>= 4;
+ } while (num != 0);
+ *--ptr = 'x';
+ *--ptr = '0';
+ piece_ = absl::string_view(ptr, scratch_ + sizeof(scratch_) - ptr);
+ }
+}
+
+} // namespace substitute_internal
+} // namespace absl
diff --git a/absl/strings/substitute.h b/absl/strings/substitute.h
new file mode 100644
index 0000000..5d6bfd9
--- /dev/null
+++ b/absl/strings/substitute.h
@@ -0,0 +1,674 @@
+//
+// 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: substitute.h
+// -----------------------------------------------------------------------------
+//
+// This package contains functions for efficiently performing std::string
+// substitutions using a format std::string with positional notation:
+// `Substitute()` and `SubstituteAndAppend()`.
+//
+// Unlike printf-style format specifiers, `Substitute()` functions do not need
+// to specify the type of the substitution arguments. Supported arguments
+// following the format std::string, such as strings, string_views, ints,
+// floats, and bools, are automatically converted to strings during the
+// substitution process. (See below for a full list of supported types.)
+//
+// `Substitute()` does not allow you to specify *how* to format a value, beyond
+// the default conversion to std::string. For example, you cannot format an integer
+// in hex.
+//
+// The format std::string uses positional identifiers indicated by a dollar sign ($)
+// and single digit positional ids to indicate which substitution arguments to
+// use at that location within the format std::string.
+//
+// Example 1:
+// std::string s = Substitute("$1 purchased $0 $2. Thanks $1!",
+// 5, "Bob", "Apples");
+// EXPECT_EQ("Bob purchased 5 Apples. Thanks Bob!", s);
+//
+// Example 2:
+// std::string s = "Hi. ";
+// SubstituteAndAppend(&s, "My name is $0 and I am $1 years old.", "Bob", 5);
+// EXPECT_EQ("Hi. My name is Bob and I am 5 years old.", s);
+//
+// Differences from `StringPrintf()`:
+// * The format std::string does not identify the types of arguments. Instead, the
+// arguments are implicitly converted to strings. See below for a list of
+// accepted types.
+// * Substitutions in the format std::string are identified by a '$' followed by a
+// single digit. You can use arguments out-of-order and use the same
+// argument multiple times.
+// * A '$$' sequence in the format std::string means output a literal '$'
+// character.
+// * `Substitute()` is significantly faster than `StringPrintf()`. For very
+// large strings, it may be orders of magnitude faster.
+//
+// Supported types:
+// * absl::string_view, std::string, const char* (null is equivalent to "")
+// * int32_t, int64_t, uint32_t, uint64
+// * float, double
+// * bool (Printed as "true" or "false")
+// * pointer types other than char* (Printed as "0x<lower case hex std::string>",
+// except that null is printed as "NULL")
+//
+// If an invalid format std::string is provided, Substitute returns an empty std::string
+// and SubstituteAndAppend does not change the provided output std::string.
+// A format std::string is invalid if it:
+// * ends in an unescaped $ character,
+// e.g. "Hello $", or
+// * calls for a position argument which is not provided,
+// e.g. Substitute("Hello $2", "world"), or
+// * specifies a non-digit, non-$ character after an unescaped $ character,
+// e.g. "Hello %f".
+// In debug mode, i.e. #ifndef NDEBUG, such errors terminate the program.
+
+#ifndef ABSL_STRINGS_SUBSTITUTE_H_
+#define ABSL_STRINGS_SUBSTITUTE_H_
+
+#include <cstring>
+#include <string>
+
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/escaping.h"
+#include "absl/strings/numbers.h"
+#include "absl/strings/str_join.h"
+#include "absl/strings/str_split.h"
+#include "absl/strings/string_view.h"
+#include "absl/strings/strip.h"
+
+namespace absl {
+namespace substitute_internal {
+
+// Arg
+//
+// This class provides an argument type for `absl::Substitute()` and
+// `absl::SubstituteAndAppend()`. `Arg` handles implicit conversion of various
+// types to a std::string. (`Arg` is very similar to the `AlphaNum` class in
+// `StrCat()`.)
+//
+// This class has implicit constructors.
+class Arg {
+ public:
+ // Overloads for std::string-y things
+ //
+ // Explicitly overload `const char*` so the compiler doesn't cast to `bool`.
+ Arg(const char* value) // NOLINT(runtime/explicit)
+ : piece_(value) {}
+ Arg(const std::string& value) // NOLINT(runtime/explicit)
+ : piece_(value) {}
+ Arg(absl::string_view value) // NOLINT(runtime/explicit)
+ : piece_(value) {}
+
+ // Overloads for primitives
+ //
+ // No overloads are available for signed and unsigned char because if people
+ // are explicitly declaring their chars as signed or unsigned then they are
+ // probably using them as 8-bit integers and would probably prefer an integer
+ // representation. However, we can't really know, so we make the caller decide
+ // what to do.
+ Arg(char value) // NOLINT(runtime/explicit)
+ : piece_(scratch_, 1) { scratch_[0] = value; }
+ Arg(short value) // NOLINT(runtime/explicit)
+ : piece_(scratch_,
+ numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+ Arg(unsigned short value) // NOLINT(runtime/explicit)
+ : piece_(scratch_,
+ numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+ Arg(int value) // NOLINT(runtime/explicit)
+ : piece_(scratch_,
+ numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+ Arg(unsigned int value) // NOLINT(runtime/explicit)
+ : piece_(scratch_,
+ numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+ Arg(long value) // NOLINT(runtime/explicit)
+ : piece_(scratch_,
+ numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+ Arg(unsigned long value) // NOLINT(runtime/explicit)
+ : piece_(scratch_,
+ numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+ Arg(long long value) // NOLINT(runtime/explicit)
+ : piece_(scratch_,
+ numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+ Arg(unsigned long long value) // NOLINT(runtime/explicit)
+ : piece_(scratch_,
+ numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+ Arg(float value) // NOLINT(runtime/explicit)
+ : piece_(numbers_internal::RoundTripFloatToBuffer(value, scratch_)) {}
+ Arg(double value) // NOLINT(runtime/explicit)
+ : piece_(numbers_internal::RoundTripDoubleToBuffer(value, scratch_)) {}
+ Arg(bool value) // NOLINT(runtime/explicit)
+ : piece_(value ? "true" : "false") {}
+ // `void*` values, with the exception of `char*`, are printed as
+ // `StringPrintf()` with format "%p": e.g. ("0x<hex value>").
+ // However, in the case of `nullptr`, "NULL" is printed.
+ Arg(const void* value); // NOLINT(runtime/explicit)
+
+ Arg(const Arg&) = delete;
+ Arg& operator=(const Arg&) = delete;
+
+ absl::string_view piece() const { return piece_; }
+
+ private:
+ absl::string_view piece_;
+ char scratch_[numbers_internal::kFastToBufferSize];
+};
+
+// Internal helper function. Don't call this from outside this implementation.
+// This interface may change without notice.
+void SubstituteAndAppendArray(std::string* output, absl::string_view format,
+ const absl::string_view* args_array,
+ size_t num_args);
+
+#if defined(ABSL_BAD_CALL_IF)
+constexpr int CalculateOneBit(const char* format) {
+ return (*format < '0' || *format > '9') ? 0 : (1 << (*format - '0'));
+}
+
+constexpr const char* SkipNumber(const char* format) {
+ return !*format ? format : (format + 1);
+}
+
+constexpr int PlaceholderBitmask(const char* format) {
+ return !*format ? 0 : *format != '$'
+ ? PlaceholderBitmask(format + 1)
+ : (CalculateOneBit(format + 1) |
+ PlaceholderBitmask(SkipNumber(format + 1)));
+}
+#endif // ABSL_BAD_CALL_IF
+
+} // namespace substitute_internal
+
+//
+// PUBLIC API
+//
+
+// SubstituteAndAppend()
+//
+// Substitutes variables into a given format std::string and appends to a given
+// output std::string. See file comments above for usage.
+//
+// The declarations of `SubstituteAndAppend()` below consist of overloads
+// for passing 0 to 10 arguments, respectively.
+//
+// NOTE: A zero-argument `SubstituteAndAppend()` may be used within variadic
+// templates to allow a variable number of arguments.
+//
+// Example:
+// template <typename... Args>
+// void VarMsg(std::string* boilerplate, const std::string& format,
+// const Args&... args) {
+// std::string s = absl::SubstituteAndAppend(boilerplate, format, args...)";
+// }
+//
+inline void SubstituteAndAppend(std::string* output, absl::string_view format) {
+ substitute_internal::SubstituteAndAppendArray(output, format, nullptr, 0);
+}
+
+inline void SubstituteAndAppend(std::string* output, absl::string_view format,
+ const substitute_internal::Arg& a0) {
+ const absl::string_view args[] = {a0.piece()};
+ substitute_internal::SubstituteAndAppendArray(output, format, args,
+ ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(std::string* output, absl::string_view format,
+ const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1) {
+ const absl::string_view args[] = {a0.piece(), a1.piece()};
+ substitute_internal::SubstituteAndAppendArray(output, format, args,
+ ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(std::string* output, absl::string_view format,
+ const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2) {
+ const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece()};
+ substitute_internal::SubstituteAndAppendArray(output, format, args,
+ ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(std::string* output, absl::string_view format,
+ const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3) {
+ const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
+ a3.piece()};
+ substitute_internal::SubstituteAndAppendArray(output, format, args,
+ ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(std::string* output, absl::string_view format,
+ const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3,
+ const substitute_internal::Arg& a4) {
+ const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
+ a3.piece(), a4.piece()};
+ substitute_internal::SubstituteAndAppendArray(output, format, args,
+ ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(std::string* output, absl::string_view format,
+ const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3,
+ const substitute_internal::Arg& a4,
+ const substitute_internal::Arg& a5) {
+ const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
+ a3.piece(), a4.piece(), a5.piece()};
+ substitute_internal::SubstituteAndAppendArray(output, format, args,
+ ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(std::string* output, absl::string_view format,
+ const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3,
+ const substitute_internal::Arg& a4,
+ const substitute_internal::Arg& a5,
+ const substitute_internal::Arg& a6) {
+ const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
+ a3.piece(), a4.piece(), a5.piece(),
+ a6.piece()};
+ substitute_internal::SubstituteAndAppendArray(output, format, args,
+ ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(
+ std::string* output, absl::string_view format,
+ const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
+ const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
+ const substitute_internal::Arg& a6, const substitute_internal::Arg& a7) {
+ const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
+ a3.piece(), a4.piece(), a5.piece(),
+ a6.piece(), a7.piece()};
+ substitute_internal::SubstituteAndAppendArray(output, format, args,
+ ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(
+ std::string* output, absl::string_view format,
+ const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
+ const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
+ const substitute_internal::Arg& a6, const substitute_internal::Arg& a7,
+ const substitute_internal::Arg& a8) {
+ const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
+ a3.piece(), a4.piece(), a5.piece(),
+ a6.piece(), a7.piece(), a8.piece()};
+ substitute_internal::SubstituteAndAppendArray(output, format, args,
+ ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(
+ std::string* output, absl::string_view format,
+ const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
+ const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
+ const substitute_internal::Arg& a6, const substitute_internal::Arg& a7,
+ const substitute_internal::Arg& a8, const substitute_internal::Arg& a9) {
+ const absl::string_view args[] = {
+ a0.piece(), a1.piece(), a2.piece(), a3.piece(), a4.piece(),
+ a5.piece(), a6.piece(), a7.piece(), a8.piece(), a9.piece()};
+ substitute_internal::SubstituteAndAppendArray(output, format, args,
+ ABSL_ARRAYSIZE(args));
+}
+
+#if defined(ABSL_BAD_CALL_IF)
+// This body of functions catches cases where the number of placeholders
+// doesn't match the number of data arguments.
+void SubstituteAndAppend(std::string* output, const char* format)
+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 0,
+ "There were no substitution arguments "
+ "but this format std::string has a $[0-9] in it");
+
+void SubstituteAndAppend(std::string* output, const char* format,
+ const substitute_internal::Arg& a0)
+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1,
+ "There was 1 substitution argument given, but "
+ "this format std::string is either missing its $0, or "
+ "contains one of $1-$9");
+
+void SubstituteAndAppend(std::string* output, const char* format,
+ const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1)
+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 3,
+ "There were 2 substitution arguments given, but "
+ "this format std::string is either missing its $0/$1, or "
+ "contains one of $2-$9");
+
+void SubstituteAndAppend(std::string* output, const char* format,
+ const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2)
+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 7,
+ "There were 3 substitution arguments given, but "
+ "this format std::string is either missing its $0/$1/$2, or "
+ "contains one of $3-$9");
+
+void SubstituteAndAppend(std::string* output, const char* format,
+ const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3)
+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 15,
+ "There were 4 substitution arguments given, but "
+ "this format std::string is either missing its $0-$3, or "
+ "contains one of $4-$9");
+
+void SubstituteAndAppend(std::string* output, const char* format,
+ const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3,
+ const substitute_internal::Arg& a4)
+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 31,
+ "There were 5 substitution arguments given, but "
+ "this format std::string is either missing its $0-$4, or "
+ "contains one of $5-$9");
+
+void SubstituteAndAppend(std::string* output, const char* format,
+ const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3,
+ const substitute_internal::Arg& a4,
+ const substitute_internal::Arg& a5)
+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 63,
+ "There were 6 substitution arguments given, but "
+ "this format std::string is either missing its $0-$5, or "
+ "contains one of $6-$9");
+
+void SubstituteAndAppend(
+ std::string* output, const char* format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+ const substitute_internal::Arg& a5, const substitute_internal::Arg& a6)
+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 127,
+ "There were 7 substitution arguments given, but "
+ "this format std::string is either missing its $0-$6, or "
+ "contains one of $7-$9");
+
+void SubstituteAndAppend(
+ std::string* output, const char* format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+ const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+ const substitute_internal::Arg& a7)
+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 255,
+ "There were 8 substitution arguments given, but "
+ "this format std::string is either missing its $0-$7, or "
+ "contains one of $8-$9");
+
+void SubstituteAndAppend(
+ std::string* output, const char* format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+ const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+ const substitute_internal::Arg& a7, const substitute_internal::Arg& a8)
+ ABSL_BAD_CALL_IF(
+ substitute_internal::PlaceholderBitmask(format) != 511,
+ "There were 9 substitution arguments given, but "
+ "this format std::string is either missing its $0-$8, or contains a $9");
+
+void SubstituteAndAppend(
+ std::string* output, const char* format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+ const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+ const substitute_internal::Arg& a7, const substitute_internal::Arg& a8,
+ const substitute_internal::Arg& a9)
+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1023,
+ "There were 10 substitution arguments given, but this "
+ "format std::string doesn't contain all of $0 through $9");
+#endif // ABSL_BAD_CALL_IF
+
+// Substitute()
+//
+// Substitutes variables into a given format std::string. See file comments above
+// for usage.
+//
+// The declarations of `Substitute()` below consist of overloads for passing 0
+// to 10 arguments, respectively.
+//
+// NOTE: A zero-argument `Substitute()` may be used within variadic templates to
+// allow a variable number of arguments.
+//
+// Example:
+// template <typename... Args>
+// void VarMsg(const std::string& format, const Args&... args) {
+// std::string s = absl::Substitute(format, args...)";
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(absl::string_view format) {
+ std::string result;
+ SubstituteAndAppend(&result, format);
+ return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+ absl::string_view format, const substitute_internal::Arg& a0) {
+ std::string result;
+ SubstituteAndAppend(&result, format, a0);
+ return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+ absl::string_view format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1) {
+ std::string result;
+ SubstituteAndAppend(&result, format, a0, a1);
+ return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+ absl::string_view format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2) {
+ std::string result;
+ SubstituteAndAppend(&result, format, a0, a1, a2);
+ return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+ absl::string_view format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3) {
+ std::string result;
+ SubstituteAndAppend(&result, format, a0, a1, a2, a3);
+ return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+ absl::string_view format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4) {
+ std::string result;
+ SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4);
+ return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+ absl::string_view format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+ const substitute_internal::Arg& a5) {
+ std::string result;
+ SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5);
+ return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+ absl::string_view format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+ const substitute_internal::Arg& a5, const substitute_internal::Arg& a6) {
+ std::string result;
+ SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6);
+ return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+ absl::string_view format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+ const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+ const substitute_internal::Arg& a7) {
+ std::string result;
+ SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7);
+ return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+ absl::string_view format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+ const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+ const substitute_internal::Arg& a7, const substitute_internal::Arg& a8) {
+ std::string result;
+ SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7, a8);
+ return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+ absl::string_view format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+ const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+ const substitute_internal::Arg& a7, const substitute_internal::Arg& a8,
+ const substitute_internal::Arg& a9) {
+ std::string result;
+ SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+ return result;
+}
+
+#if defined(ABSL_BAD_CALL_IF)
+// This body of functions catches cases where the number of placeholders
+// doesn't match the number of data arguments.
+std::string Substitute(const char* format)
+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 0,
+ "There were no substitution arguments "
+ "but this format std::string has a $[0-9] in it");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0)
+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1,
+ "There was 1 substitution argument given, but "
+ "this format std::string is either missing its $0, or "
+ "contains one of $1-$9");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1)
+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 3,
+ "There were 2 substitution arguments given, but "
+ "this format std::string is either missing its $0/$1, or "
+ "contains one of $2-$9");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2)
+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 7,
+ "There were 3 substitution arguments given, but "
+ "this format std::string is either missing its $0/$1/$2, or "
+ "contains one of $3-$9");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3)
+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 15,
+ "There were 4 substitution arguments given, but "
+ "this format std::string is either missing its $0-$3, or "
+ "contains one of $4-$9");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3,
+ const substitute_internal::Arg& a4)
+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 31,
+ "There were 5 substitution arguments given, but "
+ "this format std::string is either missing its $0-$4, or "
+ "contains one of $5-$9");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3,
+ const substitute_internal::Arg& a4,
+ const substitute_internal::Arg& a5)
+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 63,
+ "There were 6 substitution arguments given, but "
+ "this format std::string is either missing its $0-$5, or "
+ "contains one of $6-$9");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3,
+ const substitute_internal::Arg& a4,
+ const substitute_internal::Arg& a5,
+ const substitute_internal::Arg& a6)
+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 127,
+ "There were 7 substitution arguments given, but "
+ "this format std::string is either missing its $0-$6, or "
+ "contains one of $7-$9");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3,
+ const substitute_internal::Arg& a4,
+ const substitute_internal::Arg& a5,
+ const substitute_internal::Arg& a6,
+ const substitute_internal::Arg& a7)
+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 255,
+ "There were 8 substitution arguments given, but "
+ "this format std::string is either missing its $0-$7, or "
+ "contains one of $8-$9");
+
+std::string Substitute(
+ const char* format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+ const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+ const substitute_internal::Arg& a7, const substitute_internal::Arg& a8)
+ ABSL_BAD_CALL_IF(
+ substitute_internal::PlaceholderBitmask(format) != 511,
+ "There were 9 substitution arguments given, but "
+ "this format std::string is either missing its $0-$8, or contains a $9");
+
+std::string Substitute(
+ const char* format, const substitute_internal::Arg& a0,
+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+ const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+ const substitute_internal::Arg& a7, const substitute_internal::Arg& a8,
+ const substitute_internal::Arg& a9)
+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1023,
+ "There were 10 substitution arguments given, but this "
+ "format std::string doesn't contain all of $0 through $9");
+#endif // ABSL_BAD_CALL_IF
+
+} // namespace absl
+
+#endif // ABSL_STRINGS_SUBSTITUTE_H_
diff --git a/absl/strings/substitute_test.cc b/absl/strings/substitute_test.cc
new file mode 100644
index 0000000..a6d7d7b
--- /dev/null
+++ b/absl/strings/substitute_test.cc
@@ -0,0 +1,168 @@
+// 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/strings/substitute.h"
+
+#include <cstdint>
+
+#include "gtest/gtest.h"
+#include "absl/strings/str_cat.h"
+
+namespace {
+
+TEST(SubstituteTest, Substitute) {
+ // Basic.
+ EXPECT_EQ("Hello, world!", absl::Substitute("$0, $1!", "Hello", "world"));
+
+ // Non-char* types.
+ EXPECT_EQ("123 0.2 0.1 foo true false x",
+ absl::Substitute("$0 $1 $2 $3 $4 $5 $6", 123, 0.2, 0.1f,
+ std::string("foo"), true, false, 'x'));
+
+ // All int types.
+ EXPECT_EQ(
+ "-32767 65535 "
+ "-1234567890 3234567890 "
+ "-1234567890 3234567890 "
+ "-1234567890123456789 9234567890123456789",
+ absl::Substitute(
+ "$0 $1 $2 $3 $4 $5 $6 $7",
+ static_cast<short>(-32767), // NOLINT(runtime/int)
+ static_cast<unsigned short>(65535), // NOLINT(runtime/int)
+ -1234567890, 3234567890U, -1234567890L, 3234567890UL,
+ -int64_t{1234567890123456789}, uint64_t{9234567890123456789u}));
+
+ // Pointer.
+ const int* int_p = reinterpret_cast<const int*>(0x12345);
+ std::string str = absl::Substitute("$0", int_p);
+ EXPECT_EQ(absl::StrCat("0x", absl::Hex(reinterpret_cast<intptr_t>(int_p))),
+ str);
+
+ // null is special. StrCat prints 0x0. Substitute prints NULL.
+ const uint64_t* null_p = nullptr;
+ str = absl::Substitute("$0", null_p);
+ EXPECT_EQ("NULL", str);
+
+ // char* is also special.
+ const char* char_p = "print me";
+ str = absl::Substitute("$0", char_p);
+ EXPECT_EQ("print me", str);
+
+ char char_buf[16];
+ strncpy(char_buf, "print me too", sizeof(char_buf));
+ str = absl::Substitute("$0", char_buf);
+ EXPECT_EQ("print me too", str);
+
+ // null char* is "doubly" special. Represented as the empty std::string.
+ char_p = nullptr;
+ str = absl::Substitute("$0", char_p);
+ EXPECT_EQ("", str);
+
+ // Out-of-order.
+ EXPECT_EQ("b, a, c, b", absl::Substitute("$1, $0, $2, $1", "a", "b", "c"));
+
+ // Literal $
+ EXPECT_EQ("$", absl::Substitute("$$"));
+
+ EXPECT_EQ("$1", absl::Substitute("$$1"));
+
+ // Test all overloads.
+ EXPECT_EQ("a", absl::Substitute("$0", "a"));
+ EXPECT_EQ("a b", absl::Substitute("$0 $1", "a", "b"));
+ EXPECT_EQ("a b c", absl::Substitute("$0 $1 $2", "a", "b", "c"));
+ EXPECT_EQ("a b c d", absl::Substitute("$0 $1 $2 $3", "a", "b", "c", "d"));
+ EXPECT_EQ("a b c d e",
+ absl::Substitute("$0 $1 $2 $3 $4", "a", "b", "c", "d", "e"));
+ EXPECT_EQ("a b c d e f", absl::Substitute("$0 $1 $2 $3 $4 $5", "a", "b", "c",
+ "d", "e", "f"));
+ EXPECT_EQ("a b c d e f g", absl::Substitute("$0 $1 $2 $3 $4 $5 $6", "a", "b",
+ "c", "d", "e", "f", "g"));
+ EXPECT_EQ("a b c d e f g h",
+ absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7", "a", "b", "c", "d", "e",
+ "f", "g", "h"));
+ EXPECT_EQ("a b c d e f g h i",
+ absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7 $8", "a", "b", "c", "d",
+ "e", "f", "g", "h", "i"));
+ EXPECT_EQ("a b c d e f g h i j",
+ absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7 $8 $9", "a", "b", "c",
+ "d", "e", "f", "g", "h", "i", "j"));
+ EXPECT_EQ("a b c d e f g h i j b0",
+ absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7 $8 $9 $10", "a", "b", "c",
+ "d", "e", "f", "g", "h", "i", "j"));
+
+ const char* null_cstring = nullptr;
+ EXPECT_EQ("Text: ''", absl::Substitute("Text: '$0'", null_cstring));
+}
+
+TEST(SubstituteTest, SubstituteAndAppend) {
+ std::string str = "Hello";
+ absl::SubstituteAndAppend(&str, ", $0!", "world");
+ EXPECT_EQ("Hello, world!", str);
+
+ // Test all overloads.
+ str.clear();
+ absl::SubstituteAndAppend(&str, "$0", "a");
+ EXPECT_EQ("a", str);
+ str.clear();
+ absl::SubstituteAndAppend(&str, "$0 $1", "a", "b");
+ EXPECT_EQ("a b", str);
+ str.clear();
+ absl::SubstituteAndAppend(&str, "$0 $1 $2", "a", "b", "c");
+ EXPECT_EQ("a b c", str);
+ str.clear();
+ absl::SubstituteAndAppend(&str, "$0 $1 $2 $3", "a", "b", "c", "d");
+ EXPECT_EQ("a b c d", str);
+ str.clear();
+ absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4", "a", "b", "c", "d", "e");
+ EXPECT_EQ("a b c d e", str);
+ str.clear();
+ absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4 $5", "a", "b", "c", "d", "e",
+ "f");
+ EXPECT_EQ("a b c d e f", str);
+ str.clear();
+ absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4 $5 $6", "a", "b", "c", "d",
+ "e", "f", "g");
+ EXPECT_EQ("a b c d e f g", str);
+ str.clear();
+ absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4 $5 $6 $7", "a", "b", "c", "d",
+ "e", "f", "g", "h");
+ EXPECT_EQ("a b c d e f g h", str);
+ str.clear();
+ absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4 $5 $6 $7 $8", "a", "b", "c",
+ "d", "e", "f", "g", "h", "i");
+ EXPECT_EQ("a b c d e f g h i", str);
+ str.clear();
+ absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4 $5 $6 $7 $8 $9", "a", "b",
+ "c", "d", "e", "f", "g", "h", "i", "j");
+ EXPECT_EQ("a b c d e f g h i j", str);
+}
+
+#ifdef GTEST_HAS_DEATH_TEST
+
+TEST(SubstituteDeathTest, SubstituteDeath) {
+ EXPECT_DEBUG_DEATH(
+ static_cast<void>(absl::Substitute(absl::string_view("-$2"), "a", "b")),
+ "Invalid strings::Substitute\\(\\) format std::string: asked for \"\\$2\", "
+ "but only 2 args were given.");
+ EXPECT_DEBUG_DEATH(
+ static_cast<void>(absl::Substitute("-$z-")),
+ "Invalid strings::Substitute\\(\\) format std::string: \"-\\$z-\"");
+ EXPECT_DEBUG_DEATH(
+ static_cast<void>(absl::Substitute("-$")),
+ "Invalid strings::Substitute\\(\\) format std::string: \"-\\$\"");
+}
+
+#endif // GTEST_HAS_DEATH_TEST
+
+} // namespace
diff --git a/absl/strings/testdata/getline-1.txt b/absl/strings/testdata/getline-1.txt
new file mode 100644
index 0000000..19b9097
--- /dev/null
+++ b/absl/strings/testdata/getline-1.txt
@@ -0,0 +1,3 @@
+alpha
+
+beta gamma
diff --git a/absl/strings/testdata/getline-2.txt b/absl/strings/testdata/getline-2.txt
new file mode 100644
index 0000000..d6842d8
--- /dev/null
+++ b/absl/strings/testdata/getline-2.txt
@@ -0,0 +1 @@
+one.two.three
diff --git a/absl/synchronization/BUILD.bazel b/absl/synchronization/BUILD.bazel
new file mode 100644
index 0000000..bddd2ec
--- /dev/null
+++ b/absl/synchronization/BUILD.bazel
@@ -0,0 +1,178 @@
+#
+# 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
+
+# Internal data structure for efficiently detecting mutex dependency cycles
+cc_library(
+ name = "graphcycles_internal",
+ srcs = [
+ "internal/graphcycles.cc",
+ ],
+ hdrs = [
+ "internal/graphcycles.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ "//absl/base",
+ "//absl/base:core_headers",
+ "//absl/base:malloc_internal",
+ ],
+)
+
+cc_library(
+ name = "synchronization",
+ srcs = [
+ "barrier.cc",
+ "blocking_counter.cc",
+ "internal/create_thread_identity.cc",
+ "internal/per_thread_sem.cc",
+ "internal/waiter.cc",
+ "notification.cc",
+ ] + select({
+ "//conditions:default": ["mutex.cc"],
+ }),
+ hdrs = [
+ "barrier.h",
+ "blocking_counter.h",
+ "internal/create_thread_identity.h",
+ "internal/kernel_timeout.h",
+ "internal/mutex_nonprod.inc",
+ "internal/per_thread_sem.h",
+ "internal/waiter.h",
+ "mutex.h",
+ "notification.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ ":graphcycles_internal",
+ "//absl/base",
+ "//absl/base:base_internal",
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ "//absl/base:dynamic_annotations",
+ "//absl/base:malloc_extension",
+ "//absl/base:malloc_internal",
+ "//absl/debugging:stacktrace",
+ "//absl/time",
+ ],
+)
+
+cc_test(
+ name = "blocking_counter_test",
+ size = "small",
+ srcs = ["blocking_counter_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":synchronization",
+ "//absl/time",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "graphcycles_test",
+ size = "medium",
+ srcs = ["internal/graphcycles_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":graphcycles_internal",
+ "//absl/base",
+ "//absl/base:core_headers",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_library(
+ name = "thread_pool",
+ testonly = 1,
+ hdrs = ["internal/thread_pool.h"],
+ deps = [
+ ":synchronization",
+ "//absl/base:core_headers",
+ ],
+)
+
+cc_test(
+ name = "mutex_test",
+ size = "large",
+ timeout = "moderate",
+ srcs = ["mutex_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ tags = [
+ "no_test_loonix", # Too slow.
+ ],
+ deps = [
+ ":synchronization",
+ ":thread_pool",
+ "//absl/base",
+ "//absl/base:core_headers",
+ "//absl/memory",
+ "//absl/time",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "notification_test",
+ size = "small",
+ srcs = ["notification_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":synchronization",
+ "//absl/time",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_library(
+ name = "per_thread_sem_test_common",
+ testonly = 1,
+ srcs = ["internal/per_thread_sem_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":synchronization",
+ "//absl/base",
+ "//absl/base:malloc_extension",
+ "//absl/strings",
+ "//absl/time",
+ "@com_google_googletest//:gtest",
+ ],
+ alwayslink = 1,
+)
+
+cc_test(
+ name = "per_thread_sem_test",
+ size = "medium",
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":per_thread_sem_test_common",
+ ":synchronization",
+ "//absl/base",
+ "//absl/base:malloc_extension",
+ "//absl/strings",
+ "//absl/time",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/absl/synchronization/barrier.cc b/absl/synchronization/barrier.cc
new file mode 100644
index 0000000..a1b3ad5
--- /dev/null
+++ b/absl/synchronization/barrier.cc
@@ -0,0 +1,50 @@
+// 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/synchronization/barrier.h"
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+
+// Return whether int *arg is zero.
+static bool IsZero(void *arg) {
+ return 0 == *reinterpret_cast<int *>(arg);
+}
+
+bool Barrier::Block() {
+ MutexLock l(&this->lock_);
+
+ this->num_to_block_--;
+ if (this->num_to_block_ < 0) {
+ ABSL_RAW_LOG(
+ FATAL,
+ "Block() called too many times. num_to_block_=%d out of total=%d",
+ this->num_to_block_, this->num_to_exit_);
+ }
+
+ this->lock_.Await(Condition(IsZero, &this->num_to_block_));
+
+ // Determine which thread can safely delete this Barrier object
+ this->num_to_exit_--;
+ ABSL_RAW_CHECK(this->num_to_exit_ >= 0, "barrier underflow");
+
+ // If num_to_exit_ == 0 then all other threads in the barrier have
+ // exited the Wait() and have released the Mutex so this thread is
+ // free to delete the barrier.
+ return this->num_to_exit_ == 0;
+}
+
+} // namespace absl
diff --git a/absl/synchronization/barrier.h b/absl/synchronization/barrier.h
new file mode 100644
index 0000000..f834fee
--- /dev/null
+++ b/absl/synchronization/barrier.h
@@ -0,0 +1,77 @@
+// 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.
+//
+// -----------------------------------------------------------------------------
+// barrier.h
+// -----------------------------------------------------------------------------
+
+#ifndef ABSL_SYNCHRONIZATION_BARRIER_H_
+#define ABSL_SYNCHRONIZATION_BARRIER_H_
+
+#include "absl/base/thread_annotations.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+
+// Barrier
+//
+// This class creates a barrier which blocks threads until a prespecified
+// threshold of threads (`num_threads`) utilizes the barrier. A thread utilizes
+// the `Barrier` by calling `Block()` on the barrier, which will block that
+// thread; no call to `Block()` will return until `num_threads` threads have
+// called it.
+//
+// Exactly one call to `Block()` will return `true`, which is then responsible
+// for destroying the barrier; because stack allocation will cause the barrier
+// to be deleted when it is out of scope, barriers should not be stack
+// allocated.
+//
+// Example:
+//
+// // Main thread creates a `Barrier`:
+// barrier = new Barrier(num_threads);
+//
+// // Each participating thread could then call:
+// if (barrier->Block()) delete barrier; // Exactly one call to `Block()`
+// // returns `true`; that call
+// // deletes the barrier.
+class Barrier {
+ public:
+ // `num_threads` is the number of threads that will participate in the barrier
+ explicit Barrier(int num_threads)
+ : num_to_block_(num_threads), num_to_exit_(num_threads) {}
+
+ Barrier(const Barrier&) = delete;
+ Barrier& operator=(const Barrier&) = delete;
+
+ // Barrier::Block()
+ //
+ // Blocks the current thread, and returns only when the `num_threads`
+ // threshold of threads utilizing this barrier has been reached. `Block()`
+ // returns `true` for precisely one caller, which may then destroy the
+ // barrier.
+ //
+ // Memory ordering: For any threads X and Y, any action taken by X
+ // before X calls `Block()` will be visible to Y after Y returns from
+ // `Block()`.
+ bool Block();
+
+ private:
+ Mutex lock_;
+ int num_to_block_ GUARDED_BY(lock_);
+ int num_to_exit_ GUARDED_BY(lock_);
+};
+
+} // namespace absl
+#endif // ABSL_SYNCHRONIZATION_BARRIER_H_
diff --git a/absl/synchronization/blocking_counter.cc b/absl/synchronization/blocking_counter.cc
new file mode 100644
index 0000000..48e3650
--- /dev/null
+++ b/absl/synchronization/blocking_counter.cc
@@ -0,0 +1,53 @@
+// 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/synchronization/blocking_counter.h"
+
+namespace absl {
+
+// Return whether int *arg is zero.
+static bool IsZero(void *arg) {
+ return 0 == *reinterpret_cast<int *>(arg);
+}
+
+bool BlockingCounter::DecrementCount() {
+ MutexLock l(&lock_);
+ count_--;
+ if (count_ < 0) {
+ ABSL_RAW_LOG(
+ FATAL,
+ "BlockingCounter::DecrementCount() called too many times. count=%d",
+ count_);
+ }
+ return count_ == 0;
+}
+
+void BlockingCounter::Wait() {
+ MutexLock l(&this->lock_);
+ ABSL_RAW_CHECK(count_ >= 0, "BlockingCounter underflow");
+
+ // only one thread may call Wait(). To support more than one thread,
+ // implement a counter num_to_exit, like in the Barrier class.
+ ABSL_RAW_CHECK(num_waiting_ == 0, "multiple threads called Wait()");
+ num_waiting_++;
+
+ this->lock_.Await(Condition(IsZero, &this->count_));
+
+ // At this point, We know that all threads executing DecrementCount have
+ // released the lock, and so will not touch this object again.
+ // Therefore, the thread calling this method is free to delete the object
+ // after we return from this method.
+}
+
+} // namespace absl
diff --git a/absl/synchronization/blocking_counter.h b/absl/synchronization/blocking_counter.h
new file mode 100644
index 0000000..476d5f8
--- /dev/null
+++ b/absl/synchronization/blocking_counter.h
@@ -0,0 +1,96 @@
+//
+// 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.
+//
+// -----------------------------------------------------------------------------
+// blocking_counter.h
+// -----------------------------------------------------------------------------
+
+#ifndef ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_
+#define ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_
+
+#include "absl/base/thread_annotations.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+
+// BlockingCounter
+//
+// This class allows a thread to block for a pre-specified number of actions.
+// `BlockingCounter` maintains a single non-negative abstract integer "count"
+// with an initial value `initial_count`. A thread can then call `Wait()` on
+// this blocking counter to block until the specified number of events occur;
+// worker threads then call 'DecrementCount()` on the counter upon completion of
+// their work. Once the counter's internal "count" reaches zero, the blocked
+// thread unblocks.
+//
+// A `BlockingCounter` requires the following:
+// - its `initial_count` is non-negative.
+// - the number of calls to `DecrementCount()` on it is at most
+// `initial_count`.
+// - `Wait()` is called at most once on it.
+//
+// Given the above requirements, a `BlockingCounter` provides the following
+// guarantees:
+// - Once its internal "count" reaches zero, no legal action on the object
+// can further change the value of "count".
+// - When `Wait()` returns, it is legal to destroy the `BlockingCounter`.
+// - When `Wait()` returns, the number of calls to `DecrementCount()` on
+// this blocking counter exactly equals `initial_count`.
+//
+// Example:
+// BlockingCounter bcount(N); // there are N items of work
+// ... Allow worker threads to start.
+// ... On completing each work item, workers do:
+// ... bcount.DecrementCount(); // an item of work has been completed
+//
+// bcount.Wait(); // wait for all work to be complete
+//
+class BlockingCounter {
+ public:
+ explicit BlockingCounter(int initial_count)
+ : count_(initial_count), num_waiting_(0) {}
+
+ BlockingCounter(const BlockingCounter&) = delete;
+ BlockingCounter& operator=(const BlockingCounter&) = delete;
+
+ // BlockingCounter::DecrementCount()
+ //
+ // Decrements the counter's "count" by one, and return "count == 0". This
+ // function requires that "count != 0" when it is called.
+ //
+ // Memory ordering: For any threads X and Y, any action taken by X
+ // before it calls `DecrementCount()` is visible to thread Y after
+ // Y's call to `DecrementCount()`, provided Y's call returns `true`.
+ bool DecrementCount();
+
+ // BlockingCounter::Wait()
+ //
+ // Blocks until the counter reaches zero. This function may be called at most
+ // once. On return, `DecrementCount()` will have been called "initial_count"
+ // times and the blocking counter may be destroyed.
+ //
+ // Memory ordering: For any threads X and Y, any action taken by X
+ // before X calls `DecrementCount()` is visible to Y after Y returns
+ // from `Wait()`.
+ void Wait();
+
+ private:
+ Mutex lock_;
+ int count_ GUARDED_BY(lock_);
+ int num_waiting_ GUARDED_BY(lock_);
+};
+
+} // namespace absl
+#endif // ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_
diff --git a/absl/synchronization/blocking_counter_test.cc b/absl/synchronization/blocking_counter_test.cc
new file mode 100644
index 0000000..b4b6677
--- /dev/null
+++ b/absl/synchronization/blocking_counter_test.cc
@@ -0,0 +1,67 @@
+// 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/synchronization/blocking_counter.h"
+
+#include <functional>
+#include <memory>
+#include <thread> // NOLINT(build/c++11)
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/time/clock.h"
+
+namespace absl {
+namespace {
+
+void PauseAndDecreaseCounter(BlockingCounter* counter, int* done) {
+ absl::SleepFor(absl::Seconds(1));
+ *done = 1;
+ counter->DecrementCount();
+}
+
+TEST(BlockingCounterTest, BasicFunctionality) {
+ // This test verifies that BlockingCounter functions correctly. Starts a
+ // number of threads that just sleep for a second and decrement a counter.
+
+ // Initialize the counter.
+ const int num_workers = 10;
+ BlockingCounter counter(num_workers);
+
+ std::vector<std::thread> workers;
+ std::vector<int> done(num_workers, 0);
+
+ // Start a number of parallel tasks that will just wait for a seconds and
+ // then decrement the count.
+ workers.reserve(num_workers);
+ for (int k = 0; k < num_workers; k++) {
+ workers.emplace_back(
+ [&counter, &done, k] { PauseAndDecreaseCounter(&counter, &done[k]); });
+ }
+
+ // Wait for the threads to have all finished.
+ counter.Wait();
+
+ // Check that all the workers have completed.
+ for (int k = 0; k < num_workers; k++) {
+ EXPECT_EQ(1, done[k]);
+ }
+
+ for (std::thread& w : workers) {
+ w.join();
+ }
+}
+
+} // namespace
+} // namespace absl
diff --git a/absl/synchronization/internal/create_thread_identity.cc b/absl/synchronization/internal/create_thread_identity.cc
new file mode 100644
index 0000000..1497634
--- /dev/null
+++ b/absl/synchronization/internal/create_thread_identity.cc
@@ -0,0 +1,110 @@
+// 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 no-op if the required LowLevelAlloc support is missing.
+#include "absl/base/internal/low_level_alloc.h"
+#ifndef ABSL_LOW_LEVEL_ALLOC_MISSING
+
+#include <string.h>
+#include <atomic>
+#include <memory>
+
+#include "absl/base/internal/spinlock.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/per_thread_sem.h"
+
+namespace absl {
+namespace synchronization_internal {
+
+// ThreadIdentity storage is persistent, we maintain a free-list of previously
+// released ThreadIdentity objects.
+static base_internal::SpinLock freelist_lock(base_internal::kLinkerInitialized);
+static base_internal::ThreadIdentity* thread_identity_freelist;
+
+// A per-thread destructor for reclaiming associated ThreadIdentity objects.
+// Since we must preserve their storage we cache them for re-use.
+static void ReclaimThreadIdentity(void* v) {
+ base_internal::ThreadIdentity* identity =
+ static_cast<base_internal::ThreadIdentity*>(v);
+
+ // all_locks might have been allocated by the Mutex implementation.
+ // We free it here when we are notified that our thread is dying.
+ if (identity->per_thread_synch.all_locks != nullptr) {
+ base_internal::LowLevelAlloc::Free(identity->per_thread_synch.all_locks);
+ }
+
+ // We must explicitly clear the current thread's identity:
+ // (a) Subsequent (unrelated) per-thread destructors may require an identity.
+ // We must guarantee a new identity is used in this case (this instructor
+ // will be reinvoked up to PTHREAD_DESTRUCTOR_ITERATIONS in this case).
+ // (b) ThreadIdentity implementations may depend on memory that is not
+ // reinitialized before reuse. We must allow explicit clearing of the
+ // association state in this case.
+ base_internal::ClearCurrentThreadIdentity();
+ {
+ base_internal::SpinLockHolder l(&freelist_lock);
+ identity->next = thread_identity_freelist;
+ thread_identity_freelist = identity;
+ }
+}
+
+// Return value rounded up to next multiple of align.
+// Align must be a power of two.
+static intptr_t RoundUp(intptr_t addr, intptr_t align) {
+ return (addr + align - 1) & ~(align - 1);
+}
+
+static base_internal::ThreadIdentity* NewThreadIdentity() {
+ base_internal::ThreadIdentity* identity = nullptr;
+
+ {
+ // Re-use a previously released object if possible.
+ base_internal::SpinLockHolder l(&freelist_lock);
+ if (thread_identity_freelist) {
+ identity = thread_identity_freelist; // Take list-head.
+ thread_identity_freelist = thread_identity_freelist->next;
+ }
+ }
+
+ if (identity == nullptr) {
+ // Allocate enough space to align ThreadIdentity to a multiple of
+ // PerThreadSynch::kAlignment. This space is never released (it is
+ // added to a freelist by ReclaimThreadIdentity instead).
+ void* allocation = base_internal::LowLevelAlloc::Alloc(
+ sizeof(*identity) + base_internal::PerThreadSynch::kAlignment - 1);
+ // Round up the address to the required alignment.
+ identity = reinterpret_cast<base_internal::ThreadIdentity*>(
+ RoundUp(reinterpret_cast<intptr_t>(allocation),
+ base_internal::PerThreadSynch::kAlignment));
+ }
+ memset(identity, 0, sizeof(*identity));
+
+ return identity;
+}
+
+// Allocates and attaches ThreadIdentity object for the calling thread. Returns
+// the new identity.
+// REQUIRES: CurrentThreadIdentity(false) == nullptr
+base_internal::ThreadIdentity* CreateThreadIdentity() {
+ base_internal::ThreadIdentity* identity = NewThreadIdentity();
+ PerThreadSem::Init(identity);
+ // Associate the value with the current thread, and attach our destructor.
+ base_internal::SetCurrentThreadIdentity(identity, ReclaimThreadIdentity);
+ return identity;
+}
+
+} // namespace synchronization_internal
+} // namespace absl
+
+#endif // ABSL_LOW_LEVEL_ALLOC_MISSING
diff --git a/absl/synchronization/internal/create_thread_identity.h b/absl/synchronization/internal/create_thread_identity.h
new file mode 100644
index 0000000..1bb87de
--- /dev/null
+++ b/absl/synchronization/internal/create_thread_identity.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+// Interface for getting the current ThreadIdentity, creating one if necessary.
+// See thread_identity.h.
+//
+// This file is separate from thread_identity.h because creating a new
+// ThreadIdentity requires slightly higher level libraries (per_thread_sem
+// and low_level_alloc) than accessing an existing one. This separation allows
+// us to have a smaller //absl/base:base.
+
+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_CREATE_THREAD_IDENTITY_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_CREATE_THREAD_IDENTITY_H_
+
+#include "absl/base/internal/thread_identity.h"
+#include "absl/base/port.h"
+
+namespace absl {
+namespace synchronization_internal {
+
+// Allocates and attaches a ThreadIdentity object for the calling thread.
+// For private use only.
+base_internal::ThreadIdentity* CreateThreadIdentity();
+
+// 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 for the calling thread, allocate it now.
+inline base_internal::ThreadIdentity* GetOrCreateCurrentThreadIdentity() {
+ base_internal::ThreadIdentity* identity =
+ base_internal::CurrentThreadIdentityIfPresent();
+ if (ABSL_PREDICT_FALSE(identity == nullptr)) {
+ return CreateThreadIdentity();
+ }
+ return identity;
+}
+
+} // namespace synchronization_internal
+} // namespace absl
+#endif // ABSL_SYNCHRONIZATION_INTERNAL_CREATE_THREAD_IDENTITY_H_
diff --git a/absl/synchronization/internal/graphcycles.cc b/absl/synchronization/internal/graphcycles.cc
new file mode 100644
index 0000000..d7ae0cf
--- /dev/null
+++ b/absl/synchronization/internal/graphcycles.cc
@@ -0,0 +1,709 @@
+// 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.
+
+// GraphCycles provides incremental cycle detection on a dynamic
+// graph using the following algorithm:
+//
+// A dynamic topological sort algorithm for directed acyclic graphs
+// David J. Pearce, Paul H. J. Kelly
+// Journal of Experimental Algorithmics (JEA) JEA Homepage archive
+// Volume 11, 2006, Article No. 1.7
+//
+// Brief summary of the algorithm:
+//
+// (1) Maintain a rank for each node that is consistent
+// with the topological sort of the graph. I.e., path from x to y
+// implies rank[x] < rank[y].
+// (2) When a new edge (x->y) is inserted, do nothing if rank[x] < rank[y].
+// (3) Otherwise: adjust ranks in the neighborhood of x and y.
+
+// This file is a no-op if the required LowLevelAlloc support is missing.
+#include "absl/base/internal/low_level_alloc.h"
+#ifndef ABSL_LOW_LEVEL_ALLOC_MISSING
+
+#include "absl/synchronization/internal/graphcycles.h"
+
+#include <algorithm>
+#include <array>
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/spinlock.h"
+
+// Do not use STL. This module does not use standard memory allocation.
+
+namespace absl {
+namespace synchronization_internal {
+
+namespace {
+
+// Avoid LowLevelAlloc's default arena since it calls malloc hooks in
+// which people are doing things like acquiring Mutexes.
+static absl::base_internal::SpinLock arena_mu(
+ absl::base_internal::kLinkerInitialized);
+static base_internal::LowLevelAlloc::Arena* arena;
+
+static void InitArenaIfNecessary() {
+ arena_mu.Lock();
+ if (arena == nullptr) {
+ arena = base_internal::LowLevelAlloc::NewArena(
+ 0, base_internal::LowLevelAlloc::DefaultArena());
+ }
+ arena_mu.Unlock();
+}
+
+// Number of inlined elements in Vec. Hash table implementation
+// relies on this being a power of two.
+static const uint32_t kInline = 8;
+
+// A simple LowLevelAlloc based resizable vector with inlined storage
+// for a few elements. T must be a plain type since constructor
+// and destructor are not run on elements of type T managed by Vec.
+template <typename T>
+class Vec {
+ public:
+ Vec() { Init(); }
+ ~Vec() { Discard(); }
+
+ void clear() {
+ Discard();
+ Init();
+ }
+
+ bool empty() const { return size_ == 0; }
+ uint32_t size() const { return size_; }
+ T* begin() { return ptr_; }
+ T* end() { return ptr_ + size_; }
+ const T& operator[](uint32_t i) const { return ptr_[i]; }
+ T& operator[](uint32_t i) { return ptr_[i]; }
+ const T& back() const { return ptr_[size_-1]; }
+ void pop_back() { size_--; }
+
+ void push_back(const T& v) {
+ if (size_ == capacity_) Grow(size_ + 1);
+ ptr_[size_] = v;
+ size_++;
+ }
+
+ void resize(uint32_t n) {
+ if (n > capacity_) Grow(n);
+ size_ = n;
+ }
+
+ void fill(const T& val) {
+ for (uint32_t i = 0; i < size(); i++) {
+ ptr_[i] = val;
+ }
+ }
+
+ // Guarantees src is empty at end.
+ // Provided for the hash table resizing code below.
+ void MoveFrom(Vec<T>* src) {
+ if (src->ptr_ == src->space_) {
+ // Need to actually copy
+ resize(src->size_);
+ std::copy(src->ptr_, src->ptr_ + src->size_, ptr_);
+ src->size_ = 0;
+ } else {
+ Discard();
+ ptr_ = src->ptr_;
+ size_ = src->size_;
+ capacity_ = src->capacity_;
+ src->Init();
+ }
+ }
+
+ private:
+ T* ptr_;
+ T space_[kInline];
+ uint32_t size_;
+ uint32_t capacity_;
+
+ void Init() {
+ ptr_ = space_;
+ size_ = 0;
+ capacity_ = kInline;
+ }
+
+ void Discard() {
+ if (ptr_ != space_) base_internal::LowLevelAlloc::Free(ptr_);
+ }
+
+ void Grow(uint32_t n) {
+ while (capacity_ < n) {
+ capacity_ *= 2;
+ }
+ size_t request = static_cast<size_t>(capacity_) * sizeof(T);
+ T* copy = static_cast<T*>(
+ base_internal::LowLevelAlloc::AllocWithArena(request, arena));
+ std::copy(ptr_, ptr_ + size_, copy);
+ Discard();
+ ptr_ = copy;
+ }
+
+ Vec(const Vec&) = delete;
+ Vec& operator=(const Vec&) = delete;
+};
+
+// A hash set of non-negative int32_t that uses Vec for its underlying storage.
+class NodeSet {
+ public:
+ NodeSet() { Init(); }
+
+ void clear() { Init(); }
+ bool contains(int32_t v) const { return table_[FindIndex(v)] == v; }
+
+ bool insert(int32_t v) {
+ uint32_t i = FindIndex(v);
+ if (table_[i] == v) {
+ return false;
+ }
+ if (table_[i] == kEmpty) {
+ // Only inserting over an empty cell increases the number of occupied
+ // slots.
+ occupied_++;
+ }
+ table_[i] = v;
+ // Double when 75% full.
+ if (occupied_ >= table_.size() - table_.size()/4) Grow();
+ return true;
+ }
+
+ void erase(uint32_t v) {
+ uint32_t i = FindIndex(v);
+ if (static_cast<uint32_t>(table_[i]) == v) {
+ table_[i] = kDel;
+ }
+ }
+
+ // Iteration: is done via HASH_FOR_EACH
+ // Example:
+ // HASH_FOR_EACH(elem, node->out) { ... }
+#define HASH_FOR_EACH(elem, eset) \
+ for (int32_t elem, _cursor = 0; (eset).Next(&_cursor, &elem); )
+ bool Next(int32_t* cursor, int32_t* elem) {
+ while (static_cast<uint32_t>(*cursor) < table_.size()) {
+ int32_t v = table_[*cursor];
+ (*cursor)++;
+ if (v >= 0) {
+ *elem = v;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private:
+ static const int32_t kEmpty;
+ static const int32_t kDel;
+ Vec<int32_t> table_;
+ uint32_t occupied_; // Count of non-empty slots (includes deleted slots)
+
+ static uint32_t Hash(uint32_t a) { return a * 41; }
+
+ // Return index for storing v. May return an empty index or deleted index
+ int FindIndex(int32_t v) const {
+ // Search starting at hash index.
+ const uint32_t mask = table_.size() - 1;
+ uint32_t i = Hash(v) & mask;
+ int deleted_index = -1; // If >= 0, index of first deleted element we see
+ while (true) {
+ int32_t e = table_[i];
+ if (v == e) {
+ return i;
+ } else if (e == kEmpty) {
+ // Return any previously encountered deleted slot.
+ return (deleted_index >= 0) ? deleted_index : i;
+ } else if (e == kDel && deleted_index < 0) {
+ // Keep searching since v might be present later.
+ deleted_index = i;
+ }
+ i = (i + 1) & mask; // Linear probing; quadratic is slightly slower.
+ }
+ }
+
+ void Init() {
+ table_.clear();
+ table_.resize(kInline);
+ table_.fill(kEmpty);
+ occupied_ = 0;
+ }
+
+ void Grow() {
+ Vec<int32_t> copy;
+ copy.MoveFrom(&table_);
+ occupied_ = 0;
+ table_.resize(copy.size() * 2);
+ table_.fill(kEmpty);
+
+ for (const auto& e : copy) {
+ if (e >= 0) insert(e);
+ }
+ }
+
+ NodeSet(const NodeSet&) = delete;
+ NodeSet& operator=(const NodeSet&) = delete;
+};
+
+const int32_t NodeSet::kEmpty = -1;
+const int32_t NodeSet::kDel = -2;
+
+// We encode a node index and a node version in GraphId. The version
+// number is incremented when the GraphId is freed which automatically
+// invalidates all copies of the GraphId.
+
+inline GraphId MakeId(int32_t index, uint32_t version) {
+ GraphId g;
+ g.handle =
+ (static_cast<uint64_t>(version) << 32) | static_cast<uint32_t>(index);
+ return g;
+}
+
+inline int32_t NodeIndex(GraphId id) {
+ return static_cast<uint32_t>(id.handle & 0xfffffffful);
+}
+
+inline uint32_t NodeVersion(GraphId id) {
+ return static_cast<uint32_t>(id.handle >> 32);
+}
+
+// We need to hide Mutexes (or other deadlock detection's pointers)
+// from the leak detector. Xor with an arbitrary number with high bits set.
+static const uintptr_t kHideMask = static_cast<uintptr_t>(0xF03A5F7BF03A5F7Bll);
+
+static inline uintptr_t MaskPtr(void *ptr) {
+ return reinterpret_cast<uintptr_t>(ptr) ^ kHideMask;
+}
+
+static inline void* UnmaskPtr(uintptr_t word) {
+ return reinterpret_cast<void*>(word ^ kHideMask);
+}
+
+struct Node {
+ int32_t rank; // rank number assigned by Pearce-Kelly algorithm
+ uint32_t version; // Current version number
+ int32_t next_hash; // Next entry in hash table
+ bool visited; // Temporary marker used by depth-first-search
+ uintptr_t masked_ptr; // User-supplied pointer
+ NodeSet in; // List of immediate predecessor nodes in graph
+ NodeSet out; // List of immediate successor nodes in graph
+ int priority; // Priority of recorded stack trace.
+ int nstack; // Depth of recorded stack trace.
+ void* stack[40]; // stack[0,nstack-1] holds stack trace for node.
+};
+
+// Hash table for pointer to node index lookups.
+class PointerMap {
+ public:
+ explicit PointerMap(const Vec<Node*>* nodes) : nodes_(nodes) {
+ table_.fill(-1);
+ }
+
+ int32_t Find(void* ptr) {
+ auto masked = MaskPtr(ptr);
+ for (int32_t i = table_[Hash(ptr)]; i != -1;) {
+ Node* n = (*nodes_)[i];
+ if (n->masked_ptr == masked) return i;
+ i = n->next_hash;
+ }
+ return -1;
+ }
+
+ void Add(void* ptr, int32_t i) {
+ int32_t* head = &table_[Hash(ptr)];
+ (*nodes_)[i]->next_hash = *head;
+ *head = i;
+ }
+
+ int32_t Remove(void* ptr) {
+ // Advance through linked list while keeping track of the
+ // predecessor slot that points to the current entry.
+ auto masked = MaskPtr(ptr);
+ for (int32_t* slot = &table_[Hash(ptr)]; *slot != -1; ) {
+ int32_t index = *slot;
+ Node* n = (*nodes_)[index];
+ if (n->masked_ptr == masked) {
+ *slot = n->next_hash; // Remove n from linked list
+ n->next_hash = -1;
+ return index;
+ }
+ slot = &n->next_hash;
+ }
+ return -1;
+ }
+
+ private:
+ // Number of buckets in hash table for pointer lookups.
+ static constexpr uint32_t kHashTableSize = 8171; // should be prime
+
+ const Vec<Node*>* nodes_;
+ std::array<int32_t, kHashTableSize> table_;
+
+ static uint32_t Hash(void* ptr) {
+ return reinterpret_cast<uintptr_t>(ptr) % kHashTableSize;
+ }
+};
+
+} // namespace
+
+struct GraphCycles::Rep {
+ Vec<Node*> nodes_;
+ Vec<int32_t> free_nodes_; // Indices for unused entries in nodes_
+ PointerMap ptrmap_;
+
+ // Temporary state.
+ Vec<int32_t> deltaf_; // Results of forward DFS
+ Vec<int32_t> deltab_; // Results of backward DFS
+ Vec<int32_t> list_; // All nodes to reprocess
+ Vec<int32_t> merged_; // Rank values to assign to list_ entries
+ Vec<int32_t> stack_; // Emulates recursion stack for depth-first searches
+
+ Rep() : ptrmap_(&nodes_) {}
+};
+
+static Node* FindNode(GraphCycles::Rep* rep, GraphId id) {
+ Node* n = rep->nodes_[NodeIndex(id)];
+ return (n->version == NodeVersion(id)) ? n : nullptr;
+}
+
+GraphCycles::GraphCycles() {
+ InitArenaIfNecessary();
+ rep_ = new (base_internal::LowLevelAlloc::AllocWithArena(sizeof(Rep), arena))
+ Rep;
+}
+
+GraphCycles::~GraphCycles() {
+ for (auto* node : rep_->nodes_) {
+ node->Node::~Node();
+ base_internal::LowLevelAlloc::Free(node);
+ }
+ rep_->Rep::~Rep();
+ base_internal::LowLevelAlloc::Free(rep_);
+}
+
+bool GraphCycles::CheckInvariants() const {
+ Rep* r = rep_;
+ NodeSet ranks; // Set of ranks seen so far.
+ for (uint32_t x = 0; x < r->nodes_.size(); x++) {
+ Node* nx = r->nodes_[x];
+ void* ptr = UnmaskPtr(nx->masked_ptr);
+ if (ptr != nullptr && static_cast<uint32_t>(r->ptrmap_.Find(ptr)) != x) {
+ ABSL_RAW_LOG(FATAL, "Did not find live node in hash table %u %p", x, ptr);
+ }
+ if (nx->visited) {
+ ABSL_RAW_LOG(FATAL, "Did not clear visited marker on node %u", x);
+ }
+ if (!ranks.insert(nx->rank)) {
+ ABSL_RAW_LOG(FATAL, "Duplicate occurrence of rank %d", nx->rank);
+ }
+ HASH_FOR_EACH(y, nx->out) {
+ Node* ny = r->nodes_[y];
+ if (nx->rank >= ny->rank) {
+ ABSL_RAW_LOG(FATAL, "Edge %u->%d has bad rank assignment %d->%d", x, y,
+ nx->rank, ny->rank);
+ }
+ }
+ }
+ return true;
+}
+
+GraphId GraphCycles::GetId(void* ptr) {
+ int32_t i = rep_->ptrmap_.Find(ptr);
+ if (i != -1) {
+ return MakeId(i, rep_->nodes_[i]->version);
+ } else if (rep_->free_nodes_.empty()) {
+ Node* n =
+ new (base_internal::LowLevelAlloc::AllocWithArena(sizeof(Node), arena))
+ Node;
+ n->version = 1; // Avoid 0 since it is used by InvalidGraphId()
+ n->visited = false;
+ n->rank = rep_->nodes_.size();
+ n->masked_ptr = MaskPtr(ptr);
+ n->nstack = 0;
+ n->priority = 0;
+ rep_->nodes_.push_back(n);
+ rep_->ptrmap_.Add(ptr, n->rank);
+ return MakeId(n->rank, n->version);
+ } else {
+ // Preserve preceding rank since the set of ranks in use must be
+ // a permutation of [0,rep_->nodes_.size()-1].
+ int32_t r = rep_->free_nodes_.back();
+ rep_->free_nodes_.pop_back();
+ Node* n = rep_->nodes_[r];
+ n->masked_ptr = MaskPtr(ptr);
+ n->nstack = 0;
+ n->priority = 0;
+ rep_->ptrmap_.Add(ptr, r);
+ return MakeId(r, n->version);
+ }
+}
+
+void GraphCycles::RemoveNode(void* ptr) {
+ int32_t i = rep_->ptrmap_.Remove(ptr);
+ if (i == -1) {
+ return;
+ }
+ Node* x = rep_->nodes_[i];
+ HASH_FOR_EACH(y, x->out) {
+ rep_->nodes_[y]->in.erase(i);
+ }
+ HASH_FOR_EACH(y, x->in) {
+ rep_->nodes_[y]->out.erase(i);
+ }
+ x->in.clear();
+ x->out.clear();
+ x->masked_ptr = MaskPtr(nullptr);
+ if (x->version == std::numeric_limits<uint32_t>::max()) {
+ // Cannot use x any more
+ } else {
+ x->version++; // Invalidates all copies of node.
+ rep_->free_nodes_.push_back(i);
+ }
+}
+
+void* GraphCycles::Ptr(GraphId id) {
+ Node* n = FindNode(rep_, id);
+ return n == nullptr ? nullptr : UnmaskPtr(n->masked_ptr);
+}
+
+bool GraphCycles::HasNode(GraphId node) {
+ return FindNode(rep_, node) != nullptr;
+}
+
+bool GraphCycles::HasEdge(GraphId x, GraphId y) const {
+ Node* xn = FindNode(rep_, x);
+ return xn && FindNode(rep_, y) && xn->out.contains(NodeIndex(y));
+}
+
+void GraphCycles::RemoveEdge(GraphId x, GraphId y) {
+ Node* xn = FindNode(rep_, x);
+ Node* yn = FindNode(rep_, y);
+ if (xn && yn) {
+ xn->out.erase(NodeIndex(y));
+ yn->in.erase(NodeIndex(x));
+ // No need to update the rank assignment since a previous valid
+ // rank assignment remains valid after an edge deletion.
+ }
+}
+
+static bool ForwardDFS(GraphCycles::Rep* r, int32_t n, int32_t upper_bound);
+static void BackwardDFS(GraphCycles::Rep* r, int32_t n, int32_t lower_bound);
+static void Reorder(GraphCycles::Rep* r);
+static void Sort(const Vec<Node*>&, Vec<int32_t>* delta);
+static void MoveToList(
+ GraphCycles::Rep* r, Vec<int32_t>* src, Vec<int32_t>* dst);
+
+bool GraphCycles::InsertEdge(GraphId idx, GraphId idy) {
+ Rep* r = rep_;
+ const int32_t x = NodeIndex(idx);
+ const int32_t y = NodeIndex(idy);
+ Node* nx = FindNode(r, idx);
+ Node* ny = FindNode(r, idy);
+ if (nx == nullptr || ny == nullptr) return true; // Expired ids
+
+ if (nx == ny) return false; // Self edge
+ if (!nx->out.insert(y)) {
+ // Edge already exists.
+ return true;
+ }
+
+ ny->in.insert(x);
+
+ if (nx->rank <= ny->rank) {
+ // New edge is consistent with existing rank assignment.
+ return true;
+ }
+
+ // Current rank assignments are incompatible with the new edge. Recompute.
+ // We only need to consider nodes that fall in the range [ny->rank,nx->rank].
+ if (!ForwardDFS(r, y, nx->rank)) {
+ // Found a cycle. Undo the insertion and tell caller.
+ nx->out.erase(y);
+ ny->in.erase(x);
+ // Since we do not call Reorder() on this path, clear any visited
+ // markers left by ForwardDFS.
+ for (const auto& d : r->deltaf_) {
+ r->nodes_[d]->visited = false;
+ }
+ return false;
+ }
+ BackwardDFS(r, x, ny->rank);
+ Reorder(r);
+ return true;
+}
+
+static bool ForwardDFS(GraphCycles::Rep* r, int32_t n, int32_t upper_bound) {
+ // Avoid recursion since stack space might be limited.
+ // We instead keep a stack of nodes to visit.
+ r->deltaf_.clear();
+ r->stack_.clear();
+ r->stack_.push_back(n);
+ while (!r->stack_.empty()) {
+ n = r->stack_.back();
+ r->stack_.pop_back();
+ Node* nn = r->nodes_[n];
+ if (nn->visited) continue;
+
+ nn->visited = true;
+ r->deltaf_.push_back(n);
+
+ HASH_FOR_EACH(w, nn->out) {
+ Node* nw = r->nodes_[w];
+ if (nw->rank == upper_bound) {
+ return false; // Cycle
+ }
+ if (!nw->visited && nw->rank < upper_bound) {
+ r->stack_.push_back(w);
+ }
+ }
+ }
+ return true;
+}
+
+static void BackwardDFS(GraphCycles::Rep* r, int32_t n, int32_t lower_bound) {
+ r->deltab_.clear();
+ r->stack_.clear();
+ r->stack_.push_back(n);
+ while (!r->stack_.empty()) {
+ n = r->stack_.back();
+ r->stack_.pop_back();
+ Node* nn = r->nodes_[n];
+ if (nn->visited) continue;
+
+ nn->visited = true;
+ r->deltab_.push_back(n);
+
+ HASH_FOR_EACH(w, nn->in) {
+ Node* nw = r->nodes_[w];
+ if (!nw->visited && lower_bound < nw->rank) {
+ r->stack_.push_back(w);
+ }
+ }
+ }
+}
+
+static void Reorder(GraphCycles::Rep* r) {
+ Sort(r->nodes_, &r->deltab_);
+ Sort(r->nodes_, &r->deltaf_);
+
+ // Adds contents of delta lists to list_ (backwards deltas first).
+ r->list_.clear();
+ MoveToList(r, &r->deltab_, &r->list_);
+ MoveToList(r, &r->deltaf_, &r->list_);
+
+ // Produce sorted list of all ranks that will be reassigned.
+ r->merged_.resize(r->deltab_.size() + r->deltaf_.size());
+ std::merge(r->deltab_.begin(), r->deltab_.end(),
+ r->deltaf_.begin(), r->deltaf_.end(),
+ r->merged_.begin());
+
+ // Assign the ranks in order to the collected list.
+ for (uint32_t i = 0; i < r->list_.size(); i++) {
+ r->nodes_[r->list_[i]]->rank = r->merged_[i];
+ }
+}
+
+static void Sort(const Vec<Node*>& nodes, Vec<int32_t>* delta) {
+ struct ByRank {
+ const Vec<Node*>* nodes;
+ bool operator()(int32_t a, int32_t b) const {
+ return (*nodes)[a]->rank < (*nodes)[b]->rank;
+ }
+ };
+ ByRank cmp;
+ cmp.nodes = &nodes;
+ std::sort(delta->begin(), delta->end(), cmp);
+}
+
+static void MoveToList(
+ GraphCycles::Rep* r, Vec<int32_t>* src, Vec<int32_t>* dst) {
+ for (auto& v : *src) {
+ int32_t w = v;
+ v = r->nodes_[w]->rank; // Replace v entry with its rank
+ r->nodes_[w]->visited = false; // Prepare for future DFS calls
+ dst->push_back(w);
+ }
+}
+
+int GraphCycles::FindPath(GraphId idx, GraphId idy, int max_path_len,
+ GraphId path[]) const {
+ Rep* r = rep_;
+ if (FindNode(r, idx) == nullptr || FindNode(r, idy) == nullptr) return 0;
+ const int32_t x = NodeIndex(idx);
+ const int32_t y = NodeIndex(idy);
+
+ // Forward depth first search starting at x until we hit y.
+ // As we descend into a node, we push it onto the path.
+ // As we leave a node, we remove it from the path.
+ int path_len = 0;
+
+ NodeSet seen;
+ r->stack_.clear();
+ r->stack_.push_back(x);
+ while (!r->stack_.empty()) {
+ int32_t n = r->stack_.back();
+ r->stack_.pop_back();
+ if (n < 0) {
+ // Marker to indicate that we are leaving a node
+ path_len--;
+ continue;
+ }
+
+ if (path_len < max_path_len) {
+ path[path_len] = MakeId(n, rep_->nodes_[n]->version);
+ }
+ path_len++;
+ r->stack_.push_back(-1); // Will remove tentative path entry
+
+ if (n == y) {
+ return path_len;
+ }
+
+ HASH_FOR_EACH(w, r->nodes_[n]->out) {
+ if (seen.insert(w)) {
+ r->stack_.push_back(w);
+ }
+ }
+ }
+
+ return 0;
+}
+
+bool GraphCycles::IsReachable(GraphId x, GraphId y) const {
+ return FindPath(x, y, 0, nullptr) > 0;
+}
+
+void GraphCycles::UpdateStackTrace(GraphId id, int priority,
+ int (*get_stack_trace)(void** stack, int)) {
+ Node* n = FindNode(rep_, id);
+ if (n == nullptr || n->priority >= priority) {
+ return;
+ }
+ n->nstack = (*get_stack_trace)(n->stack, ABSL_ARRAYSIZE(n->stack));
+ n->priority = priority;
+}
+
+int GraphCycles::GetStackTrace(GraphId id, void*** ptr) {
+ Node* n = FindNode(rep_, id);
+ if (n == nullptr) {
+ *ptr = nullptr;
+ return 0;
+ } else {
+ *ptr = n->stack;
+ return n->nstack;
+ }
+}
+
+} // namespace synchronization_internal
+} // namespace absl
+
+#endif // ABSL_LOW_LEVEL_ALLOC_MISSING
diff --git a/absl/synchronization/internal/graphcycles.h b/absl/synchronization/internal/graphcycles.h
new file mode 100644
index 0000000..53474b7
--- /dev/null
+++ b/absl/synchronization/internal/graphcycles.h
@@ -0,0 +1,136 @@
+// 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_SYNCHRONIZATION_INTERNAL_GRAPHCYCLES_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_GRAPHCYCLES_H_
+
+// GraphCycles detects the introduction of a cycle into a directed
+// graph that is being built up incrementally.
+//
+// Nodes are identified by small integers. It is not possible to
+// record multiple edges with the same (source, destination) pair;
+// requests to add an edge where one already exists are silently
+// ignored.
+//
+// It is also not possible to introduce a cycle; an attempt to insert
+// an edge that would introduce a cycle fails and returns false.
+//
+// GraphCycles uses no internal locking; calls into it should be
+// serialized externally.
+
+// Performance considerations:
+// Works well on sparse graphs, poorly on dense graphs.
+// Extra information is maintained incrementally to detect cycles quickly.
+// InsertEdge() is very fast when the edge already exists, and reasonably fast
+// otherwise.
+// FindPath() is linear in the size of the graph.
+// The current implemenation uses O(|V|+|E|) space.
+
+#include <cstdint>
+
+namespace absl {
+namespace synchronization_internal {
+
+// Opaque identifier for a graph node.
+struct GraphId {
+ uint64_t handle;
+
+ bool operator==(const GraphId& x) const { return handle == x.handle; }
+ bool operator!=(const GraphId& x) const { return handle != x.handle; }
+};
+
+// Return an invalid graph id that will never be assigned by GraphCycles.
+inline GraphId InvalidGraphId() {
+ return GraphId{0};
+}
+
+class GraphCycles {
+ public:
+ GraphCycles();
+ ~GraphCycles();
+
+ // Return the id to use for ptr, assigning one if necessary.
+ // Subsequent calls with the same ptr value will return the same id
+ // until Remove().
+ GraphId GetId(void* ptr);
+
+ // Remove "ptr" from the graph. Its corresponding node and all
+ // edges to and from it are removed.
+ void RemoveNode(void* ptr);
+
+ // Return the pointer associated with id, or nullptr if id is not
+ // currently in the graph.
+ void* Ptr(GraphId id);
+
+ // Attempt to insert an edge from source_node to dest_node. If the
+ // edge would introduce a cycle, return false without making any
+ // changes. Otherwise add the edge and return true.
+ bool InsertEdge(GraphId source_node, GraphId dest_node);
+
+ // Remove any edge that exists from source_node to dest_node.
+ void RemoveEdge(GraphId source_node, GraphId dest_node);
+
+ // Return whether node exists in the graph.
+ bool HasNode(GraphId node);
+
+ // Return whether there is an edge directly from source_node to dest_node.
+ bool HasEdge(GraphId source_node, GraphId dest_node) const;
+
+ // Return whether dest_node is reachable from source_node
+ // by following edges.
+ bool IsReachable(GraphId source_node, GraphId dest_node) const;
+
+ // Find a path from "source" to "dest". If such a path exists,
+ // place the nodes on the path in the array path[], and return
+ // the number of nodes on the path. If the path is longer than
+ // max_path_len nodes, only the first max_path_len nodes are placed
+ // in path[]. The client should compare the return value with
+ // max_path_len" to see when this occurs. If no path exists, return
+ // 0. Any valid path stored in path[] will start with "source" and
+ // end with "dest". There is no guarantee that the path is the
+ // shortest, but no node will appear twice in the path, except the
+ // source and destination node if they are identical; therefore, the
+ // return value is at most one greater than the number of nodes in
+ // the graph.
+ int FindPath(GraphId source, GraphId dest, int max_path_len,
+ GraphId path[]) const;
+
+ // Update the stack trace recorded for id with the current stack
+ // trace if the last time it was updated had a smaller priority
+ // than the priority passed on this call.
+ //
+ // *get_stack_trace is called to get the stack trace.
+ void UpdateStackTrace(GraphId id, int priority,
+ int (*get_stack_trace)(void**, int));
+
+ // Set *ptr to the beginning of the array that holds the recorded
+ // stack trace for id and return the depth of the stack trace.
+ int GetStackTrace(GraphId id, void*** ptr);
+
+ // Check internal invariants. Crashes on failure, returns true on success.
+ // Expensive: should only be called from graphcycles_test.cc.
+ bool CheckInvariants() const;
+
+ // ----------------------------------------------------
+ struct Rep;
+ private:
+ Rep *rep_; // opaque representation
+ GraphCycles(const GraphCycles&) = delete;
+ GraphCycles& operator=(const GraphCycles&) = delete;
+};
+
+} // namespace synchronization_internal
+} // namespace absl
+#endif
diff --git a/absl/synchronization/internal/graphcycles_test.cc b/absl/synchronization/internal/graphcycles_test.cc
new file mode 100644
index 0000000..734f277
--- /dev/null
+++ b/absl/synchronization/internal/graphcycles_test.cc
@@ -0,0 +1,471 @@
+// 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.
+
+// Copyright 2007 Google, Inc.
+// All rights reserved.
+
+// Author: Mike Burrows
+
+// A test for the GraphCycles interface.
+
+// This test is testing a component of //third_party/absl. As written it
+// heavily uses logging, including VLOG, so this test can't ship with Abseil.
+// We're leaving it here until Abseil gets base/logging.h in a future release.
+#include "absl/synchronization/internal/graphcycles.h"
+
+#include <map>
+#include <random>
+#include <vector>
+#include <unordered_set>
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
+
+namespace absl {
+namespace synchronization_internal {
+
+// We emulate a GraphCycles object with a node vector and an edge vector.
+// We then compare the two implementations.
+
+using Nodes = std::vector<int>;
+struct Edge {
+ int from;
+ int to;
+};
+using Edges = std::vector<Edge>;
+using RandomEngine = std::mt19937_64;
+
+// Mapping from integer index to GraphId.
+typedef std::map<int, GraphId> IdMap;
+static GraphId Get(const IdMap& id, int num) {
+ auto iter = id.find(num);
+ return (iter == id.end()) ? InvalidGraphId() : iter->second;
+}
+
+// Return whether "to" is reachable from "from".
+static bool IsReachable(Edges *edges, int from, int to,
+ std::unordered_set<int> *seen) {
+ seen->insert(from); // we are investigating "from"; don't do it again
+ if (from == to) return true;
+ for (const auto &edge : *edges) {
+ if (edge.from == from) {
+ if (edge.to == to) { // success via edge directly
+ return true;
+ } else if (seen->find(edge.to) == seen->end() && // success via edge
+ IsReachable(edges, edge.to, to, seen)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static void PrintEdges(Edges *edges) {
+ ABSL_RAW_LOG(INFO, "EDGES (%zu)", edges->size());
+ for (const auto &edge : *edges) {
+ int a = edge.from;
+ int b = edge.to;
+ ABSL_RAW_LOG(INFO, "%d %d", a, b);
+ }
+ ABSL_RAW_LOG(INFO, "---");
+}
+
+static void PrintGCEdges(Nodes *nodes, const IdMap &id, GraphCycles *gc) {
+ ABSL_RAW_LOG(INFO, "GC EDGES");
+ for (int a : *nodes) {
+ for (int b : *nodes) {
+ if (gc->HasEdge(Get(id, a), Get(id, b))) {
+ ABSL_RAW_LOG(INFO, "%d %d", a, b);
+ }
+ }
+ }
+ ABSL_RAW_LOG(INFO, "---");
+}
+
+static void PrintTransitiveClosure(Nodes *nodes, Edges *edges) {
+ ABSL_RAW_LOG(INFO, "Transitive closure");
+ for (int a : *nodes) {
+ for (int b : *nodes) {
+ std::unordered_set<int> seen;
+ if (IsReachable(edges, a, b, &seen)) {
+ ABSL_RAW_LOG(INFO, "%d %d", a, b);
+ }
+ }
+ }
+ ABSL_RAW_LOG(INFO, "---");
+}
+
+static void PrintGCTransitiveClosure(Nodes *nodes, const IdMap &id,
+ GraphCycles *gc) {
+ ABSL_RAW_LOG(INFO, "GC Transitive closure");
+ for (int a : *nodes) {
+ for (int b : *nodes) {
+ if (gc->IsReachable(Get(id, a), Get(id, b))) {
+ ABSL_RAW_LOG(INFO, "%d %d", a, b);
+ }
+ }
+ }
+ ABSL_RAW_LOG(INFO, "---");
+}
+
+static void CheckTransitiveClosure(Nodes *nodes, Edges *edges, const IdMap &id,
+ GraphCycles *gc) {
+ std::unordered_set<int> seen;
+ for (const auto &a : *nodes) {
+ for (const auto &b : *nodes) {
+ seen.clear();
+ bool gc_reachable = gc->IsReachable(Get(id, a), Get(id, b));
+ bool reachable = IsReachable(edges, a, b, &seen);
+ if (gc_reachable != reachable) {
+ PrintEdges(edges);
+ PrintGCEdges(nodes, id, gc);
+ PrintTransitiveClosure(nodes, edges);
+ PrintGCTransitiveClosure(nodes, id, gc);
+ ABSL_RAW_LOG(FATAL, "gc_reachable %s reachable %s a %d b %d",
+ gc_reachable ? "true" : "false",
+ reachable ? "true" : "false", a, b);
+ }
+ }
+ }
+}
+
+static void CheckEdges(Nodes *nodes, Edges *edges, const IdMap &id,
+ GraphCycles *gc) {
+ int count = 0;
+ for (const auto &edge : *edges) {
+ int a = edge.from;
+ int b = edge.to;
+ if (!gc->HasEdge(Get(id, a), Get(id, b))) {
+ PrintEdges(edges);
+ PrintGCEdges(nodes, id, gc);
+ ABSL_RAW_LOG(FATAL, "!gc->HasEdge(%d, %d)", a, b);
+ }
+ }
+ for (const auto &a : *nodes) {
+ for (const auto &b : *nodes) {
+ if (gc->HasEdge(Get(id, a), Get(id, b))) {
+ count++;
+ }
+ }
+ }
+ if (count != edges->size()) {
+ PrintEdges(edges);
+ PrintGCEdges(nodes, id, gc);
+ ABSL_RAW_LOG(FATAL, "edges->size() %zu count %d", edges->size(), count);
+ }
+}
+
+static void CheckInvariants(const GraphCycles &gc) {
+ if (ABSL_PREDICT_FALSE(!gc.CheckInvariants()))
+ ABSL_RAW_LOG(FATAL, "CheckInvariants");
+}
+
+// Returns the index of a randomly chosen node in *nodes.
+// Requires *nodes be non-empty.
+static int RandomNode(RandomEngine* rng, Nodes *nodes) {
+ std::uniform_int_distribution<int> uniform(0, nodes->size()-1);
+ return uniform(*rng);
+}
+
+// Returns the index of a randomly chosen edge in *edges.
+// Requires *edges be non-empty.
+static int RandomEdge(RandomEngine* rng, Edges *edges) {
+ std::uniform_int_distribution<int> uniform(0, edges->size()-1);
+ return uniform(*rng);
+}
+
+// Returns the index of edge (from, to) in *edges or -1 if it is not in *edges.
+static int EdgeIndex(Edges *edges, int from, int to) {
+ int i = 0;
+ while (i != edges->size() &&
+ ((*edges)[i].from != from || (*edges)[i].to != to)) {
+ i++;
+ }
+ return i == edges->size()? -1 : i;
+}
+
+TEST(GraphCycles, RandomizedTest) {
+ int next_node = 0;
+ Nodes nodes;
+ Edges edges; // from, to
+ IdMap id;
+ GraphCycles graph_cycles;
+ static const int kMaxNodes = 7; // use <= 7 nodes to keep test short
+ static const int kDataOffset = 17; // an offset to the node-specific data
+ int n = 100000;
+ int op = 0;
+ RandomEngine rng(testing::UnitTest::GetInstance()->random_seed());
+ std::uniform_int_distribution<int> uniform(0, 5);
+
+ auto ptr = [](intptr_t i) {
+ return reinterpret_cast<void*>(i + kDataOffset);
+ };
+
+ for (int iter = 0; iter != n; iter++) {
+ for (const auto &node : nodes) {
+ ASSERT_EQ(graph_cycles.Ptr(Get(id, node)), ptr(node)) << " node " << node;
+ }
+ CheckEdges(&nodes, &edges, id, &graph_cycles);
+ CheckTransitiveClosure(&nodes, &edges, id, &graph_cycles);
+ op = uniform(rng);
+ switch (op) {
+ case 0: // Add a node
+ if (nodes.size() < kMaxNodes) {
+ int new_node = next_node++;
+ GraphId new_gnode = graph_cycles.GetId(ptr(new_node));
+ ASSERT_NE(new_gnode, InvalidGraphId());
+ id[new_node] = new_gnode;
+ ASSERT_EQ(ptr(new_node), graph_cycles.Ptr(new_gnode));
+ nodes.push_back(new_node);
+ }
+ break;
+
+ case 1: // Remove a node
+ if (nodes.size() > 0) {
+ int node_index = RandomNode(&rng, &nodes);
+ int node = nodes[node_index];
+ nodes[node_index] = nodes.back();
+ nodes.pop_back();
+ graph_cycles.RemoveNode(ptr(node));
+ ASSERT_EQ(graph_cycles.Ptr(Get(id, node)), nullptr);
+ id.erase(node);
+ int i = 0;
+ while (i != edges.size()) {
+ if (edges[i].from == node || edges[i].to == node) {
+ edges[i] = edges.back();
+ edges.pop_back();
+ } else {
+ i++;
+ }
+ }
+ }
+ break;
+
+ case 2: // Add an edge
+ if (nodes.size() > 0) {
+ int from = RandomNode(&rng, &nodes);
+ int to = RandomNode(&rng, &nodes);
+ if (EdgeIndex(&edges, nodes[from], nodes[to]) == -1) {
+ if (graph_cycles.InsertEdge(id[nodes[from]], id[nodes[to]])) {
+ Edge new_edge;
+ new_edge.from = nodes[from];
+ new_edge.to = nodes[to];
+ edges.push_back(new_edge);
+ } else {
+ std::unordered_set<int> seen;
+ ASSERT_TRUE(IsReachable(&edges, nodes[to], nodes[from], &seen))
+ << "Edge " << nodes[to] << "->" << nodes[from];
+ }
+ }
+ }
+ break;
+
+ case 3: // Remove an edge
+ if (edges.size() > 0) {
+ int i = RandomEdge(&rng, &edges);
+ int from = edges[i].from;
+ int to = edges[i].to;
+ ASSERT_EQ(i, EdgeIndex(&edges, from, to));
+ edges[i] = edges.back();
+ edges.pop_back();
+ ASSERT_EQ(-1, EdgeIndex(&edges, from, to));
+ graph_cycles.RemoveEdge(id[from], id[to]);
+ }
+ break;
+
+ case 4: // Check a path
+ if (nodes.size() > 0) {
+ int from = RandomNode(&rng, &nodes);
+ int to = RandomNode(&rng, &nodes);
+ GraphId path[2*kMaxNodes];
+ int path_len = graph_cycles.FindPath(id[nodes[from]], id[nodes[to]],
+ ABSL_ARRAYSIZE(path), path);
+ std::unordered_set<int> seen;
+ bool reachable = IsReachable(&edges, nodes[from], nodes[to], &seen);
+ bool gc_reachable =
+ graph_cycles.IsReachable(Get(id, nodes[from]), Get(id, nodes[to]));
+ ASSERT_EQ(path_len != 0, reachable);
+ ASSERT_EQ(path_len != 0, gc_reachable);
+ // In the following line, we add one because a node can appear
+ // twice, if the path is from that node to itself, perhaps via
+ // every other node.
+ ASSERT_LE(path_len, kMaxNodes + 1);
+ if (path_len != 0) {
+ ASSERT_EQ(id[nodes[from]], path[0]);
+ ASSERT_EQ(id[nodes[to]], path[path_len-1]);
+ for (int i = 1; i < path_len; i++) {
+ ASSERT_TRUE(graph_cycles.HasEdge(path[i-1], path[i]));
+ }
+ }
+ }
+ break;
+
+ case 5: // Check invariants
+ CheckInvariants(graph_cycles);
+ break;
+
+ default:
+ ABSL_RAW_LOG(FATAL, "op %d", op);
+ }
+
+ // Very rarely, test graph expansion by adding then removing many nodes.
+ std::bernoulli_distribution one_in_1024(1.0 / 1024);
+ if (one_in_1024(rng)) {
+ CheckEdges(&nodes, &edges, id, &graph_cycles);
+ CheckTransitiveClosure(&nodes, &edges, id, &graph_cycles);
+ for (int i = 0; i != 256; i++) {
+ int new_node = next_node++;
+ GraphId new_gnode = graph_cycles.GetId(ptr(new_node));
+ ASSERT_NE(InvalidGraphId(), new_gnode);
+ id[new_node] = new_gnode;
+ ASSERT_EQ(ptr(new_node), graph_cycles.Ptr(new_gnode));
+ for (const auto &node : nodes) {
+ ASSERT_NE(node, new_node);
+ }
+ nodes.push_back(new_node);
+ }
+ for (int i = 0; i != 256; i++) {
+ ASSERT_GT(nodes.size(), 0);
+ int node_index = RandomNode(&rng, &nodes);
+ int node = nodes[node_index];
+ nodes[node_index] = nodes.back();
+ nodes.pop_back();
+ graph_cycles.RemoveNode(ptr(node));
+ id.erase(node);
+ int j = 0;
+ while (j != edges.size()) {
+ if (edges[j].from == node || edges[j].to == node) {
+ edges[j] = edges.back();
+ edges.pop_back();
+ } else {
+ j++;
+ }
+ }
+ }
+ CheckInvariants(graph_cycles);
+ }
+ }
+}
+
+class GraphCyclesTest : public ::testing::Test {
+ public:
+ IdMap id_;
+ GraphCycles g_;
+
+ static void* Ptr(int i) {
+ return reinterpret_cast<void*>(static_cast<uintptr_t>(i));
+ }
+
+ static int Num(void* ptr) {
+ return static_cast<int>(reinterpret_cast<uintptr_t>(ptr));
+ }
+
+ // Test relies on ith NewNode() call returning Node numbered i
+ GraphCyclesTest() {
+ for (int i = 0; i < 100; i++) {
+ id_[i] = g_.GetId(Ptr(i));
+ }
+ CheckInvariants(g_);
+ }
+
+ bool AddEdge(int x, int y) {
+ return g_.InsertEdge(Get(id_, x), Get(id_, y));
+ }
+
+ void AddMultiples() {
+ // For every node x > 0: add edge to 2*x, 3*x
+ for (int x = 1; x < 25; x++) {
+ EXPECT_TRUE(AddEdge(x, 2*x)) << x;
+ EXPECT_TRUE(AddEdge(x, 3*x)) << x;
+ }
+ CheckInvariants(g_);
+ }
+
+ std::string Path(int x, int y) {
+ GraphId path[5];
+ int np = g_.FindPath(Get(id_, x), Get(id_, y), ABSL_ARRAYSIZE(path), path);
+ std::string result;
+ for (int i = 0; i < np; i++) {
+ if (i >= ABSL_ARRAYSIZE(path)) {
+ result += " ...";
+ break;
+ }
+ if (!result.empty()) result.push_back(' ');
+ char buf[20];
+ snprintf(buf, sizeof(buf), "%d", Num(g_.Ptr(path[i])));
+ result += buf;
+ }
+ return result;
+ }
+};
+
+TEST_F(GraphCyclesTest, NoCycle) {
+ AddMultiples();
+ CheckInvariants(g_);
+}
+
+TEST_F(GraphCyclesTest, SimpleCycle) {
+ AddMultiples();
+ EXPECT_FALSE(AddEdge(8, 4));
+ EXPECT_EQ("4 8", Path(4, 8));
+ CheckInvariants(g_);
+}
+
+TEST_F(GraphCyclesTest, IndirectCycle) {
+ AddMultiples();
+ EXPECT_TRUE(AddEdge(16, 9));
+ CheckInvariants(g_);
+ EXPECT_FALSE(AddEdge(9, 2));
+ EXPECT_EQ("2 4 8 16 9", Path(2, 9));
+ CheckInvariants(g_);
+}
+
+TEST_F(GraphCyclesTest, LongPath) {
+ ASSERT_TRUE(AddEdge(2, 4));
+ ASSERT_TRUE(AddEdge(4, 6));
+ ASSERT_TRUE(AddEdge(6, 8));
+ ASSERT_TRUE(AddEdge(8, 10));
+ ASSERT_TRUE(AddEdge(10, 12));
+ ASSERT_FALSE(AddEdge(12, 2));
+ EXPECT_EQ("2 4 6 8 10 ...", Path(2, 12));
+ CheckInvariants(g_);
+}
+
+TEST_F(GraphCyclesTest, RemoveNode) {
+ ASSERT_TRUE(AddEdge(1, 2));
+ ASSERT_TRUE(AddEdge(2, 3));
+ ASSERT_TRUE(AddEdge(3, 4));
+ ASSERT_TRUE(AddEdge(4, 5));
+ g_.RemoveNode(g_.Ptr(id_[3]));
+ id_.erase(3);
+ ASSERT_TRUE(AddEdge(5, 1));
+}
+
+TEST_F(GraphCyclesTest, ManyEdges) {
+ const int N = 50;
+ for (int i = 0; i < N; i++) {
+ for (int j = 1; j < N; j++) {
+ ASSERT_TRUE(AddEdge(i, i+j));
+ }
+ }
+ CheckInvariants(g_);
+ ASSERT_TRUE(AddEdge(2*N-1, 0));
+ CheckInvariants(g_);
+ ASSERT_FALSE(AddEdge(10, 9));
+ CheckInvariants(g_);
+}
+
+} // namespace synchronization_internal
+} // namespace absl
diff --git a/absl/synchronization/internal/kernel_timeout.h b/absl/synchronization/internal/kernel_timeout.h
new file mode 100644
index 0000000..a83c427
--- /dev/null
+++ b/absl/synchronization/internal/kernel_timeout.h
@@ -0,0 +1,147 @@
+// 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.
+//
+
+// An optional absolute timeout, with nanosecond granularity,
+// compatible with absl::Time. Suitable for in-register
+// parameter-passing (e.g. syscalls.)
+// Constructible from a absl::Time (for a timeout to be respected) or {}
+// (for "no timeout".)
+// This is a private low-level API for use by a handful of low-level
+// components that are friends of this class. Higher-level components
+// should build APIs based on absl::Time and absl::Duration.
+
+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
+
+#ifdef _WIN32
+#include <intsafe.h>
+#endif
+#include <time.h>
+#include <algorithm>
+#include <limits>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+
+namespace absl {
+namespace synchronization_internal {
+
+class Waiter;
+
+class KernelTimeout {
+ public:
+ // A timeout that should expire at <t>. Any value, in the full
+ // InfinitePast() to InfiniteFuture() range, is valid here and will be
+ // respected.
+ explicit KernelTimeout(absl::Time t) : ns_(MakeNs(t)) {}
+ // No timeout.
+ KernelTimeout() : ns_(0) {}
+
+ // A more explicit factory for those who prefer it. Equivalent to {}.
+ static KernelTimeout Never() { return {}; }
+
+ // We explicitly do not support other custom formats: timespec, int64_t nanos.
+ // Unify on this and absl::Time, please.
+ bool has_timeout() const { return ns_ != 0; }
+
+ private:
+ // internal rep, not user visible: ns after unix epoch.
+ // zero = no timeout.
+ // Negative we treat as an unlikely (and certainly expired!) but valid
+ // timeout.
+ int64_t ns_;
+
+ static int64_t MakeNs(absl::Time t) {
+ // optimization--InfiniteFuture is common "no timeout" value
+ // and cheaper to compare than convert.
+ if (t == absl::InfiniteFuture()) return 0;
+ int64_t x = ToUnixNanos(t);
+
+ // A timeout that lands exactly on the epoch (x=0) needs to be respected,
+ // so we alter it unnoticably to 1. Negative timeouts are in
+ // theory supported, but handled poorly by the kernel (long
+ // delays) so push them forward too; since all such times have
+ // already passed, it's indistinguishable.
+ if (x <= 0) x = 1;
+ // A time larger than what can be represented to the kernel is treated
+ // as no timeout.
+ if (x == std::numeric_limits<int64_t>::max()) x = 0;
+ return x;
+ }
+
+ // Convert to parameter for sem_timedwait/futex/similar. Only for approved
+ // users. Do not call if !has_timeout.
+ struct timespec MakeAbsTimespec() {
+ int64_t n = ns_;
+ static const int64_t kNanosPerSecond = 1000 * 1000 * 1000;
+ if (n == 0) {
+ ABSL_RAW_LOG(
+ ERROR,
+ "Tried to create a timespec from a non-timeout; never do this.");
+ // But we'll try to continue sanely. no-timeout ~= saturated timeout.
+ n = std::numeric_limits<int64_t>::max();
+ }
+
+ // Kernel APIs validate timespecs as being at or after the epoch,
+ // despite the kernel time type being signed. However, no one can
+ // tell the difference between a timeout at or before the epoch (since
+ // all such timeouts have expired!)
+ if (n < 0) n = 0;
+
+ struct timespec abstime;
+ int64_t seconds = std::min(n / kNanosPerSecond,
+ int64_t{std::numeric_limits<time_t>::max()});
+ abstime.tv_sec = static_cast<time_t>(seconds);
+ abstime.tv_nsec =
+ static_cast<decltype(abstime.tv_nsec)>(n % kNanosPerSecond);
+ return abstime;
+ }
+
+#ifdef _WIN32
+ // Converts to milliseconds from now, or INFINITE when
+ // !has_timeout(). For use by SleepConditionVariableSRW on
+ // Windows. Callers should recognize that the return value is a
+ // relative duration (it should be recomputed by calling this method
+ // in the case of a spurious wakeup).
+ DWORD InMillisecondsFromNow() const {
+ if (!has_timeout()) {
+ return INFINITE;
+ }
+ // The use of absl::Now() to convert from absolute time to
+ // relative time means that absl::Now() cannot use anything that
+ // depends on KernelTimeout (for example, Mutex) on Windows.
+ int64_t now = ToUnixNanos(absl::Now());
+ if (ns_ >= now) {
+ // Round up so that Now() + ms_from_now >= ns_.
+ constexpr uint64_t max_nanos =
+ std::numeric_limits<int64_t>::max() - 999999u;
+ uint64_t ms_from_now =
+ (std::min<uint64_t>(max_nanos, ns_ - now) + 999999u) / 1000000u;
+ if (ms_from_now > std::numeric_limits<DWORD>::max()) {
+ return INFINITE;
+ }
+ return static_cast<DWORD>(ms_from_now);
+ }
+ return 0;
+ }
+#endif
+
+ friend class Waiter;
+};
+
+} // namespace synchronization_internal
+} // namespace absl
+#endif // ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
diff --git a/absl/synchronization/internal/mutex_nonprod.cc b/absl/synchronization/internal/mutex_nonprod.cc
new file mode 100644
index 0000000..94be54b
--- /dev/null
+++ b/absl/synchronization/internal/mutex_nonprod.cc
@@ -0,0 +1,311 @@
+// 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.
+
+// Implementation of a small subset of Mutex and CondVar functionality
+// for platforms where the production implementation hasn't been fully
+// ported yet.
+
+#include "absl/synchronization/mutex.h"
+
+#if defined(_WIN32)
+#include <chrono> // NOLINT(build/c++11)
+#else
+#include <sys/time.h>
+#include <time.h>
+#endif
+
+#include <algorithm>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/time/time.h"
+
+namespace absl {
+namespace synchronization_internal {
+
+namespace {
+
+// Return the current time plus the timeout.
+absl::Time DeadlineFromTimeout(absl::Duration timeout) {
+ return absl::Now() + timeout;
+}
+
+// Limit the deadline to a positive, 32-bit time_t value to accommodate
+// implementation restrictions. This also deals with InfinitePast and
+// InfiniteFuture.
+absl::Time LimitedDeadline(absl::Time deadline) {
+ deadline = std::max(absl::FromTimeT(0), deadline);
+ deadline = std::min(deadline, absl::FromTimeT(0x7fffffff));
+ return deadline;
+}
+
+} // namespace
+
+#if defined(_WIN32)
+
+MutexImpl::MutexImpl() {}
+
+MutexImpl::~MutexImpl() {
+ if (locked_) {
+ std_mutex_.unlock();
+ }
+}
+
+void MutexImpl::Lock() {
+ std_mutex_.lock();
+ locked_ = true;
+}
+
+bool MutexImpl::TryLock() {
+ bool locked = std_mutex_.try_lock();
+ if (locked) locked_ = true;
+ return locked;
+}
+
+void MutexImpl::Unlock() {
+ locked_ = false;
+ released_.SignalAll();
+ std_mutex_.unlock();
+}
+
+CondVarImpl::CondVarImpl() {}
+
+CondVarImpl::~CondVarImpl() {}
+
+void CondVarImpl::Signal() { std_cv_.notify_one(); }
+
+void CondVarImpl::SignalAll() { std_cv_.notify_all(); }
+
+void CondVarImpl::Wait(MutexImpl* mu) {
+ mu->released_.SignalAll();
+ std_cv_.wait(mu->std_mutex_);
+}
+
+bool CondVarImpl::WaitWithDeadline(MutexImpl* mu, absl::Time deadline) {
+ mu->released_.SignalAll();
+ time_t when = ToTimeT(deadline);
+ int64_t nanos = ToInt64Nanoseconds(deadline - absl::FromTimeT(when));
+ std::chrono::system_clock::time_point deadline_tp =
+ std::chrono::system_clock::from_time_t(when) +
+ std::chrono::duration_cast<std::chrono::system_clock::duration>(
+ std::chrono::nanoseconds(nanos));
+ auto deadline_since_epoch =
+ std::chrono::duration_cast<std::chrono::duration<double>>(
+ deadline_tp - std::chrono::system_clock::from_time_t(0));
+ return std_cv_.wait_until(mu->std_mutex_, deadline_tp) ==
+ std::cv_status::timeout;
+}
+
+#else // ! _WIN32
+
+MutexImpl::MutexImpl() {
+ ABSL_RAW_CHECK(pthread_mutex_init(&pthread_mutex_, nullptr) == 0,
+ "pthread error");
+}
+
+MutexImpl::~MutexImpl() {
+ if (locked_) {
+ ABSL_RAW_CHECK(pthread_mutex_unlock(&pthread_mutex_) == 0, "pthread error");
+ }
+ ABSL_RAW_CHECK(pthread_mutex_destroy(&pthread_mutex_) == 0, "pthread error");
+}
+
+void MutexImpl::Lock() {
+ ABSL_RAW_CHECK(pthread_mutex_lock(&pthread_mutex_) == 0, "pthread error");
+ locked_ = true;
+}
+
+bool MutexImpl::TryLock() {
+ bool locked = (0 == pthread_mutex_trylock(&pthread_mutex_));
+ if (locked) locked_ = true;
+ return locked;
+}
+
+void MutexImpl::Unlock() {
+ locked_ = false;
+ released_.SignalAll();
+ ABSL_RAW_CHECK(pthread_mutex_unlock(&pthread_mutex_) == 0, "pthread error");
+}
+
+CondVarImpl::CondVarImpl() {
+ ABSL_RAW_CHECK(pthread_cond_init(&pthread_cv_, nullptr) == 0,
+ "pthread error");
+}
+
+CondVarImpl::~CondVarImpl() {
+ ABSL_RAW_CHECK(pthread_cond_destroy(&pthread_cv_) == 0, "pthread error");
+}
+
+void CondVarImpl::Signal() {
+ ABSL_RAW_CHECK(pthread_cond_signal(&pthread_cv_) == 0, "pthread error");
+}
+
+void CondVarImpl::SignalAll() {
+ ABSL_RAW_CHECK(pthread_cond_broadcast(&pthread_cv_) == 0, "pthread error");
+}
+
+void CondVarImpl::Wait(MutexImpl* mu) {
+ mu->released_.SignalAll();
+ ABSL_RAW_CHECK(pthread_cond_wait(&pthread_cv_, &mu->pthread_mutex_) == 0,
+ "pthread error");
+}
+
+bool CondVarImpl::WaitWithDeadline(MutexImpl* mu, absl::Time deadline) {
+ mu->released_.SignalAll();
+ struct timespec ts = ToTimespec(deadline);
+ int rc = pthread_cond_timedwait(&pthread_cv_, &mu->pthread_mutex_, &ts);
+ if (rc == ETIMEDOUT) return true;
+ ABSL_RAW_CHECK(rc == 0, "pthread error");
+ return false;
+}
+
+#endif // ! _WIN32
+
+void MutexImpl::Await(const Condition& cond) {
+ if (cond.Eval()) return;
+ released_.SignalAll();
+ do {
+ released_.Wait(this);
+ } while (!cond.Eval());
+}
+
+bool MutexImpl::AwaitWithDeadline(const Condition& cond, absl::Time deadline) {
+ if (cond.Eval()) return true;
+ released_.SignalAll();
+ while (true) {
+ if (released_.WaitWithDeadline(this, deadline)) return false;
+ if (cond.Eval()) return true;
+ }
+}
+
+} // namespace synchronization_internal
+
+Mutex::Mutex() {}
+
+Mutex::~Mutex() {}
+
+void Mutex::Lock() { impl()->Lock(); }
+
+void Mutex::Unlock() { impl()->Unlock(); }
+
+bool Mutex::TryLock() { return impl()->TryLock(); }
+
+void Mutex::ReaderLock() { Lock(); }
+
+void Mutex::ReaderUnlock() { Unlock(); }
+
+void Mutex::Await(const Condition& cond) { impl()->Await(cond); }
+
+void Mutex::LockWhen(const Condition& cond) {
+ Lock();
+ Await(cond);
+}
+
+bool Mutex::AwaitWithDeadline(const Condition& cond, absl::Time deadline) {
+ return impl()->AwaitWithDeadline(
+ cond, synchronization_internal::LimitedDeadline(deadline));
+}
+
+bool Mutex::AwaitWithTimeout(const Condition& cond, absl::Duration timeout) {
+ return AwaitWithDeadline(
+ cond, synchronization_internal::DeadlineFromTimeout(timeout));
+}
+
+bool Mutex::LockWhenWithDeadline(const Condition& cond, absl::Time deadline) {
+ Lock();
+ return AwaitWithDeadline(cond, deadline);
+}
+
+bool Mutex::LockWhenWithTimeout(const Condition& cond, absl::Duration timeout) {
+ return LockWhenWithDeadline(
+ cond, synchronization_internal::DeadlineFromTimeout(timeout));
+}
+
+bool Mutex::ReaderLockWhenWithTimeout(const Condition& cond,
+ absl::Duration timeout) {
+ return LockWhenWithTimeout(cond, timeout);
+}
+bool Mutex::ReaderLockWhenWithDeadline(const Condition& cond,
+ absl::Time deadline) {
+ return LockWhenWithDeadline(cond, deadline);
+}
+
+void Mutex::EnableDebugLog(const char*) {}
+void Mutex::EnableInvariantDebugging(void (*)(void*), void*) {}
+void Mutex::ForgetDeadlockInfo() {}
+void Mutex::AssertHeld() const {}
+void Mutex::AssertReaderHeld() const {}
+void Mutex::AssertNotHeld() const {}
+
+CondVar::CondVar() {}
+
+CondVar::~CondVar() {}
+
+void CondVar::Signal() { impl()->Signal(); }
+
+void CondVar::SignalAll() { impl()->SignalAll(); }
+
+void CondVar::Wait(Mutex* mu) { return impl()->Wait(mu->impl()); }
+
+bool CondVar::WaitWithDeadline(Mutex* mu, absl::Time deadline) {
+ return impl()->WaitWithDeadline(
+ mu->impl(), synchronization_internal::LimitedDeadline(deadline));
+}
+
+bool CondVar::WaitWithTimeout(Mutex* mu, absl::Duration timeout) {
+ return WaitWithDeadline(mu, absl::Now() + timeout);
+}
+
+void CondVar::EnableDebugLog(const char*) {}
+
+#ifdef THREAD_SANITIZER
+extern "C" void __tsan_read1(void *addr);
+#else
+#define __tsan_read1(addr) // do nothing if TSan not enabled
+#endif
+
+// A function that just returns its argument, dereferenced
+static bool Dereference(void *arg) {
+ // ThreadSanitizer does not instrument this file for memory accesses.
+ // This function dereferences a user variable that can participate
+ // in a data race, so we need to manually tell TSan about this memory access.
+ __tsan_read1(arg);
+ return *(static_cast<bool *>(arg));
+}
+
+Condition::Condition() {} // null constructor, used for kTrue only
+const Condition Condition::kTrue;
+
+Condition::Condition(bool (*func)(void *), void *arg)
+ : eval_(&CallVoidPtrFunction),
+ function_(func),
+ method_(nullptr),
+ arg_(arg) {}
+
+bool Condition::CallVoidPtrFunction(const Condition *c) {
+ return (*c->function_)(c->arg_);
+}
+
+Condition::Condition(const bool *cond)
+ : eval_(CallVoidPtrFunction),
+ function_(Dereference),
+ method_(nullptr),
+ // const_cast is safe since Dereference does not modify arg
+ arg_(const_cast<bool *>(cond)) {}
+
+bool Condition::Eval() const {
+ // eval_ == null for kTrue
+ return (this->eval_ == nullptr) || (*this->eval_)(this);
+}
+
+} // namespace absl
diff --git a/absl/synchronization/internal/mutex_nonprod.inc b/absl/synchronization/internal/mutex_nonprod.inc
new file mode 100644
index 0000000..51441b2
--- /dev/null
+++ b/absl/synchronization/internal/mutex_nonprod.inc
@@ -0,0 +1,256 @@
+// Do not include. This is an implementation detail of base/mutex.h.
+//
+// Declares three classes:
+//
+// base::internal::MutexImpl - implementation helper for Mutex
+// base::internal::CondVarImpl - implementation helper for CondVar
+// base::internal::SynchronizationStorage<T> - implementation helper for
+// Mutex, CondVar
+
+#include <type_traits>
+
+#if defined(_WIN32)
+#include <condition_variable>
+#include <mutex>
+#else
+#include <pthread.h>
+#endif
+
+#include "absl/base/call_once.h"
+#include "absl/time/time.h"
+
+// Declare that Mutex::ReaderLock is actually Lock(). Intended primarily
+// for tests, and even then as a last resort.
+#ifdef ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE
+#error ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE cannot be directly set
+#else
+#define ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE 1
+#endif
+
+// Declare that Mutex::EnableInvariantDebugging is not implemented.
+// Intended primarily for tests, and even then as a last resort.
+#ifdef ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED
+#error ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED cannot be directly set
+#else
+#define ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED 1
+#endif
+
+namespace absl {
+class Condition;
+
+namespace synchronization_internal {
+
+class MutexImpl;
+
+// Do not use this implementation detail of CondVar. Provides most of the
+// implementation, but should not be placed directly in static storage
+// because it will not linker initialize properly. See
+// SynchronizationStorage<T> below for what we mean by linker
+// initialization.
+class CondVarImpl {
+ public:
+ CondVarImpl();
+ CondVarImpl(const CondVarImpl&) = delete;
+ CondVarImpl& operator=(const CondVarImpl&) = delete;
+ ~CondVarImpl();
+
+ void Signal();
+ void SignalAll();
+ void Wait(MutexImpl* mutex);
+ bool WaitWithDeadline(MutexImpl* mutex, absl::Time deadline);
+
+ private:
+#if defined(_WIN32)
+ std::condition_variable_any std_cv_;
+#else
+ pthread_cond_t pthread_cv_;
+#endif
+};
+
+// Do not use this implementation detail of Mutex. Provides most of the
+// implementation, but should not be placed directly in static storage
+// because it will not linker initialize properly. See
+// SynchronizationStorage<T> below for what we mean by linker
+// initialization.
+class MutexImpl {
+ public:
+ MutexImpl();
+ MutexImpl(const MutexImpl&) = delete;
+ MutexImpl& operator=(const MutexImpl&) = delete;
+ ~MutexImpl();
+
+ void Lock();
+ bool TryLock();
+ void Unlock();
+ void Await(const Condition& cond);
+ bool AwaitWithDeadline(const Condition& cond, absl::Time deadline);
+
+ private:
+ friend class CondVarImpl;
+
+#if defined(_WIN32)
+ std::mutex std_mutex_;
+#else
+ pthread_mutex_t pthread_mutex_;
+#endif
+
+ // True if the underlying mutex is locked. If the destructor is entered
+ // while locked_, the underlying mutex is unlocked. Mutex supports
+ // destruction while locked, but the same is undefined behavior for both
+ // pthread_mutex_t and std::mutex.
+ bool locked_ = false;
+
+ // Signaled before releasing the lock, in support of Await.
+ CondVarImpl released_;
+};
+
+// Do not use this implementation detail of CondVar and Mutex. A storage
+// space for T that supports a base::LinkerInitialized constructor. T must
+// have a default constructor, which is called by the first call to
+// get(). T's destructor is never called if the base::LinkerInitialized
+// constructor is called.
+//
+// Objects constructed with the default constructor are constructed and
+// destructed like any other object, and should never be allocated in
+// static storage.
+//
+// Objects constructed with the base::LinkerInitialized constructor should
+// always be in static storage. For such objects, calls to get() are always
+// valid, except from signal handlers.
+//
+// Note that this implementation relies on undefined language behavior that
+// are known to hold for the set of supported compilers. An analysis
+// follows.
+//
+// From the C++11 standard:
+//
+// [basic.life] says an object has non-trivial initialization if it is of
+// class type and it is initialized by a constructor other than a trivial
+// default constructor. (the base::LinkerInitialized constructor is
+// non-trivial)
+//
+// [basic.life] says the lifetime of an object with a non-trivial
+// constructor begins when the call to the constructor is complete.
+//
+// [basic.life] says the lifetime of an object with non-trivial destructor
+// ends when the call to the destructor begins.
+//
+// [basic.life] p5 specifies undefined behavior when accessing non-static
+// members of an instance outside its
+// lifetime. (SynchronizationStorage::get() access non-static members)
+//
+// So, base::LinkerInitialized object of SynchronizationStorage uses a
+// non-trivial constructor, which is called at some point during dynamic
+// initialization, and is therefore subject to order of dynamic
+// initialization bugs, where get() is called before the object's
+// constructor is, resulting in undefined behavior.
+//
+// Similarly, a base::LinkerInitialized SynchronizationStorage object has a
+// non-trivial destructor, and so its lifetime ends at some point during
+// destruction of objects with static storage duration [basic.start.term]
+// p4. There is a window where other exit code could call get() after this
+// occurs, resulting in undefined behavior.
+//
+// Combined, these statements imply that base::LinkerInitialized instances
+// of SynchronizationStorage<T> rely on undefined behavior.
+//
+// However, in practice, the implementation works on all supported
+// compilers. Specifically, we rely on:
+//
+// a) zero-initialization being sufficient to initialize
+// base::LinkerInitialized instances for the purposes of calling
+// get(), regardless of when the constructor is called. This is
+// because the is_dynamic_ boolean is correctly zero-initialized to
+// false.
+//
+// b) the base::LinkerInitialized constructor is a NOP, and immaterial to
+// even to concurrent calls to get().
+//
+// c) the destructor being a NOP for base::LinkerInitialized objects
+// (guaranteed by a check for !is_dynamic_), and so any concurrent and
+// subsequent calls to get() functioning as if the destructor were not
+// called, by virtue of the instances' storage remaining valid after the
+// destructor runs.
+//
+// d) That a-c apply transitively when SynchronizationStorage<T> is the
+// only member of a class allocated in static storage.
+//
+// Nothing in the language standard guarantees that a-d hold. In practice,
+// these hold in all supported compilers.
+//
+// Future direction:
+//
+// Ideally, we would simply use std::mutex or a similar class, which when
+// allocated statically would support use immediately after static
+// initialization up until static storage is reclaimed (i.e. the properties
+// we require of all "linker initialized" instances).
+//
+// Regarding construction in static storage, std::mutex is required to
+// provide a constexpr default constructor [thread.mutex.class], which
+// ensures the instance's lifetime begins with static initialization
+// [basic.start.init], and so is immune to any problems caused by the order
+// of dynamic initialization. However, as of this writing Microsoft's
+// Visual Studio does not provide a constexpr constructor for std::mutex.
+// See
+// https://blogs.msdn.microsoft.com/vcblog/2015/06/02/constexpr-complete-for-vs-2015-rtm-c11-compiler-c17-stl/
+//
+// Regarding destruction of instances in static storage, [basic.life] does
+// say an object ends when storage in which the occupies is released, in
+// the case of non-trivial destructor. However, std::mutex is not specified
+// to have a trivial destructor.
+//
+// So, we would need a class with a constexpr default constructor and a
+// trivial destructor. Today, we can achieve neither desired property using
+// std::mutex directly.
+template <typename T>
+class SynchronizationStorage {
+ public:
+ // Instances allocated on the heap or on the stack should use the default
+ // constructor.
+ SynchronizationStorage()
+ : is_dynamic_(true), once_() {}
+
+ // Instances allocated in static storage (not on the heap, not on the
+ // stack) should use this constructor.
+ explicit SynchronizationStorage(base::LinkerInitialized) {}
+
+ SynchronizationStorage(SynchronizationStorage&) = delete;
+ SynchronizationStorage& operator=(SynchronizationStorage&) = delete;
+
+ ~SynchronizationStorage() {
+ if (is_dynamic_) {
+ get()->~T();
+ }
+ }
+
+ // Retrieve the object in storage. This is fast and thread safe, but does
+ // incur the cost of absl::call_once().
+ //
+ // For instances in static storage constructed with the
+ // base::LinkerInitialized constructor, may be called at any time without
+ // regard for order of dynamic initialization or destruction of objects
+ // in static storage. See the class comment for caveats.
+ T* get() {
+ absl::call_once(once_, SynchronizationStorage::Construct, this);
+ return reinterpret_cast<T*>(&space_);
+ }
+
+ private:
+ static void Construct(SynchronizationStorage<T>* self) {
+ new (&self->space_) T();
+ }
+
+ // When true, T's destructor is run when this is destructed.
+ //
+ // The base::LinkerInitialized constructor assumes this value will be set
+ // false by static initialization.
+ bool is_dynamic_;
+
+ absl::once_flag once_;
+
+ // An aligned space for T.
+ typename std::aligned_storage<sizeof(T), alignof(T)>::type space_;
+};
+
+} // namespace synchronization_internal
+} // namespace absl
diff --git a/absl/synchronization/internal/per_thread_sem.cc b/absl/synchronization/internal/per_thread_sem.cc
new file mode 100644
index 0000000..af87222
--- /dev/null
+++ b/absl/synchronization/internal/per_thread_sem.cc
@@ -0,0 +1,106 @@
+// 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 no-op if the required LowLevelAlloc support is missing.
+#include "absl/base/internal/low_level_alloc.h"
+#ifndef ABSL_LOW_LEVEL_ALLOC_MISSING
+
+#include "absl/synchronization/internal/per_thread_sem.h"
+
+#include <atomic>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/malloc_extension.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/waiter.h"
+
+namespace absl {
+namespace synchronization_internal {
+
+void PerThreadSem::SetThreadBlockedCounter(std::atomic<int> *counter) {
+ base_internal::ThreadIdentity *identity;
+ identity = GetOrCreateCurrentThreadIdentity();
+ identity->blocked_count_ptr = counter;
+}
+
+std::atomic<int> *PerThreadSem::GetThreadBlockedCounter() {
+ base_internal::ThreadIdentity *identity;
+ identity = GetOrCreateCurrentThreadIdentity();
+ return identity->blocked_count_ptr;
+}
+
+void PerThreadSem::Init(base_internal::ThreadIdentity *identity) {
+ Waiter::GetWaiter(identity)->Init();
+ identity->ticker.store(0, std::memory_order_relaxed);
+ identity->wait_start.store(0, std::memory_order_relaxed);
+ identity->is_idle.store(false, std::memory_order_relaxed);
+}
+
+void PerThreadSem::Tick(base_internal::ThreadIdentity *identity) {
+ const int ticker =
+ identity->ticker.fetch_add(1, std::memory_order_relaxed) + 1;
+ const int wait_start = identity->wait_start.load(std::memory_order_relaxed);
+ const bool is_idle = identity->is_idle.load(std::memory_order_relaxed);
+ if (wait_start && (ticker - wait_start > Waiter::kIdlePeriods) && !is_idle) {
+ // Wakeup the waiting thread since it is time for it to become idle.
+ Waiter::GetWaiter(identity)->Poke();
+ }
+}
+
+} // namespace synchronization_internal
+} // namespace absl
+
+extern "C" {
+
+ABSL_ATTRIBUTE_WEAK void AbslInternalPerThreadSemPost(
+ absl::base_internal::ThreadIdentity *identity) {
+ absl::synchronization_internal::Waiter::GetWaiter(identity)->Post();
+}
+
+ABSL_ATTRIBUTE_WEAK bool AbslInternalPerThreadSemWait(
+ absl::synchronization_internal::KernelTimeout t) {
+ bool timeout = false;
+ absl::base_internal::ThreadIdentity *identity;
+ identity = absl::synchronization_internal::GetOrCreateCurrentThreadIdentity();
+
+ // Ensure wait_start != 0.
+ int ticker = identity->ticker.load(std::memory_order_relaxed);
+ identity->wait_start.store(ticker ? ticker : 1, std::memory_order_relaxed);
+ identity->is_idle.store(false, std::memory_order_relaxed);
+
+ if (identity->blocked_count_ptr != nullptr) {
+ // Increment count of threads blocked in a given thread pool.
+ identity->blocked_count_ptr->fetch_add(1, std::memory_order_relaxed);
+ }
+
+ timeout =
+ !absl::synchronization_internal::Waiter::GetWaiter(identity)->Wait(t);
+
+ if (identity->blocked_count_ptr != nullptr) {
+ identity->blocked_count_ptr->fetch_sub(1, std::memory_order_relaxed);
+ }
+
+ if (identity->is_idle.load(std::memory_order_relaxed)) {
+ // We became idle during the wait; become non-idle again so that
+ // performance of deallocations done from now on does not suffer.
+ absl::base_internal::MallocExtension::instance()->MarkThreadBusy();
+ }
+ identity->is_idle.store(false, std::memory_order_relaxed);
+ identity->wait_start.store(0, std::memory_order_relaxed);
+ return !timeout;
+}
+
+} // extern "C"
+
+#endif // ABSL_LOW_LEVEL_ALLOC_MISSING
diff --git a/absl/synchronization/internal/per_thread_sem.h b/absl/synchronization/internal/per_thread_sem.h
new file mode 100644
index 0000000..678b69e
--- /dev/null
+++ b/absl/synchronization/internal/per_thread_sem.h
@@ -0,0 +1,107 @@
+// 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.
+//
+
+// PerThreadSem is a low-level synchronization primitive controlling the
+// runnability of a single thread, used internally by Mutex and CondVar.
+//
+// This is NOT a general-purpose synchronization mechanism, and should not be
+// used directly by applications. Applications should use Mutex and CondVar.
+//
+// The semantics of PerThreadSem are the same as that of a counting semaphore.
+// Each thread maintains an abstract "count" value associated with its identity.
+
+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_
+
+#include <atomic>
+
+#include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/create_thread_identity.h"
+#include "absl/synchronization/internal/kernel_timeout.h"
+
+namespace absl {
+
+class Mutex;
+
+namespace synchronization_internal {
+
+class PerThreadSem {
+ public:
+ PerThreadSem() = delete;
+ PerThreadSem(const PerThreadSem&) = delete;
+ PerThreadSem& operator=(const PerThreadSem&) = delete;
+
+ // Routine invoked periodically (once a second) by a background thread.
+ // Has no effect on user-visible state.
+ static void Tick(base_internal::ThreadIdentity* identity);
+
+ // ---------------------------------------------------------------------------
+ // Routines used by autosizing threadpools to detect when threads are
+ // blocked. Each thread has a counter pointer, initially zero. If non-zero,
+ // the implementation atomically increments the counter when it blocks on a
+ // semaphore, a decrements it again when it wakes. This allows a threadpool
+ // to keep track of how many of its threads are blocked.
+ // SetThreadBlockedCounter() should be used only by threadpool
+ // implementations. GetThreadBlockedCounter() should be used by modules that
+ // block threads; if the pointer returned is non-zero, the location should be
+ // incremented before the thread blocks, and decremented after it wakes.
+ static void SetThreadBlockedCounter(std::atomic<int> *counter);
+ static std::atomic<int> *GetThreadBlockedCounter();
+
+ private:
+ // Create the PerThreadSem associated with "identity". Initializes count=0.
+ // REQUIRES: May only be called by ThreadIdentity.
+ static void Init(base_internal::ThreadIdentity* identity);
+
+ // Increments "identity"'s count.
+ static inline void Post(base_internal::ThreadIdentity* identity);
+
+ // Waits until either our count > 0 or t has expired.
+ // If count > 0, decrements count and returns true. Otherwise returns false.
+ // !t.has_timeout() => Wait(t) will return true.
+ static inline bool Wait(KernelTimeout t);
+
+ // White-listed callers.
+ friend class PerThreadSemTest;
+ friend class absl::Mutex;
+ friend absl::base_internal::ThreadIdentity* CreateThreadIdentity();
+};
+
+} // namespace synchronization_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 AbslInternalPerThreadSemPost(
+ absl::base_internal::ThreadIdentity* identity);
+bool AbslInternalPerThreadSemWait(
+ absl::synchronization_internal::KernelTimeout t);
+} // extern "C"
+
+void absl::synchronization_internal::PerThreadSem::Post(
+ absl::base_internal::ThreadIdentity* identity) {
+ AbslInternalPerThreadSemPost(identity);
+}
+
+bool absl::synchronization_internal::PerThreadSem::Wait(
+ absl::synchronization_internal::KernelTimeout t) {
+ return AbslInternalPerThreadSemWait(t);
+}
+#endif // ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_
diff --git a/absl/synchronization/internal/per_thread_sem_test.cc b/absl/synchronization/internal/per_thread_sem_test.cc
new file mode 100644
index 0000000..1d072a7
--- /dev/null
+++ b/absl/synchronization/internal/per_thread_sem_test.cc
@@ -0,0 +1,246 @@
+// 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/synchronization/internal/per_thread_sem.h"
+
+#include <atomic>
+#include <condition_variable> // NOLINT(build/c++11)
+#include <functional>
+#include <limits>
+#include <mutex> // NOLINT(build/c++11)
+#include <string>
+#include <thread> // NOLINT(build/c++11)
+
+#include "absl/base/internal/cycleclock.h"
+#include "absl/base/internal/malloc_extension.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/strings/str_cat.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+#include "gtest/gtest.h"
+
+// In this test we explicitly avoid the use of synchronization
+// primitives which might use PerThreadSem, most notably absl::Mutex.
+
+namespace absl {
+namespace synchronization_internal {
+
+class SimpleSemaphore {
+ public:
+ SimpleSemaphore() : count_(0) {}
+
+ // Decrements (locks) the semaphore. If the semaphore's value is
+ // greater than zero, then the decrement proceeds, and the function
+ // returns, immediately. If the semaphore currently has the value
+ // zero, then the call blocks until it becomes possible to perform
+ // the decrement.
+ void Wait() {
+ std::unique_lock<std::mutex> lock(mu_);
+ cv_.wait(lock, [this]() { return count_ > 0; });
+ --count_;
+ cv_.notify_one();
+ }
+
+ // Increments (unlocks) the semaphore. If the semaphore's value
+ // consequently becomes greater than zero, then another thread
+ // blocked Wait() call will be woken up and proceed to lock the
+ // semaphore.
+ void Post() {
+ std::lock_guard<std::mutex> lock(mu_);
+ ++count_;
+ cv_.notify_one();
+ }
+
+ private:
+ std::mutex mu_;
+ std::condition_variable cv_;
+ int count_;
+};
+
+struct ThreadData {
+ int num_iterations; // Number of replies to send.
+ SimpleSemaphore identity2_written; // Posted by thread writing identity2.
+ base_internal::ThreadIdentity *identity1; // First Post()-er.
+ base_internal::ThreadIdentity *identity2; // First Wait()-er.
+ KernelTimeout timeout;
+};
+
+// Need friendship with PerThreadSem.
+class PerThreadSemTest : public testing::Test {
+ public:
+ static void TimingThread(ThreadData* t) {
+ t->identity2 = GetOrCreateCurrentThreadIdentity();
+ t->identity2_written.Post();
+ while (t->num_iterations--) {
+ Wait(t->timeout);
+ Post(t->identity1);
+ }
+ }
+
+ void TestTiming(const char *msg, bool timeout) {
+ static const int kNumIterations = 100;
+ ThreadData t;
+ t.num_iterations = kNumIterations;
+ t.timeout = timeout ?
+ KernelTimeout(absl::Now() + absl::Seconds(10000)) // far in the future
+ : KernelTimeout::Never();
+ t.identity1 = GetOrCreateCurrentThreadIdentity();
+
+ // We can't use the Thread class here because it uses the Mutex
+ // class which will invoke PerThreadSem, so we use std::thread instead.
+ std::thread partner_thread(std::bind(TimingThread, &t));
+
+ // Wait for our partner thread to register their identity.
+ t.identity2_written.Wait();
+
+ int64_t min_cycles = std::numeric_limits<int64_t>::max();
+ int64_t total_cycles = 0;
+ for (int i = 0; i < kNumIterations; ++i) {
+ absl::SleepFor(absl::Milliseconds(20));
+ int64_t cycles = base_internal::CycleClock::Now();
+ Post(t.identity2);
+ Wait(t.timeout);
+ cycles = base_internal::CycleClock::Now() - cycles;
+ min_cycles = std::min(min_cycles, cycles);
+ total_cycles += cycles;
+ }
+ std::string out =
+ StrCat(msg, "min cycle count=", min_cycles, " avg cycle count=",
+ absl::SixDigits(static_cast<double>(total_cycles) /
+ kNumIterations));
+ printf("%s\n", out.c_str());
+
+ partner_thread.join();
+ }
+
+ protected:
+ static void Post(base_internal::ThreadIdentity *id) {
+ PerThreadSem::Post(id);
+ }
+ static bool Wait(KernelTimeout t) {
+ return PerThreadSem::Wait(t);
+ }
+
+ // convenience overload
+ static bool Wait(absl::Time t) {
+ return Wait(KernelTimeout(t));
+ }
+
+ static void Tick(base_internal::ThreadIdentity *identity) {
+ PerThreadSem::Tick(identity);
+ }
+};
+
+namespace {
+
+TEST_F(PerThreadSemTest, WithoutTimeout) {
+ PerThreadSemTest::TestTiming("Without timeout: ", false);
+}
+
+TEST_F(PerThreadSemTest, WithTimeout) {
+ PerThreadSemTest::TestTiming("With timeout: ", true);
+}
+
+TEST_F(PerThreadSemTest, Timeouts) {
+ absl::Time timeout = absl::Now() + absl::Milliseconds(50);
+ EXPECT_FALSE(Wait(timeout));
+ EXPECT_LE(timeout, absl::Now());
+
+ absl::Time negative_timeout = absl::UnixEpoch() - absl::Milliseconds(100);
+ EXPECT_FALSE(Wait(negative_timeout));
+ EXPECT_LE(negative_timeout, absl::Now()); // trivially true :)
+
+ Post(GetOrCreateCurrentThreadIdentity());
+ // The wait here has an expired timeout, but we have a wake to consume,
+ // so this should succeed
+ EXPECT_TRUE(Wait(negative_timeout));
+}
+
+// Test that idle threads properly register themselves as such with malloc.
+TEST_F(PerThreadSemTest, Idle) {
+ // We can't use gmock because it might use synch calls. So we do it
+ // by hand, messily. I don't bother hitting every one of the
+ // MallocExtension calls because most of them won't get made
+ // anyway--if they do we can add them.
+ class MockMallocExtension : public base_internal::MallocExtension {
+ public:
+ MockMallocExtension(base_internal::MallocExtension *real,
+ base_internal::ThreadIdentity *id,
+ std::atomic<int> *idles, std::atomic<int> *busies)
+ : real_(real), id_(id), idles_(idles), busies_(busies) {}
+ void MarkThreadIdle() override {
+ if (base_internal::CurrentThreadIdentityIfPresent() != id_) {
+ return;
+ }
+ idles_->fetch_add(1, std::memory_order_relaxed);
+ }
+
+ void MarkThreadBusy() override {
+ if (base_internal::CurrentThreadIdentityIfPresent() != id_) {
+ return;
+ }
+ busies_->fetch_add(1, std::memory_order_relaxed);
+ }
+ size_t GetAllocatedSize(const void* p) override {
+ return real_->GetAllocatedSize(p);
+ }
+
+ private:
+ MallocExtension *real_;
+ base_internal::ThreadIdentity *id_;
+ std::atomic<int>* idles_;
+ std::atomic<int>* busies_;
+ };
+
+ base_internal::ThreadIdentity *id = GetOrCreateCurrentThreadIdentity();
+ std::atomic<int> idles(0);
+ std::atomic<int> busies(0);
+ base_internal::MallocExtension *old =
+ base_internal::MallocExtension::instance();
+ MockMallocExtension mock(old, id, &idles, &busies);
+ base_internal::MallocExtension::Register(&mock);
+ std::atomic<int> sync(0);
+
+ std::thread t([id, &idles, &sync]() {
+ // Wait for the main thread to begin the wait process
+ while (0 == sync.load(std::memory_order_relaxed)) {
+ SleepFor(absl::Milliseconds(1));
+ }
+ // Wait for main thread to become idle, then wake it
+ // pretend time is passing--enough of these should cause an idling.
+ for (int i = 0; i < 100; ++i) {
+ Tick(id);
+ }
+ while (0 == idles.load(std::memory_order_relaxed)) {
+ // Keep ticking, just in case.
+ Tick(id);
+ SleepFor(absl::Milliseconds(1));
+ }
+ Post(id);
+ });
+
+ idles.store(0, std::memory_order_relaxed); // In case we slept earlier.
+ sync.store(1, std::memory_order_relaxed);
+ Wait(KernelTimeout::Never());
+
+ // t will wake us once we become idle.
+ EXPECT_LT(0, busies.load(std::memory_order_relaxed));
+ t.join();
+ base_internal::MallocExtension::Register(old);
+}
+
+} // namespace
+
+} // namespace synchronization_internal
+} // namespace absl
diff --git a/absl/synchronization/internal/thread_pool.h b/absl/synchronization/internal/thread_pool.h
new file mode 100644
index 0000000..8464042
--- /dev/null
+++ b/absl/synchronization/internal/thread_pool.h
@@ -0,0 +1,90 @@
+// 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_SYNCHRONIZATION_INTERNAL_THREAD_POOL_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_THREAD_POOL_H_
+
+#include <cassert>
+#include <functional>
+#include <queue>
+#include <thread> // NOLINT(build/c++11)
+#include <vector>
+
+#include "absl/base/thread_annotations.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+namespace synchronization_internal {
+
+// A simple ThreadPool implementation for tests.
+class ThreadPool {
+ public:
+ explicit ThreadPool(int num_threads) {
+ for (int i = 0; i < num_threads; ++i) {
+ threads_.push_back(std::thread(&ThreadPool::WorkLoop, this));
+ }
+ }
+
+ ThreadPool(const ThreadPool &) = delete;
+ ThreadPool &operator=(const ThreadPool &) = delete;
+
+ ~ThreadPool() {
+ {
+ absl::MutexLock l(&mu_);
+ for (int i = 0; i < threads_.size(); ++i) {
+ queue_.push(nullptr); // Shutdown signal.
+ }
+ }
+ for (auto &t : threads_) {
+ t.join();
+ }
+ }
+
+ // Schedule a function to be run on a ThreadPool thread immediately.
+ void Schedule(std::function<void()> func) {
+ assert(func != nullptr);
+ absl::MutexLock l(&mu_);
+ queue_.push(std::move(func));
+ }
+
+ private:
+ bool WorkAvailable() const EXCLUSIVE_LOCKS_REQUIRED(mu_) {
+ return !queue_.empty();
+ }
+
+ void WorkLoop() {
+ while (true) {
+ std::function<void()> func;
+ {
+ absl::MutexLock l(&mu_);
+ mu_.Await(absl::Condition(this, &ThreadPool::WorkAvailable));
+ func = std::move(queue_.front());
+ queue_.pop();
+ }
+ if (func == nullptr) { // Shutdown signal.
+ break;
+ }
+ func();
+ }
+ }
+
+ absl::Mutex mu_;
+ std::queue<std::function<void()>> queue_ GUARDED_BY(mu_);
+ std::vector<std::thread> threads_;
+};
+
+} // namespace synchronization_internal
+} // namespace absl
+
+#endif // ABSL_SYNCHRONIZATION_INTERNAL_THREAD_POOL_H_
diff --git a/absl/synchronization/internal/waiter.cc b/absl/synchronization/internal/waiter.cc
new file mode 100644
index 0000000..cd16c78
--- /dev/null
+++ b/absl/synchronization/internal/waiter.cc
@@ -0,0 +1,394 @@
+// 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/synchronization/internal/waiter.h"
+
+#include "absl/base/config.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <pthread.h>
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+#ifdef __linux__
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#endif
+
+#ifdef ABSL_HAVE_SEMAPHORE_H
+#include <semaphore.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <atomic>
+#include <cassert>
+
+#include "absl/base/internal/malloc_extension.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/kernel_timeout.h"
+
+namespace absl {
+namespace synchronization_internal {
+
+static void MaybeBecomeIdle() {
+ base_internal::ThreadIdentity *identity =
+ base_internal::CurrentThreadIdentityIfPresent();
+ assert(identity != nullptr);
+ const bool is_idle = identity->is_idle.load(std::memory_order_relaxed);
+ const int ticker = identity->ticker.load(std::memory_order_relaxed);
+ const int wait_start = identity->wait_start.load(std::memory_order_relaxed);
+ if (!is_idle && ticker - wait_start > Waiter::kIdlePeriods) {
+ identity->is_idle.store(true, std::memory_order_relaxed);
+ base_internal::MallocExtension::instance()->MarkThreadIdle();
+ }
+}
+
+#if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX
+
+// Some Android headers are missing these definitions even though they
+// support these futex operations.
+#ifdef __BIONIC__
+#ifndef SYS_futex
+#define SYS_futex __NR_futex
+#endif
+#ifndef FUTEX_WAIT_BITSET
+#define FUTEX_WAIT_BITSET 9
+#endif
+#ifndef FUTEX_PRIVATE_FLAG
+#define FUTEX_PRIVATE_FLAG 128
+#endif
+#ifndef FUTEX_CLOCK_REALTIME
+#define FUTEX_CLOCK_REALTIME 256
+#endif
+#ifndef FUTEX_BITSET_MATCH_ANY
+#define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF
+#endif
+#endif
+
+void Waiter::Init() {
+ futex_.store(0, std::memory_order_relaxed);
+}
+
+bool Waiter::Wait(KernelTimeout t) {
+ // Loop until we can atomically decrement futex from a positive
+ // value, waiting on a futex while we believe it is zero.
+ while (true) {
+ int x = futex_.load(std::memory_order_relaxed);
+ if (x != 0) {
+ if (!futex_.compare_exchange_weak(x, x - 1,
+ std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ continue; // Raced with someone, retry.
+ }
+ return true; // Consumed a wakeup, we are done.
+ }
+
+ int err = 0;
+ if (t.has_timeout()) {
+ // https://locklessinc.com/articles/futex_cheat_sheet/
+ // Unlike FUTEX_WAIT, FUTEX_WAIT_BITSET uses absolute time.
+ struct timespec abs_timeout = t.MakeAbsTimespec();
+ // Atomically check that the futex value is still 0, and if it
+ // is, sleep until abs_timeout or until woken by FUTEX_WAKE.
+ err = syscall(
+ SYS_futex, reinterpret_cast<int *>(&futex_),
+ FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, 0,
+ &abs_timeout, nullptr, FUTEX_BITSET_MATCH_ANY);
+ } else {
+ // Atomically check that the futex value is still 0, and if it
+ // is, sleep until woken by FUTEX_WAKE.
+ err = syscall(SYS_futex, reinterpret_cast<int *>(&futex_),
+ FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, nullptr);
+ }
+ if (err != 0) {
+ if (errno == EINTR || errno == EWOULDBLOCK) {
+ // Do nothing, the loop will retry.
+ } else if (errno == ETIMEDOUT) {
+ return false; // Timeout.
+ } else {
+ ABSL_RAW_LOG(FATAL, "Futex operation failed with errno %d\n", errno);
+ }
+ }
+
+ MaybeBecomeIdle();
+ }
+}
+
+void Waiter::Post() {
+ if (futex_.fetch_add(1, std::memory_order_release) == 0) {
+ // We incremented from 0, need to wake a potential waker.
+ Poke();
+ }
+}
+
+void Waiter::Poke() {
+ // Wake one thread waiting on the futex.
+ int err = syscall(SYS_futex, reinterpret_cast<int *>(&futex_),
+ FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1);
+ if (err < 0) {
+ ABSL_RAW_LOG(FATAL, "FUTEX_WAKE failed with errno %d\n", errno);
+ }
+}
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_CONDVAR
+
+class PthreadMutexHolder {
+ public:
+ explicit PthreadMutexHolder(pthread_mutex_t *mu) : mu_(mu) {
+ const int err = pthread_mutex_lock(mu_);
+ if (err != 0) {
+ ABSL_RAW_LOG(FATAL, "pthread_mutex_lock failed: %d", err);
+ }
+ }
+
+ PthreadMutexHolder(const PthreadMutexHolder &rhs) = delete;
+ PthreadMutexHolder &operator=(const PthreadMutexHolder &rhs) = delete;
+
+ ~PthreadMutexHolder() {
+ const int err = pthread_mutex_unlock(mu_);
+ if (err != 0) {
+ ABSL_RAW_LOG(FATAL, "pthread_mutex_unlock failed: %d", err);
+ }
+ }
+
+ private:
+ pthread_mutex_t *mu_;
+};
+
+void Waiter::Init() {
+ const int err = pthread_mutex_init(&mu_, 0);
+ if (err != 0) {
+ ABSL_RAW_LOG(FATAL, "pthread_mutex_init failed: %d", err);
+ }
+
+ const int err2 = pthread_cond_init(&cv_, 0);
+ if (err2 != 0) {
+ ABSL_RAW_LOG(FATAL, "pthread_cond_init failed: %d", err2);
+ }
+
+ waiter_count_.store(0, std::memory_order_relaxed);
+ wakeup_count_.store(0, std::memory_order_relaxed);
+}
+
+bool Waiter::Wait(KernelTimeout t) {
+ struct timespec abs_timeout;
+ if (t.has_timeout()) {
+ abs_timeout = t.MakeAbsTimespec();
+ }
+
+ PthreadMutexHolder h(&mu_);
+ waiter_count_.fetch_add(1, std::memory_order_relaxed);
+ // Loop until we find a wakeup to consume or timeout.
+ while (true) {
+ int x = wakeup_count_.load(std::memory_order_relaxed);
+ if (x != 0) {
+ if (!wakeup_count_.compare_exchange_weak(x, x - 1,
+ std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ continue; // Raced with someone, retry.
+ }
+ // Successfully consumed a wakeup, we're done.
+ waiter_count_.fetch_sub(1, std::memory_order_relaxed);
+ return true;
+ }
+
+ // No wakeups available, time to wait.
+ if (!t.has_timeout()) {
+ const int err = pthread_cond_wait(&cv_, &mu_);
+ if (err != 0) {
+ ABSL_RAW_LOG(FATAL, "pthread_cond_wait failed: %d", err);
+ }
+ } else {
+ const int err = pthread_cond_timedwait(&cv_, &mu_, &abs_timeout);
+ if (err == ETIMEDOUT) {
+ waiter_count_.fetch_sub(1, std::memory_order_relaxed);
+ return false;
+ }
+ if (err != 0) {
+ ABSL_RAW_LOG(FATAL, "pthread_cond_wait failed: %d", err);
+ }
+ }
+ MaybeBecomeIdle();
+ }
+}
+
+void Waiter::Post() {
+ wakeup_count_.fetch_add(1, std::memory_order_release);
+ Poke();
+}
+
+void Waiter::Poke() {
+ if (waiter_count_.load(std::memory_order_relaxed) == 0) {
+ return;
+ }
+ // Potentially a waker. Take the lock and check again.
+ PthreadMutexHolder h(&mu_);
+ if (waiter_count_.load(std::memory_order_relaxed) == 0) {
+ return;
+ }
+ const int err = pthread_cond_signal(&cv_);
+ if (err != 0) {
+ ABSL_RAW_LOG(FATAL, "pthread_cond_signal failed: %d", err);
+ }
+}
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_SEM
+
+void Waiter::Init() {
+ if (sem_init(&sem_, 0, 0) != 0) {
+ ABSL_RAW_LOG(FATAL, "sem_init failed with errno %d\n", errno);
+ }
+ wakeups_.store(0, std::memory_order_relaxed);
+}
+
+bool Waiter::Wait(KernelTimeout t) {
+ struct timespec abs_timeout;
+ if (t.has_timeout()) {
+ abs_timeout = t.MakeAbsTimespec();
+ }
+
+ // Loop until we timeout or consume a wakeup.
+ while (true) {
+ int x = wakeups_.load(std::memory_order_relaxed);
+ if (x != 0) {
+ if (!wakeups_.compare_exchange_weak(x, x - 1,
+ std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ continue; // Raced with someone, retry.
+ }
+ // Successfully consumed a wakeup, we're done.
+ return true;
+ }
+
+ // Nothing to consume, wait (looping on EINTR).
+ while (true) {
+ if (!t.has_timeout()) {
+ if (sem_wait(&sem_) == 0) break;
+ if (errno == EINTR) continue;
+ ABSL_RAW_LOG(FATAL, "sem_wait failed: %d", errno);
+ } else {
+ if (sem_timedwait(&sem_, &abs_timeout) == 0) break;
+ if (errno == EINTR) continue;
+ if (errno == ETIMEDOUT) return false;
+ ABSL_RAW_LOG(FATAL, "sem_timedwait failed: %d", errno);
+ }
+ }
+ MaybeBecomeIdle();
+ }
+}
+
+void Waiter::Post() {
+ wakeups_.fetch_add(1, std::memory_order_release); // Post a wakeup.
+ Poke();
+}
+
+void Waiter::Poke() {
+ if (sem_post(&sem_) != 0) { // Wake any semaphore waiter.
+ ABSL_RAW_LOG(FATAL, "sem_post failed with errno %d\n", errno);
+ }
+}
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32
+
+class LockHolder {
+ public:
+ explicit LockHolder(SRWLOCK* mu) : mu_(mu) {
+ AcquireSRWLockExclusive(mu_);
+ }
+
+ LockHolder(const LockHolder&) = delete;
+ LockHolder& operator=(const LockHolder&) = delete;
+
+ ~LockHolder() {
+ ReleaseSRWLockExclusive(mu_);
+ }
+
+ private:
+ SRWLOCK* mu_;
+};
+
+void Waiter::Init() {
+ InitializeSRWLock(&mu_);
+ InitializeConditionVariable(&cv_);
+ waiter_count_.store(0, std::memory_order_relaxed);
+ wakeup_count_.store(0, std::memory_order_relaxed);
+}
+
+bool Waiter::Wait(KernelTimeout t) {
+ LockHolder h(&mu_);
+ waiter_count_.fetch_add(1, std::memory_order_relaxed);
+
+ // Loop until we find a wakeup to consume or timeout.
+ while (true) {
+ int x = wakeup_count_.load(std::memory_order_relaxed);
+ if (x != 0) {
+ if (!wakeup_count_.compare_exchange_weak(x, x - 1,
+ std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ continue; // Raced with someone, retry.
+ }
+ // Successfully consumed a wakeup, we're done.
+ waiter_count_.fetch_sub(1, std::memory_order_relaxed);
+ return true;
+ }
+
+ // No wakeups available, time to wait.
+ if (!SleepConditionVariableSRW(
+ &cv_, &mu_, t.InMillisecondsFromNow(), 0)) {
+ // GetLastError() returns a Win32 DWORD, but we assign to
+ // unsigned long to simplify the ABSL_RAW_LOG case below. The uniform
+ // initialization guarantees this is not a narrowing conversion.
+ const unsigned long err{GetLastError()}; // NOLINT(runtime/int)
+ if (err == ERROR_TIMEOUT) {
+ waiter_count_.fetch_sub(1, std::memory_order_relaxed);
+ return false;
+ } else {
+ ABSL_RAW_LOG(FATAL, "SleepConditionVariableSRW failed: %lu", err);
+ }
+ }
+
+ MaybeBecomeIdle();
+ }
+}
+
+void Waiter::Post() {
+ wakeup_count_.fetch_add(1, std::memory_order_release);
+ Poke();
+}
+
+void Waiter::Poke() {
+ if (waiter_count_.load(std::memory_order_relaxed) == 0) {
+ return;
+ }
+ // Potentially a waker. Take the lock and check again.
+ LockHolder h(&mu_);
+ if (waiter_count_.load(std::memory_order_relaxed) == 0) {
+ return;
+ }
+ WakeConditionVariable(&cv_);
+}
+
+#else
+#error Unknown ABSL_WAITER_MODE
+#endif
+
+} // namespace synchronization_internal
+} // namespace absl
diff --git a/absl/synchronization/internal/waiter.h b/absl/synchronization/internal/waiter.h
new file mode 100644
index 0000000..025ace4
--- /dev/null
+++ b/absl/synchronization/internal/waiter.h
@@ -0,0 +1,138 @@
+// 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_SYNCHRONIZATION_INTERNAL_WAITER_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_WAITER_H_
+
+#include "absl/base/config.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <pthread.h>
+#endif
+
+#ifdef ABSL_HAVE_SEMAPHORE_H
+#include <semaphore.h>
+#endif
+
+#include <atomic>
+
+#include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/kernel_timeout.h"
+
+// May be chosen at compile time via -DABSL_FORCE_WAITER_MODE=<index>
+#define ABSL_WAITER_MODE_FUTEX 0
+#define ABSL_WAITER_MODE_SEM 1
+#define ABSL_WAITER_MODE_CONDVAR 2
+#define ABSL_WAITER_MODE_WIN32 3
+
+#if defined(ABSL_FORCE_WAITER_MODE)
+#define ABSL_WAITER_MODE ABSL_FORCE_WAITER_MODE
+#elif defined(_WIN32)
+#define ABSL_WAITER_MODE ABSL_WAITER_MODE_WIN32
+#elif defined(__linux__)
+#define ABSL_WAITER_MODE ABSL_WAITER_MODE_FUTEX
+#elif defined(ABSL_HAVE_SEMAPHORE_H)
+#define ABSL_WAITER_MODE ABSL_WAITER_MODE_SEM
+#else
+#define ABSL_WAITER_MODE ABSL_WAITER_MODE_CONDVAR
+#endif
+
+namespace absl {
+namespace synchronization_internal {
+
+// Waiter is an OS-specific semaphore.
+class Waiter {
+ public:
+ // No constructor, instances use the reserved space in ThreadIdentity.
+ // All initialization logic belongs in `Init()`.
+ Waiter() = delete;
+ Waiter(const Waiter&) = delete;
+ Waiter& operator=(const Waiter&) = delete;
+
+ // Prepare any data to track waits.
+ void Init();
+
+ // Blocks the calling thread until a matching call to `Post()` or
+ // `t` has passed. Returns `true` if woken (`Post()` called),
+ // `false` on timeout.
+ bool Wait(KernelTimeout t);
+
+ // Restart the caller of `Wait()` as with a normal semaphore.
+ void Post();
+
+ // If anyone is waiting, wake them up temporarily and cause them to
+ // call `MaybeBecomeIdle()`. They will then return to waiting for a
+ // `Post()` or timeout.
+ void Poke();
+
+ // Returns the Waiter associated with the identity.
+ static Waiter* GetWaiter(base_internal::ThreadIdentity* identity) {
+ static_assert(
+ sizeof(Waiter) <= sizeof(base_internal::ThreadIdentity::WaiterState),
+ "Insufficient space for Waiter");
+ return reinterpret_cast<Waiter*>(identity->waiter_state.data);
+ }
+
+ // How many periods to remain idle before releasing resources
+#ifndef THREAD_SANITIZER
+ static const int kIdlePeriods = 60;
+#else
+ // Memory consumption under ThreadSanitizer is a serious concern,
+ // so we release resources sooner. The value of 1 leads to 1 to 2 second
+ // delay before marking a thread as idle.
+ static const int kIdlePeriods = 1;
+#endif
+
+ private:
+#if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX
+ // Futexes are defined by specification to be ints.
+ // Thus std::atomic<int> must be just an int with lockfree methods.
+ std::atomic<int> futex_;
+ static_assert(sizeof(int) == sizeof(futex_), "Wrong size for futex");
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_CONDVAR
+ pthread_mutex_t mu_;
+ pthread_cond_t cv_;
+ std::atomic<int> waiter_count_;
+ std::atomic<int> wakeup_count_; // Unclaimed wakeups, written under lock.
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_SEM
+ sem_t sem_;
+ // This seems superfluous, but for Poke() we need to cause spurious
+ // wakeups on the semaphore. Hence we can't actually use the
+ // semaphore's count.
+ std::atomic<int> wakeups_;
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32
+ // The Windows API has lots of choices for synchronization
+ // primivitives. We are using SRWLOCK and CONDITION_VARIABLE
+ // because they don't require a destructor to release system
+ // resources.
+ SRWLOCK mu_;
+ CONDITION_VARIABLE cv_;
+ std::atomic<int> waiter_count_;
+ std::atomic<int> wakeup_count_;
+
+#else
+ #error Unknown ABSL_WAITER_MODE
+#endif
+};
+
+} // namespace synchronization_internal
+} // namespace absl
+
+#endif // ABSL_SYNCHRONIZATION_INTERNAL_WAITER_H_
diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc
new file mode 100644
index 0000000..cb0a3a1
--- /dev/null
+++ b/absl/synchronization/mutex.cc
@@ -0,0 +1,2680 @@
+#include "absl/synchronization/mutex.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#ifdef ERROR
+#undef ERROR
+#endif
+#else
+#include <fcntl.h>
+#include <pthread.h>
+#include <sched.h>
+#include <sys/time.h>
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <algorithm>
+#include <atomic>
+#include <cinttypes>
+#include <thread> // NOLINT(build/c++11)
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/atomic_hook.h"
+#include "absl/base/internal/cycleclock.h"
+#include "absl/base/internal/low_level_alloc.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/spinlock.h"
+#include "absl/base/internal/sysinfo.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/base/internal/tsan_mutex_interface.h"
+#include "absl/base/port.h"
+#include "absl/debugging/stacktrace.h"
+#include "absl/synchronization/internal/graphcycles.h"
+#include "absl/synchronization/internal/per_thread_sem.h"
+#include "absl/time/time.h"
+
+using absl::base_internal::CurrentThreadIdentityIfPresent;
+using absl::base_internal::PerThreadSynch;
+using absl::base_internal::ThreadIdentity;
+using absl::synchronization_internal::GetOrCreateCurrentThreadIdentity;
+using absl::synchronization_internal::GraphCycles;
+using absl::synchronization_internal::GraphId;
+using absl::synchronization_internal::InvalidGraphId;
+using absl::synchronization_internal::KernelTimeout;
+using absl::synchronization_internal::PerThreadSem;
+
+extern "C" {
+ABSL_ATTRIBUTE_WEAK void AbslInternalMutexYield() { std::this_thread::yield(); }
+} // extern "C"
+
+namespace absl {
+
+namespace {
+
+#if defined(THREAD_SANITIZER)
+constexpr OnDeadlockCycle kDeadlockDetectionDefault = OnDeadlockCycle::kIgnore;
+#else
+constexpr OnDeadlockCycle kDeadlockDetectionDefault = OnDeadlockCycle::kAbort;
+#endif
+
+ABSL_CONST_INIT std::atomic<OnDeadlockCycle> synch_deadlock_detection(
+ kDeadlockDetectionDefault);
+ABSL_CONST_INIT std::atomic<bool> synch_check_invariants(false);
+
+// ------------------------------------------ spinlock support
+
+// Make sure read-only globals used in the Mutex code are contained on the
+// same cacheline and cacheline aligned to eliminate any false sharing with
+// other globals from this and other modules.
+static struct MutexGlobals {
+ MutexGlobals() {
+ // Find machine-specific data needed for Delay() and
+ // TryAcquireWithSpinning(). This runs in the global constructor
+ // sequence, and before that zeros are safe values.
+ num_cpus = absl::base_internal::NumCPUs();
+ spinloop_iterations = num_cpus > 1 ? 1500 : 0;
+ }
+ int num_cpus;
+ int spinloop_iterations;
+ // Pad this struct to a full cacheline to prevent false sharing.
+ char padding[ABSL_CACHELINE_SIZE - 2 * sizeof(int)];
+} ABSL_CACHELINE_ALIGNED mutex_globals;
+static_assert(
+ sizeof(MutexGlobals) == ABSL_CACHELINE_SIZE,
+ "MutexGlobals must occupy an entire cacheline to prevent false sharing");
+
+ABSL_CONST_INIT absl::base_internal::AtomicHook<void (*)(int64_t wait_cycles)>
+ submit_profile_data;
+ABSL_CONST_INIT absl::base_internal::AtomicHook<
+ void (*)(const char *msg, const void *obj, int64_t wait_cycles)> mutex_tracer;
+ABSL_CONST_INIT absl::base_internal::AtomicHook<
+ void (*)(const char *msg, const void *cv)> cond_var_tracer;
+ABSL_CONST_INIT absl::base_internal::AtomicHook<
+ bool (*)(const void *pc, char *out, int out_size)> symbolizer;
+
+} // namespace
+
+void RegisterMutexProfiler(void (*fn)(int64_t wait_timestamp)) {
+ submit_profile_data.Store(fn);
+}
+
+void RegisterMutexTracer(void (*fn)(const char *msg, const void *obj,
+ int64_t wait_cycles)) {
+ mutex_tracer.Store(fn);
+}
+
+void RegisterCondVarTracer(void (*fn)(const char *msg, const void *cv)) {
+ cond_var_tracer.Store(fn);
+}
+
+void RegisterSymbolizer(bool (*fn)(const void *pc, char *out, int out_size)) {
+ symbolizer.Store(fn);
+}
+
+// spinlock delay on iteration c. Returns new c.
+namespace {
+ enum DelayMode { AGGRESSIVE, GENTLE };
+};
+static int Delay(int32_t c, DelayMode mode) {
+ // If this a uniprocessor, only yield/sleep. Otherwise, if the mode is
+ // aggressive then spin many times before yielding. If the mode is
+ // gentle then spin only a few times before yielding. Aggressive spinning is
+ // used to ensure that an Unlock() call, which must get the spin lock for
+ // any thread to make progress gets it without undue delay.
+ int32_t limit = (mutex_globals.num_cpus > 1) ?
+ ((mode == AGGRESSIVE) ? 5000 : 250) : 0;
+ if (c < limit) {
+ c++; // spin
+ } else {
+ ABSL_TSAN_MUTEX_PRE_DIVERT(0, 0);
+ if (c == limit) { // yield once
+ AbslInternalMutexYield();
+ c++;
+ } else { // then wait
+ absl::SleepFor(absl::Microseconds(10));
+ c = 0;
+ }
+ ABSL_TSAN_MUTEX_POST_DIVERT(0, 0);
+ }
+ return (c);
+}
+
+// --------------------------Generic atomic ops
+// Ensure that "(*pv & bits) == bits" by doing an atomic update of "*pv" to
+// "*pv | bits" if necessary. Wait until (*pv & wait_until_clear)==0
+// before making any change.
+// This is used to set flags in mutex and condition variable words.
+static void AtomicSetBits(std::atomic<intptr_t>* pv, intptr_t bits,
+ intptr_t wait_until_clear) {
+ intptr_t v;
+ do {
+ v = pv->load(std::memory_order_relaxed);
+ } while ((v & bits) != bits &&
+ ((v & wait_until_clear) != 0 ||
+ !pv->compare_exchange_weak(v, v | bits,
+ std::memory_order_release,
+ std::memory_order_relaxed)));
+}
+
+// Ensure that "(*pv & bits) == 0" by doing an atomic update of "*pv" to
+// "*pv & ~bits" if necessary. Wait until (*pv & wait_until_clear)==0
+// before making any change.
+// This is used to unset flags in mutex and condition variable words.
+static void AtomicClearBits(std::atomic<intptr_t>* pv, intptr_t bits,
+ intptr_t wait_until_clear) {
+ intptr_t v;
+ do {
+ v = pv->load(std::memory_order_relaxed);
+ } while ((v & bits) != 0 &&
+ ((v & wait_until_clear) != 0 ||
+ !pv->compare_exchange_weak(v, v & ~bits,
+ std::memory_order_release,
+ std::memory_order_relaxed)));
+}
+
+//------------------------------------------------------------------
+
+// Data for doing deadlock detection.
+static absl::base_internal::SpinLock deadlock_graph_mu(
+ absl::base_internal::kLinkerInitialized);
+
+// graph used to detect deadlocks.
+static GraphCycles *deadlock_graph GUARDED_BY(deadlock_graph_mu)
+ PT_GUARDED_BY(deadlock_graph_mu);
+
+//------------------------------------------------------------------
+// An event mechanism for debugging mutex use.
+// It also allows mutexes to be given names for those who can't handle
+// addresses, and instead like to give their data structures names like
+// "Henry", "Fido", or "Rupert IV, King of Yondavia".
+
+namespace { // to prevent name pollution
+enum { // Mutex and CondVar events passed as "ev" to PostSynchEvent
+ // Mutex events
+ SYNCH_EV_TRYLOCK_SUCCESS,
+ SYNCH_EV_TRYLOCK_FAILED,
+ SYNCH_EV_READERTRYLOCK_SUCCESS,
+ SYNCH_EV_READERTRYLOCK_FAILED,
+ SYNCH_EV_LOCK,
+ SYNCH_EV_LOCK_RETURNING,
+ SYNCH_EV_READERLOCK,
+ SYNCH_EV_READERLOCK_RETURNING,
+ SYNCH_EV_UNLOCK,
+ SYNCH_EV_READERUNLOCK,
+
+ // CondVar events
+ SYNCH_EV_WAIT,
+ SYNCH_EV_WAIT_RETURNING,
+ SYNCH_EV_SIGNAL,
+ SYNCH_EV_SIGNALALL,
+};
+
+enum { // Event flags
+ SYNCH_F_R = 0x01, // reader event
+ SYNCH_F_LCK = 0x02, // PostSynchEvent called with mutex held
+ SYNCH_F_ACQ = 0x04, // event is an acquire
+
+ SYNCH_F_LCK_W = SYNCH_F_LCK,
+ SYNCH_F_LCK_R = SYNCH_F_LCK | SYNCH_F_R,
+ SYNCH_F_ACQ_W = SYNCH_F_ACQ,
+ SYNCH_F_ACQ_R = SYNCH_F_ACQ | SYNCH_F_R,
+};
+} // anonymous namespace
+
+// Properties of the events.
+static const struct {
+ int flags;
+ const char *msg;
+} event_properties[] = {
+ { SYNCH_F_LCK_W|SYNCH_F_ACQ_W, "TryLock succeeded " },
+ { 0, "TryLock failed " },
+ { SYNCH_F_LCK_R|SYNCH_F_ACQ_R, "ReaderTryLock succeeded " },
+ { 0, "ReaderTryLock failed " },
+ { SYNCH_F_ACQ_W, "Lock blocking " },
+ { SYNCH_F_LCK_W, "Lock returning " },
+ { SYNCH_F_ACQ_R, "ReaderLock blocking " },
+ { SYNCH_F_LCK_R, "ReaderLock returning " },
+ { SYNCH_F_LCK_W, "Unlock " },
+ { SYNCH_F_LCK_R, "ReaderUnlock " },
+ { 0, "Wait on " },
+ { 0, "Wait unblocked " },
+ { 0, "Signal on " },
+ { 0, "SignalAll on " },
+};
+
+static absl::base_internal::SpinLock synch_event_mu(
+ absl::base_internal::kLinkerInitialized);
+// protects synch_event
+
+// Hash table size; should be prime > 2.
+// Can't be too small, as it's used for deadlock detection information.
+static const uint32_t kNSynchEvent = 1031;
+
+// We need to hide Mutexes (or other deadlock detection's pointers)
+// from the leak detector.
+static const uintptr_t kHideMask = static_cast<uintptr_t>(0xF03A5F7BF03A5F7BLL);
+static uintptr_t MaskMu(const void *mu) {
+ return reinterpret_cast<uintptr_t>(mu) ^ kHideMask;
+}
+
+static struct SynchEvent { // this is a trivial hash table for the events
+ // struct is freed when refcount reaches 0
+ int refcount GUARDED_BY(synch_event_mu);
+
+ // buckets have linear, 0-terminated chains
+ SynchEvent *next GUARDED_BY(synch_event_mu);
+
+ // Constant after initialization
+ uintptr_t masked_addr; // object at this address is called "name"
+
+ // No explicit synchronization used. Instead we assume that the
+ // client who enables/disables invariants/logging on a Mutex does so
+ // while the Mutex is not being concurrently accessed by others.
+ void (*invariant)(void *arg); // called on each event
+ void *arg; // first arg to (*invariant)()
+ bool log; // logging turned on
+
+ // Constant after initialization
+ char name[1]; // actually longer---null-terminated std::string
+} *synch_event[kNSynchEvent] GUARDED_BY(synch_event_mu);
+
+// Ensure that the object at "addr" has a SynchEvent struct associated with it,
+// set "bits" in the word there (waiting until lockbit is clear before doing
+// so), and return a refcounted reference that will remain valid until
+// UnrefSynchEvent() is called. If a new SynchEvent is allocated,
+// the std::string name is copied into it.
+// When used with a mutex, the caller should also ensure that kMuEvent
+// is set in the mutex word, and similarly for condition variables and kCVEvent.
+static SynchEvent *EnsureSynchEvent(std::atomic<intptr_t> *addr,
+ const char *name, intptr_t bits,
+ intptr_t lockbit) {
+ uint32_t h = reinterpret_cast<intptr_t>(addr) % kNSynchEvent;
+ SynchEvent *e;
+ // first look for existing SynchEvent struct..
+ synch_event_mu.Lock();
+ for (e = synch_event[h]; e != nullptr && e->masked_addr != MaskMu(addr);
+ e = e->next) {
+ }
+ if (e == nullptr) { // no SynchEvent struct found; make one.
+ if (name == nullptr) {
+ name = "";
+ }
+ size_t l = strlen(name);
+ e = reinterpret_cast<SynchEvent *>(
+ base_internal::LowLevelAlloc::Alloc(sizeof(*e) + l));
+ e->refcount = 2; // one for return value, one for linked list
+ e->masked_addr = MaskMu(addr);
+ e->invariant = nullptr;
+ e->arg = nullptr;
+ e->log = false;
+ strcpy(e->name, name); // NOLINT(runtime/printf)
+ e->next = synch_event[h];
+ AtomicSetBits(addr, bits, lockbit);
+ synch_event[h] = e;
+ } else {
+ e->refcount++; // for return value
+ }
+ synch_event_mu.Unlock();
+ return e;
+}
+
+// Deallocate the SynchEvent *e, whose refcount has fallen to zero.
+static void DeleteSynchEvent(SynchEvent *e) {
+ base_internal::LowLevelAlloc::Free(e);
+}
+
+// Decrement the reference count of *e, or do nothing if e==null.
+static void UnrefSynchEvent(SynchEvent *e) {
+ if (e != nullptr) {
+ synch_event_mu.Lock();
+ bool del = (--(e->refcount) == 0);
+ synch_event_mu.Unlock();
+ if (del) {
+ DeleteSynchEvent(e);
+ }
+ }
+}
+
+// Forget the mapping from the object (Mutex or CondVar) at address addr
+// to SynchEvent object, and clear "bits" in its word (waiting until lockbit
+// is clear before doing so).
+static void ForgetSynchEvent(std::atomic<intptr_t> *addr, intptr_t bits,
+ intptr_t lockbit) {
+ uint32_t h = reinterpret_cast<intptr_t>(addr) % kNSynchEvent;
+ SynchEvent **pe;
+ SynchEvent *e;
+ synch_event_mu.Lock();
+ for (pe = &synch_event[h];
+ (e = *pe) != nullptr && e->masked_addr != MaskMu(addr); pe = &e->next) {
+ }
+ bool del = false;
+ if (e != nullptr) {
+ *pe = e->next;
+ del = (--(e->refcount) == 0);
+ }
+ AtomicClearBits(addr, bits, lockbit);
+ synch_event_mu.Unlock();
+ if (del) {
+ DeleteSynchEvent(e);
+ }
+}
+
+// Return a refcounted reference to the SynchEvent of the object at address
+// "addr", if any. The pointer returned is valid until the UnrefSynchEvent() is
+// called.
+static SynchEvent *GetSynchEvent(const void *addr) {
+ uint32_t h = reinterpret_cast<intptr_t>(addr) % kNSynchEvent;
+ SynchEvent *e;
+ synch_event_mu.Lock();
+ for (e = synch_event[h]; e != nullptr && e->masked_addr != MaskMu(addr);
+ e = e->next) {
+ }
+ if (e != nullptr) {
+ e->refcount++;
+ }
+ synch_event_mu.Unlock();
+ return e;
+}
+
+// Called when an event "ev" occurs on a Mutex of CondVar "obj"
+// if event recording is on
+static void PostSynchEvent(void *obj, int ev) {
+ SynchEvent *e = GetSynchEvent(obj);
+ // logging is on if event recording is on and either there's no event struct,
+ // or it explicitly says to log
+ if (e == nullptr || e->log) {
+ void *pcs[40];
+ int n = absl::GetStackTrace(pcs, ABSL_ARRAYSIZE(pcs), 1);
+ // A buffer with enough space for the ASCII for all the PCs, even on a
+ // 64-bit machine.
+ char buffer[ABSL_ARRAYSIZE(pcs) * 24];
+ int pos = snprintf(buffer, sizeof (buffer), " @");
+ for (int i = 0; i != n; i++) {
+ pos += snprintf(&buffer[pos], sizeof (buffer) - pos, " %p", pcs[i]);
+ }
+ ABSL_RAW_LOG(INFO, "%s%p %s %s", event_properties[ev].msg, obj,
+ (e == nullptr ? "" : e->name), buffer);
+ }
+ if ((event_properties[ev].flags & SYNCH_F_LCK) != 0 && e != nullptr &&
+ e->invariant != nullptr) {
+ (*e->invariant)(e->arg);
+ }
+ UnrefSynchEvent(e);
+}
+
+//------------------------------------------------------------------
+
+// The SynchWaitParams struct encapsulates the way in which a thread is waiting:
+// whether it has a timeout, the condition, exclusive/shared, and whether a
+// condition variable wait has an associated Mutex (as opposed to another
+// type of lock). It also points to the PerThreadSynch struct of its thread.
+// cv_word tells Enqueue() to enqueue on a CondVar using CondVarEnqueue().
+//
+// This structure is held on the stack rather than directly in
+// PerThreadSynch because a thread can be waiting on multiple Mutexes if,
+// while waiting on one Mutex, the implementation calls a client callback
+// (such as a Condition function) that acquires another Mutex. We don't
+// strictly need to allow this, but programmers become confused if we do not
+// allow them to use functions such a LOG() within Condition functions. The
+// PerThreadSynch struct points at the most recent SynchWaitParams struct when
+// the thread is on a Mutex's waiter queue.
+struct SynchWaitParams {
+ SynchWaitParams(Mutex::MuHow how_arg, const Condition *cond_arg,
+ KernelTimeout timeout_arg, Mutex *cvmu_arg,
+ PerThreadSynch *thread_arg,
+ std::atomic<intptr_t> *cv_word_arg)
+ : how(how_arg),
+ cond(cond_arg),
+ timeout(timeout_arg),
+ cvmu(cvmu_arg),
+ thread(thread_arg),
+ cv_word(cv_word_arg),
+ contention_start_cycles(base_internal::CycleClock::Now()) {}
+
+ const Mutex::MuHow how; // How this thread needs to wait.
+ const Condition *cond; // The condition that this thread is waiting for.
+ // In Mutex, this field is set to zero if a timeout
+ // expires.
+ KernelTimeout timeout; // timeout expiry---absolute time
+ // In Mutex, this field is set to zero if a timeout
+ // expires.
+ Mutex *const cvmu; // used for transfer from cond var to mutex
+ PerThreadSynch *const thread; // thread that is waiting
+
+ // If not null, thread should be enqueued on the CondVar whose state
+ // word is cv_word instead of queueing normally on the Mutex.
+ std::atomic<intptr_t> *cv_word;
+
+ int64_t contention_start_cycles; // Time (in cycles) when this thread started
+ // to contend for the mutex.
+};
+
+struct SynchLocksHeld {
+ int n; // number of valid entries in locks[]
+ bool overflow; // true iff we overflowed the array at some point
+ struct {
+ Mutex *mu; // lock acquired
+ int32_t count; // times acquired
+ GraphId id; // deadlock_graph id of acquired lock
+ } locks[40];
+ // If a thread overfills the array during deadlock detection, we
+ // continue, discarding information as needed. If no overflow has
+ // taken place, we can provide more error checking, such as
+ // detecting when a thread releases a lock it does not hold.
+};
+
+// A sentinel value in lists that is not 0.
+// A 0 value is used to mean "not on a list".
+static PerThreadSynch *const kPerThreadSynchNull =
+ reinterpret_cast<PerThreadSynch *>(1);
+
+static SynchLocksHeld *LocksHeldAlloc() {
+ SynchLocksHeld *ret = reinterpret_cast<SynchLocksHeld *>(
+ base_internal::LowLevelAlloc::Alloc(sizeof(SynchLocksHeld)));
+ ret->n = 0;
+ ret->overflow = false;
+ return ret;
+}
+
+// Return the PerThreadSynch-struct for this thread.
+static PerThreadSynch *Synch_GetPerThread() {
+ ThreadIdentity *identity = GetOrCreateCurrentThreadIdentity();
+ return &identity->per_thread_synch;
+}
+
+static PerThreadSynch *Synch_GetPerThreadAnnotated(Mutex *mu) {
+ if (mu) {
+ ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0);
+ }
+ PerThreadSynch *w = Synch_GetPerThread();
+ if (mu) {
+ ABSL_TSAN_MUTEX_POST_DIVERT(mu, 0);
+ }
+ return w;
+}
+
+static SynchLocksHeld *Synch_GetAllLocks() {
+ PerThreadSynch *s = Synch_GetPerThread();
+ if (s->all_locks == nullptr) {
+ s->all_locks = LocksHeldAlloc(); // Freed by ReclaimThreadIdentity.
+ }
+ return s->all_locks;
+}
+
+// Post on "w"'s associated PerThreadSem.
+inline void Mutex::IncrementSynchSem(Mutex *mu, PerThreadSynch *w) {
+ if (mu) {
+ ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0);
+ }
+ PerThreadSem::Post(w->thread_identity());
+ if (mu) {
+ ABSL_TSAN_MUTEX_POST_DIVERT(mu, 0);
+ }
+}
+
+// Wait on "w"'s associated PerThreadSem; returns false if timeout expired.
+bool Mutex::DecrementSynchSem(Mutex *mu, PerThreadSynch *w, KernelTimeout t) {
+ if (mu) {
+ ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0);
+ }
+ assert(w == Synch_GetPerThread());
+ static_cast<void>(w);
+ bool res = PerThreadSem::Wait(t);
+ if (mu) {
+ ABSL_TSAN_MUTEX_POST_DIVERT(mu, 0);
+ }
+ return res;
+}
+
+// We're in a fatal signal handler that hopes to use Mutex and to get
+// lucky by not deadlocking. We try to improve its chances of success
+// by effectively disabling some of the consistency checks. This will
+// prevent certain ABSL_RAW_CHECK() statements from being triggered when
+// re-rentry is detected. The ABSL_RAW_CHECK() statements are those in the
+// Mutex code checking that the "waitp" field has not been reused.
+void Mutex::InternalAttemptToUseMutexInFatalSignalHandler() {
+ // Fix the per-thread state only if it exists.
+ ThreadIdentity *identity = CurrentThreadIdentityIfPresent();
+ if (identity != nullptr) {
+ identity->per_thread_synch.suppress_fatal_errors = true;
+ }
+ // Don't do deadlock detection when we are already failing.
+ synch_deadlock_detection.store(OnDeadlockCycle::kIgnore,
+ std::memory_order_release);
+}
+
+// --------------------------time support
+
+// Return the current time plus the timeout. Use the same clock as
+// PerThreadSem::Wait() for consistency. Unfortunately, we don't have
+// such a choice when a deadline is given directly.
+static absl::Time DeadlineFromTimeout(absl::Duration timeout) {
+#ifndef _WIN32
+ struct timeval tv;
+ gettimeofday(&tv, nullptr);
+ return absl::TimeFromTimeval(tv) + timeout;
+#else
+ return absl::Now() + timeout;
+#endif
+}
+
+// --------------------------Mutexes
+
+// In the layout below, the msb of the bottom byte is currently unused. Also,
+// the following constraints were considered in choosing the layout:
+// o Both the debug allocator's "uninitialized" and "freed" patterns (0xab and
+// 0xcd) are illegal: reader and writer lock both held.
+// o kMuWriter and kMuEvent should exceed kMuDesig and kMuWait, to enable the
+// bit-twiddling trick in Mutex::Unlock().
+// o kMuWriter / kMuReader == kMuWrWait / kMuWait,
+// to enable the bit-twiddling trick in CheckForMutexCorruption().
+static const intptr_t kMuReader = 0x0001L; // a reader holds the lock
+static const intptr_t kMuDesig = 0x0002L; // there's a designated waker
+static const intptr_t kMuWait = 0x0004L; // threads are waiting
+static const intptr_t kMuWriter = 0x0008L; // a writer holds the lock
+static const intptr_t kMuEvent = 0x0010L; // record this mutex's events
+// INVARIANT1: there's a thread that was blocked on the mutex, is
+// no longer, yet has not yet acquired the mutex. If there's a
+// designated waker, all threads can avoid taking the slow path in
+// unlock because the designated waker will subsequently acquire
+// the lock and wake someone. To maintain INVARIANT1 the bit is
+// set when a thread is unblocked(INV1a), and threads that were
+// unblocked reset the bit when they either acquire or re-block
+// (INV1b).
+static const intptr_t kMuWrWait = 0x0020L; // runnable writer is waiting
+ // for a reader
+static const intptr_t kMuSpin = 0x0040L; // spinlock protects wait list
+static const intptr_t kMuLow = 0x00ffL; // mask all mutex bits
+static const intptr_t kMuHigh = ~kMuLow; // mask pointer/reader count
+
+// Hack to make constant values available to gdb pretty printer
+enum {
+ kGdbMuSpin = kMuSpin,
+ kGdbMuEvent = kMuEvent,
+ kGdbMuWait = kMuWait,
+ kGdbMuWriter = kMuWriter,
+ kGdbMuDesig = kMuDesig,
+ kGdbMuWrWait = kMuWrWait,
+ kGdbMuReader = kMuReader,
+ kGdbMuLow = kMuLow,
+};
+
+// kMuWrWait implies kMuWait.
+// kMuReader and kMuWriter are mutually exclusive.
+// If kMuReader is zero, there are no readers.
+// Otherwise, if kMuWait is zero, the high order bits contain a count of the
+// number of readers. Otherwise, the reader count is held in
+// PerThreadSynch::readers of the most recently queued waiter, again in the
+// bits above kMuLow.
+static const intptr_t kMuOne = 0x0100; // a count of one reader
+
+// flags passed to Enqueue and LockSlow{,WithTimeout,Loop}
+static const int kMuHasBlocked = 0x01; // already blocked (MUST == 1)
+static const int kMuIsCond = 0x02; // conditional waiter (CV or Condition)
+
+static_assert(PerThreadSynch::kAlignment > kMuLow,
+ "PerThreadSynch::kAlignment must be greater than kMuLow");
+
+// This struct contains various bitmasks to be used in
+// acquiring and releasing a mutex in a particular mode.
+struct MuHowS {
+ // if all the bits in fast_need_zero are zero, the lock can be acquired by
+ // adding fast_add and oring fast_or. The bit kMuDesig should be reset iff
+ // this is the designated waker.
+ intptr_t fast_need_zero;
+ intptr_t fast_or;
+ intptr_t fast_add;
+
+ intptr_t slow_need_zero; // fast_need_zero with events (e.g. logging)
+
+ intptr_t slow_inc_need_zero; // if all the bits in slow_inc_need_zero are
+ // zero a reader can acquire a read share by
+ // setting the reader bit and incrementing
+ // the reader count (in last waiter since
+ // we're now slow-path). kMuWrWait be may
+ // be ignored if we already waited once.
+};
+
+static const MuHowS kSharedS = {
+ // shared or read lock
+ kMuWriter | kMuWait | kMuEvent, // fast_need_zero
+ kMuReader, // fast_or
+ kMuOne, // fast_add
+ kMuWriter | kMuWait, // slow_need_zero
+ kMuSpin | kMuWriter | kMuWrWait, // slow_inc_need_zero
+};
+static const MuHowS kExclusiveS = {
+ // exclusive or write lock
+ kMuWriter | kMuReader | kMuEvent, // fast_need_zero
+ kMuWriter, // fast_or
+ 0, // fast_add
+ kMuWriter | kMuReader, // slow_need_zero
+ ~static_cast<intptr_t>(0), // slow_inc_need_zero
+};
+static const Mutex::MuHow kShared = &kSharedS; // shared lock
+static const Mutex::MuHow kExclusive = &kExclusiveS; // exclusive lock
+
+#ifdef NDEBUG
+static constexpr bool kDebugMode = false;
+#else
+static constexpr bool kDebugMode = true;
+#endif
+
+#ifdef THREAD_SANITIZER
+static unsigned TsanFlags(Mutex::MuHow how) {
+ return how == kShared ? __tsan_mutex_read_lock : 0;
+}
+#endif
+
+Mutex::Mutex() : mu_(0) {
+ ABSL_TSAN_MUTEX_CREATE(this, 0);
+}
+
+static bool DebugOnlyIsExiting() {
+ return false;
+}
+
+Mutex::~Mutex() {
+ intptr_t v = mu_.load(std::memory_order_relaxed);
+ if ((v & kMuEvent) != 0 && !DebugOnlyIsExiting()) {
+ ForgetSynchEvent(&this->mu_, kMuEvent, kMuSpin);
+ }
+ if (kDebugMode) {
+ this->ForgetDeadlockInfo();
+ }
+ ABSL_TSAN_MUTEX_DESTROY(this, 0);
+}
+
+void Mutex::EnableDebugLog(const char *name) {
+ SynchEvent *e = EnsureSynchEvent(&this->mu_, name, kMuEvent, kMuSpin);
+ e->log = true;
+ UnrefSynchEvent(e);
+}
+
+void EnableMutexInvariantDebugging(bool enabled) {
+ synch_check_invariants.store(enabled, std::memory_order_release);
+}
+
+void Mutex::EnableInvariantDebugging(void (*invariant)(void *),
+ void *arg) {
+ if (synch_check_invariants.load(std::memory_order_acquire) &&
+ invariant != nullptr) {
+ SynchEvent *e = EnsureSynchEvent(&this->mu_, nullptr, kMuEvent, kMuSpin);
+ e->invariant = invariant;
+ e->arg = arg;
+ UnrefSynchEvent(e);
+ }
+}
+
+void SetMutexDeadlockDetectionMode(OnDeadlockCycle mode) {
+ synch_deadlock_detection.store(mode, std::memory_order_release);
+}
+
+// Return true iff threads x and y are waiting on the same condition for the
+// same type of lock. Requires that x and y be waiting on the same Mutex
+// queue.
+static bool MuSameCondition(PerThreadSynch *x, PerThreadSynch *y) {
+ return x->waitp->how == y->waitp->how &&
+ Condition::GuaranteedEqual(x->waitp->cond, y->waitp->cond);
+}
+
+// Given the contents of a mutex word containing a PerThreadSynch pointer,
+// return the pointer.
+static inline PerThreadSynch *GetPerThreadSynch(intptr_t v) {
+ return reinterpret_cast<PerThreadSynch *>(v & kMuHigh);
+}
+
+// The next several routines maintain the per-thread next and skip fields
+// used in the Mutex waiter queue.
+// The queue is a circular singly-linked list, of which the "head" is the
+// last element, and head->next if the first element.
+// The skip field has the invariant:
+// For thread x, x->skip is one of:
+// - invalid (iff x is not in a Mutex wait queue),
+// - null, or
+// - a pointer to a distinct thread waiting later in the same Mutex queue
+// such that all threads in [x, x->skip] have the same condition and
+// lock type (MuSameCondition() is true for all pairs in [x, x->skip]).
+// In addition, if x->skip is valid, (x->may_skip || x->skip == null)
+//
+// By the spec of MuSameCondition(), it is not necessary when removing the
+// first runnable thread y from the front a Mutex queue to adjust the skip
+// field of another thread x because if x->skip==y, x->skip must (have) become
+// invalid before y is removed. The function TryRemove can remove a specified
+// thread from an arbitrary position in the queue whether runnable or not, so
+// it fixes up skip fields that would otherwise be left dangling.
+// The statement
+// if (x->may_skip && MuSameCondition(x, x->next)) { x->skip = x->next; }
+// maintains the invariant provided x is not the last waiter in a Mutex queue
+// The statement
+// if (x->skip != null) { x->skip = x->skip->skip; }
+// maintains the invariant.
+
+// Returns the last thread y in a mutex waiter queue such that all threads in
+// [x, y] inclusive share the same condition. Sets skip fields of some threads
+// in that range to optimize future evaluation of Skip() on x values in
+// the range. Requires thread x is in a mutex waiter queue.
+// The locking is unusual. Skip() is called under these conditions:
+// - spinlock is held in call from Enqueue(), with maybe_unlocking == false
+// - Mutex is held in call from UnlockSlow() by last unlocker, with
+// maybe_unlocking == true
+// - both Mutex and spinlock are held in call from DequeueAllWakeable() (from
+// UnlockSlow()) and TryRemove()
+// These cases are mutually exclusive, so Skip() never runs concurrently
+// with itself on the same Mutex. The skip chain is used in these other places
+// that cannot occur concurrently:
+// - FixSkip() (from TryRemove()) - spinlock and Mutex are held)
+// - Dequeue() (with spinlock and Mutex held)
+// - UnlockSlow() (with spinlock and Mutex held)
+// A more complex case is Enqueue()
+// - Enqueue() (with spinlock held and maybe_unlocking == false)
+// This is the first case in which Skip is called, above.
+// - Enqueue() (without spinlock held; but queue is empty and being freshly
+// formed)
+// - Enqueue() (with spinlock held and maybe_unlocking == true)
+// The first case has mutual exclusion, and the second isolation through
+// working on an otherwise unreachable data structure.
+// In the last case, Enqueue() is required to change no skip/next pointers
+// except those in the added node and the former "head" node. This implies
+// that the new node is added after head, and so must be the new head or the
+// new front of the queue.
+static PerThreadSynch *Skip(PerThreadSynch *x) {
+ PerThreadSynch *x0 = nullptr;
+ PerThreadSynch *x1 = x;
+ PerThreadSynch *x2 = x->skip;
+ if (x2 != nullptr) {
+ // Each iteration attempts to advance sequence (x0,x1,x2) to next sequence
+ // such that x1 == x0->skip && x2 == x1->skip
+ while ((x0 = x1, x1 = x2, x2 = x2->skip) != nullptr) {
+ x0->skip = x2; // short-circuit skip from x0 to x2
+ }
+ x->skip = x1; // short-circuit skip from x to result
+ }
+ return x1;
+}
+
+// "ancestor" appears before "to_be_removed" in the same Mutex waiter queue.
+// The latter is going to be removed out of order, because of a timeout.
+// Check whether "ancestor" has a skip field pointing to "to_be_removed",
+// and fix it if it does.
+static void FixSkip(PerThreadSynch *ancestor, PerThreadSynch *to_be_removed) {
+ if (ancestor->skip == to_be_removed) { // ancestor->skip left dangling
+ if (to_be_removed->skip != nullptr) {
+ ancestor->skip = to_be_removed->skip; // can skip past to_be_removed
+ } else if (ancestor->next != to_be_removed) { // they are not adjacent
+ ancestor->skip = ancestor->next; // can skip one past ancestor
+ } else {
+ ancestor->skip = nullptr; // can't skip at all
+ }
+ }
+}
+
+static void CondVarEnqueue(SynchWaitParams *waitp);
+
+// Enqueue thread "waitp->thread" on a waiter queue.
+// Called with mutex spinlock held if head != nullptr
+// If head==nullptr and waitp->cv_word==nullptr, then Enqueue() is
+// idempotent; it alters no state associated with the existing (empty)
+// queue.
+//
+// If waitp->cv_word == nullptr, queue the thread at either the front or
+// the end (according to its priority) of the circular mutex waiter queue whose
+// head is "head", and return the new head. mu is the previous mutex state,
+// which contains the reader count (perhaps adjusted for the operation in
+// progress) if the list was empty and a read lock held, and the holder hint if
+// the list was empty and a write lock held. (flags & kMuIsCond) indicates
+// whether this thread was transferred from a CondVar or is waiting for a
+// non-trivial condition. In this case, Enqueue() never returns nullptr
+//
+// If waitp->cv_word != nullptr, CondVarEnqueue() is called, and "head" is
+// returned. This mechanism is used by CondVar to queue a thread on the
+// condition variable queue instead of the mutex queue in implementing Wait().
+// In this case, Enqueue() can return nullptr (if head==nullptr).
+static PerThreadSynch *Enqueue(PerThreadSynch *head,
+ SynchWaitParams *waitp, intptr_t mu, int flags) {
+ // If we have been given a cv_word, call CondVarEnqueue() and return
+ // the previous head of the Mutex waiter queue.
+ if (waitp->cv_word != nullptr) {
+ CondVarEnqueue(waitp);
+ return head;
+ }
+
+ PerThreadSynch *s = waitp->thread;
+ ABSL_RAW_CHECK(
+ s->waitp == nullptr || // normal case
+ s->waitp == waitp || // Fer()---transfer from condition variable
+ s->suppress_fatal_errors,
+ "detected illegal recursion into Mutex code");
+ s->waitp = waitp;
+ s->skip = nullptr; // maintain skip invariant (see above)
+ s->may_skip = true; // always true on entering queue
+ s->wake = false; // not being woken
+ s->cond_waiter = ((flags & kMuIsCond) != 0);
+ if (head == nullptr) { // s is the only waiter
+ s->next = s; // it's the only entry in the cycle
+ s->readers = mu; // reader count is from mu word
+ s->maybe_unlocking = false; // no one is searching an empty list
+ head = s; // s is new head
+ } else {
+ PerThreadSynch *enqueue_after = nullptr; // we'll put s after this element
+#ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM
+ int64_t now_cycles = base_internal::CycleClock::Now();
+ if (s->next_priority_read_cycles < now_cycles) {
+ // Every so often, update our idea of the thread's priority.
+ // pthread_getschedparam() is 5% of the block/wakeup time;
+ // base_internal::CycleClock::Now() is 0.5%.
+ int policy;
+ struct sched_param param;
+ pthread_getschedparam(pthread_self(), &policy, &param);
+ s->priority = param.sched_priority;
+ s->next_priority_read_cycles =
+ now_cycles +
+ static_cast<int64_t>(base_internal::CycleClock::Frequency());
+ }
+ if (s->priority > head->priority) { // s's priority is above head's
+ // try to put s in priority-fifo order, or failing that at the front.
+ if (!head->maybe_unlocking) {
+ // No unlocker can be scanning the queue, so we can insert between
+ // skip-chains, and within a skip-chain if it has the same condition as
+ // s. We insert in priority-fifo order, examining the end of every
+ // skip-chain, plus every element with the same condition as s.
+ PerThreadSynch *advance_to = head; // next value of enqueue_after
+ PerThreadSynch *cur; // successor of enqueue_after
+ do {
+ enqueue_after = advance_to;
+ cur = enqueue_after->next; // this advance ensures progress
+ advance_to = Skip(cur); // normally, advance to end of skip chain
+ // (side-effect: optimizes skip chain)
+ if (advance_to != cur && s->priority > advance_to->priority &&
+ MuSameCondition(s, cur)) {
+ // but this skip chain is not a singleton, s has higher priority
+ // than its tail and has the same condition as the chain,
+ // so we can insert within the skip-chain
+ advance_to = cur; // advance by just one
+ }
+ } while (s->priority <= advance_to->priority);
+ // termination guaranteed because s->priority > head->priority
+ // and head is the end of a skip chain
+ } else if (waitp->how == kExclusive &&
+ Condition::GuaranteedEqual(waitp->cond, nullptr)) {
+ // An unlocker could be scanning the queue, but we know it will recheck
+ // the queue front for writers that have no condition, which is what s
+ // is, so an insert at front is safe.
+ enqueue_after = head; // add after head, at front
+ }
+ }
+#endif
+ if (enqueue_after != nullptr) {
+ s->next = enqueue_after->next;
+ enqueue_after->next = s;
+
+ // enqueue_after can be: head, Skip(...), or cur.
+ // The first two imply enqueue_after->skip == nullptr, and
+ // the last is used only if MuSameCondition(s, cur).
+ // We require this because clearing enqueue_after->skip
+ // is impossible; enqueue_after's predecessors might also
+ // incorrectly skip over s if we were to allow other
+ // insertion points.
+ ABSL_RAW_CHECK(
+ enqueue_after->skip == nullptr || MuSameCondition(enqueue_after, s),
+ "Mutex Enqueue failure");
+
+ if (enqueue_after != head && enqueue_after->may_skip &&
+ MuSameCondition(enqueue_after, enqueue_after->next)) {
+ // enqueue_after can skip to its new successor, s
+ enqueue_after->skip = enqueue_after->next;
+ }
+ if (MuSameCondition(s, s->next)) { // s->may_skip is known to be true
+ s->skip = s->next; // s may skip to its successor
+ }
+ } else { // enqueue not done any other way, so
+ // we're inserting s at the back
+ // s will become new head; copy data from head into it
+ s->next = head->next; // add s after head
+ head->next = s;
+ s->readers = head->readers; // reader count is from previous head
+ s->maybe_unlocking = head->maybe_unlocking; // same for unlock hint
+ if (head->may_skip && MuSameCondition(head, s)) {
+ // head now has successor; may skip
+ head->skip = s;
+ }
+ head = s; // s is new head
+ }
+ }
+ s->state.store(PerThreadSynch::kQueued, std::memory_order_relaxed);
+ return head;
+}
+
+// Dequeue the successor pw->next of thread pw from the Mutex waiter queue
+// whose last element is head. The new head element is returned, or null
+// if the list is made empty.
+// Dequeue is called with both spinlock and Mutex held.
+static PerThreadSynch *Dequeue(PerThreadSynch *head, PerThreadSynch *pw) {
+ PerThreadSynch *w = pw->next;
+ pw->next = w->next; // snip w out of list
+ if (head == w) { // we removed the head
+ head = (pw == w) ? nullptr : pw; // either emptied list, or pw is new head
+ } else if (pw != head && MuSameCondition(pw, pw->next)) {
+ // pw can skip to its new successor
+ if (pw->next->skip !=
+ nullptr) { // either skip to its successors skip target
+ pw->skip = pw->next->skip;
+ } else { // or to pw's successor
+ pw->skip = pw->next;
+ }
+ }
+ return head;
+}
+
+// Traverse the elements [ pw->next, h] of the circular list whose last element
+// is head.
+// Remove all elements with wake==true and place them in the
+// singly-linked list wake_list in the order found. Assumes that
+// there is only one such element if the element has how == kExclusive.
+// Return the new head.
+static PerThreadSynch *DequeueAllWakeable(PerThreadSynch *head,
+ PerThreadSynch *pw,
+ PerThreadSynch **wake_tail) {
+ PerThreadSynch *orig_h = head;
+ PerThreadSynch *w = pw->next;
+ bool skipped = false;
+ do {
+ if (w->wake) { // remove this element
+ ABSL_RAW_CHECK(pw->skip == nullptr, "bad skip in DequeueAllWakeable");
+ // we're removing pw's successor so either pw->skip is zero or we should
+ // already have removed pw since if pw->skip!=null, pw has the same
+ // condition as w.
+ head = Dequeue(head, pw);
+ w->next = *wake_tail; // keep list terminated
+ *wake_tail = w; // add w to wake_list;
+ wake_tail = &w->next; // next addition to end
+ if (w->waitp->how == kExclusive) { // wake at most 1 writer
+ break;
+ }
+ } else { // not waking this one; skip
+ pw = Skip(w); // skip as much as possible
+ skipped = true;
+ }
+ w = pw->next;
+ // We want to stop processing after we've considered the original head,
+ // orig_h. We can't test for w==orig_h in the loop because w may skip over
+ // it; we are guaranteed only that w's predecessor will not skip over
+ // orig_h. When we've considered orig_h, either we've processed it and
+ // removed it (so orig_h != head), or we considered it and skipped it (so
+ // skipped==true && pw == head because skipping from head always skips by
+ // just one, leaving pw pointing at head). So we want to
+ // continue the loop with the negation of that expression.
+ } while (orig_h == head && (pw != head || !skipped));
+ return head;
+}
+
+// Try to remove thread s from the list of waiters on this mutex.
+// Does nothing if s is not on the waiter list.
+void Mutex::TryRemove(PerThreadSynch *s) {
+ intptr_t v = mu_.load(std::memory_order_relaxed);
+ // acquire spinlock & lock
+ if ((v & (kMuWait | kMuSpin | kMuWriter | kMuReader)) == kMuWait &&
+ mu_.compare_exchange_strong(v, v | kMuSpin | kMuWriter,
+ std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ PerThreadSynch *h = GetPerThreadSynch(v);
+ if (h != nullptr) {
+ PerThreadSynch *pw = h; // pw is w's predecessor
+ PerThreadSynch *w;
+ if ((w = pw->next) != s) { // search for thread,
+ do { // processing at least one element
+ if (!MuSameCondition(s, w)) { // seeking different condition
+ pw = Skip(w); // so skip all that won't match
+ // we don't have to worry about dangling skip fields
+ // in the threads we skipped; none can point to s
+ // because their condition differs from s
+ } else { // seeking same condition
+ FixSkip(w, s); // fix up any skip pointer from w to s
+ pw = w;
+ }
+ // don't search further if we found the thread, or we're about to
+ // process the first thread again.
+ } while ((w = pw->next) != s && pw != h);
+ }
+ if (w == s) { // found thread; remove it
+ // pw->skip may be non-zero here; the loop above ensured that
+ // no ancestor of s can skip to s, so removal is safe anyway.
+ h = Dequeue(h, pw);
+ s->next = nullptr;
+ s->state.store(PerThreadSynch::kAvailable, std::memory_order_release);
+ }
+ }
+ intptr_t nv;
+ do { // release spinlock and lock
+ v = mu_.load(std::memory_order_relaxed);
+ nv = v & (kMuDesig | kMuEvent);
+ if (h != nullptr) {
+ nv |= kMuWait | reinterpret_cast<intptr_t>(h);
+ h->readers = 0; // we hold writer lock
+ h->maybe_unlocking = false; // finished unlocking
+ }
+ } while (!mu_.compare_exchange_weak(v, nv,
+ std::memory_order_release,
+ std::memory_order_relaxed));
+ }
+}
+
+// Wait until thread "s", which must be the current thread, is removed from the
+// this mutex's waiter queue. If "s->waitp->timeout" has a timeout, wake up
+// if the wait extends past the absolute time specified, even if "s" is still
+// on the mutex queue. In this case, remove "s" from the queue and return
+// true, otherwise return false.
+void Mutex::Block(PerThreadSynch *s) {
+ while (s->state.load(std::memory_order_acquire) == PerThreadSynch::kQueued) {
+ if (!DecrementSynchSem(this, s, s->waitp->timeout)) {
+ // After a timeout, we go into a spin loop until we remove ourselves
+ // from the queue, or someone else removes us. We can't be sure to be
+ // able to remove ourselves in a single lock acquisition because this
+ // mutex may be held, and the holder has the right to read the centre
+ // of the waiter queue without holding the spinlock.
+ this->TryRemove(s);
+ int c = 0;
+ while (s->next != nullptr) {
+ c = Delay(c, GENTLE);
+ this->TryRemove(s);
+ }
+ if (kDebugMode) {
+ // This ensures that we test the case that TryRemove() is called when s
+ // is not on the queue.
+ this->TryRemove(s);
+ }
+ s->waitp->timeout = KernelTimeout::Never(); // timeout is satisfied
+ s->waitp->cond = nullptr; // condition no longer relevant for wakeups
+ }
+ }
+ ABSL_RAW_CHECK(s->waitp != nullptr || s->suppress_fatal_errors,
+ "detected illegal recursion in Mutex code");
+ s->waitp = nullptr;
+}
+
+// Wake thread w, and return the next thread in the list.
+PerThreadSynch *Mutex::Wakeup(PerThreadSynch *w) {
+ PerThreadSynch *next = w->next;
+ w->next = nullptr;
+ w->state.store(PerThreadSynch::kAvailable, std::memory_order_release);
+ IncrementSynchSem(this, w);
+
+ return next;
+}
+
+static GraphId GetGraphIdLocked(Mutex *mu)
+ EXCLUSIVE_LOCKS_REQUIRED(deadlock_graph_mu) {
+ if (!deadlock_graph) { // (re)create the deadlock graph.
+ deadlock_graph =
+ new (base_internal::LowLevelAlloc::Alloc(sizeof(*deadlock_graph)))
+ GraphCycles;
+ }
+ return deadlock_graph->GetId(mu);
+}
+
+static GraphId GetGraphId(Mutex *mu) LOCKS_EXCLUDED(deadlock_graph_mu) {
+ deadlock_graph_mu.Lock();
+ GraphId id = GetGraphIdLocked(mu);
+ deadlock_graph_mu.Unlock();
+ return id;
+}
+
+// Record a lock acquisition. This is used in debug mode for deadlock
+// detection. The held_locks pointer points to the relevant data
+// structure for each case.
+static void LockEnter(Mutex* mu, GraphId id, SynchLocksHeld *held_locks) {
+ int n = held_locks->n;
+ int i = 0;
+ while (i != n && held_locks->locks[i].id != id) {
+ i++;
+ }
+ if (i == n) {
+ if (n == ABSL_ARRAYSIZE(held_locks->locks)) {
+ held_locks->overflow = true; // lost some data
+ } else { // we have room for lock
+ held_locks->locks[i].mu = mu;
+ held_locks->locks[i].count = 1;
+ held_locks->locks[i].id = id;
+ held_locks->n = n + 1;
+ }
+ } else {
+ held_locks->locks[i].count++;
+ }
+}
+
+// Record a lock release. Each call to LockEnter(mu, id, x) should be
+// eventually followed by a call to LockLeave(mu, id, x) by the same thread.
+// It does not process the event if is not needed when deadlock detection is
+// disabled.
+static void LockLeave(Mutex* mu, GraphId id, SynchLocksHeld *held_locks) {
+ int n = held_locks->n;
+ int i = 0;
+ while (i != n && held_locks->locks[i].id != id) {
+ i++;
+ }
+ if (i == n) {
+ if (!held_locks->overflow) {
+ // The deadlock id may have been reassigned after ForgetDeadlockInfo,
+ // but in that case mu should still be present.
+ i = 0;
+ while (i != n && held_locks->locks[i].mu != mu) {
+ i++;
+ }
+ if (i == n) { // mu missing means releasing unheld lock
+ SynchEvent *mu_events = GetSynchEvent(mu);
+ ABSL_RAW_LOG(FATAL,
+ "thread releasing lock it does not hold: %p %s; "
+ ,
+ static_cast<void *>(mu),
+ mu_events == nullptr ? "" : mu_events->name);
+ }
+ }
+ } else if (held_locks->locks[i].count == 1) {
+ held_locks->n = n - 1;
+ held_locks->locks[i] = held_locks->locks[n - 1];
+ held_locks->locks[n - 1].id = InvalidGraphId();
+ held_locks->locks[n - 1].mu =
+ nullptr; // clear mu to please the leak detector.
+ } else {
+ assert(held_locks->locks[i].count > 0);
+ held_locks->locks[i].count--;
+ }
+}
+
+// Call LockEnter() if in debug mode and deadlock detection is enabled.
+static inline void DebugOnlyLockEnter(Mutex *mu) {
+ if (kDebugMode) {
+ if (synch_deadlock_detection.load(std::memory_order_acquire) !=
+ OnDeadlockCycle::kIgnore) {
+ LockEnter(mu, GetGraphId(mu), Synch_GetAllLocks());
+ }
+ }
+}
+
+// Call LockEnter() if in debug mode and deadlock detection is enabled.
+static inline void DebugOnlyLockEnter(Mutex *mu, GraphId id) {
+ if (kDebugMode) {
+ if (synch_deadlock_detection.load(std::memory_order_acquire) !=
+ OnDeadlockCycle::kIgnore) {
+ LockEnter(mu, id, Synch_GetAllLocks());
+ }
+ }
+}
+
+// Call LockLeave() if in debug mode and deadlock detection is enabled.
+static inline void DebugOnlyLockLeave(Mutex *mu) {
+ if (kDebugMode) {
+ if (synch_deadlock_detection.load(std::memory_order_acquire) !=
+ OnDeadlockCycle::kIgnore) {
+ LockLeave(mu, GetGraphId(mu), Synch_GetAllLocks());
+ }
+ }
+}
+
+static char *StackString(void **pcs, int n, char *buf, int maxlen,
+ bool symbolize) {
+ static const int kSymLen = 200;
+ char sym[kSymLen];
+ int len = 0;
+ for (int i = 0; i != n; i++) {
+ if (symbolize) {
+ if (!symbolizer(pcs[i], sym, kSymLen)) {
+ sym[0] = '\0';
+ }
+ snprintf(buf + len, maxlen - len, "%s\t@ %p %s\n",
+ (i == 0 ? "\n" : ""),
+ pcs[i], sym);
+ } else {
+ snprintf(buf + len, maxlen - len, " %p", pcs[i]);
+ }
+ len += strlen(&buf[len]);
+ }
+ return buf;
+}
+
+static char *CurrentStackString(char *buf, int maxlen, bool symbolize) {
+ void *pcs[40];
+ return StackString(pcs, absl::GetStackTrace(pcs, ABSL_ARRAYSIZE(pcs), 2), buf,
+ maxlen, symbolize);
+}
+
+namespace {
+enum { kMaxDeadlockPathLen = 10 }; // maximum length of a deadlock cycle;
+ // a path this long would be remarkable
+// Buffers required to report a deadlock.
+// We do not allocate them on stack to avoid large stack frame.
+struct DeadlockReportBuffers {
+ char buf[6100];
+ GraphId path[kMaxDeadlockPathLen];
+};
+
+struct ScopedDeadlockReportBuffers {
+ ScopedDeadlockReportBuffers() {
+ b = reinterpret_cast<DeadlockReportBuffers *>(
+ base_internal::LowLevelAlloc::Alloc(sizeof(*b)));
+ }
+ ~ScopedDeadlockReportBuffers() { base_internal::LowLevelAlloc::Free(b); }
+ DeadlockReportBuffers *b;
+};
+
+// Helper to pass to GraphCycles::UpdateStackTrace.
+int GetStack(void** stack, int max_depth) {
+ return absl::GetStackTrace(stack, max_depth, 3);
+}
+} // anonymous namespace
+
+// Called in debug mode when a thread is about to acquire a lock in a way that
+// may block.
+static GraphId DeadlockCheck(Mutex *mu) {
+ if (synch_deadlock_detection.load(std::memory_order_acquire) ==
+ OnDeadlockCycle::kIgnore) {
+ return InvalidGraphId();
+ }
+
+ SynchLocksHeld *all_locks = Synch_GetAllLocks();
+
+ absl::base_internal::SpinLockHolder lock(&deadlock_graph_mu);
+ const GraphId mu_id = GetGraphIdLocked(mu);
+
+ if (all_locks->n == 0) {
+ // There are no other locks held. Return now so that we don't need to
+ // call GetSynchEvent(). This way we do not record the stack trace
+ // for this Mutex. It's ok, since if this Mutex is involved in a deadlock,
+ // it can't always be the first lock acquired by a thread.
+ return mu_id;
+ }
+
+ // We prefer to keep stack traces that show a thread holding and acquiring
+ // as many locks as possible. This increases the chances that a given edge
+ // in the acquires-before graph will be represented in the stack traces
+ // recorded for the locks.
+ deadlock_graph->UpdateStackTrace(mu_id, all_locks->n + 1, GetStack);
+
+ // For each other mutex already held by this thread:
+ for (int i = 0; i != all_locks->n; i++) {
+ const GraphId other_node_id = all_locks->locks[i].id;
+ const Mutex *other =
+ static_cast<const Mutex *>(deadlock_graph->Ptr(other_node_id));
+ if (other == nullptr) {
+ // Ignore stale lock
+ continue;
+ }
+
+ // Add the acquired-before edge to the graph.
+ if (!deadlock_graph->InsertEdge(other_node_id, mu_id)) {
+ ScopedDeadlockReportBuffers scoped_buffers;
+ DeadlockReportBuffers *b = scoped_buffers.b;
+ static int number_of_reported_deadlocks = 0;
+ number_of_reported_deadlocks++;
+ // Symbolize only 2 first deadlock report to avoid huge slowdowns.
+ bool symbolize = number_of_reported_deadlocks <= 2;
+ ABSL_RAW_LOG(ERROR, "Potential Mutex deadlock: %s",
+ CurrentStackString(b->buf, sizeof (b->buf), symbolize));
+ int len = 0;
+ for (int j = 0; j != all_locks->n; j++) {
+ void* pr = deadlock_graph->Ptr(all_locks->locks[j].id);
+ if (pr != nullptr) {
+ snprintf(b->buf + len, sizeof (b->buf) - len, " %p", pr);
+ len += static_cast<int>(strlen(&b->buf[len]));
+ }
+ }
+ ABSL_RAW_LOG(ERROR, "Acquiring %p Mutexes held: %s",
+ static_cast<void *>(mu), b->buf);
+ ABSL_RAW_LOG(ERROR, "Cycle: ");
+ int path_len = deadlock_graph->FindPath(
+ mu_id, other_node_id, ABSL_ARRAYSIZE(b->path), b->path);
+ for (int j = 0; j != path_len; j++) {
+ GraphId id = b->path[j];
+ Mutex *path_mu = static_cast<Mutex *>(deadlock_graph->Ptr(id));
+ if (path_mu == nullptr) continue;
+ void** stack;
+ int depth = deadlock_graph->GetStackTrace(id, &stack);
+ snprintf(b->buf, sizeof(b->buf),
+ "mutex@%p stack: ", static_cast<void *>(path_mu));
+ StackString(stack, depth, b->buf + strlen(b->buf),
+ static_cast<int>(sizeof(b->buf) - strlen(b->buf)),
+ symbolize);
+ ABSL_RAW_LOG(ERROR, "%s", b->buf);
+ }
+ if (synch_deadlock_detection.load(std::memory_order_acquire) ==
+ OnDeadlockCycle::kAbort) {
+ deadlock_graph_mu.Unlock(); // avoid deadlock in fatal sighandler
+ ABSL_RAW_LOG(FATAL, "dying due to potential deadlock");
+ return mu_id;
+ }
+ break; // report at most one potential deadlock per acquisition
+ }
+ }
+
+ return mu_id;
+}
+
+// Invoke DeadlockCheck() iff we're in debug mode and
+// deadlock checking has been enabled.
+static inline GraphId DebugOnlyDeadlockCheck(Mutex *mu) {
+ if (kDebugMode && synch_deadlock_detection.load(std::memory_order_acquire) !=
+ OnDeadlockCycle::kIgnore) {
+ return DeadlockCheck(mu);
+ } else {
+ return InvalidGraphId();
+ }
+}
+
+void Mutex::ForgetDeadlockInfo() {
+ if (kDebugMode && synch_deadlock_detection.load(std::memory_order_acquire) !=
+ OnDeadlockCycle::kIgnore) {
+ deadlock_graph_mu.Lock();
+ if (deadlock_graph != nullptr) {
+ deadlock_graph->RemoveNode(this);
+ }
+ deadlock_graph_mu.Unlock();
+ }
+}
+
+void Mutex::AssertNotHeld() const {
+ // We have the data to allow this check only if in debug mode and deadlock
+ // detection is enabled.
+ if (kDebugMode &&
+ (mu_.load(std::memory_order_relaxed) & (kMuWriter | kMuReader)) != 0 &&
+ synch_deadlock_detection.load(std::memory_order_acquire) !=
+ OnDeadlockCycle::kIgnore) {
+ GraphId id = GetGraphId(const_cast<Mutex *>(this));
+ SynchLocksHeld *locks = Synch_GetAllLocks();
+ for (int i = 0; i != locks->n; i++) {
+ if (locks->locks[i].id == id) {
+ SynchEvent *mu_events = GetSynchEvent(this);
+ ABSL_RAW_LOG(FATAL, "thread should not hold mutex %p %s",
+ static_cast<const void *>(this),
+ (mu_events == nullptr ? "" : mu_events->name));
+ }
+ }
+ }
+}
+
+// Attempt to acquire *mu, and return whether successful. The implementation
+// may spin for a short while if the lock cannot be acquired immediately.
+static bool TryAcquireWithSpinning(std::atomic<intptr_t>* mu) {
+ int c = mutex_globals.spinloop_iterations;
+ int result = -1; // result of operation: 0=false, 1=true, -1=unknown
+
+ do { // do/while somewhat faster on AMD
+ intptr_t v = mu->load(std::memory_order_relaxed);
+ if ((v & (kMuReader|kMuEvent)) != 0) { // a reader or tracing -> give up
+ result = 0;
+ } else if (((v & kMuWriter) == 0) && // no holder -> try to acquire
+ mu->compare_exchange_strong(v, kMuWriter | v,
+ std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ result = 1;
+ }
+ } while (result == -1 && --c > 0);
+ return result == 1;
+}
+
+ABSL_XRAY_LOG_ARGS(1) void Mutex::Lock() {
+ ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
+ GraphId id = DebugOnlyDeadlockCheck(this);
+ intptr_t v = mu_.load(std::memory_order_relaxed);
+ // try fast acquire, then spin loop
+ if ((v & (kMuWriter | kMuReader | kMuEvent)) != 0 ||
+ !mu_.compare_exchange_strong(v, kMuWriter | v,
+ std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ // try spin acquire, then slow loop
+ if (!TryAcquireWithSpinning(&this->mu_)) {
+ this->LockSlow(kExclusive, nullptr, 0);
+ }
+ }
+ DebugOnlyLockEnter(this, id);
+ ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0);
+}
+
+ABSL_XRAY_LOG_ARGS(1) void Mutex::ReaderLock() {
+ ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_read_lock);
+ GraphId id = DebugOnlyDeadlockCheck(this);
+ intptr_t v = mu_.load(std::memory_order_relaxed);
+ // try fast acquire, then slow loop
+ if ((v & (kMuWriter | kMuWait | kMuEvent)) != 0 ||
+ !mu_.compare_exchange_strong(v, (kMuReader | v) + kMuOne,
+ std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ this->LockSlow(kShared, nullptr, 0);
+ }
+ DebugOnlyLockEnter(this, id);
+ ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_read_lock, 0);
+}
+
+void Mutex::LockWhen(const Condition &cond) {
+ ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
+ GraphId id = DebugOnlyDeadlockCheck(this);
+ this->LockSlow(kExclusive, &cond, 0);
+ DebugOnlyLockEnter(this, id);
+ ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0);
+}
+
+bool Mutex::LockWhenWithTimeout(const Condition &cond, absl::Duration timeout) {
+ return LockWhenWithDeadline(cond, DeadlineFromTimeout(timeout));
+}
+
+bool Mutex::LockWhenWithDeadline(const Condition &cond, absl::Time deadline) {
+ ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
+ GraphId id = DebugOnlyDeadlockCheck(this);
+ bool res = LockSlowWithDeadline(kExclusive, &cond,
+ KernelTimeout(deadline), 0);
+ DebugOnlyLockEnter(this, id);
+ ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0);
+ return res;
+}
+
+void Mutex::ReaderLockWhen(const Condition &cond) {
+ ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_read_lock);
+ GraphId id = DebugOnlyDeadlockCheck(this);
+ this->LockSlow(kShared, &cond, 0);
+ DebugOnlyLockEnter(this, id);
+ ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_read_lock, 0);
+}
+
+bool Mutex::ReaderLockWhenWithTimeout(const Condition &cond,
+ absl::Duration timeout) {
+ return ReaderLockWhenWithDeadline(cond, DeadlineFromTimeout(timeout));
+}
+
+bool Mutex::ReaderLockWhenWithDeadline(const Condition &cond,
+ absl::Time deadline) {
+ ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_read_lock);
+ GraphId id = DebugOnlyDeadlockCheck(this);
+ bool res = LockSlowWithDeadline(kShared, &cond, KernelTimeout(deadline), 0);
+ DebugOnlyLockEnter(this, id);
+ ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_read_lock, 0);
+ return res;
+}
+
+void Mutex::Await(const Condition &cond) {
+ if (cond.Eval()) { // condition already true; nothing to do
+ if (kDebugMode) {
+ this->AssertReaderHeld();
+ }
+ } else { // normal case
+ ABSL_RAW_CHECK(this->AwaitCommon(cond, KernelTimeout::Never()),
+ "condition untrue on return from Await");
+ }
+}
+
+bool Mutex::AwaitWithTimeout(const Condition &cond, absl::Duration timeout) {
+ return AwaitWithDeadline(cond, DeadlineFromTimeout(timeout));
+}
+
+bool Mutex::AwaitWithDeadline(const Condition &cond, absl::Time deadline) {
+ if (cond.Eval()) { // condition already true; nothing to do
+ if (kDebugMode) {
+ this->AssertReaderHeld();
+ }
+ return true;
+ }
+
+ KernelTimeout t{deadline};
+ bool res = this->AwaitCommon(cond, t);
+ ABSL_RAW_CHECK(res || t.has_timeout(),
+ "condition untrue on return from Await");
+ return res;
+}
+
+bool Mutex::AwaitCommon(const Condition &cond, KernelTimeout t) {
+ this->AssertReaderHeld();
+ MuHow how =
+ (mu_.load(std::memory_order_relaxed) & kMuWriter) ? kExclusive : kShared;
+ ABSL_TSAN_MUTEX_PRE_UNLOCK(this, TsanFlags(how));
+ SynchWaitParams waitp(
+ how, &cond, t, nullptr /*no cvmu*/, Synch_GetPerThreadAnnotated(this),
+ nullptr /*no cv_word*/);
+ int flags = kMuHasBlocked;
+ if (!Condition::GuaranteedEqual(&cond, nullptr)) {
+ flags |= kMuIsCond;
+ }
+ this->UnlockSlow(&waitp);
+ this->Block(waitp.thread);
+ ABSL_TSAN_MUTEX_POST_UNLOCK(this, TsanFlags(how));
+ ABSL_TSAN_MUTEX_PRE_LOCK(this, TsanFlags(how));
+ this->LockSlowLoop(&waitp, flags);
+ bool res = waitp.cond != nullptr || // => cond known true from LockSlowLoop
+ cond.Eval();
+ ABSL_TSAN_MUTEX_POST_LOCK(this, TsanFlags(how), 0);
+ return res;
+}
+
+ABSL_XRAY_LOG_ARGS(1) bool Mutex::TryLock() {
+ ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock);
+ intptr_t v = mu_.load(std::memory_order_relaxed);
+ if ((v & (kMuWriter | kMuReader | kMuEvent)) == 0 && // try fast acquire
+ mu_.compare_exchange_strong(v, kMuWriter | v,
+ std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ DebugOnlyLockEnter(this);
+ ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_try_lock, 0);
+ return true;
+ }
+ if ((v & kMuEvent) != 0) { // we're recording events
+ if ((v & kExclusive->slow_need_zero) == 0 && // try fast acquire
+ mu_.compare_exchange_strong(
+ v, (kExclusive->fast_or | v) + kExclusive->fast_add,
+ std::memory_order_acquire, std::memory_order_relaxed)) {
+ DebugOnlyLockEnter(this);
+ PostSynchEvent(this, SYNCH_EV_TRYLOCK_SUCCESS);
+ ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_try_lock, 0);
+ return true;
+ } else {
+ PostSynchEvent(this, SYNCH_EV_TRYLOCK_FAILED);
+ }
+ }
+ ABSL_TSAN_MUTEX_POST_LOCK(
+ this, __tsan_mutex_try_lock | __tsan_mutex_try_lock_failed, 0);
+ return false;
+}
+
+ABSL_XRAY_LOG_ARGS(1) bool Mutex::ReaderTryLock() {
+ ABSL_TSAN_MUTEX_PRE_LOCK(this,
+ __tsan_mutex_read_lock | __tsan_mutex_try_lock);
+ intptr_t v = mu_.load(std::memory_order_relaxed);
+ // The while-loops (here and below) iterate only if the mutex word keeps
+ // changing (typically because the reader count changes) under the CAS. We
+ // limit the number of attempts to avoid having to think about livelock.
+ int loop_limit = 5;
+ while ((v & (kMuWriter|kMuWait|kMuEvent)) == 0 && loop_limit != 0) {
+ if (mu_.compare_exchange_strong(v, (kMuReader | v) + kMuOne,
+ std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ DebugOnlyLockEnter(this);
+ ABSL_TSAN_MUTEX_POST_LOCK(
+ this, __tsan_mutex_read_lock | __tsan_mutex_try_lock, 0);
+ return true;
+ }
+ loop_limit--;
+ v = mu_.load(std::memory_order_relaxed);
+ }
+ if ((v & kMuEvent) != 0) { // we're recording events
+ loop_limit = 5;
+ while ((v & kShared->slow_need_zero) == 0 && loop_limit != 0) {
+ if (mu_.compare_exchange_strong(v, (kMuReader | v) + kMuOne,
+ std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ DebugOnlyLockEnter(this);
+ PostSynchEvent(this, SYNCH_EV_READERTRYLOCK_SUCCESS);
+ ABSL_TSAN_MUTEX_POST_LOCK(
+ this, __tsan_mutex_read_lock | __tsan_mutex_try_lock, 0);
+ return true;
+ }
+ loop_limit--;
+ v = mu_.load(std::memory_order_relaxed);
+ }
+ if ((v & kMuEvent) != 0) {
+ PostSynchEvent(this, SYNCH_EV_READERTRYLOCK_FAILED);
+ }
+ }
+ ABSL_TSAN_MUTEX_POST_LOCK(this,
+ __tsan_mutex_read_lock | __tsan_mutex_try_lock |
+ __tsan_mutex_try_lock_failed,
+ 0);
+ return false;
+}
+
+ABSL_XRAY_LOG_ARGS(1) void Mutex::Unlock() {
+ ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0);
+ DebugOnlyLockLeave(this);
+ intptr_t v = mu_.load(std::memory_order_relaxed);
+
+ if (kDebugMode && ((v & (kMuWriter | kMuReader)) != kMuWriter)) {
+ ABSL_RAW_LOG(FATAL, "Mutex unlocked when destroyed or not locked: v=0x%x",
+ static_cast<unsigned>(v));
+ }
+
+ // should_try_cas is whether we'll try a compare-and-swap immediately.
+ // NOTE: optimized out when kDebugMode is false.
+ bool should_try_cas = ((v & (kMuEvent | kMuWriter)) == kMuWriter &&
+ (v & (kMuWait | kMuDesig)) != kMuWait);
+ // But, we can use an alternate computation of it, that compilers
+ // currently don't find on their own. When that changes, this function
+ // can be simplified.
+ intptr_t x = (v ^ (kMuWriter | kMuWait)) & (kMuWriter | kMuEvent);
+ intptr_t y = (v ^ (kMuWriter | kMuWait)) & (kMuWait | kMuDesig);
+ // Claim: "x == 0 && y > 0" is equal to should_try_cas.
+ // Also, because kMuWriter and kMuEvent exceed kMuDesig and kMuWait,
+ // all possible non-zero values for x exceed all possible values for y.
+ // Therefore, (x == 0 && y > 0) == (x < y).
+ if (kDebugMode && should_try_cas != (x < y)) {
+ // We would usually use PRIdPTR here, but is not correctly implemented
+ // within the android toolchain.
+ ABSL_RAW_LOG(FATAL, "internal logic error %llx %llx %llx\n",
+ static_cast<long long>(v), static_cast<long long>(x),
+ static_cast<long long>(y));
+ }
+ if (x < y &&
+ mu_.compare_exchange_strong(v, v & ~(kMuWrWait | kMuWriter),
+ std::memory_order_release,
+ std::memory_order_relaxed)) {
+ // fast writer release (writer with no waiters or with designated waker)
+ } else {
+ this->UnlockSlow(nullptr /*no waitp*/); // take slow path
+ }
+ ABSL_TSAN_MUTEX_POST_UNLOCK(this, 0);
+}
+
+// Requires v to represent a reader-locked state.
+static bool ExactlyOneReader(intptr_t v) {
+ assert((v & (kMuWriter|kMuReader)) == kMuReader);
+ assert((v & kMuHigh) != 0);
+ // The more straightforward "(v & kMuHigh) == kMuOne" also works, but
+ // on some architectures the following generates slightly smaller code.
+ // It may be faster too.
+ constexpr intptr_t kMuMultipleWaitersMask = kMuHigh ^ kMuOne;
+ return (v & kMuMultipleWaitersMask) == 0;
+}
+
+ABSL_XRAY_LOG_ARGS(1) void Mutex::ReaderUnlock() {
+ ABSL_TSAN_MUTEX_PRE_UNLOCK(this, __tsan_mutex_read_lock);
+ DebugOnlyLockLeave(this);
+ intptr_t v = mu_.load(std::memory_order_relaxed);
+ assert((v & (kMuWriter|kMuReader)) == kMuReader);
+ if ((v & (kMuReader|kMuWait|kMuEvent)) == kMuReader) {
+ // fast reader release (reader with no waiters)
+ intptr_t clear = ExactlyOneReader(v) ? kMuReader|kMuOne : kMuOne;
+ if (mu_.compare_exchange_strong(v, v - clear,
+ std::memory_order_release,
+ std::memory_order_relaxed)) {
+ ABSL_TSAN_MUTEX_POST_UNLOCK(this, __tsan_mutex_read_lock);
+ return;
+ }
+ }
+ this->UnlockSlow(nullptr /*no waitp*/); // take slow path
+ ABSL_TSAN_MUTEX_POST_UNLOCK(this, __tsan_mutex_read_lock);
+}
+
+// The zap_desig_waker bitmask is used to clear the designated waker flag in
+// the mutex if this thread has blocked, and therefore may be the designated
+// waker.
+static const intptr_t zap_desig_waker[] = {
+ ~static_cast<intptr_t>(0), // not blocked
+ ~static_cast<intptr_t>(
+ kMuDesig) // blocked; turn off the designated waker bit
+};
+
+// The ignore_waiting_writers bitmask is used to ignore the existence
+// of waiting writers if a reader that has already blocked once
+// wakes up.
+static const intptr_t ignore_waiting_writers[] = {
+ ~static_cast<intptr_t>(0), // not blocked
+ ~static_cast<intptr_t>(
+ kMuWrWait) // blocked; pretend there are no waiting writers
+};
+
+// Internal version of LockWhen(). See LockSlowWithDeadline()
+void Mutex::LockSlow(MuHow how, const Condition *cond, int flags) {
+ ABSL_RAW_CHECK(
+ this->LockSlowWithDeadline(how, cond, KernelTimeout::Never(), flags),
+ "condition untrue on return from LockSlow");
+}
+
+// Compute cond->Eval() and tell race detectors that we do it under mutex mu.
+static inline bool EvalConditionAnnotated(const Condition *cond, Mutex *mu,
+ bool locking, Mutex::MuHow how) {
+ // Delicate annotation dance.
+ // We are currently inside of read/write lock/unlock operation.
+ // All memory accesses are ignored inside of mutex operations + for unlock
+ // operation tsan considers that we've already released the mutex.
+ bool res = false;
+ if (locking) {
+ // For lock we pretend that we have finished the operation,
+ // evaluate the predicate, then unlock the mutex and start locking it again
+ // to match the annotation at the end of outer lock operation.
+ // Note: we can't simply do POST_LOCK, Eval, PRE_LOCK, because then tsan
+ // will think the lock acquisition is recursive which will trigger
+ // deadlock detector.
+ ABSL_TSAN_MUTEX_POST_LOCK(mu, TsanFlags(how), 0);
+ res = cond->Eval();
+ ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, TsanFlags(how));
+ ABSL_TSAN_MUTEX_POST_UNLOCK(mu, TsanFlags(how));
+ ABSL_TSAN_MUTEX_PRE_LOCK(mu, TsanFlags(how));
+ } else {
+ // Similarly, for unlock we pretend that we have unlocked the mutex,
+ // lock the mutex, evaluate the predicate, and start unlocking it again
+ // to match the annotation at the end of outer unlock operation.
+ ABSL_TSAN_MUTEX_POST_UNLOCK(mu, TsanFlags(how));
+ ABSL_TSAN_MUTEX_PRE_LOCK(mu, TsanFlags(how));
+ ABSL_TSAN_MUTEX_POST_LOCK(mu, TsanFlags(how), 0);
+ res = cond->Eval();
+ ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, TsanFlags(how));
+ }
+ // Prevent unused param warnings in non-TSAN builds.
+ static_cast<void>(mu);
+ static_cast<void>(how);
+ return res;
+}
+
+// Compute cond->Eval() hiding it from race detectors.
+// We are hiding it because inside of UnlockSlow we can evaluate a predicate
+// that was just added by a concurrent Lock operation; Lock adds the predicate
+// to the internal Mutex list without actually acquiring the Mutex
+// (it only acquires the internal spinlock, which is rightfully invisible for
+// tsan). As the result there is no tsan-visible synchronization between the
+// addition and this thread. So if we would enable race detection here,
+// it would race with the predicate initialization.
+static inline bool EvalConditionIgnored(Mutex *mu, const Condition *cond) {
+ // Memory accesses are already ignored inside of lock/unlock operations,
+ // but synchronization operations are also ignored. When we evaluate the
+ // predicate we must ignore only memory accesses but not synchronization,
+ // because missed synchronization can lead to false reports later.
+ // So we "divert" (which un-ignores both memory accesses and synchronization)
+ // and then separately turn on ignores of memory accesses.
+ ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0);
+ ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
+ bool res = cond->Eval();
+ ANNOTATE_IGNORE_READS_AND_WRITES_END();
+ ABSL_TSAN_MUTEX_POST_DIVERT(mu, 0);
+ static_cast<void>(mu); // Prevent unused param warning in non-TSAN builds.
+ return res;
+}
+
+// Internal equivalent of *LockWhenWithDeadline(), where
+// "t" represents the absolute timeout; !t.has_timeout() means "forever".
+// "how" is "kShared" (for ReaderLockWhen) or "kExclusive" (for LockWhen)
+// In flags, bits are ored together:
+// - kMuHasBlocked indicates that the client has already blocked on the call so
+// the designated waker bit must be cleared and waiting writers should not
+// obstruct this call
+// - kMuIsCond indicates that this is a conditional acquire (condition variable,
+// Await, LockWhen) so contention profiling should be suppressed.
+bool Mutex::LockSlowWithDeadline(MuHow how, const Condition *cond,
+ KernelTimeout t, int flags) {
+ intptr_t v = mu_.load(std::memory_order_relaxed);
+ bool unlock = false;
+ if ((v & how->fast_need_zero) == 0 && // try fast acquire
+ mu_.compare_exchange_strong(
+ v, (how->fast_or | (v & zap_desig_waker[flags & kMuHasBlocked])) +
+ how->fast_add,
+ std::memory_order_acquire, std::memory_order_relaxed)) {
+ if (cond == nullptr || EvalConditionAnnotated(cond, this, true, how)) {
+ return true;
+ }
+ unlock = true;
+ }
+ SynchWaitParams waitp(
+ how, cond, t, nullptr /*no cvmu*/, Synch_GetPerThreadAnnotated(this),
+ nullptr /*no cv_word*/);
+ if (!Condition::GuaranteedEqual(cond, nullptr)) {
+ flags |= kMuIsCond;
+ }
+ if (unlock) {
+ this->UnlockSlow(&waitp);
+ this->Block(waitp.thread);
+ flags |= kMuHasBlocked;
+ }
+ this->LockSlowLoop(&waitp, flags);
+ return waitp.cond != nullptr || // => cond known true from LockSlowLoop
+ cond == nullptr || EvalConditionAnnotated(cond, this, true, how);
+}
+
+// RAW_CHECK_FMT() takes a condition, a printf-style format std::string, and
+// the printf-style argument list. The format std::string must be a literal.
+// Arguments after the first are not evaluated unless the condition is true.
+#define RAW_CHECK_FMT(cond, ...) \
+ do { \
+ if (ABSL_PREDICT_FALSE(!(cond))) { \
+ ABSL_RAW_LOG(FATAL, "Check " #cond " failed: " __VA_ARGS__); \
+ } \
+ } while (0)
+
+static void CheckForMutexCorruption(intptr_t v, const char* label) {
+ // Test for either of two situations that should not occur in v:
+ // kMuWriter and kMuReader
+ // kMuWrWait and !kMuWait
+ const intptr_t w = v ^ kMuWait;
+ // By flipping that bit, we can now test for:
+ // kMuWriter and kMuReader in w
+ // kMuWrWait and kMuWait in w
+ // We've chosen these two pairs of values to be so that they will overlap,
+ // respectively, when the word is left shifted by three. This allows us to
+ // save a branch in the common (correct) case of them not being coincident.
+ static_assert(kMuReader << 3 == kMuWriter, "must match");
+ static_assert(kMuWait << 3 == kMuWrWait, "must match");
+ if (ABSL_PREDICT_TRUE((w & (w << 3) & (kMuWriter | kMuWrWait)) == 0)) return;
+ RAW_CHECK_FMT((v & (kMuWriter | kMuReader)) != (kMuWriter | kMuReader),
+ "%s: Mutex corrupt: both reader and writer lock held: %p",
+ label, reinterpret_cast<void *>(v));
+ RAW_CHECK_FMT((v & (kMuWait | kMuWrWait)) != kMuWrWait,
+ "%s: Mutex corrupt: waiting writer with no waiters: %p",
+ label, reinterpret_cast<void *>(v));
+ assert(false);
+}
+
+void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) {
+ int c = 0;
+ intptr_t v = mu_.load(std::memory_order_relaxed);
+ if ((v & kMuEvent) != 0) {
+ PostSynchEvent(this,
+ waitp->how == kExclusive? SYNCH_EV_LOCK: SYNCH_EV_READERLOCK);
+ }
+ ABSL_RAW_CHECK(
+ waitp->thread->waitp == nullptr || waitp->thread->suppress_fatal_errors,
+ "detected illegal recursion into Mutex code");
+ for (;;) {
+ v = mu_.load(std::memory_order_relaxed);
+ CheckForMutexCorruption(v, "Lock");
+ if ((v & waitp->how->slow_need_zero) == 0) {
+ if (mu_.compare_exchange_strong(
+ v, (waitp->how->fast_or |
+ (v & zap_desig_waker[flags & kMuHasBlocked])) +
+ waitp->how->fast_add,
+ std::memory_order_acquire, std::memory_order_relaxed)) {
+ if (waitp->cond == nullptr ||
+ EvalConditionAnnotated(waitp->cond, this, true, waitp->how)) {
+ break; // we timed out, or condition true, so return
+ }
+ this->UnlockSlow(waitp); // got lock but condition false
+ this->Block(waitp->thread);
+ flags |= kMuHasBlocked;
+ c = 0;
+ }
+ } else { // need to access waiter list
+ bool dowait = false;
+ if ((v & (kMuSpin|kMuWait)) == 0) { // no waiters
+ // This thread tries to become the one and only waiter.
+ PerThreadSynch *new_h = Enqueue(nullptr, waitp, v, flags);
+ intptr_t nv = (v & zap_desig_waker[flags & kMuHasBlocked] & kMuLow) |
+ kMuWait;
+ ABSL_RAW_CHECK(new_h != nullptr, "Enqueue to empty list failed");
+ if (waitp->how == kExclusive && (v & kMuReader) != 0) {
+ nv |= kMuWrWait;
+ }
+ if (mu_.compare_exchange_strong(
+ v, reinterpret_cast<intptr_t>(new_h) | nv,
+ std::memory_order_release, std::memory_order_relaxed)) {
+ dowait = true;
+ } else { // attempted Enqueue() failed
+ // zero out the waitp field set by Enqueue()
+ waitp->thread->waitp = nullptr;
+ }
+ } else if ((v & waitp->how->slow_inc_need_zero &
+ ignore_waiting_writers[flags & kMuHasBlocked]) == 0) {
+ // This is a reader that needs to increment the reader count,
+ // but the count is currently held in the last waiter.
+ if (mu_.compare_exchange_strong(
+ v, (v & zap_desig_waker[flags & kMuHasBlocked]) | kMuSpin |
+ kMuReader,
+ std::memory_order_acquire, std::memory_order_relaxed)) {
+ PerThreadSynch *h = GetPerThreadSynch(v);
+ h->readers += kMuOne; // inc reader count in waiter
+ do { // release spinlock
+ v = mu_.load(std::memory_order_relaxed);
+ } while (!mu_.compare_exchange_weak(v, (v & ~kMuSpin) | kMuReader,
+ std::memory_order_release,
+ std::memory_order_relaxed));
+ if (waitp->cond == nullptr ||
+ EvalConditionAnnotated(waitp->cond, this, true, waitp->how)) {
+ break; // we timed out, or condition true, so return
+ }
+ this->UnlockSlow(waitp); // got lock but condition false
+ this->Block(waitp->thread);
+ flags |= kMuHasBlocked;
+ c = 0;
+ }
+ } else if ((v & kMuSpin) == 0 && // attempt to queue ourselves
+ mu_.compare_exchange_strong(
+ v, (v & zap_desig_waker[flags & kMuHasBlocked]) | kMuSpin |
+ kMuWait,
+ std::memory_order_acquire, std::memory_order_relaxed)) {
+ PerThreadSynch *h = GetPerThreadSynch(v);
+ PerThreadSynch *new_h = Enqueue(h, waitp, v, flags);
+ intptr_t wr_wait = 0;
+ ABSL_RAW_CHECK(new_h != nullptr, "Enqueue to list failed");
+ if (waitp->how == kExclusive && (v & kMuReader) != 0) {
+ wr_wait = kMuWrWait; // give priority to a waiting writer
+ }
+ do { // release spinlock
+ v = mu_.load(std::memory_order_relaxed);
+ } while (!mu_.compare_exchange_weak(
+ v, (v & (kMuLow & ~kMuSpin)) | kMuWait | wr_wait |
+ reinterpret_cast<intptr_t>(new_h),
+ std::memory_order_release, std::memory_order_relaxed));
+ dowait = true;
+ }
+ if (dowait) {
+ this->Block(waitp->thread); // wait until removed from list or timeout
+ flags |= kMuHasBlocked;
+ c = 0;
+ }
+ }
+ ABSL_RAW_CHECK(
+ waitp->thread->waitp == nullptr || waitp->thread->suppress_fatal_errors,
+ "detected illegal recursion into Mutex code");
+ c = Delay(c, GENTLE); // delay, then try again
+ }
+ ABSL_RAW_CHECK(
+ waitp->thread->waitp == nullptr || waitp->thread->suppress_fatal_errors,
+ "detected illegal recursion into Mutex code");
+ if ((v & kMuEvent) != 0) {
+ PostSynchEvent(this,
+ waitp->how == kExclusive? SYNCH_EV_LOCK_RETURNING :
+ SYNCH_EV_READERLOCK_RETURNING);
+ }
+}
+
+// Unlock this mutex, which is held by the current thread.
+// If waitp is non-zero, it must be the wait parameters for the current thread
+// which holds the lock but is not runnable because its condition is false
+// or it n the process of blocking on a condition variable; it must requeue
+// itself on the mutex/condvar to wait for its condition to become true.
+void Mutex::UnlockSlow(SynchWaitParams *waitp) {
+ intptr_t v = mu_.load(std::memory_order_relaxed);
+ this->AssertReaderHeld();
+ CheckForMutexCorruption(v, "Unlock");
+ if ((v & kMuEvent) != 0) {
+ PostSynchEvent(this,
+ (v & kMuWriter) != 0? SYNCH_EV_UNLOCK: SYNCH_EV_READERUNLOCK);
+ }
+ int c = 0;
+ // the waiter under consideration to wake, or zero
+ PerThreadSynch *w = nullptr;
+ // the predecessor to w or zero
+ PerThreadSynch *pw = nullptr;
+ // head of the list searched previously, or zero
+ PerThreadSynch *old_h = nullptr;
+ // a condition that's known to be false.
+ const Condition *known_false = nullptr;
+ PerThreadSynch *wake_list = kPerThreadSynchNull; // list of threads to wake
+ intptr_t wr_wait = 0; // set to kMuWrWait if we wake a reader and a
+ // later writer could have acquired the lock
+ // (starvation avoidance)
+ ABSL_RAW_CHECK(waitp == nullptr || waitp->thread->waitp == nullptr ||
+ waitp->thread->suppress_fatal_errors,
+ "detected illegal recursion into Mutex code");
+ // This loop finds threads wake_list to wakeup if any, and removes them from
+ // the list of waiters. In addition, it places waitp.thread on the queue of
+ // waiters if waitp is non-zero.
+ for (;;) {
+ v = mu_.load(std::memory_order_relaxed);
+ if ((v & kMuWriter) != 0 && (v & (kMuWait | kMuDesig)) != kMuWait &&
+ waitp == nullptr) {
+ // fast writer release (writer with no waiters or with designated waker)
+ if (mu_.compare_exchange_strong(v, v & ~(kMuWrWait | kMuWriter),
+ std::memory_order_release,
+ std::memory_order_relaxed)) {
+ return;
+ }
+ } else if ((v & (kMuReader | kMuWait)) == kMuReader && waitp == nullptr) {
+ // fast reader release (reader with no waiters)
+ intptr_t clear = ExactlyOneReader(v) ? kMuReader | kMuOne : kMuOne;
+ if (mu_.compare_exchange_strong(v, v - clear,
+ std::memory_order_release,
+ std::memory_order_relaxed)) {
+ return;
+ }
+ } else if ((v & kMuSpin) == 0 && // attempt to get spinlock
+ mu_.compare_exchange_strong(v, v | kMuSpin,
+ std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ if ((v & kMuWait) == 0) { // no one to wake
+ intptr_t nv;
+ bool do_enqueue = true; // always Enqueue() the first time
+ ABSL_RAW_CHECK(waitp != nullptr,
+ "UnlockSlow is confused"); // about to sleep
+ do { // must loop to release spinlock as reader count may change
+ v = mu_.load(std::memory_order_relaxed);
+ // decrement reader count if there are readers
+ intptr_t new_readers = (v >= kMuOne)? v - kMuOne : v;
+ PerThreadSynch *new_h = nullptr;
+ if (do_enqueue) {
+ // If we are enqueuing on a CondVar (waitp->cv_word != nullptr) then
+ // we must not retry here. The initial attempt will always have
+ // succeeded, further attempts would enqueue us against *this due to
+ // Fer() handling.
+ do_enqueue = (waitp->cv_word == nullptr);
+ new_h = Enqueue(nullptr, waitp, new_readers, kMuIsCond);
+ }
+ intptr_t clear = kMuWrWait | kMuWriter; // by default clear write bit
+ if ((v & kMuWriter) == 0 && ExactlyOneReader(v)) { // last reader
+ clear = kMuWrWait | kMuReader; // clear read bit
+ }
+ nv = (v & kMuLow & ~clear & ~kMuSpin);
+ if (new_h != nullptr) {
+ nv |= kMuWait | reinterpret_cast<intptr_t>(new_h);
+ } else { // new_h could be nullptr if we queued ourselves on a
+ // CondVar
+ // In that case, we must place the reader count back in the mutex
+ // word, as Enqueue() did not store it in the new waiter.
+ nv |= new_readers & kMuHigh;
+ }
+ // release spinlock & our lock; retry if reader-count changed
+ // (writer count cannot change since we hold lock)
+ } while (!mu_.compare_exchange_weak(v, nv,
+ std::memory_order_release,
+ std::memory_order_relaxed));
+ break;
+ }
+
+ // There are waiters.
+ // Set h to the head of the circular waiter list.
+ PerThreadSynch *h = GetPerThreadSynch(v);
+ if ((v & kMuReader) != 0 && (h->readers & kMuHigh) > kMuOne) {
+ // a reader but not the last
+ h->readers -= kMuOne; // release our lock
+ intptr_t nv = v; // normally just release spinlock
+ if (waitp != nullptr) { // but waitp!=nullptr => must queue ourselves
+ PerThreadSynch *new_h = Enqueue(h, waitp, v, kMuIsCond);
+ ABSL_RAW_CHECK(new_h != nullptr,
+ "waiters disappeared during Enqueue()!");
+ nv &= kMuLow;
+ nv |= kMuWait | reinterpret_cast<intptr_t>(new_h);
+ }
+ mu_.store(nv, std::memory_order_release); // release spinlock
+ // can release with a store because there were waiters
+ break;
+ }
+
+ // Either we didn't search before, or we marked the queue
+ // as "maybe_unlocking" and no one else should have changed it.
+ ABSL_RAW_CHECK(old_h == nullptr || h->maybe_unlocking,
+ "Mutex queue changed beneath us");
+
+ // The lock is becoming free, and there's a waiter
+ if (old_h != nullptr &&
+ !old_h->may_skip) { // we used old_h as a terminator
+ old_h->may_skip = true; // allow old_h to skip once more
+ ABSL_RAW_CHECK(old_h->skip == nullptr, "illegal skip from head");
+ if (h != old_h && MuSameCondition(old_h, old_h->next)) {
+ old_h->skip = old_h->next; // old_h not head & can skip to successor
+ }
+ }
+ if (h->next->waitp->how == kExclusive &&
+ Condition::GuaranteedEqual(h->next->waitp->cond, nullptr)) {
+ // easy case: writer with no condition; no need to search
+ pw = h; // wake w, the successor of h (=pw)
+ w = h->next;
+ w->wake = true;
+ // We are waking up a writer. This writer may be racing against
+ // an already awake reader for the lock. We want the
+ // writer to usually win this race,
+ // because if it doesn't, we can potentially keep taking a reader
+ // perpetually and writers will starve. Worse than
+ // that, this can also starve other readers if kMuWrWait gets set
+ // later.
+ wr_wait = kMuWrWait;
+ } else if (w != nullptr && (w->waitp->how == kExclusive || h == old_h)) {
+ // we found a waiter w to wake on a previous iteration and either it's
+ // a writer, or we've searched the entire list so we have all the
+ // readers.
+ if (pw == nullptr) { // if w's predecessor is unknown, it must be h
+ pw = h;
+ }
+ } else {
+ // At this point we don't know all the waiters to wake, and the first
+ // waiter has a condition or is a reader. We avoid searching over
+ // waiters we've searched on previous iterations by starting at
+ // old_h if it's set. If old_h==h, there's no one to wakeup at all.
+ if (old_h == h) { // we've searched before, and nothing's new
+ // so there's no one to wake.
+ intptr_t nv = (v & ~(kMuReader|kMuWriter|kMuWrWait));
+ h->readers = 0;
+ h->maybe_unlocking = false; // finished unlocking
+ if (waitp != nullptr) { // we must queue ourselves and sleep
+ PerThreadSynch *new_h = Enqueue(h, waitp, v, kMuIsCond);
+ nv &= kMuLow;
+ if (new_h != nullptr) {
+ nv |= kMuWait | reinterpret_cast<intptr_t>(new_h);
+ } // else new_h could be nullptr if we queued ourselves on a
+ // CondVar
+ }
+ // release spinlock & lock
+ // can release with a store because there were waiters
+ mu_.store(nv, std::memory_order_release);
+ break;
+ }
+
+ // set up to walk the list
+ PerThreadSynch *w_walk; // current waiter during list walk
+ PerThreadSynch *pw_walk; // previous waiter during list walk
+ if (old_h != nullptr) { // we've searched up to old_h before
+ pw_walk = old_h;
+ w_walk = old_h->next;
+ } else { // no prior search, start at beginning
+ pw_walk =
+ nullptr; // h->next's predecessor may change; don't record it
+ w_walk = h->next;
+ }
+
+ h->may_skip = false; // ensure we never skip past h in future searches
+ // even if other waiters are queued after it.
+ ABSL_RAW_CHECK(h->skip == nullptr, "illegal skip from head");
+
+ h->maybe_unlocking = true; // we're about to scan the waiter list
+ // without the spinlock held.
+ // Enqueue must be conservative about
+ // priority queuing.
+
+ // We must release the spinlock to evaluate the conditions.
+ mu_.store(v, std::memory_order_release); // release just spinlock
+ // can release with a store because there were waiters
+
+ // h is the last waiter queued, and w_walk the first unsearched waiter.
+ // Without the spinlock, the locations mu_ and h->next may now change
+ // underneath us, but since we hold the lock itself, the only legal
+ // change is to add waiters between h and w_walk. Therefore, it's safe
+ // to walk the path from w_walk to h inclusive. (TryRemove() can remove
+ // a waiter anywhere, but it acquires both the spinlock and the Mutex)
+
+ old_h = h; // remember we searched to here
+
+ // Walk the path upto and including h looking for waiters we can wake.
+ while (pw_walk != h) {
+ w_walk->wake = false;
+ if (w_walk->waitp->cond ==
+ nullptr || // no condition => vacuously true OR
+ (w_walk->waitp->cond != known_false &&
+ // this thread's condition is not known false, AND
+ // is in fact true
+ EvalConditionIgnored(this, w_walk->waitp->cond))) {
+ if (w == nullptr) {
+ w_walk->wake = true; // can wake this waiter
+ w = w_walk;
+ pw = pw_walk;
+ if (w_walk->waitp->how == kExclusive) {
+ wr_wait = kMuWrWait;
+ break; // bail if waking this writer
+ }
+ } else if (w_walk->waitp->how == kShared) { // wake if a reader
+ w_walk->wake = true;
+ } else { // writer with true condition
+ wr_wait = kMuWrWait;
+ }
+ } else { // can't wake; condition false
+ known_false = w_walk->waitp->cond; // remember last false condition
+ }
+ if (w_walk->wake) { // we're waking reader w_walk
+ pw_walk = w_walk; // don't skip similar waiters
+ } else { // not waking; skip as much as possible
+ pw_walk = Skip(w_walk);
+ }
+ // If pw_walk == h, then load of pw_walk->next can race with
+ // concurrent write in Enqueue(). However, at the same time
+ // we do not need to do the load, because we will bail out
+ // from the loop anyway.
+ if (pw_walk != h) {
+ w_walk = pw_walk->next;
+ }
+ }
+
+ continue; // restart for(;;)-loop to wakeup w or to find more waiters
+ }
+ ABSL_RAW_CHECK(pw->next == w, "pw not w's predecessor");
+ // The first (and perhaps only) waiter we've chosen to wake is w, whose
+ // predecessor is pw. If w is a reader, we must wake all the other
+ // waiters with wake==true as well. We may also need to queue
+ // ourselves if waitp != null. The spinlock and the lock are still
+ // held.
+
+ // This traverses the list in [ pw->next, h ], where h is the head,
+ // removing all elements with wake==true and placing them in the
+ // singly-linked list wake_list. Returns the new head.
+ h = DequeueAllWakeable(h, pw, &wake_list);
+
+ intptr_t nv = (v & kMuEvent) | kMuDesig;
+ // assume no waiters left,
+ // set kMuDesig for INV1a
+
+ if (waitp != nullptr) { // we must queue ourselves and sleep
+ h = Enqueue(h, waitp, v, kMuIsCond);
+ // h is new last waiter; could be null if we queued ourselves on a
+ // CondVar
+ }
+
+ ABSL_RAW_CHECK(wake_list != kPerThreadSynchNull,
+ "unexpected empty wake list");
+
+ if (h != nullptr) { // there are waiters left
+ h->readers = 0;
+ h->maybe_unlocking = false; // finished unlocking
+ nv |= wr_wait | kMuWait | reinterpret_cast<intptr_t>(h);
+ }
+
+ // release both spinlock & lock
+ // can release with a store because there were waiters
+ mu_.store(nv, std::memory_order_release);
+ break; // out of for(;;)-loop
+ }
+ c = Delay(c, AGGRESSIVE); // aggressive here; no one can proceed till we do
+ } // end of for(;;)-loop
+
+ if (wake_list != kPerThreadSynchNull) {
+ int64_t enqueue_timestamp = wake_list->waitp->contention_start_cycles;
+ bool cond_waiter = wake_list->cond_waiter;
+ do {
+ wake_list = Wakeup(wake_list); // wake waiters
+ } while (wake_list != kPerThreadSynchNull);
+ if (!cond_waiter) {
+ // Sample lock contention events only if the (first) waiter was trying to
+ // acquire the lock, not waiting on a condition variable or Condition.
+ int64_t wait_cycles = base_internal::CycleClock::Now() - enqueue_timestamp;
+ mutex_tracer("slow release", this, wait_cycles);
+ ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0);
+ submit_profile_data(enqueue_timestamp);
+ ABSL_TSAN_MUTEX_POST_DIVERT(this, 0);
+ }
+ }
+}
+
+// Used by CondVar implementation to reacquire mutex after waking from
+// condition variable. This routine is used instead of Lock() because the
+// waiting thread may have been moved from the condition variable queue to the
+// mutex queue without a wakeup, by Trans(). In that case, when the thread is
+// finally woken, the woken thread will believe it has been woken from the
+// condition variable (i.e. its PC will be in when in the CondVar code), when
+// in fact it has just been woken from the mutex. Thus, it must enter the slow
+// path of the mutex in the same state as if it had just woken from the mutex.
+// That is, it must ensure to clear kMuDesig (INV1b).
+void Mutex::Trans(MuHow how) {
+ this->LockSlow(how, nullptr, kMuHasBlocked | kMuIsCond);
+}
+
+// Used by CondVar implementation to effectively wake thread w from the
+// condition variable. If this mutex is free, we simply wake the thread.
+// It will later acquire the mutex with high probability. Otherwise, we
+// enqueue thread w on this mutex.
+void Mutex::Fer(PerThreadSynch *w) {
+ int c = 0;
+ ABSL_RAW_CHECK(w->waitp->cond == nullptr,
+ "Mutex::Fer while waiting on Condition");
+ ABSL_RAW_CHECK(!w->waitp->timeout.has_timeout(),
+ "Mutex::Fer while in timed wait");
+ ABSL_RAW_CHECK(w->waitp->cv_word == nullptr,
+ "Mutex::Fer with pending CondVar queueing");
+ for (;;) {
+ intptr_t v = mu_.load(std::memory_order_relaxed);
+ // Note: must not queue if the mutex is unlocked (nobody will wake it).
+ // For example, we can have only kMuWait (conditional) or maybe
+ // kMuWait|kMuWrWait.
+ // conflicting != 0 implies that the waking thread cannot currently take
+ // the mutex, which in turn implies that someone else has it and can wake
+ // us if we queue.
+ const intptr_t conflicting =
+ kMuWriter | (w->waitp->how == kShared ? 0 : kMuReader);
+ if ((v & conflicting) == 0) {
+ w->next = nullptr;
+ w->state.store(PerThreadSynch::kAvailable, std::memory_order_release);
+ IncrementSynchSem(this, w);
+ return;
+ } else {
+ if ((v & (kMuSpin|kMuWait)) == 0) { // no waiters
+ // This thread tries to become the one and only waiter.
+ PerThreadSynch *new_h = Enqueue(nullptr, w->waitp, v, kMuIsCond);
+ ABSL_RAW_CHECK(new_h != nullptr,
+ "Enqueue failed"); // we must queue ourselves
+ if (mu_.compare_exchange_strong(
+ v, reinterpret_cast<intptr_t>(new_h) | (v & kMuLow) | kMuWait,
+ std::memory_order_release, std::memory_order_relaxed)) {
+ return;
+ }
+ } else if ((v & kMuSpin) == 0 &&
+ mu_.compare_exchange_strong(v, v | kMuSpin | kMuWait)) {
+ PerThreadSynch *h = GetPerThreadSynch(v);
+ PerThreadSynch *new_h = Enqueue(h, w->waitp, v, kMuIsCond);
+ ABSL_RAW_CHECK(new_h != nullptr,
+ "Enqueue failed"); // we must queue ourselves
+ do {
+ v = mu_.load(std::memory_order_relaxed);
+ } while (!mu_.compare_exchange_weak(
+ v,
+ (v & kMuLow & ~kMuSpin) | kMuWait |
+ reinterpret_cast<intptr_t>(new_h),
+ std::memory_order_release, std::memory_order_relaxed));
+ return;
+ }
+ }
+ c = Delay(c, GENTLE);
+ }
+}
+
+void Mutex::AssertHeld() const {
+ if ((mu_.load(std::memory_order_relaxed) & kMuWriter) == 0) {
+ SynchEvent *e = GetSynchEvent(this);
+ ABSL_RAW_LOG(FATAL, "thread should hold write lock on Mutex %p %s",
+ static_cast<const void *>(this),
+ (e == nullptr ? "" : e->name));
+ }
+}
+
+void Mutex::AssertReaderHeld() const {
+ if ((mu_.load(std::memory_order_relaxed) & (kMuReader | kMuWriter)) == 0) {
+ SynchEvent *e = GetSynchEvent(this);
+ ABSL_RAW_LOG(
+ FATAL, "thread should hold at least a read lock on Mutex %p %s",
+ static_cast<const void *>(this), (e == nullptr ? "" : e->name));
+ }
+}
+
+// -------------------------------- condition variables
+static const intptr_t kCvSpin = 0x0001L; // spinlock protects waiter list
+static const intptr_t kCvEvent = 0x0002L; // record events
+
+static const intptr_t kCvLow = 0x0003L; // low order bits of CV
+
+// Hack to make constant values available to gdb pretty printer
+enum { kGdbCvSpin = kCvSpin, kGdbCvEvent = kCvEvent, kGdbCvLow = kCvLow, };
+
+static_assert(PerThreadSynch::kAlignment > kCvLow,
+ "PerThreadSynch::kAlignment must be greater than kCvLow");
+
+void CondVar::EnableDebugLog(const char *name) {
+ SynchEvent *e = EnsureSynchEvent(&this->cv_, name, kCvEvent, kCvSpin);
+ e->log = true;
+ UnrefSynchEvent(e);
+}
+
+CondVar::~CondVar() {
+ if ((cv_.load(std::memory_order_relaxed) & kCvEvent) != 0) {
+ ForgetSynchEvent(&this->cv_, kCvEvent, kCvSpin);
+ }
+}
+
+
+// Remove thread s from the list of waiters on this condition variable.
+void CondVar::Remove(PerThreadSynch *s) {
+ intptr_t v;
+ int c = 0;
+ for (v = cv_.load(std::memory_order_relaxed);;
+ v = cv_.load(std::memory_order_relaxed)) {
+ if ((v & kCvSpin) == 0 && // attempt to acquire spinlock
+ cv_.compare_exchange_strong(v, v | kCvSpin,
+ std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ PerThreadSynch *h = reinterpret_cast<PerThreadSynch *>(v & ~kCvLow);
+ if (h != nullptr) {
+ PerThreadSynch *w = h;
+ while (w->next != s && w->next != h) { // search for thread
+ w = w->next;
+ }
+ if (w->next == s) { // found thread; remove it
+ w->next = s->next;
+ if (h == s) {
+ h = (w == s) ? nullptr : w;
+ }
+ s->next = nullptr;
+ s->state.store(PerThreadSynch::kAvailable, std::memory_order_release);
+ }
+ }
+ // release spinlock
+ cv_.store((v & kCvEvent) | reinterpret_cast<intptr_t>(h),
+ std::memory_order_release);
+ return;
+ } else {
+ c = Delay(c, GENTLE); // try again after a delay
+ }
+ }
+}
+
+// Queue thread waitp->thread on condition variable word cv_word using
+// wait parameters waitp.
+// We split this into a separate routine, rather than simply doing it as part
+// of WaitCommon(). If we were to queue ourselves on the condition variable
+// before calling Mutex::UnlockSlow(), the Mutex code might be re-entered (via
+// the logging code, or via a Condition function) and might potentially attempt
+// to block this thread. That would be a problem if the thread were already on
+// a the condition variable waiter queue. Thus, we use the waitp->cv_word
+// to tell the unlock code to call CondVarEnqueue() to queue the thread on the
+// condition variable queue just before the mutex is to be unlocked, and (most
+// importantly) after any call to an external routine that might re-enter the
+// mutex code.
+static void CondVarEnqueue(SynchWaitParams *waitp) {
+ // This thread might be transferred to the Mutex queue by Fer() when
+ // we are woken. To make sure that is what happens, Enqueue() doesn't
+ // call CondVarEnqueue() again but instead uses its normal code. We
+ // must do this before we queue ourselves so that cv_word will be null
+ // when seen by the dequeuer, who may wish immediately to requeue
+ // this thread on another queue.
+ std::atomic<intptr_t> *cv_word = waitp->cv_word;
+ waitp->cv_word = nullptr;
+
+ intptr_t v = cv_word->load(std::memory_order_relaxed);
+ int c = 0;
+ while ((v & kCvSpin) != 0 || // acquire spinlock
+ !cv_word->compare_exchange_weak(v, v | kCvSpin,
+ std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ c = Delay(c, GENTLE);
+ v = cv_word->load(std::memory_order_relaxed);
+ }
+ ABSL_RAW_CHECK(waitp->thread->waitp == nullptr, "waiting when shouldn't be");
+ waitp->thread->waitp = waitp; // prepare ourselves for waiting
+ PerThreadSynch *h = reinterpret_cast<PerThreadSynch *>(v & ~kCvLow);
+ if (h == nullptr) { // add this thread to waiter list
+ waitp->thread->next = waitp->thread;
+ } else {
+ waitp->thread->next = h->next;
+ h->next = waitp->thread;
+ }
+ waitp->thread->state.store(PerThreadSynch::kQueued,
+ std::memory_order_relaxed);
+ cv_word->store((v & kCvEvent) | reinterpret_cast<intptr_t>(waitp->thread),
+ std::memory_order_release);
+}
+
+bool CondVar::WaitCommon(Mutex *mutex, KernelTimeout t) {
+ bool rc = false; // return value; true iff we timed-out
+
+ intptr_t mutex_v = mutex->mu_.load(std::memory_order_relaxed);
+ Mutex::MuHow mutex_how = ((mutex_v & kMuWriter) != 0) ? kExclusive : kShared;
+ ABSL_TSAN_MUTEX_PRE_UNLOCK(mutex, TsanFlags(mutex_how));
+
+ // maybe trace this call
+ intptr_t v = cv_.load(std::memory_order_relaxed);
+ cond_var_tracer("Wait", this);
+ if ((v & kCvEvent) != 0) {
+ PostSynchEvent(this, SYNCH_EV_WAIT);
+ }
+
+ // Release mu and wait on condition variable.
+ SynchWaitParams waitp(mutex_how, nullptr, t, mutex,
+ Synch_GetPerThreadAnnotated(mutex), &cv_);
+ // UnlockSlow() will call CondVarEnqueue() just before releasing the
+ // Mutex, thus queuing this thread on the condition variable. See
+ // CondVarEnqueue() for the reasons.
+ mutex->UnlockSlow(&waitp);
+
+ // wait for signal
+ while (waitp.thread->state.load(std::memory_order_acquire) ==
+ PerThreadSynch::kQueued) {
+ if (!Mutex::DecrementSynchSem(mutex, waitp.thread, t)) {
+ this->Remove(waitp.thread);
+ rc = true;
+ }
+ }
+
+ ABSL_RAW_CHECK(waitp.thread->waitp != nullptr, "not waiting when should be");
+ waitp.thread->waitp = nullptr; // cleanup
+
+ // maybe trace this call
+ cond_var_tracer("Unwait", this);
+ if ((v & kCvEvent) != 0) {
+ PostSynchEvent(this, SYNCH_EV_WAIT_RETURNING);
+ }
+
+ // From synchronization point of view Wait is unlock of the mutex followed
+ // by lock of the mutex. We've annotated start of unlock in the beginning
+ // of the function. Now, finish unlock and annotate lock of the mutex.
+ // (Trans is effectively lock).
+ ABSL_TSAN_MUTEX_POST_UNLOCK(mutex, TsanFlags(mutex_how));
+ ABSL_TSAN_MUTEX_PRE_LOCK(mutex, TsanFlags(mutex_how));
+ mutex->Trans(mutex_how); // Reacquire mutex
+ ABSL_TSAN_MUTEX_POST_LOCK(mutex, TsanFlags(mutex_how), 0);
+ return rc;
+}
+
+bool CondVar::WaitWithTimeout(Mutex *mu, absl::Duration timeout) {
+ return WaitWithDeadline(mu, DeadlineFromTimeout(timeout));
+}
+
+bool CondVar::WaitWithDeadline(Mutex *mu, absl::Time deadline) {
+ return WaitCommon(mu, KernelTimeout(deadline));
+}
+
+void CondVar::Wait(Mutex *mu) {
+ WaitCommon(mu, KernelTimeout::Never());
+}
+
+// Wake thread w
+// If it was a timed wait, w will be waiting on w->cv
+// Otherwise, if it was not a Mutex mutex, w will be waiting on w->sem
+// Otherwise, w is transferred to the Mutex mutex via Mutex::Fer().
+void CondVar::Wakeup(PerThreadSynch *w) {
+ if (w->waitp->timeout.has_timeout() || w->waitp->cvmu == nullptr) {
+ // The waiting thread only needs to observe "w->state == kAvailable" to be
+ // released, we must cache "cvmu" before clearing "next".
+ Mutex *mu = w->waitp->cvmu;
+ w->next = nullptr;
+ w->state.store(PerThreadSynch::kAvailable, std::memory_order_release);
+ Mutex::IncrementSynchSem(mu, w);
+ } else {
+ w->waitp->cvmu->Fer(w);
+ }
+}
+
+void CondVar::Signal() {
+ ABSL_TSAN_MUTEX_PRE_SIGNAL(0, 0);
+ intptr_t v;
+ int c = 0;
+ for (v = cv_.load(std::memory_order_relaxed); v != 0;
+ v = cv_.load(std::memory_order_relaxed)) {
+ if ((v & kCvSpin) == 0 && // attempt to acquire spinlock
+ cv_.compare_exchange_strong(v, v | kCvSpin,
+ std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ PerThreadSynch *h = reinterpret_cast<PerThreadSynch *>(v & ~kCvLow);
+ PerThreadSynch *w = nullptr;
+ if (h != nullptr) { // remove first waiter
+ w = h->next;
+ if (w == h) {
+ h = nullptr;
+ } else {
+ h->next = w->next;
+ }
+ }
+ // release spinlock
+ cv_.store((v & kCvEvent) | reinterpret_cast<intptr_t>(h),
+ std::memory_order_release);
+ if (w != nullptr) {
+ CondVar::Wakeup(w); // wake waiter, if there was one
+ cond_var_tracer("Signal wakeup", this);
+ }
+ if ((v & kCvEvent) != 0) {
+ PostSynchEvent(this, SYNCH_EV_SIGNAL);
+ }
+ ABSL_TSAN_MUTEX_POST_SIGNAL(0, 0);
+ return;
+ } else {
+ c = Delay(c, GENTLE);
+ }
+ }
+ ABSL_TSAN_MUTEX_POST_SIGNAL(0, 0);
+}
+
+void CondVar::SignalAll () {
+ ABSL_TSAN_MUTEX_PRE_SIGNAL(0, 0);
+ intptr_t v;
+ int c = 0;
+ for (v = cv_.load(std::memory_order_relaxed); v != 0;
+ v = cv_.load(std::memory_order_relaxed)) {
+ // empty the list if spinlock free
+ // We do this by simply setting the list to empty using
+ // compare and swap. We then have the entire list in our hands,
+ // which cannot be changing since we grabbed it while no one
+ // held the lock.
+ if ((v & kCvSpin) == 0 &&
+ cv_.compare_exchange_strong(v, v & kCvEvent, std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ PerThreadSynch *h = reinterpret_cast<PerThreadSynch *>(v & ~kCvLow);
+ if (h != nullptr) {
+ PerThreadSynch *w;
+ PerThreadSynch *n = h->next;
+ do { // for every thread, wake it up
+ w = n;
+ n = n->next;
+ CondVar::Wakeup(w);
+ } while (w != h);
+ cond_var_tracer("SignalAll wakeup", this);
+ }
+ if ((v & kCvEvent) != 0) {
+ PostSynchEvent(this, SYNCH_EV_SIGNALALL);
+ }
+ ABSL_TSAN_MUTEX_POST_SIGNAL(0, 0);
+ return;
+ } else {
+ c = Delay(c, GENTLE); // try again after a delay
+ }
+ }
+ ABSL_TSAN_MUTEX_POST_SIGNAL(0, 0);
+}
+
+void ReleasableMutexLock::Release() {
+ ABSL_RAW_CHECK(this->mu_ != nullptr,
+ "ReleasableMutexLock::Release may only be called once");
+ this->mu_->Unlock();
+ this->mu_ = nullptr;
+}
+
+#ifdef THREAD_SANITIZER
+extern "C" void __tsan_read1(void *addr);
+#else
+#define __tsan_read1(addr) // do nothing if TSan not enabled
+#endif
+
+// A function that just returns its argument, dereferenced
+static bool Dereference(void *arg) {
+ // ThreadSanitizer does not instrument this file for memory accesses.
+ // This function dereferences a user variable that can participate
+ // in a data race, so we need to manually tell TSan about this memory access.
+ __tsan_read1(arg);
+ return *(static_cast<bool *>(arg));
+}
+
+Condition::Condition() {} // null constructor, used for kTrue only
+const Condition Condition::kTrue;
+
+Condition::Condition(bool (*func)(void *), void *arg)
+ : eval_(&CallVoidPtrFunction),
+ function_(func),
+ method_(nullptr),
+ arg_(arg) {}
+
+bool Condition::CallVoidPtrFunction(const Condition *c) {
+ return (*c->function_)(c->arg_);
+}
+
+Condition::Condition(const bool *cond)
+ : eval_(CallVoidPtrFunction),
+ function_(Dereference),
+ method_(nullptr),
+ // const_cast is safe since Dereference does not modify arg
+ arg_(const_cast<bool *>(cond)) {}
+
+bool Condition::Eval() const {
+ // eval_ == null for kTrue
+ return (this->eval_ == nullptr) || (*this->eval_)(this);
+}
+
+bool Condition::GuaranteedEqual(const Condition *a, const Condition *b) {
+ if (a == nullptr) {
+ return b == nullptr || b->eval_ == nullptr;
+ }
+ if (b == nullptr || b->eval_ == nullptr) {
+ return a->eval_ == nullptr;
+ }
+ return a->eval_ == b->eval_ && a->function_ == b->function_ &&
+ a->arg_ == b->arg_ && a->method_ == b->method_;
+}
+
+} // namespace absl
diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h
new file mode 100644
index 0000000..a417802
--- /dev/null
+++ b/absl/synchronization/mutex.h
@@ -0,0 +1,1013 @@
+// 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.
+//
+// -----------------------------------------------------------------------------
+// mutex.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines a `Mutex` -- a mutually exclusive lock -- and the
+// most common type of synchronization primitive for facilitating locks on
+// shared resources. A mutex is used to prevent multiple threads from accessing
+// and/or writing to a shared resource concurrently.
+//
+// Unlike a `std::mutex`, the Abseil `Mutex` provides the following additional
+// features:
+// * Conditional predicates intrinsic to the `Mutex` object
+// * Reader/writer locks, in addition to standard exclusive/writer locks
+// * Deadlock detection and debug support.
+//
+// The following helper classes are also defined within this file:
+//
+// MutexLock - An RAII wrapper to acquire and release a `Mutex` for exclusive/
+// write access within the current scope.
+// ReaderMutexLock
+// - An RAII wrapper to acquire and release a `Mutex` for shared/read
+// access within the current scope.
+//
+// WriterMutexLock
+// - Alias for `MutexLock` above, designed for use in distinguishing
+// reader and writer locks within code.
+//
+// In addition to simple mutex locks, this file also defines ways to perform
+// locking under certain conditions.
+//
+// Condition - (Preferred) Used to wait for a particular predicate that
+// depends on state protected by the `Mutex` to become true.
+// CondVar - A lower-level variant of `Condition` that relies on
+// application code to explicitly signal the `CondVar` when
+// a condition has been met.
+//
+// See below for more information on using `Condition` or `CondVar`.
+//
+// Mutexes and mutex behavior can be quite complicated. The information within
+// this header file is limited, as a result. Please consult the Mutex guide for
+// more complete information and examples.
+
+#ifndef ABSL_SYNCHRONIZATION_MUTEX_H_
+#define ABSL_SYNCHRONIZATION_MUTEX_H_
+
+#include <atomic>
+#include <cstdint>
+#include <string>
+
+#include "absl/base/internal/identity.h"
+#include "absl/base/internal/low_level_alloc.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/base/port.h"
+#include "absl/base/thread_annotations.h"
+#include "absl/synchronization/internal/kernel_timeout.h"
+#include "absl/synchronization/internal/per_thread_sem.h"
+#include "absl/time/time.h"
+
+// Decide if we should use the non-production implementation because
+// the production implementation hasn't been fully ported yet.
+#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX
+#error ABSL_INTERNAL_USE_NONPROD_MUTEX cannot be directly set
+#elif defined(ABSL_LOW_LEVEL_ALLOC_MISSING)
+#define ABSL_INTERNAL_USE_NONPROD_MUTEX 1
+#include "absl/synchronization/internal/mutex_nonprod.inc"
+#endif
+
+namespace absl {
+
+struct SynchWaitParams;
+class Condition;
+
+// -----------------------------------------------------------------------------
+// Mutex
+// -----------------------------------------------------------------------------
+//
+// A `Mutex` is a non-reentrant (aka non-recursive) Mutually Exclusive lock
+// on some resource, typically a variable or data structure with associated
+// invariants. Proper usage of mutexes prevents concurrent access by different
+// threads to the same resource.
+//
+// A `Mutex` has two basic operations: `Mutex::Lock()` and `Mutex::Unlock()`.
+// The `Lock()` operation *acquires* a `Mutex` (in a state known as an
+// *exclusive* -- or write -- lock), while the `Unlock()` operation *releases* a
+// Mutex. During the span of time between the Lock() and Unlock() operations,
+// a mutex is said to be *held*. By design all mutexes support exclusive/write
+// locks, as this is the most common way to use a mutex.
+//
+// The `Mutex` state machine for basic lock/unlock operations is quite simple:
+//
+// | | Lock() | Unlock() |
+// |----------------+------------+----------|
+// | Free | Exclusive | invalid |
+// | Exclusive | blocks | Free |
+//
+// Attempts to `Unlock()` must originate from the thread that performed the
+// corresponding `Lock()` operation.
+//
+// An "invalid" operation is disallowed by the API. The `Mutex` implementation
+// is allowed to do anything on an invalid call, including but not limited to
+// crashing with a useful error message, silently succeeding, or corrupting
+// data structures. In debug mode, the implementation attempts to crash with a
+// useful error message.
+//
+// `Mutex` is not guaranteed to be "fair" in prioritizing waiting threads; it
+// is, however, approximately fair over long periods, and starvation-free for
+// threads at the same priority.
+//
+// The lock/unlock primitives are now annotated with lock annotations
+// defined in (base/thread_annotations.h). When writing multi-threaded code,
+// you should use lock annotations whenever possible to document your lock
+// synchronization policy. Besides acting as documentation, these annotations
+// also help compilers or static analysis tools to identify and warn about
+// issues that could potentially result in race conditions and deadlocks.
+//
+// For more information about the lock annotations, please see
+// [Thread Safety Analysis](http://clang.llvm.org/docs/ThreadSafetyAnalysis.html)
+// in the Clang documentation.
+//
+// See also `MutexLock`, below, for scoped `Mutex` acquisition.
+
+class LOCKABLE Mutex {
+ public:
+ Mutex();
+ ~Mutex();
+
+ // Mutex::Lock()
+ //
+ // Blocks the calling thread, if necessary, until this `Mutex` is free, and
+ // then acquires it exclusively. (This lock is also known as a "write lock.")
+ void Lock() EXCLUSIVE_LOCK_FUNCTION();
+
+ // Mutex::Unlock()
+ //
+ // Releases this `Mutex` and returns it from the exclusive/write state to the
+ // free state. Caller must hold the `Mutex` exclusively.
+ void Unlock() UNLOCK_FUNCTION();
+
+ // Mutex::TryLock()
+ //
+ // If the mutex can be acquired without blocking, does so exclusively and
+ // returns `true`. Otherwise, returns `false`. Returns `true` with high
+ // probability if the `Mutex` was free.
+ bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true);
+
+ // Mutex::AssertHeld()
+ //
+ // Return immediately if this thread holds the `Mutex` exclusively (in write
+ // mode). Otherwise, may report an error (typically by crashing with a
+ // diagnostic), or may return immediately.
+ void AssertHeld() const ASSERT_EXCLUSIVE_LOCK();
+
+ // ---------------------------------------------------------------------------
+ // Reader-Writer Locking
+ // ---------------------------------------------------------------------------
+
+ // A Mutex can also be used as a starvation-free reader-writer lock.
+ // Neither read-locks nor write-locks are reentrant/recursive to avoid
+ // potential client programming errors.
+ //
+ // The Mutex API provides `Writer*()` aliases for the existing `Lock()`,
+ // `Unlock()` and `TryLock()` methods for use within applications mixing
+ // reader/writer locks. Using `Reader*()` and `Writer*()` operations in this
+ // manner can make locking behavior clearer when mixing read and write modes.
+ //
+ // Introducing reader locks necessarily complicates the `Mutex` state
+ // machine somewhat. The table below illustrates the allowed state transitions
+ // of a mutex in such cases. Note that ReaderLock() may block even if the lock
+ // is held in shared mode; this occurs when another thread is blocked on a
+ // call to WriterLock().
+ //
+ // ---------------------------------------------------------------------------
+ // Operation: WriterLock() Unlock() ReaderLock() ReaderUnlock()
+ // ---------------------------------------------------------------------------
+ // State
+ // ---------------------------------------------------------------------------
+ // Free Exclusive invalid Shared(1) invalid
+ // Shared(1) blocks invalid Shared(2) or blocks Free
+ // Shared(n) n>1 blocks invalid Shared(n+1) or blocks Shared(n-1)
+ // Exclusive blocks Free blocks invalid
+ // ---------------------------------------------------------------------------
+ //
+ // In comments below, "shared" refers to a state of Shared(n) for any n > 0.
+
+ // Mutex::ReaderLock()
+ //
+ // Blocks the calling thread, if necessary, until this `Mutex` is either free,
+ // or in shared mode, and then acquires a share of it. Note that
+ // `ReaderLock()` will block if some other thread has an exclusive/writer lock
+ // on the mutex.
+
+ void ReaderLock() SHARED_LOCK_FUNCTION();
+
+ // Mutex::ReaderUnlock()
+ //
+ // Releases a read share of this `Mutex`. `ReaderUnlock` may return a mutex to
+ // the free state if this thread holds the last reader lock on the mutex. Note
+ // that you cannot call `ReaderUnlock()` on a mutex held in write mode.
+ void ReaderUnlock() UNLOCK_FUNCTION();
+
+ // Mutex::ReaderTryLock()
+ //
+ // If the mutex can be acquired without blocking, acquires this mutex for
+ // shared access and returns `true`. Otherwise, returns `false`. Returns
+ // `true` with high probability if the `Mutex` was free or shared.
+ bool ReaderTryLock() SHARED_TRYLOCK_FUNCTION(true);
+
+ // Mutex::AssertReaderHeld()
+ //
+ // Returns immediately if this thread holds the `Mutex` in at least shared
+ // mode (read mode). Otherwise, may report an error (typically by
+ // crashing with a diagnostic), or may return immediately.
+ void AssertReaderHeld() const ASSERT_SHARED_LOCK();
+
+ // Mutex::WriterLock()
+ // Mutex::WriterUnlock()
+ // Mutex::WriterTryLock()
+ //
+ // Aliases for `Mutex::Lock()`, `Mutex::Unlock()`, and `Mutex::TryLock()`.
+ //
+ // Use the `Writer*()` versions of these method names when using complementary
+ // `Reader*()` methods to distingish simple exclusive `Mutex` usage (`Lock()`,
+ // etc.) from reader/writer lock usage.
+ void WriterLock() EXCLUSIVE_LOCK_FUNCTION() { this->Lock(); }
+
+ void WriterUnlock() UNLOCK_FUNCTION() { this->Unlock(); }
+
+ bool WriterTryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
+ return this->TryLock();
+ }
+
+ // ---------------------------------------------------------------------------
+ // Conditional Critical Regions
+ // ---------------------------------------------------------------------------
+
+ // Conditional usage of a `Mutex` can occur using two distinct paradigms:
+ //
+ // * Use of `Mutex` member functions with `Condition` objects.
+ // * Use of the separate `CondVar` abstraction.
+ //
+ // In general, prefer use of `Condition` and the `Mutex` member functions
+ // listed below over `CondVar`. When there are multiple threads waiting on
+ // distinctly different conditions, however, a battery of `CondVar`s may be
+ // more efficient. This section discusses use of `Condition` objects.
+ //
+ // `Mutex` contains member functions for performing lock operations only under
+ // certain conditions, of class `Condition`. For correctness, the `Condition`
+ // must return a boolean that is a pure function, only of state protected by
+ // the `Mutex`. The condition must be invariant w.r.t. environmental state
+ // such as thread, cpu id, or time, and must be `noexcept`. The condition will
+ // always be invoked with the mutex held in at least read mode, so you should
+ // not block it for long periods or sleep it on a timer.
+ //
+ // Since a condition must not depend directly on the current time, use
+ // `*WithTimeout()` member function variants to make your condition
+ // effectively true after a given duration, or `*WithDeadline()` variants to
+ // make your condition effectively true after a given time.
+ //
+ // The condition function should have no side-effects aside from debug
+ // logging; as a special exception, the function may acquire other mutexes
+ // provided it releases all those that it acquires. (This exception was
+ // required to allow logging.)
+
+ // Mutex::Await()
+ //
+ // Unlocks this `Mutex` and blocks until simultaneously both `cond` is `true`
+ // and this `Mutex` can be reacquired, then reacquires this `Mutex` in the
+ // same mode in which it was previously held. If the condition is initially
+ // `true`, `Await()` *may* skip the release/re-acquire step.
+ //
+ // `Await()` requires that this thread holds this `Mutex` in some mode.
+ void Await(const Condition &cond);
+
+ // Mutex::LockWhen()
+ // Mutex::ReaderLockWhen()
+ // Mutex::WriterLockWhen()
+ //
+ // Blocks until simultaneously both `cond` is `true` and this` Mutex` can
+ // be acquired, then atomically acquires this `Mutex`. `LockWhen()` is
+ // logically equivalent to `*Lock(); Await();` though they may have different
+ // performance characteristics.
+ void LockWhen(const Condition &cond) EXCLUSIVE_LOCK_FUNCTION();
+
+ void ReaderLockWhen(const Condition &cond) SHARED_LOCK_FUNCTION();
+
+ void WriterLockWhen(const Condition &cond) EXCLUSIVE_LOCK_FUNCTION() {
+ this->LockWhen(cond);
+ }
+
+ // ---------------------------------------------------------------------------
+ // Mutex Variants with Timeouts/Deadlines
+ // ---------------------------------------------------------------------------
+
+ // Mutex::AwaitWithTimeout()
+ // Mutex::AwaitWithDeadline()
+ //
+ // If `cond` is initially true, do nothing, or act as though `cond` is
+ // initially false.
+ //
+ // If `cond` is initially false, unlock this `Mutex` and block until
+ // simultaneously:
+ // - either `cond` is true or the {timeout has expired, deadline has passed}
+ // and
+ // - this `Mutex` can be reacquired,
+ // then reacquire this `Mutex` in the same mode in which it was previously
+ // held, returning `true` iff `cond` is `true` on return.
+ //
+ // Deadlines in the past are equivalent to an immediate deadline.
+ // Negative timeouts are equivalent to a zero timeout.
+ //
+ // This method requires that this thread holds this `Mutex` in some mode.
+ bool AwaitWithTimeout(const Condition &cond, absl::Duration timeout);
+
+ bool AwaitWithDeadline(const Condition &cond, absl::Time deadline);
+
+ // Mutex::LockWhenWithTimeout()
+ // Mutex::ReaderLockWhenWithTimeout()
+ // Mutex::WriterLockWhenWithTimeout()
+ //
+ // Blocks until simultaneously both:
+ // - either `cond` is `true` or the timeout has expired, and
+ // - this `Mutex` can be acquired,
+ // then atomically acquires this `Mutex`, returning `true` iff `cond` is
+ // `true` on return.
+ //
+ // Negative timeouts are equivalent to a zero timeout.
+ bool LockWhenWithTimeout(const Condition &cond, absl::Duration timeout)
+ EXCLUSIVE_LOCK_FUNCTION();
+ bool ReaderLockWhenWithTimeout(const Condition &cond, absl::Duration timeout)
+ SHARED_LOCK_FUNCTION();
+ bool WriterLockWhenWithTimeout(const Condition &cond, absl::Duration timeout)
+ EXCLUSIVE_LOCK_FUNCTION() {
+ return this->LockWhenWithTimeout(cond, timeout);
+ }
+
+ // Mutex::LockWhenWithDeadline()
+ // Mutex::ReaderLockWhenWithDeadline()
+ // Mutex::WriterLockWhenWithDeadline()
+ //
+ // Blocks until simultaneously both:
+ // - either `cond` is `true` or the deadline has been passed, and
+ // - this `Mutex` can be acquired,
+ // then atomically acquires this Mutex, returning `true` iff `cond` is `true`
+ // on return.
+ //
+ // Deadlines in the past are equivalent to an immediate deadline.
+ bool LockWhenWithDeadline(const Condition &cond, absl::Time deadline)
+ EXCLUSIVE_LOCK_FUNCTION();
+ bool ReaderLockWhenWithDeadline(const Condition &cond, absl::Time deadline)
+ SHARED_LOCK_FUNCTION();
+ bool WriterLockWhenWithDeadline(const Condition &cond, absl::Time deadline)
+ EXCLUSIVE_LOCK_FUNCTION() {
+ return this->LockWhenWithDeadline(cond, deadline);
+ }
+
+ // ---------------------------------------------------------------------------
+ // Debug Support: Invariant Checking, Deadlock Detection, Logging.
+ // ---------------------------------------------------------------------------
+
+ // Mutex::EnableInvariantDebugging()
+ //
+ // If `invariant`!=null and if invariant debugging has been enabled globally,
+ // cause `(*invariant)(arg)` to be called at moments when the invariant for
+ // this `Mutex` should hold (for example: just after acquire, just before
+ // release).
+ //
+ // The routine `invariant` should have no side-effects since it is not
+ // guaranteed how many times it will be called; it should check the invariant
+ // and crash if it does not hold. Enabling global invariant debugging may
+ // substantially reduce `Mutex` performance; it should be set only for
+ // non-production runs. Optimization options may also disable invariant
+ // checks.
+ void EnableInvariantDebugging(void (*invariant)(void *), void *arg);
+
+ // Mutex::EnableDebugLog()
+ //
+ // Cause all subsequent uses of this `Mutex` to be logged via
+ // `ABSL_RAW_LOG(INFO)`. Log entries are tagged with `name` if no previous
+ // call to `EnableInvariantDebugging()` or `EnableDebugLog()` has been made.
+ //
+ // Note: This method substantially reduces `Mutex` performance.
+ void EnableDebugLog(const char *name);
+
+ // Deadlock detection
+
+ // Mutex::ForgetDeadlockInfo()
+ //
+ // Forget any deadlock-detection information previously gathered
+ // about this `Mutex`. Call this method in debug mode when the lock ordering
+ // of a `Mutex` changes.
+ void ForgetDeadlockInfo();
+
+ // Mutex::AssertNotHeld()
+ //
+ // Return immediately if this thread does not hold this `Mutex` in any
+ // mode; otherwise, may report an error (typically by crashing with a
+ // diagnostic), or may return immediately.
+ //
+ // Currently this check is performed only if all of:
+ // - in debug mode
+ // - SetMutexDeadlockDetectionMode() has been set to kReport or kAbort
+ // - number of locks concurrently held by this thread is not large.
+ // are true.
+ void AssertNotHeld() const;
+
+ // Special cases.
+
+ // A `MuHow` is a constant that indicates how a lock should be acquired.
+ // Internal implementation detail. Clients should ignore.
+ typedef const struct MuHowS *MuHow;
+
+ // Mutex::InternalAttemptToUseMutexInFatalSignalHandler()
+ //
+ // Causes the `Mutex` implementation to prepare itself for re-entry caused by
+ // future use of `Mutex` within a fatal signal handler. This method is
+ // intended for use only for last-ditch attempts to log crash information.
+ // It does not guarantee that attempts to use Mutexes within the handler will
+ // not deadlock; it merely makes other faults less likely.
+ //
+ // WARNING: This routine must be invoked from a signal handler, and the
+ // signal handler must either loop forever or terminate the process.
+ // Attempts to return from (or `longjmp` out of) the signal handler once this
+ // call has been made may cause arbitrary program behaviour including
+ // crashes and deadlocks.
+ static void InternalAttemptToUseMutexInFatalSignalHandler();
+
+ private:
+#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX
+ friend class CondVar;
+
+ synchronization_internal::MutexImpl *impl() { return impl_.get(); }
+
+ synchronization_internal::SynchronizationStorage<
+ synchronization_internal::MutexImpl>
+ impl_;
+#else
+ std::atomic<intptr_t> mu_; // The Mutex state.
+
+ // Post()/Wait() versus associated PerThreadSem; in class for required
+ // friendship with PerThreadSem.
+ static inline void IncrementSynchSem(Mutex *mu,
+ base_internal::PerThreadSynch *w);
+ static inline bool DecrementSynchSem(
+ Mutex *mu, base_internal::PerThreadSynch *w,
+ synchronization_internal::KernelTimeout t);
+
+ // slow path acquire
+ void LockSlowLoop(SynchWaitParams *waitp, int flags);
+ // wrappers around LockSlowLoop()
+ bool LockSlowWithDeadline(MuHow how, const Condition *cond,
+ synchronization_internal::KernelTimeout t,
+ int flags);
+ void LockSlow(MuHow how, const Condition *cond,
+ int flags) ABSL_ATTRIBUTE_COLD;
+ // slow path release
+ void UnlockSlow(SynchWaitParams *waitp) ABSL_ATTRIBUTE_COLD;
+ // Common code between Await() and AwaitWithTimeout/Deadline()
+ bool AwaitCommon(const Condition &cond,
+ synchronization_internal::KernelTimeout t);
+ // Attempt to remove thread s from queue.
+ void TryRemove(base_internal::PerThreadSynch *s);
+ // Block a thread on mutex.
+ void Block(base_internal::PerThreadSynch *s);
+ // Wake a thread; return successor.
+ base_internal::PerThreadSynch *Wakeup(base_internal::PerThreadSynch *w);
+
+ friend class CondVar; // for access to Trans()/Fer().
+ void Trans(MuHow how); // used for CondVar->Mutex transfer
+ void Fer(
+ base_internal::PerThreadSynch *w); // used for CondVar->Mutex transfer
+#endif
+
+ // Catch the error of writing Mutex when intending MutexLock.
+ Mutex(const volatile Mutex * /*ignored*/) {} // NOLINT(runtime/explicit)
+
+ Mutex(const Mutex&) = delete;
+ Mutex& operator=(const Mutex&) = delete;
+};
+
+// -----------------------------------------------------------------------------
+// Mutex RAII Wrappers
+// -----------------------------------------------------------------------------
+
+// MutexLock
+//
+// `MutexLock` is a helper class, which acquires and releases a `Mutex` via
+// RAII.
+//
+// Example:
+//
+// Class Foo {
+//
+// Foo::Bar* Baz() {
+// MutexLock l(&lock_);
+// ...
+// return bar;
+// }
+//
+// private:
+// Mutex lock_;
+// };
+class SCOPED_LOCKABLE MutexLock {
+ public:
+ explicit MutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
+ this->mu_->Lock();
+ }
+ ~MutexLock() UNLOCK_FUNCTION() { this->mu_->Unlock(); }
+ private:
+ Mutex *const mu_;
+ MutexLock(const MutexLock &) = delete; // NOLINT(runtime/mutex)
+ MutexLock& operator=(const MutexLock&) = delete;
+};
+
+// ReaderMutexLock
+//
+// The `ReaderMutexLock` is a helper class, like `MutexLock`, which acquires and
+// releases a shared lock on a `Mutex` via RAII.
+class SCOPED_LOCKABLE ReaderMutexLock {
+ public:
+ explicit ReaderMutexLock(Mutex *mu) SHARED_LOCK_FUNCTION(mu)
+ : mu_(mu) {
+ mu->ReaderLock();
+ }
+ ~ReaderMutexLock() UNLOCK_FUNCTION() {
+ this->mu_->ReaderUnlock();
+ }
+ private:
+ Mutex *const mu_;
+ ReaderMutexLock(const ReaderMutexLock&) = delete;
+ ReaderMutexLock& operator=(const ReaderMutexLock&) = delete;
+};
+
+// WriterMutexLock
+//
+// The `WriterMutexLock` is a helper class, like `MutexLock`, which acquires and
+// releases a write (exclusive) lock on a `Mutex` va RAII.
+class SCOPED_LOCKABLE WriterMutexLock {
+ public:
+ explicit WriterMutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu)
+ : mu_(mu) {
+ mu->WriterLock();
+ }
+ ~WriterMutexLock() UNLOCK_FUNCTION() {
+ this->mu_->WriterUnlock();
+ }
+ private:
+ Mutex *const mu_;
+ WriterMutexLock(const WriterMutexLock&) = delete;
+ WriterMutexLock& operator=(const WriterMutexLock&) = delete;
+};
+
+// -----------------------------------------------------------------------------
+// Condition
+// -----------------------------------------------------------------------------
+//
+// As noted above, `Mutex` contains a number of member functions which take a
+// `Condition` as a argument; clients can wait for conditions to become `true`
+// before attempting to acquire the mutex. These sections are known as
+// "condition critical" sections. To use a `Condition`, you simply need to
+// construct it, and use within an appropriate `Mutex` member function;
+// everything else in the `Condition` class is an implementation detail.
+//
+// A `Condition` is specified as a function pointer which returns a boolean.
+// `Condition` functions should be pure functions -- their results should depend
+// only on passed arguments, should not consult any external state (such as
+// clocks), and should have no side-effects, aside from debug logging. Any
+// objects that the function may access should be limited to those which are
+// constant while the mutex is blocked on the condition (e.g. a stack variable),
+// or objects of state protected explicitly by the mutex.
+//
+// No matter which construction is used for `Condition`, the underlying
+// function pointer / functor / callable must not throw any
+// exceptions. Correctness of `Mutex` / `Condition` is not guaranteed in
+// the face of a throwing `Condition`. (When Abseil is allowed to depend
+// on C++17, these function pointers will be explicitly marked
+// `noexcept`; until then this requirement cannot be enforced in the
+// type system.)
+//
+// Note: to use a `Condition`, you need only construct it and pass it within the
+// appropriate `Mutex' member function, such as `Mutex::Await()`.
+//
+// Example:
+//
+// // assume count_ is not internal reference count
+// int count_ GUARDED_BY(mu_);
+//
+// mu_.LockWhen(Condition(+[](const int* count) { return *count == 0; },
+// &count_));
+//
+// When multiple threads are waiting on exactly the same condition, make sure
+// that they are constructed with the same parameters (same pointer to function
+// + arg, or same pointer to object + method), so that the mutex implementation
+// can avoid redundantly evaluating the same condition for each thread.
+class Condition {
+ public:
+ // A Condition that returns the result of "(*func)(arg)"
+ Condition(bool (*func)(void *), void *arg);
+
+ // Templated version for people who are averse to casts.
+ //
+ // To use a lambda, prepend it with unary plus, which converts the lambda
+ // into a function pointer:
+ // Condition(+[](T* t) { return ...; }, arg).
+ //
+ // Note: lambdas in this case must contain no bound variables.
+ //
+ // See class comment for performance advice.
+ template<typename T>
+ Condition(bool (*func)(T *), T *arg);
+
+ // Templated version for invoking a method that returns a `bool`.
+ //
+ // `Condition(object, &Class::Method)` constructs a `Condition` that evaluates
+ // `object->Method()`.
+ //
+ // Implementation Note: `absl::internal::identity` is used to allow methods to
+ // come from base classes. A simpler signature like
+ // `Condition(T*, bool (T::*)())` does not suffice.
+ template<typename T>
+ Condition(T *object, bool (absl::internal::identity<T>::type::* method)());
+
+ // Same as above, for const members
+ template<typename T>
+ Condition(const T *object,
+ bool (absl::internal::identity<T>::type::* method)() const);
+
+ // A Condition that returns the value of `*cond`
+ explicit Condition(const bool *cond);
+
+ // Templated version for invoking a functor that returns a `bool`.
+ // This approach accepts pointers to non-mutable lambdas, `std::function`,
+ // the result of` std::bind` and user-defined functors that define
+ // `bool F::operator()() const`.
+ //
+ // Example:
+ //
+ // auto reached = [this, current]() {
+ // mu_.AssertReaderHeld(); // For annotalysis.
+ // return processed_ >= current;
+ // };
+ // mu_.Await(Condition(&reached));
+
+ // See class comment for performance advice. In particular, if there
+ // might be more than one waiter for the same condition, make sure
+ // that all waiters construct the condition with the same pointers.
+
+ // Implementation note: The second template parameter ensures that this
+ // constructor doesn't participate in overload resolution if T doesn't have
+ // `bool operator() const`.
+ template <typename T, typename E = decltype(
+ static_cast<bool (T::*)() const>(&T::operator()))>
+ explicit Condition(const T *obj)
+ : Condition(obj, static_cast<bool (T::*)() const>(&T::operator())) {}
+
+ // A Condition that always returns `true`.
+ static const Condition kTrue;
+
+ // Evaluates the condition.
+ bool Eval() const;
+
+ // Returns `true` if the two conditions are guaranteed to return the same
+ // value if evaluated at the same time, `false` if the evaluation *may* return
+ // different results.
+ //
+ // Two `Condition` values are guaranteed equal if both their `func` and `arg`
+ // components are the same. A null pointer is equivalent to a `true`
+ // condition.
+ static bool GuaranteedEqual(const Condition *a, const Condition *b);
+
+ private:
+ typedef bool (*InternalFunctionType)(void * arg);
+ typedef bool (Condition::*InternalMethodType)();
+ typedef bool (*InternalMethodCallerType)(void * arg,
+ InternalMethodType internal_method);
+
+ bool (*eval_)(const Condition*); // Actual evaluator
+ InternalFunctionType function_; // function taking pointer returning bool
+ InternalMethodType method_; // method returning bool
+ void *arg_; // arg of function_ or object of method_
+
+ Condition(); // null constructor used only to create kTrue
+
+ // Various functions eval_ can point to:
+ static bool CallVoidPtrFunction(const Condition*);
+ template <typename T> static bool CastAndCallFunction(const Condition* c);
+ template <typename T> static bool CastAndCallMethod(const Condition* c);
+};
+
+// -----------------------------------------------------------------------------
+// CondVar
+// -----------------------------------------------------------------------------
+//
+// A condition variable, reflecting state evaluated separately outside of the
+// `Mutex` object, which can be signaled to wake callers.
+// This class is not normally needed; use `Mutex` member functions such as
+// `Mutex::Await()` and intrinsic `Condition` abstractions. In rare cases
+// with many threads and many conditions, `CondVar` may be faster.
+//
+// The implementation may deliver signals to any condition variable at
+// any time, even when no call to `Signal()` or `SignalAll()` is made; as a
+// result, upon being awoken, you must check the logical condition you have
+// been waiting upon. The implementation wakes waiters in the FIFO order.
+//
+// Examples:
+//
+// Usage for a thread waiting for some condition C protected by mutex mu:
+// mu.Lock();
+// while (!C) { cv->Wait(&mu); } // releases and reacquires mu
+// // C holds; process data
+// mu.Unlock();
+//
+// Usage to wake T is:
+// mu.Lock();
+// // process data, possibly establishing C
+// if (C) { cv->Signal(); }
+// mu.Unlock();
+//
+// If C may be useful to more than one waiter, use `SignalAll()` instead of
+// `Signal()`.
+//
+// With this implementation it is efficient to use `Signal()/SignalAll()` inside
+// the locked region; this usage can make reasoning about your program easier.
+//
+class CondVar {
+ public:
+ CondVar();
+ ~CondVar();
+
+ // CondVar::Wait()
+ //
+ // Atomically releases a `Mutex` and blocks on this condition variable. After
+ // blocking, the thread will unblock, reacquire the `Mutex`, and return if
+ // either:
+ // - this condition variable is signalled with `SignalAll()`, or
+ // - this condition variable is signalled in any manner and this thread
+ // was the most recently blocked thread that has not yet woken.
+ // Requires and ensures that the current thread holds the `Mutex`.
+ void Wait(Mutex *mu);
+
+ // CondVar::WaitWithTimeout()
+ //
+ // Atomically releases a `Mutex`, blocks on this condition variable, and
+ // attempts to reacquire the mutex upon being signalled, or upon reaching the
+ // timeout.
+ //
+ // After blocking, the thread will unblock, reacquire the `Mutex`, and return
+ // for any of the following:
+ // - this condition variable is signalled with `SignalAll()`
+ // - the timeout has expired
+ // - this condition variable is signalled in any manner and this thread
+ // was the most recently blocked thread that has not yet woken.
+ //
+ // Negative timeouts are equivalent to a zero timeout.
+ //
+ // Returns true if the timeout has expired without this `CondVar`
+ // being signalled in any manner. If both the timeout has expired
+ // and this `CondVar` has been signalled, the implementation is free
+ // to return `true` or `false`.
+ //
+ // Requires and ensures that the current thread holds the `Mutex`.
+ bool WaitWithTimeout(Mutex *mu, absl::Duration timeout);
+
+ // CondVar::WaitWithDeadline()
+ //
+ // Atomically releases a `Mutex`, blocks on this condition variable, and
+ // attempts to reacquire the mutex within the provided deadline.
+ //
+ // After blocking, the thread will unblock, reacquire the `Mutex`, and return
+ // for any of the following:
+ // - this condition variable is signalled with `SignalAll()`
+ // - the deadline has passed
+ // - this condition variable is signalled in any manner and this thread
+ // was the most recently blocked thread that has not yet woken.
+ //
+ // Deadlines in the past are equivalent to an immediate deadline.
+ //
+ // Returns true if the deadline has passed without this `CondVar`
+ // being signalled in any manner. If both the deadline has passed
+ // and this `CondVar` has been signalled, the implementation is free
+ // to return `true` or `false`.
+ //
+ // Requires and ensures that the current thread holds the `Mutex`.
+ bool WaitWithDeadline(Mutex *mu, absl::Time deadline);
+
+ // CondVar::Signal()
+ //
+ // Signal this `CondVar`; wake at least one waiter if one exists.
+ void Signal();
+
+ // CondVar::SignalAll()
+ //
+ // Signal this `CondVar`; wake all waiters.
+ void SignalAll();
+
+ // CondVar::EnableDebugLog()
+ //
+ // Causes all subsequent uses of this `CondVar` to be logged via
+ // `ABSL_RAW_LOG(INFO)`. Log entries are tagged with `name` if `name != 0`.
+ // Note: this method substantially reduces `CondVar` performance.
+ void EnableDebugLog(const char *name);
+
+ private:
+#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX
+ synchronization_internal::CondVarImpl *impl() { return impl_.get(); }
+ synchronization_internal::SynchronizationStorage<
+ synchronization_internal::CondVarImpl>
+ impl_;
+#else
+ bool WaitCommon(Mutex *mutex, synchronization_internal::KernelTimeout t);
+ void Remove(base_internal::PerThreadSynch *s);
+ void Wakeup(base_internal::PerThreadSynch *w);
+ std::atomic<intptr_t> cv_; // Condition variable state.
+#endif
+ CondVar(const CondVar&) = delete;
+ CondVar& operator=(const CondVar&) = delete;
+};
+
+
+// Variants of MutexLock.
+//
+// If you find yourself using one of these, consider instead using
+// Mutex::Unlock() and/or if-statements for clarity.
+
+// MutexLockMaybe
+//
+// MutexLockMaybe is like MutexLock, but is a no-op when mu is null.
+class SCOPED_LOCKABLE MutexLockMaybe {
+ public:
+ explicit MutexLockMaybe(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu)
+ : mu_(mu) { if (this->mu_ != nullptr) { this->mu_->Lock(); } }
+ ~MutexLockMaybe() UNLOCK_FUNCTION() {
+ if (this->mu_ != nullptr) { this->mu_->Unlock(); }
+ }
+ private:
+ Mutex *const mu_;
+ MutexLockMaybe(const MutexLockMaybe&) = delete;
+ MutexLockMaybe& operator=(const MutexLockMaybe&) = delete;
+};
+
+// ReleaseableMutexLock
+//
+// ReleasableMutexLock is like MutexLock, but permits `Release()` of its
+// mutex before destruction. `Release()` may be called at most once.
+class SCOPED_LOCKABLE ReleasableMutexLock {
+ public:
+ explicit ReleasableMutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu)
+ : mu_(mu) {
+ this->mu_->Lock();
+ }
+ ~ReleasableMutexLock() UNLOCK_FUNCTION() {
+ if (this->mu_ != nullptr) { this->mu_->Unlock(); }
+ }
+
+ void Release() UNLOCK_FUNCTION();
+
+ private:
+ Mutex *mu_;
+ ReleasableMutexLock(const ReleasableMutexLock&) = delete;
+ ReleasableMutexLock& operator=(const ReleasableMutexLock&) = delete;
+};
+
+#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX
+#else
+inline CondVar::CondVar() : cv_(0) {}
+#endif
+
+// static
+template <typename T>
+bool Condition::CastAndCallMethod(const Condition *c) {
+ typedef bool (T::*MemberType)();
+ MemberType rm = reinterpret_cast<MemberType>(c->method_);
+ T *x = static_cast<T *>(c->arg_);
+ return (x->*rm)();
+}
+
+// static
+template <typename T>
+bool Condition::CastAndCallFunction(const Condition *c) {
+ typedef bool (*FuncType)(T *);
+ FuncType fn = reinterpret_cast<FuncType>(c->function_);
+ T *x = static_cast<T *>(c->arg_);
+ return (*fn)(x);
+}
+
+template <typename T>
+inline Condition::Condition(bool (*func)(T *), T *arg)
+ : eval_(&CastAndCallFunction<T>),
+ function_(reinterpret_cast<InternalFunctionType>(func)),
+ method_(nullptr),
+ arg_(const_cast<void *>(static_cast<const void *>(arg))) {}
+
+template <typename T>
+inline Condition::Condition(T *object,
+ bool (absl::internal::identity<T>::type::*method)())
+ : eval_(&CastAndCallMethod<T>),
+ function_(nullptr),
+ method_(reinterpret_cast<InternalMethodType>(method)),
+ arg_(object) {}
+
+template <typename T>
+inline Condition::Condition(const T *object,
+ bool (absl::internal::identity<T>::type::*method)()
+ const)
+ : eval_(&CastAndCallMethod<T>),
+ function_(nullptr),
+ method_(reinterpret_cast<InternalMethodType>(method)),
+ arg_(reinterpret_cast<void *>(const_cast<T *>(object))) {}
+
+// Register a hook for profiling support.
+//
+// The function pointer registered here will be called whenever a mutex is
+// contended. The callback is given the absl/base/cycleclock.h timestamp when
+// waiting began.
+//
+// Calls to this function do not race or block, but there is no ordering
+// guaranteed between calls to this function and call to the provided hook.
+// In particular, the previously registered hook may still be called for some
+// time after this function returns.
+void RegisterMutexProfiler(void (*fn)(int64_t wait_timestamp));
+
+// Register a hook for Mutex tracing.
+//
+// The function pointer registered here will be called whenever a mutex is
+// contended. The callback is given an opaque handle to the contended mutex,
+// an event name, and the number of wait cycles (as measured by
+// //absl/base/internal/cycleclock.h, and which may not be real
+// "cycle" counts.)
+//
+// The only event name currently sent is "slow release".
+//
+// This has the same memory ordering concerns as RegisterMutexProfiler() above.
+void RegisterMutexTracer(void (*fn)(const char *msg, const void *obj,
+ int64_t wait_cycles));
+
+// TODO(gfalcon): Combine RegisterMutexProfiler() and RegisterMutexTracer()
+// into a single interface, since they are only ever called in pairs.
+
+// Register a hook for CondVar tracing.
+//
+// The function pointer registered here will be called here on various CondVar
+// events. The callback is given an opaque handle to the CondVar object and
+// a std::string identifying the event. This is thread-safe, but only a single
+// tracer can be registered.
+//
+// Events that can be sent are "Wait", "Unwait", "Signal wakeup", and
+// "SignalAll wakeup".
+//
+// This has the same memory ordering concerns as RegisterMutexProfiler() above.
+void RegisterCondVarTracer(void (*fn)(const char *msg, const void *cv));
+
+// Register a hook for symbolizing stack traces in deadlock detector reports.
+//
+// 'pc' is the program counter being symbolized, 'out' is the buffer to write
+// into, and 'out_size' is the size of the buffer. This function can return
+// false if symbolizing failed, or true if a null-terminated symbol was written
+// to 'out.'
+//
+// This has the same memory ordering concerns as RegisterMutexProfiler() above.
+void RegisterSymbolizer(bool (*fn)(const void *pc, char *out, int out_size));
+
+// EnableMutexInvariantDebugging()
+//
+// Enable or disable global support for Mutex invariant debugging. If enabled,
+// then invariant predicates can be registered per-Mutex for debug checking.
+// See Mutex::EnableInvariantDebugging().
+void EnableMutexInvariantDebugging(bool enabled);
+
+// When in debug mode, and when the feature has been enabled globally, the
+// implementation will keep track of lock ordering and complain (or optionally
+// crash) if a cycle is detected in the acquired-before graph.
+
+// Possible modes of operation for the deadlock detector in debug mode.
+enum class OnDeadlockCycle {
+ kIgnore, // Neither report on nor attempt to track cycles in lock ordering
+ kReport, // Report lock cycles to stderr when detected
+ kAbort, // Report lock cycles to stderr when detected, then abort
+};
+
+// SetMutexDeadlockDetectionMode()
+//
+// Enable or disable global support for detection of potential deadlocks
+// due to Mutex lock ordering inversions. When set to 'kIgnore', tracking of
+// lock ordering is disabled. Otherwise, in debug builds, a lock ordering graph
+// will be maintained internally, and detected cycles will be reported in
+// the manner chosen here.
+void SetMutexDeadlockDetectionMode(OnDeadlockCycle mode);
+
+} // 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 AbslInternalMutexYield();
+} // extern "C"
+#endif // ABSL_SYNCHRONIZATION_MUTEX_H_
diff --git a/absl/synchronization/mutex_test.cc b/absl/synchronization/mutex_test.cc
new file mode 100644
index 0000000..9cf34fc
--- /dev/null
+++ b/absl/synchronization/mutex_test.cc
@@ -0,0 +1,1538 @@
+// 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/synchronization/mutex.h"
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <algorithm>
+#include <atomic>
+#include <cstdint>
+#include <cstdlib>
+#include <functional>
+#include <memory>
+#include <random>
+#include <string>
+#include <thread> // NOLINT(build/c++11)
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/sysinfo.h"
+#include "absl/base/macros.h"
+#include "absl/base/thread_annotations.h"
+#include "absl/memory/memory.h"
+#include "absl/synchronization/internal/thread_pool.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+
+namespace {
+
+// TODO(dmauro): Replace with a commandline flag.
+static constexpr bool kExtendedTest = false;
+
+std::unique_ptr<absl::synchronization_internal::ThreadPool> CreatePool(
+ int threads) {
+ return absl::make_unique<absl::synchronization_internal::ThreadPool>(threads);
+}
+
+std::unique_ptr<absl::synchronization_internal::ThreadPool>
+CreateDefaultPool() {
+ return CreatePool(kExtendedTest ? 32 : 10);
+}
+
+// Hack to schedule a function to run on a thread pool thread after a
+// duration has elapsed.
+static void ScheduleAfter(absl::synchronization_internal::ThreadPool *tp,
+ const std::function<void()> &func,
+ absl::Duration after) {
+ tp->Schedule([func, after] {
+ absl::SleepFor(after);
+ func();
+ });
+}
+
+struct TestContext {
+ int iterations;
+ int threads;
+ int g0; // global 0
+ int g1; // global 1
+ absl::Mutex mu;
+ absl::CondVar cv;
+};
+
+// To test whether the invariant check call occurs
+static std::atomic<bool> invariant_checked;
+
+static bool GetInvariantChecked() {
+ return invariant_checked.load(std::memory_order_relaxed);
+}
+
+static void SetInvariantChecked(bool new_value) {
+ invariant_checked.store(new_value, std::memory_order_relaxed);
+}
+
+static void CheckSumG0G1(void *v) {
+ TestContext *cxt = static_cast<TestContext *>(v);
+ ABSL_RAW_CHECK(cxt->g0 == -cxt->g1, "Error in CheckSumG0G1");
+ SetInvariantChecked(true);
+}
+
+static void TestMu(TestContext *cxt, int c) {
+ SetInvariantChecked(false);
+ cxt->mu.EnableInvariantDebugging(CheckSumG0G1, cxt);
+ for (int i = 0; i != cxt->iterations; i++) {
+ absl::MutexLock l(&cxt->mu);
+ int a = cxt->g0 + 1;
+ cxt->g0 = a;
+ cxt->g1--;
+ }
+}
+
+static void TestTry(TestContext *cxt, int c) {
+ SetInvariantChecked(false);
+ cxt->mu.EnableInvariantDebugging(CheckSumG0G1, cxt);
+ for (int i = 0; i != cxt->iterations; i++) {
+ do {
+ std::this_thread::yield();
+ } while (!cxt->mu.TryLock());
+ int a = cxt->g0 + 1;
+ cxt->g0 = a;
+ cxt->g1--;
+ cxt->mu.Unlock();
+ }
+}
+
+static void TestR20ms(TestContext *cxt, int c) {
+ for (int i = 0; i != cxt->iterations; i++) {
+ absl::ReaderMutexLock l(&cxt->mu);
+ absl::SleepFor(absl::Milliseconds(20));
+ cxt->mu.AssertReaderHeld();
+ }
+}
+
+static void TestRW(TestContext *cxt, int c) {
+ SetInvariantChecked(false);
+ cxt->mu.EnableInvariantDebugging(CheckSumG0G1, cxt);
+ if ((c & 1) == 0) {
+ for (int i = 0; i != cxt->iterations; i++) {
+ absl::WriterMutexLock l(&cxt->mu);
+ cxt->g0++;
+ cxt->g1--;
+ cxt->mu.AssertHeld();
+ cxt->mu.AssertReaderHeld();
+ }
+ } else {
+ for (int i = 0; i != cxt->iterations; i++) {
+ absl::ReaderMutexLock l(&cxt->mu);
+ ABSL_RAW_CHECK(cxt->g0 == -cxt->g1, "Error in TestRW");
+ cxt->mu.AssertReaderHeld();
+ }
+ }
+}
+
+struct MyContext {
+ int target;
+ TestContext *cxt;
+ bool MyTurn();
+};
+
+bool MyContext::MyTurn() {
+ TestContext *cxt = this->cxt;
+ return cxt->g0 == this->target || cxt->g0 == cxt->iterations;
+}
+
+static void TestAwait(TestContext *cxt, int c) {
+ MyContext mc;
+ mc.target = c;
+ mc.cxt = cxt;
+ absl::MutexLock l(&cxt->mu);
+ cxt->mu.AssertHeld();
+ while (cxt->g0 < cxt->iterations) {
+ cxt->mu.Await(absl::Condition(&mc, &MyContext::MyTurn));
+ ABSL_RAW_CHECK(mc.MyTurn(), "Error in TestAwait");
+ cxt->mu.AssertHeld();
+ if (cxt->g0 < cxt->iterations) {
+ int a = cxt->g0 + 1;
+ cxt->g0 = a;
+ mc.target += cxt->threads;
+ }
+ }
+}
+
+static void TestSignalAll(TestContext *cxt, int c) {
+ int target = c;
+ absl::MutexLock l(&cxt->mu);
+ cxt->mu.AssertHeld();
+ while (cxt->g0 < cxt->iterations) {
+ while (cxt->g0 != target && cxt->g0 != cxt->iterations) {
+ cxt->cv.Wait(&cxt->mu);
+ }
+ if (cxt->g0 < cxt->iterations) {
+ int a = cxt->g0 + 1;
+ cxt->g0 = a;
+ cxt->cv.SignalAll();
+ target += cxt->threads;
+ }
+ }
+}
+
+static void TestSignal(TestContext *cxt, int c) {
+ ABSL_RAW_CHECK(cxt->threads == 2, "TestSignal should use 2 threads");
+ int target = c;
+ absl::MutexLock l(&cxt->mu);
+ cxt->mu.AssertHeld();
+ while (cxt->g0 < cxt->iterations) {
+ while (cxt->g0 != target && cxt->g0 != cxt->iterations) {
+ cxt->cv.Wait(&cxt->mu);
+ }
+ if (cxt->g0 < cxt->iterations) {
+ int a = cxt->g0 + 1;
+ cxt->g0 = a;
+ cxt->cv.Signal();
+ target += cxt->threads;
+ }
+ }
+}
+
+static void TestCVTimeout(TestContext *cxt, int c) {
+ int target = c;
+ absl::MutexLock l(&cxt->mu);
+ cxt->mu.AssertHeld();
+ while (cxt->g0 < cxt->iterations) {
+ while (cxt->g0 != target && cxt->g0 != cxt->iterations) {
+ cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(100));
+ }
+ if (cxt->g0 < cxt->iterations) {
+ int a = cxt->g0 + 1;
+ cxt->g0 = a;
+ cxt->cv.SignalAll();
+ target += cxt->threads;
+ }
+ }
+}
+
+static bool G0GE2(TestContext *cxt) { return cxt->g0 >= 2; }
+
+static void TestTime(TestContext *cxt, int c, bool use_cv) {
+ ABSL_RAW_CHECK(cxt->iterations == 1, "TestTime should only use 1 iteration");
+ ABSL_RAW_CHECK(cxt->threads > 2, "TestTime should use more than 2 threads");
+ const bool kFalse = false;
+ absl::Condition false_cond(&kFalse);
+ absl::Condition g0ge2(G0GE2, cxt);
+ if (c == 0) {
+ absl::MutexLock l(&cxt->mu);
+
+ absl::Time start = absl::Now();
+ if (use_cv) {
+ cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1));
+ } else {
+ ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)),
+ "TestTime failed");
+ }
+ absl::Duration elapsed = absl::Now() - start;
+ ABSL_RAW_CHECK(
+ absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0),
+ "TestTime failed");
+ ABSL_RAW_CHECK(cxt->g0 == 1, "TestTime failed");
+
+ start = absl::Now();
+ if (use_cv) {
+ cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1));
+ } else {
+ ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)),
+ "TestTime failed");
+ }
+ elapsed = absl::Now() - start;
+ ABSL_RAW_CHECK(
+ absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0),
+ "TestTime failed");
+ cxt->g0++;
+ if (use_cv) {
+ cxt->cv.Signal();
+ }
+
+ start = absl::Now();
+ if (use_cv) {
+ cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(4));
+ } else {
+ ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(4)),
+ "TestTime failed");
+ }
+ elapsed = absl::Now() - start;
+ ABSL_RAW_CHECK(
+ absl::Seconds(3.9) <= elapsed && elapsed <= absl::Seconds(6.0),
+ "TestTime failed");
+ ABSL_RAW_CHECK(cxt->g0 >= 3, "TestTime failed");
+
+ start = absl::Now();
+ if (use_cv) {
+ cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1));
+ } else {
+ ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)),
+ "TestTime failed");
+ }
+ elapsed = absl::Now() - start;
+ ABSL_RAW_CHECK(
+ absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0),
+ "TestTime failed");
+ if (use_cv) {
+ cxt->cv.SignalAll();
+ }
+
+ start = absl::Now();
+ if (use_cv) {
+ cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1));
+ } else {
+ ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)),
+ "TestTime failed");
+ }
+ elapsed = absl::Now() - start;
+ ABSL_RAW_CHECK(absl::Seconds(0.9) <= elapsed &&
+ elapsed <= absl::Seconds(2.0), "TestTime failed");
+ ABSL_RAW_CHECK(cxt->g0 == cxt->threads, "TestTime failed");
+
+ } else if (c == 1) {
+ absl::MutexLock l(&cxt->mu);
+ const absl::Time start = absl::Now();
+ if (use_cv) {
+ cxt->cv.WaitWithTimeout(&cxt->mu, absl::Milliseconds(500));
+ } else {
+ ABSL_RAW_CHECK(
+ !cxt->mu.AwaitWithTimeout(false_cond, absl::Milliseconds(500)),
+ "TestTime failed");
+ }
+ const absl::Duration elapsed = absl::Now() - start;
+ ABSL_RAW_CHECK(
+ absl::Seconds(0.4) <= elapsed && elapsed <= absl::Seconds(0.9),
+ "TestTime failed");
+ cxt->g0++;
+ } else if (c == 2) {
+ absl::MutexLock l(&cxt->mu);
+ if (use_cv) {
+ while (cxt->g0 < 2) {
+ cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(100));
+ }
+ } else {
+ ABSL_RAW_CHECK(cxt->mu.AwaitWithTimeout(g0ge2, absl::Seconds(100)),
+ "TestTime failed");
+ }
+ cxt->g0++;
+ } else {
+ absl::MutexLock l(&cxt->mu);
+ if (use_cv) {
+ while (cxt->g0 < 2) {
+ cxt->cv.Wait(&cxt->mu);
+ }
+ } else {
+ cxt->mu.Await(g0ge2);
+ }
+ cxt->g0++;
+ }
+}
+
+static void TestMuTime(TestContext *cxt, int c) { TestTime(cxt, c, false); }
+
+static void TestCVTime(TestContext *cxt, int c) { TestTime(cxt, c, true); }
+
+static void EndTest(int *c0, int *c1, absl::Mutex *mu, absl::CondVar *cv,
+ const std::function<void(int)>& cb) {
+ mu->Lock();
+ int c = (*c0)++;
+ mu->Unlock();
+ cb(c);
+ absl::MutexLock l(mu);
+ (*c1)++;
+ cv->Signal();
+}
+
+// Basis for the parameterized tests configured below.
+static int RunTest(void (*test)(TestContext *cxt, int), int threads,
+ int iterations, int operations) {
+ TestContext cxt;
+ absl::Mutex mu2;
+ absl::CondVar cv2;
+ int c0;
+ int c1;
+
+ // run with large thread count for full test and to get timing
+
+#if !defined(ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED)
+ absl::EnableMutexInvariantDebugging(false);
+#endif
+ c0 = 0;
+ c1 = 0;
+ cxt.g0 = 0;
+ cxt.g1 = 0;
+ cxt.iterations = iterations;
+ cxt.threads = threads;
+ absl::synchronization_internal::ThreadPool tp(threads);
+ for (int i = 0; i != threads; i++) {
+ tp.Schedule(std::bind(&EndTest, &c0, &c1, &mu2, &cv2,
+ std::function<void(int)>(
+ std::bind(test, &cxt, std::placeholders::_1))));
+ }
+ mu2.Lock();
+ while (c1 != threads) {
+ cv2.Wait(&mu2);
+ }
+ mu2.Unlock();
+ int saved_g0 = cxt.g0;
+
+ // run again with small number of iterations to test invariant checking
+
+#if !defined(ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED)
+ absl::EnableMutexInvariantDebugging(true);
+#endif
+ SetInvariantChecked(true);
+ c0 = 0;
+ c1 = 0;
+ cxt.g0 = 0;
+ cxt.g1 = 0;
+ cxt.iterations = (iterations > 10 ? 10 : iterations);
+ cxt.threads = threads;
+ for (int i = 0; i != threads; i++) {
+ tp.Schedule(std::bind(&EndTest, &c0, &c1, &mu2, &cv2,
+ std::function<void(int)>(
+ std::bind(test, &cxt, std::placeholders::_1))));
+ }
+ mu2.Lock();
+ while (c1 != threads) {
+ cv2.Wait(&mu2);
+ }
+ mu2.Unlock();
+#if !defined(ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED)
+ ABSL_RAW_CHECK(GetInvariantChecked(), "Invariant not checked");
+#endif
+
+ return saved_g0;
+}
+
+// --------------------------------------------------------
+// Test for fix of bug in TryRemove()
+struct TimeoutBugStruct {
+ absl::Mutex mu;
+ bool a;
+ int a_waiter_count;
+};
+
+static void WaitForA(TimeoutBugStruct *x) {
+ x->mu.LockWhen(absl::Condition(&x->a));
+ x->a_waiter_count--;
+ x->mu.Unlock();
+}
+
+static bool NoAWaiters(TimeoutBugStruct *x) { return x->a_waiter_count == 0; }
+
+// Test that a CondVar.Wait(&mutex) can un-block a call to mutex.Await() in
+// another thread.
+TEST(Mutex, CondVarWaitSignalsAwait) {
+ // Use a struct so the lock annotations apply.
+ struct {
+ absl::Mutex barrier_mu;
+ bool barrier GUARDED_BY(barrier_mu) = false;
+
+ absl::Mutex release_mu;
+ bool release GUARDED_BY(release_mu) = false;
+ absl::CondVar released_cv;
+ } state;
+
+ auto pool = CreateDefaultPool();
+
+ // Thread A. Sets barrier, waits for release using Mutex::Await, then
+ // signals released_cv.
+ pool->Schedule([&state] {
+ state.release_mu.Lock();
+
+ state.barrier_mu.Lock();
+ state.barrier = true;
+ state.barrier_mu.Unlock();
+
+ state.release_mu.Await(absl::Condition(&state.release));
+ state.released_cv.Signal();
+ state.release_mu.Unlock();
+ });
+
+ state.barrier_mu.LockWhen(absl::Condition(&state.barrier));
+ state.barrier_mu.Unlock();
+ state.release_mu.Lock();
+ // Thread A is now blocked on release by way of Mutex::Await().
+
+ // Set release. Calling released_cv.Wait() should un-block thread A,
+ // which will signal released_cv. If not, the test will hang.
+ state.release = true;
+ state.released_cv.Wait(&state.release_mu);
+ state.release_mu.Unlock();
+}
+
+// Test that a CondVar.WaitWithTimeout(&mutex) can un-block a call to
+// mutex.Await() in another thread.
+TEST(Mutex, CondVarWaitWithTimeoutSignalsAwait) {
+ // Use a struct so the lock annotations apply.
+ struct {
+ absl::Mutex barrier_mu;
+ bool barrier GUARDED_BY(barrier_mu) = false;
+
+ absl::Mutex release_mu;
+ bool release GUARDED_BY(release_mu) = false;
+ absl::CondVar released_cv;
+ } state;
+
+ auto pool = CreateDefaultPool();
+
+ // Thread A. Sets barrier, waits for release using Mutex::Await, then
+ // signals released_cv.
+ pool->Schedule([&state] {
+ state.release_mu.Lock();
+
+ state.barrier_mu.Lock();
+ state.barrier = true;
+ state.barrier_mu.Unlock();
+
+ state.release_mu.Await(absl::Condition(&state.release));
+ state.released_cv.Signal();
+ state.release_mu.Unlock();
+ });
+
+ state.barrier_mu.LockWhen(absl::Condition(&state.barrier));
+ state.barrier_mu.Unlock();
+ state.release_mu.Lock();
+ // Thread A is now blocked on release by way of Mutex::Await().
+
+ // Set release. Calling released_cv.Wait() should un-block thread A,
+ // which will signal released_cv. If not, the test will hang.
+ state.release = true;
+ EXPECT_TRUE(
+ !state.released_cv.WaitWithTimeout(&state.release_mu, absl::Seconds(10)))
+ << "; Unrecoverable test failure: CondVar::WaitWithTimeout did not "
+ "unblock the absl::Mutex::Await call in another thread.";
+
+ state.release_mu.Unlock();
+}
+
+// Test for regression of a bug in loop of TryRemove()
+TEST(Mutex, MutexTimeoutBug) {
+ auto tp = CreateDefaultPool();
+
+ TimeoutBugStruct x;
+ x.a = false;
+ x.a_waiter_count = 2;
+ tp->Schedule(std::bind(&WaitForA, &x));
+ tp->Schedule(std::bind(&WaitForA, &x));
+ absl::SleepFor(absl::Seconds(1)); // Allow first two threads to hang.
+ // The skip field of the second will point to the first because there are
+ // only two.
+
+ // Now cause a thread waiting on an always-false to time out
+ // This would deadlock when the bug was present.
+ bool always_false = false;
+ x.mu.LockWhenWithTimeout(absl::Condition(&always_false),
+ absl::Milliseconds(500));
+
+ // if we get here, the bug is not present. Cleanup the state.
+
+ x.a = true; // wakeup the two waiters on A
+ x.mu.Await(absl::Condition(&NoAWaiters, &x)); // wait for them to exit
+ x.mu.Unlock();
+}
+
+struct CondVarWaitDeadlock : testing::TestWithParam<int> {
+ absl::Mutex mu;
+ absl::CondVar cv;
+ bool cond1 = false;
+ bool cond2 = false;
+ bool read_lock1;
+ bool read_lock2;
+ bool signal_unlocked;
+
+ CondVarWaitDeadlock() {
+ read_lock1 = GetParam() & (1 << 0);
+ read_lock2 = GetParam() & (1 << 1);
+ signal_unlocked = GetParam() & (1 << 2);
+ }
+
+ void Waiter1() {
+ if (read_lock1) {
+ mu.ReaderLock();
+ while (!cond1) {
+ cv.Wait(&mu);
+ }
+ mu.ReaderUnlock();
+ } else {
+ mu.Lock();
+ while (!cond1) {
+ cv.Wait(&mu);
+ }
+ mu.Unlock();
+ }
+ }
+
+ void Waiter2() {
+ if (read_lock2) {
+ mu.ReaderLockWhen(absl::Condition(&cond2));
+ mu.ReaderUnlock();
+ } else {
+ mu.LockWhen(absl::Condition(&cond2));
+ mu.Unlock();
+ }
+ }
+};
+
+// Test for a deadlock bug in Mutex::Fer().
+// The sequence of events that lead to the deadlock is:
+// 1. waiter1 blocks on cv in read mode (mu bits = 0).
+// 2. waiter2 blocks on mu in either mode (mu bits = kMuWait).
+// 3. main thread locks mu, sets cond1, unlocks mu (mu bits = kMuWait).
+// 4. main thread signals on cv and this eventually calls Mutex::Fer().
+// Currently Fer wakes waiter1 since mu bits = kMuWait (mutex is unlocked).
+// Before the bug fix Fer neither woke waiter1 nor queued it on mutex,
+// which resulted in deadlock.
+TEST_P(CondVarWaitDeadlock, Test) {
+ auto waiter1 = CreatePool(1);
+ auto waiter2 = CreatePool(1);
+ waiter1->Schedule([this] { this->Waiter1(); });
+ waiter2->Schedule([this] { this->Waiter2(); });
+
+ // Wait while threads block (best-effort is fine).
+ absl::SleepFor(absl::Milliseconds(100));
+
+ // Wake condwaiter.
+ mu.Lock();
+ cond1 = true;
+ if (signal_unlocked) {
+ mu.Unlock();
+ cv.Signal();
+ } else {
+ cv.Signal();
+ mu.Unlock();
+ }
+ waiter1.reset(); // "join" waiter1
+
+ // Wake waiter.
+ mu.Lock();
+ cond2 = true;
+ mu.Unlock();
+ waiter2.reset(); // "join" waiter2
+}
+
+INSTANTIATE_TEST_CASE_P(CondVarWaitDeadlockTest, CondVarWaitDeadlock,
+ ::testing::Range(0, 8),
+ ::testing::PrintToStringParamName());
+
+// --------------------------------------------------------
+// Test for fix of bug in DequeueAllWakeable()
+// Bug was that if there was more than one waiting reader
+// and all should be woken, the most recently blocked one
+// would not be.
+
+struct DequeueAllWakeableBugStruct {
+ absl::Mutex mu;
+ absl::Mutex mu2; // protects all fields below
+ int unfinished_count; // count of unfinished readers; under mu2
+ bool done1; // unfinished_count == 0; under mu2
+ int finished_count; // count of finished readers, under mu2
+ bool done2; // finished_count == 0; under mu2
+};
+
+// Test for regression of a bug in loop of DequeueAllWakeable()
+static void AcquireAsReader(DequeueAllWakeableBugStruct *x) {
+ x->mu.ReaderLock();
+ x->mu2.Lock();
+ x->unfinished_count--;
+ x->done1 = (x->unfinished_count == 0);
+ x->mu2.Unlock();
+ // make sure that both readers acquired mu before we release it.
+ absl::SleepFor(absl::Seconds(2));
+ x->mu.ReaderUnlock();
+
+ x->mu2.Lock();
+ x->finished_count--;
+ x->done2 = (x->finished_count == 0);
+ x->mu2.Unlock();
+}
+
+// Test for regression of a bug in loop of DequeueAllWakeable()
+TEST(Mutex, MutexReaderWakeupBug) {
+ auto tp = CreateDefaultPool();
+
+ DequeueAllWakeableBugStruct x;
+ x.unfinished_count = 2;
+ x.done1 = false;
+ x.finished_count = 2;
+ x.done2 = false;
+ x.mu.Lock(); // acquire mu exclusively
+ // queue two thread that will block on reader locks on x.mu
+ tp->Schedule(std::bind(&AcquireAsReader, &x));
+ tp->Schedule(std::bind(&AcquireAsReader, &x));
+ absl::SleepFor(absl::Seconds(1)); // give time for reader threads to block
+ x.mu.Unlock(); // wake them up
+
+ // both readers should finish promptly
+ EXPECT_TRUE(
+ x.mu2.LockWhenWithTimeout(absl::Condition(&x.done1), absl::Seconds(10)));
+ x.mu2.Unlock();
+
+ EXPECT_TRUE(
+ x.mu2.LockWhenWithTimeout(absl::Condition(&x.done2), absl::Seconds(10)));
+ x.mu2.Unlock();
+}
+
+struct LockWhenTestStruct {
+ absl::Mutex mu1;
+ bool cond = false;
+
+ absl::Mutex mu2;
+ bool waiting = false;
+};
+
+static bool LockWhenTestIsCond(LockWhenTestStruct* s) {
+ s->mu2.Lock();
+ s->waiting = true;
+ s->mu2.Unlock();
+ return s->cond;
+}
+
+static void LockWhenTestWaitForIsCond(LockWhenTestStruct* s) {
+ s->mu1.LockWhen(absl::Condition(&LockWhenTestIsCond, s));
+ s->mu1.Unlock();
+}
+
+TEST(Mutex, LockWhen) {
+ LockWhenTestStruct s;
+
+ // Don't use ThreadPool for this test. See b/65107115.
+ std::thread t(LockWhenTestWaitForIsCond, &s);
+ s.mu2.LockWhen(absl::Condition(&s.waiting));
+ s.mu2.Unlock();
+
+ s.mu1.Lock();
+ s.cond = true;
+ s.mu1.Unlock();
+
+ t.join();
+}
+
+// --------------------------------------------------------
+// The following test requires Mutex::ReaderLock to be a real shared
+// lock, which is not the case in all builds.
+#if !defined(ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE)
+
+// Test for fix of bug in UnlockSlow() that incorrectly decremented the reader
+// count when putting a thread to sleep waiting for a false condition when the
+// lock was not held.
+
+// For this bug to strike, we make a thread wait on a free mutex with no
+// waiters by causing its wakeup condition to be false. Then the
+// next two acquirers must be readers. The bug causes the lock
+// to be released when one reader unlocks, rather than both.
+
+struct ReaderDecrementBugStruct {
+ bool cond; // to delay first thread (under mu)
+ int done; // reference count (under mu)
+ absl::Mutex mu;
+
+ bool waiting_on_cond; // under mu2
+ bool have_reader_lock; // under mu2
+ bool complete; // under mu2
+ absl::Mutex mu2; // > mu
+};
+
+// L >= mu, L < mu_waiting_on_cond
+static bool IsCond(void *v) {
+ ReaderDecrementBugStruct *x = reinterpret_cast<ReaderDecrementBugStruct *>(v);
+ x->mu2.Lock();
+ x->waiting_on_cond = true;
+ x->mu2.Unlock();
+ return x->cond;
+}
+
+// L >= mu
+static bool AllDone(void *v) {
+ ReaderDecrementBugStruct *x = reinterpret_cast<ReaderDecrementBugStruct *>(v);
+ return x->done == 0;
+}
+
+// L={}
+static void WaitForCond(ReaderDecrementBugStruct *x) {
+ absl::Mutex dummy;
+ absl::MutexLock l(&dummy);
+ x->mu.LockWhen(absl::Condition(&IsCond, x));
+ x->done--;
+ x->mu.Unlock();
+}
+
+// L={}
+static void GetReadLock(ReaderDecrementBugStruct *x) {
+ x->mu.ReaderLock();
+ x->mu2.Lock();
+ x->have_reader_lock = true;
+ x->mu2.Await(absl::Condition(&x->complete));
+ x->mu2.Unlock();
+ x->mu.ReaderUnlock();
+ x->mu.Lock();
+ x->done--;
+ x->mu.Unlock();
+}
+
+// Test for reader counter being decremented incorrectly by waiter
+// with false condition.
+TEST(Mutex, MutexReaderDecrementBug) NO_THREAD_SAFETY_ANALYSIS {
+ ReaderDecrementBugStruct x;
+ x.cond = false;
+ x.waiting_on_cond = false;
+ x.have_reader_lock = false;
+ x.complete = false;
+ x.done = 2; // initial ref count
+
+ // Run WaitForCond() and wait for it to sleep
+ std::thread thread1(WaitForCond, &x);
+ x.mu2.LockWhen(absl::Condition(&x.waiting_on_cond));
+ x.mu2.Unlock();
+
+ // Run GetReadLock(), and wait for it to get the read lock
+ std::thread thread2(GetReadLock, &x);
+ x.mu2.LockWhen(absl::Condition(&x.have_reader_lock));
+ x.mu2.Unlock();
+
+ // Get the reader lock ourselves, and release it.
+ x.mu.ReaderLock();
+ x.mu.ReaderUnlock();
+
+ // The lock should be held in read mode by GetReadLock().
+ // If we have the bug, the lock will be free.
+ x.mu.AssertReaderHeld();
+
+ // Wake up all the threads.
+ x.mu2.Lock();
+ x.complete = true;
+ x.mu2.Unlock();
+
+ // TODO(delesley): turn on analysis once lock upgrading is supported.
+ // (This call upgrades the lock from shared to exclusive.)
+ x.mu.Lock();
+ x.cond = true;
+ x.mu.Await(absl::Condition(&AllDone, &x));
+ x.mu.Unlock();
+
+ thread1.join();
+ thread2.join();
+}
+#endif // !ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE
+
+// Test that we correctly handle the situation when a lock is
+// held and then destroyed (w/o unlocking).
+TEST(Mutex, LockedMutexDestructionBug) NO_THREAD_SAFETY_ANALYSIS {
+ for (int i = 0; i != 10; i++) {
+ // Create, lock and destroy 10 locks.
+ const int kNumLocks = 10;
+ auto mu = absl::make_unique<absl::Mutex[]>(kNumLocks);
+ for (int j = 0; j != kNumLocks; j++) {
+ if ((j % 2) == 0) {
+ mu[j].WriterLock();
+ } else {
+ mu[j].ReaderLock();
+ }
+ }
+ }
+}
+
+// --------------------------------------------------------
+// Test for bug with pattern of readers using a condvar. The bug was that if a
+// reader went to sleep on a condition variable while one or more other readers
+// held the lock, but there were no waiters, the reader count (held in the
+// mutex word) would be lost. (This is because Enqueue() had at one time
+// always placed the thread on the Mutex queue. Later (CL 4075610), to
+// tolerate re-entry into Mutex from a Condition predicate, Enqueue() was
+// changed so that it could also place a thread on a condition-variable. This
+// introduced the case where Enqueue() returned with an empty queue, and this
+// case was handled incorrectly in one place.)
+
+static void ReaderForReaderOnCondVar(absl::Mutex *mu, absl::CondVar *cv,
+ int *running) {
+ std::random_device dev;
+ std::mt19937 gen(dev());
+ std::uniform_int_distribution<int> random_millis(0, 15);
+ mu->ReaderLock();
+ while (*running == 3) {
+ absl::SleepFor(absl::Milliseconds(random_millis(gen)));
+ cv->WaitWithTimeout(mu, absl::Milliseconds(random_millis(gen)));
+ }
+ mu->ReaderUnlock();
+ mu->Lock();
+ (*running)--;
+ mu->Unlock();
+}
+
+struct True {
+ template <class... Args>
+ bool operator()(Args...) const {
+ return true;
+ }
+};
+
+struct DerivedTrue : True {};
+
+TEST(Mutex, FunctorCondition) {
+ { // Variadic
+ True f;
+ EXPECT_TRUE(absl::Condition(&f).Eval());
+ }
+
+ { // Inherited
+ DerivedTrue g;
+ EXPECT_TRUE(absl::Condition(&g).Eval());
+ }
+
+ { // lambda
+ int value = 3;
+ auto is_zero = [&value] { return value == 0; };
+ absl::Condition c(&is_zero);
+ EXPECT_FALSE(c.Eval());
+ value = 0;
+ EXPECT_TRUE(c.Eval());
+ }
+
+ { // bind
+ int value = 0;
+ auto is_positive = std::bind(std::less<int>(), 0, std::cref(value));
+ absl::Condition c(&is_positive);
+ EXPECT_FALSE(c.Eval());
+ value = 1;
+ EXPECT_TRUE(c.Eval());
+ }
+
+ { // std::function
+ int value = 3;
+ std::function<bool()> is_zero = [&value] { return value == 0; };
+ absl::Condition c(&is_zero);
+ EXPECT_FALSE(c.Eval());
+ value = 0;
+ EXPECT_TRUE(c.Eval());
+ }
+}
+
+static bool IntIsZero(int *x) { return *x == 0; }
+
+// Test for reader waiting condition variable when there are other readers
+// but no waiters.
+TEST(Mutex, TestReaderOnCondVar) {
+ auto tp = CreateDefaultPool();
+ absl::Mutex mu;
+ absl::CondVar cv;
+ int running = 3;
+ tp->Schedule(std::bind(&ReaderForReaderOnCondVar, &mu, &cv, &running));
+ tp->Schedule(std::bind(&ReaderForReaderOnCondVar, &mu, &cv, &running));
+ absl::SleepFor(absl::Seconds(2));
+ mu.Lock();
+ running--;
+ mu.Await(absl::Condition(&IntIsZero, &running));
+ mu.Unlock();
+}
+
+// --------------------------------------------------------
+struct AcquireFromConditionStruct {
+ absl::Mutex mu0; // protects value, done
+ int value; // times condition function is called; under mu0,
+ bool done; // done with test? under mu0
+ absl::Mutex mu1; // used to attempt to mess up state of mu0
+ absl::CondVar cv; // so the condition function can be invoked from
+ // CondVar::Wait().
+};
+
+static bool ConditionWithAcquire(AcquireFromConditionStruct *x) {
+ x->value++; // count times this function is called
+
+ if (x->value == 2 || x->value == 3) {
+ // On the second and third invocation of this function, sleep for 100ms,
+ // but with the side-effect of altering the state of a Mutex other than
+ // than one for which this is a condition. The spec now explicitly allows
+ // this side effect; previously it did not. it was illegal.
+ bool always_false = false;
+ x->mu1.LockWhenWithTimeout(absl::Condition(&always_false),
+ absl::Milliseconds(100));
+ x->mu1.Unlock();
+ }
+ ABSL_RAW_CHECK(x->value < 4, "should not be invoked a fourth time");
+
+ // We arrange for the condition to return true on only the 2nd and 3rd calls.
+ return x->value == 2 || x->value == 3;
+}
+
+static void WaitForCond2(AcquireFromConditionStruct *x) {
+ // wait for cond0 to become true
+ x->mu0.LockWhen(absl::Condition(&ConditionWithAcquire, x));
+ x->done = true;
+ x->mu0.Unlock();
+}
+
+// Test for Condition whose function acquires other Mutexes
+TEST(Mutex, AcquireFromCondition) {
+ auto tp = CreateDefaultPool();
+
+ AcquireFromConditionStruct x;
+ x.value = 0;
+ x.done = false;
+ tp->Schedule(
+ std::bind(&WaitForCond2, &x)); // run WaitForCond2() in a thread T
+ // T will hang because the first invocation of ConditionWithAcquire() will
+ // return false.
+ absl::SleepFor(absl::Milliseconds(500)); // allow T time to hang
+
+ x.mu0.Lock();
+ x.cv.WaitWithTimeout(&x.mu0, absl::Milliseconds(500)); // wake T
+ // T will be woken because the Wait() will call ConditionWithAcquire()
+ // for the second time, and it will return true.
+
+ x.mu0.Unlock();
+
+ // T will then acquire the lock and recheck its own condition.
+ // It will find the condition true, as this is the third invocation,
+ // but the use of another Mutex by the calling function will
+ // cause the old mutex implementation to think that the outer
+ // LockWhen() has timed out because the inner LockWhenWithTimeout() did.
+ // T will then check the condition a fourth time because it finds a
+ // timeout occurred. This should not happen in the new
+ // implementation that allows the Condition function to use Mutexes.
+
+ // It should also succeed, even though the Condition function
+ // is being invoked from CondVar::Wait, and thus this thread
+ // is conceptually waiting both on the condition variable, and on mu2.
+
+ x.mu0.LockWhen(absl::Condition(&x.done));
+ x.mu0.Unlock();
+}
+
+// The deadlock detector is not part of non-prod builds, so do not test it.
+#if !defined(ABSL_INTERNAL_USE_NONPROD_MUTEX)
+
+TEST(Mutex, DeadlockDetector) {
+ absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);
+
+ // check that we can call ForgetDeadlockInfo() on a lock with the lock held
+ absl::Mutex m1;
+ absl::Mutex m2;
+ absl::Mutex m3;
+ absl::Mutex m4;
+
+ m1.Lock(); // m1 gets ID1
+ m2.Lock(); // m2 gets ID2
+ m3.Lock(); // m3 gets ID3
+ m3.Unlock();
+ m2.Unlock();
+ // m1 still held
+ m1.ForgetDeadlockInfo(); // m1 loses ID
+ m2.Lock(); // m2 gets ID2
+ m3.Lock(); // m3 gets ID3
+ m4.Lock(); // m4 gets ID4
+ m3.Unlock();
+ m2.Unlock();
+ m4.Unlock();
+ m1.Unlock();
+ // Pre b/7636708 the thread local cache remembered that ID1 is assigned to m1.
+ // So, we had a cycle ID1=>ID1=>ID1.
+}
+
+// Bazel has a test "warning" file that programs can write to if the
+// test should pass with a warning. This class disables the warning
+// file until it goes out of scope.
+class ScopedDisableBazelTestWarnings {
+ public:
+ ScopedDisableBazelTestWarnings() {
+#ifdef WIN32
+ char file[MAX_PATH];
+ if (GetEnvironmentVariable(kVarName, file, sizeof(file)) < sizeof(file)) {
+ warnings_output_file_ = file;
+ SetEnvironmentVariable(kVarName, nullptr);
+ }
+#else
+ const char *file = getenv(kVarName);
+ if (file != nullptr) {
+ warnings_output_file_ = file;
+ unsetenv(kVarName);
+ }
+#endif
+ }
+
+ ~ScopedDisableBazelTestWarnings() {
+ if (!warnings_output_file_.empty()) {
+#ifdef WIN32
+ SetEnvironmentVariable(kVarName, warnings_output_file_.c_str());
+#else
+ setenv(kVarName, warnings_output_file_.c_str(), 0);
+#endif
+ }
+ }
+
+ private:
+ static const char kVarName[];
+ std::string warnings_output_file_;
+};
+const char ScopedDisableBazelTestWarnings::kVarName[] =
+ "TEST_WARNINGS_OUTPUT_FILE";
+
+TEST(Mutex, DeadlockDetectorBazelWarning) {
+ absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kReport);
+
+ // Cause deadlock detection to detect something, if it's
+ // compiled in and enabled. But turn off the bazel warning.
+ ScopedDisableBazelTestWarnings disable_bazel_test_warnings;
+
+ absl::Mutex mu0;
+ absl::Mutex mu1;
+ bool got_mu0 = mu0.TryLock();
+ mu1.Lock(); // acquire mu1 while holding mu0
+ if (got_mu0) {
+ mu0.Unlock();
+ }
+ if (mu0.TryLock()) { // try lock shouldn't cause deadlock detector to fire
+ mu0.Unlock();
+ }
+ mu0.Lock(); // acquire mu0 while holding mu1; should get one deadlock
+ // report here
+ mu0.Unlock();
+ mu1.Unlock();
+
+ absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);
+}
+
+// This test is tagged with NO_THREAD_SAFETY_ANALYSIS because the
+// annotation-based static thread-safety analysis is not currently
+// predicate-aware and cannot tell if the two for-loops that acquire and
+// release the locks have the same predicates.
+TEST(Mutex, DeadlockDetectorStessTest) NO_THREAD_SAFETY_ANALYSIS {
+ // Stress test: Here we create a large number of locks and use all of them.
+ // If a deadlock detector keeps a full graph of lock acquisition order,
+ // it will likely be too slow for this test to pass.
+ const int n_locks = 1 << 17;
+ auto array_of_locks = absl::make_unique<absl::Mutex[]>(n_locks);
+ for (int i = 0; i < n_locks; i++) {
+ int end = std::min(n_locks, i + 5);
+ // acquire and then release locks i, i+1, ..., i+4
+ for (int j = i; j < end; j++) {
+ array_of_locks[j].Lock();
+ }
+ for (int j = i; j < end; j++) {
+ array_of_locks[j].Unlock();
+ }
+ }
+}
+
+TEST(Mutex, DeadlockIdBug) NO_THREAD_SAFETY_ANALYSIS {
+ // Test a scenario where a cached deadlock graph node id in the
+ // list of held locks is not invalidated when the corresponding
+ // mutex is deleted.
+ absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);
+ // Mutex that will be destroyed while being held
+ absl::Mutex *a = new absl::Mutex;
+ // Other mutexes needed by test
+ absl::Mutex b, c;
+
+ // Hold mutex.
+ a->Lock();
+
+ // Force deadlock id assignment by acquiring another lock.
+ b.Lock();
+ b.Unlock();
+
+ // Delete the mutex. The Mutex destructor tries to remove held locks,
+ // but the attempt isn't foolproof. It can fail if:
+ // (a) Deadlock detection is currently disabled.
+ // (b) The destruction is from another thread.
+ // We exploit (a) by temporarily disabling deadlock detection.
+ absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kIgnore);
+ delete a;
+ absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort);
+
+ // Now acquire another lock which will force a deadlock id assignment.
+ // We should end up getting assigned the same deadlock id that was
+ // freed up when "a" was deleted, which will cause a spurious deadlock
+ // report if the held lock entry for "a" was not invalidated.
+ c.Lock();
+ c.Unlock();
+}
+#endif // !defined(ABSL_INTERNAL_USE_NONPROD_MUTEX)
+
+// --------------------------------------------------------
+// Test for timeouts/deadlines on condition waits that are specified using
+// absl::Duration and absl::Time. For each waiting function we test with
+// a timeout/deadline that has already expired/passed, one that is infinite
+// and so never expires/passes, and one that will expire/pass in the near
+// future.
+
+// Encapsulate a Mutex-protected bool with its associated Condition/CondVar.
+class Cond {
+ public:
+ explicit Cond(bool use_deadline) : use_deadline_(use_deadline), c_(&b_) {}
+
+ void Set(bool v) {
+ absl::MutexLock lock(&mu_);
+ b_ = v;
+ }
+
+ bool AwaitWithTimeout(absl::Duration timeout) {
+ absl::MutexLock lock(&mu_);
+ return use_deadline_ ? mu_.AwaitWithDeadline(c_, absl::Now() + timeout)
+ : mu_.AwaitWithTimeout(c_, timeout);
+ }
+
+ bool LockWhenWithTimeout(absl::Duration timeout) {
+ bool b = use_deadline_ ? mu_.LockWhenWithDeadline(c_, absl::Now() + timeout)
+ : mu_.LockWhenWithTimeout(c_, timeout);
+ mu_.Unlock();
+ return b;
+ }
+
+ bool ReaderLockWhenWithTimeout(absl::Duration timeout) {
+ bool b = use_deadline_
+ ? mu_.ReaderLockWhenWithDeadline(c_, absl::Now() + timeout)
+ : mu_.ReaderLockWhenWithTimeout(c_, timeout);
+ mu_.ReaderUnlock();
+ return b;
+ }
+
+ void Await() {
+ absl::MutexLock lock(&mu_);
+ mu_.Await(c_);
+ }
+
+ void Signal(bool v) {
+ absl::MutexLock lock(&mu_);
+ b_ = v;
+ cv_.Signal();
+ }
+
+ bool WaitWithTimeout(absl::Duration timeout) {
+ absl::MutexLock lock(&mu_);
+ absl::Time deadline = absl::Now() + timeout;
+ if (use_deadline_) {
+ while (!b_ && !cv_.WaitWithDeadline(&mu_, deadline)) {
+ }
+ } else {
+ while (!b_ && !cv_.WaitWithTimeout(&mu_, timeout)) {
+ timeout = deadline - absl::Now(); // recompute timeout
+ }
+ }
+ return b_;
+ }
+
+ void Wait() {
+ absl::MutexLock lock(&mu_);
+ while (!b_) cv_.Wait(&mu_);
+ }
+
+ private:
+ const bool use_deadline_;
+
+ bool b_;
+ absl::Condition c_;
+ absl::CondVar cv_;
+ absl::Mutex mu_;
+};
+
+class OperationTimer {
+ public:
+ OperationTimer() : start_(absl::Now()) {}
+ absl::Duration Get() const { return absl::Now() - start_; }
+
+ private:
+ const absl::Time start_;
+};
+
+static void CheckResults(bool exp_result, bool act_result,
+ absl::Duration exp_duration,
+ absl::Duration act_duration) {
+ ABSL_RAW_CHECK(exp_result == act_result, "CheckResults failed");
+ // Allow for some worse-case scheduling delay and clock skew.
+ ABSL_RAW_CHECK(exp_duration - absl::Milliseconds(40) <= act_duration,
+ "CheckResults failed");
+ ABSL_RAW_CHECK(exp_duration + absl::Milliseconds(150) >= act_duration,
+ "CheckResults failed");
+}
+
+static void TestAwaitTimeout(Cond *cp, absl::Duration timeout, bool exp_result,
+ absl::Duration exp_duration) {
+ OperationTimer t;
+ bool act_result = cp->AwaitWithTimeout(timeout);
+ CheckResults(exp_result, act_result, exp_duration, t.Get());
+}
+
+static void TestLockWhenTimeout(Cond *cp, absl::Duration timeout,
+ bool exp_result, absl::Duration exp_duration) {
+ OperationTimer t;
+ bool act_result = cp->LockWhenWithTimeout(timeout);
+ CheckResults(exp_result, act_result, exp_duration, t.Get());
+}
+
+static void TestReaderLockWhenTimeout(Cond *cp, absl::Duration timeout,
+ bool exp_result,
+ absl::Duration exp_duration) {
+ OperationTimer t;
+ bool act_result = cp->ReaderLockWhenWithTimeout(timeout);
+ CheckResults(exp_result, act_result, exp_duration, t.Get());
+}
+
+static void TestWaitTimeout(Cond *cp, absl::Duration timeout, bool exp_result,
+ absl::Duration exp_duration) {
+ OperationTimer t;
+ bool act_result = cp->WaitWithTimeout(timeout);
+ CheckResults(exp_result, act_result, exp_duration, t.Get());
+}
+
+// Tests with a negative timeout (deadline in the past), which should
+// immediately return the current state of the condition.
+static void TestNegativeTimeouts(absl::synchronization_internal::ThreadPool *tp,
+ Cond *cp) {
+ const absl::Duration negative = -absl::InfiniteDuration();
+ const absl::Duration immediate = absl::ZeroDuration();
+
+ // The condition is already true:
+ cp->Set(true);
+ TestAwaitTimeout(cp, negative, true, immediate);
+ TestLockWhenTimeout(cp, negative, true, immediate);
+ TestReaderLockWhenTimeout(cp, negative, true, immediate);
+ TestWaitTimeout(cp, negative, true, immediate);
+
+ // The condition becomes true, but the timeout has already expired:
+ const absl::Duration delay = absl::Milliseconds(200);
+ cp->Set(false);
+ ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), 3 * delay);
+ TestAwaitTimeout(cp, negative, false, immediate);
+ TestLockWhenTimeout(cp, negative, false, immediate);
+ TestReaderLockWhenTimeout(cp, negative, false, immediate);
+ cp->Await(); // wait for the scheduled Set() to complete
+ cp->Set(false);
+ ScheduleAfter(tp, std::bind(&Cond::Signal, cp, true), delay);
+ TestWaitTimeout(cp, negative, false, immediate);
+ cp->Wait(); // wait for the scheduled Signal() to complete
+
+ // The condition never becomes true:
+ cp->Set(false);
+ TestAwaitTimeout(cp, negative, false, immediate);
+ TestLockWhenTimeout(cp, negative, false, immediate);
+ TestReaderLockWhenTimeout(cp, negative, false, immediate);
+ TestWaitTimeout(cp, negative, false, immediate);
+}
+
+// Tests with an infinite timeout (deadline in the infinite future), which
+// should only return when the condition becomes true.
+static void TestInfiniteTimeouts(absl::synchronization_internal::ThreadPool *tp,
+ Cond *cp) {
+ const absl::Duration infinite = absl::InfiniteDuration();
+ const absl::Duration immediate = absl::ZeroDuration();
+
+ // The condition is already true:
+ cp->Set(true);
+ TestAwaitTimeout(cp, infinite, true, immediate);
+ TestLockWhenTimeout(cp, infinite, true, immediate);
+ TestReaderLockWhenTimeout(cp, infinite, true, immediate);
+ TestWaitTimeout(cp, infinite, true, immediate);
+
+ // The condition becomes true before the (infinite) expiry:
+ const absl::Duration delay = absl::Milliseconds(200);
+ cp->Set(false);
+ ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay);
+ TestAwaitTimeout(cp, infinite, true, delay);
+ cp->Set(false);
+ ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay);
+ TestLockWhenTimeout(cp, infinite, true, delay);
+ cp->Set(false);
+ ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay);
+ TestReaderLockWhenTimeout(cp, infinite, true, delay);
+ cp->Set(false);
+ ScheduleAfter(tp, std::bind(&Cond::Signal, cp, true), delay);
+ TestWaitTimeout(cp, infinite, true, delay);
+}
+
+// Tests with a (small) finite timeout (deadline soon), with the condition
+// becoming true both before and after its expiry.
+static void TestFiniteTimeouts(absl::synchronization_internal::ThreadPool *tp,
+ Cond *cp) {
+ const absl::Duration finite = absl::Milliseconds(400);
+ const absl::Duration immediate = absl::ZeroDuration();
+
+ // The condition is already true:
+ cp->Set(true);
+ TestAwaitTimeout(cp, finite, true, immediate);
+ TestLockWhenTimeout(cp, finite, true, immediate);
+ TestReaderLockWhenTimeout(cp, finite, true, immediate);
+ TestWaitTimeout(cp, finite, true, immediate);
+
+ // The condition becomes true before the expiry:
+ const absl::Duration delay1 = finite / 2;
+ cp->Set(false);
+ ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay1);
+ TestAwaitTimeout(cp, finite, true, delay1);
+ cp->Set(false);
+ ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay1);
+ TestLockWhenTimeout(cp, finite, true, delay1);
+ cp->Set(false);
+ ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), delay1);
+ TestReaderLockWhenTimeout(cp, finite, true, delay1);
+ cp->Set(false);
+ ScheduleAfter(tp, std::bind(&Cond::Signal, cp, true), delay1);
+ TestWaitTimeout(cp, finite, true, delay1);
+
+ // The condition becomes true, but the timeout has already expired:
+ const absl::Duration delay2 = finite * 2;
+ cp->Set(false);
+ ScheduleAfter(tp, std::bind(&Cond::Set, cp, true), 3 * delay2);
+ TestAwaitTimeout(cp, finite, false, finite);
+ TestLockWhenTimeout(cp, finite, false, finite);
+ TestReaderLockWhenTimeout(cp, finite, false, finite);
+ cp->Await(); // wait for the scheduled Set() to complete
+ cp->Set(false);
+ ScheduleAfter(tp, std::bind(&Cond::Signal, cp, true), delay2);
+ TestWaitTimeout(cp, finite, false, finite);
+ cp->Wait(); // wait for the scheduled Signal() to complete
+
+ // The condition never becomes true:
+ cp->Set(false);
+ TestAwaitTimeout(cp, finite, false, finite);
+ TestLockWhenTimeout(cp, finite, false, finite);
+ TestReaderLockWhenTimeout(cp, finite, false, finite);
+ TestWaitTimeout(cp, finite, false, finite);
+}
+
+TEST(Mutex, Timeouts) {
+ auto tp = CreateDefaultPool();
+ for (bool use_deadline : {false, true}) {
+ Cond cond(use_deadline);
+ TestNegativeTimeouts(tp.get(), &cond);
+ TestInfiniteTimeouts(tp.get(), &cond);
+ TestFiniteTimeouts(tp.get(), &cond);
+ }
+}
+
+TEST(Mutex, Logging) {
+ // Allow user to look at logging output
+ absl::Mutex logged_mutex;
+ logged_mutex.EnableDebugLog("fido_mutex");
+ absl::CondVar logged_cv;
+ logged_cv.EnableDebugLog("rover_cv");
+ logged_mutex.Lock();
+ logged_cv.WaitWithTimeout(&logged_mutex, absl::Milliseconds(20));
+ logged_mutex.Unlock();
+ logged_mutex.ReaderLock();
+ logged_mutex.ReaderUnlock();
+ logged_mutex.Lock();
+ logged_mutex.Unlock();
+ logged_cv.Signal();
+ logged_cv.SignalAll();
+}
+
+// --------------------------------------------------------
+
+// Generate the vector of thread counts for tests parameterized on thread count.
+static std::vector<int> AllThreadCountValues() {
+ if (kExtendedTest) {
+ return {2, 4, 8, 10, 16, 20, 24, 30, 32};
+ }
+ return {2, 4, 10};
+}
+
+// A test fixture parameterized by thread count.
+class MutexVariableThreadCountTest : public ::testing::TestWithParam<int> {};
+
+// Instantiate the above with AllThreadCountOptions().
+INSTANTIATE_TEST_CASE_P(ThreadCounts, MutexVariableThreadCountTest,
+ ::testing::ValuesIn(AllThreadCountValues()),
+ ::testing::PrintToStringParamName());
+
+// Reduces iterations by some factor for slow platforms
+// (determined empirically).
+static int ScaleIterations(int x) {
+ // ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE is set in the implementation
+ // of Mutex that uses either std::mutex or pthread_mutex_t. Use
+ // these as keys to determine the slow implementation.
+#if defined(ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE)
+ return x / 10;
+#else
+ return x;
+#endif
+}
+
+TEST_P(MutexVariableThreadCountTest, Mutex) {
+ int threads = GetParam();
+ int iterations = ScaleIterations(10000000) / threads;
+ int operations = threads * iterations;
+ EXPECT_EQ(RunTest(&TestMu, threads, iterations, operations), operations);
+}
+
+TEST_P(MutexVariableThreadCountTest, Try) {
+ int threads = GetParam();
+ int iterations = 1000000 / threads;
+ int operations = iterations * threads;
+ EXPECT_EQ(RunTest(&TestTry, threads, iterations, operations), operations);
+}
+
+TEST_P(MutexVariableThreadCountTest, R20ms) {
+ int threads = GetParam();
+ int iterations = 100;
+ int operations = iterations * threads;
+ EXPECT_EQ(RunTest(&TestR20ms, threads, iterations, operations), 0);
+}
+
+TEST_P(MutexVariableThreadCountTest, RW) {
+ int threads = GetParam();
+ int iterations = ScaleIterations(20000000) / threads;
+ int operations = iterations * threads;
+ EXPECT_EQ(RunTest(&TestRW, threads, iterations, operations), operations / 2);
+}
+
+TEST_P(MutexVariableThreadCountTest, Await) {
+ int threads = GetParam();
+ int iterations = ScaleIterations(500000);
+ int operations = iterations;
+ EXPECT_EQ(RunTest(&TestAwait, threads, iterations, operations), operations);
+}
+
+TEST_P(MutexVariableThreadCountTest, SignalAll) {
+ int threads = GetParam();
+ int iterations = 200000 / threads;
+ int operations = iterations;
+ EXPECT_EQ(RunTest(&TestSignalAll, threads, iterations, operations),
+ operations);
+}
+
+TEST(Mutex, Signal) {
+ int threads = 2; // TestSignal must use two threads
+ int iterations = 200000;
+ int operations = iterations;
+ EXPECT_EQ(RunTest(&TestSignal, threads, iterations, operations), operations);
+}
+
+TEST(Mutex, Timed) {
+ int threads = 10; // Use a fixed thread count of 10
+ int iterations = 1000;
+ int operations = iterations;
+ EXPECT_EQ(RunTest(&TestCVTimeout, threads, iterations, operations),
+ operations);
+}
+
+TEST(Mutex, CVTime) {
+ int threads = 10; // Use a fixed thread count of 10
+ int iterations = 1;
+ EXPECT_EQ(RunTest(&TestCVTime, threads, iterations, 1),
+ threads * iterations);
+}
+
+TEST(Mutex, MuTime) {
+ int threads = 10; // Use a fixed thread count of 10
+ int iterations = 1;
+ EXPECT_EQ(RunTest(&TestMuTime, threads, iterations, 1), threads * iterations);
+}
+
+} // namespace
diff --git a/absl/synchronization/notification.cc b/absl/synchronization/notification.cc
new file mode 100644
index 0000000..ed8cc90
--- /dev/null
+++ b/absl/synchronization/notification.cc
@@ -0,0 +1,84 @@
+// 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/synchronization/notification.h"
+
+#include <atomic>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/synchronization/mutex.h"
+#include "absl/time/time.h"
+
+namespace absl {
+void Notification::Notify() {
+ MutexLock l(&this->mutex_);
+
+#ifndef NDEBUG
+ if (ABSL_PREDICT_FALSE(notified_yet_.load(std::memory_order_relaxed))) {
+ ABSL_RAW_LOG(
+ FATAL,
+ "Notify() method called more than once for Notification object %p",
+ static_cast<void *>(this));
+ }
+#endif
+
+ notified_yet_.store(true, std::memory_order_release);
+}
+
+Notification::~Notification() {
+ // Make sure that the thread running Notify() exits before the object is
+ // destructed.
+ MutexLock l(&this->mutex_);
+}
+
+static inline bool HasBeenNotifiedInternal(
+ const std::atomic<bool> *notified_yet) {
+ return notified_yet->load(std::memory_order_acquire);
+}
+
+bool Notification::HasBeenNotified() const {
+ return HasBeenNotifiedInternal(&this->notified_yet_);
+}
+
+void Notification::WaitForNotification() const {
+ if (!HasBeenNotifiedInternal(&this->notified_yet_)) {
+ this->mutex_.LockWhen(Condition(&HasBeenNotifiedInternal,
+ &this->notified_yet_));
+ this->mutex_.Unlock();
+ }
+}
+
+bool Notification::WaitForNotificationWithTimeout(
+ absl::Duration timeout) const {
+ bool notified = HasBeenNotifiedInternal(&this->notified_yet_);
+ if (!notified) {
+ notified = this->mutex_.LockWhenWithTimeout(
+ Condition(&HasBeenNotifiedInternal, &this->notified_yet_), timeout);
+ this->mutex_.Unlock();
+ }
+ return notified;
+}
+
+bool Notification::WaitForNotificationWithDeadline(absl::Time deadline) const {
+ bool notified = HasBeenNotifiedInternal(&this->notified_yet_);
+ if (!notified) {
+ notified = this->mutex_.LockWhenWithDeadline(
+ Condition(&HasBeenNotifiedInternal, &this->notified_yet_), deadline);
+ this->mutex_.Unlock();
+ }
+ return notified;
+}
+
+} // namespace absl
diff --git a/absl/synchronization/notification.h b/absl/synchronization/notification.h
new file mode 100644
index 0000000..107932f
--- /dev/null
+++ b/absl/synchronization/notification.h
@@ -0,0 +1,112 @@
+// 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.
+//
+// -----------------------------------------------------------------------------
+// notification.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines a `Notification` abstraction, which allows threads
+// to receive notification of a single occurrence of a single event.
+//
+// The `Notification` object maintains a private boolean "notified" state that
+// transitions to `true` at most once. The `Notification` class provides the
+// following primary member functions:
+// * `HasBeenNotified() `to query its state
+// * `WaitForNotification*()` to have threads wait until the "notified" state
+// is `true`.
+// * `Notify()` to set the notification's "notified" state to `true` and
+// notify all waiting threads that the event has occurred.
+// This method may only be called once.
+//
+// Note that while `Notify()` may only be called once, it is perfectly valid to
+// call any of the `WaitForNotification*()` methods multiple times, from
+// multiple threads -- even after the notification's "notified" state has been
+// set -- in which case those methods will immediately return.
+//
+// Note that the lifetime of a `Notification` requires careful consideration;
+// it might not be safe to destroy a notification after calling `Notify()` since
+// it is still legal for other threads to call `WaitForNotification*()` methods
+// on the notification. However, observers responding to a "notified" state of
+// `true` can safely delete the notification without interfering with the call
+// to `Notify()` in the other thread.
+//
+// Memory ordering: For any threads X and Y, if X calls `Notify()`, then any
+// action taken by X before it calls `Notify()` is visible to thread Y after:
+// * Y returns from `WaitForNotification()`, or
+// * Y receives a `true` return value from either `HasBeenNotified()` or
+// `WaitForNotificationWithTimeout()`.
+
+#ifndef ABSL_SYNCHRONIZATION_NOTIFICATION_H_
+#define ABSL_SYNCHRONIZATION_NOTIFICATION_H_
+
+#include <atomic>
+
+#include "absl/synchronization/mutex.h"
+#include "absl/time/time.h"
+
+namespace absl {
+
+// -----------------------------------------------------------------------------
+// Notification
+// -----------------------------------------------------------------------------
+class Notification {
+ public:
+ // Initializes the "notified" state to unnotified.
+ Notification() : notified_yet_(false) {}
+ explicit Notification(bool prenotify) : notified_yet_(prenotify) {}
+ Notification(const Notification&) = delete;
+ Notification& operator=(const Notification&) = delete;
+ ~Notification();
+
+ // Notification::HasBeenNotified()
+ //
+ // Returns the value of the notification's internal "notified" state.
+ bool HasBeenNotified() const;
+
+ // Notification::WaitForNotification()
+ //
+ // Blocks the calling thread until the notification's "notified" state is
+ // `true`. Note that if `Notify()` has been previously called on this
+ // notification, this function will immediately return.
+ void WaitForNotification() const;
+
+ // Notification::WaitForNotificationWithTimeout()
+ //
+ // Blocks until either the notification's "notified" state is `true` (which
+ // may occur immediately) or the timeout has elapsed, returning the value of
+ // its "notified" state in either case.
+ bool WaitForNotificationWithTimeout(absl::Duration timeout) const;
+
+ // Notification::WaitForNotificationWithDeadline()
+ //
+ // Blocks until either the notification's "notified" state is `true` (which
+ // may occur immediately) or the deadline has expired, returning the value of
+ // its "notified" state in either case.
+ bool WaitForNotificationWithDeadline(absl::Time deadline) const;
+
+ // Notification::Notify()
+ //
+ // Sets the "notified" state of this notification to `true` and wakes waiting
+ // threads. Note: do not call `Notify()` multiple times on the same
+ // `Notification`; calling `Notify()` more than once on the same notification
+ // results in undefined behavior.
+ void Notify();
+
+ private:
+ mutable Mutex mutex_;
+ std::atomic<bool> notified_yet_; // written under mutex_
+};
+
+} // namespace absl
+#endif // ABSL_SYNCHRONIZATION_NOTIFICATION_H_
diff --git a/absl/synchronization/notification_test.cc b/absl/synchronization/notification_test.cc
new file mode 100644
index 0000000..9b3b6a5
--- /dev/null
+++ b/absl/synchronization/notification_test.cc
@@ -0,0 +1,124 @@
+// 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/synchronization/notification.h"
+
+#include <thread> // NOLINT(build/c++11)
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+
+// A thread-safe class that holds a counter.
+class ThreadSafeCounter {
+ public:
+ ThreadSafeCounter() : count_(0) {}
+
+ void Increment() {
+ MutexLock lock(&mutex_);
+ ++count_;
+ }
+
+ int Get() const {
+ MutexLock lock(&mutex_);
+ return count_;
+ }
+
+ void WaitUntilGreaterOrEqual(int n) {
+ MutexLock lock(&mutex_);
+ auto cond = [this, n]() { return count_ >= n; };
+ mutex_.Await(Condition(&cond));
+ }
+
+ private:
+ mutable Mutex mutex_;
+ int count_;
+};
+
+// Runs the |i|'th worker thread for the tests in BasicTests(). Increments the
+// |ready_counter|, waits on the |notification|, and then increments the
+// |done_counter|.
+static void RunWorker(int i, ThreadSafeCounter* ready_counter,
+ Notification* notification,
+ ThreadSafeCounter* done_counter) {
+ ready_counter->Increment();
+ notification->WaitForNotification();
+ done_counter->Increment();
+}
+
+// Tests that the |notification| properly blocks and awakens threads. Assumes
+// that the |notification| is not yet triggered. If |notify_before_waiting| is
+// true, the |notification| is triggered before any threads are created, so the
+// threads never block in WaitForNotification(). Otherwise, the |notification|
+// is triggered at a later point when most threads are likely to be blocking in
+// WaitForNotification().
+static void BasicTests(bool notify_before_waiting, Notification* notification) {
+ EXPECT_FALSE(notification->HasBeenNotified());
+ EXPECT_FALSE(
+ notification->WaitForNotificationWithTimeout(absl::Milliseconds(0)));
+ EXPECT_FALSE(notification->WaitForNotificationWithDeadline(absl::Now()));
+
+ absl::Time start = absl::Now();
+ EXPECT_FALSE(
+ notification->WaitForNotificationWithTimeout(absl::Milliseconds(50)));
+ EXPECT_LE(start + absl::Milliseconds(50), absl::Now());
+
+ ThreadSafeCounter ready_counter;
+ ThreadSafeCounter done_counter;
+
+ if (notify_before_waiting) {
+ notification->Notify();
+ }
+
+ // Create a bunch of threads that increment the |done_counter| after being
+ // notified.
+ const int kNumThreads = 10;
+ std::vector<std::thread> workers;
+ for (int i = 0; i < kNumThreads; ++i) {
+ workers.push_back(std::thread(&RunWorker, i, &ready_counter, notification,
+ &done_counter));
+ }
+
+ if (!notify_before_waiting) {
+ ready_counter.WaitUntilGreaterOrEqual(kNumThreads);
+
+ // Workers have not been notified yet, so the |done_counter| should be
+ // unmodified.
+ EXPECT_EQ(0, done_counter.Get());
+
+ notification->Notify();
+ }
+
+ // After notifying and then joining the workers, both counters should be
+ // fully incremented.
+ notification->WaitForNotification(); // should exit immediately
+ EXPECT_TRUE(notification->HasBeenNotified());
+ EXPECT_TRUE(notification->WaitForNotificationWithTimeout(absl::Seconds(0)));
+ EXPECT_TRUE(notification->WaitForNotificationWithDeadline(absl::Now()));
+ for (std::thread& worker : workers) {
+ worker.join();
+ }
+ EXPECT_EQ(kNumThreads, ready_counter.Get());
+ EXPECT_EQ(kNumThreads, done_counter.Get());
+}
+
+TEST(NotificationTest, SanityTest) {
+ Notification local_notification1, local_notification2;
+ BasicTests(false, &local_notification1);
+ BasicTests(true, &local_notification2);
+}
+
+} // namespace absl
diff --git a/absl/test_dependencies.bzl b/absl/test_dependencies.bzl
new file mode 100644
index 0000000..eca88d8
--- /dev/null
+++ b/absl/test_dependencies.bzl
@@ -0,0 +1,40 @@
+"""Common definitions of gunit and gmock dependencies for Abseil."""
+
+# pylint: disable=pointless-std::string-statement
+
+# TODO(catlyons): Clean up below selectors when possible. Hold on to them for
+# now as we may still need our own gunit_main selectors that do not bring in any
+# heapchecker-related deps, and possibly to deal with benchmark dependencies.
+
+"""Use GUNIT_DEPS_SELECTOR when you don't need gunit_main."""
+GUNIT_DEPS_SELECTOR = {
+ "//conditions:default": [
+ "@com_google_googletest//:gtest",
+ ],
+}
+
+"""Use GUNIT_MAIN_DEPS_SELECTOR to get gunit_main with leak checking."""
+GUNIT_MAIN_DEPS_SELECTOR = {
+ "//conditions:default": [
+ "@com_google_googletest//:gtest_main",
+ ],
+}
+
+# TODO(b/30141238): In order to set up absl deps on leak checking
+# without base, we'll need gunit_main without either
+# base:heapcheck or base:noheapcheck.
+GUNIT_MAIN_NO_LEAK_CHECK_DEPS = [
+ "@com_google_googletest//:gtest_main",
+]
+
+# TODO(alanjones): Merge this into @com_google_googletest//:gunit_main_no_heapcheck
+GUNIT_MAIN_NO_LEAK_CHECK_PORTABLE_DEPS = [
+ "@com_google_googletest//:gtest_main",
+]
+
+"""Use GUNIT_MAIN_NO_LEAK_CHECK_DEPS_SELECTOR to turn off leak checking."""
+GUNIT_MAIN_NO_LEAK_CHECK_DEPS_SELECTOR = {
+ "//absl:ios": GUNIT_MAIN_NO_LEAK_CHECK_PORTABLE_DEPS,
+ "//absl:windows": GUNIT_MAIN_NO_LEAK_CHECK_PORTABLE_DEPS,
+ "//conditions:default": GUNIT_MAIN_NO_LEAK_CHECK_DEPS,
+}
diff --git a/absl/time/BUILD.bazel b/absl/time/BUILD.bazel
new file mode 100644
index 0000000..da8167f
--- /dev/null
+++ b/absl/time/BUILD.bazel
@@ -0,0 +1,112 @@
+#
+# 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",
+)
+load(
+ "//absl:test_dependencies.bzl",
+ "GUNIT_MAIN_DEPS_SELECTOR",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"]) # Apache 2.0
+
+cc_library(
+ name = "time",
+ srcs = [
+ "clock.cc",
+ "duration.cc",
+ "format.cc",
+ "internal/get_current_time_ios.inc",
+ "internal/get_current_time_posix.inc",
+ "internal/get_current_time_windows.inc",
+ "time.cc",
+ ],
+ hdrs = [
+ "clock.h",
+ "time.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ "//absl/base",
+ "//absl/base:core_headers",
+ "//absl/numeric:int128",
+ "@com_googlesource_code_cctz//:civil_time",
+ "@com_googlesource_code_cctz//:time_zone",
+ ],
+)
+
+cc_library(
+ name = "test_util",
+ srcs = [
+ "internal/test_util.cc",
+ "internal/zoneinfo.inc",
+ ],
+ hdrs = ["internal/test_util.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ ":time",
+ "//absl/base",
+ "@com_googlesource_code_cctz//:time_zone",
+ ],
+)
+
+cc_test(
+ name = "time_test",
+ srcs = [
+ "clock_test.cc",
+ "duration_test.cc",
+ "format_test.cc",
+ "time_norm_test.cc",
+ "time_test.cc",
+ "time_zone_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ tags = [
+ "no_test_android_arm",
+ "no_test_android_arm64",
+ "no_test_android_x86",
+ "no_test_ios_x86_64",
+ "no_test_loonix",
+ "no_test_msvc_x64",
+ ],
+ deps = [
+ ":test_util",
+ ":time",
+ "//absl/base",
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ "@com_google_googletest//:gtest_main",
+ "@com_googlesource_code_cctz//:time_zone",
+ ],
+)
+
+# Used by get_current_time_test, which, due to a dependency on commandlineflags
+# and some required cleanup, is staying back in //base for now.
+cc_library(
+ name = "get_current_time_for_test",
+ testonly = 1,
+ copts = ABSL_DEFAULT_COPTS,
+ textual_hdrs = [
+ "clock.cc",
+ "clock.h",
+ ],
+ deps = ["//absl/base"],
+)
diff --git a/absl/time/clock.cc b/absl/time/clock.cc
new file mode 100644
index 0000000..e2bc01b
--- /dev/null
+++ b/absl/time/clock.cc
@@ -0,0 +1,547 @@
+#include "absl/time/clock.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#include <algorithm>
+#include <atomic>
+#include <cerrno>
+#include <cstdint>
+#include <ctime>
+#include <limits>
+
+#include "absl/base/internal/spinlock.h"
+#include "absl/base/internal/unscaledcycleclock.h"
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/base/thread_annotations.h"
+
+namespace absl {
+Time Now() {
+ // TODO(bww): Get a timespec instead so we don't have to divide.
+ int64_t n = absl::GetCurrentTimeNanos();
+ if (n >= 0) {
+ return time_internal::FromUnixDuration(
+ time_internal::MakeDuration(n / 1000000000, n % 1000000000 * 4));
+ }
+ return time_internal::FromUnixDuration(absl::Nanoseconds(n));
+}
+} // namespace absl
+
+// Decide if we should use the fast GetCurrentTimeNanos() algorithm
+// based on the cyclecounter, otherwise just get the time directly
+// from the OS on every call. This can be chosen at compile-time via
+// -DABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS=[0|1]
+#ifndef ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
+#if ABSL_USE_UNSCALED_CYCLECLOCK
+#define ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS 1
+#else
+#define ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS 0
+#endif
+#endif
+
+#if defined(__APPLE__)
+#include "absl/time/internal/get_current_time_ios.inc"
+#elif defined(_WIN32)
+#include "absl/time/internal/get_current_time_windows.inc"
+#else
+#include "absl/time/internal/get_current_time_posix.inc"
+#endif
+
+// Allows override by test.
+#ifndef GET_CURRENT_TIME_NANOS_FROM_SYSTEM
+#define GET_CURRENT_TIME_NANOS_FROM_SYSTEM() \
+ ::absl::time_internal::GetCurrentTimeNanosFromSystem()
+#endif
+
+#if !ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
+namespace absl {
+int64_t GetCurrentTimeNanos() {
+ return GET_CURRENT_TIME_NANOS_FROM_SYSTEM();
+}
+} // namespace absl
+#else // Use the cyclecounter-based implementation below.
+
+// Allows override by test.
+#ifndef GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW
+#define GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW() \
+ ::absl::time_internal::UnscaledCycleClockWrapperForGetCurrentTime::Now()
+#endif
+
+// The following counters are used only by the test code.
+static int64_t stats_initializations;
+static int64_t stats_reinitializations;
+static int64_t stats_calibrations;
+static int64_t stats_slow_paths;
+static int64_t stats_fast_slow_paths;
+
+namespace absl {
+namespace time_internal {
+// This is a friend wrapper around UnscaledCycleClock::Now()
+// (needed to access UnscaledCycleClock).
+class UnscaledCycleClockWrapperForGetCurrentTime {
+ public:
+ static int64_t Now() { return base_internal::UnscaledCycleClock::Now(); }
+};
+} // namespace time_internal
+
+// uint64_t is used in this module to provide an extra bit in multiplications
+
+// Return the time in ns as told by the kernel interface. Place in *cycleclock
+// the value of the cycleclock at about the time of the syscall.
+// This call represents the time base that this module synchronizes to.
+// Ensures that *cycleclock does not step back by up to (1 << 16) from
+// last_cycleclock, to discard small backward counter steps. (Larger steps are
+// assumed to be complete resyncs, which shouldn't happen. If they do, a full
+// reinitialization of the outer algorithm should occur.)
+static int64_t GetCurrentTimeNanosFromKernel(uint64_t last_cycleclock,
+ uint64_t *cycleclock) {
+ // We try to read clock values at about the same time as the kernel clock.
+ // This value gets adjusted up or down as estimate of how long that should
+ // take, so we can reject attempts that take unusually long.
+ static std::atomic<uint64_t> approx_syscall_time_in_cycles{10 * 1000};
+
+ uint64_t local_approx_syscall_time_in_cycles = // local copy
+ approx_syscall_time_in_cycles.load(std::memory_order_relaxed);
+
+ int64_t current_time_nanos_from_system;
+ uint64_t before_cycles;
+ uint64_t after_cycles;
+ uint64_t elapsed_cycles;
+ int loops = 0;
+ do {
+ before_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW();
+ current_time_nanos_from_system = GET_CURRENT_TIME_NANOS_FROM_SYSTEM();
+ after_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW();
+ // elapsed_cycles is unsigned, so is large on overflow
+ elapsed_cycles = after_cycles - before_cycles;
+ if (elapsed_cycles >= local_approx_syscall_time_in_cycles &&
+ ++loops == 20) { // clock changed frequencies? Back off.
+ loops = 0;
+ if (local_approx_syscall_time_in_cycles < 1000 * 1000) {
+ local_approx_syscall_time_in_cycles =
+ (local_approx_syscall_time_in_cycles + 1) << 1;
+ }
+ approx_syscall_time_in_cycles.store(
+ local_approx_syscall_time_in_cycles,
+ std::memory_order_relaxed);
+ }
+ } while (elapsed_cycles >= local_approx_syscall_time_in_cycles ||
+ last_cycleclock - after_cycles < (static_cast<uint64_t>(1) << 16));
+
+ // Number of times in a row we've seen a kernel time call take substantially
+ // less than approx_syscall_time_in_cycles.
+ static std::atomic<uint32_t> seen_smaller{ 0 };
+
+ // Adjust approx_syscall_time_in_cycles to be within a factor of 2
+ // of the typical time to execute one iteration of the loop above.
+ if ((local_approx_syscall_time_in_cycles >> 1) < elapsed_cycles) {
+ // measured time is no smaller than half current approximation
+ seen_smaller.store(0, std::memory_order_relaxed);
+ } else if (seen_smaller.fetch_add(1, std::memory_order_relaxed) >= 3) {
+ // smaller delays several times in a row; reduce approximation by 12.5%
+ const uint64_t new_approximation =
+ local_approx_syscall_time_in_cycles -
+ (local_approx_syscall_time_in_cycles >> 3);
+ approx_syscall_time_in_cycles.store(new_approximation,
+ std::memory_order_relaxed);
+ seen_smaller.store(0, std::memory_order_relaxed);
+ }
+
+ *cycleclock = after_cycles;
+ return current_time_nanos_from_system;
+}
+
+
+// ---------------------------------------------------------------------
+// An implementation of reader-write locks that use no atomic ops in the read
+// case. This is a generalization of Lamport's method for reading a multiword
+// clock. Increment a word on each write acquisition, using the low-order bit
+// as a spinlock; the word is the high word of the "clock". Readers read the
+// high word, then all other data, then the high word again, and repeat the
+// read if the reads of the high words yields different answers, or an odd
+// value (either case suggests possible interference from a writer).
+// Here we use a spinlock to ensure only one writer at a time, rather than
+// spinning on the bottom bit of the word to benefit from SpinLock
+// spin-delay tuning.
+
+// Acquire seqlock (*seq) and return the value to be written to unlock.
+static inline uint64_t SeqAcquire(std::atomic<uint64_t> *seq) {
+ uint64_t x = seq->fetch_add(1, std::memory_order_relaxed);
+
+ // We put a release fence between update to *seq and writes to shared data.
+ // Thus all stores to shared data are effectively release operations and
+ // update to *seq above cannot be re-ordered past any of them. Note that
+ // this barrier is not for the fetch_add above. A release barrier for the
+ // fetch_add would be before it, not after.
+ std::atomic_thread_fence(std::memory_order_release);
+
+ return x + 2; // original word plus 2
+}
+
+// Release seqlock (*seq) by writing x to it---a value previously returned by
+// SeqAcquire.
+static inline void SeqRelease(std::atomic<uint64_t> *seq, uint64_t x) {
+ // The unlock store to *seq must have release ordering so that all
+ // updates to shared data must finish before this store.
+ seq->store(x, std::memory_order_release); // release lock for readers
+}
+
+// ---------------------------------------------------------------------
+
+// "nsscaled" is unit of time equal to a (2**kScale)th of a nanosecond.
+enum { kScale = 30 };
+
+// The minimum interval between samples of the time base.
+// We pick enough time to amortize the cost of the sample,
+// to get a reasonably accurate cycle counter rate reading,
+// and not so much that calculations will overflow 64-bits.
+static const uint64_t kMinNSBetweenSamples = 2000 << 20;
+
+// We require that kMinNSBetweenSamples shifted by kScale
+// have at least a bit left over for 64-bit calculations.
+static_assert(((kMinNSBetweenSamples << (kScale + 1)) >> (kScale + 1)) ==
+ kMinNSBetweenSamples,
+ "cannot represent kMaxBetweenSamplesNSScaled");
+
+// A reader-writer lock protecting the static locations below.
+// See SeqAcquire() and SeqRelease() above.
+static absl::base_internal::SpinLock lock(
+ absl::base_internal::kLinkerInitialized);
+static std::atomic<uint64_t> seq(0);
+
+// data from a sample of the kernel's time value
+struct TimeSampleAtomic {
+ std::atomic<uint64_t> raw_ns; // raw kernel time
+ std::atomic<uint64_t> base_ns; // our estimate of time
+ std::atomic<uint64_t> base_cycles; // cycle counter reading
+ std::atomic<uint64_t> nsscaled_per_cycle; // cycle period
+ // cycles before we'll sample again (a scaled reciprocal of the period,
+ // to avoid a division on the fast path).
+ std::atomic<uint64_t> min_cycles_per_sample;
+};
+// Same again, but with non-atomic types
+struct TimeSample {
+ uint64_t raw_ns; // raw kernel time
+ uint64_t base_ns; // our estimate of time
+ uint64_t base_cycles; // cycle counter reading
+ uint64_t nsscaled_per_cycle; // cycle period
+ uint64_t min_cycles_per_sample; // approx cycles before next sample
+};
+
+static struct TimeSampleAtomic last_sample; // the last sample; under seq
+
+static int64_t GetCurrentTimeNanosSlowPath() ABSL_ATTRIBUTE_COLD;
+
+// Read the contents of *atomic into *sample.
+// Each field is read atomically, but to maintain atomicity between fields,
+// the access must be done under a lock.
+static void ReadTimeSampleAtomic(const struct TimeSampleAtomic *atomic,
+ struct TimeSample *sample) {
+ sample->base_ns = atomic->base_ns.load(std::memory_order_relaxed);
+ sample->base_cycles = atomic->base_cycles.load(std::memory_order_relaxed);
+ sample->nsscaled_per_cycle =
+ atomic->nsscaled_per_cycle.load(std::memory_order_relaxed);
+ sample->min_cycles_per_sample =
+ atomic->min_cycles_per_sample.load(std::memory_order_relaxed);
+ sample->raw_ns = atomic->raw_ns.load(std::memory_order_relaxed);
+}
+
+// Public routine.
+// Algorithm: We wish to compute real time from a cycle counter. In normal
+// operation, we construct a piecewise linear approximation to the kernel time
+// source, using the cycle counter value. The start of each line segment is at
+// the same point as the end of the last, but may have a different slope (that
+// is, a different idea of the cycle counter frequency). Every couple of
+// seconds, the kernel time source is sampled and compared with the current
+// approximation. A new slope is chosen that, if followed for another couple
+// of seconds, will correct the error at the current position. The information
+// for a sample is in the "last_sample" struct. The linear approximation is
+// estimated_time = last_sample.base_ns +
+// last_sample.ns_per_cycle * (counter_reading - last_sample.base_cycles)
+// (ns_per_cycle is actually stored in different units and scaled, to avoid
+// overflow). The base_ns of the next linear approximation is the
+// estimated_time using the last approximation; the base_cycles is the cycle
+// counter value at that time; the ns_per_cycle is the number of ns per cycle
+// measured since the last sample, but adjusted so that most of the difference
+// between the estimated_time and the kernel time will be corrected by the
+// estimated time to the next sample. In normal operation, this algorithm
+// relies on:
+// - the cycle counter and kernel time rates not changing a lot in a few
+// seconds.
+// - the client calling into the code often compared to a couple of seconds, so
+// the time to the next correction can be estimated.
+// Any time ns_per_cycle is not known, a major error is detected, or the
+// assumption about frequent calls is violated, the implementation returns the
+// kernel time. It records sufficient data that a linear approximation can
+// resume a little later.
+
+int64_t GetCurrentTimeNanos() {
+ // read the data from the "last_sample" struct (but don't need raw_ns yet)
+ // The reads of "seq" and test of the values emulate a reader lock.
+ uint64_t base_ns;
+ uint64_t base_cycles;
+ uint64_t nsscaled_per_cycle;
+ uint64_t min_cycles_per_sample;
+ uint64_t seq_read0;
+ uint64_t seq_read1;
+
+ // If we have enough information to interpolate, the value returned will be
+ // derived from this cycleclock-derived time estimate. On some platforms
+ // (POWER) the function to retrieve this value has enough complexity to
+ // contribute to register pressure - reading it early before initializing
+ // the other pieces of the calculation minimizes spill/restore instructions,
+ // minimizing icache cost.
+ uint64_t now_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW();
+
+ // Acquire pairs with the barrier in SeqRelease - if this load sees that
+ // store, the shared-data reads necessarily see that SeqRelease's updates
+ // to the same shared data.
+ seq_read0 = seq.load(std::memory_order_acquire);
+
+ base_ns = last_sample.base_ns.load(std::memory_order_relaxed);
+ base_cycles = last_sample.base_cycles.load(std::memory_order_relaxed);
+ nsscaled_per_cycle =
+ last_sample.nsscaled_per_cycle.load(std::memory_order_relaxed);
+ min_cycles_per_sample =
+ last_sample.min_cycles_per_sample.load(std::memory_order_relaxed);
+
+ // This acquire fence pairs with the release fence in SeqAcquire. Since it
+ // is sequenced between reads of shared data and seq_read1, the reads of
+ // shared data are effectively acquiring.
+ std::atomic_thread_fence(std::memory_order_acquire);
+
+ // The shared-data reads are effectively acquire ordered, and the
+ // shared-data writes are effectively release ordered. Therefore if our
+ // shared-data reads see any of a particular update's shared-data writes,
+ // seq_read1 is guaranteed to see that update's SeqAcquire.
+ seq_read1 = seq.load(std::memory_order_relaxed);
+
+ // Fast path. Return if min_cycles_per_sample has not yet elapsed since the
+ // last sample, and we read a consistent sample. The fast path activates
+ // only when min_cycles_per_sample is non-zero, which happens when we get an
+ // estimate for the cycle time. The predicate will fail if now_cycles <
+ // base_cycles, or if some other thread is in the slow path.
+ //
+ // Since we now read now_cycles before base_ns, it is possible for now_cycles
+ // to be less than base_cycles (if we were interrupted between those loads and
+ // last_sample was updated). This is harmless, because delta_cycles will wrap
+ // and report a time much much bigger than min_cycles_per_sample. In that case
+ // we will take the slow path.
+ uint64_t delta_cycles = now_cycles - base_cycles;
+ if (seq_read0 == seq_read1 && (seq_read0 & 1) == 0 &&
+ delta_cycles < min_cycles_per_sample) {
+ return base_ns + ((delta_cycles * nsscaled_per_cycle) >> kScale);
+ }
+ return GetCurrentTimeNanosSlowPath();
+}
+
+// Return (a << kScale)/b.
+// Zero is returned if b==0. Scaling is performed internally to
+// preserve precision without overflow.
+static uint64_t SafeDivideAndScale(uint64_t a, uint64_t b) {
+ // Find maximum safe_shift so that
+ // 0 <= safe_shift <= kScale and (a << safe_shift) does not overflow.
+ int safe_shift = kScale;
+ while (((a << safe_shift) >> safe_shift) != a) {
+ safe_shift--;
+ }
+ uint64_t scaled_b = b >> (kScale - safe_shift);
+ uint64_t quotient = 0;
+ if (scaled_b != 0) {
+ quotient = (a << safe_shift) / scaled_b;
+ }
+ return quotient;
+}
+
+static uint64_t UpdateLastSample(
+ uint64_t now_cycles, uint64_t now_ns, uint64_t delta_cycles,
+ const struct TimeSample *sample) ABSL_ATTRIBUTE_COLD;
+
+// The slow path of GetCurrentTimeNanos(). This is taken while gathering
+// initial samples, when enough time has elapsed since the last sample, and if
+// any other thread is writing to last_sample.
+//
+// Manually mark this 'noinline' to minimize stack frame size of the fast
+// path. Without this, sometimes a compiler may inline this big block of code
+// into the fast past. That causes lots of register spills and reloads that
+// are unnecessary unless the slow path is taken.
+//
+// TODO(b/36012148) Remove this attribute when our compiler is smart enough
+// to do the right thing.
+ABSL_ATTRIBUTE_NOINLINE
+static int64_t GetCurrentTimeNanosSlowPath() LOCKS_EXCLUDED(lock) {
+ // Serialize access to slow-path. Fast-path readers are not blocked yet, and
+ // code below must not modify last_sample until the seqlock is acquired.
+ lock.Lock();
+
+ // Sample the kernel time base. This is the definition of
+ // "now" if we take the slow path.
+ static uint64_t last_now_cycles; // protected by lock
+ uint64_t now_cycles;
+ uint64_t now_ns = GetCurrentTimeNanosFromKernel(last_now_cycles, &now_cycles);
+ last_now_cycles = now_cycles;
+
+ uint64_t estimated_base_ns;
+
+ // ----------
+ // Read the "last_sample" values again; this time holding the write lock.
+ struct TimeSample sample;
+ ReadTimeSampleAtomic(&last_sample, &sample);
+
+ // ----------
+ // Try running the fast path again; another thread may have updated the
+ // sample between our run of the fast path and the sample we just read.
+ uint64_t delta_cycles = now_cycles - sample.base_cycles;
+ if (delta_cycles < sample.min_cycles_per_sample) {
+ // Another thread updated the sample. This path does not take the seqlock
+ // so that blocked readers can make progress without blocking new readers.
+ estimated_base_ns = sample.base_ns +
+ ((delta_cycles * sample.nsscaled_per_cycle) >> kScale);
+ stats_fast_slow_paths++;
+ } else {
+ estimated_base_ns =
+ UpdateLastSample(now_cycles, now_ns, delta_cycles, &sample);
+ }
+
+ lock.Unlock();
+
+ return estimated_base_ns;
+}
+
+// Main part of the algorithm. Locks out readers, updates the approximation
+// using the new sample from the kernel, and stores the result in last_sample
+// for readers. Returns the new estimated time.
+static uint64_t UpdateLastSample(uint64_t now_cycles, uint64_t now_ns,
+ uint64_t delta_cycles,
+ const struct TimeSample *sample)
+ EXCLUSIVE_LOCKS_REQUIRED(lock) {
+ uint64_t estimated_base_ns = now_ns;
+ uint64_t lock_value = SeqAcquire(&seq); // acquire seqlock to block readers
+
+ // The 5s in the next if-statement limits the time for which we will trust
+ // the cycle counter and our last sample to give a reasonable result.
+ // Errors in the rate of the source clock can be multiplied by the ratio
+ // between this limit and kMinNSBetweenSamples.
+ if (sample->raw_ns == 0 || // no recent sample, or clock went backwards
+ sample->raw_ns + static_cast<uint64_t>(5) * 1000 * 1000 * 1000 < now_ns ||
+ now_ns < sample->raw_ns || now_cycles < sample->base_cycles) {
+ // record this sample, and forget any previously known slope.
+ last_sample.raw_ns.store(now_ns, std::memory_order_relaxed);
+ last_sample.base_ns.store(estimated_base_ns, std::memory_order_relaxed);
+ last_sample.base_cycles.store(now_cycles, std::memory_order_relaxed);
+ last_sample.nsscaled_per_cycle.store(0, std::memory_order_relaxed);
+ last_sample.min_cycles_per_sample.store(0, std::memory_order_relaxed);
+ stats_initializations++;
+ } else if (sample->raw_ns + 500 * 1000 * 1000 < now_ns &&
+ sample->base_cycles + 100 < now_cycles) {
+ // Enough time has passed to compute the cycle time.
+ if (sample->nsscaled_per_cycle != 0) { // Have a cycle time estimate.
+ // Compute time from counter reading, but avoiding overflow
+ // delta_cycles may be larger than on the fast path.
+ uint64_t estimated_scaled_ns;
+ int s = -1;
+ do {
+ s++;
+ estimated_scaled_ns = (delta_cycles >> s) * sample->nsscaled_per_cycle;
+ } while (estimated_scaled_ns / sample->nsscaled_per_cycle !=
+ (delta_cycles >> s));
+ estimated_base_ns = sample->base_ns +
+ (estimated_scaled_ns >> (kScale - s));
+ }
+
+ // Compute the assumed cycle time kMinNSBetweenSamples ns into the future
+ // assuming the cycle counter rate stays the same as the last interval.
+ uint64_t ns = now_ns - sample->raw_ns;
+ uint64_t measured_nsscaled_per_cycle = SafeDivideAndScale(ns, delta_cycles);
+
+ uint64_t assumed_next_sample_delta_cycles =
+ SafeDivideAndScale(kMinNSBetweenSamples, measured_nsscaled_per_cycle);
+
+ int64_t diff_ns = now_ns - estimated_base_ns; // estimate low by this much
+
+ // We want to set nsscaled_per_cycle so that our estimate of the ns time
+ // at the assumed cycle time is the assumed ns time.
+ // That is, we want to set nsscaled_per_cycle so:
+ // kMinNSBetweenSamples + diff_ns ==
+ // (assumed_next_sample_delta_cycles * nsscaled_per_cycle) >> kScale
+ // But we wish to damp oscillations, so instead correct only most
+ // of our current error, by solving:
+ // kMinNSBetweenSamples + diff_ns - (diff_ns / 16) ==
+ // (assumed_next_sample_delta_cycles * nsscaled_per_cycle) >> kScale
+ ns = kMinNSBetweenSamples + diff_ns - (diff_ns / 16);
+ uint64_t new_nsscaled_per_cycle =
+ SafeDivideAndScale(ns, assumed_next_sample_delta_cycles);
+ if (new_nsscaled_per_cycle != 0 &&
+ diff_ns < 100 * 1000 * 1000 && -diff_ns < 100 * 1000 * 1000) {
+ // record the cycle time measurement
+ last_sample.nsscaled_per_cycle.store(
+ new_nsscaled_per_cycle, std::memory_order_relaxed);
+ uint64_t new_min_cycles_per_sample =
+ SafeDivideAndScale(kMinNSBetweenSamples, new_nsscaled_per_cycle);
+ last_sample.min_cycles_per_sample.store(
+ new_min_cycles_per_sample, std::memory_order_relaxed);
+ stats_calibrations++;
+ } else { // something went wrong; forget the slope
+ last_sample.nsscaled_per_cycle.store(0, std::memory_order_relaxed);
+ last_sample.min_cycles_per_sample.store(0, std::memory_order_relaxed);
+ estimated_base_ns = now_ns;
+ stats_reinitializations++;
+ }
+ last_sample.raw_ns.store(now_ns, std::memory_order_relaxed);
+ last_sample.base_ns.store(estimated_base_ns, std::memory_order_relaxed);
+ last_sample.base_cycles.store(now_cycles, std::memory_order_relaxed);
+ } else {
+ // have a sample, but no slope; waiting for enough time for a calibration
+ stats_slow_paths++;
+ }
+
+ SeqRelease(&seq, lock_value); // release the readers
+
+ return estimated_base_ns;
+}
+} // namespace absl
+#endif // ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
+
+namespace absl {
+namespace {
+
+// Returns the maximum duration that SleepOnce() can sleep for.
+constexpr absl::Duration MaxSleep() {
+#ifdef _WIN32
+ // Windows _sleep() takes unsigned long argument in milliseconds.
+ return absl::Milliseconds(
+ std::numeric_limits<unsigned long>::max()); // NOLINT(runtime/int)
+#else
+ return absl::Seconds(std::numeric_limits<time_t>::max());
+#endif
+}
+
+// Sleeps for the given duration.
+// REQUIRES: to_sleep <= MaxSleep().
+void SleepOnce(absl::Duration to_sleep) {
+#ifdef _WIN32
+ _sleep(to_sleep / absl::Milliseconds(1));
+#else
+ struct timespec sleep_time = absl::ToTimespec(to_sleep);
+ while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) {
+ // Ignore signals and wait for the full interval to elapse.
+ }
+#endif
+}
+
+} // namespace
+} // namespace absl
+
+extern "C" {
+
+ABSL_ATTRIBUTE_WEAK void AbslInternalSleepFor(absl::Duration duration) {
+ while (duration > absl::ZeroDuration()) {
+ absl::Duration to_sleep = std::min(duration, absl::MaxSleep());
+ absl::SleepOnce(to_sleep);
+ duration -= to_sleep;
+ }
+}
+
+} // extern "C"
diff --git a/absl/time/clock.h b/absl/time/clock.h
new file mode 100644
index 0000000..3753d4e
--- /dev/null
+++ b/absl/time/clock.h
@@ -0,0 +1,72 @@
+// 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: clock.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains utility functions for working with the system-wide
+// realtime clock. For descriptions of the main time abstractions used within
+// this header file, consult the time.h header file.
+#ifndef ABSL_TIME_CLOCK_H_
+#define ABSL_TIME_CLOCK_H_
+
+#include "absl/base/macros.h"
+#include "absl/time/time.h"
+
+namespace absl {
+
+// Now()
+//
+// Returns the current time, expressed as an `absl::Time` absolute time value.
+absl::Time Now();
+
+// GetCurrentTimeNanos()
+//
+// Returns the current time, expressed as a count of nanoseconds since the Unix
+// Epoch (https://en.wikipedia.org/wiki/Unix_time). Prefer `absl::Now()` instead
+// for all but the most performance-sensitive cases (i.e. when you are calling
+// this function hundreds of thousands of times per second).
+int64_t GetCurrentTimeNanos();
+
+// SleepFor()
+//
+// Sleeps for the specified duration, expressed as an `absl::Duration`.
+//
+// Notes:
+// * Signal interruptions will not reduce the sleep duration.
+// * Returns immediately when passed a nonpositive duration.
+void SleepFor(absl::Duration duration);
+
+} // namespace absl
+
+// -----------------------------------------------------------------------------
+// Implementation Details
+// -----------------------------------------------------------------------------
+
+// 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 AbslInternalSleepFor(absl::Duration duration);
+} // extern "C"
+
+inline void absl::SleepFor(absl::Duration duration) {
+ AbslInternalSleepFor(duration);
+}
+
+#endif // ABSL_TIME_CLOCK_H_
diff --git a/absl/time/clock_test.cc b/absl/time/clock_test.cc
new file mode 100644
index 0000000..933ed24
--- /dev/null
+++ b/absl/time/clock_test.cc
@@ -0,0 +1,70 @@
+// 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/time/clock.h"
+
+#include "absl/base/config.h"
+#if defined(ABSL_HAVE_ALARM)
+#include <signal.h>
+#include <unistd.h>
+#elif defined(__linux__) || defined(__APPLE__)
+#error all known Linux and Apple targets have alarm
+#endif
+
+#include "gtest/gtest.h"
+#include "absl/time/time.h"
+
+namespace {
+
+TEST(Time, Now) {
+ const absl::Time before = absl::FromUnixNanos(absl::GetCurrentTimeNanos());
+ const absl::Time now = absl::Now();
+ const absl::Time after = absl::FromUnixNanos(absl::GetCurrentTimeNanos());
+ EXPECT_GE(now, before);
+ EXPECT_GE(after, now);
+}
+
+TEST(SleepForTest, BasicSanity) {
+ absl::Duration sleep_time = absl::Milliseconds(2500);
+ absl::Time start = absl::Now();
+ absl::SleepFor(sleep_time);
+ absl::Time end = absl::Now();
+ EXPECT_LE(sleep_time - absl::Milliseconds(100), end - start);
+ EXPECT_GE(sleep_time + absl::Milliseconds(100), end - start);
+}
+
+#ifdef ABSL_HAVE_ALARM
+// Helper for test SleepFor.
+bool alarm_handler_invoked = false;
+void AlarmHandler(int signo) {
+ ASSERT_EQ(signo, SIGALRM);
+ alarm_handler_invoked = true;
+}
+
+TEST(SleepForTest, AlarmSupport) {
+ alarm_handler_invoked = false;
+ sig_t old_alarm = signal(SIGALRM, AlarmHandler);
+ alarm(2);
+ absl::Duration sleep_time = absl::Milliseconds(3500);
+ absl::Time start = absl::Now();
+ absl::SleepFor(sleep_time);
+ absl::Time end = absl::Now();
+ EXPECT_TRUE(alarm_handler_invoked);
+ EXPECT_LE(sleep_time - absl::Milliseconds(100), end - start);
+ EXPECT_GE(sleep_time + absl::Milliseconds(100), end - start);
+ signal(SIGALRM, old_alarm);
+}
+#endif // ABSL_HAVE_ALARM
+
+} // namespace
diff --git a/absl/time/duration.cc b/absl/time/duration.cc
new file mode 100644
index 0000000..07d1082
--- /dev/null
+++ b/absl/time/duration.cc
@@ -0,0 +1,864 @@
+// 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 the absl::Duration class, which is declared in
+// //absl/time.h. This class behaves like a numeric type; it has no public
+// methods and is used only through the operators defined here.
+//
+// Implementation notes:
+//
+// An absl::Duration is represented as
+//
+// rep_hi_ : (int64_t) Whole seconds
+// rep_lo_ : (uint32_t) Fractions of a second
+//
+// The seconds value (rep_hi_) may be positive or negative as appropriate.
+// The fractional seconds (rep_lo_) is always a positive offset from rep_hi_.
+// The API for Duration guarantees at least nanosecond resolution, which
+// means rep_lo_ could have a max value of 1B - 1 if it stored nanoseconds.
+// However, to utilize more of the available 32 bits of space in rep_lo_,
+// we instead store quarters of a nanosecond in rep_lo_ resulting in a max
+// value of 4B - 1. This allows us to correctly handle calculations like
+// 0.5 nanos + 0.5 nanos = 1 nano. The following example shows the actual
+// Duration rep using quarters of a nanosecond.
+//
+// 2.5 sec = {rep_hi_=2, rep_lo_=2000000000} // lo = 4 * 500000000
+// -2.5 sec = {rep_hi_=-3, rep_lo_=2000000000}
+//
+// Infinite durations are represented as Durations with the rep_lo_ field set
+// to all 1s.
+//
+// +InfiniteDuration:
+// rep_hi_ : kint64max
+// rep_lo_ : ~0U
+//
+// -InfiniteDuration:
+// rep_hi_ : kint64min
+// rep_lo_ : ~0U
+//
+// Arithmetic overflows/underflows to +/- infinity and saturates.
+
+#include <algorithm>
+#include <cassert>
+#include <cctype>
+#include <cerrno>
+#include <cmath>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <functional>
+#include <limits>
+#include <string>
+
+#include "absl/numeric/int128.h"
+#include "absl/time/time.h"
+
+namespace absl {
+
+namespace {
+
+using time_internal::kTicksPerNanosecond;
+using time_internal::kTicksPerSecond;
+
+constexpr int64_t kint64max = std::numeric_limits<int64_t>::max();
+constexpr int64_t kint64min = std::numeric_limits<int64_t>::min();
+
+// Can't use std::isinfinite() because it doesn't exist on windows.
+inline bool IsFinite(double d) {
+ return d != std::numeric_limits<double>::infinity() &&
+ d != -std::numeric_limits<double>::infinity();
+}
+
+// Can't use std::round() because it is only available in C++11.
+// Note that we ignore the possibility of floating-point over/underflow.
+template <typename Double>
+inline double Round(Double d) {
+ return d < 0 ? std::ceil(d - 0.5) : std::floor(d + 0.5);
+}
+
+// *sec may be positive or negative. *ticks must be in the range
+// -kTicksPerSecond < *ticks < kTicksPerSecond. If *ticks is negative it
+// will be normalized to a positive value by adjusting *sec accordingly.
+inline void NormalizeTicks(int64_t* sec, int64_t* ticks) {
+ if (*ticks < 0) {
+ --*sec;
+ *ticks += kTicksPerSecond;
+ }
+}
+
+// Makes a uint128 from the absolute value of the given scalar.
+inline uint128 MakeU128(int64_t a) {
+ uint128 u128 = 0;
+ if (a < 0) {
+ ++u128;
+ ++a; // Makes it safe to negate 'a'
+ a = -a;
+ }
+ u128 += static_cast<uint64_t>(a);
+ return u128;
+}
+
+// Makes a uint128 count of ticks out of the absolute value of the Duration.
+inline uint128 MakeU128Ticks(Duration d) {
+ int64_t rep_hi = time_internal::GetRepHi(d);
+ uint32_t rep_lo = time_internal::GetRepLo(d);
+ if (rep_hi < 0) {
+ ++rep_hi;
+ rep_hi = -rep_hi;
+ rep_lo = kTicksPerSecond - rep_lo;
+ }
+ uint128 u128 = static_cast<uint64_t>(rep_hi);
+ u128 *= static_cast<uint64_t>(kTicksPerSecond);
+ u128 += rep_lo;
+ return u128;
+}
+
+// Breaks a uint128 of ticks into a Duration.
+inline Duration MakeDurationFromU128(uint128 u128, bool is_neg) {
+ int64_t rep_hi;
+ uint32_t rep_lo;
+ const uint64_t h64 = Uint128High64(u128);
+ const uint64_t l64 = Uint128Low64(u128);
+ if (h64 == 0) { // fastpath
+ const uint64_t hi = l64 / kTicksPerSecond;
+ rep_hi = static_cast<int64_t>(hi);
+ rep_lo = static_cast<uint32_t>(l64 - hi * kTicksPerSecond);
+ } else {
+ // kMaxRepHi64 is the high 64 bits of (2^63 * kTicksPerSecond).
+ // Any positive tick count whose high 64 bits are >= kMaxRepHi64
+ // is not representable as a Duration. A negative tick count can
+ // have its high 64 bits == kMaxRepHi64 but only when the low 64
+ // bits are all zero, otherwise it is not representable either.
+ const uint64_t kMaxRepHi64 = 0x77359400UL;
+ if (h64 >= kMaxRepHi64) {
+ if (is_neg && h64 == kMaxRepHi64 && l64 == 0) {
+ // Avoid trying to represent -kint64min below.
+ return time_internal::MakeDuration(kint64min);
+ }
+ return is_neg ? -InfiniteDuration() : InfiniteDuration();
+ }
+ const uint128 kTicksPerSecond128 = static_cast<uint64_t>(kTicksPerSecond);
+ const uint128 hi = u128 / kTicksPerSecond128;
+ rep_hi = static_cast<int64_t>(Uint128Low64(hi));
+ rep_lo =
+ static_cast<uint32_t>(Uint128Low64(u128 - hi * kTicksPerSecond128));
+ }
+ if (is_neg) {
+ rep_hi = -rep_hi;
+ if (rep_lo != 0) {
+ --rep_hi;
+ rep_lo = kTicksPerSecond - rep_lo;
+ }
+ }
+ return time_internal::MakeDuration(rep_hi, rep_lo);
+}
+
+// Convert int64_t to uint64_t in twos-complement system.
+inline uint64_t EncodeTwosComp(int64_t v) { return static_cast<uint64_t>(v); }
+
+// Convert uint64_t to int64_t in twos-complement system.
+inline int64_t DecodeTwosComp(uint64_t v) {
+ if (v <= kint64max) return static_cast<int64_t>(v);
+ return static_cast<int64_t>(v - kint64max - 1) + kint64min;
+}
+
+// Note: The overflow detection in this function is done using greater/less *or
+// equal* because kint64max/min is too large to be represented exactly in a
+// double (which only has 53 bits of precision). In order to avoid assigning to
+// rep->hi a double value that is too large for an int64_t (and therefore is
+// undefined), we must consider computations that equal kint64max/min as a
+// double as overflow cases.
+inline bool SafeAddRepHi(double a_hi, double b_hi, Duration* d) {
+ double c = a_hi + b_hi;
+ if (c >= kint64max) {
+ *d = InfiniteDuration();
+ return false;
+ }
+ if (c <= kint64min) {
+ *d = -InfiniteDuration();
+ return false;
+ }
+ *d = time_internal::MakeDuration(c, time_internal::GetRepLo(*d));
+ return true;
+}
+
+// A functor that's similar to std::multiplies<T>, except this returns the max
+// T value instead of overflowing. This is only defined for uint128.
+template <typename Ignored>
+struct SafeMultiply {
+ uint128 operator()(uint128 a, uint128 b) const {
+ // b hi is always zero because it originated as an int64_t.
+ assert(Uint128High64(b) == 0);
+ // Fastpath to avoid the expensive overflow check with division.
+ if (Uint128High64(a) == 0) {
+ return (((Uint128Low64(a) | Uint128Low64(b)) >> 32) == 0)
+ ? static_cast<uint128>(Uint128Low64(a) * Uint128Low64(b))
+ : a * b;
+ }
+ return b == 0 ? b : (a > kuint128max / b) ? kuint128max : a * b;
+ }
+};
+
+// Scales (i.e., multiplies or divides, depending on the Operation template)
+// the Duration d by the int64_t r.
+template <template <typename> class Operation>
+inline Duration ScaleFixed(Duration d, int64_t r) {
+ const uint128 a = MakeU128Ticks(d);
+ const uint128 b = MakeU128(r);
+ const uint128 q = Operation<uint128>()(a, b);
+ const bool is_neg = (time_internal::GetRepHi(d) < 0) != (r < 0);
+ return MakeDurationFromU128(q, is_neg);
+}
+
+// Scales (i.e., multiplies or divides, depending on the Operation template)
+// the Duration d by the double r.
+template <template <typename> class Operation>
+inline Duration ScaleDouble(Duration d, double r) {
+ Operation<double> op;
+ double hi_doub = op(time_internal::GetRepHi(d), r);
+ double lo_doub = op(time_internal::GetRepLo(d), r);
+
+ double hi_int = 0;
+ double hi_frac = std::modf(hi_doub, &hi_int);
+
+ // Moves hi's fractional bits to lo.
+ lo_doub /= kTicksPerSecond;
+ lo_doub += hi_frac;
+
+ double lo_int = 0;
+ double lo_frac = std::modf(lo_doub, &lo_int);
+
+ // Rolls lo into hi if necessary.
+ int64_t lo64 = Round(lo_frac * kTicksPerSecond);
+
+ Duration ans;
+ if (!SafeAddRepHi(hi_int, lo_int, &ans)) return ans;
+ int64_t hi64 = time_internal::GetRepHi(ans);
+ if (!SafeAddRepHi(hi64, lo64 / kTicksPerSecond, &ans)) return ans;
+ hi64 = time_internal::GetRepHi(ans);
+ lo64 %= kTicksPerSecond;
+ NormalizeTicks(&hi64, &lo64);
+ return time_internal::MakeDuration(hi64, lo64);
+}
+
+// Tries to divide num by den as fast as possible by looking for common, easy
+// cases. If the division was done, the quotient is in *q and the remainder is
+// in *rem and true will be returned.
+inline bool IDivFastPath(const Duration num, const Duration den, int64_t* q,
+ Duration* rem) {
+ // Bail if num or den is an infinity.
+ if (time_internal::IsInfiniteDuration(num) ||
+ time_internal::IsInfiniteDuration(den))
+ return false;
+
+ int64_t num_hi = time_internal::GetRepHi(num);
+ uint32_t num_lo = time_internal::GetRepLo(num);
+ int64_t den_hi = time_internal::GetRepHi(den);
+ uint32_t den_lo = time_internal::GetRepLo(den);
+
+ if (den_hi == 0 && den_lo == kTicksPerNanosecond) {
+ // Dividing by 1ns
+ if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 1000000000) {
+ *q = num_hi * 1000000000 + num_lo / kTicksPerNanosecond;
+ *rem = time_internal::MakeDuration(0, num_lo % den_lo);
+ return true;
+ }
+ } else if (den_hi == 0 && den_lo == 100 * kTicksPerNanosecond) {
+ // Dividing by 100ns (common when converting to Universal time)
+ if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 10000000) {
+ *q = num_hi * 10000000 + num_lo / (100 * kTicksPerNanosecond);
+ *rem = time_internal::MakeDuration(0, num_lo % den_lo);
+ return true;
+ }
+ } else if (den_hi == 0 && den_lo == 1000 * kTicksPerNanosecond) {
+ // Dividing by 1us
+ if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 1000000) {
+ *q = num_hi * 1000000 + num_lo / (1000 * kTicksPerNanosecond);
+ *rem = time_internal::MakeDuration(0, num_lo % den_lo);
+ return true;
+ }
+ } else if (den_hi == 0 && den_lo == 1000000 * kTicksPerNanosecond) {
+ // Dividing by 1ms
+ if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 1000) {
+ *q = num_hi * 1000 + num_lo / (1000000 * kTicksPerNanosecond);
+ *rem = time_internal::MakeDuration(0, num_lo % den_lo);
+ return true;
+ }
+ } else if (den_hi > 0 && den_lo == 0) {
+ // Dividing by positive multiple of 1s
+ if (num_hi >= 0) {
+ if (den_hi == 1) {
+ *q = num_hi;
+ *rem = time_internal::MakeDuration(0, num_lo);
+ return true;
+ }
+ *q = num_hi / den_hi;
+ *rem = time_internal::MakeDuration(num_hi % den_hi, num_lo);
+ return true;
+ }
+ if (num_lo != 0) {
+ num_hi += 1;
+ }
+ int64_t quotient = num_hi / den_hi;
+ int64_t rem_sec = num_hi % den_hi;
+ if (rem_sec > 0) {
+ rem_sec -= den_hi;
+ quotient += 1;
+ }
+ if (num_lo != 0) {
+ rem_sec -= 1;
+ }
+ *q = quotient;
+ *rem = time_internal::MakeDuration(rem_sec, num_lo);
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace
+
+namespace time_internal {
+
+// The 'satq' argument indicates whether the quotient should saturate at the
+// bounds of int64_t. If it does saturate, the difference will spill over to
+// the remainder. If it does not saturate, the remainder remain accurate,
+// but the returned quotient will over/underflow int64_t and should not be used.
+int64_t IDivDuration(bool satq, const Duration num, const Duration den,
+ Duration* rem) {
+ int64_t q = 0;
+ if (IDivFastPath(num, den, &q, rem)) {
+ return q;
+ }
+
+ const bool num_neg = num < ZeroDuration();
+ const bool den_neg = den < ZeroDuration();
+ const bool quotient_neg = num_neg != den_neg;
+
+ if (time_internal::IsInfiniteDuration(num) || den == ZeroDuration()) {
+ *rem = num_neg ? -InfiniteDuration() : InfiniteDuration();
+ return quotient_neg ? kint64min : kint64max;
+ }
+ if (time_internal::IsInfiniteDuration(den)) {
+ *rem = num;
+ return 0;
+ }
+
+ const uint128 a = MakeU128Ticks(num);
+ const uint128 b = MakeU128Ticks(den);
+ uint128 quotient128 = a / b;
+
+ if (satq) {
+ // Limits the quotient to the range of int64_t.
+ if (quotient128 > uint128(static_cast<uint64_t>(kint64max))) {
+ quotient128 = quotient_neg ? uint128(static_cast<uint64_t>(kint64min))
+ : uint128(static_cast<uint64_t>(kint64max));
+ }
+ }
+
+ const uint128 remainder128 = a - quotient128 * b;
+ *rem = MakeDurationFromU128(remainder128, num_neg);
+
+ if (!quotient_neg || quotient128 == 0) {
+ return Uint128Low64(quotient128) & kint64max;
+ }
+ // The quotient needs to be negated, but we need to carefully handle
+ // quotient128s with the top bit on.
+ return -static_cast<int64_t>(Uint128Low64(quotient128 - 1) & kint64max) - 1;
+}
+
+} // namespace time_internal
+
+//
+// Additive operators.
+//
+
+Duration& Duration::operator+=(Duration rhs) {
+ if (time_internal::IsInfiniteDuration(*this)) return *this;
+ if (time_internal::IsInfiniteDuration(rhs)) return *this = rhs;
+ const int64_t orig_rep_hi = rep_hi_;
+ rep_hi_ =
+ DecodeTwosComp(EncodeTwosComp(rep_hi_) + EncodeTwosComp(rhs.rep_hi_));
+ if (rep_lo_ >= kTicksPerSecond - rhs.rep_lo_) {
+ rep_hi_ = DecodeTwosComp(EncodeTwosComp(rep_hi_) + 1);
+ rep_lo_ -= kTicksPerSecond;
+ }
+ rep_lo_ += rhs.rep_lo_;
+ if (rhs.rep_hi_ < 0 ? rep_hi_ > orig_rep_hi : rep_hi_ < orig_rep_hi) {
+ return *this = rhs.rep_hi_ < 0 ? -InfiniteDuration() : InfiniteDuration();
+ }
+ return *this;
+}
+
+Duration& Duration::operator-=(Duration rhs) {
+ if (time_internal::IsInfiniteDuration(*this)) return *this;
+ if (time_internal::IsInfiniteDuration(rhs)) {
+ return *this = rhs.rep_hi_ >= 0 ? -InfiniteDuration() : InfiniteDuration();
+ }
+ const int64_t orig_rep_hi = rep_hi_;
+ rep_hi_ =
+ DecodeTwosComp(EncodeTwosComp(rep_hi_) - EncodeTwosComp(rhs.rep_hi_));
+ if (rep_lo_ < rhs.rep_lo_) {
+ rep_hi_ = DecodeTwosComp(EncodeTwosComp(rep_hi_) - 1);
+ rep_lo_ += kTicksPerSecond;
+ }
+ rep_lo_ -= rhs.rep_lo_;
+ if (rhs.rep_hi_ < 0 ? rep_hi_ < orig_rep_hi : rep_hi_ > orig_rep_hi) {
+ return *this = rhs.rep_hi_ >= 0 ? -InfiniteDuration() : InfiniteDuration();
+ }
+ return *this;
+}
+
+//
+// Multiplicative operators.
+//
+
+Duration& Duration::operator*=(int64_t r) {
+ if (time_internal::IsInfiniteDuration(*this)) {
+ const bool is_neg = (r < 0) != (rep_hi_ < 0);
+ return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
+ }
+ return *this = ScaleFixed<SafeMultiply>(*this, r);
+}
+
+Duration& Duration::operator*=(double r) {
+ if (time_internal::IsInfiniteDuration(*this) || !IsFinite(r)) {
+ const bool is_neg = (std::signbit(r) != 0) != (rep_hi_ < 0);
+ return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
+ }
+ return *this = ScaleDouble<std::multiplies>(*this, r);
+}
+
+Duration& Duration::operator/=(int64_t r) {
+ if (time_internal::IsInfiniteDuration(*this) || r == 0) {
+ const bool is_neg = (r < 0) != (rep_hi_ < 0);
+ return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
+ }
+ return *this = ScaleFixed<std::divides>(*this, r);
+}
+
+Duration& Duration::operator/=(double r) {
+ if (time_internal::IsInfiniteDuration(*this) || r == 0.0) {
+ const bool is_neg = (std::signbit(r) != 0) != (rep_hi_ < 0);
+ return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
+ }
+ return *this = ScaleDouble<std::divides>(*this, r);
+}
+
+Duration& Duration::operator%=(Duration rhs) {
+ time_internal::IDivDuration(false, *this, rhs, this);
+ return *this;
+}
+
+double FDivDuration(Duration num, Duration den) {
+ // Arithmetic with infinity is sticky.
+ if (time_internal::IsInfiniteDuration(num) || den == ZeroDuration()) {
+ return (num < ZeroDuration()) == (den < ZeroDuration())
+ ? std::numeric_limits<double>::infinity()
+ : -std::numeric_limits<double>::infinity();
+ }
+ if (time_internal::IsInfiniteDuration(den)) return 0.0;
+
+ double a =
+ static_cast<double>(time_internal::GetRepHi(num)) * kTicksPerSecond +
+ time_internal::GetRepLo(num);
+ double b =
+ static_cast<double>(time_internal::GetRepHi(den)) * kTicksPerSecond +
+ time_internal::GetRepLo(den);
+ return a / b;
+}
+
+//
+// Trunc/Floor/Ceil.
+//
+
+Duration Trunc(Duration d, Duration unit) {
+ return d - (d % unit);
+}
+
+Duration Floor(const Duration d, const Duration unit) {
+ const absl::Duration td = Trunc(d, unit);
+ return td <= d ? td : td - AbsDuration(unit);
+}
+
+Duration Ceil(const Duration d, const Duration unit) {
+ const absl::Duration td = Trunc(d, unit);
+ return td >= d ? td : td + AbsDuration(unit);
+}
+
+//
+// Factory functions.
+//
+
+Duration DurationFromTimespec(timespec ts) {
+ if (static_cast<uint64_t>(ts.tv_nsec) < 1000 * 1000 * 1000) {
+ int64_t ticks = ts.tv_nsec * kTicksPerNanosecond;
+ return time_internal::MakeDuration(ts.tv_sec, ticks);
+ }
+ return Seconds(ts.tv_sec) + Nanoseconds(ts.tv_nsec);
+}
+
+Duration DurationFromTimeval(timeval tv) {
+ if (static_cast<uint64_t>(tv.tv_usec) < 1000 * 1000) {
+ int64_t ticks = tv.tv_usec * 1000 * kTicksPerNanosecond;
+ return time_internal::MakeDuration(tv.tv_sec, ticks);
+ }
+ return Seconds(tv.tv_sec) + Microseconds(tv.tv_usec);
+}
+
+//
+// Conversion to other duration types.
+//
+
+int64_t ToInt64Nanoseconds(Duration d) {
+ if (time_internal::GetRepHi(d) >= 0 &&
+ time_internal::GetRepHi(d) >> 33 == 0) {
+ return (time_internal::GetRepHi(d) * 1000 * 1000 * 1000) +
+ (time_internal::GetRepLo(d) / kTicksPerNanosecond);
+ }
+ return d / Nanoseconds(1);
+}
+int64_t ToInt64Microseconds(Duration d) {
+ if (time_internal::GetRepHi(d) >= 0 &&
+ time_internal::GetRepHi(d) >> 43 == 0) {
+ return (time_internal::GetRepHi(d) * 1000 * 1000) +
+ (time_internal::GetRepLo(d) / (kTicksPerNanosecond * 1000));
+ }
+ return d / Microseconds(1);
+}
+int64_t ToInt64Milliseconds(Duration d) {
+ if (time_internal::GetRepHi(d) >= 0 &&
+ time_internal::GetRepHi(d) >> 53 == 0) {
+ return (time_internal::GetRepHi(d) * 1000) +
+ (time_internal::GetRepLo(d) / (kTicksPerNanosecond * 1000 * 1000));
+ }
+ return d / Milliseconds(1);
+}
+int64_t ToInt64Seconds(Duration d) {
+ int64_t hi = time_internal::GetRepHi(d);
+ if (time_internal::IsInfiniteDuration(d)) return hi;
+ if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi;
+ return hi;
+}
+int64_t ToInt64Minutes(Duration d) {
+ int64_t hi = time_internal::GetRepHi(d);
+ if (time_internal::IsInfiniteDuration(d)) return hi;
+ if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi;
+ return hi / 60;
+}
+int64_t ToInt64Hours(Duration d) {
+ int64_t hi = time_internal::GetRepHi(d);
+ if (time_internal::IsInfiniteDuration(d)) return hi;
+ if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi;
+ return hi / (60 * 60);
+}
+
+double ToDoubleNanoseconds(Duration d) {
+ return FDivDuration(d, Nanoseconds(1));
+}
+double ToDoubleMicroseconds(Duration d) {
+ return FDivDuration(d, Microseconds(1));
+}
+double ToDoubleMilliseconds(Duration d) {
+ return FDivDuration(d, Milliseconds(1));
+}
+double ToDoubleSeconds(Duration d) {
+ return FDivDuration(d, Seconds(1));
+}
+double ToDoubleMinutes(Duration d) {
+ return FDivDuration(d, Minutes(1));
+}
+double ToDoubleHours(Duration d) {
+ return FDivDuration(d, Hours(1));
+}
+
+timespec ToTimespec(Duration d) {
+ timespec ts;
+ if (!time_internal::IsInfiniteDuration(d)) {
+ int64_t rep_hi = time_internal::GetRepHi(d);
+ uint32_t rep_lo = time_internal::GetRepLo(d);
+ if (rep_hi < 0) {
+ // Tweak the fields so that unsigned division of rep_lo
+ // maps to truncation (towards zero) for the timespec.
+ rep_lo += kTicksPerNanosecond - 1;
+ if (rep_lo >= kTicksPerSecond) {
+ rep_hi += 1;
+ rep_lo -= kTicksPerSecond;
+ }
+ }
+ ts.tv_sec = rep_hi;
+ if (ts.tv_sec == rep_hi) { // no time_t narrowing
+ ts.tv_nsec = rep_lo / kTicksPerNanosecond;
+ return ts;
+ }
+ }
+ if (d >= ZeroDuration()) {
+ ts.tv_sec = std::numeric_limits<time_t>::max();
+ ts.tv_nsec = 1000 * 1000 * 1000 - 1;
+ } else {
+ ts.tv_sec = std::numeric_limits<time_t>::min();
+ ts.tv_nsec = 0;
+ }
+ return ts;
+}
+
+timeval ToTimeval(Duration d) {
+ timeval tv;
+ timespec ts = ToTimespec(d);
+ if (ts.tv_sec < 0) {
+ // Tweak the fields so that positive division of tv_nsec
+ // maps to truncation (towards zero) for the timeval.
+ ts.tv_nsec += 1000 - 1;
+ if (ts.tv_nsec >= 1000 * 1000 * 1000) {
+ ts.tv_sec += 1;
+ ts.tv_nsec -= 1000 * 1000 * 1000;
+ }
+ }
+ tv.tv_sec = ts.tv_sec;
+ if (tv.tv_sec != ts.tv_sec) { // narrowing
+ if (ts.tv_sec < 0) {
+ tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::min();
+ tv.tv_usec = 0;
+ } else {
+ tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::max();
+ tv.tv_usec = 1000 * 1000 - 1;
+ }
+ return tv;
+ }
+ tv.tv_usec = static_cast<int>(ts.tv_nsec / 1000); // suseconds_t
+ return tv;
+}
+
+//
+// To/From std::string formatting.
+//
+
+namespace {
+
+// Formats a positive 64-bit integer in the given field width. Note that
+// it is up to the caller of Format64() to ensure that there is sufficient
+// space before ep to hold the conversion.
+char* Format64(char* ep, int width, int64_t v) {
+ do {
+ --width;
+ *--ep = "0123456789"[v % 10];
+ } while (v /= 10);
+ while (--width >= 0) *--ep = '0'; // zero pad
+ return ep;
+}
+
+// Helpers for FormatDuration() that format 'n' and append it to 'out'
+// followed by the given 'unit'. If 'n' formats to "0", nothing is
+// appended (not even the unit).
+
+// A type that encapsulates how to display a value of a particular unit. For
+// values that are displayed with fractional parts, the precision indicates
+// where to round the value. The precision varies with the display unit because
+// a Duration can hold only quarters of a nanosecond, so displaying information
+// beyond that is just noise.
+//
+// For example, a microsecond value of 42.00025xxxxx should not display beyond 5
+// fractional digits, because it is in the noise of what a Duration can
+// represent.
+struct DisplayUnit {
+ const char* abbr;
+ int prec;
+ double pow10;
+};
+const DisplayUnit kDisplayNano = {"ns", 2, 1e2};
+const DisplayUnit kDisplayMicro = {"us", 5, 1e5};
+const DisplayUnit kDisplayMilli = {"ms", 8, 1e8};
+const DisplayUnit kDisplaySec = {"s", 11, 1e11};
+const DisplayUnit kDisplayMin = {"m", -1, 0.0}; // prec ignored
+const DisplayUnit kDisplayHour = {"h", -1, 0.0}; // prec ignored
+
+void AppendNumberUnit(std::string* out, int64_t n, DisplayUnit unit) {
+ char buf[sizeof("2562047788015216")]; // hours in max duration
+ char* const ep = buf + sizeof(buf);
+ char* bp = Format64(ep, 0, n);
+ if (*bp != '0' || bp + 1 != ep) {
+ out->append(bp, ep - bp);
+ out->append(unit.abbr);
+ }
+}
+
+// Note: unit.prec is limited to double's digits10 value (typically 15) so it
+// always fits in buf[].
+void AppendNumberUnit(std::string* out, double n, DisplayUnit unit) {
+ const int buf_size = std::numeric_limits<double>::digits10;
+ const int prec = std::min(buf_size, unit.prec);
+ char buf[buf_size]; // also large enough to hold integer part
+ char* ep = buf + sizeof(buf);
+ double d = 0;
+ int64_t frac_part = Round(std::modf(n, &d) * unit.pow10);
+ int64_t int_part = d;
+ if (int_part != 0 || frac_part != 0) {
+ char* bp = Format64(ep, 0, int_part); // always < 1000
+ out->append(bp, ep - bp);
+ if (frac_part != 0) {
+ out->push_back('.');
+ bp = Format64(ep, prec, frac_part);
+ while (ep[-1] == '0') --ep;
+ out->append(bp, ep - bp);
+ }
+ out->append(unit.abbr);
+ }
+}
+
+} // namespace
+
+// From Go's doc at http://golang.org/pkg/time/#Duration.String
+// [FormatDuration] returns a std::string representing the duration in the
+// form "72h3m0.5s". Leading zero units are omitted. As a special
+// case, durations less than one second format use a smaller unit
+// (milli-, micro-, or nanoseconds) to ensure that the leading digit
+// is non-zero. The zero duration formats as 0, with no unit.
+std::string FormatDuration(Duration d) {
+ const Duration min_duration = Seconds(kint64min);
+ if (d == min_duration) {
+ // Avoid needing to negate kint64min by directly returning what the
+ // following code should produce in that case.
+ return "-2562047788015215h30m8s";
+ }
+ std::string s;
+ if (d < ZeroDuration()) {
+ s.append("-");
+ d = -d;
+ }
+ if (d == InfiniteDuration()) {
+ s.append("inf");
+ } else if (d < Seconds(1)) {
+ // Special case for durations with a magnitude < 1 second. The duration
+ // is printed as a fraction of a single unit, e.g., "1.2ms".
+ if (d < Microseconds(1)) {
+ AppendNumberUnit(&s, FDivDuration(d, Nanoseconds(1)), kDisplayNano);
+ } else if (d < Milliseconds(1)) {
+ AppendNumberUnit(&s, FDivDuration(d, Microseconds(1)), kDisplayMicro);
+ } else {
+ AppendNumberUnit(&s, FDivDuration(d, Milliseconds(1)), kDisplayMilli);
+ }
+ } else {
+ AppendNumberUnit(&s, IDivDuration(d, Hours(1), &d), kDisplayHour);
+ AppendNumberUnit(&s, IDivDuration(d, Minutes(1), &d), kDisplayMin);
+ AppendNumberUnit(&s, FDivDuration(d, Seconds(1)), kDisplaySec);
+ }
+ if (s.empty() || s == "-") {
+ s = "0";
+ }
+ return s;
+}
+
+namespace {
+
+// A helper for ParseDuration() that parses a leading number from the given
+// std::string and stores the result in *n. The given std::string pointer is modified
+// to point to the first unconsumed char.
+bool ConsumeDurationNumber(const char** start, double* n) {
+ const char* s = *start;
+ char* end = nullptr;
+ errno = 0;
+ *n = strtod(s, &end);
+ *start = end;
+ return !std::isspace(*s) && errno == 0 && end != s && *n >= 0;
+}
+
+// A helper for ParseDuration() that parses a leading unit designator (e.g.,
+// ns, us, ms, s, m, h) from the given std::string and stores the resulting unit
+// in "*unit". The given std::string pointer is modified to point to the first
+// unconsumed char.
+bool ConsumeDurationUnit(const char** start, Duration* unit) {
+ const char *s = *start;
+ bool ok = true;
+ if (strncmp(s, "ns", 2) == 0) {
+ s += 2;
+ *unit = Nanoseconds(1);
+ } else if (strncmp(s, "us", 2) == 0) {
+ s += 2;
+ *unit = Microseconds(1);
+ } else if (strncmp(s, "ms", 2) == 0) {
+ s += 2;
+ *unit = Milliseconds(1);
+ } else if (strncmp(s, "s", 1) == 0) {
+ s += 1;
+ *unit = Seconds(1);
+ } else if (strncmp(s, "m", 1) == 0) {
+ s += 1;
+ *unit = Minutes(1);
+ } else if (strncmp(s, "h", 1) == 0) {
+ s += 1;
+ *unit = Hours(1);
+ } else {
+ ok = false;
+ }
+ *start = s;
+ return ok;
+}
+
+} // namespace
+
+// From Go's doc at http://golang.org/pkg/time/#ParseDuration
+// [ParseDuration] parses a duration std::string. A duration std::string is
+// a possibly signed sequence of decimal numbers, each with optional
+// fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m".
+// Valid time units are "ns", "us" "ms", "s", "m", "h".
+bool ParseDuration(const std::string& dur_string, Duration* d) {
+ const char* start = dur_string.c_str();
+ int sign = 1;
+
+ if (*start == '-' || *start == '+') {
+ sign = *start == '-' ? -1 : 1;
+ ++start;
+ }
+
+ // Can't parse a duration from an empty std::string.
+ if (*start == '\0') {
+ return false;
+ }
+
+ // Special case for a std::string of "0".
+ if (*start == '0' && *(start + 1) == '\0') {
+ *d = ZeroDuration();
+ return true;
+ }
+
+ if (strcmp(start, "inf") == 0) {
+ *d = sign * InfiniteDuration();
+ return true;
+ }
+
+ Duration dur;
+ while (*start != '\0') {
+ double n = 0;
+ Duration unit;
+ if (!ConsumeDurationNumber(&start, &n) ||
+ !ConsumeDurationUnit(&start, &unit)) {
+ return false;
+ }
+ dur += sign * n * unit;
+ }
+ *d = dur;
+ return true;
+}
+
+// TODO(b/63899288) copybara strip once dependencies are removed.
+bool ParseFlag(const std::string& text, Duration* dst, std::string* /* err */) {
+ return ParseDuration(text, dst);
+}
+
+std::string UnparseFlag(Duration d) {
+ return FormatDuration(d);
+}
+
+} // namespace absl
diff --git a/absl/time/duration_test.cc b/absl/time/duration_test.cc
new file mode 100644
index 0000000..eed96e3
--- /dev/null
+++ b/absl/time/duration_test.cc
@@ -0,0 +1,1530 @@
+// 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 <cmath>
+#include <cstdint>
+#include <ctime>
+#include <limits>
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/time/time.h"
+
+namespace {
+
+constexpr int64_t kint64max = std::numeric_limits<int64_t>::max();
+constexpr int64_t kint64min = std::numeric_limits<int64_t>::min();
+
+// Approximates the given number of years. This is only used to make some test
+// code more readable.
+absl::Duration ApproxYears(int64_t n) { return absl::Hours(n) * 365 * 24; }
+
+// A gMock matcher to match timespec values. Use this matcher like:
+// timespec ts1, ts2;
+// EXPECT_THAT(ts1, TimespecMatcher(ts2));
+MATCHER_P(TimespecMatcher, ts, "") {
+ if (ts.tv_sec == arg.tv_sec && ts.tv_nsec == arg.tv_nsec)
+ return true;
+ *result_listener << "expected: {" << ts.tv_sec << ", " << ts.tv_nsec << "} ";
+ *result_listener << "actual: {" << arg.tv_sec << ", " << arg.tv_nsec << "}";
+ return false;
+}
+
+// A gMock matcher to match timeval values. Use this matcher like:
+// timeval tv1, tv2;
+// EXPECT_THAT(tv1, TimevalMatcher(tv2));
+MATCHER_P(TimevalMatcher, tv, "") {
+ if (tv.tv_sec == arg.tv_sec && tv.tv_usec == arg.tv_usec)
+ return true;
+ *result_listener << "expected: {" << tv.tv_sec << ", " << tv.tv_usec << "} ";
+ *result_listener << "actual: {" << arg.tv_sec << ", " << arg.tv_usec << "}";
+ return false;
+}
+
+TEST(Duration, ValueSemantics) {
+ // If this compiles, the test passes.
+ constexpr absl::Duration a; // Default construction
+ constexpr absl::Duration b = a; // Copy construction
+ constexpr absl::Duration c(b); // Copy construction (again)
+
+ absl::Duration d;
+ d = c; // Assignment
+}
+
+TEST(Duration, Factories) {
+ constexpr absl::Duration zero = absl::ZeroDuration();
+ constexpr absl::Duration nano = absl::Nanoseconds(1);
+ constexpr absl::Duration micro = absl::Microseconds(1);
+ constexpr absl::Duration milli = absl::Milliseconds(1);
+ constexpr absl::Duration sec = absl::Seconds(1);
+ constexpr absl::Duration min = absl::Minutes(1);
+ constexpr absl::Duration hour = absl::Hours(1);
+
+ EXPECT_EQ(zero, absl::Duration());
+ EXPECT_EQ(zero, absl::Seconds(0));
+ EXPECT_EQ(nano, absl::Nanoseconds(1));
+ EXPECT_EQ(micro, absl::Nanoseconds(1000));
+ EXPECT_EQ(milli, absl::Microseconds(1000));
+ EXPECT_EQ(sec, absl::Milliseconds(1000));
+ EXPECT_EQ(min, absl::Seconds(60));
+ EXPECT_EQ(hour, absl::Minutes(60));
+
+ // Tests factory limits
+ const absl::Duration inf = absl::InfiniteDuration();
+
+ EXPECT_GT(inf, absl::Seconds(kint64max));
+ EXPECT_LT(-inf, absl::Seconds(kint64min));
+ EXPECT_LT(-inf, absl::Seconds(-kint64max));
+
+ EXPECT_EQ(inf, absl::Minutes(kint64max));
+ EXPECT_EQ(-inf, absl::Minutes(kint64min));
+ EXPECT_EQ(-inf, absl::Minutes(-kint64max));
+ EXPECT_GT(inf, absl::Minutes(kint64max / 60));
+ EXPECT_LT(-inf, absl::Minutes(kint64min / 60));
+ EXPECT_LT(-inf, absl::Minutes(-kint64max / 60));
+
+ EXPECT_EQ(inf, absl::Hours(kint64max));
+ EXPECT_EQ(-inf, absl::Hours(kint64min));
+ EXPECT_EQ(-inf, absl::Hours(-kint64max));
+ EXPECT_GT(inf, absl::Hours(kint64max / 3600));
+ EXPECT_LT(-inf, absl::Hours(kint64min / 3600));
+ EXPECT_LT(-inf, absl::Hours(-kint64max / 3600));
+}
+
+TEST(Duration, ToConversion) {
+#define TEST_DURATION_CONVERSION(UNIT) \
+ do { \
+ const absl::Duration d = absl::UNIT(1.5); \
+ const absl::Duration z = absl::ZeroDuration(); \
+ const absl::Duration inf = absl::InfiniteDuration(); \
+ const double dbl_inf = std::numeric_limits<double>::infinity(); \
+ EXPECT_EQ(kint64min, absl::ToInt64##UNIT(-inf)); \
+ EXPECT_EQ(-1, absl::ToInt64##UNIT(-d)); \
+ EXPECT_EQ(0, absl::ToInt64##UNIT(z)); \
+ EXPECT_EQ(1, absl::ToInt64##UNIT(d)); \
+ EXPECT_EQ(kint64max, absl::ToInt64##UNIT(inf)); \
+ EXPECT_EQ(-dbl_inf, absl::ToDouble##UNIT(-inf)); \
+ EXPECT_EQ(-1.5, absl::ToDouble##UNIT(-d)); \
+ EXPECT_EQ(0, absl::ToDouble##UNIT(z)); \
+ EXPECT_EQ(1.5, absl::ToDouble##UNIT(d)); \
+ EXPECT_EQ(dbl_inf, absl::ToDouble##UNIT(inf)); \
+ } while (0)
+
+ TEST_DURATION_CONVERSION(Nanoseconds);
+ TEST_DURATION_CONVERSION(Microseconds);
+ TEST_DURATION_CONVERSION(Milliseconds);
+ TEST_DURATION_CONVERSION(Seconds);
+ TEST_DURATION_CONVERSION(Minutes);
+ TEST_DURATION_CONVERSION(Hours);
+
+#undef TEST_DURATION_CONVERSION
+}
+
+template <int64_t n>
+void TestToConversion() {
+ constexpr absl::Duration nano = absl::Nanoseconds(n);
+ EXPECT_EQ(n, absl::ToInt64Nanoseconds(nano));
+ EXPECT_EQ(0, absl::ToInt64Microseconds(nano));
+ EXPECT_EQ(0, absl::ToInt64Milliseconds(nano));
+ EXPECT_EQ(0, absl::ToInt64Seconds(nano));
+ EXPECT_EQ(0, absl::ToInt64Minutes(nano));
+ EXPECT_EQ(0, absl::ToInt64Hours(nano));
+ const absl::Duration micro = absl::Microseconds(n);
+ EXPECT_EQ(n * 1000, absl::ToInt64Nanoseconds(micro));
+ EXPECT_EQ(n, absl::ToInt64Microseconds(micro));
+ EXPECT_EQ(0, absl::ToInt64Milliseconds(micro));
+ EXPECT_EQ(0, absl::ToInt64Seconds(micro));
+ EXPECT_EQ(0, absl::ToInt64Minutes(micro));
+ EXPECT_EQ(0, absl::ToInt64Hours(micro));
+ const absl::Duration milli = absl::Milliseconds(n);
+ EXPECT_EQ(n * 1000 * 1000, absl::ToInt64Nanoseconds(milli));
+ EXPECT_EQ(n * 1000, absl::ToInt64Microseconds(milli));
+ EXPECT_EQ(n, absl::ToInt64Milliseconds(milli));
+ EXPECT_EQ(0, absl::ToInt64Seconds(milli));
+ EXPECT_EQ(0, absl::ToInt64Minutes(milli));
+ EXPECT_EQ(0, absl::ToInt64Hours(milli));
+ const absl::Duration sec = absl::Seconds(n);
+ EXPECT_EQ(n * 1000 * 1000 * 1000, absl::ToInt64Nanoseconds(sec));
+ EXPECT_EQ(n * 1000 * 1000, absl::ToInt64Microseconds(sec));
+ EXPECT_EQ(n * 1000, absl::ToInt64Milliseconds(sec));
+ EXPECT_EQ(n, absl::ToInt64Seconds(sec));
+ EXPECT_EQ(0, absl::ToInt64Minutes(sec));
+ EXPECT_EQ(0, absl::ToInt64Hours(sec));
+ const absl::Duration min = absl::Minutes(n);
+ EXPECT_EQ(n * 60 * 1000 * 1000 * 1000, absl::ToInt64Nanoseconds(min));
+ EXPECT_EQ(n * 60 * 1000 * 1000, absl::ToInt64Microseconds(min));
+ EXPECT_EQ(n * 60 * 1000, absl::ToInt64Milliseconds(min));
+ EXPECT_EQ(n * 60, absl::ToInt64Seconds(min));
+ EXPECT_EQ(n, absl::ToInt64Minutes(min));
+ EXPECT_EQ(0, absl::ToInt64Hours(min));
+ const absl::Duration hour = absl::Hours(n);
+ EXPECT_EQ(n * 60 * 60 * 1000 * 1000 * 1000, absl::ToInt64Nanoseconds(hour));
+ EXPECT_EQ(n * 60 * 60 * 1000 * 1000, absl::ToInt64Microseconds(hour));
+ EXPECT_EQ(n * 60 * 60 * 1000, absl::ToInt64Milliseconds(hour));
+ EXPECT_EQ(n * 60 * 60, absl::ToInt64Seconds(hour));
+ EXPECT_EQ(n * 60, absl::ToInt64Minutes(hour));
+ EXPECT_EQ(n, absl::ToInt64Hours(hour));
+}
+
+TEST(Duration, ToConversionDeprecated) {
+ TestToConversion<43>();
+ TestToConversion<1>();
+ TestToConversion<0>();
+ TestToConversion<-1>();
+ TestToConversion<-43>();
+}
+
+// Used for testing the factory overloads.
+template <typename T>
+struct ImplicitlyConvertible {
+ T n_;
+ explicit ImplicitlyConvertible(T n) : n_(n) {}
+ // Marking this conversion operator with 'explicit' will cause the test to
+ // fail (as desired).
+ operator T() { return n_; }
+};
+
+TEST(Duration, FactoryOverloads) {
+#define TEST_FACTORY_OVERLOADS(NAME) \
+ EXPECT_EQ(1, NAME(static_cast<int8_t>(1)) / NAME(1)); \
+ EXPECT_EQ(1, NAME(static_cast<int16_t>(1)) / NAME(1)); \
+ EXPECT_EQ(1, NAME(static_cast<int32_t>(1)) / NAME(1)); \
+ EXPECT_EQ(1, NAME(static_cast<int64_t>(1)) / NAME(1)); \
+ EXPECT_EQ(1, NAME(static_cast<uint8_t>(1)) / NAME(1)); \
+ EXPECT_EQ(1, NAME(static_cast<uint16_t>(1)) / NAME(1)); \
+ EXPECT_EQ(1, NAME(static_cast<uint32_t>(1)) / NAME(1)); \
+ EXPECT_EQ(1, NAME(static_cast<uint64_t>(1)) / NAME(1)); \
+ EXPECT_EQ(1, NAME(ImplicitlyConvertible<int8_t>(1)) / NAME(1)); \
+ EXPECT_EQ(1, NAME(ImplicitlyConvertible<int16_t>(1)) / NAME(1)); \
+ EXPECT_EQ(1, NAME(ImplicitlyConvertible<int32_t>(1)) / NAME(1)); \
+ EXPECT_EQ(1, NAME(ImplicitlyConvertible<int64_t>(1)) / NAME(1)); \
+ EXPECT_EQ(1, NAME(ImplicitlyConvertible<uint8_t>(1)) / NAME(1)); \
+ EXPECT_EQ(1, NAME(ImplicitlyConvertible<uint16_t>(1)) / NAME(1)); \
+ EXPECT_EQ(1, NAME(ImplicitlyConvertible<uint32_t>(1)) / NAME(1)); \
+ EXPECT_EQ(1, NAME(ImplicitlyConvertible<uint64_t>(1)) / NAME(1)); \
+ EXPECT_EQ(NAME(1) / 2, NAME(static_cast<float>(0.5))); \
+ EXPECT_EQ(NAME(1) / 2, NAME(static_cast<double>(0.5))); \
+ EXPECT_EQ(1.5, absl::FDivDuration(NAME(static_cast<float>(1.5)), NAME(1))); \
+ EXPECT_EQ(1.5, absl::FDivDuration(NAME(static_cast<double>(1.5)), NAME(1)));
+
+ TEST_FACTORY_OVERLOADS(absl::Nanoseconds);
+ TEST_FACTORY_OVERLOADS(absl::Microseconds);
+ TEST_FACTORY_OVERLOADS(absl::Milliseconds);
+ TEST_FACTORY_OVERLOADS(absl::Seconds);
+ TEST_FACTORY_OVERLOADS(absl::Minutes);
+ TEST_FACTORY_OVERLOADS(absl::Hours);
+
+#undef TEST_FACTORY_OVERLOADS
+
+ EXPECT_EQ(absl::Milliseconds(1500), absl::Seconds(1.5));
+ EXPECT_LT(absl::Nanoseconds(1), absl::Nanoseconds(1.5));
+ EXPECT_GT(absl::Nanoseconds(2), absl::Nanoseconds(1.5));
+
+ const double dbl_inf = std::numeric_limits<double>::infinity();
+ EXPECT_EQ(absl::InfiniteDuration(), absl::Nanoseconds(dbl_inf));
+ EXPECT_EQ(absl::InfiniteDuration(), absl::Microseconds(dbl_inf));
+ EXPECT_EQ(absl::InfiniteDuration(), absl::Milliseconds(dbl_inf));
+ EXPECT_EQ(absl::InfiniteDuration(), absl::Seconds(dbl_inf));
+ EXPECT_EQ(absl::InfiniteDuration(), absl::Minutes(dbl_inf));
+ EXPECT_EQ(absl::InfiniteDuration(), absl::Hours(dbl_inf));
+ EXPECT_EQ(-absl::InfiniteDuration(), absl::Nanoseconds(-dbl_inf));
+ EXPECT_EQ(-absl::InfiniteDuration(), absl::Microseconds(-dbl_inf));
+ EXPECT_EQ(-absl::InfiniteDuration(), absl::Milliseconds(-dbl_inf));
+ EXPECT_EQ(-absl::InfiniteDuration(), absl::Seconds(-dbl_inf));
+ EXPECT_EQ(-absl::InfiniteDuration(), absl::Minutes(-dbl_inf));
+ EXPECT_EQ(-absl::InfiniteDuration(), absl::Hours(-dbl_inf));
+}
+
+TEST(Duration, InfinityExamples) {
+ // These examples are used in the documentation in //base/time.h. They are
+ // written so that they can be copy-n-pasted easily.
+
+ constexpr absl::Duration inf = absl::InfiniteDuration();
+ constexpr absl::Duration d = absl::Seconds(1); // Any finite duration
+
+ EXPECT_TRUE(inf == inf + inf);
+ EXPECT_TRUE(inf == inf + d);
+ EXPECT_TRUE(inf == inf - inf);
+ EXPECT_TRUE(-inf == d - inf);
+
+ EXPECT_TRUE(inf == d * 1e100);
+ EXPECT_TRUE(0 == d / inf); // NOLINT(readability/check)
+
+ // Division by zero returns infinity, or kint64min/MAX where necessary.
+ EXPECT_TRUE(inf == d / 0);
+ EXPECT_TRUE(kint64max == d / absl::ZeroDuration());
+}
+
+TEST(Duration, InfinityComparison) {
+ const absl::Duration inf = absl::InfiniteDuration();
+ const absl::Duration any_dur = absl::Seconds(1);
+
+ // Equality
+ EXPECT_EQ(inf, inf);
+ EXPECT_EQ(-inf, -inf);
+ EXPECT_NE(inf, -inf);
+ EXPECT_NE(any_dur, inf);
+ EXPECT_NE(any_dur, -inf);
+
+ // Relational
+ EXPECT_GT(inf, any_dur);
+ EXPECT_LT(-inf, any_dur);
+ EXPECT_LT(-inf, inf);
+ EXPECT_GT(inf, -inf);
+}
+
+TEST(Duration, InfinityAddition) {
+ const absl::Duration sec_max = absl::Seconds(kint64max);
+ const absl::Duration sec_min = absl::Seconds(kint64min);
+ const absl::Duration any_dur = absl::Seconds(1);
+ const absl::Duration inf = absl::InfiniteDuration();
+
+ // Addition
+ EXPECT_EQ(inf, inf + inf);
+ EXPECT_EQ(inf, inf + -inf);
+ EXPECT_EQ(-inf, -inf + inf);
+ EXPECT_EQ(-inf, -inf + -inf);
+
+ EXPECT_EQ(inf, inf + any_dur);
+ EXPECT_EQ(inf, any_dur + inf);
+ EXPECT_EQ(-inf, -inf + any_dur);
+ EXPECT_EQ(-inf, any_dur + -inf);
+
+ // Interesting case
+ absl::Duration almost_inf = sec_max + absl::Nanoseconds(999999999);
+ EXPECT_GT(inf, almost_inf);
+ almost_inf += -absl::Nanoseconds(999999999);
+ EXPECT_GT(inf, almost_inf);
+
+ // Addition overflow/underflow
+ EXPECT_EQ(inf, sec_max + absl::Seconds(1));
+ EXPECT_EQ(inf, sec_max + sec_max);
+ EXPECT_EQ(-inf, sec_min + -absl::Seconds(1));
+ EXPECT_EQ(-inf, sec_min + -sec_max);
+
+ // For reference: IEEE 754 behavior
+ const double dbl_inf = std::numeric_limits<double>::infinity();
+ EXPECT_TRUE(isinf(dbl_inf + dbl_inf));
+ EXPECT_TRUE(isnan(dbl_inf + -dbl_inf)); // We return inf
+ EXPECT_TRUE(isnan(-dbl_inf + dbl_inf)); // We return inf
+ EXPECT_TRUE(isinf(-dbl_inf + -dbl_inf));
+}
+
+TEST(Duration, InfinitySubtraction) {
+ const absl::Duration sec_max = absl::Seconds(kint64max);
+ const absl::Duration sec_min = absl::Seconds(kint64min);
+ const absl::Duration any_dur = absl::Seconds(1);
+ const absl::Duration inf = absl::InfiniteDuration();
+
+ // Subtraction
+ EXPECT_EQ(inf, inf - inf);
+ EXPECT_EQ(inf, inf - -inf);
+ EXPECT_EQ(-inf, -inf - inf);
+ EXPECT_EQ(-inf, -inf - -inf);
+
+ EXPECT_EQ(inf, inf - any_dur);
+ EXPECT_EQ(-inf, any_dur - inf);
+ EXPECT_EQ(-inf, -inf - any_dur);
+ EXPECT_EQ(inf, any_dur - -inf);
+
+ // Subtraction overflow/underflow
+ EXPECT_EQ(inf, sec_max - -absl::Seconds(1));
+ EXPECT_EQ(inf, sec_max - -sec_max);
+ EXPECT_EQ(-inf, sec_min - absl::Seconds(1));
+ EXPECT_EQ(-inf, sec_min - sec_max);
+
+ // Interesting case
+ absl::Duration almost_neg_inf = sec_min;
+ EXPECT_LT(-inf, almost_neg_inf);
+ almost_neg_inf -= -absl::Nanoseconds(1);
+ EXPECT_LT(-inf, almost_neg_inf);
+
+ // For reference: IEEE 754 behavior
+ const double dbl_inf = std::numeric_limits<double>::infinity();
+ EXPECT_TRUE(isnan(dbl_inf - dbl_inf)); // We return inf
+ EXPECT_TRUE(isinf(dbl_inf - -dbl_inf));
+ EXPECT_TRUE(isinf(-dbl_inf - dbl_inf));
+ EXPECT_TRUE(isnan(-dbl_inf - -dbl_inf)); // We return inf
+}
+
+TEST(Duration, InfinityMultiplication) {
+ const absl::Duration sec_max = absl::Seconds(kint64max);
+ const absl::Duration sec_min = absl::Seconds(kint64min);
+ const absl::Duration inf = absl::InfiniteDuration();
+
+#define TEST_INF_MUL_WITH_TYPE(T) \
+ EXPECT_EQ(inf, inf * static_cast<T>(2)); \
+ EXPECT_EQ(-inf, inf * static_cast<T>(-2)); \
+ EXPECT_EQ(-inf, -inf * static_cast<T>(2)); \
+ EXPECT_EQ(inf, -inf * static_cast<T>(-2)); \
+ EXPECT_EQ(inf, inf * static_cast<T>(0)); \
+ EXPECT_EQ(-inf, -inf * static_cast<T>(0)); \
+ EXPECT_EQ(inf, sec_max * static_cast<T>(2)); \
+ EXPECT_EQ(inf, sec_min * static_cast<T>(-2)); \
+ EXPECT_EQ(inf, (sec_max / static_cast<T>(2)) * static_cast<T>(3)); \
+ EXPECT_EQ(-inf, sec_max * static_cast<T>(-2)); \
+ EXPECT_EQ(-inf, sec_min * static_cast<T>(2)); \
+ EXPECT_EQ(-inf, (sec_min / static_cast<T>(2)) * static_cast<T>(3));
+
+ TEST_INF_MUL_WITH_TYPE(int64_t); // NOLINT(readability/function)
+ TEST_INF_MUL_WITH_TYPE(double); // NOLINT(readability/function)
+
+#undef TEST_INF_MUL_WITH_TYPE
+
+ const double dbl_inf = std::numeric_limits<double>::infinity();
+ EXPECT_EQ(inf, inf * dbl_inf);
+ EXPECT_EQ(-inf, -inf * dbl_inf);
+ EXPECT_EQ(-inf, inf * -dbl_inf);
+ EXPECT_EQ(inf, -inf * -dbl_inf);
+
+ const absl::Duration any_dur = absl::Seconds(1);
+ EXPECT_EQ(inf, any_dur * dbl_inf);
+ EXPECT_EQ(-inf, -any_dur * dbl_inf);
+ EXPECT_EQ(-inf, any_dur * -dbl_inf);
+ EXPECT_EQ(inf, -any_dur * -dbl_inf);
+
+ // Fixed-point multiplication will produce a finite value, whereas floating
+ // point fuzziness will overflow to inf.
+ EXPECT_NE(absl::InfiniteDuration(), absl::Seconds(1) * kint64max);
+ EXPECT_EQ(inf, absl::Seconds(1) * static_cast<double>(kint64max));
+ EXPECT_NE(-absl::InfiniteDuration(), absl::Seconds(1) * kint64min);
+ EXPECT_EQ(-inf, absl::Seconds(1) * static_cast<double>(kint64min));
+
+ // Note that sec_max * or / by 1.0 overflows to inf due to the 53-bit
+ // limitations of double.
+ EXPECT_NE(inf, sec_max);
+ EXPECT_NE(inf, sec_max / 1);
+ EXPECT_EQ(inf, sec_max / 1.0);
+ EXPECT_NE(inf, sec_max * 1);
+ EXPECT_EQ(inf, sec_max * 1.0);
+}
+
+TEST(Duration, InfinityDivision) {
+ const absl::Duration sec_max = absl::Seconds(kint64max);
+ const absl::Duration sec_min = absl::Seconds(kint64min);
+ const absl::Duration inf = absl::InfiniteDuration();
+
+ // Division of Duration by a double
+#define TEST_INF_DIV_WITH_TYPE(T) \
+ EXPECT_EQ(inf, inf / static_cast<T>(2)); \
+ EXPECT_EQ(-inf, inf / static_cast<T>(-2)); \
+ EXPECT_EQ(-inf, -inf / static_cast<T>(2)); \
+ EXPECT_EQ(inf, -inf / static_cast<T>(-2));
+
+ TEST_INF_DIV_WITH_TYPE(int64_t); // NOLINT(readability/function)
+ TEST_INF_DIV_WITH_TYPE(double); // NOLINT(readability/function)
+
+#undef TEST_INF_DIV_WITH_TYPE
+
+ // Division of Duration by a double overflow/underflow
+ EXPECT_EQ(inf, sec_max / 0.5);
+ EXPECT_EQ(inf, sec_min / -0.5);
+ EXPECT_EQ(inf, ((sec_max / 0.5) + absl::Seconds(1)) / 0.5);
+ EXPECT_EQ(-inf, sec_max / -0.5);
+ EXPECT_EQ(-inf, sec_min / 0.5);
+ EXPECT_EQ(-inf, ((sec_min / 0.5) - absl::Seconds(1)) / 0.5);
+
+ const double dbl_inf = std::numeric_limits<double>::infinity();
+ EXPECT_EQ(inf, inf / dbl_inf);
+ EXPECT_EQ(-inf, inf / -dbl_inf);
+ EXPECT_EQ(-inf, -inf / dbl_inf);
+ EXPECT_EQ(inf, -inf / -dbl_inf);
+
+ const absl::Duration any_dur = absl::Seconds(1);
+ EXPECT_EQ(absl::ZeroDuration(), any_dur / dbl_inf);
+ EXPECT_EQ(absl::ZeroDuration(), any_dur / -dbl_inf);
+ EXPECT_EQ(absl::ZeroDuration(), -any_dur / dbl_inf);
+ EXPECT_EQ(absl::ZeroDuration(), -any_dur / -dbl_inf);
+}
+
+TEST(Duration, InfinityModulus) {
+ const absl::Duration sec_max = absl::Seconds(kint64max);
+ const absl::Duration any_dur = absl::Seconds(1);
+ const absl::Duration inf = absl::InfiniteDuration();
+
+ EXPECT_EQ(inf, inf % inf);
+ EXPECT_EQ(inf, inf % -inf);
+ EXPECT_EQ(-inf, -inf % -inf);
+ EXPECT_EQ(-inf, -inf % inf);
+
+ EXPECT_EQ(any_dur, any_dur % inf);
+ EXPECT_EQ(any_dur, any_dur % -inf);
+ EXPECT_EQ(-any_dur, -any_dur % inf);
+ EXPECT_EQ(-any_dur, -any_dur % -inf);
+
+ EXPECT_EQ(inf, inf % -any_dur);
+ EXPECT_EQ(inf, inf % any_dur);
+ EXPECT_EQ(-inf, -inf % -any_dur);
+ EXPECT_EQ(-inf, -inf % any_dur);
+
+ // Remainder isn't affected by overflow.
+ EXPECT_EQ(absl::ZeroDuration(), sec_max % absl::Seconds(1));
+ EXPECT_EQ(absl::ZeroDuration(), sec_max % absl::Milliseconds(1));
+ EXPECT_EQ(absl::ZeroDuration(), sec_max % absl::Microseconds(1));
+ EXPECT_EQ(absl::ZeroDuration(), sec_max % absl::Nanoseconds(1));
+ EXPECT_EQ(absl::ZeroDuration(), sec_max % absl::Nanoseconds(1) / 4);
+}
+
+TEST(Duration, InfinityIDiv) {
+ const absl::Duration sec_max = absl::Seconds(kint64max);
+ const absl::Duration any_dur = absl::Seconds(1);
+ const absl::Duration inf = absl::InfiniteDuration();
+ const double dbl_inf = std::numeric_limits<double>::infinity();
+
+ // IDivDuration (int64_t return value + a remainer)
+ absl::Duration rem = absl::ZeroDuration();
+ EXPECT_EQ(kint64max, absl::IDivDuration(inf, inf, &rem));
+ EXPECT_EQ(inf, rem);
+
+ rem = absl::ZeroDuration();
+ EXPECT_EQ(kint64max, absl::IDivDuration(-inf, -inf, &rem));
+ EXPECT_EQ(-inf, rem);
+
+ rem = absl::ZeroDuration();
+ EXPECT_EQ(kint64max, absl::IDivDuration(inf, any_dur, &rem));
+ EXPECT_EQ(inf, rem);
+
+ rem = absl::ZeroDuration();
+ EXPECT_EQ(0, absl::IDivDuration(any_dur, inf, &rem));
+ EXPECT_EQ(any_dur, rem);
+
+ rem = absl::ZeroDuration();
+ EXPECT_EQ(kint64max, absl::IDivDuration(-inf, -any_dur, &rem));
+ EXPECT_EQ(-inf, rem);
+
+ rem = absl::ZeroDuration();
+ EXPECT_EQ(0, absl::IDivDuration(-any_dur, -inf, &rem));
+ EXPECT_EQ(-any_dur, rem);
+
+ rem = absl::ZeroDuration();
+ EXPECT_EQ(kint64min, absl::IDivDuration(-inf, inf, &rem));
+ EXPECT_EQ(-inf, rem);
+
+ rem = absl::ZeroDuration();
+ EXPECT_EQ(kint64min, absl::IDivDuration(inf, -inf, &rem));
+ EXPECT_EQ(inf, rem);
+
+ rem = absl::ZeroDuration();
+ EXPECT_EQ(kint64min, absl::IDivDuration(-inf, any_dur, &rem));
+ EXPECT_EQ(-inf, rem);
+
+ rem = absl::ZeroDuration();
+ EXPECT_EQ(0, absl::IDivDuration(-any_dur, inf, &rem));
+ EXPECT_EQ(-any_dur, rem);
+
+ rem = absl::ZeroDuration();
+ EXPECT_EQ(kint64min, absl::IDivDuration(inf, -any_dur, &rem));
+ EXPECT_EQ(inf, rem);
+
+ rem = absl::ZeroDuration();
+ EXPECT_EQ(0, absl::IDivDuration(any_dur, -inf, &rem));
+ EXPECT_EQ(any_dur, rem);
+
+ // IDivDuration overflow/underflow
+ rem = any_dur;
+ EXPECT_EQ(kint64max,
+ absl::IDivDuration(sec_max, absl::Nanoseconds(1) / 4, &rem));
+ EXPECT_EQ(sec_max - absl::Nanoseconds(kint64max) / 4, rem);
+
+ rem = any_dur;
+ EXPECT_EQ(kint64max,
+ absl::IDivDuration(sec_max, absl::Milliseconds(1), &rem));
+ EXPECT_EQ(sec_max - absl::Milliseconds(kint64max), rem);
+
+ rem = any_dur;
+ EXPECT_EQ(kint64max,
+ absl::IDivDuration(-sec_max, -absl::Milliseconds(1), &rem));
+ EXPECT_EQ(-sec_max + absl::Milliseconds(kint64max), rem);
+
+ rem = any_dur;
+ EXPECT_EQ(kint64min,
+ absl::IDivDuration(-sec_max, absl::Milliseconds(1), &rem));
+ EXPECT_EQ(-sec_max - absl::Milliseconds(kint64min), rem);
+
+ rem = any_dur;
+ EXPECT_EQ(kint64min,
+ absl::IDivDuration(sec_max, -absl::Milliseconds(1), &rem));
+ EXPECT_EQ(sec_max + absl::Milliseconds(kint64min), rem);
+
+ //
+ // operator/(Duration, Duration) is a wrapper for IDivDuration().
+ //
+
+ // IEEE 754 says inf / inf should be nan, but int64_t doesn't have
+ // nan so we'll return kint64max/kint64min instead.
+ EXPECT_TRUE(isnan(dbl_inf / dbl_inf));
+ EXPECT_EQ(kint64max, inf / inf);
+ EXPECT_EQ(kint64max, -inf / -inf);
+ EXPECT_EQ(kint64min, -inf / inf);
+ EXPECT_EQ(kint64min, inf / -inf);
+
+ EXPECT_TRUE(isinf(dbl_inf / 2.0));
+ EXPECT_EQ(kint64max, inf / any_dur);
+ EXPECT_EQ(kint64max, -inf / -any_dur);
+ EXPECT_EQ(kint64min, -inf / any_dur);
+ EXPECT_EQ(kint64min, inf / -any_dur);
+
+ EXPECT_EQ(0.0, 2.0 / dbl_inf);
+ EXPECT_EQ(0, any_dur / inf);
+ EXPECT_EQ(0, any_dur / -inf);
+ EXPECT_EQ(0, -any_dur / inf);
+ EXPECT_EQ(0, -any_dur / -inf);
+ EXPECT_EQ(0, absl::ZeroDuration() / inf);
+
+ // Division of Duration by a Duration overflow/underflow
+ EXPECT_EQ(kint64max, sec_max / absl::Milliseconds(1));
+ EXPECT_EQ(kint64max, -sec_max / -absl::Milliseconds(1));
+ EXPECT_EQ(kint64min, -sec_max / absl::Milliseconds(1));
+ EXPECT_EQ(kint64min, sec_max / -absl::Milliseconds(1));
+}
+
+TEST(Duration, InfinityFDiv) {
+ const absl::Duration any_dur = absl::Seconds(1);
+ const absl::Duration inf = absl::InfiniteDuration();
+ const double dbl_inf = std::numeric_limits<double>::infinity();
+
+ EXPECT_EQ(dbl_inf, absl::FDivDuration(inf, inf));
+ EXPECT_EQ(dbl_inf, absl::FDivDuration(-inf, -inf));
+ EXPECT_EQ(dbl_inf, absl::FDivDuration(inf, any_dur));
+ EXPECT_EQ(0.0, absl::FDivDuration(any_dur, inf));
+ EXPECT_EQ(dbl_inf, absl::FDivDuration(-inf, -any_dur));
+ EXPECT_EQ(0.0, absl::FDivDuration(-any_dur, -inf));
+
+ EXPECT_EQ(-dbl_inf, absl::FDivDuration(-inf, inf));
+ EXPECT_EQ(-dbl_inf, absl::FDivDuration(inf, -inf));
+ EXPECT_EQ(-dbl_inf, absl::FDivDuration(-inf, any_dur));
+ EXPECT_EQ(0.0, absl::FDivDuration(-any_dur, inf));
+ EXPECT_EQ(-dbl_inf, absl::FDivDuration(inf, -any_dur));
+ EXPECT_EQ(0.0, absl::FDivDuration(any_dur, -inf));
+}
+
+TEST(Duration, DivisionByZero) {
+ const absl::Duration zero = absl::ZeroDuration();
+ const absl::Duration inf = absl::InfiniteDuration();
+ const absl::Duration any_dur = absl::Seconds(1);
+ const double dbl_inf = std::numeric_limits<double>::infinity();
+ const double dbl_denorm = std::numeric_limits<double>::denorm_min();
+
+ // IEEE 754 behavior
+ double z = 0.0, two = 2.0;
+ EXPECT_TRUE(isinf(two / z));
+ EXPECT_TRUE(isnan(z / z)); // We'll return inf
+
+ // Operator/(Duration, double)
+ EXPECT_EQ(inf, zero / 0.0);
+ EXPECT_EQ(-inf, zero / -0.0);
+ EXPECT_EQ(inf, any_dur / 0.0);
+ EXPECT_EQ(-inf, any_dur / -0.0);
+ EXPECT_EQ(-inf, -any_dur / 0.0);
+ EXPECT_EQ(inf, -any_dur / -0.0);
+
+ // Tests dividing by a number very close to, but not quite zero.
+ EXPECT_EQ(zero, zero / dbl_denorm);
+ EXPECT_EQ(zero, zero / -dbl_denorm);
+ EXPECT_EQ(inf, any_dur / dbl_denorm);
+ EXPECT_EQ(-inf, any_dur / -dbl_denorm);
+ EXPECT_EQ(-inf, -any_dur / dbl_denorm);
+ EXPECT_EQ(inf, -any_dur / -dbl_denorm);
+
+ // IDiv
+ absl::Duration rem = zero;
+ EXPECT_EQ(kint64max, absl::IDivDuration(zero, zero, &rem));
+ EXPECT_EQ(inf, rem);
+
+ rem = zero;
+ EXPECT_EQ(kint64max, absl::IDivDuration(any_dur, zero, &rem));
+ EXPECT_EQ(inf, rem);
+
+ rem = zero;
+ EXPECT_EQ(kint64min, absl::IDivDuration(-any_dur, zero, &rem));
+ EXPECT_EQ(-inf, rem);
+
+ // Operator/(Duration, Duration)
+ EXPECT_EQ(kint64max, zero / zero);
+ EXPECT_EQ(kint64max, any_dur / zero);
+ EXPECT_EQ(kint64min, -any_dur / zero);
+
+ // FDiv
+ EXPECT_EQ(dbl_inf, absl::FDivDuration(zero, zero));
+ EXPECT_EQ(dbl_inf, absl::FDivDuration(any_dur, zero));
+ EXPECT_EQ(-dbl_inf, absl::FDivDuration(-any_dur, zero));
+}
+
+TEST(Duration, Range) {
+ const absl::Duration range = ApproxYears(100 * 1e9);
+ const absl::Duration range_future = range;
+ const absl::Duration range_past = -range;
+
+ EXPECT_LT(range_future, absl::InfiniteDuration());
+ EXPECT_GT(range_past, -absl::InfiniteDuration());
+
+ const absl::Duration full_range = range_future - range_past;
+ EXPECT_GT(full_range, absl::ZeroDuration());
+ EXPECT_LT(full_range, absl::InfiniteDuration());
+
+ const absl::Duration neg_full_range = range_past - range_future;
+ EXPECT_LT(neg_full_range, absl::ZeroDuration());
+ EXPECT_GT(neg_full_range, -absl::InfiniteDuration());
+
+ EXPECT_LT(neg_full_range, full_range);
+ EXPECT_EQ(neg_full_range, -full_range);
+}
+
+TEST(Duration, RelationalOperators) {
+#define TEST_REL_OPS(UNIT) \
+ static_assert(UNIT(2) == UNIT(2), ""); \
+ static_assert(UNIT(1) != UNIT(2), ""); \
+ static_assert(UNIT(1) < UNIT(2), ""); \
+ static_assert(UNIT(3) > UNIT(2), ""); \
+ static_assert(UNIT(1) <= UNIT(2), ""); \
+ static_assert(UNIT(2) <= UNIT(2), ""); \
+ static_assert(UNIT(3) >= UNIT(2), ""); \
+ static_assert(UNIT(2) >= UNIT(2), "");
+
+ TEST_REL_OPS(absl::Nanoseconds);
+ TEST_REL_OPS(absl::Microseconds);
+ TEST_REL_OPS(absl::Milliseconds);
+ TEST_REL_OPS(absl::Seconds);
+ TEST_REL_OPS(absl::Minutes);
+ TEST_REL_OPS(absl::Hours);
+
+#undef TEST_REL_OPS
+}
+
+TEST(Duration, Addition) {
+#define TEST_ADD_OPS(UNIT) \
+ do { \
+ EXPECT_EQ(UNIT(2), UNIT(1) + UNIT(1)); \
+ EXPECT_EQ(UNIT(1), UNIT(2) - UNIT(1)); \
+ EXPECT_EQ(UNIT(0), UNIT(2) - UNIT(2)); \
+ EXPECT_EQ(UNIT(-1), UNIT(1) - UNIT(2)); \
+ EXPECT_EQ(UNIT(-2), UNIT(0) - UNIT(2)); \
+ EXPECT_EQ(UNIT(-2), UNIT(1) - UNIT(3)); \
+ absl::Duration a = UNIT(1); \
+ a += UNIT(1); \
+ EXPECT_EQ(UNIT(2), a); \
+ a -= UNIT(1); \
+ EXPECT_EQ(UNIT(1), a); \
+ } while (0)
+
+ TEST_ADD_OPS(absl::Nanoseconds);
+ TEST_ADD_OPS(absl::Microseconds);
+ TEST_ADD_OPS(absl::Milliseconds);
+ TEST_ADD_OPS(absl::Seconds);
+ TEST_ADD_OPS(absl::Minutes);
+ TEST_ADD_OPS(absl::Hours);
+
+#undef TEST_ADD_OPS
+
+ EXPECT_EQ(absl::Seconds(2), absl::Seconds(3) - 2 * absl::Milliseconds(500));
+ EXPECT_EQ(absl::Seconds(2) + absl::Milliseconds(500),
+ absl::Seconds(3) - absl::Milliseconds(500));
+
+ EXPECT_EQ(absl::Seconds(1) + absl::Milliseconds(998),
+ absl::Milliseconds(999) + absl::Milliseconds(999));
+
+ EXPECT_EQ(absl::Milliseconds(-1),
+ absl::Milliseconds(998) - absl::Milliseconds(999));
+
+ // Tests fractions of a nanoseconds. These are implementation details only.
+ EXPECT_GT(absl::Nanoseconds(1), absl::Nanoseconds(1) / 2);
+ EXPECT_EQ(absl::Nanoseconds(1),
+ absl::Nanoseconds(1) / 2 + absl::Nanoseconds(1) / 2);
+ EXPECT_GT(absl::Nanoseconds(1) / 4, absl::Nanoseconds(0));
+ EXPECT_EQ(absl::Nanoseconds(1) / 8, absl::Nanoseconds(0));
+
+ // Tests subtraction that will cause wrap around of the rep_lo_ bits.
+ absl::Duration d_7_5 = absl::Seconds(7) + absl::Milliseconds(500);
+ absl::Duration d_3_7 = absl::Seconds(3) + absl::Milliseconds(700);
+ absl::Duration ans_3_8 = absl::Seconds(3) + absl::Milliseconds(800);
+ EXPECT_EQ(ans_3_8, d_7_5 - d_3_7);
+
+ // Subtracting min_duration
+ absl::Duration min_dur = absl::Seconds(kint64min);
+ EXPECT_EQ(absl::Seconds(0), min_dur - min_dur);
+ EXPECT_EQ(absl::Seconds(kint64max), absl::Seconds(-1) - min_dur);
+}
+
+TEST(Duration, Negation) {
+ // By storing negations of various values in constexpr variables we
+ // verify that the initializers are constant expressions.
+ constexpr absl::Duration negated_zero_duration = -absl::ZeroDuration();
+ EXPECT_EQ(negated_zero_duration, absl::ZeroDuration());
+
+ constexpr absl::Duration negated_infinite_duration =
+ -absl::InfiniteDuration();
+ EXPECT_NE(negated_infinite_duration, absl::InfiniteDuration());
+ EXPECT_EQ(-negated_infinite_duration, absl::InfiniteDuration());
+
+ // The public APIs to check if a duration is infinite depend on using
+ // -InfiniteDuration(), but we're trying to test operator- here, so we
+ // need to use the lower-level internal query IsInfiniteDuration.
+ EXPECT_TRUE(
+ absl::time_internal::IsInfiniteDuration(negated_infinite_duration));
+
+ // The largest Duration is kint64max seconds and kTicksPerSecond - 1 ticks.
+ // Using the absl::time_internal::MakeDuration API is the cleanest way to
+ // construct that Duration.
+ constexpr absl::Duration max_duration = absl::time_internal::MakeDuration(
+ kint64max, absl::time_internal::kTicksPerSecond - 1);
+ constexpr absl::Duration negated_max_duration = -max_duration;
+ // The largest negatable value is one tick above the minimum representable;
+ // it's the negation of max_duration.
+ constexpr absl::Duration nearly_min_duration =
+ absl::time_internal::MakeDuration(kint64min, int64_t{1});
+ constexpr absl::Duration negated_nearly_min_duration = -nearly_min_duration;
+
+ EXPECT_EQ(negated_max_duration, nearly_min_duration);
+ EXPECT_EQ(negated_nearly_min_duration, max_duration);
+ EXPECT_EQ(-(-max_duration), max_duration);
+
+ constexpr absl::Duration min_duration =
+ absl::time_internal::MakeDuration(kint64min);
+ constexpr absl::Duration negated_min_duration = -min_duration;
+ EXPECT_EQ(negated_min_duration, absl::InfiniteDuration());
+}
+
+TEST(Duration, AbsoluteValue) {
+ EXPECT_EQ(absl::ZeroDuration(), AbsDuration(absl::ZeroDuration()));
+ EXPECT_EQ(absl::Seconds(1), AbsDuration(absl::Seconds(1)));
+ EXPECT_EQ(absl::Seconds(1), AbsDuration(absl::Seconds(-1)));
+
+ EXPECT_EQ(absl::InfiniteDuration(), AbsDuration(absl::InfiniteDuration()));
+ EXPECT_EQ(absl::InfiniteDuration(), AbsDuration(-absl::InfiniteDuration()));
+
+ absl::Duration max_dur =
+ absl::Seconds(kint64max) + (absl::Seconds(1) - absl::Nanoseconds(1) / 4);
+ EXPECT_EQ(max_dur, AbsDuration(max_dur));
+
+ absl::Duration min_dur = absl::Seconds(kint64min);
+ EXPECT_EQ(absl::InfiniteDuration(), AbsDuration(min_dur));
+ EXPECT_EQ(max_dur, AbsDuration(min_dur + absl::Nanoseconds(1) / 4));
+}
+
+TEST(Duration, Multiplication) {
+#define TEST_MUL_OPS(UNIT) \
+ do { \
+ EXPECT_EQ(UNIT(5), UNIT(2) * 2.5); \
+ EXPECT_EQ(UNIT(2), UNIT(5) / 2.5); \
+ EXPECT_EQ(UNIT(-5), UNIT(-2) * 2.5); \
+ EXPECT_EQ(UNIT(-5), -UNIT(2) * 2.5); \
+ EXPECT_EQ(UNIT(-5), UNIT(2) * -2.5); \
+ EXPECT_EQ(UNIT(-2), UNIT(-5) / 2.5); \
+ EXPECT_EQ(UNIT(-2), -UNIT(5) / 2.5); \
+ EXPECT_EQ(UNIT(-2), UNIT(5) / -2.5); \
+ EXPECT_EQ(UNIT(2), UNIT(11) % UNIT(3)); \
+ absl::Duration a = UNIT(2); \
+ a *= 2.5; \
+ EXPECT_EQ(UNIT(5), a); \
+ a /= 2.5; \
+ EXPECT_EQ(UNIT(2), a); \
+ a %= UNIT(1); \
+ EXPECT_EQ(UNIT(0), a); \
+ absl::Duration big = UNIT(1000000000); \
+ big *= 3; \
+ big /= 3; \
+ EXPECT_EQ(UNIT(1000000000), big); \
+ EXPECT_EQ(-UNIT(2), -UNIT(2)); \
+ EXPECT_EQ(-UNIT(2), UNIT(2) * -1); \
+ EXPECT_EQ(-UNIT(2), -1 * UNIT(2)); \
+ EXPECT_EQ(-UNIT(-2), UNIT(2)); \
+ EXPECT_EQ(2, UNIT(2) / UNIT(1)); \
+ absl::Duration rem; \
+ EXPECT_EQ(2, absl::IDivDuration(UNIT(2), UNIT(1), &rem)); \
+ EXPECT_EQ(2.0, absl::FDivDuration(UNIT(2), UNIT(1))); \
+ } while (0)
+
+ TEST_MUL_OPS(absl::Nanoseconds);
+ TEST_MUL_OPS(absl::Microseconds);
+ TEST_MUL_OPS(absl::Milliseconds);
+ TEST_MUL_OPS(absl::Seconds);
+ TEST_MUL_OPS(absl::Minutes);
+ TEST_MUL_OPS(absl::Hours);
+
+#undef TEST_MUL_OPS
+
+ // Ensures that multiplication and division by 1 with a maxed-out durations
+ // doesn't lose precision.
+ absl::Duration max_dur =
+ absl::Seconds(kint64max) + (absl::Seconds(1) - absl::Nanoseconds(1) / 4);
+ absl::Duration min_dur = absl::Seconds(kint64min);
+ EXPECT_EQ(max_dur, max_dur * 1);
+ EXPECT_EQ(max_dur, max_dur / 1);
+ EXPECT_EQ(min_dur, min_dur * 1);
+ EXPECT_EQ(min_dur, min_dur / 1);
+
+ // Tests division on a Duration with a large number of significant digits.
+ // Tests when the digits span hi and lo as well as only in hi.
+ absl::Duration sigfigs = absl::Seconds(2000000000) + absl::Nanoseconds(3);
+ EXPECT_EQ(absl::Seconds(666666666) + absl::Nanoseconds(666666667) +
+ absl::Nanoseconds(1) / 2,
+ sigfigs / 3);
+ sigfigs = absl::Seconds(7000000000LL);
+ EXPECT_EQ(absl::Seconds(2333333333) + absl::Nanoseconds(333333333) +
+ absl::Nanoseconds(1) / 4,
+ sigfigs / 3);
+
+ EXPECT_EQ(absl::Seconds(7) + absl::Milliseconds(500), absl::Seconds(3) * 2.5);
+ EXPECT_EQ(absl::Seconds(8) * -1 + absl::Milliseconds(300),
+ (absl::Seconds(2) + absl::Milliseconds(200)) * -3.5);
+ EXPECT_EQ(-absl::Seconds(8) + absl::Milliseconds(300),
+ (absl::Seconds(2) + absl::Milliseconds(200)) * -3.5);
+ EXPECT_EQ(absl::Seconds(1) + absl::Milliseconds(875),
+ (absl::Seconds(7) + absl::Milliseconds(500)) / 4);
+ EXPECT_EQ(absl::Seconds(30),
+ (absl::Seconds(7) + absl::Milliseconds(500)) / 0.25);
+ EXPECT_EQ(absl::Seconds(3),
+ (absl::Seconds(7) + absl::Milliseconds(500)) / 2.5);
+
+ // Tests division remainder.
+ EXPECT_EQ(absl::Nanoseconds(0), absl::Nanoseconds(7) % absl::Nanoseconds(1));
+ EXPECT_EQ(absl::Nanoseconds(0), absl::Nanoseconds(0) % absl::Nanoseconds(10));
+ EXPECT_EQ(absl::Nanoseconds(2), absl::Nanoseconds(7) % absl::Nanoseconds(5));
+ EXPECT_EQ(absl::Nanoseconds(2), absl::Nanoseconds(2) % absl::Nanoseconds(5));
+
+ EXPECT_EQ(absl::Nanoseconds(1), absl::Nanoseconds(10) % absl::Nanoseconds(3));
+ EXPECT_EQ(absl::Nanoseconds(1),
+ absl::Nanoseconds(10) % absl::Nanoseconds(-3));
+ EXPECT_EQ(absl::Nanoseconds(-1),
+ absl::Nanoseconds(-10) % absl::Nanoseconds(3));
+ EXPECT_EQ(absl::Nanoseconds(-1),
+ absl::Nanoseconds(-10) % absl::Nanoseconds(-3));
+
+ EXPECT_EQ(absl::Milliseconds(100),
+ absl::Seconds(1) % absl::Milliseconds(300));
+ EXPECT_EQ(
+ absl::Milliseconds(300),
+ (absl::Seconds(3) + absl::Milliseconds(800)) % absl::Milliseconds(500));
+
+ EXPECT_EQ(absl::Nanoseconds(1), absl::Nanoseconds(1) % absl::Seconds(1));
+ EXPECT_EQ(absl::Nanoseconds(-1), absl::Nanoseconds(-1) % absl::Seconds(1));
+ EXPECT_EQ(0, absl::Nanoseconds(-1) / absl::Seconds(1)); // Actual -1e-9
+
+ // Tests identity a = (a/b)*b + a%b
+#define TEST_MOD_IDENTITY(a, b) \
+ EXPECT_EQ((a), ((a) / (b))*(b) + ((a)%(b)))
+
+ TEST_MOD_IDENTITY(absl::Seconds(0), absl::Seconds(2));
+ TEST_MOD_IDENTITY(absl::Seconds(1), absl::Seconds(1));
+ TEST_MOD_IDENTITY(absl::Seconds(1), absl::Seconds(2));
+ TEST_MOD_IDENTITY(absl::Seconds(2), absl::Seconds(1));
+
+ TEST_MOD_IDENTITY(absl::Seconds(-2), absl::Seconds(1));
+ TEST_MOD_IDENTITY(absl::Seconds(2), absl::Seconds(-1));
+ TEST_MOD_IDENTITY(absl::Seconds(-2), absl::Seconds(-1));
+
+ TEST_MOD_IDENTITY(absl::Nanoseconds(0), absl::Nanoseconds(2));
+ TEST_MOD_IDENTITY(absl::Nanoseconds(1), absl::Nanoseconds(1));
+ TEST_MOD_IDENTITY(absl::Nanoseconds(1), absl::Nanoseconds(2));
+ TEST_MOD_IDENTITY(absl::Nanoseconds(2), absl::Nanoseconds(1));
+
+ TEST_MOD_IDENTITY(absl::Nanoseconds(-2), absl::Nanoseconds(1));
+ TEST_MOD_IDENTITY(absl::Nanoseconds(2), absl::Nanoseconds(-1));
+ TEST_MOD_IDENTITY(absl::Nanoseconds(-2), absl::Nanoseconds(-1));
+
+ // Mixed seconds + subseconds
+ absl::Duration mixed_a = absl::Seconds(1) + absl::Nanoseconds(2);
+ absl::Duration mixed_b = absl::Seconds(1) + absl::Nanoseconds(3);
+
+ TEST_MOD_IDENTITY(absl::Seconds(0), mixed_a);
+ TEST_MOD_IDENTITY(mixed_a, mixed_a);
+ TEST_MOD_IDENTITY(mixed_a, mixed_b);
+ TEST_MOD_IDENTITY(mixed_b, mixed_a);
+
+ TEST_MOD_IDENTITY(-mixed_a, mixed_b);
+ TEST_MOD_IDENTITY(mixed_a, -mixed_b);
+ TEST_MOD_IDENTITY(-mixed_a, -mixed_b);
+
+#undef TEST_MOD_IDENTITY
+}
+
+TEST(Duration, Truncation) {
+ const absl::Duration d = absl::Nanoseconds(1234567890);
+ const absl::Duration inf = absl::InfiniteDuration();
+ for (int unit_sign : {1, -1}) { // sign shouldn't matter
+ EXPECT_EQ(absl::Nanoseconds(1234567890),
+ Trunc(d, unit_sign * absl::Nanoseconds(1)));
+ EXPECT_EQ(absl::Microseconds(1234567),
+ Trunc(d, unit_sign * absl::Microseconds(1)));
+ EXPECT_EQ(absl::Milliseconds(1234),
+ Trunc(d, unit_sign * absl::Milliseconds(1)));
+ EXPECT_EQ(absl::Seconds(1), Trunc(d, unit_sign * absl::Seconds(1)));
+ EXPECT_EQ(inf, Trunc(inf, unit_sign * absl::Seconds(1)));
+
+ EXPECT_EQ(absl::Nanoseconds(-1234567890),
+ Trunc(-d, unit_sign * absl::Nanoseconds(1)));
+ EXPECT_EQ(absl::Microseconds(-1234567),
+ Trunc(-d, unit_sign * absl::Microseconds(1)));
+ EXPECT_EQ(absl::Milliseconds(-1234),
+ Trunc(-d, unit_sign * absl::Milliseconds(1)));
+ EXPECT_EQ(absl::Seconds(-1), Trunc(-d, unit_sign * absl::Seconds(1)));
+ EXPECT_EQ(-inf, Trunc(-inf, unit_sign * absl::Seconds(1)));
+ }
+}
+
+TEST(Duration, Flooring) {
+ const absl::Duration d = absl::Nanoseconds(1234567890);
+ const absl::Duration inf = absl::InfiniteDuration();
+ for (int unit_sign : {1, -1}) { // sign shouldn't matter
+ EXPECT_EQ(absl::Nanoseconds(1234567890),
+ absl::Floor(d, unit_sign * absl::Nanoseconds(1)));
+ EXPECT_EQ(absl::Microseconds(1234567),
+ absl::Floor(d, unit_sign * absl::Microseconds(1)));
+ EXPECT_EQ(absl::Milliseconds(1234),
+ absl::Floor(d, unit_sign * absl::Milliseconds(1)));
+ EXPECT_EQ(absl::Seconds(1), absl::Floor(d, unit_sign * absl::Seconds(1)));
+ EXPECT_EQ(inf, absl::Floor(inf, unit_sign * absl::Seconds(1)));
+
+ EXPECT_EQ(absl::Nanoseconds(-1234567890),
+ absl::Floor(-d, unit_sign * absl::Nanoseconds(1)));
+ EXPECT_EQ(absl::Microseconds(-1234568),
+ absl::Floor(-d, unit_sign * absl::Microseconds(1)));
+ EXPECT_EQ(absl::Milliseconds(-1235),
+ absl::Floor(-d, unit_sign * absl::Milliseconds(1)));
+ EXPECT_EQ(absl::Seconds(-2), absl::Floor(-d, unit_sign * absl::Seconds(1)));
+ EXPECT_EQ(-inf, absl::Floor(-inf, unit_sign * absl::Seconds(1)));
+ }
+}
+
+TEST(Duration, Ceiling) {
+ const absl::Duration d = absl::Nanoseconds(1234567890);
+ const absl::Duration inf = absl::InfiniteDuration();
+ for (int unit_sign : {1, -1}) { // // sign shouldn't matter
+ EXPECT_EQ(absl::Nanoseconds(1234567890),
+ absl::Ceil(d, unit_sign * absl::Nanoseconds(1)));
+ EXPECT_EQ(absl::Microseconds(1234568),
+ absl::Ceil(d, unit_sign * absl::Microseconds(1)));
+ EXPECT_EQ(absl::Milliseconds(1235),
+ absl::Ceil(d, unit_sign * absl::Milliseconds(1)));
+ EXPECT_EQ(absl::Seconds(2), absl::Ceil(d, unit_sign * absl::Seconds(1)));
+ EXPECT_EQ(inf, absl::Ceil(inf, unit_sign * absl::Seconds(1)));
+
+ EXPECT_EQ(absl::Nanoseconds(-1234567890),
+ absl::Ceil(-d, unit_sign * absl::Nanoseconds(1)));
+ EXPECT_EQ(absl::Microseconds(-1234567),
+ absl::Ceil(-d, unit_sign * absl::Microseconds(1)));
+ EXPECT_EQ(absl::Milliseconds(-1234),
+ absl::Ceil(-d, unit_sign * absl::Milliseconds(1)));
+ EXPECT_EQ(absl::Seconds(-1), absl::Ceil(-d, unit_sign * absl::Seconds(1)));
+ EXPECT_EQ(-inf, absl::Ceil(-inf, unit_sign * absl::Seconds(1)));
+ }
+}
+
+TEST(Duration, RoundTripUnits) {
+ const int kRange = 100000;
+
+#define ROUND_TRIP_UNIT(U, LOW, HIGH) \
+ do { \
+ for (int64_t i = LOW; i < HIGH; ++i) { \
+ absl::Duration d = absl::U(i); \
+ if (d == absl::InfiniteDuration()) \
+ EXPECT_EQ(kint64max, d / absl::U(1)); \
+ else if (d == -absl::InfiniteDuration()) \
+ EXPECT_EQ(kint64min, d / absl::U(1)); \
+ else \
+ EXPECT_EQ(i, absl::U(i) / absl::U(1)); \
+ } \
+ } while (0)
+
+ ROUND_TRIP_UNIT(Nanoseconds, kint64min, kint64min + kRange);
+ ROUND_TRIP_UNIT(Nanoseconds, -kRange, kRange);
+ ROUND_TRIP_UNIT(Nanoseconds, kint64max - kRange, kint64max);
+
+ ROUND_TRIP_UNIT(Microseconds, kint64min, kint64min + kRange);
+ ROUND_TRIP_UNIT(Microseconds, -kRange, kRange);
+ ROUND_TRIP_UNIT(Microseconds, kint64max - kRange, kint64max);
+
+ ROUND_TRIP_UNIT(Milliseconds, kint64min, kint64min + kRange);
+ ROUND_TRIP_UNIT(Milliseconds, -kRange, kRange);
+ ROUND_TRIP_UNIT(Milliseconds, kint64max - kRange, kint64max);
+
+ ROUND_TRIP_UNIT(Seconds, kint64min, kint64min + kRange);
+ ROUND_TRIP_UNIT(Seconds, -kRange, kRange);
+ ROUND_TRIP_UNIT(Seconds, kint64max - kRange, kint64max);
+
+ ROUND_TRIP_UNIT(Minutes, kint64min / 60, kint64min / 60 + kRange);
+ ROUND_TRIP_UNIT(Minutes, -kRange, kRange);
+ ROUND_TRIP_UNIT(Minutes, kint64max / 60 - kRange, kint64max / 60);
+
+ ROUND_TRIP_UNIT(Hours, kint64min / 3600, kint64min / 3600 + kRange);
+ ROUND_TRIP_UNIT(Hours, -kRange, kRange);
+ ROUND_TRIP_UNIT(Hours, kint64max / 3600 - kRange, kint64max / 3600);
+
+#undef ROUND_TRIP_UNIT
+}
+
+TEST(Duration, TruncConversions) {
+ // Tests ToTimespec()/DurationFromTimespec()
+ const struct {
+ absl::Duration d;
+ timespec ts;
+ } to_ts[] = {
+ {absl::Seconds(1) + absl::Nanoseconds(1), {1, 1}},
+ {absl::Seconds(1) + absl::Nanoseconds(1) / 2, {1, 0}},
+ {absl::Seconds(1) + absl::Nanoseconds(0), {1, 0}},
+ {absl::Seconds(0) + absl::Nanoseconds(0), {0, 0}},
+ {absl::Seconds(0) - absl::Nanoseconds(1) / 2, {0, 0}},
+ {absl::Seconds(0) - absl::Nanoseconds(1), {-1, 999999999}},
+ {absl::Seconds(-1) + absl::Nanoseconds(1), {-1, 1}},
+ {absl::Seconds(-1) + absl::Nanoseconds(1) / 2, {-1, 1}},
+ {absl::Seconds(-1) + absl::Nanoseconds(0), {-1, 0}},
+ {absl::Seconds(-1) - absl::Nanoseconds(1) / 2, {-1, 0}},
+ };
+ for (const auto& test : to_ts) {
+ EXPECT_THAT(absl::ToTimespec(test.d), TimespecMatcher(test.ts));
+ }
+ const struct {
+ timespec ts;
+ absl::Duration d;
+ } from_ts[] = {
+ {{1, 1}, absl::Seconds(1) + absl::Nanoseconds(1)},
+ {{1, 0}, absl::Seconds(1) + absl::Nanoseconds(0)},
+ {{0, 0}, absl::Seconds(0) + absl::Nanoseconds(0)},
+ {{0, -1}, absl::Seconds(0) - absl::Nanoseconds(1)},
+ {{-1, 999999999}, absl::Seconds(0) - absl::Nanoseconds(1)},
+ {{-1, 1}, absl::Seconds(-1) + absl::Nanoseconds(1)},
+ {{-1, 0}, absl::Seconds(-1) + absl::Nanoseconds(0)},
+ {{-1, -1}, absl::Seconds(-1) - absl::Nanoseconds(1)},
+ {{-2, 999999999}, absl::Seconds(-1) - absl::Nanoseconds(1)},
+ };
+ for (const auto& test : from_ts) {
+ EXPECT_EQ(test.d, absl::DurationFromTimespec(test.ts));
+ }
+
+ // Tests ToTimeval()/DurationFromTimeval() (same as timespec above)
+ const struct {
+ absl::Duration d;
+ timeval tv;
+ } to_tv[] = {
+ {absl::Seconds(1) + absl::Microseconds(1), {1, 1}},
+ {absl::Seconds(1) + absl::Microseconds(1) / 2, {1, 0}},
+ {absl::Seconds(1) + absl::Microseconds(0), {1, 0}},
+ {absl::Seconds(0) + absl::Microseconds(0), {0, 0}},
+ {absl::Seconds(0) - absl::Microseconds(1) / 2, {0, 0}},
+ {absl::Seconds(0) - absl::Microseconds(1), {-1, 999999}},
+ {absl::Seconds(-1) + absl::Microseconds(1), {-1, 1}},
+ {absl::Seconds(-1) + absl::Microseconds(1) / 2, {-1, 1}},
+ {absl::Seconds(-1) + absl::Microseconds(0), {-1, 0}},
+ {absl::Seconds(-1) - absl::Microseconds(1) / 2, {-1, 0}},
+ };
+ for (const auto& test : to_tv) {
+ EXPECT_THAT(absl::ToTimeval(test.d), TimevalMatcher(test.tv));
+ }
+ const struct {
+ timeval tv;
+ absl::Duration d;
+ } from_tv[] = {
+ {{1, 1}, absl::Seconds(1) + absl::Microseconds(1)},
+ {{1, 0}, absl::Seconds(1) + absl::Microseconds(0)},
+ {{0, 0}, absl::Seconds(0) + absl::Microseconds(0)},
+ {{0, -1}, absl::Seconds(0) - absl::Microseconds(1)},
+ {{-1, 999999}, absl::Seconds(0) - absl::Microseconds(1)},
+ {{-1, 1}, absl::Seconds(-1) + absl::Microseconds(1)},
+ {{-1, 0}, absl::Seconds(-1) + absl::Microseconds(0)},
+ {{-1, -1}, absl::Seconds(-1) - absl::Microseconds(1)},
+ {{-2, 999999}, absl::Seconds(-1) - absl::Microseconds(1)},
+ };
+ for (const auto& test : from_tv) {
+ EXPECT_EQ(test.d, absl::DurationFromTimeval(test.tv));
+ }
+}
+
+TEST(Duration, SmallConversions) {
+ // Special tests for conversions of small durations.
+
+ EXPECT_EQ(absl::ZeroDuration(), absl::Seconds(0));
+ // TODO(bww): Is the next one OK?
+ EXPECT_EQ(absl::ZeroDuration(), absl::Seconds(0.124999999e-9));
+ EXPECT_EQ(absl::Nanoseconds(1) / 4, absl::Seconds(0.125e-9));
+ EXPECT_EQ(absl::Nanoseconds(1) / 4, absl::Seconds(0.250e-9));
+ EXPECT_EQ(absl::Nanoseconds(1) / 2, absl::Seconds(0.375e-9));
+ EXPECT_EQ(absl::Nanoseconds(1) / 2, absl::Seconds(0.500e-9));
+ EXPECT_EQ(absl::Nanoseconds(3) / 4, absl::Seconds(0.625e-9));
+ EXPECT_EQ(absl::Nanoseconds(3) / 4, absl::Seconds(0.750e-9));
+ EXPECT_EQ(absl::Nanoseconds(1), absl::Seconds(0.875e-9));
+ EXPECT_EQ(absl::Nanoseconds(1), absl::Seconds(1.000e-9));
+
+ timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ EXPECT_THAT(ToTimespec(absl::Nanoseconds(0)), TimespecMatcher(ts));
+ // TODO(bww): Are the next three OK?
+ EXPECT_THAT(ToTimespec(absl::Nanoseconds(1) / 4), TimespecMatcher(ts));
+ EXPECT_THAT(ToTimespec(absl::Nanoseconds(2) / 4), TimespecMatcher(ts));
+ EXPECT_THAT(ToTimespec(absl::Nanoseconds(3) / 4), TimespecMatcher(ts));
+ ts.tv_nsec = 1;
+ EXPECT_THAT(ToTimespec(absl::Nanoseconds(4) / 4), TimespecMatcher(ts));
+ EXPECT_THAT(ToTimespec(absl::Nanoseconds(5) / 4), TimespecMatcher(ts));
+ EXPECT_THAT(ToTimespec(absl::Nanoseconds(6) / 4), TimespecMatcher(ts));
+ EXPECT_THAT(ToTimespec(absl::Nanoseconds(7) / 4), TimespecMatcher(ts));
+ ts.tv_nsec = 2;
+ EXPECT_THAT(ToTimespec(absl::Nanoseconds(8) / 4), TimespecMatcher(ts));
+
+ timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ EXPECT_THAT(ToTimeval(absl::Nanoseconds(0)), TimevalMatcher(tv));
+ // TODO(bww): Is the next one OK?
+ EXPECT_THAT(ToTimeval(absl::Nanoseconds(999)), TimevalMatcher(tv));
+ tv.tv_usec = 1;
+ EXPECT_THAT(ToTimeval(absl::Nanoseconds(1000)), TimevalMatcher(tv));
+ EXPECT_THAT(ToTimeval(absl::Nanoseconds(1999)), TimevalMatcher(tv));
+ tv.tv_usec = 2;
+ EXPECT_THAT(ToTimeval(absl::Nanoseconds(2000)), TimevalMatcher(tv));
+}
+
+TEST(Duration, ConversionSaturation) {
+ absl::Duration d;
+
+ const auto max_timeval_sec =
+ std::numeric_limits<decltype(timeval::tv_sec)>::max();
+ const auto min_timeval_sec =
+ std::numeric_limits<decltype(timeval::tv_sec)>::min();
+ timeval tv;
+ tv.tv_sec = max_timeval_sec;
+ tv.tv_usec = 999998;
+ d = absl::DurationFromTimeval(tv);
+ tv = ToTimeval(d);
+ EXPECT_EQ(max_timeval_sec, tv.tv_sec);
+ EXPECT_EQ(999998, tv.tv_usec);
+ d += absl::Microseconds(1);
+ tv = ToTimeval(d);
+ EXPECT_EQ(max_timeval_sec, tv.tv_sec);
+ EXPECT_EQ(999999, tv.tv_usec);
+ d += absl::Microseconds(1); // no effect
+ tv = ToTimeval(d);
+ EXPECT_EQ(max_timeval_sec, tv.tv_sec);
+ EXPECT_EQ(999999, tv.tv_usec);
+
+ tv.tv_sec = min_timeval_sec;
+ tv.tv_usec = 1;
+ d = absl::DurationFromTimeval(tv);
+ tv = ToTimeval(d);
+ EXPECT_EQ(min_timeval_sec, tv.tv_sec);
+ EXPECT_EQ(1, tv.tv_usec);
+ d -= absl::Microseconds(1);
+ tv = ToTimeval(d);
+ EXPECT_EQ(min_timeval_sec, tv.tv_sec);
+ EXPECT_EQ(0, tv.tv_usec);
+ d -= absl::Microseconds(1); // no effect
+ tv = ToTimeval(d);
+ EXPECT_EQ(min_timeval_sec, tv.tv_sec);
+ EXPECT_EQ(0, tv.tv_usec);
+
+ const auto max_timespec_sec =
+ std::numeric_limits<decltype(timespec::tv_sec)>::max();
+ const auto min_timespec_sec =
+ std::numeric_limits<decltype(timespec::tv_sec)>::min();
+ timespec ts;
+ ts.tv_sec = max_timespec_sec;
+ ts.tv_nsec = 999999998;
+ d = absl::DurationFromTimespec(ts);
+ ts = absl::ToTimespec(d);
+ EXPECT_EQ(max_timespec_sec, ts.tv_sec);
+ EXPECT_EQ(999999998, ts.tv_nsec);
+ d += absl::Nanoseconds(1);
+ ts = absl::ToTimespec(d);
+ EXPECT_EQ(max_timespec_sec, ts.tv_sec);
+ EXPECT_EQ(999999999, ts.tv_nsec);
+ d += absl::Nanoseconds(1); // no effect
+ ts = absl::ToTimespec(d);
+ EXPECT_EQ(max_timespec_sec, ts.tv_sec);
+ EXPECT_EQ(999999999, ts.tv_nsec);
+
+ ts.tv_sec = min_timespec_sec;
+ ts.tv_nsec = 1;
+ d = absl::DurationFromTimespec(ts);
+ ts = absl::ToTimespec(d);
+ EXPECT_EQ(min_timespec_sec, ts.tv_sec);
+ EXPECT_EQ(1, ts.tv_nsec);
+ d -= absl::Nanoseconds(1);
+ ts = absl::ToTimespec(d);
+ EXPECT_EQ(min_timespec_sec, ts.tv_sec);
+ EXPECT_EQ(0, ts.tv_nsec);
+ d -= absl::Nanoseconds(1); // no effect
+ ts = absl::ToTimespec(d);
+ EXPECT_EQ(min_timespec_sec, ts.tv_sec);
+ EXPECT_EQ(0, ts.tv_nsec);
+}
+
+TEST(Duration, FormatDuration) {
+ // Example from Go's docs.
+ EXPECT_EQ("72h3m0.5s",
+ absl::FormatDuration(absl::Hours(72) + absl::Minutes(3) +
+ absl::Milliseconds(500)));
+ // Go's largest time: 2540400h10m10.000000000s
+ EXPECT_EQ("2540400h10m10s",
+ absl::FormatDuration(absl::Hours(2540400) + absl::Minutes(10) +
+ absl::Seconds(10)));
+
+ EXPECT_EQ("0", absl::FormatDuration(absl::ZeroDuration()));
+ EXPECT_EQ("0", absl::FormatDuration(absl::Seconds(0)));
+ EXPECT_EQ("0", absl::FormatDuration(absl::Nanoseconds(0)));
+
+ EXPECT_EQ("1ns", absl::FormatDuration(absl::Nanoseconds(1)));
+ EXPECT_EQ("1us", absl::FormatDuration(absl::Microseconds(1)));
+ EXPECT_EQ("1ms", absl::FormatDuration(absl::Milliseconds(1)));
+ EXPECT_EQ("1s", absl::FormatDuration(absl::Seconds(1)));
+ EXPECT_EQ("1m", absl::FormatDuration(absl::Minutes(1)));
+ EXPECT_EQ("1h", absl::FormatDuration(absl::Hours(1)));
+
+ EXPECT_EQ("1h1m", absl::FormatDuration(absl::Hours(1) + absl::Minutes(1)));
+ EXPECT_EQ("1h1s", absl::FormatDuration(absl::Hours(1) + absl::Seconds(1)));
+ EXPECT_EQ("1m1s", absl::FormatDuration(absl::Minutes(1) + absl::Seconds(1)));
+
+ EXPECT_EQ("1h0.25s",
+ absl::FormatDuration(absl::Hours(1) + absl::Milliseconds(250)));
+ EXPECT_EQ("1m0.25s",
+ absl::FormatDuration(absl::Minutes(1) + absl::Milliseconds(250)));
+ EXPECT_EQ("1h1m0.25s",
+ absl::FormatDuration(absl::Hours(1) + absl::Minutes(1) +
+ absl::Milliseconds(250)));
+ EXPECT_EQ("1h0.0005s",
+ absl::FormatDuration(absl::Hours(1) + absl::Microseconds(500)));
+ EXPECT_EQ("1h0.0000005s",
+ absl::FormatDuration(absl::Hours(1) + absl::Nanoseconds(500)));
+
+ // Subsecond special case.
+ EXPECT_EQ("1.5ns", absl::FormatDuration(absl::Nanoseconds(1) +
+ absl::Nanoseconds(1) / 2));
+ EXPECT_EQ("1.25ns", absl::FormatDuration(absl::Nanoseconds(1) +
+ absl::Nanoseconds(1) / 4));
+ EXPECT_EQ("1ns", absl::FormatDuration(absl::Nanoseconds(1) +
+ absl::Nanoseconds(1) / 9));
+ EXPECT_EQ("1.2us", absl::FormatDuration(absl::Microseconds(1) +
+ absl::Nanoseconds(200)));
+ EXPECT_EQ("1.2ms", absl::FormatDuration(absl::Milliseconds(1) +
+ absl::Microseconds(200)));
+ EXPECT_EQ("1.0002ms", absl::FormatDuration(absl::Milliseconds(1) +
+ absl::Nanoseconds(200)));
+ EXPECT_EQ("1.00001ms", absl::FormatDuration(absl::Milliseconds(1) +
+ absl::Nanoseconds(10)));
+ EXPECT_EQ("1.000001ms",
+ absl::FormatDuration(absl::Milliseconds(1) + absl::Nanoseconds(1)));
+
+ // Negative durations.
+ EXPECT_EQ("-1ns", absl::FormatDuration(absl::Nanoseconds(-1)));
+ EXPECT_EQ("-1us", absl::FormatDuration(absl::Microseconds(-1)));
+ EXPECT_EQ("-1ms", absl::FormatDuration(absl::Milliseconds(-1)));
+ EXPECT_EQ("-1s", absl::FormatDuration(absl::Seconds(-1)));
+ EXPECT_EQ("-1m", absl::FormatDuration(absl::Minutes(-1)));
+ EXPECT_EQ("-1h", absl::FormatDuration(absl::Hours(-1)));
+
+ EXPECT_EQ("-1h1m",
+ absl::FormatDuration(-(absl::Hours(1) + absl::Minutes(1))));
+ EXPECT_EQ("-1h1s",
+ absl::FormatDuration(-(absl::Hours(1) + absl::Seconds(1))));
+ EXPECT_EQ("-1m1s",
+ absl::FormatDuration(-(absl::Minutes(1) + absl::Seconds(1))));
+
+ EXPECT_EQ("-1ns", absl::FormatDuration(absl::Nanoseconds(-1)));
+ EXPECT_EQ("-1.2us", absl::FormatDuration(
+ -(absl::Microseconds(1) + absl::Nanoseconds(200))));
+ EXPECT_EQ("-1.2ms", absl::FormatDuration(
+ -(absl::Milliseconds(1) + absl::Microseconds(200))));
+ EXPECT_EQ("-1.0002ms", absl::FormatDuration(-(absl::Milliseconds(1) +
+ absl::Nanoseconds(200))));
+ EXPECT_EQ("-1.00001ms", absl::FormatDuration(-(absl::Milliseconds(1) +
+ absl::Nanoseconds(10))));
+ EXPECT_EQ("-1.000001ms", absl::FormatDuration(-(absl::Milliseconds(1) +
+ absl::Nanoseconds(1))));
+
+ //
+ // Interesting corner cases.
+ //
+
+ const absl::Duration qns = absl::Nanoseconds(1) / 4;
+ const absl::Duration max_dur =
+ absl::Seconds(kint64max) + (absl::Seconds(1) - qns);
+ const absl::Duration min_dur = absl::Seconds(kint64min);
+
+ EXPECT_EQ("0.25ns", absl::FormatDuration(qns));
+ EXPECT_EQ("-0.25ns", absl::FormatDuration(-qns));
+ EXPECT_EQ("2562047788015215h30m7.99999999975s",
+ absl::FormatDuration(max_dur));
+ EXPECT_EQ("-2562047788015215h30m8s", absl::FormatDuration(min_dur));
+
+ // Tests printing full precision from units that print using FDivDuration
+ EXPECT_EQ("55.00000000025s", absl::FormatDuration(absl::Seconds(55) + qns));
+ EXPECT_EQ("55.00000025ms",
+ absl::FormatDuration(absl::Milliseconds(55) + qns));
+ EXPECT_EQ("55.00025us", absl::FormatDuration(absl::Microseconds(55) + qns));
+ EXPECT_EQ("55.25ns", absl::FormatDuration(absl::Nanoseconds(55) + qns));
+
+ // Formatting infinity
+ EXPECT_EQ("inf", absl::FormatDuration(absl::InfiniteDuration()));
+ EXPECT_EQ("-inf", absl::FormatDuration(-absl::InfiniteDuration()));
+
+ // Formatting approximately +/- 100 billion years
+ const absl::Duration huge_range = ApproxYears(100000000000);
+ EXPECT_EQ("876000000000000h", absl::FormatDuration(huge_range));
+ EXPECT_EQ("-876000000000000h", absl::FormatDuration(-huge_range));
+
+ EXPECT_EQ("876000000000000h0.999999999s",
+ absl::FormatDuration(huge_range +
+ (absl::Seconds(1) - absl::Nanoseconds(1))));
+ EXPECT_EQ("876000000000000h0.9999999995s",
+ absl::FormatDuration(
+ huge_range + (absl::Seconds(1) - absl::Nanoseconds(1) / 2)));
+ EXPECT_EQ("876000000000000h0.99999999975s",
+ absl::FormatDuration(
+ huge_range + (absl::Seconds(1) - absl::Nanoseconds(1) / 4)));
+
+ EXPECT_EQ("-876000000000000h0.999999999s",
+ absl::FormatDuration(-huge_range -
+ (absl::Seconds(1) - absl::Nanoseconds(1))));
+ EXPECT_EQ("-876000000000000h0.9999999995s",
+ absl::FormatDuration(
+ -huge_range - (absl::Seconds(1) - absl::Nanoseconds(1) / 2)));
+ EXPECT_EQ("-876000000000000h0.99999999975s",
+ absl::FormatDuration(
+ -huge_range - (absl::Seconds(1) - absl::Nanoseconds(1) / 4)));
+}
+
+TEST(Duration, ParseDuration) {
+ absl::Duration d;
+
+ // No specified unit. Should only work for zero and infinity.
+ EXPECT_TRUE(absl::ParseDuration("0", &d));
+ EXPECT_EQ(absl::ZeroDuration(), d);
+ EXPECT_TRUE(absl::ParseDuration("+0", &d));
+ EXPECT_EQ(absl::ZeroDuration(), d);
+ EXPECT_TRUE(absl::ParseDuration("-0", &d));
+ EXPECT_EQ(absl::ZeroDuration(), d);
+
+ EXPECT_TRUE(absl::ParseDuration("inf", &d));
+ EXPECT_EQ(absl::InfiniteDuration(), d);
+ EXPECT_TRUE(absl::ParseDuration("+inf", &d));
+ EXPECT_EQ(absl::InfiniteDuration(), d);
+ EXPECT_TRUE(absl::ParseDuration("-inf", &d));
+ EXPECT_EQ(-absl::InfiniteDuration(), d);
+ EXPECT_FALSE(absl::ParseDuration("infBlah", &d));
+
+ // Illegal input forms.
+ EXPECT_FALSE(absl::ParseDuration("", &d));
+ EXPECT_FALSE(absl::ParseDuration("0.0", &d));
+ EXPECT_FALSE(absl::ParseDuration(".0", &d));
+ EXPECT_FALSE(absl::ParseDuration(".", &d));
+ EXPECT_FALSE(absl::ParseDuration("01", &d));
+ EXPECT_FALSE(absl::ParseDuration("1", &d));
+ EXPECT_FALSE(absl::ParseDuration("-1", &d));
+ EXPECT_FALSE(absl::ParseDuration("2", &d));
+ EXPECT_FALSE(absl::ParseDuration("2 s", &d));
+ EXPECT_FALSE(absl::ParseDuration(".s", &d));
+ EXPECT_FALSE(absl::ParseDuration("-.s", &d));
+ EXPECT_FALSE(absl::ParseDuration("s", &d));
+ EXPECT_FALSE(absl::ParseDuration(" 2s", &d));
+ EXPECT_FALSE(absl::ParseDuration("2s ", &d));
+ EXPECT_FALSE(absl::ParseDuration(" 2s ", &d));
+ EXPECT_FALSE(absl::ParseDuration("2mt", &d));
+
+ // One unit type.
+ EXPECT_TRUE(absl::ParseDuration("1ns", &d));
+ EXPECT_EQ(absl::Nanoseconds(1), d);
+ EXPECT_TRUE(absl::ParseDuration("1us", &d));
+ EXPECT_EQ(absl::Microseconds(1), d);
+ EXPECT_TRUE(absl::ParseDuration("1ms", &d));
+ EXPECT_EQ(absl::Milliseconds(1), d);
+ EXPECT_TRUE(absl::ParseDuration("1s", &d));
+ EXPECT_EQ(absl::Seconds(1), d);
+ EXPECT_TRUE(absl::ParseDuration("2m", &d));
+ EXPECT_EQ(absl::Minutes(2), d);
+ EXPECT_TRUE(absl::ParseDuration("2h", &d));
+ EXPECT_EQ(absl::Hours(2), d);
+
+ // Multiple units.
+ EXPECT_TRUE(absl::ParseDuration("2h3m4s", &d));
+ EXPECT_EQ(absl::Hours(2) + absl::Minutes(3) + absl::Seconds(4), d);
+ EXPECT_TRUE(absl::ParseDuration("3m4s5us", &d));
+ EXPECT_EQ(absl::Minutes(3) + absl::Seconds(4) + absl::Microseconds(5), d);
+ EXPECT_TRUE(absl::ParseDuration("2h3m4s5ms6us7ns", &d));
+ EXPECT_EQ(absl::Hours(2) + absl::Minutes(3) + absl::Seconds(4) +
+ absl::Milliseconds(5) + absl::Microseconds(6) +
+ absl::Nanoseconds(7),
+ d);
+
+ // Multiple units out of order.
+ EXPECT_TRUE(absl::ParseDuration("2us3m4s5h", &d));
+ EXPECT_EQ(absl::Hours(5) + absl::Minutes(3) + absl::Seconds(4) +
+ absl::Microseconds(2),
+ d);
+
+ // Fractional values of units.
+ EXPECT_TRUE(absl::ParseDuration("1.5ns", &d));
+ EXPECT_EQ(1.5 * absl::Nanoseconds(1), d);
+ EXPECT_TRUE(absl::ParseDuration("1.5us", &d));
+ EXPECT_EQ(1.5 * absl::Microseconds(1), d);
+ EXPECT_TRUE(absl::ParseDuration("1.5ms", &d));
+ EXPECT_EQ(1.5 * absl::Milliseconds(1), d);
+ EXPECT_TRUE(absl::ParseDuration("1.5s", &d));
+ EXPECT_EQ(1.5 * absl::Seconds(1), d);
+ EXPECT_TRUE(absl::ParseDuration("1.5m", &d));
+ EXPECT_EQ(1.5 * absl::Minutes(1), d);
+ EXPECT_TRUE(absl::ParseDuration("1.5h", &d));
+ EXPECT_EQ(1.5 * absl::Hours(1), d);
+
+ // Negative durations.
+ EXPECT_TRUE(absl::ParseDuration("-1s", &d));
+ EXPECT_EQ(absl::Seconds(-1), d);
+ EXPECT_TRUE(absl::ParseDuration("-1m", &d));
+ EXPECT_EQ(absl::Minutes(-1), d);
+ EXPECT_TRUE(absl::ParseDuration("-1h", &d));
+ EXPECT_EQ(absl::Hours(-1), d);
+
+ EXPECT_TRUE(absl::ParseDuration("-1h2s", &d));
+ EXPECT_EQ(-(absl::Hours(1) + absl::Seconds(2)), d);
+ EXPECT_FALSE(absl::ParseDuration("1h-2s", &d));
+ EXPECT_FALSE(absl::ParseDuration("-1h-2s", &d));
+ EXPECT_FALSE(absl::ParseDuration("-1h -2s", &d));
+}
+
+TEST(Duration, FormatParseRoundTrip) {
+#define TEST_PARSE_ROUNDTRIP(d) \
+ do { \
+ std::string s = absl::FormatDuration(d); \
+ absl::Duration dur; \
+ EXPECT_TRUE(absl::ParseDuration(s, &dur)); \
+ EXPECT_EQ(d, dur); \
+ } while (0)
+
+ TEST_PARSE_ROUNDTRIP(absl::Nanoseconds(1));
+ TEST_PARSE_ROUNDTRIP(absl::Microseconds(1));
+ TEST_PARSE_ROUNDTRIP(absl::Milliseconds(1));
+ TEST_PARSE_ROUNDTRIP(absl::Seconds(1));
+ TEST_PARSE_ROUNDTRIP(absl::Minutes(1));
+ TEST_PARSE_ROUNDTRIP(absl::Hours(1));
+ TEST_PARSE_ROUNDTRIP(absl::Hours(1) + absl::Nanoseconds(2));
+
+ TEST_PARSE_ROUNDTRIP(absl::Nanoseconds(-1));
+ TEST_PARSE_ROUNDTRIP(absl::Microseconds(-1));
+ TEST_PARSE_ROUNDTRIP(absl::Milliseconds(-1));
+ TEST_PARSE_ROUNDTRIP(absl::Seconds(-1));
+ TEST_PARSE_ROUNDTRIP(absl::Minutes(-1));
+ TEST_PARSE_ROUNDTRIP(absl::Hours(-1));
+
+ TEST_PARSE_ROUNDTRIP(absl::Hours(-1) + absl::Nanoseconds(2));
+ TEST_PARSE_ROUNDTRIP(absl::Hours(1) + absl::Nanoseconds(-2));
+ TEST_PARSE_ROUNDTRIP(absl::Hours(-1) + absl::Nanoseconds(-2));
+
+ TEST_PARSE_ROUNDTRIP(absl::Nanoseconds(1) +
+ absl::Nanoseconds(1) / 4); // 1.25ns
+
+ const absl::Duration huge_range = ApproxYears(100000000000);
+ TEST_PARSE_ROUNDTRIP(huge_range);
+ TEST_PARSE_ROUNDTRIP(huge_range + (absl::Seconds(1) - absl::Nanoseconds(1)));
+
+#undef TEST_PARSE_ROUNDTRIP
+}
+} // namespace
diff --git a/absl/time/format.cc b/absl/time/format.cc
new file mode 100644
index 0000000..c58a886
--- /dev/null
+++ b/absl/time/format.cc
@@ -0,0 +1,140 @@
+// 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 <string.h>
+#include <cctype>
+#include <cstdint>
+
+#include "absl/time/time.h"
+#include "cctz/time_zone.h"
+
+namespace absl {
+
+extern const char RFC3339_full[] = "%Y-%m-%dT%H:%M:%E*S%Ez";
+extern const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez";
+
+extern const char RFC1123_full[] = "%a, %d %b %E4Y %H:%M:%S %z";
+extern const char RFC1123_no_wday[] = "%d %b %E4Y %H:%M:%S %z";
+
+namespace {
+
+const char kInfiniteFutureStr[] = "infinite-future";
+const char kInfinitePastStr[] = "infinite-past";
+
+using cctz_sec = cctz::time_point<cctz::sys_seconds>;
+using cctz_fem = cctz::detail::femtoseconds;
+struct cctz_parts {
+ cctz_sec sec;
+ cctz_fem fem;
+};
+
+inline cctz_sec unix_epoch() {
+ return std::chrono::time_point_cast<cctz::sys_seconds>(
+ std::chrono::system_clock::from_time_t(0));
+}
+
+// Splits a Time into seconds and femtoseconds, which can be used with CCTZ.
+// Requires that 't' is finite. See duration.cc for details about rep_hi and
+// rep_lo.
+cctz_parts Split(absl::Time t) {
+ const auto d = time_internal::ToUnixDuration(t);
+ const int64_t rep_hi = time_internal::GetRepHi(d);
+ const int64_t rep_lo = time_internal::GetRepLo(d);
+ const auto sec = unix_epoch() + cctz::sys_seconds(rep_hi);
+ const auto fem = cctz_fem(rep_lo * (1000 * 1000 / 4));
+ return {sec, fem};
+}
+
+// Joins the given seconds and femtoseconds into a Time. See duration.cc for
+// details about rep_hi and rep_lo.
+absl::Time Join(const cctz_parts& parts) {
+ const int64_t rep_hi = (parts.sec - unix_epoch()).count();
+ const uint32_t rep_lo = parts.fem.count() / (1000 * 1000 / 4);
+ const auto d = time_internal::MakeDuration(rep_hi, rep_lo);
+ return time_internal::FromUnixDuration(d);
+}
+
+} // namespace
+
+std::string FormatTime(const std::string& format, absl::Time t, absl::TimeZone tz) {
+ if (t == absl::InfiniteFuture()) return kInfiniteFutureStr;
+ if (t == absl::InfinitePast()) return kInfinitePastStr;
+ const auto parts = Split(t);
+ return cctz::detail::format(format, parts.sec, parts.fem,
+ cctz::time_zone(tz));
+}
+
+std::string FormatTime(absl::Time t, absl::TimeZone tz) {
+ return FormatTime(RFC3339_full, t, tz);
+}
+
+std::string FormatTime(absl::Time t) {
+ return absl::FormatTime(RFC3339_full, t, absl::LocalTimeZone());
+}
+
+bool ParseTime(const std::string& format, const std::string& input, absl::Time* time,
+ std::string* err) {
+ return absl::ParseTime(format, input, absl::UTCTimeZone(), time, err);
+}
+
+// If the input std::string does not contain an explicit UTC offset, interpret
+// the fields with respect to the given TimeZone.
+bool ParseTime(const std::string& format, const std::string& input, absl::TimeZone tz,
+ absl::Time* time, std::string* err) {
+ const char* data = input.c_str();
+ while (std::isspace(*data)) ++data;
+
+ size_t inf_size = strlen(kInfiniteFutureStr);
+ if (strncmp(data, kInfiniteFutureStr, inf_size) == 0) {
+ const char* new_data = data + inf_size;
+ while (std::isspace(*new_data)) ++new_data;
+ if (*new_data == '\0') {
+ *time = InfiniteFuture();
+ return true;
+ }
+ }
+
+ inf_size = strlen(kInfinitePastStr);
+ if (strncmp(data, kInfinitePastStr, inf_size) == 0) {
+ const char* new_data = data + inf_size;
+ while (std::isspace(*new_data)) ++new_data;
+ if (*new_data == '\0') {
+ *time = InfinitePast();
+ return true;
+ }
+ }
+
+ std::string error;
+ cctz_parts parts;
+ const bool b = cctz::detail::parse(format, input, cctz::time_zone(tz),
+ &parts.sec, &parts.fem, &error);
+ if (b) {
+ *time = Join(parts);
+ } else if (err != nullptr) {
+ *err = error;
+ }
+ return b;
+}
+
+// TODO(b/63899288) copybara strip once dependencies are removed.
+// Functions required to support absl::Time flags. See go/flags.
+bool ParseFlag(const std::string& text, absl::Time* t, std::string* error) {
+ return absl::ParseTime(RFC3339_full, text, absl::UTCTimeZone(), t, error);
+}
+
+std::string UnparseFlag(absl::Time t) {
+ return absl::FormatTime(RFC3339_full, t, absl::UTCTimeZone());
+}
+
+} // namespace absl
diff --git a/absl/time/format_test.cc b/absl/time/format_test.cc
new file mode 100644
index 0000000..cd9a6f9
--- /dev/null
+++ b/absl/time/format_test.cc
@@ -0,0 +1,430 @@
+// 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 <limits>
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/time/internal/test_util.h"
+#include "absl/time/time.h"
+
+using testing::HasSubstr;
+
+namespace {
+
+// A helper that tests the given format specifier by itself, and with leading
+// and trailing characters. For example: TestFormatSpecifier(t, "%a", "Thu").
+void TestFormatSpecifier(absl::Time t, absl::TimeZone tz, const std::string& fmt,
+ const std::string& ans) {
+ EXPECT_EQ(ans, absl::FormatTime(fmt, t, tz));
+ EXPECT_EQ("xxx " + ans, absl::FormatTime("xxx " + fmt, t, tz));
+ EXPECT_EQ(ans + " yyy", absl::FormatTime(fmt + " yyy", t, tz));
+ EXPECT_EQ("xxx " + ans + " yyy",
+ absl::FormatTime("xxx " + fmt + " yyy", t, tz));
+}
+
+//
+// Testing FormatTime()
+//
+
+TEST(FormatTime, Basics) {
+ absl::TimeZone tz = absl::UTCTimeZone();
+ absl::Time t = absl::FromTimeT(0);
+
+ // Starts with a couple basic edge cases.
+ EXPECT_EQ("", absl::FormatTime("", t, tz));
+ EXPECT_EQ(" ", absl::FormatTime(" ", t, tz));
+ EXPECT_EQ(" ", absl::FormatTime(" ", t, tz));
+ EXPECT_EQ("xxx", absl::FormatTime("xxx", t, tz));
+ std::string big(128, 'x');
+ EXPECT_EQ(big, absl::FormatTime(big, t, tz));
+ // Cause the 1024-byte buffer to grow.
+ std::string bigger(100000, 'x');
+ EXPECT_EQ(bigger, absl::FormatTime(bigger, t, tz));
+
+ t += absl::Hours(13) + absl::Minutes(4) + absl::Seconds(5);
+ t += absl::Milliseconds(6) + absl::Microseconds(7) + absl::Nanoseconds(8);
+ EXPECT_EQ("1970-01-01", absl::FormatTime("%Y-%m-%d", t, tz));
+ EXPECT_EQ("13:04:05", absl::FormatTime("%H:%M:%S", t, tz));
+ EXPECT_EQ("13:04:05.006", absl::FormatTime("%H:%M:%E3S", t, tz));
+ EXPECT_EQ("13:04:05.006007", absl::FormatTime("%H:%M:%E6S", t, tz));
+ EXPECT_EQ("13:04:05.006007008", absl::FormatTime("%H:%M:%E9S", t, tz));
+}
+
+TEST(FormatTime, LocaleSpecific) {
+ const absl::TimeZone tz = absl::UTCTimeZone();
+ absl::Time t = absl::FromTimeT(0);
+
+ TestFormatSpecifier(t, tz, "%a", "Thu");
+ TestFormatSpecifier(t, tz, "%A", "Thursday");
+ TestFormatSpecifier(t, tz, "%b", "Jan");
+ TestFormatSpecifier(t, tz, "%B", "January");
+
+ // %c should at least produce the numeric year and time-of-day.
+ const std::string s =
+ absl::FormatTime("%c", absl::FromTimeT(0), absl::UTCTimeZone());
+ EXPECT_THAT(s, HasSubstr("1970"));
+ EXPECT_THAT(s, HasSubstr("00:00:00"));
+
+ TestFormatSpecifier(t, tz, "%p", "AM");
+ TestFormatSpecifier(t, tz, "%x", "01/01/70");
+ TestFormatSpecifier(t, tz, "%X", "00:00:00");
+}
+
+TEST(FormatTime, ExtendedSeconds) {
+ const absl::TimeZone tz = absl::UTCTimeZone();
+
+ // No subseconds.
+ absl::Time t = absl::FromTimeT(0) + absl::Seconds(5);
+ EXPECT_EQ("05", absl::FormatTime("%E*S", t, tz));
+ EXPECT_EQ("05.000000000000000", absl::FormatTime("%E15S", t, tz));
+
+ // With subseconds.
+ t += absl::Milliseconds(6) + absl::Microseconds(7) + absl::Nanoseconds(8);
+ EXPECT_EQ("05.006007008", absl::FormatTime("%E*S", t, tz));
+ EXPECT_EQ("05", absl::FormatTime("%E0S", t, tz));
+ EXPECT_EQ("05.006007008000000", absl::FormatTime("%E15S", t, tz));
+
+ // Times before the Unix epoch.
+ t = absl::FromUnixMicros(-1);
+ EXPECT_EQ("1969-12-31 23:59:59.999999",
+ absl::FormatTime("%Y-%m-%d %H:%M:%E*S", t, tz));
+
+ // Here is a "%E*S" case we got wrong for a while. While the first
+ // instant below is correctly rendered as "...:07.333304", the second
+ // one used to appear as "...:07.33330499999999999".
+ t = absl::FromUnixMicros(1395024427333304);
+ EXPECT_EQ("2014-03-17 02:47:07.333304",
+ absl::FormatTime("%Y-%m-%d %H:%M:%E*S", t, tz));
+ t += absl::Microseconds(1);
+ EXPECT_EQ("2014-03-17 02:47:07.333305",
+ absl::FormatTime("%Y-%m-%d %H:%M:%E*S", t, tz));
+}
+
+TEST(FormatTime, RFC1123FormatPadsYear) { // locale specific
+ absl::TimeZone tz = absl::UTCTimeZone();
+
+ // A year of 77 should be padded to 0077.
+ absl::Time t = absl::FromDateTime(77, 6, 28, 9, 8, 7, tz);
+ EXPECT_EQ("Mon, 28 Jun 0077 09:08:07 +0000",
+ absl::FormatTime(absl::RFC1123_full, t, tz));
+ EXPECT_EQ("28 Jun 0077 09:08:07 +0000",
+ absl::FormatTime(absl::RFC1123_no_wday, t, tz));
+}
+
+TEST(FormatTime, InfiniteTime) {
+ absl::TimeZone tz = absl::time_internal::LoadTimeZone("America/Los_Angeles");
+
+ // The format and timezone are ignored.
+ EXPECT_EQ("infinite-future",
+ absl::FormatTime("%H:%M blah", absl::InfiniteFuture(), tz));
+ EXPECT_EQ("infinite-past",
+ absl::FormatTime("%H:%M blah", absl::InfinitePast(), tz));
+}
+
+//
+// Testing ParseTime()
+//
+
+TEST(ParseTime, Basics) {
+ absl::Time t = absl::FromTimeT(1234567890);
+ std::string err;
+
+ // Simple edge cases.
+ EXPECT_TRUE(absl::ParseTime("", "", &t, &err)) << err;
+ EXPECT_EQ(absl::UnixEpoch(), t); // everything defaulted
+ EXPECT_TRUE(absl::ParseTime(" ", " ", &t, &err)) << err;
+ EXPECT_TRUE(absl::ParseTime(" ", " ", &t, &err)) << err;
+ EXPECT_TRUE(absl::ParseTime("x", "x", &t, &err)) << err;
+ EXPECT_TRUE(absl::ParseTime("xxx", "xxx", &t, &err)) << err;
+
+ EXPECT_TRUE(absl::ParseTime("%Y-%m-%d %H:%M:%S %z",
+ "2013-06-28 19:08:09 -0800", &t, &err))
+ << err;
+ absl::Time::Breakdown bd = t.In(absl::FixedTimeZone(-8 * 60 * 60));
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -8 * 60 * 60, false,
+ "UTC-8");
+ EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
+}
+
+TEST(ParseTime, NullErrorString) {
+ absl::Time t;
+ EXPECT_FALSE(absl::ParseTime("%Q", "invalid format", &t, nullptr));
+ EXPECT_FALSE(absl::ParseTime("%H", "12 trailing data", &t, nullptr));
+ EXPECT_FALSE(
+ absl::ParseTime("%H out of range", "42 out of range", &t, nullptr));
+}
+
+TEST(ParseTime, WithTimeZone) {
+ const absl::TimeZone tz =
+ absl::time_internal::LoadTimeZone("America/Los_Angeles");
+ absl::Time t;
+ std::string e;
+
+ // We can parse a std::string without a UTC offset if we supply a timezone.
+ EXPECT_TRUE(
+ absl::ParseTime("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &t, &e))
+ << e;
+ absl::Time::Breakdown bd = t.In(tz);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -7 * 60 * 60, true,
+ "PDT");
+ EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
+
+ // But the timezone is ignored when a UTC offset is present.
+ EXPECT_TRUE(absl::ParseTime("%Y-%m-%d %H:%M:%S %z",
+ "2013-06-28 19:08:09 +0800", tz, &t, &e))
+ << e;
+ bd = t.In(absl::FixedTimeZone(8 * 60 * 60));
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, 8 * 60 * 60, false,
+ "UTC+8");
+ EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
+}
+
+TEST(ParseTime, ErrorCases) {
+ absl::Time t = absl::FromTimeT(0);
+ std::string err;
+
+ EXPECT_FALSE(absl::ParseTime("%S", "123", &t, &err)) << err;
+ EXPECT_THAT(err, HasSubstr("Illegal trailing data"));
+
+ // Can't parse an illegal format specifier.
+ err.clear();
+ EXPECT_FALSE(absl::ParseTime("%Q", "x", &t, &err)) << err;
+ // Exact contents of "err" are platform-dependent because of
+ // differences in the strptime implementation between OSX and Linux.
+ EXPECT_FALSE(err.empty());
+
+ // Fails because of trailing, unparsed data "blah".
+ EXPECT_FALSE(absl::ParseTime("%m-%d", "2-3 blah", &t, &err)) << err;
+ EXPECT_THAT(err, HasSubstr("Illegal trailing data"));
+
+ // Feb 31 requires normalization.
+ EXPECT_FALSE(absl::ParseTime("%m-%d", "2-31", &t, &err)) << err;
+ EXPECT_THAT(err, HasSubstr("Out-of-range"));
+
+ // Check that we cannot have spaces in UTC offsets.
+ EXPECT_TRUE(absl::ParseTime("%z", "-0203", &t, &err)) << err;
+ EXPECT_FALSE(absl::ParseTime("%z", "- 2 3", &t, &err)) << err;
+ EXPECT_THAT(err, HasSubstr("Failed to parse"));
+ EXPECT_TRUE(absl::ParseTime("%Ez", "-02:03", &t, &err)) << err;
+ EXPECT_FALSE(absl::ParseTime("%Ez", "- 2: 3", &t, &err)) << err;
+ EXPECT_THAT(err, HasSubstr("Failed to parse"));
+
+ // Check that we reject other malformed UTC offsets.
+ EXPECT_FALSE(absl::ParseTime("%Ez", "+-08:00", &t, &err)) << err;
+ EXPECT_THAT(err, HasSubstr("Failed to parse"));
+ EXPECT_FALSE(absl::ParseTime("%Ez", "-+08:00", &t, &err)) << err;
+ EXPECT_THAT(err, HasSubstr("Failed to parse"));
+
+ // Check that we do not accept "-0" in fields that allow zero.
+ EXPECT_FALSE(absl::ParseTime("%Y", "-0", &t, &err)) << err;
+ EXPECT_THAT(err, HasSubstr("Failed to parse"));
+ EXPECT_FALSE(absl::ParseTime("%E4Y", "-0", &t, &err)) << err;
+ EXPECT_THAT(err, HasSubstr("Failed to parse"));
+ EXPECT_FALSE(absl::ParseTime("%H", "-0", &t, &err)) << err;
+ EXPECT_THAT(err, HasSubstr("Failed to parse"));
+ EXPECT_FALSE(absl::ParseTime("%M", "-0", &t, &err)) << err;
+ EXPECT_THAT(err, HasSubstr("Failed to parse"));
+ EXPECT_FALSE(absl::ParseTime("%S", "-0", &t, &err)) << err;
+ EXPECT_THAT(err, HasSubstr("Failed to parse"));
+ EXPECT_FALSE(absl::ParseTime("%z", "+-000", &t, &err)) << err;
+ EXPECT_THAT(err, HasSubstr("Failed to parse"));
+ EXPECT_FALSE(absl::ParseTime("%Ez", "+-0:00", &t, &err)) << err;
+ EXPECT_THAT(err, HasSubstr("Failed to parse"));
+ EXPECT_FALSE(absl::ParseTime("%z", "-00-0", &t, &err)) << err;
+ EXPECT_THAT(err, HasSubstr("Illegal trailing data"));
+ EXPECT_FALSE(absl::ParseTime("%Ez", "-00:-0", &t, &err)) << err;
+ EXPECT_THAT(err, HasSubstr("Illegal trailing data"));
+}
+
+TEST(ParseTime, ExtendedSeconds) {
+ std::string err;
+ absl::Time t;
+
+ // Here is a "%E*S" case we got wrong for a while. The fractional
+ // part of the first instant is less than 2^31 and was correctly
+ // parsed, while the second (and any subsecond field >=2^31) failed.
+ t = absl::UnixEpoch();
+ EXPECT_TRUE(absl::ParseTime("%E*S", "0.2147483647", &t, &err)) << err;
+ EXPECT_EQ(absl::UnixEpoch() + absl::Nanoseconds(214748364) +
+ absl::Nanoseconds(1) / 2,
+ t);
+ t = absl::UnixEpoch();
+ EXPECT_TRUE(absl::ParseTime("%E*S", "0.2147483648", &t, &err)) << err;
+ EXPECT_EQ(absl::UnixEpoch() + absl::Nanoseconds(214748364) +
+ absl::Nanoseconds(3) / 4,
+ t);
+
+ // We should also be able to specify long strings of digits far
+ // beyond the current resolution and have them convert the same way.
+ t = absl::UnixEpoch();
+ EXPECT_TRUE(absl::ParseTime(
+ "%E*S", "0.214748364801234567890123456789012345678901234567890123456789",
+ &t, &err))
+ << err;
+ EXPECT_EQ(absl::UnixEpoch() + absl::Nanoseconds(214748364) +
+ absl::Nanoseconds(3) / 4,
+ t);
+}
+
+TEST(ParseTime, ExtendedOffsetErrors) {
+ std::string err;
+ absl::Time t;
+
+ // %z against +-HHMM.
+ EXPECT_FALSE(absl::ParseTime("%z", "-123", &t, &err)) << err;
+ EXPECT_THAT(err, HasSubstr("Illegal trailing data"));
+
+ // %z against +-HH.
+ EXPECT_FALSE(absl::ParseTime("%z", "-1", &t, &err)) << err;
+ EXPECT_THAT(err, HasSubstr("Failed to parse"));
+
+ // %Ez against +-HH:MM.
+ EXPECT_FALSE(absl::ParseTime("%Ez", "-12:3", &t, &err)) << err;
+ EXPECT_THAT(err, HasSubstr("Illegal trailing data"));
+
+ // %Ez against +-HHMM.
+ EXPECT_FALSE(absl::ParseTime("%Ez", "-123", &t, &err)) << err;
+ EXPECT_THAT(err, HasSubstr("Illegal trailing data"));
+
+ // %Ez against +-HH.
+ EXPECT_FALSE(absl::ParseTime("%Ez", "-1", &t, &err)) << err;
+ EXPECT_THAT(err, HasSubstr("Failed to parse"));
+}
+
+TEST(ParseTime, InfiniteTime) {
+ absl::Time t;
+ std::string err;
+ EXPECT_TRUE(absl::ParseTime("%H:%M blah", "infinite-future", &t, &err));
+ EXPECT_EQ(absl::InfiniteFuture(), t);
+
+ // Surrounding whitespace.
+ EXPECT_TRUE(absl::ParseTime("%H:%M blah", " infinite-future", &t, &err));
+ EXPECT_EQ(absl::InfiniteFuture(), t);
+ EXPECT_TRUE(absl::ParseTime("%H:%M blah", "infinite-future ", &t, &err));
+ EXPECT_EQ(absl::InfiniteFuture(), t);
+ EXPECT_TRUE(absl::ParseTime("%H:%M blah", " infinite-future ", &t, &err));
+ EXPECT_EQ(absl::InfiniteFuture(), t);
+
+ EXPECT_TRUE(absl::ParseTime("%H:%M blah", "infinite-past", &t, &err));
+ EXPECT_EQ(absl::InfinitePast(), t);
+
+ // Surrounding whitespace.
+ EXPECT_TRUE(absl::ParseTime("%H:%M blah", " infinite-past", &t, &err));
+ EXPECT_EQ(absl::InfinitePast(), t);
+ EXPECT_TRUE(absl::ParseTime("%H:%M blah", "infinite-past ", &t, &err));
+ EXPECT_EQ(absl::InfinitePast(), t);
+ EXPECT_TRUE(absl::ParseTime("%H:%M blah", " infinite-past ", &t, &err));
+ EXPECT_EQ(absl::InfinitePast(), t);
+
+ // "infinite-future" as literal std::string
+ absl::TimeZone tz = absl::UTCTimeZone();
+ EXPECT_TRUE(absl::ParseTime("infinite-future %H:%M", "infinite-future 03:04",
+ &t, &err));
+ EXPECT_NE(absl::InfiniteFuture(), t);
+ EXPECT_EQ(3, t.In(tz).hour);
+ EXPECT_EQ(4, t.In(tz).minute);
+
+ // "infinite-past" as literal std::string
+ EXPECT_TRUE(
+ absl::ParseTime("infinite-past %H:%M", "infinite-past 03:04", &t, &err));
+ EXPECT_NE(absl::InfinitePast(), t);
+ EXPECT_EQ(3, t.In(tz).hour);
+ EXPECT_EQ(4, t.In(tz).minute);
+
+ // The input doesn't match the format.
+ EXPECT_FALSE(absl::ParseTime("infinite-future %H:%M", "03:04", &t, &err));
+ EXPECT_FALSE(absl::ParseTime("infinite-past %H:%M", "03:04", &t, &err));
+}
+
+TEST(ParseTime, FailsOnUnrepresentableTime) {
+ const absl::TimeZone utc = absl::UTCTimeZone();
+ absl::Time t;
+ EXPECT_FALSE(
+ absl::ParseTime("%Y-%m-%d", "-292277022657-01-27", utc, &t, nullptr));
+ EXPECT_TRUE(
+ absl::ParseTime("%Y-%m-%d", "-292277022657-01-28", utc, &t, nullptr));
+ EXPECT_TRUE(
+ absl::ParseTime("%Y-%m-%d", "292277026596-12-04", utc, &t, nullptr));
+ EXPECT_FALSE(
+ absl::ParseTime("%Y-%m-%d", "292277026596-12-05", utc, &t, nullptr));
+}
+
+//
+// Roundtrip test for FormatTime()/ParseTime().
+//
+
+TEST(FormatParse, RoundTrip) {
+ const absl::TimeZone gst =
+ absl::time_internal::LoadTimeZone("America/Los_Angeles");
+ const absl::Time in = absl::FromDateTime(1977, 6, 28, 9, 8, 7, gst);
+ const absl::Duration subseconds = absl::Nanoseconds(654321);
+ std::string err;
+
+ // RFC3339, which renders subseconds.
+ {
+ absl::Time out;
+ const std::string s = absl::FormatTime(absl::RFC3339_full, in + subseconds, gst);
+ EXPECT_TRUE(absl::ParseTime(absl::RFC3339_full, s, &out, &err))
+ << s << ": " << err;
+ EXPECT_EQ(in + subseconds, out); // RFC3339_full includes %Ez
+ }
+
+ // RFC1123, which only does whole seconds.
+ {
+ absl::Time out;
+ const std::string s = absl::FormatTime(absl::RFC1123_full, in, gst);
+ EXPECT_TRUE(absl::ParseTime(absl::RFC1123_full, s, &out, &err))
+ << s << ": " << err;
+ EXPECT_EQ(in, out); // RFC1123_full includes %z
+ }
+
+ // Even though we don't know what %c will produce, it should roundtrip,
+ // but only in the 0-offset timezone.
+ {
+ absl::Time out;
+ const std::string s = absl::FormatTime("%c", in, absl::UTCTimeZone());
+ EXPECT_TRUE(absl::ParseTime("%c", s, &out, &err)) << s << ": " << err;
+ EXPECT_EQ(in, out);
+ }
+}
+
+TEST(FormatParse, RoundTripDistantFuture) {
+ const absl::TimeZone tz = absl::UTCTimeZone();
+ const absl::Time in =
+ absl::FromUnixSeconds(std::numeric_limits<int64_t>::max());
+ std::string err;
+
+ absl::Time out;
+ const std::string s = absl::FormatTime(absl::RFC3339_full, in, tz);
+ EXPECT_TRUE(absl::ParseTime(absl::RFC3339_full, s, &out, &err))
+ << s << ": " << err;
+ EXPECT_EQ(in, out);
+}
+
+TEST(FormatParse, RoundTripDistantPast) {
+ const absl::TimeZone tz = absl::UTCTimeZone();
+ const absl::Time in =
+ absl::FromUnixSeconds(std::numeric_limits<int64_t>::min());
+ std::string err;
+
+ absl::Time out;
+ const std::string s = absl::FormatTime(absl::RFC3339_full, in, tz);
+ EXPECT_TRUE(absl::ParseTime(absl::RFC3339_full, s, &out, &err))
+ << s << ": " << err;
+ EXPECT_EQ(in, out);
+}
+} // namespace
diff --git a/absl/time/internal/get_current_time_ios.inc b/absl/time/internal/get_current_time_ios.inc
new file mode 100644
index 0000000..f3db32b
--- /dev/null
+++ b/absl/time/internal/get_current_time_ios.inc
@@ -0,0 +1,80 @@
+#include "absl/time/clock.h"
+
+#include <sys/time.h>
+#include <ctime>
+#include <cstdint>
+
+#include "absl/base/internal/raw_logging.h"
+
+// These are not defined in the Xcode 7.3.1 SDK Headers.
+// Once we are no longer supporting Xcode 7.3.1 we can
+// remove these.
+#ifndef __WATCHOS_3_0
+#define __WATCHOS_3_0 30000
+#endif
+
+#ifndef __TVOS_10_0
+#define __TVOS_10_0 100000
+#endif
+
+#ifndef __IPHONE_10_0
+#define __IPHONE_10_0 100000
+#endif
+
+#ifndef __MAC_10_12
+#define __MAC_10_12 101200
+#endif
+
+namespace absl {
+namespace time_internal {
+
+static int64_t GetCurrentTimeNanosFromSystem() {
+#if (__MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_12) || \
+ (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0) || \
+ (__WATCH_OS_VERSION_MAX_ALLOWED >= __WATCHOS_3_0) || \
+ (__TV_OS_VERSION_MAX_ALLOWED >= __TVOS_10_0)
+ // clock_gettime_nsec_np is not defined on SDKs before Xcode 8.0.
+ // This preprocessor logic is based upon __CLOCK_AVAILABILITY in
+ // usr/include/time.h. Once we are no longer supporting Xcode 7.3.1 we can
+ // remove this #if.
+ // We must continue to check if it is defined until we are sure that ALL the
+ // platforms we are shipping on support it.
+ // clock_gettime_nsec_np is preferred because it may give higher accuracy than
+ // gettimeofday in future Apple operating systems.
+ // Currently (macOS 10.12/iOS 10.2) clock_gettime_nsec_np accuracy is
+ // microsecond accuracy (i.e. equivalent to gettimeofday).
+ if (&clock_gettime_nsec_np != nullptr) {
+ return clock_gettime_nsec_np(CLOCK_REALTIME);
+ }
+#endif
+#if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && \
+ (__MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_12)) || \
+ (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && \
+ (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_10_0)) || \
+ (defined(__WATCH_OS_VERSION_MIN_REQUIRED) && \
+ (__WATCH_OS_VERSION_MIN_REQUIRED < __WATCHOS_3_0)) || \
+ (defined(__TV_OS_VERSION_MIN_REQUIRED) && \
+ (__TV_OS_VERSION_MIN_REQUIRED < __TVOS_10_0))
+ // We need this block in 2 different cases:
+ // a) where we are compiling with Xcode 7 in which case the block above
+ // will not be compiled in, and this is the only block executed.
+ // b) where we are compiling with Xcode 8+ but supporting operating systems
+ // that do not define clock_gettime_nsec_np, so this is in effect
+ // an else block to the block above.
+ // This block will not be compiled if the min supported version is
+ // guaranteed to supply clock_gettime_nsec_np.
+ //
+ // Once we know that clock_gettime_nsec_np is in the SDK *AND* exists on
+ // all the platforms we support, we can remove both this block and alter the
+ // block above to just call clock_gettime_nsec_np directly.
+ const int64_t kNanosPerSecond = 1000 * 1000 * 1000;
+ const int64_t kNanosPerMicrosecond = 1000;
+ struct timeval tp;
+ ABSL_RAW_CHECK(gettimeofday(&tp, nullptr) == 0, "Failed gettimeofday");
+ return (int64_t{tp.tv_sec} * kNanosPerSecond +
+ int64_t{tp.tv_usec} * kNanosPerMicrosecond);
+#endif
+}
+
+} // namespace time_internal
+} // namespace absl
diff --git a/absl/time/internal/get_current_time_posix.inc b/absl/time/internal/get_current_time_posix.inc
new file mode 100644
index 0000000..65474ca
--- /dev/null
+++ b/absl/time/internal/get_current_time_posix.inc
@@ -0,0 +1,22 @@
+#include "absl/time/clock.h"
+
+#include <sys/time.h>
+#include <ctime>
+#include <cstdint>
+
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+namespace time_internal {
+
+static int64_t GetCurrentTimeNanosFromSystem() {
+ const int64_t kNanosPerSecond = 1000 * 1000 * 1000;
+ struct timespec ts;
+ ABSL_RAW_CHECK(clock_gettime(CLOCK_REALTIME, &ts) == 0,
+ "Failed to read real-time clock.");
+ return (int64_t{ts.tv_sec} * kNanosPerSecond +
+ int64_t{ts.tv_nsec});
+}
+
+} // namespace time_internal
+} // namespace absl
diff --git a/absl/time/internal/get_current_time_windows.inc b/absl/time/internal/get_current_time_windows.inc
new file mode 100644
index 0000000..b22a9c9
--- /dev/null
+++ b/absl/time/internal/get_current_time_windows.inc
@@ -0,0 +1,17 @@
+#include "absl/time/clock.h"
+
+#include <chrono>
+#include <cstdint>
+
+namespace absl {
+namespace time_internal {
+
+static int64_t GetCurrentTimeNanosFromSystem() {
+ return std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::system_clock::now() -
+ std::chrono::system_clock::from_time_t(0))
+ .count();
+}
+
+} // namespace time_internal
+} // namespace absl
diff --git a/absl/time/internal/test_util.cc b/absl/time/internal/test_util.cc
new file mode 100644
index 0000000..21d5f2a
--- /dev/null
+++ b/absl/time/internal/test_util.cc
@@ -0,0 +1,112 @@
+// 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/time/internal/test_util.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <cstring>
+
+#include "absl/base/internal/raw_logging.h"
+#include "cctz/zone_info_source.h"
+
+namespace absl {
+namespace time_internal {
+
+TimeZone LoadTimeZone(const std::string& name) {
+ TimeZone tz;
+ ABSL_RAW_CHECK(LoadTimeZone(name, &tz), name.c_str());
+ return tz;
+}
+
+} // namespace time_internal
+} // namespace absl
+
+namespace cctz_extension {
+namespace {
+
+// Embed the zoneinfo data for time zones used during tests and benchmarks.
+// The data was generated using "xxd -i zoneinfo-file". There is no need
+// to update the data as long as the tests do not depend on recent changes
+// (and the past rules remain the same).
+#include "absl/time/internal/zoneinfo.inc"
+
+const struct ZoneInfo {
+ const char* name;
+ const char* data;
+ std::size_t length;
+} kZoneInfo[] = {
+ // The three real time zones used by :time_test and :time_benchmark.
+ {"America/Los_Angeles", //
+ reinterpret_cast<char*>(America_Los_Angeles), America_Los_Angeles_len},
+ {"America/New_York", //
+ reinterpret_cast<char*>(America_New_York), America_New_York_len},
+ {"Australia/Sydney", //
+ reinterpret_cast<char*>(Australia_Sydney), Australia_Sydney_len},
+
+ // Other zones named in tests but which should fail to load.
+ {"Invalid/TimeZone", nullptr, 0},
+ {"", nullptr, 0},
+
+ // Also allow for loading the local time zone under TZ=US/Pacific.
+ {"US/Pacific", //
+ reinterpret_cast<char*>(America_Los_Angeles), America_Los_Angeles_len},
+
+ // Allows use of the local time zone from a common system-specific location.
+ {"/etc/localtime", //
+ reinterpret_cast<char*>(America_Los_Angeles), America_Los_Angeles_len},
+};
+
+class TestZoneInfoSource : public cctz::ZoneInfoSource {
+ public:
+ TestZoneInfoSource(const char* data, std::size_t size)
+ : data_(data), end_(data + size) {}
+
+ std::size_t Read(void* ptr, std::size_t size) override {
+ const std::size_t len = std::min<std::size_t>(size, end_ - data_);
+ memcpy(ptr, data_, len);
+ data_ += len;
+ return len;
+ }
+
+ int Skip(std::size_t offset) override {
+ data_ += std::min<std::size_t>(offset, end_ - data_);
+ return 0;
+ }
+
+ private:
+ const char* data_;
+ const char* const end_;
+};
+
+std::unique_ptr<cctz::ZoneInfoSource> TestFactory(
+ const std::string& name,
+ const std::function<std::unique_ptr<cctz::ZoneInfoSource>(
+ const std::string& name)>& /*fallback_factory*/) {
+ for (const ZoneInfo& zoneinfo : kZoneInfo) {
+ if (name == zoneinfo.name) {
+ if (zoneinfo.data == nullptr) return nullptr;
+ return std::unique_ptr<cctz::ZoneInfoSource>(
+ new TestZoneInfoSource(zoneinfo.data, zoneinfo.length));
+ }
+ }
+ ABSL_RAW_LOG(FATAL, "Unexpected time zone \"%s\" in test", name.c_str());
+ return nullptr;
+}
+
+} // namespace
+
+ZoneInfoSourceFactory zone_info_source_factory = TestFactory;
+
+} // namespace cctz_extension
diff --git a/absl/time/internal/test_util.h b/absl/time/internal/test_util.h
new file mode 100644
index 0000000..81a2d29
--- /dev/null
+++ b/absl/time/internal/test_util.h
@@ -0,0 +1,49 @@
+// 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_TIME_INTERNAL_TEST_UTIL_H_
+#define ABSL_TIME_INTERNAL_TEST_UTIL_H_
+
+#include <string>
+
+#include "absl/time/time.h"
+
+// This helper is a macro so that failed expectations show up with the
+// correct line numbers.
+//
+// This is for internal testing of the Base Time library itself. This is not
+// part of a public API.
+#define ABSL_INTERNAL_EXPECT_TIME(bd, y, m, d, h, min, s, off, isdst, zone) \
+ do { \
+ EXPECT_EQ(y, bd.year); \
+ EXPECT_EQ(m, bd.month); \
+ EXPECT_EQ(d, bd.day); \
+ EXPECT_EQ(h, bd.hour); \
+ EXPECT_EQ(min, bd.minute); \
+ EXPECT_EQ(s, bd.second); \
+ EXPECT_EQ(off, bd.offset); \
+ EXPECT_EQ(isdst, bd.is_dst); \
+ EXPECT_STREQ(zone, bd.zone_abbr); \
+ } while (0)
+
+namespace absl {
+namespace time_internal {
+
+// Loads the named timezone, but dies on any failure.
+absl::TimeZone LoadTimeZone(const std::string& name);
+
+} // namespace time_internal
+} // namespace absl
+
+#endif // ABSL_TIME_INTERNAL_TEST_UTIL_H_
diff --git a/absl/time/internal/zoneinfo.inc b/absl/time/internal/zoneinfo.inc
new file mode 100644
index 0000000..bfed829
--- /dev/null
+++ b/absl/time/internal/zoneinfo.inc
@@ -0,0 +1,729 @@
+unsigned char America_Los_Angeles[] = {
+ 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba,
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00,
+ 0x9e, 0xa6, 0x48, 0xa0, 0x9f, 0xbb, 0x15, 0x90, 0xa0, 0x86, 0x2a, 0xa0,
+ 0xa1, 0x9a, 0xf7, 0x90, 0xcb, 0x89, 0x1a, 0xa0, 0xd2, 0x23, 0xf4, 0x70,
+ 0xd2, 0x61, 0x26, 0x10, 0xd6, 0xfe, 0x74, 0x5c, 0xd8, 0x80, 0xad, 0x90,
+ 0xda, 0xfe, 0xc3, 0x90, 0xdb, 0xc0, 0x90, 0x10, 0xdc, 0xde, 0xa5, 0x90,
+ 0xdd, 0xa9, 0xac, 0x90, 0xde, 0xbe, 0x87, 0x90, 0xdf, 0x89, 0x8e, 0x90,
+ 0xe0, 0x9e, 0x69, 0x90, 0xe1, 0x69, 0x70, 0x90, 0xe2, 0x7e, 0x4b, 0x90,
+ 0xe3, 0x49, 0x52, 0x90, 0xe4, 0x5e, 0x2d, 0x90, 0xe5, 0x29, 0x34, 0x90,
+ 0xe6, 0x47, 0x4a, 0x10, 0xe7, 0x12, 0x51, 0x10, 0xe8, 0x27, 0x2c, 0x10,
+ 0xe8, 0xf2, 0x33, 0x10, 0xea, 0x07, 0x0e, 0x10, 0xea, 0xd2, 0x15, 0x10,
+ 0xeb, 0xe6, 0xf0, 0x10, 0xec, 0xb1, 0xf7, 0x10, 0xed, 0xc6, 0xd2, 0x10,
+ 0xee, 0x91, 0xd9, 0x10, 0xef, 0xaf, 0xee, 0x90, 0xf0, 0x71, 0xbb, 0x10,
+ 0xf1, 0x8f, 0xd0, 0x90, 0xf2, 0x7f, 0xc1, 0x90, 0xf3, 0x6f, 0xb2, 0x90,
+ 0xf4, 0x5f, 0xa3, 0x90, 0xf5, 0x4f, 0x94, 0x90, 0xf6, 0x3f, 0x85, 0x90,
+ 0xf7, 0x2f, 0x76, 0x90, 0xf8, 0x28, 0xa2, 0x10, 0xf9, 0x0f, 0x58, 0x90,
+ 0xfa, 0x08, 0x84, 0x10, 0xfa, 0xf8, 0x83, 0x20, 0xfb, 0xe8, 0x66, 0x10,
+ 0xfc, 0xd8, 0x65, 0x20, 0xfd, 0xc8, 0x48, 0x10, 0xfe, 0xb8, 0x47, 0x20,
+ 0xff, 0xa8, 0x2a, 0x10, 0x00, 0x98, 0x29, 0x20, 0x01, 0x88, 0x0c, 0x10,
+ 0x02, 0x78, 0x0b, 0x20, 0x03, 0x71, 0x28, 0x90, 0x04, 0x61, 0x27, 0xa0,
+ 0x05, 0x51, 0x0a, 0x90, 0x06, 0x41, 0x09, 0xa0, 0x07, 0x30, 0xec, 0x90,
+ 0x07, 0x8d, 0x43, 0xa0, 0x09, 0x10, 0xce, 0x90, 0x09, 0xad, 0xbf, 0x20,
+ 0x0a, 0xf0, 0xb0, 0x90, 0x0b, 0xe0, 0xaf, 0xa0, 0x0c, 0xd9, 0xcd, 0x10,
+ 0x0d, 0xc0, 0x91, 0xa0, 0x0e, 0xb9, 0xaf, 0x10, 0x0f, 0xa9, 0xae, 0x20,
+ 0x10, 0x99, 0x91, 0x10, 0x11, 0x89, 0x90, 0x20, 0x12, 0x79, 0x73, 0x10,
+ 0x13, 0x69, 0x72, 0x20, 0x14, 0x59, 0x55, 0x10, 0x15, 0x49, 0x54, 0x20,
+ 0x16, 0x39, 0x37, 0x10, 0x17, 0x29, 0x36, 0x20, 0x18, 0x22, 0x53, 0x90,
+ 0x19, 0x09, 0x18, 0x20, 0x1a, 0x02, 0x35, 0x90, 0x1a, 0xf2, 0x34, 0xa0,
+ 0x1b, 0xe2, 0x17, 0x90, 0x1c, 0xd2, 0x16, 0xa0, 0x1d, 0xc1, 0xf9, 0x90,
+ 0x1e, 0xb1, 0xf8, 0xa0, 0x1f, 0xa1, 0xdb, 0x90, 0x20, 0x76, 0x2b, 0x20,
+ 0x21, 0x81, 0xbd, 0x90, 0x22, 0x56, 0x0d, 0x20, 0x23, 0x6a, 0xda, 0x10,
+ 0x24, 0x35, 0xef, 0x20, 0x25, 0x4a, 0xbc, 0x10, 0x26, 0x15, 0xd1, 0x20,
+ 0x27, 0x2a, 0x9e, 0x10, 0x27, 0xfe, 0xed, 0xa0, 0x29, 0x0a, 0x80, 0x10,
+ 0x29, 0xde, 0xcf, 0xa0, 0x2a, 0xea, 0x62, 0x10, 0x2b, 0xbe, 0xb1, 0xa0,
+ 0x2c, 0xd3, 0x7e, 0x90, 0x2d, 0x9e, 0x93, 0xa0, 0x2e, 0xb3, 0x60, 0x90,
+ 0x2f, 0x7e, 0x75, 0xa0, 0x30, 0x93, 0x42, 0x90, 0x31, 0x67, 0x92, 0x20,
+ 0x32, 0x73, 0x24, 0x90, 0x33, 0x47, 0x74, 0x20, 0x34, 0x53, 0x06, 0x90,
+ 0x35, 0x27, 0x56, 0x20, 0x36, 0x32, 0xe8, 0x90, 0x37, 0x07, 0x38, 0x20,
+ 0x38, 0x1c, 0x05, 0x10, 0x38, 0xe7, 0x1a, 0x20, 0x39, 0xfb, 0xe7, 0x10,
+ 0x3a, 0xc6, 0xfc, 0x20, 0x3b, 0xdb, 0xc9, 0x10, 0x3c, 0xb0, 0x18, 0xa0,
+ 0x3d, 0xbb, 0xab, 0x10, 0x3e, 0x8f, 0xfa, 0xa0, 0x3f, 0x9b, 0x8d, 0x10,
+ 0x40, 0x6f, 0xdc, 0xa0, 0x41, 0x84, 0xa9, 0x90, 0x42, 0x4f, 0xbe, 0xa0,
+ 0x43, 0x64, 0x8b, 0x90, 0x44, 0x2f, 0xa0, 0xa0, 0x45, 0x44, 0x6d, 0x90,
+ 0x45, 0xf3, 0xd3, 0x20, 0x47, 0x2d, 0x8a, 0x10, 0x47, 0xd3, 0xb5, 0x20,
+ 0x49, 0x0d, 0x6c, 0x10, 0x49, 0xb3, 0x97, 0x20, 0x4a, 0xed, 0x4e, 0x10,
+ 0x4b, 0x9c, 0xb3, 0xa0, 0x4c, 0xd6, 0x6a, 0x90, 0x4d, 0x7c, 0x95, 0xa0,
+ 0x4e, 0xb6, 0x4c, 0x90, 0x4f, 0x5c, 0x77, 0xa0, 0x50, 0x96, 0x2e, 0x90,
+ 0x51, 0x3c, 0x59, 0xa0, 0x52, 0x76, 0x10, 0x90, 0x53, 0x1c, 0x3b, 0xa0,
+ 0x54, 0x55, 0xf2, 0x90, 0x54, 0xfc, 0x1d, 0xa0, 0x56, 0x35, 0xd4, 0x90,
+ 0x56, 0xe5, 0x3a, 0x20, 0x58, 0x1e, 0xf1, 0x10, 0x58, 0xc5, 0x1c, 0x20,
+ 0x59, 0xfe, 0xd3, 0x10, 0x5a, 0xa4, 0xfe, 0x20, 0x5b, 0xde, 0xb5, 0x10,
+ 0x5c, 0x84, 0xe0, 0x20, 0x5d, 0xbe, 0x97, 0x10, 0x5e, 0x64, 0xc2, 0x20,
+ 0x5f, 0x9e, 0x79, 0x10, 0x60, 0x4d, 0xde, 0xa0, 0x61, 0x87, 0x95, 0x90,
+ 0x62, 0x2d, 0xc0, 0xa0, 0x63, 0x67, 0x77, 0x90, 0x64, 0x0d, 0xa2, 0xa0,
+ 0x65, 0x47, 0x59, 0x90, 0x65, 0xed, 0x84, 0xa0, 0x67, 0x27, 0x3b, 0x90,
+ 0x67, 0xcd, 0x66, 0xa0, 0x69, 0x07, 0x1d, 0x90, 0x69, 0xad, 0x48, 0xa0,
+ 0x6a, 0xe6, 0xff, 0x90, 0x6b, 0x96, 0x65, 0x20, 0x6c, 0xd0, 0x1c, 0x10,
+ 0x6d, 0x76, 0x47, 0x20, 0x6e, 0xaf, 0xfe, 0x10, 0x6f, 0x56, 0x29, 0x20,
+ 0x70, 0x8f, 0xe0, 0x10, 0x71, 0x36, 0x0b, 0x20, 0x72, 0x6f, 0xc2, 0x10,
+ 0x73, 0x15, 0xed, 0x20, 0x74, 0x4f, 0xa4, 0x10, 0x74, 0xff, 0x09, 0xa0,
+ 0x76, 0x38, 0xc0, 0x90, 0x76, 0xde, 0xeb, 0xa0, 0x78, 0x18, 0xa2, 0x90,
+ 0x78, 0xbe, 0xcd, 0xa0, 0x79, 0xf8, 0x84, 0x90, 0x7a, 0x9e, 0xaf, 0xa0,
+ 0x7b, 0xd8, 0x66, 0x90, 0x7c, 0x7e, 0x91, 0xa0, 0x7d, 0xb8, 0x48, 0x90,
+ 0x7e, 0x5e, 0x73, 0xa0, 0x7f, 0x98, 0x2a, 0x90, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x03, 0x04, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0xff, 0xff, 0x91, 0x26, 0x00, 0x00, 0xff, 0xff, 0x9d, 0x90,
+ 0x01, 0x04, 0xff, 0xff, 0x8f, 0x80, 0x00, 0x08, 0xff, 0xff, 0x9d, 0x90,
+ 0x01, 0x0c, 0xff, 0xff, 0x9d, 0x90, 0x01, 0x10, 0x4c, 0x4d, 0x54, 0x00,
+ 0x50, 0x44, 0x54, 0x00, 0x50, 0x53, 0x54, 0x00, 0x50, 0x57, 0x54, 0x00,
+ 0x50, 0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xbb, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0xf8, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x5e, 0x04,
+ 0x1a, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x9e, 0xa6, 0x48, 0xa0, 0xff, 0xff,
+ 0xff, 0xff, 0x9f, 0xbb, 0x15, 0x90, 0xff, 0xff, 0xff, 0xff, 0xa0, 0x86,
+ 0x2a, 0xa0, 0xff, 0xff, 0xff, 0xff, 0xa1, 0x9a, 0xf7, 0x90, 0xff, 0xff,
+ 0xff, 0xff, 0xcb, 0x89, 0x1a, 0xa0, 0xff, 0xff, 0xff, 0xff, 0xd2, 0x23,
+ 0xf4, 0x70, 0xff, 0xff, 0xff, 0xff, 0xd2, 0x61, 0x26, 0x10, 0xff, 0xff,
+ 0xff, 0xff, 0xd6, 0xfe, 0x74, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xd8, 0x80,
+ 0xad, 0x90, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfe, 0xc3, 0x90, 0xff, 0xff,
+ 0xff, 0xff, 0xdb, 0xc0, 0x90, 0x10, 0xff, 0xff, 0xff, 0xff, 0xdc, 0xde,
+ 0xa5, 0x90, 0xff, 0xff, 0xff, 0xff, 0xdd, 0xa9, 0xac, 0x90, 0xff, 0xff,
+ 0xff, 0xff, 0xde, 0xbe, 0x87, 0x90, 0xff, 0xff, 0xff, 0xff, 0xdf, 0x89,
+ 0x8e, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x9e, 0x69, 0x90, 0xff, 0xff,
+ 0xff, 0xff, 0xe1, 0x69, 0x70, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe2, 0x7e,
+ 0x4b, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe3, 0x49, 0x52, 0x90, 0xff, 0xff,
+ 0xff, 0xff, 0xe4, 0x5e, 0x2d, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe5, 0x29,
+ 0x34, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe6, 0x47, 0x4a, 0x10, 0xff, 0xff,
+ 0xff, 0xff, 0xe7, 0x12, 0x51, 0x10, 0xff, 0xff, 0xff, 0xff, 0xe8, 0x27,
+ 0x2c, 0x10, 0xff, 0xff, 0xff, 0xff, 0xe8, 0xf2, 0x33, 0x10, 0xff, 0xff,
+ 0xff, 0xff, 0xea, 0x07, 0x0e, 0x10, 0xff, 0xff, 0xff, 0xff, 0xea, 0xd2,
+ 0x15, 0x10, 0xff, 0xff, 0xff, 0xff, 0xeb, 0xe6, 0xf0, 0x10, 0xff, 0xff,
+ 0xff, 0xff, 0xec, 0xb1, 0xf7, 0x10, 0xff, 0xff, 0xff, 0xff, 0xed, 0xc6,
+ 0xd2, 0x10, 0xff, 0xff, 0xff, 0xff, 0xee, 0x91, 0xd9, 0x10, 0xff, 0xff,
+ 0xff, 0xff, 0xef, 0xaf, 0xee, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x71,
+ 0xbb, 0x10, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x8f, 0xd0, 0x90, 0xff, 0xff,
+ 0xff, 0xff, 0xf2, 0x7f, 0xc1, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x6f,
+ 0xb2, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x5f, 0xa3, 0x90, 0xff, 0xff,
+ 0xff, 0xff, 0xf5, 0x4f, 0x94, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf6, 0x3f,
+ 0x85, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x2f, 0x76, 0x90, 0xff, 0xff,
+ 0xff, 0xff, 0xf8, 0x28, 0xa2, 0x10, 0xff, 0xff, 0xff, 0xff, 0xf9, 0x0f,
+ 0x58, 0x90, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x08, 0x84, 0x10, 0xff, 0xff,
+ 0xff, 0xff, 0xfa, 0xf8, 0x83, 0x20, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xe8,
+ 0x66, 0x10, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xd8, 0x65, 0x20, 0xff, 0xff,
+ 0xff, 0xff, 0xfd, 0xc8, 0x48, 0x10, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xb8,
+ 0x47, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa8, 0x2a, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x98, 0x29, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01, 0x88,
+ 0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x78, 0x0b, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x03, 0x71, 0x28, 0x90, 0x00, 0x00, 0x00, 0x00, 0x04, 0x61,
+ 0x27, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x05, 0x51, 0x0a, 0x90, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x41, 0x09, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x07, 0x30,
+ 0xec, 0x90, 0x00, 0x00, 0x00, 0x00, 0x07, 0x8d, 0x43, 0xa0, 0x00, 0x00,
+ 0x00, 0x00, 0x09, 0x10, 0xce, 0x90, 0x00, 0x00, 0x00, 0x00, 0x09, 0xad,
+ 0xbf, 0x20, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xf0, 0xb0, 0x90, 0x00, 0x00,
+ 0x00, 0x00, 0x0b, 0xe0, 0xaf, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xd9,
+ 0xcd, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xc0, 0x91, 0xa0, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0xb9, 0xaf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xa9,
+ 0xae, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, 0x91, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x11, 0x89, 0x90, 0x20, 0x00, 0x00, 0x00, 0x00, 0x12, 0x79,
+ 0x73, 0x10, 0x00, 0x00, 0x00, 0x00, 0x13, 0x69, 0x72, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x14, 0x59, 0x55, 0x10, 0x00, 0x00, 0x00, 0x00, 0x15, 0x49,
+ 0x54, 0x20, 0x00, 0x00, 0x00, 0x00, 0x16, 0x39, 0x37, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x17, 0x29, 0x36, 0x20, 0x00, 0x00, 0x00, 0x00, 0x18, 0x22,
+ 0x53, 0x90, 0x00, 0x00, 0x00, 0x00, 0x19, 0x09, 0x18, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x1a, 0x02, 0x35, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xf2,
+ 0x34, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xe2, 0x17, 0x90, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0xd2, 0x16, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x1d, 0xc1,
+ 0xf9, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xb1, 0xf8, 0xa0, 0x00, 0x00,
+ 0x00, 0x00, 0x1f, 0xa1, 0xdb, 0x90, 0x00, 0x00, 0x00, 0x00, 0x20, 0x76,
+ 0x2b, 0x20, 0x00, 0x00, 0x00, 0x00, 0x21, 0x81, 0xbd, 0x90, 0x00, 0x00,
+ 0x00, 0x00, 0x22, 0x56, 0x0d, 0x20, 0x00, 0x00, 0x00, 0x00, 0x23, 0x6a,
+ 0xda, 0x10, 0x00, 0x00, 0x00, 0x00, 0x24, 0x35, 0xef, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x25, 0x4a, 0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x26, 0x15,
+ 0xd1, 0x20, 0x00, 0x00, 0x00, 0x00, 0x27, 0x2a, 0x9e, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x27, 0xfe, 0xed, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x29, 0x0a,
+ 0x80, 0x10, 0x00, 0x00, 0x00, 0x00, 0x29, 0xde, 0xcf, 0xa0, 0x00, 0x00,
+ 0x00, 0x00, 0x2a, 0xea, 0x62, 0x10, 0x00, 0x00, 0x00, 0x00, 0x2b, 0xbe,
+ 0xb1, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xd3, 0x7e, 0x90, 0x00, 0x00,
+ 0x00, 0x00, 0x2d, 0x9e, 0x93, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x2e, 0xb3,
+ 0x60, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x7e, 0x75, 0xa0, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x93, 0x42, 0x90, 0x00, 0x00, 0x00, 0x00, 0x31, 0x67,
+ 0x92, 0x20, 0x00, 0x00, 0x00, 0x00, 0x32, 0x73, 0x24, 0x90, 0x00, 0x00,
+ 0x00, 0x00, 0x33, 0x47, 0x74, 0x20, 0x00, 0x00, 0x00, 0x00, 0x34, 0x53,
+ 0x06, 0x90, 0x00, 0x00, 0x00, 0x00, 0x35, 0x27, 0x56, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x36, 0x32, 0xe8, 0x90, 0x00, 0x00, 0x00, 0x00, 0x37, 0x07,
+ 0x38, 0x20, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1c, 0x05, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0xe7, 0x1a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x39, 0xfb,
+ 0xe7, 0x10, 0x00, 0x00, 0x00, 0x00, 0x3a, 0xc6, 0xfc, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x3b, 0xdb, 0xc9, 0x10, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xb0,
+ 0x18, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x3d, 0xbb, 0xab, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x3e, 0x8f, 0xfa, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x9b,
+ 0x8d, 0x10, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6f, 0xdc, 0xa0, 0x00, 0x00,
+ 0x00, 0x00, 0x41, 0x84, 0xa9, 0x90, 0x00, 0x00, 0x00, 0x00, 0x42, 0x4f,
+ 0xbe, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x43, 0x64, 0x8b, 0x90, 0x00, 0x00,
+ 0x00, 0x00, 0x44, 0x2f, 0xa0, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x45, 0x44,
+ 0x6d, 0x90, 0x00, 0x00, 0x00, 0x00, 0x45, 0xf3, 0xd3, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x47, 0x2d, 0x8a, 0x10, 0x00, 0x00, 0x00, 0x00, 0x47, 0xd3,
+ 0xb5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x49, 0x0d, 0x6c, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x49, 0xb3, 0x97, 0x20, 0x00, 0x00, 0x00, 0x00, 0x4a, 0xed,
+ 0x4e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x9c, 0xb3, 0xa0, 0x00, 0x00,
+ 0x00, 0x00, 0x4c, 0xd6, 0x6a, 0x90, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x7c,
+ 0x95, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xb6, 0x4c, 0x90, 0x00, 0x00,
+ 0x00, 0x00, 0x4f, 0x5c, 0x77, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x50, 0x96,
+ 0x2e, 0x90, 0x00, 0x00, 0x00, 0x00, 0x51, 0x3c, 0x59, 0xa0, 0x00, 0x00,
+ 0x00, 0x00, 0x52, 0x76, 0x10, 0x90, 0x00, 0x00, 0x00, 0x00, 0x53, 0x1c,
+ 0x3b, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0xf2, 0x90, 0x00, 0x00,
+ 0x00, 0x00, 0x54, 0xfc, 0x1d, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x56, 0x35,
+ 0xd4, 0x90, 0x00, 0x00, 0x00, 0x00, 0x56, 0xe5, 0x3a, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x58, 0x1e, 0xf1, 0x10, 0x00, 0x00, 0x00, 0x00, 0x58, 0xc5,
+ 0x1c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x59, 0xfe, 0xd3, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x5a, 0xa4, 0xfe, 0x20, 0x00, 0x00, 0x00, 0x00, 0x5b, 0xde,
+ 0xb5, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x84, 0xe0, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x5d, 0xbe, 0x97, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x64,
+ 0xc2, 0x20, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x9e, 0x79, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x4d, 0xde, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x61, 0x87,
+ 0x95, 0x90, 0x00, 0x00, 0x00, 0x00, 0x62, 0x2d, 0xc0, 0xa0, 0x00, 0x00,
+ 0x00, 0x00, 0x63, 0x67, 0x77, 0x90, 0x00, 0x00, 0x00, 0x00, 0x64, 0x0d,
+ 0xa2, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x65, 0x47, 0x59, 0x90, 0x00, 0x00,
+ 0x00, 0x00, 0x65, 0xed, 0x84, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x67, 0x27,
+ 0x3b, 0x90, 0x00, 0x00, 0x00, 0x00, 0x67, 0xcd, 0x66, 0xa0, 0x00, 0x00,
+ 0x00, 0x00, 0x69, 0x07, 0x1d, 0x90, 0x00, 0x00, 0x00, 0x00, 0x69, 0xad,
+ 0x48, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x6a, 0xe6, 0xff, 0x90, 0x00, 0x00,
+ 0x00, 0x00, 0x6b, 0x96, 0x65, 0x20, 0x00, 0x00, 0x00, 0x00, 0x6c, 0xd0,
+ 0x1c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x76, 0x47, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x6e, 0xaf, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x56,
+ 0x29, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, 0x8f, 0xe0, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x71, 0x36, 0x0b, 0x20, 0x00, 0x00, 0x00, 0x00, 0x72, 0x6f,
+ 0xc2, 0x10, 0x00, 0x00, 0x00, 0x00, 0x73, 0x15, 0xed, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x74, 0x4f, 0xa4, 0x10, 0x00, 0x00, 0x00, 0x00, 0x74, 0xff,
+ 0x09, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x76, 0x38, 0xc0, 0x90, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xde, 0xeb, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x78, 0x18,
+ 0xa2, 0x90, 0x00, 0x00, 0x00, 0x00, 0x78, 0xbe, 0xcd, 0xa0, 0x00, 0x00,
+ 0x00, 0x00, 0x79, 0xf8, 0x84, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x9e,
+ 0xaf, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x7b, 0xd8, 0x66, 0x90, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0x7e, 0x91, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x7d, 0xb8,
+ 0x48, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x5e, 0x73, 0xa0, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0x98, 0x2a, 0x90, 0x00, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x03, 0x04, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0xff, 0xff, 0x91, 0x26, 0x00, 0x00, 0xff, 0xff, 0x9d, 0x90, 0x01,
+ 0x04, 0xff, 0xff, 0x8f, 0x80, 0x00, 0x08, 0xff, 0xff, 0x9d, 0x90, 0x01,
+ 0x0c, 0xff, 0xff, 0x9d, 0x90, 0x01, 0x10, 0x4c, 0x4d, 0x54, 0x00, 0x50,
+ 0x44, 0x54, 0x00, 0x50, 0x53, 0x54, 0x00, 0x50, 0x57, 0x54, 0x00, 0x50,
+ 0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x0a, 0x50, 0x53, 0x54, 0x38, 0x50, 0x44, 0x54, 0x2c, 0x4d, 0x33,
+ 0x2e, 0x32, 0x2e, 0x30, 0x2c, 0x4d, 0x31, 0x31, 0x2e, 0x31, 0x2e, 0x30,
+ 0x0a
+};
+unsigned int America_Los_Angeles_len = 2845;
+unsigned char America_New_York[] = {
+ 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec,
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00,
+ 0x9e, 0xa6, 0x1e, 0x70, 0x9f, 0xba, 0xeb, 0x60, 0xa0, 0x86, 0x00, 0x70,
+ 0xa1, 0x9a, 0xcd, 0x60, 0xa2, 0x65, 0xe2, 0x70, 0xa3, 0x83, 0xe9, 0xe0,
+ 0xa4, 0x6a, 0xae, 0x70, 0xa5, 0x35, 0xa7, 0x60, 0xa6, 0x53, 0xca, 0xf0,
+ 0xa7, 0x15, 0x89, 0x60, 0xa8, 0x33, 0xac, 0xf0, 0xa8, 0xfe, 0xa5, 0xe0,
+ 0xaa, 0x13, 0x8e, 0xf0, 0xaa, 0xde, 0x87, 0xe0, 0xab, 0xf3, 0x70, 0xf0,
+ 0xac, 0xbe, 0x69, 0xe0, 0xad, 0xd3, 0x52, 0xf0, 0xae, 0x9e, 0x4b, 0xe0,
+ 0xaf, 0xb3, 0x34, 0xf0, 0xb0, 0x7e, 0x2d, 0xe0, 0xb1, 0x9c, 0x51, 0x70,
+ 0xb2, 0x67, 0x4a, 0x60, 0xb3, 0x7c, 0x33, 0x70, 0xb4, 0x47, 0x2c, 0x60,
+ 0xb5, 0x5c, 0x15, 0x70, 0xb6, 0x27, 0x0e, 0x60, 0xb7, 0x3b, 0xf7, 0x70,
+ 0xb8, 0x06, 0xf0, 0x60, 0xb9, 0x1b, 0xd9, 0x70, 0xb9, 0xe6, 0xd2, 0x60,
+ 0xbb, 0x04, 0xf5, 0xf0, 0xbb, 0xc6, 0xb4, 0x60, 0xbc, 0xe4, 0xd7, 0xf0,
+ 0xbd, 0xaf, 0xd0, 0xe0, 0xbe, 0xc4, 0xb9, 0xf0, 0xbf, 0x8f, 0xb2, 0xe0,
+ 0xc0, 0xa4, 0x9b, 0xf0, 0xc1, 0x6f, 0x94, 0xe0, 0xc2, 0x84, 0x7d, 0xf0,
+ 0xc3, 0x4f, 0x76, 0xe0, 0xc4, 0x64, 0x5f, 0xf0, 0xc5, 0x2f, 0x58, 0xe0,
+ 0xc6, 0x4d, 0x7c, 0x70, 0xc7, 0x0f, 0x3a, 0xe0, 0xc8, 0x2d, 0x5e, 0x70,
+ 0xc8, 0xf8, 0x57, 0x60, 0xca, 0x0d, 0x40, 0x70, 0xca, 0xd8, 0x39, 0x60,
+ 0xcb, 0x88, 0xf0, 0x70, 0xd2, 0x23, 0xf4, 0x70, 0xd2, 0x60, 0xfb, 0xe0,
+ 0xd3, 0x75, 0xe4, 0xf0, 0xd4, 0x40, 0xdd, 0xe0, 0xd5, 0x55, 0xc6, 0xf0,
+ 0xd6, 0x20, 0xbf, 0xe0, 0xd7, 0x35, 0xa8, 0xf0, 0xd8, 0x00, 0xa1, 0xe0,
+ 0xd9, 0x15, 0x8a, 0xf0, 0xd9, 0xe0, 0x83, 0xe0, 0xda, 0xfe, 0xa7, 0x70,
+ 0xdb, 0xc0, 0x65, 0xe0, 0xdc, 0xde, 0x89, 0x70, 0xdd, 0xa9, 0x82, 0x60,
+ 0xde, 0xbe, 0x6b, 0x70, 0xdf, 0x89, 0x64, 0x60, 0xe0, 0x9e, 0x4d, 0x70,
+ 0xe1, 0x69, 0x46, 0x60, 0xe2, 0x7e, 0x2f, 0x70, 0xe3, 0x49, 0x28, 0x60,
+ 0xe4, 0x5e, 0x11, 0x70, 0xe5, 0x57, 0x2e, 0xe0, 0xe6, 0x47, 0x2d, 0xf0,
+ 0xe7, 0x37, 0x10, 0xe0, 0xe8, 0x27, 0x0f, 0xf0, 0xe9, 0x16, 0xf2, 0xe0,
+ 0xea, 0x06, 0xf1, 0xf0, 0xea, 0xf6, 0xd4, 0xe0, 0xeb, 0xe6, 0xd3, 0xf0,
+ 0xec, 0xd6, 0xb6, 0xe0, 0xed, 0xc6, 0xb5, 0xf0, 0xee, 0xbf, 0xd3, 0x60,
+ 0xef, 0xaf, 0xd2, 0x70, 0xf0, 0x9f, 0xb5, 0x60, 0xf1, 0x8f, 0xb4, 0x70,
+ 0xf2, 0x7f, 0x97, 0x60, 0xf3, 0x6f, 0x96, 0x70, 0xf4, 0x5f, 0x79, 0x60,
+ 0xf5, 0x4f, 0x78, 0x70, 0xf6, 0x3f, 0x5b, 0x60, 0xf7, 0x2f, 0x5a, 0x70,
+ 0xf8, 0x28, 0x77, 0xe0, 0xf9, 0x0f, 0x3c, 0x70, 0xfa, 0x08, 0x59, 0xe0,
+ 0xfa, 0xf8, 0x58, 0xf0, 0xfb, 0xe8, 0x3b, 0xe0, 0xfc, 0xd8, 0x3a, 0xf0,
+ 0xfd, 0xc8, 0x1d, 0xe0, 0xfe, 0xb8, 0x1c, 0xf0, 0xff, 0xa7, 0xff, 0xe0,
+ 0x00, 0x97, 0xfe, 0xf0, 0x01, 0x87, 0xe1, 0xe0, 0x02, 0x77, 0xe0, 0xf0,
+ 0x03, 0x70, 0xfe, 0x60, 0x04, 0x60, 0xfd, 0x70, 0x05, 0x50, 0xe0, 0x60,
+ 0x06, 0x40, 0xdf, 0x70, 0x07, 0x30, 0xc2, 0x60, 0x07, 0x8d, 0x19, 0x70,
+ 0x09, 0x10, 0xa4, 0x60, 0x09, 0xad, 0x94, 0xf0, 0x0a, 0xf0, 0x86, 0x60,
+ 0x0b, 0xe0, 0x85, 0x70, 0x0c, 0xd9, 0xa2, 0xe0, 0x0d, 0xc0, 0x67, 0x70,
+ 0x0e, 0xb9, 0x84, 0xe0, 0x0f, 0xa9, 0x83, 0xf0, 0x10, 0x99, 0x66, 0xe0,
+ 0x11, 0x89, 0x65, 0xf0, 0x12, 0x79, 0x48, 0xe0, 0x13, 0x69, 0x47, 0xf0,
+ 0x14, 0x59, 0x2a, 0xe0, 0x15, 0x49, 0x29, 0xf0, 0x16, 0x39, 0x0c, 0xe0,
+ 0x17, 0x29, 0x0b, 0xf0, 0x18, 0x22, 0x29, 0x60, 0x19, 0x08, 0xed, 0xf0,
+ 0x1a, 0x02, 0x0b, 0x60, 0x1a, 0xf2, 0x0a, 0x70, 0x1b, 0xe1, 0xed, 0x60,
+ 0x1c, 0xd1, 0xec, 0x70, 0x1d, 0xc1, 0xcf, 0x60, 0x1e, 0xb1, 0xce, 0x70,
+ 0x1f, 0xa1, 0xb1, 0x60, 0x20, 0x76, 0x00, 0xf0, 0x21, 0x81, 0x93, 0x60,
+ 0x22, 0x55, 0xe2, 0xf0, 0x23, 0x6a, 0xaf, 0xe0, 0x24, 0x35, 0xc4, 0xf0,
+ 0x25, 0x4a, 0x91, 0xe0, 0x26, 0x15, 0xa6, 0xf0, 0x27, 0x2a, 0x73, 0xe0,
+ 0x27, 0xfe, 0xc3, 0x70, 0x29, 0x0a, 0x55, 0xe0, 0x29, 0xde, 0xa5, 0x70,
+ 0x2a, 0xea, 0x37, 0xe0, 0x2b, 0xbe, 0x87, 0x70, 0x2c, 0xd3, 0x54, 0x60,
+ 0x2d, 0x9e, 0x69, 0x70, 0x2e, 0xb3, 0x36, 0x60, 0x2f, 0x7e, 0x4b, 0x70,
+ 0x30, 0x93, 0x18, 0x60, 0x31, 0x67, 0x67, 0xf0, 0x32, 0x72, 0xfa, 0x60,
+ 0x33, 0x47, 0x49, 0xf0, 0x34, 0x52, 0xdc, 0x60, 0x35, 0x27, 0x2b, 0xf0,
+ 0x36, 0x32, 0xbe, 0x60, 0x37, 0x07, 0x0d, 0xf0, 0x38, 0x1b, 0xda, 0xe0,
+ 0x38, 0xe6, 0xef, 0xf0, 0x39, 0xfb, 0xbc, 0xe0, 0x3a, 0xc6, 0xd1, 0xf0,
+ 0x3b, 0xdb, 0x9e, 0xe0, 0x3c, 0xaf, 0xee, 0x70, 0x3d, 0xbb, 0x80, 0xe0,
+ 0x3e, 0x8f, 0xd0, 0x70, 0x3f, 0x9b, 0x62, 0xe0, 0x40, 0x6f, 0xb2, 0x70,
+ 0x41, 0x84, 0x7f, 0x60, 0x42, 0x4f, 0x94, 0x70, 0x43, 0x64, 0x61, 0x60,
+ 0x44, 0x2f, 0x76, 0x70, 0x45, 0x44, 0x43, 0x60, 0x45, 0xf3, 0xa8, 0xf0,
+ 0x47, 0x2d, 0x5f, 0xe0, 0x47, 0xd3, 0x8a, 0xf0, 0x49, 0x0d, 0x41, 0xe0,
+ 0x49, 0xb3, 0x6c, 0xf0, 0x4a, 0xed, 0x23, 0xe0, 0x4b, 0x9c, 0x89, 0x70,
+ 0x4c, 0xd6, 0x40, 0x60, 0x4d, 0x7c, 0x6b, 0x70, 0x4e, 0xb6, 0x22, 0x60,
+ 0x4f, 0x5c, 0x4d, 0x70, 0x50, 0x96, 0x04, 0x60, 0x51, 0x3c, 0x2f, 0x70,
+ 0x52, 0x75, 0xe6, 0x60, 0x53, 0x1c, 0x11, 0x70, 0x54, 0x55, 0xc8, 0x60,
+ 0x54, 0xfb, 0xf3, 0x70, 0x56, 0x35, 0xaa, 0x60, 0x56, 0xe5, 0x0f, 0xf0,
+ 0x58, 0x1e, 0xc6, 0xe0, 0x58, 0xc4, 0xf1, 0xf0, 0x59, 0xfe, 0xa8, 0xe0,
+ 0x5a, 0xa4, 0xd3, 0xf0, 0x5b, 0xde, 0x8a, 0xe0, 0x5c, 0x84, 0xb5, 0xf0,
+ 0x5d, 0xbe, 0x6c, 0xe0, 0x5e, 0x64, 0x97, 0xf0, 0x5f, 0x9e, 0x4e, 0xe0,
+ 0x60, 0x4d, 0xb4, 0x70, 0x61, 0x87, 0x6b, 0x60, 0x62, 0x2d, 0x96, 0x70,
+ 0x63, 0x67, 0x4d, 0x60, 0x64, 0x0d, 0x78, 0x70, 0x65, 0x47, 0x2f, 0x60,
+ 0x65, 0xed, 0x5a, 0x70, 0x67, 0x27, 0x11, 0x60, 0x67, 0xcd, 0x3c, 0x70,
+ 0x69, 0x06, 0xf3, 0x60, 0x69, 0xad, 0x1e, 0x70, 0x6a, 0xe6, 0xd5, 0x60,
+ 0x6b, 0x96, 0x3a, 0xf0, 0x6c, 0xcf, 0xf1, 0xe0, 0x6d, 0x76, 0x1c, 0xf0,
+ 0x6e, 0xaf, 0xd3, 0xe0, 0x6f, 0x55, 0xfe, 0xf0, 0x70, 0x8f, 0xb5, 0xe0,
+ 0x71, 0x35, 0xe0, 0xf0, 0x72, 0x6f, 0x97, 0xe0, 0x73, 0x15, 0xc2, 0xf0,
+ 0x74, 0x4f, 0x79, 0xe0, 0x74, 0xfe, 0xdf, 0x70, 0x76, 0x38, 0x96, 0x60,
+ 0x76, 0xde, 0xc1, 0x70, 0x78, 0x18, 0x78, 0x60, 0x78, 0xbe, 0xa3, 0x70,
+ 0x79, 0xf8, 0x5a, 0x60, 0x7a, 0x9e, 0x85, 0x70, 0x7b, 0xd8, 0x3c, 0x60,
+ 0x7c, 0x7e, 0x67, 0x70, 0x7d, 0xb8, 0x1e, 0x60, 0x7e, 0x5e, 0x49, 0x70,
+ 0x7f, 0x98, 0x00, 0x60, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x04, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0xff, 0xff, 0xba, 0x9e, 0x00, 0x00, 0xff, 0xff, 0xc7, 0xc0, 0x01, 0x04,
+ 0xff, 0xff, 0xb9, 0xb0, 0x00, 0x08, 0xff, 0xff, 0xc7, 0xc0, 0x01, 0x0c,
+ 0xff, 0xff, 0xc7, 0xc0, 0x01, 0x10, 0x4c, 0x4d, 0x54, 0x00, 0x45, 0x44,
+ 0x54, 0x00, 0x45, 0x53, 0x54, 0x00, 0x45, 0x57, 0x54, 0x00, 0x45, 0x50,
+ 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xed,
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x5e, 0x03, 0xf0, 0x90,
+ 0xff, 0xff, 0xff, 0xff, 0x9e, 0xa6, 0x1e, 0x70, 0xff, 0xff, 0xff, 0xff,
+ 0x9f, 0xba, 0xeb, 0x60, 0xff, 0xff, 0xff, 0xff, 0xa0, 0x86, 0x00, 0x70,
+ 0xff, 0xff, 0xff, 0xff, 0xa1, 0x9a, 0xcd, 0x60, 0xff, 0xff, 0xff, 0xff,
+ 0xa2, 0x65, 0xe2, 0x70, 0xff, 0xff, 0xff, 0xff, 0xa3, 0x83, 0xe9, 0xe0,
+ 0xff, 0xff, 0xff, 0xff, 0xa4, 0x6a, 0xae, 0x70, 0xff, 0xff, 0xff, 0xff,
+ 0xa5, 0x35, 0xa7, 0x60, 0xff, 0xff, 0xff, 0xff, 0xa6, 0x53, 0xca, 0xf0,
+ 0xff, 0xff, 0xff, 0xff, 0xa7, 0x15, 0x89, 0x60, 0xff, 0xff, 0xff, 0xff,
+ 0xa8, 0x33, 0xac, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xa8, 0xfe, 0xa5, 0xe0,
+ 0xff, 0xff, 0xff, 0xff, 0xaa, 0x13, 0x8e, 0xf0, 0xff, 0xff, 0xff, 0xff,
+ 0xaa, 0xde, 0x87, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xab, 0xf3, 0x70, 0xf0,
+ 0xff, 0xff, 0xff, 0xff, 0xac, 0xbe, 0x69, 0xe0, 0xff, 0xff, 0xff, 0xff,
+ 0xad, 0xd3, 0x52, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xae, 0x9e, 0x4b, 0xe0,
+ 0xff, 0xff, 0xff, 0xff, 0xaf, 0xb3, 0x34, 0xf0, 0xff, 0xff, 0xff, 0xff,
+ 0xb0, 0x7e, 0x2d, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x9c, 0x51, 0x70,
+ 0xff, 0xff, 0xff, 0xff, 0xb2, 0x67, 0x4a, 0x60, 0xff, 0xff, 0xff, 0xff,
+ 0xb3, 0x7c, 0x33, 0x70, 0xff, 0xff, 0xff, 0xff, 0xb4, 0x47, 0x2c, 0x60,
+ 0xff, 0xff, 0xff, 0xff, 0xb5, 0x5c, 0x15, 0x70, 0xff, 0xff, 0xff, 0xff,
+ 0xb6, 0x27, 0x0e, 0x60, 0xff, 0xff, 0xff, 0xff, 0xb7, 0x3b, 0xf7, 0x70,
+ 0xff, 0xff, 0xff, 0xff, 0xb8, 0x06, 0xf0, 0x60, 0xff, 0xff, 0xff, 0xff,
+ 0xb9, 0x1b, 0xd9, 0x70, 0xff, 0xff, 0xff, 0xff, 0xb9, 0xe6, 0xd2, 0x60,
+ 0xff, 0xff, 0xff, 0xff, 0xbb, 0x04, 0xf5, 0xf0, 0xff, 0xff, 0xff, 0xff,
+ 0xbb, 0xc6, 0xb4, 0x60, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe4, 0xd7, 0xf0,
+ 0xff, 0xff, 0xff, 0xff, 0xbd, 0xaf, 0xd0, 0xe0, 0xff, 0xff, 0xff, 0xff,
+ 0xbe, 0xc4, 0xb9, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x8f, 0xb2, 0xe0,
+ 0xff, 0xff, 0xff, 0xff, 0xc0, 0xa4, 0x9b, 0xf0, 0xff, 0xff, 0xff, 0xff,
+ 0xc1, 0x6f, 0x94, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x84, 0x7d, 0xf0,
+ 0xff, 0xff, 0xff, 0xff, 0xc3, 0x4f, 0x76, 0xe0, 0xff, 0xff, 0xff, 0xff,
+ 0xc4, 0x64, 0x5f, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xc5, 0x2f, 0x58, 0xe0,
+ 0xff, 0xff, 0xff, 0xff, 0xc6, 0x4d, 0x7c, 0x70, 0xff, 0xff, 0xff, 0xff,
+ 0xc7, 0x0f, 0x3a, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xc8, 0x2d, 0x5e, 0x70,
+ 0xff, 0xff, 0xff, 0xff, 0xc8, 0xf8, 0x57, 0x60, 0xff, 0xff, 0xff, 0xff,
+ 0xca, 0x0d, 0x40, 0x70, 0xff, 0xff, 0xff, 0xff, 0xca, 0xd8, 0x39, 0x60,
+ 0xff, 0xff, 0xff, 0xff, 0xcb, 0x88, 0xf0, 0x70, 0xff, 0xff, 0xff, 0xff,
+ 0xd2, 0x23, 0xf4, 0x70, 0xff, 0xff, 0xff, 0xff, 0xd2, 0x60, 0xfb, 0xe0,
+ 0xff, 0xff, 0xff, 0xff, 0xd3, 0x75, 0xe4, 0xf0, 0xff, 0xff, 0xff, 0xff,
+ 0xd4, 0x40, 0xdd, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xd5, 0x55, 0xc6, 0xf0,
+ 0xff, 0xff, 0xff, 0xff, 0xd6, 0x20, 0xbf, 0xe0, 0xff, 0xff, 0xff, 0xff,
+ 0xd7, 0x35, 0xa8, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xd8, 0x00, 0xa1, 0xe0,
+ 0xff, 0xff, 0xff, 0xff, 0xd9, 0x15, 0x8a, 0xf0, 0xff, 0xff, 0xff, 0xff,
+ 0xd9, 0xe0, 0x83, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfe, 0xa7, 0x70,
+ 0xff, 0xff, 0xff, 0xff, 0xdb, 0xc0, 0x65, 0xe0, 0xff, 0xff, 0xff, 0xff,
+ 0xdc, 0xde, 0x89, 0x70, 0xff, 0xff, 0xff, 0xff, 0xdd, 0xa9, 0x82, 0x60,
+ 0xff, 0xff, 0xff, 0xff, 0xde, 0xbe, 0x6b, 0x70, 0xff, 0xff, 0xff, 0xff,
+ 0xdf, 0x89, 0x64, 0x60, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x9e, 0x4d, 0x70,
+ 0xff, 0xff, 0xff, 0xff, 0xe1, 0x69, 0x46, 0x60, 0xff, 0xff, 0xff, 0xff,
+ 0xe2, 0x7e, 0x2f, 0x70, 0xff, 0xff, 0xff, 0xff, 0xe3, 0x49, 0x28, 0x60,
+ 0xff, 0xff, 0xff, 0xff, 0xe4, 0x5e, 0x11, 0x70, 0xff, 0xff, 0xff, 0xff,
+ 0xe5, 0x57, 0x2e, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xe6, 0x47, 0x2d, 0xf0,
+ 0xff, 0xff, 0xff, 0xff, 0xe7, 0x37, 0x10, 0xe0, 0xff, 0xff, 0xff, 0xff,
+ 0xe8, 0x27, 0x0f, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xe9, 0x16, 0xf2, 0xe0,
+ 0xff, 0xff, 0xff, 0xff, 0xea, 0x06, 0xf1, 0xf0, 0xff, 0xff, 0xff, 0xff,
+ 0xea, 0xf6, 0xd4, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xeb, 0xe6, 0xd3, 0xf0,
+ 0xff, 0xff, 0xff, 0xff, 0xec, 0xd6, 0xb6, 0xe0, 0xff, 0xff, 0xff, 0xff,
+ 0xed, 0xc6, 0xb5, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xee, 0xbf, 0xd3, 0x60,
+ 0xff, 0xff, 0xff, 0xff, 0xef, 0xaf, 0xd2, 0x70, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0x9f, 0xb5, 0x60, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x8f, 0xb4, 0x70,
+ 0xff, 0xff, 0xff, 0xff, 0xf2, 0x7f, 0x97, 0x60, 0xff, 0xff, 0xff, 0xff,
+ 0xf3, 0x6f, 0x96, 0x70, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x5f, 0x79, 0x60,
+ 0xff, 0xff, 0xff, 0xff, 0xf5, 0x4f, 0x78, 0x70, 0xff, 0xff, 0xff, 0xff,
+ 0xf6, 0x3f, 0x5b, 0x60, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x2f, 0x5a, 0x70,
+ 0xff, 0xff, 0xff, 0xff, 0xf8, 0x28, 0x77, 0xe0, 0xff, 0xff, 0xff, 0xff,
+ 0xf9, 0x0f, 0x3c, 0x70, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x08, 0x59, 0xe0,
+ 0xff, 0xff, 0xff, 0xff, 0xfa, 0xf8, 0x58, 0xf0, 0xff, 0xff, 0xff, 0xff,
+ 0xfb, 0xe8, 0x3b, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xd8, 0x3a, 0xf0,
+ 0xff, 0xff, 0xff, 0xff, 0xfd, 0xc8, 0x1d, 0xe0, 0xff, 0xff, 0xff, 0xff,
+ 0xfe, 0xb8, 0x1c, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa7, 0xff, 0xe0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0xfe, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x87, 0xe1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x02, 0x77, 0xe0, 0xf0,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x70, 0xfe, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x60, 0xfd, 0x70, 0x00, 0x00, 0x00, 0x00, 0x05, 0x50, 0xe0, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x06, 0x40, 0xdf, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x30, 0xc2, 0x60, 0x00, 0x00, 0x00, 0x00, 0x07, 0x8d, 0x19, 0x70,
+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x10, 0xa4, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0xad, 0x94, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xf0, 0x86, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x0b, 0xe0, 0x85, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0xd9, 0xa2, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xc0, 0x67, 0x70,
+ 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb9, 0x84, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x0f, 0xa9, 0x83, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, 0x66, 0xe0,
+ 0x00, 0x00, 0x00, 0x00, 0x11, 0x89, 0x65, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x12, 0x79, 0x48, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x13, 0x69, 0x47, 0xf0,
+ 0x00, 0x00, 0x00, 0x00, 0x14, 0x59, 0x2a, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x15, 0x49, 0x29, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x16, 0x39, 0x0c, 0xe0,
+ 0x00, 0x00, 0x00, 0x00, 0x17, 0x29, 0x0b, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x22, 0x29, 0x60, 0x00, 0x00, 0x00, 0x00, 0x19, 0x08, 0xed, 0xf0,
+ 0x00, 0x00, 0x00, 0x00, 0x1a, 0x02, 0x0b, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x1a, 0xf2, 0x0a, 0x70, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xe1, 0xed, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x1c, 0xd1, 0xec, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x1d, 0xc1, 0xcf, 0x60, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xb1, 0xce, 0x70,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0xa1, 0xb1, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x76, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x21, 0x81, 0x93, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x22, 0x55, 0xe2, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x23, 0x6a, 0xaf, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x24, 0x35, 0xc4, 0xf0,
+ 0x00, 0x00, 0x00, 0x00, 0x25, 0x4a, 0x91, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x26, 0x15, 0xa6, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x27, 0x2a, 0x73, 0xe0,
+ 0x00, 0x00, 0x00, 0x00, 0x27, 0xfe, 0xc3, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x29, 0x0a, 0x55, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x29, 0xde, 0xa5, 0x70,
+ 0x00, 0x00, 0x00, 0x00, 0x2a, 0xea, 0x37, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x2b, 0xbe, 0x87, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xd3, 0x54, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x2d, 0x9e, 0x69, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x2e, 0xb3, 0x36, 0x60, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x7e, 0x4b, 0x70,
+ 0x00, 0x00, 0x00, 0x00, 0x30, 0x93, 0x18, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x31, 0x67, 0x67, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x32, 0x72, 0xfa, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x33, 0x47, 0x49, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x34, 0x52, 0xdc, 0x60, 0x00, 0x00, 0x00, 0x00, 0x35, 0x27, 0x2b, 0xf0,
+ 0x00, 0x00, 0x00, 0x00, 0x36, 0x32, 0xbe, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x37, 0x07, 0x0d, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1b, 0xda, 0xe0,
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0xe6, 0xef, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x39, 0xfb, 0xbc, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x3a, 0xc6, 0xd1, 0xf0,
+ 0x00, 0x00, 0x00, 0x00, 0x3b, 0xdb, 0x9e, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x3c, 0xaf, 0xee, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3d, 0xbb, 0x80, 0xe0,
+ 0x00, 0x00, 0x00, 0x00, 0x3e, 0x8f, 0xd0, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x3f, 0x9b, 0x62, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6f, 0xb2, 0x70,
+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x84, 0x7f, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x42, 0x4f, 0x94, 0x70, 0x00, 0x00, 0x00, 0x00, 0x43, 0x64, 0x61, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x2f, 0x76, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x45, 0x44, 0x43, 0x60, 0x00, 0x00, 0x00, 0x00, 0x45, 0xf3, 0xa8, 0xf0,
+ 0x00, 0x00, 0x00, 0x00, 0x47, 0x2d, 0x5f, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x47, 0xd3, 0x8a, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x49, 0x0d, 0x41, 0xe0,
+ 0x00, 0x00, 0x00, 0x00, 0x49, 0xb3, 0x6c, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x4a, 0xed, 0x23, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x9c, 0x89, 0x70,
+ 0x00, 0x00, 0x00, 0x00, 0x4c, 0xd6, 0x40, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x4d, 0x7c, 0x6b, 0x70, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xb6, 0x22, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x4f, 0x5c, 0x4d, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x50, 0x96, 0x04, 0x60, 0x00, 0x00, 0x00, 0x00, 0x51, 0x3c, 0x2f, 0x70,
+ 0x00, 0x00, 0x00, 0x00, 0x52, 0x75, 0xe6, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x53, 0x1c, 0x11, 0x70, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0xc8, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x54, 0xfb, 0xf3, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x56, 0x35, 0xaa, 0x60, 0x00, 0x00, 0x00, 0x00, 0x56, 0xe5, 0x0f, 0xf0,
+ 0x00, 0x00, 0x00, 0x00, 0x58, 0x1e, 0xc6, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x58, 0xc4, 0xf1, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x59, 0xfe, 0xa8, 0xe0,
+ 0x00, 0x00, 0x00, 0x00, 0x5a, 0xa4, 0xd3, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x5b, 0xde, 0x8a, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x84, 0xb5, 0xf0,
+ 0x00, 0x00, 0x00, 0x00, 0x5d, 0xbe, 0x6c, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x5e, 0x64, 0x97, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x9e, 0x4e, 0xe0,
+ 0x00, 0x00, 0x00, 0x00, 0x60, 0x4d, 0xb4, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x61, 0x87, 0x6b, 0x60, 0x00, 0x00, 0x00, 0x00, 0x62, 0x2d, 0x96, 0x70,
+ 0x00, 0x00, 0x00, 0x00, 0x63, 0x67, 0x4d, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x64, 0x0d, 0x78, 0x70, 0x00, 0x00, 0x00, 0x00, 0x65, 0x47, 0x2f, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x65, 0xed, 0x5a, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x67, 0x27, 0x11, 0x60, 0x00, 0x00, 0x00, 0x00, 0x67, 0xcd, 0x3c, 0x70,
+ 0x00, 0x00, 0x00, 0x00, 0x69, 0x06, 0xf3, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x69, 0xad, 0x1e, 0x70, 0x00, 0x00, 0x00, 0x00, 0x6a, 0xe6, 0xd5, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x6b, 0x96, 0x3a, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x6c, 0xcf, 0xf1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x76, 0x1c, 0xf0,
+ 0x00, 0x00, 0x00, 0x00, 0x6e, 0xaf, 0xd3, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x6f, 0x55, 0xfe, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x8f, 0xb5, 0xe0,
+ 0x00, 0x00, 0x00, 0x00, 0x71, 0x35, 0xe0, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x72, 0x6f, 0x97, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x73, 0x15, 0xc2, 0xf0,
+ 0x00, 0x00, 0x00, 0x00, 0x74, 0x4f, 0x79, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x74, 0xfe, 0xdf, 0x70, 0x00, 0x00, 0x00, 0x00, 0x76, 0x38, 0x96, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xde, 0xc1, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x78, 0x18, 0x78, 0x60, 0x00, 0x00, 0x00, 0x00, 0x78, 0xbe, 0xa3, 0x70,
+ 0x00, 0x00, 0x00, 0x00, 0x79, 0xf8, 0x5a, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x7a, 0x9e, 0x85, 0x70, 0x00, 0x00, 0x00, 0x00, 0x7b, 0xd8, 0x3c, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7e, 0x67, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x7d, 0xb8, 0x1e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x5e, 0x49, 0x70,
+ 0x00, 0x00, 0x00, 0x00, 0x7f, 0x98, 0x00, 0x60, 0x00, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x04,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0xff, 0xff, 0xba, 0x9e, 0x00, 0x00, 0xff,
+ 0xff, 0xc7, 0xc0, 0x01, 0x04, 0xff, 0xff, 0xb9, 0xb0, 0x00, 0x08, 0xff,
+ 0xff, 0xc7, 0xc0, 0x01, 0x0c, 0xff, 0xff, 0xc7, 0xc0, 0x01, 0x10, 0x4c,
+ 0x4d, 0x54, 0x00, 0x45, 0x44, 0x54, 0x00, 0x45, 0x53, 0x54, 0x00, 0x45,
+ 0x57, 0x54, 0x00, 0x45, 0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x45, 0x53, 0x54, 0x35, 0x45, 0x44,
+ 0x54, 0x2c, 0x4d, 0x33, 0x2e, 0x32, 0x2e, 0x30, 0x2c, 0x4d, 0x31, 0x31,
+ 0x2e, 0x31, 0x2e, 0x30, 0x0a
+};
+unsigned int America_New_York_len = 3545;
+unsigned char Australia_Sydney[] = {
+ 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e,
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00,
+ 0x9c, 0x4e, 0xa6, 0x9c, 0x9c, 0xbc, 0x20, 0xf0, 0xcb, 0x54, 0xb3, 0x00,
+ 0xcb, 0xc7, 0x57, 0x70, 0xcc, 0xb7, 0x56, 0x80, 0xcd, 0xa7, 0x39, 0x70,
+ 0xce, 0xa0, 0x73, 0x00, 0xcf, 0x87, 0x1b, 0x70, 0x03, 0x70, 0x39, 0x80,
+ 0x04, 0x0d, 0x1c, 0x00, 0x05, 0x50, 0x1b, 0x80, 0x05, 0xf6, 0x38, 0x80,
+ 0x07, 0x2f, 0xfd, 0x80, 0x07, 0xd6, 0x1a, 0x80, 0x09, 0x0f, 0xdf, 0x80,
+ 0x09, 0xb5, 0xfc, 0x80, 0x0a, 0xef, 0xc1, 0x80, 0x0b, 0x9f, 0x19, 0x00,
+ 0x0c, 0xd8, 0xde, 0x00, 0x0d, 0x7e, 0xfb, 0x00, 0x0e, 0xb8, 0xc0, 0x00,
+ 0x0f, 0x5e, 0xdd, 0x00, 0x10, 0x98, 0xa2, 0x00, 0x11, 0x3e, 0xbf, 0x00,
+ 0x12, 0x78, 0x84, 0x00, 0x13, 0x1e, 0xa1, 0x00, 0x14, 0x58, 0x66, 0x00,
+ 0x14, 0xfe, 0x83, 0x00, 0x16, 0x38, 0x48, 0x00, 0x17, 0x0c, 0x89, 0x80,
+ 0x18, 0x21, 0x64, 0x80, 0x18, 0xc7, 0x81, 0x80, 0x1a, 0x01, 0x46, 0x80,
+ 0x1a, 0xa7, 0x63, 0x80, 0x1b, 0xe1, 0x28, 0x80, 0x1c, 0x87, 0x45, 0x80,
+ 0x1d, 0xc1, 0x0a, 0x80, 0x1e, 0x79, 0x9c, 0x80, 0x1f, 0x97, 0xb2, 0x00,
+ 0x20, 0x59, 0x7e, 0x80, 0x21, 0x80, 0xce, 0x80, 0x22, 0x42, 0x9b, 0x00,
+ 0x23, 0x69, 0xeb, 0x00, 0x24, 0x22, 0x7d, 0x00, 0x25, 0x49, 0xcd, 0x00,
+ 0x25, 0xef, 0xea, 0x00, 0x27, 0x29, 0xaf, 0x00, 0x27, 0xcf, 0xcc, 0x00,
+ 0x29, 0x09, 0x91, 0x00, 0x29, 0xaf, 0xae, 0x00, 0x2a, 0xe9, 0x73, 0x00,
+ 0x2b, 0x98, 0xca, 0x80, 0x2c, 0xd2, 0x8f, 0x80, 0x2d, 0x78, 0xac, 0x80,
+ 0x2e, 0xb2, 0x71, 0x80, 0x2f, 0x58, 0x8e, 0x80, 0x30, 0x92, 0x53, 0x80,
+ 0x31, 0x5d, 0x5a, 0x80, 0x32, 0x72, 0x35, 0x80, 0x33, 0x3d, 0x3c, 0x80,
+ 0x34, 0x52, 0x17, 0x80, 0x35, 0x1d, 0x1e, 0x80, 0x36, 0x31, 0xf9, 0x80,
+ 0x36, 0xfd, 0x00, 0x80, 0x38, 0x1b, 0x16, 0x00, 0x38, 0xdc, 0xe2, 0x80,
+ 0x39, 0xa7, 0xe9, 0x80, 0x3a, 0xbc, 0xc4, 0x80, 0x3b, 0xda, 0xda, 0x00,
+ 0x3c, 0xa5, 0xe1, 0x00, 0x3d, 0xba, 0xbc, 0x00, 0x3e, 0x85, 0xc3, 0x00,
+ 0x3f, 0x9a, 0x9e, 0x00, 0x40, 0x65, 0xa5, 0x00, 0x41, 0x83, 0xba, 0x80,
+ 0x42, 0x45, 0x87, 0x00, 0x43, 0x63, 0x9c, 0x80, 0x44, 0x2e, 0xa3, 0x80,
+ 0x45, 0x43, 0x7e, 0x80, 0x46, 0x05, 0x4b, 0x00, 0x47, 0x23, 0x60, 0x80,
+ 0x47, 0xf7, 0xa2, 0x00, 0x48, 0xe7, 0x93, 0x00, 0x49, 0xd7, 0x84, 0x00,
+ 0x4a, 0xc7, 0x75, 0x00, 0x4b, 0xb7, 0x66, 0x00, 0x4c, 0xa7, 0x57, 0x00,
+ 0x4d, 0x97, 0x48, 0x00, 0x4e, 0x87, 0x39, 0x00, 0x4f, 0x77, 0x2a, 0x00,
+ 0x50, 0x70, 0x55, 0x80, 0x51, 0x60, 0x46, 0x80, 0x52, 0x50, 0x37, 0x80,
+ 0x53, 0x40, 0x28, 0x80, 0x54, 0x30, 0x19, 0x80, 0x55, 0x20, 0x0a, 0x80,
+ 0x56, 0x0f, 0xfb, 0x80, 0x56, 0xff, 0xec, 0x80, 0x57, 0xef, 0xdd, 0x80,
+ 0x58, 0xdf, 0xce, 0x80, 0x59, 0xcf, 0xbf, 0x80, 0x5a, 0xbf, 0xb0, 0x80,
+ 0x5b, 0xb8, 0xdc, 0x00, 0x5c, 0xa8, 0xcd, 0x00, 0x5d, 0x98, 0xbe, 0x00,
+ 0x5e, 0x88, 0xaf, 0x00, 0x5f, 0x78, 0xa0, 0x00, 0x60, 0x68, 0x91, 0x00,
+ 0x61, 0x58, 0x82, 0x00, 0x62, 0x48, 0x73, 0x00, 0x63, 0x38, 0x64, 0x00,
+ 0x64, 0x28, 0x55, 0x00, 0x65, 0x18, 0x46, 0x00, 0x66, 0x11, 0x71, 0x80,
+ 0x67, 0x01, 0x62, 0x80, 0x67, 0xf1, 0x53, 0x80, 0x68, 0xe1, 0x44, 0x80,
+ 0x69, 0xd1, 0x35, 0x80, 0x6a, 0xc1, 0x26, 0x80, 0x6b, 0xb1, 0x17, 0x80,
+ 0x6c, 0xa1, 0x08, 0x80, 0x6d, 0x90, 0xf9, 0x80, 0x6e, 0x80, 0xea, 0x80,
+ 0x6f, 0x70, 0xdb, 0x80, 0x70, 0x6a, 0x07, 0x00, 0x71, 0x59, 0xf8, 0x00,
+ 0x72, 0x49, 0xe9, 0x00, 0x73, 0x39, 0xda, 0x00, 0x74, 0x29, 0xcb, 0x00,
+ 0x75, 0x19, 0xbc, 0x00, 0x76, 0x09, 0xad, 0x00, 0x76, 0xf9, 0x9e, 0x00,
+ 0x77, 0xe9, 0x8f, 0x00, 0x78, 0xd9, 0x80, 0x00, 0x79, 0xc9, 0x71, 0x00,
+ 0x7a, 0xb9, 0x62, 0x00, 0x7b, 0xb2, 0x8d, 0x80, 0x7c, 0xa2, 0x7e, 0x80,
+ 0x7d, 0x92, 0x6f, 0x80, 0x7e, 0x82, 0x60, 0x80, 0x7f, 0x72, 0x51, 0x80,
+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x04, 0x03,
+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x00, 0x00,
+ 0x8d, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x9a, 0xb0, 0x01, 0x04, 0x00, 0x00,
+ 0x8c, 0xa0, 0x00, 0x09, 0x00, 0x00, 0x9a, 0xb0, 0x01, 0x04, 0x00, 0x00,
+ 0x8c, 0xa0, 0x00, 0x09, 0x4c, 0x4d, 0x54, 0x00, 0x41, 0x45, 0x44, 0x54,
+ 0x00, 0x41, 0x45, 0x53, 0x54, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0e,
+ 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x73, 0x16, 0x7f, 0x3c, 0xff, 0xff, 0xff, 0xff, 0x9c, 0x4e, 0xa6, 0x9c,
+ 0xff, 0xff, 0xff, 0xff, 0x9c, 0xbc, 0x20, 0xf0, 0xff, 0xff, 0xff, 0xff,
+ 0xcb, 0x54, 0xb3, 0x00, 0xff, 0xff, 0xff, 0xff, 0xcb, 0xc7, 0x57, 0x70,
+ 0xff, 0xff, 0xff, 0xff, 0xcc, 0xb7, 0x56, 0x80, 0xff, 0xff, 0xff, 0xff,
+ 0xcd, 0xa7, 0x39, 0x70, 0xff, 0xff, 0xff, 0xff, 0xce, 0xa0, 0x73, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xcf, 0x87, 0x1b, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x70, 0x39, 0x80, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0d, 0x1c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x50, 0x1b, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0xf6, 0x38, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0x2f, 0xfd, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x07, 0xd6, 0x1a, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x0f, 0xdf, 0x80, 0x00, 0x00, 0x00, 0x00, 0x09, 0xb5, 0xfc, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x0a, 0xef, 0xc1, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x0b, 0x9f, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xd8, 0xde, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0d, 0x7e, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0e, 0xb8, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x5e, 0xdd, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x98, 0xa2, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x3e, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x78, 0x84, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x13, 0x1e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x14, 0x58, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xfe, 0x83, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x16, 0x38, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x17, 0x0c, 0x89, 0x80, 0x00, 0x00, 0x00, 0x00, 0x18, 0x21, 0x64, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0xc7, 0x81, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x1a, 0x01, 0x46, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xa7, 0x63, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x1b, 0xe1, 0x28, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x1c, 0x87, 0x45, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1d, 0xc1, 0x0a, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x1e, 0x79, 0x9c, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x97, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x59, 0x7e, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x21, 0x80, 0xce, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x22, 0x42, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x69, 0xeb, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x24, 0x22, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x25, 0x49, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0xef, 0xea, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x27, 0x29, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x27, 0xcf, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x09, 0x91, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x29, 0xaf, 0xae, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2a, 0xe9, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x98, 0xca, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x2c, 0xd2, 0x8f, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x2d, 0x78, 0xac, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2e, 0xb2, 0x71, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x2f, 0x58, 0x8e, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x92, 0x53, 0x80, 0x00, 0x00, 0x00, 0x00, 0x31, 0x5d, 0x5a, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x32, 0x72, 0x35, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x33, 0x3d, 0x3c, 0x80, 0x00, 0x00, 0x00, 0x00, 0x34, 0x52, 0x17, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x35, 0x1d, 0x1e, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x31, 0xf9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x36, 0xfd, 0x00, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x1b, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0xdc, 0xe2, 0x80, 0x00, 0x00, 0x00, 0x00, 0x39, 0xa7, 0xe9, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x3a, 0xbc, 0xc4, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x3b, 0xda, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xa5, 0xe1, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0xba, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3e, 0x85, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x9a, 0x9e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x40, 0x65, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x41, 0x83, 0xba, 0x80, 0x00, 0x00, 0x00, 0x00, 0x42, 0x45, 0x87, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x43, 0x63, 0x9c, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x44, 0x2e, 0xa3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x45, 0x43, 0x7e, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x46, 0x05, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x47, 0x23, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x47, 0xf7, 0xa2, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x48, 0xe7, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x49, 0xd7, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0xc7, 0x75, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x4b, 0xb7, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x4c, 0xa7, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x97, 0x48, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x4e, 0x87, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x4f, 0x77, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x70, 0x55, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x51, 0x60, 0x46, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x52, 0x50, 0x37, 0x80, 0x00, 0x00, 0x00, 0x00, 0x53, 0x40, 0x28, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x54, 0x30, 0x19, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x55, 0x20, 0x0a, 0x80, 0x00, 0x00, 0x00, 0x00, 0x56, 0x0f, 0xfb, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x56, 0xff, 0xec, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x57, 0xef, 0xdd, 0x80, 0x00, 0x00, 0x00, 0x00, 0x58, 0xdf, 0xce, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x59, 0xcf, 0xbf, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x5a, 0xbf, 0xb0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x5b, 0xb8, 0xdc, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5c, 0xa8, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5d, 0x98, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x88, 0xaf, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x5f, 0x78, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x60, 0x68, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x58, 0x82, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x62, 0x48, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x63, 0x38, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x28, 0x55, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x65, 0x18, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x66, 0x11, 0x71, 0x80, 0x00, 0x00, 0x00, 0x00, 0x67, 0x01, 0x62, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x67, 0xf1, 0x53, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x68, 0xe1, 0x44, 0x80, 0x00, 0x00, 0x00, 0x00, 0x69, 0xd1, 0x35, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x6a, 0xc1, 0x26, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x6b, 0xb1, 0x17, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6c, 0xa1, 0x08, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x6d, 0x90, 0xf9, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x6e, 0x80, 0xea, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x70, 0xdb, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x70, 0x6a, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x71, 0x59, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x49, 0xe9, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x73, 0x39, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x74, 0x29, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x19, 0xbc, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0x09, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x76, 0xf9, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0xe9, 0x8f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x78, 0xd9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x79, 0xc9, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0xb9, 0x62, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7b, 0xb2, 0x8d, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x7c, 0xa2, 0x7e, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x92, 0x6f, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x82, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x7f, 0x72, 0x51, 0x80, 0x00, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+ 0x01, 0x02, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+ 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+ 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+ 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+ 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+ 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+ 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+ 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+ 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+ 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+ 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+ 0x03, 0x04, 0x03, 0x00, 0x00, 0x8d, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x9a,
+ 0xb0, 0x01, 0x04, 0x00, 0x00, 0x8c, 0xa0, 0x00, 0x09, 0x00, 0x00, 0x9a,
+ 0xb0, 0x01, 0x04, 0x00, 0x00, 0x8c, 0xa0, 0x00, 0x09, 0x4c, 0x4d, 0x54,
+ 0x00, 0x41, 0x45, 0x44, 0x54, 0x00, 0x41, 0x45, 0x53, 0x54, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x41, 0x45,
+ 0x53, 0x54, 0x2d, 0x31, 0x30, 0x41, 0x45, 0x44, 0x54, 0x2c, 0x4d, 0x31,
+ 0x30, 0x2e, 0x31, 0x2e, 0x30, 0x2c, 0x4d, 0x34, 0x2e, 0x31, 0x2e, 0x30,
+ 0x2f, 0x33, 0x0a
+};
+unsigned int Australia_Sydney_len = 2223;
diff --git a/absl/time/time.cc b/absl/time/time.cc
new file mode 100644
index 0000000..fd5a41b
--- /dev/null
+++ b/absl/time/time.cc
@@ -0,0 +1,370 @@
+// 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 the absl::Time class, which is declared in
+// //absl/time.h.
+//
+// The representation for a absl::Time is a absl::Duration offset from the
+// epoch. We use the traditional Unix epoch (1970-01-01 00:00:00 +0000)
+// for convenience, but this is not exposed in the API and could be changed.
+//
+// NOTE: To keep type verbosity to a minimum, the following variable naming
+// conventions are used throughout this file.
+//
+// cz: A cctz::time_zone
+// tz: A absl::TimeZone
+// cl: A cctz::time_zone::civil_lookup
+// al: A cctz::time_zone::absolute_lookup
+// cd: A cctz::civil_day
+// cs: A cctz::civil_second
+// bd: A absl::Time::Breakdown
+
+#include "absl/time/time.h"
+
+#include <cstring>
+#include <ctime>
+#include <limits>
+
+#include "cctz/civil_time.h"
+#include "cctz/time_zone.h"
+namespace absl {
+
+namespace {
+
+inline cctz::time_point<cctz::sys_seconds> unix_epoch() {
+ return std::chrono::time_point_cast<cctz::sys_seconds>(
+ std::chrono::system_clock::from_time_t(0));
+}
+
+// Floors d to the next unit boundary closer to negative infinity.
+inline int64_t FloorToUnit(absl::Duration d, absl::Duration unit) {
+ absl::Duration rem;
+ int64_t q = absl::IDivDuration(d, unit, &rem);
+ return (q > 0 ||
+ rem >= ZeroDuration() ||
+ q == std::numeric_limits<int64_t>::min()) ? q : q - 1;
+}
+
+inline absl::Time::Breakdown InfiniteFutureBreakdown() {
+ absl::Time::Breakdown bd;
+ bd.year = std::numeric_limits<int64_t>::max();
+ bd.month = 12;
+ bd.day = 31;
+ bd.hour = 23;
+ bd.minute = 59;
+ bd.second = 59;
+ bd.subsecond = absl::InfiniteDuration();
+ bd.weekday = 4;
+ bd.yearday = 365;
+ bd.offset = 0;
+ bd.is_dst = false;
+ bd.zone_abbr = "-0000";
+ return bd;
+}
+
+inline Time::Breakdown InfinitePastBreakdown() {
+ Time::Breakdown bd;
+ bd.year = std::numeric_limits<int64_t>::min();
+ bd.month = 1;
+ bd.day = 1;
+ bd.hour = 0;
+ bd.minute = 0;
+ bd.second = 0;
+ bd.subsecond = -absl::InfiniteDuration();
+ bd.weekday = 7;
+ bd.yearday = 1;
+ bd.offset = 0;
+ bd.is_dst = false;
+ bd.zone_abbr = "-0000";
+ return bd;
+}
+
+inline absl::TimeConversion InfiniteFutureTimeConversion() {
+ absl::TimeConversion tc;
+ tc.pre = tc.trans = tc.post = absl::InfiniteFuture();
+ tc.kind = absl::TimeConversion::UNIQUE;
+ tc.normalized = true;
+ return tc;
+}
+
+inline TimeConversion InfinitePastTimeConversion() {
+ absl::TimeConversion tc;
+ tc.pre = tc.trans = tc.post = absl::InfinitePast();
+ tc.kind = absl::TimeConversion::UNIQUE;
+ tc.normalized = true;
+ return tc;
+}
+
+// Makes a Time from sec, overflowing to InfiniteFuture/InfinitePast as
+// necessary. If sec is min/max, then consult cs+tz to check for overlow.
+Time MakeTimeWithOverflow(const cctz::time_point<cctz::sys_seconds>& sec,
+ const cctz::civil_second& cs,
+ const cctz::time_zone& tz,
+ bool* normalized = nullptr) {
+ const auto max = cctz::time_point<cctz::sys_seconds>::max();
+ const auto min = cctz::time_point<cctz::sys_seconds>::min();
+ if (sec == max) {
+ const auto al = tz.lookup(max);
+ if (cs > al.cs) {
+ if (normalized) *normalized = true;
+ return absl::InfiniteFuture();
+ }
+ }
+ if (sec == min) {
+ const auto al = tz.lookup(min);
+ if (cs < al.cs) {
+ if (normalized) *normalized = true;
+ return absl::InfinitePast();
+ }
+ }
+ const auto hi = (sec - unix_epoch()).count();
+ return time_internal::FromUnixDuration(time_internal::MakeDuration(hi));
+}
+
+inline absl::TimeConversion::Kind MapKind(
+ const cctz::time_zone::civil_lookup::civil_kind& kind) {
+ switch (kind) {
+ case cctz::time_zone::civil_lookup::UNIQUE:
+ return absl::TimeConversion::UNIQUE;
+ case cctz::time_zone::civil_lookup::SKIPPED:
+ return absl::TimeConversion::SKIPPED;
+ case cctz::time_zone::civil_lookup::REPEATED:
+ return absl::TimeConversion::REPEATED;
+ }
+ return absl::TimeConversion::UNIQUE;
+}
+
+// Returns Mon=1..Sun=7.
+inline int MapWeekday(const cctz::weekday& wd) {
+ switch (wd) {
+ case cctz::weekday::monday:
+ return 1;
+ case cctz::weekday::tuesday:
+ return 2;
+ case cctz::weekday::wednesday:
+ return 3;
+ case cctz::weekday::thursday:
+ return 4;
+ case cctz::weekday::friday:
+ return 5;
+ case cctz::weekday::saturday:
+ return 6;
+ case cctz::weekday::sunday:
+ return 7;
+ }
+ return 1;
+}
+
+} // namespace
+
+absl::Time::Breakdown Time::In(absl::TimeZone tz) const {
+ if (*this == absl::InfiniteFuture()) return absl::InfiniteFutureBreakdown();
+ if (*this == absl::InfinitePast()) return absl::InfinitePastBreakdown();
+
+ const auto tp =
+ unix_epoch() + cctz::sys_seconds(time_internal::GetRepHi(rep_));
+ const auto al = cctz::time_zone(tz).lookup(tp);
+ const auto cs = al.cs;
+ const auto cd = cctz::civil_day(cs);
+
+ absl::Time::Breakdown bd;
+ bd.year = cs.year();
+ bd.month = cs.month();
+ bd.day = cs.day();
+ bd.hour = cs.hour();
+ bd.minute = cs.minute();
+ bd.second = cs.second();
+ bd.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(rep_));
+ bd.weekday = MapWeekday(get_weekday(cd));
+ bd.yearday = get_yearday(cd);
+ bd.offset = al.offset;
+ bd.is_dst = al.is_dst;
+ bd.zone_abbr = al.abbr;
+ return bd;
+}
+
+absl::Time FromTM(const struct tm& tm, absl::TimeZone tz) {
+ const auto cz = cctz::time_zone(tz);
+ const auto cs =
+ cctz::civil_second(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+ const auto cl = cz.lookup(cs);
+ const auto tp = tm.tm_isdst == 0 ? cl.post : cl.pre;
+ return MakeTimeWithOverflow(tp, cs, cz);
+}
+
+struct tm ToTM(absl::Time t, absl::TimeZone tz) {
+ const absl::Time::Breakdown bd = t.In(tz);
+ struct tm tm;
+ std::memset(&tm, 0, sizeof(tm));
+ tm.tm_sec = bd.second;
+ tm.tm_min = bd.minute;
+ tm.tm_hour = bd.hour;
+ tm.tm_mday = bd.day;
+ tm.tm_mon = bd.month - 1;
+
+ // Saturates tm.tm_year in cases of over/underflow, accounting for the fact
+ // that tm.tm_year is years since 1900.
+ if (bd.year < std::numeric_limits<int>::min() + 1900) {
+ tm.tm_year = std::numeric_limits<int>::min();
+ } else if (bd.year > std::numeric_limits<int>::max()) {
+ tm.tm_year = std::numeric_limits<int>::max() - 1900;
+ } else {
+ tm.tm_year = static_cast<int>(bd.year - 1900);
+ }
+
+ tm.tm_wday = bd.weekday % 7;
+ tm.tm_yday = bd.yearday - 1;
+ tm.tm_isdst = bd.is_dst ? 1 : 0;
+
+ return tm;
+}
+
+//
+// Factory functions.
+//
+
+absl::TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour,
+ int min, int sec, TimeZone tz) {
+ // Avoids years that are too extreme for civil_second to normalize.
+ if (year > 300000000000) return InfiniteFutureTimeConversion();
+ if (year < -300000000000) return InfinitePastTimeConversion();
+ const auto cz = cctz::time_zone(tz);
+ const auto cs = cctz::civil_second(year, mon, day, hour, min, sec);
+ absl::TimeConversion tc;
+ tc.normalized = year != cs.year() || mon != cs.month() || day != cs.day() ||
+ hour != cs.hour() || min != cs.minute() || sec != cs.second();
+ const auto cl = cz.lookup(cs);
+ // Converts the civil_lookup struct to a TimeConversion.
+ tc.pre = MakeTimeWithOverflow(cl.pre, cs, cz, &tc.normalized);
+ tc.trans = MakeTimeWithOverflow(cl.trans, cs, cz, &tc.normalized);
+ tc.post = MakeTimeWithOverflow(cl.post, cs, cz, &tc.normalized);
+ tc.kind = MapKind(cl.kind);
+ return tc;
+}
+
+absl::Time FromDateTime(int64_t year, int mon, int day, int hour, int min,
+ int sec, TimeZone tz) {
+ if (year > 300000000000) return InfiniteFuture();
+ if (year < -300000000000) return InfinitePast();
+ const auto cz = cctz::time_zone(tz);
+ const auto cs = cctz::civil_second(year, mon, day, hour, min, sec);
+ const auto cl = cz.lookup(cs);
+ return MakeTimeWithOverflow(cl.pre, cs, cz);
+}
+
+absl::Time TimeFromTimespec(timespec ts) {
+ return time_internal::FromUnixDuration(absl::DurationFromTimespec(ts));
+}
+
+absl::Time TimeFromTimeval(timeval tv) {
+ return time_internal::FromUnixDuration(absl::DurationFromTimeval(tv));
+}
+
+absl::Time FromUDate(double udate) {
+ return time_internal::FromUnixDuration(absl::Milliseconds(udate));
+}
+
+absl::Time FromUniversal(int64_t universal) {
+ return absl::UniversalEpoch() + 100 * absl::Nanoseconds(universal);
+}
+
+//
+// Conversion to other time types.
+//
+
+int64_t ToUnixNanos(Time t) {
+ if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
+ time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 33 == 0) {
+ return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) *
+ 1000 * 1000 * 1000) +
+ (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4);
+ }
+ return FloorToUnit(time_internal::ToUnixDuration(t), absl::Nanoseconds(1));
+}
+
+int64_t ToUnixMicros(Time t) {
+ if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
+ time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 43 == 0) {
+ return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) *
+ 1000 * 1000) +
+ (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4000);
+ }
+ return FloorToUnit(time_internal::ToUnixDuration(t), absl::Microseconds(1));
+}
+
+int64_t ToUnixMillis(Time t) {
+ if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
+ time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 53 == 0) {
+ return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) * 1000) +
+ (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) /
+ (4000 * 1000));
+ }
+ return FloorToUnit(time_internal::ToUnixDuration(t), absl::Milliseconds(1));
+}
+
+int64_t ToUnixSeconds(Time t) {
+ return time_internal::GetRepHi(time_internal::ToUnixDuration(t));
+}
+
+time_t ToTimeT(Time t) { return absl::ToTimespec(t).tv_sec; }
+
+timespec ToTimespec(Time t) {
+ timespec ts;
+ absl::Duration d = time_internal::ToUnixDuration(t);
+ if (!time_internal::IsInfiniteDuration(d)) {
+ ts.tv_sec = time_internal::GetRepHi(d);
+ if (ts.tv_sec == time_internal::GetRepHi(d)) { // no time_t narrowing
+ ts.tv_nsec = time_internal::GetRepLo(d) / 4; // floor
+ return ts;
+ }
+ }
+ if (d >= absl::ZeroDuration()) {
+ ts.tv_sec = std::numeric_limits<time_t>::max();
+ ts.tv_nsec = 1000 * 1000 * 1000 - 1;
+ } else {
+ ts.tv_sec = std::numeric_limits<time_t>::min();
+ ts.tv_nsec = 0;
+ }
+ return ts;
+}
+
+timeval ToTimeval(Time t) {
+ timeval tv;
+ timespec ts = absl::ToTimespec(t);
+ tv.tv_sec = ts.tv_sec;
+ if (tv.tv_sec != ts.tv_sec) { // narrowing
+ if (ts.tv_sec < 0) {
+ tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::min();
+ tv.tv_usec = 0;
+ } else {
+ tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::max();
+ tv.tv_usec = 1000 * 1000 - 1;
+ }
+ return tv;
+ }
+ tv.tv_usec = static_cast<int>(ts.tv_nsec / 1000); // suseconds_t
+ return tv;
+}
+
+double ToUDate(Time t) {
+ return absl::FDivDuration(time_internal::ToUnixDuration(t),
+ absl::Milliseconds(1));
+}
+
+int64_t ToUniversal(absl::Time t) {
+ return absl::FloorToUnit(t - absl::UniversalEpoch(), absl::Nanoseconds(100));
+}
+
+} // namespace absl
diff --git a/absl/time/time.h b/absl/time/time.h
new file mode 100644
index 0000000..302c760
--- /dev/null
+++ b/absl/time/time.h
@@ -0,0 +1,1181 @@
+// 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: time.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines abstractions for computing with absolute points
+// in time, durations of time, and formatting and parsing time within a given
+// time zone. The following abstractions are defined:
+//
+// * `absl::Time` defines an absolute, specific instance in time
+// * `absl::Duration` defines a signed, fixed-length span of time
+// * `absl::TimeZone` defines geopolitical time zone regions (as collected
+// within the IANA Time Zone database (https://www.iana.org/time-zones)).
+//
+// Example:
+//
+// absl::TimeZone nyc;
+//
+// // LoadTimeZone may fail so it's always better to check for success.
+// if (!absl::LoadTimeZone("America/New_York", &nyc)) {
+// // handle error case
+// }
+//
+// // My flight leaves NYC on Jan 2, 2017 at 03:04:05
+// absl::Time takeoff = absl::FromDateTime(2017, 1, 2, 3, 4, 5, nyc);
+// absl::Duration flight_duration = absl::Hours(21) + absl::Minutes(35);
+// absl::Time landing = takeoff + flight_duration;
+//
+// absl::TimeZone syd;
+// if (!absl::LoadTimeZone("Australia/Sydney", &syd)) {
+// // handle error case
+// }
+// std::string s = absl::FormatTime(
+// "My flight will land in Sydney on %Y-%m-%d at %H:%M:%S",
+// landing, syd);
+//
+#ifndef ABSL_TIME_TIME_H_
+#define ABSL_TIME_TIME_H_
+
+#if !defined(_WIN32)
+#include <sys/time.h>
+#else
+#include <winsock2.h>
+#endif
+#include <chrono> // NOLINT(build/c++11)
+#include <cstdint>
+#include <ctime>
+#include <ostream>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/port.h" // Needed for string vs std::string
+#include "cctz/time_zone.h"
+
+namespace absl {
+
+class Duration; // Defined below
+class Time; // Defined below
+class TimeZone; // Defined below
+
+namespace time_internal {
+int64_t IDivDuration(bool satq, Duration num, Duration den, Duration* rem);
+constexpr Time FromUnixDuration(Duration d);
+constexpr Duration ToUnixDuration(Time t);
+constexpr int64_t GetRepHi(Duration d);
+constexpr uint32_t GetRepLo(Duration d);
+constexpr Duration MakeDuration(int64_t hi, uint32_t lo);
+constexpr Duration MakeDuration(int64_t hi, int64_t lo);
+constexpr int64_t kTicksPerNanosecond = 4;
+constexpr int64_t kTicksPerSecond = 1000 * 1000 * 1000 * kTicksPerNanosecond;
+template <typename T>
+using IsFloatingPoint =
+ typename std::enable_if<std::is_floating_point<T>::value, int>::type;
+} // namespace time_internal
+
+// Duration
+//
+// The `absl::Duration` class represents a signed, fixed-length span of time.
+// A `Duration` is generated using a unit-specific factory function, or is
+// the result of subtracting one `absl::Time` from another. Durations behave
+// like unit-safe integers and they support all the natural integer-like
+// arithmetic operations. Arithmetic overflows and saturates at +/- infinity.
+// `Duration` should be passed by value rather than const reference.
+//
+// Factory functions `Nanoseconds()`, `Microseconds()`, `Milliseconds()`,
+// `Seconds()`, `Minutes()`, `Hours()` and `InfiniteDuration()` allow for
+// creation of constexpr `Duration` values
+//
+// Examples:
+//
+// constexpr absl::Duration ten_ns = absl::Nanoseconds(10);
+// constexpr absl::Duration min = absl::Minutes(1);
+// constexpr absl::Duration hour = absl::Hours(1);
+// absl::Duration dur = 60 * min; // dur == hour
+// absl::Duration half_sec = absl::Milliseconds(500);
+// absl::Duration quarter_sec = 0.25 * absl::Seconds(1);
+//
+// `Duration` values can be easily converted to an integral number of units
+// using the division operator.
+//
+// Example:
+//
+// constexpr absl::Duration dur = absl::Milliseconds(1500);
+// int64_t ns = dur / absl::Nanoseconds(1); // ns == 1500000000
+// int64_t ms = dur / absl::Milliseconds(1); // ms == 1500
+// int64_t sec = dur / absl::Seconds(1); // sec == 1 (subseconds truncated)
+// int64_t min = dur / absl::Minutes(1); // min == 0
+//
+// See the `IDivDuration()` and `FDivDuration()` functions below for details on
+// how to access the fractional parts of the quotient.
+//
+// Alternatively, conversions can be performed using helpers such as
+// `ToInt64Microseconds()` and `ToDoubleSeconds()`.
+class Duration {
+ public:
+ // Value semantics.
+ constexpr Duration() : rep_hi_(0), rep_lo_(0) {} // zero-length duration
+
+ // Compound assignment operators.
+ Duration& operator+=(Duration d);
+ Duration& operator-=(Duration d);
+ Duration& operator*=(int64_t r);
+ Duration& operator*=(double r);
+ Duration& operator/=(int64_t r);
+ Duration& operator/=(double r);
+ Duration& operator%=(Duration rhs);
+
+ // Overloads that forward to either the int64_t or double overloads above.
+ template <typename T>
+ Duration& operator*=(T r) {
+ int64_t x = r;
+ return *this *= x;
+ }
+ template <typename T>
+ Duration& operator/=(T r) {
+ int64_t x = r;
+ return *this /= x;
+ }
+ Duration& operator*=(float r) { return *this *= static_cast<double>(r); }
+ Duration& operator/=(float r) { return *this /= static_cast<double>(r); }
+
+ private:
+ friend constexpr int64_t time_internal::GetRepHi(Duration d);
+ friend constexpr uint32_t time_internal::GetRepLo(Duration d);
+ friend constexpr Duration time_internal::MakeDuration(int64_t hi,
+ uint32_t lo);
+ constexpr Duration(int64_t hi, uint32_t lo) : rep_hi_(hi), rep_lo_(lo) {}
+ int64_t rep_hi_;
+ uint32_t rep_lo_;
+};
+
+// Relational Operators
+constexpr bool operator<(Duration lhs, Duration rhs);
+constexpr bool operator>(Duration lhs, Duration rhs) { return rhs < lhs; }
+constexpr bool operator>=(Duration lhs, Duration rhs) { return !(lhs < rhs); }
+constexpr bool operator<=(Duration lhs, Duration rhs) { return !(rhs < lhs); }
+constexpr bool operator==(Duration lhs, Duration rhs);
+constexpr bool operator!=(Duration lhs, Duration rhs) { return !(lhs == rhs); }
+
+// Additive Operators
+constexpr Duration operator-(Duration d);
+inline Duration operator+(Duration lhs, Duration rhs) { return lhs += rhs; }
+inline Duration operator-(Duration lhs, Duration rhs) { return lhs -= rhs; }
+
+// Multiplicative Operators
+template <typename T>
+inline Duration operator*(Duration lhs, T rhs) {
+ return lhs *= rhs;
+}
+template <typename T>
+inline Duration operator*(T lhs, Duration rhs) {
+ return rhs *= lhs;
+}
+template <typename T>
+inline Duration operator/(Duration lhs, T rhs) {
+ return lhs /= rhs;
+}
+inline int64_t operator/(Duration lhs, Duration rhs) {
+ return time_internal::IDivDuration(true, lhs, rhs,
+ &lhs); // trunc towards zero
+}
+inline Duration operator%(Duration lhs, Duration rhs) { return lhs %= rhs; }
+
+// IDivDuration()
+//
+// Divides a numerator `Duration` by a denominator `Duration`, returning the
+// quotient and remainder. The remainder always has the same sign as the
+// numerator. The returned quotient and remainder respect the identity:
+//
+// numerator = denominator * quotient + remainder
+//
+// Returned quotients are capped to the range of `int64_t`, with the difference
+// spilling into the remainder to uphold the above identity. This means that the
+// remainder returned could differ from the remainder returned by
+// `Duration::operator%` for huge quotients.
+//
+// See also the notes on `InfiniteDuration()` below regarding the behavior of
+// division involving zero and infinite durations.
+//
+// Example:
+//
+// constexpr absl::Duration a =
+// absl::Seconds(std::numeric_limits<int64_t>::max()); // big
+// constexpr absl::Duration b = absl::Nanoseconds(1); // small
+//
+// absl::Duration rem = a % b;
+// // rem == absl::ZeroDuration()
+//
+// // Here, q would overflow int64_t, so rem accounts for the difference.
+// int64_t q = absl::IDivDuration(a, b, &rem);
+// // q == std::numeric_limits<int64_t>::max(), rem == a - b * q
+inline int64_t IDivDuration(Duration num, Duration den, Duration* rem) {
+ return time_internal::IDivDuration(true, num, den,
+ rem); // trunc towards zero
+}
+
+// FDivDuration()
+//
+// Divides a `Duration` numerator into a fractional number of units of a
+// `Duration` denominator.
+//
+// See also the notes on `InfiniteDuration()` below regarding the behavior of
+// division involving zero and infinite durations.
+//
+// Example:
+//
+// double d = absl::FDivDuration(absl::Milliseconds(1500), absl::Seconds(1));
+// // d == 1.5
+double FDivDuration(Duration num, Duration den);
+
+// ZeroDuration()
+//
+// Returns a zero-length duration. This function behaves just like the default
+// constructor, but the name helps make the semantics clear at call sites.
+constexpr Duration ZeroDuration() { return Duration(); }
+
+// AbsDuration()
+//
+// Returns the absolute value of a duration.
+inline Duration AbsDuration(Duration d) {
+ return (d < ZeroDuration()) ? -d : d;
+}
+
+// Trunc()
+//
+// Truncates a duration (toward zero) to a multiple of a non-zero unit.
+//
+// Example:
+//
+// absl::Duration d = absl::Nanoseconds(123456789);
+// absl::Duration a = absl::Trunc(d, absl::Microseconds(1)); // 123456us
+Duration Trunc(Duration d, Duration unit);
+
+// Floor()
+//
+// Floors a duration using the passed duration unit to its largest value not
+// greater than the duration.
+//
+// Example:
+//
+// absl::Duration d = absl::Nanoseconds(123456789);
+// absl::Duration b = absl::Floor(d, absl::Microseconds(1)); // 123456us
+Duration Floor(Duration d, Duration unit);
+
+// Ceil()
+//
+// Returns the ceiling of a duration using the passed duration unit to its
+// smallest value not less than the duration.
+//
+// Example:
+//
+// absl::Duration d = absl::Nanoseconds(123456789);
+// absl::Duration c = absl::Ceil(d, absl::Microseconds(1)); // 123457us
+Duration Ceil(Duration d, Duration unit);
+
+// Nanoseconds()
+// Microseconds()
+// Milliseconds()
+// Seconds()
+// Minutes
+// Hours()
+//
+// Factory functions for constructing `Duration` values from an integral number
+// of the unit indicated by the factory function's name.
+//
+// Note: no "Days()" factory function exists because "a day" is ambiguous. Civil
+// days are not always 24 hours long, and a 24-hour duration often does not
+// correspond with a civil day. If a 24-hour duration is needed, use
+// `absl::Hours(24)`.
+//
+//
+// Example:
+//
+// absl::Duration a = absl::Seconds(60);
+// absl::Duration b = absl::Minutes(1); // b == a
+constexpr Duration Nanoseconds(int64_t n);
+constexpr Duration Microseconds(int64_t n);
+constexpr Duration Milliseconds(int64_t n);
+constexpr Duration Seconds(int64_t n);
+constexpr Duration Minutes(int64_t n);
+constexpr Duration Hours(int64_t n);
+
+// Factory overloads for constructing `Duration` values from a floating-point
+// number of the unit indicated by the factory function's name. These functions
+// exist for convenience, but they are not as efficient as the integral
+// factories, which should be preferred.
+//
+// Example:
+// auto a = absl::Seconds(1.5); // OK
+// auto b = absl::Milliseconds(1500); // BETTER
+template <typename T, time_internal::IsFloatingPoint<T> = 0>
+Duration Nanoseconds(T n) {
+ return n * Nanoseconds(1);
+}
+template <typename T, time_internal::IsFloatingPoint<T> = 0>
+Duration Microseconds(T n) {
+ return n * Microseconds(1);
+}
+template <typename T, time_internal::IsFloatingPoint<T> = 0>
+Duration Milliseconds(T n) {
+ return n * Milliseconds(1);
+}
+template <typename T, time_internal::IsFloatingPoint<T> = 0>
+Duration Seconds(T n) {
+ return n * Seconds(1);
+}
+template <typename T, time_internal::IsFloatingPoint<T> = 0>
+Duration Minutes(T n) {
+ return n * Minutes(1);
+}
+template <typename T, time_internal::IsFloatingPoint<T> = 0>
+Duration Hours(T n) {
+ return n * Hours(1);
+}
+
+// ToInt64Nanoseconds()
+// ToInt64Microseconds()
+// ToInt64Milliseconds()
+// ToInt64Seconds()
+// ToInt64Minutes()
+// ToInt64Hours()
+//
+// Helper functions that convert a Duration to an integral count of the
+// indicated unit. These functions are shorthand for the `IDivDuration()`
+// function above; see its documentation for details about overflow, etc.
+//
+// Example:
+//
+// absl::Duration d = absl::Milliseconds(1500);
+// int64_t isec = ToInt64Seconds(d); // isec == 1
+int64_t ToInt64Nanoseconds(Duration d);
+int64_t ToInt64Microseconds(Duration d);
+int64_t ToInt64Milliseconds(Duration d);
+int64_t ToInt64Seconds(Duration d);
+int64_t ToInt64Minutes(Duration d);
+int64_t ToInt64Hours(Duration d);
+
+// ToDoubleNanoSeconds()
+// ToDoubleMicroseconds()
+// ToDoubleMilliseconds()
+// ToDoubleSeconds()
+// ToDoubleMinutes()
+// ToDoubleHours
+//
+// Helper functions that convert a Duration to a floating point count of the
+// indicated unit. These functions are shorthand for the `FDivDuration()`
+// function above; see its documentation for details about overflow, etc.
+//
+// Example:
+//
+// absl::Duration d = absl::Milliseconds(1500);
+// double dsec = ToDoubleSeconds(d); // dsec == 1.5
+double ToDoubleNanoseconds(Duration d);
+double ToDoubleMicroseconds(Duration d);
+double ToDoubleMilliseconds(Duration d);
+double ToDoubleSeconds(Duration d);
+double ToDoubleMinutes(Duration d);
+double ToDoubleHours(Duration d);
+
+// InfiniteDuration()
+//
+// Returns an infinite `Duration`. To get a `Duration` representing negative
+// infinity, use `-InfiniteDuration()`.
+//
+// Duration arithmetic overflows to +/- infinity and saturates. In general,
+// arithmetic with `Duration` infinities is similar to IEEE 754 infinities
+// except where IEEE 754 NaN would be involved, in which case +/-
+// `InfiniteDuration()` is used in place of a "nan" Duration.
+//
+// Examples:
+//
+// constexpr absl::Duration inf = absl::InfiniteDuration();
+// const absl::Duration d = ... any finite duration ...
+//
+// inf == inf + inf
+// inf == inf + d
+// inf == inf - inf
+// -inf == d - inf
+//
+// inf == d * 1e100
+// inf == inf / 2
+// 0 == d / inf
+// INT64_MAX == inf / d
+//
+// // Division by zero returns infinity, or INT64_MIN/MAX where appropriate.
+// inf == d / 0
+// INT64_MAX == d / absl::ZeroDuration()
+//
+// The examples involving the `/` operator above also apply to `IDivDuration()`
+// and `FDivDuration()`.
+constexpr Duration InfiniteDuration();
+
+// FormatDuration()
+//
+// Returns a std::string representing the duration in the form "72h3m0.5s".
+// Returns "inf" or "-inf" for +/- `InfiniteDuration()`.
+std::string FormatDuration(Duration d);
+
+// Output stream operator.
+inline std::ostream& operator<<(std::ostream& os, Duration d) {
+ return os << FormatDuration(d);
+}
+
+// ParseDuration()
+//
+// Parses a duration std::string consisting of a possibly signed sequence
+// of decimal numbers, each with an optional fractional part and a
+// unit suffix. The valid suffixes are "ns", "us" "ms", "s", "m",
+// and "h". Simple examples include "300ms", "-1.5h", and "2h45m".
+// Parses "inf" and "-inf" as +/- `InfiniteDuration()`.
+bool ParseDuration(const std::string& dur_string, Duration* d);
+
+// Flag Support
+// TODO(b/63899288) copybara strip once dependencies are removed.
+
+// ParseFlag()
+//
+bool ParseFlag(const std::string& text, Duration* dst, std::string* error);
+
+// UnparseFlag()
+//
+std::string UnparseFlag(Duration d);
+
+// Time
+//
+// An `absl::Time` represents a specific instant in time. Arithmetic operators
+// are provided for naturally expressing time calculations. Instances are
+// created using `absl::Now()` and the `absl::From*()` factory functions that
+// accept the gamut of other time representations. Formatting and parsing
+// functions are provided for conversion to and from strings. `absl::Time`
+// should be passed by value rather than const reference.
+//
+// `absl::Time` assumes there are 60 seconds in a minute, which means the
+// underlying time scales must be "smeared" to eliminate leap seconds.
+// POSIX, for example, legislates that a `time_t` value of `536457599` shall
+// correspond to "1986-12-31 23:59:59 +0000".
+//
+//
+// Even though `absl::Time` supports a wide range of timestamps, exercise
+// caution when using values in the distant past. `absl::Time` uses the
+// Proleptic Gregorian calendar, which extends the Gregorian calendar backward
+// to dates before its introduction in 1582.
+// See https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar
+// for more information. Use the ICU calendar classes to convert a date in
+// some other calendar (http://userguide.icu-project.org/datetime/calendar).
+//
+// Similarly, standardized time zones are a reasonably recent innovation, with
+// the Greenwich prime meridian being established in 1884. The TZ database
+// itself does not profess accurate offsets for timestamps prior to 1970. The
+// breakdown of future timestamps is subject to the whim of regional
+// governments.
+//
+// The `absl::Time` class represents an instant in time as a count of clock
+// ticks of some granularity (resolution) from some starting point (epoch).
+//
+//
+// `absl::Time` uses a resolution that is high enough to avoid loss in
+// precision, and a range that is wide enough to avoid overflow, when
+// converting between tick counts in most Google time scales (i.e., precision
+// of at least one nanosecond, and range +/-100 billion years). Conversions
+// between the time scales are performed by truncating (towards negative
+// infinity) to the nearest representable point.
+//
+// Examples:
+//
+// absl::Time t1 = ...;
+// absl::Time t2 = t1 + absl::Minutes(2);
+// absl::Duration d = t2 - t1; // == absl::Minutes(2)
+// absl::Time::Breakdown bd = t1.In(absl::LocalTimeZone());
+//
+class Time {
+ public:
+ // Value semantics.
+
+ // Returns the Unix epoch. However, those reading your code may not know
+ // or expect the Unix epoch as the default value, so make your code more
+ // readable by explicitly initializing all instances before use.
+ //
+ // Example:
+ // absl::Time t = absl::UnixEpoch();
+ // absl::Time t = absl::Now();
+ // absl::Time t = absl::TimeFromTimeval(tv);
+ // absl::Time t = absl::InfinitePast();
+ constexpr Time() {}
+
+ // Assignment operators.
+ Time& operator+=(Duration d) { rep_ += d; return *this; }
+ Time& operator-=(Duration d) { rep_ -= d; return *this; }
+
+ // Time::Breakdown
+ //
+ // The calendar and wall-clock (aka "civil time") components of a
+ // `absl::Time` in a certain `absl::TimeZone`. This struct is not
+ // intended to represent an instant in time. So, rather than passing
+ // a `Time::Breakdown` to a function, pass an `absl::Time` and an
+ // `absl::TimeZone`.
+ struct Breakdown {
+ int64_t year; // year (e.g., 2013)
+ int month; // month of year [1:12]
+ int day; // day of month [1:31]
+ int hour; // hour of day [0:23]
+ int minute; // minute of hour [0:59]
+ int second; // second of minute [0:59]
+ Duration subsecond; // [Seconds(0):Seconds(1)) if finite
+ int weekday; // 1==Mon, ..., 7=Sun
+ int yearday; // day of year [1:366]
+
+ // Note: The following fields exist for backward compatibility
+ // with older APIs. Accessing these fields directly is a sign of
+ // imprudent logic in the calling code. Modern time-related code
+ // should only access this data indirectly by way of FormatTime().
+ // These fields are undefined for InfiniteFuture() and InfinitePast().
+ int offset; // seconds east of UTC
+ bool is_dst; // is offset non-standard?
+ const char* zone_abbr; // time-zone abbreviation (e.g., "PST")
+ };
+
+ // Time::In()
+ //
+ // Returns the breakdown of this instant in the given TimeZone.
+ Breakdown In(TimeZone tz) const;
+
+ private:
+ friend constexpr Time time_internal::FromUnixDuration(Duration d);
+ friend constexpr Duration time_internal::ToUnixDuration(Time t);
+ friend constexpr bool operator<(Time lhs, Time rhs);
+ friend constexpr bool operator==(Time lhs, Time rhs);
+ friend Duration operator-(Time lhs, Time rhs);
+ friend constexpr Time UniversalEpoch();
+ friend constexpr Time InfiniteFuture();
+ friend constexpr Time InfinitePast();
+ constexpr explicit Time(Duration rep) : rep_(rep) {}
+ Duration rep_;
+};
+
+// Relational Operators
+constexpr bool operator<(Time lhs, Time rhs) { return lhs.rep_ < rhs.rep_; }
+constexpr bool operator>(Time lhs, Time rhs) { return rhs < lhs; }
+constexpr bool operator>=(Time lhs, Time rhs) { return !(lhs < rhs); }
+constexpr bool operator<=(Time lhs, Time rhs) { return !(rhs < lhs); }
+constexpr bool operator==(Time lhs, Time rhs) { return lhs.rep_ == rhs.rep_; }
+constexpr bool operator!=(Time lhs, Time rhs) { return !(lhs == rhs); }
+
+// Additive Operators
+inline Time operator+(Time lhs, Duration rhs) { return lhs += rhs; }
+inline Time operator+(Duration lhs, Time rhs) { return rhs += lhs; }
+inline Time operator-(Time lhs, Duration rhs) { return lhs -= rhs; }
+inline Duration operator-(Time lhs, Time rhs) { return lhs.rep_ - rhs.rep_; }
+
+// UnixEpoch()
+//
+// Returns the `absl::Time` representing "1970-01-01 00:00:00.0 +0000".
+constexpr Time UnixEpoch() {
+ return Time();
+}
+
+// UniversalEpoch()
+//
+// Returns the `absl::Time` representing "0001-01-01 00:00:00.0 +0000", the
+// epoch of the ICU Universal Time Scale.
+constexpr Time UniversalEpoch() {
+ // 719162 is the number of days from 0001-01-01 to 1970-01-01,
+ // assuming the Gregorian calendar.
+ return Time(time_internal::MakeDuration(-24 * 719162 * int64_t{3600}, 0U));
+}
+
+// InfiniteFuture()
+//
+// Returns an `absl::Time` that is infinitely far in the future.
+constexpr Time InfiniteFuture() {
+ return Time(
+ time_internal::MakeDuration(std::numeric_limits<int64_t>::max(), ~0U));
+}
+
+// InfinitePast()
+//
+// Returns an `absl::Time` that is infinitely far in the past.
+constexpr Time InfinitePast() {
+ return Time(
+ time_internal::MakeDuration(std::numeric_limits<int64_t>::min(), ~0U));
+}
+
+// TimeConversion
+//
+// An `absl::TimeConversion` represents the conversion of year, month, day,
+// hour, minute, and second values (i.e., a civil time), in a particular
+// `absl::TimeZone`, to a time instant (an absolute time), as returned by
+// `absl::ConvertDateTime()`. (Subseconds must be handled separately.)
+//
+// It is possible, though, for a caller to try to convert values that
+// do not represent an actual or unique instant in time (due to a shift
+// in UTC offset in the `absl::TimeZone`, which results in a discontinuity in
+// the civil-time components). For example, a daylight-saving-time
+// transition skips or repeats civil times---in the United States, March
+// 13, 2011 02:15 never occurred, while November 6, 2011 01:15 occurred
+// twice---so requests for such times are not well-defined.
+//
+// To account for these possibilities, `absl::TimeConversion` is richer
+// than just a single `absl::Time`. When the civil time is skipped or
+// repeated, `absl::ConvertDateTime()` returns times calculated using the
+// pre-transition and post-transition UTC offsets, plus the transition
+// time itself.
+//
+// Examples:
+//
+// absl::TimeZone lax;
+// if (!absl::LoadTimeZone("America/Los_Angeles", &lax)) { ... }
+//
+// // A unique civil time
+// absl::TimeConversion jan01 =
+// absl::ConvertDateTime(2011, 1, 1, 0, 0, 0, lax);
+// // jan01.kind == TimeConversion::UNIQUE
+// // jan01.pre is 2011/01/01 00:00:00 -0800
+// // jan01.trans is 2011/01/01 00:00:00 -0800
+// // jan01.post is 2011/01/01 00:00:00 -0800
+//
+// // A Spring DST transition, when there is a gap in civil time
+// absl::TimeConversion mar13 =
+// absl::ConvertDateTime(2011, 3, 13, 2, 15, 0, lax);
+// // mar13.kind == TimeConversion::SKIPPED
+// // mar13.pre is 2011/03/13 03:15:00 -0700
+// // mar13.trans is 2011/03/13 03:00:00 -0700
+// // mar13.post is 2011/03/13 01:15:00 -0800
+//
+// // A Fall DST transition, when civil times are repeated
+// absl::TimeConversion nov06 =
+// absl::ConvertDateTime(2011, 11, 6, 1, 15, 0, lax);
+// // nov06.kind == TimeConversion::REPEATED
+// // nov06.pre is 2011/11/06 01:15:00 -0700
+// // nov06.trans is 2011/11/06 01:00:00 -0800
+// // nov06.post is 2011/11/06 01:15:00 -0800
+//
+// The input month, day, hour, minute, and second values can also be
+// outside of their valid ranges, in which case they will be "normalized"
+// during the conversion.
+//
+// Example:
+//
+// // "October 32" normalizes to "November 1".
+// absl::TimeZone tz = absl::LocalTimeZone();
+// absl::TimeConversion tc =
+// absl::ConvertDateTime(2013, 10, 32, 8, 30, 0, tz);
+// // tc.kind == TimeConversion::UNIQUE && tc.normalized == true
+// // tc.pre.In(tz).month == 11 && tc.pre.In(tz).day == 1
+struct TimeConversion {
+ Time pre; // time calculated using the pre-transition offset
+ Time trans; // when the civil-time discontinuity occurred
+ Time post; // time calculated using the post-transition offset
+
+ enum Kind {
+ UNIQUE, // the civil time was singular (pre == trans == post)
+ SKIPPED, // the civil time did not exist
+ REPEATED, // the civil time was ambiguous
+ };
+ Kind kind;
+
+ bool normalized; // input values were outside their valid ranges
+};
+
+// ConvertDateTime()
+//
+// The full generality of a civil time to absl::Time conversion.
+TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour,
+ int min, int sec, TimeZone tz);
+
+// FromDateTime()
+//
+// A convenience wrapper for `absl::ConvertDateTime()` that simply returns the
+// "pre" `absl::Time`. That is, the unique result, or the instant that
+// is correct using the pre-transition offset (as if the transition
+// never happened). This is typically the answer that humans expected when
+// faced with non-unique times, such as near daylight-saving time transitions.
+//
+// Example:
+//
+// absl::TimeZone seattle;
+// if (!absl::LoadTimeZone("America/Los_Angeles", &seattle)) { ... }
+// absl::Time t = absl::FromDateTime(2017, 9, 26, 9, 30, 0, seattle);
+Time FromDateTime(int64_t year, int mon, int day, int hour, int min, int sec,
+ TimeZone tz);
+
+// FromTM()
+//
+// Converts the `tm_year`, `tm_mon`, `tm_mday`, `tm_hour`, `tm_min`, and
+// `tm_sec` fields to an `absl::Time` using the given time zone. See ctime(3)
+// for a description of the expected values of the tm fields. IFF the indicated
+// time instant is not unique (see `absl::ConvertDateTime()` above), the
+// `tm_isdst` field is consulted to select the desired instant (`tm_isdst` > 0
+// means DST, `tm_isdst` == 0 means no DST, `tm_isdst` < 0 means use the default
+// like `absl::FromDateTime()`).
+Time FromTM(const struct tm& tm, TimeZone tz);
+
+// ToTM()
+//
+// Converts the given `absl::Time` to a struct tm using the given time zone.
+// See ctime(3) for a description of the values of the tm fields.
+struct tm ToTM(Time t, TimeZone tz);
+
+// FromUnixNanos()
+// FromUnixMicros()
+// FromUnixMillis()
+// FromUnixSeconds()
+// FromTimeT()
+// FromUDate()
+// FromUniversal()
+//
+// Creates an `absl::Time` from a variety of other representations.
+constexpr Time FromUnixNanos(int64_t ns);
+constexpr Time FromUnixMicros(int64_t us);
+constexpr Time FromUnixMillis(int64_t ms);
+constexpr Time FromUnixSeconds(int64_t s);
+constexpr Time FromTimeT(time_t t);
+Time FromUDate(double udate);
+Time FromUniversal(int64_t universal);
+
+// ToUnixNanos()
+// ToUnixMicros()
+// ToUnixMillis()
+// ToUnixSeconds()
+// ToTimeT()
+// ToUDate()
+// ToUniversal()
+//
+// Converts an `absl::Time` to a variety of other representations. Note that
+// these operations round down toward negative infinity where necessary to
+// adjust to the resolution of the result type. Beware of possible time_t
+// over/underflow in ToTime{T,val,spec}() on 32-bit platforms.
+int64_t ToUnixNanos(Time t);
+int64_t ToUnixMicros(Time t);
+int64_t ToUnixMillis(Time t);
+int64_t ToUnixSeconds(Time t);
+time_t ToTimeT(Time t);
+double ToUDate(Time t);
+int64_t ToUniversal(Time t);
+
+// DurationFromTimespec()
+// DurationFromTimeval()
+// ToTimespec()
+// ToTimeval()
+// TimeFromTimespec()
+// TimeFromTimeval()
+// ToTimespec()
+// ToTimeval()
+//
+// Some APIs use a timespec or a timeval as a Duration (e.g., nanosleep(2)
+// and select(2)), while others use them as a Time (e.g. clock_gettime(2)
+// and gettimeofday(2)), so conversion functions are provided for both cases.
+// The "to timespec/val" direction is easily handled via overloading, but
+// for "from timespec/val" the desired type is part of the function name.
+Duration DurationFromTimespec(timespec ts);
+Duration DurationFromTimeval(timeval tv);
+timespec ToTimespec(Duration d);
+timeval ToTimeval(Duration d);
+Time TimeFromTimespec(timespec ts);
+Time TimeFromTimeval(timeval tv);
+timespec ToTimespec(Time t);
+timeval ToTimeval(Time t);
+
+// RFC3339_full
+// RFC3339_sec
+//
+// FormatTime()/ParseTime() format specifiers for RFC3339 date/time strings,
+// with trailing zeros trimmed or with fractional seconds omitted altogether.
+//
+// Note that RFC3339_sec[] matches an ISO 8601 extended format for date
+// and time with UTC offset.
+extern const char RFC3339_full[]; // %Y-%m-%dT%H:%M:%E*S%Ez
+extern const char RFC3339_sec[]; // %Y-%m-%dT%H:%M:%S%Ez
+
+// RFC1123_full
+// RFC1123_no_wday
+//
+// FormatTime()/ParseTime() format specifiers for RFC1123 date/time strings.
+extern const char RFC1123_full[]; // %a, %d %b %E4Y %H:%M:%S %z
+extern const char RFC1123_no_wday[]; // %d %b %E4Y %H:%M:%S %z
+
+// FormatTime()
+//
+// Formats the given `absl::Time` in the `absl::TimeZone` according to the
+// provided format std::string. Uses strftime()-like formatting options, with
+// the following extensions:
+//
+// - %Ez - RFC3339-compatible numeric time zone (+hh:mm or -hh:mm)
+// - %E#S - Seconds with # digits of fractional precision
+// - %E*S - Seconds with full fractional precision (a literal '*')
+// - %E#f - Fractional seconds with # digits of precision
+// - %E*f - Fractional seconds with full precision (a literal '*')
+// - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
+//
+// Note that %E0S behaves like %S, and %E0f produces no characters. In
+// contrast %E*f always produces at least one digit, which may be '0'.
+//
+// Note that %Y produces as many characters as it takes to fully render the
+// year. A year outside of [-999:9999] when formatted with %E4Y will produce
+// more than four characters, just like %Y.
+//
+// We recommend that format strings include %Ez so that the result uniquely
+// identifies a time instant.
+//
+// Example:
+//
+// absl::TimeZone lax;
+// if (!absl::LoadTimeZone("America/Los_Angeles", &lax)) { ... }
+// absl::Time t = absl::FromDateTime(2013, 1, 2, 3, 4, 5, lax);
+//
+// std::string f = absl::FormatTime("%H:%M:%S", t, lax); // "03:04:05"
+// f = absl::FormatTime("%H:%M:%E3S", t, lax); // "03:04:05.000"
+//
+// Note: If the given `absl::Time` is `absl::InfiniteFuture()`, the returned
+// std::string will be exactly "infinite-future". If the given `absl::Time` is
+// `absl::InfinitePast()`, the returned std::string will be exactly "infinite-past".
+// In both cases the given format std::string and `absl::TimeZone` are ignored.
+//
+std::string FormatTime(const std::string& format, Time t, TimeZone tz);
+
+// Convenience functions that format the given time using the RFC3339_full
+// format. The first overload uses the provided TimeZone, while the second
+// uses LocalTimeZone().
+std::string FormatTime(Time t, TimeZone tz);
+std::string FormatTime(Time t);
+
+// Output stream operator.
+inline std::ostream& operator<<(std::ostream& os, Time t) {
+ return os << FormatTime(t);
+}
+
+// ParseTime()
+//
+// Parses an input std::string according to the provided format std::string and
+// returns the corresponding `absl::Time`. Uses strftime()-like formatting
+// options, with the same extensions as FormatTime(), but with the
+// exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f.
+//
+// %Y consumes as many numeric characters as it can, so the matching data
+// should always be terminated with a non-numeric. %E4Y always consumes
+// exactly four characters, including any sign.
+//
+// Unspecified fields are taken from the default date and time of ...
+//
+// "1970-01-01 00:00:00.0 +0000"
+//
+// For example, parsing a std::string of "15:45" (%H:%M) will return a absl::Time
+// that represents "1970-01-01 15:45:00.0 +0000". Note: Since ParseTime()
+// returns time instants, it makes the most sense to parse fully-specified
+// date/time strings that include a UTC offset (%z/%Ez), such as those
+// matching RFC3339_full above.
+//
+// Note also that `absl::ParseTime()` only heeds the fields year, month, day,
+// hour, minute, (fractional) second, and UTC offset. Other fields, like
+// weekday (%a or %A), while parsed for syntactic validity, are ignored
+// in the conversion.
+//
+// Date and time fields that are out-of-range will be treated as errors
+// rather than normalizing them like `absl::FromDateTime()` does. For example,
+// it is an error to parse the date "Oct 32, 2013" because 32 is out of range.
+//
+// A leap second of ":60" is normalized to ":00" of the following minute
+// with fractional seconds discarded. The following table shows how the
+// given seconds and subseconds will be parsed:
+//
+// "59.x" -> 59.x // exact
+// "60.x" -> 00.0 // normalized
+// "00.x" -> 00.x // exact
+//
+// Errors are indicated by returning false and assigning an error message
+// to the "err" out param if it is non-null.
+//
+// Note: If the input std::string is exactly "infinite-future", the returned
+// `absl::Time` will be `absl::InfiniteFuture()` and `true` will be returned.
+// If the input std::string is "infinite-past", the returned `absl::Time` will be
+// `absl::InfinitePast()` and `true` will be returned.
+//
+bool ParseTime(const std::string& format, const std::string& input,
+ Time* time, std::string* err);
+
+// Like ParseTime() above, but if the format std::string does not contain a UTC
+// offset specification (%z/%Ez) then the input is interpreted in the given
+// TimeZone. This means that the input, by itself, does not identify a
+// unique instant. Being time-zone dependent, it also admits the possibility
+// of ambiguity or non-existence, in which case the "pre" time (as defined
+// for ConvertDateTime()) is returned. For these reasons we recommend that
+// all date/time strings include a UTC offset so they're context independent.
+bool ParseTime(const std::string& format, const std::string& input, TimeZone tz,
+ Time* time, std::string* err);
+
+// TODO(b/63899288) copybara strip once dependencies are removed.
+
+// ParseFlag()
+// UnparseFlag()
+//
+// Support for flag values of type Time. Time flags must be specified in a
+// format that matches absl::RFC3339_full. For example:
+//
+// --start_time=2016-01-02T03:04:05.678+08:00
+//
+// Note: A UTC offset (or 'Z' indicating a zero-offset from UTC) is required.
+// If your application doesn't have a UTC offset to specify, perhaps you're
+// really specifying a Civil Time
+// Additionally, if you'd like to specify a time as a count of
+// seconds/milliseconds/etc from the Unix epoch, use a absl::Duration flag and
+// add that duration to absl::UnixEpoch() to get a absl::Time.
+bool ParseFlag(const std::string& text, Time* t, std::string* error);
+std::string UnparseFlag(Time t);
+
+// TimeZone
+//
+// The `absl::TimeZone` is an opaque, small, value-type class representing a
+// geo-political region within which particular rules are used for converting
+// between absolute and civil times (see https://git.io/v59Ly). `absl::TimeZone`
+// values are named using the TZ identifiers from the IANA Time Zone Database,
+// such as "America/Los_Angeles" or "Australia/Sydney". `absl::TimeZone` values
+// are created from factory functions such as `absl::LoadTimeZone()`. Note:
+// strings like "PST" and "EDT" are not valid TZ identifiers. Prefer to pass by
+// value rather than const reference.
+//
+// For more on the fundamental concepts of time zones, absolute times, and civil
+// times, see https://github.com/google/cctz#fundamental-concepts
+//
+// Examples:
+//
+// absl::TimeZone utc = absl::UTCTimeZone();
+// absl::TimeZone pst = absl::FixedTimeZone(-8 * 60 * 60);
+// absl::TimeZone loc = absl::LocalTimeZone();
+// absl::TimeZone lax;
+// if (!absl::LoadTimeZone("America/Los_Angeles", &lax)) { ... }
+//
+// See also:
+// - https://github.com/google/cctz
+// - http://www.iana.org/time-zones
+// - http://en.wikipedia.org/wiki/Zoneinfo
+// TimeZone backing data with your binary.
+class TimeZone {
+ public:
+ explicit TimeZone(cctz::time_zone tz) : cz_(tz) {}
+ TimeZone() = default; // UTC, but prefer UTCTimeZone() to be explicit.
+ TimeZone(const TimeZone&) = default;
+ TimeZone& operator=(const TimeZone&) = default;
+
+ explicit operator cctz::time_zone() const { return cz_; }
+
+ std::string name() const { return cz_.name(); }
+
+ private:
+ friend bool operator==(TimeZone a, TimeZone b) { return a.cz_ == b.cz_; }
+ friend bool operator!=(TimeZone a, TimeZone b) { return a.cz_ != b.cz_; }
+ friend std::ostream& operator<<(std::ostream& os, TimeZone tz) {
+ return os << tz.name();
+ }
+
+ cctz::time_zone cz_;
+};
+
+// LoadTimeZone()
+//
+// Loads the named zone. May perform I/O on the initial load of the named
+// zone. If the name is invalid, or some other kind of error occurs, returns
+// `false` and `*tz` is set to the UTC time zone.
+inline bool LoadTimeZone(const std::string& name, TimeZone* tz) {
+ if (name == "localtime") {
+ *tz = TimeZone(cctz::local_time_zone());
+ return true;
+ }
+ cctz::time_zone cz;
+ const bool b = cctz::load_time_zone(name, &cz);
+ *tz = TimeZone(cz);
+ return b;
+}
+
+// FixedTimeZone()
+//
+// Returns a TimeZone that is a fixed offset (seconds east) from UTC.
+// Note: If the absolute value of the offset is greater than 24 hours
+// you'll get UTC (i.e., no offset) instead.
+inline TimeZone FixedTimeZone(int seconds) {
+ return TimeZone(cctz::fixed_time_zone(std::chrono::seconds(seconds)));
+}
+
+// UTCTimeZone()
+//
+// Convenience method returning the UTC time zone.
+inline TimeZone UTCTimeZone() { return TimeZone(cctz::utc_time_zone()); }
+
+// LocalTimeZone()
+//
+// Convenience method returning the local time zone, or UTC if there is
+// no configured local zone. Warning: Be wary of using LocalTimeZone(),
+// and particularly so in a server process, as the zone configured for the
+// local machine should be irrelevant. Prefer an explicit zone name.
+inline TimeZone LocalTimeZone() { return TimeZone(cctz::local_time_zone()); }
+
+// ============================================================================
+// Implementation Details Follow
+// ============================================================================
+
+namespace time_internal {
+
+// Creates a Duration with a given representation.
+// REQUIRES: hi,lo is a valid representation of a Duration as specified
+// in time/duration.cc.
+constexpr Duration MakeDuration(int64_t hi, uint32_t lo = 0) {
+ return Duration(hi, lo);
+}
+
+constexpr Duration MakeDuration(int64_t hi, int64_t lo) {
+ return time_internal::MakeDuration(hi, static_cast<uint32_t>(lo));
+}
+
+// Creates a normalized Duration from an almost-normalized (sec,ticks)
+// pair. sec may be positive or negative. ticks must be in the range
+// -kTicksPerSecond < *ticks < kTicksPerSecond. If ticks is negative it
+// will be normalized to a positive value in the resulting Duration.
+constexpr Duration MakeNormalizedDuration(int64_t sec, int64_t ticks) {
+ return (ticks < 0)
+ ? time_internal::MakeDuration(sec - 1, ticks + kTicksPerSecond)
+ : time_internal::MakeDuration(sec, ticks);
+}
+// Provide access to the Duration representation.
+constexpr int64_t GetRepHi(Duration d) { return d.rep_hi_; }
+constexpr uint32_t GetRepLo(Duration d) { return d.rep_lo_; }
+constexpr bool IsInfiniteDuration(Duration d) { return GetRepLo(d) == ~0U; }
+
+// Returns an infinite Duration with the opposite sign.
+// REQUIRES: IsInfiniteDuration(d)
+constexpr Duration OppositeInfinity(Duration d) {
+ return GetRepHi(d) < 0
+ ? MakeDuration(std::numeric_limits<int64_t>::max(), ~0U)
+ : MakeDuration(std::numeric_limits<int64_t>::min(), ~0U);
+}
+
+// Returns (-n)-1 (equivalently -(n+1)) without overflowing on any input value.
+constexpr int64_t NegateAndSubtractOne(int64_t n) {
+ return (n < 0) ? -(n + 1) : (-n) - 1;
+}
+
+// Map between a Time and a Duration since the Unix epoch. Note that these
+// functions depend on the above mentioned choice of the Unix epoch for the
+// Time representation (and both need to be Time friends). Without this
+// knowledge, we would need to add-in/subtract-out UnixEpoch() respectively.
+constexpr Time FromUnixDuration(Duration d) { return Time(d); }
+constexpr Duration ToUnixDuration(Time t) { return t.rep_; }
+} // namespace time_internal
+
+constexpr bool operator<(Duration lhs, Duration rhs) {
+ return time_internal::GetRepHi(lhs) != time_internal::GetRepHi(rhs)
+ ? time_internal::GetRepHi(lhs) < time_internal::GetRepHi(rhs)
+ : time_internal::GetRepHi(lhs) == std::numeric_limits<int64_t>::min()
+ ? time_internal::GetRepLo(lhs) + 1 <
+ time_internal::GetRepLo(rhs) + 1
+ : time_internal::GetRepLo(lhs) <
+ time_internal::GetRepLo(rhs);
+}
+
+constexpr bool operator==(Duration lhs, Duration rhs) {
+ return time_internal::GetRepHi(lhs) == time_internal::GetRepHi(rhs) &&
+ time_internal::GetRepLo(lhs) == time_internal::GetRepLo(rhs);
+}
+
+constexpr Duration operator-(Duration d) {
+ // This is a little interesting because of the special cases.
+ //
+ // Infinities stay infinite, and just change direction.
+ //
+ // The maximum negative finite duration can't be negated (at least, not
+ // on a two's complement machine), so we return infinity for that case.
+ // Next we dispatch the case where rep_lo_ is zero, observing that it's
+ // safe to negate rep_hi_ in this case because it's not int64_t-min (or
+ // else we'd have handled it above, returning InfiniteDuration()).
+ //
+ // Finally we're in the case where rep_lo_ is non-zero, and we can borrow
+ // a second's worth of ticks and avoid overflow (as negating int64_t-min + 1
+ // is safe).
+ return time_internal::IsInfiniteDuration(d)
+ ? time_internal::OppositeInfinity(d)
+ : (time_internal::GetRepHi(d) ==
+ std::numeric_limits<int64_t>::min() &&
+ time_internal::GetRepLo(d) == 0)
+ ? InfiniteDuration()
+ : (time_internal::GetRepLo(d) == 0)
+ ? time_internal::MakeDuration(
+ -time_internal::GetRepHi(d))
+ : time_internal::MakeDuration(
+ time_internal::NegateAndSubtractOne(
+ time_internal::GetRepHi(d)),
+ time_internal::kTicksPerSecond -
+ time_internal::GetRepLo(d));
+}
+
+constexpr Duration Nanoseconds(int64_t n) {
+ return time_internal::MakeNormalizedDuration(
+ n / (1000 * 1000 * 1000),
+ n % (1000 * 1000 * 1000) * time_internal::kTicksPerNanosecond);
+}
+
+constexpr Duration Microseconds(int64_t n) {
+ return time_internal::MakeNormalizedDuration(
+ n / (1000 * 1000),
+ n % (1000 * 1000) * (1000 * time_internal::kTicksPerNanosecond));
+}
+
+constexpr Duration Milliseconds(int64_t n) {
+ return time_internal::MakeNormalizedDuration(
+ n / 1000, n % 1000 * (1000 * 1000 * time_internal::kTicksPerNanosecond));
+}
+
+constexpr Duration Seconds(int64_t n) { return time_internal::MakeDuration(n); }
+
+constexpr Duration Minutes(int64_t n) {
+ return (n <= std::numeric_limits<int64_t>::max() / 60 &&
+ n >= std::numeric_limits<int64_t>::min() / 60)
+ ? time_internal::MakeDuration(n * 60)
+ : n > 0 ? InfiniteDuration() : -InfiniteDuration();
+}
+
+constexpr Duration Hours(int64_t n) {
+ return (n <= std::numeric_limits<int64_t>::max() / 3600 &&
+ n >= std::numeric_limits<int64_t>::min() / 3600)
+ ? time_internal::MakeDuration(n * 3600)
+ : n > 0 ? InfiniteDuration() : -InfiniteDuration();
+}
+
+constexpr Duration InfiniteDuration() {
+ return time_internal::MakeDuration(std::numeric_limits<int64_t>::max(), ~0U);
+}
+
+constexpr Time FromUnixNanos(int64_t ns) {
+ return time_internal::FromUnixDuration(Nanoseconds(ns));
+}
+
+constexpr Time FromUnixMicros(int64_t us) {
+ return time_internal::FromUnixDuration(Microseconds(us));
+}
+
+constexpr Time FromUnixMillis(int64_t ms) {
+ return time_internal::FromUnixDuration(Milliseconds(ms));
+}
+
+constexpr Time FromUnixSeconds(int64_t s) {
+ return time_internal::FromUnixDuration(Seconds(s));
+}
+
+constexpr Time FromTimeT(time_t t) {
+ return time_internal::FromUnixDuration(Seconds(t));
+}
+
+} // namespace absl
+
+#endif // ABSL_TIME_TIME_H_
diff --git a/absl/time/time_norm_test.cc b/absl/time/time_norm_test.cc
new file mode 100644
index 0000000..005756e
--- /dev/null
+++ b/absl/time/time_norm_test.cc
@@ -0,0 +1,306 @@
+// 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 contains tests for FromDateTime() normalization, which is
+// time-zone independent so we just use UTC throughout.
+
+#include <cstdint>
+#include <limits>
+
+#include "gtest/gtest.h"
+#include "absl/time/internal/test_util.h"
+#include "absl/time/time.h"
+
+namespace {
+
+TEST(TimeNormCase, SimpleOverflow) {
+ const absl::TimeZone utc = absl::UTCTimeZone();
+
+ absl::TimeConversion tc =
+ absl::ConvertDateTime(2013, 11, 15, 16, 32, 59 + 1, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ absl::Time::Breakdown bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 33, 0, 0, false, "UTC");
+
+ tc = absl::ConvertDateTime(2013, 11, 15, 16, 59 + 1, 14, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 17, 0, 14, 0, false, "UTC");
+
+ tc = absl::ConvertDateTime(2013, 11, 15, 23 + 1, 32, 14, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 16, 0, 32, 14, 0, false, "UTC");
+
+ tc = absl::ConvertDateTime(2013, 11, 30 + 1, 16, 32, 14, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 1, 16, 32, 14, 0, false, "UTC");
+
+ tc = absl::ConvertDateTime(2013, 12 + 1, 15, 16, 32, 14, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 15, 16, 32, 14, 0, false, "UTC");
+}
+
+TEST(TimeNormCase, SimpleUnderflow) {
+ const absl::TimeZone utc = absl::UTCTimeZone();
+
+ absl::TimeConversion tc = ConvertDateTime(2013, 11, 15, 16, 32, 0 - 1, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ absl::Time::Breakdown bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 31, 59, 0, false, "UTC");
+
+ tc = ConvertDateTime(2013, 11, 15, 16, 0 - 1, 14, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 15, 59, 14, 0, false, "UTC");
+
+ tc = ConvertDateTime(2013, 11, 15, 0 - 1, 32, 14, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 14, 23, 32, 14, 0, false, "UTC");
+
+ tc = ConvertDateTime(2013, 11, 1 - 1, 16, 32, 14, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 10, 31, 16, 32, 14, 0, false, "UTC");
+
+ tc = ConvertDateTime(2013, 1 - 1, 15, 16, 32, 14, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 12, 15, 16, 32, 14, 0, false, "UTC");
+}
+
+TEST(TimeNormCase, MultipleOverflow) {
+ const absl::TimeZone utc = absl::UTCTimeZone();
+ absl::TimeConversion tc = ConvertDateTime(2013, 12, 31, 23, 59, 59 + 1, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ absl::Time::Breakdown bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 1, 0, 0, 0, 0, false, "UTC");
+}
+
+TEST(TimeNormCase, MultipleUnderflow) {
+ const absl::TimeZone utc = absl::UTCTimeZone();
+ absl::TimeConversion tc = absl::ConvertDateTime(2014, 1, 1, 0, 0, 0 - 1, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ absl::Time::Breakdown bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 31, 23, 59, 59, 0, false, "UTC");
+}
+
+TEST(TimeNormCase, OverflowLimits) {
+ const absl::TimeZone utc = absl::UTCTimeZone();
+ absl::TimeConversion tc;
+ absl::Time::Breakdown bd;
+
+ const int kintmax = std::numeric_limits<int>::max();
+ tc = absl::ConvertDateTime(0, kintmax, kintmax, kintmax, kintmax, kintmax,
+ utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 185085715, 11, 27, 12, 21, 7, 0, false, "UTC");
+
+ const int kintmin = std::numeric_limits<int>::min();
+ tc = absl::ConvertDateTime(0, kintmin, kintmin, kintmin, kintmin, kintmin,
+ utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, -185085717, 10, 31, 10, 37, 52, 0, false,
+ "UTC");
+
+ const int64_t max_year = std::numeric_limits<int64_t>::max();
+ tc = absl::ConvertDateTime(max_year, 12, 31, 23, 59, 59, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ EXPECT_EQ(absl::InfiniteFuture(), tc.pre);
+
+ const int64_t min_year = std::numeric_limits<int64_t>::min();
+ tc = absl::ConvertDateTime(min_year, 1, 1, 0, 0, 0, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ EXPECT_EQ(absl::InfinitePast(), tc.pre);
+}
+
+TEST(TimeNormCase, ComplexOverflow) {
+ const absl::TimeZone utc = absl::UTCTimeZone();
+
+ absl::TimeConversion tc =
+ ConvertDateTime(2013, 11, 15, 16, 32, 14 + 123456789, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ absl::Time::Breakdown bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 10, 14, 14, 5, 23, 0, false, "UTC");
+
+ tc = absl::ConvertDateTime(2013, 11, 15, 16, 32 + 1234567, 14, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2016, 3, 22, 0, 39, 14, 0, false, "UTC");
+
+ tc = absl::ConvertDateTime(2013, 11, 15, 16 + 123456, 32, 14, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2027, 12, 16, 16, 32, 14, 0, false, "UTC");
+
+ tc = absl::ConvertDateTime(2013, 11, 15 + 1234, 16, 32, 14, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 4, 2, 16, 32, 14, 0, false, "UTC");
+
+ tc = absl::ConvertDateTime(2013, 11 + 123, 15, 16, 32, 14, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2024, 2, 15, 16, 32, 14, 0, false, "UTC");
+}
+
+TEST(TimeNormCase, ComplexUnderflow) {
+ const absl::TimeZone utc = absl::UTCTimeZone();
+
+ absl::TimeConversion tc =
+ absl::ConvertDateTime(1999, 3, 0, 0, 0, 0, utc); // year 400
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ absl::Time::Breakdown bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 2, 28, 0, 0, 0, 0, false, "UTC");
+
+ tc = absl::ConvertDateTime(2013, 11, 15, 16, 32, 14 - 123456789, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2009, 12, 17, 18, 59, 5, 0, false, "UTC");
+
+ tc = absl::ConvertDateTime(2013, 11, 15, 16, 32 - 1234567, 14, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2011, 7, 12, 8, 25, 14, 0, false, "UTC");
+
+ tc = absl::ConvertDateTime(2013, 11, 15, 16 - 123456, 32, 14, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 10, 16, 16, 32, 14, 0, false, "UTC");
+
+ tc = absl::ConvertDateTime(2013, 11, 15 - 1234, 16, 32, 14, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2010, 6, 30, 16, 32, 14, 0, false, "UTC");
+
+ tc = absl::ConvertDateTime(2013, 11 - 123, 15, 16, 32, 14, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2003, 8, 15, 16, 32, 14, 0, false, "UTC");
+}
+
+TEST(TimeNormCase, Mishmash) {
+ const absl::TimeZone utc = absl::UTCTimeZone();
+
+ absl::TimeConversion tc =
+ absl::ConvertDateTime(2013, 11 - 123, 15 + 1234, 16 - 123456,
+ 32 + 1234567, 14 - 123456789, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ absl::Time::Breakdown bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 1991, 5, 9, 3, 6, 5, 0, false, "UTC");
+
+ tc = absl::ConvertDateTime(2013, 11 + 123, 15 - 1234, 16 + 123456,
+ 32 - 1234567, 14 + 123456789, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2036, 5, 24, 5, 58, 23, 0, false, "UTC");
+
+ // Here is a normalization case we got wrong for a while. Because the
+ // day is converted to "1" within a 400-year (146097-day) period, we
+ // didn't need to roll the month and so we didn't mark it as normalized.
+ tc = absl::ConvertDateTime(2013, 11, -146097 + 1, 16, 32, 14, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 1613, 11, 1, 16, 32, 14, 0, false, "UTC");
+
+ // Even though the month overflow compensates for the day underflow,
+ // this should still be marked as normalized.
+ tc = absl::ConvertDateTime(2013, 11 + 400 * 12, -146097 + 1, 16, 32, 14, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 1, 16, 32, 14, 0, false, "UTC");
+}
+
+TEST(TimeNormCase, LeapYears) {
+ const absl::TimeZone utc = absl::UTCTimeZone();
+
+ absl::TimeConversion tc =
+ absl::ConvertDateTime(2013, 2, 28 + 1, 0, 0, 0, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ absl::Time::Breakdown bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 3, 1, 0, 0, 0, 0, false, "UTC");
+
+ tc = absl::ConvertDateTime(2012, 2, 28 + 1, 0, 0, 0, utc);
+ EXPECT_FALSE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 2, 29, 0, 0, 0, 0, false, "UTC");
+
+ tc = absl::ConvertDateTime(2000, 2, 28 + 1, 0, 0, 0, utc);
+ EXPECT_FALSE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 2000, 2, 29, 0, 0, 0, 0, false, "UTC");
+
+ tc = absl::ConvertDateTime(1900, 2, 28 + 1, 0, 0, 0, utc);
+ EXPECT_TRUE(tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ bd = tc.pre.In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 1900, 3, 1, 0, 0, 0, 0, false, "UTC");
+}
+
+// Convert all the days from 1970-1-1 to 1970-1-146097 (aka 2369-12-31)
+// and check that they normalize to the expected time. 146097 days span
+// the 400-year Gregorian cycle used during normalization.
+TEST(TimeNormCase, AllTheDays) {
+ const absl::TimeZone utc = absl::UTCTimeZone();
+ absl::Time exp_time = absl::UnixEpoch();
+
+ for (int day = 1; day <= 146097; ++day) {
+ absl::TimeConversion tc = absl::ConvertDateTime(1970, 1, day, 0, 0, 0, utc);
+ EXPECT_EQ(day > 31, tc.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
+ EXPECT_EQ(exp_time, tc.pre);
+ exp_time += absl::Hours(24);
+ }
+}
+
+} // namespace
diff --git a/absl/time/time_test.cc b/absl/time/time_test.cc
new file mode 100644
index 0000000..51b9e53
--- /dev/null
+++ b/absl/time/time_test.cc
@@ -0,0 +1,1027 @@
+// 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/time/time.h"
+
+#include <cstring>
+#include <ctime>
+#include <iomanip>
+#include <limits>
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/time/clock.h"
+#include "absl/time/internal/test_util.h"
+
+namespace {
+
+// A gMock matcher to match timespec values. Use this matcher like:
+// timespec ts1, ts2;
+// EXPECT_THAT(ts1, TimespecMatcher(ts2));
+MATCHER_P(TimespecMatcher, ts, "") {
+ if (ts.tv_sec == arg.tv_sec && ts.tv_nsec == arg.tv_nsec)
+ return true;
+ *result_listener << "expected: {" << ts.tv_sec << ", " << ts.tv_nsec << "} ";
+ *result_listener << "actual: {" << arg.tv_sec << ", " << arg.tv_nsec << "}";
+ return false;
+}
+
+// A gMock matcher to match timeval values. Use this matcher like:
+// timeval tv1, tv2;
+// EXPECT_THAT(tv1, TimevalMatcher(tv2));
+MATCHER_P(TimevalMatcher, tv, "") {
+ if (tv.tv_sec == arg.tv_sec && tv.tv_usec == arg.tv_usec)
+ return true;
+ *result_listener << "expected: {" << tv.tv_sec << ", " << tv.tv_usec << "} ";
+ *result_listener << "actual: {" << arg.tv_sec << ", " << arg.tv_usec << "}";
+ return false;
+}
+
+TEST(Time, ConstExpr) {
+ constexpr absl::Time t0 = absl::UnixEpoch();
+ static_assert(t0 == absl::Time(), "UnixEpoch");
+ constexpr absl::Time t1 = absl::InfiniteFuture();
+ static_assert(t1 != absl::Time(), "InfiniteFuture");
+ constexpr absl::Time t2 = absl::InfinitePast();
+ static_assert(t2 != absl::Time(), "InfinitePast");
+ constexpr absl::Time t3 = absl::FromUnixNanos(0);
+ static_assert(t3 == absl::Time(), "FromUnixNanos");
+ constexpr absl::Time t4 = absl::FromUnixMicros(0);
+ static_assert(t4 == absl::Time(), "FromUnixMicros");
+ constexpr absl::Time t5 = absl::FromUnixMillis(0);
+ static_assert(t5 == absl::Time(), "FromUnixMillis");
+ constexpr absl::Time t6 = absl::FromUnixSeconds(0);
+ static_assert(t6 == absl::Time(), "FromUnixSeconds");
+ constexpr absl::Time t7 = absl::FromTimeT(0);
+ static_assert(t7 == absl::Time(), "FromTimeT");
+}
+
+TEST(Time, ValueSemantics) {
+ absl::Time a; // Default construction
+ absl::Time b = a; // Copy construction
+ EXPECT_EQ(a, b);
+ absl::Time c(a); // Copy construction (again)
+ EXPECT_EQ(a, b);
+ EXPECT_EQ(a, c);
+ EXPECT_EQ(b, c);
+ b = c; // Assignment
+ EXPECT_EQ(a, b);
+ EXPECT_EQ(a, c);
+ EXPECT_EQ(b, c);
+}
+
+TEST(Time, UnixEpoch) {
+ absl::Time::Breakdown bd = absl::UnixEpoch().In(absl::UTCTimeZone());
+ ABSL_INTERNAL_EXPECT_TIME(bd, 1970, 1, 1, 0, 0, 0, 0, false, "UTC");
+ EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
+ EXPECT_EQ(4, bd.weekday); // Thursday
+}
+
+TEST(Time, Breakdown) {
+ absl::TimeZone tz = absl::time_internal::LoadTimeZone("America/New_York");
+ absl::Time t = absl::UnixEpoch();
+
+ // The Unix epoch as seen in NYC.
+ absl::Time::Breakdown bd = t.In(tz);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 19, 0, 0, -18000, false, "EST");
+ EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
+ EXPECT_EQ(3, bd.weekday); // Wednesday
+
+ // Just before the epoch.
+ t -= absl::Nanoseconds(1);
+ bd = t.In(tz);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 18, 59, 59, -18000, false, "EST");
+ EXPECT_EQ(absl::Nanoseconds(999999999), bd.subsecond);
+ EXPECT_EQ(3, bd.weekday); // Wednesday
+
+ // Some time later.
+ t += absl::Hours(24) * 2735;
+ t += absl::Hours(18) + absl::Minutes(30) + absl::Seconds(15) +
+ absl::Nanoseconds(9);
+ bd = t.In(tz);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 1977, 6, 28, 14, 30, 15, -14400, true, "EDT");
+ EXPECT_EQ(8, bd.subsecond / absl::Nanoseconds(1));
+ EXPECT_EQ(2, bd.weekday); // Tuesday
+}
+
+TEST(Time, AdditiveOperators) {
+ const absl::Duration d = absl::Nanoseconds(1);
+ const absl::Time t0;
+ const absl::Time t1 = t0 + d;
+
+ EXPECT_EQ(d, t1 - t0);
+ EXPECT_EQ(-d, t0 - t1);
+ EXPECT_EQ(t0, t1 - d);
+
+ absl::Time t(t0);
+ EXPECT_EQ(t0, t);
+ t += d;
+ EXPECT_EQ(t0 + d, t);
+ EXPECT_EQ(d, t - t0);
+ t -= d;
+ EXPECT_EQ(t0, t);
+
+ // Tests overflow between subseconds and seconds.
+ t = absl::UnixEpoch();
+ t += absl::Milliseconds(500);
+ EXPECT_EQ(absl::UnixEpoch() + absl::Milliseconds(500), t);
+ t += absl::Milliseconds(600);
+ EXPECT_EQ(absl::UnixEpoch() + absl::Milliseconds(1100), t);
+ t -= absl::Milliseconds(600);
+ EXPECT_EQ(absl::UnixEpoch() + absl::Milliseconds(500), t);
+ t -= absl::Milliseconds(500);
+ EXPECT_EQ(absl::UnixEpoch(), t);
+}
+
+TEST(Time, RelationalOperators) {
+ constexpr absl::Time t1 = absl::FromUnixNanos(0);
+ constexpr absl::Time t2 = absl::FromUnixNanos(1);
+ constexpr absl::Time t3 = absl::FromUnixNanos(2);
+
+ static_assert(absl::Time() == t1, "");
+ static_assert(t1 == t1, "");
+ static_assert(t2 == t2, "");
+ static_assert(t3 == t3, "");
+
+ static_assert(t1 < t2, "");
+ static_assert(t2 < t3, "");
+ static_assert(t1 < t3, "");
+
+ static_assert(t1 <= t1, "");
+ static_assert(t1 <= t2, "");
+ static_assert(t2 <= t2, "");
+ static_assert(t2 <= t3, "");
+ static_assert(t3 <= t3, "");
+ static_assert(t1 <= t3, "");
+
+ static_assert(t2 > t1, "");
+ static_assert(t3 > t2, "");
+ static_assert(t3 > t1, "");
+
+ static_assert(t2 >= t2, "");
+ static_assert(t2 >= t1, "");
+ static_assert(t3 >= t3, "");
+ static_assert(t3 >= t2, "");
+ static_assert(t1 >= t1, "");
+ static_assert(t3 >= t1, "");
+}
+
+TEST(Time, Infinity) {
+ constexpr absl::Time ifuture = absl::InfiniteFuture();
+ constexpr absl::Time ipast = absl::InfinitePast();
+
+ static_assert(ifuture == ifuture, "");
+ static_assert(ipast == ipast, "");
+ static_assert(ipast < ifuture, "");
+ static_assert(ifuture > ipast, "");
+
+ // Arithmetic saturates
+ EXPECT_EQ(ifuture, ifuture + absl::Seconds(1));
+ EXPECT_EQ(ifuture, ifuture - absl::Seconds(1));
+ EXPECT_EQ(ipast, ipast + absl::Seconds(1));
+ EXPECT_EQ(ipast, ipast - absl::Seconds(1));
+
+ EXPECT_EQ(absl::InfiniteDuration(), ifuture - ifuture);
+ EXPECT_EQ(absl::InfiniteDuration(), ifuture - ipast);
+ EXPECT_EQ(-absl::InfiniteDuration(), ipast - ifuture);
+ EXPECT_EQ(-absl::InfiniteDuration(), ipast - ipast);
+
+ constexpr absl::Time t = absl::UnixEpoch(); // Any finite time.
+ static_assert(t < ifuture, "");
+ static_assert(t > ipast, "");
+}
+
+TEST(Time, FloorConversion) {
+#define TEST_FLOOR_CONVERSION(TO, FROM) \
+ EXPECT_EQ(1, TO(FROM(1001))); \
+ EXPECT_EQ(1, TO(FROM(1000))); \
+ EXPECT_EQ(0, TO(FROM(999))); \
+ EXPECT_EQ(0, TO(FROM(1))); \
+ EXPECT_EQ(0, TO(FROM(0))); \
+ EXPECT_EQ(-1, TO(FROM(-1))); \
+ EXPECT_EQ(-1, TO(FROM(-999))); \
+ EXPECT_EQ(-1, TO(FROM(-1000))); \
+ EXPECT_EQ(-2, TO(FROM(-1001)));
+
+ TEST_FLOOR_CONVERSION(absl::ToUnixMicros, absl::FromUnixNanos);
+ TEST_FLOOR_CONVERSION(absl::ToUnixMillis, absl::FromUnixMicros);
+ TEST_FLOOR_CONVERSION(absl::ToUnixSeconds, absl::FromUnixMillis);
+ TEST_FLOOR_CONVERSION(absl::ToTimeT, absl::FromUnixMillis);
+
+#undef TEST_FLOOR_CONVERSION
+
+ // Tests ToUnixNanos.
+ EXPECT_EQ(1, absl::ToUnixNanos(absl::UnixEpoch() + absl::Nanoseconds(3) / 2));
+ EXPECT_EQ(1, absl::ToUnixNanos(absl::UnixEpoch() + absl::Nanoseconds(1)));
+ EXPECT_EQ(0, absl::ToUnixNanos(absl::UnixEpoch() + absl::Nanoseconds(1) / 2));
+ EXPECT_EQ(0, absl::ToUnixNanos(absl::UnixEpoch() + absl::Nanoseconds(0)));
+ EXPECT_EQ(-1,
+ absl::ToUnixNanos(absl::UnixEpoch() - absl::Nanoseconds(1) / 2));
+ EXPECT_EQ(-1, absl::ToUnixNanos(absl::UnixEpoch() - absl::Nanoseconds(1)));
+ EXPECT_EQ(-2,
+ absl::ToUnixNanos(absl::UnixEpoch() - absl::Nanoseconds(3) / 2));
+
+ // Tests ToUniversal, which uses a different epoch than the tests above.
+ EXPECT_EQ(1,
+ absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(101)));
+ EXPECT_EQ(1,
+ absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(100)));
+ EXPECT_EQ(0,
+ absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(99)));
+ EXPECT_EQ(0,
+ absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(1)));
+ EXPECT_EQ(0,
+ absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(0)));
+ EXPECT_EQ(-1,
+ absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(-1)));
+ EXPECT_EQ(-1,
+ absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(-99)));
+ EXPECT_EQ(
+ -1, absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(-100)));
+ EXPECT_EQ(
+ -2, absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(-101)));
+
+ // Tests ToTimespec()/TimeFromTimespec()
+ const struct {
+ absl::Time t;
+ timespec ts;
+ } to_ts[] = {
+ {absl::FromUnixSeconds(1) + absl::Nanoseconds(1), {1, 1}},
+ {absl::FromUnixSeconds(1) + absl::Nanoseconds(1) / 2, {1, 0}},
+ {absl::FromUnixSeconds(1) + absl::Nanoseconds(0), {1, 0}},
+ {absl::FromUnixSeconds(0) + absl::Nanoseconds(0), {0, 0}},
+ {absl::FromUnixSeconds(0) - absl::Nanoseconds(1) / 2, {-1, 999999999}},
+ {absl::FromUnixSeconds(0) - absl::Nanoseconds(1), {-1, 999999999}},
+ {absl::FromUnixSeconds(-1) + absl::Nanoseconds(1), {-1, 1}},
+ {absl::FromUnixSeconds(-1) + absl::Nanoseconds(1) / 2, {-1, 0}},
+ {absl::FromUnixSeconds(-1) + absl::Nanoseconds(0), {-1, 0}},
+ {absl::FromUnixSeconds(-1) - absl::Nanoseconds(1) / 2, {-2, 999999999}},
+ };
+ for (const auto& test : to_ts) {
+ EXPECT_THAT(absl::ToTimespec(test.t), TimespecMatcher(test.ts));
+ }
+ const struct {
+ timespec ts;
+ absl::Time t;
+ } from_ts[] = {
+ {{1, 1}, absl::FromUnixSeconds(1) + absl::Nanoseconds(1)},
+ {{1, 0}, absl::FromUnixSeconds(1) + absl::Nanoseconds(0)},
+ {{0, 0}, absl::FromUnixSeconds(0) + absl::Nanoseconds(0)},
+ {{0, -1}, absl::FromUnixSeconds(0) - absl::Nanoseconds(1)},
+ {{-1, 999999999}, absl::FromUnixSeconds(0) - absl::Nanoseconds(1)},
+ {{-1, 1}, absl::FromUnixSeconds(-1) + absl::Nanoseconds(1)},
+ {{-1, 0}, absl::FromUnixSeconds(-1) + absl::Nanoseconds(0)},
+ {{-1, -1}, absl::FromUnixSeconds(-1) - absl::Nanoseconds(1)},
+ {{-2, 999999999}, absl::FromUnixSeconds(-1) - absl::Nanoseconds(1)},
+ };
+ for (const auto& test : from_ts) {
+ EXPECT_EQ(test.t, absl::TimeFromTimespec(test.ts));
+ }
+
+ // Tests ToTimeval()/TimeFromTimeval() (same as timespec above)
+ const struct {
+ absl::Time t;
+ timeval tv;
+ } to_tv[] = {
+ {absl::FromUnixSeconds(1) + absl::Microseconds(1), {1, 1}},
+ {absl::FromUnixSeconds(1) + absl::Microseconds(1) / 2, {1, 0}},
+ {absl::FromUnixSeconds(1) + absl::Microseconds(0), {1, 0}},
+ {absl::FromUnixSeconds(0) + absl::Microseconds(0), {0, 0}},
+ {absl::FromUnixSeconds(0) - absl::Microseconds(1) / 2, {-1, 999999}},
+ {absl::FromUnixSeconds(0) - absl::Microseconds(1), {-1, 999999}},
+ {absl::FromUnixSeconds(-1) + absl::Microseconds(1), {-1, 1}},
+ {absl::FromUnixSeconds(-1) + absl::Microseconds(1) / 2, {-1, 0}},
+ {absl::FromUnixSeconds(-1) + absl::Microseconds(0), {-1, 0}},
+ {absl::FromUnixSeconds(-1) - absl::Microseconds(1) / 2, {-2, 999999}},
+ };
+ for (const auto& test : to_tv) {
+ EXPECT_THAT(ToTimeval(test.t), TimevalMatcher(test.tv));
+ }
+ const struct {
+ timeval tv;
+ absl::Time t;
+ } from_tv[] = {
+ {{1, 1}, absl::FromUnixSeconds(1) + absl::Microseconds(1)},
+ {{1, 0}, absl::FromUnixSeconds(1) + absl::Microseconds(0)},
+ {{0, 0}, absl::FromUnixSeconds(0) + absl::Microseconds(0)},
+ {{0, -1}, absl::FromUnixSeconds(0) - absl::Microseconds(1)},
+ {{-1, 999999}, absl::FromUnixSeconds(0) - absl::Microseconds(1)},
+ {{-1, 1}, absl::FromUnixSeconds(-1) + absl::Microseconds(1)},
+ {{-1, 0}, absl::FromUnixSeconds(-1) + absl::Microseconds(0)},
+ {{-1, -1}, absl::FromUnixSeconds(-1) - absl::Microseconds(1)},
+ {{-2, 999999}, absl::FromUnixSeconds(-1) - absl::Microseconds(1)},
+ };
+ for (const auto& test : from_tv) {
+ EXPECT_EQ(test.t, absl::TimeFromTimeval(test.tv));
+ }
+
+ // Tests flooring near negative infinity.
+ const int64_t min_plus_1 = std::numeric_limits<int64_t>::min() + 1;
+ EXPECT_EQ(min_plus_1, absl::ToUnixSeconds(absl::FromUnixSeconds(min_plus_1)));
+ EXPECT_EQ(std::numeric_limits<int64_t>::min(),
+ absl::ToUnixSeconds(
+ absl::FromUnixSeconds(min_plus_1) - absl::Nanoseconds(1) / 2));
+
+ // Tests flooring near positive infinity.
+ EXPECT_EQ(std::numeric_limits<int64_t>::max(),
+ absl::ToUnixSeconds(absl::FromUnixSeconds(
+ std::numeric_limits<int64_t>::max()) + absl::Nanoseconds(1) / 2));
+ EXPECT_EQ(std::numeric_limits<int64_t>::max(),
+ absl::ToUnixSeconds(
+ absl::FromUnixSeconds(std::numeric_limits<int64_t>::max())));
+ EXPECT_EQ(std::numeric_limits<int64_t>::max() - 1,
+ absl::ToUnixSeconds(absl::FromUnixSeconds(
+ std::numeric_limits<int64_t>::max()) - absl::Nanoseconds(1) / 2));
+}
+
+TEST(Time, RoundtripConversion) {
+#define TEST_CONVERSION_ROUND_TRIP(SOURCE, FROM, TO, MATCHER) \
+ EXPECT_THAT(TO(FROM(SOURCE)), MATCHER(SOURCE))
+
+ // FromUnixNanos() and ToUnixNanos()
+ int64_t now_ns = absl::GetCurrentTimeNanos();
+ TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUnixNanos, absl::ToUnixNanos,
+ testing::Eq);
+ TEST_CONVERSION_ROUND_TRIP(0, absl::FromUnixNanos, absl::ToUnixNanos,
+ testing::Eq);
+ TEST_CONVERSION_ROUND_TRIP(1, absl::FromUnixNanos, absl::ToUnixNanos,
+ testing::Eq);
+ TEST_CONVERSION_ROUND_TRIP(now_ns, absl::FromUnixNanos, absl::ToUnixNanos,
+ testing::Eq)
+ << now_ns;
+
+ // FromUnixMicros() and ToUnixMicros()
+ int64_t now_us = absl::GetCurrentTimeNanos() / 1000;
+ TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUnixMicros, absl::ToUnixMicros,
+ testing::Eq);
+ TEST_CONVERSION_ROUND_TRIP(0, absl::FromUnixMicros, absl::ToUnixMicros,
+ testing::Eq);
+ TEST_CONVERSION_ROUND_TRIP(1, absl::FromUnixMicros, absl::ToUnixMicros,
+ testing::Eq);
+ TEST_CONVERSION_ROUND_TRIP(now_us, absl::FromUnixMicros, absl::ToUnixMicros,
+ testing::Eq)
+ << now_us;
+
+ // FromUnixMillis() and ToUnixMillis()
+ int64_t now_ms = absl::GetCurrentTimeNanos() / 1000000;
+ TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUnixMillis, absl::ToUnixMillis,
+ testing::Eq);
+ TEST_CONVERSION_ROUND_TRIP(0, absl::FromUnixMillis, absl::ToUnixMillis,
+ testing::Eq);
+ TEST_CONVERSION_ROUND_TRIP(1, absl::FromUnixMillis, absl::ToUnixMillis,
+ testing::Eq);
+ TEST_CONVERSION_ROUND_TRIP(now_ms, absl::FromUnixMillis, absl::ToUnixMillis,
+ testing::Eq)
+ << now_ms;
+
+ // FromUnixSeconds() and ToUnixSeconds()
+ int64_t now_s = std::time(nullptr);
+ TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUnixSeconds, absl::ToUnixSeconds,
+ testing::Eq);
+ TEST_CONVERSION_ROUND_TRIP(0, absl::FromUnixSeconds, absl::ToUnixSeconds,
+ testing::Eq);
+ TEST_CONVERSION_ROUND_TRIP(1, absl::FromUnixSeconds, absl::ToUnixSeconds,
+ testing::Eq);
+ TEST_CONVERSION_ROUND_TRIP(now_s, absl::FromUnixSeconds, absl::ToUnixSeconds,
+ testing::Eq)
+ << now_s;
+
+ // FromTimeT() and ToTimeT()
+ time_t now_time_t = std::time(nullptr);
+ TEST_CONVERSION_ROUND_TRIP(-1, absl::FromTimeT, absl::ToTimeT, testing::Eq);
+ TEST_CONVERSION_ROUND_TRIP(0, absl::FromTimeT, absl::ToTimeT, testing::Eq);
+ TEST_CONVERSION_ROUND_TRIP(1, absl::FromTimeT, absl::ToTimeT, testing::Eq);
+ TEST_CONVERSION_ROUND_TRIP(now_time_t, absl::FromTimeT, absl::ToTimeT,
+ testing::Eq)
+ << now_time_t;
+
+ // TimeFromTimeval() and ToTimeval()
+ timeval tv;
+ tv.tv_sec = -1;
+ tv.tv_usec = 0;
+ TEST_CONVERSION_ROUND_TRIP(tv, absl::TimeFromTimeval, absl::ToTimeval,
+ TimevalMatcher);
+ tv.tv_sec = -1;
+ tv.tv_usec = 999999;
+ TEST_CONVERSION_ROUND_TRIP(tv, absl::TimeFromTimeval, absl::ToTimeval,
+ TimevalMatcher);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ TEST_CONVERSION_ROUND_TRIP(tv, absl::TimeFromTimeval, absl::ToTimeval,
+ TimevalMatcher);
+ tv.tv_sec = 0;
+ tv.tv_usec = 1;
+ TEST_CONVERSION_ROUND_TRIP(tv, absl::TimeFromTimeval, absl::ToTimeval,
+ TimevalMatcher);
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ TEST_CONVERSION_ROUND_TRIP(tv, absl::TimeFromTimeval, absl::ToTimeval,
+ TimevalMatcher);
+
+ // TimeFromTimespec() and ToTimespec()
+ timespec ts;
+ ts.tv_sec = -1;
+ ts.tv_nsec = 0;
+ TEST_CONVERSION_ROUND_TRIP(ts, absl::TimeFromTimespec, absl::ToTimespec,
+ TimespecMatcher);
+ ts.tv_sec = -1;
+ ts.tv_nsec = 999999999;
+ TEST_CONVERSION_ROUND_TRIP(ts, absl::TimeFromTimespec, absl::ToTimespec,
+ TimespecMatcher);
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ TEST_CONVERSION_ROUND_TRIP(ts, absl::TimeFromTimespec, absl::ToTimespec,
+ TimespecMatcher);
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1;
+ TEST_CONVERSION_ROUND_TRIP(ts, absl::TimeFromTimespec, absl::ToTimespec,
+ TimespecMatcher);
+ ts.tv_sec = 1;
+ ts.tv_nsec = 0;
+ TEST_CONVERSION_ROUND_TRIP(ts, absl::TimeFromTimespec, absl::ToTimespec,
+ TimespecMatcher);
+
+ // FromUDate() and ToUDate()
+ double now_ud = absl::GetCurrentTimeNanos() / 1000000;
+ TEST_CONVERSION_ROUND_TRIP(-1.5, absl::FromUDate, absl::ToUDate,
+ testing::DoubleEq);
+ TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUDate, absl::ToUDate,
+ testing::DoubleEq);
+ TEST_CONVERSION_ROUND_TRIP(-0.5, absl::FromUDate, absl::ToUDate,
+ testing::DoubleEq);
+ TEST_CONVERSION_ROUND_TRIP(0, absl::FromUDate, absl::ToUDate,
+ testing::DoubleEq);
+ TEST_CONVERSION_ROUND_TRIP(0.5, absl::FromUDate, absl::ToUDate,
+ testing::DoubleEq);
+ TEST_CONVERSION_ROUND_TRIP(1, absl::FromUDate, absl::ToUDate,
+ testing::DoubleEq);
+ TEST_CONVERSION_ROUND_TRIP(1.5, absl::FromUDate, absl::ToUDate,
+ testing::DoubleEq);
+ TEST_CONVERSION_ROUND_TRIP(now_ud, absl::FromUDate, absl::ToUDate,
+ testing::DoubleEq)
+ << std::fixed << std::setprecision(17) << now_ud;
+
+ // FromUniversal() and ToUniversal()
+ int64_t now_uni = ((719162LL * (24 * 60 * 60)) * (1000 * 1000 * 10)) +
+ (absl::GetCurrentTimeNanos() / 100);
+ TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUniversal, absl::ToUniversal,
+ testing::Eq);
+ TEST_CONVERSION_ROUND_TRIP(0, absl::FromUniversal, absl::ToUniversal,
+ testing::Eq);
+ TEST_CONVERSION_ROUND_TRIP(1, absl::FromUniversal, absl::ToUniversal,
+ testing::Eq);
+ TEST_CONVERSION_ROUND_TRIP(now_uni, absl::FromUniversal, absl::ToUniversal,
+ testing::Eq)
+ << now_uni;
+
+#undef TEST_CONVERSION_ROUND_TRIP
+}
+
+TEST(Time, ConvertDateTime) {
+ const absl::TimeZone utc = absl::UTCTimeZone();
+ const absl::TimeZone goog =
+ absl::time_internal::LoadTimeZone("America/Los_Angeles");
+ const absl::TimeZone nyc =
+ absl::time_internal::LoadTimeZone("America/New_York");
+ const std::string fmt = "%a, %e %b %Y %H:%M:%S %z (%Z)";
+
+ // A simple case of normalization.
+ absl::TimeConversion oct32 = ConvertDateTime(2013, 10, 32, 8, 30, 0, goog);
+ EXPECT_TRUE(oct32.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, oct32.kind);
+ absl::TimeConversion nov01 = ConvertDateTime(2013, 11, 1, 8, 30, 0, goog);
+ EXPECT_FALSE(nov01.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, nov01.kind);
+ EXPECT_EQ(oct32.pre, nov01.pre);
+ EXPECT_EQ("Fri, 1 Nov 2013 08:30:00 -0700 (PDT)",
+ absl::FormatTime(fmt, nov01.pre, goog));
+
+ // A Spring DST transition, when there is a gap in civil time
+ // and we prefer the later of the possible interpretations of a
+ // non-existent time.
+ absl::TimeConversion mar13 = ConvertDateTime(2011, 3, 13, 2, 15, 0, nyc);
+ EXPECT_FALSE(mar13.normalized);
+ EXPECT_EQ(absl::TimeConversion::SKIPPED, mar13.kind);
+ EXPECT_EQ("Sun, 13 Mar 2011 03:15:00 -0400 (EDT)",
+ absl::FormatTime(fmt, mar13.pre, nyc));
+ EXPECT_EQ("Sun, 13 Mar 2011 03:00:00 -0400 (EDT)",
+ absl::FormatTime(fmt, mar13.trans, nyc));
+ EXPECT_EQ("Sun, 13 Mar 2011 01:15:00 -0500 (EST)",
+ absl::FormatTime(fmt, mar13.post, nyc));
+ EXPECT_EQ(mar13.pre, absl::FromDateTime(2011, 3, 13, 2, 15, 0, nyc));
+
+ // A Fall DST transition, when civil times are repeated and
+ // we prefer the earlier of the possible interpretations of an
+ // ambiguous time.
+ absl::TimeConversion nov06 = ConvertDateTime(2011, 11, 6, 1, 15, 0, nyc);
+ EXPECT_FALSE(nov06.normalized);
+ EXPECT_EQ(absl::TimeConversion::REPEATED, nov06.kind);
+ EXPECT_EQ("Sun, 6 Nov 2011 01:15:00 -0400 (EDT)",
+ absl::FormatTime(fmt, nov06.pre, nyc));
+ EXPECT_EQ("Sun, 6 Nov 2011 01:00:00 -0500 (EST)",
+ absl::FormatTime(fmt, nov06.trans, nyc));
+ EXPECT_EQ("Sun, 6 Nov 2011 01:15:00 -0500 (EST)",
+ absl::FormatTime(fmt, nov06.post, nyc));
+ EXPECT_EQ(nov06.pre, absl::FromDateTime(2011, 11, 6, 1, 15, 0, nyc));
+
+ // Check that (time_t) -1 is handled correctly.
+ absl::TimeConversion minus1 = ConvertDateTime(1969, 12, 31, 18, 59, 59, nyc);
+ EXPECT_FALSE(minus1.normalized);
+ EXPECT_EQ(absl::TimeConversion::UNIQUE, minus1.kind);
+ EXPECT_EQ(-1, absl::ToTimeT(minus1.pre));
+ EXPECT_EQ("Wed, 31 Dec 1969 18:59:59 -0500 (EST)",
+ absl::FormatTime(fmt, minus1.pre, nyc));
+ EXPECT_EQ("Wed, 31 Dec 1969 23:59:59 +0000 (UTC)",
+ absl::FormatTime(fmt, minus1.pre, utc));
+}
+
+// FromDateTime(year, mon, day, hour, min, sec, UTCTimeZone()) has
+// a specialized fastpath implementation which we exercise here.
+TEST(Time, FromDateTimeUTC) {
+ const absl::TimeZone utc = absl::UTCTimeZone();
+ const std::string fmt = "%a, %e %b %Y %H:%M:%S %z (%Z)";
+ const int kMax = std::numeric_limits<int>::max();
+ const int kMin = std::numeric_limits<int>::min();
+ absl::Time t;
+
+ // 292091940881 is the last positive year to use the fastpath.
+ t = absl::FromDateTime(292091940881, kMax, kMax, kMax, kMax, kMax, utc);
+ EXPECT_EQ("Fri, 25 Nov 292277026596 12:21:07 +0000 (UTC)",
+ absl::FormatTime(fmt, t, utc));
+ t = absl::FromDateTime(292091940882, kMax, kMax, kMax, kMax, kMax, utc);
+ EXPECT_EQ("infinite-future", absl::FormatTime(fmt, t, utc)); // no overflow
+ t = absl::FromDateTime(
+ std::numeric_limits<int64_t>::max(), kMax, kMax, kMax, kMax, kMax, utc);
+ EXPECT_EQ("infinite-future", absl::FormatTime(fmt, t, utc)); // no overflow
+
+ // -292091936940 is the last negative year to use the fastpath.
+ t = absl::FromDateTime(-292091936940, kMin, kMin, kMin, kMin, kMin, utc);
+ EXPECT_EQ("Fri, 1 Nov -292277022657 10:37:52 +0000 (UTC)",
+ absl::FormatTime(fmt, t, utc));
+ t = absl::FromDateTime(-292091936941, kMin, kMin, kMin, kMin, kMin, utc);
+ EXPECT_EQ("infinite-past", absl::FormatTime(fmt, t, utc)); // no underflow
+ t = absl::FromDateTime(
+ std::numeric_limits<int64_t>::min(), kMin, kMin, kMin, kMin, kMin, utc);
+ EXPECT_EQ("infinite-past", absl::FormatTime(fmt, t, utc)); // no overflow
+
+ // Check that we're counting leap years correctly.
+ t = absl::FromDateTime(1900, 2, 28, 23, 59, 59, utc);
+ EXPECT_EQ("Wed, 28 Feb 1900 23:59:59 +0000 (UTC)",
+ absl::FormatTime(fmt, t, utc));
+ t = absl::FromDateTime(1900, 3, 1, 0, 0, 0, utc);
+ EXPECT_EQ("Thu, 1 Mar 1900 00:00:00 +0000 (UTC)",
+ absl::FormatTime(fmt, t, utc));
+ t = absl::FromDateTime(2000, 2, 29, 23, 59, 59, utc);
+ EXPECT_EQ("Tue, 29 Feb 2000 23:59:59 +0000 (UTC)",
+ absl::FormatTime(fmt, t, utc));
+ t = absl::FromDateTime(2000, 3, 1, 0, 0, 0, utc);
+ EXPECT_EQ("Wed, 1 Mar 2000 00:00:00 +0000 (UTC)",
+ absl::FormatTime(fmt, t, utc));
+
+ // Check normalization.
+ const std::string ymdhms = "%Y-%m-%d %H:%M:%S";
+ t = absl::FromDateTime(2015, 1, 1, 0, 0, 60, utc);
+ EXPECT_EQ("2015-01-01 00:01:00", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, 1, 1, 0, 60, 0, utc);
+ EXPECT_EQ("2015-01-01 01:00:00", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, 1, 1, 24, 0, 0, utc);
+ EXPECT_EQ("2015-01-02 00:00:00", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, 1, 32, 0, 0, 0, utc);
+ EXPECT_EQ("2015-02-01 00:00:00", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, 13, 1, 0, 0, 0, utc);
+ EXPECT_EQ("2016-01-01 00:00:00", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, 13, 32, 60, 60, 60, utc);
+ EXPECT_EQ("2016-02-03 13:01:00", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, 1, 1, 0, 0, -1, utc);
+ EXPECT_EQ("2014-12-31 23:59:59", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, 1, 1, 0, -1, 0, utc);
+ EXPECT_EQ("2014-12-31 23:59:00", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, 1, 1, -1, 0, 0, utc);
+ EXPECT_EQ("2014-12-31 23:00:00", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, 1, -1, 0, 0, 0, utc);
+ EXPECT_EQ("2014-12-30 00:00:00", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, -1, 1, 0, 0, 0, utc);
+ EXPECT_EQ("2014-11-01 00:00:00", absl::FormatTime(ymdhms, t, utc));
+ t = absl::FromDateTime(2015, -1, -1, -1, -1, -1, utc);
+ EXPECT_EQ("2014-10-29 22:58:59", absl::FormatTime(ymdhms, t, utc));
+}
+
+TEST(Time, ToTM) {
+ const absl::TimeZone utc = absl::UTCTimeZone();
+
+ // Compares the results of ToTM() to gmtime_r() for lots of times over the
+ // course of a few days.
+ const absl::Time start = absl::FromDateTime(2014, 1, 2, 3, 4, 5, utc);
+ const absl::Time end = absl::FromDateTime(2014, 1, 5, 3, 4, 5, utc);
+ for (absl::Time t = start; t < end; t += absl::Seconds(30)) {
+ const struct tm tm_bt = ToTM(t, utc);
+ const time_t tt = absl::ToTimeT(t);
+ struct tm tm_lc;
+#ifdef _WIN32
+ gmtime_s(&tm_lc, &tt);
+#else
+ gmtime_r(&tt, &tm_lc);
+#endif
+ EXPECT_EQ(tm_lc.tm_year, tm_bt.tm_year);
+ EXPECT_EQ(tm_lc.tm_mon, tm_bt.tm_mon);
+ EXPECT_EQ(tm_lc.tm_mday, tm_bt.tm_mday);
+ EXPECT_EQ(tm_lc.tm_hour, tm_bt.tm_hour);
+ EXPECT_EQ(tm_lc.tm_min, tm_bt.tm_min);
+ EXPECT_EQ(tm_lc.tm_sec, tm_bt.tm_sec);
+ EXPECT_EQ(tm_lc.tm_wday, tm_bt.tm_wday);
+ EXPECT_EQ(tm_lc.tm_yday, tm_bt.tm_yday);
+ EXPECT_EQ(tm_lc.tm_isdst, tm_bt.tm_isdst);
+
+ ASSERT_FALSE(HasFailure());
+ }
+
+ // Checks that the tm_isdst field is correct when in standard time.
+ const absl::TimeZone nyc =
+ absl::time_internal::LoadTimeZone("America/New_York");
+ absl::Time t = absl::FromDateTime(2014, 3, 1, 0, 0, 0, nyc);
+ struct tm tm = ToTM(t, nyc);
+ EXPECT_FALSE(tm.tm_isdst);
+
+ // Checks that the tm_isdst field is correct when in daylight time.
+ t = absl::FromDateTime(2014, 4, 1, 0, 0, 0, nyc);
+ tm = ToTM(t, nyc);
+ EXPECT_TRUE(tm.tm_isdst);
+
+ // Checks overflow.
+ tm = ToTM(absl::InfiniteFuture(), nyc);
+ EXPECT_EQ(std::numeric_limits<int>::max() - 1900, tm.tm_year);
+ EXPECT_EQ(11, tm.tm_mon);
+ EXPECT_EQ(31, tm.tm_mday);
+ EXPECT_EQ(23, tm.tm_hour);
+ EXPECT_EQ(59, tm.tm_min);
+ EXPECT_EQ(59, tm.tm_sec);
+ EXPECT_EQ(4, tm.tm_wday);
+ EXPECT_EQ(364, tm.tm_yday);
+ EXPECT_FALSE(tm.tm_isdst);
+
+ // Checks underflow.
+ tm = ToTM(absl::InfinitePast(), nyc);
+ EXPECT_EQ(std::numeric_limits<int>::min(), tm.tm_year);
+ EXPECT_EQ(0, tm.tm_mon);
+ EXPECT_EQ(1, tm.tm_mday);
+ EXPECT_EQ(0, tm.tm_hour);
+ EXPECT_EQ(0, tm.tm_min);
+ EXPECT_EQ(0, tm.tm_sec);
+ EXPECT_EQ(0, tm.tm_wday);
+ EXPECT_EQ(0, tm.tm_yday);
+ EXPECT_FALSE(tm.tm_isdst);
+}
+
+TEST(Time, FromTM) {
+ const absl::TimeZone nyc =
+ absl::time_internal::LoadTimeZone("America/New_York");
+
+ // Verifies that tm_isdst doesn't affect anything when the time is unique.
+ struct tm tm;
+ std::memset(&tm, 0, sizeof(tm));
+ tm.tm_year = 2014 - 1900;
+ tm.tm_mon = 6 - 1;
+ tm.tm_mday = 28;
+ tm.tm_hour = 1;
+ tm.tm_min = 2;
+ tm.tm_sec = 3;
+ tm.tm_isdst = -1;
+ absl::Time t = FromTM(tm, nyc);
+ EXPECT_EQ("2014-06-28T01:02:03-04:00", absl::FormatTime(t, nyc)); // DST
+ tm.tm_isdst = 0;
+ t = FromTM(tm, nyc);
+ EXPECT_EQ("2014-06-28T01:02:03-04:00", absl::FormatTime(t, nyc)); // DST
+ tm.tm_isdst = 1;
+ t = FromTM(tm, nyc);
+ EXPECT_EQ("2014-06-28T01:02:03-04:00", absl::FormatTime(t, nyc)); // DST
+
+ // Adjusts tm to refer to an ambiguous time.
+ tm.tm_year = 2014 - 1900;
+ tm.tm_mon = 11 - 1;
+ tm.tm_mday = 2;
+ tm.tm_hour = 1;
+ tm.tm_min = 30;
+ tm.tm_sec = 42;
+ tm.tm_isdst = -1;
+ t = FromTM(tm, nyc);
+ EXPECT_EQ("2014-11-02T01:30:42-04:00", absl::FormatTime(t, nyc)); // DST
+ tm.tm_isdst = 0;
+ t = FromTM(tm, nyc);
+ EXPECT_EQ("2014-11-02T01:30:42-05:00", absl::FormatTime(t, nyc)); // STD
+ tm.tm_isdst = 1;
+ t = FromTM(tm, nyc);
+ EXPECT_EQ("2014-11-02T01:30:42-04:00", absl::FormatTime(t, nyc)); // DST
+
+ // Adjusts tm to refer to a skipped time.
+ tm.tm_year = 2014 - 1900;
+ tm.tm_mon = 3 - 1;
+ tm.tm_mday = 9;
+ tm.tm_hour = 2;
+ tm.tm_min = 30;
+ tm.tm_sec = 42;
+ tm.tm_isdst = -1;
+ t = FromTM(tm, nyc);
+ EXPECT_EQ("2014-03-09T03:30:42-04:00", absl::FormatTime(t, nyc)); // DST
+ tm.tm_isdst = 0;
+ t = FromTM(tm, nyc);
+ EXPECT_EQ("2014-03-09T01:30:42-05:00", absl::FormatTime(t, nyc)); // STD
+ tm.tm_isdst = 1;
+ t = FromTM(tm, nyc);
+ EXPECT_EQ("2014-03-09T03:30:42-04:00", absl::FormatTime(t, nyc)); // DST
+}
+
+TEST(Time, TMRoundTrip) {
+ const absl::TimeZone nyc =
+ absl::time_internal::LoadTimeZone("America/New_York");
+
+ // Test round-tripping across a skipped transition
+ absl::Time start = absl::FromDateTime(2014, 3, 9, 0, 0, 0, nyc);
+ absl::Time end = absl::FromDateTime(2014, 3, 9, 4, 0, 0, nyc);
+ for (absl::Time t = start; t < end; t += absl::Minutes(1)) {
+ struct tm tm = ToTM(t, nyc);
+ absl::Time rt = FromTM(tm, nyc);
+ EXPECT_EQ(rt, t);
+ }
+
+ // Test round-tripping across an ambiguous transition
+ start = absl::FromDateTime(2014, 11, 2, 0, 0, 0, nyc);
+ end = absl::FromDateTime(2014, 11, 2, 4, 0, 0, nyc);
+ for (absl::Time t = start; t < end; t += absl::Minutes(1)) {
+ struct tm tm = ToTM(t, nyc);
+ absl::Time rt = FromTM(tm, nyc);
+ EXPECT_EQ(rt, t);
+ }
+
+ // Test round-tripping of unique instants crossing a day boundary
+ start = absl::FromDateTime(2014, 6, 27, 22, 0, 0, nyc);
+ end = absl::FromDateTime(2014, 6, 28, 4, 0, 0, nyc);
+ for (absl::Time t = start; t < end; t += absl::Minutes(1)) {
+ struct tm tm = ToTM(t, nyc);
+ absl::Time rt = FromTM(tm, nyc);
+ EXPECT_EQ(rt, t);
+ }
+}
+
+TEST(Time, Range) {
+ // The API's documented range is +/- 100 billion years.
+ const absl::Duration range = absl::Hours(24) * 365.2425 * 100000000000;
+
+ // Arithmetic and comparison still works at +/-range around base values.
+ absl::Time bases[2] = {absl::UnixEpoch(), absl::Now()};
+ for (const auto base : bases) {
+ absl::Time bottom = base - range;
+ EXPECT_GT(bottom, bottom - absl::Nanoseconds(1));
+ EXPECT_LT(bottom, bottom + absl::Nanoseconds(1));
+ absl::Time top = base + range;
+ EXPECT_GT(top, top - absl::Nanoseconds(1));
+ EXPECT_LT(top, top + absl::Nanoseconds(1));
+ absl::Duration full_range = 2 * range;
+ EXPECT_EQ(full_range, top - bottom);
+ EXPECT_EQ(-full_range, bottom - top);
+ }
+}
+
+TEST(Time, Limits) {
+ // It is an implementation detail that Time().rep_ == ZeroDuration(),
+ // and that the resolution of a Duration is 1/4 of a nanosecond.
+ const absl::Time zero;
+ const absl::Time max =
+ zero + absl::Seconds(std::numeric_limits<int64_t>::max()) +
+ absl::Nanoseconds(999999999) + absl::Nanoseconds(3) / 4;
+ const absl::Time min =
+ zero + absl::Seconds(std::numeric_limits<int64_t>::min());
+
+ // Some simple max/min bounds checks.
+ EXPECT_LT(max, absl::InfiniteFuture());
+ EXPECT_GT(min, absl::InfinitePast());
+ EXPECT_LT(zero, max);
+ EXPECT_GT(zero, min);
+ EXPECT_GE(absl::UnixEpoch(), min);
+ EXPECT_LT(absl::UnixEpoch(), max);
+
+ // Check sign of Time differences.
+ EXPECT_LT(absl::ZeroDuration(), max - zero);
+ EXPECT_LT(absl::ZeroDuration(),
+ zero - absl::Nanoseconds(1) / 4 - min); // avoid zero - min
+
+ // Arithmetic works at max - 0.25ns and min + 0.25ns.
+ EXPECT_GT(max, max - absl::Nanoseconds(1) / 4);
+ EXPECT_LT(min, min + absl::Nanoseconds(1) / 4);
+}
+
+TEST(Time, ConversionSaturation) {
+ const absl::TimeZone utc = absl::UTCTimeZone();
+ absl::Time t;
+
+ const auto max_time_t = std::numeric_limits<time_t>::max();
+ const auto min_time_t = std::numeric_limits<time_t>::min();
+ time_t tt = max_time_t - 1;
+ t = absl::FromTimeT(tt);
+ tt = absl::ToTimeT(t);
+ EXPECT_EQ(max_time_t - 1, tt);
+ t += absl::Seconds(1);
+ tt = absl::ToTimeT(t);
+ EXPECT_EQ(max_time_t, tt);
+ t += absl::Seconds(1); // no effect
+ tt = absl::ToTimeT(t);
+ EXPECT_EQ(max_time_t, tt);
+
+ tt = min_time_t + 1;
+ t = absl::FromTimeT(tt);
+ tt = absl::ToTimeT(t);
+ EXPECT_EQ(min_time_t + 1, tt);
+ t -= absl::Seconds(1);
+ tt = absl::ToTimeT(t);
+ EXPECT_EQ(min_time_t, tt);
+ t -= absl::Seconds(1); // no effect
+ tt = absl::ToTimeT(t);
+ EXPECT_EQ(min_time_t, tt);
+
+ const auto max_timeval_sec =
+ std::numeric_limits<decltype(timeval::tv_sec)>::max();
+ const auto min_timeval_sec =
+ std::numeric_limits<decltype(timeval::tv_sec)>::min();
+ timeval tv;
+ tv.tv_sec = max_timeval_sec;
+ tv.tv_usec = 999998;
+ t = absl::TimeFromTimeval(tv);
+ tv = ToTimeval(t);
+ EXPECT_EQ(max_timeval_sec, tv.tv_sec);
+ EXPECT_EQ(999998, tv.tv_usec);
+ t += absl::Microseconds(1);
+ tv = ToTimeval(t);
+ EXPECT_EQ(max_timeval_sec, tv.tv_sec);
+ EXPECT_EQ(999999, tv.tv_usec);
+ t += absl::Microseconds(1); // no effect
+ tv = ToTimeval(t);
+ EXPECT_EQ(max_timeval_sec, tv.tv_sec);
+ EXPECT_EQ(999999, tv.tv_usec);
+
+ tv.tv_sec = min_timeval_sec;
+ tv.tv_usec = 1;
+ t = absl::TimeFromTimeval(tv);
+ tv = ToTimeval(t);
+ EXPECT_EQ(min_timeval_sec, tv.tv_sec);
+ EXPECT_EQ(1, tv.tv_usec);
+ t -= absl::Microseconds(1);
+ tv = ToTimeval(t);
+ EXPECT_EQ(min_timeval_sec, tv.tv_sec);
+ EXPECT_EQ(0, tv.tv_usec);
+ t -= absl::Microseconds(1); // no effect
+ tv = ToTimeval(t);
+ EXPECT_EQ(min_timeval_sec, tv.tv_sec);
+ EXPECT_EQ(0, tv.tv_usec);
+
+ const auto max_timespec_sec =
+ std::numeric_limits<decltype(timespec::tv_sec)>::max();
+ const auto min_timespec_sec =
+ std::numeric_limits<decltype(timespec::tv_sec)>::min();
+ timespec ts;
+ ts.tv_sec = max_timespec_sec;
+ ts.tv_nsec = 999999998;
+ t = absl::TimeFromTimespec(ts);
+ ts = absl::ToTimespec(t);
+ EXPECT_EQ(max_timespec_sec, ts.tv_sec);
+ EXPECT_EQ(999999998, ts.tv_nsec);
+ t += absl::Nanoseconds(1);
+ ts = absl::ToTimespec(t);
+ EXPECT_EQ(max_timespec_sec, ts.tv_sec);
+ EXPECT_EQ(999999999, ts.tv_nsec);
+ t += absl::Nanoseconds(1); // no effect
+ ts = absl::ToTimespec(t);
+ EXPECT_EQ(max_timespec_sec, ts.tv_sec);
+ EXPECT_EQ(999999999, ts.tv_nsec);
+
+ ts.tv_sec = min_timespec_sec;
+ ts.tv_nsec = 1;
+ t = absl::TimeFromTimespec(ts);
+ ts = absl::ToTimespec(t);
+ EXPECT_EQ(min_timespec_sec, ts.tv_sec);
+ EXPECT_EQ(1, ts.tv_nsec);
+ t -= absl::Nanoseconds(1);
+ ts = absl::ToTimespec(t);
+ EXPECT_EQ(min_timespec_sec, ts.tv_sec);
+ EXPECT_EQ(0, ts.tv_nsec);
+ t -= absl::Nanoseconds(1); // no effect
+ ts = absl::ToTimespec(t);
+ EXPECT_EQ(min_timespec_sec, ts.tv_sec);
+ EXPECT_EQ(0, ts.tv_nsec);
+
+ // Checks how Time::In() saturates on infinities.
+ absl::Time::Breakdown bd = absl::InfiniteFuture().In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, std::numeric_limits<int64_t>::max(), 12, 31, 23,
+ 59, 59, 0, false, "-0000");
+ EXPECT_EQ(absl::InfiniteDuration(), bd.subsecond);
+ EXPECT_EQ(4, bd.weekday); // Thursday
+ EXPECT_EQ(365, bd.yearday);
+ bd = absl::InfinitePast().In(utc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, std::numeric_limits<int64_t>::min(), 1, 1, 0, 0,
+ 0, 0, false, "-0000");
+ EXPECT_EQ(-absl::InfiniteDuration(), bd.subsecond);
+ EXPECT_EQ(7, bd.weekday); // Sunday
+ EXPECT_EQ(1, bd.yearday);
+
+ // Approach the maximal Time value from below.
+ t = absl::FromDateTime(292277026596, 12, 4, 15, 30, 6, utc);
+ EXPECT_EQ("292277026596-12-04T15:30:06+00:00",
+ absl::FormatTime(absl::RFC3339_full, t, utc));
+ t = absl::FromDateTime(292277026596, 12, 4, 15, 30, 7, utc);
+ EXPECT_EQ("292277026596-12-04T15:30:07+00:00",
+ absl::FormatTime(absl::RFC3339_full, t, utc));
+ EXPECT_EQ(
+ absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()), t);
+
+ // Checks that we can also get the maximal Time value for a far-east zone.
+ const absl::TimeZone plus14 = absl::FixedTimeZone(14 * 60 * 60);
+ t = absl::FromDateTime(292277026596, 12, 5, 5, 30, 7, plus14);
+ EXPECT_EQ("292277026596-12-05T05:30:07+14:00",
+ absl::FormatTime(absl::RFC3339_full, t, plus14));
+ EXPECT_EQ(
+ absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()), t);
+
+ // One second later should push us to infinity.
+ t = absl::FromDateTime(292277026596, 12, 4, 15, 30, 8, utc);
+ EXPECT_EQ("infinite-future", absl::FormatTime(absl::RFC3339_full, t, utc));
+
+ // Approach the minimal Time value from above.
+ t = absl::FromDateTime(-292277022657, 1, 27, 8, 29, 53, utc);
+ EXPECT_EQ("-292277022657-01-27T08:29:53+00:00",
+ absl::FormatTime(absl::RFC3339_full, t, utc));
+ t = absl::FromDateTime(-292277022657, 1, 27, 8, 29, 52, utc);
+ EXPECT_EQ("-292277022657-01-27T08:29:52+00:00",
+ absl::FormatTime(absl::RFC3339_full, t, utc));
+ EXPECT_EQ(
+ absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()), t);
+
+ // Checks that we can also get the minimal Time value for a far-west zone.
+ const absl::TimeZone minus12 = absl::FixedTimeZone(-12 * 60 * 60);
+ t = absl::FromDateTime(-292277022657, 1, 26, 20, 29, 52, minus12);
+ EXPECT_EQ("-292277022657-01-26T20:29:52-12:00",
+ absl::FormatTime(absl::RFC3339_full, t, minus12));
+ EXPECT_EQ(
+ absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()), t);
+
+ // One second before should push us to -infinity.
+ t = absl::FromDateTime(-292277022657, 1, 27, 8, 29, 51, utc);
+ EXPECT_EQ("infinite-past", absl::FormatTime(absl::RFC3339_full, t, utc));
+}
+
+// In zones with POSIX-style recurring rules we use special logic to
+// handle conversions in the distant future. Here we check the limits
+// of those conversions, particularly with respect to integer overflow.
+TEST(Time, ExtendedConversionSaturation) {
+ const absl::TimeZone syd =
+ absl::time_internal::LoadTimeZone("Australia/Sydney");
+ const absl::TimeZone nyc =
+ absl::time_internal::LoadTimeZone("America/New_York");
+ const absl::Time max =
+ absl::FromUnixSeconds(std::numeric_limits<int64_t>::max());
+ absl::Time::Breakdown bd;
+ absl::Time t;
+
+ // The maximal time converted in each zone.
+ bd = max.In(syd);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 5, 2, 30, 7, 39600, true,
+ "AEDT");
+ t = absl::FromDateTime(292277026596, 12, 5, 2, 30, 7, syd);
+ EXPECT_EQ(max, t);
+ bd = max.In(nyc);
+ ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 4, 10, 30, 7, -18000, false,
+ "EST");
+ t = absl::FromDateTime(292277026596, 12, 4, 10, 30, 7, nyc);
+ EXPECT_EQ(max, t);
+
+ // One second later should push us to infinity.
+ t = absl::FromDateTime(292277026596, 12, 5, 2, 30, 8, syd);
+ EXPECT_EQ(absl::InfiniteFuture(), t);
+ t = absl::FromDateTime(292277026596, 12, 4, 10, 30, 8, nyc);
+ EXPECT_EQ(absl::InfiniteFuture(), t);
+
+ // And we should stick there.
+ t = absl::FromDateTime(292277026596, 12, 5, 2, 30, 9, syd);
+ EXPECT_EQ(absl::InfiniteFuture(), t);
+ t = absl::FromDateTime(292277026596, 12, 4, 10, 30, 9, nyc);
+ EXPECT_EQ(absl::InfiniteFuture(), t);
+
+ // All the way up to a saturated date/time, without overflow.
+ t = absl::FromDateTime(
+ std::numeric_limits<int64_t>::max(), 12, 31, 23, 59, 59, syd);
+ EXPECT_EQ(absl::InfiniteFuture(), t);
+ t = absl::FromDateTime(
+ std::numeric_limits<int64_t>::max(), 12, 31, 23, 59, 59, nyc);
+ EXPECT_EQ(absl::InfiniteFuture(), t);
+}
+
+} // namespace
diff --git a/absl/time/time_zone_test.cc b/absl/time/time_zone_test.cc
new file mode 100644
index 0000000..2991568
--- /dev/null
+++ b/absl/time/time_zone_test.cc
@@ -0,0 +1,95 @@
+// 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 "cctz/time_zone.h"
+
+#include "gtest/gtest.h"
+#include "absl/time/internal/test_util.h"
+#include "absl/time/time.h"
+
+namespace {
+
+TEST(TimeZone, ValueSemantics) {
+ absl::TimeZone tz;
+ absl::TimeZone tz2 = tz; // Copy-construct
+ EXPECT_EQ(tz, tz2);
+ tz2 = tz; // Copy-assign
+ EXPECT_EQ(tz, tz2);
+}
+
+TEST(TimeZone, Equality) {
+ absl::TimeZone a, b;
+ EXPECT_EQ(a, b);
+ EXPECT_EQ(a.name(), b.name());
+
+ absl::TimeZone implicit_utc;
+ absl::TimeZone explicit_utc = absl::UTCTimeZone();
+ EXPECT_EQ(implicit_utc, explicit_utc);
+ EXPECT_EQ(implicit_utc.name(), explicit_utc.name());
+
+ absl::TimeZone la = absl::time_internal::LoadTimeZone("America/Los_Angeles");
+ absl::TimeZone nyc = absl::time_internal::LoadTimeZone("America/New_York");
+ EXPECT_NE(la, nyc);
+}
+
+TEST(TimeZone, CCTZConversion) {
+ const cctz::time_zone cz = cctz::utc_time_zone();
+ const absl::TimeZone tz(cz);
+ EXPECT_EQ(cz, cctz::time_zone(tz));
+}
+
+TEST(TimeZone, DefaultTimeZones) {
+ absl::TimeZone tz;
+ EXPECT_EQ("UTC", absl::TimeZone().name());
+ EXPECT_EQ("UTC", absl::UTCTimeZone().name());
+}
+
+TEST(TimeZone, FixedTimeZone) {
+ const absl::TimeZone tz = absl::FixedTimeZone(123);
+ const cctz::time_zone cz = cctz::fixed_time_zone(cctz::sys_seconds(123));
+ EXPECT_EQ(tz, absl::TimeZone(cz));
+}
+
+TEST(TimeZone, LocalTimeZone) {
+ const absl::TimeZone local_tz = absl::LocalTimeZone();
+ absl::TimeZone tz = absl::time_internal::LoadTimeZone("localtime");
+ EXPECT_EQ(tz, local_tz);
+}
+
+TEST(TimeZone, NamedTimeZones) {
+ absl::TimeZone nyc = absl::time_internal::LoadTimeZone("America/New_York");
+ EXPECT_EQ("America/New_York", nyc.name());
+ absl::TimeZone syd = absl::time_internal::LoadTimeZone("Australia/Sydney");
+ EXPECT_EQ("Australia/Sydney", syd.name());
+ absl::TimeZone fixed = absl::FixedTimeZone((((3 * 60) + 25) * 60) + 45);
+ EXPECT_EQ("Fixed/UTC+03:25:45", fixed.name());
+}
+
+TEST(TimeZone, Failures) {
+ absl::TimeZone tz = absl::time_internal::LoadTimeZone("America/Los_Angeles");
+ EXPECT_FALSE(LoadTimeZone("Invalid/TimeZone", &tz));
+ EXPECT_EQ(absl::UTCTimeZone(), tz); // guaranteed fallback to UTC
+
+ // Ensures that the load still fails on a subsequent attempt.
+ tz = absl::time_internal::LoadTimeZone("America/Los_Angeles");
+ EXPECT_FALSE(LoadTimeZone("Invalid/TimeZone", &tz));
+ EXPECT_EQ(absl::UTCTimeZone(), tz); // guaranteed fallback to UTC
+
+ // Loading an empty std::string timezone should fail.
+ tz = absl::time_internal::LoadTimeZone("America/Los_Angeles");
+ EXPECT_FALSE(LoadTimeZone("", &tz));
+ EXPECT_EQ(absl::UTCTimeZone(), tz); // guaranteed fallback to UTC
+}
+
+} // namespace
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel
new file mode 100644
index 0000000..8d09440
--- /dev/null
+++ b/absl/types/BUILD.bazel
@@ -0,0 +1,178 @@
+#
+# 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",
+)
+load(
+ "//absl:test_dependencies.bzl",
+ "GUNIT_MAIN_DEPS_SELECTOR",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"]) # Apache 2.0
+
+cc_library(
+ name = "any",
+ hdrs = ["any.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ ":bad_any_cast",
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ "//absl/meta:type_traits",
+ "//absl/utility",
+ ],
+)
+
+cc_library(
+ name = "bad_any_cast",
+ srcs = ["bad_any_cast.cc"],
+ hdrs = ["bad_any_cast.h"],
+ copts = ABSL_EXCEPTIONS_FLAG + ABSL_DEFAULT_COPTS,
+ features = [
+ "-use_header_modules", # b/33207452
+ ],
+ deps = [
+ "//absl/base",
+ "//absl/base:config",
+ ],
+)
+
+cc_test(
+ name = "any_test",
+ size = "small",
+ srcs = [
+ "any_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+ deps = [
+ ":any",
+ "//absl/base",
+ "//absl/base:config",
+ "//absl/base:exception_testing",
+ "//absl/container:test_instance_tracker",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "any_test_noexceptions",
+ size = "small",
+ srcs = [
+ "any_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":any",
+ "//absl/base",
+ "//absl/base:config",
+ "//absl/base:exception_testing",
+ "//absl/container:test_instance_tracker",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_library(
+ name = "span",
+ hdrs = ["span.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ "//absl/algorithm",
+ "//absl/base:core_headers",
+ "//absl/base:throw_delegate",
+ "//absl/meta:type_traits",
+ "//absl/strings",
+ ],
+)
+
+cc_test(
+ name = "span_test",
+ size = "small",
+ srcs = ["span_test.cc"],
+ copts = ABSL_TEST_COPTS + ["-fexceptions"],
+ deps = [
+ ":span",
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ "//absl/base:exception_testing",
+ "//absl/container:fixed_array",
+ "//absl/container:inlined_vector",
+ "//absl/strings",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_test(
+ name = "span_test_noexceptions",
+ size = "small",
+ srcs = ["span_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":span",
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ "//absl/base:exception_testing",
+ "//absl/container:fixed_array",
+ "//absl/container:inlined_vector",
+ "//absl/strings",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
+
+cc_library(
+ name = "optional",
+ srcs = ["optional.cc"],
+ hdrs = ["optional.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ ":bad_optional_access",
+ "//absl/base:config",
+ "//absl/memory",
+ "//absl/meta:type_traits",
+ "//absl/utility",
+ ],
+)
+
+cc_library(
+ name = "bad_optional_access",
+ srcs = ["bad_optional_access.cc"],
+ hdrs = ["bad_optional_access.h"],
+ copts = ABSL_DEFAULT_COPTS + ABSL_EXCEPTIONS_FLAG,
+ features = [
+ "-use_header_modules", # b/33207452
+ ],
+ deps = [
+ "//absl/base",
+ "//absl/base:config",
+ ],
+)
+
+cc_test(
+ name = "optional_test",
+ size = "small",
+ srcs = [
+ "optional_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+ deps = [
+ ":optional",
+ "//absl/base",
+ "//absl/base:config",
+ "//absl/meta:type_traits",
+ "//absl/strings",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
diff --git a/absl/types/any.h b/absl/types/any.h
new file mode 100644
index 0000000..a51dea1
--- /dev/null
+++ b/absl/types/any.h
@@ -0,0 +1,539 @@
+//
+// 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.
+//
+// -----------------------------------------------------------------------------
+// any.h
+// -----------------------------------------------------------------------------
+//
+// This header file define the `absl::any` type for holding a type-safe value
+// of any type. The 'absl::any` type is useful for providing a way to hold
+// something that is, as yet, unspecified. Such unspecified types
+// traditionally are passed between API boundaries until they are later cast to
+// their "destination" types. To cast to such a destination type, use
+// `absl::any_cast()`. Note that when casting an `absl::any`, you must cast it
+// to an explicit type; implicit conversions will throw.
+//
+// Example:
+//
+// auto a = absl::any(65);
+// absl::any_cast<int>(a); // 65
+// absl::any_cast<char>(a); // throws absl::bad_any_cast
+// absl::any_cast<std::string>(a); // throws absl::bad_any_cast
+//
+// `absl::any` is a C++11 compatible version of the C++17 `std::any` abstraction
+// and is designed to be a drop-in replacement for code compliant with C++17.
+//
+// Traditionally, the behavior of casting to a temporary unspecified type has
+// been accomplished with the `void *` paradigm, where the pointer was to some
+// other unspecified type. `absl::any` provides an "owning" version of `void *`
+// that avoids issues of pointer management.
+//
+// Note: just as in the case of `void *`, use of `absl::any` (and its C++17
+// version `std::any`) is a code smell indicating that your API might not be
+// constructed correctly. We have seen that most uses of `any` are unwarranted,
+// and `absl::any`, like `std::any`, is difficult to use properly. Before using
+// this abstraction, make sure that you should not instead be rewriting your
+// code to be more specific.
+//
+// Abseil expects to release an `absl::variant` type shortly (a C++11 compatible
+// version of the C++17 `std::variant), which is generally preferred for use
+// over `absl::any`.
+#ifndef ABSL_TYPES_ANY_H_
+#define ABSL_TYPES_ANY_H_
+
+#include "absl/base/config.h"
+#include "absl/utility/utility.h"
+
+#ifdef ABSL_HAVE_STD_ANY
+
+#include <any>
+
+namespace absl {
+using std::any;
+using std::any_cast;
+using std::bad_any_cast;
+using std::make_any;
+} // namespace absl
+
+#else // ABSL_HAVE_STD_ANY
+
+#include <algorithm>
+#include <cstddef>
+#include <initializer_list>
+#include <memory>
+#include <stdexcept>
+#include <type_traits>
+#include <typeinfo>
+#include <utility>
+
+#include "absl/base/macros.h"
+#include "absl/meta/type_traits.h"
+#include "absl/types/bad_any_cast.h"
+
+// NOTE: This macro is an implementation detail that is undefined at the bottom
+// of the file. It is not intended for expansion directly from user code.
+#ifdef ABSL_ANY_DETAIL_HAS_RTTI
+#error ABSL_ANY_DETAIL_HAS_RTTI cannot be directly set
+#elif !defined(__GNUC__) || defined(__GXX_RTTI)
+#define ABSL_ANY_DETAIL_HAS_RTTI 1
+#endif // !defined(__GNUC__) || defined(__GXX_RTTI)
+
+namespace absl {
+
+namespace any_internal {
+
+// FastTypeId<Type>() evaluates at compile/link-time to a unique integer for the
+// passed in type. Their values are neither contiguous nor small, making them
+// unfit for using as an index into a vector, but a good match for keys into
+// maps or straight up comparisons.
+// Note that on 64-bit (unix) systems size_t is 64-bit while int is 32-bit and
+// the compiler will happily and quietly assign such a 64-bit value to a
+// 32-bit integer. While a client should never do that it SHOULD still be safe,
+// assuming the BSS segment doesn't span more than 4GiB.
+template<typename Type>
+inline size_t FastTypeId() {
+ static_assert(sizeof(char*) <= sizeof(size_t),
+ "ptr size too large for size_t");
+
+ // This static variable isn't actually used, only its address, so there are
+ // no concurrency issues.
+ static char dummy_var;
+ return reinterpret_cast<size_t>(&dummy_var);
+}
+
+} // namespace any_internal
+
+class any;
+
+// swap()
+//
+// Swaps two `absl::any` values. Equivalent to `x.swap(y) where `x` and `y` are
+// `absl::any` types.
+void swap(any& x, any& y) noexcept;
+
+// make_any()
+//
+// Constructs an `absl::any` of type `T` with the given arguments.
+template <typename T, typename... Args>
+any make_any(Args&&... args);
+
+// Overload of `absl::make_any()` for constructing an `absl::any` type from an
+// initializer list.
+template <typename T, typename U, typename... Args>
+any make_any(std::initializer_list<U> il, Args&&... args);
+
+// any_cast()
+//
+// Statically casts the value of a `const absl::any` type to the given type.
+// This function will throw `absl::bad_any_cast` if the stored value type of the
+// `absl::any` does not match the cast.
+//
+// `any_cast()` can also be used to get a reference to the internal storage iff
+// a reference type is passed as its `ValueType`:
+//
+// Example:
+//
+// absl::any my_any = std::vector<int>();
+// absl::any_cast<std::vector<int>&>(my_any).push_back(42);
+template <typename ValueType>
+ValueType any_cast(const any& operand);
+
+// Overload of `any_cast()` to statically cast the value of a non-const
+// `absl::any` type to the given type. This function will throw
+// `absl::bad_any_cast` if the stored value type of the `absl::any` does not
+// match the cast.
+template <typename ValueType>
+ValueType any_cast(any& operand); // NOLINT(runtime/references)
+
+// Overload of `any_cast()` to statically cast the rvalue of an `absl::any`
+// type. This function will throw `absl::bad_any_cast` if the stored value type
+// of the `absl::any` does not match the cast.
+template <typename ValueType>
+ValueType any_cast(any&& operand);
+
+// Overload of `any_cast()` to statically cast the value of a const pointer
+// `absl::any` type to the given pointer type, or `nullptr` if the stored value
+// type of the `absl::any` does not match the cast.
+template <typename ValueType>
+const ValueType* any_cast(const any* operand) noexcept;
+
+// Overload of `any_cast()` to statically cast the value of a pointer
+// `absl::any` type to the given pointer type, or `nullptr` if the stored value
+// type of the `absl::any` does not match the cast.
+template <typename ValueType>
+ValueType* any_cast(any* operand) noexcept;
+
+// any
+//
+// An `absl::any` object provides the facility to either store an instance of a
+// type, known as the "contained object", or no value. An `absl::any` is used to
+// store values of types that are unknown at compile time. The `absl::any`
+// object, when containing a value, must contain a value type; storing a
+// reference type is neither desired nor supported.
+//
+// An `absl::any` can only store a type that is copy-constructable; move-only
+// types are not allowed within an `any` object.
+//
+// Example:
+//
+// auto a = absl::any(65); // Literal, copyable
+// auto b = absl::any(std::vector<int>()); // Default-initialized, copyable
+// std::unique_ptr<Foo> my_foo;
+// auto c = absl::any(std::move(my_foo)); // Error, not copy-constructable
+//
+// Note that `absl::any` makes use of decayed types (`absl::decay_t` in this
+// context) to remove const-volative qualifiers (known as "cv qualifiers"),
+// decay functions to function pointers, etc. We essentially "decay" a given
+// type into its essential type.
+//
+// `absl::any` makes use of decayed types when determing the basic type `T` of
+// the value to store in the any's contained object. In the documentation below,
+// we explcitly denote this by using the phrase "a decayed type of `T`".
+//
+// Example:
+//
+// const int a = 4;
+// absl::any foo(a); // Decay ensures we store an "int", not a "const int&".
+//
+// void my_function() {}
+// absl::any bar(my_function); // Decay ensures we store a function pointer.
+//
+// `absl::any` is a C++11 compatible version of the C++17 `std::any` abstraction
+// and is designed to be a drop-in replacement for code compliant with C++17.
+class any {
+ private:
+ template <typename T>
+ struct IsInPlaceType;
+
+ public:
+ // Constructors
+
+ // Constructs an empty `absl::any` object (`any::has_value()` will return
+ // `false`).
+ constexpr any() noexcept;
+
+ // Copy constructs an `absl::any` object with a "contained object" of the
+ // passed type of `other` (or an empty `absl::any` if `other.has_value()` is
+ // `false`.
+ any(const any& other)
+ : obj_(other.has_value() ? other.obj_->Clone()
+ : std::unique_ptr<ObjInterface>()) {}
+
+ // Move constructs an `absl::any` object with a "contained object" of the
+ // passed type of `other` (or an empty `absl::any` if `other.has_value()` is
+ // `false`).
+ any(any&& other) noexcept = default;
+
+ // Constructs an `absl::any` object with a "contained object" of the decayed
+ // type of `T`, which is initialized via `std::forward<T>(value)`.
+ //
+ // This constructor will not participate in overload resolution if the
+ // decayed type of `T` is not copy-constructible.
+ template <
+ typename T, typename VT = absl::decay_t<T>,
+ absl::enable_if_t<!absl::disjunction<
+ std::is_same<any, VT>, IsInPlaceType<VT>,
+ absl::negation<std::is_copy_constructible<VT> > >::value>* = nullptr>
+ any(T&& value) : obj_(new Obj<VT>(in_place, std::forward<T>(value))) {}
+
+ // Constructs an `absl::any` object with a "contained object" of the decayed
+ // type of `T`, which is initialized via `std::forward<T>(value)`.
+ template <typename T, typename... Args, typename VT = absl::decay_t<T>,
+ absl::enable_if_t<absl::conjunction<
+ std::is_copy_constructible<VT>,
+ std::is_constructible<VT, Args...>>::value>* = nullptr>
+ explicit any(in_place_type_t<T> /*tag*/, Args&&... args)
+ : obj_(new Obj<VT>(in_place, std::forward<Args>(args)...)) {}
+
+ // Constructs an `absl::any` object with a "contained object" of the passed
+ // type `VT` as a decayed type of `T`. `VT` is initialized as if
+ // direct-non-list-initializing an object of type `VT` with the arguments
+ // `initializer_list, std::forward<Args>(args)...`.
+ template <
+ typename T, typename U, typename... Args, typename VT = absl::decay_t<T>,
+ absl::enable_if_t<
+ absl::conjunction<std::is_copy_constructible<VT>,
+ std::is_constructible<VT, std::initializer_list<U>&,
+ Args...>>::value>* = nullptr>
+ explicit any(in_place_type_t<T> /*tag*/, std::initializer_list<U> ilist,
+ Args&&... args)
+ : obj_(new Obj<VT>(in_place, ilist, std::forward<Args>(args)...)) {}
+
+ // Assignment operators
+
+ // Copy assigns an `absl::any` object with a "contained object" of the
+ // passed type.
+ any& operator=(const any& rhs) {
+ any(rhs).swap(*this);
+ return *this;
+ }
+
+ // Move assigns an `absl::any` object with a "contained object" of the
+ // passed type. `rhs` is left in a valid but otherwise unspecified state.
+ any& operator=(any&& rhs) noexcept {
+ any(std::move(rhs)).swap(*this);
+ return *this;
+ }
+
+ // Assigns an `absl::any` object with a "contained object" of the passed type.
+ template <typename T, typename VT = absl::decay_t<T>,
+ absl::enable_if_t<absl::conjunction<
+ absl::negation<std::is_same<VT, any>>,
+ std::is_copy_constructible<VT>>::value>* = nullptr>
+ any& operator=(T&& rhs) {
+ any tmp(in_place_type_t<VT>(), std::forward<T>(rhs));
+ tmp.swap(*this);
+ return *this;
+ }
+
+ // Modifiers
+
+ // any::emplace()
+ //
+ // Emplaces a value within an `absl::any` object by calling `any::reset()`,
+ // initializing the contained value as if direct-non-list-initializing an
+ // object of type `VT` with the arguments `std::forward<Args>(args)...`, and
+ // returning a reference to the new contained value.
+ //
+ // Note: If an exception is thrown during the call to `VT`’s constructor,
+ // `*this` does not contain a value, and any previously contained value has
+ // been destroyed.
+ template <
+ typename T, typename... Args, typename VT = absl::decay_t<T>,
+ absl::enable_if_t<std::is_copy_constructible<VT>::value &&
+ std::is_constructible<VT, Args...>::value>* = nullptr>
+ VT& emplace(Args&&... args) {
+ reset(); // NOTE: reset() is required here even in the world of exceptions.
+ Obj<VT>* const object_ptr =
+ new Obj<VT>(in_place, std::forward<Args>(args)...);
+ obj_ = std::unique_ptr<ObjInterface>(object_ptr);
+ return object_ptr->value;
+ }
+
+ // Overload of `any::emplace()` to emplace a value within an `absl::any`
+ // object by calling `any::reset()`, initializing the contained value as if
+ // direct-non-list-initializing an object of type `VT` with the arguments
+ // `initilizer_list, std::forward<Args>(args)...`, and returning a reference
+ // to the new contained value.
+ //
+ // Note: If an exception is thrown during the call to `VT`’s constructor,
+ // `*this` does not contain a value, and any previously contained value has
+ // been destroyed. The function shall not participate in overload resolution
+ // unless `is_copy_constructible_v<VT>` is `true` and
+ // `is_constructible_v<VT, initializer_list<U>&, Args...>` is `true`.
+ template <
+ typename T, typename U, typename... Args, typename VT = absl::decay_t<T>,
+ absl::enable_if_t<std::is_copy_constructible<VT>::value &&
+ std::is_constructible<VT, std::initializer_list<U>&,
+ Args...>::value>* = nullptr>
+ VT& emplace(std::initializer_list<U> ilist, Args&&... args) {
+ reset(); // NOTE: reset() is required here even in the world of exceptions.
+ Obj<VT>* const object_ptr =
+ new Obj<VT>(in_place, ilist, std::forward<Args>(args)...);
+ obj_ = std::unique_ptr<ObjInterface>(object_ptr);
+ return object_ptr->value;
+ }
+
+ // any::reset()
+ //
+ // Resets the state of the `absl::any` object, destroying the contained object
+ // if present.
+ void reset() noexcept { obj_ = nullptr; }
+
+ // any::swap()
+ //
+ // Swaps the passed value and the value of this `absl::any` object.
+ void swap(any& other) noexcept { obj_.swap(other.obj_); }
+
+ // Observors
+
+ // any::has_value()
+ //
+ // Returns `true` if the `any` object has a contained value, otherwise
+ // returns `false`.
+ bool has_value() const noexcept { return obj_ != nullptr; }
+
+#if ABSL_ANY_DETAIL_HAS_RTTI
+ // Returns: typeid(T) if *this has a contained object of type T, otherwise
+ // typeid(void).
+ const std::type_info& type() const noexcept {
+ if (has_value()) {
+ return obj_->Type();
+ }
+
+ return typeid(void);
+ }
+#endif // ABSL_ANY_DETAIL_HAS_RTTI
+ private:
+ // Tagged type-erased abstraction for holding a cloneable object.
+ class ObjInterface {
+ public:
+ virtual ~ObjInterface() = default;
+ virtual std::unique_ptr<ObjInterface> Clone() const = 0;
+ virtual size_t type_id() const noexcept = 0;
+#if ABSL_ANY_DETAIL_HAS_RTTI
+ virtual const std::type_info& Type() const noexcept = 0;
+#endif // ABSL_ANY_DETAIL_HAS_RTTI
+ };
+
+ // Hold a value of some queryable type, with an ability to Clone it.
+ template <typename T>
+ class Obj : public ObjInterface {
+ public:
+ template <typename... Args>
+ explicit Obj(in_place_t /*tag*/, Args&&... args)
+ : value(std::forward<Args>(args)...) {}
+
+ std::unique_ptr<ObjInterface> Clone() const final {
+ return std::unique_ptr<ObjInterface>(new Obj(in_place, value));
+ }
+
+ size_t type_id() const noexcept final { return IdForType<T>(); }
+
+#if ABSL_ANY_DETAIL_HAS_RTTI
+ const std::type_info& Type() const noexcept final { return typeid(T); }
+#endif // ABSL_ANY_DETAIL_HAS_RTTI
+
+ T value;
+ };
+
+ std::unique_ptr<ObjInterface> CloneObj() const {
+ if (!obj_) return nullptr;
+ return obj_->Clone();
+ }
+
+ template <typename T>
+ static size_t IdForType() {
+ // Note: This type dance is to make the behavior consistent with typeid.
+ using NormalizedType =
+ typename std::remove_cv<typename std::remove_reference<T>::type>::type;
+
+ return any_internal::FastTypeId<NormalizedType>();
+ }
+
+ size_t GetObjTypeId() const {
+ return obj_ == nullptr ? any_internal::FastTypeId<void>() : obj_->type_id();
+ }
+
+ // `absl::any` nonmember functions //
+
+ // Description at the declaration site (top of file).
+ template <typename ValueType>
+ friend ValueType any_cast(const any& operand);
+
+ // Description at the declaration site (top of file).
+ template <typename ValueType>
+ friend ValueType any_cast(any& operand); // NOLINT(runtime/references)
+
+ // Description at the declaration site (top of file).
+ template <typename T>
+ friend const T* any_cast(const any* operand) noexcept;
+
+ // Description at the declaration site (top of file).
+ template <typename T>
+ friend T* any_cast(any* operand) noexcept;
+
+ std::unique_ptr<ObjInterface> obj_;
+};
+
+// -----------------------------------------------------------------------------
+// Implementation Details
+// -----------------------------------------------------------------------------
+
+constexpr any::any() noexcept = default;
+
+template <typename T>
+struct any::IsInPlaceType : std::false_type {};
+
+template <typename T>
+struct any::IsInPlaceType<in_place_type_t<T>> : std::true_type {};
+
+inline void swap(any& x, any& y) noexcept { x.swap(y); }
+
+// Description at the declaration site (top of file).
+template <typename T, typename... Args>
+any make_any(Args&&... args) {
+ return any(in_place_type_t<T>(), std::forward<Args>(args)...);
+}
+
+// Description at the declaration site (top of file).
+template <typename T, typename U, typename... Args>
+any make_any(std::initializer_list<U> il, Args&&... args) {
+ return any(in_place_type_t<T>(), il, std::forward<Args>(args)...);
+}
+
+// Description at the declaration site (top of file).
+template <typename ValueType>
+ValueType any_cast(const any& operand) {
+ using U = typename std::remove_cv<
+ typename std::remove_reference<ValueType>::type>::type;
+ static_assert(std::is_constructible<ValueType, const U&>::value,
+ "Invalid ValueType");
+ auto* const result = (any_cast<U>)(&operand);
+ if (result == nullptr) {
+ any_internal::ThrowBadAnyCast();
+ }
+ return static_cast<ValueType>(*result);
+}
+
+// Description at the declaration site (top of file).
+template <typename ValueType>
+ValueType any_cast(any& operand) { // NOLINT(runtime/references)
+ using U = typename std::remove_cv<
+ typename std::remove_reference<ValueType>::type>::type;
+ static_assert(std::is_constructible<ValueType, U&>::value,
+ "Invalid ValueType");
+ auto* result = (any_cast<U>)(&operand);
+ if (result == nullptr) {
+ any_internal::ThrowBadAnyCast();
+ }
+ return static_cast<ValueType>(*result);
+}
+
+// Description at the declaration site (top of file).
+template <typename ValueType>
+ValueType any_cast(any&& operand) {
+ using U = typename std::remove_cv<
+ typename std::remove_reference<ValueType>::type>::type;
+ static_assert(std::is_constructible<ValueType, U>::value,
+ "Invalid ValueType");
+ return static_cast<ValueType>(std::move((any_cast<U&>)(operand)));
+}
+
+// Description at the declaration site (top of file).
+template <typename T>
+const T* any_cast(const any* operand) noexcept {
+ return operand && operand->GetObjTypeId() == any::IdForType<T>()
+ ? std::addressof(
+ static_cast<const any::Obj<T>*>(operand->obj_.get())->value)
+ : nullptr;
+}
+
+// Description at the declaration site (top of file).
+template <typename T>
+T* any_cast(any* operand) noexcept {
+ return operand && operand->GetObjTypeId() == any::IdForType<T>()
+ ? std::addressof(
+ static_cast<any::Obj<T>*>(operand->obj_.get())->value)
+ : nullptr;
+}
+
+} // namespace absl
+
+#undef ABSL_ANY_DETAIL_HAS_RTTI
+
+#endif // ABSL_HAVE_STD_ANY
+
+#endif // ABSL_TYPES_ANY_H_
diff --git a/absl/types/any_test.cc b/absl/types/any_test.cc
new file mode 100644
index 0000000..ab04bf5
--- /dev/null
+++ b/absl/types/any_test.cc
@@ -0,0 +1,713 @@
+// 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/types/any.h"
+
+#include <initializer_list>
+#include <type_traits>
+#include <typeinfo>
+#include <utility>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/exception_testing.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/container/internal/test_instance_tracker.h"
+
+namespace {
+using absl::test_internal::CopyableOnlyInstance;
+using absl::test_internal::InstanceTracker;
+
+template <typename T>
+const T& AsConst(const T& t) {
+ return t;
+}
+
+struct MoveOnly {
+ MoveOnly() = default;
+ explicit MoveOnly(int value) : value(value) {}
+ MoveOnly(MoveOnly&&) = default;
+ MoveOnly& operator=(MoveOnly&&) = default;
+
+ int value = 0;
+};
+
+struct CopyOnly {
+ CopyOnly() = default;
+ explicit CopyOnly(int value) : value(value) {}
+ CopyOnly(CopyOnly&&) = delete;
+ CopyOnly& operator=(CopyOnly&&) = delete;
+ CopyOnly(const CopyOnly&) = default;
+ CopyOnly& operator=(const CopyOnly&) = default;
+
+ int value = 0;
+};
+
+struct MoveOnlyWithListConstructor {
+ MoveOnlyWithListConstructor() = default;
+ explicit MoveOnlyWithListConstructor(std::initializer_list<int> /*ilist*/,
+ int value)
+ : value(value) {}
+ MoveOnlyWithListConstructor(MoveOnlyWithListConstructor&&) = default;
+ MoveOnlyWithListConstructor& operator=(MoveOnlyWithListConstructor&&) =
+ default;
+
+ int value = 0;
+};
+
+struct IntMoveOnlyCopyOnly {
+ IntMoveOnlyCopyOnly(int value, MoveOnly /*move_only*/, CopyOnly /*copy_only*/)
+ : value(value) {}
+
+ int value;
+};
+
+struct ListMoveOnlyCopyOnly {
+ ListMoveOnlyCopyOnly(std::initializer_list<int> ilist, MoveOnly /*move_only*/,
+ CopyOnly /*copy_only*/)
+ : values(ilist) {}
+
+ std::vector<int> values;
+};
+
+using FunctionType = void();
+void FunctionToEmplace() {}
+
+using ArrayType = int[2];
+using DecayedArray = absl::decay_t<ArrayType>;
+
+TEST(AnyTest, Noexcept) {
+ static_assert(std::is_nothrow_default_constructible<absl::any>(), "");
+ static_assert(std::is_nothrow_move_constructible<absl::any>(), "");
+ static_assert(std::is_nothrow_move_assignable<absl::any>(), "");
+ static_assert(noexcept(std::declval<absl::any&>().has_value()), "");
+ static_assert(noexcept(std::declval<absl::any&>().type()), "");
+ static_assert(noexcept(absl::any_cast<int>(std::declval<absl::any*>())), "");
+ static_assert(
+ noexcept(std::declval<absl::any&>().swap(std::declval<absl::any&>())),
+ "");
+
+ using std::swap;
+ static_assert(
+ noexcept(swap(std::declval<absl::any&>(), std::declval<absl::any&>())),
+ "");
+}
+
+TEST(AnyTest, HasValue) {
+ absl::any o;
+ EXPECT_FALSE(o.has_value());
+ o.emplace<int>();
+ EXPECT_TRUE(o.has_value());
+ o.reset();
+ EXPECT_FALSE(o.has_value());
+}
+
+TEST(AnyTest, Type) {
+ absl::any o;
+ EXPECT_EQ(typeid(void), o.type());
+ o.emplace<int>(5);
+ EXPECT_EQ(typeid(int), o.type());
+ o.emplace<float>(5.f);
+ EXPECT_EQ(typeid(float), o.type());
+ o.reset();
+ EXPECT_EQ(typeid(void), o.type());
+}
+
+TEST(AnyTest, EmptyPointerCast) {
+ // pointer-to-unqualified overload
+ {
+ absl::any o;
+ EXPECT_EQ(nullptr, absl::any_cast<int>(&o));
+ o.emplace<int>();
+ EXPECT_NE(nullptr, absl::any_cast<int>(&o));
+ o.reset();
+ EXPECT_EQ(nullptr, absl::any_cast<int>(&o));
+ }
+
+ // pointer-to-const overload
+ {
+ absl::any o;
+ EXPECT_EQ(nullptr, absl::any_cast<int>(&AsConst(o)));
+ o.emplace<int>();
+ EXPECT_NE(nullptr, absl::any_cast<int>(&AsConst(o)));
+ o.reset();
+ EXPECT_EQ(nullptr, absl::any_cast<int>(&AsConst(o)));
+ }
+}
+
+TEST(AnyTest, InPlaceConstruction) {
+ const CopyOnly copy_only{};
+ absl::any o(absl::in_place_type_t<IntMoveOnlyCopyOnly>(), 5, MoveOnly(),
+ copy_only);
+ IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
+ EXPECT_EQ(5, v.value);
+}
+
+TEST(AnyTest, InPlaceConstructionWithCV) {
+ const CopyOnly copy_only{};
+ absl::any o(absl::in_place_type_t<const volatile IntMoveOnlyCopyOnly>(), 5,
+ MoveOnly(), copy_only);
+ IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
+ EXPECT_EQ(5, v.value);
+}
+
+TEST(AnyTest, InPlaceConstructionWithFunction) {
+ absl::any o(absl::in_place_type_t<FunctionType>(), FunctionToEmplace);
+ FunctionType*& construction_result = absl::any_cast<FunctionType*&>(o);
+ EXPECT_EQ(&FunctionToEmplace, construction_result);
+}
+
+TEST(AnyTest, InPlaceConstructionWithArray) {
+ ArrayType ar = {5, 42};
+ absl::any o(absl::in_place_type_t<ArrayType>(), ar);
+ DecayedArray& construction_result = absl::any_cast<DecayedArray&>(o);
+ EXPECT_EQ(&ar[0], construction_result);
+}
+
+TEST(AnyTest, InPlaceConstructionIlist) {
+ const CopyOnly copy_only{};
+ absl::any o(absl::in_place_type_t<ListMoveOnlyCopyOnly>(), {1, 2, 3, 4},
+ MoveOnly(), copy_only);
+ ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
+ std::vector<int> expected_values = {1, 2, 3, 4};
+ EXPECT_EQ(expected_values, v.values);
+}
+
+TEST(AnyTest, InPlaceConstructionIlistWithCV) {
+ const CopyOnly copy_only{};
+ absl::any o(absl::in_place_type_t<const volatile ListMoveOnlyCopyOnly>(),
+ {1, 2, 3, 4}, MoveOnly(), copy_only);
+ ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
+ std::vector<int> expected_values = {1, 2, 3, 4};
+ EXPECT_EQ(expected_values, v.values);
+}
+
+TEST(AnyTest, InPlaceNoArgs) {
+ absl::any o(absl::in_place_type_t<int>{});
+ EXPECT_EQ(0, absl::any_cast<int&>(o));
+}
+
+template <typename Enabler, typename T, typename... Args>
+struct CanEmplaceAnyImpl : std::false_type {};
+
+template <typename T, typename... Args>
+struct CanEmplaceAnyImpl<
+ absl::void_t<decltype(
+ std::declval<absl::any&>().emplace<T>(std::declval<Args>()...))>,
+ T, Args...> : std::true_type {};
+
+template <typename T, typename... Args>
+using CanEmplaceAny = CanEmplaceAnyImpl<void, T, Args...>;
+
+TEST(AnyTest, Emplace) {
+ const CopyOnly copy_only{};
+ absl::any o;
+ EXPECT_TRUE((std::is_same<decltype(o.emplace<IntMoveOnlyCopyOnly>(
+ 5, MoveOnly(), copy_only)),
+ IntMoveOnlyCopyOnly&>::value));
+ IntMoveOnlyCopyOnly& emplace_result =
+ o.emplace<IntMoveOnlyCopyOnly>(5, MoveOnly(), copy_only);
+ EXPECT_EQ(5, emplace_result.value);
+ IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
+ EXPECT_EQ(5, v.value);
+ EXPECT_EQ(&emplace_result, &v);
+
+ static_assert(!CanEmplaceAny<int, int, int>::value, "");
+ static_assert(!CanEmplaceAny<MoveOnly, MoveOnly>::value, "");
+}
+
+TEST(AnyTest, EmplaceWithCV) {
+ const CopyOnly copy_only{};
+ absl::any o;
+ EXPECT_TRUE(
+ (std::is_same<decltype(o.emplace<const volatile IntMoveOnlyCopyOnly>(
+ 5, MoveOnly(), copy_only)),
+ IntMoveOnlyCopyOnly&>::value));
+ IntMoveOnlyCopyOnly& emplace_result =
+ o.emplace<const volatile IntMoveOnlyCopyOnly>(5, MoveOnly(), copy_only);
+ EXPECT_EQ(5, emplace_result.value);
+ IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
+ EXPECT_EQ(5, v.value);
+ EXPECT_EQ(&emplace_result, &v);
+}
+
+TEST(AnyTest, EmplaceWithFunction) {
+ absl::any o;
+ EXPECT_TRUE(
+ (std::is_same<decltype(o.emplace<FunctionType>(FunctionToEmplace)),
+ FunctionType*&>::value));
+ FunctionType*& emplace_result = o.emplace<FunctionType>(FunctionToEmplace);
+ EXPECT_EQ(&FunctionToEmplace, emplace_result);
+}
+
+TEST(AnyTest, EmplaceWithArray) {
+ absl::any o;
+ ArrayType ar = {5, 42};
+ EXPECT_TRUE(
+ (std::is_same<decltype(o.emplace<ArrayType>(ar)), DecayedArray&>::value));
+ DecayedArray& emplace_result = o.emplace<ArrayType>(ar);
+ EXPECT_EQ(&ar[0], emplace_result);
+}
+
+TEST(AnyTest, EmplaceIlist) {
+ const CopyOnly copy_only{};
+ absl::any o;
+ EXPECT_TRUE((std::is_same<decltype(o.emplace<ListMoveOnlyCopyOnly>(
+ {1, 2, 3, 4}, MoveOnly(), copy_only)),
+ ListMoveOnlyCopyOnly&>::value));
+ ListMoveOnlyCopyOnly& emplace_result =
+ o.emplace<ListMoveOnlyCopyOnly>({1, 2, 3, 4}, MoveOnly(), copy_only);
+ ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
+ EXPECT_EQ(&v, &emplace_result);
+ std::vector<int> expected_values = {1, 2, 3, 4};
+ EXPECT_EQ(expected_values, v.values);
+
+ static_assert(!CanEmplaceAny<int, std::initializer_list<int>>::value, "");
+ static_assert(!CanEmplaceAny<MoveOnlyWithListConstructor,
+ std::initializer_list<int>, int>::value,
+ "");
+}
+
+TEST(AnyTest, EmplaceIlistWithCV) {
+ const CopyOnly copy_only{};
+ absl::any o;
+ EXPECT_TRUE(
+ (std::is_same<decltype(o.emplace<const volatile ListMoveOnlyCopyOnly>(
+ {1, 2, 3, 4}, MoveOnly(), copy_only)),
+ ListMoveOnlyCopyOnly&>::value));
+ ListMoveOnlyCopyOnly& emplace_result =
+ o.emplace<const volatile ListMoveOnlyCopyOnly>({1, 2, 3, 4}, MoveOnly(),
+ copy_only);
+ ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
+ EXPECT_EQ(&v, &emplace_result);
+ std::vector<int> expected_values = {1, 2, 3, 4};
+ EXPECT_EQ(expected_values, v.values);
+}
+
+TEST(AnyTest, EmplaceNoArgs) {
+ absl::any o;
+ o.emplace<int>();
+ EXPECT_EQ(0, absl::any_cast<int>(o));
+}
+
+TEST(AnyTest, ConversionConstruction) {
+ {
+ absl::any o = 5;
+ EXPECT_EQ(5, absl::any_cast<int>(o));
+ }
+
+ {
+ const CopyOnly copy_only(5);
+ absl::any o = copy_only;
+ EXPECT_EQ(5, absl::any_cast<CopyOnly&>(o).value);
+ }
+
+ static_assert(!std::is_convertible<MoveOnly, absl::any>::value, "");
+}
+
+TEST(AnyTest, ConversionAssignment) {
+ {
+ absl::any o;
+ o = 5;
+ EXPECT_EQ(5, absl::any_cast<int>(o));
+ }
+
+ {
+ const CopyOnly copy_only(5);
+ absl::any o;
+ o = copy_only;
+ EXPECT_EQ(5, absl::any_cast<CopyOnly&>(o).value);
+ }
+
+ static_assert(!std::is_assignable<MoveOnly, absl::any>::value, "");
+}
+
+// Suppress MSVC warnings.
+// 4521: multiple copy constructors specified
+// We wrote multiple of them to test that the correct overloads are selected.
+#ifdef _MSC_VER
+#pragma warning( push )
+#pragma warning( disable : 4521)
+#endif
+
+// Weird type for testing, only used to make sure we "properly" perfect-forward
+// when being placed into an absl::any (use the l-value constructor if given an
+// l-value rather than use the copy constructor).
+struct WeirdConstructor42 {
+ explicit WeirdConstructor42(int value) : value(value) {}
+
+ // Copy-constructor
+ WeirdConstructor42(const WeirdConstructor42& other) : value(other.value) {}
+
+ // L-value "weird" constructor (used when given an l-value)
+ WeirdConstructor42(
+ WeirdConstructor42& /*other*/) // NOLINT(runtime/references)
+ : value(42) {}
+
+ int value;
+};
+#ifdef _MSC_VER
+#pragma warning( pop )
+#endif
+
+TEST(AnyTest, WeirdConversionConstruction) {
+ {
+ const WeirdConstructor42 source(5);
+ absl::any o = source; // Actual copy
+ EXPECT_EQ(5, absl::any_cast<WeirdConstructor42&>(o).value);
+ }
+
+ {
+ WeirdConstructor42 source(5);
+ absl::any o = source; // Weird "conversion"
+ EXPECT_EQ(42, absl::any_cast<WeirdConstructor42&>(o).value);
+ }
+}
+
+TEST(AnyTest, WeirdConversionAssignment) {
+ {
+ const WeirdConstructor42 source(5);
+ absl::any o;
+ o = source; // Actual copy
+ EXPECT_EQ(5, absl::any_cast<WeirdConstructor42&>(o).value);
+ }
+
+ {
+ WeirdConstructor42 source(5);
+ absl::any o;
+ o = source; // Weird "conversion"
+ EXPECT_EQ(42, absl::any_cast<WeirdConstructor42&>(o).value);
+ }
+}
+
+struct Value {};
+
+TEST(AnyTest, AnyCastValue) {
+ {
+ absl::any o;
+ o.emplace<int>(5);
+ EXPECT_EQ(5, absl::any_cast<int>(o));
+ EXPECT_EQ(5, absl::any_cast<int>(AsConst(o)));
+ static_assert(
+ std::is_same<decltype(absl::any_cast<Value>(o)), Value>::value, "");
+ }
+
+ {
+ absl::any o;
+ o.emplace<int>(5);
+ EXPECT_EQ(5, absl::any_cast<const int>(o));
+ EXPECT_EQ(5, absl::any_cast<const int>(AsConst(o)));
+ static_assert(std::is_same<decltype(absl::any_cast<const Value>(o)),
+ const Value>::value,
+ "");
+ }
+}
+
+TEST(AnyTest, AnyCastReference) {
+ {
+ absl::any o;
+ o.emplace<int>(5);
+ EXPECT_EQ(5, absl::any_cast<int&>(o));
+ EXPECT_EQ(5, absl::any_cast<const int&>(AsConst(o)));
+ static_assert(
+ std::is_same<decltype(absl::any_cast<Value&>(o)), Value&>::value, "");
+ }
+
+ {
+ absl::any o;
+ o.emplace<int>(5);
+ EXPECT_EQ(5, absl::any_cast<const int>(o));
+ EXPECT_EQ(5, absl::any_cast<const int>(AsConst(o)));
+ static_assert(std::is_same<decltype(absl::any_cast<const Value&>(o)),
+ const Value&>::value,
+ "");
+ }
+
+ {
+ absl::any o;
+ o.emplace<int>(5);
+ EXPECT_EQ(5, absl::any_cast<int&&>(std::move(o)));
+ static_assert(std::is_same<decltype(absl::any_cast<Value&&>(std::move(o))),
+ Value&&>::value,
+ "");
+ }
+
+ {
+ absl::any o;
+ o.emplace<int>(5);
+ EXPECT_EQ(5, absl::any_cast<const int>(std::move(o)));
+ static_assert(
+ std::is_same<decltype(absl::any_cast<const Value&&>(std::move(o))),
+ const Value&&>::value,
+ "");
+ }
+}
+
+TEST(AnyTest, AnyCastPointer) {
+ {
+ absl::any o;
+ EXPECT_EQ(nullptr, absl::any_cast<char>(&o));
+ o.emplace<int>(5);
+ EXPECT_EQ(nullptr, absl::any_cast<char>(&o));
+ o.emplace<char>('a');
+ EXPECT_EQ('a', *absl::any_cast<char>(&o));
+ static_assert(
+ std::is_same<decltype(absl::any_cast<Value>(&o)), Value*>::value, "");
+ }
+
+ {
+ absl::any o;
+ EXPECT_EQ(nullptr, absl::any_cast<const char>(&o));
+ o.emplace<int>(5);
+ EXPECT_EQ(nullptr, absl::any_cast<const char>(&o));
+ o.emplace<char>('a');
+ EXPECT_EQ('a', *absl::any_cast<const char>(&o));
+ static_assert(std::is_same<decltype(absl::any_cast<const Value>(&o)),
+ const Value*>::value,
+ "");
+ }
+}
+
+TEST(AnyTest, MakeAny) {
+ const CopyOnly copy_only{};
+ auto o = absl::make_any<IntMoveOnlyCopyOnly>(5, MoveOnly(), copy_only);
+ static_assert(std::is_same<decltype(o), absl::any>::value, "");
+ EXPECT_EQ(5, absl::any_cast<IntMoveOnlyCopyOnly&>(o).value);
+}
+
+TEST(AnyTest, MakeAnyIList) {
+ const CopyOnly copy_only{};
+ auto o =
+ absl::make_any<ListMoveOnlyCopyOnly>({1, 2, 3}, MoveOnly(), copy_only);
+ static_assert(std::is_same<decltype(o), absl::any>::value, "");
+ ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
+ std::vector<int> expected_values = {1, 2, 3};
+ EXPECT_EQ(expected_values, v.values);
+}
+
+// Test the use of copy constructor and operator=
+TEST(AnyTest, Copy) {
+ InstanceTracker tracker_raii;
+
+ {
+ absl::any o(absl::in_place_type_t<CopyableOnlyInstance>{}, 123);
+ CopyableOnlyInstance* f1 = absl::any_cast<CopyableOnlyInstance>(&o);
+
+ absl::any o2(o);
+ const CopyableOnlyInstance* f2 = absl::any_cast<CopyableOnlyInstance>(&o2);
+ EXPECT_EQ(123, f2->value());
+ EXPECT_NE(f1, f2);
+
+ absl::any o3;
+ o3 = o2;
+ const CopyableOnlyInstance* f3 = absl::any_cast<CopyableOnlyInstance>(&o3);
+ EXPECT_EQ(123, f3->value());
+ EXPECT_NE(f2, f3);
+
+ const absl::any o4(4);
+ // copy construct from const lvalue ref.
+ absl::any o5 = o4;
+ EXPECT_EQ(4, absl::any_cast<int>(o4));
+ EXPECT_EQ(4, absl::any_cast<int>(o5));
+
+ // Copy construct from const rvalue ref.
+ absl::any o6 = std::move(o4); // NOLINT
+ EXPECT_EQ(4, absl::any_cast<int>(o4));
+ EXPECT_EQ(4, absl::any_cast<int>(o6));
+ }
+}
+
+TEST(AnyTest, Move) {
+ InstanceTracker tracker_raii;
+
+ absl::any any1;
+ any1.emplace<CopyableOnlyInstance>(5);
+
+ // This is a copy, so copy count increases to 1.
+ absl::any any2 = any1;
+ EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any1).value());
+ EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any2).value());
+ EXPECT_EQ(1, tracker_raii.copies());
+
+ // This isn't a copy, so copy count doesn't increase.
+ absl::any any3 = std::move(any2);
+ EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any3).value());
+ EXPECT_EQ(1, tracker_raii.copies());
+
+ absl::any any4;
+ any4 = std::move(any3);
+ EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any4).value());
+ EXPECT_EQ(1, tracker_raii.copies());
+
+ absl::any tmp4(4);
+ absl::any o4(std::move(tmp4)); // move construct
+ EXPECT_EQ(4, absl::any_cast<int>(o4));
+ o4 = o4; // self assign
+ EXPECT_EQ(4, absl::any_cast<int>(o4));
+ EXPECT_TRUE(o4.has_value());
+
+ absl::any o5;
+ absl::any tmp5(5);
+ o5 = std::move(tmp5); // move assign
+ EXPECT_EQ(5, absl::any_cast<int>(o5));
+}
+
+// Reset the ObjectOwner with an object of a different type
+TEST(AnyTest, Reset) {
+ absl::any o;
+ o.emplace<int>();
+
+ o.reset();
+ EXPECT_FALSE(o.has_value());
+
+ o.emplace<char>();
+ EXPECT_TRUE(o.has_value());
+}
+
+TEST(AnyTest, ConversionConstructionCausesOneCopy) {
+ InstanceTracker tracker_raii;
+ CopyableOnlyInstance counter(5);
+ absl::any o(counter);
+ EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(o).value());
+ EXPECT_EQ(1, tracker_raii.copies());
+}
+
+//////////////////////////////////
+// Tests for Exception Behavior //
+//////////////////////////////////
+
+#define ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(...) \
+ ABSL_BASE_INTERNAL_EXPECT_FAIL((__VA_ARGS__), absl::bad_any_cast, \
+ "Bad any cast")
+
+TEST(AnyTest, ThrowBadAlloc) {
+ {
+ absl::any a;
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int&>(a));
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int&>(a));
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int&&>(absl::any{}));
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int&&>(absl::any{}));
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int>(a));
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int>(a));
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int>(absl::any{}));
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int>(absl::any{}));
+
+ // const absl::any operand
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int&>(AsConst(a)));
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int>(AsConst(a)));
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int>(AsConst(a)));
+ }
+
+ {
+ absl::any a(absl::in_place_type_t<int>{});
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float&>(a));
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float&>(a));
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float&&>(absl::any{}));
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(
+ absl::any_cast<const float&&>(absl::any{}));
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float>(a));
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float>(a));
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float>(absl::any{}));
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float>(absl::any{}));
+
+ // const absl::any operand
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float&>(AsConst(a)));
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float>(AsConst(a)));
+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float>(AsConst(a)));
+ }
+}
+
+class BadCopy {};
+
+struct BadCopyable {
+ BadCopyable() = default;
+ BadCopyable(BadCopyable&&) = default;
+ BadCopyable(const BadCopyable&) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+ throw BadCopy();
+#else
+ ABSL_RAW_LOG(FATAL, "Bad copy");
+#endif
+ }
+};
+
+#define ABSL_ANY_TEST_EXPECT_BAD_COPY(...) \
+ ABSL_BASE_INTERNAL_EXPECT_FAIL((__VA_ARGS__), BadCopy, "Bad copy")
+
+// Test the guarantees regarding exceptions in copy/assign.
+TEST(AnyTest, FailedCopy) {
+ {
+ const BadCopyable bad{};
+ ABSL_ANY_TEST_EXPECT_BAD_COPY(absl::any{bad});
+ }
+
+ {
+ absl::any src(absl::in_place_type_t<BadCopyable>{});
+ ABSL_ANY_TEST_EXPECT_BAD_COPY(absl::any{src});
+ }
+
+ {
+ BadCopyable bad;
+ absl::any target;
+ ABSL_ANY_TEST_EXPECT_BAD_COPY(target = bad);
+ }
+
+ {
+ BadCopyable bad;
+ absl::any target(absl::in_place_type_t<BadCopyable>{});
+ ABSL_ANY_TEST_EXPECT_BAD_COPY(target = bad);
+ EXPECT_TRUE(target.has_value());
+ }
+
+ {
+ absl::any src(absl::in_place_type_t<BadCopyable>{});
+ absl::any target;
+ ABSL_ANY_TEST_EXPECT_BAD_COPY(target = src);
+ EXPECT_FALSE(target.has_value());
+ }
+
+ {
+ absl::any src(absl::in_place_type_t<BadCopyable>{});
+ absl::any target(absl::in_place_type_t<BadCopyable>{});
+ ABSL_ANY_TEST_EXPECT_BAD_COPY(target = src);
+ EXPECT_TRUE(target.has_value());
+ }
+}
+
+// Test the guarantees regarding exceptions in emplace.
+TEST(AnyTest, FailedEmplace) {
+ {
+ BadCopyable bad;
+ absl::any target;
+ ABSL_ANY_TEST_EXPECT_BAD_COPY(target.emplace<BadCopyable>(bad));
+ }
+
+ {
+ BadCopyable bad;
+ absl::any target(absl::in_place_type_t<int>{});
+ ABSL_ANY_TEST_EXPECT_BAD_COPY(target.emplace<BadCopyable>(bad));
+#if defined(ABSL_HAVE_STD_ANY) && defined(__GLIBCXX__)
+ // libstdc++ std::any::emplace() implementation (as of 7.2) has a bug: if an
+ // exception is thrown, *this contains a value.
+#define ABSL_GLIBCXX_ANY_EMPLACE_EXCEPTION_BUG 1
+#endif
+#if defined(ABSL_HAVE_EXCEPTIONS) && \
+ !defined(ABSL_GLIBCXX_ANY_EMPLACE_EXCEPTION_BUG)
+ EXPECT_FALSE(target.has_value());
+#endif
+ }
+}
+
+} // namespace
diff --git a/absl/types/bad_any_cast.cc b/absl/types/bad_any_cast.cc
new file mode 100644
index 0000000..c9b7330
--- /dev/null
+++ b/absl/types/bad_any_cast.cc
@@ -0,0 +1,40 @@
+// 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/types/bad_any_cast.h"
+
+#include <cstdlib>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+
+bad_any_cast::~bad_any_cast() = default;
+
+const char* bad_any_cast::what() const noexcept { return "Bad any cast"; }
+
+namespace any_internal {
+
+void ThrowBadAnyCast() {
+#ifdef ABSL_HAVE_EXCEPTIONS
+ throw bad_any_cast();
+#else
+ ABSL_RAW_LOG(FATAL, "Bad any cast");
+ std::abort();
+#endif
+}
+
+} // namespace any_internal
+} // namespace absl
diff --git a/absl/types/bad_any_cast.h b/absl/types/bad_any_cast.h
new file mode 100644
index 0000000..8ffbe4b
--- /dev/null
+++ b/absl/types/bad_any_cast.h
@@ -0,0 +1,44 @@
+// 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_TYPES_BAD_ANY_CAST_H_
+#define ABSL_TYPES_BAD_ANY_CAST_H_
+
+#include <typeinfo>
+
+namespace absl {
+
+////////////////////////
+// [any.bad_any_cast] //
+////////////////////////
+
+// Objects of type bad_any_cast are thrown by a failed any_cast.
+class bad_any_cast : public std::bad_cast {
+ public:
+ ~bad_any_cast() override;
+ const char* what() const noexcept override;
+};
+
+//////////////////////////////////////////////
+// Implementation-details beyond this point //
+//////////////////////////////////////////////
+
+namespace any_internal {
+
+[[noreturn]] void ThrowBadAnyCast();
+
+} // namespace any_internal
+} // namespace absl
+
+#endif // ABSL_TYPES_BAD_ANY_CAST_H_
diff --git a/absl/types/bad_optional_access.cc b/absl/types/bad_optional_access.cc
new file mode 100644
index 0000000..6bc67df
--- /dev/null
+++ b/absl/types/bad_optional_access.cc
@@ -0,0 +1,42 @@
+// 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/types/bad_optional_access.h"
+
+#include <cstdlib>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+
+bad_optional_access::~bad_optional_access() = default;
+
+const char* bad_optional_access::what() const noexcept {
+ return "optional has no value";
+}
+
+namespace optional_internal {
+
+void throw_bad_optional_access() {
+#ifdef ABSL_HAVE_EXCEPTIONS
+ throw bad_optional_access();
+#else
+ ABSL_RAW_LOG(FATAL, "Bad optional access");
+ abort();
+#endif
+}
+
+} // namespace optional_internal
+} // namespace absl
diff --git a/absl/types/bad_optional_access.h b/absl/types/bad_optional_access.h
new file mode 100644
index 0000000..c4c7444
--- /dev/null
+++ b/absl/types/bad_optional_access.h
@@ -0,0 +1,37 @@
+// 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_TYPES_BAD_OPTIONAL_ACCESS_H_
+#define ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_
+
+#include <stdexcept>
+
+namespace absl {
+
+class bad_optional_access : public std::exception {
+ public:
+ bad_optional_access() = default;
+ ~bad_optional_access() override;
+ const char* what() const noexcept override;
+};
+
+namespace optional_internal {
+
+// throw delegator
+[[noreturn]] void throw_bad_optional_access();
+
+} // namespace optional_internal
+} // namespace absl
+
+#endif // ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_
diff --git a/absl/types/optional.cc b/absl/types/optional.cc
new file mode 100644
index 0000000..ef27290
--- /dev/null
+++ b/absl/types/optional.cc
@@ -0,0 +1,24 @@
+// 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/types/optional.h"
+
+#ifndef ABSL_HAVE_STD_OPTIONAL
+namespace absl {
+
+nullopt_t::init_t nullopt_t::init;
+extern const nullopt_t nullopt{nullopt_t::init};
+
+} // namespace absl
+#endif // ABSL_HAVE_STD_OPTIONAL
diff --git a/absl/types/optional.h b/absl/types/optional.h
new file mode 100644
index 0000000..5099d48
--- /dev/null
+++ b/absl/types/optional.h
@@ -0,0 +1,1092 @@
+//
+// 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.
+//
+// -----------------------------------------------------------------------------
+// optional.h
+// -----------------------------------------------------------------------------
+//
+// This header file define the `absl::optional` type for holding a value which
+// may or may not be present. This type is useful for providing value semantics
+// for operations that may either wish to return or hold "something-or-nothing".
+//
+// Example:
+//
+// // A common way to signal operation failure is to provide an output
+// // parameter and a bool return type:
+// bool AcquireResource(const Input&, Resource * out);
+//
+// // Providing an absl::optional return type provides a cleaner API:
+// absl::optional<Resource> AcquireResource(const Input&);
+//
+// `absl::optional` is a C++11 compatible version of the C++17 `std::optional`
+// abstraction and is designed to be a drop-in replacement for code compliant
+// with C++17.
+#ifndef ABSL_TYPES_OPTIONAL_H_
+#define ABSL_TYPES_OPTIONAL_H_
+
+#include "absl/base/config.h"
+#include "absl/utility/utility.h"
+
+#ifdef ABSL_HAVE_STD_OPTIONAL
+
+#include <optional>
+
+namespace absl {
+using std::bad_optional_access;
+using std::optional;
+using std::make_optional;
+using std::nullopt_t;
+using std::nullopt;
+}
+
+#else // ABSL_HAVE_STD_OPTIONAL
+
+#include <cassert>
+#include <functional>
+#include <initializer_list>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "absl/meta/type_traits.h"
+#include "absl/types/bad_optional_access.h"
+
+// ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+//
+// Inheriting constructors is supported in GCC 4.8+, Clang 3.3+ and MSVC 2015.
+// __cpp_inheriting_constructors is a predefined macro and a recommended way to
+// check for this language feature, but GCC doesn't support it until 5.0 and
+// Clang doesn't support it until 3.6.
+// Also, MSVC 2015 has a bug: it doesn't inherit the constexpr template
+// constructor. For example, the following code won't work on MSVC 2015 Update3:
+// struct Base {
+// int t;
+// template <typename T>
+// constexpr Base(T t_) : t(t_) {}
+// };
+// struct Foo : Base {
+// using Base::Base;
+// }
+// constexpr Foo foo(0); // doesn't work on MSVC 2015
+#if defined(__clang__)
+#if __has_feature(cxx_inheriting_constructors)
+#define ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1
+#endif
+#elif (defined(__GNUC__) && \
+ (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 8)) || \
+ (__cpp_inheriting_constructors >= 200802) || \
+ (defined(_MSC_VER) && _MSC_VER >= 1910)
+#define ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1
+#endif
+
+namespace absl {
+
+// optional
+//
+// A value of type `absl::optional<T>` holds either a value of `T` or an
+// "empty" value. When it holds a value of `T`, it stores it as a direct
+// sub-object, so `sizeof(optional<T>)` is approximately
+// `sizeof(T) + sizeof(bool)`.
+//
+// This implementation is based on the specification in the latest draft of the
+// C++17 `std::optional` specification as of May 2017, section 20.6.
+//
+// Differences between `absl::optional<T>` and `std::optional<T>` include:
+//
+// * `constexpr` is not used for non-const member functions.
+// (dependency on some differences between C++11 and C++14.)
+// * `absl::nullopt` and `absl::in_place` are not declared `constexpr`. We
+// need the inline variable support in C++17 for external linkage.
+// * Throws `absl::bad_optional_access` instead of
+// `std::bad_optional_access`.
+// * `optional::swap()` and `absl::swap()` relies on
+// `std::is_(nothrow_)swappable()`, which has been introduced in C++17.
+// As a workaround, we assume `is_swappable()` is always `true`
+// and `is_nothrow_swappable()` is the same as `std::is_trivial()`.
+// * `make_optional()` cannot be declared `constexpr` due to the absence of
+// guaranteed copy elision.
+template <typename T>
+class optional;
+
+// nullopt_t
+//
+// Class type for `absl::nullopt` used to indicate an `absl::optional<T>` type
+// that does not contain a value.
+struct nullopt_t {
+ struct init_t {};
+ static init_t init;
+
+ // It must not be default-constructible to avoid ambiguity for opt = {}.
+ // Note the non-const reference, which is to eliminate ambiguity for code
+ // like:
+ //
+ // struct S { int value; };
+ //
+ // void Test() {
+ // optional<S> opt;
+ // opt = {{}};
+ // }
+ explicit constexpr nullopt_t(init_t& /*unused*/) {}
+};
+
+// nullopt
+//
+// A tag constant of type `absl::nullopt_t` used to indicate an empty
+// `absl::optional` in certain functions, such as construction or assignment.
+extern const nullopt_t nullopt;
+
+namespace optional_internal {
+
+struct empty_struct {};
+// This class stores the data in optional<T>.
+// It is specialized based on whether T is trivially destructible.
+// This is the specialization for non trivially destructible type.
+template <typename T, bool = std::is_trivially_destructible<T>::value>
+class optional_data_dtor_base {
+ struct dummy_type {
+ static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
+ // Use an array to avoid GCC 6 placement-new warning.
+ empty_struct data[sizeof(T) / sizeof(empty_struct)];
+ };
+
+ protected:
+ // Whether there is data or not.
+ bool engaged_;
+ // Data storage
+ union {
+ dummy_type dummy_;
+ T data_;
+ };
+
+ void destruct() noexcept {
+ if (engaged_) {
+ data_.~T();
+ engaged_ = false;
+ }
+ }
+
+ // dummy_ must be initialized for constexpr constructor.
+ constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
+
+ template <typename... Args>
+ constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
+ : engaged_(true), data_(absl::forward<Args>(args)...) {}
+
+ ~optional_data_dtor_base() { destruct(); }
+};
+
+// Specialization for trivially destructible type.
+template <typename T>
+class optional_data_dtor_base<T, true> {
+ struct dummy_type {
+ static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
+ // Use array to avoid GCC 6 placement-new warning.
+ empty_struct data[sizeof(T) / sizeof(empty_struct)];
+ };
+
+ protected:
+ // Whether there is data or not.
+ bool engaged_;
+ // Data storage
+ union {
+ dummy_type dummy_;
+ T data_;
+ };
+ void destruct() noexcept { engaged_ = false; }
+
+ // dummy_ must be initialized for constexpr constructor.
+ constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
+
+ template <typename... Args>
+ constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
+ : engaged_(true), data_(absl::forward<Args>(args)...) {}
+};
+
+template <typename T>
+class optional_data_base : public optional_data_dtor_base<T> {
+ protected:
+ using base = optional_data_dtor_base<T>;
+#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+ using base::base;
+#else
+ optional_data_base() = default;
+
+ template <typename... Args>
+ constexpr explicit optional_data_base(in_place_t t, Args&&... args)
+ : base(t, absl::forward<Args>(args)...) {}
+#endif
+
+ template <typename... Args>
+ void construct(Args&&... args) {
+ // Use dummy_'s address to work around casting cv-qualified T* to void*.
+ ::new (static_cast<void*>(&this->dummy_)) T(std::forward<Args>(args)...);
+ this->engaged_ = true;
+ }
+
+ template <typename U>
+ void assign(U&& u) {
+ if (this->engaged_) {
+ this->data_ = std::forward<U>(u);
+ } else {
+ construct(std::forward<U>(u));
+ }
+ }
+};
+
+// TODO(b/34201852): Add another base class using
+// std::is_trivially_move_constructible trait when available to match
+// http://cplusplus.github.io/LWG/lwg-defects.html#2900, for types that
+// have trivial move but nontrivial copy.
+// Also, we should be checking is_trivially_copyable here, which is not
+// supported now, so we use is_trivially_* traits instead.
+template <typename T, bool = absl::is_trivially_copy_constructible<T>::value&&
+ absl::is_trivially_copy_assignable<
+ typename std::remove_cv<T>::type>::value&&
+ std::is_trivially_destructible<T>::value>
+class optional_data;
+
+// Trivially copyable types
+template <typename T>
+class optional_data<T, true> : public optional_data_base<T> {
+ protected:
+#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+ using optional_data_base<T>::optional_data_base;
+#else
+ optional_data() = default;
+
+ template <typename... Args>
+ constexpr explicit optional_data(in_place_t t, Args&&... args)
+ : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
+#endif
+};
+
+template <typename T>
+class optional_data<T, false> : public optional_data_base<T> {
+ protected:
+#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+ using optional_data_base<T>::optional_data_base;
+#else
+ template <typename... Args>
+ constexpr explicit optional_data(in_place_t t, Args&&... args)
+ : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
+#endif
+
+ optional_data() = default;
+
+ optional_data(const optional_data& rhs) {
+ if (rhs.engaged_) {
+ this->construct(rhs.data_);
+ }
+ }
+
+ optional_data(optional_data&& rhs) noexcept(
+ absl::default_allocator_is_nothrow::value ||
+ std::is_nothrow_move_constructible<T>::value) {
+ if (rhs.engaged_) {
+ this->construct(std::move(rhs.data_));
+ }
+ }
+
+ optional_data& operator=(const optional_data& rhs) {
+ if (rhs.engaged_) {
+ this->assign(rhs.data_);
+ } else {
+ this->destruct();
+ }
+ return *this;
+ }
+
+ optional_data& operator=(optional_data&& rhs) noexcept(
+ std::is_nothrow_move_assignable<T>::value&&
+ std::is_nothrow_move_constructible<T>::value) {
+ if (rhs.engaged_) {
+ this->assign(std::move(rhs.data_));
+ } else {
+ this->destruct();
+ }
+ return *this;
+ }
+};
+
+// Ordered by level of restriction, from low to high.
+// Copyable implies movable.
+enum class copy_traits { copyable = 0, movable = 1, non_movable = 2 };
+
+// Base class for enabling/disabling copy/move constructor.
+template <copy_traits>
+class optional_ctor_base;
+
+template <>
+class optional_ctor_base<copy_traits::copyable> {
+ public:
+ constexpr optional_ctor_base() = default;
+ optional_ctor_base(const optional_ctor_base&) = default;
+ optional_ctor_base(optional_ctor_base&&) = default;
+ optional_ctor_base& operator=(const optional_ctor_base&) = default;
+ optional_ctor_base& operator=(optional_ctor_base&&) = default;
+};
+
+template <>
+class optional_ctor_base<copy_traits::movable> {
+ public:
+ constexpr optional_ctor_base() = default;
+ optional_ctor_base(const optional_ctor_base&) = delete;
+ optional_ctor_base(optional_ctor_base&&) = default;
+ optional_ctor_base& operator=(const optional_ctor_base&) = default;
+ optional_ctor_base& operator=(optional_ctor_base&&) = default;
+};
+
+template <>
+class optional_ctor_base<copy_traits::non_movable> {
+ public:
+ constexpr optional_ctor_base() = default;
+ optional_ctor_base(const optional_ctor_base&) = delete;
+ optional_ctor_base(optional_ctor_base&&) = delete;
+ optional_ctor_base& operator=(const optional_ctor_base&) = default;
+ optional_ctor_base& operator=(optional_ctor_base&&) = default;
+};
+
+// Base class for enabling/disabling copy/move assignment.
+template <copy_traits>
+class optional_assign_base;
+
+template <>
+class optional_assign_base<copy_traits::copyable> {
+ public:
+ constexpr optional_assign_base() = default;
+ optional_assign_base(const optional_assign_base&) = default;
+ optional_assign_base(optional_assign_base&&) = default;
+ optional_assign_base& operator=(const optional_assign_base&) = default;
+ optional_assign_base& operator=(optional_assign_base&&) = default;
+};
+
+template <>
+class optional_assign_base<copy_traits::movable> {
+ public:
+ constexpr optional_assign_base() = default;
+ optional_assign_base(const optional_assign_base&) = default;
+ optional_assign_base(optional_assign_base&&) = default;
+ optional_assign_base& operator=(const optional_assign_base&) = delete;
+ optional_assign_base& operator=(optional_assign_base&&) = default;
+};
+
+template <>
+class optional_assign_base<copy_traits::non_movable> {
+ public:
+ constexpr optional_assign_base() = default;
+ optional_assign_base(const optional_assign_base&) = default;
+ optional_assign_base(optional_assign_base&&) = default;
+ optional_assign_base& operator=(const optional_assign_base&) = delete;
+ optional_assign_base& operator=(optional_assign_base&&) = delete;
+};
+
+template <typename T>
+constexpr copy_traits get_ctor_copy_traits() {
+ return std::is_copy_constructible<T>::value
+ ? copy_traits::copyable
+ : std::is_move_constructible<T>::value ? copy_traits::movable
+ : copy_traits::non_movable;
+}
+
+template <typename T>
+constexpr copy_traits get_assign_copy_traits() {
+ return std::is_copy_assignable<T>::value &&
+ std::is_copy_constructible<T>::value
+ ? copy_traits::copyable
+ : std::is_move_assignable<T>::value &&
+ std::is_move_constructible<T>::value
+ ? copy_traits::movable
+ : copy_traits::non_movable;
+}
+
+// Whether T is constructible or convertible from optional<U>.
+template <typename T, typename U>
+struct is_constructible_convertible_from_optional
+ : std::integral_constant<
+ bool, std::is_constructible<T, optional<U>&>::value ||
+ std::is_constructible<T, optional<U>&&>::value ||
+ std::is_constructible<T, const optional<U>&>::value ||
+ std::is_constructible<T, const optional<U>&&>::value ||
+ std::is_convertible<optional<U>&, T>::value ||
+ std::is_convertible<optional<U>&&, T>::value ||
+ std::is_convertible<const optional<U>&, T>::value ||
+ std::is_convertible<const optional<U>&&, T>::value> {};
+
+// Whether T is constructible or convertible or assignable from optional<U>.
+template <typename T, typename U>
+struct is_constructible_convertible_assignable_from_optional
+ : std::integral_constant<
+ bool, is_constructible_convertible_from_optional<T, U>::value ||
+ std::is_assignable<T&, optional<U>&>::value ||
+ std::is_assignable<T&, optional<U>&&>::value ||
+ std::is_assignable<T&, const optional<U>&>::value ||
+ std::is_assignable<T&, const optional<U>&&>::value> {};
+
+// Helper function used by [optional.relops], [optional.comp_with_t],
+// for checking whether an expression is convertible to bool.
+bool convertible_to_bool(bool);
+
+} // namespace optional_internal
+
+// -----------------------------------------------------------------------------
+// absl::optional class definition
+// -----------------------------------------------------------------------------
+
+template <typename T>
+class optional : private optional_internal::optional_data<T>,
+ private optional_internal::optional_ctor_base<
+ optional_internal::get_ctor_copy_traits<T>()>,
+ private optional_internal::optional_assign_base<
+ optional_internal::get_assign_copy_traits<T>()> {
+ using data_base = optional_internal::optional_data<T>;
+
+ public:
+ typedef T value_type;
+
+ // Constructors
+
+ // Constructs a default-constructed `optional` holding the empty value, NOT a
+ // default constructed `T`.
+ constexpr optional() noexcept {}
+
+ // Construct an` optional` initialized with `nullopt` to hold an empty value.
+ constexpr optional(nullopt_t) noexcept {} // NOLINT(runtime/explicit)
+
+ // Copy constructor, standard semantics
+ optional(const optional& src) = default;
+
+ // Move constructor, standard semantics
+ optional(optional&& src) = default;
+
+ // Constructs a non-empty `optional` direct-initialized value of type `T` from
+ // the arguments `std::forward<Args>(args)...` within the `optional`.
+ // (The `in_place_t` is a tag used to indicate that the contained object
+ // should be constructed in-place.)
+ // TODO(b/34201852): Add std::is_constructible<T, Args&&...> SFINAE.
+ template <typename... Args>
+ constexpr explicit optional(in_place_t, Args&&... args)
+ : data_base(in_place_t(), absl::forward<Args>(args)...) {}
+
+ // Constructs a non-empty `optional' direct-initialized value of type `T` from
+ // the arguments of an initializer_list and `std::forward<Args>(args)...`.
+ // (The `in_place_t` is a tag used to indicate that the contained object
+ // should be constructed in-place.)
+ template <typename U, typename... Args,
+ typename = typename std::enable_if<std::is_constructible<
+ T, std::initializer_list<U>&, Args&&...>::value>::type>
+ constexpr explicit optional(in_place_t, std::initializer_list<U> il,
+ Args&&... args)
+ : data_base(in_place_t(), il, absl::forward<Args>(args)...) {
+ }
+
+ // Value constructor (implicit)
+ template <
+ typename U = T,
+ typename std::enable_if<
+ absl::conjunction<absl::negation<std::is_same<
+ in_place_t, typename std::decay<U>::type> >,
+ absl::negation<std::is_same<
+ optional<T>, typename std::decay<U>::type> >,
+ std::is_convertible<U&&, T>,
+ std::is_constructible<T, U&&> >::value,
+ bool>::type = false>
+ constexpr optional(U&& v) : data_base(in_place_t(), absl::forward<U>(v)) {}
+
+ // Value constructor (explicit)
+ template <
+ typename U = T,
+ typename std::enable_if<
+ absl::conjunction<absl::negation<std::is_same<
+ in_place_t, typename std::decay<U>::type>>,
+ absl::negation<std::is_same<
+ optional<T>, typename std::decay<U>::type>>,
+ absl::negation<std::is_convertible<U&&, T>>,
+ std::is_constructible<T, U&&>>::value,
+ bool>::type = false>
+ explicit constexpr optional(U&& v)
+ : data_base(in_place_t(), absl::forward<U>(v)) {}
+
+ // Converting copy constructor (implicit)
+ template <typename U,
+ typename std::enable_if<
+ absl::conjunction<
+ absl::negation<std::is_same<T, U> >,
+ std::is_constructible<T, const U&>,
+ absl::negation<
+ optional_internal::
+ is_constructible_convertible_from_optional<T, U> >,
+ std::is_convertible<const U&, T> >::value,
+ bool>::type = false>
+ optional(const optional<U>& rhs) {
+ if (rhs) {
+ this->construct(*rhs);
+ }
+ }
+
+ // Converting copy constructor (explicit)
+ template <typename U,
+ typename std::enable_if<
+ absl::conjunction<
+ absl::negation<std::is_same<T, U>>,
+ std::is_constructible<T, const U&>,
+ absl::negation<
+ optional_internal::
+ is_constructible_convertible_from_optional<T, U>>,
+ absl::negation<std::is_convertible<const U&, T>>>::value,
+ bool>::type = false>
+ explicit optional(const optional<U>& rhs) {
+ if (rhs) {
+ this->construct(*rhs);
+ }
+ }
+
+ // Converting move constructor (implicit)
+ template <typename U,
+ typename std::enable_if<
+ absl::conjunction<
+ absl::negation<std::is_same<T, U> >,
+ std::is_constructible<T, U&&>,
+ absl::negation<
+ optional_internal::
+ is_constructible_convertible_from_optional<T, U> >,
+ std::is_convertible<U&&, T> >::value,
+ bool>::type = false>
+ optional(optional<U>&& rhs) {
+ if (rhs) {
+ this->construct(std::move(*rhs));
+ }
+ }
+
+ // Converting move constructor (explicit)
+ template <
+ typename U,
+ typename std::enable_if<
+ absl::conjunction<
+ absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
+ absl::negation<
+ optional_internal::is_constructible_convertible_from_optional<
+ T, U>>,
+ absl::negation<std::is_convertible<U&&, T>>>::value,
+ bool>::type = false>
+ explicit optional(optional<U>&& rhs) {
+ if (rhs) {
+ this->construct(std::move(*rhs));
+ }
+ }
+
+ // Destructor. Trivial if `T` is trivially destructible.
+ ~optional() = default;
+
+ // Assignment Operators
+
+ // Assignment from `nullopt`
+ //
+ // Example:
+ //
+ // struct S { int value; };
+ // optional<S> opt = absl::nullopt; // Could also use opt = { };
+ optional& operator=(nullopt_t) noexcept {
+ this->destruct();
+ return *this;
+ }
+
+ // Copy assignment operator, standard semantics
+ optional& operator=(const optional& src) = default;
+
+ // Move assignment operator, standard semantics
+ optional& operator=(optional&& src) = default;
+
+ // Value assignment operators
+ template <
+ typename U = T,
+ typename = typename std::enable_if<absl::conjunction<
+ absl::negation<
+ std::is_same<optional<T>, typename std::decay<U>::type>>,
+ absl::negation<
+ absl::conjunction<std::is_scalar<T>,
+ std::is_same<T, typename std::decay<U>::type>>>,
+ std::is_constructible<T, U>, std::is_assignable<T&, U>>::value>::type>
+ optional& operator=(U&& v) {
+ this->assign(std::forward<U>(v));
+ return *this;
+ }
+
+ template <
+ typename U,
+ typename = typename std::enable_if<absl::conjunction<
+ absl::negation<std::is_same<T, U>>,
+ std::is_constructible<T, const U&>, std::is_assignable<T&, const U&>,
+ absl::negation<
+ optional_internal::
+ is_constructible_convertible_assignable_from_optional<
+ T, U>>>::value>::type>
+ optional& operator=(const optional<U>& rhs) {
+ if (rhs) {
+ this->assign(*rhs);
+ } else {
+ this->destruct();
+ }
+ return *this;
+ }
+
+ template <typename U,
+ typename = typename std::enable_if<absl::conjunction<
+ absl::negation<std::is_same<T, U>>, std::is_constructible<T, U>,
+ std::is_assignable<T&, U>,
+ absl::negation<
+ optional_internal::
+ is_constructible_convertible_assignable_from_optional<
+ T, U>>>::value>::type>
+ optional& operator=(optional<U>&& rhs) {
+ if (rhs) {
+ this->assign(std::move(*rhs));
+ } else {
+ this->destruct();
+ }
+ return *this;
+ }
+
+ // Modifiers
+
+ // optional::reset()
+ //
+ // Destroys the inner `T` value of an `absl::optional` if one is present.
+ void reset() noexcept { this->destruct(); }
+
+ // optional::emplace()
+ //
+ // (Re)constructs the underlying `T` in-place with the given forwarded
+ // arguments.
+ //
+ // Example:
+ //
+ // optional<Foo> opt;
+ // opt.emplace(arg1,arg2,arg3); // Constructs Foo(arg1,arg2,arg3)
+ //
+ // If the optional is non-empty, and the `args` refer to subobjects of the
+ // current object, then behaviour is undefined, because the current object
+ // will be destructed before the new object is constructed with `args`.
+ template <typename... Args,
+ typename = typename std::enable_if<
+ std::is_constructible<T, Args&&...>::value>::type>
+ T& emplace(Args&&... args) {
+ this->destruct();
+ this->construct(std::forward<Args>(args)...);
+ return reference();
+ }
+
+ // Emplace reconstruction overload for an initializer list and the given
+ // forwarded arguments.
+ //
+ // Example:
+ //
+ // struct Foo {
+ // Foo(std::initializer_list<int>);
+ // };
+ //
+ // optional<Foo> opt;
+ // opt.emplace({1,2,3}); // Constructs Foo({1,2,3})
+ template <typename U, typename... Args,
+ typename = typename std::enable_if<std::is_constructible<
+ T, std::initializer_list<U>&, Args&&...>::value>::type>
+ T& emplace(std::initializer_list<U> il, Args&&... args) {
+ this->destruct();
+ this->construct(il, std::forward<Args>(args)...);
+ return reference();
+ }
+
+ // Swaps
+
+ // Swap, standard semantics
+ void swap(optional& rhs) noexcept(
+ std::is_nothrow_move_constructible<T>::value&&
+ std::is_trivial<T>::value) {
+ if (*this) {
+ if (rhs) {
+ using std::swap;
+ swap(**this, *rhs);
+ } else {
+ rhs.construct(std::move(**this));
+ this->destruct();
+ }
+ } else {
+ if (rhs) {
+ this->construct(std::move(*rhs));
+ rhs.destruct();
+ } else {
+ // No effect (swap(disengaged, disengaged)).
+ }
+ }
+ }
+
+ // Observers
+
+ // optional::operator->()
+ //
+ // Accesses the underlying `T` value's member `m` of an `optional`. If the
+ // `optional` is empty, behavior is undefined.
+ constexpr const T* operator->() const { return this->pointer(); }
+ T* operator->() {
+ assert(this->engaged_);
+ return this->pointer();
+ }
+
+ // optional::operator*()
+ //
+ // Accesses the underlying `T `value of an `optional`. If the `optional` is
+ // empty, behavior is undefined.
+ constexpr const T& operator*() const & { return reference(); }
+ T& operator*() & {
+ assert(this->engaged_);
+ return reference();
+ }
+ constexpr const T&& operator*() const && {
+ return absl::move(reference());
+ }
+ T&& operator*() && {
+ assert(this->engaged_);
+ return std::move(reference());
+ }
+
+ // optional::operator bool()
+ //
+ // Returns false if and only if the `optional` is empty.
+ //
+ // if (opt) {
+ // // do something with opt.value();
+ // } else {
+ // // opt is empty.
+ // }
+ //
+ constexpr explicit operator bool() const noexcept { return this->engaged_; }
+
+ // optional::has_value()
+ //
+ // Determines whether the `optional` contains a value. Returns `false` if and
+ // only if `*this` is empty.
+ constexpr bool has_value() const noexcept { return this->engaged_; }
+
+ // optional::value()
+ //
+ // Returns a reference to an `optional`s underlying value. The constness
+ // and lvalue/rvalue-ness of the `optional` is preserved to the view of
+ // the `T` sub-object. Throws `absl::bad_optional_access` when the `optional`
+ // is empty.
+ constexpr const T& value() const & {
+ return static_cast<bool>(*this)
+ ? reference()
+ : (optional_internal::throw_bad_optional_access(), reference());
+ }
+ T& value() & {
+ return static_cast<bool>(*this)
+ ? reference()
+ : (optional_internal::throw_bad_optional_access(), reference());
+ }
+ T&& value() && { // NOLINT(build/c++11)
+ return std::move(
+ static_cast<bool>(*this)
+ ? reference()
+ : (optional_internal::throw_bad_optional_access(), reference()));
+ }
+ constexpr const T&& value() const && { // NOLINT(build/c++11)
+ return absl::move(
+ static_cast<bool>(*this)
+ ? reference()
+ : (optional_internal::throw_bad_optional_access(), reference()));
+ }
+
+ // optional::value_or()
+ //
+ // Returns either the value of `T` or a passed default `val` if the `optional`
+ // is empty.
+ template <typename U>
+ constexpr T value_or(U&& v) const& {
+ return static_cast<bool>(*this)
+ ? **this
+ : static_cast<T>(absl::forward<U>(v));
+ }
+ template <typename U>
+ T value_or(U&& v) && { // NOLINT(build/c++11)
+ return static_cast<bool>(*this) ? std::move(**this)
+ : static_cast<T>(std::forward<U>(v));
+ }
+
+ private:
+ // Private accessors for internal storage viewed as pointer to T.
+ constexpr const T* pointer() const { return &this->data_; }
+ T* pointer() { return &this->data_; }
+
+ // Private accessors for internal storage viewed as reference to T.
+ constexpr const T& reference() const { return *this->pointer(); }
+ T& reference() { return *(this->pointer()); }
+
+ // T constraint checks. You can't have an optional of nullopt_t, in_place_t
+ // or a reference.
+ static_assert(
+ !std::is_same<nullopt_t, typename std::remove_cv<T>::type>::value,
+ "optional<nullopt_t> is not allowed.");
+ static_assert(
+ !std::is_same<in_place_t, typename std::remove_cv<T>::type>::value,
+ "optional<in_place_t> is not allowed.");
+ static_assert(!std::is_reference<T>::value,
+ "optional<reference> is not allowed.");
+};
+
+// Non-member functions
+
+// swap()
+//
+// Performs a swap between two `absl::optional` objects, using standard
+// semantics.
+//
+// NOTE: we assume `is_swappable()` is always `true`. A compile error will
+// result if this is not the case.
+template <typename T,
+ typename std::enable_if<std::is_move_constructible<T>::value,
+ bool>::type = false>
+void swap(optional<T>& a, optional<T>& b) noexcept(noexcept(a.swap(b))) {
+ a.swap(b);
+}
+
+// make_optional()
+//
+// Creates a non-empty `optional<T>` where the type of `T` is deduced. An
+// `absl::optional` can also be explicitly instantiated with
+// `make_optional<T>(v)`.
+//
+// Note: `make_optional()` constructions may be declared `constexpr` for
+// trivially copyable types `T`. Non-trivial types require copy elision
+// support in C++17 for `make_optional` to support `constexpr` on such
+// non-trivial types.
+//
+// Example:
+//
+// constexpr absl::optional<int> opt = absl::make_optional(1);
+// static_assert(opt.value() == 1, "");
+template <typename T>
+constexpr optional<typename std::decay<T>::type> make_optional(T&& v) {
+ return optional<typename std::decay<T>::type>(absl::forward<T>(v));
+}
+
+template <typename T, typename... Args>
+constexpr optional<T> make_optional(Args&&... args) {
+ return optional<T>(in_place_t(), absl::forward<Args>(args)...);
+}
+
+template <typename T, typename U, typename... Args>
+constexpr optional<T> make_optional(std::initializer_list<U> il,
+ Args&&... args) {
+ return optional<T>(in_place_t(), il,
+ absl::forward<Args>(args)...);
+}
+
+// Relational operators [optional.relops]
+
+// Empty optionals are considered equal to each other and less than non-empty
+// optionals. Supports relations between optional<T> and optional<U>, between
+// optional<T> and U, and between optional<T> and nullopt.
+//
+// Note: We're careful to support T having non-bool relationals.
+
+// Requires: The expression, e.g. "*x == *y" shall be well-formed and its result
+// shall be convertible to bool.
+// The C++17 (N4606) "Returns:" statements are translated into
+// code in an obvious way here, and the original text retained as function docs.
+// Returns: If bool(x) != bool(y), false; otherwise if bool(x) == false, true;
+// otherwise *x == *y.
+template <typename T, typename U>
+constexpr auto operator==(const optional<T>& x, const optional<U>& y)
+ -> decltype(optional_internal::convertible_to_bool(*x == *y)) {
+ return static_cast<bool>(x) != static_cast<bool>(y)
+ ? false
+ : static_cast<bool>(x) == false ? true : *x == *y;
+}
+
+// Returns: If bool(x) != bool(y), true; otherwise, if bool(x) == false, false;
+// otherwise *x != *y.
+template <typename T, typename U>
+constexpr auto operator!=(const optional<T>& x, const optional<U>& y)
+ -> decltype(optional_internal::convertible_to_bool(*x != *y)) {
+ return static_cast<bool>(x) != static_cast<bool>(y)
+ ? true
+ : static_cast<bool>(x) == false ? false : *x != *y;
+}
+// Returns: If !y, false; otherwise, if !x, true; otherwise *x < *y.
+template <typename T, typename U>
+constexpr auto operator<(const optional<T>& x, const optional<U>& y)
+ -> decltype(optional_internal::convertible_to_bool(*x < *y)) {
+ return !y ? false : !x ? true : *x < *y;
+}
+// Returns: If !x, false; otherwise, if !y, true; otherwise *x > *y.
+template <typename T, typename U>
+constexpr auto operator>(const optional<T>& x, const optional<U>& y)
+ -> decltype(optional_internal::convertible_to_bool(*x > *y)) {
+ return !x ? false : !y ? true : *x > *y;
+}
+// Returns: If !x, true; otherwise, if !y, false; otherwise *x <= *y.
+template <typename T, typename U>
+constexpr auto operator<=(const optional<T>& x, const optional<U>& y)
+ -> decltype(optional_internal::convertible_to_bool(*x <= *y)) {
+ return !x ? true : !y ? false : *x <= *y;
+}
+// Returns: If !y, true; otherwise, if !x, false; otherwise *x >= *y.
+template <typename T, typename U>
+constexpr auto operator>=(const optional<T>& x, const optional<U>& y)
+ -> decltype(optional_internal::convertible_to_bool(*x >= *y)) {
+ return !y ? true : !x ? false : *x >= *y;
+}
+
+// Comparison with nullopt [optional.nullops]
+// The C++17 (N4606) "Returns:" statements are used directly here.
+template <typename T>
+constexpr bool operator==(const optional<T>& x, nullopt_t) noexcept {
+ return !x;
+}
+template <typename T>
+constexpr bool operator==(nullopt_t, const optional<T>& x) noexcept {
+ return !x;
+}
+template <typename T>
+constexpr bool operator!=(const optional<T>& x, nullopt_t) noexcept {
+ return static_cast<bool>(x);
+}
+template <typename T>
+constexpr bool operator!=(nullopt_t, const optional<T>& x) noexcept {
+ return static_cast<bool>(x);
+}
+template <typename T>
+constexpr bool operator<(const optional<T>&, nullopt_t) noexcept {
+ return false;
+}
+template <typename T>
+constexpr bool operator<(nullopt_t, const optional<T>& x) noexcept {
+ return static_cast<bool>(x);
+}
+template <typename T>
+constexpr bool operator<=(const optional<T>& x, nullopt_t) noexcept {
+ return !x;
+}
+template <typename T>
+constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept {
+ return true;
+}
+template <typename T>
+constexpr bool operator>(const optional<T>& x, nullopt_t) noexcept {
+ return static_cast<bool>(x);
+}
+template <typename T>
+constexpr bool operator>(nullopt_t, const optional<T>&) noexcept {
+ return false;
+}
+template <typename T>
+constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept {
+ return true;
+}
+template <typename T>
+constexpr bool operator>=(nullopt_t, const optional<T>& x) noexcept {
+ return !x;
+}
+
+// Comparison with T [optional.comp_with_t]
+
+// Requires: The expression, e.g. "*x == v" shall be well-formed and its result
+// shall be convertible to bool.
+// The C++17 (N4606) "Equivalent to:" statements are used directly here.
+template <typename T, typename U>
+constexpr auto operator==(const optional<T>& x, const U& v)
+ -> decltype(optional_internal::convertible_to_bool(*x == v)) {
+ return static_cast<bool>(x) ? *x == v : false;
+}
+template <typename T, typename U>
+constexpr auto operator==(const U& v, const optional<T>& x)
+ -> decltype(optional_internal::convertible_to_bool(v == *x)) {
+ return static_cast<bool>(x) ? v == *x : false;
+}
+template <typename T, typename U>
+constexpr auto operator!=(const optional<T>& x, const U& v)
+ -> decltype(optional_internal::convertible_to_bool(*x != v)) {
+ return static_cast<bool>(x) ? *x != v : true;
+}
+template <typename T, typename U>
+constexpr auto operator!=(const U& v, const optional<T>& x)
+ -> decltype(optional_internal::convertible_to_bool(v != *x)) {
+ return static_cast<bool>(x) ? v != *x : true;
+}
+template <typename T, typename U>
+constexpr auto operator<(const optional<T>& x, const U& v)
+ -> decltype(optional_internal::convertible_to_bool(*x < v)) {
+ return static_cast<bool>(x) ? *x < v : true;
+}
+template <typename T, typename U>
+constexpr auto operator<(const U& v, const optional<T>& x)
+ -> decltype(optional_internal::convertible_to_bool(v < *x)) {
+ return static_cast<bool>(x) ? v < *x : false;
+}
+template <typename T, typename U>
+constexpr auto operator<=(const optional<T>& x, const U& v)
+ -> decltype(optional_internal::convertible_to_bool(*x <= v)) {
+ return static_cast<bool>(x) ? *x <= v : true;
+}
+template <typename T, typename U>
+constexpr auto operator<=(const U& v, const optional<T>& x)
+ -> decltype(optional_internal::convertible_to_bool(v <= *x)) {
+ return static_cast<bool>(x) ? v <= *x : false;
+}
+template <typename T, typename U>
+constexpr auto operator>(const optional<T>& x, const U& v)
+ -> decltype(optional_internal::convertible_to_bool(*x > v)) {
+ return static_cast<bool>(x) ? *x > v : false;
+}
+template <typename T, typename U>
+constexpr auto operator>(const U& v, const optional<T>& x)
+ -> decltype(optional_internal::convertible_to_bool(v > *x)) {
+ return static_cast<bool>(x) ? v > *x : true;
+}
+template <typename T, typename U>
+constexpr auto operator>=(const optional<T>& x, const U& v)
+ -> decltype(optional_internal::convertible_to_bool(*x >= v)) {
+ return static_cast<bool>(x) ? *x >= v : false;
+}
+template <typename T, typename U>
+constexpr auto operator>=(const U& v, const optional<T>& x)
+ -> decltype(optional_internal::convertible_to_bool(v >= *x)) {
+ return static_cast<bool>(x) ? v >= *x : true;
+}
+
+} // namespace absl
+
+namespace std {
+
+// std::hash specialization for absl::optional.
+template <typename T>
+struct hash<absl::optional<T>> {
+ size_t operator()(const absl::optional<T>& opt) const {
+ if (opt) {
+ return hash<T>()(*opt);
+ } else {
+ return static_cast<size_t>(0x297814aaad196e6dULL);
+ }
+ }
+};
+
+} // namespace std
+
+#undef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+#undef ABSL_MSVC_CONSTEXPR_BUG_IN_UNION_LIKE_CLASS
+
+#endif // ABSL_HAVE_STD_OPTIONAL
+
+#endif // ABSL_TYPES_OPTIONAL_H_
diff --git a/absl/types/optional_test.cc b/absl/types/optional_test.cc
new file mode 100644
index 0000000..25b44b1
--- /dev/null
+++ b/absl/types/optional_test.cc
@@ -0,0 +1,1539 @@
+// 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/types/optional.h"
+
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/meta/type_traits.h"
+#include "absl/strings/string_view.h"
+
+namespace {
+
+std::string TypeQuals(std::string&) { return "&"; }
+std::string TypeQuals(std::string&&) { return "&&"; }
+std::string TypeQuals(const std::string&) { return "c&"; }
+std::string TypeQuals(const std::string&&) { return "c&&"; }
+
+struct StructorListener {
+ int construct0 = 0;
+ int construct1 = 0;
+ int construct2 = 0;
+ int listinit = 0;
+ int copy = 0;
+ int move = 0;
+ int copy_assign = 0;
+ int move_assign = 0;
+ int destruct = 0;
+ int volatile_copy = 0;
+ int volatile_move = 0;
+ int volatile_copy_assign = 0;
+ int volatile_move_assign = 0;
+};
+
+// Suppress MSVC warnings.
+// 4521: multiple copy constructors specified
+// 4522: multiple assignment operators specified
+// We wrote multiple of them to test that the correct overloads are selected.
+#ifdef _MSC_VER
+#pragma warning( push )
+#pragma warning( disable : 4521)
+#pragma warning( disable : 4522)
+#endif
+struct Listenable {
+ static StructorListener* listener;
+
+ Listenable() { ++listener->construct0; }
+ explicit Listenable(int /*unused*/) { ++listener->construct1; }
+ Listenable(int /*unused*/, int /*unused*/) { ++listener->construct2; }
+ Listenable(std::initializer_list<int> /*unused*/) { ++listener->listinit; }
+ Listenable(const Listenable& /*unused*/) { ++listener->copy; }
+ Listenable(const volatile Listenable& /*unused*/) {
+ ++listener->volatile_copy;
+ }
+ Listenable(volatile Listenable&& /*unused*/) { ++listener->volatile_move; }
+ Listenable(Listenable&& /*unused*/) { ++listener->move; }
+ Listenable& operator=(const Listenable& /*unused*/) {
+ ++listener->copy_assign;
+ return *this;
+ }
+ Listenable& operator=(Listenable&& /*unused*/) {
+ ++listener->move_assign;
+ return *this;
+ }
+ // use void return type instead of volatile T& to work around GCC warning
+ // when the assignment's returned reference is ignored.
+ void operator=(const volatile Listenable& /*unused*/) volatile {
+ ++listener->volatile_copy_assign;
+ }
+ void operator=(volatile Listenable&& /*unused*/) volatile {
+ ++listener->volatile_move_assign;
+ }
+ ~Listenable() { ++listener->destruct; }
+};
+#ifdef _MSC_VER
+#pragma warning( pop )
+#endif
+
+StructorListener* Listenable::listener = nullptr;
+
+// ABSL_HAVE_NO_CONSTEXPR_INITIALIZER_LIST is defined to 1 when the standard
+// library implementation doesn't marked initializer_list's default constructor
+// constexpr. The C++11 standard doesn't specify constexpr on it, but C++14
+// added it. However, libstdc++ 4.7 marked it constexpr.
+#if defined(_LIBCPP_VERSION) && \
+ (_LIBCPP_STD_VER <= 11 || defined(_LIBCPP_HAS_NO_CXX14_CONSTEXPR))
+#define ABSL_HAVE_NO_CONSTEXPR_INITIALIZER_LIST 1
+#endif
+
+struct ConstexprType {
+ enum CtorTypes {
+ kCtorDefault,
+ kCtorInt,
+ kCtorInitializerList,
+ kCtorConstChar
+ };
+ constexpr ConstexprType() : x(kCtorDefault) {}
+ constexpr explicit ConstexprType(int i) : x(kCtorInt) {}
+#ifndef ABSL_HAVE_NO_CONSTEXPR_INITIALIZER_LIST
+ constexpr ConstexprType(std::initializer_list<int> il)
+ : x(kCtorInitializerList) {}
+#endif
+ constexpr ConstexprType(const char*) // NOLINT(runtime/explicit)
+ : x(kCtorConstChar) {}
+ int x;
+};
+
+struct Copyable {
+ Copyable() {}
+ Copyable(const Copyable&) {}
+ Copyable& operator=(const Copyable&) { return *this; }
+};
+
+struct MoveableThrow {
+ MoveableThrow() {}
+ MoveableThrow(MoveableThrow&&) {}
+ MoveableThrow& operator=(MoveableThrow&&) { return *this; }
+};
+
+struct MoveableNoThrow {
+ MoveableNoThrow() {}
+ MoveableNoThrow(MoveableNoThrow&&) noexcept {}
+ MoveableNoThrow& operator=(MoveableNoThrow&&) noexcept { return *this; }
+};
+
+struct NonMovable {
+ NonMovable() {}
+ NonMovable(const NonMovable&) = delete;
+ NonMovable& operator=(const NonMovable&) = delete;
+ NonMovable(NonMovable&&) = delete;
+ NonMovable& operator=(NonMovable&&) = delete;
+};
+
+TEST(optionalTest, DefaultConstructor) {
+ absl::optional<int> empty;
+ EXPECT_FALSE(empty);
+ constexpr absl::optional<int> cempty;
+ static_assert(!cempty.has_value(), "");
+ EXPECT_TRUE(
+ std::is_nothrow_default_constructible<absl::optional<int>>::value);
+}
+
+TEST(optionalTest, nulloptConstructor) {
+ absl::optional<int> empty(absl::nullopt);
+ EXPECT_FALSE(empty);
+
+#ifdef ABSL_HAVE_STD_OPTIONAL
+ constexpr absl::optional<int> cempty{absl::nullopt};
+#else
+ // Creating a temporary absl::nullopt_t object instead of using absl::nullopt
+ // because absl::nullopt cannot be constexpr and have external linkage at the
+ // same time.
+ constexpr absl::optional<int> cempty{absl::nullopt_t(absl::nullopt_t::init)};
+#endif
+ static_assert(!cempty.has_value(), "");
+ EXPECT_TRUE((std::is_nothrow_constructible<absl::optional<int>,
+ absl::nullopt_t>::value));
+}
+
+TEST(optionalTest, CopyConstructor) {
+ {
+ absl::optional<int> empty, opt42 = 42;
+ absl::optional<int> empty_copy(empty);
+ EXPECT_FALSE(empty_copy);
+ absl::optional<int> opt42_copy(opt42);
+ EXPECT_TRUE(opt42_copy);
+ EXPECT_EQ(42, *opt42_copy);
+ }
+ {
+ absl::optional<const int> empty, opt42 = 42;
+ absl::optional<const int> empty_copy(empty);
+ EXPECT_FALSE(empty_copy);
+ absl::optional<const int> opt42_copy(opt42);
+ EXPECT_TRUE(opt42_copy);
+ EXPECT_EQ(42, *opt42_copy);
+ }
+ {
+ absl::optional<volatile int> empty, opt42 = 42;
+ absl::optional<volatile int> empty_copy(empty);
+ EXPECT_FALSE(empty_copy);
+ absl::optional<volatile int> opt42_copy(opt42);
+ EXPECT_TRUE(opt42_copy);
+ EXPECT_EQ(42, *opt42_copy);
+ }
+ // test copyablility
+ EXPECT_TRUE(std::is_copy_constructible<absl::optional<int>>::value);
+ EXPECT_TRUE(std::is_copy_constructible<absl::optional<Copyable>>::value);
+ EXPECT_FALSE(
+ std::is_copy_constructible<absl::optional<MoveableThrow>>::value);
+ EXPECT_FALSE(
+ std::is_copy_constructible<absl::optional<MoveableNoThrow>>::value);
+ EXPECT_FALSE(std::is_copy_constructible<absl::optional<NonMovable>>::value);
+
+ EXPECT_FALSE(
+ absl::is_trivially_copy_constructible<absl::optional<Copyable>>::value);
+#if defined(ABSL_HAVE_STD_OPTIONAL) && defined(__GLIBCXX__)
+ // libstdc++ std::optional implementation (as of 7.2) has a bug: when T is
+ // trivially copyable, optional<T> is not trivially copyable (due to one of
+ // its base class is unconditionally nontrivial).
+#define ABSL_GLIBCXX_OPTIONAL_TRIVIALITY_BUG 1
+#endif
+#ifndef ABSL_GLIBCXX_OPTIONAL_TRIVIALITY_BUG
+ EXPECT_TRUE(
+ absl::is_trivially_copy_constructible<absl::optional<int>>::value);
+ EXPECT_TRUE(
+ absl::is_trivially_copy_constructible<absl::optional<const int>>::value);
+#ifndef _MSC_VER
+ // See defect report "Trivial copy/move constructor for class with volatile
+ // member" at
+ // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2094
+ // A class with non-static data member of volatile-qualified type should still
+ // have a trivial copy constructor if the data member is trivial.
+ // Also a cv-qualified scalar type should be trivially copyable.
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<
+ absl::optional<volatile int>>::value);
+#endif // _MSC_VER
+#endif // ABSL_GLIBCXX_OPTIONAL_TRIVIALITY_BUG
+
+ // constexpr copy constructor for trivially copyable types
+ {
+ constexpr absl::optional<int> o1;
+ constexpr absl::optional<int> o2 = o1;
+ static_assert(!o2, "");
+ }
+ {
+ constexpr absl::optional<int> o1 = 42;
+ constexpr absl::optional<int> o2 = o1;
+ static_assert(o2, "");
+ static_assert(*o2 == 42, "");
+ }
+ {
+ struct TrivialCopyable {
+ constexpr TrivialCopyable() : x(0) {}
+ constexpr explicit TrivialCopyable(int i) : x(i) {}
+ int x;
+ };
+ constexpr absl::optional<TrivialCopyable> o1(42);
+ constexpr absl::optional<TrivialCopyable> o2 = o1;
+ static_assert(o2, "");
+ static_assert(o2->x == 42, "");
+#ifndef ABSL_GLIBCXX_OPTIONAL_TRIVIALITY_BUG
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<
+ absl::optional<TrivialCopyable>>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<
+ absl::optional<const TrivialCopyable>>::value);
+#endif
+ EXPECT_FALSE(std::is_copy_constructible<
+ absl::optional<volatile TrivialCopyable>>::value);
+ }
+}
+
+TEST(optionalTest, MoveConstructor) {
+ absl::optional<int> empty, opt42 = 42;
+ absl::optional<int> empty_move(std::move(empty));
+ EXPECT_FALSE(empty_move);
+ absl::optional<int> opt42_move(std::move(opt42));
+ EXPECT_TRUE(opt42_move);
+ EXPECT_EQ(42, opt42_move);
+ // test movability
+ EXPECT_TRUE(std::is_move_constructible<absl::optional<int>>::value);
+ EXPECT_TRUE(std::is_move_constructible<absl::optional<Copyable>>::value);
+ EXPECT_TRUE(std::is_move_constructible<absl::optional<MoveableThrow>>::value);
+ EXPECT_TRUE(
+ std::is_move_constructible<absl::optional<MoveableNoThrow>>::value);
+ EXPECT_FALSE(std::is_move_constructible<absl::optional<NonMovable>>::value);
+ // test noexcept
+ EXPECT_TRUE(std::is_nothrow_move_constructible<absl::optional<int>>::value);
+#ifndef ABSL_HAVE_STD_OPTIONAL
+ EXPECT_EQ(
+ absl::default_allocator_is_nothrow::value,
+ std::is_nothrow_move_constructible<absl::optional<MoveableThrow>>::value);
+#endif
+ EXPECT_TRUE(std::is_nothrow_move_constructible<
+ absl::optional<MoveableNoThrow>>::value);
+}
+
+TEST(optionalTest, Destructor) {
+ struct Trivial {};
+
+ struct NonTrivial {
+ NonTrivial(const NonTrivial&) {}
+ NonTrivial& operator=(const NonTrivial&) { return *this; }
+ ~NonTrivial() {}
+ };
+
+ EXPECT_TRUE(std::is_trivially_destructible<absl::optional<int>>::value);
+ EXPECT_TRUE(std::is_trivially_destructible<absl::optional<Trivial>>::value);
+ EXPECT_FALSE(
+ std::is_trivially_destructible<absl::optional<NonTrivial>>::value);
+}
+
+TEST(optionalTest, InPlaceConstructor) {
+ constexpr absl::optional<ConstexprType> opt0{absl::in_place_t()};
+ static_assert(opt0, "");
+ static_assert(opt0->x == ConstexprType::kCtorDefault, "");
+ constexpr absl::optional<ConstexprType> opt1{absl::in_place_t(), 1};
+ static_assert(opt1, "");
+ static_assert(opt1->x == ConstexprType::kCtorInt, "");
+#ifndef ABSL_HAVE_NO_CONSTEXPR_INITIALIZER_LIST
+ constexpr absl::optional<ConstexprType> opt2{absl::in_place_t(), {1, 2}};
+ static_assert(opt2, "");
+ static_assert(opt2->x == ConstexprType::kCtorInitializerList, "");
+#endif
+
+ // TODO(b/34201852): uncomment these when std::is_constructible<T, Args&&...>
+ // SFINAE is added to optional::optional(absl::in_place_t, Args&&...).
+ // struct I {
+ // I(absl::in_place_t);
+ // };
+
+ // EXPECT_FALSE((std::is_constructible<absl::optional<I>,
+ // absl::in_place_t>::value));
+ // EXPECT_FALSE((std::is_constructible<absl::optional<I>, const
+ // absl::in_place_t&>::value));
+}
+
+// template<U=T> optional(U&&);
+TEST(optionalTest, ValueConstructor) {
+ constexpr absl::optional<int> opt0(0);
+ static_assert(opt0, "");
+ static_assert(*opt0 == 0, "");
+ EXPECT_TRUE((std::is_convertible<int, absl::optional<int>>::value));
+ // Copy initialization ( = "abc") won't work due to optional(optional&&)
+ // is not constexpr. Use list initialization instead. This invokes
+ // absl::optional<ConstexprType>::absl::optional<U>(U&&), with U = const char
+ // (&) [4], which direct-initializes the ConstexprType value held by the
+ // optional via ConstexprType::ConstexprType(const char*).
+ constexpr absl::optional<ConstexprType> opt1 = {"abc"};
+ static_assert(opt1, "");
+ static_assert(ConstexprType::kCtorConstChar == opt1->x, "");
+ EXPECT_TRUE(
+ (std::is_convertible<const char*, absl::optional<ConstexprType>>::value));
+ // direct initialization
+ constexpr absl::optional<ConstexprType> opt2{2};
+ static_assert(opt2, "");
+ static_assert(ConstexprType::kCtorInt == opt2->x, "");
+ EXPECT_FALSE(
+ (std::is_convertible<int, absl::optional<ConstexprType>>::value));
+
+ // this invokes absl::optional<int>::optional(int&&)
+ // NOTE: this has different behavior than assignment, e.g.
+ // "opt3 = {};" clears the optional rather than setting the value to 0
+ // According to C++17 standard N4659 [over.ics.list] 16.3.3.1.5, (9.2)- "if
+ // the initializer list has no elements, the implicit conversion is the
+ // identity conversion", so `optional(int&&)` should be a better match than
+ // `optional(optional&&)` which is a user-defined conversion.
+ // Note: GCC 7 has a bug with this overload selection when compiled with
+ // `-std=c++17`.
+#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 7 && \
+ __cplusplus == 201703L
+#define ABSL_GCC7_OVER_ICS_LIST_BUG 1
+#endif
+#ifndef ABSL_GCC7_OVER_ICS_LIST_BUG
+ constexpr absl::optional<int> opt3({});
+ static_assert(opt3, "");
+ static_assert(*opt3 == 0, "");
+#endif
+
+ // this invokes the move constructor with a default constructed optional
+ // because non-template function is a better match than template function.
+ absl::optional<ConstexprType> opt4({});
+ EXPECT_FALSE(opt4);
+}
+
+struct Implicit {};
+
+struct Explicit {};
+
+struct Convert {
+ Convert(const Implicit&) // NOLINT(runtime/explicit)
+ : implicit(true), move(false) {}
+ Convert(Implicit&&) // NOLINT(runtime/explicit)
+ : implicit(true), move(true) {}
+ explicit Convert(const Explicit&) : implicit(false), move(false) {}
+ explicit Convert(Explicit&&) : implicit(false), move(true) {}
+
+ bool implicit;
+ bool move;
+};
+
+struct ConvertFromOptional {
+ ConvertFromOptional(const Implicit&) // NOLINT(runtime/explicit)
+ : implicit(true), move(false), from_optional(false) {}
+ ConvertFromOptional(Implicit&&) // NOLINT(runtime/explicit)
+ : implicit(true), move(true), from_optional(false) {}
+ ConvertFromOptional(
+ const absl::optional<Implicit>&) // NOLINT(runtime/explicit)
+ : implicit(true), move(false), from_optional(true) {}
+ ConvertFromOptional(absl::optional<Implicit>&&) // NOLINT(runtime/explicit)
+ : implicit(true), move(true), from_optional(true) {}
+ explicit ConvertFromOptional(const Explicit&)
+ : implicit(false), move(false), from_optional(false) {}
+ explicit ConvertFromOptional(Explicit&&)
+ : implicit(false), move(true), from_optional(false) {}
+ explicit ConvertFromOptional(const absl::optional<Explicit>&)
+ : implicit(false), move(false), from_optional(true) {}
+ explicit ConvertFromOptional(absl::optional<Explicit>&&)
+ : implicit(false), move(true), from_optional(true) {}
+
+ bool implicit;
+ bool move;
+ bool from_optional;
+};
+
+TEST(optionalTest, ConvertingConstructor) {
+ absl::optional<Implicit> i_empty;
+ absl::optional<Implicit> i(absl::in_place);
+ absl::optional<Explicit> e_empty;
+ absl::optional<Explicit> e(absl::in_place);
+ {
+ // implicitly constructing absl::optional<Convert> from
+ // absl::optional<Implicit>
+ absl::optional<Convert> empty = i_empty;
+ EXPECT_FALSE(empty);
+ absl::optional<Convert> opt_copy = i;
+ EXPECT_TRUE(opt_copy);
+ EXPECT_TRUE(opt_copy->implicit);
+ EXPECT_FALSE(opt_copy->move);
+ absl::optional<Convert> opt_move = absl::optional<Implicit>(absl::in_place);
+ EXPECT_TRUE(opt_move);
+ EXPECT_TRUE(opt_move->implicit);
+ EXPECT_TRUE(opt_move->move);
+ }
+ {
+ // explicitly constructing absl::optional<Convert> from
+ // absl::optional<Explicit>
+ absl::optional<Convert> empty(e_empty);
+ EXPECT_FALSE(empty);
+ absl::optional<Convert> opt_copy(e);
+ EXPECT_TRUE(opt_copy);
+ EXPECT_FALSE(opt_copy->implicit);
+ EXPECT_FALSE(opt_copy->move);
+ EXPECT_FALSE((std::is_convertible<const absl::optional<Explicit>&,
+ absl::optional<Convert>>::value));
+ absl::optional<Convert> opt_move{absl::optional<Explicit>(absl::in_place)};
+ EXPECT_TRUE(opt_move);
+ EXPECT_FALSE(opt_move->implicit);
+ EXPECT_TRUE(opt_move->move);
+ EXPECT_FALSE((std::is_convertible<absl::optional<Explicit>&&,
+ absl::optional<Convert>>::value));
+ }
+ {
+ // implicitly constructing absl::optional<ConvertFromOptional> from
+ // absl::optional<Implicit> via
+ // ConvertFromOptional(absl::optional<Implicit>&&) check that
+ // ConvertFromOptional(Implicit&&) is NOT called
+ static_assert(
+ std::is_convertible<absl::optional<Implicit>,
+ absl::optional<ConvertFromOptional>>::value,
+ "");
+ absl::optional<ConvertFromOptional> opt0 = i_empty;
+ EXPECT_TRUE(opt0);
+ EXPECT_TRUE(opt0->implicit);
+ EXPECT_FALSE(opt0->move);
+ EXPECT_TRUE(opt0->from_optional);
+ absl::optional<ConvertFromOptional> opt1 = absl::optional<Implicit>();
+ EXPECT_TRUE(opt1);
+ EXPECT_TRUE(opt1->implicit);
+ EXPECT_TRUE(opt1->move);
+ EXPECT_TRUE(opt1->from_optional);
+ }
+ {
+ // implicitly constructing absl::optional<ConvertFromOptional> from
+ // absl::optional<Explicit> via
+ // ConvertFromOptional(absl::optional<Explicit>&&) check that
+ // ConvertFromOptional(Explicit&&) is NOT called
+ absl::optional<ConvertFromOptional> opt0(e_empty);
+ EXPECT_TRUE(opt0);
+ EXPECT_FALSE(opt0->implicit);
+ EXPECT_FALSE(opt0->move);
+ EXPECT_TRUE(opt0->from_optional);
+ EXPECT_FALSE(
+ (std::is_convertible<const absl::optional<Explicit>&,
+ absl::optional<ConvertFromOptional>>::value));
+ absl::optional<ConvertFromOptional> opt1{absl::optional<Explicit>()};
+ EXPECT_TRUE(opt1);
+ EXPECT_FALSE(opt1->implicit);
+ EXPECT_TRUE(opt1->move);
+ EXPECT_TRUE(opt1->from_optional);
+ EXPECT_FALSE(
+ (std::is_convertible<absl::optional<Explicit>&&,
+ absl::optional<ConvertFromOptional>>::value));
+ }
+}
+
+TEST(optionalTest, StructorBasic) {
+ StructorListener listener;
+ Listenable::listener = &listener;
+ {
+ absl::optional<Listenable> empty;
+ EXPECT_FALSE(empty);
+ absl::optional<Listenable> opt0(absl::in_place);
+ EXPECT_TRUE(opt0);
+ absl::optional<Listenable> opt1(absl::in_place, 1);
+ EXPECT_TRUE(opt1);
+ absl::optional<Listenable> opt2(absl::in_place, 1, 2);
+ EXPECT_TRUE(opt2);
+ }
+ EXPECT_EQ(1, listener.construct0);
+ EXPECT_EQ(1, listener.construct1);
+ EXPECT_EQ(1, listener.construct2);
+ EXPECT_EQ(3, listener.destruct);
+}
+
+TEST(optionalTest, CopyMoveStructor) {
+ StructorListener listener;
+ Listenable::listener = &listener;
+ absl::optional<Listenable> original(absl::in_place);
+ EXPECT_EQ(1, listener.construct0);
+ EXPECT_EQ(0, listener.copy);
+ EXPECT_EQ(0, listener.move);
+ absl::optional<Listenable> copy(original);
+ EXPECT_EQ(1, listener.construct0);
+ EXPECT_EQ(1, listener.copy);
+ EXPECT_EQ(0, listener.move);
+ absl::optional<Listenable> move(std::move(original));
+ EXPECT_EQ(1, listener.construct0);
+ EXPECT_EQ(1, listener.copy);
+ EXPECT_EQ(1, listener.move);
+}
+
+TEST(optionalTest, ListInit) {
+ StructorListener listener;
+ Listenable::listener = &listener;
+ absl::optional<Listenable> listinit1(absl::in_place, {1});
+ absl::optional<Listenable> listinit2(absl::in_place, {1, 2});
+ EXPECT_EQ(2, listener.listinit);
+}
+
+TEST(optionalTest, AssignFromNullopt) {
+ absl::optional<int> opt(1);
+ opt = absl::nullopt;
+ EXPECT_FALSE(opt);
+
+ StructorListener listener;
+ Listenable::listener = &listener;
+ absl::optional<Listenable> opt1(absl::in_place);
+ opt1 = absl::nullopt;
+ EXPECT_FALSE(opt1);
+ EXPECT_EQ(1, listener.construct0);
+ EXPECT_EQ(1, listener.destruct);
+
+ EXPECT_TRUE((
+ std::is_nothrow_assignable<absl::optional<int>, absl::nullopt_t>::value));
+ EXPECT_TRUE((std::is_nothrow_assignable<absl::optional<Listenable>,
+ absl::nullopt_t>::value));
+}
+
+TEST(optionalTest, CopyAssignment) {
+ const absl::optional<int> empty, opt1 = 1, opt2 = 2;
+ absl::optional<int> empty_to_opt1, opt1_to_opt2, opt2_to_empty;
+
+ EXPECT_FALSE(empty_to_opt1);
+ empty_to_opt1 = empty;
+ EXPECT_FALSE(empty_to_opt1);
+ empty_to_opt1 = opt1;
+ EXPECT_TRUE(empty_to_opt1);
+ EXPECT_EQ(1, empty_to_opt1.value());
+
+ EXPECT_FALSE(opt1_to_opt2);
+ opt1_to_opt2 = opt1;
+ EXPECT_TRUE(opt1_to_opt2);
+ EXPECT_EQ(1, opt1_to_opt2.value());
+ opt1_to_opt2 = opt2;
+ EXPECT_TRUE(opt1_to_opt2);
+ EXPECT_EQ(2, opt1_to_opt2.value());
+
+ EXPECT_FALSE(opt2_to_empty);
+ opt2_to_empty = opt2;
+ EXPECT_TRUE(opt2_to_empty);
+ EXPECT_EQ(2, opt2_to_empty.value());
+ opt2_to_empty = empty;
+ EXPECT_FALSE(opt2_to_empty);
+
+ EXPECT_FALSE(std::is_copy_assignable<absl::optional<const int>>::value);
+ EXPECT_TRUE(std::is_copy_assignable<absl::optional<Copyable>>::value);
+ EXPECT_FALSE(std::is_copy_assignable<absl::optional<MoveableThrow>>::value);
+ EXPECT_FALSE(std::is_copy_assignable<absl::optional<MoveableNoThrow>>::value);
+ EXPECT_FALSE(std::is_copy_assignable<absl::optional<NonMovable>>::value);
+
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<int>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<volatile int>::value);
+
+ struct Trivial {
+ int i;
+ };
+ struct NonTrivial {
+ NonTrivial& operator=(const NonTrivial&) { return *this; }
+ int i;
+ };
+
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<Trivial>::value);
+ EXPECT_FALSE(std::is_copy_assignable<const Trivial>::value);
+ EXPECT_FALSE(std::is_copy_assignable<volatile Trivial>::value);
+ EXPECT_TRUE(std::is_copy_assignable<NonTrivial>::value);
+ EXPECT_FALSE(absl::is_trivially_copy_assignable<NonTrivial>::value);
+
+ // std::optional doesn't support volatile nontrivial types.
+#ifndef ABSL_HAVE_STD_OPTIONAL
+ {
+ StructorListener listener;
+ Listenable::listener = &listener;
+
+ absl::optional<volatile Listenable> empty, set(absl::in_place);
+ EXPECT_EQ(1, listener.construct0);
+ absl::optional<volatile Listenable> empty_to_empty, empty_to_set,
+ set_to_empty(absl::in_place), set_to_set(absl::in_place);
+ EXPECT_EQ(3, listener.construct0);
+ empty_to_empty = empty; // no effect
+ empty_to_set = set; // copy construct
+ set_to_empty = empty; // destruct
+ set_to_set = set; // copy assign
+ EXPECT_EQ(1, listener.volatile_copy);
+ EXPECT_EQ(0, listener.volatile_move);
+ EXPECT_EQ(1, listener.destruct);
+ EXPECT_EQ(1, listener.volatile_copy_assign);
+ }
+#endif // ABSL_HAVE_STD_OPTIONAL
+}
+
+TEST(optionalTest, MoveAssignment) {
+ {
+ StructorListener listener;
+ Listenable::listener = &listener;
+
+ absl::optional<Listenable> empty1, empty2, set1(absl::in_place),
+ set2(absl::in_place);
+ EXPECT_EQ(2, listener.construct0);
+ absl::optional<Listenable> empty_to_empty, empty_to_set,
+ set_to_empty(absl::in_place), set_to_set(absl::in_place);
+ EXPECT_EQ(4, listener.construct0);
+ empty_to_empty = std::move(empty1);
+ empty_to_set = std::move(set1);
+ set_to_empty = std::move(empty2);
+ set_to_set = std::move(set2);
+ EXPECT_EQ(0, listener.copy);
+ EXPECT_EQ(1, listener.move);
+ EXPECT_EQ(1, listener.destruct);
+ EXPECT_EQ(1, listener.move_assign);
+ }
+ // std::optional doesn't support volatile nontrivial types.
+#ifndef ABSL_HAVE_STD_OPTIONAL
+ {
+ StructorListener listener;
+ Listenable::listener = &listener;
+
+ absl::optional<volatile Listenable> empty1, empty2, set1(absl::in_place),
+ set2(absl::in_place);
+ EXPECT_EQ(2, listener.construct0);
+ absl::optional<volatile Listenable> empty_to_empty, empty_to_set,
+ set_to_empty(absl::in_place), set_to_set(absl::in_place);
+ EXPECT_EQ(4, listener.construct0);
+ empty_to_empty = std::move(empty1); // no effect
+ empty_to_set = std::move(set1); // move construct
+ set_to_empty = std::move(empty2); // destruct
+ set_to_set = std::move(set2); // move assign
+ EXPECT_EQ(0, listener.volatile_copy);
+ EXPECT_EQ(1, listener.volatile_move);
+ EXPECT_EQ(1, listener.destruct);
+ EXPECT_EQ(1, listener.volatile_move_assign);
+ }
+#endif // ABSL_HAVE_STD_OPTIONAL
+ EXPECT_FALSE(std::is_move_assignable<absl::optional<const int>>::value);
+ EXPECT_TRUE(std::is_move_assignable<absl::optional<Copyable>>::value);
+ EXPECT_TRUE(std::is_move_assignable<absl::optional<MoveableThrow>>::value);
+ EXPECT_TRUE(std::is_move_assignable<absl::optional<MoveableNoThrow>>::value);
+ EXPECT_FALSE(std::is_move_assignable<absl::optional<NonMovable>>::value);
+
+ EXPECT_FALSE(
+ std::is_nothrow_move_assignable<absl::optional<MoveableThrow>>::value);
+ EXPECT_TRUE(
+ std::is_nothrow_move_assignable<absl::optional<MoveableNoThrow>>::value);
+}
+
+struct NoConvertToOptional {
+ // disable implicit conversion from const NoConvertToOptional&
+ // to absl::optional<NoConvertToOptional>.
+ NoConvertToOptional(const NoConvertToOptional&) = delete;
+};
+
+struct CopyConvert {
+ CopyConvert(const NoConvertToOptional&);
+ CopyConvert& operator=(const CopyConvert&) = delete;
+ CopyConvert& operator=(const NoConvertToOptional&);
+};
+
+struct CopyConvertFromOptional {
+ CopyConvertFromOptional(const NoConvertToOptional&);
+ CopyConvertFromOptional(const absl::optional<NoConvertToOptional>&);
+ CopyConvertFromOptional& operator=(const CopyConvertFromOptional&) = delete;
+ CopyConvertFromOptional& operator=(const NoConvertToOptional&);
+ CopyConvertFromOptional& operator=(
+ const absl::optional<NoConvertToOptional>&);
+};
+
+struct MoveConvert {
+ MoveConvert(NoConvertToOptional&&);
+ MoveConvert& operator=(const MoveConvert&) = delete;
+ MoveConvert& operator=(NoConvertToOptional&&);
+};
+
+struct MoveConvertFromOptional {
+ MoveConvertFromOptional(NoConvertToOptional&&);
+ MoveConvertFromOptional(absl::optional<NoConvertToOptional>&&);
+ MoveConvertFromOptional& operator=(const MoveConvertFromOptional&) = delete;
+ MoveConvertFromOptional& operator=(NoConvertToOptional&&);
+ MoveConvertFromOptional& operator=(absl::optional<NoConvertToOptional>&&);
+};
+
+// template <typename U = T> absl::optional<T>& operator=(U&& v);
+TEST(optionalTest, ValueAssignment) {
+ absl::optional<int> opt;
+ EXPECT_FALSE(opt);
+ opt = 42;
+ EXPECT_TRUE(opt);
+ EXPECT_EQ(42, opt.value());
+ opt = absl::nullopt;
+ EXPECT_FALSE(opt);
+ opt = 42;
+ EXPECT_TRUE(opt);
+ EXPECT_EQ(42, opt.value());
+ opt = 43;
+ EXPECT_TRUE(opt);
+ EXPECT_EQ(43, opt.value());
+ opt = {}; // this should clear optional
+ EXPECT_FALSE(opt);
+
+ opt = {44};
+ EXPECT_TRUE(opt);
+ EXPECT_EQ(44, opt.value());
+
+ // U = const NoConvertToOptional&
+ EXPECT_TRUE((std::is_assignable<absl::optional<CopyConvert>&,
+ const NoConvertToOptional&>::value));
+ // U = const absl::optional<NoConvertToOptional>&
+ EXPECT_TRUE((std::is_assignable<absl::optional<CopyConvertFromOptional>&,
+ const NoConvertToOptional&>::value));
+ // U = const NoConvertToOptional& triggers SFINAE because
+ // std::is_constructible_v<MoveConvert, const NoConvertToOptional&> is false
+ EXPECT_FALSE((std::is_assignable<absl::optional<MoveConvert>&,
+ const NoConvertToOptional&>::value));
+ // U = NoConvertToOptional
+ EXPECT_TRUE((std::is_assignable<absl::optional<MoveConvert>&,
+ NoConvertToOptional&&>::value));
+ // U = const NoConvertToOptional& triggers SFINAE because
+ // std::is_constructible_v<MoveConvertFromOptional, const
+ // NoConvertToOptional&> is false
+ EXPECT_FALSE((std::is_assignable<absl::optional<MoveConvertFromOptional>&,
+ const NoConvertToOptional&>::value));
+ // U = NoConvertToOptional
+ EXPECT_TRUE((std::is_assignable<absl::optional<MoveConvertFromOptional>&,
+ NoConvertToOptional&&>::value));
+ // U = const absl::optional<NoConvertToOptional>&
+ EXPECT_TRUE(
+ (std::is_assignable<absl::optional<CopyConvertFromOptional>&,
+ const absl::optional<NoConvertToOptional>&>::value));
+ // U = absl::optional<NoConvertToOptional>
+ EXPECT_TRUE(
+ (std::is_assignable<absl::optional<MoveConvertFromOptional>&,
+ absl::optional<NoConvertToOptional>&&>::value));
+}
+
+// template <typename U> absl::optional<T>& operator=(const absl::optional<U>&
+// rhs); template <typename U> absl::optional<T>& operator=(absl::optional<U>&&
+// rhs);
+TEST(optionalTest, ConvertingAssignment) {
+ absl::optional<int> opt_i;
+ absl::optional<char> opt_c('c');
+ opt_i = opt_c;
+ EXPECT_TRUE(opt_i);
+ EXPECT_EQ(*opt_c, *opt_i);
+ opt_i = absl::optional<char>();
+ EXPECT_FALSE(opt_i);
+ opt_i = absl::optional<char>('d');
+ EXPECT_TRUE(opt_i);
+ EXPECT_EQ('d', *opt_i);
+
+ absl::optional<std::string> opt_str;
+ absl::optional<const char*> opt_cstr("abc");
+ opt_str = opt_cstr;
+ EXPECT_TRUE(opt_str);
+ EXPECT_EQ(std::string("abc"), *opt_str);
+ opt_str = absl::optional<const char*>();
+ EXPECT_FALSE(opt_str);
+ opt_str = absl::optional<const char*>("def");
+ EXPECT_TRUE(opt_str);
+ EXPECT_EQ(std::string("def"), *opt_str);
+
+ // operator=(const absl::optional<U>&) with U = NoConvertToOptional
+ EXPECT_TRUE(
+ (std::is_assignable<absl::optional<CopyConvert>,
+ const absl::optional<NoConvertToOptional>&>::value));
+ // operator=(const absl::optional<U>&) with U = NoConvertToOptional
+ // triggers SFINAE because
+ // std::is_constructible_v<MoveConvert, const NoConvertToOptional&> is false
+ EXPECT_FALSE(
+ (std::is_assignable<absl::optional<MoveConvert>&,
+ const absl::optional<NoConvertToOptional>&>::value));
+ // operator=(absl::optional<U>&&) with U = NoConvertToOptional
+ EXPECT_TRUE(
+ (std::is_assignable<absl::optional<MoveConvert>&,
+ absl::optional<NoConvertToOptional>&&>::value));
+ // operator=(const absl::optional<U>&) with U = NoConvertToOptional triggers
+ // SFINAE because std::is_constructible_v<MoveConvertFromOptional, const
+ // NoConvertToOptional&> is false. operator=(U&&) with U = const
+ // absl::optional<NoConverToOptional>& triggers SFINAE because
+ // std::is_constructible<MoveConvertFromOptional,
+ // absl::optional<NoConvertToOptional>&&> is true.
+ EXPECT_FALSE(
+ (std::is_assignable<absl::optional<MoveConvertFromOptional>&,
+ const absl::optional<NoConvertToOptional>&>::value));
+}
+
+TEST(optionalTest, ResetAndHasValue) {
+ StructorListener listener;
+ Listenable::listener = &listener;
+ absl::optional<Listenable> opt;
+ EXPECT_FALSE(opt);
+ EXPECT_FALSE(opt.has_value());
+ opt.emplace();
+ EXPECT_TRUE(opt);
+ EXPECT_TRUE(opt.has_value());
+ opt.reset();
+ EXPECT_FALSE(opt);
+ EXPECT_FALSE(opt.has_value());
+ EXPECT_EQ(1, listener.destruct);
+ opt.reset();
+ EXPECT_FALSE(opt);
+ EXPECT_FALSE(opt.has_value());
+
+ constexpr absl::optional<int> empty;
+ static_assert(!empty.has_value(), "");
+ constexpr absl::optional<int> nonempty(1);
+ static_assert(nonempty.has_value(), "");
+}
+
+TEST(optionalTest, Emplace) {
+ StructorListener listener;
+ Listenable::listener = &listener;
+ absl::optional<Listenable> opt;
+ EXPECT_FALSE(opt);
+ opt.emplace(1);
+ EXPECT_TRUE(opt);
+ opt.emplace(1, 2);
+ EXPECT_EQ(1, listener.construct1);
+ EXPECT_EQ(1, listener.construct2);
+ EXPECT_EQ(1, listener.destruct);
+
+ absl::optional<std::string> o;
+ EXPECT_TRUE((std::is_same<std::string&, decltype(o.emplace("abc"))>::value));
+ std::string& ref = o.emplace("abc");
+ EXPECT_EQ(&ref, &o.value());
+}
+
+TEST(optionalTest, ListEmplace) {
+ StructorListener listener;
+ Listenable::listener = &listener;
+ absl::optional<Listenable> opt;
+ EXPECT_FALSE(opt);
+ opt.emplace({1});
+ EXPECT_TRUE(opt);
+ opt.emplace({1, 2});
+ EXPECT_EQ(2, listener.listinit);
+ EXPECT_EQ(1, listener.destruct);
+
+ absl::optional<Listenable> o;
+ EXPECT_TRUE((std::is_same<Listenable&, decltype(o.emplace({1}))>::value));
+ Listenable& ref = o.emplace({1});
+ EXPECT_EQ(&ref, &o.value());
+}
+
+TEST(optionalTest, Swap) {
+ absl::optional<int> opt_empty, opt1 = 1, opt2 = 2;
+ EXPECT_FALSE(opt_empty);
+ EXPECT_TRUE(opt1);
+ EXPECT_EQ(1, opt1.value());
+ EXPECT_TRUE(opt2);
+ EXPECT_EQ(2, opt2.value());
+ swap(opt_empty, opt1);
+ EXPECT_FALSE(opt1);
+ EXPECT_TRUE(opt_empty);
+ EXPECT_EQ(1, opt_empty.value());
+ EXPECT_TRUE(opt2);
+ EXPECT_EQ(2, opt2.value());
+ swap(opt_empty, opt1);
+ EXPECT_FALSE(opt_empty);
+ EXPECT_TRUE(opt1);
+ EXPECT_EQ(1, opt1.value());
+ EXPECT_TRUE(opt2);
+ EXPECT_EQ(2, opt2.value());
+ swap(opt1, opt2);
+ EXPECT_FALSE(opt_empty);
+ EXPECT_TRUE(opt1);
+ EXPECT_EQ(2, opt1.value());
+ EXPECT_TRUE(opt2);
+ EXPECT_EQ(1, opt2.value());
+
+ EXPECT_TRUE(noexcept(opt1.swap(opt2)));
+ EXPECT_TRUE(noexcept(swap(opt1, opt2)));
+}
+
+TEST(optionalTest, PointerStuff) {
+ absl::optional<std::string> opt(absl::in_place, "foo");
+ EXPECT_EQ("foo", *opt);
+ const auto& opt_const = opt;
+ EXPECT_EQ("foo", *opt_const);
+ EXPECT_EQ(opt->size(), 3);
+ EXPECT_EQ(opt_const->size(), 3);
+
+ constexpr absl::optional<ConstexprType> opt1(1);
+ static_assert(opt1->x == ConstexprType::kCtorInt, "");
+}
+
+// gcc has a bug pre 4.9.1 where it doesn't do correct overload resolution
+// when overloads are const-qualified and *this is an raluve.
+// Skip that test to make the build green again when using the old compiler.
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59296 is fixed in 4.9.1.
+#if defined(__GNUC__) && !defined(__clang__)
+#define GCC_VERSION (__GNUC__ * 10000 \
+ + __GNUC_MINOR__ * 100 \
+ + __GNUC_PATCHLEVEL__)
+#if GCC_VERSION < 40901
+#define ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG
+#endif
+#endif
+
+// MSVC has a bug with "cv-qualifiers in class construction", fixed in 2017. See
+// https://docs.microsoft.com/en-us/cpp/cpp-conformance-improvements-2017#bug-fixes
+// The compiler some incorrectly ingores the cv-qualifier when generating a
+// class object via a constructor call. For example:
+//
+// class optional {
+// constexpr T&& value() &&;
+// constexpr const T&& value() const &&;
+// }
+//
+// using COI = const absl::optional<int>;
+// static_assert(2 == COI(2).value(), ""); // const &&
+//
+// This should invoke the "const &&" overload but since it ignores the const
+// qualifier it finds the "&&" overload the best candidate.
+#if defined(_MSC_VER) && _MSC_VER < 1910
+#define ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG
+#endif
+
+TEST(optionalTest, Value) {
+ using O = absl::optional<std::string>;
+ using CO = const absl::optional<std::string>;
+ using OC = absl::optional<const std::string>;
+ O lvalue(absl::in_place, "lvalue");
+ CO clvalue(absl::in_place, "clvalue");
+ OC lvalue_c(absl::in_place, "lvalue_c");
+ EXPECT_EQ("lvalue", lvalue.value());
+ EXPECT_EQ("clvalue", clvalue.value());
+ EXPECT_EQ("lvalue_c", lvalue_c.value());
+ EXPECT_EQ("xvalue", O(absl::in_place, "xvalue").value());
+ EXPECT_EQ("xvalue_c", OC(absl::in_place, "xvalue_c").value());
+#ifndef ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG
+ EXPECT_EQ("cxvalue", CO(absl::in_place, "cxvalue").value());
+#endif
+ EXPECT_EQ("&", TypeQuals(lvalue.value()));
+ EXPECT_EQ("c&", TypeQuals(clvalue.value()));
+ EXPECT_EQ("c&", TypeQuals(lvalue_c.value()));
+ EXPECT_EQ("&&", TypeQuals(O(absl::in_place, "xvalue").value()));
+#if !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG) && \
+ !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG)
+ EXPECT_EQ("c&&", TypeQuals(CO(absl::in_place, "cxvalue").value()));
+#endif
+ EXPECT_EQ("c&&", TypeQuals(OC(absl::in_place, "xvalue_c").value()));
+
+ // test on volatile type
+ using OV = absl::optional<volatile int>;
+ OV lvalue_v(absl::in_place, 42);
+ EXPECT_EQ(42, lvalue_v.value());
+ EXPECT_EQ(42, OV(42).value());
+ EXPECT_TRUE((std::is_same<volatile int&, decltype(lvalue_v.value())>::value));
+ EXPECT_TRUE((std::is_same<volatile int&&, decltype(OV(42).value())>::value));
+
+ // test exception throw on value()
+ absl::optional<int> empty;
+#ifdef ABSL_HAVE_EXCEPTIONS
+ EXPECT_THROW(empty.value(), absl::bad_optional_access);
+#else
+ EXPECT_DEATH(empty.value(), "Bad optional access");
+#endif
+
+ // test constexpr value()
+ constexpr absl::optional<int> o1(1);
+ static_assert(1 == o1.value(), ""); // const &
+#if !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG) && \
+ !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG)
+ using COI = const absl::optional<int>;
+ static_assert(2 == COI(2).value(), ""); // const &&
+#endif
+}
+
+TEST(optionalTest, DerefOperator) {
+ using O = absl::optional<std::string>;
+ using CO = const absl::optional<std::string>;
+ using OC = absl::optional<const std::string>;
+ O lvalue(absl::in_place, "lvalue");
+ CO clvalue(absl::in_place, "clvalue");
+ OC lvalue_c(absl::in_place, "lvalue_c");
+ EXPECT_EQ("lvalue", *lvalue);
+ EXPECT_EQ("clvalue", *clvalue);
+ EXPECT_EQ("lvalue_c", *lvalue_c);
+ EXPECT_EQ("xvalue", *O(absl::in_place, "xvalue"));
+ EXPECT_EQ("xvalue_c", *OC(absl::in_place, "xvalue_c"));
+#ifndef ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG
+ EXPECT_EQ("cxvalue", *CO(absl::in_place, "cxvalue"));
+#endif
+ EXPECT_EQ("&", TypeQuals(*lvalue));
+ EXPECT_EQ("c&", TypeQuals(*clvalue));
+ EXPECT_EQ("&&", TypeQuals(*O(absl::in_place, "xvalue")));
+#if !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG) && \
+ !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG)
+ EXPECT_EQ("c&&", TypeQuals(*CO(absl::in_place, "cxvalue")));
+#endif
+ EXPECT_EQ("c&&", TypeQuals(*OC(absl::in_place, "xvalue_c")));
+
+ // test on volatile type
+ using OV = absl::optional<volatile int>;
+ OV lvalue_v(absl::in_place, 42);
+ EXPECT_EQ(42, *lvalue_v);
+ EXPECT_EQ(42, *OV(42));
+ EXPECT_TRUE((std::is_same<volatile int&, decltype(*lvalue_v)>::value));
+ EXPECT_TRUE((std::is_same<volatile int&&, decltype(*OV(42))>::value));
+
+ constexpr absl::optional<int> opt1(1);
+ static_assert(*opt1 == 1, "");
+#if !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG) && \
+ !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG)
+ using COI = const absl::optional<int>;
+ static_assert(*COI(2) == 2, "");
+#endif
+}
+
+TEST(optionalTest, ValueOr) {
+ absl::optional<double> opt_empty, opt_set = 1.2;
+ EXPECT_EQ(42.0, opt_empty.value_or(42));
+ EXPECT_EQ(1.2, opt_set.value_or(42));
+ EXPECT_EQ(42.0, absl::optional<double>().value_or(42));
+ EXPECT_EQ(1.2, absl::optional<double>(1.2).value_or(42));
+
+ constexpr absl::optional<double> copt_empty, copt_set = {1.2};
+ static_assert(42.0 == copt_empty.value_or(42), "");
+ static_assert(1.2 == copt_set.value_or(42), "");
+#ifndef ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG
+ using COD = const absl::optional<double>;
+ static_assert(42.0 == COD().value_or(42), "");
+ static_assert(1.2 == COD(1.2).value_or(42), "");
+#endif
+}
+
+// make_optional cannot be constexpr until C++17
+TEST(optionalTest, make_optional) {
+ auto opt_int = absl::make_optional(42);
+ EXPECT_TRUE((std::is_same<decltype(opt_int), absl::optional<int>>::value));
+ EXPECT_EQ(42, opt_int);
+
+ StructorListener listener;
+ Listenable::listener = &listener;
+
+ absl::optional<Listenable> opt0 = absl::make_optional<Listenable>();
+ EXPECT_EQ(1, listener.construct0);
+ absl::optional<Listenable> opt1 = absl::make_optional<Listenable>(1);
+ EXPECT_EQ(1, listener.construct1);
+ absl::optional<Listenable> opt2 = absl::make_optional<Listenable>(1, 2);
+ EXPECT_EQ(1, listener.construct2);
+ absl::optional<Listenable> opt3 = absl::make_optional<Listenable>({1});
+ absl::optional<Listenable> opt4 = absl::make_optional<Listenable>({1, 2});
+ EXPECT_EQ(2, listener.listinit);
+
+ // Constexpr tests on trivially copyable types
+ // optional<T> has trivial copy/move ctors when T is trivially copyable.
+ // For nontrivial types with constexpr constructors, we need copy elision in
+ // C++17 for make_optional to be constexpr.
+ {
+ constexpr absl::optional<int> c_opt = absl::make_optional(42);
+ static_assert(c_opt.value() == 42, "");
+ }
+ {
+ struct TrivialCopyable {
+ constexpr TrivialCopyable() : x(0) {}
+ constexpr explicit TrivialCopyable(int i) : x(i) {}
+ int x;
+ };
+
+ constexpr TrivialCopyable v;
+ constexpr absl::optional<TrivialCopyable> c_opt0 = absl::make_optional(v);
+ static_assert(c_opt0->x == 0, "");
+ constexpr absl::optional<TrivialCopyable> c_opt1 =
+ absl::make_optional<TrivialCopyable>();
+ static_assert(c_opt1->x == 0, "");
+ constexpr absl::optional<TrivialCopyable> c_opt2 =
+ absl::make_optional<TrivialCopyable>(42);
+ static_assert(c_opt2->x == 42, "");
+ }
+}
+
+template <typename T, typename U>
+void optionalTest_Comparisons_EXPECT_LESS(T x, U y) {
+ EXPECT_FALSE(x == y);
+ EXPECT_TRUE(x != y);
+ EXPECT_TRUE(x < y);
+ EXPECT_FALSE(x > y);
+ EXPECT_TRUE(x <= y);
+ EXPECT_FALSE(x >= y);
+}
+
+template <typename T, typename U>
+void optionalTest_Comparisons_EXPECT_SAME(T x, U y) {
+ EXPECT_TRUE(x == y);
+ EXPECT_FALSE(x != y);
+ EXPECT_FALSE(x < y);
+ EXPECT_FALSE(x > y);
+ EXPECT_TRUE(x <= y);
+ EXPECT_TRUE(x >= y);
+}
+
+template <typename T, typename U>
+void optionalTest_Comparisons_EXPECT_GREATER(T x, U y) {
+ EXPECT_FALSE(x == y);
+ EXPECT_TRUE(x != y);
+ EXPECT_FALSE(x < y);
+ EXPECT_TRUE(x > y);
+ EXPECT_FALSE(x <= y);
+ EXPECT_TRUE(x >= y);
+}
+
+
+template <typename T, typename U, typename V>
+void TestComparisons() {
+ absl::optional<T> ae, a2{2}, a4{4};
+ absl::optional<U> be, b2{2}, b4{4};
+ V v3 = 3;
+
+ // LHS: absl::nullopt, ae, a2, v3, a4
+ // RHS: absl::nullopt, be, b2, v3, b4
+
+ // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(absl::nullopt,absl::nullopt);
+ optionalTest_Comparisons_EXPECT_SAME(absl::nullopt, be);
+ optionalTest_Comparisons_EXPECT_LESS(absl::nullopt, b2);
+ // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(absl::nullopt,v3);
+ optionalTest_Comparisons_EXPECT_LESS(absl::nullopt, b4);
+
+ optionalTest_Comparisons_EXPECT_SAME(ae, absl::nullopt);
+ optionalTest_Comparisons_EXPECT_SAME(ae, be);
+ optionalTest_Comparisons_EXPECT_LESS(ae, b2);
+ optionalTest_Comparisons_EXPECT_LESS(ae, v3);
+ optionalTest_Comparisons_EXPECT_LESS(ae, b4);
+
+ optionalTest_Comparisons_EXPECT_GREATER(a2, absl::nullopt);
+ optionalTest_Comparisons_EXPECT_GREATER(a2, be);
+ optionalTest_Comparisons_EXPECT_SAME(a2, b2);
+ optionalTest_Comparisons_EXPECT_LESS(a2, v3);
+ optionalTest_Comparisons_EXPECT_LESS(a2, b4);
+
+ // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(v3,absl::nullopt);
+ optionalTest_Comparisons_EXPECT_GREATER(v3, be);
+ optionalTest_Comparisons_EXPECT_GREATER(v3, b2);
+ optionalTest_Comparisons_EXPECT_SAME(v3, v3);
+ optionalTest_Comparisons_EXPECT_LESS(v3, b4);
+
+ optionalTest_Comparisons_EXPECT_GREATER(a4, absl::nullopt);
+ optionalTest_Comparisons_EXPECT_GREATER(a4, be);
+ optionalTest_Comparisons_EXPECT_GREATER(a4, b2);
+ optionalTest_Comparisons_EXPECT_GREATER(a4, v3);
+ optionalTest_Comparisons_EXPECT_SAME(a4, b4);
+}
+
+struct Int1 {
+ Int1() = default;
+ Int1(int i) : i(i) {} // NOLINT(runtime/explicit)
+ int i;
+};
+
+struct Int2 {
+ Int2() = default;
+ Int2(int i) : i(i) {} // NOLINT(runtime/explicit)
+ int i;
+};
+
+// comparison between Int1 and Int2
+constexpr bool operator==(const Int1& lhs, const Int2& rhs) {
+ return lhs.i == rhs.i;
+}
+constexpr bool operator!=(const Int1& lhs, const Int2& rhs) {
+ return !(lhs == rhs);
+}
+constexpr bool operator<(const Int1& lhs, const Int2& rhs) {
+ return lhs.i < rhs.i;
+}
+constexpr bool operator<=(const Int1& lhs, const Int2& rhs) {
+ return lhs < rhs || lhs == rhs;
+}
+constexpr bool operator>(const Int1& lhs, const Int2& rhs) {
+ return !(lhs <= rhs);
+}
+constexpr bool operator>=(const Int1& lhs, const Int2& rhs) {
+ return !(lhs < rhs);
+}
+
+TEST(optionalTest, Comparisons) {
+ TestComparisons<int, int, int>();
+ TestComparisons<const int, int, int>();
+ TestComparisons<Int1, int, int>();
+ TestComparisons<int, Int2, int>();
+ TestComparisons<Int1, Int2, int>();
+
+ // compare absl::optional<std::string> with const char*
+ absl::optional<std::string> opt_str = "abc";
+ const char* cstr = "abc";
+ EXPECT_TRUE(opt_str == cstr);
+ // compare absl::optional<std::string> with absl::optional<const char*>
+ absl::optional<const char*> opt_cstr = cstr;
+ EXPECT_TRUE(opt_str == opt_cstr);
+ // compare absl::optional<std::string> with absl::optional<absl::string_view>
+ absl::optional<absl::string_view> e1;
+ absl::optional<std::string> e2;
+ EXPECT_TRUE(e1 == e2);
+}
+
+
+TEST(optionalTest, SwapRegression) {
+ StructorListener listener;
+ Listenable::listener = &listener;
+
+ {
+ absl::optional<Listenable> a;
+ absl::optional<Listenable> b(absl::in_place);
+ a.swap(b);
+ }
+
+ EXPECT_EQ(1, listener.construct0);
+ EXPECT_EQ(1, listener.move);
+ EXPECT_EQ(2, listener.destruct);
+
+ {
+ absl::optional<Listenable> a(absl::in_place);
+ absl::optional<Listenable> b;
+ a.swap(b);
+ }
+
+ EXPECT_EQ(2, listener.construct0);
+ EXPECT_EQ(2, listener.move);
+ EXPECT_EQ(4, listener.destruct);
+}
+
+TEST(optionalTest, BigStringLeakCheck) {
+ constexpr size_t n = 1 << 16;
+
+ using OS = absl::optional<std::string>;
+
+ OS a;
+ OS b = absl::nullopt;
+ OS c = std::string(n, 'c');
+ std::string sd(n, 'd');
+ OS d = sd;
+ OS e(absl::in_place, n, 'e');
+ OS f;
+ f.emplace(n, 'f');
+
+ OS ca(a);
+ OS cb(b);
+ OS cc(c);
+ OS cd(d);
+ OS ce(e);
+
+ OS oa;
+ OS ob = absl::nullopt;
+ OS oc = std::string(n, 'c');
+ std::string sod(n, 'd');
+ OS od = sod;
+ OS oe(absl::in_place, n, 'e');
+ OS of;
+ of.emplace(n, 'f');
+
+ OS ma(std::move(oa));
+ OS mb(std::move(ob));
+ OS mc(std::move(oc));
+ OS md(std::move(od));
+ OS me(std::move(oe));
+ OS mf(std::move(of));
+
+ OS aa1;
+ OS ab1 = absl::nullopt;
+ OS ac1 = std::string(n, 'c');
+ std::string sad1(n, 'd');
+ OS ad1 = sad1;
+ OS ae1(absl::in_place, n, 'e');
+ OS af1;
+ af1.emplace(n, 'f');
+
+ OS aa2;
+ OS ab2 = absl::nullopt;
+ OS ac2 = std::string(n, 'c');
+ std::string sad2(n, 'd');
+ OS ad2 = sad2;
+ OS ae2(absl::in_place, n, 'e');
+ OS af2;
+ af2.emplace(n, 'f');
+
+ aa1 = af2;
+ ab1 = ae2;
+ ac1 = ad2;
+ ad1 = ac2;
+ ae1 = ab2;
+ af1 = aa2;
+
+ OS aa3;
+ OS ab3 = absl::nullopt;
+ OS ac3 = std::string(n, 'c');
+ std::string sad3(n, 'd');
+ OS ad3 = sad3;
+ OS ae3(absl::in_place, n, 'e');
+ OS af3;
+ af3.emplace(n, 'f');
+
+ aa3 = absl::nullopt;
+ ab3 = absl::nullopt;
+ ac3 = absl::nullopt;
+ ad3 = absl::nullopt;
+ ae3 = absl::nullopt;
+ af3 = absl::nullopt;
+
+ OS aa4;
+ OS ab4 = absl::nullopt;
+ OS ac4 = std::string(n, 'c');
+ std::string sad4(n, 'd');
+ OS ad4 = sad4;
+ OS ae4(absl::in_place, n, 'e');
+ OS af4;
+ af4.emplace(n, 'f');
+
+ aa4 = OS(absl::in_place, n, 'a');
+ ab4 = OS(absl::in_place, n, 'b');
+ ac4 = OS(absl::in_place, n, 'c');
+ ad4 = OS(absl::in_place, n, 'd');
+ ae4 = OS(absl::in_place, n, 'e');
+ af4 = OS(absl::in_place, n, 'f');
+
+ OS aa5;
+ OS ab5 = absl::nullopt;
+ OS ac5 = std::string(n, 'c');
+ std::string sad5(n, 'd');
+ OS ad5 = sad5;
+ OS ae5(absl::in_place, n, 'e');
+ OS af5;
+ af5.emplace(n, 'f');
+
+ std::string saa5(n, 'a');
+ std::string sab5(n, 'a');
+ std::string sac5(n, 'a');
+ std::string sad52(n, 'a');
+ std::string sae5(n, 'a');
+ std::string saf5(n, 'a');
+
+ aa5 = saa5;
+ ab5 = sab5;
+ ac5 = sac5;
+ ad5 = sad52;
+ ae5 = sae5;
+ af5 = saf5;
+
+ OS aa6;
+ OS ab6 = absl::nullopt;
+ OS ac6 = std::string(n, 'c');
+ std::string sad6(n, 'd');
+ OS ad6 = sad6;
+ OS ae6(absl::in_place, n, 'e');
+ OS af6;
+ af6.emplace(n, 'f');
+
+ aa6 = std::string(n, 'a');
+ ab6 = std::string(n, 'b');
+ ac6 = std::string(n, 'c');
+ ad6 = std::string(n, 'd');
+ ae6 = std::string(n, 'e');
+ af6 = std::string(n, 'f');
+
+ OS aa7;
+ OS ab7 = absl::nullopt;
+ OS ac7 = std::string(n, 'c');
+ std::string sad7(n, 'd');
+ OS ad7 = sad7;
+ OS ae7(absl::in_place, n, 'e');
+ OS af7;
+ af7.emplace(n, 'f');
+
+ aa7.emplace(n, 'A');
+ ab7.emplace(n, 'B');
+ ac7.emplace(n, 'C');
+ ad7.emplace(n, 'D');
+ ae7.emplace(n, 'E');
+ af7.emplace(n, 'F');
+}
+
+TEST(optionalTest, MoveAssignRegression) {
+ StructorListener listener;
+ Listenable::listener = &listener;
+
+ {
+ absl::optional<Listenable> a;
+ Listenable b;
+ a = std::move(b);
+ }
+
+ EXPECT_EQ(1, listener.construct0);
+ EXPECT_EQ(1, listener.move);
+ EXPECT_EQ(2, listener.destruct);
+}
+
+TEST(optionalTest, ValueType) {
+ EXPECT_TRUE((std::is_same<absl::optional<int>::value_type, int>::value));
+ EXPECT_TRUE(
+ (std::is_same<absl::optional<std::string>::value_type, std::string>::value));
+ EXPECT_FALSE(
+ (std::is_same<absl::optional<int>::value_type, absl::nullopt_t>::value));
+}
+
+TEST(optionalTest, Hash) {
+ std::hash<absl::optional<int>> hash;
+ std::set<size_t> hashcodes;
+ hashcodes.insert(hash(absl::nullopt));
+ for (int i = 0; i < 100; ++i) {
+ hashcodes.insert(hash(i));
+ }
+ EXPECT_GT(hashcodes.size(), 90);
+}
+
+struct MoveMeNoThrow {
+ MoveMeNoThrow() : x(0) {}
+ [[noreturn]] MoveMeNoThrow(const MoveMeNoThrow& other) : x(other.x) {
+ ABSL_RAW_LOG(FATAL, "Should not be called.");
+ abort();
+ }
+ MoveMeNoThrow(MoveMeNoThrow&& other) noexcept : x(other.x) {}
+ int x;
+};
+
+struct MoveMeThrow {
+ MoveMeThrow() : x(0) {}
+ MoveMeThrow(const MoveMeThrow& other) : x(other.x) {}
+ MoveMeThrow(MoveMeThrow&& other) : x(other.x) {}
+ int x;
+};
+
+TEST(optionalTest, NoExcept) {
+ static_assert(
+ std::is_nothrow_move_constructible<absl::optional<MoveMeNoThrow>>::value,
+ "");
+#ifndef ABSL_HAVE_STD_OPTIONAL
+ static_assert(absl::default_allocator_is_nothrow::value ==
+ std::is_nothrow_move_constructible<
+ absl::optional<MoveMeThrow>>::value,
+ "");
+#endif
+ std::vector<absl::optional<MoveMeNoThrow>> v;
+ for (int i = 0; i < 10; ++i) v.emplace_back();
+}
+
+struct AnyLike {
+ AnyLike(AnyLike&&) = default;
+ AnyLike(const AnyLike&) = default;
+
+ template <typename ValueType,
+ typename T = typename std::decay<ValueType>::type,
+ typename std::enable_if<
+ !absl::disjunction<
+ std::is_same<AnyLike, T>,
+ absl::negation<std::is_copy_constructible<T>>>::value,
+ int>::type = 0>
+ AnyLike(ValueType&&) {} // NOLINT(runtime/explicit)
+
+ AnyLike& operator=(AnyLike&&) = default;
+ AnyLike& operator=(const AnyLike&) = default;
+
+ template <typename ValueType,
+ typename T = typename std::decay<ValueType>::type>
+ typename std::enable_if<
+ absl::conjunction<absl::negation<std::is_same<AnyLike, T>>,
+ std::is_copy_constructible<T>>::value,
+ AnyLike&>::type
+ operator=(ValueType&& /* rhs */) {
+ return *this;
+ }
+};
+
+TEST(optionalTest, ConstructionConstraints) {
+ EXPECT_TRUE((std::is_constructible<AnyLike, absl::optional<AnyLike>>::value));
+
+ EXPECT_TRUE(
+ (std::is_constructible<AnyLike, const absl::optional<AnyLike>&>::value));
+
+ EXPECT_TRUE((std::is_constructible<absl::optional<AnyLike>, AnyLike>::value));
+ EXPECT_TRUE(
+ (std::is_constructible<absl::optional<AnyLike>, const AnyLike&>::value));
+
+ EXPECT_TRUE((std::is_convertible<absl::optional<AnyLike>, AnyLike>::value));
+
+ EXPECT_TRUE(
+ (std::is_convertible<const absl::optional<AnyLike>&, AnyLike>::value));
+
+ EXPECT_TRUE((std::is_convertible<AnyLike, absl::optional<AnyLike>>::value));
+ EXPECT_TRUE(
+ (std::is_convertible<const AnyLike&, absl::optional<AnyLike>>::value));
+
+ EXPECT_TRUE(std::is_move_constructible<absl::optional<AnyLike>>::value);
+ EXPECT_TRUE(std::is_copy_constructible<absl::optional<AnyLike>>::value);
+}
+
+TEST(optionalTest, AssignmentConstraints) {
+ EXPECT_TRUE((std::is_assignable<AnyLike&, absl::optional<AnyLike>>::value));
+ EXPECT_TRUE(
+ (std::is_assignable<AnyLike&, const absl::optional<AnyLike>&>::value));
+ EXPECT_TRUE((std::is_assignable<absl::optional<AnyLike>&, AnyLike>::value));
+ EXPECT_TRUE(
+ (std::is_assignable<absl::optional<AnyLike>&, const AnyLike&>::value));
+ EXPECT_TRUE(std::is_move_assignable<absl::optional<AnyLike>>::value);
+ EXPECT_TRUE(std::is_copy_assignable<absl::optional<AnyLike>>::value);
+}
+
+} // namespace
diff --git a/absl/types/span.h b/absl/types/span.h
new file mode 100644
index 0000000..0e26fd4
--- /dev/null
+++ b/absl/types/span.h
@@ -0,0 +1,738 @@
+//
+// 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.
+//
+// -----------------------------------------------------------------------------
+// span.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines a `Span<T>` type for holding a view of an existing
+// array of data. The `Span` object, much like the `absl::string_view` object,
+// does not own such data itself. A span provides a lightweight way to pass
+// around view of such data.
+//
+// Additionally, this header file defines `MakeSpan()` and `MakeConstSpan()`
+// factory functions, for clearly creating spans of type `Span<T>` or read-only
+// `Span<const T>` when such types may be difficult to identify due to issues
+// with implicit conversion.
+//
+// The C++ standards committee currently has a proposal for a `std::span` type,
+// (http://wg21.link/p0122), which is not yet part of the standard (though may
+// become part of C++20). As of August 2017, the differences between
+// `absl::Span` and this proposal are:
+// * `absl::Span` uses `size_t` for `size_type`
+// * `absl::Span` has no `operator()`
+// * `absl::Span` has no constructors for `std::unique_ptr` or
+// `std::shared_ptr`
+// * `absl::span` has the factory functions `MakeSpan()` and
+// `MakeConstSpan()`
+// * `absl::Span` has `front()` and `back()` methods
+// * bounds-checked access to `absl::Span` is accomplished with `at()`
+// * `absl::Span` has compiler-provided move and copy constructors and
+// assignment. This is due to them being specified as `constexpr`, but that
+// implies const in C++11.
+// * `absl::Span` has no `element_type` or `index_type` typedefs
+// * A read-only `absl::Span<const T>` can be implicitly constructed from an
+// initializer list.
+// * `absl::Span` has no `bytes()`, `size_bytes()`, `as_bytes()`, or
+// `as_mutable_bytes()` methods
+// * `absl::Span` has no static extent template parameter, nor constructors
+// which exist only because of the static extent parameter.
+// * `absl::Span` has an explicit mutable-reference constructor
+//
+// For more information, see the class comments below.
+#ifndef ABSL_TYPES_SPAN_H_
+#define ABSL_TYPES_SPAN_H_
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <initializer_list>
+#include <iterator>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "absl/algorithm/algorithm.h"
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/base/macros.h"
+#include "absl/base/optimization.h"
+#include "absl/base/port.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+
+template <typename T>
+class Span;
+
+namespace span_internal {
+// A constexpr min function
+constexpr size_t Min(size_t a, size_t b) noexcept { return a < b ? a : b; }
+
+// Wrappers for access to container data pointers.
+template <typename C>
+constexpr auto GetDataImpl(C& c, char) noexcept // NOLINT(runtime/references)
+ -> decltype(c.data()) {
+ return c.data();
+}
+
+// Before C++17, std::string::data returns a const char* in all cases.
+inline char* GetDataImpl(std::string& s, // NOLINT(runtime/references)
+ int) noexcept {
+ return &s[0];
+}
+
+template <typename C>
+constexpr auto GetData(C& c) noexcept // NOLINT(runtime/references)
+ -> decltype(GetDataImpl(c, 0)) {
+ return GetDataImpl(c, 0);
+}
+
+// Detection idioms for size() and data().
+template <typename C>
+using HasSize =
+ std::is_integral<absl::decay_t<decltype(std::declval<C&>().size())>>;
+
+// We want to enable conversion from vector<T*> to Span<const T* const> but
+// disable conversion from vector<Derived> to Span<Base>. Here we use
+// the fact that U** is convertible to Q* const* if and only if Q is the same
+// type or a more cv-qualified version of U. We also decay the result type of
+// data() to avoid problems with classes which have a member function data()
+// which returns a reference.
+template <typename T, typename C>
+using HasData =
+ std::is_convertible<absl::decay_t<decltype(GetData(std::declval<C&>()))>*,
+ T* const*>;
+
+// Extracts value type from a Container
+template <typename C>
+struct ElementType {
+ using type = typename absl::remove_reference_t<C>::value_type;
+};
+
+template <typename T, size_t N>
+struct ElementType<T (&)[N]> {
+ using type = T;
+};
+
+template <typename C>
+using ElementT = typename ElementType<C>::type;
+
+template <typename T>
+using EnableIfMutable =
+ typename std::enable_if<!std::is_const<T>::value, int>::type;
+
+template <typename T>
+bool EqualImpl(Span<T> a, Span<T> b) {
+ static_assert(std::is_const<T>::value, "");
+ return absl::equal(a.begin(), a.end(), b.begin(), b.end());
+}
+
+template <typename T>
+bool LessThanImpl(Span<T> a, Span<T> b) {
+ static_assert(std::is_const<T>::value, "");
+ return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
+}
+
+// The `IsConvertible` classes here are needed because of the
+// `std::is_convertible` bug in libcxx when compiled with GCC. This build
+// configuration is used by Android NDK toolchain. Reference link:
+// https://bugs.llvm.org/show_bug.cgi?id=27538.
+template <typename From, typename To>
+struct IsConvertibleHelper {
+ private:
+ static std::true_type test(To);
+ static std::false_type test(...);
+
+ public:
+ using type = decltype(test(std::declval<From>()));
+};
+
+template <typename From, typename To>
+struct IsConvertible : IsConvertibleHelper<From, To>::type {};
+
+// TODO(zhangxy): replace `IsConvertible` with `std::is_convertible` once the
+// older version of libcxx is not supported.
+template <typename From, typename To>
+using EnableIfConvertibleToSpanConst =
+ typename std::enable_if<IsConvertible<From, Span<const To>>::value>::type;
+} // namespace span_internal
+
+//------------------------------------------------------------------------------
+// Span
+//------------------------------------------------------------------------------
+//
+// A `Span` is an "array view" type for holding a view of a contiguous data
+// array; the `Span` object does not and cannot own such data itself. A span
+// provides an easy way to provide overloads for anything operating on
+// contiguous sequences without needing to manage pointers and array lengths
+// manually.
+
+// A span is conceptually a pointer (ptr) and a length (size) into an already
+// existing array of contiguous memory; the array it represents references the
+// elements "ptr[0] .. ptr[size-1]". Passing a properly-constructed `Span`
+// instead of raw pointers avoids many issues related to index out of bounds
+// errors.
+//
+// Spans may also be constructed from containers holding contiguous sequences.
+// Such containers must supply `data()` and `size() const` methods (e.g
+// `std::vector<T>`, `absl::InlinedVector<T, N>`). All implicit conversions to
+// `absl::Span` from such containers will create spans of type `const T`;
+// spans which can mutate their values (of type `T`) must use explicit
+// constructors.
+//
+// A `Span<T>` is somewhat analogous to an `absl::string_view`, but for an array
+// of elements of type `T`. A user of `Span` must ensure that the data being
+// pointed to outlives the `Span` itself.
+//
+// You can construct a `Span<T>` in several ways:
+//
+// * Explicitly from a reference to a container type
+// * Explicitly from a pointer and size
+// * Implicitly from a container type (but only for spans of type `const T`)
+// * Using the `MakeSpan()` or `MakeConstSpan()` factory functions.
+//
+// Examples:
+//
+// // Construct a Span explicitly from a container:
+// std::vector<int> v = {1, 2, 3, 4, 5};
+// auto span = absl::Span<const int>(v);
+//
+// // Construct a Span explicitly from a C-style array:
+// int a[5] = {1, 2, 3, 4, 5};
+// auto span = absl::Span<const int>(a);
+//
+// // Construct a Span implicitly from a container
+// void MyRoutine(absl::Span<const int> a) {
+// ...
+// };
+// std::vector v = {1,2,3,4,5};
+// MyRoutine(v) // convert to Span<const T>
+//
+// Note that `Span` objects, in addition to requiring that the memory they
+// point to remains alive, must also ensure that such memory does not get
+// reallocated. Therefore, to avoid undefined behavior, containers with
+// associated span views should not invoke operations that may reallocate memory
+// (such as resizing) or invalidate iterarors into the container.
+//
+// One common use for a `Span` is when passing arguments to a routine that can
+// accept a variety of array types (e.g. a `std::vector`, `absl::InlinedVector`,
+// a C-style array, etc.). Instead of creating overloads for each case, you
+// can simply specify a `Span` as the argument to such a routine.
+//
+// Example:
+//
+// void MyRoutine(absl::Span<const int> a) {
+// ...
+// };
+//
+// std::vector v = {1,2,3,4,5};
+// MyRoutine(v);
+//
+// absl::InlinedVector<int, 4> my_inline_vector;
+// MyRoutine(my_inline_vector);
+//
+// // Explicit constructor from pointer,size
+// int* my_array = new int[10];
+// MyRoutine(absl::Span<const int>(my_array, 10));
+template <typename T>
+class Span {
+ private:
+ // Used to determine whether a Span can be constructed from a container of
+ // type C.
+ template <typename C>
+ using EnableIfConvertibleFrom =
+ typename std::enable_if<span_internal::HasData<T, C>::value &&
+ span_internal::HasSize<C>::value>::type;
+
+ // Used to SFINAE-enable a function when the slice elements are const.
+ template <typename U>
+ using EnableIfConstView =
+ typename std::enable_if<std::is_const<T>::value, U>::type;
+
+ // Used to SFINAE-enable a function when the slice elements are mutable.
+ template <typename U>
+ using EnableIfMutableView =
+ typename std::enable_if<!std::is_const<T>::value, U>::type;
+
+ public:
+ using value_type = absl::remove_cv_t<T>;
+ using pointer = T*;
+ using const_pointer = const T*;
+ using reference = T&;
+ using const_reference = const T&;
+ using iterator = pointer;
+ using const_iterator = const_pointer;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ using size_type = size_t;
+ using difference_type = ptrdiff_t;
+
+ static const size_type npos = -1;
+
+ constexpr Span() noexcept : Span(nullptr, 0) {}
+ constexpr Span(pointer array, size_type length) noexcept
+ : ptr_(array), len_(length) {}
+
+ // Implicit conversion constructors
+ template <size_t N>
+ constexpr Span(T (&a)[N]) noexcept // NOLINT(runtime/explicit)
+ : Span(a, N) {}
+
+ // Explicit reference constructor for a mutable `Span<T>` type
+ template <typename V, typename = EnableIfConvertibleFrom<V>,
+ typename = EnableIfMutableView<V>>
+ explicit Span(V& v) noexcept // NOLINT(runtime/references)
+ : Span(span_internal::GetData(v), v.size()) {}
+
+ // Implicit reference constructor for a read-only `Span<const T>` type
+ template <typename V, typename = EnableIfConvertibleFrom<V>,
+ typename = EnableIfConstView<V>>
+ constexpr Span(const V& v) noexcept // NOLINT(runtime/explicit)
+ : Span(span_internal::GetData(v), v.size()) {}
+
+ // Implicit constructor from an initializer list, making it possible to pass a
+ // brace-enclosed initializer list to a function expecting a `Span`. Such
+ // spans constructed from an initializer list must be of type `Span<const T>`.
+ //
+ // void Process(absl::Span<const int> x);
+ // Process({1, 2, 3});
+ //
+ // Note that as always the array referenced by the span must outlive the span.
+ // Since an initializer list constructor acts as if it is fed a temporary
+ // array (cf. C++ standard [dcl.init.list]/5), it's safe to use this
+ // constructor only when the `std::initializer_list` itself outlives the span.
+ // In order to meet this requirement it's sufficient to ensure that neither
+ // the span nor a copy of it is used outside of the expression in which it's
+ // created:
+ //
+ // // Assume that this function uses the array directly, not retaining any
+ // // copy of the span or pointer to any of its elements.
+ // void Process(absl::Span<const int> ints);
+ //
+ // // Okay: the std::initializer_list<int> will reference a temporary array
+ // // that isn't destroyed until after the call to Process returns.
+ // Process({ 17, 19 });
+ //
+ // // Not okay: the storage used by the std::initializer_list<int> is not
+ // // allowed to be referenced after the first line.
+ // absl::Span<const int> ints = { 17, 19 };
+ // Process(ints);
+ //
+ // // Not okay for the same reason as above: even when the elements of the
+ // // initializer list expression are not temporaries the underlying array
+ // // is, so the initializer list must still outlive the span.
+ // const int foo = 17;
+ // absl::Span<const int> ints = { foo };
+ // Process(ints);
+ //
+ template <typename LazyT = T,
+ typename = EnableIfConstView<LazyT>>
+ Span(
+ std::initializer_list<value_type> v) noexcept // NOLINT(runtime/explicit)
+ : Span(v.begin(), v.size()) {}
+
+ // Accessors
+
+ // Span::data()
+ //
+ // Returns a pointer to the span's underlying array of data (which is held
+ // outside the span).
+ constexpr pointer data() const noexcept { return ptr_; }
+
+ // Span::size()
+ //
+ // Returns the size of this span.
+ constexpr size_type size() const noexcept { return len_; }
+
+ // Span::length()
+ //
+ // Returns the length (size) of this span.
+ constexpr size_type length() const noexcept { return size(); }
+
+ // Span::empty()
+ //
+ // Returns a boolean indicating whether or not this span is considered empty.
+ constexpr bool empty() const noexcept { return size() == 0; }
+
+ // Span::operator[]
+ //
+ // Returns a reference to the i'th element of this span.
+ constexpr reference operator[](size_type i) const noexcept {
+ // MSVC 2015 accepts this as constexpr, but not ptr_[i]
+ return *(data() + i);
+ }
+
+ // Span::at()
+ //
+ // Returns a reference to the i'th element of this span.
+ constexpr reference at(size_type i) const {
+ return ABSL_PREDICT_FALSE(i < size())
+ ? ptr_[i]
+ : (base_internal::ThrowStdOutOfRange(
+ "Span::at failed bounds check"),
+ ptr_[i]);
+ }
+
+ // Span::front()
+ //
+ // Returns a reference to the first element of this span.
+ reference front() const noexcept { return ABSL_ASSERT(size() > 0), ptr_[0]; }
+
+ // Span::back()
+ //
+ // Returns a reference to the last element of this span.
+ reference back() const noexcept {
+ return ABSL_ASSERT(size() > 0), ptr_[size() - 1];
+ }
+
+ // Span::begin()
+ //
+ // Returns an iterator to the first element of this span.
+ constexpr iterator begin() const noexcept { return ptr_; }
+
+ // Span::cbegin()
+ //
+ // Returns a const iterator to the first element of this span.
+ constexpr const_iterator cbegin() const noexcept { return ptr_; }
+
+ // Span::end()
+ //
+ // Returns an iterator to the last element of this span.
+ iterator end() const noexcept { return ptr_ + len_; }
+
+ // Span::cend()
+ //
+ // Returns a const iterator to the last element of this span.
+ const_iterator cend() const noexcept { return end(); }
+
+ // Span::rbegin()
+ //
+ // Returns a reverse iterator starting at the last element of this span.
+ reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); }
+
+ // Span::crbegin()
+ //
+ // Returns a reverse const iterator starting at the last element of this span.
+ const_reverse_iterator crbegin() const noexcept { return rbegin(); }
+
+ // Span::rend()
+ //
+ // Returns a reverse iterator starting at the first element of this span.
+ reverse_iterator rend() const noexcept { return reverse_iterator(begin()); }
+
+ // Span::crend()
+ //
+ // Returns a reverse iterator starting at the first element of this span.
+ const_reverse_iterator crend() const noexcept { return rend(); }
+
+ // Span mutations
+
+ // Span::remove_prefix()
+ //
+ // Removes the first `n` elements from the span.
+ void remove_prefix(size_type n) noexcept {
+ assert(len_ >= n);
+ ptr_ += n;
+ len_ -= n;
+ }
+
+ // Span::remove_suffix()
+ //
+ // Removes the last `n` elements from the span.
+ void remove_suffix(size_type n) noexcept {
+ assert(len_ >= n);
+ len_ -= n;
+ }
+
+ // Span::subspan()
+ //
+ // Returns a `Span` starting at element `pos` and of length `len`, with
+ // proper bounds checking to ensure `len` does not exceed the ptr+size of the
+ // original array. (Spans whose `len` would point past the end of the array
+ // will throw a `std::out_of_range`.)
+ constexpr Span subspan(size_type pos = 0, size_type len = npos) const {
+ return (pos <= len_)
+ ? Span(ptr_ + pos, span_internal::Min(len_ - pos, len))
+ : (base_internal::ThrowStdOutOfRange("pos > size()"), Span());
+ }
+
+ private:
+ pointer ptr_;
+ size_type len_;
+};
+
+template <typename T>
+const typename Span<T>::size_type Span<T>::npos;
+
+// Span relationals
+
+// Equality is compared element-by-element, while ordering is lexicographical.
+// We provide three overloads for each operator to cover any combination on the
+// left or right hand side of mutable Span<T>, read-only Span<const T>, and
+// convertible-to-read-only Span<T>.
+// TODO(zhangxy): Due to MSVC overload resolution bug with partial ordering
+// template functions, 5 overloads per operator is needed as a workaround. We
+// should update them to 3 overloads per operator using non-deduced context like
+// string_view, i.e.
+// - (Span<T>, Span<T>)
+// - (Span<T>, non_deduced<Span<const T>>)
+// - (non_deduced<Span<const T>>, Span<T>)
+
+// operator==
+template <typename T>
+bool operator==(Span<T> a, Span<T> b) {
+ return span_internal::EqualImpl<const T>(a, b);
+}
+template <typename T>
+bool operator==(Span<const T> a, Span<T> b) {
+ return span_internal::EqualImpl<const T>(a, b);
+}
+template <typename T>
+bool operator==(Span<T> a, Span<const T> b) {
+ return span_internal::EqualImpl<const T>(a, b);
+}
+template <typename T, typename U,
+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator==(const U& a, Span<T> b) {
+ return span_internal::EqualImpl<const T>(a, b);
+}
+template <typename T, typename U,
+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator==(Span<T> a, const U& b) {
+ return span_internal::EqualImpl<const T>(a, b);
+}
+
+// operator!=
+template <typename T>
+bool operator!=(Span<T> a, Span<T> b) {
+ return !(a == b);
+}
+template <typename T>
+bool operator!=(Span<const T> a, Span<T> b) {
+ return !(a == b);
+}
+template <typename T>
+bool operator!=(Span<T> a, Span<const T> b) {
+ return !(a == b);
+}
+template <typename T, typename U,
+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator!=(const U& a, Span<T> b) {
+ return !(a == b);
+}
+template <typename T, typename U,
+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator!=(Span<T> a, const U& b) {
+ return !(a == b);
+}
+
+// operator<
+template <typename T>
+bool operator<(Span<T> a, Span<T> b) {
+ return span_internal::LessThanImpl<const T>(a, b);
+}
+template <typename T>
+bool operator<(Span<const T> a, Span<T> b) {
+ return span_internal::LessThanImpl<const T>(a, b);
+}
+template <typename T>
+bool operator<(Span<T> a, Span<const T> b) {
+ return span_internal::LessThanImpl<const T>(a, b);
+}
+template <typename T, typename U,
+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator<(const U& a, Span<T> b) {
+ return span_internal::LessThanImpl<const T>(a, b);
+}
+template <typename T, typename U,
+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator<(Span<T> a, const U& b) {
+ return span_internal::LessThanImpl<const T>(a, b);
+}
+
+// operator>
+template <typename T>
+bool operator>(Span<T> a, Span<T> b) {
+ return b < a;
+}
+template <typename T>
+bool operator>(Span<const T> a, Span<T> b) {
+ return b < a;
+}
+template <typename T>
+bool operator>(Span<T> a, Span<const T> b) {
+ return b < a;
+}
+template <typename T, typename U,
+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator>(const U& a, Span<T> b) {
+ return b < a;
+}
+template <typename T, typename U,
+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator>(Span<T> a, const U& b) {
+ return b < a;
+}
+
+// operator<=
+template <typename T>
+bool operator<=(Span<T> a, Span<T> b) {
+ return !(b < a);
+}
+template <typename T>
+bool operator<=(Span<const T> a, Span<T> b) {
+ return !(b < a);
+}
+template <typename T>
+bool operator<=(Span<T> a, Span<const T> b) {
+ return !(b < a);
+}
+template <typename T, typename U,
+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator<=(const U& a, Span<T> b) {
+ return !(b < a);
+}
+template <typename T, typename U,
+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator<=(Span<T> a, const U& b) {
+ return !(b < a);
+}
+
+// operator>=
+template <typename T>
+bool operator>=(Span<T> a, Span<T> b) {
+ return !(a < b);
+}
+template <typename T>
+bool operator>=(Span<const T> a, Span<T> b) {
+ return !(a < b);
+}
+template <typename T>
+bool operator>=(Span<T> a, Span<const T> b) {
+ return !(a < b);
+}
+template <typename T, typename U,
+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator>=(const U& a, Span<T> b) {
+ return !(a < b);
+}
+template <typename T, typename U,
+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+bool operator>=(Span<T> a, const U& b) {
+ return !(a < b);
+}
+
+// MakeSpan()
+//
+// Constructs a mutable `Span<T>`, deducing `T` automatically from either a
+// container or pointer+size.
+//
+// Because a read-only `Span<const T>` is implicitly constructed from container
+// types regardless of whether the container itself is a const container,
+// constructing mutable spans of type `Span<T>` from containers requires
+// explicit constructors. The container-accepting version of `MakeSpan()`
+// deduces the type of `T` by the constness of the pointer received from the
+// container's `data()` member. Similarly, the pointer-accepting version returns
+// a `Span<const T>` if `T` is `const`, and a `Span<T>` otherwise.
+//
+// Examples:
+//
+// void MyRoutine(absl::Span<MyComplicatedType> a) {
+// ...
+// };
+// // my_vector is a container of non-const types
+// std::vector<MyComplicatedType> my_vector;
+//
+// // Constructing a Span implicitly attempts to create a Span of type
+// // `Span<const T>`
+// MyRoutine(my_vector); // error, type mismatch
+//
+// // Explicitly constructing the Span is verbose
+// MyRoutine(absl::Span<MyComplicatedType>(my_vector);
+//
+// // Use MakeSpan() to make an absl::Span<T>
+// MyRoutine(absl::MakeSpan(my_vector));
+//
+// // Construct a span from an array ptr+size
+// absl::Span<T> my_span() {
+// return absl::MakeSpan(&array[0], num_elements_);
+// }
+//
+template <int&... ExplicitArgumentBarrier, typename T>
+constexpr Span<T> MakeSpan(T* ptr, size_t size) noexcept {
+ return Span<T>(ptr, size);
+}
+
+template <int&... ExplicitArgumentBarrier, typename T>
+Span<T> MakeSpan(T* begin, T* end) noexcept {
+ return ABSL_ASSERT(begin <= end), Span<T>(begin, end - begin);
+}
+
+template <int&... ExplicitArgumentBarrier, typename C>
+constexpr auto MakeSpan(C& c) noexcept // NOLINT(runtime/references)
+ -> decltype(absl::MakeSpan(span_internal::GetData(c), c.size())) {
+ return MakeSpan(span_internal::GetData(c), c.size());
+}
+
+template <int&... ExplicitArgumentBarrier, typename T, size_t N>
+constexpr Span<T> MakeSpan(T (&array)[N]) noexcept {
+ return Span<T>(array, N);
+}
+
+// MakeConstSpan()
+//
+// Constructs a `Span<const T>` as with `MakeSpan`, deducing `T` automatically,
+// but always returning a `Span<const T>`.
+//
+// Examples:
+//
+// void ProcessInts(absl::Span<const int> some_ints);
+//
+// // Call with a pointer and size.
+// int array[3] = { 0, 0, 0 };
+// ProcessInts(absl::MakeConstSpan(&array[0], 3));
+//
+// // Call with a [begin, end) pair.
+// ProcessInts(absl::MakeConstSpan(&array[0], &array[3]));
+//
+// // Call directly with an array.
+// ProcessInts(absl::MakeConstSpan(array));
+//
+// // Call with a contiguous container.
+// std::vector<int> some_ints = ...;
+// ProcessInts(absl::MakeConstSpan(some_ints));
+// ProcessInts(absl::MakeConstSpan(std::vector<int>{ 0, 0, 0 }));
+//
+template <int&... ExplicitArgumentBarrier, typename T>
+constexpr Span<const T> MakeConstSpan(T* ptr, size_t size) noexcept {
+ return Span<const T>(ptr, size);
+}
+
+template <int&... ExplicitArgumentBarrier, typename T>
+Span<const T> MakeConstSpan(T* begin, T* end) noexcept {
+ return ABSL_ASSERT(begin <= end), Span<const T>(begin, end - begin);
+}
+
+template <int&... ExplicitArgumentBarrier, typename C>
+constexpr auto MakeConstSpan(const C& c) noexcept -> decltype(MakeSpan(c)) {
+ return MakeSpan(c);
+}
+
+template <int&... ExplicitArgumentBarrier, typename T, size_t N>
+constexpr Span<const T> MakeConstSpan(const T (&array)[N]) noexcept {
+ return Span<const T>(array, N);
+}
+} // namespace absl
+#endif // ABSL_TYPES_SPAN_H_
diff --git a/absl/types/span_test.cc b/absl/types/span_test.cc
new file mode 100644
index 0000000..22ea33e
--- /dev/null
+++ b/absl/types/span_test.cc
@@ -0,0 +1,783 @@
+// 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/types/span.h"
+
+#include <algorithm>
+#include <array>
+#include <initializer_list>
+#include <numeric>
+#include <stdexcept>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/exception_testing.h"
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/container/fixed_array.h"
+#include "absl/container/inlined_vector.h"
+#include "absl/strings/str_cat.h"
+
+namespace {
+
+MATCHER_P(DataIs, data,
+ absl::StrCat("data() is ", negation ? "is " : "isn't ",
+ testing::PrintToString(data))) {
+ return arg.data() == data;
+}
+
+template <typename T>
+auto SpanIs(T data, size_t size)
+ -> decltype(testing::AllOf(DataIs(data), testing::SizeIs(size))) {
+ return testing::AllOf(DataIs(data), testing::SizeIs(size));
+}
+
+template <typename Container>
+auto SpanIs(const Container& c) -> decltype(SpanIs(c.data(), c.size())) {
+ return SpanIs(c.data(), c.size());
+}
+
+std::vector<int> MakeRamp(int len, int offset = 0) {
+ std::vector<int> v(len);
+ std::iota(v.begin(), v.end(), offset);
+ return v;
+}
+
+TEST(IntSpan, EmptyCtors) {
+ absl::Span<int> s;
+ EXPECT_THAT(s, SpanIs(nullptr, 0));
+}
+
+TEST(IntSpan, PtrLenCtor) {
+ int a[] = {1, 2, 3};
+ absl::Span<int> s(&a[0], 2);
+ EXPECT_THAT(s, SpanIs(a, 2));
+}
+
+TEST(IntSpan, ArrayCtor) {
+ int a[] = {1, 2, 3};
+ absl::Span<int> s(a);
+ EXPECT_THAT(s, SpanIs(a, 3));
+
+ EXPECT_TRUE((std::is_constructible<absl::Span<const int>, int[3]>::value));
+ EXPECT_TRUE(
+ (std::is_constructible<absl::Span<const int>, const int[3]>::value));
+ EXPECT_FALSE((std::is_constructible<absl::Span<int>, const int[3]>::value));
+ EXPECT_TRUE((std::is_convertible<int[3], absl::Span<const int>>::value));
+ EXPECT_TRUE(
+ (std::is_convertible<const int[3], absl::Span<const int>>::value));
+}
+
+template <typename T>
+void TakesGenericSpan(absl::Span<T>) {}
+
+TEST(IntSpan, ContainerCtor) {
+ std::vector<int> empty;
+ absl::Span<int> s_empty(empty);
+ EXPECT_THAT(s_empty, SpanIs(empty));
+
+ std::vector<int> filled{1, 2, 3};
+ absl::Span<int> s_filled(filled);
+ EXPECT_THAT(s_filled, SpanIs(filled));
+
+ absl::Span<int> s_from_span(filled);
+ EXPECT_THAT(s_from_span, SpanIs(s_filled));
+
+ absl::Span<const int> const_filled = filled;
+ EXPECT_THAT(const_filled, SpanIs(filled));
+
+ absl::Span<const int> const_from_span = s_filled;
+ EXPECT_THAT(const_from_span, SpanIs(s_filled));
+
+ EXPECT_TRUE(
+ (std::is_convertible<std::vector<int>&, absl::Span<const int>>::value));
+ EXPECT_TRUE(
+ (std::is_convertible<absl::Span<int>&, absl::Span<const int>>::value));
+
+ TakesGenericSpan(absl::Span<int>(filled));
+}
+
+// A struct supplying shallow data() const.
+struct ContainerWithShallowConstData {
+ std::vector<int> storage;
+ int* data() const { return const_cast<int*>(storage.data()); }
+ int size() const { return storage.size(); }
+};
+
+TEST(IntSpan, ShallowConstness) {
+ const ContainerWithShallowConstData c{MakeRamp(20)};
+ absl::Span<int> s(
+ c); // We should be able to do this even though data() is const.
+ s[0] = -1;
+ EXPECT_EQ(c.storage[0], -1);
+}
+
+TEST(CharSpan, StringCtor) {
+ std::string empty = "";
+ absl::Span<char> s_empty(empty);
+ EXPECT_THAT(s_empty, SpanIs(empty));
+
+ std::string abc = "abc";
+ absl::Span<char> s_abc(abc);
+ EXPECT_THAT(s_abc, SpanIs(abc));
+
+ absl::Span<const char> s_const_abc = abc;
+ EXPECT_THAT(s_const_abc, SpanIs(abc));
+
+ EXPECT_FALSE((std::is_constructible<absl::Span<int>, std::string>::value));
+ EXPECT_FALSE((std::is_constructible<absl::Span<const int>, std::string>::value));
+ EXPECT_TRUE((std::is_convertible<std::string, absl::Span<const char>>::value));
+}
+
+TEST(IntSpan, FromConstPointer) {
+ EXPECT_TRUE((std::is_constructible<absl::Span<const int* const>,
+ std::vector<int*>>::value));
+ EXPECT_TRUE((std::is_constructible<absl::Span<const int* const>,
+ std::vector<const int*>>::value));
+ EXPECT_FALSE((
+ std::is_constructible<absl::Span<const int*>, std::vector<int*>>::value));
+ EXPECT_FALSE((
+ std::is_constructible<absl::Span<int*>, std::vector<const int*>>::value));
+}
+
+struct TypeWithMisleadingData {
+ int& data() { return i; }
+ int size() { return 1; }
+ int i;
+};
+
+struct TypeWithMisleadingSize {
+ int* data() { return &i; }
+ const char* size() { return "1"; }
+ int i;
+};
+
+TEST(IntSpan, EvilTypes) {
+ EXPECT_FALSE(
+ (std::is_constructible<absl::Span<int>, TypeWithMisleadingData&>::value));
+ EXPECT_FALSE(
+ (std::is_constructible<absl::Span<int>, TypeWithMisleadingSize&>::value));
+}
+
+struct Base {
+ int* data() { return &i; }
+ int size() { return 1; }
+ int i;
+};
+struct Derived : Base {};
+
+TEST(IntSpan, SpanOfDerived) {
+ EXPECT_TRUE((std::is_constructible<absl::Span<int>, Base&>::value));
+ EXPECT_TRUE((std::is_constructible<absl::Span<int>, Derived&>::value));
+ EXPECT_FALSE(
+ (std::is_constructible<absl::Span<Base>, std::vector<Derived>>::value));
+}
+
+void TestInitializerList(absl::Span<const int> s, const std::vector<int>& v) {
+ EXPECT_TRUE(absl::equal(s.begin(), s.end(), v.begin(), v.end()));
+}
+
+TEST(ConstIntSpan, InitializerListConversion) {
+ TestInitializerList({}, {});
+ TestInitializerList({1}, {1});
+ TestInitializerList({1, 2, 3}, {1, 2, 3});
+
+ EXPECT_FALSE((std::is_constructible<absl::Span<int>,
+ std::initializer_list<int>>::value));
+ EXPECT_FALSE((
+ std::is_convertible<absl::Span<int>, std::initializer_list<int>>::value));
+}
+
+TEST(IntSpan, Data) {
+ int i;
+ absl::Span<int> s(&i, 1);
+ EXPECT_EQ(&i, s.data());
+}
+
+TEST(IntSpan, SizeLengthEmpty) {
+ absl::Span<int> empty;
+ EXPECT_EQ(empty.size(), 0);
+ EXPECT_TRUE(empty.empty());
+ EXPECT_EQ(empty.size(), empty.length());
+
+ auto v = MakeRamp(10);
+ absl::Span<int> s(v);
+ EXPECT_EQ(s.size(), 10);
+ EXPECT_FALSE(s.empty());
+ EXPECT_EQ(s.size(), s.length());
+}
+
+TEST(IntSpan, ElementAccess) {
+ auto v = MakeRamp(10);
+ absl::Span<int> s(v);
+ for (int i = 0; i < s.size(); ++i) {
+ EXPECT_EQ(s[i], s.at(i));
+ }
+
+ EXPECT_EQ(s.front(), s[0]);
+ EXPECT_EQ(s.back(), s[9]);
+}
+
+TEST(IntSpan, AtThrows) {
+ auto v = MakeRamp(10);
+ absl::Span<int> s(v);
+
+ EXPECT_EQ(s.at(9), 9);
+ ABSL_BASE_INTERNAL_EXPECT_FAIL(s.at(10), std::out_of_range,
+ "failed bounds check");
+}
+
+TEST(IntSpan, RemovePrefixAndSuffix) {
+ auto v = MakeRamp(20, 1);
+ absl::Span<int> s(v);
+ EXPECT_EQ(s.size(), 20);
+
+ s.remove_suffix(0);
+ s.remove_prefix(0);
+ EXPECT_EQ(s.size(), 20);
+
+ s.remove_prefix(1);
+ EXPECT_EQ(s.size(), 19);
+ EXPECT_EQ(s[0], 2);
+
+ s.remove_suffix(1);
+ EXPECT_EQ(s.size(), 18);
+ EXPECT_EQ(s.back(), 19);
+
+ s.remove_prefix(7);
+ EXPECT_EQ(s.size(), 11);
+ EXPECT_EQ(s[0], 9);
+
+ s.remove_suffix(11);
+ EXPECT_EQ(s.size(), 0);
+
+ EXPECT_EQ(v, MakeRamp(20, 1));
+}
+
+TEST(IntSpan, Subspan) {
+ std::vector<int> empty;
+ EXPECT_EQ(absl::MakeSpan(empty).subspan(), empty);
+ EXPECT_THAT(absl::MakeSpan(empty).subspan(0, 0), SpanIs(empty));
+ EXPECT_THAT(absl::MakeSpan(empty).subspan(0, absl::Span<const int>::npos),
+ SpanIs(empty));
+
+ auto ramp = MakeRamp(10);
+ EXPECT_THAT(absl::MakeSpan(ramp).subspan(), SpanIs(ramp));
+ EXPECT_THAT(absl::MakeSpan(ramp).subspan(0, 10), SpanIs(ramp));
+ EXPECT_THAT(absl::MakeSpan(ramp).subspan(0, absl::Span<const int>::npos),
+ SpanIs(ramp));
+ EXPECT_THAT(absl::MakeSpan(ramp).subspan(0, 3), SpanIs(ramp.data(), 3));
+ EXPECT_THAT(absl::MakeSpan(ramp).subspan(5, absl::Span<const int>::npos),
+ SpanIs(ramp.data() + 5, 5));
+ EXPECT_THAT(absl::MakeSpan(ramp).subspan(3, 3), SpanIs(ramp.data() + 3, 3));
+ EXPECT_THAT(absl::MakeSpan(ramp).subspan(10, 5), SpanIs(ramp.data() + 10, 0));
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+ EXPECT_THROW(absl::MakeSpan(ramp).subspan(11, 5), std::out_of_range);
+#else
+ EXPECT_DEATH(absl::MakeSpan(ramp).subspan(11, 5), "");
+#endif
+}
+
+TEST(IntSpan, MakeSpanPtrLength) {
+ std::vector<int> empty;
+ auto s_empty = absl::MakeSpan(empty.data(), empty.size());
+ EXPECT_THAT(s_empty, SpanIs(empty));
+
+ std::array<int, 3> a{{1, 2, 3}};
+ auto s = absl::MakeSpan(a.data(), a.size());
+ EXPECT_THAT(s, SpanIs(a));
+
+ EXPECT_THAT(absl::MakeConstSpan(empty.data(), empty.size()), SpanIs(s_empty));
+ EXPECT_THAT(absl::MakeConstSpan(a.data(), a.size()), SpanIs(s));
+}
+
+TEST(IntSpan, MakeSpanTwoPtrs) {
+ std::vector<int> empty;
+ auto s_empty = absl::MakeSpan(empty.data(), empty.data());
+ EXPECT_THAT(s_empty, SpanIs(empty));
+
+ std::vector<int> v{1, 2, 3};
+ auto s = absl::MakeSpan(v.data(), v.data() + 1);
+ EXPECT_THAT(s, SpanIs(v.data(), 1));
+
+ EXPECT_THAT(absl::MakeConstSpan(empty.data(), empty.data()), SpanIs(s_empty));
+ EXPECT_THAT(absl::MakeConstSpan(v.data(), v.data() + 1), SpanIs(s));
+}
+
+TEST(IntSpan, MakeSpanContainer) {
+ std::vector<int> empty;
+ auto s_empty = absl::MakeSpan(empty);
+ EXPECT_THAT(s_empty, SpanIs(empty));
+
+ std::vector<int> v{1, 2, 3};
+ auto s = absl::MakeSpan(v);
+ EXPECT_THAT(s, SpanIs(v));
+
+ EXPECT_THAT(absl::MakeConstSpan(empty), SpanIs(s_empty));
+ EXPECT_THAT(absl::MakeConstSpan(v), SpanIs(s));
+
+ EXPECT_THAT(absl::MakeSpan(s), SpanIs(s));
+ EXPECT_THAT(absl::MakeConstSpan(s), SpanIs(s));
+}
+
+TEST(CharSpan, MakeSpanString) {
+ std::string empty = "";
+ auto s_empty = absl::MakeSpan(empty);
+ EXPECT_THAT(s_empty, SpanIs(empty));
+
+ std::string str = "abc";
+ auto s_str = absl::MakeSpan(str);
+ EXPECT_THAT(s_str, SpanIs(str));
+
+ EXPECT_THAT(absl::MakeConstSpan(empty), SpanIs(s_empty));
+ EXPECT_THAT(absl::MakeConstSpan(str), SpanIs(s_str));
+}
+
+TEST(IntSpan, MakeSpanArray) {
+ int a[] = {1, 2, 3};
+ auto s = absl::MakeSpan(a);
+ EXPECT_THAT(s, SpanIs(a, 3));
+
+ const int ca[] = {1, 2, 3};
+ auto s_ca = absl::MakeSpan(ca);
+ EXPECT_THAT(s_ca, SpanIs(ca, 3));
+
+ EXPECT_THAT(absl::MakeConstSpan(a), SpanIs(s));
+ EXPECT_THAT(absl::MakeConstSpan(ca), SpanIs(s_ca));
+}
+
+// Compile-asserts that the argument has the expected decayed type.
+template <typename Expected, typename T>
+void CheckType(const T& /* value */) {
+ testing::StaticAssertTypeEq<Expected, T>();
+}
+
+TEST(IntSpan, MakeSpanTypes) {
+ std::vector<int> vec;
+ const std::vector<int> cvec;
+ int a[1];
+ const int ca[] = {1};
+ int* ip = a;
+ const int* cip = ca;
+ std::string s = "";
+ const std::string cs = "";
+ CheckType<absl::Span<int>>(absl::MakeSpan(vec));
+ CheckType<absl::Span<const int>>(absl::MakeSpan(cvec));
+ CheckType<absl::Span<int>>(absl::MakeSpan(ip, ip + 1));
+ CheckType<absl::Span<int>>(absl::MakeSpan(ip, 1));
+ CheckType<absl::Span<const int>>(absl::MakeSpan(cip, cip + 1));
+ CheckType<absl::Span<const int>>(absl::MakeSpan(cip, 1));
+ CheckType<absl::Span<int>>(absl::MakeSpan(a));
+ CheckType<absl::Span<int>>(absl::MakeSpan(a, a + 1));
+ CheckType<absl::Span<int>>(absl::MakeSpan(a, 1));
+ CheckType<absl::Span<const int>>(absl::MakeSpan(ca));
+ CheckType<absl::Span<const int>>(absl::MakeSpan(ca, ca + 1));
+ CheckType<absl::Span<const int>>(absl::MakeSpan(ca, 1));
+ CheckType<absl::Span<char>>(absl::MakeSpan(s));
+ CheckType<absl::Span<const char>>(absl::MakeSpan(cs));
+}
+
+TEST(ConstIntSpan, MakeConstSpanTypes) {
+ std::vector<int> vec;
+ const std::vector<int> cvec;
+ int array[1];
+ const int carray[] = {0};
+ int* ptr = array;
+ const int* cptr = carray;
+ std::string s = "";
+ std::string cs = "";
+ CheckType<absl::Span<const int>>(absl::MakeConstSpan(vec));
+ CheckType<absl::Span<const int>>(absl::MakeConstSpan(cvec));
+ CheckType<absl::Span<const int>>(absl::MakeConstSpan(ptr, ptr + 1));
+ CheckType<absl::Span<const int>>(absl::MakeConstSpan(ptr, 1));
+ CheckType<absl::Span<const int>>(absl::MakeConstSpan(cptr, cptr + 1));
+ CheckType<absl::Span<const int>>(absl::MakeConstSpan(cptr, 1));
+ CheckType<absl::Span<const int>>(absl::MakeConstSpan(array));
+ CheckType<absl::Span<const int>>(absl::MakeConstSpan(carray));
+ CheckType<absl::Span<const char>>(absl::MakeConstSpan(s));
+ CheckType<absl::Span<const char>>(absl::MakeConstSpan(cs));
+}
+
+TEST(IntSpan, Equality) {
+ const int arr1[] = {1, 2, 3, 4, 5};
+ int arr2[] = {1, 2, 3, 4, 5};
+ std::vector<int> vec1(std::begin(arr1), std::end(arr1));
+ std::vector<int> vec2 = vec1;
+ std::vector<int> other_vec = {2, 4, 6, 8, 10};
+ // These two slices are from different vectors, but have the same size and
+ // have the same elements (right now). They should compare equal. Test both
+ // == and !=.
+ const absl::Span<const int> from1 = vec1;
+ const absl::Span<const int> from2 = vec2;
+ EXPECT_EQ(from1, from1);
+ EXPECT_FALSE(from1 != from1);
+ EXPECT_EQ(from1, from2);
+ EXPECT_FALSE(from1 != from2);
+
+ // These two slices have different underlying vector values. They should be
+ // considered not equal. Test both == and !=.
+ const absl::Span<const int> from_other = other_vec;
+ EXPECT_NE(from1, from_other);
+ EXPECT_FALSE(from1 == from_other);
+
+ // Comparison between a vector and its slice should be equal. And vice-versa.
+ // This ensures implicit conversion to Span works on both sides of ==.
+ EXPECT_EQ(vec1, from1);
+ EXPECT_FALSE(vec1 != from1);
+ EXPECT_EQ(from1, vec1);
+ EXPECT_FALSE(from1 != vec1);
+
+ // This verifies that absl::Span<T> can be compared freely with
+ // absl::Span<const T>.
+ const absl::Span<int> mutable_from1(vec1);
+ const absl::Span<int> mutable_from2(vec2);
+ EXPECT_EQ(from1, mutable_from1);
+ EXPECT_EQ(mutable_from1, from1);
+ EXPECT_EQ(mutable_from1, mutable_from2);
+ EXPECT_EQ(mutable_from2, mutable_from1);
+
+ // Comparison between a vector and its slice should be equal for mutable
+ // Spans as well.
+ EXPECT_EQ(vec1, mutable_from1);
+ EXPECT_FALSE(vec1 != mutable_from1);
+ EXPECT_EQ(mutable_from1, vec1);
+ EXPECT_FALSE(mutable_from1 != vec1);
+
+ // Comparison between convertible-to-Span-of-const and Span-of-mutable. Arrays
+ // are used because they're the only value type which converts to a
+ // Span-of-mutable. EXPECT_TRUE is used instead of EXPECT_EQ to avoid
+ // array-to-pointer decay.
+ EXPECT_TRUE(arr1 == mutable_from1);
+ EXPECT_FALSE(arr1 != mutable_from1);
+ EXPECT_TRUE(mutable_from1 == arr1);
+ EXPECT_FALSE(mutable_from1 != arr1);
+
+ // Comparison between convertible-to-Span-of-mutable and Span-of-const
+ EXPECT_TRUE(arr2 == from1);
+ EXPECT_FALSE(arr2 != from1);
+ EXPECT_TRUE(from1 == arr2);
+ EXPECT_FALSE(from1 != arr2);
+
+ // With a different size, the array slices should not be equal.
+ EXPECT_NE(from1, absl::Span<const int>(from1).subspan(0, from1.size() - 1));
+
+ // With different contents, the array slices should not be equal.
+ ++vec2.back();
+ EXPECT_NE(from1, from2);
+}
+
+class IntSpanOrderComparisonTest : public testing::Test {
+ public:
+ IntSpanOrderComparisonTest()
+ : arr_before_{1, 2, 3},
+ arr_after_{1, 2, 4},
+ carr_after_{1, 2, 4},
+ vec_before_(std::begin(arr_before_), std::end(arr_before_)),
+ vec_after_(std::begin(arr_after_), std::end(arr_after_)),
+ before_(vec_before_),
+ after_(vec_after_),
+ cbefore_(vec_before_),
+ cafter_(vec_after_) {}
+
+ protected:
+ int arr_before_[3], arr_after_[3];
+ const int carr_after_[3];
+ std::vector<int> vec_before_, vec_after_;
+ absl::Span<int> before_, after_;
+ absl::Span<const int> cbefore_, cafter_;
+};
+
+TEST_F(IntSpanOrderComparisonTest, CompareSpans) {
+ EXPECT_TRUE(cbefore_ < cafter_);
+ EXPECT_TRUE(cbefore_ <= cafter_);
+ EXPECT_TRUE(cafter_ > cbefore_);
+ EXPECT_TRUE(cafter_ >= cbefore_);
+
+ EXPECT_FALSE(cbefore_ > cafter_);
+ EXPECT_FALSE(cafter_ < cbefore_);
+
+ EXPECT_TRUE(before_ < after_);
+ EXPECT_TRUE(before_ <= after_);
+ EXPECT_TRUE(after_ > before_);
+ EXPECT_TRUE(after_ >= before_);
+
+ EXPECT_FALSE(before_ > after_);
+ EXPECT_FALSE(after_ < before_);
+
+ EXPECT_TRUE(cbefore_ < after_);
+ EXPECT_TRUE(cbefore_ <= after_);
+ EXPECT_TRUE(after_ > cbefore_);
+ EXPECT_TRUE(after_ >= cbefore_);
+
+ EXPECT_FALSE(cbefore_ > after_);
+ EXPECT_FALSE(after_ < cbefore_);
+}
+
+TEST_F(IntSpanOrderComparisonTest, SpanOfConstAndContainer) {
+ EXPECT_TRUE(cbefore_ < vec_after_);
+ EXPECT_TRUE(cbefore_ <= vec_after_);
+ EXPECT_TRUE(vec_after_ > cbefore_);
+ EXPECT_TRUE(vec_after_ >= cbefore_);
+
+ EXPECT_FALSE(cbefore_ > vec_after_);
+ EXPECT_FALSE(vec_after_ < cbefore_);
+
+ EXPECT_TRUE(arr_before_ < cafter_);
+ EXPECT_TRUE(arr_before_ <= cafter_);
+ EXPECT_TRUE(cafter_ > arr_before_);
+ EXPECT_TRUE(cafter_ >= arr_before_);
+
+ EXPECT_FALSE(arr_before_ > cafter_);
+ EXPECT_FALSE(cafter_ < arr_before_);
+}
+
+TEST_F(IntSpanOrderComparisonTest, SpanOfMutableAndContainer) {
+ EXPECT_TRUE(vec_before_ < after_);
+ EXPECT_TRUE(vec_before_ <= after_);
+ EXPECT_TRUE(after_ > vec_before_);
+ EXPECT_TRUE(after_ >= vec_before_);
+
+ EXPECT_FALSE(vec_before_ > after_);
+ EXPECT_FALSE(after_ < vec_before_);
+
+ EXPECT_TRUE(before_ < carr_after_);
+ EXPECT_TRUE(before_ <= carr_after_);
+ EXPECT_TRUE(carr_after_ > before_);
+ EXPECT_TRUE(carr_after_ >= before_);
+
+ EXPECT_FALSE(before_ > carr_after_);
+ EXPECT_FALSE(carr_after_ < before_);
+}
+
+TEST_F(IntSpanOrderComparisonTest, EqualSpans) {
+ EXPECT_FALSE(before_ < before_);
+ EXPECT_TRUE(before_ <= before_);
+ EXPECT_FALSE(before_ > before_);
+ EXPECT_TRUE(before_ >= before_);
+}
+
+TEST_F(IntSpanOrderComparisonTest, Subspans) {
+ auto subspan = before_.subspan(0, 1);
+ EXPECT_TRUE(subspan < before_);
+ EXPECT_TRUE(subspan <= before_);
+ EXPECT_TRUE(before_ > subspan);
+ EXPECT_TRUE(before_ >= subspan);
+
+ EXPECT_FALSE(subspan > before_);
+ EXPECT_FALSE(before_ < subspan);
+}
+
+TEST_F(IntSpanOrderComparisonTest, EmptySpans) {
+ absl::Span<int> empty;
+ EXPECT_FALSE(empty < empty);
+ EXPECT_TRUE(empty <= empty);
+ EXPECT_FALSE(empty > empty);
+ EXPECT_TRUE(empty >= empty);
+
+ EXPECT_TRUE(empty < before_);
+ EXPECT_TRUE(empty <= before_);
+ EXPECT_TRUE(before_ > empty);
+ EXPECT_TRUE(before_ >= empty);
+
+ EXPECT_FALSE(empty > before_);
+ EXPECT_FALSE(before_ < empty);
+}
+
+TEST(IntSpan, ExposesContainerTypesAndConsts) {
+ absl::Span<int> slice;
+ CheckType<absl::Span<int>::iterator>(slice.begin());
+ EXPECT_TRUE((std::is_convertible<decltype(slice.begin()),
+ absl::Span<int>::const_iterator>::value));
+ CheckType<absl::Span<int>::const_iterator>(slice.cbegin());
+ EXPECT_TRUE((std::is_convertible<decltype(slice.end()),
+ absl::Span<int>::const_iterator>::value));
+ CheckType<absl::Span<int>::const_iterator>(slice.cend());
+ CheckType<absl::Span<int>::reverse_iterator>(slice.rend());
+ EXPECT_TRUE(
+ (std::is_convertible<decltype(slice.rend()),
+ absl::Span<int>::const_reverse_iterator>::value));
+ CheckType<absl::Span<int>::const_reverse_iterator>(slice.crend());
+ testing::StaticAssertTypeEq<int, absl::Span<int>::value_type>();
+ testing::StaticAssertTypeEq<int, absl::Span<const int>::value_type>();
+ testing::StaticAssertTypeEq<int*, absl::Span<int>::pointer>();
+ testing::StaticAssertTypeEq<const int*, absl::Span<const int>::pointer>();
+ testing::StaticAssertTypeEq<int&, absl::Span<int>::reference>();
+ testing::StaticAssertTypeEq<const int&, absl::Span<const int>::reference>();
+ testing::StaticAssertTypeEq<const int&, absl::Span<int>::const_reference>();
+ testing::StaticAssertTypeEq<const int&,
+ absl::Span<const int>::const_reference>();
+ EXPECT_EQ(static_cast<absl::Span<int>::size_type>(-1), absl::Span<int>::npos);
+}
+
+TEST(IntSpan, IteratorsAndReferences) {
+ auto accept_pointer = [](int*) {};
+ auto accept_reference = [](int&) {};
+ auto accept_iterator = [](absl::Span<int>::iterator) {};
+ auto accept_const_iterator = [](absl::Span<int>::const_iterator) {};
+ auto accept_reverse_iterator = [](absl::Span<int>::reverse_iterator) {};
+ auto accept_const_reverse_iterator =
+ [](absl::Span<int>::const_reverse_iterator) {};
+
+ int a[1];
+ absl::Span<int> s = a;
+
+ accept_pointer(s.data());
+ accept_iterator(s.begin());
+ accept_const_iterator(s.begin());
+ accept_const_iterator(s.cbegin());
+ accept_iterator(s.end());
+ accept_const_iterator(s.end());
+ accept_const_iterator(s.cend());
+ accept_reverse_iterator(s.rbegin());
+ accept_const_reverse_iterator(s.rbegin());
+ accept_const_reverse_iterator(s.crbegin());
+ accept_reverse_iterator(s.rend());
+ accept_const_reverse_iterator(s.rend());
+ accept_const_reverse_iterator(s.crend());
+
+ accept_reference(s[0]);
+ accept_reference(s.at(0));
+ accept_reference(s.front());
+ accept_reference(s.back());
+}
+
+TEST(IntSpan, IteratorsAndReferences_Const) {
+ auto accept_pointer = [](int*) {};
+ auto accept_reference = [](int&) {};
+ auto accept_iterator = [](absl::Span<int>::iterator) {};
+ auto accept_const_iterator = [](absl::Span<int>::const_iterator) {};
+ auto accept_reverse_iterator = [](absl::Span<int>::reverse_iterator) {};
+ auto accept_const_reverse_iterator =
+ [](absl::Span<int>::const_reverse_iterator) {};
+
+ int a[1];
+ const absl::Span<int> s = a;
+
+ accept_pointer(s.data());
+ accept_iterator(s.begin());
+ accept_const_iterator(s.begin());
+ accept_const_iterator(s.cbegin());
+ accept_iterator(s.end());
+ accept_const_iterator(s.end());
+ accept_const_iterator(s.cend());
+ accept_reverse_iterator(s.rbegin());
+ accept_const_reverse_iterator(s.rbegin());
+ accept_const_reverse_iterator(s.crbegin());
+ accept_reverse_iterator(s.rend());
+ accept_const_reverse_iterator(s.rend());
+ accept_const_reverse_iterator(s.crend());
+
+ accept_reference(s[0]);
+ accept_reference(s.at(0));
+ accept_reference(s.front());
+ accept_reference(s.back());
+}
+
+TEST(IntSpan, NoexceptTest) {
+ int a[] = {1, 2, 3};
+ std::vector<int> v;
+ EXPECT_TRUE(noexcept(absl::Span<const int>()));
+ EXPECT_TRUE(noexcept(absl::Span<const int>(a, 2)));
+ EXPECT_TRUE(noexcept(absl::Span<const int>(a)));
+ EXPECT_TRUE(noexcept(absl::Span<const int>(v)));
+ EXPECT_TRUE(noexcept(absl::Span<int>(v)));
+ EXPECT_TRUE(noexcept(absl::Span<const int>({1, 2, 3})));
+ EXPECT_TRUE(noexcept(absl::MakeSpan(v)));
+ EXPECT_TRUE(noexcept(absl::MakeSpan(a)));
+ EXPECT_TRUE(noexcept(absl::MakeSpan(a, 2)));
+ EXPECT_TRUE(noexcept(absl::MakeSpan(a, a + 1)));
+ EXPECT_TRUE(noexcept(absl::MakeConstSpan(v)));
+ EXPECT_TRUE(noexcept(absl::MakeConstSpan(a)));
+ EXPECT_TRUE(noexcept(absl::MakeConstSpan(a, 2)));
+ EXPECT_TRUE(noexcept(absl::MakeConstSpan(a, a + 1)));
+
+ absl::Span<int> s(v);
+ EXPECT_TRUE(noexcept(s.data()));
+ EXPECT_TRUE(noexcept(s.size()));
+ EXPECT_TRUE(noexcept(s.length()));
+ EXPECT_TRUE(noexcept(s.empty()));
+ EXPECT_TRUE(noexcept(s[0]));
+ EXPECT_TRUE(noexcept(s.front()));
+ EXPECT_TRUE(noexcept(s.back()));
+ EXPECT_TRUE(noexcept(s.begin()));
+ EXPECT_TRUE(noexcept(s.cbegin()));
+ EXPECT_TRUE(noexcept(s.end()));
+ EXPECT_TRUE(noexcept(s.cend()));
+ EXPECT_TRUE(noexcept(s.rbegin()));
+ EXPECT_TRUE(noexcept(s.crbegin()));
+ EXPECT_TRUE(noexcept(s.rend()));
+ EXPECT_TRUE(noexcept(s.crend()));
+ EXPECT_TRUE(noexcept(s.remove_prefix(0)));
+ EXPECT_TRUE(noexcept(s.remove_suffix(0)));
+}
+
+// ConstexprTester exercises expressions in a constexpr context. Simply placing
+// the expression in a constexpr function is not enough, as some compilers will
+// simply compile the constexpr function as runtime code. Using template
+// parameters forces compile-time execution.
+template <int i>
+struct ConstexprTester {};
+
+#define ABSL_TEST_CONSTEXPR(expr) \
+ do { \
+ ABSL_ATTRIBUTE_UNUSED ConstexprTester<(expr, 1)> t; \
+ } while (0)
+
+struct ContainerWithConstexprMethods {
+ constexpr int size() const { return 1; }
+ constexpr const int* data() const { return &i; }
+ const int i;
+};
+
+TEST(ConstIntSpan, ConstexprTest) {
+ static constexpr int a[] = {1, 2, 3};
+ static constexpr int sized_arr[2] = {1, 2};
+ static constexpr ContainerWithConstexprMethods c{1};
+ ABSL_TEST_CONSTEXPR(absl::Span<const int>());
+ ABSL_TEST_CONSTEXPR(absl::Span<const int>(a, 2));
+ ABSL_TEST_CONSTEXPR(absl::Span<const int>(sized_arr));
+ ABSL_TEST_CONSTEXPR(absl::Span<const int>(c));
+ ABSL_TEST_CONSTEXPR(absl::MakeSpan(&a[0], 1));
+ ABSL_TEST_CONSTEXPR(absl::MakeSpan(c));
+ ABSL_TEST_CONSTEXPR(absl::MakeSpan(a));
+ ABSL_TEST_CONSTEXPR(absl::MakeConstSpan(&a[0], 1));
+ ABSL_TEST_CONSTEXPR(absl::MakeConstSpan(c));
+ ABSL_TEST_CONSTEXPR(absl::MakeConstSpan(a));
+
+ constexpr absl::Span<const int> span = c;
+ ABSL_TEST_CONSTEXPR(span.data());
+ ABSL_TEST_CONSTEXPR(span.size());
+ ABSL_TEST_CONSTEXPR(span.length());
+ ABSL_TEST_CONSTEXPR(span.empty());
+ ABSL_TEST_CONSTEXPR(span.begin());
+ ABSL_TEST_CONSTEXPR(span.cbegin());
+ ABSL_TEST_CONSTEXPR(span.subspan(0, 0));
+ ABSL_TEST_CONSTEXPR(span[0]);
+}
+
+struct BigStruct {
+ char bytes[10000];
+};
+
+TEST(Span, SpanSize) {
+ EXPECT_LE(sizeof(absl::Span<int>), 2 * sizeof(void*));
+ EXPECT_LE(sizeof(absl::Span<BigStruct>), 2 * sizeof(void*));
+}
+
+} // namespace
diff --git a/absl/utility/BUILD.bazel b/absl/utility/BUILD.bazel
new file mode 100644
index 0000000..73d0519
--- /dev/null
+++ b/absl/utility/BUILD.bazel
@@ -0,0 +1,34 @@
+load(
+ "//absl:copts.bzl",
+ "ABSL_DEFAULT_COPTS",
+ "ABSL_TEST_COPTS",
+)
+load(
+ "//absl:test_dependencies.bzl",
+ "GUNIT_MAIN_DEPS_SELECTOR",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["unencumbered"]) # Owned by Google
+
+cc_library(
+ name = "utility",
+ srcs = ["utility.cc"],
+ hdrs = ["utility.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ "//absl/base:config",
+ "//absl/meta:type_traits",
+ ],
+)
+
+cc_test(
+ name = "utility_test",
+ srcs = ["utility_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":utility",
+ "//absl/base:core_headers",
+ ] + select(GUNIT_MAIN_DEPS_SELECTOR),
+)
diff --git a/absl/utility/utility.cc b/absl/utility/utility.cc
new file mode 100644
index 0000000..fce79f5
--- /dev/null
+++ b/absl/utility/utility.cc
@@ -0,0 +1,27 @@
+// 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: ascii.h
+// -----------------------------------------------------------------------------
+//
+#include "absl/utility/utility.h"
+
+namespace absl {
+
+#ifndef ABSL_HAVE_STD_OPTIONAL
+const in_place_t in_place{};
+#endif
+
+} // namespace absl
diff --git a/absl/utility/utility.h b/absl/utility/utility.h
new file mode 100644
index 0000000..4f4a062
--- /dev/null
+++ b/absl/utility/utility.h
@@ -0,0 +1,177 @@
+// 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/utility:utility is an extension of the <utility> header
+//
+// It provides stand-ins for C++14's std::integer_sequence and
+// related utilities. They are intended to be exactly equivalent.
+// - integer_sequence<T, Ints...> == std::integer_sequence<T, Ints...>
+// - index_sequence<Ints...> == std::index_sequence<Ints...>
+// - make_integer_sequence<T, N> == std::make_integer_sequence<T, N>
+// - make_index_sequence<N> == std::make_index_sequence<N>
+// - index_sequence_for<Ts...> == std::index_sequence_for<Ts...>
+//
+// It also provides the tag types in_place_t, in_place_type_t, and
+// in_place_index_t, as well as the constant in_place, and constexpr std::move
+// and std::forward impolementations in C++11.
+//
+// References:
+// http://en.cppreference.com/w/cpp/utility/integer_sequence
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3658.html
+//
+// Example:
+// // Unpack a tuple for use as a function call's argument list.
+//
+// template <typename F, typename Tup, size_t... Is>
+// auto Impl(F f, const Tup& tup, index_sequence<Is...>)
+// -> decltype(f(std::get<Is>(tup) ...)) {
+// return f(std::get<Is>(tup) ...);
+// }
+//
+// template <typename Tup>
+// using TupIdxSeq = make_index_sequence<std::tuple_size<Tup>::value>;
+//
+// template <typename F, typename Tup>
+// auto ApplyFromTuple(F f, const Tup& tup)
+// -> decltype(Impl(f, tup, TupIdxSeq<Tup>{})) {
+// return Impl(f, tup, TupIdxSeq<Tup>{});
+// }
+#ifndef ABSL_UTILITY_UTILITY_H_
+#define ABSL_UTILITY_UTILITY_H_
+
+#include <cstddef>
+#include <cstdlib>
+#include <utility>
+
+#include "absl/base/config.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+
+// Equivalent to std::integer_sequence.
+//
+// Function templates can deduce compile-time integer sequences by accepting
+// an argument of integer_sequence<T, Ints...>. This is a common need when
+// working with C++11 variadic templates.
+//
+// T - the integer type of the sequence elements
+// ...Ints - a parameter pack of T values representing the sequence
+template <typename T, T... Ints>
+struct integer_sequence {
+ using value_type = T;
+ static constexpr size_t size() noexcept { return sizeof...(Ints); }
+};
+
+// Equivalent to std::index_sequence.
+//
+// Alias for an integer_sequence of size_t.
+template <size_t... Ints>
+using index_sequence = integer_sequence<size_t, Ints...>;
+
+namespace utility_internal {
+
+template <typename Seq, size_t SeqSize, size_t Rem>
+struct Extend;
+
+// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency.
+template <typename T, T... Ints, size_t SeqSize>
+struct Extend<integer_sequence<T, Ints...>, SeqSize, 0> {
+ using type = integer_sequence<T, Ints..., (Ints + SeqSize)...>;
+};
+
+template <typename T, T... Ints, size_t SeqSize>
+struct Extend<integer_sequence<T, Ints...>, SeqSize, 1> {
+ using type = integer_sequence<T, Ints..., (Ints + SeqSize)..., 2 * SeqSize>;
+};
+
+// Recursion helper for 'make_integer_sequence<T, N>'.
+// 'Gen<T, N>::type' is an alias for 'integer_sequence<T, 0, 1, ... N-1>'.
+template <typename T, size_t N>
+struct Gen {
+ using type =
+ typename Extend<typename Gen<T, N / 2>::type, N / 2, N % 2>::type;
+};
+
+template <typename T>
+struct Gen<T, 0> {
+ using type = integer_sequence<T>;
+};
+
+} // namespace utility_internal
+
+// Compile-time sequences of integers
+
+// Equivalent to std::make_integer_sequence.
+//
+// make_integer_sequence<int, N> is integer_sequence<int, 0, 1, ..., N-1>;
+template <typename T, T N>
+using make_integer_sequence = typename utility_internal::Gen<T, N>::type;
+
+// Equivalent to std::make_index_sequence.
+//
+// make_index_sequence<N> is index_sequence<0, 1, ..., N-1>;
+template <size_t N>
+using make_index_sequence = make_integer_sequence<size_t, N>;
+
+// Equivalent to std::index_sequence_for.
+//
+// Convert a typename pack into an index sequence of the same length.
+template <typename... Ts>
+using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
+
+// Tag types
+
+#ifdef ABSL_HAVE_STD_OPTIONAL
+
+using std::in_place_t;
+using std::in_place;
+
+#else // ABSL_HAVE_STD_OPTIONAL
+
+// Tag type used in order to specify in-place construction, such as with
+// absl::optional.
+struct in_place_t {};
+extern const in_place_t in_place;
+
+#endif // ABSL_HAVE_STD_OPTIONAL
+
+#ifdef ABSL_HAVE_STD_ANY
+using std::in_place_type_t;
+#else
+// Tag types used for in-place construction when the type to construct needs to
+// be specified, such as with absl::variant and absl::any.
+template <typename T>
+struct in_place_type_t {};
+#endif // ABSL_HAVE_STD_ANY
+
+template <size_t I>
+struct in_place_index_t {};
+
+// Constexpr move and forward
+
+template <typename T>
+constexpr absl::remove_reference_t<T>&& move(T&& t) noexcept {
+ return static_cast<absl::remove_reference_t<T>&&>(t);
+}
+
+template <typename T>
+constexpr T&& forward(
+ absl::remove_reference_t<T>& t) noexcept { // NOLINT(runtime/references)
+ return static_cast<T&&>(t);
+}
+
+} // namespace absl
+
+#endif // ABSL_UTILITY_UTILITY_H_
diff --git a/absl/utility/utility_test.cc b/absl/utility/utility_test.cc
new file mode 100644
index 0000000..62cb46f
--- /dev/null
+++ b/absl/utility/utility_test.cc
@@ -0,0 +1,163 @@
+// 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/utility/utility.h"
+
+#include <sstream>
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+
+namespace {
+
+#ifdef _MSC_VER
+// Warnings for unused variables in this test are false positives. On other
+// platforms, they are suppressed by ABSL_ATTRIBUTE_UNUSED, but that doesn't
+// work on MSVC.
+// Both the unused variables and the name length warnings are due to calls
+// to absl::make_index_sequence with very large values, creating very long type
+// names. The resulting warnings are so long they make build output unreadable.
+#pragma warning( push )
+#pragma warning( disable : 4503 ) // decorated name length exceeded
+#pragma warning( disable : 4101 ) // unreferenced local variable
+#endif // _MSC_VER
+
+using testing::StaticAssertTypeEq;
+using testing::ElementsAre;
+
+TEST(IntegerSequenceTest, ValueType) {
+ StaticAssertTypeEq<int, absl::integer_sequence<int>::value_type>();
+ StaticAssertTypeEq<char, absl::integer_sequence<char>::value_type>();
+}
+
+TEST(IntegerSequenceTest, Size) {
+ EXPECT_EQ(0, (absl::integer_sequence<int>::size()));
+ EXPECT_EQ(1, (absl::integer_sequence<int, 0>::size()));
+ EXPECT_EQ(1, (absl::integer_sequence<int, 1>::size()));
+ EXPECT_EQ(2, (absl::integer_sequence<int, 1, 2>::size()));
+ EXPECT_EQ(3, (absl::integer_sequence<int, 0, 1, 2>::size()));
+ EXPECT_EQ(3, (absl::integer_sequence<int, -123, 123, 456>::size()));
+ constexpr size_t sz = absl::integer_sequence<int, 0, 1>::size();
+ EXPECT_EQ(2, sz);
+}
+
+TEST(IntegerSequenceTest, MakeIndexSequence) {
+ StaticAssertTypeEq<absl::index_sequence<>, absl::make_index_sequence<0>>();
+ StaticAssertTypeEq<absl::index_sequence<0>, absl::make_index_sequence<1>>();
+ StaticAssertTypeEq<absl::index_sequence<0, 1>,
+ absl::make_index_sequence<2>>();
+ StaticAssertTypeEq<absl::index_sequence<0, 1, 2>,
+ absl::make_index_sequence<3>>();
+}
+
+TEST(IntegerSequenceTest, MakeIntegerSequence) {
+ StaticAssertTypeEq<absl::integer_sequence<int>,
+ absl::make_integer_sequence<int, 0>>();
+ StaticAssertTypeEq<absl::integer_sequence<int, 0>,
+ absl::make_integer_sequence<int, 1>>();
+ StaticAssertTypeEq<absl::integer_sequence<int, 0, 1>,
+ absl::make_integer_sequence<int, 2>>();
+ StaticAssertTypeEq<absl::integer_sequence<int, 0, 1, 2>,
+ absl::make_integer_sequence<int, 3>>();
+}
+
+template <typename... Ts>
+class Counter {};
+
+template <size_t... Is>
+void CountAll(absl::index_sequence<Is...>) {
+ // We only need an alias here, but instantiate a variable to silence warnings
+ // for unused typedefs in some compilers.
+ ABSL_ATTRIBUTE_UNUSED Counter<absl::make_index_sequence<Is>...> seq;
+}
+
+// This test verifies that absl::make_index_sequence can handle large arguments
+// without blowing up template instantiation stack, going OOM or taking forever
+// to compile (there is hard 15 minutes limit imposed by forge).
+TEST(IntegerSequenceTest, MakeIndexSequencePerformance) {
+ // O(log N) template instantiations.
+ // We only need an alias here, but instantiate a variable to silence warnings
+ // for unused typedefs in some compilers.
+ ABSL_ATTRIBUTE_UNUSED absl::make_index_sequence<(1 << 16) - 1> seq;
+ // O(N) template instantiations.
+ CountAll(absl::make_index_sequence<(1 << 8) - 1>());
+}
+
+template <typename F, typename Tup, size_t... Is>
+auto ApplyFromTupleImpl(F f, const Tup& tup, absl::index_sequence<Is...>)
+ -> decltype(f(std::get<Is>(tup)...)) {
+ return f(std::get<Is>(tup)...);
+}
+
+template <typename Tup>
+using TupIdxSeq = absl::make_index_sequence<std::tuple_size<Tup>::value>;
+
+template <typename F, typename Tup>
+auto ApplyFromTuple(F f, const Tup& tup)
+ -> decltype(ApplyFromTupleImpl(f, tup, TupIdxSeq<Tup>{})) {
+ return ApplyFromTupleImpl(f, tup, TupIdxSeq<Tup>{});
+}
+
+template <typename T>
+std::string Fmt(const T& x) {
+ std::ostringstream os;
+ os << x;
+ return os.str();
+}
+
+struct PoorStrCat {
+ template <typename... Args>
+ std::string operator()(const Args&... args) const {
+ std::string r;
+ for (const auto& e : {Fmt(args)...}) r += e;
+ return r;
+ }
+};
+
+template <typename Tup, size_t... Is>
+std::vector<std::string> TupStringVecImpl(const Tup& tup,
+ absl::index_sequence<Is...>) {
+ return {Fmt(std::get<Is>(tup))...};
+}
+
+template <typename... Ts>
+std::vector<std::string> TupStringVec(const std::tuple<Ts...>& tup) {
+ return TupStringVecImpl(tup, absl::index_sequence_for<Ts...>());
+}
+
+TEST(MakeIndexSequenceTest, ApplyFromTupleExample) {
+ PoorStrCat f{};
+ EXPECT_EQ("12abc3.14", f(12, "abc", 3.14));
+ EXPECT_EQ("12abc3.14", ApplyFromTuple(f, std::make_tuple(12, "abc", 3.14)));
+}
+
+TEST(IndexSequenceForTest, Basic) {
+ StaticAssertTypeEq<absl::index_sequence<>, absl::index_sequence_for<>>();
+ StaticAssertTypeEq<absl::index_sequence<0>, absl::index_sequence_for<int>>();
+ StaticAssertTypeEq<absl::index_sequence<0, 1, 2, 3>,
+ absl::index_sequence_for<int, void, char, int>>();
+}
+
+TEST(IndexSequenceForTest, Example) {
+ EXPECT_THAT(TupStringVec(std::make_tuple(12, "abc", 3.14)),
+ ElementsAre("12", "abc", "3.14"));
+}
+
+} // namespace
+