Merge commit '0813614061b70207373d8ecebe5eece00d2c725a' into master
Update absl to get int128
Change-Id: I25cde112fe3b68bbbd41e45b2e5b704a7f5af9a0
diff --git a/third_party/abseil/.github/ISSUE_TEMPLATE/00-bug_report.md b/third_party/abseil/.github/ISSUE_TEMPLATE/00-bug_report.md
new file mode 100644
index 0000000..1edf3de
--- /dev/null
+++ b/third_party/abseil/.github/ISSUE_TEMPLATE/00-bug_report.md
@@ -0,0 +1,41 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: 'bug'
+assignees: ''
+---
+
+**Describe the bug**
+
+Include a clear and concise description of what the problem is, including what
+you expected to happen, and what actually happened.
+
+**Steps to reproduce the bug**
+
+It's important that we are able to reproduce the problem that you are
+experiencing. Please provide all code and relevant steps to reproduce the
+problem, including your `BUILD`/`CMakeLists.txt` file and build commands. Links
+to a GitHub branch or [godbolt.org](https://godbolt.org/) that demonstrate the
+problem are also helpful.
+
+**What version of Abseil are you using?**
+
+**What operating system and version are you using**
+
+If you are using a Linux distribution please include the name and version of the
+distribution as well.
+
+**What compiler and version are you using?**
+
+Please include the output of `gcc -v` or `clang -v`, or the equivalent for your
+compiler.
+
+**What build system are you using?**
+
+Please include the output of `bazel --version` or `cmake --version`, or the
+equivalent for your build system.
+
+**Additional context**
+
+Add any other context about the problem here.
diff --git a/third_party/abseil/.github/ISSUE_TEMPLATE/90-question.md b/third_party/abseil/.github/ISSUE_TEMPLATE/90-question.md
new file mode 100644
index 0000000..84cf349
--- /dev/null
+++ b/third_party/abseil/.github/ISSUE_TEMPLATE/90-question.md
@@ -0,0 +1,7 @@
+---
+name: Question
+about: Have a question? Ask us anything! :-)
+title: ''
+labels: 'question'
+assignees: ''
+---
diff --git a/third_party/abseil/.github/ISSUE_TEMPLATE/config.yml b/third_party/abseil/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..9794ae1
--- /dev/null
+++ b/third_party/abseil/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1 @@
+blank_issues_enables: true
diff --git a/third_party/abseil/BUILD.bazel b/third_party/abseil/BUILD.bazel
new file mode 100644
index 0000000..79fb0ec
--- /dev/null
+++ b/third_party/abseil/BUILD.bazel
@@ -0,0 +1,25 @@
+#
+# Copyright 2020 The Abseil Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"]) # Apache 2.0
+
+# Expose license for external usage through bazel.
+exports_files([
+ "AUTHORS",
+ "LICENSE",
+])
diff --git a/third_party/abseil/CMake/AbseilDll.cmake b/third_party/abseil/CMake/AbseilDll.cmake
new file mode 100644
index 0000000..7c98b21
--- /dev/null
+++ b/third_party/abseil/CMake/AbseilDll.cmake
@@ -0,0 +1,519 @@
+include(CMakeParseArguments)
+
+set(ABSL_INTERNAL_DLL_FILES
+ "algorithm/algorithm.h"
+ "algorithm/container.h"
+ "base/attributes.h"
+ "base/call_once.h"
+ "base/casts.h"
+ "base/config.h"
+ "base/const_init.h"
+ "base/dynamic_annotations.h"
+ "base/internal/atomic_hook.h"
+ "base/internal/cycleclock.cc"
+ "base/internal/cycleclock.h"
+ "base/internal/direct_mmap.h"
+ "base/internal/dynamic_annotations.h"
+ "base/internal/endian.h"
+ "base/internal/errno_saver.h"
+ "base/internal/exponential_biased.cc"
+ "base/internal/exponential_biased.h"
+ "base/internal/fast_type_id.h"
+ "base/internal/hide_ptr.h"
+ "base/internal/identity.h"
+ "base/internal/invoke.h"
+ "base/internal/inline_variable.h"
+ "base/internal/low_level_alloc.cc"
+ "base/internal/low_level_alloc.h"
+ "base/internal/low_level_scheduling.h"
+ "base/internal/per_thread_tls.h"
+ "base/internal/periodic_sampler.cc"
+ "base/internal/periodic_sampler.h"
+ "base/internal/pretty_function.h"
+ "base/internal/raw_logging.cc"
+ "base/internal/raw_logging.h"
+ "base/internal/scheduling_mode.h"
+ "base/internal/scoped_set_env.cc"
+ "base/internal/scoped_set_env.h"
+ "base/internal/strerror.h"
+ "base/internal/strerror.cc"
+ "base/internal/spinlock.cc"
+ "base/internal/spinlock.h"
+ "base/internal/spinlock_wait.cc"
+ "base/internal/spinlock_wait.h"
+ "base/internal/sysinfo.cc"
+ "base/internal/sysinfo.h"
+ "base/internal/thread_annotations.h"
+ "base/internal/thread_identity.cc"
+ "base/internal/thread_identity.h"
+ "base/internal/throw_delegate.cc"
+ "base/internal/throw_delegate.h"
+ "base/internal/tsan_mutex_interface.h"
+ "base/internal/unaligned_access.h"
+ "base/internal/unscaledcycleclock.cc"
+ "base/internal/unscaledcycleclock.h"
+ "base/log_severity.cc"
+ "base/log_severity.h"
+ "base/macros.h"
+ "base/optimization.h"
+ "base/options.h"
+ "base/policy_checks.h"
+ "base/port.h"
+ "base/thread_annotations.h"
+ "container/btree_map.h"
+ "container/btree_set.h"
+ "container/fixed_array.h"
+ "container/flat_hash_map.h"
+ "container/flat_hash_set.h"
+ "container/inlined_vector.h"
+ "container/internal/btree.h"
+ "container/internal/btree_container.h"
+ "container/internal/common.h"
+ "container/internal/compressed_tuple.h"
+ "container/internal/container_memory.h"
+ "container/internal/counting_allocator.h"
+ "container/internal/hash_function_defaults.h"
+ "container/internal/hash_policy_traits.h"
+ "container/internal/hashtable_debug.h"
+ "container/internal/hashtable_debug_hooks.h"
+ "container/internal/hashtablez_sampler.cc"
+ "container/internal/hashtablez_sampler.h"
+ "container/internal/hashtablez_sampler_force_weak_definition.cc"
+ "container/internal/have_sse.h"
+ "container/internal/inlined_vector.h"
+ "container/internal/layout.h"
+ "container/internal/node_hash_policy.h"
+ "container/internal/raw_hash_map.h"
+ "container/internal/raw_hash_set.cc"
+ "container/internal/raw_hash_set.h"
+ "container/internal/tracked.h"
+ "container/node_hash_map.h"
+ "container/node_hash_set.h"
+ "debugging/failure_signal_handler.cc"
+ "debugging/failure_signal_handler.h"
+ "debugging/leak_check.h"
+ "debugging/leak_check_disable.cc"
+ "debugging/stacktrace.cc"
+ "debugging/stacktrace.h"
+ "debugging/symbolize.cc"
+ "debugging/symbolize.h"
+ "debugging/internal/address_is_readable.cc"
+ "debugging/internal/address_is_readable.h"
+ "debugging/internal/demangle.cc"
+ "debugging/internal/demangle.h"
+ "debugging/internal/elf_mem_image.cc"
+ "debugging/internal/elf_mem_image.h"
+ "debugging/internal/examine_stack.cc"
+ "debugging/internal/examine_stack.h"
+ "debugging/internal/stack_consumption.cc"
+ "debugging/internal/stack_consumption.h"
+ "debugging/internal/stacktrace_config.h"
+ "debugging/internal/symbolize.h"
+ "debugging/internal/vdso_support.cc"
+ "debugging/internal/vdso_support.h"
+ "functional/internal/front_binder.h"
+ "functional/bind_front.h"
+ "functional/function_ref.h"
+ "functional/internal/function_ref.h"
+ "hash/hash.h"
+ "hash/internal/city.h"
+ "hash/internal/city.cc"
+ "hash/internal/hash.h"
+ "hash/internal/hash.cc"
+ "hash/internal/spy_hash_state.h"
+ "hash/internal/wyhash.h"
+ "hash/internal/wyhash.cc"
+ "memory/memory.h"
+ "meta/type_traits.h"
+ "numeric/bits.h"
+ "numeric/int128.cc"
+ "numeric/int128.h"
+ "numeric/internal/bits.h"
+ "random/bernoulli_distribution.h"
+ "random/beta_distribution.h"
+ "random/bit_gen_ref.h"
+ "random/discrete_distribution.cc"
+ "random/discrete_distribution.h"
+ "random/distributions.h"
+ "random/exponential_distribution.h"
+ "random/gaussian_distribution.cc"
+ "random/gaussian_distribution.h"
+ "random/internal/distribution_caller.h"
+ "random/internal/fastmath.h"
+ "random/internal/fast_uniform_bits.h"
+ "random/internal/generate_real.h"
+ "random/internal/iostream_state_saver.h"
+ "random/internal/mock_helpers.h"
+ "random/internal/nonsecure_base.h"
+ "random/internal/pcg_engine.h"
+ "random/internal/platform.h"
+ "random/internal/pool_urbg.cc"
+ "random/internal/pool_urbg.h"
+ "random/internal/randen.cc"
+ "random/internal/randen.h"
+ "random/internal/randen_detect.cc"
+ "random/internal/randen_detect.h"
+ "random/internal/randen_engine.h"
+ "random/internal/randen_hwaes.cc"
+ "random/internal/randen_hwaes.h"
+ "random/internal/randen_round_keys.cc"
+ "random/internal/randen_slow.cc"
+ "random/internal/randen_slow.h"
+ "random/internal/randen_traits.h"
+ "random/internal/salted_seed_seq.h"
+ "random/internal/seed_material.cc"
+ "random/internal/seed_material.h"
+ "random/internal/sequence_urbg.h"
+ "random/internal/traits.h"
+ "random/internal/uniform_helper.h"
+ "random/internal/wide_multiply.h"
+ "random/log_uniform_int_distribution.h"
+ "random/poisson_distribution.h"
+ "random/random.h"
+ "random/seed_gen_exception.cc"
+ "random/seed_gen_exception.h"
+ "random/seed_sequences.cc"
+ "random/seed_sequences.h"
+ "random/uniform_int_distribution.h"
+ "random/uniform_real_distribution.h"
+ "random/zipf_distribution.h"
+ "status/internal/status_internal.h"
+ "status/internal/statusor_internal.h"
+ "status/status.h"
+ "status/status.cc"
+ "status/statusor.h"
+ "status/statusor.cc"
+ "status/status_payload_printer.h"
+ "status/status_payload_printer.cc"
+ "strings/ascii.cc"
+ "strings/ascii.h"
+ "strings/charconv.cc"
+ "strings/charconv.h"
+ "strings/cord.cc"
+ "strings/cord.h"
+ "strings/escaping.cc"
+ "strings/escaping.h"
+ "strings/internal/cord_internal.cc"
+ "strings/internal/cord_internal.h"
+ "strings/internal/cord_rep_flat.h"
+ "strings/internal/charconv_bigint.cc"
+ "strings/internal/charconv_bigint.h"
+ "strings/internal/charconv_parse.cc"
+ "strings/internal/charconv_parse.h"
+ "strings/internal/stl_type_traits.h"
+ "strings/internal/string_constant.h"
+ "strings/match.cc"
+ "strings/match.h"
+ "strings/numbers.cc"
+ "strings/numbers.h"
+ "strings/str_format.h"
+ "strings/str_cat.cc"
+ "strings/str_cat.h"
+ "strings/str_join.h"
+ "strings/str_replace.cc"
+ "strings/str_replace.h"
+ "strings/str_split.cc"
+ "strings/str_split.h"
+ "strings/string_view.cc"
+ "strings/string_view.h"
+ "strings/strip.h"
+ "strings/substitute.cc"
+ "strings/substitute.h"
+ "strings/internal/char_map.h"
+ "strings/internal/escaping.h"
+ "strings/internal/escaping.cc"
+ "strings/internal/memutil.cc"
+ "strings/internal/memutil.h"
+ "strings/internal/ostringstream.cc"
+ "strings/internal/ostringstream.h"
+ "strings/internal/pow10_helper.cc"
+ "strings/internal/pow10_helper.h"
+ "strings/internal/resize_uninitialized.h"
+ "strings/internal/str_format/arg.cc"
+ "strings/internal/str_format/arg.h"
+ "strings/internal/str_format/bind.cc"
+ "strings/internal/str_format/bind.h"
+ "strings/internal/str_format/checker.h"
+ "strings/internal/str_format/extension.cc"
+ "strings/internal/str_format/extension.h"
+ "strings/internal/str_format/float_conversion.cc"
+ "strings/internal/str_format/float_conversion.h"
+ "strings/internal/str_format/output.cc"
+ "strings/internal/str_format/output.h"
+ "strings/internal/str_format/parser.cc"
+ "strings/internal/str_format/parser.h"
+ "strings/internal/str_join_internal.h"
+ "strings/internal/str_split_internal.h"
+ "strings/internal/utf8.cc"
+ "strings/internal/utf8.h"
+ "synchronization/barrier.cc"
+ "synchronization/barrier.h"
+ "synchronization/blocking_counter.cc"
+ "synchronization/blocking_counter.h"
+ "synchronization/mutex.cc"
+ "synchronization/mutex.h"
+ "synchronization/notification.cc"
+ "synchronization/notification.h"
+ "synchronization/internal/create_thread_identity.cc"
+ "synchronization/internal/create_thread_identity.h"
+ "synchronization/internal/futex.h"
+ "synchronization/internal/graphcycles.cc"
+ "synchronization/internal/graphcycles.h"
+ "synchronization/internal/kernel_timeout.h"
+ "synchronization/internal/per_thread_sem.cc"
+ "synchronization/internal/per_thread_sem.h"
+ "synchronization/internal/thread_pool.h"
+ "synchronization/internal/waiter.cc"
+ "synchronization/internal/waiter.h"
+ "time/civil_time.cc"
+ "time/civil_time.h"
+ "time/clock.cc"
+ "time/clock.h"
+ "time/duration.cc"
+ "time/format.cc"
+ "time/time.cc"
+ "time/time.h"
+ "time/internal/cctz/include/cctz/civil_time.h"
+ "time/internal/cctz/include/cctz/civil_time_detail.h"
+ "time/internal/cctz/include/cctz/time_zone.h"
+ "time/internal/cctz/include/cctz/zone_info_source.h"
+ "time/internal/cctz/src/civil_time_detail.cc"
+ "time/internal/cctz/src/time_zone_fixed.cc"
+ "time/internal/cctz/src/time_zone_fixed.h"
+ "time/internal/cctz/src/time_zone_format.cc"
+ "time/internal/cctz/src/time_zone_if.cc"
+ "time/internal/cctz/src/time_zone_if.h"
+ "time/internal/cctz/src/time_zone_impl.cc"
+ "time/internal/cctz/src/time_zone_impl.h"
+ "time/internal/cctz/src/time_zone_info.cc"
+ "time/internal/cctz/src/time_zone_info.h"
+ "time/internal/cctz/src/time_zone_libc.cc"
+ "time/internal/cctz/src/time_zone_libc.h"
+ "time/internal/cctz/src/time_zone_lookup.cc"
+ "time/internal/cctz/src/time_zone_posix.cc"
+ "time/internal/cctz/src/time_zone_posix.h"
+ "time/internal/cctz/src/tzfile.h"
+ "time/internal/cctz/src/zone_info_source.cc"
+ "types/any.h"
+ "types/bad_any_cast.cc"
+ "types/bad_any_cast.h"
+ "types/bad_optional_access.cc"
+ "types/bad_optional_access.h"
+ "types/bad_variant_access.cc"
+ "types/bad_variant_access.h"
+ "types/compare.h"
+ "types/internal/conformance_aliases.h"
+ "types/internal/conformance_archetype.h"
+ "types/internal/conformance_profile.h"
+ "types/internal/parentheses.h"
+ "types/internal/transform_args.h"
+ "types/internal/variant.h"
+ "types/optional.h"
+ "types/internal/optional.h"
+ "types/span.h"
+ "types/internal/span.h"
+ "types/variant.h"
+ "utility/utility.h"
+)
+
+set(ABSL_INTERNAL_DLL_TARGETS
+ "stacktrace"
+ "symbolize"
+ "examine_stack"
+ "failure_signal_handler"
+ "debugging_internal"
+ "demangle_internal"
+ "leak_check"
+ "leak_check_disable"
+ "stack_consumption"
+ "debugging"
+ "hash"
+ "spy_hash_state"
+ "city"
+ "memory"
+ "strings"
+ "strings_internal"
+ "cord"
+ "str_format"
+ "str_format_internal"
+ "pow10_helper"
+ "int128"
+ "numeric"
+ "utility"
+ "any"
+ "bad_any_cast"
+ "bad_any_cast_impl"
+ "span"
+ "optional"
+ "bad_optional_access"
+ "bad_variant_access"
+ "variant"
+ "compare"
+ "algorithm"
+ "algorithm_container"
+ "graphcycles_internal"
+ "kernel_timeout_internal"
+ "synchronization"
+ "thread_pool"
+ "bind_front"
+ "function_ref"
+ "atomic_hook"
+ "log_severity"
+ "raw_logging_internal"
+ "spinlock_wait"
+ "config"
+ "dynamic_annotations"
+ "core_headers"
+ "malloc_internal"
+ "base_internal"
+ "base"
+ "throw_delegate"
+ "pretty_function"
+ "endian"
+ "bits"
+ "exponential_biased"
+ "periodic_sampler"
+ "scoped_set_env"
+ "type_traits"
+ "meta"
+ "random_random"
+ "random_bit_gen_ref"
+ "random_distributions"
+ "random_seed_gen_exception"
+ "random_seed_sequences"
+ "random_internal_traits"
+ "random_internal_distribution_caller"
+ "random_internal_distributions"
+ "random_internal_fast_uniform_bits"
+ "random_internal_seed_material"
+ "random_internal_pool_urbg"
+ "random_internal_explicit_seed_seq"
+ "random_internal_sequence_urbg"
+ "random_internal_salted_seed_seq"
+ "random_internal_iostream_state_saver"
+ "random_internal_generate_real"
+ "random_internal_wide_multiply"
+ "random_internal_fastmath"
+ "random_internal_nonsecure_base"
+ "random_internal_pcg_engine"
+ "random_internal_randen_engine"
+ "random_internal_platform"
+ "random_internal_randen"
+ "random_internal_randen_slow"
+ "random_internal_randen_hwaes"
+ "random_internal_randen_hwaes_impl"
+ "random_internal_uniform_helper"
+ "status"
+ "time"
+ "civil_time"
+ "time_zone"
+ "container"
+ "btree"
+ "compressed_tuple"
+ "fixed_array"
+ "inlined_vector_internal"
+ "inlined_vector"
+ "counting_allocator"
+ "flat_hash_map"
+ "flat_hash_set"
+ "node_hash_map"
+ "node_hash_set"
+ "container_memory"
+ "hash_function_defaults"
+ "hash_policy_traits"
+ "hashtablez_sampler"
+ "hashtable_debug"
+ "hashtable_debug_hooks"
+ "have_sse"
+ "node_hash_policy"
+ "raw_hash_map"
+ "container_common"
+ "raw_hash_set"
+ "layout"
+ "tracked"
+)
+
+function(absl_internal_dll_contains)
+ cmake_parse_arguments(ABSL_INTERNAL_DLL
+ ""
+ "OUTPUT;TARGET"
+ ""
+ ${ARGN}
+ )
+
+ STRING(REGEX REPLACE "^absl::" "" _target ${ABSL_INTERNAL_DLL_TARGET})
+
+ list(FIND
+ ABSL_INTERNAL_DLL_TARGETS
+ "${_target}"
+ _index)
+
+ if (${_index} GREATER -1)
+ set(${ABSL_INTERNAL_DLL_OUTPUT} 1 PARENT_SCOPE)
+ else()
+ set(${ABSL_INTERNAL_DLL_OUTPUT} 0 PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(absl_internal_dll_targets)
+ cmake_parse_arguments(ABSL_INTERNAL_DLL
+ ""
+ "OUTPUT"
+ "DEPS"
+ ${ARGN}
+ )
+
+ set(_deps "")
+ foreach(dep IN LISTS ABSL_INTERNAL_DLL_DEPS)
+ absl_internal_dll_contains(TARGET ${dep} OUTPUT _contains)
+ if (_contains)
+ list(APPEND _deps abseil_dll)
+ else()
+ list(APPEND _deps ${dep})
+ endif()
+ endforeach()
+
+ # Because we may have added the DLL multiple times
+ list(REMOVE_DUPLICATES _deps)
+ set(${ABSL_INTERNAL_DLL_OUTPUT} "${_deps}" PARENT_SCOPE)
+endfunction()
+
+function(absl_make_dll)
+ add_library(
+ abseil_dll
+ SHARED
+ "${ABSL_INTERNAL_DLL_FILES}"
+ )
+ target_link_libraries(
+ abseil_dll
+ PRIVATE
+ ${ABSL_DEFAULT_LINKOPTS}
+ )
+ set_property(TARGET abseil_dll PROPERTY LINKER_LANGUAGE "CXX")
+ target_include_directories(
+ abseil_dll
+ PUBLIC
+ "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>"
+ $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
+ )
+
+ target_compile_options(
+ abseil_dll
+ PRIVATE
+ ${ABSL_DEFAULT_COPTS}
+ )
+
+ target_compile_definitions(
+ abseil_dll
+ PRIVATE
+ ABSL_BUILD_DLL
+ NOMINMAX
+ INTERFACE
+ ${ABSL_CC_LIB_DEFINES}
+ )
+ install(TARGETS abseil_dll EXPORT ${PROJECT_NAME}Targets
+ RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${ABSL_INSTALL_LIBDIR}
+ )
+endfunction()
diff --git a/third_party/abseil/CMake/AbseilHelpers.cmake b/third_party/abseil/CMake/AbseilHelpers.cmake
index 67b97fe..e88507d 100644
--- a/third_party/abseil/CMake/AbseilHelpers.cmake
+++ b/third_party/abseil/CMake/AbseilHelpers.cmake
@@ -16,13 +16,16 @@
include(CMakeParseArguments)
include(AbseilConfigureCopts)
+include(AbseilDll)
include(AbseilInstallDirs)
# The IDE folder for Abseil that will be used if Abseil is included in a CMake
# project that sets
# set_property(GLOBAL PROPERTY USE_FOLDERS ON)
# For example, Visual Studio supports folders.
-set(ABSL_IDE_FOLDER Abseil)
+if(NOT DEFINED ABSL_IDE_FOLDER)
+ set(ABSL_IDE_FOLDER Abseil)
+endif()
# absl_cc_library()
#
@@ -80,95 +83,220 @@
${ARGN}
)
- if(NOT ABSL_CC_LIB_TESTONLY OR ABSL_RUN_TESTS)
- if(ABSL_ENABLE_INSTALL)
- set(_NAME "${ABSL_CC_LIB_NAME}")
- else()
- set(_NAME "absl_${ABSL_CC_LIB_NAME}")
- endif()
+ if(ABSL_CC_LIB_TESTONLY AND NOT ABSL_RUN_TESTS)
+ return()
+ endif()
- # Check if this is a header-only library
- # Note that as of February 2019, many popular OS's (for example, Ubuntu
- # 16.04 LTS) only come with cmake 3.5 by default. For this reason, we can't
- # use list(FILTER...)
- set(ABSL_CC_SRCS "${ABSL_CC_LIB_SRCS}")
- foreach(src_file IN LISTS ABSL_CC_SRCS)
- if(${src_file} MATCHES ".*\\.(h|inc)")
- list(REMOVE_ITEM ABSL_CC_SRCS "${src_file}")
- endif()
- endforeach()
- if("${ABSL_CC_SRCS}" STREQUAL "")
+ if(ABSL_ENABLE_INSTALL)
+ set(_NAME "${ABSL_CC_LIB_NAME}")
+ else()
+ set(_NAME "absl_${ABSL_CC_LIB_NAME}")
+ endif()
+
+ # Check if this is a header-only library
+ # Note that as of February 2019, many popular OS's (for example, Ubuntu
+ # 16.04 LTS) only come with cmake 3.5 by default. For this reason, we can't
+ # use list(FILTER...)
+ set(ABSL_CC_SRCS "${ABSL_CC_LIB_SRCS}")
+ foreach(src_file IN LISTS ABSL_CC_SRCS)
+ if(${src_file} MATCHES ".*\\.(h|inc)")
+ list(REMOVE_ITEM ABSL_CC_SRCS "${src_file}")
+ endif()
+ endforeach()
+
+ if("${ABSL_CC_SRCS}" STREQUAL "")
+ set(ABSL_CC_LIB_IS_INTERFACE 1)
+ else()
+ set(ABSL_CC_LIB_IS_INTERFACE 0)
+ endif()
+
+ # Determine this build target's relationship to the DLL. It's one of four things:
+ # 1. "dll" -- This target is part of the DLL
+ # 2. "dll_dep" -- This target is not part of the DLL, but depends on the DLL.
+ # Note that we assume any target not in the DLL depends on the
+ # DLL. This is not a technical necessity but a convenience
+ # which happens to be true, because nearly every target is
+ # part of the DLL.
+ # 3. "shared" -- This is a shared library, perhaps on a non-windows platform
+ # where DLL doesn't make sense.
+ # 4. "static" -- This target does not depend on the DLL and should be built
+ # statically.
+ if (${ABSL_BUILD_DLL})
+ if(ABSL_ENABLE_INSTALL)
+ absl_internal_dll_contains(TARGET ${_NAME} OUTPUT _in_dll)
+ else()
+ absl_internal_dll_contains(TARGET ${ABSL_CC_LIB_NAME} OUTPUT _in_dll)
+ endif()
+ if (${_in_dll})
+ # This target should be replaced by the DLL
+ set(_build_type "dll")
set(ABSL_CC_LIB_IS_INTERFACE 1)
else()
- set(ABSL_CC_LIB_IS_INTERFACE 0)
+ # Building a DLL, but this target is not part of the DLL
+ set(_build_type "dll_dep")
endif()
+ elseif(BUILD_SHARED_LIBS)
+ set(_build_type "shared")
+ else()
+ set(_build_type "static")
+ endif()
- if(NOT ABSL_CC_LIB_IS_INTERFACE)
+ # Generate a pkg-config file for every library:
+ if(${_build_type} STREQUAL "static" OR ${_build_type} STREQUAL "shared")
+ if(NOT ABSL_CC_LIB_TESTONLY)
+ if(absl_VERSION)
+ set(PC_VERSION "${absl_VERSION}")
+ else()
+ set(PC_VERSION "head")
+ endif()
+ foreach(dep ${ABSL_CC_LIB_DEPS})
+ if(${dep} MATCHES "^absl::(.*)")
+ set(PC_DEPS "${PC_DEPS} absl_${CMAKE_MATCH_1} = ${PC_VERSION}")
+ endif()
+ endforeach()
+ foreach(cflag ${ABSL_CC_LIB_COPTS})
+ if(${cflag} MATCHES "^(-Wno|/wd)")
+ # These flags are needed to suppress warnings that might fire in our headers.
+ set(PC_CFLAGS "${PC_CFLAGS} ${cflag}")
+ elseif(${cflag} MATCHES "^(-W|/w[1234eo])")
+ # Don't impose our warnings on others.
+ else()
+ set(PC_CFLAGS "${PC_CFLAGS} ${cflag}")
+ endif()
+ endforeach()
+ FILE(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/lib/pkgconfig/absl_${_NAME}.pc" CONTENT "\
+prefix=${CMAKE_INSTALL_PREFIX}\n\
+exec_prefix=\${prefix}\n\
+libdir=\${prefix}/lib\n\
+includedir=\${prefix}/include\n\
+\n\
+Name: absl_${_NAME}\n\
+Description: Abseil ${_NAME} library\n\
+URL: https://abseil.io/\n\
+Version: ${PC_VERSION}\n\
+Requires.private:${PC_DEPS}\n\
+Libs: -L\${libdir} $<JOIN:${ABSL_CC_LIB_LINKOPTS}, > $<$<NOT:$<BOOL:${ABSL_CC_LIB_IS_INTERFACE}>>:-labsl_${_NAME}>\n\
+Cflags: -I\${includedir}${PC_CFLAGS}\n")
+ INSTALL(FILES "${CMAKE_BINARY_DIR}/lib/pkgconfig/absl_${_NAME}.pc"
+ DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig")
+ endif()
+ endif()
+
+ if(NOT ABSL_CC_LIB_IS_INTERFACE)
+ if(${_build_type} STREQUAL "dll_dep")
+ # This target depends on the DLL. When adding dependencies to this target,
+ # any depended-on-target which is contained inside the DLL is replaced
+ # with a dependency on the DLL.
add_library(${_NAME} STATIC "")
target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS})
- target_include_directories(${_NAME}
- PUBLIC
- "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>"
- $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
+ absl_internal_dll_targets(
+ DEPS ${ABSL_CC_LIB_DEPS}
+ OUTPUT _dll_deps
)
- target_compile_options(${_NAME}
- PRIVATE ${ABSL_CC_LIB_COPTS})
target_link_libraries(${_NAME}
- PUBLIC ${ABSL_CC_LIB_DEPS}
+ PUBLIC ${_dll_deps}
PRIVATE
${ABSL_CC_LIB_LINKOPTS}
${ABSL_DEFAULT_LINKOPTS}
)
- target_compile_definitions(${_NAME} PUBLIC ${ABSL_CC_LIB_DEFINES})
- # Add all Abseil targets to a a folder in the IDE for organization.
- if(ABSL_CC_LIB_PUBLIC)
- set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER})
- elseif(ABSL_CC_LIB_TESTONLY)
- set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/test)
+ if (ABSL_CC_LIB_TESTONLY)
+ set(_gtest_link_define "GTEST_LINKED_AS_SHARED_LIBRARY=1")
else()
- set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/internal)
+ set(_gtest_link_define)
endif()
- # INTERFACE libraries can't have the CXX_STANDARD property set
- set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
- set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
+ target_compile_definitions(${_NAME}
+ PUBLIC
+ ABSL_CONSUME_DLL
+ "${_gtest_link_define}"
+ )
- # When being installed, we lose the absl_ prefix. We want to put it back
- # to have properly named lib files. This is a no-op when we are not being
- # installed.
- set_target_properties(${_NAME} PROPERTIES
- OUTPUT_NAME "absl_${_NAME}"
+ elseif(${_build_type} STREQUAL "static" OR ${_build_type} STREQUAL "shared")
+ add_library(${_NAME} "")
+ target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS})
+ target_link_libraries(${_NAME}
+ PUBLIC ${ABSL_CC_LIB_DEPS}
+ PRIVATE
+ ${ABSL_CC_LIB_LINKOPTS}
+ ${ABSL_DEFAULT_LINKOPTS}
)
else()
- # Generating header-only library
- add_library(${_NAME} INTERFACE)
- target_include_directories(${_NAME}
- INTERFACE
- "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>"
- $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
- )
- target_link_libraries(${_NAME}
- INTERFACE
- ${ABSL_CC_LIB_DEPS}
- ${ABSL_CC_LIB_LINKOPTS}
- ${ABSL_DEFAULT_LINKOPTS}
- )
- target_compile_definitions(${_NAME} INTERFACE ${ABSL_CC_LIB_DEFINES})
+ message(FATAL_ERROR "Invalid build type: ${_build_type}")
endif()
- # TODO currently we don't install googletest alongside abseil sources, so
- # installed abseil can't be tested.
- if(NOT ABSL_CC_LIB_TESTONLY AND ABSL_ENABLE_INSTALL)
- install(TARGETS ${_NAME} EXPORT ${PROJECT_NAME}Targets
- RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR}
- LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR}
- ARCHIVE DESTINATION ${ABSL_INSTALL_LIBDIR}
+ # Linker language can be inferred from sources, but in the case of DLLs we
+ # don't have any .cc files so it would be ambiguous. We could set it
+ # explicitly only in the case of DLLs but, because "CXX" is always the
+ # correct linker language for static or for shared libraries, we set it
+ # unconditionally.
+ set_property(TARGET ${_NAME} PROPERTY LINKER_LANGUAGE "CXX")
+
+ target_include_directories(${_NAME}
+ PUBLIC
+ "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>"
+ $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
+ )
+ target_compile_options(${_NAME}
+ PRIVATE ${ABSL_CC_LIB_COPTS})
+ target_compile_definitions(${_NAME} PUBLIC ${ABSL_CC_LIB_DEFINES})
+
+ # Add all Abseil targets to a a folder in the IDE for organization.
+ if(ABSL_CC_LIB_PUBLIC)
+ set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER})
+ elseif(ABSL_CC_LIB_TESTONLY)
+ set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/test)
+ else()
+ set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/internal)
+ endif()
+
+ # INTERFACE libraries can't have the CXX_STANDARD property set
+ set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
+ set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
+
+ # When being installed, we lose the absl_ prefix. We want to put it back
+ # to have properly named lib files. This is a no-op when we are not being
+ # installed.
+ if(ABSL_ENABLE_INSTALL)
+ set_target_properties(${_NAME} PROPERTIES
+ OUTPUT_NAME "absl_${_NAME}"
+ # TODO(b/173696973): Figure out how to set SOVERSION for LTS releases.
+ SOVERSION 0
)
endif()
+ else()
+ # Generating header-only library
+ add_library(${_NAME} INTERFACE)
+ target_include_directories(${_NAME}
+ INTERFACE
+ "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>"
+ $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
+ )
+
+ if (${_build_type} STREQUAL "dll")
+ set(ABSL_CC_LIB_DEPS abseil_dll)
+ endif()
+
+ target_link_libraries(${_NAME}
+ INTERFACE
+ ${ABSL_CC_LIB_DEPS}
+ ${ABSL_CC_LIB_LINKOPTS}
+ ${ABSL_DEFAULT_LINKOPTS}
+ )
+ target_compile_definitions(${_NAME} INTERFACE ${ABSL_CC_LIB_DEFINES})
+ endif()
+
+ # TODO currently we don't install googletest alongside abseil sources, so
+ # installed abseil can't be tested.
+ if(NOT ABSL_CC_LIB_TESTONLY AND ABSL_ENABLE_INSTALL)
+ install(TARGETS ${_NAME} EXPORT ${PROJECT_NAME}Targets
+ RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${ABSL_INSTALL_LIBDIR}
+ )
+ endif()
add_library(absl::${ABSL_CC_LIB_NAME} ALIAS ${_NAME})
- endif()
endfunction()
# absl_cc_test()
@@ -221,23 +349,42 @@
)
set(_NAME "absl_${ABSL_CC_TEST_NAME}")
+
add_executable(${_NAME} "")
target_sources(${_NAME} PRIVATE ${ABSL_CC_TEST_SRCS})
target_include_directories(${_NAME}
PUBLIC ${ABSL_COMMON_INCLUDE_DIRS}
PRIVATE ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS}
)
- target_compile_definitions(${_NAME}
- PUBLIC ${ABSL_CC_TEST_DEFINES}
- )
+
+ if (${ABSL_BUILD_DLL})
+ target_compile_definitions(${_NAME}
+ PUBLIC
+ ${ABSL_CC_TEST_DEFINES}
+ ABSL_CONSUME_DLL
+ GTEST_LINKED_AS_SHARED_LIBRARY=1
+ )
+
+ # Replace dependencies on targets inside the DLL with abseil_dll itself.
+ absl_internal_dll_targets(
+ DEPS ${ABSL_CC_TEST_DEPS}
+ OUTPUT ABSL_CC_TEST_DEPS
+ )
+ else()
+ target_compile_definitions(${_NAME}
+ PUBLIC
+ ${ABSL_CC_TEST_DEFINES}
+ )
+ endif()
target_compile_options(${_NAME}
PRIVATE ${ABSL_CC_TEST_COPTS}
)
+
target_link_libraries(${_NAME}
PUBLIC ${ABSL_CC_TEST_DEPS}
PRIVATE ${ABSL_CC_TEST_LINKOPTS}
)
- # Add all Abseil targets to a a folder in the IDE for organization.
+ # Add all Abseil targets to a folder in the IDE for organization.
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/test)
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
diff --git a/third_party/abseil/CMake/AbseilInstallDirs.cmake b/third_party/abseil/CMake/AbseilInstallDirs.cmake
index b67272f..6fc914b 100644
--- a/third_party/abseil/CMake/AbseilInstallDirs.cmake
+++ b/third_party/abseil/CMake/AbseilInstallDirs.cmake
@@ -10,11 +10,11 @@
set(ABSL_SUBDIR "${PROJECT_NAME}_${PROJECT_VERSION}")
set(ABSL_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}/${ABSL_SUBDIR}")
set(ABSL_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${ABSL_SUBDIR}")
- set(ABSL_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}/{ABSL_SUBDIR}")
+ set(ABSL_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}/${ABSL_SUBDIR}")
set(ABSL_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}/${ABSL_SUBDIR}")
else()
set(ABSL_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}")
set(ABSL_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
set(ABSL_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}")
set(ABSL_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}")
-endif()
\ No newline at end of file
+endif()
diff --git a/third_party/abseil/CMake/Googletest/CMakeLists.txt.in b/third_party/abseil/CMake/Googletest/CMakeLists.txt.in
index d60a33e..5769e3a 100644
--- a/third_party/abseil/CMake/Googletest/CMakeLists.txt.in
+++ b/third_party/abseil/CMake/Googletest/CMakeLists.txt.in
@@ -1,15 +1,14 @@
cmake_minimum_required(VERSION 2.8.2)
-project(googletest-download NONE)
+project(googletest-external NONE)
include(ExternalProject)
ExternalProject_Add(googletest
- GIT_REPOSITORY https://github.com/google/googletest.git
- GIT_TAG master
- SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src"
- BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build"
+ URL "${absl_gtest_download_url}" # May be empty
+ SOURCE_DIR "${absl_gtest_src_dir}"
+ BINARY_DIR "${absl_gtest_build_dir}"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
-)
\ No newline at end of file
+)
diff --git a/third_party/abseil/CMake/Googletest/DownloadGTest.cmake b/third_party/abseil/CMake/Googletest/DownloadGTest.cmake
index 3c682ae..9d071c9 100644
--- a/third_party/abseil/CMake/Googletest/DownloadGTest.cmake
+++ b/third_party/abseil/CMake/Googletest/DownloadGTest.cmake
@@ -1,32 +1,41 @@
-# Downloads and unpacks googletest at configure time. Based on the instructions
-# at https://github.com/google/googletest/tree/master/googletest#incorporating-into-an-existing-cmake-project
+# Integrates googletest at configure time. Based on the instructions at
+# https://github.com/google/googletest/tree/master/googletest#incorporating-into-an-existing-cmake-project
-# Download the latest googletest from Github master
+# Set up the external googletest project, downloading the latest from Github
+# master if requested.
configure_file(
${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt.in
- ${CMAKE_BINARY_DIR}/googletest-download/CMakeLists.txt
+ ${CMAKE_BINARY_DIR}/googletest-external/CMakeLists.txt
)
-# Configure and build the downloaded googletest source
+set(ABSL_SAVE_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
+set(ABSL_SAVE_CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
+if (BUILD_SHARED_LIBS)
+ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGTEST_CREATE_SHARED_LIBRARY=1")
+endif()
+
+# Configure and build the googletest source.
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
- WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-external )
if(result)
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
endif()
execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
- WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-external)
if(result)
message(FATAL_ERROR "Build step for googletest failed: ${result}")
endif()
+set(CMAKE_CXX_FLAGS ${ABSL_SAVE_CMAKE_CXX_FLAGS})
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${ABSL_SAVE_CMAKE_RUNTIME_OUTPUT_DIRECTORY})
+
# Prevent overriding the parent project's compiler/linker settings on Windows
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
# Add googletest directly to our build. This defines the gtest and gtest_main
# targets.
-add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
- ${CMAKE_BINARY_DIR}/googletest-build
- EXCLUDE_FROM_ALL)
+add_subdirectory(${absl_gtest_src_dir} ${absl_gtest_build_dir} EXCLUDE_FROM_ALL)
diff --git a/third_party/abseil/CMake/README.md b/third_party/abseil/CMake/README.md
index 04d5df3..8f73475 100644
--- a/third_party/abseil/CMake/README.md
+++ b/third_party/abseil/CMake/README.md
@@ -93,7 +93,7 @@
absl::memory
absl::meta
absl::numeric
-absl::random
+absl::random_random
absl::strings
absl::synchronization
absl::time
diff --git a/third_party/abseil/CMake/abslConfig.cmake.in b/third_party/abseil/CMake/abslConfig.cmake.in
index 60847fa..62d246d 100644
--- a/third_party/abseil/CMake/abslConfig.cmake.in
+++ b/third_party/abseil/CMake/abslConfig.cmake.in
@@ -1,7 +1,8 @@
# absl CMake configuration file.
-include(FindThreads)
+include(CMakeFindDependencyMacro)
+find_dependency(Threads)
@PACKAGE_INIT@
-include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
\ No newline at end of file
+include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
diff --git a/third_party/abseil/CMake/install_test_project/test.sh b/third_party/abseil/CMake/install_test_project/test.sh
index 99989b0..ddc7726 100755
--- a/third_party/abseil/CMake/install_test_project/test.sh
+++ b/third_party/abseil/CMake/install_test_project/test.sh
@@ -118,6 +118,24 @@
exit 1
fi
+pushd "${HOME}"
+cat > hello-abseil.cc << EOF
+#include <cstdlib>
+
+#include "absl/strings/str_format.h"
+
+int main(int argc, char **argv) {
+ absl::PrintF("Hello Abseil!\n");
+ return EXIT_SUCCESS;
+}
+EOF
+export PKG_CONFIG_PATH="${install_dir}/${libdir}/pkgconfig"
+pc_args=($(pkg-config --cflags --libs --static absl_str_format))
+g++ -static -o hello-abseil hello-abseil.cc "${pc_args[@]}"
+hello="$(./hello-abseil)"
+[[ "${hello}" == "Hello Abseil!" ]]
+popd
+
uninstall_absl
popd
diff --git a/third_party/abseil/CMakeLists.txt b/third_party/abseil/CMakeLists.txt
index 86f5634..c1ae8d5 100644
--- a/third_party/abseil/CMakeLists.txt
+++ b/third_party/abseil/CMakeLists.txt
@@ -22,22 +22,39 @@
cmake_minimum_required(VERSION 3.5)
# Compiler id for Apple Clang is now AppleClang.
-cmake_policy(SET CMP0025 NEW)
+if (POLICY CMP0025)
+ cmake_policy(SET CMP0025 NEW)
+endif (POLICY CMP0025)
# if command can use IN_LIST
-cmake_policy(SET CMP0057 NEW)
+if (POLICY CMP0057)
+ cmake_policy(SET CMP0057 NEW)
+endif (POLICY CMP0057)
-# Project version variables are the empty std::string if version is unspecified
-cmake_policy(SET CMP0048 NEW)
+# Project version variables are the empty string if version is unspecified
+if (POLICY CMP0048)
+ cmake_policy(SET CMP0048 NEW)
+endif (POLICY CMP0048)
+
+# option() honor variables
+if (POLICY CMP0077)
+ cmake_policy(SET CMP0077 NEW)
+endif (POLICY CMP0077)
project(absl CXX)
+# Output directory is correct by default for most build setups. However, when
+# building Abseil as a DLL, it is important to have the DLL in the same
+# directory as the executable using it. Thus, we put all executables in a single
+# /bin directory.
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+
# when absl is included as subproject (i.e. using add_subdirectory(abseil-cpp))
# in the source tree of a project that uses it, install rules are disabled.
if(NOT "^${CMAKE_SOURCE_DIR}$" STREQUAL "^${PROJECT_SOURCE_DIR}$")
- set(ABSL_ENABLE_INSTALL FALSE)
+ option(ABSL_ENABLE_INSTALL "Enable install rule" OFF)
else()
- set(ABSL_ENABLE_INSTALL TRUE)
+ option(ABSL_ENABLE_INSTALL "Enable install rule" ON)
endif()
list(APPEND CMAKE_MODULE_PATH
@@ -47,6 +64,7 @@
include(AbseilInstallDirs)
include(CMakePackageConfigHelpers)
+include(AbseilDll)
include(AbseilHelpers)
@@ -74,8 +92,17 @@
## pthread
find_package(Threads REQUIRED)
+option(ABSL_USE_EXTERNAL_GOOGLETEST
+ "If ON, Abseil will assume that the targets for GoogleTest are already provided by the including project. This makes sense when Abseil is used with add_subproject." OFF)
+
option(ABSL_USE_GOOGLETEST_HEAD
- "If ON, abseil will download HEAD from googletest at config time." OFF)
+ "If ON, abseil will download HEAD from GoogleTest at config time." OFF)
+
+set(ABSL_GOOGLETEST_DOWNLOAD_URL "" CACHE STRING "If set, download GoogleTest from this URL")
+
+set(ABSL_LOCAL_GOOGLETEST_DIR "/usr/src/googletest" CACHE PATH
+ "If ABSL_USE_GOOGLETEST_HEAD is OFF and ABSL_GOOGLETEST_URL is not set, specifies the directory of a local GoogleTest checkout."
+ )
option(ABSL_RUN_TESTS "If ON, Abseil tests will be run." OFF)
@@ -83,16 +110,24 @@
# enable CTest. This will set BUILD_TESTING to ON unless otherwise specified
# on the command line
include(CTest)
- enable_testing()
-endif()
-## check targets
-if(BUILD_TESTING)
-
- if(${ABSL_USE_GOOGLETEST_HEAD})
- include(CMake/Googletest/DownloadGTest.cmake)
- set(absl_gtest_src_dir ${CMAKE_BINARY_DIR}/googletest-src)
+ ## check targets
+ if (NOT ABSL_USE_EXTERNAL_GOOGLETEST)
set(absl_gtest_build_dir ${CMAKE_BINARY_DIR}/googletest-build)
+ if(ABSL_USE_GOOGLETEST_HEAD AND ABSL_GOOGLETEST_DOWNLOAD_URL)
+ message(FATAL_ERROR "Do not set both ABSL_USE_GOOGLETEST_HEAD and ABSL_GOOGLETEST_DOWNLOAD_URL")
+ endif()
+ if(ABSL_USE_GOOGLETEST_HEAD)
+ set(absl_gtest_download_url "https://github.com/google/googletest/archive/master.zip")
+ elseif(ABSL_GOOGLETEST_DOWNLOAD_URL)
+ set(absl_gtest_download_url ${ABSL_GOOGLETEST_DOWNLOAD_URL})
+ endif()
+ if(absl_gtest_download_url)
+ set(absl_gtest_src_dir ${CMAKE_BINARY_DIR}/googletest-src)
+ else()
+ set(absl_gtest_src_dir ${ABSL_LOCAL_GOOGLETEST_DIR})
+ endif()
+ include(CMake/Googletest/DownloadGTest.cmake)
endif()
check_target(gtest)
@@ -156,5 +191,7 @@
FILES_MATCHING
PATTERN "*.inc"
PATTERN "*.h"
- )
+ PATTERN "copts" EXCLUDE
+ PATTERN "testdata" EXCLUDE
+ )
endif() # ABSL_ENABLE_INSTALL
diff --git a/third_party/abseil/CONTRIBUTING.md b/third_party/abseil/CONTRIBUTING.md
index f4cb4a2..9dadae9 100644
--- a/third_party/abseil/CONTRIBUTING.md
+++ b/third_party/abseil/CONTRIBUTING.md
@@ -123,10 +123,13 @@
## Running Tests
-Use "bazel test <>" functionality to run the unit tests.
+If you have [Bazel](https://bazel.build/) installed, use `bazel test
+--test_tag_filters="-benchmark" ...` to run the unit tests.
-Prerequisites for building and running tests are listed in
-[README.md](README.md)
+If you are running the Linux operating system and have
+[Docker](https://www.docker.com/) installed, you can also run the `linux_*.sh`
+scripts under the `ci/`(https://github.com/abseil/abseil-cpp/tree/master/ci)
+directory to test Abseil under a variety of conditions.
## Abseil Committers
diff --git a/third_party/abseil/FAQ.md b/third_party/abseil/FAQ.md
new file mode 100644
index 0000000..78028fc
--- /dev/null
+++ b/third_party/abseil/FAQ.md
@@ -0,0 +1,164 @@
+# Abseil FAQ
+
+## Is Abseil the right home for my utility library?
+
+Most often the answer to the question is "no." As both the [About
+Abseil](https://abseil.io/about/) page and our [contributing
+guidelines](https://github.com/abseil/abseil-cpp/blob/master/CONTRIBUTING.md#contribution-guidelines)
+explain, Abseil contains a variety of core C++ library code that is widely used
+at [Google](https://www.google.com/). As such, Abseil's primary purpose is to be
+used as a dependency by Google's open source C++ projects. While we do hope that
+Abseil is also useful to the C++ community at large, this added constraint also
+means that we are unlikely to accept a contribution of utility code that isn't
+already widely used by Google.
+
+## How to I set the C++ dialect used to build Abseil?
+
+The short answer is that whatever mechanism you choose, you need to make sure
+that you set this option consistently at the global level for your entire
+project. If, for example, you want to set the C++ dialect to C++17, with
+[Bazel](https://bazel/build/) as the build system and `gcc` or `clang` as the
+compiler, there several ways to do this:
+* Pass `--cxxopt=-std=c++17` on the command line (for example, `bazel build
+ --cxxopt=-std=c++17 ...`)
+* Set the environment variable `BAZEL_CXXOPTS` (for example,
+ `BAZEL_CXXOPTS=-std=c++17`)
+* Add `build --cxxopt=-std=c++17` to your [`.bazelrc`
+ file](https://docs.bazel.build/versions/master/guide.html#bazelrc)
+
+If you are using CMake as the build system, you'll need to add a line like
+`set(CMAKE_CXX_STANDARD 17)` to your top level `CMakeLists.txt` file. See the
+[CMake build
+instructions](https://github.com/abseil/abseil-cpp/blob/master/CMake/README.md)
+for more information.
+
+For a longer answer to this question and to understand why some other approaches
+don't work, see the answer to ["What is ABI and why don't you recommend using a
+pre-compiled version of
+Abseil?"](#what-is-abi-and-why-dont-you-recommend-using-a-pre-compiled-version-of-abseil)
+
+## What is ABI and why don't you recommend using a pre-compiled version of Abseil?
+
+For the purposes of this discussion, you can think of
+[ABI](https://en.wikipedia.org/wiki/Application_binary_interface) as the
+compiled representation of the interfaces in code. This is in contrast to
+[API](https://en.wikipedia.org/wiki/Application_programming_interface), which
+you can think of as the interfaces as defined by the code itself. [Abseil has a
+strong promise of API compatibility, but does not make any promise of ABI
+compatibility](https://abseil.io/about/compatibility). Let's take a look at what
+this means in practice.
+
+You might be tempted to do something like this in a
+[Bazel](https://bazel.build/) `BUILD` file:
+
+```
+# DON'T DO THIS!!!
+cc_library(
+ name = "my_library",
+ srcs = ["my_library.cc"],
+ copts = ["-std=c++17"], # May create a mixed-mode compile!
+ deps = ["@com_google_absl//absl/strings"],
+)
+```
+
+Applying `-std=c++17` to an individual target in your `BUILD` file is going to
+compile that specific target in C++17 mode, but it isn't going to ensure the
+Abseil library is built in C++17 mode, since the Abseil library itself is a
+different build target. If your code includes an Abseil header, then your
+program may contain conflicting definitions of the same
+class/function/variable/enum, etc. As a rule, all compile options that affect
+the ABI of a program need to be applied to the entire build on a global basis.
+
+C++ has something called the [One Definition
+Rule](https://en.wikipedia.org/wiki/One_Definition_Rule) (ODR). C++ doesn't
+allow multiple definitions of the same class/function/variable/enum, etc. ODR
+violations sometimes result in linker errors, but linkers do not always catch
+violations. Uncaught ODR violations can result in strange runtime behaviors or
+crashes that can be hard to debug.
+
+If you build the Abseil library and your code using different compile options
+that affect ABI, there is a good chance you will run afoul of the One Definition
+Rule. Examples of GCC compile options that affect ABI include (but aren't
+limited to) language dialect (e.g. `-std=`), optimization level (e.g. `-O2`),
+code generation flags (e.g. `-fexceptions`), and preprocessor defines
+(e.g. `-DNDEBUG`).
+
+If you use a pre-compiled version of Abseil, (for example, from your Linux
+distribution package manager or from something like
+[vcpkg](https://github.com/microsoft/vcpkg)) you have to be very careful to
+ensure ABI compatibility across the components of your program. The only way you
+can be sure your program is going to be correct regarding ABI is to ensure
+you've used the exact same compile options as were used to build the
+pre-compiled library. This does not mean that Abseil cannot work as part of a
+Linux distribution since a knowledgeable binary packager will have ensured that
+all packages have been built with consistent compile options. This is one of the
+reasons we warn against - though do not outright reject - using Abseil as a
+pre-compiled library.
+
+Another possible way that you might afoul of ABI issues is if you accidentally
+include two versions of Abseil in your program. Multiple versions of Abseil can
+end up within the same binary if your program uses the Abseil library and
+another library also transitively depends on Abseil (resulting in what is
+sometimes called the diamond dependency problem). In cases such as this you must
+structure your build so that all libraries use the same version of Abseil.
+[Abseil's strong promise of API compatibility between
+releases](https://abseil.io/about/compatibility) means the latest "HEAD" release
+of Abseil is almost certainly the right choice if you are doing as we recommend
+and building all of your code from source.
+
+For these reasons we recommend you avoid pre-compiled code and build the Abseil
+library yourself in a consistent manner with the rest of your code.
+
+## What is "live at head" and how do I do it?
+
+From Abseil's point-of-view, "live at head" means that every Abseil source
+release (which happens on an almost daily basis) is either API compatible with
+the previous release, or comes with an automated tool that you can run over code
+to make it compatible. In practice, the need to use an automated tool is
+extremely rare. This means that upgrading from one source release to another
+should be a routine practice that can and should be performed often.
+
+We recommend you update to the [latest commit in the `master` branch of
+Abseil](https://github.com/abseil/abseil-cpp/commits/master) as often as
+possible. Not only will you pick up bug fixes more quickly, but if you have good
+automated testing, you will catch and be able to fix any [Hyrum's
+Law](https://www.hyrumslaw.com/) dependency problems on an incremental basis
+instead of being overwhelmed by them and having difficulty isolating them if you
+wait longer between updates.
+
+If you are using the [Bazel](https://bazel.build/) build system and its
+[external dependencies](https://docs.bazel.build/versions/master/external.html)
+feature, updating the
+[`http_archive`](https://docs.bazel.build/versions/master/repo/http.html#http_archive)
+rule in your
+[`WORKSPACE`](https://docs.bazel.build/versions/master/be/workspace.html) for
+`com_google_abseil` to point to the [latest commit in the `master` branch of
+Abseil](https://github.com/abseil/abseil-cpp/commits/master) is all you need to
+do. For example, on February 11, 2020, the latest commit to the master branch
+was `98eb410c93ad059f9bba1bf43f5bb916fc92a5ea`. To update to this commit, you
+would add the following snippet to your `WORKSPACE` file:
+
+```
+http_archive(
+ name = "com_google_absl",
+ urls = ["https://github.com/abseil/abseil-cpp/archive/98eb410c93ad059f9bba1bf43f5bb916fc92a5ea.zip"], # 2020-02-11T18:50:53Z
+ strip_prefix = "abseil-cpp-98eb410c93ad059f9bba1bf43f5bb916fc92a5ea",
+ sha256 = "aabf6c57e3834f8dc3873a927f37eaf69975d4b28117fc7427dfb1c661542a87",
+)
+```
+
+To get the `sha256` of this URL, run `curl -sL --output -
+https://github.com/abseil/abseil-cpp/archive/98eb410c93ad059f9bba1bf43f5bb916fc92a5ea.zip
+| sha256sum -`.
+
+You can commit the updated `WORKSPACE` file to your source control every time
+you update, and if you have good automated testing, you might even consider
+automating this.
+
+One thing we don't recommend is using GitHub's `master.zip` files (for example
+[https://github.com/abseil/abseil-cpp/archive/master.zip](https://github.com/abseil/abseil-cpp/archive/master.zip)),
+which are always the latest commit in the `master` branch, to implement live at
+head. Since these `master.zip` URLs are not versioned, you will lose build
+reproducibility. In addition, some build systems, including Bazel, will simply
+cache this file, which means you won't actually be updating to the latest
+release until your cache is cleared or invalidated.
diff --git a/third_party/abseil/LTS.md b/third_party/abseil/LTS.md
index 94363b6..ade8b17 100644
--- a/third_party/abseil/LTS.md
+++ b/third_party/abseil/LTS.md
@@ -13,3 +13,4 @@
* [LTS Branch December 18, 2018](https://github.com/abseil/abseil-cpp/tree/lts_2018_12_18/)
* [LTS Branch June 20, 2018](https://github.com/abseil/abseil-cpp/tree/lts_2018_06_20/)
* [LTS Branch August 8, 2019](https://github.com/abseil/abseil-cpp/tree/lts_2019_08_08/)
+* [LTS Branch February 25, 2020](https://github.com/abseil/abseil-cpp/tree/lts_2020_02_25/)
diff --git a/third_party/abseil/README.md b/third_party/abseil/README.md
index 85de569..76f1d1e 100644
--- a/third_party/abseil/README.md
+++ b/third_party/abseil/README.md
@@ -9,7 +9,9 @@
- [About Abseil](#about)
- [Quickstart](#quickstart)
- [Building Abseil](#build)
+- [Support](#support)
- [Codemap](#codemap)
+- [Releases](#releases)
- [License](#license)
- [Links](#links)
@@ -42,14 +44,22 @@
<a name="build"></a>
## Building Abseil
-[Bazel](https://bazel.build) is the official build system for Abseil,
-which is supported on most major platforms (Linux, Windows, macOS, for example)
-and compilers. See the [quickstart](https://abseil.io/docs/cpp/quickstart) for
-more information on building Abseil using the Bazel build system.
+[Bazel](https://bazel.build) and [CMake](https://cmake.org/) are the official
+build systems for Abseil.
-<a name="cmake"></a>
-If you require CMake support, please check the
-[CMake build instructions](CMake/README.md).
+See the [quickstart](https://abseil.io/docs/cpp/quickstart) for more information
+on building Abseil using the Bazel build system.
+
+If you require CMake support, please check the [CMake build
+instructions](CMake/README.md) and [CMake
+Quickstart](https://abseil.io/docs/cpp/quickstart-cmake).
+
+## Support
+
+Abseil is officially supported on many platforms. See the [Abseil
+platform support
+guide](https://abseil.io/docs/cpp/platforms/platforms) for details on
+supported operating systems, compilers, CPUs, etc.
## Codemap
@@ -79,6 +89,9 @@
available within C++14 and C++17 versions of the C++ `<type_traits>` library.
* [`numeric`](absl/numeric/)
<br /> The `numeric` library contains C++11-compatible 128-bit integers.
+* [`status`](absl/status/)
+ <br /> The `status` contains abstractions for error handling, specifically
+ `absl::Status` and `absl::StatusOr<T>`.
* [`strings`](absl/strings/)
<br /> The `strings` library contains a variety of strings routines and
utilities, including a C++11-compatible version of the C++17
@@ -97,6 +110,15 @@
* [`utility`](absl/utility/)
<br /> The `utility` library contains utility and helper code.
+## Releases
+
+Abseil recommends users "live-at-head" (update to the latest commit from the
+master branch as often as possible). However, we realize this philosophy doesn't
+work for every project, so we also provide [Long Term Support
+Releases](https://github.com/abseil/abseil-cpp/releases) to which we backport
+fixes for severe bugs. See our [release
+management](https://abseil.io/about/releases) document for more details.
+
## License
The Abseil C++ library is licensed under the terms of the Apache
diff --git a/third_party/abseil/WORKSPACE b/third_party/abseil/WORKSPACE
index 572f5b1..258d23b 100644
--- a/third_party/abseil/WORKSPACE
+++ b/third_party/abseil/WORKSPACE
@@ -19,27 +19,27 @@
# GoogleTest/GoogleMock framework. Used by most unit-tests.
http_archive(
- name = "com_google_googletest",
- urls = ["https://github.com/google/googletest/archive/b6cd405286ed8635ece71c72f118e659f4ade3fb.zip"], # 2019-01-07
- strip_prefix = "googletest-b6cd405286ed8635ece71c72f118e659f4ade3fb",
- sha256 = "ff7a82736e158c077e76188232eac77913a15dac0b22508c390ab3f88e6d6d86",
+ name = "com_google_googletest",
+ # Keep this URL in sync with ABSL_GOOGLETEST_COMMIT in ci/cmake_common.sh.
+ urls = ["https://github.com/google/googletest/archive/8567b09290fe402cf01923e2131c5635b8ed851b.zip"], # 2020-06-12T22:24:28Z
+ strip_prefix = "googletest-8567b09290fe402cf01923e2131c5635b8ed851b",
+ sha256 = "9a8a166eb6a56c7b3d7b19dc2c946fe4778fd6f21c7a12368ad3b836d8f1be48",
)
# Google benchmark.
http_archive(
name = "com_github_google_benchmark",
- urls = ["https://github.com/google/benchmark/archive/16703ff83c1ae6d53e5155df3bb3ab0bc96083be.zip"],
- strip_prefix = "benchmark-16703ff83c1ae6d53e5155df3bb3ab0bc96083be",
- sha256 = "59f918c8ccd4d74b6ac43484467b500f1d64b40cc1010daa055375b322a43ba3",
+ urls = ["https://github.com/google/benchmark/archive/bf585a2789e30585b4e3ce6baf11ef2750b54677.zip"], # 2020-11-26T11:14:03Z
+ strip_prefix = "benchmark-bf585a2789e30585b4e3ce6baf11ef2750b54677",
+ sha256 = "2a778d821997df7d8646c9c59b8edb9a573a6e04c534c01892a40aa524a7b68c",
)
# C++ rules for Bazel.
http_archive(
name = "rules_cc",
- sha256 = "67412176974bfce3f4cf8bdaff39784a72ed709fc58def599d1f68710b58d68b",
- strip_prefix = "rules_cc-b7fe9697c0c76ab2fd431a891dbb9a6a32ed7c3e",
+ sha256 = "9a446e9dd9c1bb180c86977a8dc1e9e659550ae732ae58bd2e8fd51e15b2c91d",
+ strip_prefix = "rules_cc-262ebec3c2296296526740db4aefce68c80de7fa",
urls = [
- "https://mirror.bazel.build/github.com/bazelbuild/rules_cc/archive/b7fe9697c0c76ab2fd431a891dbb9a6a32ed7c3e.zip",
- "https://github.com/bazelbuild/rules_cc/archive/b7fe9697c0c76ab2fd431a891dbb9a6a32ed7c3e.zip",
+ "https://github.com/bazelbuild/rules_cc/archive/262ebec3c2296296526740db4aefce68c80de7fa.zip",
],
)
diff --git a/third_party/abseil/absl/BUILD.bazel b/third_party/abseil/absl/BUILD.bazel
index 853330d..6da20c4 100644
--- a/third_party/abseil/absl/BUILD.bazel
+++ b/third_party/abseil/absl/BUILD.bazel
@@ -12,16 +12,16 @@
# WITHOUT 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
+licenses(["notice"])
-load(":compiler_config_setting.bzl", "create_llvm_config")
-
-create_llvm_config(
- name = "llvm_compiler",
+config_setting(
+ name = "clang_compiler",
+ flag_values = {
+ "@bazel_tools//tools/cpp:compiler": "clang",
+ },
visibility = [":__subpackages__"],
)
@@ -41,9 +41,10 @@
config_setting(
name = "windows",
- values = {
- "cpu": "x64_windows",
- },
+ constraint_values = [
+ "@bazel_tools//platforms:x86_64",
+ "@bazel_tools//platforms:windows",
+ ],
visibility = [":__subpackages__"],
)
@@ -54,3 +55,11 @@
},
visibility = [":__subpackages__"],
)
+
+config_setting(
+ name = "wasm",
+ values = {
+ "cpu": "wasm32",
+ },
+ visibility = [":__subpackages__"],
+)
diff --git a/third_party/abseil/absl/CMakeLists.txt b/third_party/abseil/absl/CMakeLists.txt
index 3e78397..fbfa782 100644
--- a/third_party/abseil/absl/CMakeLists.txt
+++ b/third_party/abseil/absl/CMakeLists.txt
@@ -14,20 +14,24 @@
# limitations under the License.
#
-
-
add_subdirectory(base)
add_subdirectory(algorithm)
add_subdirectory(container)
add_subdirectory(debugging)
add_subdirectory(flags)
+add_subdirectory(functional)
add_subdirectory(hash)
add_subdirectory(memory)
add_subdirectory(meta)
add_subdirectory(numeric)
add_subdirectory(random)
+add_subdirectory(status)
add_subdirectory(strings)
add_subdirectory(synchronization)
add_subdirectory(time)
add_subdirectory(types)
add_subdirectory(utility)
+
+if (${ABSL_BUILD_DLL})
+ absl_make_dll()
+endif()
diff --git a/third_party/abseil/absl/abseil.podspec.gen.py b/third_party/abseil/absl/abseil.podspec.gen.py
new file mode 100755
index 0000000..6375298
--- /dev/null
+++ b/third_party/abseil/absl/abseil.podspec.gen.py
@@ -0,0 +1,229 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""This script generates abseil.podspec from all BUILD.bazel files.
+
+This is expected to run on abseil git repository with Bazel 1.0 on Linux.
+It recursively analyzes BUILD.bazel files using query command of Bazel to
+dump its build rules in XML format. From these rules, it constructs podspec
+structure.
+"""
+
+import argparse
+import collections
+import os
+import re
+import subprocess
+import xml.etree.ElementTree
+
+# Template of root podspec.
+SPEC_TEMPLATE = """
+# This file has been automatically generated from a script.
+# Please make modifications to `abseil.podspec.gen.py` instead.
+Pod::Spec.new do |s|
+ s.name = 'abseil'
+ s.version = '${version}'
+ s.summary = 'Abseil Common Libraries (C++) from Google'
+ s.homepage = 'https://abseil.io'
+ s.license = 'Apache License, Version 2.0'
+ s.authors = { 'Abseil Team' => 'abseil-io@googlegroups.com' }
+ s.source = {
+ :git => 'https://github.com/abseil/abseil-cpp.git',
+ :tag => '${tag}',
+ }
+ s.module_name = 'absl'
+ s.header_mappings_dir = 'absl'
+ s.header_dir = 'absl'
+ s.libraries = 'c++'
+ s.compiler_flags = '-Wno-everything'
+ s.pod_target_xcconfig = {
+ 'USER_HEADER_SEARCH_PATHS' => '$(inherited) "$(PODS_TARGET_SRCROOT)"',
+ 'USE_HEADERMAP' => 'NO',
+ 'ALWAYS_SEARCH_USER_PATHS' => 'NO',
+ }
+ s.ios.deployment_target = '9.0'
+ s.osx.deployment_target = '10.10'
+ s.tvos.deployment_target = '9.0'
+ s.watchos.deployment_target = '2.0'
+"""
+
+# Rule object representing the rule of Bazel BUILD.
+Rule = collections.namedtuple(
+ "Rule", "type name package srcs hdrs textual_hdrs deps visibility testonly")
+
+
+def get_elem_value(elem, name):
+ """Returns the value of XML element with the given name."""
+ for child in elem:
+ if child.attrib.get("name") != name:
+ continue
+ if child.tag == "string":
+ return child.attrib.get("value")
+ if child.tag == "boolean":
+ return child.attrib.get("value") == "true"
+ if child.tag == "list":
+ return [nested_child.attrib.get("value") for nested_child in child]
+ raise "Cannot recognize tag: " + child.tag
+ return None
+
+
+def normalize_paths(paths):
+ """Returns the list of normalized path."""
+ # e.g. ["//absl/strings:dir/header.h"] -> ["absl/strings/dir/header.h"]
+ return [path.lstrip("/").replace(":", "/") for path in paths]
+
+
+def parse_rule(elem, package):
+ """Returns a rule from bazel XML rule."""
+ return Rule(
+ type=elem.attrib["class"],
+ name=get_elem_value(elem, "name"),
+ package=package,
+ srcs=normalize_paths(get_elem_value(elem, "srcs") or []),
+ hdrs=normalize_paths(get_elem_value(elem, "hdrs") or []),
+ textual_hdrs=normalize_paths(get_elem_value(elem, "textual_hdrs") or []),
+ deps=get_elem_value(elem, "deps") or [],
+ visibility=get_elem_value(elem, "visibility") or [],
+ testonly=get_elem_value(elem, "testonly") or False)
+
+
+def read_build(package):
+ """Runs bazel query on given package file and returns all cc rules."""
+ result = subprocess.check_output(
+ ["bazel", "query", package + ":all", "--output", "xml"])
+ root = xml.etree.ElementTree.fromstring(result)
+ return [
+ parse_rule(elem, package)
+ for elem in root
+ if elem.tag == "rule" and elem.attrib["class"].startswith("cc_")
+ ]
+
+
+def collect_rules(root_path):
+ """Collects and returns all rules from root path recursively."""
+ rules = []
+ for cur, _, _ in os.walk(root_path):
+ build_path = os.path.join(cur, "BUILD.bazel")
+ if os.path.exists(build_path):
+ rules.extend(read_build("//" + cur))
+ return rules
+
+
+def relevant_rule(rule):
+ """Returns true if a given rule is relevant when generating a podspec."""
+ return (
+ # cc_library only (ignore cc_test, cc_binary)
+ rule.type == "cc_library" and
+ # ignore empty rule
+ (rule.hdrs + rule.textual_hdrs + rule.srcs) and
+ # ignore test-only rule
+ not rule.testonly)
+
+
+def get_spec_var(depth):
+ """Returns the name of variable for spec with given depth."""
+ return "s" if depth == 0 else "s{}".format(depth)
+
+
+def get_spec_name(label):
+ """Converts the label of bazel rule to the name of podspec."""
+ assert label.startswith("//absl/"), "{} doesn't start with //absl/".format(
+ label)
+ # e.g. //absl/apple/banana -> abseil/apple/banana
+ return "abseil/" + label[7:]
+
+
+def write_podspec(f, rules, args):
+ """Writes a podspec from given rules and args."""
+ rule_dir = build_rule_directory(rules)["abseil"]
+ # Write root part with given arguments
+ spec = re.sub(r"\$\{(\w+)\}", lambda x: args[x.group(1)],
+ SPEC_TEMPLATE).lstrip()
+ f.write(spec)
+ # Write all target rules
+ write_podspec_map(f, rule_dir, 0)
+ f.write("end\n")
+
+
+def build_rule_directory(rules):
+ """Builds a tree-style rule directory from given rules."""
+ rule_dir = {}
+ for rule in rules:
+ cur = rule_dir
+ for frag in get_spec_name(rule.package).split("/"):
+ cur = cur.setdefault(frag, {})
+ cur[rule.name] = rule
+ return rule_dir
+
+
+def write_podspec_map(f, cur_map, depth):
+ """Writes podspec from rule map recursively."""
+ for key, value in sorted(cur_map.items()):
+ indent = " " * (depth + 1)
+ f.write("{indent}{var0}.subspec '{key}' do |{var1}|\n".format(
+ indent=indent,
+ key=key,
+ var0=get_spec_var(depth),
+ var1=get_spec_var(depth + 1)))
+ if isinstance(value, dict):
+ write_podspec_map(f, value, depth + 1)
+ else:
+ write_podspec_rule(f, value, depth + 1)
+ f.write("{indent}end\n".format(indent=indent))
+
+
+def write_podspec_rule(f, rule, depth):
+ """Writes podspec from given rule."""
+ indent = " " * (depth + 1)
+ spec_var = get_spec_var(depth)
+ # Puts all files in hdrs, textual_hdrs, and srcs into source_files.
+ # Since CocoaPods treats header_files a bit differently from bazel,
+ # this won't generate a header_files field so that all source_files
+ # are considered as header files.
+ srcs = sorted(set(rule.hdrs + rule.textual_hdrs + rule.srcs))
+ write_indented_list(
+ f, "{indent}{var}.source_files = ".format(indent=indent, var=spec_var),
+ srcs)
+ # Writes dependencies of this rule.
+ for dep in sorted(rule.deps):
+ name = get_spec_name(dep.replace(":", "/"))
+ f.write("{indent}{var}.dependency '{dep}'\n".format(
+ indent=indent, var=spec_var, dep=name))
+
+
+def write_indented_list(f, leading, values):
+ """Writes leading values in an indented style."""
+ f.write(leading)
+ f.write((",\n" + " " * len(leading)).join("'{}'".format(v) for v in values))
+ f.write("\n")
+
+
+def generate(args):
+ """Generates a podspec file from all BUILD files under absl directory."""
+ rules = filter(relevant_rule, collect_rules("absl"))
+ with open(args.output, "wt") as f:
+ write_podspec(f, rules, vars(args))
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description="Generates abseil.podspec from BUILD.bazel")
+ parser.add_argument(
+ "-v", "--version", help="The version of podspec", required=True)
+ parser.add_argument(
+ "-t",
+ "--tag",
+ default=None,
+ help="The name of git tag (default: version)")
+ parser.add_argument(
+ "-o",
+ "--output",
+ default="abseil.podspec",
+ help="The name of output file (default: abseil.podspec)")
+ args = parser.parse_args()
+ if args.tag is None:
+ args.tag = args.version
+ generate(args)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/third_party/abseil/absl/algorithm/BUILD.bazel b/third_party/abseil/absl/algorithm/BUILD.bazel
index 62b139c..a3002b7 100644
--- a/third_party/abseil/absl/algorithm/BUILD.bazel
+++ b/third_party/abseil/absl/algorithm/BUILD.bazel
@@ -14,7 +14,7 @@
# limitations under the License.
#
-#load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load(
"//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
@@ -24,13 +24,16 @@
package(default_visibility = ["//visibility:public"])
-licenses(["notice"]) # Apache 2.0
+licenses(["notice"])
cc_library(
name = "algorithm",
hdrs = ["algorithm.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ "//absl/base:config",
+ ],
)
cc_test(
diff --git a/third_party/abseil/absl/algorithm/CMakeLists.txt b/third_party/abseil/absl/algorithm/CMakeLists.txt
index 9fbe36f..56cd0fb 100644
--- a/third_party/abseil/absl/algorithm/CMakeLists.txt
+++ b/third_party/abseil/absl/algorithm/CMakeLists.txt
@@ -21,6 +21,8 @@
"algorithm.h"
COPTS
${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::config
PUBLIC
)
diff --git a/third_party/abseil/absl/algorithm/algorithm.h b/third_party/abseil/absl/algorithm/algorithm.h
index bb90215..e9b4733 100644
--- a/third_party/abseil/absl/algorithm/algorithm.h
+++ b/third_party/abseil/absl/algorithm/algorithm.h
@@ -26,7 +26,10 @@
#include <iterator>
#include <type_traits>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace algorithm_internal {
@@ -84,6 +87,8 @@
} // namespace algorithm_internal
+// equal()
+//
// 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
@@ -104,8 +109,8 @@
typename std::iterator_traits<InputIter2>::iterator_category{});
}
-// Performs comparison of two ranges specified by pairs of iterators using
-// operator==.
+// Overload of equal() that 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) {
@@ -113,6 +118,8 @@
algorithm_internal::EqualTo{});
}
+// linear_search()
+//
// 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`.
@@ -126,6 +133,8 @@
return std::find(first, last, value) != last;
}
+// rotate()
+//
// 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
@@ -135,7 +144,6 @@
// 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) {
@@ -145,6 +153,7 @@
ForwardIterator>());
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_ALGORITHM_ALGORITHM_H_
diff --git a/third_party/abseil/absl/algorithm/container.h b/third_party/abseil/absl/algorithm/container.h
index c84de46..6398438 100644
--- a/third_party/abseil/absl/algorithm/container.h
+++ b/third_party/abseil/absl/algorithm/container.h
@@ -55,6 +55,7 @@
#include "absl/meta/type_traits.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_algorithm_internal {
// NOTE: it is important to defer to ADL lookup for building with C++ modules,
@@ -89,10 +90,10 @@
// lookup of std::begin and std::end, i.e.
// using std::begin;
// using std::end;
-// std::foo(begin(c), end(c);
+// std::foo(begin(c), end(c));
// becomes
// std::foo(container_algorithm_internal::begin(c),
-// container_algorithm_internal::end(c));
+// container_algorithm_internal::end(c));
// These are meant for internal use only.
template <typename C>
@@ -112,6 +113,18 @@
struct IsUnorderedContainer<std::unordered_set<Key, Hash, KeyEqual, Allocator>>
: std::true_type {};
+// container_algorithm_internal::c_size. It is meant for internal use only.
+
+template <class C>
+auto c_size(C& c) -> decltype(c.size()) {
+ return c.size();
+}
+
+template <class T, std::size_t N>
+constexpr std::size_t c_size(T (&)[N]) {
+ return N;
+}
+
} // namespace container_algorithm_internal
// PUBLIC API
@@ -175,7 +188,7 @@
// c_none_of()
//
// Container-based version of the <algorithm> `std::none_of()` function to
-// test if no elements in a container fulfil a condition.
+// test if no elements in a container fulfill 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),
@@ -256,7 +269,8 @@
// 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.
+// find the first element within the container that is also within the options
+// container.
template <typename C1, typename C2>
container_algorithm_internal::ContainerIter<C1> c_find_first_of(C1& container,
C2& options) {
@@ -326,24 +340,45 @@
// c_mismatch()
//
// Container-based version of the <algorithm> `std::mismatch()` function to
-// return the first element where two ordered containers differ.
+// return the first element where two ordered containers differ. Applies `==` to
+// the first N elements of `c1` and `c2`, where N = min(size(c1), size(c2)).
template <typename C1, typename C2>
container_algorithm_internal::ContainerIterPairType<C1, 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));
+ auto first1 = container_algorithm_internal::c_begin(c1);
+ auto last1 = container_algorithm_internal::c_end(c1);
+ auto first2 = container_algorithm_internal::c_begin(c2);
+ auto last2 = container_algorithm_internal::c_end(c2);
+
+ for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) {
+ // Negates equality because Cpp17EqualityComparable doesn't require clients
+ // to overload both `operator==` and `operator!=`.
+ if (!(*first1 == *first2)) {
+ break;
+ }
+ }
+
+ return std::make_pair(first1, first2);
}
// Overload of c_mismatch() for using a predicate evaluation other than `==` as
-// the function's test condition.
+// the function's test condition. Applies `pred`to the first N elements of `c1`
+// and `c2`, where N = min(size(c1), size(c2)).
template <typename C1, typename C2, typename BinaryPredicate>
container_algorithm_internal::ContainerIterPairType<C1, 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_mismatch(C1& c1, C2& c2, BinaryPredicate pred) {
+ auto first1 = container_algorithm_internal::c_begin(c1);
+ auto last1 = container_algorithm_internal::c_end(c1);
+ auto first2 = container_algorithm_internal::c_begin(c2);
+ auto last2 = container_algorithm_internal::c_end(c2);
+
+ for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) {
+ if (!pred(*first1, *first2)) {
+ break;
+ }
+ }
+
+ return std::make_pair(first1, first2);
}
// c_equal()
@@ -365,7 +400,8 @@
template <typename C1, typename C2>
bool c_equal(const C1& c1, const C2& c2) {
- return ((c1.size() == c2.size()) &&
+ return ((container_algorithm_internal::c_size(c1) ==
+ container_algorithm_internal::c_size(c2)) &&
std::equal(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2)));
@@ -375,7 +411,8 @@
// 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()) &&
+ return ((container_algorithm_internal::c_size(c1) ==
+ container_algorithm_internal::c_size(c2)) &&
std::equal(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2),
@@ -523,12 +560,20 @@
// c_swap_ranges()
//
// Container-based version of the <algorithm> `std::swap_ranges()` function to
-// swap a container's elements with another container's elements.
+// swap a container's elements with another container's elements. Swaps the
+// first N elements of `c1` and `c2`, where N = min(size(c1), size(c2)).
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));
+ auto first1 = container_algorithm_internal::c_begin(c1);
+ auto last1 = container_algorithm_internal::c_end(c1);
+ auto first2 = container_algorithm_internal::c_begin(c2);
+ auto last2 = container_algorithm_internal::c_end(c2);
+
+ using std::swap;
+ for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) {
+ swap(*first1, *first2);
+ }
+ return first2;
}
// c_transform()
@@ -546,16 +591,23 @@
}
// Overload of c_transform() for performing a transformation using a binary
-// predicate.
+// predicate. Applies `binary_op` to the first N elements of `c1` and `c2`,
+// where N = min(size(c1), size(c2)).
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));
+ auto first1 = container_algorithm_internal::c_begin(input1);
+ auto last1 = container_algorithm_internal::c_end(input1);
+ auto first2 = container_algorithm_internal::c_begin(input2);
+ auto last2 = container_algorithm_internal::c_end(input2);
+ for (; first1 != last1 && first2 != last2;
+ ++first1, (void)++first2, ++output) {
+ *output = binary_op(*first1, *first2);
+ }
+
+ return output;
}
// c_replace()
@@ -927,9 +979,10 @@
// 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.
+// function to sort the elements in the given range `result` within the larger
+// `sequence` in ascending order (and using `result` as the output parameter).
+// At most min(result.last - result.first, sequence.last - sequence.first)
+// elements from the sequence will be stored in the result.
template <typename C, typename RandomAccessContainer>
container_algorithm_internal::ContainerIter<RandomAccessContainer>
c_partial_sort_copy(const C& sequence, RandomAccessContainer& result) {
@@ -1705,6 +1758,7 @@
output_first, std::forward<BinaryOp>(op));
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_ALGORITHM_CONTAINER_H_
diff --git a/third_party/abseil/absl/algorithm/container_test.cc b/third_party/abseil/absl/algorithm/container_test.cc
index 86bf9d3..605afc8 100644
--- a/third_party/abseil/absl/algorithm/container_test.cc
+++ b/third_party/abseil/absl/algorithm/container_test.cc
@@ -57,9 +57,7 @@
};
struct AccumulateCalls {
- void operator()(int value) {
- calls.push_back(value);
- }
+ void operator()(int value) { calls.push_back(value); }
std::vector<int> calls;
};
@@ -68,7 +66,6 @@
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_));
@@ -151,35 +148,118 @@
}
TEST_F(NonMutatingTest, Mismatch) {
- absl::c_mismatch(container_, sequence_);
- absl::c_mismatch(sequence_, container_);
+ // Testing necessary as absl::c_mismatch executes logic.
+ {
+ auto result = absl::c_mismatch(vector_, sequence_);
+ EXPECT_EQ(result.first, vector_.end());
+ EXPECT_EQ(result.second, sequence_.end());
+ }
+ {
+ auto result = absl::c_mismatch(sequence_, vector_);
+ EXPECT_EQ(result.first, sequence_.end());
+ EXPECT_EQ(result.second, vector_.end());
+ }
+
+ sequence_.back() = 5;
+ {
+ auto result = absl::c_mismatch(vector_, sequence_);
+ EXPECT_EQ(result.first, std::prev(vector_.end()));
+ EXPECT_EQ(result.second, std::prev(sequence_.end()));
+ }
+ {
+ auto result = absl::c_mismatch(sequence_, vector_);
+ EXPECT_EQ(result.first, std::prev(sequence_.end()));
+ EXPECT_EQ(result.second, std::prev(vector_.end()));
+ }
+
+ sequence_.pop_back();
+ {
+ auto result = absl::c_mismatch(vector_, sequence_);
+ EXPECT_EQ(result.first, std::prev(vector_.end()));
+ EXPECT_EQ(result.second, sequence_.end());
+ }
+ {
+ auto result = absl::c_mismatch(sequence_, vector_);
+ EXPECT_EQ(result.first, sequence_.end());
+ EXPECT_EQ(result.second, std::prev(vector_.end()));
+ }
+ {
+ struct NoNotEquals {
+ constexpr bool operator==(NoNotEquals) const { return true; }
+ constexpr bool operator!=(NoNotEquals) const = delete;
+ };
+ std::vector<NoNotEquals> first;
+ std::list<NoNotEquals> second;
+
+ // Check this still compiles.
+ absl::c_mismatch(first, second);
+ }
}
TEST_F(NonMutatingTest, MismatchWithPredicate) {
- absl::c_mismatch(container_, sequence_, BinPredicate);
- absl::c_mismatch(sequence_, container_, BinPredicate);
+ // Testing necessary as absl::c_mismatch executes logic.
+ {
+ auto result = absl::c_mismatch(vector_, sequence_, BinPredicate);
+ EXPECT_EQ(result.first, vector_.begin());
+ EXPECT_EQ(result.second, sequence_.begin());
+ }
+ {
+ auto result = absl::c_mismatch(sequence_, vector_, BinPredicate);
+ EXPECT_EQ(result.first, sequence_.begin());
+ EXPECT_EQ(result.second, vector_.begin());
+ }
+
+ sequence_.front() = 0;
+ {
+ auto result = absl::c_mismatch(vector_, sequence_, BinPredicate);
+ EXPECT_EQ(result.first, vector_.begin());
+ EXPECT_EQ(result.second, sequence_.begin());
+ }
+ {
+ auto result = absl::c_mismatch(sequence_, vector_, BinPredicate);
+ EXPECT_EQ(result.first, std::next(sequence_.begin()));
+ EXPECT_EQ(result.second, std::next(vector_.begin()));
+ }
+
+ sequence_.clear();
+ {
+ auto result = absl::c_mismatch(vector_, sequence_, BinPredicate);
+ EXPECT_EQ(result.first, vector_.begin());
+ EXPECT_EQ(result.second, sequence_.end());
+ }
+ {
+ auto result = absl::c_mismatch(sequence_, vector_, BinPredicate);
+ EXPECT_EQ(result.first, sequence_.end());
+ EXPECT_EQ(result.second, vector_.begin());
+ }
}
TEST_F(NonMutatingTest, Equal) {
EXPECT_TRUE(absl::c_equal(vector_, sequence_));
EXPECT_TRUE(absl::c_equal(sequence_, vector_));
+ EXPECT_TRUE(absl::c_equal(sequence_, array_));
+ EXPECT_TRUE(absl::c_equal(array_, 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));
+ EXPECT_FALSE(absl::c_equal(array_, vector_plus));
}
TEST_F(NonMutatingTest, EqualWithPredicate) {
EXPECT_TRUE(absl::c_equal(vector_, sequence_, Equals));
EXPECT_TRUE(absl::c_equal(sequence_, vector_, Equals));
+ EXPECT_TRUE(absl::c_equal(array_, sequence_, Equals));
+ EXPECT_TRUE(absl::c_equal(vector_, array_, 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));
+ EXPECT_FALSE(absl::c_equal(vector_plus, array_, Equals));
}
TEST_F(NonMutatingTest, IsPermutation) {
@@ -513,11 +593,9 @@
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)));
+ 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)));
+ EXPECT_THAT(unsorted, ElementsAre(Gt(2), Gt(2), 2, Lt(2)));
}
TEST(MutatingTest, IsPartitioned) {
@@ -670,6 +748,15 @@
absl::c_swap_ranges(odds, evens);
EXPECT_THAT(odds, ElementsAre(1, 3, 5));
EXPECT_THAT(evens, ElementsAre(2, 4, 6));
+
+ odds.pop_back();
+ absl::c_swap_ranges(odds, evens);
+ EXPECT_THAT(odds, ElementsAre(2, 4));
+ EXPECT_THAT(evens, ElementsAre(1, 3, 6));
+
+ absl::c_swap_ranges(evens, odds);
+ EXPECT_THAT(odds, ElementsAre(1, 3));
+ EXPECT_THAT(evens, ElementsAre(2, 4, 6));
}
TEST_F(NonMutatingTest, Transform) {
@@ -684,6 +771,20 @@
EXPECT_EQ(std::vector<int>({1, 5, 4}), z);
*end = 7;
EXPECT_EQ(std::vector<int>({1, 5, 4, 7}), z);
+
+ z.clear();
+ y.pop_back();
+ end = absl::c_transform(x, y, std::back_inserter(z), std::plus<int>());
+ EXPECT_EQ(std::vector<int>({1, 5}), z);
+ *end = 7;
+ EXPECT_EQ(std::vector<int>({1, 5, 7}), z);
+
+ z.clear();
+ std::swap(x, y);
+ end = absl::c_transform(x, y, std::back_inserter(z), std::plus<int>());
+ EXPECT_EQ(std::vector<int>({1, 5}), z);
+ *end = 7;
+ EXPECT_EQ(std::vector<int>({1, 5, 7}), z);
}
TEST(MutatingTest, Replace) {
@@ -749,10 +850,9 @@
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)));
+ EXPECT_THAT(test_vector,
+ ElementsAre(IsElement(1, 1), IsElement(1, 0), IsElement(2, 1),
+ IsElement(2, 0), IsElement(2, 2)));
}
TEST(MutatingTest, StableSortWithPredicate) {
@@ -760,10 +860,9 @@
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)));
+ EXPECT_THAT(test_vector,
+ ElementsAre(IsElement(2, 1), IsElement(2, 0), IsElement(2, 2),
+ IsElement(1, 1), IsElement(1, 0)));
}
TEST(MutatingTest, ReplaceCopyIf) {
diff --git a/third_party/abseil/absl/base/BUILD.bazel b/third_party/abseil/absl/base/BUILD.bazel
index b7754de..a56620f 100644
--- a/third_party/abseil/absl/base/BUILD.bazel
+++ b/third_party/abseil/absl/base/BUILD.bazel
@@ -14,7 +14,7 @@
# limitations under the License.
#
-#load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
+load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
load(
"//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
@@ -24,7 +24,7 @@
package(default_visibility = ["//visibility:public"])
-licenses(["notice"]) # Apache 2.0
+licenses(["notice"])
cc_library(
name = "atomic_hook",
@@ -34,6 +34,21 @@
visibility = [
"//absl:__subpackages__",
],
+ deps = [
+ ":config",
+ ":core_headers",
+ ],
+)
+
+cc_library(
+ name = "errno_saver",
+ hdrs = ["internal/errno_saver.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = [
+ "//absl:__subpackages__",
+ ],
+ deps = [":config"],
)
cc_library(
@@ -42,7 +57,10 @@
hdrs = ["log_severity.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
- deps = [":core_headers"],
+ deps = [
+ ":config",
+ ":core_headers",
+ ],
)
cc_library(
@@ -71,22 +89,24 @@
"internal/spinlock_wait.cc",
"internal/spinlock_win32.inc",
],
- hdrs = [
- "internal/scheduling_mode.h",
- "internal/spinlock_wait.h",
- ],
+ hdrs = ["internal/spinlock_wait.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl/base:__pkg__",
],
- deps = [":core_headers"],
+ deps = [
+ ":base_internal",
+ ":core_headers",
+ ":errno_saver",
+ ],
)
cc_library(
name = "config",
hdrs = [
"config.h",
+ "options.h",
"policy_checks.h",
],
copts = ABSL_DEFAULT_COPTS,
@@ -95,11 +115,18 @@
cc_library(
name = "dynamic_annotations",
- srcs = ["dynamic_annotations.cc"],
- hdrs = ["dynamic_annotations.h"],
+ srcs = [
+ "internal/dynamic_annotations.h",
+ ],
+ hdrs = [
+ "dynamic_annotations.h",
+ ],
copts = ABSL_DEFAULT_COPTS,
- defines = ["__CLANG_SUPPORT_DYN_ANNOTATION__"],
linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":config",
+ ":core_headers",
+ ],
)
cc_library(
@@ -132,17 +159,21 @@
"internal/low_level_alloc.h",
],
copts = ABSL_DEFAULT_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
+ linkopts = select({
+ "//absl:windows": [],
+ "//absl:wasm": [],
+ "//conditions:default": [],
+ }) + ABSL_DEFAULT_LINKOPTS,
visibility = [
- "//absl:__subpackages__",
+ "//visibility:public",
],
deps = [
":base",
+ ":base_internal",
":config",
":core_headers",
":dynamic_annotations",
":raw_logging_internal",
- ":spinlock_wait",
],
)
@@ -161,6 +192,7 @@
"//absl:__subpackages__",
],
deps = [
+ ":config",
"//absl/meta:type_traits",
],
)
@@ -188,7 +220,10 @@
],
copts = ABSL_DEFAULT_COPTS,
linkopts = select({
- "//absl:windows": [],
+ "//absl:windows": [
+ "-DEFAULTLIB:advapi32.lib",
+ ],
+ "//absl:wasm": [],
"//conditions:default": [],
}) + ABSL_DEFAULT_LINKOPTS,
deps = [
@@ -204,6 +239,19 @@
],
)
+cc_library(
+ name = "atomic_hook_test_helper",
+ testonly = 1,
+ srcs = ["internal/atomic_hook_test_helper.cc"],
+ hdrs = ["internal/atomic_hook_test_helper.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":atomic_hook",
+ ":core_headers",
+ ],
+)
+
cc_test(
name = "atomic_hook_test",
size = "small",
@@ -212,6 +260,7 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":atomic_hook",
+ ":atomic_hook_test_helper",
":core_headers",
"@com_google_googletest//:gtest_main",
],
@@ -259,6 +308,19 @@
],
)
+cc_test(
+ name = "errno_saver_test",
+ size = "small",
+ srcs = ["internal/errno_saver_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":errno_saver",
+ ":strerror",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
cc_library(
name = "exception_testing",
testonly = 1,
@@ -352,8 +414,9 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":base",
+ ":base_internal",
+ ":config",
":core_headers",
- ":spinlock_wait",
"//absl/synchronization",
"@com_google_googletest//:gtest",
],
@@ -368,8 +431,9 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":base",
+ ":base_internal",
+ ":config",
":core_headers",
- ":spinlock_wait",
"//absl/synchronization",
"@com_google_googletest//:gtest_main",
],
@@ -399,6 +463,7 @@
testonly = 1,
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
+ tags = ["benchmark"],
visibility = ["//visibility:private"],
deps = [
":spinlock_benchmark_common",
@@ -486,8 +551,13 @@
srcs = ["internal/low_level_alloc_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
- tags = ["no_test_ios_x86_64"],
- deps = [":malloc_internal"],
+ tags = [
+ "no_test_ios_x86_64",
+ ],
+ deps = [
+ ":malloc_internal",
+ "//absl/container:node_hash_map",
+ ],
)
cc_test(
@@ -519,28 +589,75 @@
)
cc_library(
- name = "bits",
- hdrs = ["internal/bits.h"],
+ name = "exponential_biased",
+ srcs = ["internal/exponential_biased.cc"],
+ hdrs = ["internal/exponential_biased.h"],
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl:__subpackages__",
],
- deps = [":core_headers"],
+ deps = [
+ ":config",
+ ":core_headers",
+ ],
)
cc_test(
- name = "bits_test",
+ name = "exponential_biased_test",
size = "small",
- srcs = ["internal/bits_test.cc"],
+ srcs = ["internal/exponential_biased_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = ["//visibility:private"],
deps = [
- ":bits",
+ ":exponential_biased",
+ "//absl/strings",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
+ name = "periodic_sampler",
+ srcs = ["internal/periodic_sampler.cc"],
+ hdrs = ["internal/periodic_sampler.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":core_headers",
+ ":exponential_biased",
+ ],
+)
+
+cc_test(
+ name = "periodic_sampler_test",
+ size = "small",
+ srcs = ["internal/periodic_sampler_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = ["//visibility:private"],
+ deps = [
+ ":core_headers",
+ ":periodic_sampler",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_binary(
+ name = "periodic_sampler_benchmark",
+ testonly = 1,
+ srcs = ["internal/periodic_sampler_benchmark.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ tags = ["benchmark"],
+ visibility = ["//visibility:private"],
+ deps = [
+ ":core_headers",
+ ":periodic_sampler",
+ "@com_github_google_benchmark//:benchmark_main",
+ ],
+)
+
+cc_library(
name = "scoped_set_env",
testonly = 1,
srcs = ["internal/scoped_set_env.cc"],
@@ -549,7 +666,10 @@
visibility = [
"//absl:__subpackages__",
],
- deps = [":raw_logging_internal"],
+ deps = [
+ ":config",
+ ":raw_logging_internal",
+ ],
)
cc_test(
@@ -572,8 +692,104 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":log_severity",
+ "//absl/flags:flag_internal",
"//absl/flags:marshalling",
"//absl/strings",
"@com_google_googletest//:gtest_main",
],
)
+
+cc_library(
+ name = "strerror",
+ srcs = ["internal/strerror.cc"],
+ hdrs = ["internal/strerror.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = [
+ "//absl:__subpackages__",
+ ],
+ deps = [
+ ":config",
+ ":core_headers",
+ ":errno_saver",
+ ],
+)
+
+cc_test(
+ name = "strerror_test",
+ size = "small",
+ srcs = ["internal/strerror_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":strerror",
+ "//absl/strings",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_binary(
+ name = "strerror_benchmark",
+ testonly = 1,
+ srcs = ["internal/strerror_benchmark.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ tags = ["benchmark"],
+ visibility = ["//visibility:private"],
+ deps = [
+ ":strerror",
+ "@com_github_google_benchmark//:benchmark_main",
+ ],
+)
+
+cc_library(
+ name = "fast_type_id",
+ hdrs = ["internal/fast_type_id.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = [
+ "//absl:__subpackages__",
+ ],
+ deps = [
+ ":config",
+ ],
+)
+
+cc_test(
+ name = "fast_type_id_test",
+ size = "small",
+ srcs = ["internal/fast_type_id_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":fast_type_id",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "unique_small_name_test",
+ size = "small",
+ srcs = ["internal/unique_small_name_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ linkstatic = 1,
+ deps = [
+ ":core_headers",
+ "//absl/strings",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "optimization_test",
+ size = "small",
+ srcs = ["optimization_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":core_headers",
+ "//absl/types:optional",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/third_party/abseil/absl/base/CMakeLists.txt b/third_party/abseil/absl/base/CMakeLists.txt
index 2f11ef8..3d930b8 100644
--- a/third_party/abseil/absl/base/CMakeLists.txt
+++ b/third_party/abseil/absl/base/CMakeLists.txt
@@ -14,11 +14,27 @@
# limitations under the License.
#
+find_library(LIBRT rt)
+
absl_cc_library(
NAME
atomic_hook
HDRS
"internal/atomic_hook.h"
+ DEPS
+ absl::config
+ absl::core_headers
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+)
+
+absl_cc_library(
+ NAME
+ errno_saver
+ HDRS
+ "internal/errno_saver.h"
+ DEPS
+ absl::config
COPTS
${ABSL_DEFAULT_COPTS}
)
@@ -56,7 +72,6 @@
NAME
spinlock_wait
HDRS
- "internal/scheduling_mode.h"
"internal/spinlock_wait.h"
SRCS
"internal/spinlock_akaros.inc"
@@ -67,7 +82,9 @@
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
+ absl::base_internal
absl::core_headers
+ absl::errno_saver
)
absl_cc_library(
@@ -75,6 +92,7 @@
config
HDRS
"config.h"
+ "options.h"
"policy_checks.h"
COPTS
${ABSL_DEFAULT_COPTS}
@@ -87,11 +105,11 @@
HDRS
"dynamic_annotations.h"
SRCS
- "dynamic_annotations.cc"
+ "internal/dynamic_annotations.h"
COPTS
${ABSL_DEFAULT_COPTS}
- DEFINES
- "__CLANG_SUPPORT_DYN_ANNOTATION__"
+ DEPS
+ absl::config
PUBLIC
)
@@ -125,11 +143,11 @@
${ABSL_DEFAULT_COPTS}
DEPS
absl::base
+ absl::base_internal
absl::config
absl::core_headers
absl::dynamic_annotations
absl::raw_logging_internal
- absl::spinlock_wait
Threads::Threads
)
@@ -141,9 +159,11 @@
"internal/identity.h"
"internal/inline_variable.h"
"internal/invoke.h"
+ "internal/scheduling_mode.h"
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
+ absl::config
absl::type_traits
)
@@ -161,16 +181,18 @@
"internal/thread_identity.h"
"internal/tsan_mutex_interface.h"
"internal/unscaledcycleclock.h"
- "log_severity.h"
SRCS
"internal/cycleclock.cc"
"internal/spinlock.cc"
"internal/sysinfo.cc"
"internal/thread_identity.cc"
"internal/unscaledcycleclock.cc"
- "log_severity.cc"
COPTS
${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ $<$<BOOL:${LIBRT}>:-lrt>
+ $<$<BOOL:${MINGW}>:"advapi32">
DEPS
absl::atomic_hook
absl::base_internal
@@ -254,6 +276,19 @@
gtest_main
)
+absl_cc_library(
+ NAME
+ atomic_hook_test_helper
+ SRCS
+ "internal/atomic_hook_test_helper.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::atomic_hook
+ absl::core_headers
+ TESTONLY
+)
+
absl_cc_test(
NAME
atomic_hook_test
@@ -262,8 +297,10 @@
COPTS
${ABSL_TEST_COPTS}
DEPS
+ absl::atomic_hook_test_helper
absl::atomic_hook
absl::core_headers
+ gmock
gtest_main
)
@@ -282,6 +319,20 @@
absl_cc_test(
NAME
+ errno_saver_test
+ SRCS
+ "internal/errno_saver_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::errno_saver
+ absl::strerror
+ gmock
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
throw_delegate_test
SRCS
"throw_delegate_test.cc"
@@ -333,8 +384,9 @@
${ABSL_TEST_COPTS}
DEPS
absl::base
+ absl::config
+ absl::base_internal
absl::core_headers
- absl::spinlock_wait
absl::synchronization
gtest
TESTONLY
@@ -350,8 +402,9 @@
${ABSL_TEST_COPTS}
DEPS
absl::base
+ absl::base_internal
+ absl::config
absl::core_headers
- absl::spinlock_wait
absl::synchronization
gtest_main
)
@@ -446,6 +499,7 @@
${ABSL_TEST_COPTS}
DEPS
absl::malloc_internal
+ absl::node_hash_map
Threads::Threads
)
@@ -466,25 +520,56 @@
absl_cc_library(
NAME
- bits
+ exponential_biased
+ SRCS
+ "internal/exponential_biased.cc"
HDRS
- "internal/bits.h"
+ "internal/exponential_biased.h"
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
+ absl::config
absl::core_headers
)
absl_cc_test(
NAME
- bits_test
+ exponential_biased_test
SRCS
- "internal/bits_test.cc"
+ "internal/exponential_biased_test.cc"
COPTS
${ABSL_TEST_COPTS}
DEPS
- absl::bits
- gtest_main
+ absl::exponential_biased
+ absl::strings
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
+ periodic_sampler
+ SRCS
+ "internal/periodic_sampler.cc"
+ HDRS
+ "internal/periodic_sampler.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::core_headers
+ absl::exponential_biased
+)
+
+absl_cc_test(
+ NAME
+ periodic_sampler_test
+ SRCS
+ "internal/periodic_sampler_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::core_headers
+ absl::periodic_sampler
+ gmock_main
)
absl_cc_library(
@@ -497,6 +582,7 @@
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
+ absl::config
absl::raw_logging_internal
)
@@ -529,9 +615,79 @@
SRCS
"log_severity_test.cc"
DEPS
+ absl::flags_internal
absl::flags_marshalling
absl::log_severity
absl::strings
gmock
gtest_main
)
+
+absl_cc_library(
+ NAME
+ strerror
+ SRCS
+ "internal/strerror.cc"
+ HDRS
+ "internal/strerror.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::config
+ absl::core_headers
+ absl::errno_saver
+)
+
+absl_cc_test(
+ NAME
+ strerror_test
+ SRCS
+ "internal/strerror_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strerror
+ absl::strings
+ gmock
+ gtest_main
+)
+
+absl_cc_library(
+ NAME
+ fast_type_id
+ HDRS
+ "internal/fast_type_id.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::config
+)
+
+absl_cc_test(
+ NAME
+ fast_type_id_test
+ SRCS
+ "internal/fast_type_id_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::fast_type_id
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ optimization_test
+ SRCS
+ "optimization_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::core_headers
+ absl::optional
+ gtest_main
+)
diff --git a/third_party/abseil/absl/base/attributes.h b/third_party/abseil/absl/base/attributes.h
index a7da62a..0ba1e7d 100644
--- a/third_party/abseil/absl/base/attributes.h
+++ b/third_party/abseil/absl/base/attributes.h
@@ -32,34 +32,12 @@
// of them are not supported in older version of Clang. Thus, we check
// `__has_attribute()` first. If the check fails, we check if we are on GCC and
// assume the attribute exists on GCC (which is verified on GCC 4.7).
-//
-// -----------------------------------------------------------------------------
-// Sanitizer Attributes
-// -----------------------------------------------------------------------------
-//
-// Sanitizer-related attributes are not "defined" in this file (and indeed
-// are not defined as such in any file). To utilize the following
-// sanitizer-related attributes within your builds, define the following macros
-// within your build using a `-D` flag, along with the given value for
-// `-fsanitize`:
-//
-// * `ADDRESS_SANITIZER` + `-fsanitize=address` (Clang, GCC 4.8)
-// * `MEMORY_SANITIZER` + `-fsanitize=memory` (Clang-only)
-// * `THREAD_SANITIZER + `-fsanitize=thread` (Clang, GCC 4.8+)
-// * `UNDEFINED_BEHAVIOR_SANITIZER` + `-fsanitize=undefined` (Clang, GCC 4.9+)
-// * `CONTROL_FLOW_INTEGRITY` + -fsanitize=cfi (Clang-only)
-//
-// Example:
-//
-// // Enable branches in the Abseil code that are tagged for ASan:
-// $ bazel build --copt=-DADDRESS_SANITIZER --copt=-fsanitize=address
-// --linkopt=-fsanitize=address *target*
-//
-// Since these macro names are only supported by GCC and Clang, we only check
-// for `__GNUC__` (GCC or Clang) and the above macros.
+
#ifndef ABSL_BASE_ATTRIBUTES_H_
#define ABSL_BASE_ATTRIBUTES_H_
+#include "absl/base/config.h"
+
// ABSL_HAVE_ATTRIBUTE
//
// A function-like feature checking macro that is a wrapper around
@@ -157,10 +135,12 @@
// Tags a function as weak for the purposes of compilation and linking.
// Weak attributes currently do not work properly in LLVM's Windows backend,
// so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598
-// for futher information.
-#if (ABSL_HAVE_ATTRIBUTE(weak) || \
+// for further information.
+// The MinGW compiler doesn't complain about the weak attribute until the link
+// step, presumably because Windows doesn't use ELF binaries.
+#if (ABSL_HAVE_ATTRIBUTE(weak) || \
(defined(__GNUC__) && !defined(__clang__))) && \
- !(defined(__llvm__) && defined(_WIN32))
+ !(defined(__llvm__) && defined(_WIN32)) && !defined(__MINGW32__)
#undef ABSL_ATTRIBUTE_WEAK
#define ABSL_ATTRIBUTE_WEAK __attribute__((weak))
#define ABSL_HAVE_ATTRIBUTE_WEAK 1
@@ -232,7 +212,7 @@
// 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__)
+#if ABSL_HAVE_ATTRIBUTE(no_sanitize_address)
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
#else
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
@@ -240,13 +220,13 @@
// ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
//
-// Tells the MemorySanitizer to relax the handling of a given function. All
-// "Use of uninitialized value" warnings from such functions will be suppressed,
-// and all values loaded from memory will be considered fully initialized.
-// This attribute is similar to the ADDRESS_SANITIZER attribute above, but deals
-// with initialized-ness rather than addressability issues.
+// Tells the MemorySanitizer to relax the handling of a given function. All "Use
+// of uninitialized value" warnings from such functions will be suppressed, and
+// all values loaded from memory will be considered fully initialized. This
+// attribute is similar to the ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS attribute
+// above, but deals with initialized-ness rather than addressability issues.
// NOTE: MemorySanitizer(msan) is supported by Clang but not GCC.
-#if defined(__clang__)
+#if ABSL_HAVE_ATTRIBUTE(no_sanitize_memory)
#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
#else
#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
@@ -257,7 +237,7 @@
// Tells the ThreadSanitizer to not instrument a given function.
// NOTE: GCC supports ThreadSanitizer(tsan) since 4.8.
// https://gcc.gnu.org/gcc-4.8/changes.html
-#if defined(__GNUC__)
+#if ABSL_HAVE_ATTRIBUTE(no_sanitize_thread)
#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
#else
#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
@@ -269,8 +249,10 @@
// where certain behavior (eg. division by zero) is being used intentionally.
// NOTE: GCC supports UndefinedBehaviorSanitizer(ubsan) since 4.9.
// https://gcc.gnu.org/gcc-4.9/changes.html
-#if defined(__GNUC__) && \
- (defined(UNDEFINED_BEHAVIOR_SANITIZER) || defined(ADDRESS_SANITIZER))
+#if ABSL_HAVE_ATTRIBUTE(no_sanitize_undefined)
+#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
+ __attribute__((no_sanitize_undefined))
+#elif ABSL_HAVE_ATTRIBUTE(no_sanitize)
#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
__attribute__((no_sanitize("undefined")))
#else
@@ -281,7 +263,7 @@
//
// Tells the ControlFlowIntegrity sanitizer to not instrument a given function.
// See https://clang.llvm.org/docs/ControlFlowIntegrity.html for details.
-#if defined(__GNUC__) && defined(CONTROL_FLOW_INTEGRITY)
+#if ABSL_HAVE_ATTRIBUTE(no_sanitize)
#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi")))
#else
#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI
@@ -291,7 +273,7 @@
//
// Tells the SafeStack to not instrument a given function.
// See https://clang.llvm.org/docs/SafeStack.html for details.
-#if defined(__GNUC__) && defined(SAFESTACK_SANITIZER)
+#if ABSL_HAVE_ATTRIBUTE(no_sanitize)
#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK \
__attribute__((no_sanitize("safe-stack")))
#else
@@ -505,8 +487,10 @@
// packages/targets, as this may lead to conflicting definitions of functions at
// link-time.
//
+// XRay isn't currently supported on Android:
+// https://github.com/android/ndk/issues/368
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_always_instrument) && \
- !defined(ABSL_NO_XRAY_ATTRIBUTES)
+ !defined(ABSL_NO_XRAY_ATTRIBUTES) && !defined(__ANDROID__)
#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)
@@ -561,7 +545,19 @@
// ABSL_ATTRIBUTE_PACKED
//
-// Prevents the compiler from padding a structure to natural alignment
+// Instructs the compiler not to use natural alignment for a tagged data
+// structure, but instead to reduce its alignment to 1. This attribute can
+// either be applied to members of a structure or to a structure in its
+// entirety. Applying this attribute (judiciously) to a structure in its
+// entirety to optimize the memory footprint of very commonly-used structs is
+// fine. Do not apply this attribute to a structure in its entirety if the
+// purpose is to control the offsets of the members in the structure. Instead,
+// apply this attribute only to structure members that need it.
+//
+// When applying ABSL_ATTRIBUTE_PACKED only to specific structure members the
+// natural alignment of structure members not annotated is preserved. Aligned
+// member accesses are faster than non-aligned member accesses even if the
+// targeted microprocessor supports non-aligned accesses.
#if ABSL_HAVE_ATTRIBUTE(packed) || (defined(__GNUC__) && !defined(__clang__))
#define ABSL_ATTRIBUTE_PACKED __attribute__((__packed__))
#else
@@ -578,6 +574,86 @@
#define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes)
#endif
+// 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:
+// https://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).
+//
+// Examples:
+//
+// class ABSL_DEPRECATED("Use Bar instead") Foo {...};
+//
+// ABSL_DEPRECATED("Use Baz() instead") void Bar() {...}
+//
+// template <typename T>
+// ABSL_DEPRECATED("Use DoThat() instead")
+// void DoThis();
+//
+// Every usage of a deprecated entity will trigger a warning when compiled with
+// clang's `-Wdeprecated-declarations` option. This option is turned off by
+// default, but the warnings will be reported by clang-tidy.
+#if defined(__clang__) && defined(__cplusplus) && __cplusplus >= 201103L
+#define ABSL_DEPRECATED(message) __attribute__((deprecated(message)))
+#endif
+
+#ifndef ABSL_DEPRECATED
+#define ABSL_DEPRECATED(message)
+#endif
+
// ABSL_CONST_INIT
//
// A variable declaration annotated with the `ABSL_CONST_INIT` attribute will
@@ -599,7 +675,6 @@
//
// Note that this attribute is redundant if the variable is declared constexpr.
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
-// NOLINTNEXTLINE(whitespace/braces)
#define ABSL_CONST_INIT [[clang::require_constant_initialization]]
#else
#define ABSL_CONST_INIT
diff --git a/third_party/abseil/absl/base/bit_cast_test.cc b/third_party/abseil/absl/base/bit_cast_test.cc
index 4846add..8a3a41e 100644
--- a/third_party/abseil/absl/base/bit_cast_test.cc
+++ b/third_party/abseil/absl/base/bit_cast_test.cc
@@ -22,6 +22,7 @@
#include "absl/base/macros.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
template <int N>
@@ -104,4 +105,5 @@
}
} // namespace
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/base/call_once.h b/third_party/abseil/absl/base/call_once.h
index 4aa6360..96109f5 100644
--- a/third_party/abseil/absl/base/call_once.h
+++ b/third_party/abseil/absl/base/call_once.h
@@ -41,6 +41,7 @@
#include "absl/base/port.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
class once_flag;
@@ -148,7 +149,7 @@
Args&&... args) {
#ifndef NDEBUG
{
- uint32_t old_control = control->load(std::memory_order_acquire);
+ uint32_t old_control = control->load(std::memory_order_relaxed);
if (old_control != kOnceInit &&
old_control != kOnceRunning &&
old_control != kOnceWaiter &&
@@ -166,16 +167,18 @@
// Must do this before potentially modifying control word's state.
base_internal::SchedulingHelper maybe_disable_scheduling(scheduling_mode);
// Short circuit the simplest case to avoid procedure call overhead.
+ // The base_internal::SpinLockWait() call returns either kOnceInit or
+ // kOnceDone. If it returns kOnceDone, it must have loaded the control word
+ // with std::memory_order_acquire and seen a value of kOnceDone.
uint32_t old_control = kOnceInit;
if (control->compare_exchange_strong(old_control, kOnceRunning,
- std::memory_order_acquire,
std::memory_order_relaxed) ||
base_internal::SpinLockWait(control, ABSL_ARRAYSIZE(trans), trans,
scheduling_mode) == kOnceInit) {
- base_internal::Invoke(std::forward<Callable>(fn),
+ 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);
+ old_control =
+ control->exchange(base_internal::kOnceDone, std::memory_order_release);
if (old_control == base_internal::kOnceWaiter) {
base_internal::SpinLockWake(control, true);
}
@@ -210,6 +213,7 @@
}
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_CALL_ONCE_H_
diff --git a/third_party/abseil/absl/base/call_once_test.cc b/third_party/abseil/absl/base/call_once_test.cc
index 9a5a5c1..11d26c4 100644
--- a/third_party/abseil/absl/base/call_once_test.cc
+++ b/third_party/abseil/absl/base/call_once_test.cc
@@ -24,6 +24,7 @@
#include "absl/synchronization/mutex.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
absl::once_flag once;
@@ -102,4 +103,5 @@
}
} // namespace
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/base/casts.h b/third_party/abseil/absl/base/casts.h
index aba0178..83c6912 100644
--- a/third_party/abseil/absl/base/casts.h
+++ b/third_party/abseil/absl/base/casts.h
@@ -34,6 +34,7 @@
#include "absl/meta/type_traits.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace internal_casts {
@@ -158,16 +159,19 @@
return dest;
}
-// NOTE: This overload is only picked if the requirements of bit_cast are not
-// met. It is therefore UB, but is provided temporarily as previous versions of
-// this function template were unchecked. Do not use this in new code.
+// NOTE: This overload is only picked if the requirements of bit_cast are
+// not met. It is therefore UB, but is provided temporarily as previous
+// versions of this function template were unchecked. Do not use this in
+// new code.
template <
typename Dest, typename Source,
typename std::enable_if<
- !internal_casts::is_bitcastable<Dest, Source>::value, int>::type = 0>
+ !internal_casts::is_bitcastable<Dest, Source>::value,
+ int>::type = 0>
ABSL_DEPRECATED(
- "absl::bit_cast type requirements were violated. Update the types being "
- "used such that they are the same size and are both TriviallyCopyable.")
+ "absl::bit_cast type requirements were violated. Update the types "
+ "being used such that they are the same size and are both "
+ "TriviallyCopyable.")
inline Dest bit_cast(const Source& source) {
static_assert(sizeof(Dest) == sizeof(Source),
"Source and destination types should have equal sizes.");
@@ -177,6 +181,7 @@
return dest;
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_CASTS_H_
diff --git a/third_party/abseil/absl/base/config.h b/third_party/abseil/absl/base/config.h
index 1cb69b0..3f7f32b 100644
--- a/third_party/abseil/absl/base/config.h
+++ b/third_party/abseil/absl/base/config.h
@@ -63,8 +63,72 @@
#include <TargetConditionals.h>
#endif
+#include "absl/base/options.h"
#include "absl/base/policy_checks.h"
+// Helper macro to convert a CPP variable to a string literal.
+#define ABSL_INTERNAL_DO_TOKEN_STR(x) #x
+#define ABSL_INTERNAL_TOKEN_STR(x) ABSL_INTERNAL_DO_TOKEN_STR(x)
+
+// -----------------------------------------------------------------------------
+// Abseil namespace annotations
+// -----------------------------------------------------------------------------
+
+// ABSL_NAMESPACE_BEGIN/ABSL_NAMESPACE_END
+//
+// An annotation placed at the beginning/end of each `namespace absl` scope.
+// This is used to inject an inline namespace.
+//
+// The proper way to write Abseil code in the `absl` namespace is:
+//
+// namespace absl {
+// ABSL_NAMESPACE_BEGIN
+//
+// void Foo(); // absl::Foo().
+//
+// ABSL_NAMESPACE_END
+// } // namespace absl
+//
+// Users of Abseil should not use these macros, because users of Abseil should
+// not write `namespace absl {` in their own code for any reason. (Abseil does
+// not support forward declarations of its own types, nor does it support
+// user-provided specialization of Abseil templates. Code that violates these
+// rules may be broken without warning.)
+#if !defined(ABSL_OPTION_USE_INLINE_NAMESPACE) || \
+ !defined(ABSL_OPTION_INLINE_NAMESPACE_NAME)
+#error options.h is misconfigured.
+#endif
+
+// Check that ABSL_OPTION_INLINE_NAMESPACE_NAME is neither "head" nor ""
+#if defined(__cplusplus) && ABSL_OPTION_USE_INLINE_NAMESPACE == 1
+
+#define ABSL_INTERNAL_INLINE_NAMESPACE_STR \
+ ABSL_INTERNAL_TOKEN_STR(ABSL_OPTION_INLINE_NAMESPACE_NAME)
+
+static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != '\0',
+ "options.h misconfigured: ABSL_OPTION_INLINE_NAMESPACE_NAME must "
+ "not be empty.");
+static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
+ ABSL_INTERNAL_INLINE_NAMESPACE_STR[1] != 'e' ||
+ ABSL_INTERNAL_INLINE_NAMESPACE_STR[2] != 'a' ||
+ ABSL_INTERNAL_INLINE_NAMESPACE_STR[3] != 'd' ||
+ ABSL_INTERNAL_INLINE_NAMESPACE_STR[4] != '\0',
+ "options.h misconfigured: ABSL_OPTION_INLINE_NAMESPACE_NAME must "
+ "be changed to a new, unique identifier name.");
+
+#endif
+
+#if ABSL_OPTION_USE_INLINE_NAMESPACE == 0
+#define ABSL_NAMESPACE_BEGIN
+#define ABSL_NAMESPACE_END
+#elif ABSL_OPTION_USE_INLINE_NAMESPACE == 1
+#define ABSL_NAMESPACE_BEGIN \
+ inline namespace ABSL_OPTION_INLINE_NAMESPACE_NAME {
+#define ABSL_NAMESPACE_END }
+#else
+#error options.h is misconfigured.
+#endif
+
// -----------------------------------------------------------------------------
// Compiler Feature Checks
// -----------------------------------------------------------------------------
@@ -84,6 +148,18 @@
#define ABSL_HAVE_BUILTIN(x) 0
#endif
+#if defined(__is_identifier)
+#define ABSL_INTERNAL_HAS_KEYWORD(x) !(__is_identifier(x))
+#else
+#define ABSL_INTERNAL_HAS_KEYWORD(x) 0
+#endif
+
+#ifdef __has_feature
+#define ABSL_HAVE_FEATURE(f) __has_feature(f)
+#else
+#define ABSL_HAVE_FEATURE(f) 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.
@@ -132,6 +208,17 @@
#define ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1
#endif
+// ABSL_HAVE_SOURCE_LOCATION_CURRENT
+//
+// Indicates whether `absl::SourceLocation::current()` will return useful
+// information in some contexts.
+#ifndef ABSL_HAVE_SOURCE_LOCATION_CURRENT
+#if ABSL_INTERNAL_HAS_KEYWORD(__builtin_LINE) && \
+ ABSL_INTERNAL_HAS_KEYWORD(__builtin_FILE)
+#define ABSL_HAVE_SOURCE_LOCATION_CURRENT 1
+#endif
+#endif
+
// ABSL_HAVE_THREAD_LOCAL
//
// Checks whether C++11's `thread_local` storage duration specifier is
@@ -145,11 +232,9 @@
// * Xcode 9.3 started disallowing `thread_local` for 32-bit iOS simulator
// targeting iOS 9.x.
// * Xcode 10 moves the deployment target check for iOS < 9.0 to link time
-// making __has_feature unreliable there.
+// making ABSL_HAVE_FEATURE unreliable there.
//
-// Otherwise, `__has_feature` is only supported by Clang so it has be inside
-// `defined(__APPLE__)` check.
-#if __has_feature(cxx_thread_local) && \
+#if ABSL_HAVE_FEATURE(cxx_thread_local) && \
!(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0)
#define ABSL_HAVE_THREAD_LOCAL 1
#endif
@@ -181,13 +266,6 @@
#endif
#endif // defined(__ANDROID__) && defined(__clang__)
-// Emscripten doesn't yet support `thread_local` or `__thread`.
-// https://github.com/emscripten-core/emscripten/issues/3502
-#if defined(__EMSCRIPTEN__)
-#undef ABSL_HAVE_TLS
-#undef ABSL_HAVE_THREAD_LOCAL
-#endif // defined(__EMSCRIPTEN__)
-
// ABSL_HAVE_INTRINSIC_INT128
//
// Checks whether the __int128 compiler extension for a 128-bit integral type is
@@ -235,13 +313,19 @@
#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)
+
+#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6)
+// Clang >= 3.6
+#if ABSL_HAVE_FEATURE(cxx_exceptions)
#define ABSL_HAVE_EXCEPTIONS 1
-#endif // defined(__EXCEPTIONS) && __has_feature(cxx_exceptions)
+#endif // ABSL_HAVE_FEATURE(cxx_exceptions)
+#else
+// Clang < 3.6
+// http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro
+#if defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions)
+#define ABSL_HAVE_EXCEPTIONS 1
+#endif // defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions)
+#endif // __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6)
// Handle remaining special cases and default to exceptions being supported.
#elif !(defined(__GNUC__) && (__GNUC__ < 5) && !defined(__EXCEPTIONS)) && \
@@ -280,7 +364,7 @@
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
defined(__ros__) || defined(__native_client__) || defined(__asmjs__) || \
defined(__wasm__) || defined(__Fuchsia__) || defined(__sun) || \
- defined(__ASYLO__)
+ defined(__ASYLO__) || defined(__myriad2__)
#define ABSL_HAVE_MMAP 1
#endif
@@ -307,7 +391,7 @@
// ABSL_HAVE_SEMAPHORE_H
//
-// Checks whether the platform supports the <semaphore.h> header and sem_open(3)
+// Checks whether the platform supports the <semaphore.h> header and sem_init(3)
// family of functions as standardized in POSIX.1-2001.
//
// Note: While Apple provides <semaphore.h> for both iOS and macOS, it is
@@ -334,6 +418,11 @@
#define ABSL_HAVE_ALARM 1
#elif defined(_MSC_VER)
// feature tests for Microsoft's library
+#elif defined(__MINGW32__)
+// mingw32 doesn't provide alarm(2):
+// https://osdn.net/projects/mingw/scm/git/mingw-org-wsl/blobs/5.2-trunk/mingwrt/include/unistd.h
+// mingw-w64 provides a no-op implementation:
+// https://sourceforge.net/p/mingw-w64/mingw-w64/ci/master/tree/mingw-w64-crt/misc/alarm.c
#elif defined(__EMSCRIPTEN__)
// emscripten doesn't support signals
#elif defined(__Fuchsia__)
@@ -385,9 +474,9 @@
(defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 120000) || \
(defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \
- __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 120000) || \
+ __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000) || \
(defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \
- __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 50000))
+ __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 120000))
#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 1
#else
#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 0
@@ -463,6 +552,68 @@
#define ABSL_HAVE_STD_STRING_VIEW 1
#endif
+// ABSL_USES_STD_ANY
+//
+// Indicates whether absl::any is an alias for std::any.
+#if !defined(ABSL_OPTION_USE_STD_ANY)
+#error options.h is misconfigured.
+#elif ABSL_OPTION_USE_STD_ANY == 0 || \
+ (ABSL_OPTION_USE_STD_ANY == 2 && !defined(ABSL_HAVE_STD_ANY))
+#undef ABSL_USES_STD_ANY
+#elif ABSL_OPTION_USE_STD_ANY == 1 || \
+ (ABSL_OPTION_USE_STD_ANY == 2 && defined(ABSL_HAVE_STD_ANY))
+#define ABSL_USES_STD_ANY 1
+#else
+#error options.h is misconfigured.
+#endif
+
+// ABSL_USES_STD_OPTIONAL
+//
+// Indicates whether absl::optional is an alias for std::optional.
+#if !defined(ABSL_OPTION_USE_STD_OPTIONAL)
+#error options.h is misconfigured.
+#elif ABSL_OPTION_USE_STD_OPTIONAL == 0 || \
+ (ABSL_OPTION_USE_STD_OPTIONAL == 2 && !defined(ABSL_HAVE_STD_OPTIONAL))
+#undef ABSL_USES_STD_OPTIONAL
+#elif ABSL_OPTION_USE_STD_OPTIONAL == 1 || \
+ (ABSL_OPTION_USE_STD_OPTIONAL == 2 && defined(ABSL_HAVE_STD_OPTIONAL))
+#define ABSL_USES_STD_OPTIONAL 1
+#else
+#error options.h is misconfigured.
+#endif
+
+// ABSL_USES_STD_VARIANT
+//
+// Indicates whether absl::variant is an alias for std::variant.
+#if !defined(ABSL_OPTION_USE_STD_VARIANT)
+#error options.h is misconfigured.
+#elif ABSL_OPTION_USE_STD_VARIANT == 0 || \
+ (ABSL_OPTION_USE_STD_VARIANT == 2 && !defined(ABSL_HAVE_STD_VARIANT))
+#undef ABSL_USES_STD_VARIANT
+#elif ABSL_OPTION_USE_STD_VARIANT == 1 || \
+ (ABSL_OPTION_USE_STD_VARIANT == 2 && defined(ABSL_HAVE_STD_VARIANT))
+#define ABSL_USES_STD_VARIANT 1
+#else
+#error options.h is misconfigured.
+#endif
+
+// ABSL_USES_STD_STRING_VIEW
+//
+// Indicates whether absl::string_view is an alias for std::string_view.
+#if !defined(ABSL_OPTION_USE_STD_STRING_VIEW)
+#error options.h is misconfigured.
+#elif ABSL_OPTION_USE_STD_STRING_VIEW == 0 || \
+ (ABSL_OPTION_USE_STD_STRING_VIEW == 2 && \
+ !defined(ABSL_HAVE_STD_STRING_VIEW))
+#undef ABSL_USES_STD_STRING_VIEW
+#elif ABSL_OPTION_USE_STD_STRING_VIEW == 1 || \
+ (ABSL_OPTION_USE_STD_STRING_VIEW == 2 && \
+ defined(ABSL_HAVE_STD_STRING_VIEW))
+#define ABSL_USES_STD_STRING_VIEW 1
+#else
+#error options.h is misconfigured.
+#endif
+
// In debug mode, MSVC 2017's std::variant throws a EXCEPTION_ACCESS_VIOLATION
// SEH exception from emplace for variant<SomeStruct> when constructing the
// struct can throw. This defeats some of variant_test and
@@ -471,4 +622,93 @@
#define ABSL_INTERNAL_MSVC_2017_DBG_MODE
#endif
+// ABSL_INTERNAL_MANGLED_NS
+// ABSL_INTERNAL_MANGLED_BACKREFERENCE
+//
+// Internal macros for building up mangled names in our internal fork of CCTZ.
+// This implementation detail is only needed and provided for the MSVC build.
+//
+// These macros both expand to string literals. ABSL_INTERNAL_MANGLED_NS is
+// the mangled spelling of the `absl` namespace, and
+// ABSL_INTERNAL_MANGLED_BACKREFERENCE is a back-reference integer representing
+// the proper count to skip past the CCTZ fork namespace names. (This number
+// is one larger when there is an inline namespace name to skip.)
+#if defined(_MSC_VER)
+#if ABSL_OPTION_USE_INLINE_NAMESPACE == 0
+#define ABSL_INTERNAL_MANGLED_NS "absl"
+#define ABSL_INTERNAL_MANGLED_BACKREFERENCE "5"
+#else
+#define ABSL_INTERNAL_MANGLED_NS \
+ ABSL_INTERNAL_TOKEN_STR(ABSL_OPTION_INLINE_NAMESPACE_NAME) "@absl"
+#define ABSL_INTERNAL_MANGLED_BACKREFERENCE "6"
+#endif
+#endif
+
+#undef ABSL_INTERNAL_HAS_KEYWORD
+
+// ABSL_DLL
+//
+// When building Abseil as a DLL, this macro expands to `__declspec(dllexport)`
+// so we can annotate symbols appropriately as being exported. When used in
+// headers consuming a DLL, this macro expands to `__declspec(dllimport)` so
+// that consumers know the symbol is defined inside the DLL. In all other cases,
+// the macro expands to nothing.
+#if defined(_MSC_VER)
+#if defined(ABSL_BUILD_DLL)
+#define ABSL_DLL __declspec(dllexport)
+#elif defined(ABSL_CONSUME_DLL)
+#define ABSL_DLL __declspec(dllimport)
+#else
+#define ABSL_DLL
+#endif
+#else
+#define ABSL_DLL
+#endif // defined(_MSC_VER)
+
+// ABSL_HAVE_MEMORY_SANITIZER
+//
+// MemorySanitizer (MSan) is a detector of uninitialized reads. It consists of
+// a compiler instrumentation module and a run-time library.
+#ifdef ABSL_HAVE_MEMORY_SANITIZER
+#error "ABSL_HAVE_MEMORY_SANITIZER cannot be directly set."
+#elif defined(MEMORY_SANITIZER)
+// The MEMORY_SANITIZER macro is deprecated but we will continue to honor it
+// for now.
+#define ABSL_HAVE_MEMORY_SANITIZER 1
+#elif defined(__SANITIZE_MEMORY__)
+#define ABSL_HAVE_MEMORY_SANITIZER 1
+#elif !defined(__native_client__) && ABSL_HAVE_FEATURE(memory_sanitizer)
+#define ABSL_HAVE_MEMORY_SANITIZER 1
+#endif
+
+// ABSL_HAVE_THREAD_SANITIZER
+//
+// ThreadSanitizer (TSan) is a fast data race detector.
+#ifdef ABSL_HAVE_THREAD_SANITIZER
+#error "ABSL_HAVE_THREAD_SANITIZER cannot be directly set."
+#elif defined(THREAD_SANITIZER)
+// The THREAD_SANITIZER macro is deprecated but we will continue to honor it
+// for now.
+#define ABSL_HAVE_THREAD_SANITIZER 1
+#elif defined(__SANITIZE_THREAD__)
+#define ABSL_HAVE_THREAD_SANITIZER 1
+#elif ABSL_HAVE_FEATURE(thread_sanitizer)
+#define ABSL_HAVE_THREAD_SANITIZER 1
+#endif
+
+// ABSL_HAVE_ADDRESS_SANITIZER
+//
+// AddressSanitizer (ASan) is a fast memory error detector.
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+#error "ABSL_HAVE_ADDRESS_SANITIZER cannot be directly set."
+#elif defined(ADDRESS_SANITIZER)
+// The ADDRESS_SANITIZER macro is deprecated but we will continue to honor it
+// for now.
+#define ABSL_HAVE_ADDRESS_SANITIZER 1
+#elif defined(__SANITIZE_ADDRESS__)
+#define ABSL_HAVE_ADDRESS_SANITIZER 1
+#elif ABSL_HAVE_FEATURE(address_sanitizer)
+#define ABSL_HAVE_ADDRESS_SANITIZER 1
+#endif
+
#endif // ABSL_BASE_CONFIG_H_
diff --git a/third_party/abseil/absl/base/const_init.h b/third_party/abseil/absl/base/const_init.h
index 17858a7..16520b6 100644
--- a/third_party/abseil/absl/base/const_init.h
+++ b/third_party/abseil/absl/base/const_init.h
@@ -22,6 +22,8 @@
#ifndef ABSL_BASE_CONST_INIT_H_
#define ABSL_BASE_CONST_INIT_H_
+#include "absl/base/config.h"
+
// In general, objects with static storage duration (such as global variables)
// can trigger tricky object lifetime situations. Attempting to access them
// from the constructors or destructors of other global objects can result in
@@ -62,11 +64,13 @@
// or thread_local storage duration.
namespace absl {
+ABSL_NAMESPACE_BEGIN
enum ConstInitType {
kConstInit,
};
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_CONST_INIT_H_
diff --git a/third_party/abseil/absl/base/dynamic_annotations.cc b/third_party/abseil/absl/base/dynamic_annotations.cc
deleted file mode 100644
index 21e822e..0000000
--- a/third_party/abseil/absl/base/dynamic_annotations.cc
+++ /dev/null
@@ -1,129 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#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/third_party/abseil/absl/base/dynamic_annotations.h b/third_party/abseil/absl/base/dynamic_annotations.h
index 65a54b4..545f8cb 100644
--- a/third_party/abseil/absl/base/dynamic_annotations.h
+++ b/third_party/abseil/absl/base/dynamic_annotations.h
@@ -1,389 +1,482 @@
-/*
- * Copyright 2017 The Abseil Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/* This file defines dynamic annotations for use with dynamic analysis
- tool such as valgrind, PIN, etc.
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
- 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. */
+// This file defines dynamic annotations for use with dynamic analysis tool
+// such as valgrind, PIN, etc.
+//
+// Dynamic annotation is a source code annotation that affects the generated
+// code (that is, the annotation is not a comment). Each such annotation is
+// attached to a particular instruction and/or to a particular object (address)
+// in the program.
+//
+// The annotations that should be used by users are macros in all upper-case
+// (e.g., ABSL_ANNOTATE_THREAD_NAME).
+//
+// Actual implementation of these macros may differ depending on the dynamic
+// analysis tool being used.
+//
+// This file supports the following configurations:
+// - Dynamic Annotations enabled (with static thread-safety warnings disabled).
+// In this case, macros expand to functions implemented by Thread Sanitizer,
+// when building with TSan. When not provided an external implementation,
+// dynamic_annotations.cc provides no-op implementations.
+//
+// - Static Clang thread-safety warnings enabled.
+// When building with a Clang compiler that supports thread-safety warnings,
+// a subset of annotations can be statically-checked at compile-time. We
+// expand these macros to static-inline functions that can be analyzed for
+// thread-safety, but afterwards elided when building the final binary.
+//
+// - All annotations are disabled.
+// If neither Dynamic Annotations nor Clang thread-safety warnings are
+// enabled, then all annotation-macros expand to empty.
#ifndef ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
#define ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
-#ifndef DYNAMIC_ANNOTATIONS_ENABLED
-# define DYNAMIC_ANNOTATIONS_ENABLED 0
-#endif
-
-#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>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.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 IGNORE_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
+#include "absl/base/macros.h"
#endif
-/* Return non-zero value if running under valgrind.
+// TODO(rogeeff): Remove after the backward compatibility period.
+#include "absl/base/internal/dynamic_annotations.h" // IWYU pragma: export
- 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
+// -------------------------------------------------------------------------
+// Decide which features are enabled.
- 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);
+#ifdef ABSL_HAVE_THREAD_SANITIZER
-/* 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);
+#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 1
+#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 1
+#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 1
+#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0
+#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED 1
+
+#else
+
+#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 0
+#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 0
+#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 0
+
+// 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. When running in opt-mode, GCC
+// will issue a warning, if these attributes are compiled. Only include them
+// when compiling using Clang.
+
+#if defined(__clang__)
+#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 1
+#if !defined(SWIG)
+#define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 1
+#endif
+#else
+#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0
+#endif
+
+// Read/write annotations are enabled in Annotalysis mode; disabled otherwise.
+#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED \
+ ABSL_INTERNAL_ANNOTALYSIS_ENABLED
+
+#endif // ABSL_HAVE_THREAD_SANITIZER
#ifdef __cplusplus
-}
+#define ABSL_INTERNAL_BEGIN_EXTERN_C extern "C" {
+#define ABSL_INTERNAL_END_EXTERN_C } // extern "C"
+#define ABSL_INTERNAL_GLOBAL_SCOPED(F) ::F
+#define ABSL_INTERNAL_STATIC_INLINE inline
+#else
+#define ABSL_INTERNAL_BEGIN_EXTERN_C // empty
+#define ABSL_INTERNAL_END_EXTERN_C // empty
+#define ABSL_INTERNAL_GLOBAL_SCOPED(F) F
+#define ABSL_INTERNAL_STATIC_INLINE static inline
#endif
-/* ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
+// -------------------------------------------------------------------------
+// Define race annotations.
- 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)
+#if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1
+
+// -------------------------------------------------------------
+// Annotations that suppress errors. It is usually better to express the
+// program's synchronization using the other annotations, but these can be used
+// when all else fails.
+
+// Report that we may have a benign race at `pointer`, with size
+// "sizeof(*(pointer))". `pointer` must be a non-void* pointer. Insert at the
+// point where `pointer` has been allocated, preferably close to the point
+// where the race happens. See also ABSL_ANNOTATE_BENIGN_RACE_STATIC.
+#define ABSL_ANNOTATE_BENIGN_RACE(pointer, description) \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \
+ (__FILE__, __LINE__, pointer, sizeof(*(pointer)), description)
+
+// Same as ABSL_ANNOTATE_BENIGN_RACE(`address`, `description`), but applies to
+// the memory range [`address`, `address`+`size`).
+#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
+ ABSL_INTERNAL_GLOBAL_SCOPED(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 ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateEnableRaceDetection) \
+ (__FILE__, __LINE__, enable)
+
+// -------------------------------------------------------------
+// Annotations useful for debugging.
+
+// Report the current thread `name` to a race detector.
+#define ABSL_ANNOTATE_THREAD_NAME(name) \
+ ABSL_INTERNAL_GLOBAL_SCOPED(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 ABSL_ANNOTATE_RWLOCK_CREATE(lock) \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreate)(__FILE__, __LINE__, lock)
+
+// Report that a linker initialized lock has been created at address `lock`.
+#ifdef ABSL_HAVE_THREAD_SANITIZER
+#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreateStatic) \
+ (__FILE__, __LINE__, lock)
+#else
+#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
+ ABSL_ANNOTATE_RWLOCK_CREATE(lock)
+#endif
+
+// Report that the lock at address `lock` is about to be destroyed.
+#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) \
+ ABSL_INTERNAL_GLOBAL_SCOPED(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 ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockAcquired) \
+ (__FILE__, __LINE__, lock, is_w)
+
+// Report that the lock at address `lock` is about to be released.
+// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
+#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockReleased) \
+ (__FILE__, __LINE__, lock, is_w)
+
+// Apply ABSL_ANNOTATE_BENIGN_RACE_SIZED to a static variable `static_var`.
+#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \
+ namespace { \
+ class static_var##_annotator { \
+ public: \
+ static_var##_annotator() { \
+ ABSL_ANNOTATE_BENIGN_RACE_SIZED(&static_var, sizeof(static_var), \
+ #static_var ": " description); \
+ } \
+ }; \
+ static static_var##_annotator the##static_var##_annotator; \
+ } // namespace
+
+// Function prototypes of annotations provided by the compiler-based sanitizer
+// implementation.
+ABSL_INTERNAL_BEGIN_EXTERN_C
+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);
+ABSL_INTERNAL_END_EXTERN_C
+
+#else // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 0
+
+#define ABSL_ANNOTATE_RWLOCK_CREATE(lock) // empty
+#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) // empty
+#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) // empty
+#define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) // empty
+#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) // empty
+#define ABSL_ANNOTATE_BENIGN_RACE(address, description) // empty
+#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) // empty
+#define ABSL_ANNOTATE_THREAD_NAME(name) // empty
+#define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) // empty
+#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) // empty
+
+#endif // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
+
+// -------------------------------------------------------------------------
+// Define memory annotations.
+
+#ifdef ABSL_HAVE_MEMORY_SANITIZER
+
+#include <sanitizer/msan_interface.h>
+
+#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
+ __msan_unpoison(address, size)
+
+#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
+ __msan_allocated_memory(address, size)
+
+#else // !defined(ABSL_HAVE_MEMORY_SANITIZER)
+
+// TODO(rogeeff): remove this branch
+#ifdef ABSL_HAVE_THREAD_SANITIZER
+#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
+ do { \
+ (void)(address); \
+ (void)(size); \
+ } while (0)
+#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
+ do { \
+ (void)(address); \
+ (void)(size); \
+ } while (0)
+#else
+
+#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) // empty
+#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) // empty
+
+#endif
+
+#endif // ABSL_HAVE_MEMORY_SANITIZER
+
+// -------------------------------------------------------------------------
+// Define IGNORE_READS_BEGIN/_END attributes.
+
+#if defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
+
+#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE \
+ __attribute((exclusive_lock_function("*")))
+#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE \
+ __attribute((unlock_function("*")))
+
+#else // !defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
+
+#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE // empty
+#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE // empty
+
+#endif // defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
+
+// -------------------------------------------------------------------------
+// Define IGNORE_READS_BEGIN/_END annotations.
+
+#if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1
+
+// Request the analysis tool to ignore all reads in the current thread until
+// ABSL_ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey
+// reads, while still checking other reads and all writes.
+// See also ABSL_ANNOTATE_UNPROTECTED_READ.
+#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin)(__FILE__, __LINE__)
+
+// Stop ignoring reads.
+#define ABSL_ANNOTATE_IGNORE_READS_END() \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd)(__FILE__, __LINE__)
+
+// Function prototypes of annotations provided by the compiler-based sanitizer
+// implementation.
+ABSL_INTERNAL_BEGIN_EXTERN_C
+void AnnotateIgnoreReadsBegin(const char* file, int line)
+ ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE;
+void AnnotateIgnoreReadsEnd(const char* file,
+ int line) ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE;
+ABSL_INTERNAL_END_EXTERN_C
+
+#elif defined(ABSL_INTERNAL_ANNOTALYSIS_ENABLED)
+
+// When Annotalysis is enabled without Dynamic Annotations, the use of
+// static-inline functions allows the annotations to be read at compile-time,
+// while still letting the compiler elide the functions from the final build.
+//
+// TODO(delesley) -- The exclusive lock here ignores writes as well, but
+// allows IGNORE_READS_AND_WRITES to work properly.
+
+#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsBegin)()
+
+#define ABSL_ANNOTATE_IGNORE_READS_END() \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsEnd)()
+
+ABSL_INTERNAL_STATIC_INLINE void AbslInternalAnnotateIgnoreReadsBegin()
+ ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE {}
+
+ABSL_INTERNAL_STATIC_INLINE void AbslInternalAnnotateIgnoreReadsEnd()
+ ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE {}
+
+#else
+
+#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() // empty
+#define ABSL_ANNOTATE_IGNORE_READS_END() // empty
+
+#endif
+
+// -------------------------------------------------------------------------
+// Define IGNORE_WRITES_BEGIN/_END annotations.
+
+#if ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED == 1
+
+// Similar to ABSL_ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead.
+#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__)
+
+// Stop ignoring writes.
+#define ABSL_ANNOTATE_IGNORE_WRITES_END() \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__)
+
+// Function prototypes of annotations provided by the compiler-based sanitizer
+// implementation.
+ABSL_INTERNAL_BEGIN_EXTERN_C
+void AnnotateIgnoreWritesBegin(const char* file, int line);
+void AnnotateIgnoreWritesEnd(const char* file, int line);
+ABSL_INTERNAL_END_EXTERN_C
+
+#else
+
+#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() // empty
+#define ABSL_ANNOTATE_IGNORE_WRITES_END() // empty
+
+#endif
+
+// -------------------------------------------------------------------------
+// Define the ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more
+// primitive annotations defined above.
+//
+// Instead of doing
+// ABSL_ANNOTATE_IGNORE_READS_BEGIN();
+// ... = x;
+// ABSL_ANNOTATE_IGNORE_READS_END();
+// one can use
+// ... = ABSL_ANNOTATE_UNPROTECTED_READ(x);
+
+#if defined(ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED)
+
+// Start ignoring all memory accesses (both reads and writes).
+#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
+ do { \
+ ABSL_ANNOTATE_IGNORE_READS_BEGIN(); \
+ ABSL_ANNOTATE_IGNORE_WRITES_BEGIN(); \
+ } while (0)
+
+// Stop ignoring both reads and writes.
+#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() \
+ do { \
+ ABSL_ANNOTATE_IGNORE_WRITES_END(); \
+ ABSL_ANNOTATE_IGNORE_READS_END(); \
+ } while (0)
+
+#ifdef __cplusplus
+// ABSL_ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
+#define ABSL_ANNOTATE_UNPROTECTED_READ(x) \
+ absl::base_internal::AnnotateUnprotectedRead(x)
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
template <typename T>
-inline T ANNOTATE_UNPROTECTED_READ(const volatile T &x) { /* NOLINT */
- ANNOTATE_IGNORE_READS_BEGIN();
+inline T AnnotateUnprotectedRead(const volatile T& x) { // NOLINT
+ ABSL_ANNOTATE_IGNORE_READS_BEGIN();
T res = x;
- ANNOTATE_IGNORE_READS_END();
+ ABSL_ANNOTATE_IGNORE_READS_END();
return res;
- }
-#else
- #define ANNOTATE_UNPROTECTED_READ(x) (x)
+}
+
+} // namespace base_internal
+ABSL_NAMESPACE_END
+} // namespace absl
#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) static_assert(true, "")
-#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
+#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() // empty
+#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() // empty
+#define ABSL_ANNOTATE_UNPROTECTED_READ(x) (x)
-#endif /* ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ */
+#endif
+
+#ifdef __cplusplus
+#ifdef ABSL_HAVE_THREAD_SANITIZER
+ABSL_INTERNAL_BEGIN_EXTERN_C
+int RunningOnValgrind();
+double ValgrindSlowdown();
+ABSL_INTERNAL_END_EXTERN_C
+#else
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+ABSL_DEPRECATED(
+ "Don't use this interface. It is misleading and is being deleted.")
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline int RunningOnValgrind() { return 0; }
+ABSL_DEPRECATED(
+ "Don't use this interface. It is misleading and is being deleted.")
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline double ValgrindSlowdown() { return 1.0; }
+} // namespace base_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+using absl::base_internal::RunningOnValgrind;
+using absl::base_internal::ValgrindSlowdown;
+#endif
+#endif
+
+// -------------------------------------------------------------------------
+// Address sanitizer annotations
+
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+// Describe the current state of a contiguous container such as e.g.
+// std::vector or std::string. For more details see
+// sanitizer/common_interface_defs.h, which is provided by the compiler.
+#include <sanitizer/common_interface_defs.h>
+
+#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \
+ __sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid)
+#define ABSL_ADDRESS_SANITIZER_REDZONE(name) \
+ struct { \
+ char x[8] __attribute__((aligned(8))); \
+ } name
+
+#else
+
+#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) // empty
+#define ABSL_ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "")
+
+#endif // ABSL_HAVE_ADDRESS_SANITIZER
+
+// -------------------------------------------------------------------------
+// Undefine the macros intended only for this file.
+
+#undef ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_ANNOTALYSIS_ENABLED
+#undef ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_BEGIN_EXTERN_C
+#undef ABSL_INTERNAL_END_EXTERN_C
+#undef ABSL_INTERNAL_STATIC_INLINE
+
+#endif // ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
diff --git a/third_party/abseil/absl/base/exception_safety_testing_test.cc b/third_party/abseil/absl/base/exception_safety_testing_test.cc
index 575b535..a59be29 100644
--- a/third_party/abseil/absl/base/exception_safety_testing_test.cc
+++ b/third_party/abseil/absl/base/exception_safety_testing_test.cc
@@ -328,17 +328,15 @@
UnsetCountdown();
}
-using Storage =
- absl::aligned_storage_t<sizeof(ThrowingValue<>), alignof(ThrowingValue<>)>;
-
TEST(ThrowingValueTest, NonThrowingPlacementDelete) {
constexpr int kArrayLen = 2;
// We intentionally create extra space to store the tag allocated by placement
// new[].
constexpr int kStorageLen = 4;
- Storage buf;
- Storage array_buf[kStorageLen];
+ alignas(ThrowingValue<>) unsigned char buf[sizeof(ThrowingValue<>)];
+ alignas(ThrowingValue<>) unsigned char
+ array_buf[sizeof(ThrowingValue<>[kStorageLen])];
auto* placed = new (&buf) ThrowingValue<>(1);
auto placed_array = new (&array_buf) ThrowingValue<>[kArrayLen];
@@ -902,12 +900,12 @@
}
TEST(ConstructorTrackerTest, NotDestroyedAfter) {
- absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage;
+ alignas(Tracked) unsigned char storage[sizeof(Tracked)];
EXPECT_NONFATAL_FAILURE(
{
exceptions_internal::ConstructorTracker ct(
exceptions_internal::countdown);
- new (&storage) Tracked;
+ new (&storage) Tracked();
},
"not destroyed");
}
@@ -924,11 +922,11 @@
TEST(ConstructorTrackerTest, ConstructedTwice) {
exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
- absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage;
+ alignas(Tracked) unsigned char storage[sizeof(Tracked)];
EXPECT_NONFATAL_FAILURE(
{
- new (&storage) Tracked;
- new (&storage) Tracked;
+ new (&storage) Tracked();
+ new (&storage) Tracked();
reinterpret_cast<Tracked*>(&storage)->~Tracked();
},
"re-constructed");
diff --git a/third_party/abseil/absl/base/inline_variable_test.cc b/third_party/abseil/absl/base/inline_variable_test.cc
index 471f706..37a40e1 100644
--- a/third_party/abseil/absl/base/inline_variable_test.cc
+++ b/third_party/abseil/absl/base/inline_variable_test.cc
@@ -20,6 +20,7 @@
#include "gtest/gtest.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace inline_variable_testing_internal {
namespace {
@@ -59,4 +60,5 @@
} // namespace
} // namespace inline_variable_testing_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/base/inline_variable_test_a.cc b/third_party/abseil/absl/base/inline_variable_test_a.cc
index d0b8e7d..f96a58d 100644
--- a/third_party/abseil/absl/base/inline_variable_test_a.cc
+++ b/third_party/abseil/absl/base/inline_variable_test_a.cc
@@ -15,6 +15,7 @@
#include "absl/base/internal/inline_variable_testing.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace inline_variable_testing_internal {
const Foo& get_foo_a() { return inline_variable_foo; }
@@ -22,4 +23,5 @@
const int& get_int_a() { return inline_variable_int; }
} // namespace inline_variable_testing_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/base/inline_variable_test_b.cc b/third_party/abseil/absl/base/inline_variable_test_b.cc
index 931d56d..038adc3 100644
--- a/third_party/abseil/absl/base/inline_variable_test_b.cc
+++ b/third_party/abseil/absl/base/inline_variable_test_b.cc
@@ -15,6 +15,7 @@
#include "absl/base/internal/inline_variable_testing.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace inline_variable_testing_internal {
const Foo& get_foo_b() { return inline_variable_foo; }
@@ -22,4 +23,5 @@
const int& get_int_b() { return inline_variable_int; }
} // namespace inline_variable_testing_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/base/internal/atomic_hook.h b/third_party/abseil/absl/base/internal/atomic_hook.h
index 803e905..ae21cd7 100644
--- a/third_party/abseil/absl/base/internal/atomic_hook.h
+++ b/third_party/abseil/absl/base/internal/atomic_hook.h
@@ -11,7 +11,6 @@
// WITHOUT 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_
@@ -21,28 +20,51 @@
#include <cstdint>
#include <utility>
-#ifdef _MSC_FULL_VER
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+
+#if defined(_MSC_VER) && !defined(__clang__)
+#define ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT 0
+#else
+#define ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT 1
+#endif
+
+#if defined(_MSC_VER)
#define ABSL_HAVE_WORKING_ATOMIC_POINTER 0
#else
#define ABSL_HAVE_WORKING_ATOMIC_POINTER 1
#endif
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
template <typename T>
class AtomicHook;
-// AtomicHook is a helper class, templatized on a raw function pointer type, for
-// implementing Abseil customization hooks. It is a callable object that
-// dispatches to the registered hook.
+// To workaround AtomicHook not being constant-initializable on some platforms,
+// prefer to annotate instances with `ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES`
+// instead of `ABSL_CONST_INIT`.
+#if ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
+#define ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_CONST_INIT
+#else
+#define ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
+#endif
+
+// `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. Objects of type `AtomicHook` must have
+// static or thread storage duration.
//
// A default constructed object performs a no-op (and returns a default
// constructed object) if no hook has been registered.
//
-// Hooks can be pre-registered via constant initialization, for example,
-// ABSL_CONST_INIT static AtomicHook<void(*)()> my_hook(DefaultAction);
-// and then changed at runtime via a call to Store().
+// Hooks can be pre-registered via constant initialization, for example:
+//
+// ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static AtomicHook<void(*)()>
+// my_hook(DefaultAction);
+//
+// and then changed at runtime via a call to `Store()`.
//
// Reads and writes guarantee memory_order_acquire/memory_order_release
// semantics.
@@ -57,12 +79,23 @@
// Constructs an object that by default dispatches to/returns the
// pre-registered default_fn when no hook has been registered at runtime.
-#if ABSL_HAVE_WORKING_ATOMIC_POINTER
+#if ABSL_HAVE_WORKING_ATOMIC_POINTER && ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
explicit constexpr AtomicHook(FnPtr default_fn)
: hook_(default_fn), default_fn_(default_fn) {}
-#else
+#elif ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
explicit constexpr AtomicHook(FnPtr default_fn)
: hook_(kUninitialized), default_fn_(default_fn) {}
+#else
+ // As of January 2020, on all known versions of MSVC this constructor runs in
+ // the global constructor sequence. If `Store()` is called by a dynamic
+ // initializer, we want to preserve the value, even if this constructor runs
+ // after the call to `Store()`. If not, `hook_` will be
+ // zero-initialized by the linker and we have no need to set it.
+ // https://developercommunity.visualstudio.com/content/problem/336946/class-with-constexpr-constructor-not-using-static.html
+ explicit constexpr AtomicHook(FnPtr default_fn)
+ : /* hook_(deliberately omitted), */ default_fn_(default_fn) {
+ static_assert(kUninitialized == 0, "here we rely on zero-initialization");
+ }
#endif
// Stores the provided function pointer as the value for this hook.
@@ -158,8 +191,10 @@
};
#undef ABSL_HAVE_WORKING_ATOMIC_POINTER
+#undef ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
diff --git a/third_party/abseil/absl/base/internal/atomic_hook_test.cc b/third_party/abseil/absl/base/internal/atomic_hook_test.cc
index ecc8040..e577a8f 100644
--- a/third_party/abseil/absl/base/internal/atomic_hook_test.cc
+++ b/third_party/abseil/absl/base/internal/atomic_hook_test.cc
@@ -14,16 +14,22 @@
#include "absl/base/internal/atomic_hook.h"
+#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/attributes.h"
+#include "absl/base/internal/atomic_hook_test_helper.h"
namespace {
+using ::testing::Eq;
+
int value = 0;
void TestHook(int x) { value = x; }
TEST(AtomicHookTest, NoDefaultFunction) {
- ABSL_CONST_INIT static absl::base_internal::AtomicHook<void(*)(int)> hook;
+ ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static absl::base_internal::AtomicHook<
+ void (*)(int)>
+ hook;
value = 0;
// Test the default DummyFunction.
@@ -49,8 +55,9 @@
TEST(AtomicHookTest, WithDefaultFunction) {
// Set the default value to TestHook at compile-time.
- ABSL_CONST_INIT static absl::base_internal::AtomicHook<void (*)(int)> hook(
- TestHook);
+ ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static absl::base_internal::AtomicHook<
+ void (*)(int)>
+ hook(TestHook);
value = 0;
// Test the default value is TestHook.
@@ -67,4 +74,24 @@
EXPECT_EQ(value, 2);
}
+ABSL_CONST_INIT int override_func_calls = 0;
+void OverrideFunc() { override_func_calls++; }
+static struct OverrideInstaller {
+ OverrideInstaller() { absl::atomic_hook_internal::func.Store(OverrideFunc); }
+} override_installer;
+
+TEST(AtomicHookTest, DynamicInitFromAnotherTU) {
+ // MSVC 14.2 doesn't do constexpr static init correctly; in particular it
+ // tends to sequence static init (i.e. defaults) of `AtomicHook` objects
+ // after their dynamic init (i.e. overrides), overwriting whatever value was
+ // written during dynamic init. This regression test validates the fix.
+ // https://developercommunity.visualstudio.com/content/problem/336946/class-with-constexpr-constructor-not-using-static.html
+ EXPECT_THAT(absl::atomic_hook_internal::default_func_calls, Eq(0));
+ EXPECT_THAT(override_func_calls, Eq(0));
+ absl::atomic_hook_internal::func();
+ EXPECT_THAT(absl::atomic_hook_internal::default_func_calls, Eq(0));
+ EXPECT_THAT(override_func_calls, Eq(1));
+ EXPECT_THAT(absl::atomic_hook_internal::func.Load(), Eq(OverrideFunc));
+}
+
} // namespace
diff --git a/third_party/abseil/absl/base/internal/atomic_hook_test_helper.cc b/third_party/abseil/absl/base/internal/atomic_hook_test_helper.cc
new file mode 100644
index 0000000..537d47c
--- /dev/null
+++ b/third_party/abseil/absl/base/internal/atomic_hook_test_helper.cc
@@ -0,0 +1,32 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/atomic_hook_test_helper.h"
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/atomic_hook.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace atomic_hook_internal {
+
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES absl::base_internal::AtomicHook<VoidF>
+ func(DefaultFunc);
+ABSL_CONST_INIT int default_func_calls = 0;
+void DefaultFunc() { default_func_calls++; }
+void RegisterFunc(VoidF f) { func.Store(f); }
+
+} // namespace atomic_hook_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/base/internal/atomic_hook_test_helper.h b/third_party/abseil/absl/base/internal/atomic_hook_test_helper.h
new file mode 100644
index 0000000..3e72b49
--- /dev/null
+++ b/third_party/abseil/absl/base/internal/atomic_hook_test_helper.h
@@ -0,0 +1,34 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_BASE_ATOMIC_HOOK_TEST_HELPER_H_
+#define ABSL_BASE_ATOMIC_HOOK_TEST_HELPER_H_
+
+#include "absl/base/internal/atomic_hook.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace atomic_hook_internal {
+
+using VoidF = void (*)();
+extern absl::base_internal::AtomicHook<VoidF> func;
+extern int default_func_calls;
+void DefaultFunc();
+void RegisterFunc(VoidF func);
+
+} // namespace atomic_hook_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_BASE_ATOMIC_HOOK_TEST_HELPER_H_
diff --git a/third_party/abseil/absl/base/internal/bits.h b/third_party/abseil/absl/base/internal/bits.h
deleted file mode 100644
index b0780f2..0000000
--- a/third_party/abseil/absl/base/internal/bits.h
+++ /dev/null
@@ -1,193 +0,0 @@
-// Copyright 2018 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef ABSL_BASE_INTERNAL_BITS_H_
-#define ABSL_BASE_INTERNAL_BITS_H_
-
-// This file contains bitwise ops which are implementation details of various
-// absl libraries.
-
-#include <cstdint>
-
-// Clang on Windows has __builtin_clzll; otherwise we need to use the
-// windows intrinsic functions.
-#if defined(_MSC_VER)
-#include <intrin.h>
-#if defined(_M_X64)
-#pragma intrinsic(_BitScanReverse64)
-#pragma intrinsic(_BitScanForward64)
-#endif
-#pragma intrinsic(_BitScanReverse)
-#pragma intrinsic(_BitScanForward)
-#endif
-
-#include "absl/base/attributes.h"
-
-#if defined(_MSC_VER)
-// We can achieve something similar to attribute((always_inline)) with MSVC by
-// using the __forceinline keyword, however this is not perfect. MSVC is
-// much less aggressive about inlining, and even with the __forceinline keyword.
-#define ABSL_BASE_INTERNAL_FORCEINLINE __forceinline
-#else
-// Use default attribute inline.
-#define ABSL_BASE_INTERNAL_FORCEINLINE inline ABSL_ATTRIBUTE_ALWAYS_INLINE
-#endif
-
-
-namespace absl {
-namespace base_internal {
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64Slow(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"[n] + zeroes;
-}
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) {
-#if defined(_MSC_VER) && defined(_M_X64)
- // MSVC does not have __buitin_clzll. Use _BitScanReverse64.
- unsigned long result = 0; // NOLINT(runtime/int)
- if (_BitScanReverse64(&result, n)) {
- return 63 - result;
- }
- return 64;
-#elif defined(_MSC_VER)
- // MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse
- unsigned long result = 0; // NOLINT(runtime/int)
- if ((n >> 32) && _BitScanReverse(&result, n >> 32)) {
- return 31 - result;
- }
- if (_BitScanReverse(&result, n)) {
- return 63 - result;
- }
- return 64;
-#elif defined(__GNUC__)
- // Use __builtin_clzll, which uses the following instructions:
- // x86: bsr
- // ARM64: clz
- // PPC: cntlzd
- static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int)
- "__builtin_clzll does not take 64-bit arg");
-
- // Handle 0 as a special case because __builtin_clzll(0) is undefined.
- if (n == 0) {
- return 64;
- }
- return __builtin_clzll(n);
-#else
- return CountLeadingZeros64Slow(n);
-#endif
-}
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32Slow(uint64_t n) {
- int zeroes = 28;
- 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"[n] + zeroes;
-}
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32(uint32_t n) {
-#if defined(_MSC_VER)
- unsigned long result = 0; // NOLINT(runtime/int)
- if (_BitScanReverse(&result, n)) {
- return 31 - result;
- }
- return 32;
-#elif defined(__GNUC__)
- // Use __builtin_clz, which uses the following instructions:
- // x86: bsr
- // ARM64: clz
- // PPC: cntlzd
- static_assert(sizeof(int) == sizeof(n),
- "__builtin_clz does not take 32-bit arg");
-
- // Handle 0 as a special case because __builtin_clz(0) is undefined.
- if (n == 0) {
- return 32;
- }
- return __builtin_clz(n);
-#else
- return CountLeadingZeros32Slow(n);
-#endif
-}
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64Slow(uint64_t n) {
- int c = 63;
- n &= ~n + 1;
- if (n & 0x00000000FFFFFFFF) c -= 32;
- if (n & 0x0000FFFF0000FFFF) c -= 16;
- if (n & 0x00FF00FF00FF00FF) c -= 8;
- if (n & 0x0F0F0F0F0F0F0F0F) c -= 4;
- if (n & 0x3333333333333333) c -= 2;
- if (n & 0x5555555555555555) c -= 1;
- return c;
-}
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64(uint64_t n) {
-#if defined(_MSC_VER) && defined(_M_X64)
- unsigned long result = 0; // NOLINT(runtime/int)
- _BitScanForward64(&result, n);
- return result;
-#elif defined(_MSC_VER)
- unsigned long result = 0; // NOLINT(runtime/int)
- if (static_cast<uint32_t>(n) == 0) {
- _BitScanForward(&result, n >> 32);
- return result + 32;
- }
- _BitScanForward(&result, n);
- return result;
-#elif defined(__GNUC__)
- static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int)
- "__builtin_ctzll does not take 64-bit arg");
- return __builtin_ctzll(n);
-#else
- return CountTrailingZerosNonZero64Slow(n);
-#endif
-}
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32Slow(uint32_t n) {
- int c = 31;
- n &= ~n + 1;
- if (n & 0x0000FFFF) c -= 16;
- if (n & 0x00FF00FF) c -= 8;
- if (n & 0x0F0F0F0F) c -= 4;
- if (n & 0x33333333) c -= 2;
- if (n & 0x55555555) c -= 1;
- return c;
-}
-
-ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32(uint32_t n) {
-#if defined(_MSC_VER)
- unsigned long result = 0; // NOLINT(runtime/int)
- _BitScanForward(&result, n);
- return result;
-#elif defined(__GNUC__)
- static_assert(sizeof(int) == sizeof(n),
- "__builtin_ctz does not take 32-bit arg");
- return __builtin_ctz(n);
-#else
- return CountTrailingZerosNonZero32Slow(n);
-#endif
-}
-
-#undef ABSL_BASE_INTERNAL_FORCEINLINE
-
-} // namespace base_internal
-} // namespace absl
-
-#endif // ABSL_BASE_INTERNAL_BITS_H_
diff --git a/third_party/abseil/absl/base/internal/bits_test.cc b/third_party/abseil/absl/base/internal/bits_test.cc
deleted file mode 100644
index 7855fa6..0000000
--- a/third_party/abseil/absl/base/internal/bits_test.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2018 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/base/internal/bits.h"
-
-#include "gtest/gtest.h"
-
-namespace {
-
-int CLZ64(uint64_t n) {
- int fast = absl::base_internal::CountLeadingZeros64(n);
- int slow = absl::base_internal::CountLeadingZeros64Slow(n);
- EXPECT_EQ(fast, slow) << n;
- return fast;
-}
-
-TEST(BitsTest, CountLeadingZeros64) {
- EXPECT_EQ(64, CLZ64(uint64_t{}));
- EXPECT_EQ(0, CLZ64(~uint64_t{}));
-
- for (int index = 0; index < 64; index++) {
- uint64_t x = static_cast<uint64_t>(1) << index;
- const auto cnt = 63 - index;
- ASSERT_EQ(cnt, CLZ64(x)) << index;
- ASSERT_EQ(cnt, CLZ64(x + x - 1)) << index;
- }
-}
-
-int CLZ32(uint32_t n) {
- int fast = absl::base_internal::CountLeadingZeros32(n);
- int slow = absl::base_internal::CountLeadingZeros32Slow(n);
- EXPECT_EQ(fast, slow) << n;
- return fast;
-}
-
-TEST(BitsTest, CountLeadingZeros32) {
- EXPECT_EQ(32, CLZ32(uint32_t{}));
- EXPECT_EQ(0, CLZ32(~uint32_t{}));
-
- for (int index = 0; index < 32; index++) {
- uint32_t x = static_cast<uint32_t>(1) << index;
- const auto cnt = 31 - index;
- ASSERT_EQ(cnt, CLZ32(x)) << index;
- ASSERT_EQ(cnt, CLZ32(x + x - 1)) << index;
- ASSERT_EQ(CLZ64(x), CLZ32(x) + 32);
- }
-}
-
-int CTZ64(uint64_t n) {
- int fast = absl::base_internal::CountTrailingZerosNonZero64(n);
- int slow = absl::base_internal::CountTrailingZerosNonZero64Slow(n);
- EXPECT_EQ(fast, slow) << n;
- return fast;
-}
-
-TEST(BitsTest, CountTrailingZerosNonZero64) {
- EXPECT_EQ(0, CTZ64(~uint64_t{}));
-
- for (int index = 0; index < 64; index++) {
- uint64_t x = static_cast<uint64_t>(1) << index;
- const auto cnt = index;
- ASSERT_EQ(cnt, CTZ64(x)) << index;
- ASSERT_EQ(cnt, CTZ64(~(x - 1))) << index;
- }
-}
-
-int CTZ32(uint32_t n) {
- int fast = absl::base_internal::CountTrailingZerosNonZero32(n);
- int slow = absl::base_internal::CountTrailingZerosNonZero32Slow(n);
- EXPECT_EQ(fast, slow) << n;
- return fast;
-}
-
-TEST(BitsTest, CountTrailingZerosNonZero32) {
- EXPECT_EQ(0, CTZ32(~uint32_t{}));
-
- for (int index = 0; index < 32; index++) {
- uint32_t x = static_cast<uint32_t>(1) << index;
- const auto cnt = index;
- ASSERT_EQ(cnt, CTZ32(x)) << index;
- ASSERT_EQ(cnt, CTZ32(~(x - 1))) << index;
- }
-}
-
-
-} // namespace
diff --git a/third_party/abseil/absl/base/internal/cycleclock.cc b/third_party/abseil/absl/base/internal/cycleclock.cc
index e9844b7..0e65005 100644
--- a/third_party/abseil/absl/base/internal/cycleclock.cc
+++ b/third_party/abseil/absl/base/internal/cycleclock.cc
@@ -28,6 +28,7 @@
#include "absl/base/internal/unscaledcycleclock.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
#if ABSL_USE_UNSCALED_CYCLECLOCK
@@ -102,4 +103,5 @@
#endif
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/base/internal/cycleclock.h b/third_party/abseil/absl/base/internal/cycleclock.h
index 794564e..a18b584 100644
--- a/third_party/abseil/absl/base/internal/cycleclock.h
+++ b/third_party/abseil/absl/base/internal/cycleclock.h
@@ -44,7 +44,10 @@
#include <cstdint>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
// -----------------------------------------------------------------------------
@@ -85,6 +88,7 @@
};
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_CYCLECLOCK_H_
diff --git a/third_party/abseil/absl/base/internal/direct_mmap.h b/third_party/abseil/absl/base/internal/direct_mmap.h
index 0401ddf..16accf0 100644
--- a/third_party/abseil/absl/base/internal/direct_mmap.h
+++ b/third_party/abseil/absl/base/internal/direct_mmap.h
@@ -61,7 +61,12 @@
#endif
#endif // __BIONIC__
+#if defined(__NR_mmap2) && !defined(SYS_mmap2)
+#define SYS_mmap2 __NR_mmap2
+#endif
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
// Platform specific logic extracted from
@@ -71,6 +76,7 @@
#if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \
(defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \
(defined(__PPC__) && !defined(__PPC64__)) || \
+ (defined(__riscv) && __riscv_xlen == 32) || \
(defined(__s390__) && !defined(__s390x__))
// On these architectures, implement mmap with mmap2.
static int pagesize = 0;
@@ -128,6 +134,7 @@
}
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
#else // !__linux__
@@ -136,6 +143,7 @@
// actual mmap()/munmap() methods.
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd,
@@ -148,6 +156,7 @@
}
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // __linux__
diff --git a/third_party/abseil/absl/base/internal/dynamic_annotations.h b/third_party/abseil/absl/base/internal/dynamic_annotations.h
new file mode 100644
index 0000000..b23c5ec
--- /dev/null
+++ b/third_party/abseil/absl/base/internal/dynamic_annotations.h
@@ -0,0 +1,398 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// 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_INTERNAL_DYNAMIC_ANNOTATIONS_H_
+#define ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_
+
+#include <stddef.h>
+
+#include "absl/base/config.h"
+
+// -------------------------------------------------------------------------
+// Decide which features are enabled
+
+#ifndef DYNAMIC_ANNOTATIONS_ENABLED
+#define DYNAMIC_ANNOTATIONS_ENABLED 0
+#endif
+
+#if defined(__clang__) && !defined(SWIG)
+#define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 1
+#endif
+
+#if DYNAMIC_ANNOTATIONS_ENABLED != 0
+
+#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 1
+#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 1
+#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 1
+#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0
+#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED 1
+
+#else
+
+#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 0
+#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 0
+#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 0
+
+// 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. When running in opt-mode, GCC
+// will issue a warning, if these attributes are compiled. Only include them
+// when compiling using Clang.
+
+// ANNOTALYSIS_ENABLED == 1 when IGNORE_READ_ATTRIBUTE_ENABLED == 1
+#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED \
+ defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
+// Read/write annotations are enabled in Annotalysis mode; disabled otherwise.
+#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED \
+ ABSL_INTERNAL_ANNOTALYSIS_ENABLED
+#endif
+
+// Memory annotations are also made available to LLVM's Memory Sanitizer
+#if defined(ABSL_HAVE_MEMORY_SANITIZER) && !defined(__native_client__)
+#define ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED 1
+#endif
+
+#ifndef ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED
+#define ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED 0
+#endif
+
+#ifdef __cplusplus
+#define ABSL_INTERNAL_BEGIN_EXTERN_C extern "C" {
+#define ABSL_INTERNAL_END_EXTERN_C } // extern "C"
+#define ABSL_INTERNAL_GLOBAL_SCOPED(F) ::F
+#define ABSL_INTERNAL_STATIC_INLINE inline
+#else
+#define ABSL_INTERNAL_BEGIN_EXTERN_C // empty
+#define ABSL_INTERNAL_END_EXTERN_C // empty
+#define ABSL_INTERNAL_GLOBAL_SCOPED(F) F
+#define ABSL_INTERNAL_STATIC_INLINE static inline
+#endif
+
+// -------------------------------------------------------------------------
+// Define race annotations.
+
+#if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1
+
+// -------------------------------------------------------------
+// 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) \
+ ABSL_INTERNAL_GLOBAL_SCOPED(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) \
+ ABSL_INTERNAL_GLOBAL_SCOPED(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) \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateEnableRaceDetection) \
+ (__FILE__, __LINE__, enable)
+
+// -------------------------------------------------------------
+// Annotations useful for debugging.
+
+// Report the current thread `name` to a race detector.
+#define ANNOTATE_THREAD_NAME(name) \
+ ABSL_INTERNAL_GLOBAL_SCOPED(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) \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreate)(__FILE__, __LINE__, lock)
+
+// Report that a linker initialized lock has been created at address `lock`.
+#ifdef ABSL_HAVE_THREAD_SANITIZER
+#define ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
+ ABSL_INTERNAL_GLOBAL_SCOPED(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) \
+ ABSL_INTERNAL_GLOBAL_SCOPED(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) \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockAcquired) \
+ (__FILE__, __LINE__, lock, is_w)
+
+// Report that the lock at address `lock` is about to be released.
+// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
+#define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockReleased) \
+ (__FILE__, __LINE__, lock, is_w)
+
+// Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable `static_var`.
+#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 // ABSL_INTERNAL_RACE_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
+#define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) // empty
+
+#endif // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
+
+// -------------------------------------------------------------------------
+// Define memory annotations.
+
+#if ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED == 1
+
+#include <sanitizer/msan_interface.h>
+
+#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
+ __msan_unpoison(address, size)
+
+#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
+ __msan_allocated_memory(address, size)
+
+#else // ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED == 0
+
+#if DYNAMIC_ANNOTATIONS_ENABLED == 1
+#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
+ do { \
+ (void)(address); \
+ (void)(size); \
+ } while (0)
+#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
+ do { \
+ (void)(address); \
+ (void)(size); \
+ } while (0)
+#else
+#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) // empty
+#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) // empty
+#endif
+
+#endif // ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED
+
+// -------------------------------------------------------------------------
+// Define IGNORE_READS_BEGIN/_END attributes.
+
+#if defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
+
+#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE \
+ __attribute((exclusive_lock_function("*")))
+#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE \
+ __attribute((unlock_function("*")))
+
+#else // !defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
+
+#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE // empty
+#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE // empty
+
+#endif // defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
+
+// -------------------------------------------------------------------------
+// Define IGNORE_READS_BEGIN/_END annotations.
+
+#if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1
+
+// 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() \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin)(__FILE__, __LINE__)
+
+// Stop ignoring reads.
+#define ANNOTATE_IGNORE_READS_END() \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd)(__FILE__, __LINE__)
+
+#elif defined(ABSL_INTERNAL_ANNOTALYSIS_ENABLED)
+
+// When Annotalysis is enabled without Dynamic Annotations, the use of
+// static-inline functions allows the annotations to be read at compile-time,
+// while still letting the compiler elide the functions from the final build.
+//
+// TODO(delesley) -- The exclusive lock here ignores writes as well, but
+// allows IGNORE_READS_AND_WRITES to work properly.
+
+#define ANNOTATE_IGNORE_READS_BEGIN() \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsBegin)()
+
+#define ANNOTATE_IGNORE_READS_END() \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsEnd)()
+
+#else
+
+#define ANNOTATE_IGNORE_READS_BEGIN() // empty
+#define ANNOTATE_IGNORE_READS_END() // empty
+
+#endif
+
+// -------------------------------------------------------------------------
+// Define IGNORE_WRITES_BEGIN/_END annotations.
+
+#if ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED == 1
+
+// Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead.
+#define ANNOTATE_IGNORE_WRITES_BEGIN() \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__)
+
+// Stop ignoring writes.
+#define ANNOTATE_IGNORE_WRITES_END() \
+ ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__)
+
+#else
+
+#define ANNOTATE_IGNORE_WRITES_BEGIN() // empty
+#define ANNOTATE_IGNORE_WRITES_END() // empty
+
+#endif
+
+// -------------------------------------------------------------------------
+// Define the ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more
+// primitive annotations defined above.
+//
+// Instead of doing
+// ANNOTATE_IGNORE_READS_BEGIN();
+// ... = x;
+// ANNOTATE_IGNORE_READS_END();
+// one can use
+// ... = ANNOTATE_UNPROTECTED_READ(x);
+
+#if defined(ABSL_INTERNAL_READS_WRITES_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)
+
+#ifdef __cplusplus
+// ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
+#define ANNOTATE_UNPROTECTED_READ(x) \
+ absl::base_internal::AnnotateUnprotectedRead(x)
+
+#endif
+
+#else
+
+#define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() // empty
+#define ANNOTATE_IGNORE_READS_AND_WRITES_END() // empty
+#define ANNOTATE_UNPROTECTED_READ(x) (x)
+
+#endif
+
+// -------------------------------------------------------------------------
+// Address sanitizer annotations
+
+#ifdef ABSL_HAVE_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) static_assert(true, "")
+
+#endif // ABSL_HAVE_ADDRESS_SANITIZER
+
+// -------------------------------------------------------------------------
+// Undefine the macros intended only for this file.
+
+#undef ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_ANNOTALYSIS_ENABLED
+#undef ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_BEGIN_EXTERN_C
+#undef ABSL_INTERNAL_END_EXTERN_C
+#undef ABSL_INTERNAL_STATIC_INLINE
+
+#endif // ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_
diff --git a/third_party/abseil/absl/base/internal/endian.h b/third_party/abseil/absl/base/internal/endian.h
index 296e92d..9677530 100644
--- a/third_party/abseil/absl/base/internal/endian.h
+++ b/third_party/abseil/absl/base/internal/endian.h
@@ -19,9 +19,6 @@
// The following guarantees declaration of the byte swap functions
#ifdef _MSC_VER
#include <stdlib.h> // NOLINT(build/include)
-#elif defined(__APPLE__)
-// macOS / Darwin features
-#include <libkern/OSByteOrder.h>
#elif defined(__FreeBSD__)
#include <sys/endian.h>
#elif defined(__GLIBC__)
@@ -34,6 +31,7 @@
#include "absl/base/port.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// 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.
@@ -63,11 +61,6 @@
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__)
@@ -113,7 +106,7 @@
#endif
}
-#endif // intrinics available
+#endif // intrinsics available
#ifdef ABSL_IS_LITTLE_ENDIAN
@@ -267,6 +260,7 @@
} // namespace big_endian
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_ENDIAN_H_
diff --git a/third_party/abseil/absl/base/internal/endian_test.cc b/third_party/abseil/absl/base/internal/endian_test.cc
index 98a099e..a1691b1 100644
--- a/third_party/abseil/absl/base/internal/endian_test.cc
+++ b/third_party/abseil/absl/base/internal/endian_test.cc
@@ -24,6 +24,7 @@
#include "absl/base/config.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
const uint64_t kInitialNumber{0x0123456789abcdef};
@@ -53,24 +54,22 @@
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;
+std::vector<uint16_t> GenerateAllUint16Values() {
+ std::vector<uint16_t> result;
+ result.reserve(size_t{1} << (sizeof(uint16_t) * 8));
+ for (uint32_t i = std::numeric_limits<uint16_t>::min();
+ i <= std::numeric_limits<uint16_t>::max(); ++i) {
+ result.push_back(static_cast<uint16_t>(i));
}
+ return result;
}
template<typename T>
-std::vector<T> GenerateRandomIntegers(size_t numValuesToTest) {
+std::vector<T> GenerateRandomIntegers(size_t num_values_to_test) {
std::vector<T> result;
+ result.reserve(num_values_to_test);
std::mt19937_64 rng(kRandomSeed);
- for (size_t i = 0; i < numValuesToTest; ++i) {
+ for (size_t i = 0; i < num_values_to_test; ++i) {
result.push_back(rng());
}
return result;
@@ -147,7 +146,7 @@
}
TEST(EndianessTest, Uint16) {
- GBSwapHelper(GenerateAllValuesForType<uint16_t>(), &Swap16);
+ GBSwapHelper(GenerateAllUint16Values(), &Swap16);
}
TEST(EndianessTest, Uint32) {
@@ -260,4 +259,5 @@
}
} // namespace
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/base/internal/errno_saver.h b/third_party/abseil/absl/base/internal/errno_saver.h
new file mode 100644
index 0000000..251de51
--- /dev/null
+++ b/third_party/abseil/absl/base/internal/errno_saver.h
@@ -0,0 +1,43 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_BASE_INTERNAL_ERRNO_SAVER_H_
+#define ABSL_BASE_INTERNAL_ERRNO_SAVER_H_
+
+#include <cerrno>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// `ErrnoSaver` captures the value of `errno` upon construction and restores it
+// upon deletion. It is used in low-level code and must be super fast. Do not
+// add instrumentation, even in debug modes.
+class ErrnoSaver {
+ public:
+ ErrnoSaver() : saved_errno_(errno) {}
+ ~ErrnoSaver() { errno = saved_errno_; }
+ int operator()() const { return saved_errno_; }
+
+ private:
+ const int saved_errno_;
+};
+
+} // namespace base_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_BASE_INTERNAL_ERRNO_SAVER_H_
diff --git a/third_party/abseil/absl/base/internal/errno_saver_test.cc b/third_party/abseil/absl/base/internal/errno_saver_test.cc
new file mode 100644
index 0000000..e9b742c
--- /dev/null
+++ b/third_party/abseil/absl/base/internal/errno_saver_test.cc
@@ -0,0 +1,45 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/errno_saver.h"
+
+#include <cerrno>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/strerror.h"
+
+namespace {
+using ::testing::Eq;
+
+struct ErrnoPrinter {
+ int no;
+};
+std::ostream &operator<<(std::ostream &os, ErrnoPrinter ep) {
+ return os << absl::base_internal::StrError(ep.no) << " [" << ep.no << "]";
+}
+bool operator==(ErrnoPrinter one, ErrnoPrinter two) { return one.no == two.no; }
+
+TEST(ErrnoSaverTest, Works) {
+ errno = EDOM;
+ {
+ absl::base_internal::ErrnoSaver errno_saver;
+ EXPECT_THAT(ErrnoPrinter{errno}, Eq(ErrnoPrinter{EDOM}));
+ errno = ERANGE;
+ EXPECT_THAT(ErrnoPrinter{errno}, Eq(ErrnoPrinter{ERANGE}));
+ EXPECT_THAT(ErrnoPrinter{errno_saver()}, Eq(ErrnoPrinter{EDOM}));
+ }
+ EXPECT_THAT(ErrnoPrinter{errno}, Eq(ErrnoPrinter{EDOM}));
+}
+} // namespace
diff --git a/third_party/abseil/absl/base/internal/exponential_biased.cc b/third_party/abseil/absl/base/internal/exponential_biased.cc
new file mode 100644
index 0000000..1b30c06
--- /dev/null
+++ b/third_party/abseil/absl/base/internal/exponential_biased.cc
@@ -0,0 +1,93 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/exponential_biased.h"
+
+#include <stdint.h>
+
+#include <algorithm>
+#include <atomic>
+#include <cmath>
+#include <limits>
+
+#include "absl/base/attributes.h"
+#include "absl/base/optimization.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// The algorithm generates a random number between 0 and 1 and applies the
+// inverse cumulative distribution function for an exponential. Specifically:
+// Let m be the inverse of the sample period, then the probability
+// distribution function is m*exp(-mx) so the CDF is
+// p = 1 - exp(-mx), so
+// q = 1 - p = exp(-mx)
+// log_e(q) = -mx
+// -log_e(q)/m = x
+// log_2(q) * (-log_e(2) * 1/m) = x
+// In the code, q is actually in the range 1 to 2**26, hence the -26 below
+int64_t ExponentialBiased::GetSkipCount(int64_t mean) {
+ if (ABSL_PREDICT_FALSE(!initialized_)) {
+ Initialize();
+ }
+
+ uint64_t rng = NextRandom(rng_);
+ rng_ = rng;
+
+ // Take the top 26 bits as the random number
+ // (This plus the 1<<58 sampling bound give a max possible step of
+ // 5194297183973780480 bytes.)
+ // The uint32_t cast is to prevent a (hard-to-reproduce) NAN
+ // under piii debug for some binaries.
+ double q = static_cast<uint32_t>(rng >> (kPrngNumBits - 26)) + 1.0;
+ // Put the computed p-value through the CDF of a geometric.
+ double interval = bias_ + (std::log2(q) - 26) * (-std::log(2.0) * mean);
+ // Very large values of interval overflow int64_t. To avoid that, we will
+ // cheat and clamp any huge values to (int64_t max)/2. This is a potential
+ // source of bias, but the mean would need to be such a large value that it's
+ // not likely to come up. For example, with a mean of 1e18, the probability of
+ // hitting this condition is about 1/1000. For a mean of 1e17, standard
+ // calculators claim that this event won't happen.
+ if (interval > static_cast<double>(std::numeric_limits<int64_t>::max() / 2)) {
+ // Assume huge values are bias neutral, retain bias for next call.
+ return std::numeric_limits<int64_t>::max() / 2;
+ }
+ double value = std::round(interval);
+ bias_ = interval - value;
+ return value;
+}
+
+int64_t ExponentialBiased::GetStride(int64_t mean) {
+ return GetSkipCount(mean - 1) + 1;
+}
+
+void ExponentialBiased::Initialize() {
+ // We don't get well distributed numbers from `this` so we call NextRandom() a
+ // bunch to mush the bits around. We use a global_rand to handle the case
+ // where the same thread (by memory address) gets created and destroyed
+ // repeatedly.
+ ABSL_CONST_INIT static std::atomic<uint32_t> global_rand(0);
+ uint64_t r = reinterpret_cast<uint64_t>(this) +
+ global_rand.fetch_add(1, std::memory_order_relaxed);
+ for (int i = 0; i < 20; ++i) {
+ r = NextRandom(r);
+ }
+ rng_ = r;
+ initialized_ = true;
+}
+
+} // namespace base_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/base/internal/exponential_biased.h b/third_party/abseil/absl/base/internal/exponential_biased.h
new file mode 100644
index 0000000..94f79a3
--- /dev/null
+++ b/third_party/abseil/absl/base/internal/exponential_biased.h
@@ -0,0 +1,130 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_BASE_INTERNAL_EXPONENTIAL_BIASED_H_
+#define ABSL_BASE_INTERNAL_EXPONENTIAL_BIASED_H_
+
+#include <stdint.h>
+
+#include "absl/base/config.h"
+#include "absl/base/macros.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// ExponentialBiased provides a small and fast random number generator for a
+// rounded exponential distribution. This generator manages very little state,
+// and imposes no synchronization overhead. This makes it useful in specialized
+// scenarios requiring minimum overhead, such as stride based periodic sampling.
+//
+// ExponentialBiased provides two closely related functions, GetSkipCount() and
+// GetStride(), both returning a rounded integer defining a number of events
+// required before some event with a given mean probability occurs.
+//
+// The distribution is useful to generate a random wait time or some periodic
+// event with a given mean probability. For example, if an action is supposed to
+// happen on average once every 'N' events, then we can get a random 'stride'
+// counting down how long before the event to happen. For example, if we'd want
+// to sample one in every 1000 'Frobber' calls, our code could look like this:
+//
+// Frobber::Frobber() {
+// stride_ = exponential_biased_.GetStride(1000);
+// }
+//
+// void Frobber::Frob(int arg) {
+// if (--stride == 0) {
+// SampleFrob(arg);
+// stride_ = exponential_biased_.GetStride(1000);
+// }
+// ...
+// }
+//
+// The rounding of the return value creates a bias, especially for smaller means
+// where the distribution of the fraction is not evenly distributed. We correct
+// this bias by tracking the fraction we rounded up or down on each iteration,
+// effectively tracking the distance between the cumulative value, and the
+// rounded cumulative value. For example, given a mean of 2:
+//
+// raw = 1.63076, cumulative = 1.63076, rounded = 2, bias = -0.36923
+// raw = 0.14624, cumulative = 1.77701, rounded = 2, bias = 0.14624
+// raw = 4.93194, cumulative = 6.70895, rounded = 7, bias = -0.06805
+// raw = 0.24206, cumulative = 6.95101, rounded = 7, bias = 0.24206
+// etc...
+//
+// Adjusting with rounding bias is relatively trivial:
+//
+// double value = bias_ + exponential_distribution(mean)();
+// double rounded_value = std::round(value);
+// bias_ = value - rounded_value;
+// return rounded_value;
+//
+// This class is thread-compatible.
+class ExponentialBiased {
+ public:
+ // The number of bits set by NextRandom.
+ static constexpr int kPrngNumBits = 48;
+
+ // `GetSkipCount()` returns the number of events to skip before some chosen
+ // event happens. For example, randomly tossing a coin, we will on average
+ // throw heads once before we get tails. We can simulate random coin tosses
+ // using GetSkipCount() as:
+ //
+ // ExponentialBiased eb;
+ // for (...) {
+ // int number_of_heads_before_tail = eb.GetSkipCount(1);
+ // for (int flips = 0; flips < number_of_heads_before_tail; ++flips) {
+ // printf("head...");
+ // }
+ // printf("tail\n");
+ // }
+ //
+ int64_t GetSkipCount(int64_t mean);
+
+ // GetStride() returns the number of events required for a specific event to
+ // happen. See the class comments for a usage example. `GetStride()` is
+ // equivalent to `GetSkipCount(mean - 1) + 1`. When to use `GetStride()` or
+ // `GetSkipCount()` depends mostly on what best fits the use case.
+ int64_t GetStride(int64_t mean);
+
+ // Computes a random number in the range [0, 1<<(kPrngNumBits+1) - 1]
+ //
+ // This is public to enable testing.
+ static uint64_t NextRandom(uint64_t rnd);
+
+ private:
+ void Initialize();
+
+ uint64_t rng_{0};
+ double bias_{0};
+ bool initialized_{false};
+};
+
+// Returns the next prng value.
+// pRNG is: aX+b mod c with a = 0x5DEECE66D, b = 0xB, c = 1<<48
+// This is the lrand64 generator.
+inline uint64_t ExponentialBiased::NextRandom(uint64_t rnd) {
+ const uint64_t prng_mult = uint64_t{0x5DEECE66D};
+ const uint64_t prng_add = 0xB;
+ const uint64_t prng_mod_power = 48;
+ const uint64_t prng_mod_mask =
+ ~((~static_cast<uint64_t>(0)) << prng_mod_power);
+ return (prng_mult * rnd + prng_add) & prng_mod_mask;
+}
+
+} // namespace base_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_BASE_INTERNAL_EXPONENTIAL_BIASED_H_
diff --git a/third_party/abseil/absl/base/internal/exponential_biased_test.cc b/third_party/abseil/absl/base/internal/exponential_biased_test.cc
new file mode 100644
index 0000000..075583c
--- /dev/null
+++ b/third_party/abseil/absl/base/internal/exponential_biased_test.cc
@@ -0,0 +1,199 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/exponential_biased.h"
+
+#include <stddef.h>
+
+#include <cmath>
+#include <cstdint>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/strings/str_cat.h"
+
+using ::testing::Ge;
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+MATCHER_P2(IsBetween, a, b,
+ absl::StrCat(std::string(negation ? "isn't" : "is"), " between ", a,
+ " and ", b)) {
+ return a <= arg && arg <= b;
+}
+
+// Tests of the quality of the random numbers generated
+// This uses the Anderson Darling test for uniformity.
+// See "Evaluating the Anderson-Darling Distribution" by Marsaglia
+// for details.
+
+// Short cut version of ADinf(z), z>0 (from Marsaglia)
+// This returns the p-value for Anderson Darling statistic in
+// the limit as n-> infinity. For finite n, apply the error fix below.
+double AndersonDarlingInf(double z) {
+ if (z < 2) {
+ return exp(-1.2337141 / z) / sqrt(z) *
+ (2.00012 +
+ (0.247105 -
+ (0.0649821 - (0.0347962 - (0.011672 - 0.00168691 * z) * z) * z) *
+ z) *
+ z);
+ }
+ return exp(
+ -exp(1.0776 -
+ (2.30695 -
+ (0.43424 - (0.082433 - (0.008056 - 0.0003146 * z) * z) * z) * z) *
+ z));
+}
+
+// Corrects the approximation error in AndersonDarlingInf for small values of n
+// Add this to AndersonDarlingInf to get a better approximation
+// (from Marsaglia)
+double AndersonDarlingErrFix(int n, double x) {
+ if (x > 0.8) {
+ return (-130.2137 +
+ (745.2337 -
+ (1705.091 - (1950.646 - (1116.360 - 255.7844 * x) * x) * x) * x) *
+ x) /
+ n;
+ }
+ double cutoff = 0.01265 + 0.1757 / n;
+ if (x < cutoff) {
+ double t = x / cutoff;
+ t = sqrt(t) * (1 - t) * (49 * t - 102);
+ return t * (0.0037 / (n * n) + 0.00078 / n + 0.00006) / n;
+ } else {
+ double t = (x - cutoff) / (0.8 - cutoff);
+ t = -0.00022633 +
+ (6.54034 - (14.6538 - (14.458 - (8.259 - 1.91864 * t) * t) * t) * t) *
+ t;
+ return t * (0.04213 + 0.01365 / n) / n;
+ }
+}
+
+// Returns the AndersonDarling p-value given n and the value of the statistic
+double AndersonDarlingPValue(int n, double z) {
+ double ad = AndersonDarlingInf(z);
+ double errfix = AndersonDarlingErrFix(n, ad);
+ return ad + errfix;
+}
+
+double AndersonDarlingStatistic(const std::vector<double>& random_sample) {
+ int n = random_sample.size();
+ double ad_sum = 0;
+ for (int i = 0; i < n; i++) {
+ ad_sum += (2 * i + 1) *
+ std::log(random_sample[i] * (1 - random_sample[n - 1 - i]));
+ }
+ double ad_statistic = -n - 1 / static_cast<double>(n) * ad_sum;
+ return ad_statistic;
+}
+
+// Tests if the array of doubles is uniformly distributed.
+// Returns the p-value of the Anderson Darling Statistic
+// for the given set of sorted random doubles
+// See "Evaluating the Anderson-Darling Distribution" by
+// Marsaglia and Marsaglia for details.
+double AndersonDarlingTest(const std::vector<double>& random_sample) {
+ double ad_statistic = AndersonDarlingStatistic(random_sample);
+ double p = AndersonDarlingPValue(random_sample.size(), ad_statistic);
+ return p;
+}
+
+TEST(ExponentialBiasedTest, CoinTossDemoWithGetSkipCount) {
+ ExponentialBiased eb;
+ for (int runs = 0; runs < 10; ++runs) {
+ for (int flips = eb.GetSkipCount(1); flips > 0; --flips) {
+ printf("head...");
+ }
+ printf("tail\n");
+ }
+ int heads = 0;
+ for (int i = 0; i < 10000000; i += 1 + eb.GetSkipCount(1)) {
+ ++heads;
+ }
+ printf("Heads = %d (%f%%)\n", heads, 100.0 * heads / 10000000);
+}
+
+TEST(ExponentialBiasedTest, SampleDemoWithStride) {
+ ExponentialBiased eb;
+ int stride = eb.GetStride(10);
+ int samples = 0;
+ for (int i = 0; i < 10000000; ++i) {
+ if (--stride == 0) {
+ ++samples;
+ stride = eb.GetStride(10);
+ }
+ }
+ printf("Samples = %d (%f%%)\n", samples, 100.0 * samples / 10000000);
+}
+
+
+// Testing that NextRandom generates uniform random numbers. Applies the
+// Anderson-Darling test for uniformity
+TEST(ExponentialBiasedTest, TestNextRandom) {
+ for (auto n : std::vector<int>({
+ 10, // Check short-range correlation
+ 100, 1000,
+ 10000 // Make sure there's no systemic error
+ })) {
+ uint64_t x = 1;
+ // This assumes that the prng returns 48 bit numbers
+ uint64_t max_prng_value = static_cast<uint64_t>(1) << 48;
+ // Initialize.
+ for (int i = 1; i <= 20; i++) {
+ x = ExponentialBiased::NextRandom(x);
+ }
+ std::vector<uint64_t> int_random_sample(n);
+ // Collect samples
+ for (int i = 0; i < n; i++) {
+ int_random_sample[i] = x;
+ x = ExponentialBiased::NextRandom(x);
+ }
+ // First sort them...
+ std::sort(int_random_sample.begin(), int_random_sample.end());
+ std::vector<double> random_sample(n);
+ // Convert them to uniform randoms (in the range [0,1])
+ for (int i = 0; i < n; i++) {
+ random_sample[i] =
+ static_cast<double>(int_random_sample[i]) / max_prng_value;
+ }
+ // Now compute the Anderson-Darling statistic
+ double ad_pvalue = AndersonDarlingTest(random_sample);
+ EXPECT_GT(std::min(ad_pvalue, 1 - ad_pvalue), 0.0001)
+ << "prng is not uniform: n = " << n << " p = " << ad_pvalue;
+ }
+}
+
+// The generator needs to be available as a thread_local and as a static
+// variable.
+TEST(ExponentialBiasedTest, InitializationModes) {
+ ABSL_CONST_INIT static ExponentialBiased eb_static;
+ EXPECT_THAT(eb_static.GetSkipCount(2), Ge(0));
+
+#ifdef ABSL_HAVE_THREAD_LOCAL
+ thread_local ExponentialBiased eb_thread;
+ EXPECT_THAT(eb_thread.GetSkipCount(2), Ge(0));
+#endif
+
+ ExponentialBiased eb_stack;
+ EXPECT_THAT(eb_stack.GetSkipCount(2), Ge(0));
+}
+
+} // namespace base_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/base/internal/fast_type_id.h b/third_party/abseil/absl/base/internal/fast_type_id.h
new file mode 100644
index 0000000..3db59e8
--- /dev/null
+++ b/third_party/abseil/absl/base/internal/fast_type_id.h
@@ -0,0 +1,48 @@
+//
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
+#define ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+template <typename Type>
+struct FastTypeTag {
+ constexpr static char dummy_var = 0;
+};
+
+template <typename Type>
+constexpr char FastTypeTag<Type>::dummy_var;
+
+// FastTypeId<Type>() evaluates at compile/link-time to a unique pointer for the
+// passed-in type. These are meant to be good match for keys into maps or
+// straight up comparisons.
+using FastTypeIdType = const void*;
+
+template <typename Type>
+constexpr inline FastTypeIdType FastTypeId() {
+ return &FastTypeTag<Type>::dummy_var;
+}
+
+} // namespace base_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
diff --git a/third_party/abseil/absl/base/internal/fast_type_id_test.cc b/third_party/abseil/absl/base/internal/fast_type_id_test.cc
new file mode 100644
index 0000000..16f3c14
--- /dev/null
+++ b/third_party/abseil/absl/base/internal/fast_type_id_test.cc
@@ -0,0 +1,123 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/fast_type_id.h"
+
+#include <cstdint>
+#include <map>
+#include <vector>
+
+#include "gtest/gtest.h"
+
+namespace {
+namespace bi = absl::base_internal;
+
+// NOLINTNEXTLINE
+#define PRIM_TYPES(A) \
+ A(bool) \
+ A(short) \
+ A(unsigned short) \
+ A(int) \
+ A(unsigned int) \
+ A(long) \
+ A(unsigned long) \
+ A(long long) \
+ A(unsigned long long) \
+ A(float) \
+ A(double) \
+ A(long double)
+
+TEST(FastTypeIdTest, PrimitiveTypes) {
+ bi::FastTypeIdType type_ids[] = {
+#define A(T) bi::FastTypeId<T>(),
+ PRIM_TYPES(A)
+#undef A
+#define A(T) bi::FastTypeId<const T>(),
+ PRIM_TYPES(A)
+#undef A
+#define A(T) bi::FastTypeId<volatile T>(),
+ PRIM_TYPES(A)
+#undef A
+#define A(T) bi::FastTypeId<const volatile T>(),
+ PRIM_TYPES(A)
+#undef A
+ };
+ size_t total_type_ids = sizeof(type_ids) / sizeof(bi::FastTypeIdType);
+
+ for (int i = 0; i < total_type_ids; ++i) {
+ EXPECT_EQ(type_ids[i], type_ids[i]);
+ for (int j = 0; j < i; ++j) {
+ EXPECT_NE(type_ids[i], type_ids[j]);
+ }
+ }
+}
+
+#define FIXED_WIDTH_TYPES(A) \
+ A(int8_t) \
+ A(uint8_t) \
+ A(int16_t) \
+ A(uint16_t) \
+ A(int32_t) \
+ A(uint32_t) \
+ A(int64_t) \
+ A(uint64_t)
+
+TEST(FastTypeIdTest, FixedWidthTypes) {
+ bi::FastTypeIdType type_ids[] = {
+#define A(T) bi::FastTypeId<T>(),
+ FIXED_WIDTH_TYPES(A)
+#undef A
+#define A(T) bi::FastTypeId<const T>(),
+ FIXED_WIDTH_TYPES(A)
+#undef A
+#define A(T) bi::FastTypeId<volatile T>(),
+ FIXED_WIDTH_TYPES(A)
+#undef A
+#define A(T) bi::FastTypeId<const volatile T>(),
+ FIXED_WIDTH_TYPES(A)
+#undef A
+ };
+ size_t total_type_ids = sizeof(type_ids) / sizeof(bi::FastTypeIdType);
+
+ for (int i = 0; i < total_type_ids; ++i) {
+ EXPECT_EQ(type_ids[i], type_ids[i]);
+ for (int j = 0; j < i; ++j) {
+ EXPECT_NE(type_ids[i], type_ids[j]);
+ }
+ }
+}
+
+TEST(FastTypeIdTest, AliasTypes) {
+ using int_alias = int;
+ EXPECT_EQ(bi::FastTypeId<int_alias>(), bi::FastTypeId<int>());
+}
+
+TEST(FastTypeIdTest, TemplateSpecializations) {
+ EXPECT_NE(bi::FastTypeId<std::vector<int>>(),
+ bi::FastTypeId<std::vector<long>>());
+
+ EXPECT_NE((bi::FastTypeId<std::map<int, float>>()),
+ (bi::FastTypeId<std::map<int, double>>()));
+}
+
+struct Base {};
+struct Derived : Base {};
+struct PDerived : private Base {};
+
+TEST(FastTypeIdTest, Inheritance) {
+ EXPECT_NE(bi::FastTypeId<Base>(), bi::FastTypeId<Derived>());
+ EXPECT_NE(bi::FastTypeId<Base>(), bi::FastTypeId<PDerived>());
+}
+
+} // namespace
diff --git a/third_party/abseil/absl/base/internal/hide_ptr.h b/third_party/abseil/absl/base/internal/hide_ptr.h
index cf8f408..1dba809 100644
--- a/third_party/abseil/absl/base/internal/hide_ptr.h
+++ b/third_party/abseil/absl/base/internal/hide_ptr.h
@@ -17,7 +17,10 @@
#include <cstdint>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
// Arbitrary value with high bits set. Xor'ing with it is unlikely
@@ -42,6 +45,7 @@
}
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_HIDE_PTR_H_
diff --git a/third_party/abseil/absl/base/internal/identity.h b/third_party/abseil/absl/base/internal/identity.h
index 086447c..a3154ed 100644
--- a/third_party/abseil/absl/base/internal/identity.h
+++ b/third_party/abseil/absl/base/internal/identity.h
@@ -16,7 +16,10 @@
#ifndef ABSL_BASE_INTERNAL_IDENTITY_H_
#define ABSL_BASE_INTERNAL_IDENTITY_H_
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace internal {
template <typename T>
@@ -28,6 +31,7 @@
using identity_t = typename identity<T>::type;
} // namespace internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_IDENTITY_H_
diff --git a/third_party/abseil/absl/base/internal/inline_variable_testing.h b/third_party/abseil/absl/base/internal/inline_variable_testing.h
index 15dc481..3856b9f 100644
--- a/third_party/abseil/absl/base/internal/inline_variable_testing.h
+++ b/third_party/abseil/absl/base/internal/inline_variable_testing.h
@@ -18,6 +18,7 @@
#include "absl/base/internal/inline_variable.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace inline_variable_testing_internal {
struct Foo {
@@ -39,6 +40,7 @@
const int& get_int_b();
} // namespace inline_variable_testing_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INLINE_VARIABLE_TESTING_H_
diff --git a/third_party/abseil/absl/base/internal/invoke.h b/third_party/abseil/absl/base/internal/invoke.h
index 44f1330..5c71f32 100644
--- a/third_party/abseil/absl/base/internal/invoke.h
+++ b/third_party/abseil/absl/base/internal/invoke.h
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-// absl::base_internal::Invoke(f, args...) is an implementation of
+// absl::base_internal::invoke(f, args...) is an implementation of
// INVOKE(f, args...) from section [func.require] of the C++ standard.
//
// [func.require]
@@ -29,7 +29,7 @@
// 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()
+// The implementation is SFINAE-friendly: substitution failure within invoke()
// isn't an error.
#ifndef ABSL_BASE_INTERNAL_INVOKE_H_
@@ -45,6 +45,7 @@
// top of this file for the API documentation.
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
// The five classes below each implement one of the clauses from the definition
@@ -169,17 +170,18 @@
// The result type of Invoke<F, Args...>.
template <typename F, typename... Args>
-using InvokeT = decltype(Invoker<F, Args...>::type::Invoke(
+using invoke_result_t = 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) {
+invoke_result_t<F, Args...> invoke(F&& f, Args&&... args) {
return Invoker<F, Args...>::type::Invoke(std::forward<F>(f),
std::forward<Args>(args)...);
}
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_INVOKE_H_
diff --git a/third_party/abseil/absl/base/internal/low_level_alloc.cc b/third_party/abseil/absl/base/internal/low_level_alloc.cc
index 64d7aa8..229ab91 100644
--- a/third_party/abseil/absl/base/internal/low_level_alloc.cc
+++ b/third_party/abseil/absl/base/internal/low_level_alloc.cc
@@ -63,6 +63,7 @@
#endif // __APPLE__
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
// A first-fit allocator with amortized logarithmic free() time.
@@ -211,7 +212,7 @@
// Result of sysconf(_SC_PAGESIZE)
const size_t pagesize;
// Lowest power of two >= max(16, sizeof(AllocList))
- const size_t roundup;
+ const size_t round_up;
// Smallest allocation block size
const size_t min_size;
// PRNG state
@@ -219,16 +220,17 @@
};
namespace {
-using ArenaStorage = std::aligned_storage<sizeof(LowLevelAlloc::Arena),
- alignof(LowLevelAlloc::Arena)>::type;
-
// Static storage space for the lazily-constructed, default global arena
// instances. We require this space because the whole point of LowLevelAlloc
// is to avoid relying on malloc/new.
-ArenaStorage default_arena_storage;
-ArenaStorage unhooked_arena_storage;
+alignas(LowLevelAlloc::Arena) unsigned char default_arena_storage[sizeof(
+ LowLevelAlloc::Arena)];
+alignas(LowLevelAlloc::Arena) unsigned char unhooked_arena_storage[sizeof(
+ LowLevelAlloc::Arena)];
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
-ArenaStorage unhooked_async_sig_safe_arena_storage;
+alignas(
+ LowLevelAlloc::Arena) unsigned char unhooked_async_sig_safe_arena_storage
+ [sizeof(LowLevelAlloc::Arena)];
#endif
// We must use LowLevelCallOnce here to construct the global arenas, rather than
@@ -336,11 +338,11 @@
size_t RoundedUpBlockSize() {
// Round up block sizes to a power of two close to the header size.
- size_t roundup = 16;
- while (roundup < sizeof(AllocList::Header)) {
- roundup += roundup;
+ size_t round_up = 16;
+ while (round_up < sizeof(AllocList::Header)) {
+ round_up += round_up;
}
- return roundup;
+ return round_up;
}
} // namespace
@@ -350,8 +352,8 @@
allocation_count(0),
flags(flags_value),
pagesize(GetPageSize()),
- roundup(RoundedUpBlockSize()),
- min_size(2 * roundup),
+ round_up(RoundedUpBlockSize()),
+ min_size(2 * round_up),
random(0) {
freelist.header.size = 0;
freelist.header.magic =
@@ -447,7 +449,7 @@
// 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
+// 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];
@@ -508,8 +510,6 @@
if (v != nullptr) {
AllocList *f = reinterpret_cast<AllocList *>(
reinterpret_cast<char *>(v) - sizeof (f->header));
- ABSL_RAW_CHECK(f->header.magic == Magic(kMagicAllocated, &f->header),
- "bad magic number in Free()");
LowLevelAlloc::Arena *arena = f->header.arena;
ArenaLock section(arena);
AddToFreelist(v, arena);
@@ -528,7 +528,7 @@
ArenaLock section(arena);
// round up with header
size_t req_rnd = RoundUp(CheckedAdd(request, sizeof (s->header)),
- arena->roundup);
+ arena->round_up);
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;
@@ -598,7 +598,7 @@
section.Leave();
result = &s->levels;
}
- ANNOTATE_MEMORY_IS_UNINITIALIZED(result, request);
+ ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(result, request);
return result;
}
@@ -614,6 +614,7 @@
}
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_LOW_LEVEL_ALLOC_MISSING
diff --git a/third_party/abseil/absl/base/internal/low_level_alloc.h b/third_party/abseil/absl/base/internal/low_level_alloc.h
index c98cdb3..db91951 100644
--- a/third_party/abseil/absl/base/internal/low_level_alloc.h
+++ b/third_party/abseil/absl/base/internal/low_level_alloc.h
@@ -55,6 +55,7 @@
#include "absl/base/port.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
class LowLevelAlloc {
@@ -119,6 +120,7 @@
};
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
diff --git a/third_party/abseil/absl/base/internal/low_level_alloc_test.cc b/third_party/abseil/absl/base/internal/low_level_alloc_test.cc
index 34a080c..31abb88 100644
--- a/third_party/abseil/absl/base/internal/low_level_alloc_test.cc
+++ b/third_party/abseil/absl/base/internal/low_level_alloc_test.cc
@@ -21,7 +21,14 @@
#include <unordered_map>
#include <utility>
+#ifdef __EMSCRIPTEN__
+#include <emscripten.h>
+#endif
+
+#include "absl/container/node_hash_map.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
namespace {
@@ -74,7 +81,7 @@
// 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;
+ typedef absl::node_hash_map<int, BlockDesc> AllocMap;
AllocMap allocated;
AllocMap::iterator it;
BlockDesc block_desc;
@@ -149,10 +156,26 @@
} // namespace
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
int main(int argc, char *argv[]) {
// The actual test runs in the global constructor of `before_main`.
printf("PASS\n");
+#ifdef __EMSCRIPTEN__
+ // clang-format off
+// This is JS here. Don't try to format it.
+ MAIN_THREAD_EM_ASM({
+ if (ENVIRONMENT_IS_WEB) {
+ if (typeof TEST_FINISH === 'function') {
+ TEST_FINISH($0);
+ } else {
+ console.error('Attempted to exit with status ' + $0);
+ console.error('But TEST_FINSIHED is not a function.');
+ }
+ }
+ }, 0);
+// clang-format on
+#endif
return 0;
}
diff --git a/third_party/abseil/absl/base/internal/low_level_scheduling.h b/third_party/abseil/absl/base/internal/low_level_scheduling.h
index 0fcc8d3..9baccc0 100644
--- a/third_party/abseil/absl/base/internal/low_level_scheduling.h
+++ b/third_party/abseil/absl/base/internal/low_level_scheduling.h
@@ -18,6 +18,7 @@
#ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
#define ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
+#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/scheduling_mode.h"
#include "absl/base/macros.h"
@@ -28,6 +29,14 @@
extern "C" void __google_enable_rescheduling(bool disable_result);
namespace absl {
+ABSL_NAMESPACE_BEGIN
+class CondVar;
+class Mutex;
+
+namespace synchronization_internal {
+int MutexDelay(int32_t c, int mode);
+} // namespace synchronization_internal
+
namespace base_internal {
class SchedulingHelper; // To allow use of SchedulingGuard.
@@ -52,6 +61,8 @@
public:
// Returns true iff the calling thread may be cooperatively rescheduled.
static bool ReschedulingIsAllowed();
+ SchedulingGuard(const SchedulingGuard&) = delete;
+ SchedulingGuard& operator=(const SchedulingGuard&) = delete;
private:
// Disable cooperative rescheduling of the calling thread. It may still
@@ -75,12 +86,23 @@
bool disabled;
};
- // Access to SchedulingGuard is explicitly white-listed.
+ // A scoped helper to enable rescheduling temporarily.
+ // REQUIRES: destructor must run in same thread as constructor.
+ class ScopedEnable {
+ public:
+ ScopedEnable();
+ ~ScopedEnable();
+
+ private:
+ int scheduling_disabled_depth_;
+ };
+
+ // Access to SchedulingGuard is explicitly permitted.
+ friend class absl::CondVar;
+ friend class absl::Mutex;
friend class SchedulingHelper;
friend class SpinLock;
-
- SchedulingGuard(const SchedulingGuard&) = delete;
- SchedulingGuard& operator=(const SchedulingGuard&) = delete;
+ friend int absl::synchronization_internal::MutexDelay(int32_t c, int mode);
};
//------------------------------------------------------------------------------
@@ -99,7 +121,14 @@
return;
}
+inline SchedulingGuard::ScopedEnable::ScopedEnable()
+ : scheduling_disabled_depth_(0) {}
+inline SchedulingGuard::ScopedEnable::~ScopedEnable() {
+ ABSL_RAW_CHECK(scheduling_disabled_depth_ == 0, "disable unused warning");
+}
+
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
diff --git a/third_party/abseil/absl/base/internal/periodic_sampler.cc b/third_party/abseil/absl/base/internal/periodic_sampler.cc
new file mode 100644
index 0000000..520dabb
--- /dev/null
+++ b/third_party/abseil/absl/base/internal/periodic_sampler.cc
@@ -0,0 +1,53 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/periodic_sampler.h"
+
+#include <atomic>
+
+#include "absl/base/internal/exponential_biased.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+int64_t PeriodicSamplerBase::GetExponentialBiased(int period) noexcept {
+ return rng_.GetStride(period);
+}
+
+bool PeriodicSamplerBase::SubtleConfirmSample() noexcept {
+ int current_period = period();
+
+ // Deal with period case 0 (always off) and 1 (always on)
+ if (ABSL_PREDICT_FALSE(current_period < 2)) {
+ stride_ = 0;
+ return current_period == 1;
+ }
+
+ // Check if this is the first call to Sample()
+ if (ABSL_PREDICT_FALSE(stride_ == 1)) {
+ stride_ = static_cast<uint64_t>(-GetExponentialBiased(current_period));
+ if (static_cast<int64_t>(stride_) < -1) {
+ ++stride_;
+ return false;
+ }
+ }
+
+ stride_ = static_cast<uint64_t>(-GetExponentialBiased(current_period));
+ return true;
+}
+
+} // namespace base_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/base/internal/periodic_sampler.h b/third_party/abseil/absl/base/internal/periodic_sampler.h
new file mode 100644
index 0000000..f8a8679
--- /dev/null
+++ b/third_party/abseil/absl/base/internal/periodic_sampler.h
@@ -0,0 +1,211 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_BASE_INTERNAL_PERIODIC_SAMPLER_H_
+#define ABSL_BASE_INTERNAL_PERIODIC_SAMPLER_H_
+
+#include <stdint.h>
+
+#include <atomic>
+
+#include "absl/base/internal/exponential_biased.h"
+#include "absl/base/optimization.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// PeriodicSamplerBase provides the basic period sampler implementation.
+//
+// This is the base class for the templated PeriodicSampler class, which holds
+// a global std::atomic value identified by a user defined tag, such that
+// each specific PeriodSampler implementation holds its own global period.
+//
+// PeriodicSamplerBase is thread-compatible except where stated otherwise.
+class PeriodicSamplerBase {
+ public:
+ // PeriodicSamplerBase is trivial / copyable / movable / destructible.
+ PeriodicSamplerBase() = default;
+ PeriodicSamplerBase(PeriodicSamplerBase&&) = default;
+ PeriodicSamplerBase(const PeriodicSamplerBase&) = default;
+
+ // Returns true roughly once every `period` calls. This is established by a
+ // randomly picked `stride` that is counted down on each call to `Sample`.
+ // This stride is picked such that the probability of `Sample()` returning
+ // true is 1 in `period`.
+ inline bool Sample() noexcept;
+
+ // The below methods are intended for optimized use cases where the
+ // size of the inlined fast path code is highly important. Applications
+ // should use the `Sample()` method unless they have proof that their
+ // specific use case requires the optimizations offered by these methods.
+ //
+ // An example of such a use case is SwissTable sampling. All sampling checks
+ // are in inlined SwissTable methods, and the number of call sites is huge.
+ // In this case, the inlined code size added to each translation unit calling
+ // SwissTable methods is non-trivial.
+ //
+ // The `SubtleMaybeSample()` function spuriously returns true even if the
+ // function should not be sampled, applications MUST match each call to
+ // 'SubtleMaybeSample()' returning true with a `SubtleConfirmSample()` call,
+ // and use the result of the latter as the sampling decision.
+ // In other words: the code should logically be equivalent to:
+ //
+ // if (SubtleMaybeSample() && SubtleConfirmSample()) {
+ // // Sample this call
+ // }
+ //
+ // In the 'inline-size' optimized case, the `SubtleConfirmSample()` call can
+ // be placed out of line, for example, the typical use case looks as follows:
+ //
+ // // --- frobber.h -----------
+ // void FrobberSampled();
+ //
+ // inline void FrobberImpl() {
+ // // ...
+ // }
+ //
+ // inline void Frobber() {
+ // if (ABSL_PREDICT_FALSE(sampler.SubtleMaybeSample())) {
+ // FrobberSampled();
+ // } else {
+ // FrobberImpl();
+ // }
+ // }
+ //
+ // // --- frobber.cc -----------
+ // void FrobberSampled() {
+ // if (!sampler.SubtleConfirmSample())) {
+ // // Spurious false positive
+ // FrobberImpl();
+ // return;
+ // }
+ //
+ // // Sampled execution
+ // // ...
+ // }
+ inline bool SubtleMaybeSample() noexcept;
+ bool SubtleConfirmSample() noexcept;
+
+ protected:
+ // We explicitly don't use a virtual destructor as this class is never
+ // virtually destroyed, and it keeps the class trivial, which avoids TLS
+ // prologue and epilogue code for our TLS instances.
+ ~PeriodicSamplerBase() = default;
+
+ // Returns the next stride for our sampler.
+ // This function is virtual for testing purposes only.
+ virtual int64_t GetExponentialBiased(int period) noexcept;
+
+ private:
+ // Returns the current period of this sampler. Thread-safe.
+ virtual int period() const noexcept = 0;
+
+ // Keep and decrement stride_ as an unsigned integer, but compare the value
+ // to zero casted as a signed int. clang and msvc do not create optimum code
+ // if we use signed for the combined decrement and sign comparison.
+ //
+ // Below 3 alternative options, all compiles generate the best code
+ // using the unsigned increment <---> signed int comparison option.
+ //
+ // Option 1:
+ // int64_t stride_;
+ // if (ABSL_PREDICT_TRUE(++stride_ < 0)) { ... }
+ //
+ // GCC x64 (OK) : https://gcc.godbolt.org/z/R5MzzA
+ // GCC ppc (OK) : https://gcc.godbolt.org/z/z7NZAt
+ // Clang x64 (BAD): https://gcc.godbolt.org/z/t4gPsd
+ // ICC x64 (OK) : https://gcc.godbolt.org/z/rE6s8W
+ // MSVC x64 (OK) : https://gcc.godbolt.org/z/ARMXqS
+ //
+ // Option 2:
+ // int64_t stride_ = 0;
+ // if (ABSL_PREDICT_TRUE(--stride_ >= 0)) { ... }
+ //
+ // GCC x64 (OK) : https://gcc.godbolt.org/z/jSQxYK
+ // GCC ppc (OK) : https://gcc.godbolt.org/z/VJdYaA
+ // Clang x64 (BAD): https://gcc.godbolt.org/z/Xm4NjX
+ // ICC x64 (OK) : https://gcc.godbolt.org/z/4snaFd
+ // MSVC x64 (BAD): https://gcc.godbolt.org/z/BgnEKE
+ //
+ // Option 3:
+ // uint64_t stride_;
+ // if (ABSL_PREDICT_TRUE(static_cast<int64_t>(++stride_) < 0)) { ... }
+ //
+ // GCC x64 (OK) : https://gcc.godbolt.org/z/bFbfPy
+ // GCC ppc (OK) : https://gcc.godbolt.org/z/S9KkUE
+ // Clang x64 (OK) : https://gcc.godbolt.org/z/UYzRb4
+ // ICC x64 (OK) : https://gcc.godbolt.org/z/ptTNfD
+ // MSVC x64 (OK) : https://gcc.godbolt.org/z/76j4-5
+ uint64_t stride_ = 0;
+ ExponentialBiased rng_;
+};
+
+inline bool PeriodicSamplerBase::SubtleMaybeSample() noexcept {
+ // See comments on `stride_` for the unsigned increment / signed compare.
+ if (ABSL_PREDICT_TRUE(static_cast<int64_t>(++stride_) < 0)) {
+ return false;
+ }
+ return true;
+}
+
+inline bool PeriodicSamplerBase::Sample() noexcept {
+ return ABSL_PREDICT_FALSE(SubtleMaybeSample()) ? SubtleConfirmSample()
+ : false;
+}
+
+// PeriodicSampler is a concreted periodic sampler implementation.
+// The user provided Tag identifies the implementation, and is required to
+// isolate the global state of this instance from other instances.
+//
+// Typical use case:
+//
+// struct HashTablezTag {};
+// thread_local PeriodicSampler sampler;
+//
+// void HashTableSamplingLogic(...) {
+// if (sampler.Sample()) {
+// HashTableSlowSamplePath(...);
+// }
+// }
+//
+template <typename Tag, int default_period = 0>
+class PeriodicSampler final : public PeriodicSamplerBase {
+ public:
+ ~PeriodicSampler() = default;
+
+ int period() const noexcept final {
+ return period_.load(std::memory_order_relaxed);
+ }
+
+ // Sets the global period for this sampler. Thread-safe.
+ // Setting a period of 0 disables the sampler, i.e., every call to Sample()
+ // will return false. Setting a period of 1 puts the sampler in 'always on'
+ // mode, i.e., every call to Sample() returns true.
+ static void SetGlobalPeriod(int period) {
+ period_.store(period, std::memory_order_relaxed);
+ }
+
+ private:
+ static std::atomic<int> period_;
+};
+
+template <typename Tag, int default_period>
+std::atomic<int> PeriodicSampler<Tag, default_period>::period_(default_period);
+
+} // namespace base_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_BASE_INTERNAL_PERIODIC_SAMPLER_H_
diff --git a/third_party/abseil/absl/base/internal/periodic_sampler_benchmark.cc b/third_party/abseil/absl/base/internal/periodic_sampler_benchmark.cc
new file mode 100644
index 0000000..5ad469c
--- /dev/null
+++ b/third_party/abseil/absl/base/internal/periodic_sampler_benchmark.cc
@@ -0,0 +1,79 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "benchmark/benchmark.h"
+#include "absl/base/internal/periodic_sampler.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+namespace {
+
+template <typename Sampler>
+void BM_Sample(Sampler* sampler, benchmark::State& state) {
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(sampler);
+ benchmark::DoNotOptimize(sampler->Sample());
+ }
+}
+
+template <typename Sampler>
+void BM_SampleMinunumInlined(Sampler* sampler, benchmark::State& state) {
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(sampler);
+ if (ABSL_PREDICT_FALSE(sampler->SubtleMaybeSample())) {
+ benchmark::DoNotOptimize(sampler->SubtleConfirmSample());
+ }
+ }
+}
+
+void BM_PeriodicSampler_TinySample(benchmark::State& state) {
+ struct Tag {};
+ PeriodicSampler<Tag, 10> sampler;
+ BM_Sample(&sampler, state);
+}
+BENCHMARK(BM_PeriodicSampler_TinySample);
+
+void BM_PeriodicSampler_ShortSample(benchmark::State& state) {
+ struct Tag {};
+ PeriodicSampler<Tag, 1024> sampler;
+ BM_Sample(&sampler, state);
+}
+BENCHMARK(BM_PeriodicSampler_ShortSample);
+
+void BM_PeriodicSampler_LongSample(benchmark::State& state) {
+ struct Tag {};
+ PeriodicSampler<Tag, 1024 * 1024> sampler;
+ BM_Sample(&sampler, state);
+}
+BENCHMARK(BM_PeriodicSampler_LongSample);
+
+void BM_PeriodicSampler_LongSampleMinunumInlined(benchmark::State& state) {
+ struct Tag {};
+ PeriodicSampler<Tag, 1024 * 1024> sampler;
+ BM_SampleMinunumInlined(&sampler, state);
+}
+BENCHMARK(BM_PeriodicSampler_LongSampleMinunumInlined);
+
+void BM_PeriodicSampler_Disabled(benchmark::State& state) {
+ struct Tag {};
+ PeriodicSampler<Tag, 0> sampler;
+ BM_Sample(&sampler, state);
+}
+BENCHMARK(BM_PeriodicSampler_Disabled);
+
+} // namespace
+} // namespace base_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/base/internal/periodic_sampler_test.cc b/third_party/abseil/absl/base/internal/periodic_sampler_test.cc
new file mode 100644
index 0000000..3b301e3
--- /dev/null
+++ b/third_party/abseil/absl/base/internal/periodic_sampler_test.cc
@@ -0,0 +1,177 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/periodic_sampler.h"
+
+#include <thread> // NOLINT(build/c++11)
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+#include "absl/base/macros.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+namespace {
+
+using testing::Eq;
+using testing::Return;
+using testing::StrictMock;
+
+class MockPeriodicSampler : public PeriodicSamplerBase {
+ public:
+ virtual ~MockPeriodicSampler() = default;
+
+ MOCK_METHOD(int, period, (), (const, noexcept));
+ MOCK_METHOD(int64_t, GetExponentialBiased, (int), (noexcept));
+};
+
+TEST(PeriodicSamplerBaseTest, Sample) {
+ StrictMock<MockPeriodicSampler> sampler;
+
+ EXPECT_CALL(sampler, period()).Times(3).WillRepeatedly(Return(16));
+ EXPECT_CALL(sampler, GetExponentialBiased(16))
+ .WillOnce(Return(2))
+ .WillOnce(Return(3))
+ .WillOnce(Return(4));
+
+ EXPECT_FALSE(sampler.Sample());
+ EXPECT_TRUE(sampler.Sample());
+
+ EXPECT_FALSE(sampler.Sample());
+ EXPECT_FALSE(sampler.Sample());
+ EXPECT_TRUE(sampler.Sample());
+
+ EXPECT_FALSE(sampler.Sample());
+ EXPECT_FALSE(sampler.Sample());
+ EXPECT_FALSE(sampler.Sample());
+}
+
+TEST(PeriodicSamplerBaseTest, ImmediatelySample) {
+ StrictMock<MockPeriodicSampler> sampler;
+
+ EXPECT_CALL(sampler, period()).Times(2).WillRepeatedly(Return(16));
+ EXPECT_CALL(sampler, GetExponentialBiased(16))
+ .WillOnce(Return(1))
+ .WillOnce(Return(2))
+ .WillOnce(Return(3));
+
+ EXPECT_TRUE(sampler.Sample());
+
+ EXPECT_FALSE(sampler.Sample());
+ EXPECT_TRUE(sampler.Sample());
+
+ EXPECT_FALSE(sampler.Sample());
+ EXPECT_FALSE(sampler.Sample());
+}
+
+TEST(PeriodicSamplerBaseTest, Disabled) {
+ StrictMock<MockPeriodicSampler> sampler;
+
+ EXPECT_CALL(sampler, period()).Times(3).WillRepeatedly(Return(0));
+
+ EXPECT_FALSE(sampler.Sample());
+ EXPECT_FALSE(sampler.Sample());
+ EXPECT_FALSE(sampler.Sample());
+}
+
+TEST(PeriodicSamplerBaseTest, AlwaysOn) {
+ StrictMock<MockPeriodicSampler> sampler;
+
+ EXPECT_CALL(sampler, period()).Times(3).WillRepeatedly(Return(1));
+
+ EXPECT_TRUE(sampler.Sample());
+ EXPECT_TRUE(sampler.Sample());
+ EXPECT_TRUE(sampler.Sample());
+}
+
+TEST(PeriodicSamplerBaseTest, Disable) {
+ StrictMock<MockPeriodicSampler> sampler;
+
+ EXPECT_CALL(sampler, period()).WillOnce(Return(16));
+ EXPECT_CALL(sampler, GetExponentialBiased(16)).WillOnce(Return(3));
+ EXPECT_FALSE(sampler.Sample());
+ EXPECT_FALSE(sampler.Sample());
+
+ EXPECT_CALL(sampler, period()).Times(2).WillRepeatedly(Return(0));
+
+ EXPECT_FALSE(sampler.Sample());
+ EXPECT_FALSE(sampler.Sample());
+}
+
+TEST(PeriodicSamplerBaseTest, Enable) {
+ StrictMock<MockPeriodicSampler> sampler;
+
+ EXPECT_CALL(sampler, period()).WillOnce(Return(0));
+ EXPECT_FALSE(sampler.Sample());
+
+ EXPECT_CALL(sampler, period()).Times(2).WillRepeatedly(Return(16));
+ EXPECT_CALL(sampler, GetExponentialBiased(16))
+ .Times(2)
+ .WillRepeatedly(Return(3));
+
+ EXPECT_FALSE(sampler.Sample());
+ EXPECT_FALSE(sampler.Sample());
+ EXPECT_TRUE(sampler.Sample());
+
+ EXPECT_FALSE(sampler.Sample());
+ EXPECT_FALSE(sampler.Sample());
+}
+
+TEST(PeriodicSamplerTest, ConstructConstInit) {
+ struct Tag {};
+ ABSL_CONST_INIT static PeriodicSampler<Tag> sampler;
+ (void)sampler;
+}
+
+TEST(PeriodicSamplerTest, DefaultPeriod0) {
+ struct Tag {};
+ PeriodicSampler<Tag> sampler;
+ EXPECT_THAT(sampler.period(), Eq(0));
+}
+
+TEST(PeriodicSamplerTest, DefaultPeriod) {
+ struct Tag {};
+ PeriodicSampler<Tag, 100> sampler;
+ EXPECT_THAT(sampler.period(), Eq(100));
+}
+
+TEST(PeriodicSamplerTest, SetGlobalPeriod) {
+ struct Tag1 {};
+ struct Tag2 {};
+ PeriodicSampler<Tag1, 25> sampler1;
+ PeriodicSampler<Tag2, 50> sampler2;
+
+ EXPECT_THAT(sampler1.period(), Eq(25));
+ EXPECT_THAT(sampler2.period(), Eq(50));
+
+ std::thread thread([] {
+ PeriodicSampler<Tag1, 25> sampler1;
+ PeriodicSampler<Tag2, 50> sampler2;
+ EXPECT_THAT(sampler1.period(), Eq(25));
+ EXPECT_THAT(sampler2.period(), Eq(50));
+ sampler1.SetGlobalPeriod(10);
+ sampler2.SetGlobalPeriod(20);
+ });
+ thread.join();
+
+ EXPECT_THAT(sampler1.period(), Eq(10));
+ EXPECT_THAT(sampler2.period(), Eq(20));
+}
+
+} // namespace
+} // namespace base_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/base/internal/raw_logging.cc b/third_party/abseil/absl/base/internal/raw_logging.cc
index 878fe6c..074e026 100644
--- a/third_party/abseil/absl/base/internal/raw_logging.cc
+++ b/third_party/abseil/absl/base/internal/raw_logging.cc
@@ -37,9 +37,9 @@
// this, consider moving both to config.h instead.
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
defined(__Fuchsia__) || defined(__native_client__) || \
- defined(__EMSCRIPTEN__)
-#include <unistd.h>
+ defined(__EMSCRIPTEN__) || defined(__ASYLO__)
+#include <unistd.h>
#define ABSL_HAVE_POSIX_WRITE 1
#define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1
@@ -67,26 +67,32 @@
#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.
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace raw_logging_internal {
+namespace {
-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;
+// 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 selected set of platforms for which we expect not to be able to raw log.
+
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
+ absl::base_internal::AtomicHook<LogPrefixHook>
+ log_prefix_hook;
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
+ absl::base_internal::AtomicHook<AbortHook>
+ abort_hook;
#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
-static const char kTruncated[] = " ... (message truncated)\n";
+constexpr char kTruncated[] = " ... (message truncated)\n";
// sprintf the format to the buffer, adjusting *buf and *size to reflect the
// consumed bytes, and return whether the message fit without truncation. If
// truncation occurred, if possible leave room in the buffer for the message
// kTruncated[].
-inline static bool VADoRawLog(char** buf, int* size, const char* format,
- va_list ap) ABSL_PRINTF_ATTRIBUTE(3, 0);
-inline static bool VADoRawLog(char** buf, int* size,
- const char* format, va_list ap) {
+bool VADoRawLog(char** buf, int* size, const char* format, va_list ap)
+ ABSL_PRINTF_ATTRIBUTE(3, 0);
+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) {
@@ -94,7 +100,7 @@
if (static_cast<size_t>(*size) > sizeof(kTruncated)) {
n = *size - sizeof(kTruncated); // room for truncation message
} else {
- n = 0; // no room for truncation message
+ n = 0; // no room for truncation message
}
}
*size -= n;
@@ -103,9 +109,7 @@
}
#endif // ABSL_LOW_LEVEL_WRITE_SUPPORTED
-static constexpr int kLogBufSize = 3000;
-
-namespace {
+constexpr int kLogBufSize = 3000;
// CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths
// that invoke malloc() and getenv() that might acquire some locks.
@@ -164,7 +168,7 @@
} else {
DoRawLog(&buf, &size, "%s", kTruncated);
}
- absl::raw_logging_internal::SafeWriteToStderr(buffer, strlen(buffer));
+ SafeWriteToStderr(buffer, strlen(buffer));
}
#else
static_cast<void>(format);
@@ -179,10 +183,18 @@
}
}
+// Non-formatting version of RawLog().
+//
+// TODO(gfalcon): When string_view no longer depends on base, change this
+// interface to take its message as a string_view instead.
+void DefaultInternalLog(absl::LogSeverity severity, const char* file, int line,
+ const std::string& message) {
+ RawLog(severity, file, line, "%.*s", static_cast<int>(message.size()),
+ message.data());
+}
+
} // namespace
-namespace absl {
-namespace raw_logging_internal {
void SafeWriteToStderr(const char *s, size_t len) {
#if defined(ABSL_HAVE_SYSCALL_WRITE)
syscall(SYS_write, STDERR_FILENO, s, len);
@@ -198,8 +210,6 @@
}
void RawLog(absl::LogSeverity severity, const char* file, int line,
- const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5);
-void RawLog(absl::LogSeverity severity, const char* file, int line,
const char* format, ...) {
va_list ap;
va_start(ap, format);
@@ -207,15 +217,6 @@
va_end(ap);
}
-// Non-formatting version of RawLog().
-//
-// TODO(gfalcon): When string_view no longer depends on base, change this
-// interface to take its message as a string_view instead.
-static void DefaultInternalLog(absl::LogSeverity severity, const char* file,
- int line, const std::string& message) {
- RawLog(severity, file, line, "%s", message.c_str());
-}
-
bool RawLoggingFullySupported() {
#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
return true;
@@ -224,12 +225,18 @@
#endif // !ABSL_LOW_LEVEL_WRITE_SUPPORTED
}
-ABSL_CONST_INIT absl::base_internal::AtomicHook<InternalLogFunction>
- internal_log_function(DefaultInternalLog);
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_DLL
+ absl::base_internal::AtomicHook<InternalLogFunction>
+ internal_log_function(DefaultInternalLog);
+
+void RegisterLogPrefixHook(LogPrefixHook func) { log_prefix_hook.Store(func); }
+
+void RegisterAbortHook(AbortHook func) { abort_hook.Store(func); }
void RegisterInternalLogFunction(InternalLogFunction func) {
internal_log_function.Store(func);
}
} // namespace raw_logging_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/base/internal/raw_logging.h b/third_party/abseil/absl/base/internal/raw_logging.h
index 6a4c093..2bf7aab 100644
--- a/third_party/abseil/absl/base/internal/raw_logging.h
+++ b/third_party/abseil/absl/base/internal/raw_logging.h
@@ -22,9 +22,11 @@
#include <string>
#include "absl/base/attributes.h"
+#include "absl/base/config.h"
#include "absl/base/internal/atomic_hook.h"
#include "absl/base/log_severity.h"
#include "absl/base/macros.h"
+#include "absl/base/optimization.h"
#include "absl/base/port.h"
// This is similar to LOG(severity) << format..., but
@@ -70,14 +72,14 @@
//
// The API is a subset of the above: each macro only takes two arguments. Use
// StrCat if you need to build a richer message.
-#define ABSL_INTERNAL_LOG(severity, message) \
- do { \
- constexpr const char* absl_raw_logging_internal_basename = \
- ::absl::raw_logging_internal::Basename(__FILE__, \
- sizeof(__FILE__) - 1); \
- ::absl::raw_logging_internal::internal_log_function( \
- ABSL_RAW_LOGGING_INTERNAL_##severity, \
- absl_raw_logging_internal_basename, __LINE__, message); \
+#define ABSL_INTERNAL_LOG(severity, message) \
+ do { \
+ constexpr const char* absl_raw_logging_internal_filename = __FILE__; \
+ ::absl::raw_logging_internal::internal_log_function( \
+ ABSL_RAW_LOGGING_INTERNAL_##severity, \
+ absl_raw_logging_internal_filename, __LINE__, message); \
+ if (ABSL_RAW_LOGGING_INTERNAL_##severity == ::absl::LogSeverity::kFatal) \
+ ABSL_INTERNAL_UNREACHABLE; \
} while (0)
#define ABSL_INTERNAL_CHECK(condition, message) \
@@ -97,6 +99,7 @@
::absl::NormalizeLogSeverity(severity)
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace raw_logging_internal {
// Helper function to implement ABSL_RAW_LOG
@@ -157,7 +160,7 @@
//
// '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'
+// The NUL-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,
@@ -171,11 +174,22 @@
const char* file, int line,
const std::string& message);
-extern base_internal::AtomicHook<InternalLogFunction> internal_log_function;
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_DLL extern base_internal::AtomicHook<
+ InternalLogFunction>
+ internal_log_function;
+// Registers hooks of the above types. Only a single hook of each type may be
+// registered. It is an error to call these functions multiple times with
+// different input arguments.
+//
+// These functions are safe to call at any point during initialization; they do
+// not block or malloc, and are async-signal safe.
+void RegisterLogPrefixHook(LogPrefixHook func);
+void RegisterAbortHook(AbortHook func);
void RegisterInternalLogFunction(InternalLogFunction func);
} // namespace raw_logging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_RAW_LOGGING_H_
diff --git a/third_party/abseil/absl/base/internal/scheduling_mode.h b/third_party/abseil/absl/base/internal/scheduling_mode.h
index d5b4b7f..8be5ab6 100644
--- a/third_party/abseil/absl/base/internal/scheduling_mode.h
+++ b/third_party/abseil/absl/base/internal/scheduling_mode.h
@@ -18,7 +18,10 @@
#ifndef ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
#define ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
// Used to describe how a thread may be scheduled. Typically associated with
@@ -49,6 +52,7 @@
};
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
diff --git a/third_party/abseil/absl/base/internal/scoped_set_env.cc b/third_party/abseil/absl/base/internal/scoped_set_env.cc
index 3ac3f68..8a934cb 100644
--- a/third_party/abseil/absl/base/internal/scoped_set_env.cc
+++ b/third_party/abseil/absl/base/internal/scoped_set_env.cc
@@ -23,6 +23,7 @@
#include "absl/base/internal/raw_logging.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
namespace {
@@ -76,4 +77,5 @@
}
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/base/internal/scoped_set_env.h b/third_party/abseil/absl/base/internal/scoped_set_env.h
index 855b22f..19ec7b5 100644
--- a/third_party/abseil/absl/base/internal/scoped_set_env.h
+++ b/third_party/abseil/absl/base/internal/scoped_set_env.h
@@ -19,7 +19,10 @@
#include <string>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
class ScopedSetEnv {
@@ -36,6 +39,7 @@
};
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_
diff --git a/third_party/abseil/absl/base/internal/spinlock.cc b/third_party/abseil/absl/base/internal/spinlock.cc
index 7354438..a7d44f3 100644
--- a/third_party/abseil/absl/base/internal/spinlock.cc
+++ b/third_party/abseil/absl/base/internal/spinlock.cc
@@ -54,10 +54,11 @@
// holder to acquire the lock. There may be outstanding waiter(s).
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
-ABSL_CONST_INIT static base_internal::AtomicHook<void (*)(const void *lock,
- int64_t wait_cycles)>
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static base_internal::AtomicHook<void (*)(
+ const void *lock, int64_t wait_cycles)>
submit_profile_data;
void RegisterSpinLockProfiler(void (*fn)(const void *contendedlock,
@@ -65,35 +66,19 @@
submit_profile_data.Store(fn);
}
+// Static member variable definitions.
+constexpr uint32_t SpinLock::kSpinLockHeld;
+constexpr uint32_t SpinLock::kSpinLockCooperative;
+constexpr uint32_t SpinLock::kSpinLockDisabledScheduling;
+constexpr uint32_t SpinLock::kSpinLockSleeper;
+constexpr uint32_t SpinLock::kWaitTimeMask;
+
// Uncommon constructors.
SpinLock::SpinLock(base_internal::SchedulingMode mode)
: lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
}
-SpinLock::SpinLock(base_internal::LinkerInitialized,
- base_internal::SchedulingMode mode) {
- ABSL_TSAN_MUTEX_CREATE(this, 0);
- if (IsCooperative(mode)) {
- InitLinkerInitializedAndCooperative();
- }
- // Otherwise, lockword_ is already initialized.
-}
-
-// Static (linker initialized) spinlocks always start life as functional
-// non-cooperative locks. When their static constructor does run, it will call
-// this initializer to augment the lockword with the cooperative bit. By
-// actually taking the lock when we do this we avoid the need for an atomic
-// operation in the regular unlock path.
-//
-// SlowLock() must be careful to re-test for this bit so that any outstanding
-// waiters may be upgraded to cooperative status.
-void SpinLock::InitLinkerInitializedAndCooperative() {
- Lock();
- lockword_.fetch_or(kSpinLockCooperative, std::memory_order_relaxed);
- Unlock();
-}
-
// Monitor the lock to see if its value changes within some time period
// (adaptive_spin_count loop iterations). The last value read from the lock
// is returned from the method.
@@ -120,6 +105,14 @@
if ((lock_value & kSpinLockHeld) == 0) {
return;
}
+
+ 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;
+ }
+
// 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
@@ -150,12 +143,6 @@
}
}
- 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);
@@ -189,30 +176,32 @@
// 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
+// processors we divide to reduce the granularity to 2^kProfileTimestampShift
// 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.
+static constexpr int kProfileTimestampShift = 7;
+
+// We currently reserve the lower 3 bits.
+static constexpr int kLockwordReservedShift = 3;
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;
+ std::numeric_limits<uint32_t>::max() >> kLockwordReservedShift;
int64_t scaled_wait_time =
- (wait_end_time - wait_start_time) >> PROFILE_TIMESTAMP_SHIFT;
+ (wait_end_time - wait_start_time) >> kProfileTimestampShift;
// Return a representation of the time spent waiting that can be stored in
// the lock word's upper bits.
uint32_t clamped = static_cast<uint32_t>(
- std::min(scaled_wait_time, kMaxWaitTime) << LOCKWORD_RESERVED_SHIFT);
+ std::min(scaled_wait_time, kMaxWaitTime) << kLockwordReservedShift);
if (clamped == 0) {
return kSpinLockSleeper; // Just wake waiters, but don't record contention.
}
// Bump up value if necessary to avoid returning kSpinLockSleeper.
const uint32_t kMinWaitTime =
- kSpinLockSleeper + (1 << LOCKWORD_RESERVED_SHIFT);
+ kSpinLockSleeper + (1 << kLockwordReservedShift);
if (clamped == kSpinLockSleeper) {
return kMinWaitTime;
}
@@ -223,9 +212,9 @@
// 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);
+ return scaled_wait_time << (kProfileTimestampShift - kLockwordReservedShift);
}
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/base/internal/spinlock.h b/third_party/abseil/absl/base/internal/spinlock.h
index 1d1bd6c..dce1c85 100644
--- a/third_party/abseil/absl/base/internal/spinlock.h
+++ b/third_party/abseil/absl/base/internal/spinlock.h
@@ -15,11 +15,8 @@
//
// Most users requiring mutual exclusion should use Mutex.
-// SpinLock is provided for use in three situations:
+// SpinLock is provided for use in two 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
@@ -36,6 +33,7 @@
#include <atomic>
#include "absl/base/attributes.h"
+#include "absl/base/const_init.h"
#include "absl/base/dynamic_annotations.h"
#include "absl/base/internal/low_level_scheduling.h"
#include "absl/base/internal/raw_logging.h"
@@ -46,6 +44,7 @@
#include "absl/base/thread_annotations.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
class ABSL_LOCKABLE SpinLock {
@@ -54,29 +53,22 @@
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
}
- // Special constructor for use with static SpinLock objects. E.g.,
- //
- // static SpinLock lock(base_internal::kLinkerInitialized);
- //
- // When initialized using this constructor, we depend on the fact
- // that the linker has already initialized the memory appropriately. The lock
- // is initialized in non-cooperative mode.
- //
- // A SpinLock constructed like this can be freely used from global
- // initializers without worrying about the order in which global
- // initializers run.
- explicit SpinLock(base_internal::LinkerInitialized) {
- // Does nothing; lockword_ is already initialized
- ABSL_TSAN_MUTEX_CREATE(this, 0);
- }
-
// Constructors that allow non-cooperative spinlocks to be created for use
// inside thread schedulers. Normal clients should not use these.
explicit SpinLock(base_internal::SchedulingMode mode);
- SpinLock(base_internal::LinkerInitialized,
- base_internal::SchedulingMode mode);
+ // Constructor for global SpinLock instances. See absl/base/const_init.h.
+ constexpr SpinLock(absl::ConstInitType, base_internal::SchedulingMode mode)
+ : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {}
+
+ // For global SpinLock instances prefer trivial destructor when possible.
+ // Default but non-trivial destructor in some build configurations causes an
+ // extra static initializer.
+#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
~SpinLock() { ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); }
+#else
+ ~SpinLock() = default;
+#endif
// Acquire this SpinLock.
inline void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() {
@@ -147,12 +139,13 @@
// 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) };
+ static constexpr uint32_t kSpinLockHeld = 1;
+ static constexpr uint32_t kSpinLockCooperative = 2;
+ static constexpr uint32_t kSpinLockDisabledScheduling = 4;
+ static constexpr uint32_t kSpinLockSleeper = 8;
+ // Includes kSpinLockSleeper.
+ static constexpr uint32_t kWaitTimeMask =
+ ~(kSpinLockHeld | kSpinLockCooperative | kSpinLockDisabledScheduling);
// Returns true if the provided scheduling mode is cooperative.
static constexpr bool IsCooperative(
@@ -161,7 +154,6 @@
}
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();
@@ -236,6 +228,7 @@
}
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_SPINLOCK_H_
diff --git a/third_party/abseil/absl/base/internal/spinlock_linux.inc b/third_party/abseil/absl/base/internal/spinlock_linux.inc
index 28e29d1..e31c6ed 100644
--- a/third_party/abseil/absl/base/internal/spinlock_linux.inc
+++ b/third_party/abseil/absl/base/internal/spinlock_linux.inc
@@ -19,12 +19,12 @@
#include <unistd.h>
#include <atomic>
-#include <cerrno>
#include <climits>
#include <cstdint>
#include <ctime>
#include "absl/base/attributes.h"
+#include "absl/base/internal/errno_saver.h"
// The SpinLock lockword is `std::atomic<uint32_t>`. Here we assert that
// `std::atomic<uint32_t>` is bitwise equivalent of the `int` expected
@@ -46,17 +46,24 @@
#endif
#endif
+#if defined(__NR_futex_time64) && !defined(SYS_futex_time64)
+#define SYS_futex_time64 __NR_futex_time64
+#endif
+
+#if defined(SYS_futex_time64) && !defined(SYS_futex)
+#define SYS_futex SYS_futex_time64
+#endif
+
extern "C" {
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
std::atomic<uint32_t> *w, uint32_t value, int loop,
absl::base_internal::SchedulingMode) {
- int save_errno = errno;
+ absl::base_internal::ErrnoSaver errno_saver;
struct timespec tm;
tm.tv_sec = 0;
tm.tv_nsec = absl::base_internal::SpinLockSuggestedDelayNS(loop);
syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, &tm);
- errno = save_errno;
}
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(std::atomic<uint32_t> *w,
diff --git a/third_party/abseil/absl/base/internal/spinlock_posix.inc b/third_party/abseil/absl/base/internal/spinlock_posix.inc
index f025b5f..fcd21b1 100644
--- a/third_party/abseil/absl/base/internal/spinlock_posix.inc
+++ b/third_party/abseil/absl/base/internal/spinlock_posix.inc
@@ -15,10 +15,11 @@
// This file is a Posix-specific part of spinlock_wait.cc
#include <sched.h>
+
#include <atomic>
#include <ctime>
-#include <cerrno>
+#include "absl/base/internal/errno_saver.h"
#include "absl/base/internal/scheduling_mode.h"
#include "absl/base/port.h"
@@ -27,7 +28,7 @@
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;
+ absl::base_internal::ErrnoSaver errno_saver;
if (loop == 0) {
} else if (loop == 1) {
sched_yield();
@@ -37,7 +38,6 @@
tm.tv_nsec = absl::base_internal::SpinLockSuggestedDelayNS(loop);
nanosleep(&tm, nullptr);
}
- errno = save_errno;
}
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(
diff --git a/third_party/abseil/absl/base/internal/spinlock_wait.cc b/third_party/abseil/absl/base/internal/spinlock_wait.cc
index fac8a21..fa824be 100644
--- a/third_party/abseil/absl/base/internal/spinlock_wait.cc
+++ b/third_party/abseil/absl/base/internal/spinlock_wait.cc
@@ -32,6 +32,7 @@
#endif
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
// See spinlock_wait.h for spec.
@@ -76,4 +77,5 @@
}
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/base/internal/spinlock_wait.h b/third_party/abseil/absl/base/internal/spinlock_wait.h
index 6642ce1..c34ce41 100644
--- a/third_party/abseil/absl/base/internal/spinlock_wait.h
+++ b/third_party/abseil/absl/base/internal/spinlock_wait.h
@@ -24,6 +24,7 @@
#include "absl/base/internal/scheduling_mode.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
// SpinLockWait() waits until it can perform one of several transitions from
@@ -42,18 +43,16 @@
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.
+// If possible, wake some thread that has called SpinLockDelay(w, ...). If `all`
+// is true, wake all such threads. On some systems, this may be a no-op; on
+// those systems, 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.
+// or may wait for a call to SpinLockWake(w).
void SpinLockDelay(std::atomic<uint32_t> *w, uint32_t value, int loop,
base_internal::SchedulingMode scheduling_mode);
@@ -62,6 +61,7 @@
int SpinLockSuggestedDelayNS(int loop);
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
// In some build configurations we pass --detect-odr-violations to the
diff --git a/third_party/abseil/absl/base/internal/strerror.cc b/third_party/abseil/absl/base/internal/strerror.cc
new file mode 100644
index 0000000..0d6226f
--- /dev/null
+++ b/third_party/abseil/absl/base/internal/strerror.cc
@@ -0,0 +1,88 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/strerror.h"
+
+#include <array>
+#include <cerrno>
+#include <cstddef>
+#include <cstdio>
+#include <cstring>
+#include <string>
+#include <type_traits>
+
+#include "absl/base/internal/errno_saver.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+namespace {
+
+const char* StrErrorAdaptor(int errnum, char* buf, size_t buflen) {
+#if defined(_WIN32)
+ int rc = strerror_s(buf, buflen, errnum);
+ buf[buflen - 1] = '\0'; // guarantee NUL termination
+ if (rc == 0 && strncmp(buf, "Unknown error", buflen) == 0) *buf = '\0';
+ return buf;
+#else
+ // The type of `ret` is platform-specific; both of these branches must compile
+ // either way but only one will execute on any given platform:
+ auto ret = strerror_r(errnum, buf, buflen);
+ if (std::is_same<decltype(ret), int>::value) {
+ // XSI `strerror_r`; `ret` is `int`:
+ if (ret) *buf = '\0';
+ return buf;
+ } else {
+ // GNU `strerror_r`; `ret` is `char *`:
+ return reinterpret_cast<const char*>(ret);
+ }
+#endif
+}
+
+std::string StrErrorInternal(int errnum) {
+ char buf[100];
+ const char* str = StrErrorAdaptor(errnum, buf, sizeof buf);
+ if (*str == '\0') {
+ snprintf(buf, sizeof buf, "Unknown error %d", errnum);
+ str = buf;
+ }
+ return str;
+}
+
+// kSysNerr is the number of errors from a recent glibc. `StrError()` falls back
+// to `StrErrorAdaptor()` if the value is larger than this.
+constexpr int kSysNerr = 135;
+
+std::array<std::string, kSysNerr>* NewStrErrorTable() {
+ auto* table = new std::array<std::string, kSysNerr>;
+ for (int i = 0; i < static_cast<int>(table->size()); ++i) {
+ (*table)[i] = StrErrorInternal(i);
+ }
+ return table;
+}
+
+} // namespace
+
+std::string StrError(int errnum) {
+ absl::base_internal::ErrnoSaver errno_saver;
+ static const auto* table = NewStrErrorTable();
+ if (errnum >= 0 && errnum < static_cast<int>(table->size())) {
+ return (*table)[errnum];
+ }
+ return StrErrorInternal(errnum);
+}
+
+} // namespace base_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/base/internal/strerror.h b/third_party/abseil/absl/base/internal/strerror.h
new file mode 100644
index 0000000..3500973
--- /dev/null
+++ b/third_party/abseil/absl/base/internal/strerror.h
@@ -0,0 +1,39 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_BASE_INTERNAL_STRERROR_H_
+#define ABSL_BASE_INTERNAL_STRERROR_H_
+
+#include <string>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// A portable and thread-safe alternative to C89's `strerror`.
+//
+// The C89 specification of `strerror` is not suitable for use in a
+// multi-threaded application as the returned string may be changed by calls to
+// `strerror` from another thread. The many non-stdlib alternatives differ
+// enough in their names, availability, and semantics to justify this wrapper
+// around them. `errno` will not be modified by a call to `absl::StrError`.
+std::string StrError(int errnum);
+
+} // namespace base_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_BASE_INTERNAL_STRERROR_H_
diff --git a/third_party/abseil/absl/random/internal/seed_salting_sequence_generator_empty_sequence.cc b/third_party/abseil/absl/base/internal/strerror_benchmark.cc
similarity index 60%
rename from third_party/abseil/absl/random/internal/seed_salting_sequence_generator_empty_sequence.cc
rename to third_party/abseil/absl/base/internal/strerror_benchmark.cc
index 8797e2e..c9ab14a 100644
--- a/third_party/abseil/absl/random/internal/seed_salting_sequence_generator_empty_sequence.cc
+++ b/third_party/abseil/absl/base/internal/strerror_benchmark.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Abseil Authors.
+// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,19 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include <iostream>
-#include <random>
+#include <cerrno>
+#include <cstdio>
+#include <string>
-#include "absl/random/random.h"
+#include "absl/base/internal/strerror.h"
+#include "benchmark/benchmark.h"
-// This program is used in integration tests.
-
-int main() {
- std::seed_seq seed_seq{};
- absl::BitGen rng(seed_seq);
- constexpr size_t kSequenceLength = 8;
- for (size_t i = 0; i < kSequenceLength; i++) {
- std::cout << rng() << "\n";
+namespace {
+void BM_AbslStrError(benchmark::State& state) {
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(absl::base_internal::StrError(ERANGE));
}
- return 0;
}
+BENCHMARK(BM_AbslStrError);
+} // namespace
diff --git a/third_party/abseil/absl/base/internal/strerror_test.cc b/third_party/abseil/absl/base/internal/strerror_test.cc
new file mode 100644
index 0000000..e32d5b5
--- /dev/null
+++ b/third_party/abseil/absl/base/internal/strerror_test.cc
@@ -0,0 +1,88 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/strerror.h"
+
+#include <atomic>
+#include <cerrno>
+#include <cstdio>
+#include <cstring>
+#include <string>
+#include <thread> // NOLINT(build/c++11)
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/strings/match.h"
+
+namespace {
+using ::testing::AnyOf;
+using ::testing::Eq;
+
+TEST(StrErrorTest, ValidErrorCode) {
+ errno = ERANGE;
+ EXPECT_THAT(absl::base_internal::StrError(EDOM), Eq(strerror(EDOM)));
+ EXPECT_THAT(errno, Eq(ERANGE));
+}
+
+TEST(StrErrorTest, InvalidErrorCode) {
+ errno = ERANGE;
+ EXPECT_THAT(absl::base_internal::StrError(-1),
+ AnyOf(Eq("No error information"), Eq("Unknown error -1")));
+ EXPECT_THAT(errno, Eq(ERANGE));
+}
+
+TEST(StrErrorTest, MultipleThreads) {
+ // In this test, we will start up 2 threads and have each one call
+ // StrError 1000 times, each time with a different errnum. We
+ // expect that StrError(errnum) will return a string equal to the
+ // one returned by strerror(errnum), if the code is known. Since
+ // strerror is known to be thread-hostile, collect all the expected
+ // strings up front.
+ const int kNumCodes = 1000;
+ std::vector<std::string> expected_strings(kNumCodes);
+ for (int i = 0; i < kNumCodes; ++i) {
+ expected_strings[i] = strerror(i);
+ }
+
+ std::atomic_int counter(0);
+ auto thread_fun = [&]() {
+ for (int i = 0; i < kNumCodes; ++i) {
+ ++counter;
+ errno = ERANGE;
+ const std::string value = absl::base_internal::StrError(i);
+ // EXPECT_* could change errno. Stash it first.
+ int check_err = errno;
+ EXPECT_THAT(check_err, Eq(ERANGE));
+ // Only the GNU implementation is guaranteed to provide the
+ // string "Unknown error nnn". POSIX doesn't say anything.
+ if (!absl::StartsWith(value, "Unknown error ")) {
+ EXPECT_THAT(value, Eq(expected_strings[i]));
+ }
+ }
+ };
+
+ const int kNumThreads = 100;
+ std::vector<std::thread> threads;
+ for (int i = 0; i < kNumThreads; ++i) {
+ threads.push_back(std::thread(thread_fun));
+ }
+ for (auto& thread : threads) {
+ thread.join();
+ }
+
+ EXPECT_THAT(counter, Eq(kNumThreads * kNumCodes));
+}
+
+} // namespace
diff --git a/third_party/abseil/absl/base/internal/sysinfo.cc b/third_party/abseil/absl/base/internal/sysinfo.cc
index 4dd3add..4a3b205 100644
--- a/third_party/abseil/absl/base/internal/sysinfo.cc
+++ b/third_party/abseil/absl/base/internal/sysinfo.cc
@@ -17,7 +17,6 @@
#include "absl/base/attributes.h"
#ifdef _WIN32
-#include <shlwapi.h>
#include <windows.h>
#else
#include <fcntl.h>
@@ -40,6 +39,7 @@
#endif
#include <string.h>
+
#include <cassert>
#include <cstdint>
#include <cstdio>
@@ -51,17 +51,16 @@
#include <vector>
#include "absl/base/call_once.h"
+#include "absl/base/config.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 {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
-static once_flag init_system_info_once;
-static int num_cpus = 0;
-static double nominal_cpu_frequency = 1.0; // 0.0 might be dangerous.
-
static int GetNumCPUs() {
#if defined(__myriad2__)
return 1;
@@ -76,16 +75,32 @@
#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.
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
+ !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+ // UWP apps don't have access to the registry and currently don't provide an
+ // API informing about CPU nominal frequency.
+ return 1.0;
+#else
+#pragma comment(lib, "advapi32.lib") // For Reg* functions.
+ HKEY key;
+ // Use the Reg* functions rather than the SH functions because shlwapi.dll
+ // pulls in gdi32.dll which makes process destruction much more costly.
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
+ "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0,
+ KEY_READ, &key) == ERROR_SUCCESS) {
+ DWORD type = 0;
+ DWORD data = 0;
+ DWORD data_size = sizeof(data);
+ auto result = RegQueryValueExA(key, "~MHz", 0, &type,
+ reinterpret_cast<LPBYTE>(&data), &data_size);
+ RegCloseKey(key);
+ if (result == ERROR_SUCCESS && type == REG_DWORD &&
+ data_size == sizeof(data)) {
+ return data * 1e6; // Value is MHz.
+ }
}
return 1.0;
+#endif // WINAPI_PARTITION_APP && !WINAPI_PARTITION_DESKTOP
}
#elif defined(CTL_HW) && defined(HW_CPU_FREQ)
@@ -256,28 +271,34 @@
#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();
-}
+ABSL_CONST_INIT static once_flag init_num_cpus_once;
+ABSL_CONST_INIT static int num_cpus = 0;
+// NumCPUs() may be called before main() and before malloc is properly
+// initialized, therefore this must not allocate memory.
int NumCPUs() {
- base_internal::LowLevelCallOnce(&init_system_info_once, InitializeSystemInfo);
+ base_internal::LowLevelCallOnce(
+ &init_num_cpus_once, []() { num_cpus = GetNumCPUs(); });
return num_cpus;
}
+// A default frequency of 0.0 might be dangerous if it is used in division.
+ABSL_CONST_INIT static once_flag init_nominal_cpu_frequency_once;
+ABSL_CONST_INIT static double nominal_cpu_frequency = 1.0;
+
+// NominalCPUFrequency() may be called before main() and before malloc is
+// properly initialized, therefore this must not allocate memory.
double NominalCPUFrequency() {
- base_internal::LowLevelCallOnce(&init_system_info_once, InitializeSystemInfo);
+ base_internal::LowLevelCallOnce(
+ &init_nominal_cpu_frequency_once,
+ []() { nominal_cpu_frequency = GetNominalCPUFrequency(); });
return nominal_cpu_frequency;
}
#if defined(_WIN32)
pid_t GetTID() {
- return GetCurrentThreadId();
+ return pid_t{GetCurrentThreadId()};
}
#elif defined(__linux__)
@@ -325,15 +346,16 @@
#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);
+ABSL_CONST_INIT static once_flag tid_once;
+ABSL_CONST_INIT static pthread_key_t tid_key;
+ABSL_CONST_INIT static absl::base_internal::SpinLock tid_lock(
+ absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
// 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;
+ABSL_CONST_INIT static std::vector<uint32_t> *tid_array
+ ABSL_GUARDED_BY(tid_lock) = nullptr;
static constexpr int kBitsPerWord = 32; // tid_array is uint32_t.
// Returns the TID to tid_array.
@@ -400,5 +422,18 @@
#endif
+// GetCachedTID() caches the thread ID in thread-local storage (which is a
+// userspace construct) to avoid unnecessary system calls. Without this caching,
+// it can take roughly 98ns, while it takes roughly 1ns with this caching.
+pid_t GetCachedTID() {
+#ifdef ABSL_HAVE_THREAD_LOCAL
+ static thread_local pid_t thread_id = GetTID();
+ return thread_id;
+#else
+ return GetTID();
+#endif // ABSL_HAVE_THREAD_LOCAL
+}
+
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/base/internal/sysinfo.h b/third_party/abseil/absl/base/internal/sysinfo.h
index b864a59..119cf1f 100644
--- a/third_party/abseil/absl/base/internal/sysinfo.h
+++ b/third_party/abseil/absl/base/internal/sysinfo.h
@@ -26,13 +26,15 @@
#ifndef _WIN32
#include <sys/types.h>
-#else
-#include <intsafe.h>
#endif
+#include <cstdint>
+
+#include "absl/base/config.h"
#include "absl/base/port.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
// Nominal core processor cycles per second of each processor. This is _not_
@@ -51,13 +53,22 @@
// 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;
+// On Windows, process id and thread id are of the same type according to the
+// return types of GetProcessId() and GetThreadId() are both DWORD, an unsigned
+// 32-bit type.
+using pid_t = uint32_t;
#endif
pid_t GetTID();
+// Like GetTID(), but caches the result in thread-local storage in order
+// to avoid unnecessary system calls. Note that there are some cases where
+// one must call through to GetTID directly, which is why this exists as a
+// separate function. For example, GetCachedTID() is not safe to call in
+// an asynchronous signal-handling context nor right after a call to fork().
+pid_t GetCachedTID();
+
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_SYSINFO_H_
diff --git a/third_party/abseil/absl/base/internal/sysinfo_test.cc b/third_party/abseil/absl/base/internal/sysinfo_test.cc
index 82bbcc2..5f9e45f 100644
--- a/third_party/abseil/absl/base/internal/sysinfo_test.cc
+++ b/third_party/abseil/absl/base/internal/sysinfo_test.cc
@@ -28,6 +28,7 @@
#include "absl/synchronization/mutex.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
namespace {
@@ -36,17 +37,28 @@
<< "NumCPUs() should not have the default value of 0";
}
+// Ensure that NominalCPUFrequency returns a reasonable value, or 1.00 on
+// platforms where the CPU frequency is not available through sysfs.
+//
+// POWER is particularly problematic here; some Linux kernels expose the CPU
+// frequency, while others do not. Since we can't predict a priori what a given
+// machine is going to do, just disable this test on POWER on Linux.
+#if !(defined(__linux) && (defined(__ppc64__) || defined(__PPC64__)))
TEST(SysinfoTest, NominalCPUFrequency) {
-#if !(defined(__aarch64__) && defined(__linux__)) && !defined(__EMSCRIPTEN__)
- EXPECT_GE(NominalCPUFrequency(), 1000.0)
- << "NominalCPUFrequency() did not return a reasonable value";
-#else
- // Aarch64 cannot read the CPU frequency from sysfs, so we get back 1.0.
- // Emscripten does not have a sysfs to read from at all.
+ // Linux only exposes the CPU frequency on certain architectures, and
+ // Emscripten doesn't expose it at all.
+#if defined(__linux__) && \
+ (defined(__aarch64__) || defined(__hppa__) || defined(__mips__) || \
+ defined(__riscv) || defined(__s390x__)) || \
+ defined(__EMSCRIPTEN__)
EXPECT_EQ(NominalCPUFrequency(), 1.0)
<< "CPU frequency detection was fixed! Please update unittest.";
+#else
+ EXPECT_GE(NominalCPUFrequency(), 1000.0)
+ << "NominalCPUFrequency() did not return a reasonable value";
#endif
}
+#endif
TEST(SysinfoTest, GetTID) {
EXPECT_EQ(GetTID(), GetTID()); // Basic compile and equality test.
@@ -58,8 +70,8 @@
#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;
+ for (int i = 0; i < 10; ++i) {
+ constexpr int kNumThreads = 10;
Barrier all_threads_done(kNumThreads);
std::vector<std::thread> threads;
@@ -95,4 +107,5 @@
} // namespace
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/base/internal/thread_identity.cc b/third_party/abseil/absl/base/internal/thread_identity.cc
index 91273a6..6ea010e 100644
--- a/third_party/abseil/absl/base/internal/thread_identity.cc
+++ b/third_party/abseil/absl/base/internal/thread_identity.cc
@@ -23,11 +23,13 @@
#include <cassert>
#include <memory>
+#include "absl/base/attributes.h"
#include "absl/base/call_once.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/spinlock.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
#if ABSL_THREAD_IDENTITY_MODE != ABSL_THREAD_IDENTITY_MODE_USE_CPP11
@@ -52,10 +54,17 @@
// exist within a process (via dlopen() or similar), references to
// thread_identity_ptr from each instance of the code will refer to
// *different* instances of this ptr.
-#ifdef __GNUC__
+// Apple platforms have the visibility attribute, but issue a compile warning
+// that protected visibility is unsupported.
+#if ABSL_HAVE_ATTRIBUTE(visibility) && !defined(__APPLE__)
__attribute__((visibility("protected")))
-#endif // __GNUC__
- ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr;
+#endif // ABSL_HAVE_ATTRIBUTE(visibility) && !defined(__APPLE__)
+#if ABSL_PER_THREAD_TLS
+// Prefer __thread to thread_local as benchmarks indicate it is a bit faster.
+ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr = nullptr;
+#elif defined(ABSL_HAVE_THREAD_LOCAL)
+thread_local ThreadIdentity* thread_identity_ptr = nullptr;
+#endif // ABSL_PER_THREAD_TLS
#endif // TLS or CPP11
void SetCurrentThreadIdentity(
@@ -69,8 +78,8 @@
absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey,
reclaimer);
-#ifdef __EMSCRIPTEN__
- // Emscripten PThread implementation does not support signals.
+#if defined(__EMSCRIPTEN__) || defined(__MINGW32__)
+ // Emscripten and MinGW pthread implementations does not support signals.
// See https://kripken.github.io/emscripten-site/docs/porting/pthreads.html
// for more information.
pthread_setspecific(thread_identity_pthread_key,
@@ -89,7 +98,7 @@
pthread_setspecific(thread_identity_pthread_key,
reinterpret_cast<void*>(identity));
pthread_sigmask(SIG_SETMASK, &curr_signals, nullptr);
-#endif // !__EMSCRIPTEN__
+#endif // !__EMSCRIPTEN__ && !__MINGW32__
#elif ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS
// NOTE: Not async-safe. But can be open-coded.
@@ -107,6 +116,18 @@
#endif
}
+#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
+ ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
+
+// Please see the comment on `CurrentThreadIdentityIfPresent` in
+// thread_identity.h. Because DLLs cannot expose thread_local variables in
+// headers, we opt for the correct-but-slower option of placing the definition
+// of this function only in a translation unit inside DLL.
+#if defined(ABSL_BUILD_DLL) || defined(ABSL_CONSUME_DLL)
+ThreadIdentity* CurrentThreadIdentityIfPresent() { return thread_identity_ptr; }
+#endif
+#endif
+
void ClearCurrentThreadIdentity() {
#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
@@ -130,4 +151,5 @@
#endif
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/base/internal/thread_identity.h b/third_party/abseil/absl/base/internal/thread_identity.h
index b34674a..d2a65fd 100644
--- a/third_party/abseil/absl/base/internal/thread_identity.h
+++ b/third_party/abseil/absl/base/internal/thread_identity.h
@@ -30,9 +30,12 @@
#include <atomic>
#include <cstdint>
+#include "absl/base/config.h"
#include "absl/base/internal/per_thread_tls.h"
+#include "absl/base/optimization.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
struct SynchLocksHeld;
struct SynchWaitParams;
@@ -67,30 +70,28 @@
// 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;
+ 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;
+ 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 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.
+ int priority; // Priority of thread (updated every so often).
// State values:
// kAvailable: This PerThreadSynch is available.
@@ -109,30 +110,30 @@
};
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
+ // 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 wake; // This thread is to be woken from a Mutex.
+ intptr_t readers; // Number of readers in 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;
+ // When priority will next be read (cycles).
+ int64_t next_priority_read_cycles;
// Locks held; used during deadlock detection.
// Allocated in Synch_GetAllLocks() and freed in ReclaimThreadIdentity().
SynchLocksHeld *all_locks;
};
+// The instances of this class are allocated in NewThreadIdentity() with an
+// alignment of PerThreadSynch::kAlignment.
struct ThreadIdentity {
// Must be the first member. The Mutex implementation requires that
// the PerThreadSynch object associated with each thread is
@@ -208,9 +209,11 @@
#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)
+#elif defined(_WIN32) && !defined(__MINGW32__)
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
-#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \
+#elif defined(__APPLE__) && defined(ABSL_HAVE_THREAD_LOCAL)
+#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.
@@ -224,11 +227,26 @@
#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;
+#if ABSL_PER_THREAD_TLS
+ABSL_CONST_INIT extern ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity*
+ thread_identity_ptr;
+#elif defined(ABSL_HAVE_THREAD_LOCAL)
+ABSL_CONST_INIT extern thread_local ThreadIdentity* thread_identity_ptr;
+#else
+#error Thread-local storage not detected on this platform
+#endif
+// thread_local variables cannot be in headers exposed by DLLs. However, it is
+// important for performance reasons in general that
+// `CurrentThreadIdentityIfPresent` be inlined. This is not possible across a
+// DLL boundary so, with DLLs, we opt to have the function not be inlined. Note
+// that `CurrentThreadIdentityIfPresent` is declared above so we can exclude
+// this entire inline definition when compiling as a DLL.
+#if !defined(ABSL_BUILD_DLL) && !defined(ABSL_CONSUME_DLL)
inline ThreadIdentity* CurrentThreadIdentityIfPresent() {
return thread_identity_ptr;
}
+#endif
#elif ABSL_THREAD_IDENTITY_MODE != \
ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
@@ -236,6 +254,7 @@
#endif
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
diff --git a/third_party/abseil/absl/base/internal/thread_identity_test.cc b/third_party/abseil/absl/base/internal/thread_identity_test.cc
index 13bfbe3..46a6f74 100644
--- a/third_party/abseil/absl/base/internal/thread_identity_test.cc
+++ b/third_party/abseil/absl/base/internal/thread_identity_test.cc
@@ -21,17 +21,18 @@
#include "absl/base/attributes.h"
#include "absl/base/internal/spinlock.h"
#include "absl/base/macros.h"
+#include "absl/base/thread_annotations.h"
#include "absl/synchronization/internal/per_thread_sem.h"
#include "absl/synchronization/mutex.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
namespace {
-// protects num_identities_reused
-static absl::base_internal::SpinLock map_lock(
- absl::base_internal::kLinkerInitialized);
-static int num_identities_reused;
+ABSL_CONST_INIT static absl::base_internal::SpinLock map_lock(
+ absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
+ABSL_CONST_INIT static int num_identities_reused ABSL_GUARDED_BY(map_lock);
static const void* const kCheckNoIdentity = reinterpret_cast<void*>(1);
@@ -74,7 +75,7 @@
// - If a thread implementation chooses to recycle threads, that
// correct re-initialization occurs.
static const int kNumLoops = 3;
- static const int kNumThreads = 400;
+ static const int kNumThreads = 32;
for (int iter = 0; iter < kNumLoops; iter++) {
std::vector<std::thread> threads;
for (int i = 0; i < kNumThreads; ++i) {
@@ -89,6 +90,7 @@
// 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.
+ absl::base_internal::SpinLockHolder l(&map_lock);
EXPECT_LT(kNumThreads, num_identities_reused);
}
@@ -123,4 +125,5 @@
} // namespace
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/base/internal/throw_delegate.cc b/third_party/abseil/absl/base/internal/throw_delegate.cc
index 8e928b8..c260ff1 100644
--- a/third_party/abseil/absl/base/internal/throw_delegate.cc
+++ b/third_party/abseil/absl/base/internal/throw_delegate.cc
@@ -18,89 +18,195 @@
#include <functional>
#include <new>
#include <stdexcept>
+
#include "absl/base/config.h"
#include "absl/base/internal/raw_logging.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
+// NOTE: The various STL exception throwing functions are placed within the
+// #ifdef blocks so the symbols aren't exposed on platforms that don't support
+// them, such as the Android NDK. For example, ANGLE fails to link when building
+// within AOSP without them, since the STL functions don't exist.
namespace {
+#ifdef ABSL_HAVE_EXCEPTIONS
template <typename T>
[[noreturn]] void Throw(const T& error) {
-#ifdef ABSL_HAVE_EXCEPTIONS
throw error;
-#else
- ABSL_RAW_LOG(FATAL, "%s", error.what());
- std::abort();
-#endif
}
+#endif
} // namespace
void ThrowStdLogicError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::logic_error(what_arg));
+#else
+ ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+ std::abort();
+#endif
}
void ThrowStdLogicError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::logic_error(what_arg));
+#else
+ ABSL_RAW_LOG(FATAL, "%s", what_arg);
+ std::abort();
+#endif
}
void ThrowStdInvalidArgument(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::invalid_argument(what_arg));
+#else
+ ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+ std::abort();
+#endif
}
void ThrowStdInvalidArgument(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::invalid_argument(what_arg));
+#else
+ ABSL_RAW_LOG(FATAL, "%s", what_arg);
+ std::abort();
+#endif
}
void ThrowStdDomainError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::domain_error(what_arg));
+#else
+ ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+ std::abort();
+#endif
}
void ThrowStdDomainError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::domain_error(what_arg));
+#else
+ ABSL_RAW_LOG(FATAL, "%s", what_arg);
+ std::abort();
+#endif
}
void ThrowStdLengthError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::length_error(what_arg));
+#else
+ ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+ std::abort();
+#endif
}
void ThrowStdLengthError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::length_error(what_arg));
+#else
+ ABSL_RAW_LOG(FATAL, "%s", what_arg);
+ std::abort();
+#endif
}
void ThrowStdOutOfRange(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::out_of_range(what_arg));
+#else
+ ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+ std::abort();
+#endif
}
void ThrowStdOutOfRange(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::out_of_range(what_arg));
+#else
+ ABSL_RAW_LOG(FATAL, "%s", what_arg);
+ std::abort();
+#endif
}
void ThrowStdRuntimeError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::runtime_error(what_arg));
+#else
+ ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+ std::abort();
+#endif
}
void ThrowStdRuntimeError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::runtime_error(what_arg));
+#else
+ ABSL_RAW_LOG(FATAL, "%s", what_arg);
+ std::abort();
+#endif
}
void ThrowStdRangeError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::range_error(what_arg));
+#else
+ ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+ std::abort();
+#endif
}
void ThrowStdRangeError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::range_error(what_arg));
+#else
+ ABSL_RAW_LOG(FATAL, "%s", what_arg);
+ std::abort();
+#endif
}
void ThrowStdOverflowError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::overflow_error(what_arg));
+#else
+ ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+ std::abort();
+#endif
}
void ThrowStdOverflowError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::overflow_error(what_arg));
+#else
+ ABSL_RAW_LOG(FATAL, "%s", what_arg);
+ std::abort();
+#endif
}
void ThrowStdUnderflowError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::underflow_error(what_arg));
+#else
+ ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+ std::abort();
+#endif
}
void ThrowStdUnderflowError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::underflow_error(what_arg));
+#else
+ ABSL_RAW_LOG(FATAL, "%s", what_arg);
+ std::abort();
+#endif
}
-void ThrowStdBadFunctionCall() { Throw(std::bad_function_call()); }
+void ThrowStdBadFunctionCall() {
+#ifdef ABSL_HAVE_EXCEPTIONS
+ Throw(std::bad_function_call());
+#else
+ std::abort();
+#endif
+}
-void ThrowStdBadAlloc() { Throw(std::bad_alloc()); }
+void ThrowStdBadAlloc() {
+#ifdef ABSL_HAVE_EXCEPTIONS
+ Throw(std::bad_alloc());
+#else
+ std::abort();
+#endif
+}
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/base/internal/throw_delegate.h b/third_party/abseil/absl/base/internal/throw_delegate.h
index 03c700b..075f527 100644
--- a/third_party/abseil/absl/base/internal/throw_delegate.h
+++ b/third_party/abseil/absl/base/internal/throw_delegate.h
@@ -19,7 +19,10 @@
#include <string>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
// Helper functions that allow throwing exceptions consistently from anywhere.
@@ -66,6 +69,7 @@
// [[noreturn]] void ThrowStdBadArrayNewLength();
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_THROW_DELEGATE_H_
diff --git a/third_party/abseil/absl/base/internal/tsan_mutex_interface.h b/third_party/abseil/absl/base/internal/tsan_mutex_interface.h
index 2a51060..39207d8 100644
--- a/third_party/abseil/absl/base/internal/tsan_mutex_interface.h
+++ b/third_party/abseil/absl/base/internal/tsan_mutex_interface.h
@@ -19,6 +19,8 @@
#ifndef ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
#define ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
+#include "absl/base/config.h"
+
// ABSL_INTERNAL_HAVE_TSAN_INTERFACE
// Macro intended only for internal use.
//
@@ -28,7 +30,7 @@
#error "ABSL_INTERNAL_HAVE_TSAN_INTERFACE cannot be directly set."
#endif
-#if defined(THREAD_SANITIZER) && defined(__has_include)
+#if defined(ABSL_HAVE_THREAD_SANITIZER) && defined(__has_include)
#if __has_include(<sanitizer/tsan_interface.h>)
#define ABSL_INTERNAL_HAVE_TSAN_INTERFACE 1
#endif
diff --git a/third_party/abseil/absl/base/internal/unaligned_access.h b/third_party/abseil/absl/base/internal/unaligned_access.h
index 2cf7c1d..093dd9b 100644
--- a/third_party/abseil/absl/base/internal/unaligned_access.h
+++ b/third_party/abseil/absl/base/internal/unaligned_access.h
@@ -18,9 +18,11 @@
#define ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
#include <string.h>
+
#include <cstdint>
#include "absl/base/attributes.h"
+#include "absl/base/config.h"
// unaligned APIs
@@ -29,79 +31,8 @@
// 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 {
-namespace base_internal {
-
-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 base_internal
-} // namespace absl
-
-#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
- (absl::base_internal::UnalignedLoad16(_p))
-#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \
- (absl::base_internal::UnalignedLoad32(_p))
-#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \
- (absl::base_internal::UnalignedLoad64(_p))
-
-#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
- (absl::base_internal::UnalignedStore16(_p, _val))
-#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
- (absl::base_internal::UnalignedStore32(_p, _val))
-#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
- (absl::base_internal::UnalignedStore64(_p, _val))
-
-#else
-
-namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
inline uint16_t UnalignedLoad16(const void *p) {
@@ -129,6 +60,7 @@
inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
@@ -145,8 +77,6 @@
#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
(absl::base_internal::UnalignedStore64(_p, _val))
-#endif
-
#endif // defined(__cplusplus), end of unaligned API
#endif // ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
diff --git a/third_party/abseil/absl/base/internal/unique_small_name_test.cc b/third_party/abseil/absl/base/internal/unique_small_name_test.cc
new file mode 100644
index 0000000..ff8c2b3
--- /dev/null
+++ b/third_party/abseil/absl/base/internal/unique_small_name_test.cc
@@ -0,0 +1,77 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "gtest/gtest.h"
+#include "absl/base/optimization.h"
+#include "absl/strings/string_view.h"
+
+// This test by itself does not do anything fancy, but it serves as binary I can
+// query in shell test.
+
+namespace {
+
+template <class T>
+void DoNotOptimize(const T& var) {
+#ifdef __GNUC__
+ asm volatile("" : "+m"(const_cast<T&>(var)));
+#else
+ std::cout << (void*)&var;
+#endif
+}
+
+int very_long_int_variable_name ABSL_INTERNAL_UNIQUE_SMALL_NAME() = 0;
+char very_long_str_variable_name[] ABSL_INTERNAL_UNIQUE_SMALL_NAME() = "abc";
+
+TEST(UniqueSmallName, NonAutomaticVar) {
+ EXPECT_EQ(very_long_int_variable_name, 0);
+ EXPECT_EQ(absl::string_view(very_long_str_variable_name), "abc");
+}
+
+int VeryLongFreeFunctionName() ABSL_INTERNAL_UNIQUE_SMALL_NAME();
+
+TEST(UniqueSmallName, FreeFunction) {
+ DoNotOptimize(&VeryLongFreeFunctionName);
+
+ EXPECT_EQ(VeryLongFreeFunctionName(), 456);
+}
+
+int VeryLongFreeFunctionName() { return 456; }
+
+struct VeryLongStructName {
+ explicit VeryLongStructName(int i);
+
+ int VeryLongMethodName() ABSL_INTERNAL_UNIQUE_SMALL_NAME();
+
+ static int VeryLongStaticMethodName() ABSL_INTERNAL_UNIQUE_SMALL_NAME();
+
+ private:
+ int fld;
+};
+
+TEST(UniqueSmallName, Struct) {
+ VeryLongStructName var(10);
+
+ DoNotOptimize(var);
+ DoNotOptimize(&VeryLongStructName::VeryLongMethodName);
+ DoNotOptimize(&VeryLongStructName::VeryLongStaticMethodName);
+
+ EXPECT_EQ(var.VeryLongMethodName(), 10);
+ EXPECT_EQ(VeryLongStructName::VeryLongStaticMethodName(), 123);
+}
+
+VeryLongStructName::VeryLongStructName(int i) : fld(i) {}
+int VeryLongStructName::VeryLongMethodName() { return fld; }
+int VeryLongStructName::VeryLongStaticMethodName() { return 123; }
+
+} // namespace
diff --git a/third_party/abseil/absl/base/internal/unscaledcycleclock.cc b/third_party/abseil/absl/base/internal/unscaledcycleclock.cc
index 593762b..1545288 100644
--- a/third_party/abseil/absl/base/internal/unscaledcycleclock.cc
+++ b/third_party/abseil/absl/base/internal/unscaledcycleclock.cc
@@ -21,12 +21,18 @@
#endif
#if defined(__powerpc__) || defined(__ppc__)
+#ifdef __GLIBC__
#include <sys/platform/ppc.h>
+#elif defined(__FreeBSD__)
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#endif
#endif
#include "absl/base/internal/sysinfo.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
#if defined(__i386__)
@@ -56,11 +62,43 @@
#elif defined(__powerpc__) || defined(__ppc__)
int64_t UnscaledCycleClock::Now() {
+#ifdef __GLIBC__
return __ppc_get_timebase();
+#else
+#ifdef __powerpc64__
+ int64_t tbr;
+ asm volatile("mfspr %0, 268" : "=r"(tbr));
+ return tbr;
+#else
+ int32_t tbu, tbl, tmp;
+ asm volatile(
+ "0:\n"
+ "mftbu %[hi32]\n"
+ "mftb %[lo32]\n"
+ "mftbu %[tmp]\n"
+ "cmpw %[tmp],%[hi32]\n"
+ "bne 0b\n"
+ : [ hi32 ] "=r"(tbu), [ lo32 ] "=r"(tbl), [ tmp ] "=r"(tmp));
+ return (static_cast<int64_t>(tbu) << 32) | tbl;
+#endif
+#endif
}
double UnscaledCycleClock::Frequency() {
+#ifdef __GLIBC__
return __ppc_get_timebase_freq();
+#elif defined(__FreeBSD__)
+ static once_flag init_timebase_frequency_once;
+ static double timebase_frequency = 0.0;
+ base_internal::LowLevelCallOnce(&init_timebase_frequency_once, [&]() {
+ size_t length = sizeof(timebase_frequency);
+ sysctlbyname("kern.timecounter.tc.timebase.frequency", &timebase_frequency,
+ &length, nullptr, 0);
+ });
+ return timebase_frequency;
+#else
+#error Must implement UnscaledCycleClock::Frequency()
+#endif
}
#elif defined(__aarch64__)
@@ -85,9 +123,7 @@
#pragma intrinsic(__rdtsc)
-int64_t UnscaledCycleClock::Now() {
- return __rdtsc();
-}
+int64_t UnscaledCycleClock::Now() { return __rdtsc(); }
double UnscaledCycleClock::Frequency() {
return base_internal::NominalCPUFrequency();
@@ -96,6 +132,7 @@
#endif
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_USE_UNSCALED_CYCLECLOCK
diff --git a/third_party/abseil/absl/base/internal/unscaledcycleclock.h b/third_party/abseil/absl/base/internal/unscaledcycleclock.h
index 2d361e9..82f2c87 100644
--- a/third_party/abseil/absl/base/internal/unscaledcycleclock.h
+++ b/third_party/abseil/absl/base/internal/unscaledcycleclock.h
@@ -15,8 +15,8 @@
// 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.
+// This class is for internal use only, you should consider using CycleClock
+// instead.
//
// Notes:
// The cycle counter frequency is not necessarily the core clock frequency.
@@ -86,6 +86,7 @@
#endif
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
class UnscaledCycleClockWrapperForGetCurrentTime;
} // namespace time_internal
@@ -108,13 +109,14 @@
// value.
static double Frequency();
- // Whitelisted friends.
+ // Allowed users
friend class base_internal::CycleClock;
friend class time_internal::UnscaledCycleClockWrapperForGetCurrentTime;
friend class base_internal::UnscaledCycleClockWrapperForInitializeFrequency;
};
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_USE_UNSCALED_CYCLECLOCK
diff --git a/third_party/abseil/absl/base/invoke_test.cc b/third_party/abseil/absl/base/invoke_test.cc
index 9074443..bcdef36 100644
--- a/third_party/abseil/absl/base/invoke_test.cc
+++ b/third_party/abseil/absl/base/invoke_test.cc
@@ -25,6 +25,7 @@
#include "absl/strings/str_cat.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
namespace {
@@ -85,71 +86,73 @@
int member;
};
-// CallMaybeWithArg(f) resolves either to Invoke(f) or Invoke(f, 42), depending
+// 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);
+decltype(base_internal::invoke(std::declval<const F&>())) CallMaybeWithArg(
+ const F& f) {
+ return base_internal::invoke(f);
}
template <typename F>
-decltype(Invoke(std::declval<const F&>(), 42)) CallMaybeWithArg(const F& f) {
- return Invoke(f, 42);
+decltype(base_internal::invoke(std::declval<const F&>(), 42)) CallMaybeWithArg(
+ const F& f) {
+ return base_internal::invoke(f, 42);
}
TEST(InvokeTest, Function) {
- EXPECT_EQ(1, Invoke(Function, 3, 2));
- EXPECT_EQ(1, Invoke(&Function, 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(Function, 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(&Function, 3, 2));
}
TEST(InvokeTest, NonCopyableArgument) {
- EXPECT_EQ(42, Invoke(Sink, make_unique<int>(42)));
+ EXPECT_EQ(42, base_internal::invoke(Sink, make_unique<int>(42)));
}
TEST(InvokeTest, NonCopyableResult) {
- EXPECT_THAT(Invoke(Factory, 42), ::testing::Pointee(42));
+ EXPECT_THAT(base_internal::invoke(Factory, 42), ::testing::Pointee(42));
}
-TEST(InvokeTest, VoidResult) {
- Invoke(NoOp);
-}
+TEST(InvokeTest, VoidResult) { base_internal::invoke(NoOp); }
TEST(InvokeTest, ConstFunctor) {
- EXPECT_EQ(1, Invoke(ConstFunctor(), 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(ConstFunctor(), 3, 2));
}
TEST(InvokeTest, MutableFunctor) {
MutableFunctor f;
- EXPECT_EQ(1, Invoke(f, 3, 2));
- EXPECT_EQ(1, Invoke(MutableFunctor(), 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(f, 3, 2));
+ EXPECT_EQ(1, base_internal::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));
+ EXPECT_EQ(1, base_internal::invoke(std::move(f), 3, 2));
+ EXPECT_EQ(1, base_internal::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("&", base_internal::invoke(f));
+ EXPECT_EQ("& 42", base_internal::invoke(f, " 42"));
- EXPECT_EQ("const&", Invoke(cf));
- EXPECT_EQ("const& 42", Invoke(cf, " 42"));
+ EXPECT_EQ("const&", base_internal::invoke(cf));
+ EXPECT_EQ("const& 42", base_internal::invoke(cf, " 42"));
- EXPECT_EQ("&&", Invoke(std::move(f)));
- EXPECT_EQ("&& 42", Invoke(std::move(f), " 42"));
+ EXPECT_EQ("&&", base_internal::invoke(std::move(f)));
+
+ OverloadedFunctor f2;
+ EXPECT_EQ("&& 42", base_internal::invoke(std::move(f2), " 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));
+ EXPECT_EQ(1, base_internal::invoke(std::cref(cf), 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(std::ref(cf), 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(std::ref(mf), 3, 2));
}
TEST(InvokeTest, MemberFunction) {
@@ -157,58 +160,62 @@
std::unique_ptr<const Class> cp(new Class);
std::unique_ptr<volatile Class> vp(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::Method, *p, 3, 2));
- EXPECT_EQ(1, Invoke(&Class::RefMethod, p, 3, 2));
- EXPECT_EQ(1, Invoke(&Class::RefMethod, p.get(), 3, 2));
- EXPECT_EQ(1, Invoke(&Class::RefMethod, *p, 3, 2));
- EXPECT_EQ(1, Invoke(&Class::RefRefMethod, std::move(*p), 3, 2)); // NOLINT
- EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, p, 3, 2));
- EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, p.get(), 3, 2));
- EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, *p, 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(&Class::Method, p, 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(&Class::Method, p.get(), 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(&Class::Method, *p, 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(&Class::RefMethod, p, 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(&Class::RefMethod, p.get(), 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(&Class::RefMethod, *p, 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(&Class::RefRefMethod, std::move(*p), 3,
+ 2)); // NOLINT
+ EXPECT_EQ(1, base_internal::invoke(&Class::NoExceptMethod, p, 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(&Class::NoExceptMethod, p.get(), 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(&Class::NoExceptMethod, *p, 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, base_internal::invoke(&Class::ConstMethod, p, 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, p.get(), 3, 2));
+ EXPECT_EQ(1, base_internal::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, base_internal::invoke(&Class::ConstMethod, cp, 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, cp.get(), 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, *cp, 3, 2));
- EXPECT_EQ(1, Invoke(&Class::VolatileMethod, p, 3, 2));
- EXPECT_EQ(1, Invoke(&Class::VolatileMethod, p.get(), 3, 2));
- EXPECT_EQ(1, Invoke(&Class::VolatileMethod, *p, 3, 2));
- EXPECT_EQ(1, Invoke(&Class::VolatileMethod, vp, 3, 2));
- EXPECT_EQ(1, Invoke(&Class::VolatileMethod, vp.get(), 3, 2));
- EXPECT_EQ(1, Invoke(&Class::VolatileMethod, *vp, 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, p, 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, p.get(), 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, *p, 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, vp, 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, vp.get(), 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, *vp, 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));
+ EXPECT_EQ(1,
+ base_internal::invoke(&Class::Method, make_unique<Class>(), 3, 2));
+ EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, make_unique<Class>(),
+ 3, 2));
+ EXPECT_EQ(1, base_internal::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()));
+ EXPECT_EQ(42, base_internal::invoke(&Class::member, p));
+ EXPECT_EQ(42, base_internal::invoke(&Class::member, *p));
+ EXPECT_EQ(42, base_internal::invoke(&Class::member, p.get()));
- Invoke(&Class::member, p) = 42;
- Invoke(&Class::member, p.get()) = 42;
+ base_internal::invoke(&Class::member, p) = 42;
+ base_internal::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()));
+ EXPECT_EQ(42, base_internal::invoke(&Class::member, cp));
+ EXPECT_EQ(42, base_internal::invoke(&Class::member, *cp));
+ EXPECT_EQ(42, base_internal::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));
+ EXPECT_EQ(42, base_internal::invoke(&FlipFlop::ConstMethod, obj));
+ EXPECT_EQ(42, base_internal::invoke(&FlipFlop::member, obj));
}
TEST(InvokeTest, SfinaeFriendly) {
@@ -218,4 +225,5 @@
} // namespace
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/base/log_severity.cc b/third_party/abseil/absl/base/log_severity.cc
index 02a2a48..72312af 100644
--- a/third_party/abseil/absl/base/log_severity.cc
+++ b/third_party/abseil/absl/base/log_severity.cc
@@ -17,9 +17,11 @@
#include <ostream>
namespace absl {
+ABSL_NAMESPACE_BEGIN
std::ostream& operator<<(std::ostream& os, absl::LogSeverity s) {
if (s == absl::NormalizeLogSeverity(s)) return os << absl::LogSeverityName(s);
return os << "absl::LogSeverity(" << static_cast<int>(s) << ")";
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/base/log_severity.h b/third_party/abseil/absl/base/log_severity.h
index f5dc7d2..045f17f 100644
--- a/third_party/abseil/absl/base/log_severity.h
+++ b/third_party/abseil/absl/base/log_severity.h
@@ -12,29 +12,57 @@
// 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_
+#ifndef ABSL_BASE_LOG_SEVERITY_H_
+#define ABSL_BASE_LOG_SEVERITY_H_
#include <array>
#include <ostream>
#include "absl/base/attributes.h"
+#include "absl/base/config.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
-// Four severity levels are defined. Logging APIs should terminate the program
+// absl::LogSeverity
+//
+// Four severity levels are defined. Logging APIs should terminate the program
// when a message is logged at severity `kFatal`; the other levels have no
// special semantics.
//
-// Abseil flags may be defined with type `LogSeverity`. Dependency layering
-// constraints require that the `AbslParseFlag` overload be declared and defined
-// in the flags module rather than here. The `AbslUnparseFlag` overload is
-// defined there too for consistency.
+// Values other than the four defined levels (e.g. produced by `static_cast`)
+// are valid, but their semantics when passed to a function, macro, or flag
+// depend on the function, macro, or flag. The usual behavior is to normalize
+// such values to a defined severity level, however in some cases values other
+// than the defined levels are useful for comparison.
//
-// The parser accepts arbitrary integers (as if the type were `int`). It also
-// accepts each named enumerator, without regard for case, with or without the
-// leading 'k'. For example: "kInfo", "INFO", and "info" all parse to the value
-// `absl::LogSeverity::kInfo`.
+// Exmaple:
+//
+// // Effectively disables all logging:
+// SetMinLogLevel(static_cast<absl::LogSeverity>(100));
+//
+// Abseil flags may be defined with type `LogSeverity`. Dependency layering
+// constraints require that the `AbslParseFlag()` overload be declared and
+// defined in the flags library itself rather than here. The `AbslUnparseFlag()`
+// overload is defined there as well for consistency.
+//
+// absl::LogSeverity Flag String Representation
+//
+// An `absl::LogSeverity` has a string representation used for parsing
+// command-line flags based on the enumerator name (e.g. `kFatal`) or
+// its unprefixed name (without the `k`) in any case-insensitive form. (E.g.
+// "FATAL", "fatal" or "Fatal" are all valid.) Unparsing such flags produces an
+// unprefixed string representation in all caps (e.g. "FATAL") or an integer.
+//
+// Additionally, the parser accepts arbitrary integers (as if the type were
+// `int`).
+//
+// Examples:
+//
+// --my_log_level=kInfo
+// --my_log_level=INFO
+// --my_log_level=info
+// --my_log_level=0
//
// Unparsing a flag produces the same result as `absl::LogSeverityName()` for
// the standard levels and a base-ten integer otherwise.
@@ -45,6 +73,8 @@
kFatal = 3,
};
+// LogSeverities()
+//
// Returns an iterable of all standard `absl::LogSeverity` values, ordered from
// least to most severe.
constexpr std::array<absl::LogSeverity, 4> LogSeverities() {
@@ -52,6 +82,8 @@
absl::LogSeverity::kError, absl::LogSeverity::kFatal}};
}
+// LogSeverityName()
+//
// Returns the all-caps string representation (e.g. "INFO") of the specified
// severity level if it is one of the standard levels and "UNKNOWN" otherwise.
constexpr const char* LogSeverityName(absl::LogSeverity s) {
@@ -64,6 +96,8 @@
: s == absl::LogSeverity::kFatal ? "FATAL" : "UNKNOWN";
}
+// NormalizeLogSeverity()
+//
// Values less than `kInfo` normalize to `kInfo`; values greater than `kFatal`
// normalize to `kError` (**NOT** `kFatal`).
constexpr absl::LogSeverity NormalizeLogSeverity(absl::LogSeverity s) {
@@ -75,10 +109,13 @@
return absl::NormalizeLogSeverity(static_cast<absl::LogSeverity>(s));
}
+// operator<<
+//
// The exact representation of a streamed `absl::LogSeverity` is deliberately
// unspecified; do not rely on it.
std::ostream& operator<<(std::ostream& os, absl::LogSeverity s);
+ABSL_NAMESPACE_END
} // namespace absl
-#endif // ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
+#endif // ABSL_BASE_LOG_SEVERITY_H_
diff --git a/third_party/abseil/absl/base/log_severity_test.cc b/third_party/abseil/absl/base/log_severity_test.cc
index 1e3aafa..2c6872b 100644
--- a/third_party/abseil/absl/base/log_severity_test.cc
+++ b/third_party/abseil/absl/base/log_severity_test.cc
@@ -24,6 +24,7 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/flags/internal/flag.h"
#include "absl/flags/marshalling.h"
#include "absl/strings/str_cat.h"
@@ -51,6 +52,10 @@
Eq("absl::LogSeverity(4)"));
}
+static_assert(
+ absl::flags_internal::FlagUseOneWordStorage<absl::LogSeverity>::value,
+ "Flags of type absl::LogSeverity ought to be lock-free.");
+
using ParseFlagFromOutOfRangeIntegerTest = TestWithParam<int64_t>;
INSTANTIATE_TEST_SUITE_P(
Instantiation, ParseFlagFromOutOfRangeIntegerTest,
diff --git a/third_party/abseil/absl/base/macros.h b/third_party/abseil/absl/base/macros.h
index d481288..3e085a9 100644
--- a/third_party/abseil/absl/base/macros.h
+++ b/third_party/abseil/absl/base/macros.h
@@ -31,6 +31,8 @@
#include <cassert>
#include <cstddef>
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
#include "absl/base/optimization.h"
#include "absl/base/port.h"
@@ -43,127 +45,22 @@
(sizeof(::absl::macros_internal::ArraySizeHelper(array)))
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace macros_internal {
// Note: this internal template function declaration is used by ABSL_ARRAYSIZE.
// The function doesn't need a definition, as we only use its type.
template <typename T, size_t N>
auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
} // namespace macros_internal
+ABSL_NAMESPACE_END
} // namespace absl
-// kLinkerInitialized
-//
-// An enum used only as a constructor argument to indicate that a variable has
-// static storage duration, and that the constructor should do nothing to its
-// state. Use of this macro indicates to the reader that it is legal to
-// declare a static instance of the class, provided the constructor is given
-// the absl::base_internal::kLinkerInitialized argument.
-//
-// Normally, it is unsafe to declare a static variable that has a constructor or
-// a destructor because invocation order is undefined. However, if the type can
-// be zero-initialized (which the loader does for static variables) into a valid
-// state and the type's destructor does not affect storage, then a constructor
-// for static initialization can be declared.
-//
-// Example:
-// // Declaration
-// explicit MyClass(absl::base_internal:LinkerInitialized x) {}
-//
-// // Invocation
-// static MyClass my_global(absl::base_internal::kLinkerInitialized);
-namespace absl {
-namespace base_internal {
-enum LinkerInitialized {
- kLinkerInitialized = 0,
-};
-} // namespace base_internal
-} // namespace absl
-
-// ABSL_FALLTHROUGH_INTENDED
-//
-// Annotates implicit fall-through between switch labels, allowing a case to
-// indicate intentional fallthrough and turn off warnings about any lack of a
-// `break` statement. The ABSL_FALLTHROUGH_INTENDED macro should be followed by
-// a semicolon and can be used in most places where `break` can, provided that
-// no statements exist between it and the next switch label.
-//
-// Example:
-//
-// switch (x) {
-// case 40:
-// case 41:
-// if (truth_is_out_there) {
-// ++x;
-// ABSL_FALLTHROUGH_INTENDED; // Use instead of/along with annotations
-// // in comments
-// } else {
-// return x;
-// }
-// case 42:
-// ...
-//
-// Notes: when compiled with clang in C++11 mode, the ABSL_FALLTHROUGH_INTENDED
-// macro is expanded to the [[clang::fallthrough]] attribute, which is analysed
-// when performing switch labels fall-through diagnostic
-// (`-Wimplicit-fallthrough`). See clang documentation on language extensions
-// for details:
-// http://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough
-//
-// When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro
-// has no effect on diagnostics. In any case this macro has no effect on runtime
-// behavior and performance of code.
-#ifdef ABSL_FALLTHROUGH_INTENDED
-#error "ABSL_FALLTHROUGH_INTENDED should not be defined."
-#endif
-
-// TODO(zhangxy): Use c++17 standard [[fallthrough]] macro, when supported.
-#if defined(__clang__) && defined(__has_warning)
-#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
-#define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]]
-#endif
-#elif defined(__GNUC__) && __GNUC__ >= 7
-#define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]]
-#endif
-
-#ifndef ABSL_FALLTHROUGH_INTENDED
-#define ABSL_FALLTHROUGH_INTENDED \
- do { \
- } while (0)
-#endif
-
-// ABSL_DEPRECATED()
-//
-// Marks a deprecated class, struct, enum, function, method and variable
-// declarations. The macro argument is used as a custom diagnostic message (e.g.
-// suggestion of a better alternative).
-//
-// Examples:
-//
-// class ABSL_DEPRECATED("Use Bar instead") Foo {...};
-//
-// ABSL_DEPRECATED("Use Baz() instead") void Bar() {...}
-//
-// template <typename T>
-// ABSL_DEPRECATED("Use DoThat() instead")
-// void DoThis();
-//
-// Every usage of a deprecated entity will trigger a warning when compiled with
-// clang's `-Wdeprecated-declarations` option. This option is turned off by
-// default, but the warnings will be reported by clang-tidy.
-#if defined(__clang__) && __cplusplus >= 201103L
-#define ABSL_DEPRECATED(message) __attribute__((deprecated(message)))
-#endif
-
-#ifndef ABSL_DEPRECATED
-#define ABSL_DEPRECATED(message)
-#endif
-
// ABSL_BAD_CALL_IF()
//
// Used on a function overload to trap bad calls: any call that matches the
// overload will cause a compile-time error. This macro uses a clang-specific
// "enable_if" attribute, as described at
-// http://clang.llvm.org/docs/AttributeReference.html#enable-if
+// https://clang.llvm.org/docs/AttributeReference.html#enable-if
//
// Overloads which use this macro should be bracketed by
// `#ifdef ABSL_BAD_CALL_IF`.
@@ -176,12 +73,9 @@
// 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
+#if ABSL_HAVE_ATTRIBUTE(enable_if)
+#define ABSL_BAD_CALL_IF(expr, msg) \
+ __attribute__((enable_if(expr, "Bad call trap"), unavailable(msg)))
#endif
// ABSL_ASSERT()
@@ -205,6 +99,41 @@
: [] { assert(false && #expr); }()) // NOLINT
#endif
+// `ABSL_INTERNAL_HARDENING_ABORT()` controls how `ABSL_HARDENING_ASSERT()`
+// aborts the program in release mode (when NDEBUG is defined). The
+// implementation should abort the program as quickly as possible and ideally it
+// should not be possible to ignore the abort request.
+#if (ABSL_HAVE_BUILTIN(__builtin_trap) && \
+ ABSL_HAVE_BUILTIN(__builtin_unreachable)) || \
+ (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_INTERNAL_HARDENING_ABORT() \
+ do { \
+ __builtin_trap(); \
+ __builtin_unreachable(); \
+ } while (false)
+#else
+#define ABSL_INTERNAL_HARDENING_ABORT() abort()
+#endif
+
+// ABSL_HARDENING_ASSERT()
+//
+// `ABSL_HARDENING_ASSERT()` is like `ABSL_ASSERT()`, but used to implement
+// runtime assertions that should be enabled in hardened builds even when
+// `NDEBUG` is defined.
+//
+// When `NDEBUG` is not defined, `ABSL_HARDENING_ASSERT()` is identical to
+// `ABSL_ASSERT()`.
+//
+// See `ABSL_OPTION_HARDENED` in `absl/base/options.h` for more information on
+// hardened mode.
+#if ABSL_OPTION_HARDENED == 1 && defined(NDEBUG)
+#define ABSL_HARDENING_ASSERT(expr) \
+ (ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \
+ : [] { ABSL_INTERNAL_HARDENING_ABORT(); }())
+#else
+#define ABSL_HARDENING_ASSERT(expr) ABSL_ASSERT(expr)
+#endif
+
#ifdef ABSL_HAVE_EXCEPTIONS
#define ABSL_INTERNAL_TRY try
#define ABSL_INTERNAL_CATCH_ANY catch (...)
@@ -215,4 +144,15 @@
#define ABSL_INTERNAL_RETHROW do {} while (false)
#endif // ABSL_HAVE_EXCEPTIONS
+// `ABSL_INTERNAL_UNREACHABLE` is an unreachable statement. A program which
+// reaches one has undefined behavior, and the compiler may optimize
+// accordingly.
+#if defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
+#define ABSL_INTERNAL_UNREACHABLE __builtin_unreachable()
+#elif defined(_MSC_VER)
+#define ABSL_INTERNAL_UNREACHABLE __assume(0)
+#else
+#define ABSL_INTERNAL_UNREACHABLE
+#endif
+
#endif // ABSL_BASE_MACROS_H_
diff --git a/third_party/abseil/absl/base/optimization.h b/third_party/abseil/absl/base/optimization.h
index 0dcbef3..6332b62 100644
--- a/third_party/abseil/absl/base/optimization.h
+++ b/third_party/abseil/absl/base/optimization.h
@@ -22,13 +22,15 @@
#ifndef ABSL_BASE_OPTIMIZATION_H_
#define ABSL_BASE_OPTIMIZATION_H_
+#include <assert.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.
+// Instructs the compiler to avoid optimizing tail-call recursion. This macro is
+// useful when you wish to preserve the existing function order within a stack
+// trace for logging, debugging, or profiling purposes.
//
// Example:
//
@@ -171,11 +173,71 @@
// to yield performance improvements.
#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))
+#define ABSL_PREDICT_FALSE(x) (__builtin_expect(false || (x), false))
+#define ABSL_PREDICT_TRUE(x) (__builtin_expect(false || (x), true))
#else
#define ABSL_PREDICT_FALSE(x) (x)
#define ABSL_PREDICT_TRUE(x) (x)
#endif
+// ABSL_INTERNAL_ASSUME(cond)
+// Informs the compiler that a condition is always true and that it can assume
+// it to be true for optimization purposes. The call has undefined behavior if
+// the condition is false.
+// In !NDEBUG mode, the condition is checked with an assert().
+// NOTE: The expression must not have side effects, as it will only be evaluated
+// in some compilation modes and not others.
+//
+// Example:
+//
+// int x = ...;
+// ABSL_INTERNAL_ASSUME(x >= 0);
+// // The compiler can optimize the division to a simple right shift using the
+// // assumption specified above.
+// int y = x / 16;
+//
+#if !defined(NDEBUG)
+#define ABSL_INTERNAL_ASSUME(cond) assert(cond)
+#elif ABSL_HAVE_BUILTIN(__builtin_assume)
+#define ABSL_INTERNAL_ASSUME(cond) __builtin_assume(cond)
+#elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
+#define ABSL_INTERNAL_ASSUME(cond) \
+ do { \
+ if (!(cond)) __builtin_unreachable(); \
+ } while (0)
+#elif defined(_MSC_VER)
+#define ABSL_INTERNAL_ASSUME(cond) __assume(cond)
+#else
+#define ABSL_INTERNAL_ASSUME(cond) \
+ do { \
+ static_cast<void>(false && (cond)); \
+ } while (0)
+#endif
+
+// ABSL_INTERNAL_UNIQUE_SMALL_NAME(cond)
+// This macro forces small unique name on a static file level symbols like
+// static local variables or static functions. This is intended to be used in
+// macro definitions to optimize the cost of generated code. Do NOT use it on
+// symbols exported from translation unit since it may cause a link time
+// conflict.
+//
+// Example:
+//
+// #define MY_MACRO(txt)
+// namespace {
+// char VeryVeryLongVarName[] ABSL_INTERNAL_UNIQUE_SMALL_NAME() = txt;
+// const char* VeryVeryLongFuncName() ABSL_INTERNAL_UNIQUE_SMALL_NAME();
+// const char* VeryVeryLongFuncName() { return txt; }
+// }
+//
+
+#if defined(__GNUC__)
+#define ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x) #x
+#define ABSL_INTERNAL_UNIQUE_SMALL_NAME1(x) ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x)
+#define ABSL_INTERNAL_UNIQUE_SMALL_NAME() \
+ asm(ABSL_INTERNAL_UNIQUE_SMALL_NAME1(.absl.__COUNTER__))
+#else
+#define ABSL_INTERNAL_UNIQUE_SMALL_NAME()
+#endif
+
#endif // ABSL_BASE_OPTIMIZATION_H_
diff --git a/third_party/abseil/absl/base/optimization_test.cc b/third_party/abseil/absl/base/optimization_test.cc
new file mode 100644
index 0000000..e83369f
--- /dev/null
+++ b/third_party/abseil/absl/base/optimization_test.cc
@@ -0,0 +1,129 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/optimization.h"
+
+#include "gtest/gtest.h"
+#include "absl/types/optional.h"
+
+namespace {
+
+// Tests for the ABSL_PREDICT_TRUE and ABSL_PREDICT_FALSE macros.
+// The tests only verify that the macros are functionally correct - i.e. code
+// behaves as if they weren't used. They don't try to check their impact on
+// optimization.
+
+TEST(PredictTest, PredictTrue) {
+ EXPECT_TRUE(ABSL_PREDICT_TRUE(true));
+ EXPECT_FALSE(ABSL_PREDICT_TRUE(false));
+ EXPECT_TRUE(ABSL_PREDICT_TRUE(1 == 1));
+ EXPECT_FALSE(ABSL_PREDICT_TRUE(1 == 2));
+
+ if (ABSL_PREDICT_TRUE(false)) ADD_FAILURE();
+ if (!ABSL_PREDICT_TRUE(true)) ADD_FAILURE();
+
+ EXPECT_TRUE(ABSL_PREDICT_TRUE(true) && true);
+ EXPECT_TRUE(ABSL_PREDICT_TRUE(true) || false);
+}
+
+TEST(PredictTest, PredictFalse) {
+ EXPECT_TRUE(ABSL_PREDICT_FALSE(true));
+ EXPECT_FALSE(ABSL_PREDICT_FALSE(false));
+ EXPECT_TRUE(ABSL_PREDICT_FALSE(1 == 1));
+ EXPECT_FALSE(ABSL_PREDICT_FALSE(1 == 2));
+
+ if (ABSL_PREDICT_FALSE(false)) ADD_FAILURE();
+ if (!ABSL_PREDICT_FALSE(true)) ADD_FAILURE();
+
+ EXPECT_TRUE(ABSL_PREDICT_FALSE(true) && true);
+ EXPECT_TRUE(ABSL_PREDICT_FALSE(true) || false);
+}
+
+TEST(PredictTest, OneEvaluation) {
+ // Verify that the expression is only evaluated once.
+ int x = 0;
+ if (ABSL_PREDICT_TRUE((++x) == 0)) ADD_FAILURE();
+ EXPECT_EQ(x, 1);
+ if (ABSL_PREDICT_FALSE((++x) == 0)) ADD_FAILURE();
+ EXPECT_EQ(x, 2);
+}
+
+TEST(PredictTest, OperatorOrder) {
+ // Verify that operator order inside and outside the macro behaves well.
+ // These would fail for a naive '#define ABSL_PREDICT_TRUE(x) x'
+ EXPECT_TRUE(ABSL_PREDICT_TRUE(1 && 2) == true);
+ EXPECT_TRUE(ABSL_PREDICT_FALSE(1 && 2) == true);
+ EXPECT_TRUE(!ABSL_PREDICT_TRUE(1 == 2));
+ EXPECT_TRUE(!ABSL_PREDICT_FALSE(1 == 2));
+}
+
+TEST(PredictTest, Pointer) {
+ const int x = 3;
+ const int *good_intptr = &x;
+ const int *null_intptr = nullptr;
+ EXPECT_TRUE(ABSL_PREDICT_TRUE(good_intptr));
+ EXPECT_FALSE(ABSL_PREDICT_TRUE(null_intptr));
+ EXPECT_TRUE(ABSL_PREDICT_FALSE(good_intptr));
+ EXPECT_FALSE(ABSL_PREDICT_FALSE(null_intptr));
+}
+
+TEST(PredictTest, Optional) {
+ // Note: An optional's truth value is the value's existence, not its truth.
+ absl::optional<bool> has_value(false);
+ absl::optional<bool> no_value;
+ EXPECT_TRUE(ABSL_PREDICT_TRUE(has_value));
+ EXPECT_FALSE(ABSL_PREDICT_TRUE(no_value));
+ EXPECT_TRUE(ABSL_PREDICT_FALSE(has_value));
+ EXPECT_FALSE(ABSL_PREDICT_FALSE(no_value));
+}
+
+class ImplictlyConvertibleToBool {
+ public:
+ explicit ImplictlyConvertibleToBool(bool value) : value_(value) {}
+ operator bool() const { // NOLINT(google-explicit-constructor)
+ return value_;
+ }
+
+ private:
+ bool value_;
+};
+
+TEST(PredictTest, ImplicitBoolConversion) {
+ const ImplictlyConvertibleToBool is_true(true);
+ const ImplictlyConvertibleToBool is_false(false);
+ if (!ABSL_PREDICT_TRUE(is_true)) ADD_FAILURE();
+ if (ABSL_PREDICT_TRUE(is_false)) ADD_FAILURE();
+ if (!ABSL_PREDICT_FALSE(is_true)) ADD_FAILURE();
+ if (ABSL_PREDICT_FALSE(is_false)) ADD_FAILURE();
+}
+
+class ExplictlyConvertibleToBool {
+ public:
+ explicit ExplictlyConvertibleToBool(bool value) : value_(value) {}
+ explicit operator bool() const { return value_; }
+
+ private:
+ bool value_;
+};
+
+TEST(PredictTest, ExplicitBoolConversion) {
+ const ExplictlyConvertibleToBool is_true(true);
+ const ExplictlyConvertibleToBool is_false(false);
+ if (!ABSL_PREDICT_TRUE(is_true)) ADD_FAILURE();
+ if (ABSL_PREDICT_TRUE(is_false)) ADD_FAILURE();
+ if (!ABSL_PREDICT_FALSE(is_true)) ADD_FAILURE();
+ if (ABSL_PREDICT_FALSE(is_false)) ADD_FAILURE();
+}
+
+} // namespace
diff --git a/third_party/abseil/absl/base/options.h b/third_party/abseil/absl/base/options.h
new file mode 100644
index 0000000..230bf1e
--- /dev/null
+++ b/third_party/abseil/absl/base/options.h
@@ -0,0 +1,238 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: options.h
+// -----------------------------------------------------------------------------
+//
+// This file contains Abseil configuration options for setting specific
+// implementations instead of letting Abseil determine which implementation to
+// use at compile-time. Setting these options may be useful for package or build
+// managers who wish to guarantee ABI stability within binary builds (which are
+// otherwise difficult to enforce).
+//
+// *** IMPORTANT NOTICE FOR PACKAGE MANAGERS: It is important that
+// maintainers of package managers who wish to package Abseil read and
+// understand this file! ***
+//
+// Abseil contains a number of possible configuration endpoints, based on
+// parameters such as the detected platform, language version, or command-line
+// flags used to invoke the underlying binary. As is the case with all
+// libraries, binaries which contain Abseil code must ensure that separate
+// packages use the same compiled copy of Abseil to avoid a diamond dependency
+// problem, which can occur if two packages built with different Abseil
+// configuration settings are linked together. Diamond dependency problems in
+// C++ may manifest as violations to the One Definition Rule (ODR) (resulting in
+// linker errors), or undefined behavior (resulting in crashes).
+//
+// Diamond dependency problems can be avoided if all packages utilize the same
+// exact version of Abseil. Building from source code with the same compilation
+// parameters is the easiest way to avoid such dependency problems. However, for
+// package managers who cannot control such compilation parameters, we are
+// providing the file to allow you to inject ABI (Application Binary Interface)
+// stability across builds. Settings options in this file will neither change
+// API nor ABI, providing a stable copy of Abseil between packages.
+//
+// Care must be taken to keep options within these configurations isolated
+// from any other dynamic settings, such as command-line flags which could alter
+// these options. This file is provided specifically to help build and package
+// managers provide a stable copy of Abseil within their libraries and binaries;
+// other developers should not have need to alter the contents of this file.
+//
+// -----------------------------------------------------------------------------
+// Usage
+// -----------------------------------------------------------------------------
+//
+// For any particular package release, set the appropriate definitions within
+// this file to whatever value makes the most sense for your package(s). Note
+// that, by default, most of these options, at the moment, affect the
+// implementation of types; future options may affect other implementation
+// details.
+//
+// NOTE: the defaults within this file all assume that Abseil can select the
+// proper Abseil implementation at compile-time, which will not be sufficient
+// to guarantee ABI stability to package managers.
+
+#ifndef ABSL_BASE_OPTIONS_H_
+#define ABSL_BASE_OPTIONS_H_
+
+// Include a standard library header to allow configuration based on the
+// standard library in use.
+#ifdef __cplusplus
+#include <ciso646>
+#endif
+
+// -----------------------------------------------------------------------------
+// Type Compatibility Options
+// -----------------------------------------------------------------------------
+//
+// ABSL_OPTION_USE_STD_ANY
+//
+// This option controls whether absl::any is implemented as an alias to
+// std::any, or as an independent implementation.
+//
+// A value of 0 means to use Abseil's implementation. This requires only C++11
+// support, and is expected to work on every toolchain we support.
+//
+// A value of 1 means to use an alias to std::any. This requires that all code
+// using Abseil is built in C++17 mode or later.
+//
+// A value of 2 means to detect the C++ version being used to compile Abseil,
+// and use an alias only if a working std::any is available. This option is
+// useful when you are building your entire program, including all of its
+// dependencies, from source. It should not be used otherwise -- for example,
+// if you are distributing Abseil in a binary package manager -- since in
+// mode 2, absl::any will name a different type, with a different mangled name
+// and binary layout, depending on the compiler flags passed by the end user.
+// For more info, see https://abseil.io/about/design/dropin-types.
+//
+// User code should not inspect this macro. To check in the preprocessor if
+// absl::any is a typedef of std::any, use the feature macro ABSL_USES_STD_ANY.
+
+#define ABSL_OPTION_USE_STD_ANY 2
+
+
+// ABSL_OPTION_USE_STD_OPTIONAL
+//
+// This option controls whether absl::optional is implemented as an alias to
+// std::optional, or as an independent implementation.
+//
+// A value of 0 means to use Abseil's implementation. This requires only C++11
+// support, and is expected to work on every toolchain we support.
+//
+// A value of 1 means to use an alias to std::optional. This requires that all
+// code using Abseil is built in C++17 mode or later.
+//
+// A value of 2 means to detect the C++ version being used to compile Abseil,
+// and use an alias only if a working std::optional is available. This option
+// is useful when you are building your program from source. It should not be
+// used otherwise -- for example, if you are distributing Abseil in a binary
+// package manager -- since in mode 2, absl::optional will name a different
+// type, with a different mangled name and binary layout, depending on the
+// compiler flags passed by the end user. For more info, see
+// https://abseil.io/about/design/dropin-types.
+
+// User code should not inspect this macro. To check in the preprocessor if
+// absl::optional is a typedef of std::optional, use the feature macro
+// ABSL_USES_STD_OPTIONAL.
+
+#define ABSL_OPTION_USE_STD_OPTIONAL 2
+
+
+// ABSL_OPTION_USE_STD_STRING_VIEW
+//
+// This option controls whether absl::string_view is implemented as an alias to
+// std::string_view, or as an independent implementation.
+//
+// A value of 0 means to use Abseil's implementation. This requires only C++11
+// support, and is expected to work on every toolchain we support.
+//
+// A value of 1 means to use an alias to std::string_view. This requires that
+// all code using Abseil is built in C++17 mode or later.
+//
+// A value of 2 means to detect the C++ version being used to compile Abseil,
+// and use an alias only if a working std::string_view is available. This
+// option is useful when you are building your program from source. It should
+// not be used otherwise -- for example, if you are distributing Abseil in a
+// binary package manager -- since in mode 2, absl::string_view will name a
+// different type, with a different mangled name and binary layout, depending on
+// the compiler flags passed by the end user. For more info, see
+// https://abseil.io/about/design/dropin-types.
+//
+// User code should not inspect this macro. To check in the preprocessor if
+// absl::string_view is a typedef of std::string_view, use the feature macro
+// ABSL_USES_STD_STRING_VIEW.
+
+#define ABSL_OPTION_USE_STD_STRING_VIEW 2
+
+// ABSL_OPTION_USE_STD_VARIANT
+//
+// This option controls whether absl::variant is implemented as an alias to
+// std::variant, or as an independent implementation.
+//
+// A value of 0 means to use Abseil's implementation. This requires only C++11
+// support, and is expected to work on every toolchain we support.
+//
+// A value of 1 means to use an alias to std::variant. This requires that all
+// code using Abseil is built in C++17 mode or later.
+//
+// A value of 2 means to detect the C++ version being used to compile Abseil,
+// and use an alias only if a working std::variant is available. This option
+// is useful when you are building your program from source. It should not be
+// used otherwise -- for example, if you are distributing Abseil in a binary
+// package manager -- since in mode 2, absl::variant will name a different
+// type, with a different mangled name and binary layout, depending on the
+// compiler flags passed by the end user. For more info, see
+// https://abseil.io/about/design/dropin-types.
+//
+// User code should not inspect this macro. To check in the preprocessor if
+// absl::variant is a typedef of std::variant, use the feature macro
+// ABSL_USES_STD_VARIANT.
+
+#define ABSL_OPTION_USE_STD_VARIANT 2
+
+
+// ABSL_OPTION_USE_INLINE_NAMESPACE
+// ABSL_OPTION_INLINE_NAMESPACE_NAME
+//
+// These options controls whether all entities in the absl namespace are
+// contained within an inner inline namespace. This does not affect the
+// user-visible API of Abseil, but it changes the mangled names of all symbols.
+//
+// This can be useful as a version tag if you are distributing Abseil in
+// precompiled form. This will prevent a binary library build of Abseil with
+// one inline namespace being used with headers configured with a different
+// inline namespace name. Binary packagers are reminded that Abseil does not
+// guarantee any ABI stability in Abseil, so any update of Abseil or
+// configuration change in such a binary package should be combined with a
+// new, unique value for the inline namespace name.
+//
+// A value of 0 means not to use inline namespaces.
+//
+// A value of 1 means to use an inline namespace with the given name inside
+// namespace absl. If this is set, ABSL_OPTION_INLINE_NAMESPACE_NAME must also
+// be changed to a new, unique identifier name. In particular "head" is not
+// allowed.
+
+#define ABSL_OPTION_USE_INLINE_NAMESPACE 0
+#define ABSL_OPTION_INLINE_NAMESPACE_NAME head
+
+// ABSL_OPTION_HARDENED
+//
+// This option enables a "hardened" build in release mode (in this context,
+// release mode is defined as a build where the `NDEBUG` macro is defined).
+//
+// A value of 0 means that "hardened" mode is not enabled.
+//
+// A value of 1 means that "hardened" mode is enabled.
+//
+// Hardened builds have additional security checks enabled when `NDEBUG` is
+// defined. Defining `NDEBUG` is normally used to turn `assert()` macro into a
+// no-op, as well as disabling other bespoke program consistency checks. By
+// defining ABSL_OPTION_HARDENED to 1, a select set of checks remain enabled in
+// release mode. These checks guard against programming errors that may lead to
+// security vulnerabilities. In release mode, when one of these programming
+// errors is encountered, the program will immediately abort, possibly without
+// any attempt at logging.
+//
+// The checks enabled by this option are not free; they do incur runtime cost.
+//
+// The checks enabled by this option are always active when `NDEBUG` is not
+// defined, even in the case when ABSL_OPTION_HARDENED is defined to 0. The
+// checks enabled by this option may abort the program in a different way and
+// log additional information when `NDEBUG` is not defined.
+
+#define ABSL_OPTION_HARDENED 0
+
+#endif // ABSL_BASE_OPTIONS_H_
diff --git a/third_party/abseil/absl/base/policy_checks.h b/third_party/abseil/absl/base/policy_checks.h
index 699fb1a..06b3243 100644
--- a/third_party/abseil/absl/base/policy_checks.h
+++ b/third_party/abseil/absl/base/policy_checks.h
@@ -41,7 +41,7 @@
#endif
// -----------------------------------------------------------------------------
-// Compiler Check
+// Toolchain Check
// -----------------------------------------------------------------------------
// We support MSVC++ 14.0 update 2 and later.
@@ -82,16 +82,6 @@
// Standard Library Check
// -----------------------------------------------------------------------------
-// We have chosen glibc 2.12 as the minimum as it was tagged for release
-// in May, 2010 and includes some functionality used in Google software
-// (for instance pthread_setname_np):
-// https://sourceware.org/ml/libc-alpha/2010-05/msg00000.html
-#if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
-#if !__GLIBC_PREREQ(2, 12)
-#error "Minimum required version of glibc is 2.12."
-#endif
-#endif
-
#if defined(_STLPORT_VERSION)
#error "STLPort is not supported."
#endif
diff --git a/third_party/abseil/absl/base/spinlock_test_common.cc b/third_party/abseil/absl/base/spinlock_test_common.cc
index 84fc4da..dee266e 100644
--- a/third_party/abseil/absl/base/spinlock_test_common.cc
+++ b/third_party/abseil/absl/base/spinlock_test_common.cc
@@ -20,10 +20,12 @@
#include <limits>
#include <random>
#include <thread> // NOLINT(build/c++11)
+#include <type_traits>
#include <vector>
#include "gtest/gtest.h"
#include "absl/base/attributes.h"
+#include "absl/base/config.h"
#include "absl/base/internal/low_level_scheduling.h"
#include "absl/base/internal/scheduling_mode.h"
#include "absl/base/internal/spinlock.h"
@@ -36,6 +38,7 @@
constexpr int32_t kIters = 1000;
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
// This is defined outside of anonymous namespace so that it can be
@@ -55,12 +58,10 @@
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);
+ABSL_CONST_INIT static SpinLock static_cooperative_spinlock(
+ absl::kConstInit, base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL);
+ABSL_CONST_INIT static SpinLock static_noncooperative_spinlock(
+ absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
// Simple integer hash function based on the public domain lookup2 hash.
// http://burtleburtle.net/bob/c/lookup2.c
@@ -104,6 +105,10 @@
}
}
+#ifndef ABSL_HAVE_THREAD_SANITIZER
+static_assert(std::is_trivially_destructible<SpinLock>(), "");
+#endif
+
TEST(SpinLock, StackNonCooperativeDisablesScheduling) {
SpinLock spinlock(base_internal::SCHEDULE_KERNEL_ONLY);
spinlock.Lock();
@@ -190,10 +195,6 @@
EXPECT_GT(expected_max_value_decoded, before_max_value_decoded);
}
-TEST(SpinLockWithThreads, StaticSpinLock) {
- ThreadedTest(&static_spinlock);
-}
-
TEST(SpinLockWithThreads, StackSpinLock) {
SpinLock spinlock;
ThreadedTest(&spinlock);
@@ -266,4 +267,5 @@
} // namespace
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/base/thread_annotations.h b/third_party/abseil/absl/base/thread_annotations.h
index f98af9f..e23fff1 100644
--- a/third_party/abseil/absl/base/thread_annotations.h
+++ b/third_party/abseil/absl/base/thread_annotations.h
@@ -34,15 +34,11 @@
#ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_
#define ABSL_BASE_THREAD_ANNOTATIONS_H_
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
// TODO(mbonadei): Remove after the backward compatibility period.
#include "absl/base/internal/thread_annotations.h" // IWYU pragma: export
-#if defined(__clang__)
-#define ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(x) __attribute__((x))
-#else
-#define ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(x) // no-op
-#endif
-
// ABSL_GUARDED_BY()
//
// Documents if a shared field or global variable needs to be protected by a
@@ -60,8 +56,11 @@
// int p1_ ABSL_GUARDED_BY(mu_);
// ...
// };
-#define ABSL_GUARDED_BY(x) \
- ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(guarded_by(x))
+#if ABSL_HAVE_ATTRIBUTE(guarded_by)
+#define ABSL_GUARDED_BY(x) __attribute__((guarded_by(x)))
+#else
+#define ABSL_GUARDED_BY(x)
+#endif
// ABSL_PT_GUARDED_BY()
//
@@ -83,8 +82,11 @@
// // `q_`, guarded by `mu1_`, points to a shared memory location that is
// // guarded by `mu2_`:
// int *q_ ABSL_GUARDED_BY(mu1_) ABSL_PT_GUARDED_BY(mu2_);
-#define ABSL_PT_GUARDED_BY(x) \
- ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(pt_guarded_by(x))
+#if ABSL_HAVE_ATTRIBUTE(pt_guarded_by)
+#define ABSL_PT_GUARDED_BY(x) __attribute__((pt_guarded_by(x)))
+#else
+#define ABSL_PT_GUARDED_BY(x)
+#endif
// ABSL_ACQUIRED_AFTER() / ABSL_ACQUIRED_BEFORE()
//
@@ -101,11 +103,17 @@
//
// Mutex m1_;
// Mutex m2_ ABSL_ACQUIRED_AFTER(m1_);
-#define ABSL_ACQUIRED_AFTER(...) \
- ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(acquired_after(__VA_ARGS__))
+#if ABSL_HAVE_ATTRIBUTE(acquired_after)
+#define ABSL_ACQUIRED_AFTER(...) __attribute__((acquired_after(__VA_ARGS__)))
+#else
+#define ABSL_ACQUIRED_AFTER(...)
+#endif
-#define ABSL_ACQUIRED_BEFORE(...) \
- ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(acquired_before(__VA_ARGS__))
+#if ABSL_HAVE_ATTRIBUTE(acquired_before)
+#define ABSL_ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__)))
+#else
+#define ABSL_ACQUIRED_BEFORE(...)
+#endif
// ABSL_EXCLUSIVE_LOCKS_REQUIRED() / ABSL_SHARED_LOCKS_REQUIRED()
//
@@ -130,33 +138,50 @@
//
// void foo() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
// void bar() const ABSL_SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
-#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) \
- ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
- exclusive_locks_required(__VA_ARGS__))
+#if ABSL_HAVE_ATTRIBUTE(exclusive_locks_required)
+#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) \
+ __attribute__((exclusive_locks_required(__VA_ARGS__)))
+#else
+#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...)
+#endif
+#if ABSL_HAVE_ATTRIBUTE(shared_locks_required)
#define ABSL_SHARED_LOCKS_REQUIRED(...) \
- ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(shared_locks_required(__VA_ARGS__))
+ __attribute__((shared_locks_required(__VA_ARGS__)))
+#else
+#define ABSL_SHARED_LOCKS_REQUIRED(...)
+#endif
// ABSL_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 ABSL_LOCKS_EXCLUDED(...) \
- ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(locks_excluded(__VA_ARGS__))
+#if ABSL_HAVE_ATTRIBUTE(locks_excluded)
+#define ABSL_LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__)))
+#else
+#define ABSL_LOCKS_EXCLUDED(...)
+#endif
// ABSL_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 ABSL_LOCK_RETURNED.
-#define ABSL_LOCK_RETURNED(x) \
- ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(lock_returned(x))
+#if ABSL_HAVE_ATTRIBUTE(lock_returned)
+#define ABSL_LOCK_RETURNED(x) __attribute__((lock_returned(x)))
+#else
+#define ABSL_LOCK_RETURNED(x)
+#endif
// ABSL_LOCKABLE
//
// Documents if a class/type is a lockable type (such as the `Mutex` class).
-#define ABSL_LOCKABLE ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(lockable)
+#if ABSL_HAVE_ATTRIBUTE(lockable)
+#define ABSL_LOCKABLE __attribute__((lockable))
+#else
+#define ABSL_LOCKABLE
+#endif
// ABSL_SCOPED_LOCKABLE
//
@@ -165,30 +190,43 @@
// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no
// arguments; the analysis will assume that the destructor unlocks whatever the
// constructor locked.
-#define ABSL_SCOPED_LOCKABLE \
- ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(scoped_lockable)
+#if ABSL_HAVE_ATTRIBUTE(scoped_lockable)
+#define ABSL_SCOPED_LOCKABLE __attribute__((scoped_lockable))
+#else
+#define ABSL_SCOPED_LOCKABLE
+#endif
// ABSL_EXCLUSIVE_LOCK_FUNCTION()
//
// Documents functions that acquire a lock in the body of a function, and do
// not release it.
-#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) \
- ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
- exclusive_lock_function(__VA_ARGS__))
+#if ABSL_HAVE_ATTRIBUTE(exclusive_lock_function)
+#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) \
+ __attribute__((exclusive_lock_function(__VA_ARGS__)))
+#else
+#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...)
+#endif
// ABSL_SHARED_LOCK_FUNCTION()
//
// Documents functions that acquire a shared (reader) lock in the body of a
// function, and do not release it.
+#if ABSL_HAVE_ATTRIBUTE(shared_lock_function)
#define ABSL_SHARED_LOCK_FUNCTION(...) \
- ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(shared_lock_function(__VA_ARGS__))
+ __attribute__((shared_lock_function(__VA_ARGS__)))
+#else
+#define ABSL_SHARED_LOCK_FUNCTION(...)
+#endif
// ABSL_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 ABSL_UNLOCK_FUNCTION(...) \
- ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(unlock_function(__VA_ARGS__))
+#if ABSL_HAVE_ATTRIBUTE(unlock_function)
+#define ABSL_UNLOCK_FUNCTION(...) __attribute__((unlock_function(__VA_ARGS__)))
+#else
+#define ABSL_UNLOCK_FUNCTION(...)
+#endif
// ABSL_EXCLUSIVE_TRYLOCK_FUNCTION() / ABSL_SHARED_TRYLOCK_FUNCTION()
//
@@ -198,31 +236,49 @@
// 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`.
+#if ABSL_HAVE_ATTRIBUTE(exclusive_trylock_function)
#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...) \
- ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
- exclusive_trylock_function(__VA_ARGS__))
+ __attribute__((exclusive_trylock_function(__VA_ARGS__)))
+#else
+#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...)
+#endif
-#define ABSL_SHARED_TRYLOCK_FUNCTION(...) \
- ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
- shared_trylock_function(__VA_ARGS__))
+#if ABSL_HAVE_ATTRIBUTE(shared_trylock_function)
+#define ABSL_SHARED_TRYLOCK_FUNCTION(...) \
+ __attribute__((shared_trylock_function(__VA_ARGS__)))
+#else
+#define ABSL_SHARED_TRYLOCK_FUNCTION(...)
+#endif
// ABSL_ASSERT_EXCLUSIVE_LOCK() / ABSL_ASSERT_SHARED_LOCK()
//
// Documents functions that dynamically check to see if a lock is held, and fail
// if it is not held.
+#if ABSL_HAVE_ATTRIBUTE(assert_exclusive_lock)
#define ABSL_ASSERT_EXCLUSIVE_LOCK(...) \
- ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(assert_exclusive_lock(__VA_ARGS__))
+ __attribute__((assert_exclusive_lock(__VA_ARGS__)))
+#else
+#define ABSL_ASSERT_EXCLUSIVE_LOCK(...)
+#endif
+#if ABSL_HAVE_ATTRIBUTE(assert_shared_lock)
#define ABSL_ASSERT_SHARED_LOCK(...) \
- ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(assert_shared_lock(__VA_ARGS__))
+ __attribute__((assert_shared_lock(__VA_ARGS__)))
+#else
+#define ABSL_ASSERT_SHARED_LOCK(...)
+#endif
// ABSL_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.
+#if ABSL_HAVE_ATTRIBUTE(no_thread_safety_analysis)
#define ABSL_NO_THREAD_SAFETY_ANALYSIS \
- ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(no_thread_safety_analysis)
+ __attribute__((no_thread_safety_analysis))
+#else
+#define ABSL_NO_THREAD_SAFETY_ANALYSIS
+#endif
//------------------------------------------------------------------------------
// Tool-Supplied Annotations
@@ -256,6 +312,7 @@
#define ABSL_TS_UNCHECKED_READ(x) absl::base_internal::ts_unchecked_read(x)
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace base_internal {
// Takes a reference to a guarded data member, and returns an unguarded
@@ -272,6 +329,7 @@
}
} // namespace base_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_THREAD_ANNOTATIONS_H_
diff --git a/third_party/abseil/absl/compiler_config_setting.bzl b/third_party/abseil/absl/compiler_config_setting.bzl
deleted file mode 100644
index 6696229..0000000
--- a/third_party/abseil/absl/compiler_config_setting.bzl
+++ /dev/null
@@ -1,38 +0,0 @@
-#
-# Copyright 2018 The Abseil Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Creates config_setting that allows selecting based on 'compiler' value."""
-
-def create_llvm_config(name, visibility):
- # The "do_not_use_tools_cpp_compiler_present" attribute exists to
- # distinguish between older versions of Bazel that do not support
- # "@bazel_tools//tools/cpp:compiler" flag_value, and newer ones that do.
- # In the future, the only way to select on the compiler will be through
- # flag_values{"@bazel_tools//tools/cpp:compiler"} and the else branch can
- # be removed.
- if hasattr(cc_common, "do_not_use_tools_cpp_compiler_present"):
- native.config_setting(
- name = name,
- flag_values = {
- "@bazel_tools//tools/cpp:compiler": "llvm",
- },
- visibility = visibility,
- )
- else:
- native.config_setting(
- name = name,
- values = {"compiler": "llvm"},
- visibility = visibility,
- )
diff --git a/third_party/abseil/absl/container/BUILD.bazel b/third_party/abseil/absl/container/BUILD.bazel
index e2ceeee..f22fdc6 100644
--- a/third_party/abseil/absl/container/BUILD.bazel
+++ b/third_party/abseil/absl/container/BUILD.bazel
@@ -14,7 +14,7 @@
# limitations under the License.
#
-#load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
load(
"//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
@@ -24,7 +24,7 @@
package(default_visibility = ["//visibility:public"])
-licenses(["notice"]) # Apache 2.0
+licenses(["notice"])
cc_library(
name = "compressed_tuple",
@@ -60,6 +60,7 @@
deps = [
":compressed_tuple",
"//absl/algorithm",
+ "//absl/base:config",
"//absl/base:core_headers",
"//absl/base:dynamic_annotations",
"//absl/base:throw_delegate",
@@ -73,7 +74,9 @@
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
+ ":counting_allocator",
":fixed_array",
+ "//absl/base:config",
"//absl/base:exception_testing",
"//absl/hash:hash_testing",
"//absl/memory",
@@ -141,6 +144,7 @@
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = ["//visibility:private"],
+ deps = ["//absl/base:config"],
)
cc_test(
@@ -152,6 +156,7 @@
":counting_allocator",
":inlined_vector",
":test_instance_tracker",
+ "//absl/base:config",
"//absl/base:core_headers",
"//absl/base:exception_testing",
"//absl/base:raw_logging_internal",
@@ -254,6 +259,7 @@
":unordered_map_lookup_test",
":unordered_map_members_test",
":unordered_map_modifiers_test",
+ "//absl/base:raw_logging_internal",
"//absl/types:any",
"@com_google_googletest//:gtest_main",
],
@@ -287,6 +293,7 @@
":unordered_set_lookup_test",
":unordered_set_members_test",
":unordered_set_modifiers_test",
+ "//absl/base:raw_logging_internal",
"//absl/memory",
"//absl/strings",
"@com_google_googletest//:gtest_main",
@@ -362,7 +369,9 @@
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
+ "//absl/base:config",
"//absl/memory",
+ "//absl/meta:type_traits",
"//absl/utility",
],
)
@@ -375,6 +384,7 @@
tags = NOTEST_TAGS_NONMOBILE,
deps = [
":container_memory",
+ ":test_instance_tracker",
"//absl/strings",
"@com_google_googletest//:gtest_main",
],
@@ -389,6 +399,7 @@
"//absl/base:config",
"//absl/hash",
"//absl/strings",
+ "//absl/strings:cord",
],
)
@@ -401,7 +412,10 @@
deps = [
":hash_function_defaults",
"//absl/hash",
+ "//absl/random",
"//absl/strings",
+ "//absl/strings:cord",
+ "//absl/strings:cord_test_helpers",
"@com_google_googletest//:gtest_main",
],
)
@@ -478,6 +492,9 @@
hdrs = ["internal/hashtable_debug_hooks.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ "//absl/base:config",
+ ],
)
cc_library(
@@ -493,6 +510,7 @@
":have_sse",
"//absl/base",
"//absl/base:core_headers",
+ "//absl/base:exponential_biased",
"//absl/debugging:stacktrace",
"//absl/memory",
"//absl/synchronization",
@@ -520,6 +538,7 @@
hdrs = ["internal/node_hash_policy.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = ["//absl/base:config"],
)
cc_test(
@@ -580,12 +599,12 @@
":hashtablez_sampler",
":have_sse",
":layout",
- "//absl/base:bits",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:endian",
"//absl/memory",
"//absl/meta:type_traits",
+ "//absl/numeric:bits",
"//absl/utility",
],
)
@@ -603,6 +622,7 @@
":hashtable_debug",
":raw_hash_set",
"//absl/base",
+ "//absl/base:config",
"//absl/base:core_headers",
"//absl/base:raw_logging_internal",
"//absl/strings",
@@ -610,6 +630,45 @@
],
)
+cc_binary(
+ name = "raw_hash_set_benchmark",
+ testonly = 1,
+ srcs = ["internal/raw_hash_set_benchmark.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ tags = ["benchmark"],
+ visibility = ["//visibility:private"],
+ deps = [
+ ":hash_function_defaults",
+ ":raw_hash_set",
+ "//absl/base:raw_logging_internal",
+ "//absl/strings:str_format",
+ "@com_github_google_benchmark//:benchmark_main",
+ ],
+)
+
+cc_binary(
+ name = "raw_hash_set_probe_benchmark",
+ testonly = 1,
+ srcs = ["internal/raw_hash_set_probe_benchmark.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = select({
+ "//conditions:default": [],
+ }) + ABSL_DEFAULT_LINKOPTS,
+ tags = ["benchmark"],
+ visibility = ["//visibility:private"],
+ deps = [
+ ":flat_hash_map",
+ ":hash_function_defaults",
+ ":hashtable_debug",
+ ":raw_hash_set",
+ "//absl/random",
+ "//absl/random:distributions",
+ "//absl/strings",
+ "//absl/strings:str_format",
+ ],
+)
+
cc_test(
name = "raw_hash_set_allocator_test",
size = "small",
@@ -630,6 +689,7 @@
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
+ "//absl/base:config",
"//absl/base:core_headers",
"//absl/meta:type_traits",
"//absl/strings",
@@ -648,6 +708,7 @@
visibility = ["//visibility:private"],
deps = [
":layout",
+ "//absl/base:config",
"//absl/base:core_headers",
"//absl/base:raw_logging_internal",
"//absl/types:span",
@@ -655,12 +716,31 @@
],
)
+cc_binary(
+ name = "layout_benchmark",
+ testonly = 1,
+ srcs = ["internal/layout_benchmark.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ tags = ["benchmark"],
+ visibility = ["//visibility:private"],
+ deps = [
+ ":layout",
+ "//absl/base:core_headers",
+ "//absl/base:raw_logging_internal",
+ "@com_github_google_benchmark//:benchmark_main",
+ ],
+)
+
cc_library(
name = "tracked",
testonly = 1,
hdrs = ["internal/tracked.h"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ "//absl/base:config",
+ ],
)
cc_library(
@@ -819,6 +899,7 @@
"//absl/memory",
"//absl/meta:type_traits",
"//absl/strings",
+ "//absl/strings:cord",
"//absl/types:compare",
"//absl/utility",
],
@@ -835,6 +916,7 @@
":btree",
":flat_hash_set",
"//absl/strings",
+ "//absl/strings:cord",
"//absl/time",
],
)
@@ -865,3 +947,30 @@
"@com_google_googletest//:gtest_main",
],
)
+
+cc_binary(
+ name = "btree_benchmark",
+ testonly = 1,
+ srcs = [
+ "btree_benchmark.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ tags = ["benchmark"],
+ visibility = ["//visibility:private"],
+ deps = [
+ ":btree",
+ ":btree_test_common",
+ ":flat_hash_map",
+ ":flat_hash_set",
+ ":hashtable_debug",
+ "//absl/base:raw_logging_internal",
+ "//absl/flags:flag",
+ "//absl/hash",
+ "//absl/memory",
+ "//absl/strings:cord",
+ "//absl/strings:str_format",
+ "//absl/time",
+ "@com_github_google_benchmark//:benchmark_main",
+ ],
+)
diff --git a/third_party/abseil/absl/container/CMakeLists.txt b/third_party/abseil/absl/container/CMakeLists.txt
index 933c7a8..eb202c4 100644
--- a/third_party/abseil/absl/container/CMakeLists.txt
+++ b/third_party/abseil/absl/container/CMakeLists.txt
@@ -40,6 +40,7 @@
absl::compare
absl::compressed_tuple
absl::container_memory
+ absl::cord
absl::core_headers
absl::layout
absl::memory
@@ -60,6 +61,7 @@
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::btree
+ absl::cord
absl::flat_hash_set
absl::strings
absl::time
@@ -129,6 +131,7 @@
DEPS
absl::compressed_tuple
absl::algorithm
+ absl::config
absl::core_headers
absl::dynamic_annotations
absl::throw_delegate
@@ -145,6 +148,8 @@
${ABSL_TEST_COPTS}
DEPS
absl::fixed_array
+ absl::counting_allocator
+ absl::config
absl::exception_testing
absl::hash_testing
absl::memory
@@ -204,6 +209,8 @@
"internal/counting_allocator.h"
COPTS
${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::config
)
absl_cc_test(
@@ -217,6 +224,7 @@
absl::counting_allocator
absl::inlined_vector
absl::test_instance_tracker
+ absl::config
absl::core_headers
absl::exception_testing
absl::hash_testing
@@ -297,6 +305,7 @@
absl::unordered_map_members_test
absl::unordered_map_modifiers_test
absl::any
+ absl::raw_logging_internal
gmock_main
)
@@ -333,6 +342,7 @@
absl::unordered_set_members_test
absl::unordered_set_modifiers_test
absl::memory
+ absl::raw_logging_internal
absl::strings
gmock_main
)
@@ -414,7 +424,9 @@
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
+ absl::config
absl::memory
+ absl::type_traits
absl::utility
PUBLIC
)
@@ -429,6 +441,7 @@
DEPS
absl::container_memory
absl::strings
+ absl::test_instance_tracker
gmock_main
)
@@ -441,6 +454,7 @@
${ABSL_DEFAULT_COPTS}
DEPS
absl::config
+ absl::cord
absl::hash
absl::strings
PUBLIC
@@ -454,8 +468,11 @@
COPTS
${ABSL_TEST_COPTS}
DEPS
+ absl::cord
+ absl::cord_test_helpers
absl::hash_function_defaults
absl::hash
+ absl::random_random
absl::strings
gmock_main
)
@@ -538,6 +555,7 @@
${ABSL_DEFAULT_COPTS}
DEPS
absl::base
+ absl::exponential_biased
absl::have_sse
absl::synchronization
)
@@ -573,6 +591,8 @@
"internal/hashtable_debug_hooks.h"
COPTS
${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::config
PUBLIC
)
@@ -592,6 +612,8 @@
"internal/node_hash_policy.h"
COPTS
${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::config
PUBLIC
)
@@ -626,7 +648,7 @@
NAME
container_common
HDRS
- "internal/commom.h"
+ "internal/common.h"
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
@@ -676,6 +698,7 @@
absl::hashtable_debug
absl::raw_hash_set
absl::base
+ absl::config
absl::core_headers
absl::raw_logging_internal
absl::strings
@@ -704,6 +727,7 @@
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
+ absl::config
absl::core_headers
absl::meta
absl::strings
@@ -721,6 +745,7 @@
${ABSL_TEST_COPTS}
DEPS
absl::layout
+ absl::config
absl::core_headers
absl::raw_logging_internal
absl::span
@@ -734,6 +759,8 @@
"internal/tracked.h"
COPTS
${ABSL_TEST_COPTS}
+ DEPS
+ absl::config
TESTONLY
)
diff --git a/third_party/abseil/absl/container/btree_benchmark.cc b/third_party/abseil/absl/container/btree_benchmark.cc
new file mode 100644
index 0000000..4679867
--- /dev/null
+++ b/third_party/abseil/absl/container/btree_benchmark.cc
@@ -0,0 +1,735 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stdint.h>
+
+#include <algorithm>
+#include <functional>
+#include <map>
+#include <numeric>
+#include <random>
+#include <set>
+#include <string>
+#include <type_traits>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/container/btree_map.h"
+#include "absl/container/btree_set.h"
+#include "absl/container/btree_test.h"
+#include "absl/container/flat_hash_map.h"
+#include "absl/container/flat_hash_set.h"
+#include "absl/container/internal/hashtable_debug.h"
+#include "absl/flags/flag.h"
+#include "absl/hash/hash.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/cord.h"
+#include "absl/strings/str_format.h"
+#include "absl/time/time.h"
+#include "benchmark/benchmark.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+namespace {
+
+constexpr size_t kBenchmarkValues = 1 << 20;
+
+// How many times we add and remove sub-batches in one batch of *AddRem
+// benchmarks.
+constexpr size_t kAddRemBatchSize = 1 << 2;
+
+// Generates n values in the range [0, 4 * n].
+template <typename V>
+std::vector<V> GenerateValues(int n) {
+ constexpr int kSeed = 23;
+ return GenerateValuesWithSeed<V>(n, 4 * n, kSeed);
+}
+
+// Benchmark insertion of values into a container.
+template <typename T>
+void BM_InsertImpl(benchmark::State& state, bool sorted) {
+ using V = typename remove_pair_const<typename T::value_type>::type;
+ typename KeyOfValue<typename T::key_type, V>::type key_of_value;
+
+ std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
+ if (sorted) {
+ std::sort(values.begin(), values.end());
+ }
+ T container(values.begin(), values.end());
+
+ // Remove and re-insert 10% of the keys per batch.
+ const int batch_size = (kBenchmarkValues + 9) / 10;
+ while (state.KeepRunningBatch(batch_size)) {
+ state.PauseTiming();
+ const auto i = static_cast<int>(state.iterations());
+
+ for (int j = i; j < i + batch_size; j++) {
+ int x = j % kBenchmarkValues;
+ container.erase(key_of_value(values[x]));
+ }
+
+ state.ResumeTiming();
+
+ for (int j = i; j < i + batch_size; j++) {
+ int x = j % kBenchmarkValues;
+ container.insert(values[x]);
+ }
+ }
+}
+
+template <typename T>
+void BM_Insert(benchmark::State& state) {
+ BM_InsertImpl<T>(state, false);
+}
+
+template <typename T>
+void BM_InsertSorted(benchmark::State& state) {
+ BM_InsertImpl<T>(state, true);
+}
+
+// container::insert sometimes returns a pair<iterator, bool> and sometimes
+// returns an iterator (for multi- containers).
+template <typename Iter>
+Iter GetIterFromInsert(const std::pair<Iter, bool>& pair) {
+ return pair.first;
+}
+template <typename Iter>
+Iter GetIterFromInsert(const Iter iter) {
+ return iter;
+}
+
+// Benchmark insertion of values into a container at the end.
+template <typename T>
+void BM_InsertEnd(benchmark::State& state) {
+ using V = typename remove_pair_const<typename T::value_type>::type;
+ typename KeyOfValue<typename T::key_type, V>::type key_of_value;
+
+ T container;
+ const int kSize = 10000;
+ for (int i = 0; i < kSize; ++i) {
+ container.insert(Generator<V>(kSize)(i));
+ }
+ V v = Generator<V>(kSize)(kSize - 1);
+ typename T::key_type k = key_of_value(v);
+
+ auto it = container.find(k);
+ while (state.KeepRunning()) {
+ // Repeatedly removing then adding v.
+ container.erase(it);
+ it = GetIterFromInsert(container.insert(v));
+ }
+}
+
+// Benchmark inserting the first few elements in a container. In b-tree, this is
+// when the root node grows.
+template <typename T>
+void BM_InsertSmall(benchmark::State& state) {
+ using V = typename remove_pair_const<typename T::value_type>::type;
+
+ const int kSize = 8;
+ std::vector<V> values = GenerateValues<V>(kSize);
+ T container;
+
+ while (state.KeepRunningBatch(kSize)) {
+ for (int i = 0; i < kSize; ++i) {
+ benchmark::DoNotOptimize(container.insert(values[i]));
+ }
+ state.PauseTiming();
+ // Do not measure the time it takes to clear the container.
+ container.clear();
+ state.ResumeTiming();
+ }
+}
+
+template <typename T>
+void BM_LookupImpl(benchmark::State& state, bool sorted) {
+ using V = typename remove_pair_const<typename T::value_type>::type;
+ typename KeyOfValue<typename T::key_type, V>::type key_of_value;
+
+ std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
+ if (sorted) {
+ std::sort(values.begin(), values.end());
+ }
+ T container(values.begin(), values.end());
+
+ while (state.KeepRunning()) {
+ int idx = state.iterations() % kBenchmarkValues;
+ benchmark::DoNotOptimize(container.find(key_of_value(values[idx])));
+ }
+}
+
+// Benchmark lookup of values in a container.
+template <typename T>
+void BM_Lookup(benchmark::State& state) {
+ BM_LookupImpl<T>(state, false);
+}
+
+// Benchmark lookup of values in a full container, meaning that values
+// are inserted in-order to take advantage of biased insertion, which
+// yields a full tree.
+template <typename T>
+void BM_FullLookup(benchmark::State& state) {
+ BM_LookupImpl<T>(state, true);
+}
+
+// Benchmark deletion of values from a container.
+template <typename T>
+void BM_Delete(benchmark::State& state) {
+ using V = typename remove_pair_const<typename T::value_type>::type;
+ typename KeyOfValue<typename T::key_type, V>::type key_of_value;
+ std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
+ T container(values.begin(), values.end());
+
+ // Remove and re-insert 10% of the keys per batch.
+ const int batch_size = (kBenchmarkValues + 9) / 10;
+ while (state.KeepRunningBatch(batch_size)) {
+ const int i = state.iterations();
+
+ for (int j = i; j < i + batch_size; j++) {
+ int x = j % kBenchmarkValues;
+ container.erase(key_of_value(values[x]));
+ }
+
+ state.PauseTiming();
+ for (int j = i; j < i + batch_size; j++) {
+ int x = j % kBenchmarkValues;
+ container.insert(values[x]);
+ }
+ state.ResumeTiming();
+ }
+}
+
+// Benchmark deletion of multiple values from a container.
+template <typename T>
+void BM_DeleteRange(benchmark::State& state) {
+ using V = typename remove_pair_const<typename T::value_type>::type;
+ typename KeyOfValue<typename T::key_type, V>::type key_of_value;
+ std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
+ T container(values.begin(), values.end());
+
+ // Remove and re-insert 10% of the keys per batch.
+ const int batch_size = (kBenchmarkValues + 9) / 10;
+ while (state.KeepRunningBatch(batch_size)) {
+ const int i = state.iterations();
+
+ const int start_index = i % kBenchmarkValues;
+
+ state.PauseTiming();
+ {
+ std::vector<V> removed;
+ removed.reserve(batch_size);
+ auto itr = container.find(key_of_value(values[start_index]));
+ auto start = itr;
+ for (int j = 0; j < batch_size; j++) {
+ if (itr == container.end()) {
+ state.ResumeTiming();
+ container.erase(start, itr);
+ state.PauseTiming();
+ itr = container.begin();
+ start = itr;
+ }
+ removed.push_back(*itr++);
+ }
+
+ state.ResumeTiming();
+ container.erase(start, itr);
+ state.PauseTiming();
+
+ container.insert(removed.begin(), removed.end());
+ }
+ state.ResumeTiming();
+ }
+}
+
+// Benchmark steady-state insert (into first half of range) and remove (from
+// second half of range), treating the container approximately like a queue with
+// log-time access for all elements. This benchmark does not test the case where
+// insertion and removal happen in the same region of the tree. This benchmark
+// counts two value constructors.
+template <typename T>
+void BM_QueueAddRem(benchmark::State& state) {
+ using V = typename remove_pair_const<typename T::value_type>::type;
+ typename KeyOfValue<typename T::key_type, V>::type key_of_value;
+
+ ABSL_RAW_CHECK(kBenchmarkValues % 2 == 0, "for performance");
+
+ T container;
+
+ const size_t half = kBenchmarkValues / 2;
+ std::vector<int> remove_keys(half);
+ std::vector<int> add_keys(half);
+
+ // We want to do the exact same work repeatedly, and the benchmark can end
+ // after a different number of iterations depending on the speed of the
+ // individual run so we use a large batch size here and ensure that we do
+ // deterministic work every batch.
+ while (state.KeepRunningBatch(half * kAddRemBatchSize)) {
+ state.PauseTiming();
+
+ container.clear();
+
+ for (size_t i = 0; i < half; ++i) {
+ remove_keys[i] = i;
+ add_keys[i] = i;
+ }
+ constexpr int kSeed = 5;
+ std::mt19937_64 rand(kSeed);
+ std::shuffle(remove_keys.begin(), remove_keys.end(), rand);
+ std::shuffle(add_keys.begin(), add_keys.end(), rand);
+
+ // Note needs lazy generation of values.
+ Generator<V> g(kBenchmarkValues * kAddRemBatchSize);
+
+ for (size_t i = 0; i < half; ++i) {
+ container.insert(g(add_keys[i]));
+ container.insert(g(half + remove_keys[i]));
+ }
+
+ // There are three parts each of size "half":
+ // 1 is being deleted from [offset - half, offset)
+ // 2 is standing [offset, offset + half)
+ // 3 is being inserted into [offset + half, offset + 2 * half)
+ size_t offset = 0;
+
+ for (size_t i = 0; i < kAddRemBatchSize; ++i) {
+ std::shuffle(remove_keys.begin(), remove_keys.end(), rand);
+ std::shuffle(add_keys.begin(), add_keys.end(), rand);
+ offset += half;
+
+ state.ResumeTiming();
+ for (size_t idx = 0; idx < half; ++idx) {
+ container.erase(key_of_value(g(offset - half + remove_keys[idx])));
+ container.insert(g(offset + half + add_keys[idx]));
+ }
+ state.PauseTiming();
+ }
+ state.ResumeTiming();
+ }
+}
+
+// Mixed insertion and deletion in the same range using pre-constructed values.
+template <typename T>
+void BM_MixedAddRem(benchmark::State& state) {
+ using V = typename remove_pair_const<typename T::value_type>::type;
+ typename KeyOfValue<typename T::key_type, V>::type key_of_value;
+
+ ABSL_RAW_CHECK(kBenchmarkValues % 2 == 0, "for performance");
+
+ T container;
+
+ // Create two random shuffles
+ std::vector<int> remove_keys(kBenchmarkValues);
+ std::vector<int> add_keys(kBenchmarkValues);
+
+ // We want to do the exact same work repeatedly, and the benchmark can end
+ // after a different number of iterations depending on the speed of the
+ // individual run so we use a large batch size here and ensure that we do
+ // deterministic work every batch.
+ while (state.KeepRunningBatch(kBenchmarkValues * kAddRemBatchSize)) {
+ state.PauseTiming();
+
+ container.clear();
+
+ constexpr int kSeed = 7;
+ std::mt19937_64 rand(kSeed);
+
+ std::vector<V> values = GenerateValues<V>(kBenchmarkValues * 2);
+
+ // Insert the first half of the values (already in random order)
+ container.insert(values.begin(), values.begin() + kBenchmarkValues);
+
+ // Insert the first half of the values (already in random order)
+ for (size_t i = 0; i < kBenchmarkValues; ++i) {
+ // remove_keys and add_keys will be swapped before each round,
+ // therefore fill add_keys here w/ the keys being inserted, so
+ // they'll be the first to be removed.
+ remove_keys[i] = i + kBenchmarkValues;
+ add_keys[i] = i;
+ }
+
+ for (size_t i = 0; i < kAddRemBatchSize; ++i) {
+ remove_keys.swap(add_keys);
+ std::shuffle(remove_keys.begin(), remove_keys.end(), rand);
+ std::shuffle(add_keys.begin(), add_keys.end(), rand);
+
+ state.ResumeTiming();
+ for (size_t idx = 0; idx < kBenchmarkValues; ++idx) {
+ container.erase(key_of_value(values[remove_keys[idx]]));
+ container.insert(values[add_keys[idx]]);
+ }
+ state.PauseTiming();
+ }
+ state.ResumeTiming();
+ }
+}
+
+// Insertion at end, removal from the beginning. This benchmark
+// counts two value constructors.
+// TODO(ezb): we could add a GenerateNext version of generator that could reduce
+// noise for string-like types.
+template <typename T>
+void BM_Fifo(benchmark::State& state) {
+ using V = typename remove_pair_const<typename T::value_type>::type;
+
+ T container;
+ // Need lazy generation of values as state.max_iterations is large.
+ Generator<V> g(kBenchmarkValues + state.max_iterations);
+
+ for (int i = 0; i < kBenchmarkValues; i++) {
+ container.insert(g(i));
+ }
+
+ while (state.KeepRunning()) {
+ container.erase(container.begin());
+ container.insert(container.end(), g(state.iterations() + kBenchmarkValues));
+ }
+}
+
+// Iteration (forward) through the tree
+template <typename T>
+void BM_FwdIter(benchmark::State& state) {
+ using V = typename remove_pair_const<typename T::value_type>::type;
+ using R = typename T::value_type const*;
+
+ std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
+ T container(values.begin(), values.end());
+
+ auto iter = container.end();
+
+ R r = nullptr;
+
+ while (state.KeepRunning()) {
+ if (iter == container.end()) iter = container.begin();
+ r = &(*iter);
+ ++iter;
+ }
+
+ benchmark::DoNotOptimize(r);
+}
+
+// Benchmark random range-construction of a container.
+template <typename T>
+void BM_RangeConstructionImpl(benchmark::State& state, bool sorted) {
+ using V = typename remove_pair_const<typename T::value_type>::type;
+
+ std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
+ if (sorted) {
+ std::sort(values.begin(), values.end());
+ }
+ {
+ T container(values.begin(), values.end());
+ }
+
+ while (state.KeepRunning()) {
+ T container(values.begin(), values.end());
+ benchmark::DoNotOptimize(container);
+ }
+}
+
+template <typename T>
+void BM_InsertRangeRandom(benchmark::State& state) {
+ BM_RangeConstructionImpl<T>(state, false);
+}
+
+template <typename T>
+void BM_InsertRangeSorted(benchmark::State& state) {
+ BM_RangeConstructionImpl<T>(state, true);
+}
+
+#define STL_ORDERED_TYPES(value) \
+ using stl_set_##value = std::set<value>; \
+ using stl_map_##value = std::map<value, intptr_t>; \
+ using stl_multiset_##value = std::multiset<value>; \
+ using stl_multimap_##value = std::multimap<value, intptr_t>
+
+using StdString = std::string;
+STL_ORDERED_TYPES(int32_t);
+STL_ORDERED_TYPES(int64_t);
+STL_ORDERED_TYPES(StdString);
+STL_ORDERED_TYPES(Cord);
+STL_ORDERED_TYPES(Time);
+
+#define STL_UNORDERED_TYPES(value) \
+ using stl_unordered_set_##value = std::unordered_set<value>; \
+ using stl_unordered_map_##value = std::unordered_map<value, intptr_t>; \
+ using flat_hash_set_##value = flat_hash_set<value>; \
+ using flat_hash_map_##value = flat_hash_map<value, intptr_t>; \
+ using stl_unordered_multiset_##value = std::unordered_multiset<value>; \
+ using stl_unordered_multimap_##value = \
+ std::unordered_multimap<value, intptr_t>
+
+#define STL_UNORDERED_TYPES_CUSTOM_HASH(value, hash) \
+ using stl_unordered_set_##value = std::unordered_set<value, hash>; \
+ using stl_unordered_map_##value = std::unordered_map<value, intptr_t, hash>; \
+ using flat_hash_set_##value = flat_hash_set<value, hash>; \
+ using flat_hash_map_##value = flat_hash_map<value, intptr_t, hash>; \
+ using stl_unordered_multiset_##value = std::unordered_multiset<value, hash>; \
+ using stl_unordered_multimap_##value = \
+ std::unordered_multimap<value, intptr_t, hash>
+
+STL_UNORDERED_TYPES_CUSTOM_HASH(Cord, absl::Hash<absl::Cord>);
+
+STL_UNORDERED_TYPES(int32_t);
+STL_UNORDERED_TYPES(int64_t);
+STL_UNORDERED_TYPES(StdString);
+STL_UNORDERED_TYPES_CUSTOM_HASH(Time, absl::Hash<absl::Time>);
+
+#define BTREE_TYPES(value) \
+ using btree_256_set_##value = \
+ btree_set<value, std::less<value>, std::allocator<value>>; \
+ using btree_256_map_##value = \
+ btree_map<value, intptr_t, std::less<value>, \
+ std::allocator<std::pair<const value, intptr_t>>>; \
+ using btree_256_multiset_##value = \
+ btree_multiset<value, std::less<value>, std::allocator<value>>; \
+ using btree_256_multimap_##value = \
+ btree_multimap<value, intptr_t, std::less<value>, \
+ std::allocator<std::pair<const value, intptr_t>>>
+
+BTREE_TYPES(int32_t);
+BTREE_TYPES(int64_t);
+BTREE_TYPES(StdString);
+BTREE_TYPES(Cord);
+BTREE_TYPES(Time);
+
+#define MY_BENCHMARK4(type, func) \
+ void BM_##type##_##func(benchmark::State& state) { BM_##func<type>(state); } \
+ BENCHMARK(BM_##type##_##func)
+
+#define MY_BENCHMARK3(type) \
+ MY_BENCHMARK4(type, Insert); \
+ MY_BENCHMARK4(type, InsertSorted); \
+ MY_BENCHMARK4(type, InsertEnd); \
+ MY_BENCHMARK4(type, InsertSmall); \
+ MY_BENCHMARK4(type, Lookup); \
+ MY_BENCHMARK4(type, FullLookup); \
+ MY_BENCHMARK4(type, Delete); \
+ MY_BENCHMARK4(type, DeleteRange); \
+ MY_BENCHMARK4(type, QueueAddRem); \
+ MY_BENCHMARK4(type, MixedAddRem); \
+ MY_BENCHMARK4(type, Fifo); \
+ MY_BENCHMARK4(type, FwdIter); \
+ MY_BENCHMARK4(type, InsertRangeRandom); \
+ MY_BENCHMARK4(type, InsertRangeSorted)
+
+#define MY_BENCHMARK2_SUPPORTS_MULTI_ONLY(type) \
+ MY_BENCHMARK3(stl_##type); \
+ MY_BENCHMARK3(stl_unordered_##type); \
+ MY_BENCHMARK3(btree_256_##type)
+
+#define MY_BENCHMARK2(type) \
+ MY_BENCHMARK2_SUPPORTS_MULTI_ONLY(type); \
+ MY_BENCHMARK3(flat_hash_##type)
+
+// Define MULTI_TESTING to see benchmarks for multi-containers also.
+//
+// You can use --copt=-DMULTI_TESTING.
+#ifdef MULTI_TESTING
+#define MY_BENCHMARK(type) \
+ MY_BENCHMARK2(set_##type); \
+ MY_BENCHMARK2(map_##type); \
+ MY_BENCHMARK2_SUPPORTS_MULTI_ONLY(multiset_##type); \
+ MY_BENCHMARK2_SUPPORTS_MULTI_ONLY(multimap_##type)
+#else
+#define MY_BENCHMARK(type) \
+ MY_BENCHMARK2(set_##type); \
+ MY_BENCHMARK2(map_##type)
+#endif
+
+MY_BENCHMARK(int32_t);
+MY_BENCHMARK(int64_t);
+MY_BENCHMARK(StdString);
+MY_BENCHMARK(Cord);
+MY_BENCHMARK(Time);
+
+// Define a type whose size and cost of moving are independently customizable.
+// When sizeof(value_type) increases, we expect btree to no longer have as much
+// cache-locality advantage over STL. When cost of moving increases, we expect
+// btree to actually do more work than STL because it has to move values around
+// and STL doesn't have to.
+template <int Size, int Copies>
+struct BigType {
+ BigType() : BigType(0) {}
+ explicit BigType(int x) { std::iota(values.begin(), values.end(), x); }
+
+ void Copy(const BigType& other) {
+ for (int i = 0; i < Size && i < Copies; ++i) values[i] = other.values[i];
+ // If Copies > Size, do extra copies.
+ for (int i = Size, idx = 0; i < Copies; ++i) {
+ int64_t tmp = other.values[idx];
+ benchmark::DoNotOptimize(tmp);
+ idx = idx + 1 == Size ? 0 : idx + 1;
+ }
+ }
+
+ BigType(const BigType& other) { Copy(other); }
+ BigType& operator=(const BigType& other) {
+ Copy(other);
+ return *this;
+ }
+
+ // Compare only the first Copies elements if Copies is less than Size.
+ bool operator<(const BigType& other) const {
+ return std::lexicographical_compare(
+ values.begin(), values.begin() + std::min(Size, Copies),
+ other.values.begin(), other.values.begin() + std::min(Size, Copies));
+ }
+ bool operator==(const BigType& other) const {
+ return std::equal(values.begin(), values.begin() + std::min(Size, Copies),
+ other.values.begin());
+ }
+
+ // Support absl::Hash.
+ template <typename State>
+ friend State AbslHashValue(State h, const BigType& b) {
+ for (int i = 0; i < Size && i < Copies; ++i)
+ h = State::combine(std::move(h), b.values[i]);
+ return h;
+ }
+
+ std::array<int64_t, Size> values;
+};
+
+#define BIG_TYPE_BENCHMARKS(SIZE, COPIES) \
+ using stl_set_size##SIZE##copies##COPIES = std::set<BigType<SIZE, COPIES>>; \
+ using stl_map_size##SIZE##copies##COPIES = \
+ std::map<BigType<SIZE, COPIES>, intptr_t>; \
+ using stl_multiset_size##SIZE##copies##COPIES = \
+ std::multiset<BigType<SIZE, COPIES>>; \
+ using stl_multimap_size##SIZE##copies##COPIES = \
+ std::multimap<BigType<SIZE, COPIES>, intptr_t>; \
+ using stl_unordered_set_size##SIZE##copies##COPIES = \
+ std::unordered_set<BigType<SIZE, COPIES>, \
+ absl::Hash<BigType<SIZE, COPIES>>>; \
+ using stl_unordered_map_size##SIZE##copies##COPIES = \
+ std::unordered_map<BigType<SIZE, COPIES>, intptr_t, \
+ absl::Hash<BigType<SIZE, COPIES>>>; \
+ using flat_hash_set_size##SIZE##copies##COPIES = \
+ flat_hash_set<BigType<SIZE, COPIES>>; \
+ using flat_hash_map_size##SIZE##copies##COPIES = \
+ flat_hash_map<BigType<SIZE, COPIES>, intptr_t>; \
+ using stl_unordered_multiset_size##SIZE##copies##COPIES = \
+ std::unordered_multiset<BigType<SIZE, COPIES>, \
+ absl::Hash<BigType<SIZE, COPIES>>>; \
+ using stl_unordered_multimap_size##SIZE##copies##COPIES = \
+ std::unordered_multimap<BigType<SIZE, COPIES>, intptr_t, \
+ absl::Hash<BigType<SIZE, COPIES>>>; \
+ using btree_256_set_size##SIZE##copies##COPIES = \
+ btree_set<BigType<SIZE, COPIES>>; \
+ using btree_256_map_size##SIZE##copies##COPIES = \
+ btree_map<BigType<SIZE, COPIES>, intptr_t>; \
+ using btree_256_multiset_size##SIZE##copies##COPIES = \
+ btree_multiset<BigType<SIZE, COPIES>>; \
+ using btree_256_multimap_size##SIZE##copies##COPIES = \
+ btree_multimap<BigType<SIZE, COPIES>, intptr_t>; \
+ MY_BENCHMARK(size##SIZE##copies##COPIES)
+
+// Define BIG_TYPE_TESTING to see benchmarks for more big types.
+//
+// You can use --copt=-DBIG_TYPE_TESTING.
+#ifndef NODESIZE_TESTING
+#ifdef BIG_TYPE_TESTING
+BIG_TYPE_BENCHMARKS(1, 4);
+BIG_TYPE_BENCHMARKS(4, 1);
+BIG_TYPE_BENCHMARKS(4, 4);
+BIG_TYPE_BENCHMARKS(1, 8);
+BIG_TYPE_BENCHMARKS(8, 1);
+BIG_TYPE_BENCHMARKS(8, 8);
+BIG_TYPE_BENCHMARKS(1, 16);
+BIG_TYPE_BENCHMARKS(16, 1);
+BIG_TYPE_BENCHMARKS(16, 16);
+BIG_TYPE_BENCHMARKS(1, 32);
+BIG_TYPE_BENCHMARKS(32, 1);
+BIG_TYPE_BENCHMARKS(32, 32);
+#else
+BIG_TYPE_BENCHMARKS(32, 32);
+#endif
+#endif
+
+// Benchmark using unique_ptrs to large value types. In order to be able to use
+// the same benchmark code as the other types, use a type that holds a
+// unique_ptr and has a copy constructor.
+template <int Size>
+struct BigTypePtr {
+ BigTypePtr() : BigTypePtr(0) {}
+ explicit BigTypePtr(int x) {
+ ptr = absl::make_unique<BigType<Size, Size>>(x);
+ }
+ BigTypePtr(const BigTypePtr& other) {
+ ptr = absl::make_unique<BigType<Size, Size>>(*other.ptr);
+ }
+ BigTypePtr(BigTypePtr&& other) noexcept = default;
+ BigTypePtr& operator=(const BigTypePtr& other) {
+ ptr = absl::make_unique<BigType<Size, Size>>(*other.ptr);
+ }
+ BigTypePtr& operator=(BigTypePtr&& other) noexcept = default;
+
+ bool operator<(const BigTypePtr& other) const { return *ptr < *other.ptr; }
+ bool operator==(const BigTypePtr& other) const { return *ptr == *other.ptr; }
+
+ std::unique_ptr<BigType<Size, Size>> ptr;
+};
+
+template <int Size>
+double ContainerInfo(const btree_set<BigTypePtr<Size>>& b) {
+ const double bytes_used =
+ b.bytes_used() + b.size() * sizeof(BigType<Size, Size>);
+ const double bytes_per_value = bytes_used / b.size();
+ BtreeContainerInfoLog(b, bytes_used, bytes_per_value);
+ return bytes_per_value;
+}
+template <int Size>
+double ContainerInfo(const btree_map<int, BigTypePtr<Size>>& b) {
+ const double bytes_used =
+ b.bytes_used() + b.size() * sizeof(BigType<Size, Size>);
+ const double bytes_per_value = bytes_used / b.size();
+ BtreeContainerInfoLog(b, bytes_used, bytes_per_value);
+ return bytes_per_value;
+}
+
+#define BIG_TYPE_PTR_BENCHMARKS(SIZE) \
+ using stl_set_size##SIZE##copies##SIZE##ptr = std::set<BigType<SIZE, SIZE>>; \
+ using stl_map_size##SIZE##copies##SIZE##ptr = \
+ std::map<int, BigType<SIZE, SIZE>>; \
+ using stl_unordered_set_size##SIZE##copies##SIZE##ptr = \
+ std::unordered_set<BigType<SIZE, SIZE>, \
+ absl::Hash<BigType<SIZE, SIZE>>>; \
+ using stl_unordered_map_size##SIZE##copies##SIZE##ptr = \
+ std::unordered_map<int, BigType<SIZE, SIZE>>; \
+ using flat_hash_set_size##SIZE##copies##SIZE##ptr = \
+ flat_hash_set<BigType<SIZE, SIZE>>; \
+ using flat_hash_map_size##SIZE##copies##SIZE##ptr = \
+ flat_hash_map<int, BigTypePtr<SIZE>>; \
+ using btree_256_set_size##SIZE##copies##SIZE##ptr = \
+ btree_set<BigTypePtr<SIZE>>; \
+ using btree_256_map_size##SIZE##copies##SIZE##ptr = \
+ btree_map<int, BigTypePtr<SIZE>>; \
+ MY_BENCHMARK3(stl_set_size##SIZE##copies##SIZE##ptr); \
+ MY_BENCHMARK3(stl_unordered_set_size##SIZE##copies##SIZE##ptr); \
+ MY_BENCHMARK3(flat_hash_set_size##SIZE##copies##SIZE##ptr); \
+ MY_BENCHMARK3(btree_256_set_size##SIZE##copies##SIZE##ptr); \
+ MY_BENCHMARK3(stl_map_size##SIZE##copies##SIZE##ptr); \
+ MY_BENCHMARK3(stl_unordered_map_size##SIZE##copies##SIZE##ptr); \
+ MY_BENCHMARK3(flat_hash_map_size##SIZE##copies##SIZE##ptr); \
+ MY_BENCHMARK3(btree_256_map_size##SIZE##copies##SIZE##ptr)
+
+BIG_TYPE_PTR_BENCHMARKS(32);
+
+} // namespace
+} // namespace container_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/container/btree_map.h b/third_party/abseil/absl/container/btree_map.h
index 9f35f63..abc09b0 100644
--- a/third_party/abseil/absl/container/btree_map.h
+++ b/third_party/abseil/absl/container/btree_map.h
@@ -51,6 +51,7 @@
#include "absl/container/internal/btree_container.h" // IWYU pragma: export
namespace absl {
+ABSL_NAMESPACE_BEGIN
// absl::btree_map<>
//
@@ -184,7 +185,7 @@
// template <typename K> size_type erase(const K& key):
//
// Erases the element with the matching key, if it exists, returning the
- // number of elements erased.
+ // number of elements erased (0 or 1).
using Base::erase;
// btree_map::insert()
@@ -225,6 +226,30 @@
// Inserts the elements within the initializer list `ilist`.
using Base::insert;
+ // btree_map::insert_or_assign()
+ //
+ // Inserts an element of the specified value into the `btree_map` provided
+ // that a value with the given key does not already exist, or replaces the
+ // corresponding mapped type with the forwarded `obj` argument if a key for
+ // that value already exists, returning an iterator pointing to the newly
+ // inserted element. Overloads are listed below.
+ //
+ // pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj):
+ // pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj):
+ //
+ // Inserts/Assigns (or moves) the element of the specified key into the
+ // `btree_map`. If the returned bool is true, insertion took place, and if
+ // it's false, assignment took place.
+ //
+ // iterator insert_or_assign(const_iterator hint,
+ // const key_type& k, M&& obj):
+ // iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj):
+ //
+ // Inserts/Assigns (or moves) the element of the specified key into the
+ // `btree_map` using the position of `hint` as a non-binding suggestion
+ // for where to begin the insertion search.
+ using Base::insert_or_assign;
+
// btree_map::emplace()
//
// Inserts an element of the specified value by constructing it in-place
@@ -293,13 +318,18 @@
// Extracts the element at the indicated position and returns a node handle
// owning that extracted data.
//
- // template <typename K> node_type extract(const K& x):
+ // template <typename K> node_type extract(const K& k):
//
// Extracts the element with the key matching the passed key value and
// returns a node handle owning that extracted data. If the `btree_map`
// does not contain an element with a matching key, this function returns an
// empty node handle.
//
+ // NOTE: when compiled in an earlier version of C++ than C++17,
+ // `node_type::key()` returns a const reference to the key instead of a
+ // mutable reference. We cannot safely return a mutable reference without
+ // std::launder (which is not available before C++17).
+ //
// NOTE: In this context, `node_type` refers to the C++17 concept of a
// move-only type that owns and provides access to the elements in associative
// containers (https://en.cppreference.com/w/cpp/container/node_handle).
@@ -411,6 +441,20 @@
return x.swap(y);
}
+// absl::erase_if(absl::btree_map<>, Pred)
+//
+// Erases all elements that satisfy the predicate pred from the container.
+template <typename K, typename V, typename C, typename A, typename Pred>
+void erase_if(btree_map<K, V, C, A> &map, Pred pred) {
+ for (auto it = map.begin(); it != map.end();) {
+ if (pred(*it)) {
+ it = map.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
// absl::btree_multimap
//
// An `absl::btree_multimap<K, V>` is an ordered associative container of
@@ -606,13 +650,18 @@
// Extracts the element at the indicated position and returns a node handle
// owning that extracted data.
//
- // template <typename K> node_type extract(const K& x):
+ // template <typename K> node_type extract(const K& k):
//
// Extracts the element with the key matching the passed key value and
// returns a node handle owning that extracted data. If the `btree_multimap`
// does not contain an element with a matching key, this function returns an
// empty node handle.
//
+ // NOTE: when compiled in an earlier version of C++ than C++17,
+ // `node_type::key()` returns a const reference to the key instead of a
+ // mutable reference. We cannot safely return a mutable reference without
+ // std::launder (which is not available before C++17).
+ //
// NOTE: In this context, `node_type` refers to the C++17 concept of a
// move-only type that owns and provides access to the elements in associative
// containers (https://en.cppreference.com/w/cpp/container/node_handle).
@@ -700,6 +749,21 @@
return x.swap(y);
}
+// absl::erase_if(absl::btree_multimap<>, Pred)
+//
+// Erases all elements that satisfy the predicate pred from the container.
+template <typename K, typename V, typename C, typename A, typename Pred>
+void erase_if(btree_multimap<K, V, C, A> &map, Pred pred) {
+ for (auto it = map.begin(); it != map.end();) {
+ if (pred(*it)) {
+ it = map.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_BTREE_MAP_H_
diff --git a/third_party/abseil/absl/container/btree_set.h b/third_party/abseil/absl/container/btree_set.h
index 6e47b4a..21ef0a0 100644
--- a/third_party/abseil/absl/container/btree_set.h
+++ b/third_party/abseil/absl/container/btree_set.h
@@ -51,6 +51,7 @@
#include "absl/container/internal/btree_container.h" // IWYU pragma: export
namespace absl {
+ABSL_NAMESPACE_BEGIN
// absl::btree_set<>
//
@@ -182,7 +183,7 @@
// template <typename K> size_type erase(const K& key):
//
// Erases the element with the matching key, if it exists, returning the
- // number of elements erased.
+ // number of elements erased (0 or 1).
using Base::erase;
// btree_set::insert()
@@ -262,7 +263,7 @@
// Extracts the element at the indicated position and returns a node handle
// owning that extracted data.
//
- // template <typename K> node_type extract(const K& x):
+ // template <typename K> node_type extract(const K& k):
//
// Extracts the element with the key matching the passed key value and
// returns a node handle owning that extracted data. If the `btree_set`
@@ -359,6 +360,20 @@
return x.swap(y);
}
+// absl::erase_if(absl::btree_set<>, Pred)
+//
+// Erases all elements that satisfy the predicate pred from the container.
+template <typename K, typename C, typename A, typename Pred>
+void erase_if(btree_set<K, C, A> &set, Pred pred) {
+ for (auto it = set.begin(); it != set.end();) {
+ if (pred(*it)) {
+ it = set.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
// absl::btree_multiset<>
//
// An `absl::btree_multiset<K>` is an ordered associative container of
@@ -552,7 +567,7 @@
// Extracts the element at the indicated position and returns a node handle
// owning that extracted data.
//
- // template <typename K> node_type extract(const K& x):
+ // template <typename K> node_type extract(const K& k):
//
// Extracts the element with the key matching the passed key value and
// returns a node handle owning that extracted data. If the `btree_multiset`
@@ -648,6 +663,21 @@
return x.swap(y);
}
+// absl::erase_if(absl::btree_multiset<>, Pred)
+//
+// Erases all elements that satisfy the predicate pred from the container.
+template <typename K, typename C, typename A, typename Pred>
+void erase_if(btree_multiset<K, C, A> &set, Pred pred) {
+ for (auto it = set.begin(); it != set.end();) {
+ if (pred(*it)) {
+ it = set.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_BTREE_SET_H_
diff --git a/third_party/abseil/absl/container/btree_test.cc b/third_party/abseil/absl/container/btree_test.cc
index 4edb277..367d75b 100644
--- a/third_party/abseil/absl/container/btree_test.cc
+++ b/third_party/abseil/absl/container/btree_test.cc
@@ -15,6 +15,7 @@
#include "absl/container/btree_test.h"
#include <cstdint>
+#include <limits>
#include <map>
#include <memory>
#include <stdexcept>
@@ -42,14 +43,19 @@
ABSL_FLAG(int, test_values, 10000, "The number of values to use for tests");
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace {
+using ::absl::test_internal::CopyableMovableInstance;
using ::absl::test_internal::InstanceTracker;
using ::absl::test_internal::MovableOnlyInstance;
using ::testing::ElementsAre;
using ::testing::ElementsAreArray;
+using ::testing::IsEmpty;
+using ::testing::IsNull;
using ::testing::Pair;
+using ::testing::SizeIs;
template <typename T, typename U>
void CheckPairEquals(const T &x, const U &y) {
@@ -86,8 +92,8 @@
public:
base_checker() : const_tree_(tree_) {}
- base_checker(const base_checker &x)
- : tree_(x.tree_), const_tree_(tree_), checker_(x.checker_) {}
+ base_checker(const base_checker &other)
+ : tree_(other.tree_), const_tree_(tree_), checker_(other.checker_) {}
template <typename InputIterator>
base_checker(InputIterator b, InputIterator e)
: tree_(b, e), const_tree_(tree_), checker_(b, e) {}
@@ -121,11 +127,11 @@
}
return tree_iter;
}
- void value_check(const value_type &x) {
+ void value_check(const value_type &v) {
typename KeyOfValue<typename TreeType::key_type,
typename TreeType::value_type>::type key_of_value;
- const key_type &key = key_of_value(x);
- CheckPairEquals(*find(key), x);
+ const key_type &key = key_of_value(v);
+ CheckPairEquals(*find(key), v);
lower_bound(key);
upper_bound(key);
equal_range(key);
@@ -177,18 +183,16 @@
const_iterator find(const key_type &key) const {
return iter_check(tree_.find(key), checker_.find(key));
}
- bool contains(const key_type &key) const {
- return find(key) != end();
- }
+ bool contains(const key_type &key) const { return find(key) != end(); }
size_type count(const key_type &key) const {
size_type res = checker_.count(key);
EXPECT_EQ(res, tree_.count(key));
return res;
}
- base_checker &operator=(const base_checker &x) {
- tree_ = x.tree_;
- checker_ = x.checker_;
+ base_checker &operator=(const base_checker &other) {
+ tree_ = other.tree_;
+ checker_ = other.checker_;
return *this;
}
@@ -237,8 +241,10 @@
++checker_end;
}
}
- checker_.erase(checker_begin, checker_end);
- tree_.erase(begin, end);
+ const auto checker_ret = checker_.erase(checker_begin, checker_end);
+ const auto tree_ret = tree_.erase(begin, end);
+ EXPECT_EQ(std::distance(checker_.begin(), checker_ret),
+ std::distance(tree_.begin(), tree_ret));
EXPECT_EQ(tree_.size(), checker_.size());
EXPECT_EQ(tree_.size(), size - count);
}
@@ -247,9 +253,9 @@
tree_.clear();
checker_.clear();
}
- void swap(base_checker &x) {
- tree_.swap(x.tree_);
- checker_.swap(x.checker_);
+ void swap(base_checker &other) {
+ tree_.swap(other.tree_);
+ checker_.swap(other.checker_);
}
void verify() const {
@@ -320,28 +326,28 @@
public:
unique_checker() : super_type() {}
- unique_checker(const unique_checker &x) : super_type(x) {}
+ unique_checker(const unique_checker &other) : super_type(other) {}
template <class InputIterator>
unique_checker(InputIterator b, InputIterator e) : super_type(b, e) {}
- unique_checker& operator=(const unique_checker&) = default;
+ unique_checker &operator=(const unique_checker &) = default;
// Insertion routines.
- std::pair<iterator, bool> insert(const value_type &x) {
+ std::pair<iterator, bool> insert(const value_type &v) {
int size = this->tree_.size();
std::pair<typename CheckerType::iterator, bool> checker_res =
- this->checker_.insert(x);
- std::pair<iterator, bool> tree_res = this->tree_.insert(x);
+ this->checker_.insert(v);
+ std::pair<iterator, bool> tree_res = this->tree_.insert(v);
CheckPairEquals(*tree_res.first, *checker_res.first);
EXPECT_EQ(tree_res.second, checker_res.second);
EXPECT_EQ(this->tree_.size(), this->checker_.size());
EXPECT_EQ(this->tree_.size(), size + tree_res.second);
return tree_res;
}
- iterator insert(iterator position, const value_type &x) {
+ iterator insert(iterator position, const value_type &v) {
int size = this->tree_.size();
std::pair<typename CheckerType::iterator, bool> checker_res =
- this->checker_.insert(x);
- iterator tree_res = this->tree_.insert(position, x);
+ this->checker_.insert(v);
+ iterator tree_res = this->tree_.insert(position, v);
CheckPairEquals(*tree_res, *checker_res.first);
EXPECT_EQ(this->tree_.size(), this->checker_.size());
EXPECT_EQ(this->tree_.size(), size + checker_res.second);
@@ -368,25 +374,25 @@
public:
multi_checker() : super_type() {}
- multi_checker(const multi_checker &x) : super_type(x) {}
+ multi_checker(const multi_checker &other) : super_type(other) {}
template <class InputIterator>
multi_checker(InputIterator b, InputIterator e) : super_type(b, e) {}
- multi_checker& operator=(const multi_checker&) = default;
+ multi_checker &operator=(const multi_checker &) = default;
// Insertion routines.
- iterator insert(const value_type &x) {
+ iterator insert(const value_type &v) {
int size = this->tree_.size();
- auto checker_res = this->checker_.insert(x);
- iterator tree_res = this->tree_.insert(x);
+ auto checker_res = this->checker_.insert(v);
+ iterator tree_res = this->tree_.insert(v);
CheckPairEquals(*tree_res, *checker_res);
EXPECT_EQ(this->tree_.size(), this->checker_.size());
EXPECT_EQ(this->tree_.size(), size + 1);
return tree_res;
}
- iterator insert(iterator position, const value_type &x) {
+ iterator insert(iterator position, const value_type &v) {
int size = this->tree_.size();
- auto checker_res = this->checker_.insert(x);
- iterator tree_res = this->tree_.insert(position, x);
+ auto checker_res = this->checker_.insert(v);
+ iterator tree_res = this->tree_.insert(position, v);
CheckPairEquals(*tree_res, *checker_res);
EXPECT_EQ(this->tree_.size(), this->checker_.size());
EXPECT_EQ(this->tree_.size(), size + 1);
@@ -809,10 +815,12 @@
TEST(Btree, set_int32) { SetTest<int32_t>(); }
TEST(Btree, set_int64) { SetTest<int64_t>(); }
TEST(Btree, set_string) { SetTest<std::string>(); }
+TEST(Btree, set_cord) { SetTest<absl::Cord>(); }
TEST(Btree, set_pair) { SetTest<std::pair<int, int>>(); }
TEST(Btree, map_int32) { MapTest<int32_t>(); }
TEST(Btree, map_int64) { MapTest<int64_t>(); }
TEST(Btree, map_string) { MapTest<std::string>(); }
+TEST(Btree, map_cord) { MapTest<absl::Cord>(); }
TEST(Btree, map_pair) { MapTest<std::pair<int, int>>(); }
template <typename K, int N = 256>
@@ -844,10 +852,12 @@
TEST(Btree, multiset_int32) { MultiSetTest<int32_t>(); }
TEST(Btree, multiset_int64) { MultiSetTest<int64_t>(); }
TEST(Btree, multiset_string) { MultiSetTest<std::string>(); }
+TEST(Btree, multiset_cord) { MultiSetTest<absl::Cord>(); }
TEST(Btree, multiset_pair) { MultiSetTest<std::pair<int, int>>(); }
TEST(Btree, multimap_int32) { MultiMapTest<int32_t>(); }
TEST(Btree, multimap_int64) { MultiMapTest<int64_t>(); }
TEST(Btree, multimap_string) { MultiMapTest<std::string>(); }
+TEST(Btree, multimap_cord) { MultiMapTest<absl::Cord>(); }
TEST(Btree, multimap_pair) { MultiMapTest<std::pair<int, int>>(); }
struct CompareIntToString {
@@ -865,7 +875,7 @@
struct NonTransparentCompare {
template <typename T, typename U>
- bool operator()(const T& t, const U& u) const {
+ bool operator()(const T &t, const U &u) const {
// Treating all comparators as transparent can cause inefficiencies (see
// N3657 C++ proposal). Test that for comparators without 'is_transparent'
// alias (like this one), we do not attempt heterogeneous lookup.
@@ -1002,21 +1012,15 @@
public:
StringLike() = default;
- StringLike(const char* s) : s_(s) { // NOLINT
+ StringLike(const char *s) : s_(s) { // NOLINT
++constructor_calls_;
}
- bool operator<(const StringLike& a) const {
- return s_ < a.s_;
- }
+ bool operator<(const StringLike &a) const { return s_ < a.s_; }
- static void clear_constructor_call_count() {
- constructor_calls_ = 0;
- }
+ static void clear_constructor_call_count() { constructor_calls_ = 0; }
- static int constructor_calls() {
- return constructor_calls_;
- }
+ static int constructor_calls() { return constructor_calls_; }
private:
static int constructor_calls_;
@@ -1179,6 +1183,103 @@
EXPECT_EQ(1, tmap.size());
}
+} // namespace
+
+class BtreeNodePeer {
+ public:
+ // Yields the size of a leaf node with a specific number of values.
+ template <typename ValueType>
+ constexpr static size_t GetTargetNodeSize(size_t target_values_per_node) {
+ return btree_node<
+ set_params<ValueType, std::less<ValueType>, std::allocator<ValueType>,
+ /*TargetNodeSize=*/256, // This parameter isn't used here.
+ /*Multi=*/false>>::SizeWithNValues(target_values_per_node);
+ }
+
+ // Yields the number of values in a (non-root) leaf node for this btree.
+ template <typename Btree>
+ constexpr static size_t GetNumValuesPerNode() {
+ return btree_node<typename Btree::params_type>::kNodeValues;
+ }
+
+ template <typename Btree>
+ constexpr static size_t GetMaxFieldType() {
+ return std::numeric_limits<
+ typename btree_node<typename Btree::params_type>::field_type>::max();
+ }
+
+ template <typename Btree>
+ constexpr static bool UsesLinearNodeSearch() {
+ return btree_node<typename Btree::params_type>::use_linear_search::value;
+ }
+};
+
+namespace {
+
+class BtreeMapTest : public ::testing::Test {
+ public:
+ struct Key {};
+ struct Cmp {
+ template <typename T>
+ bool operator()(T, T) const {
+ return false;
+ }
+ };
+
+ struct KeyLin {
+ using absl_btree_prefer_linear_node_search = std::true_type;
+ };
+ struct CmpLin : Cmp {
+ using absl_btree_prefer_linear_node_search = std::true_type;
+ };
+
+ struct KeyBin {
+ using absl_btree_prefer_linear_node_search = std::false_type;
+ };
+ struct CmpBin : Cmp {
+ using absl_btree_prefer_linear_node_search = std::false_type;
+ };
+
+ template <typename K, typename C>
+ static bool IsLinear() {
+ return BtreeNodePeer::UsesLinearNodeSearch<absl::btree_map<K, int, C>>();
+ }
+};
+
+TEST_F(BtreeMapTest, TestLinearSearchPreferredForKeyLinearViaAlias) {
+ // Test requesting linear search by directly exporting an alias.
+ EXPECT_FALSE((IsLinear<Key, Cmp>()));
+ EXPECT_TRUE((IsLinear<KeyLin, Cmp>()));
+ EXPECT_TRUE((IsLinear<Key, CmpLin>()));
+ EXPECT_TRUE((IsLinear<KeyLin, CmpLin>()));
+}
+
+TEST_F(BtreeMapTest, LinearChoiceTree) {
+ // Cmp has precedence, and is forcing binary
+ EXPECT_FALSE((IsLinear<Key, CmpBin>()));
+ EXPECT_FALSE((IsLinear<KeyLin, CmpBin>()));
+ EXPECT_FALSE((IsLinear<KeyBin, CmpBin>()));
+ EXPECT_FALSE((IsLinear<int, CmpBin>()));
+ EXPECT_FALSE((IsLinear<std::string, CmpBin>()));
+ // Cmp has precedence, and is forcing linear
+ EXPECT_TRUE((IsLinear<Key, CmpLin>()));
+ EXPECT_TRUE((IsLinear<KeyLin, CmpLin>()));
+ EXPECT_TRUE((IsLinear<KeyBin, CmpLin>()));
+ EXPECT_TRUE((IsLinear<int, CmpLin>()));
+ EXPECT_TRUE((IsLinear<std::string, CmpLin>()));
+ // Cmp has no preference, Key determines linear vs binary.
+ EXPECT_FALSE((IsLinear<Key, Cmp>()));
+ EXPECT_TRUE((IsLinear<KeyLin, Cmp>()));
+ EXPECT_FALSE((IsLinear<KeyBin, Cmp>()));
+ // arithmetic key w/ std::less or std::greater: linear
+ EXPECT_TRUE((IsLinear<int, std::less<int>>()));
+ EXPECT_TRUE((IsLinear<double, std::greater<double>>()));
+ // arithmetic key w/ custom compare: binary
+ EXPECT_FALSE((IsLinear<int, Cmp>()));
+ // non-arithmetic key: binary
+ EXPECT_FALSE((IsLinear<std::string, std::less<std::string>>()));
+}
+
TEST(Btree, BtreeMapCanHoldMoveOnlyTypes) {
absl::btree_map<std::string, std::unique_ptr<std::string>> m;
@@ -1271,6 +1372,8 @@
AssertKeyCompareToAdapted<std::less<absl::string_view>, absl::string_view>();
AssertKeyCompareToAdapted<std::greater<absl::string_view>,
absl::string_view>();
+ AssertKeyCompareToAdapted<std::less<absl::Cord>, absl::Cord>();
+ AssertKeyCompareToAdapted<std::greater<absl::Cord>, absl::Cord>();
AssertKeyCompareToNotAdapted<std::less<int>, int>();
AssertKeyCompareToNotAdapted<std::greater<int>, int>();
}
@@ -1322,28 +1425,6 @@
EXPECT_EQ(tracker.swaps(), 0);
}
-} // namespace
-
-class BtreeNodePeer {
- public:
- // Yields the size of a leaf node with a specific number of values.
- template <typename ValueType>
- constexpr static size_t GetTargetNodeSize(size_t target_values_per_node) {
- return btree_node<
- set_params<ValueType, std::less<ValueType>, std::allocator<ValueType>,
- /*TargetNodeSize=*/256, // This parameter isn't used here.
- /*Multi=*/false>>::SizeWithNValues(target_values_per_node);
- }
-
- // Yields the number of values in a (non-root) leaf node for this set.
- template <typename Set>
- constexpr static size_t GetNumValuesPerNode() {
- return btree_node<typename Set::params_type>::kNodeValues;
- }
-};
-
-namespace {
-
// A btree set with a specific number of values per node.
template <typename Key, int TargetValuesPerNode, typename Cmp = std::less<Key>>
class SizedBtreeSet
@@ -1473,7 +1554,7 @@
int num;
explicit NoDefaultCtor(int i) : num(i) {}
- friend bool operator<(const NoDefaultCtor& a, const NoDefaultCtor& b) {
+ friend bool operator<(const NoDefaultCtor &a, const NoDefaultCtor &b) {
return a.num < b.num;
}
};
@@ -1540,7 +1621,7 @@
#ifdef ABSL_HAVE_EXCEPTIONS
EXPECT_THROW(map.at(3), std::out_of_range);
#else
- EXPECT_DEATH(map.at(3), "absl::btree_map::at");
+ EXPECT_DEATH_IF_SUPPORTED(map.at(3), "absl::btree_map::at");
#endif
}
@@ -1823,25 +1904,80 @@
EXPECT_EQ(res.node.value(), 3);
}
-struct Deref {
- bool operator()(const std::unique_ptr<int> &lhs,
- const std::unique_ptr<int> &rhs) const {
- return *lhs < *rhs;
- }
-};
+template <typename Set>
+void TestExtractWithTrackingForSet() {
+ InstanceTracker tracker;
+ {
+ Set s;
+ // Add enough elements to make sure we test internal nodes too.
+ const size_t kSize = 1000;
+ while (s.size() < kSize) {
+ s.insert(MovableOnlyInstance(s.size()));
+ }
+ for (int i = 0; i < kSize; ++i) {
+ // Extract with key
+ auto nh = s.extract(MovableOnlyInstance(i));
+ EXPECT_EQ(s.size(), kSize - 1);
+ EXPECT_EQ(nh.value().value(), i);
+ // Insert with node
+ s.insert(std::move(nh));
+ EXPECT_EQ(s.size(), kSize);
-TEST(Btree, ExtractWithUniquePtr) {
- absl::btree_set<std::unique_ptr<int>, Deref> s;
- s.insert(absl::make_unique<int>(1));
- s.insert(absl::make_unique<int>(2));
- s.insert(absl::make_unique<int>(3));
- s.insert(absl::make_unique<int>(4));
- s.insert(absl::make_unique<int>(5));
- auto nh = s.extract(s.find(absl::make_unique<int>(3)));
- EXPECT_EQ(s.size(), 4);
- EXPECT_EQ(*nh.value(), 3);
- s.insert(std::move(nh));
- EXPECT_EQ(s.size(), 5);
+ // Extract with iterator
+ auto it = s.find(MovableOnlyInstance(i));
+ nh = s.extract(it);
+ EXPECT_EQ(s.size(), kSize - 1);
+ EXPECT_EQ(nh.value().value(), i);
+ // Insert with node and hint
+ s.insert(s.begin(), std::move(nh));
+ EXPECT_EQ(s.size(), kSize);
+ }
+ }
+ EXPECT_EQ(0, tracker.instances());
+}
+
+template <typename Map>
+void TestExtractWithTrackingForMap() {
+ InstanceTracker tracker;
+ {
+ Map m;
+ // Add enough elements to make sure we test internal nodes too.
+ const size_t kSize = 1000;
+ while (m.size() < kSize) {
+ m.insert(
+ {CopyableMovableInstance(m.size()), MovableOnlyInstance(m.size())});
+ }
+ for (int i = 0; i < kSize; ++i) {
+ // Extract with key
+ auto nh = m.extract(CopyableMovableInstance(i));
+ EXPECT_EQ(m.size(), kSize - 1);
+ EXPECT_EQ(nh.key().value(), i);
+ EXPECT_EQ(nh.mapped().value(), i);
+ // Insert with node
+ m.insert(std::move(nh));
+ EXPECT_EQ(m.size(), kSize);
+
+ // Extract with iterator
+ auto it = m.find(CopyableMovableInstance(i));
+ nh = m.extract(it);
+ EXPECT_EQ(m.size(), kSize - 1);
+ EXPECT_EQ(nh.key().value(), i);
+ EXPECT_EQ(nh.mapped().value(), i);
+ // Insert with node and hint
+ m.insert(m.begin(), std::move(nh));
+ EXPECT_EQ(m.size(), kSize);
+ }
+ }
+ EXPECT_EQ(0, tracker.instances());
+}
+
+TEST(Btree, ExtractTracking) {
+ TestExtractWithTrackingForSet<absl::btree_set<MovableOnlyInstance>>();
+ TestExtractWithTrackingForSet<absl::btree_multiset<MovableOnlyInstance>>();
+ TestExtractWithTrackingForMap<
+ absl::btree_map<CopyableMovableInstance, MovableOnlyInstance>>();
+ TestExtractWithTrackingForMap<
+ absl::btree_multimap<CopyableMovableInstance, MovableOnlyInstance>>();
}
TEST(Btree, ExtractAndInsertNodeHandleMultiSet) {
@@ -1902,6 +2038,30 @@
EXPECT_EQ(res, ++other.begin());
}
+TEST(Btree, ExtractMultiMapEquivalentKeys) {
+ // Note: using string keys means a three-way comparator.
+ absl::btree_multimap<std::string, int> map;
+ for (int i = 0; i < 100; ++i) {
+ for (int j = 0; j < 100; ++j) {
+ map.insert({absl::StrCat(i), j});
+ }
+ }
+
+ for (int i = 0; i < 100; ++i) {
+ const std::string key = absl::StrCat(i);
+ auto node_handle = map.extract(key);
+ EXPECT_EQ(node_handle.key(), key);
+ EXPECT_EQ(node_handle.mapped(), 0) << i;
+ }
+
+ for (int i = 0; i < 100; ++i) {
+ const std::string key = absl::StrCat(i);
+ auto node_handle = map.extract(key);
+ EXPECT_EQ(node_handle.key(), key);
+ EXPECT_EQ(node_handle.mapped(), 1) << i;
+ }
+}
+
// For multisets, insert with hint also affects correctness because we need to
// insert immediately before the hint if possible.
struct InsertMultiHintData {
@@ -2043,6 +2203,31 @@
Pair(4, 1), Pair(4, 4), Pair(5, 5)));
}
+TEST(Btree, MergeIntoSetMovableOnly) {
+ absl::btree_set<MovableOnlyInstance> src;
+ src.insert(MovableOnlyInstance(1));
+ absl::btree_multiset<MovableOnlyInstance> dst1;
+ dst1.insert(MovableOnlyInstance(2));
+ absl::btree_set<MovableOnlyInstance> dst2;
+
+ // Test merge into multiset.
+ dst1.merge(src);
+
+ EXPECT_TRUE(src.empty());
+ // ElementsAre/ElementsAreArray don't work with move-only types.
+ ASSERT_THAT(dst1, SizeIs(2));
+ EXPECT_EQ(*dst1.begin(), MovableOnlyInstance(1));
+ EXPECT_EQ(*std::next(dst1.begin()), MovableOnlyInstance(2));
+
+ // Test merge into set.
+ dst2.merge(dst1);
+
+ EXPECT_TRUE(dst1.empty());
+ ASSERT_THAT(dst2, SizeIs(2));
+ EXPECT_EQ(*dst2.begin(), MovableOnlyInstance(1));
+ EXPECT_EQ(*std::next(dst2.begin()), MovableOnlyInstance(2));
+}
+
struct KeyCompareToWeakOrdering {
template <typename T>
absl::weak_ordering operator()(const T &a, const T &b) const {
@@ -2074,11 +2259,11 @@
TEST(Btree, TryEmplaceBasicTest) {
absl::btree_map<int, std::string> m;
- // Should construct a std::string from the literal.
+ // Should construct a string from the literal.
m.try_emplace(1, "one");
EXPECT_EQ(1, m.size());
- // Try other std::string constructors and const lvalue key.
+ // Try other string constructors and const lvalue key.
const int key(42);
m.try_emplace(key, 3, 'a');
m.try_emplace(2, std::string("two"));
@@ -2239,6 +2424,476 @@
}
}
+TEST(Btree, EmptyTree) {
+ absl::btree_set<int> s;
+ EXPECT_TRUE(s.empty());
+ EXPECT_EQ(s.size(), 0);
+ EXPECT_GT(s.max_size(), 0);
+}
+
+bool IsEven(int k) { return k % 2 == 0; }
+
+TEST(Btree, EraseIf) {
+ // Test that erase_if works with all the container types and supports lambdas.
+ {
+ absl::btree_set<int> s = {1, 3, 5, 6, 100};
+ erase_if(s, [](int k) { return k > 3; });
+ EXPECT_THAT(s, ElementsAre(1, 3));
+ }
+ {
+ absl::btree_multiset<int> s = {1, 3, 3, 5, 6, 6, 100};
+ erase_if(s, [](int k) { return k <= 3; });
+ EXPECT_THAT(s, ElementsAre(5, 6, 6, 100));
+ }
+ {
+ absl::btree_map<int, int> m = {{1, 1}, {3, 3}, {6, 6}, {100, 100}};
+ erase_if(m, [](std::pair<const int, int> kv) { return kv.first > 3; });
+ EXPECT_THAT(m, ElementsAre(Pair(1, 1), Pair(3, 3)));
+ }
+ {
+ absl::btree_multimap<int, int> m = {{1, 1}, {3, 3}, {3, 6},
+ {6, 6}, {6, 7}, {100, 6}};
+ erase_if(m, [](std::pair<const int, int> kv) { return kv.second == 6; });
+ EXPECT_THAT(m, ElementsAre(Pair(1, 1), Pair(3, 3), Pair(6, 7)));
+ }
+ // Test that erasing all elements from a large set works and test support for
+ // function pointers.
+ {
+ absl::btree_set<int> s;
+ for (int i = 0; i < 1000; ++i) s.insert(2 * i);
+ erase_if(s, IsEven);
+ EXPECT_THAT(s, IsEmpty());
+ }
+ // Test that erase_if supports other format of function pointers.
+ {
+ absl::btree_set<int> s = {1, 3, 5, 6, 100};
+ erase_if(s, &IsEven);
+ EXPECT_THAT(s, ElementsAre(1, 3, 5));
+ }
+}
+
+TEST(Btree, InsertOrAssign) {
+ absl::btree_map<int, int> m = {{1, 1}, {3, 3}};
+ using value_type = typename decltype(m)::value_type;
+
+ auto ret = m.insert_or_assign(4, 4);
+ EXPECT_EQ(*ret.first, value_type(4, 4));
+ EXPECT_TRUE(ret.second);
+ ret = m.insert_or_assign(3, 100);
+ EXPECT_EQ(*ret.first, value_type(3, 100));
+ EXPECT_FALSE(ret.second);
+
+ auto hint_ret = m.insert_or_assign(ret.first, 3, 200);
+ EXPECT_EQ(*hint_ret, value_type(3, 200));
+ hint_ret = m.insert_or_assign(m.find(1), 0, 1);
+ EXPECT_EQ(*hint_ret, value_type(0, 1));
+ // Test with bad hint.
+ hint_ret = m.insert_or_assign(m.end(), -1, 1);
+ EXPECT_EQ(*hint_ret, value_type(-1, 1));
+
+ EXPECT_THAT(m, ElementsAre(Pair(-1, 1), Pair(0, 1), Pair(1, 1), Pair(3, 200),
+ Pair(4, 4)));
+}
+
+TEST(Btree, InsertOrAssignMovableOnly) {
+ absl::btree_map<int, MovableOnlyInstance> m;
+ using value_type = typename decltype(m)::value_type;
+
+ auto ret = m.insert_or_assign(4, MovableOnlyInstance(4));
+ EXPECT_EQ(*ret.first, value_type(4, MovableOnlyInstance(4)));
+ EXPECT_TRUE(ret.second);
+ ret = m.insert_or_assign(4, MovableOnlyInstance(100));
+ EXPECT_EQ(*ret.first, value_type(4, MovableOnlyInstance(100)));
+ EXPECT_FALSE(ret.second);
+
+ auto hint_ret = m.insert_or_assign(ret.first, 3, MovableOnlyInstance(200));
+ EXPECT_EQ(*hint_ret, value_type(3, MovableOnlyInstance(200)));
+
+ EXPECT_EQ(m.size(), 2);
+}
+
+TEST(Btree, BitfieldArgument) {
+ union {
+ int n : 1;
+ };
+ n = 0;
+ absl::btree_map<int, int> m;
+ m.erase(n);
+ m.count(n);
+ m.find(n);
+ m.contains(n);
+ m.equal_range(n);
+ m.insert_or_assign(n, n);
+ m.insert_or_assign(m.end(), n, n);
+ m.try_emplace(n);
+ m.try_emplace(m.end(), n);
+ m.at(n);
+ m[n];
+}
+
+TEST(Btree, SetRangeConstructorAndInsertSupportExplicitConversionComparable) {
+ const absl::string_view names[] = {"n1", "n2"};
+
+ absl::btree_set<std::string> name_set1{std::begin(names), std::end(names)};
+ EXPECT_THAT(name_set1, ElementsAreArray(names));
+
+ absl::btree_set<std::string> name_set2;
+ name_set2.insert(std::begin(names), std::end(names));
+ EXPECT_THAT(name_set2, ElementsAreArray(names));
+}
+
+// A type that is explicitly convertible from int and counts constructor calls.
+struct ConstructorCounted {
+ explicit ConstructorCounted(int i) : i(i) { ++constructor_calls; }
+ bool operator==(int other) const { return i == other; }
+
+ int i;
+ static int constructor_calls;
+};
+int ConstructorCounted::constructor_calls = 0;
+
+struct ConstructorCountedCompare {
+ bool operator()(int a, const ConstructorCounted &b) const { return a < b.i; }
+ bool operator()(const ConstructorCounted &a, int b) const { return a.i < b; }
+ bool operator()(const ConstructorCounted &a,
+ const ConstructorCounted &b) const {
+ return a.i < b.i;
+ }
+ using is_transparent = void;
+};
+
+TEST(Btree,
+ SetRangeConstructorAndInsertExplicitConvComparableLimitConstruction) {
+ const int i[] = {0, 1, 1};
+ ConstructorCounted::constructor_calls = 0;
+
+ absl::btree_set<ConstructorCounted, ConstructorCountedCompare> set{
+ std::begin(i), std::end(i)};
+ EXPECT_THAT(set, ElementsAre(0, 1));
+ EXPECT_EQ(ConstructorCounted::constructor_calls, 2);
+
+ set.insert(std::begin(i), std::end(i));
+ EXPECT_THAT(set, ElementsAre(0, 1));
+ EXPECT_EQ(ConstructorCounted::constructor_calls, 2);
+}
+
+TEST(Btree,
+ SetRangeConstructorAndInsertSupportExplicitConversionNonComparable) {
+ const int i[] = {0, 1};
+
+ absl::btree_set<std::vector<void *>> s1{std::begin(i), std::end(i)};
+ EXPECT_THAT(s1, ElementsAre(IsEmpty(), ElementsAre(IsNull())));
+
+ absl::btree_set<std::vector<void *>> s2;
+ s2.insert(std::begin(i), std::end(i));
+ EXPECT_THAT(s2, ElementsAre(IsEmpty(), ElementsAre(IsNull())));
+}
+
+// libstdc++ included with GCC 4.9 has a bug in the std::pair constructors that
+// prevents explicit conversions between pair types.
+// We only run this test for the libstdc++ from GCC 7 or newer because we can't
+// reliably check the libstdc++ version prior to that release.
+#if !defined(__GLIBCXX__) || \
+ (defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE >= 7)
+TEST(Btree, MapRangeConstructorAndInsertSupportExplicitConversionComparable) {
+ const std::pair<absl::string_view, int> names[] = {{"n1", 1}, {"n2", 2}};
+
+ absl::btree_map<std::string, int> name_map1{std::begin(names),
+ std::end(names)};
+ EXPECT_THAT(name_map1, ElementsAre(Pair("n1", 1), Pair("n2", 2)));
+
+ absl::btree_map<std::string, int> name_map2;
+ name_map2.insert(std::begin(names), std::end(names));
+ EXPECT_THAT(name_map2, ElementsAre(Pair("n1", 1), Pair("n2", 2)));
+}
+
+TEST(Btree,
+ MapRangeConstructorAndInsertExplicitConvComparableLimitConstruction) {
+ const std::pair<int, int> i[] = {{0, 1}, {1, 2}, {1, 3}};
+ ConstructorCounted::constructor_calls = 0;
+
+ absl::btree_map<ConstructorCounted, int, ConstructorCountedCompare> map{
+ std::begin(i), std::end(i)};
+ EXPECT_THAT(map, ElementsAre(Pair(0, 1), Pair(1, 2)));
+ EXPECT_EQ(ConstructorCounted::constructor_calls, 2);
+
+ map.insert(std::begin(i), std::end(i));
+ EXPECT_THAT(map, ElementsAre(Pair(0, 1), Pair(1, 2)));
+ EXPECT_EQ(ConstructorCounted::constructor_calls, 2);
+}
+
+TEST(Btree,
+ MapRangeConstructorAndInsertSupportExplicitConversionNonComparable) {
+ const std::pair<int, int> i[] = {{0, 1}, {1, 2}};
+
+ absl::btree_map<std::vector<void *>, int> m1{std::begin(i), std::end(i)};
+ EXPECT_THAT(m1,
+ ElementsAre(Pair(IsEmpty(), 1), Pair(ElementsAre(IsNull()), 2)));
+
+ absl::btree_map<std::vector<void *>, int> m2;
+ m2.insert(std::begin(i), std::end(i));
+ EXPECT_THAT(m2,
+ ElementsAre(Pair(IsEmpty(), 1), Pair(ElementsAre(IsNull()), 2)));
+}
+
+TEST(Btree, HeterogeneousTryEmplace) {
+ absl::btree_map<std::string, int> m;
+ std::string s = "key";
+ absl::string_view sv = s;
+ m.try_emplace(sv, 1);
+ EXPECT_EQ(m[s], 1);
+
+ m.try_emplace(m.end(), sv, 2);
+ EXPECT_EQ(m[s], 1);
+}
+
+TEST(Btree, HeterogeneousOperatorMapped) {
+ absl::btree_map<std::string, int> m;
+ std::string s = "key";
+ absl::string_view sv = s;
+ m[sv] = 1;
+ EXPECT_EQ(m[s], 1);
+
+ m[sv] = 2;
+ EXPECT_EQ(m[s], 2);
+}
+
+TEST(Btree, HeterogeneousInsertOrAssign) {
+ absl::btree_map<std::string, int> m;
+ std::string s = "key";
+ absl::string_view sv = s;
+ m.insert_or_assign(sv, 1);
+ EXPECT_EQ(m[s], 1);
+
+ m.insert_or_assign(m.end(), sv, 2);
+ EXPECT_EQ(m[s], 2);
+}
+#endif
+
+// This test requires std::launder for mutable key access in node handles.
+#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
+TEST(Btree, NodeHandleMutableKeyAccess) {
+ {
+ absl::btree_map<std::string, std::string> map;
+
+ map["key1"] = "mapped";
+
+ auto nh = map.extract(map.begin());
+ nh.key().resize(3);
+ map.insert(std::move(nh));
+
+ EXPECT_THAT(map, ElementsAre(Pair("key", "mapped")));
+ }
+ // Also for multimap.
+ {
+ absl::btree_multimap<std::string, std::string> map;
+
+ map.emplace("key1", "mapped");
+
+ auto nh = map.extract(map.begin());
+ nh.key().resize(3);
+ map.insert(std::move(nh));
+
+ EXPECT_THAT(map, ElementsAre(Pair("key", "mapped")));
+ }
+}
+#endif
+
+struct MultiKey {
+ int i1;
+ int i2;
+};
+
+bool operator==(const MultiKey a, const MultiKey b) {
+ return a.i1 == b.i1 && a.i2 == b.i2;
+}
+
+// A heterogeneous comparator that has different equivalence classes for
+// different lookup types.
+struct MultiKeyComp {
+ using is_transparent = void;
+ bool operator()(const MultiKey a, const MultiKey b) const {
+ if (a.i1 != b.i1) return a.i1 < b.i1;
+ return a.i2 < b.i2;
+ }
+ bool operator()(const int a, const MultiKey b) const { return a < b.i1; }
+ bool operator()(const MultiKey a, const int b) const { return a.i1 < b; }
+};
+
+// A heterogeneous, three-way comparator that has different equivalence classes
+// for different lookup types.
+struct MultiKeyThreeWayComp {
+ using is_transparent = void;
+ absl::weak_ordering operator()(const MultiKey a, const MultiKey b) const {
+ if (a.i1 < b.i1) return absl::weak_ordering::less;
+ if (a.i1 > b.i1) return absl::weak_ordering::greater;
+ if (a.i2 < b.i2) return absl::weak_ordering::less;
+ if (a.i2 > b.i2) return absl::weak_ordering::greater;
+ return absl::weak_ordering::equivalent;
+ }
+ absl::weak_ordering operator()(const int a, const MultiKey b) const {
+ if (a < b.i1) return absl::weak_ordering::less;
+ if (a > b.i1) return absl::weak_ordering::greater;
+ return absl::weak_ordering::equivalent;
+ }
+ absl::weak_ordering operator()(const MultiKey a, const int b) const {
+ if (a.i1 < b) return absl::weak_ordering::less;
+ if (a.i1 > b) return absl::weak_ordering::greater;
+ return absl::weak_ordering::equivalent;
+ }
+};
+
+template <typename Compare>
+class BtreeMultiKeyTest : public ::testing::Test {};
+using MultiKeyComps = ::testing::Types<MultiKeyComp, MultiKeyThreeWayComp>;
+TYPED_TEST_SUITE(BtreeMultiKeyTest, MultiKeyComps);
+
+TYPED_TEST(BtreeMultiKeyTest, EqualRange) {
+ absl::btree_set<MultiKey, TypeParam> set;
+ for (int i = 0; i < 100; ++i) {
+ for (int j = 0; j < 100; ++j) {
+ set.insert({i, j});
+ }
+ }
+
+ for (int i = 0; i < 100; ++i) {
+ auto equal_range = set.equal_range(i);
+ EXPECT_EQ(equal_range.first->i1, i);
+ EXPECT_EQ(equal_range.first->i2, 0) << i;
+ EXPECT_EQ(std::distance(equal_range.first, equal_range.second), 100) << i;
+ }
+}
+
+TYPED_TEST(BtreeMultiKeyTest, Extract) {
+ absl::btree_set<MultiKey, TypeParam> set;
+ for (int i = 0; i < 100; ++i) {
+ for (int j = 0; j < 100; ++j) {
+ set.insert({i, j});
+ }
+ }
+
+ for (int i = 0; i < 100; ++i) {
+ auto node_handle = set.extract(i);
+ EXPECT_EQ(node_handle.value().i1, i);
+ EXPECT_EQ(node_handle.value().i2, 0) << i;
+ }
+
+ for (int i = 0; i < 100; ++i) {
+ auto node_handle = set.extract(i);
+ EXPECT_EQ(node_handle.value().i1, i);
+ EXPECT_EQ(node_handle.value().i2, 1) << i;
+ }
+}
+
+TYPED_TEST(BtreeMultiKeyTest, Erase) {
+ absl::btree_set<MultiKey, TypeParam> set = {
+ {1, 1}, {2, 1}, {2, 2}, {3, 1}};
+ EXPECT_EQ(set.erase(2), 2);
+ EXPECT_THAT(set, ElementsAre(MultiKey{1, 1}, MultiKey{3, 1}));
+}
+
+TYPED_TEST(BtreeMultiKeyTest, Count) {
+ const absl::btree_set<MultiKey, TypeParam> set = {
+ {1, 1}, {2, 1}, {2, 2}, {3, 1}};
+ EXPECT_EQ(set.count(2), 2);
+}
+
+TEST(Btree, AllocConstructor) {
+ using Alloc = CountingAllocator<int>;
+ using Set = absl::btree_set<int, std::less<int>, Alloc>;
+ int64_t bytes_used = 0;
+ Alloc alloc(&bytes_used);
+ Set set(alloc);
+
+ set.insert({1, 2, 3});
+
+ EXPECT_THAT(set, ElementsAre(1, 2, 3));
+ EXPECT_GT(bytes_used, set.size() * sizeof(int));
+}
+
+TEST(Btree, AllocInitializerListConstructor) {
+ using Alloc = CountingAllocator<int>;
+ using Set = absl::btree_set<int, std::less<int>, Alloc>;
+ int64_t bytes_used = 0;
+ Alloc alloc(&bytes_used);
+ Set set({1, 2, 3}, alloc);
+
+ EXPECT_THAT(set, ElementsAre(1, 2, 3));
+ EXPECT_GT(bytes_used, set.size() * sizeof(int));
+}
+
+TEST(Btree, AllocRangeConstructor) {
+ using Alloc = CountingAllocator<int>;
+ using Set = absl::btree_set<int, std::less<int>, Alloc>;
+ int64_t bytes_used = 0;
+ Alloc alloc(&bytes_used);
+ std::vector<int> v = {1, 2, 3};
+ Set set(v.begin(), v.end(), alloc);
+
+ EXPECT_THAT(set, ElementsAre(1, 2, 3));
+ EXPECT_GT(bytes_used, set.size() * sizeof(int));
+}
+
+TEST(Btree, AllocCopyConstructor) {
+ using Alloc = CountingAllocator<int>;
+ using Set = absl::btree_set<int, std::less<int>, Alloc>;
+ int64_t bytes_used1 = 0;
+ Alloc alloc1(&bytes_used1);
+ Set set1(alloc1);
+
+ set1.insert({1, 2, 3});
+
+ int64_t bytes_used2 = 0;
+ Alloc alloc2(&bytes_used2);
+ Set set2(set1, alloc2);
+
+ EXPECT_THAT(set1, ElementsAre(1, 2, 3));
+ EXPECT_THAT(set2, ElementsAre(1, 2, 3));
+ EXPECT_GT(bytes_used1, set1.size() * sizeof(int));
+ EXPECT_EQ(bytes_used1, bytes_used2);
+}
+
+TEST(Btree, AllocMoveConstructor_SameAlloc) {
+ using Alloc = CountingAllocator<int>;
+ using Set = absl::btree_set<int, std::less<int>, Alloc>;
+ int64_t bytes_used = 0;
+ Alloc alloc(&bytes_used);
+ Set set1(alloc);
+
+ set1.insert({1, 2, 3});
+
+ const int64_t original_bytes_used = bytes_used;
+ EXPECT_GT(original_bytes_used, set1.size() * sizeof(int));
+
+ Set set2(std::move(set1), alloc);
+
+ EXPECT_THAT(set2, ElementsAre(1, 2, 3));
+ EXPECT_EQ(bytes_used, original_bytes_used);
+}
+
+TEST(Btree, AllocMoveConstructor_DifferentAlloc) {
+ using Alloc = CountingAllocator<int>;
+ using Set = absl::btree_set<int, std::less<int>, Alloc>;
+ int64_t bytes_used1 = 0;
+ Alloc alloc1(&bytes_used1);
+ Set set1(alloc1);
+
+ set1.insert({1, 2, 3});
+
+ const int64_t original_bytes_used = bytes_used1;
+ EXPECT_GT(original_bytes_used, set1.size() * sizeof(int));
+
+ int64_t bytes_used2 = 0;
+ Alloc alloc2(&bytes_used2);
+ Set set2(std::move(set1), alloc2);
+
+ EXPECT_THAT(set2, ElementsAre(1, 2, 3));
+ // We didn't free these bytes allocated by `set1` yet.
+ EXPECT_EQ(bytes_used1, original_bytes_used);
+ EXPECT_EQ(bytes_used2, original_bytes_used);
+}
+
} // namespace
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/container/btree_test.h b/third_party/abseil/absl/container/btree_test.h
index 5ecf43c..6249080 100644
--- a/third_party/abseil/absl/container/btree_test.h
+++ b/third_party/abseil/absl/container/btree_test.h
@@ -25,9 +25,11 @@
#include "absl/container/btree_map.h"
#include "absl/container/btree_set.h"
#include "absl/container/flat_hash_set.h"
+#include "absl/strings/cord.h"
#include "absl/time/time.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
// Like remove_const but propagates the removal through std::pair.
@@ -99,6 +101,16 @@
}
};
+template <>
+struct Generator<Cord> {
+ int maxval;
+ explicit Generator(int m) : maxval(m) {}
+ Cord operator()(int i) const {
+ char buf[16];
+ return Cord(GenerateDigits(buf, i, maxval));
+ }
+};
+
template <typename T, typename U>
struct Generator<std::pair<T, U> > {
Generator<typename remove_pair_const<T>::type> tgen;
@@ -148,6 +160,7 @@
}
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_BTREE_TEST_H_
diff --git a/third_party/abseil/absl/container/fixed_array.h b/third_party/abseil/absl/container/fixed_array.h
index 70e94ad..fcb3e54 100644
--- a/third_party/abseil/absl/container/fixed_array.h
+++ b/third_party/abseil/absl/container/fixed_array.h
@@ -41,6 +41,7 @@
#include <type_traits>
#include "absl/algorithm/algorithm.h"
+#include "absl/base/config.h"
#include "absl/base/dynamic_annotations.h"
#include "absl/base/internal/throw_delegate.h"
#include "absl/base/macros.h"
@@ -50,6 +51,7 @@
#include "absl/memory/memory.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
constexpr static auto kFixedArrayUseDefault = static_cast<size_t>(-1);
@@ -105,13 +107,13 @@
public:
using allocator_type = typename AllocatorTraits::allocator_type;
- 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 value_type = typename AllocatorTraits::value_type;
+ using pointer = typename AllocatorTraits::pointer;
+ using const_pointer = typename AllocatorTraits::const_pointer;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using size_type = typename AllocatorTraits::size_type;
+ using difference_type = typename AllocatorTraits::difference_type;
using iterator = pointer;
using const_iterator = const_pointer;
using reverse_iterator = std::reverse_iterator<iterator>;
@@ -216,7 +218,7 @@
// Returns a reference the ith element of the fixed array.
// REQUIRES: 0 <= i < size()
reference operator[](size_type i) {
- assert(i < size());
+ ABSL_HARDENING_ASSERT(i < size());
return data()[i];
}
@@ -224,14 +226,14 @@
// ith element of the fixed array.
// REQUIRES: 0 <= i < size()
const_reference operator[](size_type i) const {
- assert(i < size());
+ ABSL_HARDENING_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
+ // Bounds-checked access. Returns a reference to the ith element of the fixed
+ // 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");
@@ -251,20 +253,32 @@
// FixedArray::front()
//
// Returns a reference to the first element of the fixed array.
- reference front() { return *begin(); }
+ reference front() {
+ ABSL_HARDENING_ASSERT(!empty());
+ return data()[0];
+ }
// 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(); }
+ const_reference front() const {
+ ABSL_HARDENING_ASSERT(!empty());
+ return data()[0];
+ }
// FixedArray::back()
//
// Returns a reference to the last element of the fixed array.
- reference back() { return *(end() - 1); }
+ reference back() {
+ ABSL_HARDENING_ASSERT(!empty());
+ return data()[size() - 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); }
+ const_reference back() const {
+ ABSL_HARDENING_ASSERT(!empty());
+ return data()[size() - 1];
+ }
// FixedArray::begin()
//
@@ -409,15 +423,15 @@
void AnnotateConstruct(size_type n);
void AnnotateDestruct(size_type n);
-#ifdef ADDRESS_SANITIZER
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
void* RedzoneBegin() { return &redzone_begin_; }
void* RedzoneEnd() { return &redzone_end_ + 1; }
-#endif // ADDRESS_SANITIZER
+#endif // ABSL_HAVE_ADDRESS_SANITIZER
private:
- ADDRESS_SANITIZER_REDZONE(redzone_begin_);
+ ABSL_ADDRESS_SANITIZER_REDZONE(redzone_begin_);
alignas(StorageElement) char buff_[sizeof(StorageElement[inline_elements])];
- ADDRESS_SANITIZER_REDZONE(redzone_end_);
+ ABSL_ADDRESS_SANITIZER_REDZONE(redzone_end_);
};
class EmptyInlinedStorage {
@@ -490,24 +504,29 @@
template <typename T, size_t N, typename A>
void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateConstruct(
typename FixedArray<T, N, A>::size_type n) {
-#ifdef ADDRESS_SANITIZER
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
if (!n) return;
- ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), RedzoneEnd(), data() + n);
- ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), data(), RedzoneBegin());
-#endif // ADDRESS_SANITIZER
+ ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), RedzoneEnd(),
+ data() + n);
+ ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), data(),
+ RedzoneBegin());
+#endif // ABSL_HAVE_ADDRESS_SANITIZER
static_cast<void>(n); // Mark used when not in asan mode
}
template <typename T, size_t N, typename A>
void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateDestruct(
typename FixedArray<T, N, A>::size_type n) {
-#ifdef ADDRESS_SANITIZER
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
if (!n) return;
- ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), data() + n, RedzoneEnd());
- ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), RedzoneBegin(), data());
-#endif // ADDRESS_SANITIZER
+ ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), data() + n,
+ RedzoneEnd());
+ ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), RedzoneBegin(),
+ data());
+#endif // ABSL_HAVE_ADDRESS_SANITIZER
static_cast<void>(n); // Mark used when not in asan mode
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_FIXED_ARRAY_H_
diff --git a/third_party/abseil/absl/container/fixed_array_exception_safety_test.cc b/third_party/abseil/absl/container/fixed_array_exception_safety_test.cc
index 9aabfd5..e5f5929 100644
--- a/third_party/abseil/absl/container/fixed_array_exception_safety_test.cc
+++ b/third_party/abseil/absl/container/fixed_array_exception_safety_test.cc
@@ -12,9 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "absl/container/fixed_array.h"
-
#include "absl/base/config.h"
+#include "absl/container/fixed_array.h"
#ifdef ABSL_HAVE_EXCEPTIONS
@@ -24,6 +23,7 @@
#include "absl/base/internal/exception_safety_testing.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
@@ -37,10 +37,19 @@
using ::testing::TestThrowingCtor;
using Thrower = testing::ThrowingValue<testing::TypeSpec::kEverythingThrows>;
-using FixedArr = absl::FixedArray<Thrower, kInlined>;
-
+using ThrowAlloc =
+ testing::ThrowingAllocator<Thrower, testing::AllocSpec::kEverythingThrows>;
using MoveThrower = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
+using MoveThrowAlloc =
+ testing::ThrowingAllocator<MoveThrower,
+ testing::AllocSpec::kEverythingThrows>;
+
+using FixedArr = absl::FixedArray<Thrower, kInlined>;
+using FixedArrWithAlloc = absl::FixedArray<Thrower, kInlined, ThrowAlloc>;
+
using MoveFixedArr = absl::FixedArray<MoveThrower, kInlined>;
+using MoveFixedArrWithAlloc =
+ absl::FixedArray<MoveThrower, kInlined, MoveThrowAlloc>;
TEST(FixedArrayExceptionSafety, CopyConstructor) {
auto small = FixedArr(kSmallSize);
@@ -50,6 +59,14 @@
TestThrowingCtor<FixedArr>(large);
}
+TEST(FixedArrayExceptionSafety, CopyConstructorWithAlloc) {
+ auto small = FixedArrWithAlloc(kSmallSize);
+ TestThrowingCtor<FixedArrWithAlloc>(small);
+
+ auto large = FixedArrWithAlloc(kLargeSize);
+ TestThrowingCtor<FixedArrWithAlloc>(large);
+}
+
TEST(FixedArrayExceptionSafety, MoveConstructor) {
TestThrowingCtor<FixedArr>(FixedArr(kSmallSize));
TestThrowingCtor<FixedArr>(FixedArr(kLargeSize));
@@ -59,16 +76,35 @@
TestThrowingCtor<MoveFixedArr>(MoveFixedArr(kLargeSize));
}
+TEST(FixedArrayExceptionSafety, MoveConstructorWithAlloc) {
+ TestThrowingCtor<FixedArrWithAlloc>(FixedArrWithAlloc(kSmallSize));
+ TestThrowingCtor<FixedArrWithAlloc>(FixedArrWithAlloc(kLargeSize));
+
+ // TypeSpec::kNoThrowMove
+ TestThrowingCtor<MoveFixedArrWithAlloc>(MoveFixedArrWithAlloc(kSmallSize));
+ TestThrowingCtor<MoveFixedArrWithAlloc>(MoveFixedArrWithAlloc(kLargeSize));
+}
+
TEST(FixedArrayExceptionSafety, SizeConstructor) {
TestThrowingCtor<FixedArr>(kSmallSize);
TestThrowingCtor<FixedArr>(kLargeSize);
}
+TEST(FixedArrayExceptionSafety, SizeConstructorWithAlloc) {
+ TestThrowingCtor<FixedArrWithAlloc>(kSmallSize);
+ TestThrowingCtor<FixedArrWithAlloc>(kLargeSize);
+}
+
TEST(FixedArrayExceptionSafety, SizeValueConstructor) {
TestThrowingCtor<FixedArr>(kSmallSize, Thrower());
TestThrowingCtor<FixedArr>(kLargeSize, Thrower());
}
+TEST(FixedArrayExceptionSafety, SizeValueConstructorWithAlloc) {
+ TestThrowingCtor<FixedArrWithAlloc>(kSmallSize, Thrower());
+ TestThrowingCtor<FixedArrWithAlloc>(kLargeSize, Thrower());
+}
+
TEST(FixedArrayExceptionSafety, IteratorConstructor) {
auto small = FixedArr(kSmallSize);
TestThrowingCtor<FixedArr>(small.begin(), small.end());
@@ -77,6 +113,14 @@
TestThrowingCtor<FixedArr>(large.begin(), large.end());
}
+TEST(FixedArrayExceptionSafety, IteratorConstructorWithAlloc) {
+ auto small = FixedArrWithAlloc(kSmallSize);
+ TestThrowingCtor<FixedArrWithAlloc>(small.begin(), small.end());
+
+ auto large = FixedArrWithAlloc(kLargeSize);
+ TestThrowingCtor<FixedArrWithAlloc>(large.begin(), large.end());
+}
+
TEST(FixedArrayExceptionSafety, InitListConstructor) {
constexpr int small_inlined = 3;
using SmallFixedArr = absl::FixedArray<Thrower, small_inlined>;
@@ -90,9 +134,23 @@
Thrower{}, Thrower{}, Thrower{}, Thrower{}, Thrower{}});
}
-testing::AssertionResult ReadMemory(FixedArr* fixed_arr) {
- // Marked volatile to prevent optimization. Used for running asan tests.
- volatile int sum = 0;
+TEST(FixedArrayExceptionSafety, InitListConstructorWithAlloc) {
+ constexpr int small_inlined = 3;
+ using SmallFixedArrWithAlloc =
+ absl::FixedArray<Thrower, small_inlined, ThrowAlloc>;
+
+ TestThrowingCtor<SmallFixedArrWithAlloc>(std::initializer_list<Thrower>{});
+ // Test inlined allocation
+ TestThrowingCtor<SmallFixedArrWithAlloc>(
+ std::initializer_list<Thrower>{Thrower{}, Thrower{}});
+ // Test out of line allocation
+ TestThrowingCtor<SmallFixedArrWithAlloc>(std::initializer_list<Thrower>{
+ Thrower{}, Thrower{}, Thrower{}, Thrower{}, Thrower{}});
+}
+
+template <typename FixedArrT>
+testing::AssertionResult ReadMemory(FixedArrT* fixed_arr) {
+ int sum = 0;
for (const auto& thrower : *fixed_arr) {
sum += thrower.Get();
}
@@ -101,7 +159,7 @@
TEST(FixedArrayExceptionSafety, Fill) {
auto test_fill = testing::MakeExceptionSafetyTester()
- .WithContracts(ReadMemory)
+ .WithContracts(ReadMemory<FixedArr>)
.WithOperation([&](FixedArr* fixed_arr_ptr) {
auto thrower =
Thrower(kUpdatedValue, testing::nothrow_ctor);
@@ -116,8 +174,28 @@
.Test());
}
+TEST(FixedArrayExceptionSafety, FillWithAlloc) {
+ auto test_fill = testing::MakeExceptionSafetyTester()
+ .WithContracts(ReadMemory<FixedArrWithAlloc>)
+ .WithOperation([&](FixedArrWithAlloc* fixed_arr_ptr) {
+ auto thrower =
+ Thrower(kUpdatedValue, testing::nothrow_ctor);
+ fixed_arr_ptr->fill(thrower);
+ });
+
+ EXPECT_TRUE(test_fill
+ .WithInitialValue(
+ FixedArrWithAlloc(kSmallSize, Thrower(kInitialValue)))
+ .Test());
+ EXPECT_TRUE(test_fill
+ .WithInitialValue(
+ FixedArrWithAlloc(kLargeSize, Thrower(kInitialValue)))
+ .Test());
+}
+
} // namespace
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_HAVE_EXCEPTIONS
diff --git a/third_party/abseil/absl/container/fixed_array_test.cc b/third_party/abseil/absl/container/fixed_array_test.cc
index 2b1cf47..49598e7 100644
--- a/third_party/abseil/absl/container/fixed_array_test.cc
+++ b/third_party/abseil/absl/container/fixed_array_test.cc
@@ -27,7 +27,10 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/base/config.h"
#include "absl/base/internal/exception_testing.h"
+#include "absl/base/options.h"
+#include "absl/container/internal/counting_allocator.h"
#include "absl/hash/hash_testing.h"
#include "absl/memory/memory.h"
@@ -188,6 +191,21 @@
"failed bounds check");
}
+TEST(FixedArrayTest, Hardened) {
+#if !defined(NDEBUG) || ABSL_OPTION_HARDENED
+ absl::FixedArray<int> a = {1, 2, 3};
+ EXPECT_EQ(a[2], 3);
+ EXPECT_DEATH_IF_SUPPORTED(a[3], "");
+ EXPECT_DEATH_IF_SUPPORTED(a[-1], "");
+
+ absl::FixedArray<int> empty(0);
+ EXPECT_DEATH_IF_SUPPORTED(empty[0], "");
+ EXPECT_DEATH_IF_SUPPORTED(empty[-1], "");
+ EXPECT_DEATH_IF_SUPPORTED(empty.front(), "");
+ EXPECT_DEATH_IF_SUPPORTED(empty.back(), "");
+#endif
+}
+
TEST(FixedArrayRelationalsTest, EqualArrays) {
for (int i = 0; i < 10; ++i) {
absl::FixedArray<int, 5> a1(i);
@@ -604,19 +622,16 @@
empty.fill(fill_val);
}
-// TODO(johnsoncj): Investigate InlinedStorage default initialization in GCC 4.x
#ifndef __GNUC__
TEST(FixedArrayTest, DefaultCtorDoesNotValueInit) {
using T = char;
constexpr auto capacity = 10;
using FixedArrType = absl::FixedArray<T, capacity>;
- using FixedArrBuffType =
- absl::aligned_storage_t<sizeof(FixedArrType), alignof(FixedArrType)>;
constexpr auto scrubbed_bits = 0x95;
constexpr auto length = capacity / 2;
- FixedArrBuffType buff;
- std::memset(std::addressof(buff), scrubbed_bits, sizeof(FixedArrBuffType));
+ alignas(FixedArrType) unsigned char buff[sizeof(FixedArrType)];
+ std::memset(std::addressof(buff), scrubbed_bits, sizeof(FixedArrType));
FixedArrType* arr =
::new (static_cast<void*>(std::addressof(buff))) FixedArrType(length);
@@ -625,70 +640,9 @@
}
#endif // __GNUC__
-// 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), instance_count_(nullptr) {}
- explicit CountingAllocator(int64_t* b)
- : bytes_used_(b), instance_count_(nullptr) {}
- CountingAllocator(int64_t* b, int64_t* a)
- : bytes_used_(b), instance_count_(a) {}
-
- template <typename U>
- explicit CountingAllocator(const CountingAllocator<U>& x)
- : Alloc(x),
- bytes_used_(x.bytes_used_),
- instance_count_(x.instance_count_) {}
-
- pointer allocate(size_type n, const void* const 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... Args>
- void construct(pointer p, Args&&... args) {
- Alloc::construct(p, absl::forward<Args>(args)...);
- if (instance_count_) {
- *instance_count_ += 1;
- }
- }
-
- void destroy(pointer p) {
- Alloc::destroy(p);
- if (instance_count_) {
- *instance_count_ -= 1;
- }
- }
-
- template <typename U>
- class rebind {
- public:
- using other = CountingAllocator<U>;
- };
-
- int64_t* bytes_used_;
- int64_t* instance_count_;
-};
-
TEST(AllocatorSupportTest, CountInlineAllocations) {
constexpr size_t inlined_size = 4;
- using Alloc = CountingAllocator<int>;
+ using Alloc = absl::container_internal::CountingAllocator<int>;
using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
int64_t allocated = 0;
@@ -709,7 +663,7 @@
TEST(AllocatorSupportTest, CountOutoflineAllocations) {
constexpr size_t inlined_size = 4;
- using Alloc = CountingAllocator<int>;
+ using Alloc = absl::container_internal::CountingAllocator<int>;
using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
int64_t allocated = 0;
@@ -730,7 +684,7 @@
TEST(AllocatorSupportTest, CountCopyInlineAllocations) {
constexpr size_t inlined_size = 4;
- using Alloc = CountingAllocator<int>;
+ using Alloc = absl::container_internal::CountingAllocator<int>;
using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
int64_t allocated1 = 0;
@@ -758,7 +712,7 @@
TEST(AllocatorSupportTest, CountCopyOutoflineAllocations) {
constexpr size_t inlined_size = 4;
- using Alloc = CountingAllocator<int>;
+ using Alloc = absl::container_internal::CountingAllocator<int>;
using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
int64_t allocated1 = 0;
@@ -790,7 +744,7 @@
using testing::SizeIs;
constexpr size_t inlined_size = 4;
- using Alloc = CountingAllocator<int>;
+ using Alloc = absl::container_internal::CountingAllocator<int>;
using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
{
@@ -814,16 +768,16 @@
}
}
-#ifdef ADDRESS_SANITIZER
+#ifdef ABSL_HAVE_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");
+ EXPECT_DEATH_IF_SUPPORTED(raw[-2] = 0, "container-overflow");
+ EXPECT_DEATH_IF_SUPPORTED(raw[-1] = 0, "container-overflow");
+ EXPECT_DEATH_IF_SUPPORTED(raw[10] = 0, "container-overflow");
+ EXPECT_DEATH_IF_SUPPORTED(raw[31] = 0, "container-overflow");
}
TEST(FixedArrayTest, AddressSanitizerAnnotations2) {
@@ -831,10 +785,10 @@
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");
+ EXPECT_DEATH_IF_SUPPORTED(raw[-7] = 0, "container-overflow");
+ EXPECT_DEATH_IF_SUPPORTED(raw[-1] = 0, "container-overflow");
+ EXPECT_DEATH_IF_SUPPORTED(raw[12] = 0, "container-overflow");
+ EXPECT_DEATH_IF_SUPPORTED(raw[17] = 0, "container-overflow");
}
TEST(FixedArrayTest, AddressSanitizerAnnotations3) {
@@ -842,8 +796,8 @@
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");
+ EXPECT_DEATH_IF_SUPPORTED(raw[-1] = 0, "container-overflow");
+ EXPECT_DEATH_IF_SUPPORTED(raw[20] = 0, "container-overflow");
}
TEST(FixedArrayTest, AddressSanitizerAnnotations4) {
@@ -855,13 +809,13 @@
// 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");
+ EXPECT_DEATH_IF_SUPPORTED(raw[-1].z_ = 0, "container-overflow");
+ EXPECT_DEATH_IF_SUPPORTED(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");
+ EXPECT_DEATH_IF_SUPPORTED(raw[21] = ThreeInts(), "container-overflow");
}
-#endif // ADDRESS_SANITIZER
+#endif // ABSL_HAVE_ADDRESS_SANITIZER
TEST(FixedArrayTest, AbslHashValueWorks) {
using V = absl::FixedArray<int>;
diff --git a/third_party/abseil/absl/container/flat_hash_map.h b/third_party/abseil/absl/container/flat_hash_map.h
index 5c16ac8..74def0d 100644
--- a/third_party/abseil/absl/container/flat_hash_map.h
+++ b/third_party/abseil/absl/container/flat_hash_map.h
@@ -42,6 +42,7 @@
#include "absl/memory/memory.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
template <class K, class V>
struct FlatHashMapPolicy;
@@ -233,7 +234,8 @@
//
// size_type erase(const key_type& key):
//
- // Erases the element with the matching key, if it exists.
+ // Erases the element with the matching key, if it exists, returning the
+ // number of elements erased (0 or 1).
using Base::erase;
// flat_hash_map::insert()
@@ -382,6 +384,11 @@
// key value and returns a node handle owning that extracted data. If the
// `flat_hash_map` does not contain an element with a matching key, this
// function returns an empty node handle.
+ //
+ // NOTE: when compiled in an earlier version of C++ than C++17,
+ // `node_type::key()` returns a const reference to the key instead of a
+ // mutable reference. We cannot safely return a mutable reference without
+ // std::launder (which is not available before C++17).
using Base::extract;
// flat_hash_map::merge()
@@ -401,7 +408,7 @@
// for the past-the-end iterator, which is invalidated.
//
// `swap()` requires that the flat hash map's hashing and key equivalence
- // functions be Swappable, and are exchaged using unqualified calls to
+ // functions be Swappable, and are exchanged using unqualified calls to
// non-member `swap()`. If the map's allocator has
// `std::allocator_traits<allocator_type>::propagate_on_container_swap::value`
// set to `true`, the allocators are also exchanged using an unqualified call
@@ -531,6 +538,15 @@
using Base::key_eq;
};
+// erase_if(flat_hash_map<>, Pred)
+//
+// Erases all elements that satisfy the predicate `pred` from the container `c`.
+template <typename K, typename V, typename H, typename E, typename A,
+ typename Predicate>
+void erase_if(flat_hash_map<K, V, H, E, A>& c, Predicate pred) {
+ container_internal::EraseIf(pred, &c);
+}
+
namespace container_internal {
template <class K, class V>
@@ -584,6 +600,7 @@
} // namespace container_algorithm_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_FLAT_HASH_MAP_H_
diff --git a/third_party/abseil/absl/container/flat_hash_map_test.cc b/third_party/abseil/absl/container/flat_hash_map_test.cc
index 6cff1a2..89ec60c 100644
--- a/third_party/abseil/absl/container/flat_hash_map_test.cc
+++ b/third_party/abseil/absl/container/flat_hash_map_test.cc
@@ -16,6 +16,7 @@
#include <memory>
+#include "absl/base/internal/raw_logging.h"
#include "absl/container/internal/hash_generator_testing.h"
#include "absl/container/internal/unordered_map_constructor_test.h"
#include "absl/container/internal/unordered_map_lookup_test.h"
@@ -24,14 +25,29 @@
#include "absl/types/any.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace {
using ::absl::container_internal::hash_internal::Enum;
using ::absl::container_internal::hash_internal::EnumClass;
using ::testing::_;
+using ::testing::IsEmpty;
using ::testing::Pair;
using ::testing::UnorderedElementsAre;
+// Check that absl::flat_hash_map works in a global constructor.
+struct BeforeMain {
+ BeforeMain() {
+ absl::flat_hash_map<int, int> x;
+ x.insert({1, 1});
+ ABSL_RAW_CHECK(x.find(0) == x.end(), "x should not contain 0");
+ auto it = x.find(1);
+ ABSL_RAW_CHECK(it != x.end(), "x should contain 1");
+ ABSL_RAW_CHECK(it->second, "1 should map to 1");
+ }
+};
+const BeforeMain before_main;
+
template <class K, class V>
using Map = flat_hash_map<K, V, StatefulTestingHash, StatefulTestingEqual,
Alloc<std::pair<const K, V>>>;
@@ -214,41 +230,59 @@
EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 17), Pair(2, 9)));
}
-#if (defined(ABSL_HAVE_STD_ANY) || !defined(_LIBCPP_VERSION)) && \
- !defined(__EMSCRIPTEN__)
-TEST(FlatHashMap, Any) {
- absl::flat_hash_map<int, absl::any> m;
- m.emplace(1, 7);
- auto it = m.find(1);
- ASSERT_NE(it, m.end());
- EXPECT_EQ(7, absl::any_cast<int>(it->second));
+bool FirstIsEven(std::pair<const int, int> p) { return p.first % 2 == 0; }
- m.emplace(std::piecewise_construct, std::make_tuple(2), std::make_tuple(8));
- it = m.find(2);
- ASSERT_NE(it, m.end());
- EXPECT_EQ(8, absl::any_cast<int>(it->second));
-
- m.emplace(std::piecewise_construct, std::make_tuple(3),
- std::make_tuple(absl::any(9)));
- it = m.find(3);
- ASSERT_NE(it, m.end());
- EXPECT_EQ(9, absl::any_cast<int>(it->second));
-
- struct H {
- size_t operator()(const absl::any&) const { return 0; }
- };
- struct E {
- bool operator()(const absl::any&, const absl::any&) const { return true; }
- };
- absl::flat_hash_map<absl::any, int, H, E> m2;
- m2.emplace(1, 7);
- auto it2 = m2.find(1);
- ASSERT_NE(it2, m2.end());
- EXPECT_EQ(7, it2->second);
+TEST(FlatHashMap, EraseIf) {
+ // Erase all elements.
+ {
+ flat_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+ erase_if(s, [](std::pair<const int, int>) { return true; });
+ EXPECT_THAT(s, IsEmpty());
+ }
+ // Erase no elements.
+ {
+ flat_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+ erase_if(s, [](std::pair<const int, int>) { return false; });
+ EXPECT_THAT(s, UnorderedElementsAre(Pair(1, 1), Pair(2, 2), Pair(3, 3),
+ Pair(4, 4), Pair(5, 5)));
+ }
+ // Erase specific elements.
+ {
+ flat_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+ erase_if(s,
+ [](std::pair<const int, int> kvp) { return kvp.first % 2 == 1; });
+ EXPECT_THAT(s, UnorderedElementsAre(Pair(2, 2), Pair(4, 4)));
+ }
+ // Predicate is function reference.
+ {
+ flat_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+ erase_if(s, FirstIsEven);
+ EXPECT_THAT(s, UnorderedElementsAre(Pair(1, 1), Pair(3, 3), Pair(5, 5)));
+ }
+ // Predicate is function pointer.
+ {
+ flat_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+ erase_if(s, &FirstIsEven);
+ EXPECT_THAT(s, UnorderedElementsAre(Pair(1, 1), Pair(3, 3), Pair(5, 5)));
+ }
}
-#endif // (defined(ABSL_HAVE_STD_ANY) || !defined(_LIBCPP_VERSION)) &&
- // !defined(__EMSCRIPTEN__)
+
+// This test requires std::launder for mutable key access in node handles.
+#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
+TEST(FlatHashMap, NodeHandleMutableKeyAccess) {
+ flat_hash_map<std::string, std::string> map;
+
+ map["key1"] = "mapped";
+
+ auto nh = map.extract(map.begin());
+ nh.key().resize(3);
+ map.insert(std::move(nh));
+
+ EXPECT_THAT(map, testing::ElementsAre(Pair("key", "mapped")));
+}
+#endif
} // namespace
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/container/flat_hash_set.h b/third_party/abseil/absl/container/flat_hash_set.h
index 2a51c34..6b89da6 100644
--- a/third_party/abseil/absl/container/flat_hash_set.h
+++ b/third_party/abseil/absl/container/flat_hash_set.h
@@ -40,6 +40,7 @@
#include "absl/memory/memory.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
template <typename T>
struct FlatHashSetPolicy;
@@ -226,7 +227,8 @@
//
// size_type erase(const key_type& key):
//
- // Erases the element with the matching key, if it exists.
+ // Erases the element with the matching key, if it exists, returning the
+ // number of elements erased (0 or 1).
using Base::erase;
// flat_hash_set::insert()
@@ -322,7 +324,7 @@
// flat_hash_set::merge()
//
- // Extracts elements from a given `source` flat hash map into this
+ // Extracts elements from a given `source` flat hash set into this
// `flat_hash_set`. If the destination `flat_hash_set` already contains an
// element with an equivalent key, that element is not extracted.
using Base::merge;
@@ -438,6 +440,14 @@
using Base::key_eq;
};
+// erase_if(flat_hash_set<>, Pred)
+//
+// Erases all elements that satisfy the predicate `pred` from the container `c`.
+template <typename T, typename H, typename E, typename A, typename Predicate>
+void erase_if(flat_hash_set<T, H, E, A>& c, Predicate pred) {
+ container_internal::EraseIf(pred, &c);
+}
+
namespace container_internal {
template <class T>
@@ -488,6 +498,7 @@
} // namespace container_algorithm_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_FLAT_HASH_SET_H_
diff --git a/third_party/abseil/absl/container/flat_hash_set_test.cc b/third_party/abseil/absl/container/flat_hash_set_test.cc
index b55be59..8f6f994 100644
--- a/third_party/abseil/absl/container/flat_hash_set_test.cc
+++ b/third_party/abseil/absl/container/flat_hash_set_test.cc
@@ -16,6 +16,7 @@
#include <vector>
+#include "absl/base/internal/raw_logging.h"
#include "absl/container/internal/hash_generator_testing.h"
#include "absl/container/internal/unordered_set_constructor_test.h"
#include "absl/container/internal/unordered_set_lookup_test.h"
@@ -25,15 +26,28 @@
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace {
using ::absl::container_internal::hash_internal::Enum;
using ::absl::container_internal::hash_internal::EnumClass;
+using ::testing::IsEmpty;
using ::testing::Pointee;
using ::testing::UnorderedElementsAre;
using ::testing::UnorderedElementsAreArray;
+// Check that absl::flat_hash_set works in a global constructor.
+struct BeforeMain {
+ BeforeMain() {
+ absl::flat_hash_set<int> x;
+ x.insert(1);
+ ABSL_RAW_CHECK(!x.contains(0), "x should not contain 0");
+ ABSL_RAW_CHECK(x.contains(1), "x should contain 1");
+ }
+};
+const BeforeMain before_main;
+
template <class T>
using Set =
absl::flat_hash_set<T, StatefulTestingHash, StatefulTestingEqual, Alloc<T>>;
@@ -123,6 +137,42 @@
EXPECT_THAT(set2, UnorderedElementsAre(Pointee(7), Pointee(23)));
}
+bool IsEven(int k) { return k % 2 == 0; }
+
+TEST(FlatHashSet, EraseIf) {
+ // Erase all elements.
+ {
+ flat_hash_set<int> s = {1, 2, 3, 4, 5};
+ erase_if(s, [](int) { return true; });
+ EXPECT_THAT(s, IsEmpty());
+ }
+ // Erase no elements.
+ {
+ flat_hash_set<int> s = {1, 2, 3, 4, 5};
+ erase_if(s, [](int) { return false; });
+ EXPECT_THAT(s, UnorderedElementsAre(1, 2, 3, 4, 5));
+ }
+ // Erase specific elements.
+ {
+ flat_hash_set<int> s = {1, 2, 3, 4, 5};
+ erase_if(s, [](int k) { return k % 2 == 1; });
+ EXPECT_THAT(s, UnorderedElementsAre(2, 4));
+ }
+ // Predicate is function reference.
+ {
+ flat_hash_set<int> s = {1, 2, 3, 4, 5};
+ erase_if(s, IsEven);
+ EXPECT_THAT(s, UnorderedElementsAre(1, 3, 5));
+ }
+ // Predicate is function pointer.
+ {
+ flat_hash_set<int> s = {1, 2, 3, 4, 5};
+ erase_if(s, &IsEven);
+ EXPECT_THAT(s, UnorderedElementsAre(1, 3, 5));
+ }
+}
+
} // namespace
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/container/inlined_vector.h b/third_party/abseil/absl/container/inlined_vector.h
index 5138348..90bb96e 100644
--- a/third_party/abseil/absl/container/inlined_vector.h
+++ b/third_party/abseil/absl/container/inlined_vector.h
@@ -48,12 +48,14 @@
#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/container/internal/inlined_vector.h"
#include "absl/memory/memory.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// -----------------------------------------------------------------------------
// InlinedVector
// -----------------------------------------------------------------------------
@@ -62,16 +64,17 @@
// `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
// capacity, 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
+// 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 {
static_assert(N > 0, "`absl::InlinedVector` requires an inlined capacity.");
using Storage = inlined_vector_internal::Storage<T, N, A>;
- using rvalue_reference = typename Storage::rvalue_reference;
- using MoveIterator = typename Storage::MoveIterator;
+
using AllocatorTraits = typename Storage::AllocatorTraits;
+ using RValueReference = typename Storage::RValueReference;
+ using MoveIterator = typename Storage::MoveIterator;
using IsMemcpyOk = typename Storage::IsMemcpyOk;
template <typename Iterator>
@@ -92,10 +95,10 @@
using value_type = typename Storage::value_type;
using pointer = typename Storage::pointer;
using const_pointer = typename Storage::const_pointer;
- using reference = typename Storage::reference;
- using const_reference = typename Storage::const_reference;
using size_type = typename Storage::size_type;
using difference_type = typename Storage::difference_type;
+ using reference = typename Storage::reference;
+ using const_reference = typename Storage::const_reference;
using iterator = typename Storage::iterator;
using const_iterator = typename Storage::const_iterator;
using reverse_iterator = typename Storage::reverse_iterator;
@@ -305,16 +308,14 @@
//
// Returns a `reference` to the `i`th element of the inlined vector.
reference operator[](size_type i) {
- assert(i < size());
-
+ ABSL_HARDENING_ASSERT(i < size());
return data()[i];
}
// Overload of `InlinedVector::operator[](...)` that returns a
// `const_reference` to the `i`th element of the inlined vector.
const_reference operator[](size_type i) const {
- assert(i < size());
-
+ ABSL_HARDENING_ASSERT(i < size());
return data()[i];
}
@@ -329,7 +330,6 @@
base_internal::ThrowStdOutOfRange(
"`InlinedVector::at(size_type)` failed bounds check");
}
-
return data()[i];
}
@@ -343,7 +343,6 @@
base_internal::ThrowStdOutOfRange(
"`InlinedVector::at(size_type) const` failed bounds check");
}
-
return data()[i];
}
@@ -351,34 +350,30 @@
//
// Returns a `reference` to the first element of the inlined vector.
reference front() {
- assert(!empty());
-
- return at(0);
+ ABSL_HARDENING_ASSERT(!empty());
+ return data()[0];
}
// Overload of `InlinedVector::front()` that returns a `const_reference` to
// the first element of the inlined vector.
const_reference front() const {
- assert(!empty());
-
- return at(0);
+ ABSL_HARDENING_ASSERT(!empty());
+ return data()[0];
}
// `InlinedVector::back()`
//
// Returns a `reference` to the last element of the inlined vector.
reference back() {
- assert(!empty());
-
- return at(size() - 1);
+ ABSL_HARDENING_ASSERT(!empty());
+ return data()[size() - 1];
}
// Overload of `InlinedVector::back()` that returns a `const_reference` to the
// last element of the inlined vector.
const_reference back() const {
- assert(!empty());
-
- return at(size() - 1);
+ ABSL_HARDENING_ASSERT(!empty());
+ return data()[size() - 1];
}
// `InlinedVector::begin()`
@@ -529,7 +524,7 @@
void assign(InputIterator first, InputIterator last) {
size_type i = 0;
for (; i < size() && first != last; ++i, static_cast<void>(++first)) {
- at(i) = *first;
+ data()[i] = *first;
}
erase(data() + i, data() + size());
@@ -540,9 +535,12 @@
//
// Resizes the inlined vector to contain `n` elements.
//
- // NOTE: if `n` is smaller than `size()`, extra elements are destroyed. If `n`
+ // NOTE: If `n` is smaller than `size()`, extra elements are destroyed. If `n`
// is larger than `size()`, new elements are value-initialized.
- void resize(size_type n) { storage_.Resize(DefaultValueAdapter(), n); }
+ void resize(size_type n) {
+ ABSL_HARDENING_ASSERT(n <= max_size());
+ storage_.Resize(DefaultValueAdapter(), n);
+ }
// Overload of `InlinedVector::resize(...)` that resizes the inlined vector to
// contain `n` elements.
@@ -550,6 +548,7 @@
// NOTE: if `n` is smaller than `size()`, extra elements are destroyed. If `n`
// is larger than `size()`, new elements are copied-constructed from `v`.
void resize(size_type n, const_reference v) {
+ ABSL_HARDENING_ASSERT(n <= max_size());
storage_.Resize(CopyValueAdapter(v), n);
}
@@ -563,7 +562,7 @@
// Overload of `InlinedVector::insert(...)` that inserts `v` at `pos` using
// move semantics, returning an `iterator` to the newly inserted element.
- iterator insert(const_iterator pos, rvalue_reference v) {
+ iterator insert(const_iterator pos, RValueReference v) {
return emplace(pos, std::move(v));
}
@@ -571,8 +570,8 @@
// of `v` starting at `pos`, returning an `iterator` pointing to the first of
// the newly inserted elements.
iterator insert(const_iterator pos, size_type n, const_reference v) {
- assert(pos >= begin());
- assert(pos <= end());
+ ABSL_HARDENING_ASSERT(pos >= begin());
+ ABSL_HARDENING_ASSERT(pos <= end());
if (ABSL_PREDICT_TRUE(n != 0)) {
value_type dealias = v;
@@ -598,8 +597,8 @@
EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
iterator insert(const_iterator pos, ForwardIterator first,
ForwardIterator last) {
- assert(pos >= begin());
- assert(pos <= end());
+ ABSL_HARDENING_ASSERT(pos >= begin());
+ ABSL_HARDENING_ASSERT(pos <= end());
if (ABSL_PREDICT_TRUE(first != last)) {
return storage_.Insert(pos, IteratorValueAdapter<ForwardIterator>(first),
@@ -617,8 +616,8 @@
template <typename InputIterator,
DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
iterator insert(const_iterator pos, InputIterator first, InputIterator last) {
- assert(pos >= begin());
- assert(pos <= end());
+ ABSL_HARDENING_ASSERT(pos >= begin());
+ ABSL_HARDENING_ASSERT(pos <= end());
size_type index = std::distance(cbegin(), pos);
for (size_type i = index; first != last; ++i, static_cast<void>(++first)) {
@@ -634,8 +633,8 @@
// `pos`, returning an `iterator` pointing to the newly emplaced element.
template <typename... Args>
iterator emplace(const_iterator pos, Args&&... args) {
- assert(pos >= begin());
- assert(pos <= end());
+ ABSL_HARDENING_ASSERT(pos >= begin());
+ ABSL_HARDENING_ASSERT(pos <= end());
value_type dealias(std::forward<Args>(args)...);
return storage_.Insert(pos,
@@ -660,7 +659,7 @@
// Overload of `InlinedVector::push_back(...)` for inserting `v` at `end()`
// using move semantics.
- void push_back(rvalue_reference v) {
+ void push_back(RValueReference v) {
static_cast<void>(emplace_back(std::move(v)));
}
@@ -668,7 +667,7 @@
//
// Destroys the element at `back()`, reducing the size by `1`.
void pop_back() noexcept {
- assert(!empty());
+ ABSL_HARDENING_ASSERT(!empty());
AllocatorTraits::destroy(*storage_.GetAllocPtr(), data() + (size() - 1));
storage_.SubtractSize(1);
@@ -681,8 +680,8 @@
//
// NOTE: may return `end()`, which is not dereferencable.
iterator erase(const_iterator pos) {
- assert(pos >= begin());
- assert(pos < end());
+ ABSL_HARDENING_ASSERT(pos >= begin());
+ ABSL_HARDENING_ASSERT(pos < end());
return storage_.Erase(pos, pos + 1);
}
@@ -693,9 +692,9 @@
//
// NOTE: may return `end()`, which is not dereferencable.
iterator erase(const_iterator from, const_iterator to) {
- assert(from >= begin());
- assert(from <= to);
- assert(to <= end());
+ ABSL_HARDENING_ASSERT(from >= begin());
+ ABSL_HARDENING_ASSERT(from <= to);
+ ABSL_HARDENING_ASSERT(to <= end());
if (ABSL_PREDICT_TRUE(from != to)) {
return storage_.Erase(from, to);
@@ -840,6 +839,7 @@
return H::combine(H::combine_contiguous(std::move(h), a.data(), size), size);
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INLINED_VECTOR_H_
diff --git a/third_party/abseil/absl/container/inlined_vector_benchmark.cc b/third_party/abseil/absl/container/inlined_vector_benchmark.cc
index 3f2b4ed..b8dafe9 100644
--- a/third_party/abseil/absl/container/inlined_vector_benchmark.cc
+++ b/third_party/abseil/absl/container/inlined_vector_benchmark.cc
@@ -83,7 +83,7 @@
}
ABSL_RAW_LOG(
FATAL,
- "Failed to find a std::string larger than the short std::string optimization");
+ "Failed to find a string larger than the short string optimization");
return -1;
}
diff --git a/third_party/abseil/absl/container/inlined_vector_exception_safety_test.cc b/third_party/abseil/absl/container/inlined_vector_exception_safety_test.cc
index 25994f1..0e6a05b 100644
--- a/third_party/abseil/absl/container/inlined_vector_exception_safety_test.cc
+++ b/third_party/abseil/absl/container/inlined_vector_exception_safety_test.cc
@@ -16,7 +16,7 @@
#include "absl/base/config.h"
-#ifdef ABSL_HAVE_EXCEPTIONS
+#if defined(ABSL_HAVE_EXCEPTIONS)
#include <array>
#include <initializer_list>
@@ -364,9 +364,11 @@
using VecT = typename TypeParam::VecT;
constexpr static auto size = TypeParam::GetSizeAt(0);
+ // For testing calls to `emplace_back(...)` that reallocate.
VecT full_vec{size};
full_vec.resize(full_vec.capacity());
+ // For testing calls to `emplace_back(...)` that don't reallocate.
VecT nonfull_vec{size};
nonfull_vec.reserve(size + 1);
@@ -374,12 +376,11 @@
InlinedVectorInvariants<VecT>);
EXPECT_TRUE(tester.WithInitialValue(nonfull_vec).Test([](VecT* vec) {
- vec->emplace_back(); //
+ vec->emplace_back();
}));
- EXPECT_TRUE(tester.WithInitialValue(full_vec).Test([](VecT* vec) {
- vec->emplace_back(); //
- }));
+ EXPECT_TRUE(tester.WithInitialValue(full_vec).Test(
+ [](VecT* vec) { vec->emplace_back(); }));
}
TYPED_TEST(OneSizeTest, PopBack) {
@@ -418,6 +419,19 @@
EXPECT_TRUE(tester.Test([](VecT* vec) {
auto it = vec->begin();
+ vec->erase(it, it);
+ }));
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ auto it = vec->begin() + (vec->size() / 2);
+ vec->erase(it, it);
+ }));
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ auto it = vec->begin() + (vec->size() - 1);
+ vec->erase(it, it);
+ }));
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ auto it = vec->begin();
vec->erase(it, it + 1);
}));
EXPECT_TRUE(tester.Test([](VecT* vec) {
@@ -452,9 +466,7 @@
.WithInitialValue(VecT{from_size})
.WithContracts(InlinedVectorInvariants<VecT>);
- EXPECT_TRUE(tester.Test([](VecT* vec) {
- vec->reserve(to_capacity); //
- }));
+ EXPECT_TRUE(tester.Test([](VecT* vec) { vec->reserve(to_capacity); }));
}
TYPED_TEST(OneSizeTest, ShrinkToFit) {
@@ -493,4 +505,4 @@
} // namespace
-#endif // ABSL_HAVE_EXCEPTIONS
+#endif // defined(ABSL_HAVE_EXCEPTIONS)
diff --git a/third_party/abseil/absl/container/inlined_vector_test.cc b/third_party/abseil/absl/container/inlined_vector_test.cc
index 080ea95..98aff33 100644
--- a/third_party/abseil/absl/container/inlined_vector_test.cc
+++ b/third_party/abseil/absl/container/inlined_vector_test.cc
@@ -30,6 +30,7 @@
#include "absl/base/internal/exception_testing.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/macros.h"
+#include "absl/base/options.h"
#include "absl/container/internal/counting_allocator.h"
#include "absl/container/internal/test_instance_tracker.h"
#include "absl/hash/hash_testing.h"
@@ -247,6 +248,16 @@
}
}
+TEST(IntVec, Hardened) {
+ IntVec v;
+ Fill(&v, 10);
+ EXPECT_EQ(v[9], 9);
+#if !defined(NDEBUG) || ABSL_OPTION_HARDENED
+ EXPECT_DEATH_IF_SUPPORTED(v[10], "");
+ EXPECT_DEATH_IF_SUPPORTED(v[-1], "");
+#endif
+}
+
// 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.
@@ -725,22 +736,26 @@
// 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*));
+
+ struct T { void* val; };
+ size_t expected_overhead = sizeof(T);
+
+ EXPECT_EQ((2 * expected_overhead),
+ sizeof(absl::InlinedVector<T, 1>) - sizeof(T[1]));
+ EXPECT_EQ(expected_overhead,
+ sizeof(absl::InlinedVector<T, 2>) - sizeof(T[2]));
+ EXPECT_EQ(expected_overhead,
+ sizeof(absl::InlinedVector<T, 3>) - sizeof(T[3]));
+ EXPECT_EQ(expected_overhead,
+ sizeof(absl::InlinedVector<T, 4>) - sizeof(T[4]));
+ EXPECT_EQ(expected_overhead,
+ sizeof(absl::InlinedVector<T, 5>) - sizeof(T[5]));
+ EXPECT_EQ(expected_overhead,
+ sizeof(absl::InlinedVector<T, 6>) - sizeof(T[6]));
+ EXPECT_EQ(expected_overhead,
+ sizeof(absl::InlinedVector<T, 7>) - sizeof(T[7]));
+ EXPECT_EQ(expected_overhead,
+ sizeof(absl::InlinedVector<T, 8>) - sizeof(T[8]));
}
TEST(IntVec, Clear) {
@@ -780,7 +795,7 @@
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.";
+ const std::string s = "A quite long string to ensure heap.";
std_v.push_back(s);
v.push_back(s);
for (int i = 0; i < 20; ++i) {
@@ -795,7 +810,7 @@
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.";
+ const std::string s = "A quite long string to ensure heap.";
std_v.push_back(s);
v.push_back(s);
for (int i = 0; i < 20; ++i) {
@@ -808,7 +823,7 @@
}
TEST(StringVec, SelfMove) {
- const std::string s = "A quite long std::string to ensure heap.";
+ const std::string s = "A quite long string to ensure heap.";
for (int len = 0; len < 20; len++) {
SCOPED_TRACE(len);
absl::InlinedVector<std::string, 8> v;
@@ -1754,6 +1769,30 @@
}
}
+TEST(InlinedVectorTest, MinimumAllocatorCompilesUsingTraits) {
+ using T = int;
+ using A = std::allocator<T>;
+ using ATraits = absl::allocator_traits<A>;
+
+ struct MinimumAllocator {
+ using value_type = T;
+
+ value_type* allocate(size_t n) {
+ A a;
+ return ATraits::allocate(a, n);
+ }
+
+ void deallocate(value_type* p, size_t n) {
+ A a;
+ ATraits::deallocate(a, p, n);
+ }
+ };
+
+ absl::InlinedVector<T, 1, MinimumAllocator> vec;
+ vec.emplace_back();
+ vec.resize(0);
+}
+
TEST(InlinedVectorTest, AbslHashValueWorks) {
using V = absl::InlinedVector<int, 4>;
std::vector<V> cases;
diff --git a/third_party/abseil/absl/container/internal/btree.h b/third_party/abseil/absl/container/internal/btree.h
index b255984..6f5f01b 100644
--- a/third_party/abseil/absl/container/internal/btree.h
+++ b/third_party/abseil/absl/container/internal/btree.h
@@ -65,11 +65,13 @@
#include "absl/container/internal/layout.h"
#include "absl/memory/memory.h"
#include "absl/meta/type_traits.h"
+#include "absl/strings/cord.h"
#include "absl/strings/string_view.h"
#include "absl/types/compare.h"
#include "absl/utility/utility.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
// A helper class that indicates if the Compare parameter is a key-compare-to
@@ -92,6 +94,19 @@
absl::string_view rhs) const {
return compare_internal::compare_result_as_ordering(lhs.compare(rhs));
}
+ StringBtreeDefaultLess(std::less<absl::Cord>) {} // NOLINT
+ absl::weak_ordering operator()(const absl::Cord &lhs,
+ const absl::Cord &rhs) const {
+ return compare_internal::compare_result_as_ordering(lhs.Compare(rhs));
+ }
+ absl::weak_ordering operator()(const absl::Cord &lhs,
+ absl::string_view rhs) const {
+ return compare_internal::compare_result_as_ordering(lhs.Compare(rhs));
+ }
+ absl::weak_ordering operator()(absl::string_view lhs,
+ const absl::Cord &rhs) const {
+ return compare_internal::compare_result_as_ordering(-rhs.Compare(lhs));
+ }
};
struct StringBtreeDefaultGreater {
@@ -106,17 +121,30 @@
absl::string_view rhs) const {
return compare_internal::compare_result_as_ordering(rhs.compare(lhs));
}
+ StringBtreeDefaultGreater(std::greater<absl::Cord>) {} // NOLINT
+ absl::weak_ordering operator()(const absl::Cord &lhs,
+ const absl::Cord &rhs) const {
+ return compare_internal::compare_result_as_ordering(rhs.Compare(lhs));
+ }
+ absl::weak_ordering operator()(const absl::Cord &lhs,
+ absl::string_view rhs) const {
+ return compare_internal::compare_result_as_ordering(-lhs.Compare(rhs));
+ }
+ absl::weak_ordering operator()(absl::string_view lhs,
+ const absl::Cord &rhs) const {
+ return compare_internal::compare_result_as_ordering(rhs.Compare(lhs));
+ }
};
// A helper class to convert a boolean comparison into a three-way "compare-to"
-// comparison that returns a negative value to indicate less-than, zero to
-// indicate equality and a positive value to indicate greater-than. This helper
+// comparison that returns an `absl::weak_ordering`. This helper
// class is specialized for less<std::string>, greater<std::string>,
-// less<string_view>, and greater<string_view>.
+// less<string_view>, greater<string_view>, less<absl::Cord>, and
+// greater<absl::Cord>.
//
// key_compare_to_adapter is provided so that btree users
// automatically get the more efficient compare-to code when using common
-// google string types with common comparison functors.
+// Abseil string types with common comparison functors.
// These string-like specializations also turn on heterogeneous lookup by
// default.
template <typename Compare>
@@ -144,10 +172,52 @@
using type = StringBtreeDefaultGreater;
};
+template <>
+struct key_compare_to_adapter<std::less<absl::Cord>> {
+ using type = StringBtreeDefaultLess;
+};
+
+template <>
+struct key_compare_to_adapter<std::greater<absl::Cord>> {
+ using type = StringBtreeDefaultGreater;
+};
+
+// Detects an 'absl_btree_prefer_linear_node_search' member. This is
+// a protocol used as an opt-in or opt-out of linear search.
+//
+// For example, this would be useful for key types that wrap an integer
+// and define their own cheap operator<(). For example:
+//
+// class K {
+// public:
+// using absl_btree_prefer_linear_node_search = std::true_type;
+// ...
+// private:
+// friend bool operator<(K a, K b) { return a.k_ < b.k_; }
+// int k_;
+// };
+//
+// btree_map<K, V> m; // Uses linear search
+//
+// If T has the preference tag, then it has a preference.
+// Btree will use the tag's truth value.
+template <typename T, typename = void>
+struct has_linear_node_search_preference : std::false_type {};
+template <typename T, typename = void>
+struct prefers_linear_node_search : std::false_type {};
+template <typename T>
+struct has_linear_node_search_preference<
+ T, absl::void_t<typename T::absl_btree_prefer_linear_node_search>>
+ : std::true_type {};
+template <typename T>
+struct prefers_linear_node_search<
+ T, absl::void_t<typename T::absl_btree_prefer_linear_node_search>>
+ : T::absl_btree_prefer_linear_node_search {};
+
template <typename Key, typename Compare, typename Alloc, int TargetNodeSize,
bool Multi, typename SlotPolicy>
struct common_params {
- // If Compare is a common comparator for a std::string-like type, then we adapt it
+ // If Compare is a common comparator for a string-like type, then we adapt it
// to use heterogeneous lookup and to be a key-compare-to comparator.
using key_compare = typename key_compare_to_adapter<Compare>::type;
// A type which indicates if we have a key-compare-to functor or a plain old
@@ -159,9 +229,6 @@
using size_type = std::make_signed<size_t>::type;
using difference_type = ptrdiff_t;
- // True if this is a multiset or multimap.
- using is_multi_container = std::integral_constant<bool, Multi>;
-
using slot_policy = SlotPolicy;
using slot_type = typename slot_policy::slot_type;
using value_type = typename slot_policy::value_type;
@@ -171,6 +238,23 @@
using reference = value_type &;
using const_reference = const value_type &;
+ // For the given lookup key type, returns whether we can have multiple
+ // equivalent keys in the btree. If this is a multi-container, then we can.
+ // Otherwise, we can have multiple equivalent keys only if all of the
+ // following conditions are met:
+ // - The comparator is transparent.
+ // - The lookup key type is not the same as key_type.
+ // - The comparator is not a StringBtreeDefault{Less,Greater} comparator
+ // that we know has the same equivalence classes for all lookup types.
+ template <typename LookupKey>
+ constexpr static bool can_have_multiple_equivalent_keys() {
+ return Multi ||
+ (IsTransparent<key_compare>::value &&
+ !std::is_same<LookupKey, Key>::value &&
+ !std::is_same<key_compare, StringBtreeDefaultLess>::value &&
+ !std::is_same<key_compare, StringBtreeDefaultGreater>::value);
+ }
+
enum {
kTargetNodeSize = TargetNodeSize,
@@ -216,10 +300,6 @@
static void move(Alloc *alloc, slot_type *src, slot_type *dest) {
slot_policy::move(alloc, src, dest);
}
- static void move(Alloc *alloc, slot_type *first, slot_type *last,
- slot_type *result) {
- slot_policy::move(alloc, first, last, result);
- }
};
// A parameters structure for holding the type parameters for a btree_map.
@@ -251,9 +331,17 @@
};
using is_map_container = std::true_type;
- static const Key &key(const value_type &x) { return x.first; }
- static const Key &key(const init_type &x) { return x.first; }
- static const Key &key(const slot_type *x) { return slot_policy::key(x); }
+ template <typename V>
+ static auto key(const V &value) -> decltype(value.first) {
+ return value.first;
+ }
+ static const Key &key(const slot_type *s) { return slot_policy::key(s); }
+ static const Key &key(slot_type *s) { return slot_policy::key(s); }
+ // For use in node handle.
+ static auto mutable_key(slot_type *s)
+ -> decltype(slot_policy::mutable_key(s)) {
+ return slot_policy::mutable_key(s);
+ }
static mapped_type &value(value_type *value) { return value->second; }
};
@@ -294,13 +382,6 @@
static void move(Alloc * /*alloc*/, slot_type *src, slot_type *dest) {
*dest = std::move(*src);
}
-
- template <typename Alloc>
- static void move(Alloc *alloc, slot_type *first, slot_type *last,
- slot_type *result) {
- for (slot_type *src = first, *dest = result; src != last; ++src, ++dest)
- move(alloc, src, dest);
- }
};
// A parameters structure for holding the type parameters for a btree_set.
@@ -314,8 +395,10 @@
using value_compare = typename set_params::common_params::key_compare;
using is_map_container = std::false_type;
- static const Key &key(const value_type &x) { return x; }
- static const Key &key(const slot_type *x) { return *x; }
+ template <typename V>
+ static const V &key(const V &value) { return value; }
+ static const Key &key(const slot_type *slot) { return *slot; }
+ static const Key &key(slot_type *slot) { return *slot; }
};
// An adapter class that converts a lower-bound compare into an upper-bound
@@ -325,8 +408,8 @@
template <typename Compare>
struct upper_bound_adapter {
explicit upper_bound_adapter(const Compare &c) : comp(c) {}
- template <typename K, typename LK>
- bool operator()(const K &a, const LK &b) const {
+ template <typename K1, typename K2>
+ bool operator()(const K1 &a, const K2 &b) const {
// Returns true when a is not greater than b.
return !compare_internal::compare_result_as_less_than(comp(b, a));
}
@@ -351,6 +434,10 @@
// useful information.
template <typename V>
struct SearchResult<V, false> {
+ SearchResult() {}
+ explicit SearchResult(V value) : value(value) {}
+ SearchResult(V value, MatchKind /*match*/) : value(value) {}
+
V value;
static constexpr bool HasMatch() { return false; }
@@ -363,7 +450,6 @@
template <typename Params>
class btree_node {
using is_key_compare_to = typename Params::is_key_compare_to;
- using is_multi_container = typename Params::is_multi_container;
using field_type = typename Params::node_count_type;
using allocator_type = typename Params::allocator_type;
using slot_type = typename Params::slot_type;
@@ -381,15 +467,22 @@
using difference_type = typename Params::difference_type;
// Btree decides whether to use linear node search as follows:
+ // - If the comparator expresses a preference, use that.
+ // - If the key expresses a preference, use that.
// - If the key is arithmetic and the comparator is std::less or
// std::greater, choose linear.
// - Otherwise, choose binary.
// TODO(ezb): Might make sense to add condition(s) based on node-size.
using use_linear_search = std::integral_constant<
bool,
- std::is_arithmetic<key_type>::value &&
- (std::is_same<std::less<key_type>, key_compare>::value ||
- std::is_same<std::greater<key_type>, key_compare>::value)>;
+ has_linear_node_search_preference<key_compare>::value
+ ? prefers_linear_node_search<key_compare>::value
+ : has_linear_node_search_preference<key_type>::value
+ ? prefers_linear_node_search<key_type>::value
+ : std::is_arithmetic<key_type>::value &&
+ (std::is_same<std::less<key_type>, key_compare>::value ||
+ std::is_same<std::greater<key_type>,
+ key_compare>::value)>;
// This class is organized by gtl::Layout as if it had the following
// structure:
@@ -402,8 +495,9 @@
// // TODO(ezb): right now, `start` is always 0. Update insertion/merge
// // logic to allow for floating storage within nodes.
// field_type start;
- // // The count of the number of populated values in the node.
- // field_type count;
+ // // The index after the last populated value in `values`. Currently, this
+ // // is the same as the count of values.
+ // field_type finish;
// // The maximum number of values the node can hold. This is an integer in
// // [1, kNodeValues] for root leaf nodes, kNodeValues for non-root leaf
// // nodes, and kInternalNodeMaxCount (as a sentinel value) for internal
@@ -414,7 +508,7 @@
//
// // The array of values. The capacity is `max_count` for leaf nodes and
// // kNodeValues for internal nodes. Only the values in
- // // [start, start + count) have been initialized and are valid.
+ // // [start, finish) have been initialized and are valid.
// slot_type values[max_count];
//
// // The array of child pointers. The keys in children[i] are all less
@@ -445,7 +539,7 @@
slot_type, btree_node *>;
constexpr static size_type SizeWithNValues(size_type n) {
return layout_type(/*parent*/ 1,
- /*position, start, count, max_count*/ 4,
+ /*position, start, finish, max_count*/ 4,
/*values*/ n,
/*children*/ 0)
.AllocSize();
@@ -482,13 +576,13 @@
// Leaves can have less than kNodeValues values.
constexpr static layout_type LeafLayout(const int max_values = kNodeValues) {
return layout_type(/*parent*/ 1,
- /*position, start, count, max_count*/ 4,
+ /*position, start, finish, max_count*/ 4,
/*values*/ max_values,
/*children*/ 0);
}
constexpr static layout_type InternalLayout() {
return layout_type(/*parent*/ 1,
- /*position, start, count, max_count*/ 4,
+ /*position, start, finish, max_count*/ 4,
/*values*/ kNodeValues,
/*children*/ kNodeValues + 1);
}
@@ -514,12 +608,14 @@
reinterpret_cast<const char *>(this));
}
void set_parent(btree_node *p) { *GetField<0>() = p; }
- field_type &mutable_count() { return GetField<1>()[2]; }
+ field_type &mutable_finish() { return GetField<1>()[2]; }
slot_type *slot(int i) { return &GetField<2>()[i]; }
+ slot_type *start_slot() { return slot(start()); }
+ slot_type *finish_slot() { return slot(finish()); }
const slot_type *slot(int i) const { return &GetField<2>()[i]; }
void set_position(field_type v) { GetField<1>()[0] = v; }
void set_start(field_type v) { GetField<1>()[1] = v; }
- void set_count(field_type v) { GetField<1>()[2] = v; }
+ void set_finish(field_type v) { GetField<1>()[2] = v; }
// This method is only called by the node init methods.
void set_max_count(field_type v) { GetField<1>()[3] = v; }
@@ -532,10 +628,20 @@
field_type position() const { return GetField<1>()[0]; }
// Getter for the offset of the first value in the `values` array.
- field_type start() const { return GetField<1>()[1]; }
+ field_type start() const {
+ // TODO(ezb): when floating storage is implemented, return GetField<1>()[1];
+ assert(GetField<1>()[1] == 0);
+ return 0;
+ }
+
+ // Getter for the offset after the last value in the `values` array.
+ field_type finish() const { return GetField<1>()[2]; }
// Getters for the number of values stored in this node.
- field_type count() const { return GetField<1>()[2]; }
+ field_type count() const {
+ assert(finish() >= start());
+ return finish() - start();
+ }
field_type max_count() const {
// Internal nodes have max_count==kInternalNodeMaxCount.
// Leaf nodes have max_count in [1, kNodeValues].
@@ -563,6 +669,7 @@
// Getters/setter for the child at position i in the node.
btree_node *child(int i) const { return GetField<3>()[i]; }
+ btree_node *start_child() const { return child(start()); }
btree_node *&mutable_child(int i) { return GetField<3>()[i]; }
void clear_child(int i) {
absl::container_internal::SanitizerPoisonObject(&mutable_child(i));
@@ -595,14 +702,14 @@
template <typename K, typename Compare>
SearchResult<int, btree_is_key_compare_to<Compare, key_type>::value>
linear_search(const K &k, const Compare &comp) const {
- return linear_search_impl(k, 0, count(), comp,
+ return linear_search_impl(k, start(), finish(), comp,
btree_is_key_compare_to<Compare, key_type>());
}
template <typename K, typename Compare>
SearchResult<int, btree_is_key_compare_to<Compare, key_type>::value>
binary_search(const K &k, const Compare &comp) const {
- return binary_search_impl(k, 0, count(), comp,
+ return binary_search_impl(k, start(), finish(), comp,
btree_is_key_compare_to<Compare, key_type>());
}
@@ -618,7 +725,7 @@
}
++s;
}
- return {s};
+ return SearchResult<int, false>{s};
}
// Returns the position of the first value whose key is not less than k using
@@ -653,7 +760,7 @@
e = mid;
}
}
- return {s};
+ return SearchResult<int, false>{s};
}
// Returns the position of the first value whose key is not less than k using
@@ -662,7 +769,7 @@
SearchResult<int, true> binary_search_impl(
const K &k, int s, int e, const CompareTo &comp,
std::true_type /* IsCompareTo */) const {
- if (is_multi_container::value) {
+ if (params_type::template can_have_multiple_equivalent_keys<K>()) {
MatchKind exact_match = MatchKind::kNe;
while (s != e) {
const int mid = (s + e) >> 1;
@@ -673,14 +780,14 @@
e = mid;
if (c == 0) {
// Need to return the first value whose key is not less than k,
- // which requires continuing the binary search if this is a
- // multi-container.
+ // which requires continuing the binary search if there could be
+ // multiple equivalent keys.
exact_match = MatchKind::kEq;
}
}
}
return {s, exact_match};
- } else { // Not a multi-container.
+ } else { // Can't have multiple equivalent keys.
while (s != e) {
const int mid = (s + e) >> 1;
const absl::weak_ordering c = comp(key(mid), k);
@@ -701,14 +808,10 @@
template <typename... Args>
void emplace_value(size_type i, allocator_type *alloc, Args &&... args);
- // Removes the value at position i, shifting all existing values and children
- // at positions > i to the left by 1.
- void remove_value(int i, allocator_type *alloc);
-
- // Removes the values at positions [i, i + to_erase), shifting all values
- // after that range to the left by to_erase. Does not change children at all.
- void remove_values_ignore_children(int i, int to_erase,
- allocator_type *alloc);
+ // Removes the values at positions [i, i + to_erase), shifting all existing
+ // values and children after that range to the left by to_erase. Clears all
+ // children between [i, i + to_erase).
+ void remove_values(field_type i, field_type to_erase, allocator_type *alloc);
// Rebalances a node with its right sibling.
void rebalance_right_to_left(int to_move, btree_node *right,
@@ -720,74 +823,87 @@
void split(int insert_position, btree_node *dest, allocator_type *alloc);
// Merges a node with its right sibling, moving all of the values and the
- // delimiting key in the parent node onto itself.
- void merge(btree_node *sibling, allocator_type *alloc);
-
- // Swap the contents of "this" and "src".
- void swap(btree_node *src, allocator_type *alloc);
+ // delimiting key in the parent node onto itself, and deleting the src node.
+ void merge(btree_node *src, allocator_type *alloc);
// Node allocation/deletion routines.
- static btree_node *init_leaf(btree_node *n, btree_node *parent,
- int max_count) {
- n->set_parent(parent);
- n->set_position(0);
- n->set_start(0);
- n->set_count(0);
- n->set_max_count(max_count);
+ void init_leaf(btree_node *parent, int max_count) {
+ set_parent(parent);
+ set_position(0);
+ set_start(0);
+ set_finish(0);
+ set_max_count(max_count);
absl::container_internal::SanitizerPoisonMemoryRegion(
- n->slot(0), max_count * sizeof(slot_type));
- return n;
+ start_slot(), max_count * sizeof(slot_type));
}
- static btree_node *init_internal(btree_node *n, btree_node *parent) {
- init_leaf(n, parent, kNodeValues);
+ void init_internal(btree_node *parent) {
+ init_leaf(parent, kNodeValues);
// Set `max_count` to a sentinel value to indicate that this node is
// internal.
- n->set_max_count(kInternalNodeMaxCount);
+ set_max_count(kInternalNodeMaxCount);
absl::container_internal::SanitizerPoisonMemoryRegion(
- &n->mutable_child(0), (kNodeValues + 1) * sizeof(btree_node *));
- return n;
- }
- void destroy(allocator_type *alloc) {
- for (int i = 0; i < count(); ++i) {
- value_destroy(i, alloc);
- }
+ &mutable_child(start()), (kNodeValues + 1) * sizeof(btree_node *));
}
- public:
- // Exposed only for tests.
- static bool testonly_uses_linear_node_search() {
- return use_linear_search::value;
+ static void deallocate(const size_type size, btree_node *node,
+ allocator_type *alloc) {
+ absl::container_internal::Deallocate<Alignment()>(alloc, node, size);
}
+ // Deletes a node and all of its children.
+ static void clear_and_delete(btree_node *node, allocator_type *alloc);
+
private:
template <typename... Args>
- void value_init(const size_type i, allocator_type *alloc, Args &&... args) {
+ void value_init(const field_type i, allocator_type *alloc, Args &&... args) {
absl::container_internal::SanitizerUnpoisonObject(slot(i));
params_type::construct(alloc, slot(i), std::forward<Args>(args)...);
}
- void value_destroy(const size_type i, allocator_type *alloc) {
+ void value_destroy(const field_type i, allocator_type *alloc) {
params_type::destroy(alloc, slot(i));
absl::container_internal::SanitizerPoisonObject(slot(i));
}
-
- // Move n values starting at value i in this node into the values starting at
- // value j in node x.
- void uninitialized_move_n(const size_type n, const size_type i,
- const size_type j, btree_node *x,
- allocator_type *alloc) {
- absl::container_internal::SanitizerUnpoisonMemoryRegion(
- x->slot(j), n * sizeof(slot_type));
- for (slot_type *src = slot(i), *end = src + n, *dest = x->slot(j);
- src != end; ++src, ++dest) {
- params_type::construct(alloc, dest, src);
+ void value_destroy_n(const field_type i, const field_type n,
+ allocator_type *alloc) {
+ for (slot_type *s = slot(i), *end = slot(i + n); s != end; ++s) {
+ params_type::destroy(alloc, s);
+ absl::container_internal::SanitizerPoisonObject(s);
}
}
- // Destroys a range of n values, starting at index i.
- void value_destroy_n(const size_type i, const size_type n,
- allocator_type *alloc) {
- for (int j = 0; j < n; ++j) {
- value_destroy(i + j, alloc);
+ static void transfer(slot_type *dest, slot_type *src, allocator_type *alloc) {
+ absl::container_internal::SanitizerUnpoisonObject(dest);
+ params_type::transfer(alloc, dest, src);
+ absl::container_internal::SanitizerPoisonObject(src);
+ }
+
+ // Transfers value from slot `src_i` in `src_node` to slot `dest_i` in `this`.
+ void transfer(const size_type dest_i, const size_type src_i,
+ btree_node *src_node, allocator_type *alloc) {
+ transfer(slot(dest_i), src_node->slot(src_i), alloc);
+ }
+
+ // Transfers `n` values starting at value `src_i` in `src_node` into the
+ // values starting at value `dest_i` in `this`.
+ void transfer_n(const size_type n, const size_type dest_i,
+ const size_type src_i, btree_node *src_node,
+ allocator_type *alloc) {
+ for (slot_type *src = src_node->slot(src_i), *end = src + n,
+ *dest = slot(dest_i);
+ src != end; ++src, ++dest) {
+ transfer(dest, src, alloc);
+ }
+ }
+
+ // Same as above, except that we start at the end and work our way to the
+ // beginning.
+ void transfer_n_backward(const size_type n, const size_type dest_i,
+ const size_type src_i, btree_node *src_node,
+ allocator_type *alloc) {
+ for (slot_type *src = src_node->slot(src_i + n - 1), *end = src - n,
+ *dest = slot(dest_i + n - 1);
+ src != end; --src, --dest) {
+ transfer(dest, src, alloc);
}
}
@@ -804,6 +920,7 @@
using key_type = typename Node::key_type;
using size_type = typename Node::size_type;
using params_type = typename Node::params_type;
+ using is_map_container = typename params_type::is_map_container;
using node_type = Node;
using normal_node = typename std::remove_const<Node>::type;
@@ -815,7 +932,7 @@
using slot_type = typename params_type::slot_type;
using iterator =
- btree_iterator<normal_node, normal_reference, normal_pointer>;
+ btree_iterator<normal_node, normal_reference, normal_pointer>;
using const_iterator =
btree_iterator<const_node, const_reference, const_pointer>;
@@ -828,23 +945,23 @@
using iterator_category = std::bidirectional_iterator_tag;
btree_iterator() : node(nullptr), position(-1) {}
+ explicit btree_iterator(Node *n) : node(n), position(n->start()) {}
btree_iterator(Node *n, int p) : node(n), position(p) {}
// NOTE: this SFINAE allows for implicit conversions from iterator to
- // const_iterator, but it specifically avoids defining copy constructors so
- // that btree_iterator can be trivially copyable. This is for performance and
- // binary size reasons.
+ // const_iterator, but it specifically avoids hiding the copy constructor so
+ // that the trivial one will be used when possible.
template <typename N, typename R, typename P,
absl::enable_if_t<
std::is_same<btree_iterator<N, R, P>, iterator>::value &&
std::is_same<btree_iterator, const_iterator>::value,
int> = 0>
- btree_iterator(const btree_iterator<N, R, P> &x) // NOLINT
- : node(x.node), position(x.position) {}
+ btree_iterator(const btree_iterator<N, R, P> other) // NOLINT
+ : node(other.node), position(other.position) {}
private:
// This SFINAE allows explicit conversions from const_iterator to
- // iterator, but also avoids defining a copy constructor.
+ // iterator, but also avoids hiding the copy constructor.
// NOTE: the const_cast is safe because this constructor is only called by
// non-const methods and the container owns the nodes.
template <typename N, typename R, typename P,
@@ -852,12 +969,12 @@
std::is_same<btree_iterator<N, R, P>, const_iterator>::value &&
std::is_same<btree_iterator, iterator>::value,
int> = 0>
- explicit btree_iterator(const btree_iterator<N, R, P> &x)
- : node(const_cast<node_type *>(x.node)), position(x.position) {}
+ explicit btree_iterator(const btree_iterator<N, R, P> other)
+ : node(const_cast<node_type *>(other.node)), position(other.position) {}
// Increment/decrement the iterator.
void increment() {
- if (node->leaf() && ++position < node->count()) {
+ if (node->leaf() && ++position < node->finish()) {
return;
}
increment_slow();
@@ -865,7 +982,7 @@
void increment_slow();
void decrement() {
- if (node->leaf() && --position >= 0) {
+ if (node->leaf() && --position >= node->start()) {
return;
}
decrement_slow();
@@ -873,26 +990,33 @@
void decrement_slow();
public:
- bool operator==(const const_iterator &x) const {
- return node == x.node && position == x.position;
+ bool operator==(const iterator &other) const {
+ return node == other.node && position == other.position;
}
- bool operator!=(const const_iterator &x) const {
- return node != x.node || position != x.position;
+ bool operator==(const const_iterator &other) const {
+ return node == other.node && position == other.position;
+ }
+ bool operator!=(const iterator &other) const {
+ return node != other.node || position != other.position;
+ }
+ bool operator!=(const const_iterator &other) const {
+ return node != other.node || position != other.position;
}
// Accessors for the key/value the iterator is pointing at.
reference operator*() const {
+ ABSL_HARDENING_ASSERT(node != nullptr);
+ ABSL_HARDENING_ASSERT(node->start() <= position);
+ ABSL_HARDENING_ASSERT(node->finish() > position);
return node->value(position);
}
- pointer operator->() const {
- return &node->value(position);
- }
+ pointer operator->() const { return &operator*(); }
- btree_iterator& operator++() {
+ btree_iterator &operator++() {
increment();
return *this;
}
- btree_iterator& operator--() {
+ btree_iterator &operator--() {
decrement();
return *this;
}
@@ -908,6 +1032,8 @@
}
private:
+ friend iterator;
+ friend const_iterator;
template <typename Params>
friend class btree;
template <typename Tree>
@@ -918,8 +1044,6 @@
friend class btree_map_container;
template <typename Tree>
friend class btree_multiset_container;
- template <typename N, typename R, typename P>
- friend struct btree_iterator;
template <typename TreeType, typename CheckerType>
friend class base_checker;
@@ -929,7 +1053,8 @@
// The node in the tree the iterator is pointing at.
Node *node;
// The position within the node of the tree the iterator is pointing at.
- // TODO(ezb): make this a field_type
+ // NOTE: this is an int rather than a field_type because iterators can point
+ // to invalid positions (such as -1) in certain circumstances.
int position;
};
@@ -937,6 +1062,8 @@
class btree {
using node_type = btree_node<Params>;
using is_key_compare_to = typename Params::is_key_compare_to;
+ using init_type = typename Params::init_type;
+ using field_type = typename node_type::field_type;
// We use a static empty node for the root/leftmost/rightmost of empty btrees
// in order to avoid branching in begin()/end().
@@ -945,7 +1072,7 @@
node_type *parent;
field_type position = 0;
field_type start = 0;
- field_type count = 0;
+ field_type finish = 0;
// max_count must be != kInternalNodeMaxCount (so that this node is regarded
// as a leaf node). max_count() is never called when the tree is empty.
field_type max_count = node_type::kInternalNodeMaxCount + 1;
@@ -960,7 +1087,7 @@
static node_type *EmptyNode() {
#ifdef _MSC_VER
- static EmptyNodeType* empty_node = new EmptyNodeType;
+ static EmptyNodeType *empty_node = new EmptyNodeType;
// This assert fails on some other construction methods.
assert(empty_node->parent == empty_node);
return empty_node;
@@ -971,7 +1098,7 @@
#endif
}
- enum {
+ enum : uint32_t {
kNodeValues = node_type::kNodeValues,
kMinNodeValues = kNodeValues / 2,
};
@@ -979,14 +1106,11 @@
struct node_stats {
using size_type = typename Params::size_type;
- node_stats(size_type l, size_type i)
- : leaf_nodes(l),
- internal_nodes(i) {
- }
+ node_stats(size_type l, size_type i) : leaf_nodes(l), internal_nodes(i) {}
- node_stats& operator+=(const node_stats &x) {
- leaf_nodes += x.leaf_nodes;
- internal_nodes += x.internal_nodes;
+ node_stats &operator+=(const node_stats &other) {
+ leaf_nodes += other.leaf_nodes;
+ internal_nodes += other.internal_nodes;
return *this;
}
@@ -1006,7 +1130,8 @@
using const_reference = typename Params::const_reference;
using pointer = typename Params::pointer;
using const_pointer = typename Params::const_pointer;
- using iterator = btree_iterator<node_type, reference, pointer>;
+ using iterator =
+ typename btree_iterator<node_type, reference, pointer>::iterator;
using const_iterator = typename iterator::const_iterator;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
@@ -1018,28 +1143,46 @@
private:
// For use in copy_or_move_values_in_order.
- const value_type &maybe_move_from_iterator(const_iterator x) { return *x; }
- value_type &&maybe_move_from_iterator(iterator x) { return std::move(*x); }
+ const value_type &maybe_move_from_iterator(const_iterator it) { return *it; }
+ value_type &&maybe_move_from_iterator(iterator it) {
+ // This is a destructive operation on the other container so it's safe for
+ // us to const_cast and move from the keys here even if it's a set.
+ return std::move(const_cast<value_type &>(*it));
+ }
// Copies or moves (depending on the template parameter) the values in
- // x into this btree in their order in x. This btree must be empty before this
- // method is called. This method is used in copy construction, copy
- // assignment, and move assignment.
+ // other into this btree in their order in other. This btree must be empty
+ // before this method is called. This method is used in copy construction,
+ // copy assignment, and move assignment.
template <typename Btree>
- void copy_or_move_values_in_order(Btree *x);
+ void copy_or_move_values_in_order(Btree &other);
// Validates that various assumptions/requirements are true at compile time.
constexpr static bool static_assert_validation();
public:
- btree(const key_compare &comp, const allocator_type &alloc);
+ btree(const key_compare &comp, const allocator_type &alloc)
+ : root_(comp, alloc, EmptyNode()), rightmost_(EmptyNode()), size_(0) {}
- btree(const btree &x);
- btree(btree &&x) noexcept
- : root_(std::move(x.root_)),
- rightmost_(absl::exchange(x.rightmost_, EmptyNode())),
- size_(absl::exchange(x.size_, 0)) {
- x.mutable_root() = EmptyNode();
+ btree(const btree &other) : btree(other, other.allocator()) {}
+ btree(const btree &other, const allocator_type &alloc)
+ : btree(other.key_comp(), alloc) {
+ copy_or_move_values_in_order(other);
+ }
+ btree(btree &&other) noexcept
+ : root_(std::move(other.root_)),
+ rightmost_(absl::exchange(other.rightmost_, EmptyNode())),
+ size_(absl::exchange(other.size_, 0)) {
+ other.mutable_root() = EmptyNode();
+ }
+ btree(btree &&other, const allocator_type &alloc)
+ : btree(other.key_comp(), alloc) {
+ if (alloc == other.allocator()) {
+ swap(other);
+ } else {
+ // Move values from `other` one at a time when allocators are different.
+ copy_or_move_values_in_order(other);
+ }
}
~btree() {
@@ -1049,44 +1192,41 @@
clear();
}
- // Assign the contents of x to *this.
- btree &operator=(const btree &x);
- btree &operator=(btree &&x) noexcept;
+ // Assign the contents of other to *this.
+ btree &operator=(const btree &other);
+ btree &operator=(btree &&other) noexcept;
- iterator begin() {
- return iterator(leftmost(), 0);
- }
- const_iterator begin() const {
- return const_iterator(leftmost(), 0);
- }
- iterator end() { return iterator(rightmost_, rightmost_->count()); }
+ iterator begin() { return iterator(leftmost()); }
+ const_iterator begin() const { return const_iterator(leftmost()); }
+ iterator end() { return iterator(rightmost_, rightmost_->finish()); }
const_iterator end() const {
- return const_iterator(rightmost_, rightmost_->count());
+ return const_iterator(rightmost_, rightmost_->finish());
}
- reverse_iterator rbegin() {
- return reverse_iterator(end());
- }
+ reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
- reverse_iterator rend() {
- return reverse_iterator(begin());
- }
+ reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const {
return const_reverse_iterator(begin());
}
- // Finds the first element whose key is not less than key.
+ // Finds the first element whose key is not less than `key`.
template <typename K>
iterator lower_bound(const K &key) {
- return internal_end(internal_lower_bound(key));
+ return internal_end(internal_lower_bound(key).value);
}
template <typename K>
const_iterator lower_bound(const K &key) const {
- return internal_end(internal_lower_bound(key));
+ return internal_end(internal_lower_bound(key).value);
}
- // Finds the first element whose key is greater than key.
+ // Finds the first element whose key is not less than `key` and also returns
+ // whether that element is equal to `key`.
+ template <typename K>
+ std::pair<iterator, bool> lower_bound_equal(const K &key) const;
+
+ // Finds the first element whose key is greater than `key`.
template <typename K>
iterator upper_bound(const K &key) {
return internal_end(internal_upper_bound(key));
@@ -1097,23 +1237,21 @@
}
// Finds the range of values which compare equal to key. The first member of
- // the returned pair is equal to lower_bound(key). The second member pair of
- // the pair is equal to upper_bound(key).
+ // the returned pair is equal to lower_bound(key). The second member of the
+ // pair is equal to upper_bound(key).
template <typename K>
- std::pair<iterator, iterator> equal_range(const K &key) {
- return {lower_bound(key), upper_bound(key)};
- }
+ std::pair<iterator, iterator> equal_range(const K &key);
template <typename K>
std::pair<const_iterator, const_iterator> equal_range(const K &key) const {
- return {lower_bound(key), upper_bound(key)};
+ return const_cast<btree *>(this)->equal_range(key);
}
// Inserts a value into the btree only if it does not already exist. The
// boolean return value indicates whether insertion succeeded or failed.
// Requirement: if `key` already exists in the btree, does not consume `args`.
// Requirement: `key` is never referenced after consuming `args`.
- template <typename... Args>
- std::pair<iterator, bool> insert_unique(const key_type &key, Args &&... args);
+ template <typename K, typename... Args>
+ std::pair<iterator, bool> insert_unique(const K &key, Args &&... args);
// Inserts with hint. Checks to see if the value should be placed immediately
// before `position` in the tree. If so, then the insertion will take
@@ -1121,14 +1259,23 @@
// logarithmic time as if a call to insert_unique() were made.
// Requirement: if `key` already exists in the btree, does not consume `args`.
// Requirement: `key` is never referenced after consuming `args`.
- template <typename... Args>
+ template <typename K, typename... Args>
std::pair<iterator, bool> insert_hint_unique(iterator position,
- const key_type &key,
+ const K &key,
Args &&... args);
// Insert a range of values into the btree.
+ // Note: the first overload avoids constructing a value_type if the key
+ // already exists in the btree.
+ template <typename InputIterator,
+ typename = decltype(std::declval<const key_compare &>()(
+ params_type::key(*std::declval<InputIterator>()),
+ std::declval<const key_type &>()))>
+ void insert_iterator_unique(InputIterator b, InputIterator e, int);
+ // We need the second overload for cases in which we need to construct a
+ // value_type in order to compare it with the keys already in the btree.
template <typename InputIterator>
- void insert_iterator_unique(InputIterator b, InputIterator e);
+ void insert_iterator_unique(InputIterator b, InputIterator e, char);
// Inserts a value into the btree.
template <typename ValueType>
@@ -1159,20 +1306,10 @@
// Erases range. Returns the number of keys erased and an iterator pointing
// to the element after the last erased element.
- std::pair<size_type, iterator> erase(iterator begin, iterator end);
+ std::pair<size_type, iterator> erase_range(iterator begin, iterator end);
- // Erases the specified key from the btree. Returns 1 if an element was
- // erased and 0 otherwise.
- template <typename K>
- size_type erase_unique(const K &key);
-
- // Erases all of the entries matching the specified key from the
- // btree. Returns the number of elements erased.
- template <typename K>
- size_type erase_multi(const K &key);
-
- // Finds the iterator corresponding to a key or returns end() if the key is
- // not present.
+ // Finds an element with key equivalent to `key` or returns `end()` if `key`
+ // is not present.
template <typename K>
iterator find(const K &key) {
return internal_end(internal_find(key));
@@ -1182,35 +1319,18 @@
return internal_end(internal_find(key));
}
- // Returns a count of the number of times the key appears in the btree.
- template <typename K>
- size_type count_unique(const K &key) const {
- const iterator begin = internal_find(key);
- if (begin.node == nullptr) {
- // The key doesn't exist in the tree.
- return 0;
- }
- return 1;
- }
- // Returns a count of the number of times the key appears in the btree.
- template <typename K>
- size_type count_multi(const K &key) const {
- const auto range = equal_range(key);
- return std::distance(range.first, range.second);
- }
-
// Clear the btree, deleting all of the values it contains.
void clear();
- // Swap the contents of *this and x.
- void swap(btree &x);
+ // Swaps the contents of `this` and `other`.
+ void swap(btree &other);
const key_compare &key_comp() const noexcept {
return root_.template get<0>();
}
- template <typename K, typename LK>
- bool compare_keys(const K &x, const LK &y) const {
- return compare_internal::compare_result_as_less_than(key_comp()(x, y));
+ template <typename K1, typename K2>
+ bool compare_keys(const K1 &a, const K2 &b) const {
+ return compare_internal::compare_result_as_less_than(key_comp()(a, b));
}
value_compare value_comp() const { return value_compare(key_comp()); }
@@ -1226,7 +1346,7 @@
// The height of the btree. An empty tree will have height 0.
size_type height() const {
size_type h = 0;
- if (root()) {
+ if (!empty()) {
// Count the length of the chain from the leftmost node up to the
// root. We actually count from the root back around to the level below
// the root, but the calculation is the same because of the circularity
@@ -1241,9 +1361,7 @@
}
// The number of internal, leaf and total nodes used by the btree.
- size_type leaf_nodes() const {
- return internal_stats(root()).leaf_nodes;
- }
+ size_type leaf_nodes() const { return internal_stats(root()).leaf_nodes; }
size_type internal_nodes() const {
return internal_stats(root()).internal_nodes;
}
@@ -1256,11 +1374,9 @@
size_type bytes_used() const {
node_stats stats = internal_stats(root());
if (stats.leaf_nodes == 1 && stats.internal_nodes == 0) {
- return sizeof(*this) +
- node_type::LeafSize(root()->max_count());
+ return sizeof(*this) + node_type::LeafSize(root()->max_count());
} else {
- return sizeof(*this) +
- stats.leaf_nodes * node_type::LeafSize() +
+ return sizeof(*this) + stats.leaf_nodes * node_type::LeafSize() +
stats.internal_nodes * node_type::InternalSize();
}
}
@@ -1277,24 +1393,23 @@
// divided by the maximum number of elements a tree with the current number
// of nodes could hold. A value of 1 indicates perfect space
// utilization. Smaller values indicate space wastage.
+ // Returns 0 for empty trees.
double fullness() const {
+ if (empty()) return 0.0;
return static_cast<double>(size()) / (nodes() * kNodeValues);
}
// The overhead of the btree structure in bytes per node. Computed as the
// total number of bytes used by the btree minus the number of bytes used for
// storing elements divided by the number of elements.
+ // Returns 0 for empty trees.
double overhead() const {
- if (empty()) {
- return 0.0;
- }
+ if (empty()) return 0.0;
return (bytes_used() - size() * sizeof(value_type)) /
static_cast<double>(size());
}
// The allocator used by the btree.
- allocator_type get_allocator() const {
- return allocator();
- }
+ allocator_type get_allocator() const { return allocator(); }
private:
// Internal accessor routines.
@@ -1324,39 +1439,25 @@
}
// Node creation/deletion routines.
- node_type* new_internal_node(node_type *parent) {
- node_type *p = allocate(node_type::InternalSize());
- return node_type::init_internal(p, parent);
+ node_type *new_internal_node(node_type *parent) {
+ node_type *n = allocate(node_type::InternalSize());
+ n->init_internal(parent);
+ return n;
}
- node_type* new_leaf_node(node_type *parent) {
- node_type *p = allocate(node_type::LeafSize());
- return node_type::init_leaf(p, parent, kNodeValues);
+ node_type *new_leaf_node(node_type *parent) {
+ node_type *n = allocate(node_type::LeafSize());
+ n->init_leaf(parent, kNodeValues);
+ return n;
}
node_type *new_leaf_root_node(const int max_count) {
- node_type *p = allocate(node_type::LeafSize(max_count));
- return node_type::init_leaf(p, p, max_count);
+ node_type *n = allocate(node_type::LeafSize(max_count));
+ n->init_leaf(/*parent=*/n, max_count);
+ return n;
}
// Deletion helper routines.
- void erase_same_node(iterator begin, iterator end);
- iterator erase_from_leaf_node(iterator begin, size_type to_erase);
iterator rebalance_after_delete(iterator iter);
- // Deallocates a node of a certain size in bytes using the allocator.
- void deallocate(const size_type size, node_type *node) {
- absl::container_internal::Deallocate<node_type::Alignment()>(
- mutable_allocator(), node, size);
- }
-
- void delete_internal_node(node_type *node) {
- node->destroy(mutable_allocator());
- deallocate(node_type::InternalSize(), node);
- }
- void delete_leaf_node(node_type *node) {
- node->destroy(mutable_allocator());
- deallocate(node_type::LeafSize(node->max_count()), node);
- }
-
// Rebalances or splits the node iter points to.
void rebalance_or_split(iterator *iter);
@@ -1386,36 +1487,27 @@
iterator internal_emplace(iterator iter, Args &&... args);
// Returns an iterator pointing to the first value >= the value "iter" is
- // pointing at. Note that "iter" might be pointing to an invalid location as
- // iter.position == iter.node->count(). This routine simply moves iter up in
- // the tree to a valid location.
+ // pointing at. Note that "iter" might be pointing to an invalid location such
+ // as iter.position == iter.node->finish(). This routine simply moves iter up
+ // in the tree to a valid location.
// Requires: iter.node is non-null.
template <typename IterType>
static IterType internal_last(IterType iter);
// Returns an iterator pointing to the leaf position at which key would
- // reside in the tree. We provide 2 versions of internal_locate. The first
- // version uses a less-than comparator and is incapable of distinguishing when
- // there is an exact match. The second version is for the key-compare-to
- // specialization and distinguishes exact matches. The key-compare-to
- // specialization allows the caller to avoid a subsequent comparison to
- // determine if an exact match was made, which is important for keys with
- // expensive comparison, such as strings.
+ // reside in the tree, unless there is an exact match - in which case, the
+ // result may not be on a leaf. When there's a three-way comparator, we can
+ // return whether there was an exact match. This allows the caller to avoid a
+ // subsequent comparison to determine if an exact match was made, which is
+ // important for keys with expensive comparison, such as strings.
template <typename K>
SearchResult<iterator, is_key_compare_to::value> internal_locate(
const K &key) const;
- template <typename K>
- SearchResult<iterator, false> internal_locate_impl(
- const K &key, std::false_type /* IsCompareTo */) const;
-
- template <typename K>
- SearchResult<iterator, true> internal_locate_impl(
- const K &key, std::true_type /* IsCompareTo */) const;
-
// Internal routine which implements lower_bound().
template <typename K>
- iterator internal_lower_bound(const K &key) const;
+ SearchResult<iterator, is_key_compare_to::value> internal_lower_bound(
+ const K &key) const;
// Internal routine which implements upper_bound().
template <typename K>
@@ -1425,12 +1517,9 @@
template <typename K>
iterator internal_find(const K &key) const;
- // Deletes a node and all of its children.
- void internal_clear(node_type *node);
-
// Verifies the tree structure of node.
- int internal_verify(const node_type *node,
- const key_type *lo, const key_type *hi) const;
+ int internal_verify(const node_type *node, const key_type *lo,
+ const key_type *hi) const;
node_stats internal_stats(const node_type *node) const {
// The root can be a static empty node.
@@ -1441,19 +1530,12 @@
return node_stats(1, 0);
}
node_stats res(0, 1);
- for (int i = 0; i <= node->count(); ++i) {
+ for (int i = node->start(); i <= node->finish(); ++i) {
res += internal_stats(node->child(i));
}
return res;
}
- public:
- // Exposed only for tests.
- static bool testonly_uses_linear_node_search() {
- return node_type::testonly_uses_linear_node_search();
- }
-
- private:
// We use compressed tuple in order to save space because key_compare and
// allocator_type are usually empty.
absl::container_internal::CompressedTuple<key_compare, allocator_type,
@@ -1475,20 +1557,19 @@
inline void btree_node<P>::emplace_value(const size_type i,
allocator_type *alloc,
Args &&... args) {
- assert(i <= count());
+ assert(i >= start());
+ assert(i <= finish());
// Shift old values to create space for new value and then construct it in
// place.
- if (i < count()) {
- value_init(count(), alloc, slot(count() - 1));
- for (size_type j = count() - 1; j > i; --j)
- params_type::move(alloc, slot(j - 1), slot(j));
- value_destroy(i, alloc);
+ if (i < finish()) {
+ transfer_n_backward(finish() - i, /*dest_i=*/i + 1, /*src_i=*/i, this,
+ alloc);
}
value_init(i, alloc, std::forward<Args>(args)...);
- set_count(count() + 1);
+ set_finish(finish() + 1);
- if (!leaf() && count() > i + 1) {
- for (int j = count(); j > i + 1; --j) {
+ if (!leaf() && finish() > i + 1) {
+ for (int j = finish(); j > i + 1; --j) {
set_child(j, child(j - 1));
}
clear_child(i + 1);
@@ -1496,24 +1577,27 @@
}
template <typename P>
-inline void btree_node<P>::remove_value(const int i, allocator_type *alloc) {
- if (!leaf() && count() > i + 1) {
- assert(child(i + 1)->count() == 0);
- for (size_type j = i + 1; j < count(); ++j) {
- set_child(j, child(j + 1));
+inline void btree_node<P>::remove_values(const field_type i,
+ const field_type to_erase,
+ allocator_type *alloc) {
+ // Transfer values after the removed range into their new places.
+ value_destroy_n(i, to_erase, alloc);
+ const field_type orig_finish = finish();
+ const field_type src_i = i + to_erase;
+ transfer_n(orig_finish - src_i, i, src_i, this, alloc);
+
+ if (!leaf()) {
+ // Delete all children between begin and end.
+ for (int j = 0; j < to_erase; ++j) {
+ clear_and_delete(child(i + j + 1), alloc);
}
- clear_child(count());
+ // Rotate children after end into new positions.
+ for (int j = i + to_erase + 1; j <= orig_finish; ++j) {
+ set_child(j - to_erase, child(j));
+ clear_child(j);
+ }
}
-
- remove_values_ignore_children(i, /*to_erase=*/1, alloc);
-}
-
-template <typename P>
-inline void btree_node<P>::remove_values_ignore_children(
- const int i, const int to_erase, allocator_type *alloc) {
- params_type::move(alloc, slot(i + to_erase), slot(count()), slot(i));
- value_destroy_n(count() - to_erase, to_erase, alloc);
- set_count(count() - to_erase);
+ set_finish(orig_finish - to_erase);
}
template <typename P>
@@ -1527,37 +1611,33 @@
assert(to_move <= right->count());
// 1) Move the delimiting value in the parent to the left node.
- value_init(count(), alloc, parent()->slot(position()));
+ transfer(finish(), position(), parent(), alloc);
// 2) Move the (to_move - 1) values from the right node to the left node.
- right->uninitialized_move_n(to_move - 1, 0, count() + 1, this, alloc);
+ transfer_n(to_move - 1, finish() + 1, right->start(), right, alloc);
// 3) Move the new delimiting value to the parent from the right node.
- params_type::move(alloc, right->slot(to_move - 1),
- parent()->slot(position()));
+ parent()->transfer(position(), right->start() + to_move - 1, right, alloc);
- // 4) Shift the values in the right node to their correct position.
- params_type::move(alloc, right->slot(to_move), right->slot(right->count()),
- right->slot(0));
-
- // 5) Destroy the now-empty to_move entries in the right node.
- right->value_destroy_n(right->count() - to_move, to_move, alloc);
+ // 4) Shift the values in the right node to their correct positions.
+ right->transfer_n(right->count() - to_move, right->start(),
+ right->start() + to_move, right, alloc);
if (!leaf()) {
// Move the child pointers from the right to the left node.
for (int i = 0; i < to_move; ++i) {
- init_child(count() + i + 1, right->child(i));
+ init_child(finish() + i + 1, right->child(i));
}
- for (int i = 0; i <= right->count() - to_move; ++i) {
+ for (int i = right->start(); i <= right->finish() - to_move; ++i) {
assert(i + to_move <= right->max_count());
right->init_child(i, right->child(i + to_move));
right->clear_child(i + to_move);
}
}
- // Fixup the counts on the left and right nodes.
- set_count(count() + to_move);
- right->set_count(right->count() - to_move);
+ // Fixup `finish` on the left and right nodes.
+ set_finish(finish() + to_move);
+ right->set_finish(right->finish() - to_move);
}
template <typename P>
@@ -1576,67 +1656,35 @@
// Lastly, a new delimiting value is moved from the left node into the
// parent, and the remaining empty left node entries are destroyed.
- if (right->count() >= to_move) {
- // The original location of the right->count() values are sufficient to hold
- // the new to_move entries from the parent and left node.
+ // 1) Shift existing values in the right node to their correct positions.
+ right->transfer_n_backward(right->count(), right->start() + to_move,
+ right->start(), right, alloc);
- // 1) Shift existing values in the right node to their correct positions.
- right->uninitialized_move_n(to_move, right->count() - to_move,
- right->count(), right, alloc);
- for (slot_type *src = right->slot(right->count() - to_move - 1),
- *dest = right->slot(right->count() - 1),
- *end = right->slot(0);
- src >= end; --src, --dest) {
- params_type::move(alloc, src, dest);
- }
+ // 2) Move the delimiting value in the parent to the right node.
+ right->transfer(right->start() + to_move - 1, position(), parent(), alloc);
- // 2) Move the delimiting value in the parent to the right node.
- params_type::move(alloc, parent()->slot(position()),
- right->slot(to_move - 1));
-
- // 3) Move the (to_move - 1) values from the left node to the right node.
- params_type::move(alloc, slot(count() - (to_move - 1)), slot(count()),
- right->slot(0));
- } else {
- // The right node does not have enough initialized space to hold the new
- // to_move entries, so part of them will move to uninitialized space.
-
- // 1) Shift existing values in the right node to their correct positions.
- right->uninitialized_move_n(right->count(), 0, to_move, right, alloc);
-
- // 2) Move the delimiting value in the parent to the right node.
- right->value_init(to_move - 1, alloc, parent()->slot(position()));
-
- // 3) Move the (to_move - 1) values from the left node to the right node.
- const size_type uninitialized_remaining = to_move - right->count() - 1;
- uninitialized_move_n(uninitialized_remaining,
- count() - uninitialized_remaining, right->count(),
- right, alloc);
- params_type::move(alloc, slot(count() - (to_move - 1)),
- slot(count() - uninitialized_remaining), right->slot(0));
- }
+ // 3) Move the (to_move - 1) values from the left node to the right node.
+ right->transfer_n(to_move - 1, right->start(), finish() - (to_move - 1), this,
+ alloc);
// 4) Move the new delimiting value to the parent from the left node.
- params_type::move(alloc, slot(count() - to_move), parent()->slot(position()));
-
- // 5) Destroy the now-empty to_move entries in the left node.
- value_destroy_n(count() - to_move, to_move, alloc);
+ parent()->transfer(position(), finish() - to_move, this, alloc);
if (!leaf()) {
// Move the child pointers from the left to the right node.
- for (int i = right->count(); i >= 0; --i) {
+ for (int i = right->finish(); i >= right->start(); --i) {
right->init_child(i + to_move, right->child(i));
right->clear_child(i);
}
for (int i = 1; i <= to_move; ++i) {
- right->init_child(i - 1, child(count() - to_move + i));
- clear_child(count() - to_move + i);
+ right->init_child(i - 1, child(finish() - to_move + i));
+ clear_child(finish() - to_move + i);
}
}
// Fixup the counts on the left and right nodes.
- set_count(count() - to_move);
- right->set_count(right->count() + to_move);
+ set_finish(finish() - to_move);
+ right->set_finish(right->finish() + to_move);
}
template <typename P>
@@ -1649,33 +1697,31 @@
// inserting at the beginning of the left node then bias the split to put
// more values on the right node. If we're inserting at the end of the
// right node then bias the split to put more values on the left node.
- if (insert_position == 0) {
- dest->set_count(count() - 1);
+ if (insert_position == start()) {
+ dest->set_finish(dest->start() + finish() - 1);
} else if (insert_position == kNodeValues) {
- dest->set_count(0);
+ dest->set_finish(dest->start());
} else {
- dest->set_count(count() / 2);
+ dest->set_finish(dest->start() + count() / 2);
}
- set_count(count() - dest->count());
+ set_finish(finish() - dest->count());
assert(count() >= 1);
// Move values from the left sibling to the right sibling.
- uninitialized_move_n(dest->count(), count(), 0, dest, alloc);
-
- // Destroy the now-empty entries in the left node.
- value_destroy_n(count(), dest->count(), alloc);
+ dest->transfer_n(dest->count(), dest->start(), finish(), this, alloc);
// The split key is the largest value in the left sibling.
- set_count(count() - 1);
- parent()->emplace_value(position(), alloc, slot(count()));
- value_destroy(count(), alloc);
+ --mutable_finish();
+ parent()->emplace_value(position(), alloc, finish_slot());
+ value_destroy(finish(), alloc);
parent()->init_child(position() + 1, dest);
if (!leaf()) {
- for (int i = 0; i <= dest->count(); ++i) {
- assert(child(count() + i + 1) != nullptr);
- dest->init_child(i, child(count() + i + 1));
- clear_child(count() + i + 1);
+ for (int i = dest->start(), j = finish() + 1; i <= dest->finish();
+ ++i, ++j) {
+ assert(child(j) != nullptr);
+ dest->init_child(i, child(j));
+ clear_child(j);
}
}
}
@@ -1686,74 +1732,76 @@
assert(position() + 1 == src->position());
// Move the delimiting value to the left node.
- value_init(count(), alloc, parent()->slot(position()));
+ value_init(finish(), alloc, parent()->slot(position()));
// Move the values from the right to the left node.
- src->uninitialized_move_n(src->count(), 0, count() + 1, this, alloc);
-
- // Destroy the now-empty entries in the right node.
- src->value_destroy_n(0, src->count(), alloc);
+ transfer_n(src->count(), finish() + 1, src->start(), src, alloc);
if (!leaf()) {
// Move the child pointers from the right to the left node.
- for (int i = 0; i <= src->count(); ++i) {
- init_child(count() + i + 1, src->child(i));
+ for (int i = src->start(), j = finish() + 1; i <= src->finish(); ++i, ++j) {
+ init_child(j, src->child(i));
src->clear_child(i);
}
}
- // Fixup the counts on the src and dest nodes.
- set_count(1 + count() + src->count());
- src->set_count(0);
+ // Fixup `finish` on the src and dest nodes.
+ set_finish(start() + 1 + count() + src->count());
+ src->set_finish(src->start());
- // Remove the value on the parent node.
- parent()->remove_value(position(), alloc);
+ // Remove the value on the parent node and delete the src node.
+ parent()->remove_values(position(), /*to_erase=*/1, alloc);
}
template <typename P>
-void btree_node<P>::swap(btree_node *x, allocator_type *alloc) {
- using std::swap;
- assert(leaf() == x->leaf());
-
- // Determine which is the smaller/larger node.
- btree_node *smaller = this, *larger = x;
- if (smaller->count() > larger->count()) {
- swap(smaller, larger);
+void btree_node<P>::clear_and_delete(btree_node *node, allocator_type *alloc) {
+ if (node->leaf()) {
+ node->value_destroy_n(node->start(), node->count(), alloc);
+ deallocate(LeafSize(node->max_count()), node, alloc);
+ return;
+ }
+ if (node->count() == 0) {
+ deallocate(InternalSize(), node, alloc);
+ return;
}
- // Swap the values.
- for (slot_type *a = smaller->slot(0), *b = larger->slot(0),
- *end = a + smaller->count();
- a != end; ++a, ++b) {
- params_type::swap(alloc, a, b);
+ // The parent of the root of the subtree we are deleting.
+ btree_node *delete_root_parent = node->parent();
+
+ // Navigate to the leftmost leaf under node, and then delete upwards.
+ while (!node->leaf()) node = node->start_child();
+ // Use `int` because `pos` needs to be able to hold `kNodeValues+1`, which
+ // isn't guaranteed to be a valid `field_type`.
+ int pos = node->position();
+ btree_node *parent = node->parent();
+ for (;;) {
+ // In each iteration of the next loop, we delete one leaf node and go right.
+ assert(pos <= parent->finish());
+ do {
+ node = parent->child(pos);
+ if (!node->leaf()) {
+ // Navigate to the leftmost leaf under node.
+ while (!node->leaf()) node = node->start_child();
+ pos = node->position();
+ parent = node->parent();
+ }
+ node->value_destroy_n(node->start(), node->count(), alloc);
+ deallocate(LeafSize(node->max_count()), node, alloc);
+ ++pos;
+ } while (pos <= parent->finish());
+
+ // Once we've deleted all children of parent, delete parent and go up/right.
+ assert(pos > parent->finish());
+ do {
+ node = parent;
+ pos = node->position();
+ parent = node->parent();
+ node->value_destroy_n(node->start(), node->count(), alloc);
+ deallocate(InternalSize(), node, alloc);
+ if (parent == delete_root_parent) return;
+ ++pos;
+ } while (pos > parent->finish());
}
-
- // Move values that can't be swapped.
- const size_type to_move = larger->count() - smaller->count();
- larger->uninitialized_move_n(to_move, smaller->count(), smaller->count(),
- smaller, alloc);
- larger->value_destroy_n(smaller->count(), to_move, alloc);
-
- if (!leaf()) {
- // Swap the child pointers.
- std::swap_ranges(&smaller->mutable_child(0),
- &smaller->mutable_child(smaller->count() + 1),
- &larger->mutable_child(0));
- // Update swapped children's parent pointers.
- int i = 0;
- for (; i <= smaller->count(); ++i) {
- smaller->child(i)->set_parent(smaller);
- larger->child(i)->set_parent(larger);
- }
- // Move the child pointers that couldn't be swapped.
- for (; i <= larger->count(); ++i) {
- smaller->init_child(i, larger->child(i));
- larger->clear_child(i);
- }
- }
-
- // Swap the counts.
- swap(mutable_count(), x->mutable_count());
}
////
@@ -1761,23 +1809,24 @@
template <typename N, typename R, typename P>
void btree_iterator<N, R, P>::increment_slow() {
if (node->leaf()) {
- assert(position >= node->count());
+ assert(position >= node->finish());
btree_iterator save(*this);
- while (position == node->count() && !node->is_root()) {
+ while (position == node->finish() && !node->is_root()) {
assert(node->parent()->child(node->position()) == node);
position = node->position();
node = node->parent();
}
- if (position == node->count()) {
+ // TODO(ezb): assert we aren't incrementing end() instead of handling.
+ if (position == node->finish()) {
*this = save;
}
} else {
- assert(position < node->count());
+ assert(position < node->finish());
node = node->child(position + 1);
while (!node->leaf()) {
- node = node->child(0);
+ node = node->start_child();
}
- position = 0;
+ position = node->start();
}
}
@@ -1786,21 +1835,22 @@
if (node->leaf()) {
assert(position <= -1);
btree_iterator save(*this);
- while (position < 0 && !node->is_root()) {
+ while (position < node->start() && !node->is_root()) {
assert(node->parent()->child(node->position()) == node);
position = node->position() - 1;
node = node->parent();
}
- if (position < 0) {
+ // TODO(ezb): assert we aren't decrementing begin() instead of handling.
+ if (position < node->start()) {
*this = save;
}
} else {
- assert(position >= 0);
+ assert(position >= node->start());
node = node->child(position);
while (!node->leaf()) {
- node = node->child(node->count());
+ node = node->child(node->finish());
}
- position = node->count() - 1;
+ position = node->finish() - 1;
}
}
@@ -1808,7 +1858,7 @@
// btree methods
template <typename P>
template <typename Btree>
-void btree<P>::copy_or_move_values_in_order(Btree *x) {
+void btree<P>::copy_or_move_values_in_order(Btree &other) {
static_assert(std::is_same<btree, Btree>::value ||
std::is_same<const btree, Btree>::value,
"Btree type must be same or const.");
@@ -1816,11 +1866,11 @@
// We can avoid key comparisons because we know the order of the
// values is the same order we'll store them in.
- auto iter = x->begin();
- if (iter == x->end()) return;
+ auto iter = other.begin();
+ if (iter == other.end()) return;
insert_multi(maybe_move_from_iterator(iter));
++iter;
- for (; iter != x->end(); ++iter) {
+ for (; iter != other.end(); ++iter) {
// If the btree is not empty, we can just insert the new value at the end
// of the tree.
internal_emplace(end(), maybe_move_from_iterator(iter));
@@ -1859,24 +1909,57 @@
}
template <typename P>
-btree<P>::btree(const key_compare &comp, const allocator_type &alloc)
- : root_(comp, alloc, EmptyNode()), rightmost_(EmptyNode()), size_(0) {}
-
-template <typename P>
-btree<P>::btree(const btree &x) : btree(x.key_comp(), x.allocator()) {
- copy_or_move_values_in_order(&x);
+template <typename K>
+auto btree<P>::lower_bound_equal(const K &key) const
+ -> std::pair<iterator, bool> {
+ const SearchResult<iterator, is_key_compare_to::value> res =
+ internal_lower_bound(key);
+ const iterator lower = iterator(internal_end(res.value));
+ const bool equal = res.HasMatch()
+ ? res.IsEq()
+ : lower != end() && !compare_keys(key, lower.key());
+ return {lower, equal};
}
template <typename P>
-template <typename... Args>
-auto btree<P>::insert_unique(const key_type &key, Args &&... args)
+template <typename K>
+auto btree<P>::equal_range(const K &key) -> std::pair<iterator, iterator> {
+ const std::pair<iterator, bool> lower_and_equal = lower_bound_equal(key);
+ const iterator lower = lower_and_equal.first;
+ if (!lower_and_equal.second) {
+ return {lower, lower};
+ }
+
+ const iterator next = std::next(lower);
+ if (!params_type::template can_have_multiple_equivalent_keys<K>()) {
+ // The next iterator after lower must point to a key greater than `key`.
+ // Note: if this assert fails, then it may indicate that the comparator does
+ // not meet the equivalence requirements for Compare
+ // (see https://en.cppreference.com/w/cpp/named_req/Compare).
+ assert(next == end() || compare_keys(key, next.key()));
+ return {lower, next};
+ }
+ // Try once more to avoid the call to upper_bound() if there's only one
+ // equivalent key. This should prevent all calls to upper_bound() in cases of
+ // unique-containers with heterogeneous comparators in which all comparison
+ // operators have the same equivalence classes.
+ if (next == end() || compare_keys(key, next.key())) return {lower, next};
+
+ // In this case, we need to call upper_bound() to avoid worst case O(N)
+ // behavior if we were to iterate over equal keys.
+ return {lower, upper_bound(key)};
+}
+
+template <typename P>
+template <typename K, typename... Args>
+auto btree<P>::insert_unique(const K &key, Args &&... args)
-> std::pair<iterator, bool> {
if (empty()) {
mutable_root() = rightmost_ = new_leaf_root_node(1);
}
- auto res = internal_locate(key);
- iterator &iter = res.value;
+ SearchResult<iterator, is_key_compare_to::value> res = internal_locate(key);
+ iterator iter = res.value;
if (res.HasMatch()) {
if (res.IsEq()) {
@@ -1894,14 +1977,13 @@
}
template <typename P>
-template <typename... Args>
-inline auto btree<P>::insert_hint_unique(iterator position, const key_type &key,
+template <typename K, typename... Args>
+inline auto btree<P>::insert_hint_unique(iterator position, const K &key,
Args &&... args)
-> std::pair<iterator, bool> {
if (!empty()) {
if (position == end() || compare_keys(key, position.key())) {
- iterator prev = position;
- if (position == begin() || compare_keys((--prev).key(), key)) {
+ if (position == begin() || compare_keys(std::prev(position).key(), key)) {
// prev.key() < key < position.key()
return {internal_emplace(position, std::forward<Args>(args)...), true};
}
@@ -1920,14 +2002,23 @@
}
template <typename P>
-template <typename InputIterator>
-void btree<P>::insert_iterator_unique(InputIterator b, InputIterator e) {
+template <typename InputIterator, typename>
+void btree<P>::insert_iterator_unique(InputIterator b, InputIterator e, int) {
for (; b != e; ++b) {
insert_hint_unique(end(), params_type::key(*b), *b);
}
}
template <typename P>
+template <typename InputIterator>
+void btree<P>::insert_iterator_unique(InputIterator b, InputIterator e, char) {
+ for (; b != e; ++b) {
+ init_type value(*b);
+ insert_hint_unique(end(), params_type::key(value), std::move(value));
+ }
+}
+
+template <typename P>
template <typename ValueType>
auto btree<P>::insert_multi(const key_type &key, ValueType &&v) -> iterator {
if (empty()) {
@@ -1947,17 +2038,16 @@
if (!empty()) {
const key_type &key = params_type::key(v);
if (position == end() || !compare_keys(position.key(), key)) {
- iterator prev = position;
- if (position == begin() || !compare_keys(key, (--prev).key())) {
+ if (position == begin() ||
+ !compare_keys(key, std::prev(position).key())) {
// prev.key() <= key <= position.key()
return internal_emplace(position, std::forward<ValueType>(v));
}
} else {
- iterator next = position;
- ++next;
- if (next == end() || !compare_keys(next.key(), key)) {
- // position.key() < key <= next.key()
- return internal_emplace(next, std::forward<ValueType>(v));
+ ++position;
+ if (position == end() || !compare_keys(position.key(), key)) {
+ // {original `position`}.key() < key < {current `position`}.key()
+ return internal_emplace(position, std::forward<ValueType>(v));
}
}
}
@@ -1973,46 +2063,47 @@
}
template <typename P>
-auto btree<P>::operator=(const btree &x) -> btree & {
- if (this != &x) {
+auto btree<P>::operator=(const btree &other) -> btree & {
+ if (this != &other) {
clear();
- *mutable_key_comp() = x.key_comp();
+ *mutable_key_comp() = other.key_comp();
if (absl::allocator_traits<
allocator_type>::propagate_on_container_copy_assignment::value) {
- *mutable_allocator() = x.allocator();
+ *mutable_allocator() = other.allocator();
}
- copy_or_move_values_in_order(&x);
+ copy_or_move_values_in_order(other);
}
return *this;
}
template <typename P>
-auto btree<P>::operator=(btree &&x) noexcept -> btree & {
- if (this != &x) {
+auto btree<P>::operator=(btree &&other) noexcept -> btree & {
+ if (this != &other) {
clear();
using std::swap;
if (absl::allocator_traits<
allocator_type>::propagate_on_container_copy_assignment::value) {
// Note: `root_` also contains the allocator and the key comparator.
- swap(root_, x.root_);
- swap(rightmost_, x.rightmost_);
- swap(size_, x.size_);
+ swap(root_, other.root_);
+ swap(rightmost_, other.rightmost_);
+ swap(size_, other.size_);
} else {
- if (allocator() == x.allocator()) {
- swap(mutable_root(), x.mutable_root());
- swap(*mutable_key_comp(), *x.mutable_key_comp());
- swap(rightmost_, x.rightmost_);
- swap(size_, x.size_);
+ if (allocator() == other.allocator()) {
+ swap(mutable_root(), other.mutable_root());
+ swap(*mutable_key_comp(), *other.mutable_key_comp());
+ swap(rightmost_, other.rightmost_);
+ swap(size_, other.size_);
} else {
// We aren't allowed to propagate the allocator and the allocator is
// different so we can't take over its memory. We must move each element
- // individually. We need both `x` and `this` to have `x`s key comparator
- // while moving the values so we can't swap the key comparators.
- *mutable_key_comp() = x.key_comp();
- copy_or_move_values_in_order(&x);
+ // individually. We need both `other` and `this` to have `other`s key
+ // comparator while moving the values so we can't swap the key
+ // comparators.
+ *mutable_key_comp() = other.key_comp();
+ copy_or_move_values_in_order(other);
}
}
}
@@ -2024,20 +2115,19 @@
bool internal_delete = false;
if (!iter.node->leaf()) {
// Deletion of a value on an internal node. First, move the largest value
- // from our left child here, then delete that position (in remove_value()
+ // from our left child here, then delete that position (in remove_values()
// below). We can get to the largest value from our left child by
// decrementing iter.
iterator internal_iter(iter);
--iter;
assert(iter.node->leaf());
- assert(!compare_keys(internal_iter.key(), iter.key()));
params_type::move(mutable_allocator(), iter.node->slot(iter.position),
internal_iter.node->slot(internal_iter.position));
internal_delete = true;
}
// Delete the key from the leaf.
- iter.node->remove_value(iter.position, mutable_allocator());
+ iter.node->remove_values(iter.position, /*to_erase=*/1, mutable_allocator());
--size_;
// We want to return the next value after the one we just erased. If we
@@ -2088,8 +2178,8 @@
// Adjust our return value. If we're pointing at the end of a node, advance
// the iterator.
- if (res.position == res.node->count()) {
- res.position = res.node->count() - 1;
+ if (res.position == res.node->finish()) {
+ res.position = res.node->finish() - 1;
++res;
}
@@ -2097,7 +2187,7 @@
}
template <typename P>
-auto btree<P>::erase(iterator begin, iterator end)
+auto btree<P>::erase_range(iterator begin, iterator end)
-> std::pair<size_type, iterator> {
difference_type count = std::distance(begin, end);
assert(count >= 0);
@@ -2112,7 +2202,9 @@
}
if (begin.node == end.node) {
- erase_same_node(begin, end);
+ assert(end.position > begin.position);
+ begin.node->remove_values(begin.position, end.position - begin.position,
+ mutable_allocator());
size_ -= count;
return {count, rebalance_after_delete(begin)};
}
@@ -2121,9 +2213,12 @@
while (size_ > target_size) {
if (begin.node->leaf()) {
const size_type remaining_to_erase = size_ - target_size;
- const size_type remaining_in_node = begin.node->count() - begin.position;
- begin = erase_from_leaf_node(
- begin, (std::min)(remaining_to_erase, remaining_in_node));
+ const size_type remaining_in_node = begin.node->finish() - begin.position;
+ const size_type to_erase =
+ (std::min)(remaining_to_erase, remaining_in_node);
+ begin.node->remove_values(begin.position, to_erase, mutable_allocator());
+ size_ -= to_erase;
+ begin = rebalance_after_delete(begin);
} else {
begin = erase(begin);
}
@@ -2132,78 +2227,9 @@
}
template <typename P>
-void btree<P>::erase_same_node(iterator begin, iterator end) {
- assert(begin.node == end.node);
- assert(end.position > begin.position);
-
- node_type *node = begin.node;
- size_type to_erase = end.position - begin.position;
- if (!node->leaf()) {
- // Delete all children between begin and end.
- for (size_type i = 0; i < to_erase; ++i) {
- internal_clear(node->child(begin.position + i + 1));
- }
- // Rotate children after end into new positions.
- for (size_type i = begin.position + to_erase + 1; i <= node->count(); ++i) {
- node->set_child(i - to_erase, node->child(i));
- node->clear_child(i);
- }
- }
- node->remove_values_ignore_children(begin.position, to_erase,
- mutable_allocator());
-
- // Do not need to update rightmost_, because
- // * either end == this->end(), and therefore node == rightmost_, and still
- // exists
- // * or end != this->end(), and therefore rightmost_ hasn't been erased, since
- // it wasn't covered in [begin, end)
-}
-
-template <typename P>
-auto btree<P>::erase_from_leaf_node(iterator begin, size_type to_erase)
- -> iterator {
- node_type *node = begin.node;
- assert(node->leaf());
- assert(node->count() > begin.position);
- assert(begin.position + to_erase <= node->count());
-
- node->remove_values_ignore_children(begin.position, to_erase,
- mutable_allocator());
-
- size_ -= to_erase;
-
- return rebalance_after_delete(begin);
-}
-
-template <typename P>
-template <typename K>
-auto btree<P>::erase_unique(const K &key) -> size_type {
- const iterator iter = internal_find(key);
- if (iter.node == nullptr) {
- // The key doesn't exist in the tree, return nothing done.
- return 0;
- }
- erase(iter);
- return 1;
-}
-
-template <typename P>
-template <typename K>
-auto btree<P>::erase_multi(const K &key) -> size_type {
- const iterator begin = internal_lower_bound(key);
- if (begin.node == nullptr) {
- // The key doesn't exist in the tree, return nothing done.
- return 0;
- }
- // Delete all of the keys between begin and upper_bound(key).
- const iterator end = internal_end(internal_upper_bound(key));
- return erase(begin, end).first;
-}
-
-template <typename P>
void btree<P>::clear() {
if (!empty()) {
- internal_clear(root());
+ node_type::clear_and_delete(root(), mutable_allocator());
}
mutable_root() = EmptyNode();
rightmost_ = EmptyNode();
@@ -2211,20 +2237,20 @@
}
template <typename P>
-void btree<P>::swap(btree &x) {
+void btree<P>::swap(btree &other) {
using std::swap;
if (absl::allocator_traits<
allocator_type>::propagate_on_container_swap::value) {
// Note: `root_` also contains the allocator and the key comparator.
- swap(root_, x.root_);
+ swap(root_, other.root_);
} else {
// It's undefined behavior if the allocators are unequal here.
- assert(allocator() == x.allocator());
- swap(mutable_root(), x.mutable_root());
- swap(*mutable_key_comp(), *x.mutable_key_comp());
+ assert(allocator() == other.allocator());
+ swap(mutable_root(), other.mutable_root());
+ swap(*mutable_key_comp(), *other.mutable_key_comp());
}
- swap(rightmost_, x.rightmost_);
- swap(size_, x.size_);
+ swap(rightmost_, other.rightmost_);
+ swap(size_, other.size_);
}
template <typename P>
@@ -2234,7 +2260,7 @@
assert(rightmost_ != nullptr);
assert(empty() || size() == internal_verify(root(), nullptr, nullptr));
assert(leftmost() == (++const_iterator(root(), -1)).node);
- assert(rightmost_ == (--const_iterator(root(), root()->count())).node);
+ assert(rightmost_ == (--const_iterator(root(), root()->finish())).node);
assert(leftmost()->leaf());
assert(rightmost_->leaf());
}
@@ -2249,7 +2275,7 @@
// First try to make room on the node by rebalancing.
node_type *parent = node->parent();
if (node != root()) {
- if (node->position() > 0) {
+ if (node->position() > parent->start()) {
// Try rebalancing with our left sibling.
node_type *left = parent->child(node->position() - 1);
assert(left->max_count() == kNodeValues);
@@ -2258,16 +2284,16 @@
// inserting at the end of the right node then we bias rebalancing to
// fill up the left node.
int to_move = (kNodeValues - left->count()) /
- (1 + (insert_position < kNodeValues));
+ (1 + (insert_position < static_cast<int>(kNodeValues)));
to_move = (std::max)(1, to_move);
- if (((insert_position - to_move) >= 0) ||
- ((left->count() + to_move) < kNodeValues)) {
+ if (insert_position - to_move >= node->start() ||
+ left->count() + to_move < static_cast<int>(kNodeValues)) {
left->rebalance_right_to_left(to_move, node, mutable_allocator());
assert(node->max_count() - node->count() == to_move);
insert_position = insert_position - to_move;
- if (insert_position < 0) {
+ if (insert_position < node->start()) {
insert_position = insert_position + left->count() + 1;
node = left;
}
@@ -2278,7 +2304,7 @@
}
}
- if (node->position() < parent->count()) {
+ if (node->position() < parent->finish()) {
// Try rebalancing with our right sibling.
node_type *right = parent->child(node->position() + 1);
assert(right->max_count() == kNodeValues);
@@ -2286,15 +2312,15 @@
// We bias rebalancing based on the position being inserted. If we're
// inserting at the beginning of the left node then we bias rebalancing
// to fill up the right node.
- int to_move =
- (kNodeValues - right->count()) / (1 + (insert_position > 0));
+ int to_move = (static_cast<int>(kNodeValues) - right->count()) /
+ (1 + (insert_position > node->start()));
to_move = (std::max)(1, to_move);
- if ((insert_position <= (node->count() - to_move)) ||
- ((right->count() + to_move) < kNodeValues)) {
+ if (insert_position <= node->finish() - to_move ||
+ right->count() + to_move < static_cast<int>(kNodeValues)) {
node->rebalance_left_to_right(to_move, right, mutable_allocator());
- if (insert_position > node->count()) {
+ if (insert_position > node->finish()) {
insert_position = insert_position - node->count() - 1;
node = right;
}
@@ -2317,10 +2343,11 @@
// Create a new root node and set the current root node as the child of the
// new root.
parent = new_internal_node(parent);
- parent->init_child(0, root());
+ parent->init_child(parent->start(), root());
mutable_root() = parent;
// If the former root was a leaf node, then it's now the rightmost node.
- assert(!parent->child(0)->leaf() || parent->child(0) == rightmost_);
+ assert(!parent->start_child()->leaf() ||
+ parent->start_child() == rightmost_);
}
// Split the node.
@@ -2334,7 +2361,7 @@
node->split(insert_position, split_node, mutable_allocator());
}
- if (insert_position > node->count()) {
+ if (insert_position > node->finish()) {
insert_position = insert_position - node->count() - 1;
node = split_node;
}
@@ -2343,33 +2370,28 @@
template <typename P>
void btree<P>::merge_nodes(node_type *left, node_type *right) {
left->merge(right, mutable_allocator());
- if (right->leaf()) {
- if (rightmost_ == right) rightmost_ = left;
- delete_leaf_node(right);
- } else {
- delete_internal_node(right);
- }
+ if (rightmost_ == right) rightmost_ = left;
}
template <typename P>
bool btree<P>::try_merge_or_rebalance(iterator *iter) {
node_type *parent = iter->node->parent();
- if (iter->node->position() > 0) {
+ if (iter->node->position() > parent->start()) {
// Try merging with our left sibling.
node_type *left = parent->child(iter->node->position() - 1);
assert(left->max_count() == kNodeValues);
- if ((1 + left->count() + iter->node->count()) <= kNodeValues) {
+ if (1U + left->count() + iter->node->count() <= kNodeValues) {
iter->position += 1 + left->count();
merge_nodes(left, iter->node);
iter->node = left;
return true;
}
}
- if (iter->node->position() < parent->count()) {
+ if (iter->node->position() < parent->finish()) {
// Try merging with our right sibling.
node_type *right = parent->child(iter->node->position() + 1);
assert(right->max_count() == kNodeValues);
- if ((1 + iter->node->count() + right->count()) <= kNodeValues) {
+ if (1U + iter->node->count() + right->count() <= kNodeValues) {
merge_nodes(iter->node, right);
return true;
}
@@ -2377,24 +2399,22 @@
// we deleted the first element from iter->node and the node is not
// empty. This is a small optimization for the common pattern of deleting
// from the front of the tree.
- if ((right->count() > kMinNodeValues) &&
- ((iter->node->count() == 0) ||
- (iter->position > 0))) {
+ if (right->count() > kMinNodeValues &&
+ (iter->node->count() == 0 || iter->position > iter->node->start())) {
int to_move = (right->count() - iter->node->count()) / 2;
to_move = (std::min)(to_move, right->count() - 1);
iter->node->rebalance_right_to_left(to_move, right, mutable_allocator());
return false;
}
}
- if (iter->node->position() > 0) {
+ if (iter->node->position() > parent->start()) {
// Try rebalancing with our left sibling. We don't perform rebalancing if
// we deleted the last element from iter->node and the node is not
// empty. This is a small optimization for the common pattern of deleting
// from the back of the tree.
node_type *left = parent->child(iter->node->position() - 1);
- if ((left->count() > kMinNodeValues) &&
- ((iter->node->count() == 0) ||
- (iter->position < iter->node->count()))) {
+ if (left->count() > kMinNodeValues &&
+ (iter->node->count() == 0 || iter->position < iter->node->finish())) {
int to_move = (left->count() - iter->node->count()) / 2;
to_move = (std::min)(to_move, left->count() - 1);
left->rebalance_left_to_right(to_move, iter->node, mutable_allocator());
@@ -2407,28 +2427,27 @@
template <typename P>
void btree<P>::try_shrink() {
- if (root()->count() > 0) {
+ node_type *orig_root = root();
+ if (orig_root->count() > 0) {
return;
}
// Deleted the last item on the root node, shrink the height of the tree.
- if (root()->leaf()) {
+ if (orig_root->leaf()) {
assert(size() == 0);
- delete_leaf_node(root());
- mutable_root() = EmptyNode();
- rightmost_ = EmptyNode();
+ mutable_root() = rightmost_ = EmptyNode();
} else {
- node_type *child = root()->child(0);
+ node_type *child = orig_root->start_child();
child->make_root();
- delete_internal_node(root());
mutable_root() = child;
}
+ node_type::clear_and_delete(orig_root, mutable_allocator());
}
template <typename P>
template <typename IterType>
inline IterType btree<P>::internal_last(IterType iter) {
assert(iter.node != nullptr);
- while (iter.position == iter.node->count()) {
+ while (iter.position == iter.node->finish()) {
iter.position = iter.node->position();
iter.node = iter.node->parent();
if (iter.node->leaf()) {
@@ -2449,7 +2468,8 @@
--iter;
++iter.position;
}
- const int max_count = iter.node->max_count();
+ const field_type max_count = iter.node->max_count();
+ allocator_type *alloc = mutable_allocator();
if (iter.node->count() == max_count) {
// Make room in the leaf for the new item.
if (max_count < kNodeValues) {
@@ -2458,16 +2478,20 @@
assert(iter.node == root());
iter.node =
new_leaf_root_node((std::min<int>)(kNodeValues, 2 * max_count));
- iter.node->swap(root(), mutable_allocator());
- delete_leaf_node(root());
- mutable_root() = iter.node;
- rightmost_ = iter.node;
+ // Transfer the values from the old root to the new root.
+ node_type *old_root = root();
+ node_type *new_root = iter.node;
+ new_root->transfer_n(old_root->count(), new_root->start(),
+ old_root->start(), old_root, alloc);
+ new_root->set_finish(old_root->finish());
+ old_root->set_finish(old_root->start());
+ node_type::clear_and_delete(old_root, alloc);
+ mutable_root() = rightmost_ = new_root;
} else {
rebalance_or_split(&iter);
}
}
- iter.node->emplace_value(iter.position, mutable_allocator(),
- std::forward<Args>(args)...);
+ iter.node->emplace_value(iter.position, alloc, std::forward<Args>(args)...);
++size_;
return iter;
}
@@ -2476,67 +2500,57 @@
template <typename K>
inline auto btree<P>::internal_locate(const K &key) const
-> SearchResult<iterator, is_key_compare_to::value> {
- return internal_locate_impl(key, is_key_compare_to());
-}
-
-template <typename P>
-template <typename K>
-inline auto btree<P>::internal_locate_impl(
- const K &key, std::false_type /* IsCompareTo */) const
- -> SearchResult<iterator, false> {
- iterator iter(const_cast<node_type *>(root()), 0);
+ iterator iter(const_cast<node_type *>(root()));
for (;;) {
- iter.position = iter.node->lower_bound(key, key_comp()).value;
- // NOTE: we don't need to walk all the way down the tree if the keys are
- // equal, but determining equality would require doing an extra comparison
- // on each node on the way down, and we will need to go all the way to the
- // leaf node in the expected case.
- if (iter.node->leaf()) {
- break;
- }
- iter.node = iter.node->child(iter.position);
- }
- return {iter};
-}
-
-template <typename P>
-template <typename K>
-inline auto btree<P>::internal_locate_impl(
- const K &key, std::true_type /* IsCompareTo */) const
- -> SearchResult<iterator, true> {
- iterator iter(const_cast<node_type *>(root()), 0);
- for (;;) {
- SearchResult<int, true> res = iter.node->lower_bound(key, key_comp());
+ SearchResult<int, is_key_compare_to::value> res =
+ iter.node->lower_bound(key, key_comp());
iter.position = res.value;
- if (res.match == MatchKind::kEq) {
+ if (res.IsEq()) {
return {iter, MatchKind::kEq};
}
+ // Note: in the non-key-compare-to case, we don't need to walk all the way
+ // down the tree if the keys are equal, but determining equality would
+ // require doing an extra comparison on each node on the way down, and we
+ // will need to go all the way to the leaf node in the expected case.
if (iter.node->leaf()) {
break;
}
iter.node = iter.node->child(iter.position);
}
+ // Note: in the non-key-compare-to case, the key may actually be equivalent
+ // here (and the MatchKind::kNe is ignored).
return {iter, MatchKind::kNe};
}
template <typename P>
template <typename K>
-auto btree<P>::internal_lower_bound(const K &key) const -> iterator {
- iterator iter(const_cast<node_type *>(root()), 0);
+auto btree<P>::internal_lower_bound(const K &key) const
+ -> SearchResult<iterator, is_key_compare_to::value> {
+ if (!params_type::template can_have_multiple_equivalent_keys<K>()) {
+ SearchResult<iterator, is_key_compare_to::value> ret = internal_locate(key);
+ ret.value = internal_last(ret.value);
+ return ret;
+ }
+ iterator iter(const_cast<node_type *>(root()));
+ SearchResult<int, is_key_compare_to::value> res;
+ bool seen_eq = false;
for (;;) {
- iter.position = iter.node->lower_bound(key, key_comp()).value;
+ res = iter.node->lower_bound(key, key_comp());
+ iter.position = res.value;
if (iter.node->leaf()) {
break;
}
+ seen_eq = seen_eq || res.IsEq();
iter.node = iter.node->child(iter.position);
}
- return internal_last(iter);
+ if (res.IsEq()) return {iter, MatchKind::kEq};
+ return {internal_last(iter), seen_eq ? MatchKind::kEq : MatchKind::kNe};
}
template <typename P>
template <typename K>
auto btree<P>::internal_upper_bound(const K &key) const -> iterator {
- iterator iter(const_cast<node_type *>(root()), 0);
+ iterator iter(const_cast<node_type *>(root()));
for (;;) {
iter.position = iter.node->upper_bound(key, key_comp());
if (iter.node->leaf()) {
@@ -2550,7 +2564,7 @@
template <typename P>
template <typename K>
auto btree<P>::internal_find(const K &key) const -> iterator {
- auto res = internal_locate(key);
+ SearchResult<iterator, is_key_compare_to::value> res = internal_locate(key);
if (res.HasMatch()) {
if (res.IsEq()) {
return res.value;
@@ -2565,47 +2579,35 @@
}
template <typename P>
-void btree<P>::internal_clear(node_type *node) {
- if (!node->leaf()) {
- for (int i = 0; i <= node->count(); ++i) {
- internal_clear(node->child(i));
- }
- delete_internal_node(node);
- } else {
- delete_leaf_node(node);
- }
-}
-
-template <typename P>
-int btree<P>::internal_verify(
- const node_type *node, const key_type *lo, const key_type *hi) const {
+int btree<P>::internal_verify(const node_type *node, const key_type *lo,
+ const key_type *hi) const {
assert(node->count() > 0);
assert(node->count() <= node->max_count());
if (lo) {
- assert(!compare_keys(node->key(0), *lo));
+ assert(!compare_keys(node->key(node->start()), *lo));
}
if (hi) {
- assert(!compare_keys(*hi, node->key(node->count() - 1)));
+ assert(!compare_keys(*hi, node->key(node->finish() - 1)));
}
- for (int i = 1; i < node->count(); ++i) {
+ for (int i = node->start() + 1; i < node->finish(); ++i) {
assert(!compare_keys(node->key(i), node->key(i - 1)));
}
int count = node->count();
if (!node->leaf()) {
- for (int i = 0; i <= node->count(); ++i) {
+ for (int i = node->start(); i <= node->finish(); ++i) {
assert(node->child(i) != nullptr);
assert(node->child(i)->parent() == node);
assert(node->child(i)->position() == i);
- count += internal_verify(
- node->child(i),
- (i == 0) ? lo : &node->key(i - 1),
- (i == node->count()) ? hi : &node->key(i));
+ count += internal_verify(node->child(i),
+ i == node->start() ? lo : &node->key(i - 1),
+ i == node->finish() ? hi : &node->key(i));
}
}
return count;
}
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_BTREE_H_
diff --git a/third_party/abseil/absl/container/internal/btree_container.h b/third_party/abseil/absl/container/internal/btree_container.h
index 726861d..03be708 100644
--- a/third_party/abseil/absl/container/internal/btree_container.h
+++ b/third_party/abseil/absl/container/internal/btree_container.h
@@ -23,9 +23,11 @@
#include "absl/base/internal/throw_delegate.h"
#include "absl/container/internal/btree.h" // IWYU pragma: export
#include "absl/container/internal/common.h"
+#include "absl/memory/memory.h"
#include "absl/meta/type_traits.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
// A common base class for btree_set, btree_map, btree_multiset, and
@@ -67,10 +69,23 @@
explicit btree_container(const key_compare &comp,
const allocator_type &alloc = allocator_type())
: tree_(comp, alloc) {}
- btree_container(const btree_container &x) = default;
- btree_container(btree_container &&x) noexcept = default;
- btree_container &operator=(const btree_container &x) = default;
- btree_container &operator=(btree_container &&x) noexcept(
+ explicit btree_container(const allocator_type &alloc)
+ : tree_(key_compare(), alloc) {}
+
+ btree_container(const btree_container &other)
+ : btree_container(other, absl::allocator_traits<allocator_type>::
+ select_on_container_copy_construction(
+ other.get_allocator())) {}
+ btree_container(const btree_container &other, const allocator_type &alloc)
+ : tree_(other.tree_, alloc) {}
+
+ btree_container(btree_container &&other) noexcept(
+ std::is_nothrow_move_constructible<Tree>::value) = default;
+ btree_container(btree_container &&other, const allocator_type &alloc)
+ : tree_(std::move(other.tree_), alloc) {}
+
+ btree_container &operator=(const btree_container &other) = default;
+ btree_container &operator=(btree_container &&other) noexcept(
std::is_nothrow_move_assignable<Tree>::value) = default;
// Iterator routines.
@@ -89,6 +104,11 @@
// Lookup routines.
template <typename K = key_type>
+ size_type count(const key_arg<K> &key) const {
+ auto equal_range = this->equal_range(key);
+ return std::distance(equal_range.first, equal_range.second);
+ }
+ template <typename K = key_type>
iterator find(const key_arg<K> &key) {
return tree_.find(key);
}
@@ -135,7 +155,12 @@
iterator erase(const_iterator iter) { return tree_.erase(iterator(iter)); }
iterator erase(iterator iter) { return tree_.erase(iter); }
iterator erase(const_iterator first, const_iterator last) {
- return tree_.erase(iterator(first), iterator(last)).second;
+ return tree_.erase_range(iterator(first), iterator(last)).second;
+ }
+ template <typename K = key_type>
+ size_type erase(const key_arg<K> &key) {
+ auto equal_range = this->equal_range(key);
+ return tree_.erase_range(equal_range.first, equal_range.second).first;
}
// Extract routines.
@@ -150,10 +175,9 @@
return extract(iterator(position));
}
- public:
// Utility routines.
void clear() { tree_.clear(); }
- void swap(btree_container &x) { tree_.swap(x.tree_); }
+ void swap(btree_container &other) { tree_.swap(other.tree_); }
void verify() const { tree_.verify(); }
// Size routines.
@@ -234,7 +258,7 @@
using super_type::super_type;
btree_set_container() {}
- // Range constructor.
+ // Range constructors.
template <class InputIterator>
btree_set_container(InputIterator b, InputIterator e,
const key_compare &comp = key_compare(),
@@ -242,63 +266,63 @@
: super_type(comp, alloc) {
insert(b, e);
}
+ template <class InputIterator>
+ btree_set_container(InputIterator b, InputIterator e,
+ const allocator_type &alloc)
+ : btree_set_container(b, e, key_compare(), alloc) {}
- // Initializer list constructor.
+ // Initializer list constructors.
btree_set_container(std::initializer_list<init_type> init,
const key_compare &comp = key_compare(),
const allocator_type &alloc = allocator_type())
: btree_set_container(init.begin(), init.end(), comp, alloc) {}
-
- // Lookup routines.
- template <typename K = key_type>
- size_type count(const key_arg<K> &key) const {
- return this->tree_.count_unique(key);
- }
+ btree_set_container(std::initializer_list<init_type> init,
+ const allocator_type &alloc)
+ : btree_set_container(init.begin(), init.end(), alloc) {}
// Insertion routines.
- std::pair<iterator, bool> insert(const value_type &x) {
- return this->tree_.insert_unique(params_type::key(x), x);
+ std::pair<iterator, bool> insert(const value_type &v) {
+ return this->tree_.insert_unique(params_type::key(v), v);
}
- std::pair<iterator, bool> insert(value_type &&x) {
- return this->tree_.insert_unique(params_type::key(x), std::move(x));
+ std::pair<iterator, bool> insert(value_type &&v) {
+ return this->tree_.insert_unique(params_type::key(v), std::move(v));
}
template <typename... Args>
std::pair<iterator, bool> emplace(Args &&... args) {
init_type v(std::forward<Args>(args)...);
return this->tree_.insert_unique(params_type::key(v), std::move(v));
}
- iterator insert(const_iterator position, const value_type &x) {
+ iterator insert(const_iterator hint, const value_type &v) {
return this->tree_
- .insert_hint_unique(iterator(position), params_type::key(x), x)
+ .insert_hint_unique(iterator(hint), params_type::key(v), v)
.first;
}
- iterator insert(const_iterator position, value_type &&x) {
+ iterator insert(const_iterator hint, value_type &&v) {
return this->tree_
- .insert_hint_unique(iterator(position), params_type::key(x),
- std::move(x))
+ .insert_hint_unique(iterator(hint), params_type::key(v), std::move(v))
.first;
}
template <typename... Args>
- iterator emplace_hint(const_iterator position, Args &&... args) {
+ iterator emplace_hint(const_iterator hint, Args &&... args) {
init_type v(std::forward<Args>(args)...);
return this->tree_
- .insert_hint_unique(iterator(position), params_type::key(v),
- std::move(v))
+ .insert_hint_unique(iterator(hint), params_type::key(v), std::move(v))
.first;
}
template <typename InputIterator>
void insert(InputIterator b, InputIterator e) {
- this->tree_.insert_iterator_unique(b, e);
+ this->tree_.insert_iterator_unique(b, e, 0);
}
void insert(std::initializer_list<init_type> init) {
- this->tree_.insert_iterator_unique(init.begin(), init.end());
+ this->tree_.insert_iterator_unique(init.begin(), init.end(), 0);
}
insert_return_type insert(node_type &&node) {
if (!node) return {this->end(), false, node_type()};
std::pair<iterator, bool> res =
- insert(std::move(params_type::element(CommonAccess::GetSlot(node))));
+ this->tree_.insert_unique(params_type::key(CommonAccess::GetSlot(node)),
+ CommonAccess::GetSlot(node));
if (res.second) {
- CommonAccess::Reset(&node);
+ CommonAccess::Destroy(&node);
return {res.first, true, node_type()};
} else {
return {res.first, false, std::move(node)};
@@ -308,23 +332,18 @@
if (!node) return this->end();
std::pair<iterator, bool> res = this->tree_.insert_hint_unique(
iterator(hint), params_type::key(CommonAccess::GetSlot(node)),
- std::move(params_type::element(CommonAccess::GetSlot(node))));
- if (res.second) CommonAccess::Reset(&node);
+ CommonAccess::GetSlot(node));
+ if (res.second) CommonAccess::Destroy(&node);
return res.first;
}
- // Deletion routines.
- template <typename K = key_type>
- size_type erase(const key_arg<K> &key) {
- return this->tree_.erase_unique(key);
- }
- using super_type::erase;
-
// Node extraction routines.
template <typename K = key_type>
node_type extract(const key_arg<K> &key) {
- auto it = find(key);
- return it == this->end() ? node_type() : extract(it);
+ const std::pair<iterator, bool> lower_and_equal =
+ this->tree_.lower_bound_equal(key);
+ return lower_and_equal.second ? extract(lower_and_equal.first)
+ : node_type();
}
using super_type::extract;
@@ -342,7 +361,7 @@
int> = 0>
void merge(btree_container<T> &src) { // NOLINT
for (auto src_it = src.begin(); src_it != src.end();) {
- if (insert(std::move(*src_it)).second) {
+ if (insert(std::move(params_type::element(src_it.slot()))).second) {
src_it = src.erase(src_it);
} else {
++src_it;
@@ -369,8 +388,9 @@
class btree_map_container : public btree_set_container<Tree> {
using super_type = btree_set_container<Tree>;
using params_type = typename Tree::params_type;
+ friend class BtreeNodePeer;
- protected:
+ private:
template <class K>
using key_arg = typename super_type::template key_arg<K>;
@@ -388,50 +408,74 @@
btree_map_container() {}
// Insertion routines.
- template <typename... Args>
- std::pair<iterator, bool> try_emplace(const key_type &k, Args &&... args) {
- return this->tree_.insert_unique(
- k, std::piecewise_construct, std::forward_as_tuple(k),
- std::forward_as_tuple(std::forward<Args>(args)...));
+ // Note: the nullptr template arguments and extra `const M&` overloads allow
+ // for supporting bitfield arguments.
+ template <typename K = key_type, class M>
+ std::pair<iterator, bool> insert_or_assign(const key_arg<K> &k,
+ const M &obj) {
+ return insert_or_assign_impl(k, obj);
}
- template <typename... Args>
- std::pair<iterator, bool> try_emplace(key_type &&k, Args &&... args) {
- // Note: `key_ref` exists to avoid a ClangTidy warning about moving from `k`
- // and then using `k` unsequenced. This is safe because the move is into a
- // forwarding reference and insert_unique guarantees that `key` is never
- // referenced after consuming `args`.
- const key_type& key_ref = k;
- return this->tree_.insert_unique(
- key_ref, std::piecewise_construct, std::forward_as_tuple(std::move(k)),
- std::forward_as_tuple(std::forward<Args>(args)...));
+ template <typename K = key_type, class M, K * = nullptr>
+ std::pair<iterator, bool> insert_or_assign(key_arg<K> &&k, const M &obj) {
+ return insert_or_assign_impl(std::forward<K>(k), obj);
}
- template <typename... Args>
- iterator try_emplace(const_iterator hint, const key_type &k,
+ template <typename K = key_type, class M, M * = nullptr>
+ std::pair<iterator, bool> insert_or_assign(const key_arg<K> &k, M &&obj) {
+ return insert_or_assign_impl(k, std::forward<M>(obj));
+ }
+ template <typename K = key_type, class M, K * = nullptr, M * = nullptr>
+ std::pair<iterator, bool> insert_or_assign(key_arg<K> &&k, M &&obj) {
+ return insert_or_assign_impl(std::forward<K>(k), std::forward<M>(obj));
+ }
+ template <typename K = key_type, class M>
+ iterator insert_or_assign(const_iterator hint, const key_arg<K> &k,
+ const M &obj) {
+ return insert_or_assign_hint_impl(hint, k, obj);
+ }
+ template <typename K = key_type, class M, K * = nullptr>
+ iterator insert_or_assign(const_iterator hint, key_arg<K> &&k, const M &obj) {
+ return insert_or_assign_hint_impl(hint, std::forward<K>(k), obj);
+ }
+ template <typename K = key_type, class M, M * = nullptr>
+ iterator insert_or_assign(const_iterator hint, const key_arg<K> &k, M &&obj) {
+ return insert_or_assign_hint_impl(hint, k, std::forward<M>(obj));
+ }
+ template <typename K = key_type, class M, K * = nullptr, M * = nullptr>
+ iterator insert_or_assign(const_iterator hint, key_arg<K> &&k, M &&obj) {
+ return insert_or_assign_hint_impl(hint, std::forward<K>(k),
+ std::forward<M>(obj));
+ }
+
+ template <typename K = key_type, typename... Args,
+ typename absl::enable_if_t<
+ !std::is_convertible<K, const_iterator>::value, int> = 0>
+ std::pair<iterator, bool> try_emplace(const key_arg<K> &k, Args &&... args) {
+ return try_emplace_impl(k, std::forward<Args>(args)...);
+ }
+ template <typename K = key_type, typename... Args,
+ typename absl::enable_if_t<
+ !std::is_convertible<K, const_iterator>::value, int> = 0>
+ std::pair<iterator, bool> try_emplace(key_arg<K> &&k, Args &&... args) {
+ return try_emplace_impl(std::forward<K>(k), std::forward<Args>(args)...);
+ }
+ template <typename K = key_type, typename... Args>
+ iterator try_emplace(const_iterator hint, const key_arg<K> &k,
Args &&... args) {
- return this->tree_
- .insert_hint_unique(iterator(hint), k, std::piecewise_construct,
- std::forward_as_tuple(k),
- std::forward_as_tuple(std::forward<Args>(args)...))
- .first;
+ return try_emplace_hint_impl(hint, k, std::forward<Args>(args)...);
}
- template <typename... Args>
- iterator try_emplace(const_iterator hint, key_type &&k, Args &&... args) {
- // Note: `key_ref` exists to avoid a ClangTidy warning about moving from `k`
- // and then using `k` unsequenced. This is safe because the move is into a
- // forwarding reference and insert_hint_unique guarantees that `key` is
- // never referenced after consuming `args`.
- const key_type& key_ref = k;
- return this->tree_
- .insert_hint_unique(iterator(hint), key_ref, std::piecewise_construct,
- std::forward_as_tuple(std::move(k)),
- std::forward_as_tuple(std::forward<Args>(args)...))
- .first;
+ template <typename K = key_type, typename... Args>
+ iterator try_emplace(const_iterator hint, key_arg<K> &&k, Args &&... args) {
+ return try_emplace_hint_impl(hint, std::forward<K>(k),
+ std::forward<Args>(args)...);
}
- mapped_type &operator[](const key_type &k) {
+
+ template <typename K = key_type>
+ mapped_type &operator[](const key_arg<K> &k) {
return try_emplace(k).first->second;
}
- mapped_type &operator[](key_type &&k) {
- return try_emplace(std::move(k)).first->second;
+ template <typename K = key_type>
+ mapped_type &operator[](key_arg<K> &&k) {
+ return try_emplace(std::forward<K>(k)).first->second;
}
template <typename K = key_type>
@@ -448,6 +492,40 @@
base_internal::ThrowStdOutOfRange("absl::btree_map::at");
return it->second;
}
+
+ private:
+ // Note: when we call `std::forward<M>(obj)` twice, it's safe because
+ // insert_unique/insert_hint_unique are guaranteed to not consume `obj` when
+ // `ret.second` is false.
+ template <class K, class M>
+ std::pair<iterator, bool> insert_or_assign_impl(K &&k, M &&obj) {
+ const std::pair<iterator, bool> ret =
+ this->tree_.insert_unique(k, std::forward<K>(k), std::forward<M>(obj));
+ if (!ret.second) ret.first->second = std::forward<M>(obj);
+ return ret;
+ }
+ template <class K, class M>
+ iterator insert_or_assign_hint_impl(const_iterator hint, K &&k, M &&obj) {
+ const std::pair<iterator, bool> ret = this->tree_.insert_hint_unique(
+ iterator(hint), k, std::forward<K>(k), std::forward<M>(obj));
+ if (!ret.second) ret.first->second = std::forward<M>(obj);
+ return ret.first;
+ }
+
+ template <class K, class... Args>
+ std::pair<iterator, bool> try_emplace_impl(K &&k, Args &&... args) {
+ return this->tree_.insert_unique(
+ k, std::piecewise_construct, std::forward_as_tuple(std::forward<K>(k)),
+ std::forward_as_tuple(std::forward<Args>(args)...));
+ }
+ template <class K, class... Args>
+ iterator try_emplace_hint_impl(const_iterator hint, K &&k, Args &&... args) {
+ return this->tree_
+ .insert_hint_unique(iterator(hint), k, std::piecewise_construct,
+ std::forward_as_tuple(std::forward<K>(k)),
+ std::forward_as_tuple(std::forward<Args>(args)...))
+ .first;
+ }
};
// A common base class for btree_multiset and btree_multimap.
@@ -475,7 +553,7 @@
using super_type::super_type;
btree_multiset_container() {}
- // Range constructor.
+ // Range constructors.
template <class InputIterator>
btree_multiset_container(InputIterator b, InputIterator e,
const key_compare &comp = key_compare(),
@@ -483,29 +561,30 @@
: super_type(comp, alloc) {
insert(b, e);
}
+ template <class InputIterator>
+ btree_multiset_container(InputIterator b, InputIterator e,
+ const allocator_type &alloc)
+ : btree_multiset_container(b, e, key_compare(), alloc) {}
- // Initializer list constructor.
+ // Initializer list constructors.
btree_multiset_container(std::initializer_list<init_type> init,
const key_compare &comp = key_compare(),
const allocator_type &alloc = allocator_type())
: btree_multiset_container(init.begin(), init.end(), comp, alloc) {}
-
- // Lookup routines.
- template <typename K = key_type>
- size_type count(const key_arg<K> &key) const {
- return this->tree_.count_multi(key);
- }
+ btree_multiset_container(std::initializer_list<init_type> init,
+ const allocator_type &alloc)
+ : btree_multiset_container(init.begin(), init.end(), alloc) {}
// Insertion routines.
- iterator insert(const value_type &x) { return this->tree_.insert_multi(x); }
- iterator insert(value_type &&x) {
- return this->tree_.insert_multi(std::move(x));
+ iterator insert(const value_type &v) { return this->tree_.insert_multi(v); }
+ iterator insert(value_type &&v) {
+ return this->tree_.insert_multi(std::move(v));
}
- iterator insert(const_iterator position, const value_type &x) {
- return this->tree_.insert_hint_multi(iterator(position), x);
+ iterator insert(const_iterator hint, const value_type &v) {
+ return this->tree_.insert_hint_multi(iterator(hint), v);
}
- iterator insert(const_iterator position, value_type &&x) {
- return this->tree_.insert_hint_multi(iterator(position), std::move(x));
+ iterator insert(const_iterator hint, value_type &&v) {
+ return this->tree_.insert_hint_multi(iterator(hint), std::move(v));
}
template <typename InputIterator>
void insert(InputIterator b, InputIterator e) {
@@ -519,42 +598,34 @@
return this->tree_.insert_multi(init_type(std::forward<Args>(args)...));
}
template <typename... Args>
- iterator emplace_hint(const_iterator position, Args &&... args) {
+ iterator emplace_hint(const_iterator hint, Args &&... args) {
return this->tree_.insert_hint_multi(
- iterator(position), init_type(std::forward<Args>(args)...));
+ iterator(hint), init_type(std::forward<Args>(args)...));
}
-
- private:
- template <typename... Args>
- iterator insert_node_helper(node_type &&node, Args &&... args) {
+ iterator insert(node_type &&node) {
if (!node) return this->end();
iterator res =
- insert(std::forward<Args>(args)...,
- std::move(params_type::element(CommonAccess::GetSlot(node))));
- CommonAccess::Reset(&node);
+ this->tree_.insert_multi(params_type::key(CommonAccess::GetSlot(node)),
+ CommonAccess::GetSlot(node));
+ CommonAccess::Destroy(&node);
return res;
}
-
- public:
- iterator insert(node_type &&node) {
- return insert_node_helper(std::move(node));
- }
iterator insert(const_iterator hint, node_type &&node) {
- return insert_node_helper(std::move(node), hint);
+ if (!node) return this->end();
+ iterator res = this->tree_.insert_hint_multi(
+ iterator(hint),
+ std::move(params_type::element(CommonAccess::GetSlot(node))));
+ CommonAccess::Destroy(&node);
+ return res;
}
- // Deletion routines.
- template <typename K = key_type>
- size_type erase(const key_arg<K> &key) {
- return this->tree_.erase_multi(key);
- }
- using super_type::erase;
-
// Node extraction routines.
template <typename K = key_type>
node_type extract(const key_arg<K> &key) {
- auto it = find(key);
- return it == this->end() ? node_type() : extract(it);
+ const std::pair<iterator, bool> lower_and_equal =
+ this->tree_.lower_bound_equal(key);
+ return lower_and_equal.second ? extract(lower_and_equal.first)
+ : node_type();
}
using super_type::extract;
@@ -570,8 +641,9 @@
typename T::params_type::is_map_container>>::value,
int> = 0>
void merge(btree_container<T> &src) { // NOLINT
- insert(std::make_move_iterator(src.begin()),
- std::make_move_iterator(src.end()));
+ for (auto src_it = src.begin(), end = src.end(); src_it != end; ++src_it) {
+ insert(std::move(params_type::element(src_it.slot())));
+ }
src.clear();
}
@@ -604,6 +676,7 @@
};
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_BTREE_CONTAINER_H_
diff --git a/third_party/abseil/absl/container/internal/common.h b/third_party/abseil/absl/container/internal/common.h
index 591d3ea..030e9d4 100644
--- a/third_party/abseil/absl/container/internal/common.h
+++ b/third_party/abseil/absl/container/internal/common.h
@@ -22,6 +22,7 @@
#include "absl/types/optional.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
template <class, class = void>
@@ -55,7 +56,7 @@
public:
using allocator_type = Alloc;
- constexpr node_handle_base() {}
+ constexpr node_handle_base() = default;
node_handle_base(node_handle_base&& other) noexcept {
*this = std::move(other);
}
@@ -108,16 +109,15 @@
allocator_type* alloc() { return std::addressof(*alloc_); }
private:
- absl::optional<allocator_type> alloc_;
- mutable absl::aligned_storage_t<sizeof(slot_type), alignof(slot_type)>
- slot_space_;
+ absl::optional<allocator_type> alloc_ = {};
+ alignas(slot_type) mutable unsigned char slot_space_[sizeof(slot_type)] = {};
};
// For sets.
template <typename Policy, typename PolicyTraits, typename Alloc,
typename = void>
class node_handle : public node_handle_base<PolicyTraits, Alloc> {
- using Base = typename node_handle::node_handle_base;
+ using Base = node_handle_base<PolicyTraits, Alloc>;
public:
using value_type = typename PolicyTraits::value_type;
@@ -137,7 +137,8 @@
class node_handle<Policy, PolicyTraits, Alloc,
absl::void_t<typename Policy::mapped_type>>
: public node_handle_base<PolicyTraits, Alloc> {
- using Base = typename node_handle::node_handle_base;
+ using Base = node_handle_base<PolicyTraits, Alloc>;
+ using slot_type = typename PolicyTraits::slot_type;
public:
using key_type = typename Policy::key_type;
@@ -145,8 +146,11 @@
constexpr node_handle() {}
- auto key() const -> decltype(PolicyTraits::key(this->slot())) {
- return PolicyTraits::key(this->slot());
+ // When C++17 is available, we can use std::launder to provide mutable
+ // access to the key. Otherwise, we provide const access.
+ auto key() const
+ -> decltype(PolicyTraits::mutable_key(std::declval<slot_type*>())) {
+ return PolicyTraits::mutable_key(this->slot());
}
mapped_type& mapped() const {
@@ -167,6 +171,11 @@
}
template <typename Node>
+ static void Destroy(Node* node) {
+ node->destroy();
+ }
+
+ template <typename Node>
static void Reset(Node* node) {
node->reset();
}
@@ -191,6 +200,7 @@
};
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_CONTAINER_H_
diff --git a/third_party/abseil/absl/container/internal/compressed_tuple.h b/third_party/abseil/absl/container/internal/compressed_tuple.h
index 7d08e37..5ebe164 100644
--- a/third_party/abseil/absl/container/internal/compressed_tuple.h
+++ b/third_party/abseil/absl/container/internal/compressed_tuple.h
@@ -48,6 +48,7 @@
#endif
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
template <typename... Ts>
@@ -168,9 +169,33 @@
}
template <typename T, typename V>
-using TupleMoveConstructible = typename std::conditional<
- std::is_reference<T>::value, std::is_convertible<V, T>,
- std::is_constructible<T, V&&>>::type;
+using TupleElementMoveConstructible =
+ typename std::conditional<std::is_reference<T>::value,
+ std::is_convertible<V, T>,
+ std::is_constructible<T, V&&>>::type;
+
+template <bool SizeMatches, class T, class... Vs>
+struct TupleMoveConstructible : std::false_type {};
+
+template <class... Ts, class... Vs>
+struct TupleMoveConstructible<true, CompressedTuple<Ts...>, Vs...>
+ : std::integral_constant<
+ bool, absl::conjunction<
+ TupleElementMoveConstructible<Ts, Vs&&>...>::value> {};
+
+template <typename T>
+struct compressed_tuple_size;
+
+template <typename... Es>
+struct compressed_tuple_size<CompressedTuple<Es...>>
+ : public std::integral_constant<std::size_t, sizeof...(Es)> {};
+
+template <class T, class... Vs>
+struct TupleItemsMoveConstructible
+ : std::integral_constant<
+ bool, TupleMoveConstructible<compressed_tuple_size<T>::value ==
+ sizeof...(Vs),
+ T, Vs...>::value> {};
} // namespace internal_compressed_tuple
@@ -216,22 +241,23 @@
explicit constexpr CompressedTuple(const Ts&... base)
: CompressedTuple::CompressedTupleImpl(absl::in_place, base...) {}
- template <typename... Vs,
+ template <typename First, typename... Vs,
absl::enable_if_t<
absl::conjunction<
// Ensure we are not hiding default copy/move constructors.
absl::negation<std::is_same<void(CompressedTuple),
- void(absl::decay_t<Vs>...)>>,
- internal_compressed_tuple::TupleMoveConstructible<
- Ts, Vs&&>...>::value,
+ void(absl::decay_t<First>)>>,
+ internal_compressed_tuple::TupleItemsMoveConstructible<
+ CompressedTuple<Ts...>, First, Vs...>>::value,
bool> = true>
- explicit constexpr CompressedTuple(Vs&&... base)
+ explicit constexpr CompressedTuple(First&& first, Vs&&... base)
: CompressedTuple::CompressedTupleImpl(absl::in_place,
+ absl::forward<First>(first),
absl::forward<Vs>(base)...) {}
template <int I>
ElemT<I>& get() & {
- return internal_compressed_tuple::Storage<ElemT<I>, I>::get();
+ return StorageT<I>::get();
}
template <int I>
@@ -256,6 +282,7 @@
class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple<> {};
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#undef ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
diff --git a/third_party/abseil/absl/container/internal/compressed_tuple_test.cc b/third_party/abseil/absl/container/internal/compressed_tuple_test.cc
index 19af8f1..62a7483 100644
--- a/third_party/abseil/absl/container/internal/compressed_tuple_test.cc
+++ b/third_party/abseil/absl/container/internal/compressed_tuple_test.cc
@@ -48,6 +48,7 @@
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace {
@@ -276,11 +277,11 @@
TEST(CompressedTupleTest, Reference) {
int i = 7;
- std::string s = "Very long std::string that goes in the heap";
+ std::string s = "Very long string that goes in the heap";
CompressedTuple<int, int&, std::string, std::string&> x(i, i, s, s);
// Sanity check. We should have not moved from `s`
- EXPECT_EQ(s, "Very long std::string that goes in the heap");
+ EXPECT_EQ(s, "Very long string that goes in the heap");
EXPECT_EQ(x.get<0>(), x.get<1>());
EXPECT_NE(&x.get<0>(), &x.get<1>());
@@ -332,10 +333,6 @@
a = 0.5f;
EXPECT_EQ(absl::any_cast<float>(x.get<1>()), 0.5);
-
- // Ensure copy construction work in the face of a type with a universal
- // implicit constructor;
- CompressedTuple<absl::any> c{}, d(c); // NOLINT
}
TEST(CompressedTupleTest, Constexpr) {
@@ -408,4 +405,5 @@
} // namespace
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/container/internal/container_memory.h b/third_party/abseil/absl/container/internal/container_memory.h
index e5bb977..e67529e 100644
--- a/third_party/abseil/absl/container/internal/container_memory.h
+++ b/third_party/abseil/absl/container/internal/container_memory.h
@@ -15,27 +15,34 @@
#ifndef ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_
#define ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_
-#ifdef ADDRESS_SANITIZER
-#include <sanitizer/asan_interface.h>
-#endif
-
-#ifdef MEMORY_SANITIZER
-#include <sanitizer/msan_interface.h>
-#endif
-
#include <cassert>
#include <cstddef>
#include <memory>
+#include <new>
#include <tuple>
#include <type_traits>
#include <utility>
+#include "absl/base/config.h"
#include "absl/memory/memory.h"
+#include "absl/meta/type_traits.h"
#include "absl/utility/utility.h"
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+#include <sanitizer/asan_interface.h>
+#endif
+
+#ifdef ABSL_HAVE_MEMORY_SANITIZER
+#include <sanitizer/msan_interface.h>
+#endif
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
+template <size_t Alignment>
+struct alignas(Alignment) AlignedType {};
+
// Allocates at least n bytes aligned to the specified alignment.
// Alignment must be a power of 2. It must be positive.
//
@@ -47,11 +54,14 @@
void* Allocate(Alloc* alloc, size_t n) {
static_assert(Alignment > 0, "");
assert(n && "n must be positive");
- struct alignas(Alignment) M {};
+ using M = AlignedType<Alignment>;
using A = typename absl::allocator_traits<Alloc>::template rebind_alloc<M>;
using AT = typename absl::allocator_traits<Alloc>::template rebind_traits<M>;
- A mem_alloc(*alloc);
- void* p = AT::allocate(mem_alloc, (n + sizeof(M) - 1) / sizeof(M));
+ // On macOS, "mem_alloc" is a #define with one argument defined in
+ // rpc/types.h, so we can't name the variable "mem_alloc" and initialize it
+ // with the "foo(bar)" syntax.
+ A my_mem_alloc(*alloc);
+ void* p = AT::allocate(my_mem_alloc, (n + sizeof(M) - 1) / sizeof(M));
assert(reinterpret_cast<uintptr_t>(p) % Alignment == 0 &&
"allocator does not respect alignment");
return p;
@@ -63,11 +73,14 @@
void Deallocate(Alloc* alloc, void* p, size_t n) {
static_assert(Alignment > 0, "");
assert(n && "n must be positive");
- struct alignas(Alignment) M {};
+ using M = AlignedType<Alignment>;
using A = typename absl::allocator_traits<Alloc>::template rebind_alloc<M>;
using AT = typename absl::allocator_traits<Alloc>::template rebind_traits<M>;
- A mem_alloc(*alloc);
- AT::deallocate(mem_alloc, static_cast<M*>(p),
+ // On macOS, "mem_alloc" is a #define with one argument defined in
+ // rpc/types.h, so we can't name the variable "mem_alloc" and initialize it
+ // with the "foo(bar)" syntax.
+ A my_mem_alloc(*alloc);
+ AT::deallocate(my_mem_alloc, static_cast<M*>(p),
(n + sizeof(M) - 1) / sizeof(M));
}
@@ -204,10 +217,10 @@
// Helper functions for asan and msan.
inline void SanitizerPoisonMemoryRegion(const void* m, size_t s) {
-#ifdef ADDRESS_SANITIZER
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
ASAN_POISON_MEMORY_REGION(m, s);
#endif
-#ifdef MEMORY_SANITIZER
+#ifdef ABSL_HAVE_MEMORY_SANITIZER
__msan_poison(m, s);
#endif
(void)m;
@@ -215,10 +228,10 @@
}
inline void SanitizerUnpoisonMemoryRegion(const void* m, size_t s) {
-#ifdef ADDRESS_SANITIZER
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
ASAN_UNPOISON_MEMORY_REGION(m, s);
#endif
-#ifdef MEMORY_SANITIZER
+#ifdef ABSL_HAVE_MEMORY_SANITIZER
__msan_unpoison(m, s);
#endif
(void)m;
@@ -245,8 +258,8 @@
// type, which is non-portable.
template <class Pair, class = std::true_type>
struct OffsetOf {
- static constexpr size_t kFirst = -1;
- static constexpr size_t kSecond = -1;
+ static constexpr size_t kFirst = static_cast<size_t>(-1);
+ static constexpr size_t kSecond = static_cast<size_t>(-1);
};
template <class Pair>
@@ -315,11 +328,12 @@
map_slot_type() {}
~map_slot_type() = delete;
using value_type = std::pair<const K, V>;
- using mutable_value_type = std::pair<K, V>;
+ using mutable_value_type =
+ std::pair<absl::remove_const_t<K>, absl::remove_const_t<V>>;
value_type value;
mutable_value_type mutable_value;
- K key;
+ absl::remove_const_t<K> key;
};
template <class K, class V>
@@ -345,6 +359,20 @@
return slot->value;
}
+ // When C++17 is available, we can use std::launder to provide mutable
+ // access to the key for use in node handle.
+#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
+ static K& mutable_key(slot_type* slot) {
+ // Still check for kMutableKeys so that we can avoid calling std::launder
+ // unless necessary because it can interfere with optimizations.
+ return kMutableKeys::value ? slot->key
+ : *std::launder(const_cast<K*>(
+ std::addressof(slot->value.first)));
+ }
+#else // !(defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606)
+ static const K& mutable_key(slot_type* slot) { return key(slot); }
+#endif
+
static const K& key(const slot_type* slot) {
return kMutableKeys::value ? slot->key : slot->value.first;
}
@@ -423,16 +451,10 @@
std::move(src->value));
}
}
-
- template <class Allocator>
- static void move(Allocator* alloc, slot_type* first, slot_type* last,
- slot_type* result) {
- for (slot_type *src = first, *dest = result; src != last; ++src, ++dest)
- move(alloc, src, dest);
- }
};
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_
diff --git a/third_party/abseil/absl/container/internal/container_memory_test.cc b/third_party/abseil/absl/container/internal/container_memory_test.cc
index d6b0495..6a7fcd2 100644
--- a/third_party/abseil/absl/container/internal/container_memory_test.cc
+++ b/third_party/abseil/absl/container/internal/container_memory_test.cc
@@ -16,16 +16,25 @@
#include <cstdint>
#include <tuple>
+#include <typeindex>
+#include <typeinfo>
#include <utility>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/container/internal/test_instance_tracker.h"
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace {
+using ::absl::test_internal::CopyableMovableInstance;
+using ::absl::test_internal::InstanceTracker;
+using ::testing::_;
+using ::testing::ElementsAre;
+using ::testing::Gt;
using ::testing::Pair;
TEST(Memory, AlignmentLargerThanBase) {
@@ -44,6 +53,39 @@
Deallocate<2>(&alloc, mem, 3);
}
+std::map<std::type_index, int>& AllocationMap() {
+ static auto* map = new std::map<std::type_index, int>;
+ return *map;
+}
+
+template <typename T>
+struct TypeCountingAllocator {
+ TypeCountingAllocator() = default;
+ template <typename U>
+ TypeCountingAllocator(const TypeCountingAllocator<U>&) {} // NOLINT
+
+ using value_type = T;
+
+ T* allocate(size_t n, const void* = nullptr) {
+ AllocationMap()[typeid(T)] += n;
+ return std::allocator<T>().allocate(n);
+ }
+ void deallocate(T* p, std::size_t n) {
+ AllocationMap()[typeid(T)] -= n;
+ return std::allocator<T>().deallocate(p, n);
+ }
+};
+
+TEST(Memory, AllocateDeallocateMatchType) {
+ TypeCountingAllocator<int> alloc;
+ void* mem = Allocate<1>(&alloc, 1);
+ // Verify that it was allocated
+ EXPECT_THAT(AllocationMap(), ElementsAre(Pair(_, Gt(0))));
+ Deallocate<1>(&alloc, mem, 1);
+ // Verify that the deallocation matched.
+ EXPECT_THAT(AllocationMap(), ElementsAre(Pair(_, 0)));
+}
+
class Fixture : public ::testing::Test {
using Alloc = std::allocator<std::string>;
@@ -183,6 +225,32 @@
std::make_tuple(0.5)));
}
+TEST(MapSlotPolicy, ConstKeyAndValue) {
+ using slot_policy = map_slot_policy<const CopyableMovableInstance,
+ const CopyableMovableInstance>;
+ using slot_type = typename slot_policy::slot_type;
+
+ union Slots {
+ Slots() {}
+ ~Slots() {}
+ slot_type slots[100];
+ } slots;
+
+ std::allocator<
+ std::pair<const CopyableMovableInstance, const CopyableMovableInstance>>
+ alloc;
+ InstanceTracker tracker;
+ slot_policy::construct(&alloc, &slots.slots[0], CopyableMovableInstance(1),
+ CopyableMovableInstance(1));
+ for (int i = 0; i < 99; ++i) {
+ slot_policy::transfer(&alloc, &slots.slots[i + 1], &slots.slots[i]);
+ }
+ slot_policy::destroy(&alloc, &slots.slots[99]);
+
+ EXPECT_EQ(tracker.copies(), 0);
+}
+
} // namespace
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/container/internal/counting_allocator.h b/third_party/abseil/absl/container/internal/counting_allocator.h
index 4e717be..927cf08 100644
--- a/third_party/abseil/absl/container/internal/counting_allocator.h
+++ b/third_party/abseil/absl/container/internal/counting_allocator.h
@@ -15,11 +15,13 @@
#ifndef ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_
#define ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_
-#include <cassert>
#include <cstdint>
#include <memory>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
// This is a stateful allocator, but the state lives outside of the
@@ -28,33 +30,63 @@
// 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> {
+class CountingAllocator {
public:
- using Alloc = std::allocator<T>;
- using pointer = typename Alloc::pointer;
- using size_type = typename Alloc::size_type;
+ using Allocator = std::allocator<T>;
+ using AllocatorTraits = std::allocator_traits<Allocator>;
+ using value_type = typename AllocatorTraits::value_type;
+ using pointer = typename AllocatorTraits::pointer;
+ using const_pointer = typename AllocatorTraits::const_pointer;
+ using size_type = typename AllocatorTraits::size_type;
+ using difference_type = typename AllocatorTraits::difference_type;
- CountingAllocator() : bytes_used_(nullptr) {}
- explicit CountingAllocator(int64_t* b) : bytes_used_(b) {}
+ CountingAllocator() = default;
+ explicit CountingAllocator(int64_t* bytes_used) : bytes_used_(bytes_used) {}
+ CountingAllocator(int64_t* bytes_used, int64_t* instance_count)
+ : bytes_used_(bytes_used), instance_count_(instance_count) {}
template <typename U>
CountingAllocator(const CountingAllocator<U>& x)
- : Alloc(x), bytes_used_(x.bytes_used_) {}
+ : bytes_used_(x.bytes_used_), instance_count_(x.instance_count_) {}
- 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);
+ pointer allocate(
+ size_type n,
+ typename AllocatorTraits::const_void_pointer hint = nullptr) {
+ Allocator allocator;
+ pointer ptr = AllocatorTraits::allocate(allocator, n, hint);
+ if (bytes_used_ != nullptr) {
+ *bytes_used_ += n * sizeof(T);
+ }
+ return ptr;
}
void deallocate(pointer p, size_type n) {
- Alloc::deallocate(p, n);
- assert(bytes_used_ != nullptr);
- *bytes_used_ -= n * sizeof(T);
+ Allocator allocator;
+ AllocatorTraits::deallocate(allocator, p, n);
+ if (bytes_used_ != nullptr) {
+ *bytes_used_ -= n * sizeof(T);
+ }
}
- template<typename U>
+ template <typename U, typename... Args>
+ void construct(U* p, Args&&... args) {
+ Allocator allocator;
+ AllocatorTraits::construct(allocator, p, std::forward<Args>(args)...);
+ if (instance_count_ != nullptr) {
+ *instance_count_ += 1;
+ }
+ }
+
+ template <typename U>
+ void destroy(U* p) {
+ Allocator allocator;
+ AllocatorTraits::destroy(allocator, p);
+ if (instance_count_ != nullptr) {
+ *instance_count_ -= 1;
+ }
+ }
+
+ template <typename U>
class rebind {
public:
using other = CountingAllocator<U>;
@@ -62,7 +94,8 @@
friend bool operator==(const CountingAllocator& a,
const CountingAllocator& b) {
- return a.bytes_used_ == b.bytes_used_;
+ return a.bytes_used_ == b.bytes_used_ &&
+ a.instance_count_ == b.instance_count_;
}
friend bool operator!=(const CountingAllocator& a,
@@ -70,10 +103,12 @@
return !(a == b);
}
- int64_t* bytes_used_;
+ int64_t* bytes_used_ = nullptr;
+ int64_t* instance_count_ = nullptr;
};
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_
diff --git a/third_party/abseil/absl/container/internal/hash_function_defaults.h b/third_party/abseil/absl/container/internal/hash_function_defaults.h
index cb8f03c..0683422 100644
--- a/third_party/abseil/absl/container/internal/hash_function_defaults.h
+++ b/third_party/abseil/absl/container/internal/hash_function_defaults.h
@@ -53,9 +53,11 @@
#include "absl/base/config.h"
#include "absl/hash/hash.h"
+#include "absl/strings/cord.h"
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
// The hash of an object of type T is computed by using absl::Hash.
@@ -71,6 +73,9 @@
size_t operator()(absl::string_view v) const {
return absl::Hash<absl::string_view>{}(v);
}
+ size_t operator()(const absl::Cord& v) const {
+ return absl::Hash<absl::Cord>{}(v);
+ }
};
// Supports heterogeneous lookup for string-like elements.
@@ -81,6 +86,15 @@
bool operator()(absl::string_view lhs, absl::string_view rhs) const {
return lhs == rhs;
}
+ bool operator()(const absl::Cord& lhs, const absl::Cord& rhs) const {
+ return lhs == rhs;
+ }
+ bool operator()(const absl::Cord& lhs, absl::string_view rhs) const {
+ return lhs == rhs;
+ }
+ bool operator()(absl::string_view lhs, const absl::Cord& rhs) const {
+ return lhs == rhs;
+ }
};
};
@@ -88,6 +102,8 @@
struct HashEq<std::string> : StringHashEq {};
template <>
struct HashEq<absl::string_view> : StringHashEq {};
+template <>
+struct HashEq<absl::Cord> : StringHashEq {};
// Supports heterogeneous lookup for pointers and smart pointers.
template <class T>
@@ -139,6 +155,7 @@
using hash_default_eq = typename container_internal::HashEq<T>::Eq;
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_
diff --git a/third_party/abseil/absl/container/internal/hash_function_defaults_test.cc b/third_party/abseil/absl/container/internal/hash_function_defaults_test.cc
index 82708db..59576b8 100644
--- a/third_party/abseil/absl/container/internal/hash_function_defaults_test.cc
+++ b/third_party/abseil/absl/container/internal/hash_function_defaults_test.cc
@@ -19,9 +19,13 @@
#include <utility>
#include "gtest/gtest.h"
+#include "absl/random/random.h"
+#include "absl/strings/cord.h"
+#include "absl/strings/cord_test_helpers.h"
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace {
@@ -202,10 +206,91 @@
EXPECT_NE(hash(&dummy), hash(cuptr));
}
+TEST(EqCord, Works) {
+ hash_default_eq<absl::Cord> eq;
+ const absl::string_view a_string_view = "a";
+ const absl::Cord a_cord(a_string_view);
+ const absl::string_view b_string_view = "b";
+ const absl::Cord b_cord(b_string_view);
+
+ EXPECT_TRUE(eq(a_cord, a_cord));
+ EXPECT_TRUE(eq(a_cord, a_string_view));
+ EXPECT_TRUE(eq(a_string_view, a_cord));
+ EXPECT_FALSE(eq(a_cord, b_cord));
+ EXPECT_FALSE(eq(a_cord, b_string_view));
+ EXPECT_FALSE(eq(b_string_view, a_cord));
+}
+
+TEST(HashCord, Works) {
+ hash_default_hash<absl::Cord> hash;
+ const absl::string_view a_string_view = "a";
+ const absl::Cord a_cord(a_string_view);
+ const absl::string_view b_string_view = "b";
+ const absl::Cord b_cord(b_string_view);
+
+ EXPECT_EQ(hash(a_cord), hash(a_cord));
+ EXPECT_EQ(hash(b_cord), hash(b_cord));
+ EXPECT_EQ(hash(a_string_view), hash(a_cord));
+ EXPECT_EQ(hash(b_string_view), hash(b_cord));
+ EXPECT_EQ(hash(absl::Cord("")), hash(""));
+ EXPECT_EQ(hash(absl::Cord()), hash(absl::string_view()));
+
+ EXPECT_NE(hash(a_cord), hash(b_cord));
+ EXPECT_NE(hash(a_cord), hash(b_string_view));
+ EXPECT_NE(hash(a_string_view), hash(b_cord));
+ EXPECT_NE(hash(a_string_view), hash(b_string_view));
+}
+
+void NoOpReleaser(absl::string_view data, void* arg) {}
+
+TEST(HashCord, FragmentedCordWorks) {
+ hash_default_hash<absl::Cord> hash;
+ absl::Cord c = absl::MakeFragmentedCord({"a", "b", "c"});
+ EXPECT_FALSE(c.TryFlat().has_value());
+ EXPECT_EQ(hash(c), hash("abc"));
+}
+
+TEST(HashCord, FragmentedLongCordWorks) {
+ hash_default_hash<absl::Cord> hash;
+ // Crete some large strings which do not fit on the stack.
+ std::string a(65536, 'a');
+ std::string b(65536, 'b');
+ absl::Cord c = absl::MakeFragmentedCord({a, b});
+ EXPECT_FALSE(c.TryFlat().has_value());
+ EXPECT_EQ(hash(c), hash(a + b));
+}
+
+TEST(HashCord, RandomCord) {
+ hash_default_hash<absl::Cord> hash;
+ auto bitgen = absl::BitGen();
+ for (int i = 0; i < 1000; ++i) {
+ const int number_of_segments = absl::Uniform(bitgen, 0, 10);
+ std::vector<std::string> pieces;
+ for (size_t s = 0; s < number_of_segments; ++s) {
+ std::string str;
+ str.resize(absl::Uniform(bitgen, 0, 4096));
+ // MSVC needed the explicit return type in the lambda.
+ std::generate(str.begin(), str.end(), [&]() -> char {
+ return static_cast<char>(absl::Uniform<unsigned char>(bitgen));
+ });
+ pieces.push_back(str);
+ }
+ absl::Cord c = absl::MakeFragmentedCord(pieces);
+ EXPECT_EQ(hash(c), hash(std::string(c)));
+ }
+}
+
// Cartesian product of (std::string, absl::string_view)
-// with (std::string, absl::string_view, const char*).
+// with (std::string, absl::string_view, const char*, absl::Cord).
using StringTypesCartesianProduct = Types<
// clang-format off
+ std::pair<absl::Cord, std::string>,
+ std::pair<absl::Cord, absl::string_view>,
+ std::pair<absl::Cord, absl::Cord>,
+ std::pair<absl::Cord, const char*>,
+
+ std::pair<std::string, absl::Cord>,
+ std::pair<absl::string_view, absl::Cord>,
std::pair<absl::string_view, std::string>,
std::pair<absl::string_view, absl::string_view>,
@@ -248,14 +333,15 @@
} // namespace
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
enum Hash : size_t {
- kStd = 0x2, // std::hash
+ kStd = 0x1, // std::hash
#ifdef _MSC_VER
kExtension = kStd, // In MSVC, std::hash == ::hash
#else // _MSC_VER
- kExtension = 0x4, // ::hash (GCC extension)
+ kExtension = 0x2, // ::hash (GCC extension)
#endif // _MSC_VER
};
@@ -278,6 +364,7 @@
} // namespace std
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace {
@@ -292,4 +379,5 @@
} // namespace
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/container/internal/hash_generator_testing.cc b/third_party/abseil/absl/container/internal/hash_generator_testing.cc
index 37a23d6..59cc5aa 100644
--- a/third_party/abseil/absl/container/internal/hash_generator_testing.cc
+++ b/third_party/abseil/absl/container/internal/hash_generator_testing.cc
@@ -17,6 +17,7 @@
#include <deque>
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace hash_internal {
namespace {
@@ -40,8 +41,10 @@
} // namespace
std::mt19937_64* GetSharedRng() {
- RandomDeviceSeedSeq seed_seq;
- static auto* rng = new std::mt19937_64(seed_seq);
+ static auto* rng = [] {
+ RandomDeviceSeedSeq seed_seq;
+ return new std::mt19937_64(seed_seq);
+ }();
return rng;
}
@@ -69,4 +72,5 @@
} // namespace hash_internal
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/container/internal/hash_generator_testing.h b/third_party/abseil/absl/container/internal/hash_generator_testing.h
index 477215c..6869fe4 100644
--- a/third_party/abseil/absl/container/internal/hash_generator_testing.h
+++ b/third_party/abseil/absl/container/internal/hash_generator_testing.h
@@ -33,6 +33,7 @@
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace hash_internal {
namespace generator_internal {
@@ -154,6 +155,7 @@
} // namespace hash_internal
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_HASH_GENERATOR_TESTING_H_
diff --git a/third_party/abseil/absl/container/internal/hash_policy_testing.h b/third_party/abseil/absl/container/internal/hash_policy_testing.h
index c57407a..01c40d2 100644
--- a/third_party/abseil/absl/container/internal/hash_policy_testing.h
+++ b/third_party/abseil/absl/container/internal/hash_policy_testing.h
@@ -30,6 +30,7 @@
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace hash_testing_internal {
@@ -162,6 +163,7 @@
}
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
// ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS is false for glibcxx versions
diff --git a/third_party/abseil/absl/container/internal/hash_policy_testing_test.cc b/third_party/abseil/absl/container/internal/hash_policy_testing_test.cc
index 0c95eb5..f0b20fe 100644
--- a/third_party/abseil/absl/container/internal/hash_policy_testing_test.cc
+++ b/third_party/abseil/absl/container/internal/hash_policy_testing_test.cc
@@ -17,6 +17,7 @@
#include "gtest/gtest.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace {
@@ -40,4 +41,5 @@
} // namespace
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/container/internal/hash_policy_traits.h b/third_party/abseil/absl/container/internal/hash_policy_traits.h
index fd007de..46c97b1 100644
--- a/third_party/abseil/absl/container/internal/hash_policy_traits.h
+++ b/third_party/abseil/absl/container/internal/hash_policy_traits.h
@@ -17,26 +17,47 @@
#include <cstddef>
#include <memory>
+#include <new>
#include <type_traits>
#include <utility>
#include "absl/meta/type_traits.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
// Defines how slots are initialized/destroyed/moved.
template <class Policy, class = void>
struct hash_policy_traits {
+ // The type of the keys stored in the hashtable.
+ using key_type = typename Policy::key_type;
+
private:
struct ReturnKey {
- // We return `Key` here.
+ // When C++17 is available, we can use std::launder to provide mutable
+ // access to the key for use in node handle.
+#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
+ template <class Key,
+ absl::enable_if_t<std::is_lvalue_reference<Key>::value, int> = 0>
+ static key_type& Impl(Key&& k, int) {
+ return *std::launder(
+ const_cast<key_type*>(std::addressof(std::forward<Key>(k))));
+ }
+#endif
+
+ template <class Key>
+ static Key Impl(Key&& k, char) {
+ return std::forward<Key>(k);
+ }
+
// When Key=T&, we forward the lvalue reference.
// When Key=T, we return by value to avoid a dangling reference.
// eg, for string_hash_map.
template <class Key, class... Args>
- Key operator()(Key&& k, const Args&...) const {
- return std::forward<Key>(k);
+ auto operator()(Key&& k, const Args&...) const
+ -> decltype(Impl(std::forward<Key>(k), 0)) {
+ return Impl(std::forward<Key>(k), 0);
}
};
@@ -51,9 +72,6 @@
// The actual object stored in the hash table.
using slot_type = typename Policy::slot_type;
- // The type of the keys stored in the hashtable.
- using key_type = typename Policy::key_type;
-
// The argument type for insertions into the hashtable. This is different
// from value_type for increased performance. See initializer_list constructor
// and insert() member functions for more details.
@@ -155,7 +173,7 @@
// Returns the "key" portion of the slot.
// Used for node handle manipulation.
template <class P = Policy>
- static auto key(slot_type* slot)
+ static auto mutable_key(slot_type* slot)
-> decltype(P::apply(ReturnKey(), element(slot))) {
return P::apply(ReturnKey(), element(slot));
}
@@ -184,6 +202,7 @@
};
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_HASH_POLICY_TRAITS_H_
diff --git a/third_party/abseil/absl/container/internal/hash_policy_traits_test.cc b/third_party/abseil/absl/container/internal/hash_policy_traits_test.cc
index e643d18..6ef8b9e 100644
--- a/third_party/abseil/absl/container/internal/hash_policy_traits_test.cc
+++ b/third_party/abseil/absl/container/internal/hash_policy_traits_test.cc
@@ -22,6 +22,7 @@
#include "gtest/gtest.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace {
@@ -139,4 +140,5 @@
} // namespace
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/container/internal/hashtable_debug.h b/third_party/abseil/absl/container/internal/hashtable_debug.h
index 7193000..19d5212 100644
--- a/third_party/abseil/absl/container/internal/hashtable_debug.h
+++ b/third_party/abseil/absl/container/internal/hashtable_debug.h
@@ -38,6 +38,7 @@
#include "absl/container/internal/hashtable_debug_hooks.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
// Returns the number of probes required to lookup `key`. Returns 0 for a
@@ -103,6 +104,7 @@
}
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_H_
diff --git a/third_party/abseil/absl/container/internal/hashtable_debug_hooks.h b/third_party/abseil/absl/container/internal/hashtable_debug_hooks.h
index 371ce81..3e9ea59 100644
--- a/third_party/abseil/absl/container/internal/hashtable_debug_hooks.h
+++ b/third_party/abseil/absl/container/internal/hashtable_debug_hooks.h
@@ -23,7 +23,10 @@
#include <type_traits>
#include <vector>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace hashtable_debug_internal {
@@ -76,6 +79,7 @@
} // namespace hashtable_debug_internal
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_HOOKS_H_
diff --git a/third_party/abseil/absl/container/internal/hashtablez_sampler.cc b/third_party/abseil/absl/container/internal/hashtablez_sampler.cc
index d03dd82..e4484fb 100644
--- a/third_party/abseil/absl/container/internal/hashtablez_sampler.cc
+++ b/third_party/abseil/absl/container/internal/hashtablez_sampler.cc
@@ -21,12 +21,14 @@
#include <limits>
#include "absl/base/attributes.h"
+#include "absl/base/internal/exponential_biased.h"
#include "absl/container/internal/have_sse.h"
#include "absl/debugging/stacktrace.h"
#include "absl/memory/memory.h"
#include "absl/synchronization/mutex.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
constexpr int HashtablezInfo::kMaxStackDepth;
@@ -37,80 +39,17 @@
ABSL_CONST_INIT std::atomic<int32_t> g_hashtablez_sample_parameter{1 << 10};
ABSL_CONST_INIT std::atomic<int32_t> g_hashtablez_max_samples{1 << 20};
-// Returns the next pseudo-random value.
-// pRNG is: aX+b mod c with a = 0x5DEECE66D, b = 0xB, c = 1<<48
-// This is the lrand64 generator.
-uint64_t NextRandom(uint64_t rnd) {
- const uint64_t prng_mult = uint64_t{0x5DEECE66D};
- const uint64_t prng_add = 0xB;
- const uint64_t prng_mod_power = 48;
- const uint64_t prng_mod_mask = ~(~uint64_t{0} << prng_mod_power);
- return (prng_mult * rnd + prng_add) & prng_mod_mask;
-}
-
-// Generates a geometric variable with the specified mean.
-// This is done by generating a random number between 0 and 1 and applying
-// the inverse cumulative distribution function for an exponential.
-// Specifically: Let m be the inverse of the sample period, then
-// the probability distribution function is m*exp(-mx) so the CDF is
-// p = 1 - exp(-mx), so
-// q = 1 - p = exp(-mx)
-// log_e(q) = -mx
-// -log_e(q)/m = x
-// log_2(q) * (-log_e(2) * 1/m) = x
-// In the code, q is actually in the range 1 to 2**26, hence the -26 below
-//
-int64_t GetGeometricVariable(int64_t mean) {
-#if ABSL_HAVE_THREAD_LOCAL
- thread_local
-#else // ABSL_HAVE_THREAD_LOCAL
- // SampleSlow and hence GetGeometricVariable is guarded by a single mutex when
- // there are not thread locals. Thus, a single global rng is acceptable for
- // that case.
- static
-#endif // ABSL_HAVE_THREAD_LOCAL
- uint64_t rng = []() {
- // We don't get well distributed numbers from this so we call
- // NextRandom() a bunch to mush the bits around. We use a global_rand
- // to handle the case where the same thread (by memory address) gets
- // created and destroyed repeatedly.
- ABSL_CONST_INIT static std::atomic<uint32_t> global_rand(0);
- uint64_t r = reinterpret_cast<uint64_t>(&rng) +
- global_rand.fetch_add(1, std::memory_order_relaxed);
- for (int i = 0; i < 20; ++i) {
- r = NextRandom(r);
- }
- return r;
- }();
-
- rng = NextRandom(rng);
-
- // Take the top 26 bits as the random number
- // (This plus the 1<<58 sampling bound give a max possible step of
- // 5194297183973780480 bytes.)
- const uint64_t prng_mod_power = 48; // Number of bits in prng
- // The uint32_t cast is to prevent a (hard-to-reproduce) NAN
- // under piii debug for some binaries.
- double q = static_cast<uint32_t>(rng >> (prng_mod_power - 26)) + 1.0;
- // Put the computed p-value through the CDF of a geometric.
- double interval = (log2(q) - 26) * (-std::log(2.0) * mean);
-
- // Very large values of interval overflow int64_t. If we happen to
- // hit such improbable condition, we simply cheat and clamp interval
- // to largest supported value.
- if (interval > static_cast<double>(std::numeric_limits<int64_t>::max() / 2)) {
- return std::numeric_limits<int64_t>::max() / 2;
- }
-
- // Small values of interval are equivalent to just sampling next time.
- if (interval < 1) {
- return 1;
- }
- return static_cast<int64_t>(interval);
-}
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+ABSL_PER_THREAD_TLS_KEYWORD absl::base_internal::ExponentialBiased
+ g_exponential_biased_generator;
+#endif
} // namespace
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample = 0;
+#endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+
HashtablezSampler& HashtablezSampler::Global() {
static auto* sampler = new HashtablezSampler();
return *sampler;
@@ -128,6 +67,7 @@
capacity.store(0, std::memory_order_relaxed);
size.store(0, std::memory_order_relaxed);
num_erases.store(0, std::memory_order_relaxed);
+ num_rehashes.store(0, std::memory_order_relaxed);
max_probe_length.store(0, std::memory_order_relaxed);
total_probe_length.store(0, std::memory_order_relaxed);
hashes_bitwise_or.store(0, std::memory_order_relaxed);
@@ -228,15 +168,39 @@
return dropped_samples_.load(std::memory_order_relaxed);
}
+static bool ShouldForceSampling() {
+ enum ForceState {
+ kDontForce,
+ kForce,
+ kUninitialized
+ };
+ ABSL_CONST_INIT static std::atomic<ForceState> global_state{
+ kUninitialized};
+ ForceState state = global_state.load(std::memory_order_relaxed);
+ if (ABSL_PREDICT_TRUE(state == kDontForce)) return false;
+
+ if (state == kUninitialized) {
+ state = AbslContainerInternalSampleEverything() ? kForce : kDontForce;
+ global_state.store(state, std::memory_order_relaxed);
+ }
+ return state == kForce;
+}
+
HashtablezInfo* SampleSlow(int64_t* next_sample) {
- if (kAbslContainerInternalSampleEverything) {
+ if (ABSL_PREDICT_FALSE(ShouldForceSampling())) {
*next_sample = 1;
return HashtablezSampler::Global().Register();
}
+#if !defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+ *next_sample = std::numeric_limits<int64_t>::max();
+ return nullptr;
+#else
bool first = *next_sample < 0;
- *next_sample = GetGeometricVariable(
+ *next_sample = g_exponential_biased_generator.GetStride(
g_hashtablez_sample_parameter.load(std::memory_order_relaxed));
+ // Small values of interval are equivalent to just sampling next time.
+ ABSL_ASSERT(*next_sample >= 1);
// g_hashtablez_enabled can be dynamically flipped, we need to set a threshold
// low enough that we will start sampling in a reasonable time, so we just use
@@ -251,12 +215,9 @@
}
return HashtablezSampler::Global().Register();
+#endif
}
-#if ABSL_PER_THREAD_TLS == 1
-ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample = 0;
-#endif // ABSL_PER_THREAD_TLS == 1
-
void UnsampleSlow(HashtablezInfo* info) {
HashtablezSampler::Global().Unregister(info);
}
@@ -266,7 +227,7 @@
// SwissTables probe in groups of 16, so scale this to count items probes and
// not offset from desired.
size_t probe_length = distance_from_desired;
-#if SWISSTABLE_HAVE_SSE2
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
probe_length /= 16;
#else
probe_length /= 8;
@@ -305,4 +266,5 @@
}
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/container/internal/hashtablez_sampler.h b/third_party/abseil/absl/container/internal/hashtablez_sampler.h
index 4112175..394348d 100644
--- a/third_party/abseil/absl/container/internal/hashtablez_sampler.h
+++ b/third_party/abseil/absl/container/internal/hashtablez_sampler.h
@@ -51,6 +51,7 @@
#include "absl/utility/utility.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
// Stores information about a sampled hashtable. All mutations to this *must*
@@ -72,6 +73,7 @@
std::atomic<size_t> capacity;
std::atomic<size_t> size;
std::atomic<size_t> num_erases;
+ std::atomic<size_t> num_rehashes;
std::atomic<size_t> max_probe_length;
std::atomic<size_t> total_probe_length;
std::atomic<size_t> hashes_bitwise_or;
@@ -97,13 +99,18 @@
};
inline void RecordRehashSlow(HashtablezInfo* info, size_t total_probe_length) {
-#if SWISSTABLE_HAVE_SSE2
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
total_probe_length /= 16;
#else
total_probe_length /= 8;
#endif
info->total_probe_length.store(total_probe_length, std::memory_order_relaxed);
info->num_erases.store(0, std::memory_order_relaxed);
+ // There is only one concurrent writer, so `load` then `store` is sufficient
+ // instead of using `fetch_add`.
+ info->num_rehashes.store(
+ 1 + info->num_rehashes.load(std::memory_order_relaxed),
+ std::memory_order_relaxed);
}
inline void RecordStorageChangedSlow(HashtablezInfo* info, size_t size,
@@ -112,7 +119,8 @@
info->capacity.store(capacity, std::memory_order_relaxed);
if (size == 0) {
// This is a clear, reset the total/num_erases too.
- RecordRehashSlow(info, 0);
+ info->total_probe_length.store(0, std::memory_order_relaxed);
+ info->num_erases.store(0, std::memory_order_relaxed);
}
}
@@ -121,12 +129,21 @@
inline void RecordEraseSlow(HashtablezInfo* info) {
info->size.fetch_sub(1, std::memory_order_relaxed);
- info->num_erases.fetch_add(1, std::memory_order_relaxed);
+ // There is only one concurrent writer, so `load` then `store` is sufficient
+ // instead of using `fetch_add`.
+ info->num_erases.store(
+ 1 + info->num_erases.load(std::memory_order_relaxed),
+ std::memory_order_relaxed);
}
HashtablezInfo* SampleSlow(int64_t* next_sample);
void UnsampleSlow(HashtablezInfo* info);
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+#error ABSL_INTERNAL_HASHTABLEZ_SAMPLE cannot be directly set
+#endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
class HashtablezInfoHandle {
public:
explicit HashtablezInfoHandle() : info_(nullptr) {}
@@ -178,24 +195,39 @@
friend class HashtablezInfoHandlePeer;
HashtablezInfo* info_;
};
+#else
+// Ensure that when Hashtablez is turned off at compile time, HashtablezInfo can
+// be removed by the linker, in order to reduce the binary size.
+class HashtablezInfoHandle {
+ public:
+ explicit HashtablezInfoHandle() = default;
+ explicit HashtablezInfoHandle(std::nullptr_t) {}
-#if ABSL_PER_THREAD_TLS == 1
+ inline void RecordStorageChanged(size_t /*size*/, size_t /*capacity*/) {}
+ inline void RecordRehash(size_t /*total_probe_length*/) {}
+ inline void RecordInsert(size_t /*hash*/, size_t /*distance_from_desired*/) {}
+ inline void RecordErase() {}
+
+ friend inline void swap(HashtablezInfoHandle& /*lhs*/,
+ HashtablezInfoHandle& /*rhs*/) {}
+};
+#endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
extern ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample;
-#endif // ABSL_PER_THREAD_TLS
+#endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
// Returns an RAII sampling handle that manages registration and unregistation
// with the global sampler.
inline HashtablezInfoHandle Sample() {
-#if ABSL_PER_THREAD_TLS == 0
- static auto* mu = new absl::Mutex;
- static int64_t global_next_sample = 0;
- absl::MutexLock l(mu);
-#endif // !ABSL_HAVE_THREAD_LOCAL
-
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
if (ABSL_PREDICT_TRUE(--global_next_sample > 0)) {
return HashtablezInfoHandle(nullptr);
}
return HashtablezInfoHandle(SampleSlow(&global_next_sample));
+#else
+ return HashtablezInfoHandle(nullptr);
+#endif // !ABSL_PER_THREAD_TLS
}
// Holds samples and their associated stack traces with a soft limit of
@@ -280,9 +312,10 @@
// initialization of static storage duration objects.
// The definition of this constant is weak, which allows us to inject a
// different value for it at link time.
-extern "C" const bool kAbslContainerInternalSampleEverything;
+extern "C" bool AbslContainerInternalSampleEverything();
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
diff --git a/third_party/abseil/absl/container/internal/hashtablez_sampler_force_weak_definition.cc b/third_party/abseil/absl/container/internal/hashtablez_sampler_force_weak_definition.cc
index 4ca6ffd..78b9d36 100644
--- a/third_party/abseil/absl/container/internal/hashtablez_sampler_force_weak_definition.cc
+++ b/third_party/abseil/absl/container/internal/hashtablez_sampler_force_weak_definition.cc
@@ -17,11 +17,14 @@
#include "absl/base/attributes.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
// See hashtablez_sampler.h for details.
-extern "C" ABSL_ATTRIBUTE_WEAK const bool
- kAbslContainerInternalSampleEverything = false;
+extern "C" ABSL_ATTRIBUTE_WEAK bool AbslContainerInternalSampleEverything() {
+ return false;
+}
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/container/internal/hashtablez_sampler_test.cc b/third_party/abseil/absl/container/internal/hashtablez_sampler_test.cc
index 7f9e8dd..8d10a1e 100644
--- a/third_party/abseil/absl/container/internal/hashtablez_sampler_test.cc
+++ b/third_party/abseil/absl/container/internal/hashtablez_sampler_test.cc
@@ -29,14 +29,16 @@
#include "absl/time/clock.h"
#include "absl/time/time.h"
-#if SWISSTABLE_HAVE_SSE2
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
constexpr int kProbeLength = 16;
#else
constexpr int kProbeLength = 8;
#endif
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
class HashtablezInfoHandlePeer {
public:
static bool IsSampled(const HashtablezInfoHandle& h) {
@@ -45,6 +47,13 @@
static HashtablezInfo* GetInfo(HashtablezInfoHandle* h) { return h->info_; }
};
+#else
+class HashtablezInfoHandlePeer {
+ public:
+ static bool IsSampled(const HashtablezInfoHandle&) { return false; }
+ static HashtablezInfo* GetInfo(HashtablezInfoHandle*) { return nullptr; }
+};
+#endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
namespace {
using ::absl::synchronization_internal::ThreadPool;
@@ -75,6 +84,7 @@
EXPECT_EQ(info.capacity.load(), 0);
EXPECT_EQ(info.size.load(), 0);
EXPECT_EQ(info.num_erases.load(), 0);
+ EXPECT_EQ(info.num_rehashes.load(), 0);
EXPECT_EQ(info.max_probe_length.load(), 0);
EXPECT_EQ(info.total_probe_length.load(), 0);
EXPECT_EQ(info.hashes_bitwise_or.load(), 0);
@@ -94,6 +104,7 @@
EXPECT_EQ(info.capacity.load(), 0);
EXPECT_EQ(info.size.load(), 0);
EXPECT_EQ(info.num_erases.load(), 0);
+ EXPECT_EQ(info.num_rehashes.load(), 0);
EXPECT_EQ(info.max_probe_length.load(), 0);
EXPECT_EQ(info.total_probe_length.load(), 0);
EXPECT_EQ(info.hashes_bitwise_or.load(), 0);
@@ -166,8 +177,10 @@
EXPECT_EQ(info.size.load(), 2);
EXPECT_EQ(info.total_probe_length.load(), 3);
EXPECT_EQ(info.num_erases.load(), 0);
+ EXPECT_EQ(info.num_rehashes.load(), 1);
}
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
TEST(HashtablezSamplerTest, SmallSampleParameter) {
SetHashtablezEnabled(true);
SetHashtablezSampleParameter(100);
@@ -240,6 +253,8 @@
});
EXPECT_FALSE(found);
}
+#endif
+
TEST(HashtablezSamplerTest, Registration) {
HashtablezSampler sampler;
@@ -352,4 +367,5 @@
} // namespace
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/container/internal/have_sse.h b/third_party/abseil/absl/container/internal/have_sse.h
index 4341441..e75e1a1 100644
--- a/third_party/abseil/absl/container/internal/have_sse.h
+++ b/third_party/abseil/absl/container/internal/have_sse.h
@@ -16,33 +16,34 @@
#ifndef ABSL_CONTAINER_INTERNAL_HAVE_SSE_H_
#define ABSL_CONTAINER_INTERNAL_HAVE_SSE_H_
-#ifndef SWISSTABLE_HAVE_SSE2
+#ifndef ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
#if defined(__SSE2__) || \
(defined(_MSC_VER) && \
(defined(_M_X64) || (defined(_M_IX86) && _M_IX86_FP >= 2)))
-#define SWISSTABLE_HAVE_SSE2 1
+#define ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2 1
#else
-#define SWISSTABLE_HAVE_SSE2 0
+#define ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2 0
#endif
#endif
-#ifndef SWISSTABLE_HAVE_SSSE3
+#ifndef ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3
#ifdef __SSSE3__
-#define SWISSTABLE_HAVE_SSSE3 1
+#define ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3 1
#else
-#define SWISSTABLE_HAVE_SSSE3 0
+#define ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3 0
#endif
#endif
-#if SWISSTABLE_HAVE_SSSE3 && !SWISSTABLE_HAVE_SSE2
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3 && \
+ !ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
#error "Bad configuration!"
#endif
-#if SWISSTABLE_HAVE_SSE2
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
#include <emmintrin.h>
#endif
-#if SWISSTABLE_HAVE_SSSE3
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3
#include <tmmintrin.h>
#endif
diff --git a/third_party/abseil/absl/container/internal/inlined_vector.h b/third_party/abseil/absl/container/internal/inlined_vector.h
index 54369c8..120849c 100644
--- a/third_party/abseil/absl/container/internal/inlined_vector.h
+++ b/third_party/abseil/absl/container/internal/inlined_vector.h
@@ -30,23 +30,31 @@
#include "absl/types/span.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace inlined_vector_internal {
+// GCC does not deal very well with the below code
+#if !defined(__clang__) && defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+
template <typename Iterator>
using IsAtLeastForwardIterator = std::is_convertible<
typename std::iterator_traits<Iterator>::iterator_category,
std::forward_iterator_tag>;
-template <typename AllocatorType>
-using IsMemcpyOk = absl::conjunction<
- std::is_same<std::allocator<typename AllocatorType::value_type>,
- AllocatorType>,
- absl::is_trivially_copy_constructible<typename AllocatorType::value_type>,
- absl::is_trivially_copy_assignable<typename AllocatorType::value_type>,
- absl::is_trivially_destructible<typename AllocatorType::value_type>>;
+template <typename AllocatorType,
+ typename ValueType =
+ typename absl::allocator_traits<AllocatorType>::value_type>
+using IsMemcpyOk =
+ absl::conjunction<std::is_same<AllocatorType, std::allocator<ValueType>>,
+ absl::is_trivially_copy_constructible<ValueType>,
+ absl::is_trivially_copy_assignable<ValueType>,
+ absl::is_trivially_destructible<ValueType>>;
-template <typename AllocatorType, typename ValueType, typename SizeType>
-void DestroyElements(AllocatorType* alloc_ptr, ValueType* destroy_first,
+template <typename AllocatorType, typename Pointer, typename SizeType>
+void DestroyElements(AllocatorType* alloc_ptr, Pointer destroy_first,
SizeType destroy_size) {
using AllocatorTraits = absl::allocator_traits<AllocatorType>;
@@ -57,20 +65,25 @@
}
#if !defined(NDEBUG)
- // 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.
- auto* memory_ptr = static_cast<void*>(destroy_first);
- auto memory_size = sizeof(ValueType) * destroy_size;
- std::memset(memory_ptr, 0xab, memory_size);
+ {
+ using ValueType = typename AllocatorTraits::value_type;
+
+ // 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.
+ void* memory_ptr = destroy_first;
+ auto memory_size = destroy_size * sizeof(ValueType);
+ std::memset(memory_ptr, 0xab, memory_size);
+ }
#endif // !defined(NDEBUG)
}
}
-template <typename AllocatorType, typename ValueType, typename ValueAdapter,
+template <typename AllocatorType, typename Pointer, typename ValueAdapter,
typename SizeType>
-void ConstructElements(AllocatorType* alloc_ptr, ValueType* construct_first,
+void ConstructElements(AllocatorType* alloc_ptr, Pointer construct_first,
ValueAdapter* values_ptr, SizeType construct_size) {
for (SizeType i = 0; i < construct_size; ++i) {
ABSL_INTERNAL_TRY {
@@ -83,8 +96,8 @@
}
}
-template <typename ValueType, typename ValueAdapter, typename SizeType>
-void AssignElements(ValueType* assign_first, ValueAdapter* values_ptr,
+template <typename Pointer, typename ValueAdapter, typename SizeType>
+void AssignElements(Pointer assign_first, ValueAdapter* values_ptr,
SizeType assign_size) {
for (SizeType i = 0; i < assign_size; ++i) {
values_ptr->AssignNext(assign_first + i);
@@ -93,28 +106,29 @@
template <typename AllocatorType>
struct StorageView {
- using pointer = typename AllocatorType::pointer;
- using size_type = typename AllocatorType::size_type;
+ using AllocatorTraits = absl::allocator_traits<AllocatorType>;
+ using Pointer = typename AllocatorTraits::pointer;
+ using SizeType = typename AllocatorTraits::size_type;
- pointer data;
- size_type size;
- size_type capacity;
+ Pointer data;
+ SizeType size;
+ SizeType capacity;
};
template <typename AllocatorType, typename Iterator>
class IteratorValueAdapter {
- using pointer = typename AllocatorType::pointer;
using AllocatorTraits = absl::allocator_traits<AllocatorType>;
+ using Pointer = typename AllocatorTraits::pointer;
public:
explicit IteratorValueAdapter(const Iterator& it) : it_(it) {}
- void ConstructNext(AllocatorType* alloc_ptr, pointer construct_at) {
+ void ConstructNext(AllocatorType* alloc_ptr, Pointer construct_at) {
AllocatorTraits::construct(*alloc_ptr, construct_at, *it_);
++it_;
}
- void AssignNext(pointer assign_at) {
+ void AssignNext(Pointer assign_at) {
*assign_at = *it_;
++it_;
}
@@ -125,46 +139,45 @@
template <typename AllocatorType>
class CopyValueAdapter {
- using pointer = typename AllocatorType::pointer;
- using const_pointer = typename AllocatorType::const_pointer;
- using const_reference = typename AllocatorType::const_reference;
using AllocatorTraits = absl::allocator_traits<AllocatorType>;
+ using ValueType = typename AllocatorTraits::value_type;
+ using Pointer = typename AllocatorTraits::pointer;
+ using ConstPointer = typename AllocatorTraits::const_pointer;
public:
- explicit CopyValueAdapter(const_reference v) : ptr_(std::addressof(v)) {}
+ explicit CopyValueAdapter(const ValueType& v) : ptr_(std::addressof(v)) {}
- void ConstructNext(AllocatorType* alloc_ptr, pointer construct_at) {
+ void ConstructNext(AllocatorType* alloc_ptr, Pointer construct_at) {
AllocatorTraits::construct(*alloc_ptr, construct_at, *ptr_);
}
- void AssignNext(pointer assign_at) { *assign_at = *ptr_; }
+ void AssignNext(Pointer assign_at) { *assign_at = *ptr_; }
private:
- const_pointer ptr_;
+ ConstPointer ptr_;
};
template <typename AllocatorType>
class DefaultValueAdapter {
- using pointer = typename AllocatorType::pointer;
- using value_type = typename AllocatorType::value_type;
using AllocatorTraits = absl::allocator_traits<AllocatorType>;
+ using ValueType = typename AllocatorTraits::value_type;
+ using Pointer = typename AllocatorTraits::pointer;
public:
explicit DefaultValueAdapter() {}
- void ConstructNext(AllocatorType* alloc_ptr, pointer construct_at) {
+ void ConstructNext(AllocatorType* alloc_ptr, Pointer construct_at) {
AllocatorTraits::construct(*alloc_ptr, construct_at);
}
- void AssignNext(pointer assign_at) { *assign_at = value_type(); }
+ void AssignNext(Pointer assign_at) { *assign_at = ValueType(); }
};
template <typename AllocatorType>
class AllocationTransaction {
- using value_type = typename AllocatorType::value_type;
- using pointer = typename AllocatorType::pointer;
- using size_type = typename AllocatorType::size_type;
using AllocatorTraits = absl::allocator_traits<AllocatorType>;
+ using Pointer = typename AllocatorTraits::pointer;
+ using SizeType = typename AllocatorTraits::size_type;
public:
explicit AllocationTransaction(AllocatorType* alloc_ptr)
@@ -180,11 +193,11 @@
void operator=(const AllocationTransaction&) = delete;
AllocatorType& GetAllocator() { return alloc_data_.template get<0>(); }
- pointer& GetData() { return alloc_data_.template get<1>(); }
- size_type& GetCapacity() { return capacity_; }
+ Pointer& GetData() { return alloc_data_.template get<1>(); }
+ SizeType& GetCapacity() { return capacity_; }
bool DidAllocate() { return GetData() != nullptr; }
- pointer Allocate(size_type capacity) {
+ Pointer Allocate(SizeType capacity) {
GetData() = AllocatorTraits::allocate(GetAllocator(), capacity);
GetCapacity() = capacity;
return GetData();
@@ -196,14 +209,15 @@
}
private:
- container_internal::CompressedTuple<AllocatorType, pointer> alloc_data_;
- size_type capacity_ = 0;
+ container_internal::CompressedTuple<AllocatorType, Pointer> alloc_data_;
+ SizeType capacity_ = 0;
};
template <typename AllocatorType>
class ConstructionTransaction {
- using pointer = typename AllocatorType::pointer;
- using size_type = typename AllocatorType::size_type;
+ using AllocatorTraits = absl::allocator_traits<AllocatorType>;
+ using Pointer = typename AllocatorTraits::pointer;
+ using SizeType = typename AllocatorTraits::size_type;
public:
explicit ConstructionTransaction(AllocatorType* alloc_ptr)
@@ -220,12 +234,12 @@
void operator=(const ConstructionTransaction&) = delete;
AllocatorType& GetAllocator() { return alloc_data_.template get<0>(); }
- pointer& GetData() { return alloc_data_.template get<1>(); }
- size_type& GetSize() { return size_; }
+ Pointer& GetData() { return alloc_data_.template get<1>(); }
+ SizeType& GetSize() { return size_; }
bool DidConstruct() { return GetData() != nullptr; }
template <typename ValueAdapter>
- void Construct(pointer data, ValueAdapter* values_ptr, size_type size) {
+ void Construct(Pointer data, ValueAdapter* values_ptr, SizeType size) {
inlined_vector_internal::ConstructElements(std::addressof(GetAllocator()),
data, values_ptr, size);
GetData() = data;
@@ -237,28 +251,29 @@
}
private:
- container_internal::CompressedTuple<AllocatorType, pointer> alloc_data_;
- size_type size_ = 0;
+ container_internal::CompressedTuple<AllocatorType, Pointer> alloc_data_;
+ SizeType size_ = 0;
};
template <typename T, size_t N, typename A>
class Storage {
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 rvalue_reference = typename allocator_type::value_type&&;
- using size_type = typename allocator_type::size_type;
- using difference_type = typename allocator_type::difference_type;
+ using AllocatorTraits = absl::allocator_traits<A>;
+ using allocator_type = typename AllocatorTraits::allocator_type;
+ using value_type = typename AllocatorTraits::value_type;
+ using pointer = typename AllocatorTraits::pointer;
+ using const_pointer = typename AllocatorTraits::const_pointer;
+ using size_type = typename AllocatorTraits::size_type;
+ using difference_type = typename AllocatorTraits::difference_type;
+
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using RValueReference = value_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>;
using MoveIterator = std::move_iterator<iterator>;
- using AllocatorTraits = absl::allocator_traits<allocator_type>;
using IsMemcpyOk = inlined_vector_internal::IsMemcpyOk<allocator_type>;
using StorageView = inlined_vector_internal::StorageView<allocator_type>;
@@ -289,9 +304,10 @@
// Storage Constructors and Destructor
// ---------------------------------------------------------------------------
- Storage() : metadata_() {}
+ Storage() : metadata_(allocator_type(), /* size and is_allocated */ 0) {}
- explicit Storage(const allocator_type& alloc) : metadata_(alloc, {}) {}
+ explicit Storage(const allocator_type& alloc)
+ : metadata_(alloc, /* size and is_allocated */ 0) {}
~Storage() {
pointer data = GetIsAllocated() ? GetAllocatedData() : GetInlinedData();
@@ -453,6 +469,9 @@
Inlined inlined;
};
+ template <typename... Args>
+ ABSL_ATTRIBUTE_NOINLINE reference EmplaceBackSlow(Args&&... args);
+
Metadata metadata_;
Data data_;
};
@@ -471,12 +490,9 @@
// safe to take on the allocation with size `0`. If `ConstructElements(...)`
// throws, deallocation will be automatically handled by `~Storage()`.
size_type new_capacity = ComputeCapacity(GetInlinedCapacity(), new_size);
- pointer new_data = AllocatorTraits::allocate(*GetAllocPtr(), new_capacity);
-
- SetAllocatedData(new_data, new_capacity);
+ construct_data = AllocatorTraits::allocate(*GetAllocPtr(), new_capacity);
+ SetAllocatedData(construct_data, new_capacity);
SetIsAllocated();
-
- construct_data = new_data;
} else {
construct_data = GetInlinedData();
}
@@ -503,9 +519,7 @@
if (new_size > storage_view.capacity) {
size_type new_capacity = ComputeCapacity(storage_view.capacity, new_size);
- pointer new_data = allocation_tx.Allocate(new_capacity);
-
- construct_loop = {new_data, new_size};
+ construct_loop = {allocation_tx.Allocate(new_capacity), new_size};
destroy_loop = {storage_view.data, storage_view.size};
} else if (new_size > storage_view.size) {
assign_loop = {storage_view.data, storage_view.size};
@@ -538,49 +552,42 @@
template <typename ValueAdapter>
auto Storage<T, N, A>::Resize(ValueAdapter values, size_type new_size) -> void {
StorageView storage_view = MakeStorageView();
-
- AllocationTransaction allocation_tx(GetAllocPtr());
- ConstructionTransaction construction_tx(GetAllocPtr());
-
- IteratorValueAdapter<MoveIterator> move_values(
- MoveIterator(storage_view.data));
-
- absl::Span<value_type> construct_loop;
- absl::Span<value_type> move_construct_loop;
- absl::Span<value_type> destroy_loop;
-
- if (new_size > storage_view.capacity) {
+ auto* const base = storage_view.data;
+ const size_type size = storage_view.size;
+ auto* alloc = GetAllocPtr();
+ if (new_size <= size) {
+ // Destroy extra old elements.
+ inlined_vector_internal::DestroyElements(alloc, base + new_size,
+ size - new_size);
+ } else if (new_size <= storage_view.capacity) {
+ // Construct new elements in place.
+ inlined_vector_internal::ConstructElements(alloc, base + size, &values,
+ new_size - size);
+ } else {
+ // Steps:
+ // a. Allocate new backing store.
+ // b. Construct new elements in new backing store.
+ // c. Move existing elements from old backing store to now.
+ // d. Destroy all elements in old backing store.
+ // Use transactional wrappers for the first two steps so we can roll
+ // back if necessary due to exceptions.
+ AllocationTransaction allocation_tx(alloc);
size_type new_capacity = ComputeCapacity(storage_view.capacity, new_size);
pointer new_data = allocation_tx.Allocate(new_capacity);
- construct_loop = {new_data + storage_view.size,
- new_size - storage_view.size};
- move_construct_loop = {new_data, storage_view.size};
- destroy_loop = {storage_view.data, storage_view.size};
- } else if (new_size > storage_view.size) {
- construct_loop = {storage_view.data + storage_view.size,
- new_size - storage_view.size};
- } else {
- destroy_loop = {storage_view.data + new_size, storage_view.size - new_size};
- }
+ ConstructionTransaction construction_tx(alloc);
+ construction_tx.Construct(new_data + size, &values, new_size - size);
- construction_tx.Construct(construct_loop.data(), &values,
- construct_loop.size());
+ IteratorValueAdapter<MoveIterator> move_values((MoveIterator(base)));
+ inlined_vector_internal::ConstructElements(alloc, new_data, &move_values,
+ size);
- inlined_vector_internal::ConstructElements(
- GetAllocPtr(), move_construct_loop.data(), &move_values,
- move_construct_loop.size());
-
- inlined_vector_internal::DestroyElements(GetAllocPtr(), destroy_loop.data(),
- destroy_loop.size());
-
- construction_tx.Commit();
- if (allocation_tx.DidAllocate()) {
+ inlined_vector_internal::DestroyElements(alloc, base, size);
+ construction_tx.Commit();
DeallocateIfAllocated();
AcquireAllocatedData(&allocation_tx);
SetIsAllocated();
}
-
SetSize(new_size);
}
@@ -681,54 +688,57 @@
template <typename... Args>
auto Storage<T, N, A>::EmplaceBack(Args&&... args) -> reference {
StorageView storage_view = MakeStorageView();
+ const auto n = storage_view.size;
+ if (ABSL_PREDICT_TRUE(n != storage_view.capacity)) {
+ // Fast path; new element fits.
+ pointer last_ptr = storage_view.data + n;
+ AllocatorTraits::construct(*GetAllocPtr(), last_ptr,
+ std::forward<Args>(args)...);
+ AddSize(1);
+ return *last_ptr;
+ }
+ // TODO(b/173712035): Annotate with musttail attribute to prevent regression.
+ return EmplaceBackSlow(std::forward<Args>(args)...);
+}
+template <typename T, size_t N, typename A>
+template <typename... Args>
+auto Storage<T, N, A>::EmplaceBackSlow(Args&&... args) -> reference {
+ StorageView storage_view = MakeStorageView();
AllocationTransaction allocation_tx(GetAllocPtr());
-
IteratorValueAdapter<MoveIterator> move_values(
MoveIterator(storage_view.data));
+ size_type new_capacity = NextCapacity(storage_view.capacity);
+ pointer construct_data = allocation_tx.Allocate(new_capacity);
+ pointer last_ptr = construct_data + storage_view.size;
- pointer construct_data;
- if (storage_view.size == storage_view.capacity) {
- size_type new_capacity = NextCapacity(storage_view.capacity);
- pointer new_data = allocation_tx.Allocate(new_capacity);
-
- construct_data = new_data;
- } else {
- construct_data = storage_view.data;
- }
-
- AllocatorTraits::construct(*GetAllocPtr(), construct_data + storage_view.size,
+ // Construct new element.
+ AllocatorTraits::construct(*GetAllocPtr(), last_ptr,
std::forward<Args>(args)...);
-
- if (allocation_tx.DidAllocate()) {
- ABSL_INTERNAL_TRY {
- inlined_vector_internal::ConstructElements(
- GetAllocPtr(), allocation_tx.GetData(), &move_values,
- storage_view.size);
- }
- ABSL_INTERNAL_CATCH_ANY {
- AllocatorTraits::destroy(*GetAllocPtr(),
- construct_data + storage_view.size);
- ABSL_INTERNAL_RETHROW;
- }
-
- inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
- storage_view.size);
-
- DeallocateIfAllocated();
- AcquireAllocatedData(&allocation_tx);
- SetIsAllocated();
+ // Move elements from old backing store to new backing store.
+ ABSL_INTERNAL_TRY {
+ inlined_vector_internal::ConstructElements(
+ GetAllocPtr(), allocation_tx.GetData(), &move_values,
+ storage_view.size);
}
+ ABSL_INTERNAL_CATCH_ANY {
+ AllocatorTraits::destroy(*GetAllocPtr(), last_ptr);
+ ABSL_INTERNAL_RETHROW;
+ }
+ // Destroy elements in old backing store.
+ inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
+ storage_view.size);
+ DeallocateIfAllocated();
+ AcquireAllocatedData(&allocation_tx);
+ SetIsAllocated();
AddSize(1);
- return *(construct_data + storage_view.size);
+ return *last_ptr;
}
template <typename T, size_t N, typename A>
auto Storage<T, N, A>::Erase(const_iterator from, const_iterator to)
-> iterator {
- assert(from != to);
-
StorageView storage_view = MakeStorageView();
size_type erase_size = std::distance(from, to);
@@ -795,9 +805,7 @@
pointer construct_data;
if (storage_view.size > GetInlinedCapacity()) {
size_type new_capacity = storage_view.size;
- pointer new_data = allocation_tx.Allocate(new_capacity);
-
- construct_data = new_data;
+ construct_data = allocation_tx.Allocate(new_capacity);
} else {
construct_data = GetInlinedData();
}
@@ -887,7 +895,13 @@
swap(*GetAllocPtr(), *other_storage_ptr->GetAllocPtr());
}
+// End ignore "maybe-uninitialized"
+#if !defined(__clang__) && defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+
} // namespace inlined_vector_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_INTERNAL_H_
diff --git a/third_party/abseil/absl/container/internal/layout.h b/third_party/abseil/absl/container/internal/layout.h
index bbdde50..2336783 100644
--- a/third_party/abseil/absl/container/internal/layout.h
+++ b/third_party/abseil/absl/container/internal/layout.h
@@ -163,6 +163,7 @@
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
+
#include <ostream>
#include <string>
#include <tuple>
@@ -170,15 +171,16 @@
#include <typeinfo>
#include <utility>
-#ifdef ADDRESS_SANITIZER
-#include <sanitizer/asan_interface.h>
-#endif
-
+#include "absl/base/config.h"
#include "absl/meta/type_traits.h"
#include "absl/strings/str_cat.h"
#include "absl/types/span.h"
#include "absl/utility/utility.h"
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+#include <sanitizer/asan_interface.h>
+#endif
+
#if defined(__GXX_RTTI)
#define ABSL_INTERNAL_HAS_CXA_DEMANGLE
#endif
@@ -188,6 +190,7 @@
#endif
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
// A type wrapper that instructs `Layout` to use the specific alignment for the
@@ -613,7 +616,7 @@
void PoisonPadding(const Char* p) const {
static_assert(N < NumOffsets, "Index out of bounds");
(void)p;
-#ifdef ADDRESS_SANITIZER
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
PoisonPadding<Char, N - 1>(p);
// The `if` is an optimization. It doesn't affect the observable behaviour.
if (ElementAlignment<N - 1>::value % ElementAlignment<N>::value) {
@@ -734,6 +737,7 @@
};
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_LAYOUT_H_
diff --git a/third_party/abseil/absl/container/internal/layout_benchmark.cc b/third_party/abseil/absl/container/internal/layout_benchmark.cc
new file mode 100644
index 0000000..d8636e8
--- /dev/null
+++ b/third_party/abseil/absl/container/internal/layout_benchmark.cc
@@ -0,0 +1,122 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Every benchmark should have the same performance as the corresponding
+// headroom benchmark.
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/container/internal/layout.h"
+#include "benchmark/benchmark.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+namespace {
+
+using ::benchmark::DoNotOptimize;
+
+using Int128 = int64_t[2];
+
+// This benchmark provides the upper bound on performance for BM_OffsetConstant.
+template <size_t Offset, class... Ts>
+void BM_OffsetConstantHeadroom(benchmark::State& state) {
+ for (auto _ : state) {
+ DoNotOptimize(Offset);
+ }
+}
+
+template <size_t Offset, class... Ts>
+void BM_OffsetConstant(benchmark::State& state) {
+ using L = Layout<Ts...>;
+ ABSL_RAW_CHECK(L::Partial(3, 5, 7).template Offset<3>() == Offset,
+ "Invalid offset");
+ for (auto _ : state) {
+ DoNotOptimize(L::Partial(3, 5, 7).template Offset<3>());
+ }
+}
+
+template <class... Ts>
+size_t VariableOffset(size_t n, size_t m, size_t k);
+
+template <>
+size_t VariableOffset<int8_t, int16_t, int32_t, Int128>(size_t n, size_t m,
+ size_t k) {
+ auto Align = [](size_t n, size_t m) { return (n + m - 1) & ~(m - 1); };
+ return Align(Align(Align(n * 1, 2) + m * 2, 4) + k * 4, 8);
+}
+
+template <>
+size_t VariableOffset<Int128, int32_t, int16_t, int8_t>(size_t n, size_t m,
+ size_t k) {
+ // No alignment is necessary.
+ return n * 16 + m * 4 + k * 2;
+}
+
+// This benchmark provides the upper bound on performance for BM_OffsetVariable.
+template <size_t Offset, class... Ts>
+void BM_OffsetVariableHeadroom(benchmark::State& state) {
+ size_t n = 3;
+ size_t m = 5;
+ size_t k = 7;
+ ABSL_RAW_CHECK(VariableOffset<Ts...>(n, m, k) == Offset, "Invalid offset");
+ for (auto _ : state) {
+ DoNotOptimize(n);
+ DoNotOptimize(m);
+ DoNotOptimize(k);
+ DoNotOptimize(VariableOffset<Ts...>(n, m, k));
+ }
+}
+
+template <size_t Offset, class... Ts>
+void BM_OffsetVariable(benchmark::State& state) {
+ using L = Layout<Ts...>;
+ size_t n = 3;
+ size_t m = 5;
+ size_t k = 7;
+ ABSL_RAW_CHECK(L::Partial(n, m, k).template Offset<3>() == Offset,
+ "Inavlid offset");
+ for (auto _ : state) {
+ DoNotOptimize(n);
+ DoNotOptimize(m);
+ DoNotOptimize(k);
+ DoNotOptimize(L::Partial(n, m, k).template Offset<3>());
+ }
+}
+
+// Run all benchmarks in two modes:
+//
+// Layout with padding: int8_t[3], int16_t[5], int32_t[7], Int128[?].
+// Layout without padding: Int128[3], int32_t[5], int16_t[7], int8_t[?].
+
+#define OFFSET_BENCHMARK(NAME, OFFSET, T1, T2, T3, T4) \
+ auto& NAME##_##OFFSET##_##T1##_##T2##_##T3##_##T4 = \
+ NAME<OFFSET, T1, T2, T3, T4>; \
+ BENCHMARK(NAME##_##OFFSET##_##T1##_##T2##_##T3##_##T4)
+
+OFFSET_BENCHMARK(BM_OffsetConstantHeadroom, 48, int8_t, int16_t, int32_t,
+ Int128);
+OFFSET_BENCHMARK(BM_OffsetConstant, 48, int8_t, int16_t, int32_t, Int128);
+OFFSET_BENCHMARK(BM_OffsetConstantHeadroom, 82, Int128, int32_t, int16_t,
+ int8_t);
+OFFSET_BENCHMARK(BM_OffsetConstant, 82, Int128, int32_t, int16_t, int8_t);
+OFFSET_BENCHMARK(BM_OffsetVariableHeadroom, 48, int8_t, int16_t, int32_t,
+ Int128);
+OFFSET_BENCHMARK(BM_OffsetVariable, 48, int8_t, int16_t, int32_t, Int128);
+OFFSET_BENCHMARK(BM_OffsetVariableHeadroom, 82, Int128, int32_t, int16_t,
+ int8_t);
+OFFSET_BENCHMARK(BM_OffsetVariable, 82, Int128, int32_t, int16_t, int8_t);
+} // namespace
+} // namespace container_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/container/internal/layout_test.cc b/third_party/abseil/absl/container/internal/layout_test.cc
index 33b72bd..1d7158f 100644
--- a/third_party/abseil/absl/container/internal/layout_test.cc
+++ b/third_party/abseil/absl/container/internal/layout_test.cc
@@ -17,6 +17,7 @@
// We need ::max_align_t because some libstdc++ versions don't provide
// std::max_align_t
#include <stddef.h>
+
#include <cstdint>
#include <memory>
#include <sstream>
@@ -24,10 +25,12 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/base/config.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/types/span.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace {
@@ -125,8 +128,10 @@
{
using L = Layout<int32_t, int32_t>;
SameType<std::tuple<int32_t, int32_t>, L::ElementTypes>();
- SameType<std::tuple<int32_t, int32_t>, decltype(L::Partial())::ElementTypes>();
- SameType<std::tuple<int32_t, int32_t>, decltype(L::Partial(0))::ElementTypes>();
+ SameType<std::tuple<int32_t, int32_t>,
+ decltype(L::Partial())::ElementTypes>();
+ SameType<std::tuple<int32_t, int32_t>,
+ decltype(L::Partial(0))::ElementTypes>();
}
{
using L = Layout<int8_t, int32_t, Int128>;
@@ -365,18 +370,21 @@
{
using L = Layout<int32_t>;
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<0>(p))));
- EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
+ EXPECT_EQ(0,
+ Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3).Pointer<0>(p))));
}
{
using L = Layout<int32_t, int32_t>;
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<0>(p))));
- EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
- EXPECT_EQ(12, Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<1>(p))));
EXPECT_EQ(0,
- Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<0>(p))));
+ Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
EXPECT_EQ(12,
- Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<1>(p))));
+ Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<1>(p))));
+ EXPECT_EQ(
+ 0, Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<0>(p))));
+ EXPECT_EQ(
+ 12, Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3, 5).Pointer<0>(p))));
EXPECT_EQ(12, Distance(p, Type<const int32_t*>(L(3, 5).Pointer<1>(p))));
}
@@ -384,39 +392,44 @@
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<0>(p))));
EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<0>(p))));
- EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<1>(p))));
+ EXPECT_EQ(0,
+ Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<0>(p))));
- EXPECT_EQ(4, Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<1>(p))));
+ EXPECT_EQ(4,
+ Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<0>(p))));
- EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<1>(p))));
+ EXPECT_EQ(8,
+ Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<1>(p))));
EXPECT_EQ(0,
Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<0>(p))));
- EXPECT_EQ(0,
- Distance(p, Type<const int32_t*>(L::Partial(0, 0).Pointer<1>(p))));
+ EXPECT_EQ(
+ 0, Distance(p, Type<const int32_t*>(L::Partial(0, 0).Pointer<1>(p))));
EXPECT_EQ(0,
Distance(p, Type<const Int128*>(L::Partial(0, 0).Pointer<2>(p))));
EXPECT_EQ(0,
Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<0>(p))));
- EXPECT_EQ(4,
- Distance(p, Type<const int32_t*>(L::Partial(1, 0).Pointer<1>(p))));
+ EXPECT_EQ(
+ 4, Distance(p, Type<const int32_t*>(L::Partial(1, 0).Pointer<1>(p))));
EXPECT_EQ(8,
Distance(p, Type<const Int128*>(L::Partial(1, 0).Pointer<2>(p))));
EXPECT_EQ(0,
Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<0>(p))));
- EXPECT_EQ(8,
- Distance(p, Type<const int32_t*>(L::Partial(5, 3).Pointer<1>(p))));
+ EXPECT_EQ(
+ 8, Distance(p, Type<const int32_t*>(L::Partial(5, 3).Pointer<1>(p))));
EXPECT_EQ(24,
Distance(p, Type<const Int128*>(L::Partial(5, 3).Pointer<2>(p))));
EXPECT_EQ(
0, Distance(p, Type<const int8_t*>(L::Partial(0, 0, 0).Pointer<0>(p))));
EXPECT_EQ(
- 0, Distance(p, Type<const int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
+ 0,
+ Distance(p, Type<const int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
EXPECT_EQ(
0, Distance(p, Type<const Int128*>(L::Partial(0, 0, 0).Pointer<2>(p))));
EXPECT_EQ(
0, Distance(p, Type<const int8_t*>(L::Partial(1, 0, 0).Pointer<0>(p))));
EXPECT_EQ(
- 4, Distance(p, Type<const int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
+ 4,
+ Distance(p, Type<const int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
EXPECT_EQ(
8, Distance(p, Type<const Int128*>(L::Partial(1, 0, 0).Pointer<2>(p))));
EXPECT_EQ(
@@ -425,7 +438,8 @@
24,
Distance(p, Type<const Int128*>(L::Partial(5, 3, 1).Pointer<2>(p))));
EXPECT_EQ(
- 8, Distance(p, Type<const int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
+ 8,
+ Distance(p, Type<const int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L(5, 3, 1).Pointer<0>(p))));
EXPECT_EQ(24, Distance(p, Type<const Int128*>(L(5, 3, 1).Pointer<2>(p))));
EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<1>(p))));
@@ -436,75 +450,78 @@
alignas(max_align_t) const unsigned char p[100] = {};
{
using L = Layout<int32_t>;
- EXPECT_EQ(0,
- Distance(p, Type<const int32_t*>(L::Partial().Pointer<int32_t>(p))));
- EXPECT_EQ(0,
- Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
+ EXPECT_EQ(
+ 0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<int32_t>(p))));
+ EXPECT_EQ(
+ 0,
+ Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3).Pointer<int32_t>(p))));
}
{
using L = Layout<int8_t, int32_t, Int128>;
- EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<int8_t>(p))));
- EXPECT_EQ(0,
- Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<int8_t>(p))));
- EXPECT_EQ(0,
- Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
- EXPECT_EQ(0,
- Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<int8_t>(p))));
- EXPECT_EQ(4,
- Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
- EXPECT_EQ(0,
- Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<int8_t>(p))));
- EXPECT_EQ(8,
- Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
EXPECT_EQ(
- 0, Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
+ 0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<int8_t>(p))));
EXPECT_EQ(
- 0, Distance(p, Type<const int32_t*>(L::Partial(0, 0).Pointer<int32_t>(p))));
+ 0, Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<int8_t>(p))));
+ EXPECT_EQ(
+ 0,
+ Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
+ EXPECT_EQ(
+ 0, Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<int8_t>(p))));
+ EXPECT_EQ(
+ 4,
+ Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
+ EXPECT_EQ(
+ 0, Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<int8_t>(p))));
+ EXPECT_EQ(
+ 8,
+ Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
+ EXPECT_EQ(
+ 0,
+ Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
+ EXPECT_EQ(0, Distance(p, Type<const int32_t*>(
+ L::Partial(0, 0).Pointer<int32_t>(p))));
EXPECT_EQ(
0,
Distance(p, Type<const Int128*>(L::Partial(0, 0).Pointer<Int128>(p))));
EXPECT_EQ(
- 0, Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
- EXPECT_EQ(
- 4, Distance(p, Type<const int32_t*>(L::Partial(1, 0).Pointer<int32_t>(p))));
+ 0,
+ Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
+ EXPECT_EQ(4, Distance(p, Type<const int32_t*>(
+ L::Partial(1, 0).Pointer<int32_t>(p))));
EXPECT_EQ(
8,
Distance(p, Type<const Int128*>(L::Partial(1, 0).Pointer<Int128>(p))));
EXPECT_EQ(
- 0, Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
- EXPECT_EQ(
- 8, Distance(p, Type<const int32_t*>(L::Partial(5, 3).Pointer<int32_t>(p))));
+ 0,
+ Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
+ EXPECT_EQ(8, Distance(p, Type<const int32_t*>(
+ L::Partial(5, 3).Pointer<int32_t>(p))));
EXPECT_EQ(
24,
Distance(p, Type<const Int128*>(L::Partial(5, 3).Pointer<Int128>(p))));
- EXPECT_EQ(
- 0,
- Distance(p, Type<const int8_t*>(L::Partial(0, 0, 0).Pointer<int8_t>(p))));
- EXPECT_EQ(
- 0,
- Distance(p, Type<const int32_t*>(L::Partial(0, 0, 0).Pointer<int32_t>(p))));
+ EXPECT_EQ(0, Distance(p, Type<const int8_t*>(
+ L::Partial(0, 0, 0).Pointer<int8_t>(p))));
+ EXPECT_EQ(0, Distance(p, Type<const int32_t*>(
+ L::Partial(0, 0, 0).Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<const Int128*>(
L::Partial(0, 0, 0).Pointer<Int128>(p))));
- EXPECT_EQ(
- 0,
- Distance(p, Type<const int8_t*>(L::Partial(1, 0, 0).Pointer<int8_t>(p))));
- EXPECT_EQ(
- 4,
- Distance(p, Type<const int32_t*>(L::Partial(1, 0, 0).Pointer<int32_t>(p))));
+ EXPECT_EQ(0, Distance(p, Type<const int8_t*>(
+ L::Partial(1, 0, 0).Pointer<int8_t>(p))));
+ EXPECT_EQ(4, Distance(p, Type<const int32_t*>(
+ L::Partial(1, 0, 0).Pointer<int32_t>(p))));
EXPECT_EQ(8, Distance(p, Type<const Int128*>(
L::Partial(1, 0, 0).Pointer<Int128>(p))));
- EXPECT_EQ(
- 0,
- Distance(p, Type<const int8_t*>(L::Partial(5, 3, 1).Pointer<int8_t>(p))));
+ EXPECT_EQ(0, Distance(p, Type<const int8_t*>(
+ L::Partial(5, 3, 1).Pointer<int8_t>(p))));
EXPECT_EQ(24, Distance(p, Type<const Int128*>(
L::Partial(5, 3, 1).Pointer<Int128>(p))));
- EXPECT_EQ(
- 8,
- Distance(p, Type<const int32_t*>(L::Partial(5, 3, 1).Pointer<int32_t>(p))));
+ EXPECT_EQ(8, Distance(p, Type<const int32_t*>(
+ L::Partial(5, 3, 1).Pointer<int32_t>(p))));
EXPECT_EQ(24,
Distance(p, Type<const Int128*>(L(5, 3, 1).Pointer<Int128>(p))));
- EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<int32_t>(p))));
+ EXPECT_EQ(
+ 8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<int32_t>(p))));
}
}
@@ -545,15 +562,18 @@
EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<1>(p))));
EXPECT_EQ(24, Distance(p, Type<Int128*>(L::Partial(5, 3).Pointer<2>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<0>(p))));
- EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
+ EXPECT_EQ(0,
+ Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<Int128*>(L::Partial(0, 0, 0).Pointer<2>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<0>(p))));
- EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
+ EXPECT_EQ(4,
+ Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
EXPECT_EQ(8, Distance(p, Type<Int128*>(L::Partial(1, 0, 0).Pointer<2>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<0>(p))));
EXPECT_EQ(24,
Distance(p, Type<Int128*>(L::Partial(5, 3, 1).Pointer<2>(p))));
- EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
+ EXPECT_EQ(8,
+ Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L(5, 3, 1).Pointer<0>(p))));
EXPECT_EQ(24, Distance(p, Type<Int128*>(L(5, 3, 1).Pointer<2>(p))));
EXPECT_EQ(8, Distance(p, Type<int32_t*>(L(5, 3, 1).Pointer<1>(p))));
@@ -565,48 +585,61 @@
{
using L = Layout<int32_t>;
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial().Pointer<int32_t>(p))));
- EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
+ EXPECT_EQ(0,
+ Distance(p, Type<int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L(3).Pointer<int32_t>(p))));
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial().Pointer<int8_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0).Pointer<int8_t>(p))));
- EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
+ EXPECT_EQ(0,
+ Distance(p, Type<int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1).Pointer<int8_t>(p))));
- EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
+ EXPECT_EQ(4,
+ Distance(p, Type<int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5).Pointer<int8_t>(p))));
- EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
- EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
- EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0, 0).Pointer<int32_t>(p))));
+ EXPECT_EQ(8,
+ Distance(p, Type<int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
+ EXPECT_EQ(0,
+ Distance(p, Type<int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
+ EXPECT_EQ(
+ 0, Distance(p, Type<int32_t*>(L::Partial(0, 0).Pointer<int32_t>(p))));
EXPECT_EQ(0,
Distance(p, Type<Int128*>(L::Partial(0, 0).Pointer<Int128>(p))));
- EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
- EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1, 0).Pointer<int32_t>(p))));
+ EXPECT_EQ(0,
+ Distance(p, Type<int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
+ EXPECT_EQ(
+ 4, Distance(p, Type<int32_t*>(L::Partial(1, 0).Pointer<int32_t>(p))));
EXPECT_EQ(8,
Distance(p, Type<Int128*>(L::Partial(1, 0).Pointer<Int128>(p))));
- EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
- EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<int32_t>(p))));
+ EXPECT_EQ(0,
+ Distance(p, Type<int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
+ EXPECT_EQ(
+ 8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<int32_t>(p))));
EXPECT_EQ(24,
Distance(p, Type<Int128*>(L::Partial(5, 3).Pointer<Int128>(p))));
- EXPECT_EQ(0,
- Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<int8_t>(p))));
- EXPECT_EQ(0,
- Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<int32_t>(p))));
+ EXPECT_EQ(
+ 0, Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<int8_t>(p))));
+ EXPECT_EQ(
+ 0,
+ Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<int32_t>(p))));
EXPECT_EQ(
0, Distance(p, Type<Int128*>(L::Partial(0, 0, 0).Pointer<Int128>(p))));
- EXPECT_EQ(0,
- Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<int8_t>(p))));
- EXPECT_EQ(4,
- Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<int32_t>(p))));
+ EXPECT_EQ(
+ 0, Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<int8_t>(p))));
+ EXPECT_EQ(
+ 4,
+ Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<int32_t>(p))));
EXPECT_EQ(
8, Distance(p, Type<Int128*>(L::Partial(1, 0, 0).Pointer<Int128>(p))));
- EXPECT_EQ(0,
- Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<int8_t>(p))));
+ EXPECT_EQ(
+ 0, Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<int8_t>(p))));
EXPECT_EQ(
24, Distance(p, Type<Int128*>(L::Partial(5, 3, 1).Pointer<Int128>(p))));
- EXPECT_EQ(8,
- Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<int32_t>(p))));
+ EXPECT_EQ(
+ 8,
+ Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L(5, 3, 1).Pointer<int8_t>(p))));
EXPECT_EQ(24, Distance(p, Type<Int128*>(L(5, 3, 1).Pointer<Int128>(p))));
EXPECT_EQ(8, Distance(p, Type<int32_t*>(L(5, 3, 1).Pointer<int32_t>(p))));
@@ -787,67 +820,72 @@
{
using L = Layout<int32_t>;
EXPECT_EQ(
- 0,
- Distance(p, Type<Span<const int32_t>>(L::Partial(0).Slice<0>(p)).data()));
+ 0, Distance(
+ p, Type<Span<const int32_t>>(L::Partial(0).Slice<0>(p)).data()));
EXPECT_EQ(
- 0,
- Distance(p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
- EXPECT_EQ(0, Distance(p, Type<Span<const int32_t>>(L(3).Slice<0>(p)).data()));
+ 0, Distance(
+ p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
+ EXPECT_EQ(0,
+ Distance(p, Type<Span<const int32_t>>(L(3).Slice<0>(p)).data()));
}
{
using L = Layout<int32_t, int32_t>;
EXPECT_EQ(
- 0,
- Distance(p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
+ 0, Distance(
+ p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
EXPECT_EQ(
0,
- Distance(p,
- Type<Span<const int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
+ Distance(
+ p, Type<Span<const int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
EXPECT_EQ(
12,
- Distance(p,
- Type<Span<const int32_t>>(L::Partial(3, 5).Slice<1>(p)).data()));
- EXPECT_EQ(0,
- Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<0>(p)).data()));
- EXPECT_EQ(12,
- Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<1>(p)).data()));
+ Distance(
+ p, Type<Span<const int32_t>>(L::Partial(3, 5).Slice<1>(p)).data()));
+ EXPECT_EQ(
+ 0, Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<0>(p)).data()));
+ EXPECT_EQ(
+ 12, Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<1>(p)).data()));
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(
- 0,
- Distance(p, Type<Span<const int8_t>>(L::Partial(0).Slice<0>(p)).data()));
- EXPECT_EQ(
- 0,
- Distance(p, Type<Span<const int8_t>>(L::Partial(1).Slice<0>(p)).data()));
- EXPECT_EQ(
- 0,
- Distance(p, Type<Span<const int8_t>>(L::Partial(5).Slice<0>(p)).data()));
+ 0, Distance(
+ p, Type<Span<const int8_t>>(L::Partial(0).Slice<0>(p)).data()));
EXPECT_EQ(
0, Distance(
- p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
- EXPECT_EQ(
- 0,
- Distance(p,
- Type<Span<const int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
+ p, Type<Span<const int8_t>>(L::Partial(1).Slice<0>(p)).data()));
EXPECT_EQ(
0, Distance(
- p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
- EXPECT_EQ(
- 4,
- Distance(p,
- Type<Span<const int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
- EXPECT_EQ(
- 0, Distance(
- p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
- EXPECT_EQ(
- 8,
- Distance(p,
- Type<Span<const int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
+ p, Type<Span<const int8_t>>(L::Partial(5).Slice<0>(p)).data()));
EXPECT_EQ(
0,
Distance(
- p, Type<Span<const int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
+ p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
+ EXPECT_EQ(
+ 0,
+ Distance(
+ p, Type<Span<const int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
+ EXPECT_EQ(
+ 0,
+ Distance(
+ p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
+ EXPECT_EQ(
+ 4,
+ Distance(
+ p, Type<Span<const int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
+ EXPECT_EQ(
+ 0,
+ Distance(
+ p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
+ EXPECT_EQ(
+ 8,
+ Distance(
+ p, Type<Span<const int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
+ EXPECT_EQ(
+ 0,
+ Distance(
+ p,
+ Type<Span<const int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
EXPECT_EQ(
0,
Distance(
@@ -861,7 +899,8 @@
EXPECT_EQ(
0,
Distance(
- p, Type<Span<const int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
+ p,
+ Type<Span<const int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
EXPECT_EQ(
4,
Distance(
@@ -875,7 +914,8 @@
EXPECT_EQ(
0,
Distance(
- p, Type<Span<const int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
+ p,
+ Type<Span<const int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
EXPECT_EQ(
24,
Distance(
@@ -887,12 +927,14 @@
p,
Type<Span<const int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data()));
EXPECT_EQ(
- 0, Distance(p, Type<Span<const int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
+ 0,
+ Distance(p, Type<Span<const int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
EXPECT_EQ(
24,
Distance(p, Type<Span<const Int128>>(L(5, 3, 1).Slice<2>(p)).data()));
EXPECT_EQ(
- 8, Distance(p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
+ 8,
+ Distance(p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
}
}
@@ -903,98 +945,94 @@
EXPECT_EQ(
0,
Distance(
- p, Type<Span<const int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
+ p,
+ Type<Span<const int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
EXPECT_EQ(
0,
Distance(
- p, Type<Span<const int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
+ p,
+ Type<Span<const int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
EXPECT_EQ(
- 0, Distance(p, Type<Span<const int32_t>>(L(3).Slice<int32_t>(p)).data()));
+ 0,
+ Distance(p, Type<Span<const int32_t>>(L(3).Slice<int32_t>(p)).data()));
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(
- 0, Distance(
- p, Type<Span<const int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
- EXPECT_EQ(
- 0, Distance(
- p, Type<Span<const int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
- EXPECT_EQ(
- 0, Distance(
- p, Type<Span<const int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
- EXPECT_EQ(
0,
Distance(
- p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<int8_t>(p)).data()));
+ p,
+ Type<Span<const int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
EXPECT_EQ(
0,
Distance(
p,
- Type<Span<const int32_t>>(L::Partial(0, 0).Slice<int32_t>(p)).data()));
- EXPECT_EQ(
- 0,
- Distance(
- p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<int8_t>(p)).data()));
- EXPECT_EQ(
- 4,
- Distance(
- p,
- Type<Span<const int32_t>>(L::Partial(1, 0).Slice<int32_t>(p)).data()));
- EXPECT_EQ(
- 0,
- Distance(
- p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<int8_t>(p)).data()));
- EXPECT_EQ(
- 8,
- Distance(
- p,
- Type<Span<const int32_t>>(L::Partial(5, 3).Slice<int32_t>(p)).data()));
+ Type<Span<const int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
EXPECT_EQ(
0,
Distance(
p,
- Type<Span<const int8_t>>(L::Partial(0, 0, 0).Slice<int8_t>(p)).data()));
+ Type<Span<const int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
EXPECT_EQ(
0,
- Distance(p, Type<Span<const int32_t>>(L::Partial(0, 0, 0).Slice<int32_t>(p))
+ Distance(p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<int8_t>(p))
.data()));
+ EXPECT_EQ(0, Distance(p, Type<Span<const int32_t>>(
+ L::Partial(0, 0).Slice<int32_t>(p))
+ .data()));
+ EXPECT_EQ(
+ 0,
+ Distance(p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<int8_t>(p))
+ .data()));
+ EXPECT_EQ(4, Distance(p, Type<Span<const int32_t>>(
+ L::Partial(1, 0).Slice<int32_t>(p))
+ .data()));
+ EXPECT_EQ(
+ 0,
+ Distance(p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<int8_t>(p))
+ .data()));
+ EXPECT_EQ(8, Distance(p, Type<Span<const int32_t>>(
+ L::Partial(5, 3).Slice<int32_t>(p))
+ .data()));
+ EXPECT_EQ(0, Distance(p, Type<Span<const int8_t>>(
+ L::Partial(0, 0, 0).Slice<int8_t>(p))
+ .data()));
+ EXPECT_EQ(0, Distance(p, Type<Span<const int32_t>>(
+ L::Partial(0, 0, 0).Slice<int32_t>(p))
+ .data()));
EXPECT_EQ(0, Distance(p, Type<Span<const Int128>>(
L::Partial(0, 0, 0).Slice<Int128>(p))
.data()));
- EXPECT_EQ(
- 0,
- Distance(
- p,
- Type<Span<const int8_t>>(L::Partial(1, 0, 0).Slice<int8_t>(p)).data()));
- EXPECT_EQ(
- 4,
- Distance(p, Type<Span<const int32_t>>(L::Partial(1, 0, 0).Slice<int32_t>(p))
- .data()));
+ EXPECT_EQ(0, Distance(p, Type<Span<const int8_t>>(
+ L::Partial(1, 0, 0).Slice<int8_t>(p))
+ .data()));
+ EXPECT_EQ(4, Distance(p, Type<Span<const int32_t>>(
+ L::Partial(1, 0, 0).Slice<int32_t>(p))
+ .data()));
EXPECT_EQ(8, Distance(p, Type<Span<const Int128>>(
L::Partial(1, 0, 0).Slice<Int128>(p))
.data()));
- EXPECT_EQ(
- 0,
- Distance(
- p,
- Type<Span<const int8_t>>(L::Partial(5, 3, 1).Slice<int8_t>(p)).data()));
+ EXPECT_EQ(0, Distance(p, Type<Span<const int8_t>>(
+ L::Partial(5, 3, 1).Slice<int8_t>(p))
+ .data()));
EXPECT_EQ(24, Distance(p, Type<Span<const Int128>>(
L::Partial(5, 3, 1).Slice<Int128>(p))
.data()));
- EXPECT_EQ(
- 8,
- Distance(p, Type<Span<const int32_t>>(L::Partial(5, 3, 1).Slice<int32_t>(p))
- .data()));
+ EXPECT_EQ(8, Distance(p, Type<Span<const int32_t>>(
+ L::Partial(5, 3, 1).Slice<int32_t>(p))
+ .data()));
EXPECT_EQ(
0,
- Distance(p, Type<Span<const int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
+ Distance(p,
+ Type<Span<const int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
EXPECT_EQ(
24,
Distance(p,
Type<Span<const Int128>>(L(5, 3, 1).Slice<Int128>(p)).data()));
EXPECT_EQ(
- 8, Distance(
- p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
+ 8,
+ Distance(
+ p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
}
}
@@ -1002,18 +1040,19 @@
alignas(max_align_t) unsigned char p[100];
{
using L = Layout<int32_t>;
- EXPECT_EQ(0,
- Distance(p, Type<Span<int32_t>>(L::Partial(0).Slice<0>(p)).data()));
- EXPECT_EQ(0,
- Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
+ EXPECT_EQ(
+ 0, Distance(p, Type<Span<int32_t>>(L::Partial(0).Slice<0>(p)).data()));
+ EXPECT_EQ(
+ 0, Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
EXPECT_EQ(0, Distance(p, Type<Span<int32_t>>(L(3).Slice<0>(p)).data()));
}
{
using L = Layout<int32_t, int32_t>;
- EXPECT_EQ(0,
- Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
EXPECT_EQ(
- 0, Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
+ 0, Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
+ EXPECT_EQ(
+ 0,
+ Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
EXPECT_EQ(
12,
Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<1>(p)).data()));
@@ -1022,55 +1061,63 @@
}
{
using L = Layout<int8_t, int32_t, Int128>;
- EXPECT_EQ(0,
- Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<0>(p)).data()));
- EXPECT_EQ(0,
- Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<0>(p)).data()));
- EXPECT_EQ(0,
- Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<0>(p)).data()));
EXPECT_EQ(
- 0, Distance(p, Type<Span<int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
+ 0, Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<0>(p)).data()));
EXPECT_EQ(
- 0, Distance(p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
+ 0, Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<0>(p)).data()));
EXPECT_EQ(
- 0, Distance(p, Type<Span<int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
- EXPECT_EQ(
- 4, Distance(p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
- EXPECT_EQ(
- 0, Distance(p, Type<Span<int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
- EXPECT_EQ(
- 8, Distance(p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
+ 0, Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<0>(p)).data()));
EXPECT_EQ(
0,
- Distance(p, Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
+ Distance(p, Type<Span<int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
EXPECT_EQ(
0,
- Distance(p, Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<1>(p)).data()));
+ Distance(p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
+ EXPECT_EQ(
+ 0,
+ Distance(p, Type<Span<int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
+ EXPECT_EQ(
+ 4,
+ Distance(p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
+ EXPECT_EQ(
+ 0,
+ Distance(p, Type<Span<int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
+ EXPECT_EQ(
+ 8,
+ Distance(p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
+ EXPECT_EQ(
+ 0, Distance(
+ p, Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
+ EXPECT_EQ(
+ 0, Distance(
+ p, Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<1>(p)).data()));
EXPECT_EQ(
0, Distance(
p, Type<Span<Int128>>(L::Partial(0, 0, 0).Slice<2>(p)).data()));
EXPECT_EQ(
- 0,
- Distance(p, Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
+ 0, Distance(
+ p, Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
EXPECT_EQ(
- 4,
- Distance(p, Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<1>(p)).data()));
+ 4, Distance(
+ p, Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<1>(p)).data()));
EXPECT_EQ(
8, Distance(
p, Type<Span<Int128>>(L::Partial(1, 0, 0).Slice<2>(p)).data()));
EXPECT_EQ(
- 0,
- Distance(p, Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
+ 0, Distance(
+ p, Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
EXPECT_EQ(
24, Distance(
p, Type<Span<Int128>>(L::Partial(5, 3, 1).Slice<2>(p)).data()));
EXPECT_EQ(
- 8,
- Distance(p, Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data()));
- EXPECT_EQ(0, Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
+ 8, Distance(
+ p, Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data()));
+ EXPECT_EQ(0,
+ Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
EXPECT_EQ(24,
Distance(p, Type<Span<Int128>>(L(5, 3, 1).Slice<2>(p)).data()));
- EXPECT_EQ(8, Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
+ EXPECT_EQ(8,
+ Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
}
}
@@ -1079,66 +1126,84 @@
{
using L = Layout<int32_t>;
EXPECT_EQ(
- 0,
- Distance(p, Type<Span<int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
+ 0, Distance(
+ p, Type<Span<int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
EXPECT_EQ(
- 0,
- Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
- EXPECT_EQ(0, Distance(p, Type<Span<int32_t>>(L(3).Slice<int32_t>(p)).data()));
+ 0, Distance(
+ p, Type<Span<int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
+ EXPECT_EQ(0,
+ Distance(p, Type<Span<int32_t>>(L(3).Slice<int32_t>(p)).data()));
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(
- 0, Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
- EXPECT_EQ(
- 0, Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
- EXPECT_EQ(
- 0, Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
+ 0,
+ Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
EXPECT_EQ(
0,
- Distance(p, Type<Span<int8_t>>(L::Partial(0, 0).Slice<int8_t>(p)).data()));
- EXPECT_EQ(
- 0, Distance(
- p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<int32_t>(p)).data()));
+ Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
EXPECT_EQ(
0,
- Distance(p, Type<Span<int8_t>>(L::Partial(1, 0).Slice<int8_t>(p)).data()));
- EXPECT_EQ(
- 4, Distance(
- p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<int32_t>(p)).data()));
+ Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
EXPECT_EQ(
0,
- Distance(p, Type<Span<int8_t>>(L::Partial(5, 3).Slice<int8_t>(p)).data()));
- EXPECT_EQ(
- 8, Distance(
- p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<int32_t>(p)).data()));
- EXPECT_EQ(
- 0, Distance(
- p, Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<int8_t>(p)).data()));
+ Distance(p,
+ Type<Span<int8_t>>(L::Partial(0, 0).Slice<int8_t>(p)).data()));
EXPECT_EQ(
0,
Distance(
- p, Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<int32_t>(p)).data()));
+ p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<int32_t>(p)).data()));
+ EXPECT_EQ(
+ 0,
+ Distance(p,
+ Type<Span<int8_t>>(L::Partial(1, 0).Slice<int8_t>(p)).data()));
+ EXPECT_EQ(
+ 4,
+ Distance(
+ p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<int32_t>(p)).data()));
+ EXPECT_EQ(
+ 0,
+ Distance(p,
+ Type<Span<int8_t>>(L::Partial(5, 3).Slice<int8_t>(p)).data()));
+ EXPECT_EQ(
+ 8,
+ Distance(
+ p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<int32_t>(p)).data()));
+ EXPECT_EQ(
+ 0,
+ Distance(
+ p,
+ Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<int8_t>(p)).data()));
+ EXPECT_EQ(
+ 0,
+ Distance(
+ p,
+ Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<int32_t>(p)).data()));
EXPECT_EQ(
0,
Distance(
p,
Type<Span<Int128>>(L::Partial(0, 0, 0).Slice<Int128>(p)).data()));
EXPECT_EQ(
- 0, Distance(
- p, Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<int8_t>(p)).data()));
+ 0,
+ Distance(
+ p,
+ Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<int8_t>(p)).data()));
EXPECT_EQ(
4,
Distance(
- p, Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<int32_t>(p)).data()));
+ p,
+ Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<int32_t>(p)).data()));
EXPECT_EQ(
8,
Distance(
p,
Type<Span<Int128>>(L::Partial(1, 0, 0).Slice<Int128>(p)).data()));
EXPECT_EQ(
- 0, Distance(
- p, Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<int8_t>(p)).data()));
+ 0,
+ Distance(
+ p,
+ Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<int8_t>(p)).data()));
EXPECT_EQ(
24,
Distance(
@@ -1147,14 +1212,16 @@
EXPECT_EQ(
8,
Distance(
- p, Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<int32_t>(p)).data()));
- EXPECT_EQ(0,
- Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
+ p,
+ Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<int32_t>(p)).data()));
+ EXPECT_EQ(
+ 0, Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
EXPECT_EQ(
24,
Distance(p, Type<Span<Int128>>(L(5, 3, 1).Slice<Int128>(p)).data()));
EXPECT_EQ(
- 8, Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
+ 8,
+ Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
}
}
@@ -1253,17 +1320,17 @@
}
{
const auto x = L::Partial(1, 2, 3);
- EXPECT_THAT(
- (Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(x.Slices(p))),
- Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
- IsSameSlice(x.Slice<2>(p))));
+ EXPECT_THAT((Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(
+ x.Slices(p))),
+ Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
+ IsSameSlice(x.Slice<2>(p))));
}
{
const L x(1, 2, 3);
- EXPECT_THAT(
- (Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(x.Slices(p))),
- Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
- IsSameSlice(x.Slice<2>(p))));
+ EXPECT_THAT((Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(
+ x.Slices(p))),
+ Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
+ IsSameSlice(x.Slice<2>(p))));
}
}
@@ -1313,7 +1380,7 @@
};
void ExpectRegionPoisoned(const unsigned char* p, size_t n, bool poisoned) {
-#ifdef ADDRESS_SANITIZER
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
for (size_t i = 0; i != n; ++i) {
EXPECT_EQ(poisoned, __asan_address_is_poisoned(p + i));
}
@@ -1395,7 +1462,8 @@
x.DebugString());
}
{
- constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3);
+ constexpr auto x =
+ Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3);
EXPECT_EQ(
"@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; "
"@16" +
@@ -1403,7 +1471,8 @@
x.DebugString());
}
{
- constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3, 4);
+ constexpr auto x =
+ Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3, 4);
EXPECT_EQ(
"@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; "
"@16" +
@@ -1562,4 +1631,5 @@
} // namespace
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/container/internal/node_hash_policy.h b/third_party/abseil/absl/container/internal/node_hash_policy.h
index 19b4fc0..4617162 100644
--- a/third_party/abseil/absl/container/internal/node_hash_policy.h
+++ b/third_party/abseil/absl/container/internal/node_hash_policy.h
@@ -39,7 +39,10 @@
#include <type_traits>
#include <utility>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
template <class Reference, class Policy>
@@ -83,6 +86,7 @@
};
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_NODE_HASH_POLICY_H_
diff --git a/third_party/abseil/absl/container/internal/node_hash_policy_test.cc b/third_party/abseil/absl/container/internal/node_hash_policy_test.cc
index f1d3ec3..84aabba 100644
--- a/third_party/abseil/absl/container/internal/node_hash_policy_test.cc
+++ b/third_party/abseil/absl/container/internal/node_hash_policy_test.cc
@@ -21,6 +21,7 @@
#include "absl/container/internal/hash_policy_traits.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace {
@@ -64,4 +65,5 @@
} // namespace
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/container/internal/raw_hash_map.h b/third_party/abseil/absl/container/internal/raw_hash_map.h
index 7dad120..0a02757 100644
--- a/third_party/abseil/absl/container/internal/raw_hash_map.h
+++ b/third_party/abseil/absl/container/internal/raw_hash_map.h
@@ -24,6 +24,7 @@
#include "absl/container/internal/raw_hash_set.h" // IWYU pragma: export
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
template <class Policy, class Hash, class Eq, class Alloc>
@@ -190,6 +191,7 @@
};
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_RAW_HASH_MAP_H_
diff --git a/third_party/abseil/absl/container/internal/raw_hash_set.cc b/third_party/abseil/absl/container/internal/raw_hash_set.cc
index ac2d10a..bfef071 100644
--- a/third_party/abseil/absl/container/internal/raw_hash_set.cc
+++ b/third_party/abseil/absl/container/internal/raw_hash_set.cc
@@ -20,13 +20,14 @@
#include "absl/base/config.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
constexpr size_t Group::kWidth;
// Returns "random" seed.
inline size_t RandomSeed() {
-#if ABSL_HAVE_THREAD_LOCAL
+#ifdef ABSL_HAVE_THREAD_LOCAL
static thread_local size_t counter = 0;
size_t value = ++counter;
#else // ABSL_HAVE_THREAD_LOCAL
@@ -42,5 +43,19 @@
return (H1(hash, ctrl) ^ RandomSeed()) % 13 > 6;
}
+void ConvertDeletedToEmptyAndFullToDeleted(
+ ctrl_t* ctrl, size_t capacity) {
+ assert(ctrl[capacity] == kSentinel);
+ assert(IsValidCapacity(capacity));
+ for (ctrl_t* pos = ctrl; pos != ctrl + capacity + 1; pos += Group::kWidth) {
+ Group{pos}.ConvertSpecialToEmptyAndFullToDeleted(pos);
+ }
+ // Copy the cloned ctrl bytes.
+ std::memcpy(ctrl + capacity + 1, ctrl, Group::kWidth);
+ ctrl[capacity] = kSentinel;
+}
+
+
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/container/internal/raw_hash_set.h b/third_party/abseil/absl/container/internal/raw_hash_set.h
index 2e6f4dd..74b2ef4 100644
--- a/third_party/abseil/absl/container/internal/raw_hash_set.h
+++ b/third_party/abseil/absl/container/internal/raw_hash_set.h
@@ -102,8 +102,8 @@
#include <type_traits>
#include <utility>
-#include "absl/base/internal/bits.h"
#include "absl/base/internal/endian.h"
+#include "absl/base/optimization.h"
#include "absl/base/port.h"
#include "absl/container/internal/common.h"
#include "absl/container/internal/compressed_tuple.h"
@@ -115,11 +115,23 @@
#include "absl/container/internal/layout.h"
#include "absl/memory/memory.h"
#include "absl/meta/type_traits.h"
+#include "absl/numeric/bits.h"
#include "absl/utility/utility.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
+template <typename AllocType>
+void SwapAlloc(AllocType& lhs, AllocType& rhs,
+ std::true_type /* propagate_on_container_swap */) {
+ using std::swap;
+ swap(lhs, rhs);
+}
+template <typename AllocType>
+void SwapAlloc(AllocType& /*lhs*/, AllocType& /*rhs*/,
+ std::false_type /* propagate_on_container_swap */) {}
+
template <size_t Width>
class probe_seq {
public:
@@ -167,24 +179,19 @@
// TODO(alkis): Switch to std::is_nothrow_swappable when gcc/clang supports it.
template <class T>
-constexpr bool IsNoThrowSwappable() {
+constexpr bool IsNoThrowSwappable(std::true_type = {} /* is_swappable */) {
using std::swap;
return noexcept(swap(std::declval<T&>(), std::declval<T&>()));
}
-
-template <typename T>
-int TrailingZeros(T x) {
- return sizeof(T) == 8 ? base_internal::CountTrailingZerosNonZero64(
- static_cast<uint64_t>(x))
- : base_internal::CountTrailingZerosNonZero32(
- static_cast<uint32_t>(x));
+template <class T>
+constexpr bool IsNoThrowSwappable(std::false_type /* is_swappable */) {
+ return false;
}
template <typename T>
-int LeadingZeros(T x) {
- return sizeof(T) == 8
- ? base_internal::CountLeadingZeros64(static_cast<uint64_t>(x))
- : base_internal::CountLeadingZeros32(static_cast<uint32_t>(x));
+uint32_t TrailingZeros(T x) {
+ ABSL_INTERNAL_ASSUME(x != 0);
+ return countr_zero(x);
}
// An abstraction over a bitmask. It provides an easy way to iterate through the
@@ -214,26 +221,24 @@
}
explicit operator bool() const { return mask_ != 0; }
int operator*() const { return LowestBitSet(); }
- int LowestBitSet() const {
+ uint32_t LowestBitSet() const {
return container_internal::TrailingZeros(mask_) >> Shift;
}
- int HighestBitSet() const {
- return (sizeof(T) * CHAR_BIT - container_internal::LeadingZeros(mask_) -
- 1) >>
- Shift;
+ uint32_t HighestBitSet() const {
+ return static_cast<uint32_t>((bit_width(mask_) - 1) >> Shift);
}
BitMask begin() const { return *this; }
BitMask end() const { return BitMask(0); }
- int TrailingZeros() const {
+ uint32_t TrailingZeros() const {
return container_internal::TrailingZeros(mask_) >> Shift;
}
- int LeadingZeros() const {
+ uint32_t LeadingZeros() const {
constexpr int total_significant_bits = SignificantBits << Shift;
constexpr int extra_bits = sizeof(T) * 8 - total_significant_bits;
- return container_internal::LeadingZeros(mask_ << extra_bits) >> Shift;
+ return countl_zero(mask_ << extra_bits) >> Shift;
}
private:
@@ -311,7 +316,7 @@
inline bool IsDeleted(ctrl_t c) { return c == kDeleted; }
inline bool IsEmptyOrDeleted(ctrl_t c) { return c < kSentinel; }
-#if SWISSTABLE_HAVE_SSE2
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
// https://github.com/abseil/abseil-cpp/issues/209
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87853
@@ -345,7 +350,7 @@
// Returns a bitmask representing the positions of empty slots.
BitMask<uint32_t, kWidth> MatchEmpty() const {
-#if SWISSTABLE_HAVE_SSSE3
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3
// This only works because kEmpty is -128.
return BitMask<uint32_t, kWidth>(
_mm_movemask_epi8(_mm_sign_epi8(ctrl, ctrl)));
@@ -364,14 +369,14 @@
// Returns the number of trailing empty or deleted elements in the group.
uint32_t CountLeadingEmptyOrDeleted() const {
auto special = _mm_set1_epi8(kSentinel);
- return TrailingZeros(
- _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)) + 1);
+ return TrailingZeros(static_cast<uint32_t>(
+ _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)) + 1));
}
void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const {
auto msbs = _mm_set1_epi8(static_cast<char>(-128));
auto x126 = _mm_set1_epi8(126);
-#if SWISSTABLE_HAVE_SSSE3
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3
auto res = _mm_or_si128(_mm_shuffle_epi8(x126, ctrl), msbs);
#else
auto zero = _mm_setzero_si128();
@@ -383,7 +388,7 @@
__m128i ctrl;
};
-#endif // SWISSTABLE_HAVE_SSE2
+#endif // ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
struct GroupPortableImpl {
static constexpr size_t kWidth = 8;
@@ -437,7 +442,7 @@
uint64_t ctrl;
};
-#if SWISSTABLE_HAVE_SSE2
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
using Group = GroupSse2Impl;
#else
using Group = GroupPortableImpl;
@@ -456,21 +461,11 @@
// DELETED -> EMPTY
// EMPTY -> EMPTY
// FULL -> DELETED
-inline void ConvertDeletedToEmptyAndFullToDeleted(
- ctrl_t* ctrl, size_t capacity) {
- assert(ctrl[capacity] == kSentinel);
- assert(IsValidCapacity(capacity));
- for (ctrl_t* pos = ctrl; pos != ctrl + capacity + 1; pos += Group::kWidth) {
- Group{pos}.ConvertSpecialToEmptyAndFullToDeleted(pos);
- }
- // Copy the cloned ctrl bytes.
- std::memcpy(ctrl + capacity + 1, ctrl, Group::kWidth);
- ctrl[capacity] = kSentinel;
-}
+void ConvertDeletedToEmptyAndFullToDeleted(ctrl_t* ctrl, size_t capacity);
// Rounds up the capacity to the next power of 2 minus 1, with a minimum of 1.
inline size_t NormalizeCapacity(size_t n) {
- return n ? ~size_t{} >> LeadingZeros(n) : 1;
+ return n ? ~size_t{} >> countl_zero(n) : 1;
}
// We use 7/8th as maximum load factor.
@@ -495,6 +490,76 @@
return growth + static_cast<size_t>((static_cast<int64_t>(growth) - 1) / 7);
}
+inline void AssertIsFull(ctrl_t* ctrl) {
+ ABSL_HARDENING_ASSERT((ctrl != nullptr && IsFull(*ctrl)) &&
+ "Invalid operation on iterator. The element might have "
+ "been erased, or the table might have rehashed.");
+}
+
+inline void AssertIsValid(ctrl_t* ctrl) {
+ ABSL_HARDENING_ASSERT((ctrl == nullptr || IsFull(*ctrl)) &&
+ "Invalid operation on iterator. The element might have "
+ "been erased, or the table might have rehashed.");
+}
+
+struct FindInfo {
+ size_t offset;
+ size_t probe_length;
+};
+
+// The representation of the object has two modes:
+// - small: For capacities < kWidth-1
+// - large: For the rest.
+//
+// Differences:
+// - In small mode we are able to use the whole capacity. The extra control
+// bytes give us at least one "empty" control byte to stop the iteration.
+// This is important to make 1 a valid capacity.
+//
+// - In small mode only the first `capacity()` control bytes after the
+// sentinel are valid. The rest contain dummy kEmpty values that do not
+// represent a real slot. This is important to take into account on
+// find_first_non_full(), where we never try ShouldInsertBackwards() for
+// small tables.
+inline bool is_small(size_t capacity) { return capacity < Group::kWidth - 1; }
+
+inline probe_seq<Group::kWidth> probe(ctrl_t* ctrl, size_t hash,
+ size_t capacity) {
+ return probe_seq<Group::kWidth>(H1(hash, ctrl), capacity);
+}
+
+// Probes the raw_hash_set with the probe sequence for hash and returns the
+// pointer to the first empty or deleted slot.
+// NOTE: this function must work with tables having both kEmpty and kDelete
+// in one group. Such tables appears during drop_deletes_without_resize.
+//
+// This function is very useful when insertions happen and:
+// - the input is already a set
+// - there are enough slots
+// - the element with the hash is not in the table
+inline FindInfo find_first_non_full(ctrl_t* ctrl, size_t hash,
+ size_t capacity) {
+ auto seq = probe(ctrl, hash, capacity);
+ while (true) {
+ Group g{ctrl + seq.offset()};
+ auto mask = g.MatchEmptyOrDeleted();
+ if (mask) {
+#if !defined(NDEBUG)
+ // We want to add entropy even when ASLR is not enabled.
+ // In debug build we will randomly insert in either the front or back of
+ // the group.
+ // TODO(kfm,sbenza): revisit after we do unconditional mixing
+ if (!is_small(capacity) && ShouldInsertBackwards(hash, ctrl)) {
+ return {seq.offset(mask.HighestBitSet()), seq.index()};
+ }
+#endif
+ return {seq.offset(mask.LowestBitSet()), seq.index()};
+ }
+ seq.next();
+ assert(seq.index() < capacity && "full table!");
+ }
+}
+
// Policy: a policy defines how to perform different operations on
// the slots of the hashtable (see hash_policy_traits.h for the full interface
// of policy).
@@ -509,7 +574,8 @@
// if they are equal, false if they are not. If two keys compare equal, then
// their hash values as defined by Hash MUST be equal.
//
-// Allocator: an Allocator [https://devdocs.io/cpp/concept/allocator] with which
+// Allocator: an Allocator
+// [https://en.cppreference.com/w/cpp/named_req/Allocator] with which
// the storage of the hashtable will be allocated and the elements will be
// constructed and destroyed.
template <class Policy, class Hash, class Eq, class Alloc>
@@ -614,13 +680,17 @@
iterator() {}
// PRECONDITION: not an end() iterator.
- reference operator*() const { return PolicyTraits::element(slot_); }
+ reference operator*() const {
+ AssertIsFull(ctrl_);
+ return PolicyTraits::element(slot_);
+ }
// PRECONDITION: not an end() iterator.
pointer operator->() const { return &operator*(); }
// PRECONDITION: not an end() iterator.
iterator& operator++() {
+ AssertIsFull(ctrl_);
++ctrl_;
++slot_;
skip_empty_or_deleted();
@@ -634,6 +704,8 @@
}
friend bool operator==(const iterator& a, const iterator& b) {
+ AssertIsValid(a.ctrl_);
+ AssertIsValid(b.ctrl_);
return a.ctrl_ == b.ctrl_;
}
friend bool operator!=(const iterator& a, const iterator& b) {
@@ -641,23 +713,23 @@
}
private:
- iterator(ctrl_t* ctrl) : ctrl_(ctrl) {} // for end()
- iterator(ctrl_t* ctrl, slot_type* slot) : ctrl_(ctrl), slot_(slot) {}
+ iterator(ctrl_t* ctrl, slot_type* slot) : ctrl_(ctrl), slot_(slot) {
+ // This assumption helps the compiler know that any non-end iterator is
+ // not equal to any end iterator.
+ ABSL_INTERNAL_ASSUME(ctrl != nullptr);
+ }
void skip_empty_or_deleted() {
while (IsEmptyOrDeleted(*ctrl_)) {
- // ctrl is not necessarily aligned to Group::kWidth. It is also likely
- // to read past the space for ctrl bytes and into slots. This is ok
- // because ctrl has sizeof() == 1 and slot has sizeof() >= 1 so there
- // is no way to read outside the combined slot array.
uint32_t shift = Group{ctrl_}.CountLeadingEmptyOrDeleted();
ctrl_ += shift;
slot_ += shift;
}
+ if (ABSL_PREDICT_FALSE(*ctrl_ == kSentinel)) ctrl_ = nullptr;
}
ctrl_t* ctrl_ = nullptr;
- // To avoid uninitialized member warnigs, put slot_ in an anonymous union.
+ // To avoid uninitialized member warnings, put slot_ in an anonymous union.
// The member is not initialized on singleton and end iterators.
union {
slot_type* slot_;
@@ -715,7 +787,6 @@
: ctrl_(EmptyGroup()), settings_(0, hash, eq, alloc) {
if (bucket_count) {
capacity_ = NormalizeCapacity(bucket_count);
- reset_growth_left();
initialize_slots();
}
}
@@ -821,7 +892,7 @@
// than a full `insert`.
for (const auto& v : that) {
const size_t hash = PolicyTraits::apply(HashElement{hash_ref()}, v);
- auto target = find_first_non_full(hash);
+ auto target = find_first_non_full(ctrl_, hash, capacity_);
set_ctrl(target.offset, H2(hash));
emplace_at(target.offset, v);
infoz_.RecordInsert(hash, target.probe_length);
@@ -895,12 +966,12 @@
it.skip_empty_or_deleted();
return it;
}
- iterator end() { return {ctrl_ + capacity_}; }
+ iterator end() { return {}; }
const_iterator begin() const {
return const_cast<raw_hash_set*>(this)->begin();
}
- const_iterator end() const { return const_cast<raw_hash_set*>(this)->end(); }
+ const_iterator end() const { return {}; }
const_iterator cbegin() const { return begin(); }
const_iterator cend() const { return end(); }
@@ -938,8 +1009,11 @@
//
// flat_hash_map<std::string, int> m;
// m.insert(std::make_pair("abc", 42));
+ // TODO(cheshire): A type alias T2 is introduced as a workaround for the nvcc
+ // bug.
template <class T, RequiresInsertable<T> = 0,
- typename std::enable_if<IsDecomposable<T>::value, int>::type = 0,
+ class T2 = T,
+ typename std::enable_if<IsDecomposable<T2>::value, int>::type = 0,
T* = nullptr>
std::pair<iterator, bool> insert(T&& value) {
return emplace(std::forward<T>(value));
@@ -975,8 +1049,10 @@
return emplace(std::move(value));
}
- template <class T, RequiresInsertable<T> = 0,
- typename std::enable_if<IsDecomposable<T>::value, int>::type = 0,
+ // TODO(cheshire): A type alias T2 is introduced as a workaround for the nvcc
+ // bug.
+ template <class T, RequiresInsertable<T> = 0, class T2 = T,
+ typename std::enable_if<IsDecomposable<T2>::value, int>::type = 0,
T* = nullptr>
iterator insert(const_iterator, T&& value) {
return insert(std::forward<T>(value)).first;
@@ -998,7 +1074,7 @@
template <class InputIt>
void insert(InputIt first, InputIt last) {
- for (; first != last; ++first) insert(*first);
+ for (; first != last; ++first) emplace(*first);
}
template <class T, RequiresNotInit<T> = 0, RequiresInsertable<const T&> = 0>
@@ -1025,7 +1101,9 @@
}
iterator insert(const_iterator, node_type&& node) {
- return insert(std::move(node)).first;
+ auto res = insert(std::move(node));
+ node = std::move(res.node);
+ return res.position;
}
// This overload kicks in if we can deduce the key from args. This enables us
@@ -1050,8 +1128,7 @@
template <class... Args, typename std::enable_if<
!IsDecomposable<Args...>::value, int>::type = 0>
std::pair<iterator, bool> emplace(Args&&... args) {
- typename std::aligned_storage<sizeof(slot_type), alignof(slot_type)>::type
- raw;
+ alignas(slot_type) unsigned char raw[sizeof(slot_type)];
slot_type* slot = reinterpret_cast<slot_type*>(&raw);
PolicyTraits::construct(&alloc_ref(), slot, std::forward<Args>(args)...);
@@ -1067,10 +1144,15 @@
// Extension API: support for lazy emplace.
//
// Looks up key in the table. If found, returns the iterator to the element.
- // Otherwise calls f with one argument of type raw_hash_set::constructor. f
- // MUST call raw_hash_set::constructor with arguments as if a
- // raw_hash_set::value_type is constructed, otherwise the behavior is
- // undefined.
+ // Otherwise calls `f` with one argument of type `raw_hash_set::constructor`.
+ //
+ // `f` must abide by several restrictions:
+ // - it MUST call `raw_hash_set::constructor` with arguments as if a
+ // `raw_hash_set::value_type` is constructed,
+ // - it MUST NOT access the container before the call to
+ // `raw_hash_set::constructor`, and
+ // - it MUST NOT erase the lazily emplaced element.
+ // Doing any of these is undefined behavior.
//
// For example:
//
@@ -1150,7 +1232,7 @@
// This overload is necessary because otherwise erase<K>(const K&) would be
// a better match if non-const iterator is passed as an argument.
void erase(iterator it) {
- assert(it != end());
+ AssertIsFull(it.ctrl_);
PolicyTraits::destroy(&alloc_ref(), it.slot_);
erase_meta_only(it);
}
@@ -1167,12 +1249,14 @@
template <typename H, typename E>
void merge(raw_hash_set<Policy, H, E, Alloc>& src) { // NOLINT
assert(this != &src);
- for (auto it = src.begin(), e = src.end(); it != e; ++it) {
+ for (auto it = src.begin(), e = src.end(); it != e;) {
+ auto next = std::next(it);
if (PolicyTraits::apply(InsertSlot<false>{*this, std::move(*it.slot_)},
PolicyTraits::element(it.slot_))
.second) {
src.erase_meta_only(it);
}
+ it = next;
}
}
@@ -1182,6 +1266,7 @@
}
node_type extract(const_iterator position) {
+ AssertIsFull(position.inner_.ctrl_);
auto node =
CommonAccess::Transfer<node_type>(alloc_ref(), position.inner_.slot_);
erase_meta_only(position);
@@ -1198,8 +1283,8 @@
void swap(raw_hash_set& that) noexcept(
IsNoThrowSwappable<hasher>() && IsNoThrowSwappable<key_equal>() &&
- (!AllocTraits::propagate_on_container_swap::value ||
- IsNoThrowSwappable<allocator_type>())) {
+ IsNoThrowSwappable<allocator_type>(
+ typename AllocTraits::propagate_on_container_swap{})) {
using std::swap;
swap(ctrl_, that.ctrl_);
swap(slots_, that.slots_);
@@ -1209,12 +1294,8 @@
swap(hash_ref(), that.hash_ref());
swap(eq_ref(), that.eq_ref());
swap(infoz_, that.infoz_);
- if (AllocTraits::propagate_on_container_swap::value) {
- swap(alloc_ref(), that.alloc_ref());
- } else {
- // If the allocators do not compare equal it is officially undefined
- // behavior. We choose to do nothing.
- }
+ SwapAlloc(alloc_ref(), that.alloc_ref(),
+ typename AllocTraits::propagate_on_container_swap{});
}
void rehash(size_t n) {
@@ -1233,7 +1314,12 @@
}
}
- void reserve(size_t n) { rehash(GrowthToLowerboundCapacity(n)); }
+ void reserve(size_t n) {
+ size_t m = GrowthToLowerboundCapacity(n);
+ if (m > capacity_) {
+ resize(NormalizeCapacity(m));
+ }
+ }
// Extension API: support for heterogeneous keys.
//
@@ -1258,7 +1344,7 @@
void prefetch(const key_arg<K>& key) const {
(void)key;
#if defined(__GNUC__)
- auto seq = probe(hash_ref()(key));
+ auto seq = probe(ctrl_, hash_ref()(key), capacity_);
__builtin_prefetch(static_cast<const void*>(ctrl_ + seq.offset()));
__builtin_prefetch(static_cast<const void*>(slots_ + seq.offset()));
#endif // __GNUC__
@@ -1273,7 +1359,7 @@
// called heterogeneous key support.
template <class K = key_type>
iterator find(const key_arg<K>& key, size_t hash) {
- auto seq = probe(hash);
+ auto seq = probe(ctrl_, hash, capacity_);
while (true) {
Group g{ctrl_ + seq.offset()};
for (int i : g.Match(H2(hash))) {
@@ -1284,6 +1370,7 @@
}
if (ABSL_PREDICT_TRUE(g.MatchEmpty())) return end();
seq.next();
+ assert(seq.index() < capacity_ && "full table!");
}
}
template <class K = key_type>
@@ -1494,7 +1581,7 @@
if (IsFull(old_ctrl[i])) {
size_t hash = PolicyTraits::apply(HashElement{hash_ref()},
PolicyTraits::element(old_slots + i));
- auto target = find_first_non_full(hash);
+ auto target = find_first_non_full(ctrl_, hash, capacity_);
size_t new_i = target.offset;
total_probe_length += target.probe_length;
set_ctrl(new_i, H2(hash));
@@ -1513,7 +1600,7 @@
void drop_deletes_without_resize() ABSL_ATTRIBUTE_NOINLINE {
assert(IsValidCapacity(capacity_));
- assert(!is_small());
+ assert(!is_small(capacity_));
// Algorithm:
// - mark all DELETED slots as EMPTY
// - mark all FULL slots as DELETED
@@ -1531,15 +1618,14 @@
// mark target as FULL
// repeat procedure for current slot with moved from element (target)
ConvertDeletedToEmptyAndFullToDeleted(ctrl_, capacity_);
- typename std::aligned_storage<sizeof(slot_type), alignof(slot_type)>::type
- raw;
+ alignas(slot_type) unsigned char raw[sizeof(slot_type)];
size_t total_probe_length = 0;
slot_type* slot = reinterpret_cast<slot_type*>(&raw);
for (size_t i = 0; i != capacity_; ++i) {
if (!IsDeleted(ctrl_[i])) continue;
size_t hash = PolicyTraits::apply(HashElement{hash_ref()},
PolicyTraits::element(slots_ + i));
- auto target = find_first_non_full(hash);
+ auto target = find_first_non_full(ctrl_, hash, capacity_);
size_t new_i = target.offset;
total_probe_length += target.probe_length;
@@ -1547,7 +1633,8 @@
// If they do, we don't need to move the object as it falls already in the
// best probe we can.
const auto probe_index = [&](size_t pos) {
- return ((pos - probe(hash).offset()) & capacity_) / Group::kWidth;
+ return ((pos - probe(ctrl_, hash, capacity_).offset()) & capacity_) /
+ Group::kWidth;
};
// Element doesn't move.
@@ -1591,7 +1678,7 @@
bool has_element(const value_type& elem) const {
size_t hash = PolicyTraits::apply(HashElement{hash_ref()}, elem);
- auto seq = probe(hash);
+ auto seq = probe(ctrl_, hash, capacity_);
while (true) {
Group g{ctrl_ + seq.offset()};
for (int i : g.Match(H2(hash))) {
@@ -1606,41 +1693,6 @@
return false;
}
- // Probes the raw_hash_set with the probe sequence for hash and returns the
- // pointer to the first empty or deleted slot.
- // NOTE: this function must work with tables having both kEmpty and kDelete
- // in one group. Such tables appears during drop_deletes_without_resize.
- //
- // This function is very useful when insertions happen and:
- // - the input is already a set
- // - there are enough slots
- // - the element with the hash is not in the table
- struct FindInfo {
- size_t offset;
- size_t probe_length;
- };
- FindInfo find_first_non_full(size_t hash) {
- auto seq = probe(hash);
- while (true) {
- Group g{ctrl_ + seq.offset()};
- auto mask = g.MatchEmptyOrDeleted();
- if (mask) {
-#if !defined(NDEBUG)
- // We want to add entropy even when ASLR is not enabled.
- // In debug build we will randomly insert in either the front or back of
- // the group.
- // TODO(kfm,sbenza): revisit after we do unconditional mixing
- if (!is_small() && ShouldInsertBackwards(hash, ctrl_)) {
- return {seq.offset(mask.HighestBitSet()), seq.index()};
- }
-#endif
- return {seq.offset(mask.LowestBitSet()), seq.index()};
- }
- assert(seq.index() < capacity_ && "full table!");
- seq.next();
- }
- }
-
// TODO(alkis): Optimize this assuming *this and that don't overlap.
raw_hash_set& move_assign(raw_hash_set&& that, std::true_type) {
raw_hash_set tmp(std::move(that));
@@ -1657,7 +1709,7 @@
template <class K>
std::pair<size_t, bool> find_or_prepare_insert(const K& key) {
auto hash = hash_ref()(key);
- auto seq = probe(hash);
+ auto seq = probe(ctrl_, hash, capacity_);
while (true) {
Group g{ctrl_ + seq.offset()};
for (int i : g.Match(H2(hash))) {
@@ -1668,16 +1720,17 @@
}
if (ABSL_PREDICT_TRUE(g.MatchEmpty())) break;
seq.next();
+ assert(seq.index() < capacity_ && "full table!");
}
return {prepare_insert(hash), true};
}
size_t prepare_insert(size_t hash) ABSL_ATTRIBUTE_NOINLINE {
- auto target = find_first_non_full(hash);
+ auto target = find_first_non_full(ctrl_, hash, capacity_);
if (ABSL_PREDICT_FALSE(growth_left() == 0 &&
!IsDeleted(ctrl_[target.offset]))) {
rehash_and_grow_if_necessary();
- target = find_first_non_full(hash);
+ target = find_first_non_full(ctrl_, hash, capacity_);
}
++size_;
growth_left() -= IsEmpty(ctrl_[target.offset]);
@@ -1710,10 +1763,6 @@
private:
friend struct RawHashSetTestOnlyAccess;
- probe_seq<Group::kWidth> probe(size_t hash) const {
- return probe_seq<Group::kWidth>(H1(hash, ctrl_), capacity_);
- }
-
// Reset all ctrl bytes back to kEmpty, except the sentinel.
void reset_ctrl() {
std::memset(ctrl_, kEmpty, capacity_ + Group::kWidth);
@@ -1743,22 +1792,6 @@
size_t& growth_left() { return settings_.template get<0>(); }
- // The representation of the object has two modes:
- // - small: For capacities < kWidth-1
- // - large: For the rest.
- //
- // Differences:
- // - In small mode we are able to use the whole capacity. The extra control
- // bytes give us at least one "empty" control byte to stop the iteration.
- // This is important to make 1 a valid capacity.
- //
- // - In small mode only the first `capacity()` control bytes after the
- // sentinel are valid. The rest contain dummy kEmpty values that do not
- // represent a real slot. This is important to take into account on
- // find_first_non_full(), where we never try ShouldInsertBackwards() for
- // small tables.
- bool is_small() const { return capacity_ < Group::kWidth - 1; }
-
hasher& hash_ref() { return settings_.template get<1>(); }
const hasher& hash_ref() const { return settings_.template get<1>(); }
key_equal& eq_ref() { return settings_.template get<2>(); }
@@ -1781,6 +1814,17 @@
settings_{0, hasher{}, key_equal{}, allocator_type{}};
};
+// Erases all elements that satisfy the predicate `pred` from the container `c`.
+template <typename P, typename H, typename E, typename A, typename Predicate>
+void EraseIf(Predicate pred, raw_hash_set<P, H, E, A>* c) {
+ for (auto it = c->begin(), last = c->end(); it != last;) {
+ auto copy_it = it++;
+ if (pred(*copy_it)) {
+ c->erase(copy_it);
+ }
+ }
+}
+
namespace hashtable_debug_internal {
template <typename Set>
struct HashtableDebugAccess<Set, absl::void_t<typename Set::raw_hash_set>> {
@@ -1791,7 +1835,7 @@
const typename Set::key_type& key) {
size_t num_probes = 0;
size_t hash = set.hash_ref()(key);
- auto seq = set.probe(hash);
+ auto seq = probe(set.ctrl_, hash, set.capacity_);
while (true) {
container_internal::Group g{set.ctrl_ + seq.offset()};
for (int i : g.Match(container_internal::H2(hash))) {
@@ -1842,6 +1886,7 @@
} // namespace hashtable_debug_internal
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_
diff --git a/third_party/abseil/absl/container/internal/raw_hash_set_allocator_test.cc b/third_party/abseil/absl/container/internal/raw_hash_set_allocator_test.cc
index a5eff0b..e73f53f 100644
--- a/third_party/abseil/absl/container/internal/raw_hash_set_allocator_test.cc
+++ b/third_party/abseil/absl/container/internal/raw_hash_set_allocator_test.cc
@@ -20,6 +20,7 @@
#include "absl/container/internal/tracked.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace {
@@ -423,6 +424,82 @@
EXPECT_EQ(0, it->num_copies());
}
+// This allocator is similar to std::pmr::polymorphic_allocator.
+// Note the disabled assignment.
+template <class T>
+class PAlloc {
+ template <class>
+ friend class PAlloc;
+
+ public:
+ // types
+ using value_type = T;
+
+ // traits
+ using propagate_on_container_swap = std::false_type;
+
+ PAlloc() noexcept = default;
+ explicit PAlloc(size_t id) noexcept : id_(id) {}
+ PAlloc(const PAlloc&) noexcept = default;
+ PAlloc& operator=(const PAlloc&) noexcept = delete;
+
+ template <class U>
+ PAlloc(const PAlloc<U>& that) noexcept : id_(that.id_) {} // NOLINT
+
+ template <class U>
+ struct rebind {
+ using other = PAlloc<U>;
+ };
+
+ constexpr PAlloc select_on_container_copy_construction() const { return {}; }
+
+ // public member functions
+ T* allocate(size_t) { return new T; }
+ void deallocate(T* p, size_t) { delete p; }
+
+ friend bool operator==(const PAlloc& a, const PAlloc& b) {
+ return a.id_ == b.id_;
+ }
+ friend bool operator!=(const PAlloc& a, const PAlloc& b) { return !(a == b); }
+
+ private:
+ size_t id_ = std::numeric_limits<size_t>::max();
+};
+
+// This doesn't compile with GCC 5.4 and 5.5 due to a bug in noexcept handing.
+#if !defined(__GNUC__) || __GNUC__ != 5 || (__GNUC_MINOR__ != 4 && \
+ __GNUC_MINOR__ != 5)
+TEST(NoPropagateOn, Swap) {
+ using PA = PAlloc<char>;
+ using Table = raw_hash_set<Policy, Identity, std::equal_to<int32_t>, PA>;
+
+ Table t1(PA{1}), t2(PA{2});
+ swap(t1, t2);
+ EXPECT_EQ(t1.get_allocator(), PA(1));
+ EXPECT_EQ(t2.get_allocator(), PA(2));
+}
+#endif
+
+TEST(NoPropagateOn, CopyConstruct) {
+ using PA = PAlloc<char>;
+ using Table = raw_hash_set<Policy, Identity, std::equal_to<int32_t>, PA>;
+
+ Table t1(PA{1}), t2(t1);
+ EXPECT_EQ(t1.get_allocator(), PA(1));
+ EXPECT_EQ(t2.get_allocator(), PA());
+}
+
+TEST(NoPropagateOn, Assignment) {
+ using PA = PAlloc<char>;
+ using Table = raw_hash_set<Policy, Identity, std::equal_to<int32_t>, PA>;
+
+ Table t1(PA{1}), t2(PA{2});
+ t1 = t2;
+ EXPECT_EQ(t1.get_allocator(), PA(1));
+ EXPECT_EQ(t2.get_allocator(), PA(2));
+}
+
} // namespace
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/container/internal/raw_hash_set_benchmark.cc b/third_party/abseil/absl/container/internal/raw_hash_set_benchmark.cc
new file mode 100644
index 0000000..f9be2c5
--- /dev/null
+++ b/third_party/abseil/absl/container/internal/raw_hash_set_benchmark.cc
@@ -0,0 +1,396 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/container/internal/raw_hash_set.h"
+
+#include <numeric>
+#include <random>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/container/internal/hash_function_defaults.h"
+#include "absl/strings/str_format.h"
+#include "benchmark/benchmark.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+struct RawHashSetTestOnlyAccess {
+ template <typename C>
+ static auto GetSlots(const C& c) -> decltype(c.slots_) {
+ return c.slots_;
+ }
+};
+
+namespace {
+
+struct IntPolicy {
+ using slot_type = int64_t;
+ using key_type = int64_t;
+ using init_type = int64_t;
+
+ static void construct(void*, int64_t* slot, int64_t v) { *slot = v; }
+ static void destroy(void*, int64_t*) {}
+ static void transfer(void*, int64_t* new_slot, int64_t* old_slot) {
+ *new_slot = *old_slot;
+ }
+
+ static int64_t& element(slot_type* slot) { return *slot; }
+
+ template <class F>
+ static auto apply(F&& f, int64_t x) -> decltype(std::forward<F>(f)(x, x)) {
+ return std::forward<F>(f)(x, x);
+ }
+};
+
+class StringPolicy {
+ template <class F, class K, class V,
+ class = typename std::enable_if<
+ std::is_convertible<const K&, absl::string_view>::value>::type>
+ decltype(std::declval<F>()(
+ std::declval<const absl::string_view&>(), std::piecewise_construct,
+ std::declval<std::tuple<K>>(),
+ std::declval<V>())) static apply_impl(F&& f,
+ std::pair<std::tuple<K>, V> p) {
+ const absl::string_view& key = std::get<0>(p.first);
+ return std::forward<F>(f)(key, std::piecewise_construct, std::move(p.first),
+ std::move(p.second));
+ }
+
+ public:
+ struct slot_type {
+ struct ctor {};
+
+ template <class... Ts>
+ slot_type(ctor, Ts&&... ts) : pair(std::forward<Ts>(ts)...) {}
+
+ std::pair<std::string, std::string> pair;
+ };
+
+ using key_type = std::string;
+ using init_type = std::pair<std::string, std::string>;
+
+ template <class allocator_type, class... Args>
+ static void construct(allocator_type* alloc, slot_type* slot, Args... args) {
+ std::allocator_traits<allocator_type>::construct(
+ *alloc, slot, typename slot_type::ctor(), std::forward<Args>(args)...);
+ }
+
+ template <class allocator_type>
+ static void destroy(allocator_type* alloc, slot_type* slot) {
+ std::allocator_traits<allocator_type>::destroy(*alloc, slot);
+ }
+
+ template <class allocator_type>
+ static void transfer(allocator_type* alloc, slot_type* new_slot,
+ slot_type* old_slot) {
+ construct(alloc, new_slot, std::move(old_slot->pair));
+ destroy(alloc, old_slot);
+ }
+
+ static std::pair<std::string, std::string>& element(slot_type* slot) {
+ return slot->pair;
+ }
+
+ template <class F, class... Args>
+ static auto apply(F&& f, Args&&... args)
+ -> decltype(apply_impl(std::forward<F>(f),
+ PairArgs(std::forward<Args>(args)...))) {
+ return apply_impl(std::forward<F>(f),
+ PairArgs(std::forward<Args>(args)...));
+ }
+};
+
+struct StringHash : container_internal::hash_default_hash<absl::string_view> {
+ using is_transparent = void;
+};
+struct StringEq : std::equal_to<absl::string_view> {
+ using is_transparent = void;
+};
+
+struct StringTable
+ : raw_hash_set<StringPolicy, StringHash, StringEq, std::allocator<int>> {
+ using Base = typename StringTable::raw_hash_set;
+ StringTable() {}
+ using Base::Base;
+};
+
+struct IntTable
+ : raw_hash_set<IntPolicy, container_internal::hash_default_hash<int64_t>,
+ std::equal_to<int64_t>, std::allocator<int64_t>> {
+ using Base = typename IntTable::raw_hash_set;
+ IntTable() {}
+ using Base::Base;
+};
+
+struct string_generator {
+ template <class RNG>
+ std::string operator()(RNG& rng) const {
+ std::string res;
+ res.resize(12);
+ std::uniform_int_distribution<uint32_t> printable_ascii(0x20, 0x7E);
+ std::generate(res.begin(), res.end(), [&] { return printable_ascii(rng); });
+ return res;
+ }
+
+ size_t size;
+};
+
+// Model a cache in steady state.
+//
+// On a table of size N, keep deleting the LRU entry and add a random one.
+void BM_CacheInSteadyState(benchmark::State& state) {
+ std::random_device rd;
+ std::mt19937 rng(rd());
+ string_generator gen{12};
+ StringTable t;
+ std::deque<std::string> keys;
+ while (t.size() < state.range(0)) {
+ auto x = t.emplace(gen(rng), gen(rng));
+ if (x.second) keys.push_back(x.first->first);
+ }
+ ABSL_RAW_CHECK(state.range(0) >= 10, "");
+ while (state.KeepRunning()) {
+ // Some cache hits.
+ std::deque<std::string>::const_iterator it;
+ for (int i = 0; i != 90; ++i) {
+ if (i % 10 == 0) it = keys.end();
+ ::benchmark::DoNotOptimize(t.find(*--it));
+ }
+ // Some cache misses.
+ for (int i = 0; i != 10; ++i) ::benchmark::DoNotOptimize(t.find(gen(rng)));
+ ABSL_RAW_CHECK(t.erase(keys.front()), keys.front().c_str());
+ keys.pop_front();
+ while (true) {
+ auto x = t.emplace(gen(rng), gen(rng));
+ if (x.second) {
+ keys.push_back(x.first->first);
+ break;
+ }
+ }
+ }
+ state.SetItemsProcessed(state.iterations());
+ state.SetLabel(absl::StrFormat("load_factor=%.2f", t.load_factor()));
+}
+
+template <typename Benchmark>
+void CacheInSteadyStateArgs(Benchmark* bm) {
+ // The default.
+ const float max_load_factor = 0.875;
+ // When the cache is at the steady state, the probe sequence will equal
+ // capacity if there is no reclamation of deleted slots. Pick a number large
+ // enough to make the benchmark slow for that case.
+ const size_t capacity = 1 << 10;
+
+ // Check N data points to cover load factors in [0.4, 0.8).
+ const size_t kNumPoints = 10;
+ for (size_t i = 0; i != kNumPoints; ++i)
+ bm->Arg(std::ceil(
+ capacity * (max_load_factor + i * max_load_factor / kNumPoints) / 2));
+}
+BENCHMARK(BM_CacheInSteadyState)->Apply(CacheInSteadyStateArgs);
+
+void BM_EndComparison(benchmark::State& state) {
+ std::random_device rd;
+ std::mt19937 rng(rd());
+ string_generator gen{12};
+ StringTable t;
+ while (t.size() < state.range(0)) {
+ t.emplace(gen(rng), gen(rng));
+ }
+
+ for (auto _ : state) {
+ for (auto it = t.begin(); it != t.end(); ++it) {
+ benchmark::DoNotOptimize(it);
+ benchmark::DoNotOptimize(t);
+ benchmark::DoNotOptimize(it != t.end());
+ }
+ }
+}
+BENCHMARK(BM_EndComparison)->Arg(400);
+
+void BM_CopyCtor(benchmark::State& state) {
+ std::random_device rd;
+ std::mt19937 rng(rd());
+ IntTable t;
+ std::uniform_int_distribution<uint64_t> dist(0, ~uint64_t{});
+
+ while (t.size() < state.range(0)) {
+ t.emplace(dist(rng));
+ }
+
+ for (auto _ : state) {
+ IntTable t2 = t;
+ benchmark::DoNotOptimize(t2);
+ }
+}
+BENCHMARK(BM_CopyCtor)->Range(128, 4096);
+
+void BM_CopyAssign(benchmark::State& state) {
+ std::random_device rd;
+ std::mt19937 rng(rd());
+ IntTable t;
+ std::uniform_int_distribution<uint64_t> dist(0, ~uint64_t{});
+ while (t.size() < state.range(0)) {
+ t.emplace(dist(rng));
+ }
+
+ IntTable t2;
+ for (auto _ : state) {
+ t2 = t;
+ benchmark::DoNotOptimize(t2);
+ }
+}
+BENCHMARK(BM_CopyAssign)->Range(128, 4096);
+
+void BM_NoOpReserveIntTable(benchmark::State& state) {
+ IntTable t;
+ t.reserve(100000);
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(t);
+ t.reserve(100000);
+ }
+}
+BENCHMARK(BM_NoOpReserveIntTable);
+
+void BM_NoOpReserveStringTable(benchmark::State& state) {
+ StringTable t;
+ t.reserve(100000);
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(t);
+ t.reserve(100000);
+ }
+}
+BENCHMARK(BM_NoOpReserveStringTable);
+
+void BM_ReserveIntTable(benchmark::State& state) {
+ int reserve_size = state.range(0);
+ for (auto _ : state) {
+ state.PauseTiming();
+ IntTable t;
+ state.ResumeTiming();
+ benchmark::DoNotOptimize(t);
+ t.reserve(reserve_size);
+ }
+}
+BENCHMARK(BM_ReserveIntTable)->Range(128, 4096);
+
+void BM_ReserveStringTable(benchmark::State& state) {
+ int reserve_size = state.range(0);
+ for (auto _ : state) {
+ state.PauseTiming();
+ StringTable t;
+ state.ResumeTiming();
+ benchmark::DoNotOptimize(t);
+ t.reserve(reserve_size);
+ }
+}
+BENCHMARK(BM_ReserveStringTable)->Range(128, 4096);
+
+void BM_Group_Match(benchmark::State& state) {
+ std::array<ctrl_t, Group::kWidth> group;
+ std::iota(group.begin(), group.end(), -4);
+ Group g{group.data()};
+ h2_t h = 1;
+ for (auto _ : state) {
+ ::benchmark::DoNotOptimize(h);
+ ::benchmark::DoNotOptimize(g.Match(h));
+ }
+}
+BENCHMARK(BM_Group_Match);
+
+void BM_Group_MatchEmpty(benchmark::State& state) {
+ std::array<ctrl_t, Group::kWidth> group;
+ std::iota(group.begin(), group.end(), -4);
+ Group g{group.data()};
+ for (auto _ : state) ::benchmark::DoNotOptimize(g.MatchEmpty());
+}
+BENCHMARK(BM_Group_MatchEmpty);
+
+void BM_Group_MatchEmptyOrDeleted(benchmark::State& state) {
+ std::array<ctrl_t, Group::kWidth> group;
+ std::iota(group.begin(), group.end(), -4);
+ Group g{group.data()};
+ for (auto _ : state) ::benchmark::DoNotOptimize(g.MatchEmptyOrDeleted());
+}
+BENCHMARK(BM_Group_MatchEmptyOrDeleted);
+
+void BM_Group_CountLeadingEmptyOrDeleted(benchmark::State& state) {
+ std::array<ctrl_t, Group::kWidth> group;
+ std::iota(group.begin(), group.end(), -2);
+ Group g{group.data()};
+ for (auto _ : state)
+ ::benchmark::DoNotOptimize(g.CountLeadingEmptyOrDeleted());
+}
+BENCHMARK(BM_Group_CountLeadingEmptyOrDeleted);
+
+void BM_Group_MatchFirstEmptyOrDeleted(benchmark::State& state) {
+ std::array<ctrl_t, Group::kWidth> group;
+ std::iota(group.begin(), group.end(), -2);
+ Group g{group.data()};
+ for (auto _ : state) ::benchmark::DoNotOptimize(*g.MatchEmptyOrDeleted());
+}
+BENCHMARK(BM_Group_MatchFirstEmptyOrDeleted);
+
+void BM_DropDeletes(benchmark::State& state) {
+ constexpr size_t capacity = (1 << 20) - 1;
+ std::vector<ctrl_t> ctrl(capacity + 1 + Group::kWidth);
+ ctrl[capacity] = kSentinel;
+ std::vector<ctrl_t> pattern = {kEmpty, 2, kDeleted, 2, kEmpty, 1, kDeleted};
+ for (size_t i = 0; i != capacity; ++i) {
+ ctrl[i] = pattern[i % pattern.size()];
+ }
+ while (state.KeepRunning()) {
+ state.PauseTiming();
+ std::vector<ctrl_t> ctrl_copy = ctrl;
+ state.ResumeTiming();
+ ConvertDeletedToEmptyAndFullToDeleted(ctrl_copy.data(), capacity);
+ ::benchmark::DoNotOptimize(ctrl_copy[capacity]);
+ }
+}
+BENCHMARK(BM_DropDeletes);
+
+} // namespace
+} // namespace container_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+// These methods are here to make it easy to examine the assembly for targeted
+// parts of the API.
+auto CodegenAbslRawHashSetInt64Find(absl::container_internal::IntTable* table,
+ int64_t key) -> decltype(table->find(key)) {
+ return table->find(key);
+}
+
+bool CodegenAbslRawHashSetInt64FindNeEnd(
+ absl::container_internal::IntTable* table, int64_t key) {
+ return table->find(key) != table->end();
+}
+
+bool CodegenAbslRawHashSetInt64Contains(
+ absl::container_internal::IntTable* table, int64_t key) {
+ return table->contains(key);
+}
+
+void CodegenAbslRawHashSetInt64Iterate(
+ absl::container_internal::IntTable* table) {
+ for (auto x : *table) benchmark::DoNotOptimize(x);
+}
+
+int odr =
+ (::benchmark::DoNotOptimize(std::make_tuple(
+ &CodegenAbslRawHashSetInt64Find, &CodegenAbslRawHashSetInt64FindNeEnd,
+ &CodegenAbslRawHashSetInt64Contains,
+ &CodegenAbslRawHashSetInt64Iterate)),
+ 1);
diff --git a/third_party/abseil/absl/container/internal/raw_hash_set_probe_benchmark.cc b/third_party/abseil/absl/container/internal/raw_hash_set_probe_benchmark.cc
new file mode 100644
index 0000000..7169a2e
--- /dev/null
+++ b/third_party/abseil/absl/container/internal/raw_hash_set_probe_benchmark.cc
@@ -0,0 +1,590 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Generates probe length statistics for many combinations of key types and key
+// distributions, all using the default hash function for swisstable.
+
+#include <memory>
+#include <regex> // NOLINT
+#include <vector>
+
+#include "absl/container/flat_hash_map.h"
+#include "absl/container/internal/hash_function_defaults.h"
+#include "absl/container/internal/hashtable_debug.h"
+#include "absl/container/internal/raw_hash_set.h"
+#include "absl/random/distributions.h"
+#include "absl/random/random.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/string_view.h"
+#include "absl/strings/strip.h"
+
+namespace {
+
+enum class OutputStyle { kRegular, kBenchmark };
+
+// The --benchmark command line flag.
+// This is populated from main().
+// When run in "benchmark" mode, we have different output. This allows
+// A/B comparisons with tools like `benchy`.
+absl::string_view benchmarks;
+
+OutputStyle output() {
+ return !benchmarks.empty() ? OutputStyle::kBenchmark : OutputStyle::kRegular;
+}
+
+template <class T>
+struct Policy {
+ using slot_type = T;
+ using key_type = T;
+ using init_type = T;
+
+ template <class allocator_type, class Arg>
+ static void construct(allocator_type* alloc, slot_type* slot,
+ const Arg& arg) {
+ std::allocator_traits<allocator_type>::construct(*alloc, slot, arg);
+ }
+
+ template <class allocator_type>
+ static void destroy(allocator_type* alloc, slot_type* slot) {
+ std::allocator_traits<allocator_type>::destroy(*alloc, slot);
+ }
+
+ static slot_type& element(slot_type* slot) { return *slot; }
+
+ template <class F, class... Args>
+ static auto apply(F&& f, const slot_type& arg)
+ -> decltype(std::forward<F>(f)(arg, arg)) {
+ return std::forward<F>(f)(arg, arg);
+ }
+};
+
+absl::BitGen& GlobalBitGen() {
+ static auto* value = new absl::BitGen;
+ return *value;
+}
+
+// Keeps a pool of allocations and randomly gives one out.
+// This introduces more randomization to the addresses given to swisstable and
+// should help smooth out this factor from probe length calculation.
+template <class T>
+class RandomizedAllocator {
+ public:
+ using value_type = T;
+
+ RandomizedAllocator() = default;
+ template <typename U>
+ RandomizedAllocator(RandomizedAllocator<U>) {} // NOLINT
+
+ static T* allocate(size_t n) {
+ auto& pointers = GetPointers(n);
+ // Fill the pool
+ while (pointers.size() < kRandomPool) {
+ pointers.push_back(std::allocator<T>{}.allocate(n));
+ }
+
+ // Choose a random one.
+ size_t i = absl::Uniform<size_t>(GlobalBitGen(), 0, pointers.size());
+ T* result = pointers[i];
+ pointers[i] = pointers.back();
+ pointers.pop_back();
+ return result;
+ }
+
+ static void deallocate(T* p, size_t n) {
+ // Just put it back on the pool. No need to release the memory.
+ GetPointers(n).push_back(p);
+ }
+
+ private:
+ // We keep at least kRandomPool allocations for each size.
+ static constexpr size_t kRandomPool = 20;
+
+ static std::vector<T*>& GetPointers(size_t n) {
+ static auto* m = new absl::flat_hash_map<size_t, std::vector<T*>>();
+ return (*m)[n];
+ }
+};
+
+template <class T>
+struct DefaultHash {
+ using type = absl::container_internal::hash_default_hash<T>;
+};
+
+template <class T>
+using DefaultHashT = typename DefaultHash<T>::type;
+
+template <class T>
+struct Table : absl::container_internal::raw_hash_set<
+ Policy<T>, DefaultHashT<T>,
+ absl::container_internal::hash_default_eq<T>,
+ RandomizedAllocator<T>> {};
+
+struct LoadSizes {
+ size_t min_load;
+ size_t max_load;
+};
+
+LoadSizes GetMinMaxLoadSizes() {
+ static const auto sizes = [] {
+ Table<int> t;
+
+ // First, fill enough to have a good distribution.
+ constexpr size_t kMinSize = 10000;
+ while (t.size() < kMinSize) t.insert(t.size());
+
+ const auto reach_min_load_factor = [&] {
+ const double lf = t.load_factor();
+ while (lf <= t.load_factor()) t.insert(t.size());
+ };
+
+ // Then, insert until we reach min load factor.
+ reach_min_load_factor();
+ const size_t min_load_size = t.size();
+
+ // Keep going until we hit min load factor again, then go back one.
+ t.insert(t.size());
+ reach_min_load_factor();
+
+ return LoadSizes{min_load_size, t.size() - 1};
+ }();
+ return sizes;
+}
+
+struct Ratios {
+ double min_load;
+ double avg_load;
+ double max_load;
+};
+
+// See absl/container/internal/hashtable_debug.h for details on
+// probe length calculation.
+template <class ElemFn>
+Ratios CollectMeanProbeLengths() {
+ const auto min_max_sizes = GetMinMaxLoadSizes();
+
+ ElemFn elem;
+ using Key = decltype(elem());
+ Table<Key> t;
+
+ Ratios result;
+ while (t.size() < min_max_sizes.min_load) t.insert(elem());
+ result.min_load =
+ absl::container_internal::GetHashtableDebugProbeSummary(t).mean;
+
+ while (t.size() < (min_max_sizes.min_load + min_max_sizes.max_load) / 2)
+ t.insert(elem());
+ result.avg_load =
+ absl::container_internal::GetHashtableDebugProbeSummary(t).mean;
+
+ while (t.size() < min_max_sizes.max_load) t.insert(elem());
+ result.max_load =
+ absl::container_internal::GetHashtableDebugProbeSummary(t).mean;
+
+ return result;
+}
+
+template <int Align>
+uintptr_t PointerForAlignment() {
+ alignas(Align) static constexpr uintptr_t kInitPointer = 0;
+ return reinterpret_cast<uintptr_t>(&kInitPointer);
+}
+
+// This incomplete type is used for testing hash of pointers of different
+// alignments.
+// NOTE: We are generating invalid pointer values on the fly with
+// reinterpret_cast. There are not "safely derived" pointers so using them is
+// technically UB. It is unlikely to be a problem, though.
+template <int Align>
+struct Ptr;
+
+template <int Align>
+Ptr<Align>* MakePtr(uintptr_t v) {
+ if (sizeof(v) == 8) {
+ constexpr int kCopyBits = 16;
+ // Ensure high bits are all the same.
+ v = static_cast<uintptr_t>(static_cast<intptr_t>(v << kCopyBits) >>
+ kCopyBits);
+ }
+ return reinterpret_cast<Ptr<Align>*>(v);
+}
+
+struct IntIdentity {
+ uint64_t i;
+ friend bool operator==(IntIdentity a, IntIdentity b) { return a.i == b.i; }
+ IntIdentity operator++(int) { return IntIdentity{i++}; }
+};
+
+template <int Align>
+struct PtrIdentity {
+ explicit PtrIdentity(uintptr_t val = PointerForAlignment<Align>()) : i(val) {}
+ uintptr_t i;
+ friend bool operator==(PtrIdentity a, PtrIdentity b) { return a.i == b.i; }
+ PtrIdentity operator++(int) {
+ PtrIdentity p(i);
+ i += Align;
+ return p;
+ }
+};
+
+constexpr char kStringFormat[] = "/path/to/file/name-%07d-of-9999999.txt";
+
+template <bool small>
+struct String {
+ std::string value;
+ static std::string Make(uint32_t v) {
+ return {small ? absl::StrCat(v) : absl::StrFormat(kStringFormat, v)};
+ }
+};
+
+template <>
+struct DefaultHash<IntIdentity> {
+ struct type {
+ size_t operator()(IntIdentity t) const { return t.i; }
+ };
+};
+
+template <int Align>
+struct DefaultHash<PtrIdentity<Align>> {
+ struct type {
+ size_t operator()(PtrIdentity<Align> t) const { return t.i; }
+ };
+};
+
+template <class T>
+struct Sequential {
+ T operator()() const { return current++; }
+ mutable T current{};
+};
+
+template <int Align>
+struct Sequential<Ptr<Align>*> {
+ Ptr<Align>* operator()() const {
+ auto* result = MakePtr<Align>(current);
+ current += Align;
+ return result;
+ }
+ mutable uintptr_t current = PointerForAlignment<Align>();
+};
+
+
+template <bool small>
+struct Sequential<String<small>> {
+ std::string operator()() const { return String<small>::Make(current++); }
+ mutable uint32_t current = 0;
+};
+
+template <class T, class U>
+struct Sequential<std::pair<T, U>> {
+ mutable Sequential<T> tseq;
+ mutable Sequential<U> useq;
+
+ using RealT = decltype(tseq());
+ using RealU = decltype(useq());
+
+ mutable std::vector<RealT> ts;
+ mutable std::vector<RealU> us;
+ mutable size_t ti = 0, ui = 0;
+
+ std::pair<RealT, RealU> operator()() const {
+ std::pair<RealT, RealU> value{get_t(), get_u()};
+ if (ti == 0) {
+ ti = ui + 1;
+ ui = 0;
+ } else {
+ --ti;
+ ++ui;
+ }
+ return value;
+ }
+
+ RealT get_t() const {
+ while (ti >= ts.size()) ts.push_back(tseq());
+ return ts[ti];
+ }
+
+ RealU get_u() const {
+ while (ui >= us.size()) us.push_back(useq());
+ return us[ui];
+ }
+};
+
+template <class T, int percent_skip>
+struct AlmostSequential {
+ mutable Sequential<T> current;
+
+ auto operator()() const -> decltype(current()) {
+ while (absl::Uniform(GlobalBitGen(), 0.0, 1.0) <= percent_skip / 100.)
+ current();
+ return current();
+ }
+};
+
+struct Uniform {
+ template <typename T>
+ T operator()(T) const {
+ return absl::Uniform<T>(absl::IntervalClosed, GlobalBitGen(), T{0}, ~T{0});
+ }
+};
+
+struct Gaussian {
+ template <typename T>
+ T operator()(T) const {
+ double d;
+ do {
+ d = absl::Gaussian<double>(GlobalBitGen(), 1e6, 1e4);
+ } while (d <= 0 || d > std::numeric_limits<T>::max() / 2);
+ return static_cast<T>(d);
+ }
+};
+
+struct Zipf {
+ template <typename T>
+ T operator()(T) const {
+ return absl::Zipf<T>(GlobalBitGen(), std::numeric_limits<T>::max(), 1.6);
+ }
+};
+
+template <class T, class Dist>
+struct Random {
+ T operator()() const { return Dist{}(T{}); }
+};
+
+template <class Dist, int Align>
+struct Random<Ptr<Align>*, Dist> {
+ Ptr<Align>* operator()() const {
+ return MakePtr<Align>(Random<uintptr_t, Dist>{}() * Align);
+ }
+};
+
+template <class Dist>
+struct Random<IntIdentity, Dist> {
+ IntIdentity operator()() const {
+ return IntIdentity{Random<uint64_t, Dist>{}()};
+ }
+};
+
+template <class Dist, int Align>
+struct Random<PtrIdentity<Align>, Dist> {
+ PtrIdentity<Align> operator()() const {
+ return PtrIdentity<Align>{Random<uintptr_t, Dist>{}() * Align};
+ }
+};
+
+template <class Dist, bool small>
+struct Random<String<small>, Dist> {
+ std::string operator()() const {
+ return String<small>::Make(Random<uint32_t, Dist>{}());
+ }
+};
+
+template <class T, class U, class Dist>
+struct Random<std::pair<T, U>, Dist> {
+ auto operator()() const
+ -> decltype(std::make_pair(Random<T, Dist>{}(), Random<U, Dist>{}())) {
+ return std::make_pair(Random<T, Dist>{}(), Random<U, Dist>{}());
+ }
+};
+
+template <typename>
+std::string Name();
+
+std::string Name(uint32_t*) { return "u32"; }
+std::string Name(uint64_t*) { return "u64"; }
+std::string Name(IntIdentity*) { return "IntIdentity"; }
+
+template <int Align>
+std::string Name(Ptr<Align>**) {
+ return absl::StrCat("Ptr", Align);
+}
+
+template <int Align>
+std::string Name(PtrIdentity<Align>*) {
+ return absl::StrCat("PtrIdentity", Align);
+}
+
+template <bool small>
+std::string Name(String<small>*) {
+ return small ? "StrS" : "StrL";
+}
+
+template <class T, class U>
+std::string Name(std::pair<T, U>*) {
+ if (output() == OutputStyle::kBenchmark)
+ return absl::StrCat("P_", Name<T>(), "_", Name<U>());
+ return absl::StrCat("P<", Name<T>(), ",", Name<U>(), ">");
+}
+
+template <class T>
+std::string Name(Sequential<T>*) {
+ return "Sequential";
+}
+
+template <class T, int P>
+std::string Name(AlmostSequential<T, P>*) {
+ return absl::StrCat("AlmostSeq_", P);
+}
+
+template <class T>
+std::string Name(Random<T, Uniform>*) {
+ return "UnifRand";
+}
+
+template <class T>
+std::string Name(Random<T, Gaussian>*) {
+ return "GausRand";
+}
+
+template <class T>
+std::string Name(Random<T, Zipf>*) {
+ return "ZipfRand";
+}
+
+template <typename T>
+std::string Name() {
+ return Name(static_cast<T*>(nullptr));
+}
+
+constexpr int kNameWidth = 15;
+constexpr int kDistWidth = 16;
+
+bool CanRunBenchmark(absl::string_view name) {
+ static std::regex* const filter = []() -> std::regex* {
+ return benchmarks.empty() || benchmarks == "all"
+ ? nullptr
+ : new std::regex(std::string(benchmarks));
+ }();
+ return filter == nullptr || std::regex_search(std::string(name), *filter);
+}
+
+struct Result {
+ std::string name;
+ std::string dist_name;
+ Ratios ratios;
+};
+
+template <typename T, typename Dist>
+void RunForTypeAndDistribution(std::vector<Result>& results) {
+ std::string name = absl::StrCat(Name<T>(), "/", Name<Dist>());
+ // We have to check against all three names (min/avg/max) before we run it.
+ // If any of them is enabled, we run it.
+ if (!CanRunBenchmark(absl::StrCat(name, "/min")) &&
+ !CanRunBenchmark(absl::StrCat(name, "/avg")) &&
+ !CanRunBenchmark(absl::StrCat(name, "/max"))) {
+ return;
+ }
+ results.push_back({Name<T>(), Name<Dist>(), CollectMeanProbeLengths<Dist>()});
+}
+
+template <class T>
+void RunForType(std::vector<Result>& results) {
+ RunForTypeAndDistribution<T, Sequential<T>>(results);
+ RunForTypeAndDistribution<T, AlmostSequential<T, 20>>(results);
+ RunForTypeAndDistribution<T, AlmostSequential<T, 50>>(results);
+ RunForTypeAndDistribution<T, Random<T, Uniform>>(results);
+#ifdef NDEBUG
+ // Disable these in non-opt mode because they take too long.
+ RunForTypeAndDistribution<T, Random<T, Gaussian>>(results);
+ RunForTypeAndDistribution<T, Random<T, Zipf>>(results);
+#endif // NDEBUG
+}
+
+} // namespace
+
+int main(int argc, char** argv) {
+ // Parse the benchmark flags. Ignore all of them except the regex pattern.
+ for (int i = 1; i < argc; ++i) {
+ absl::string_view arg = argv[i];
+ const auto next = [&] { return argv[std::min(i + 1, argc - 1)]; };
+
+ if (absl::ConsumePrefix(&arg, "--benchmark_filter")) {
+ if (arg == "") {
+ // --benchmark_filter X
+ benchmarks = next();
+ } else if (absl::ConsumePrefix(&arg, "=")) {
+ // --benchmark_filter=X
+ benchmarks = arg;
+ }
+ }
+
+ // Any --benchmark flag turns on the mode.
+ if (absl::ConsumePrefix(&arg, "--benchmark")) {
+ if (benchmarks.empty()) benchmarks="all";
+ }
+ }
+
+ std::vector<Result> results;
+ RunForType<uint64_t>(results);
+ RunForType<IntIdentity>(results);
+ RunForType<Ptr<8>*>(results);
+ RunForType<Ptr<16>*>(results);
+ RunForType<Ptr<32>*>(results);
+ RunForType<Ptr<64>*>(results);
+ RunForType<PtrIdentity<8>>(results);
+ RunForType<PtrIdentity<16>>(results);
+ RunForType<PtrIdentity<32>>(results);
+ RunForType<PtrIdentity<64>>(results);
+ RunForType<std::pair<uint32_t, uint32_t>>(results);
+ RunForType<String<true>>(results);
+ RunForType<String<false>>(results);
+ RunForType<std::pair<uint64_t, String<true>>>(results);
+ RunForType<std::pair<String<true>, uint64_t>>(results);
+ RunForType<std::pair<uint64_t, String<false>>>(results);
+ RunForType<std::pair<String<false>, uint64_t>>(results);
+
+ switch (output()) {
+ case OutputStyle::kRegular:
+ absl::PrintF("%-*s%-*s Min Avg Max\n%s\n", kNameWidth,
+ "Type", kDistWidth, "Distribution",
+ std::string(kNameWidth + kDistWidth + 10 * 3, '-'));
+ for (const auto& result : results) {
+ absl::PrintF("%-*s%-*s %8.4f %8.4f %8.4f\n", kNameWidth, result.name,
+ kDistWidth, result.dist_name, result.ratios.min_load,
+ result.ratios.avg_load, result.ratios.max_load);
+ }
+ break;
+ case OutputStyle::kBenchmark: {
+ absl::PrintF("{\n");
+ absl::PrintF(" \"benchmarks\": [\n");
+ absl::string_view comma;
+ for (const auto& result : results) {
+ auto print = [&](absl::string_view stat, double Ratios::*val) {
+ std::string name =
+ absl::StrCat(result.name, "/", result.dist_name, "/", stat);
+ // Check the regex again. We might had have enabled only one of the
+ // stats for the benchmark.
+ if (!CanRunBenchmark(name)) return;
+ absl::PrintF(" %s{\n", comma);
+ absl::PrintF(" \"cpu_time\": %f,\n", 1e9 * result.ratios.*val);
+ absl::PrintF(" \"real_time\": %f,\n", 1e9 * result.ratios.*val);
+ absl::PrintF(" \"iterations\": 1,\n");
+ absl::PrintF(" \"name\": \"%s\",\n", name);
+ absl::PrintF(" \"time_unit\": \"ns\"\n");
+ absl::PrintF(" }\n");
+ comma = ",";
+ };
+ print("min", &Ratios::min_load);
+ print("avg", &Ratios::avg_load);
+ print("max", &Ratios::max_load);
+ }
+ absl::PrintF(" ],\n");
+ absl::PrintF(" \"context\": {\n");
+ absl::PrintF(" }\n");
+ absl::PrintF("}\n");
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/third_party/abseil/absl/container/internal/raw_hash_set_test.cc b/third_party/abseil/absl/container/internal/raw_hash_set_test.cc
index ed4ca8c..0fba46f 100644
--- a/third_party/abseil/absl/container/internal/raw_hash_set_test.cc
+++ b/third_party/abseil/absl/container/internal/raw_hash_set_test.cc
@@ -26,6 +26,7 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/attributes.h"
+#include "absl/base/config.h"
#include "absl/base/internal/cycleclock.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/container/internal/container_memory.h"
@@ -35,6 +36,7 @@
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
struct RawHashSetTestOnlyAccess {
@@ -248,25 +250,43 @@
}
}
-struct IntPolicy {
- using slot_type = int64_t;
- using key_type = int64_t;
- using init_type = int64_t;
+template <class T>
+struct ValuePolicy {
+ using slot_type = T;
+ using key_type = T;
+ using init_type = T;
- static void construct(void*, int64_t* slot, int64_t v) { *slot = v; }
- static void destroy(void*, int64_t*) {}
- static void transfer(void*, int64_t* new_slot, int64_t* old_slot) {
- *new_slot = *old_slot;
+ template <class Allocator, class... Args>
+ static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
+ absl::allocator_traits<Allocator>::construct(*alloc, slot,
+ std::forward<Args>(args)...);
}
- static int64_t& element(slot_type* slot) { return *slot; }
+ template <class Allocator>
+ static void destroy(Allocator* alloc, slot_type* slot) {
+ absl::allocator_traits<Allocator>::destroy(*alloc, slot);
+ }
- template <class F>
- static auto apply(F&& f, int64_t x) -> decltype(std::forward<F>(f)(x, x)) {
- return std::forward<F>(f)(x, x);
+ template <class Allocator>
+ static void transfer(Allocator* alloc, slot_type* new_slot,
+ slot_type* old_slot) {
+ construct(alloc, new_slot, std::move(*old_slot));
+ destroy(alloc, old_slot);
+ }
+
+ static T& element(slot_type* slot) { return *slot; }
+
+ template <class F, class... Args>
+ static decltype(absl::container_internal::DecomposeValue(
+ std::declval<F>(), std::declval<Args>()...))
+ apply(F&& f, Args&&... args) {
+ return absl::container_internal::DecomposeValue(
+ std::forward<F>(f), std::forward<Args>(args)...);
}
};
+using IntPolicy = ValuePolicy<int64_t>;
+
class StringPolicy {
template <class F, class K, class V,
class = typename std::enable_if<
@@ -417,53 +437,6 @@
EXPECT_TRUE(t.empty());
}
-#ifdef __GNUC__
-template <class T>
-ABSL_ATTRIBUTE_ALWAYS_INLINE inline void DoNotOptimize(const T& v) {
- asm volatile("" : : "r,m"(v) : "memory");
-}
-#endif
-
-TEST(Table, Prefetch) {
- IntTable t;
- t.emplace(1);
- // Works for both present and absent keys.
- t.prefetch(1);
- t.prefetch(2);
-
- // Do not run in debug mode, when prefetch is not implemented, or when
- // sanitizers are enabled, or on WebAssembly.
-#if defined(NDEBUG) && defined(__GNUC__) && defined(__x86_64__) && \
- !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) && \
- !defined(THREAD_SANITIZER) && !defined(UNDEFINED_BEHAVIOR_SANITIZER) && \
- !defined(__EMSCRIPTEN__)
- const auto now = [] { return absl::base_internal::CycleClock::Now(); };
-
- // Make size enough to not fit in L2 cache (16.7 Mb)
- static constexpr int size = 1 << 22;
- for (int i = 0; i < size; ++i) t.insert(i);
-
- int64_t no_prefetch = 0, prefetch = 0;
- for (int iter = 0; iter < 10; ++iter) {
- int64_t time = now();
- for (int i = 0; i < size; ++i) {
- DoNotOptimize(t.find(i));
- }
- no_prefetch += now() - time;
-
- time = now();
- for (int i = 0; i < size; ++i) {
- t.prefetch(i + 20);
- DoNotOptimize(t.find(i));
- }
- prefetch += now() - time;
- }
-
- // no_prefetch is at least 30% slower.
- EXPECT_GE(1.0 * no_prefetch / prefetch, 1.3);
-#endif
-}
-
TEST(Table, LookupEmpty) {
IntTable t;
auto it = t.find(0);
@@ -892,7 +865,8 @@
std::vector<int64_t> CollectBadMergeKeys(size_t N) {
static constexpr int kGroupSize = Group::kWidth - 1;
- auto topk_range = [](size_t b, size_t e, IntTable* t) -> std::vector<int64_t> {
+ auto topk_range = [](size_t b, size_t e,
+ IntTable* t) -> std::vector<int64_t> {
for (size_t i = b; i != e; ++i) {
t->emplace(i);
}
@@ -1046,8 +1020,8 @@
// 1. Create new table and reserve it to keys.size() * 2
// 2. Insert all keys xored with seed
// 3. Collect ProbeStats from final table.
-ProbeStats CollectProbeStatsOnKeysXoredWithSeed(const std::vector<int64_t>& keys,
- size_t num_iters) {
+ProbeStats CollectProbeStatsOnKeysXoredWithSeed(
+ const std::vector<int64_t>& keys, size_t num_iters) {
const size_t reserve_size = keys.size() * 2;
ProbeStats stats;
@@ -1701,6 +1675,38 @@
EXPECT_THAT(t2, UnorderedElementsAre(Pair("0", "~0")));
}
+TEST(Table, IteratorEmplaceConstructibleRequirement) {
+ struct Value {
+ explicit Value(absl::string_view view) : value(view) {}
+ std::string value;
+
+ bool operator==(const Value& other) const { return value == other.value; }
+ };
+ struct H {
+ size_t operator()(const Value& v) const {
+ return absl::Hash<std::string>{}(v.value);
+ }
+ };
+
+ struct Table : raw_hash_set<ValuePolicy<Value>, H, std::equal_to<Value>,
+ std::allocator<Value>> {
+ using Base = typename Table::raw_hash_set;
+ using Base::Base;
+ };
+
+ std::string input[3]{"A", "B", "C"};
+
+ Table t(std::begin(input), std::end(input));
+ EXPECT_THAT(t, UnorderedElementsAre(Value{"A"}, Value{"B"}, Value{"C"}));
+
+ input[0] = "D";
+ input[1] = "E";
+ input[2] = "F";
+ t.insert(std::begin(input), std::end(input));
+ EXPECT_THAT(t, UnorderedElementsAre(Value{"A"}, Value{"B"}, Value{"C"},
+ Value{"D"}, Value{"E"}, Value{"F"}));
+}
+
TEST(Nodes, EmptyNodeType) {
using node_type = StringTable::node_type;
node_type n;
@@ -1712,9 +1718,9 @@
}
TEST(Nodes, ExtractInsert) {
- constexpr char k0[] = "Very long std::string zero.";
- constexpr char k1[] = "Very long std::string one.";
- constexpr char k2[] = "Very long std::string two.";
+ constexpr char k0[] = "Very long string zero.";
+ constexpr char k1[] = "Very long string one.";
+ constexpr char k2[] = "Very long string two.";
StringTable t = {{k0, ""}, {k1, ""}, {k2, ""}};
EXPECT_THAT(t,
UnorderedElementsAre(Pair(k0, ""), Pair(k1, ""), Pair(k2, "")));
@@ -1755,6 +1761,26 @@
EXPECT_FALSE(node);
}
+TEST(Nodes, HintInsert) {
+ IntTable t = {1, 2, 3};
+ auto node = t.extract(1);
+ EXPECT_THAT(t, UnorderedElementsAre(2, 3));
+ auto it = t.insert(t.begin(), std::move(node));
+ EXPECT_THAT(t, UnorderedElementsAre(1, 2, 3));
+ EXPECT_EQ(*it, 1);
+ EXPECT_FALSE(node);
+
+ node = t.extract(2);
+ EXPECT_THAT(t, UnorderedElementsAre(1, 3));
+ // reinsert 2 to make the next insert fail.
+ t.insert(2);
+ EXPECT_THAT(t, UnorderedElementsAre(1, 2, 3));
+ it = t.insert(t.begin(), std::move(node));
+ EXPECT_EQ(*it, 2);
+ // The node was not emptied by the insert call.
+ EXPECT_TRUE(node);
+}
+
IntTable MakeSimpleTable(size_t size) {
IntTable t;
while (t.size() < size) t.insert(t.size());
@@ -1837,10 +1863,11 @@
IntTable t;
// Extra simple "regexp" as regexp support is highly varied across platforms.
- constexpr char kDeathMsg[] = "it != end";
+ constexpr char kDeathMsg[] = "Invalid operation on iterator";
EXPECT_DEATH_IF_SUPPORTED(t.erase(t.end()), kDeathMsg);
}
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
TEST(RawHashSamplerTest, Sample) {
// Enable the feature even if the prod default is off.
SetHashtablezEnabled(true);
@@ -1861,6 +1888,7 @@
EXPECT_NEAR((end_size - start_size) / static_cast<double>(tables.size()),
0.01, 0.005);
}
+#endif // ABSL_INTERNAL_HASHTABLEZ_SAMPLE
TEST(RawHashSamplerTest, DoNotSampleCustomAllocators) {
// Enable the feature even if the prod default is off.
@@ -1883,7 +1911,7 @@
0.00, 0.001);
}
-#ifdef ADDRESS_SANITIZER
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
TEST(Sanitizer, PoisoningUnused) {
IntTable t;
t.reserve(5);
@@ -1907,8 +1935,9 @@
t.erase(0);
EXPECT_TRUE(__asan_address_is_poisoned(&v));
}
-#endif // ADDRESS_SANITIZER
+#endif // ABSL_HAVE_ADDRESS_SANITIZER
} // namespace
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/container/internal/test_instance_tracker.cc b/third_party/abseil/absl/container/internal/test_instance_tracker.cc
index 5a66cb4..f9947f0 100644
--- a/third_party/abseil/absl/container/internal/test_instance_tracker.cc
+++ b/third_party/abseil/absl/container/internal/test_instance_tracker.cc
@@ -15,6 +15,7 @@
#include "absl/container/internal/test_instance_tracker.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace test_internal {
int BaseCountedInstance::num_instances_ = 0;
int BaseCountedInstance::num_live_instances_ = 0;
@@ -24,4 +25,5 @@
int BaseCountedInstance::num_comparisons_ = 0;
} // namespace test_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/container/internal/test_instance_tracker.h b/third_party/abseil/absl/container/internal/test_instance_tracker.h
index c4731db..5ff6fd7 100644
--- a/third_party/abseil/absl/container/internal/test_instance_tracker.h
+++ b/third_party/abseil/absl/container/internal/test_instance_tracker.h
@@ -21,6 +21,7 @@
#include "absl/types/compare.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace test_internal {
// A type that counts number of occurrences of the type, the live occurrences of
@@ -267,6 +268,7 @@
};
} // namespace test_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_TEST_INSTANCE_TRACKER_H_
diff --git a/third_party/abseil/absl/container/internal/tracked.h b/third_party/abseil/absl/container/internal/tracked.h
index 75173ab..29f5829 100644
--- a/third_party/abseil/absl/container/internal/tracked.h
+++ b/third_party/abseil/absl/container/internal/tracked.h
@@ -16,10 +16,14 @@
#define ABSL_CONTAINER_INTERNAL_TRACKED_H_
#include <stddef.h>
+
#include <memory>
#include <utility>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
// A class that tracks its copies and moves so that it can be queried in tests.
@@ -73,6 +77,7 @@
};
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_TRACKED_H_
diff --git a/third_party/abseil/absl/container/internal/unordered_map_constructor_test.h b/third_party/abseil/absl/container/internal/unordered_map_constructor_test.h
index 68817e4..76ee95e 100644
--- a/third_party/abseil/absl/container/internal/unordered_map_constructor_test.h
+++ b/third_party/abseil/absl/container/internal/unordered_map_constructor_test.h
@@ -24,6 +24,7 @@
#include "absl/container/internal/hash_policy_testing.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
template <class UnordMap>
@@ -482,6 +483,7 @@
AssignmentFromInitializerListOverwritesExisting, AssignmentOnSelf);
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_CONSTRUCTOR_TEST_H_
diff --git a/third_party/abseil/absl/container/internal/unordered_map_lookup_test.h b/third_party/abseil/absl/container/internal/unordered_map_lookup_test.h
index ebd3612..e76421e 100644
--- a/third_party/abseil/absl/container/internal/unordered_map_lookup_test.h
+++ b/third_party/abseil/absl/container/internal/unordered_map_lookup_test.h
@@ -21,6 +21,7 @@
#include "absl/container/internal/hash_policy_testing.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
template <class UnordMap>
@@ -110,6 +111,7 @@
EqualRange);
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_LOOKUP_TEST_H_
diff --git a/third_party/abseil/absl/container/internal/unordered_map_members_test.h b/third_party/abseil/absl/container/internal/unordered_map_members_test.h
index 1bf31ab..7d48cdb 100644
--- a/third_party/abseil/absl/container/internal/unordered_map_members_test.h
+++ b/third_party/abseil/absl/container/internal/unordered_map_members_test.h
@@ -21,6 +21,7 @@
#include "absl/meta/type_traits.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
template <class UnordMap>
@@ -80,6 +81,7 @@
REGISTER_TYPED_TEST_SUITE_P(MembersTest, Typedefs, SimpleFunctions, BeginEnd);
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MEMBERS_TEST_H_
diff --git a/third_party/abseil/absl/container/internal/unordered_map_modifiers_test.h b/third_party/abseil/absl/container/internal/unordered_map_modifiers_test.h
index f6aff54..8c9ca77 100644
--- a/third_party/abseil/absl/container/internal/unordered_map_modifiers_test.h
+++ b/third_party/abseil/absl/container/internal/unordered_map_modifiers_test.h
@@ -23,6 +23,7 @@
#include "absl/container/internal/hash_policy_testing.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
template <class UnordMap>
@@ -285,6 +286,8 @@
}
};
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UniquePtrModifiersTest);
+
TYPED_TEST_SUITE_P(UniquePtrModifiersTest);
// Test that we do not move from rvalue arguments if an insertion does not
@@ -309,6 +312,7 @@
REGISTER_TYPED_TEST_SUITE_P(UniquePtrModifiersTest, TryEmplace);
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MODIFIERS_TEST_H_
diff --git a/third_party/abseil/absl/container/internal/unordered_map_test.cc b/third_party/abseil/absl/container/internal/unordered_map_test.cc
index 114b342..9cbf512 100644
--- a/third_party/abseil/absl/container/internal/unordered_map_test.cc
+++ b/third_party/abseil/absl/container/internal/unordered_map_test.cc
@@ -21,6 +21,7 @@
#include "absl/container/internal/unordered_map_modifiers_test.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace {
@@ -45,4 +46,5 @@
} // namespace
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/container/internal/unordered_set_constructor_test.h b/third_party/abseil/absl/container/internal/unordered_set_constructor_test.h
index f484468..41165b0 100644
--- a/third_party/abseil/absl/container/internal/unordered_set_constructor_test.h
+++ b/third_party/abseil/absl/container/internal/unordered_set_constructor_test.h
@@ -26,6 +26,7 @@
#include "absl/meta/type_traits.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
template <class UnordMap>
@@ -489,6 +490,7 @@
AssignmentFromInitializerListOverwritesExisting, AssignmentOnSelf);
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_SET_CONSTRUCTOR_TEST_H_
diff --git a/third_party/abseil/absl/container/internal/unordered_set_lookup_test.h b/third_party/abseil/absl/container/internal/unordered_set_lookup_test.h
index 05b32b5..8f2f4b2 100644
--- a/third_party/abseil/absl/container/internal/unordered_set_lookup_test.h
+++ b/third_party/abseil/absl/container/internal/unordered_set_lookup_test.h
@@ -21,6 +21,7 @@
#include "absl/container/internal/hash_policy_testing.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
template <class UnordSet>
@@ -84,6 +85,7 @@
REGISTER_TYPED_TEST_CASE_P(LookupTest, Count, Find, EqualRange);
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_SET_LOOKUP_TEST_H_
diff --git a/third_party/abseil/absl/container/internal/unordered_set_members_test.h b/third_party/abseil/absl/container/internal/unordered_set_members_test.h
index b96c945..4c5e104 100644
--- a/third_party/abseil/absl/container/internal/unordered_set_members_test.h
+++ b/third_party/abseil/absl/container/internal/unordered_set_members_test.h
@@ -21,6 +21,7 @@
#include "absl/meta/type_traits.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
template <class UnordSet>
@@ -79,6 +80,7 @@
REGISTER_TYPED_TEST_SUITE_P(MembersTest, Typedefs, SimpleFunctions, BeginEnd);
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_SET_MEMBERS_TEST_H_
diff --git a/third_party/abseil/absl/container/internal/unordered_set_modifiers_test.h b/third_party/abseil/absl/container/internal/unordered_set_modifiers_test.h
index 79a8d42..26be58d 100644
--- a/third_party/abseil/absl/container/internal/unordered_set_modifiers_test.h
+++ b/third_party/abseil/absl/container/internal/unordered_set_modifiers_test.h
@@ -21,6 +21,7 @@
#include "absl/container/internal/hash_policy_testing.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
template <class UnordSet>
@@ -183,6 +184,7 @@
EraseKey, Swap);
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_SET_MODIFIERS_TEST_H_
diff --git a/third_party/abseil/absl/container/internal/unordered_set_test.cc b/third_party/abseil/absl/container/internal/unordered_set_test.cc
index 6478fac..a134b53 100644
--- a/third_party/abseil/absl/container/internal/unordered_set_test.cc
+++ b/third_party/abseil/absl/container/internal/unordered_set_test.cc
@@ -20,6 +20,7 @@
#include "absl/container/internal/unordered_set_modifiers_test.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace {
@@ -36,4 +37,5 @@
} // namespace
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/container/node_hash_map.h b/third_party/abseil/absl/container/node_hash_map.h
index a718842..7a39f62 100644
--- a/third_party/abseil/absl/container/node_hash_map.h
+++ b/third_party/abseil/absl/container/node_hash_map.h
@@ -48,6 +48,7 @@
#include "absl/memory/memory.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
template <class Key, class Value>
class NodeHashMapPolicy;
@@ -224,7 +225,8 @@
//
// size_type erase(const key_type& key):
//
- // Erases the element with the matching key, if it exists.
+ // Erases the element with the matching key, if it exists, returning the
+ // number of elements erased (0 or 1).
using Base::erase;
// node_hash_map::insert()
@@ -373,6 +375,11 @@
// key value and returns a node handle owning that extracted data. If the
// `node_hash_map` does not contain an element with a matching key, this
// function returns an empty node handle.
+ //
+ // NOTE: when compiled in an earlier version of C++ than C++17,
+ // `node_type::key()` returns a const reference to the key instead of a
+ // mutable reference. We cannot safely return a mutable reference without
+ // std::launder (which is not available before C++17).
using Base::extract;
// node_hash_map::merge()
@@ -513,14 +520,17 @@
//
// Returns the function used for comparing keys equality.
using Base::key_eq;
-
- ABSL_DEPRECATED("Call `hash_function()` instead.")
- typename Base::hasher hash_funct() { return this->hash_function(); }
-
- ABSL_DEPRECATED("Call `rehash()` instead.")
- void resize(typename Base::size_type hint) { this->rehash(hint); }
};
+// erase_if(node_hash_map<>, Pred)
+//
+// Erases all elements that satisfy the predicate `pred` from the container `c`.
+template <typename K, typename V, typename H, typename E, typename A,
+ typename Predicate>
+void erase_if(node_hash_map<K, V, H, E, A>& c, Predicate pred) {
+ container_internal::EraseIf(pred, &c);
+}
+
namespace container_internal {
template <class Key, class Value>
@@ -581,6 +591,7 @@
} // namespace container_algorithm_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_NODE_HASH_MAP_H_
diff --git a/third_party/abseil/absl/container/node_hash_map_test.cc b/third_party/abseil/absl/container/node_hash_map_test.cc
index 0f2714a..8f59a1e 100644
--- a/third_party/abseil/absl/container/node_hash_map_test.cc
+++ b/third_party/abseil/absl/container/node_hash_map_test.cc
@@ -21,10 +21,12 @@
#include "absl/container/internal/unordered_map_modifiers_test.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace {
using ::testing::Field;
+using ::testing::IsEmpty;
using ::testing::Pair;
using ::testing::UnorderedElementsAre;
@@ -215,6 +217,59 @@
EXPECT_THAT(set2, UnorderedElementsAre(Elem(7, -70), Elem(17, 23)));
}
+bool FirstIsEven(std::pair<const int, int> p) { return p.first % 2 == 0; }
+
+TEST(NodeHashMap, EraseIf) {
+ // Erase all elements.
+ {
+ node_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+ erase_if(s, [](std::pair<const int, int>) { return true; });
+ EXPECT_THAT(s, IsEmpty());
+ }
+ // Erase no elements.
+ {
+ node_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+ erase_if(s, [](std::pair<const int, int>) { return false; });
+ EXPECT_THAT(s, UnorderedElementsAre(Pair(1, 1), Pair(2, 2), Pair(3, 3),
+ Pair(4, 4), Pair(5, 5)));
+ }
+ // Erase specific elements.
+ {
+ node_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+ erase_if(s,
+ [](std::pair<const int, int> kvp) { return kvp.first % 2 == 1; });
+ EXPECT_THAT(s, UnorderedElementsAre(Pair(2, 2), Pair(4, 4)));
+ }
+ // Predicate is function reference.
+ {
+ node_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+ erase_if(s, FirstIsEven);
+ EXPECT_THAT(s, UnorderedElementsAre(Pair(1, 1), Pair(3, 3), Pair(5, 5)));
+ }
+ // Predicate is function pointer.
+ {
+ node_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+ erase_if(s, &FirstIsEven);
+ EXPECT_THAT(s, UnorderedElementsAre(Pair(1, 1), Pair(3, 3), Pair(5, 5)));
+ }
+}
+
+// This test requires std::launder for mutable key access in node handles.
+#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
+TEST(NodeHashMap, NodeHandleMutableKeyAccess) {
+ node_hash_map<std::string, std::string> map;
+
+ map["key1"] = "mapped";
+
+ auto nh = map.extract(map.begin());
+ nh.key().resize(3);
+ map.insert(std::move(nh));
+
+ EXPECT_THAT(map, testing::ElementsAre(Pair("key", "mapped")));
+}
+#endif
+
} // namespace
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/container/node_hash_set.h b/third_party/abseil/absl/container/node_hash_set.h
index 0cd1fe5..93b15f4 100644
--- a/third_party/abseil/absl/container/node_hash_set.h
+++ b/third_party/abseil/absl/container/node_hash_set.h
@@ -18,7 +18,7 @@
//
// An `absl::node_hash_set<T>` is an unordered associative container designed to
// be a more efficient replacement for `std::unordered_set`. Like
-// `unordered_set`, search, insertion, and deletion of map elements can be done
+// `unordered_set`, search, insertion, and deletion of set elements can be done
// as an `O(1)` operation. However, `node_hash_set` (and other unordered
// associative containers known as the collection of Abseil "Swiss tables")
// contain other optimizations that result in both memory and computation
@@ -44,6 +44,7 @@
#include "absl/memory/memory.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
template <typename T>
struct NodeHashSetPolicy;
@@ -59,7 +60,7 @@
// following notable differences:
//
// * Supports heterogeneous lookup, through `find()`, `operator[]()` and
-// `insert()`, provided that the map is provided a compatible heterogeneous
+// `insert()`, provided that the set is provided a compatible heterogeneous
// hashing function and equality operator.
// * Contains a `capacity()` member function indicating the number of element
// slots (open, deleted, and empty) within the hash set.
@@ -75,13 +76,13 @@
// Example:
//
// // Create a node hash set of three strings
-// absl::node_hash_map<std::string, std::string> ducks =
-// {"huey", "dewey"}, "louie"};
+// absl::node_hash_set<std::string> ducks =
+// {"huey", "dewey", "louie"};
//
-// // Insert a new element into the node hash map
-// ducks.insert("donald"};
+// // Insert a new element into the node hash set
+// ducks.insert("donald");
//
-// // Force a rehash of the node hash map
+// // Force a rehash of the node hash set
// ducks.rehash(0);
//
// // See if "dewey" is present
@@ -99,7 +100,7 @@
public:
// Constructors and Assignment Operators
//
- // A node_hash_set supports the same overload set as `std::unordered_map`
+ // A node_hash_set supports the same overload set as `std::unordered_set`
// for construction and assignment:
//
// * Default constructor
@@ -110,7 +111,7 @@
// * Initializer List constructor
//
// absl::node_hash_set<std::string> set2 =
- // {{"huey"}, {"dewey"}, {"louie"},};
+ // {{"huey"}, {"dewey"}, {"louie"}};
//
// * Copy constructor
//
@@ -166,7 +167,7 @@
// available within the `node_hash_set`.
//
// NOTE: this member function is particular to `absl::node_hash_set` and is
- // not provided in the `std::unordered_map` API.
+ // not provided in the `std::unordered_set` API.
using Base::capacity;
// node_hash_set::empty()
@@ -207,7 +208,7 @@
// `void`.
//
// NOTE: this return behavior is different than that of STL containers in
- // general and `std::unordered_map` in particular.
+ // general and `std::unordered_set` in particular.
//
// iterator erase(const_iterator first, const_iterator last):
//
@@ -216,7 +217,8 @@
//
// size_type erase(const key_type& key):
//
- // Erases the element with the matching key, if it exists.
+ // Erases the element with the matching key, if it exists, returning the
+ // number of elements erased (0 or 1).
using Base::erase;
// node_hash_set::insert()
@@ -312,7 +314,7 @@
// node_hash_set::merge()
//
- // Extracts elements from a given `source` flat hash map into this
+ // Extracts elements from a given `source` node hash set into this
// `node_hash_set`. If the destination `node_hash_set` already contains an
// element with an equivalent key, that element is not extracted.
using Base::merge;
@@ -320,15 +322,15 @@
// node_hash_set::swap(node_hash_set& other)
//
// Exchanges the contents of this `node_hash_set` with those of the `other`
- // flat hash map, avoiding invocation of any move, copy, or swap operations on
+ // node hash set, avoiding invocation of any move, copy, or swap operations on
// individual elements.
//
// All iterators and references on the `node_hash_set` remain valid, excepting
// for the past-the-end iterator, which is invalidated.
//
- // `swap()` requires that the flat hash set's hashing and key equivalence
+ // `swap()` requires that the node hash set's hashing and key equivalence
// functions be Swappable, and are exchaged using unqualified calls to
- // non-member `swap()`. If the map's allocator has
+ // non-member `swap()`. If the set's allocator has
// `std::allocator_traits<allocator_type>::propagate_on_container_swap::value`
// set to `true`, the allocators are also exchanged using an unqualified call
// to non-member `swap()`; otherwise, the allocators are not swapped.
@@ -383,14 +385,14 @@
// node_hash_set::bucket_count()
//
// Returns the number of "buckets" within the `node_hash_set`. Note that
- // because a flat hash map contains all elements within its internal storage,
+ // because a node hash set contains all elements within its internal storage,
// this value simply equals the current capacity of the `node_hash_set`.
using Base::bucket_count;
// node_hash_set::load_factor()
//
// Returns the current load factor of the `node_hash_set` (the average number
- // of slots occupied with a value within the hash map).
+ // of slots occupied with a value within the hash set).
using Base::load_factor;
// node_hash_set::max_load_factor()
@@ -426,14 +428,16 @@
//
// Returns the function used for comparing keys equality.
using Base::key_eq;
-
- ABSL_DEPRECATED("Call `hash_function()` instead.")
- typename Base::hasher hash_funct() { return this->hash_function(); }
-
- ABSL_DEPRECATED("Call `rehash()` instead.")
- void resize(typename Base::size_type hint) { this->rehash(hint); }
};
+// erase_if(node_hash_set<>, Pred)
+//
+// Erases all elements that satisfy the predicate `pred` from the container `c`.
+template <typename T, typename H, typename E, typename A, typename Predicate>
+void erase_if(node_hash_set<T, H, E, A>& c, Predicate pred) {
+ container_internal::EraseIf(pred, &c);
+}
+
namespace container_internal {
template <class T>
@@ -483,6 +487,7 @@
: std::true_type {};
} // namespace container_algorithm_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CONTAINER_NODE_HASH_SET_H_
diff --git a/third_party/abseil/absl/container/node_hash_set_test.cc b/third_party/abseil/absl/container/node_hash_set_test.cc
index 0ea76e7..7ddad20 100644
--- a/third_party/abseil/absl/container/node_hash_set_test.cc
+++ b/third_party/abseil/absl/container/node_hash_set_test.cc
@@ -20,10 +20,12 @@
#include "absl/container/internal/unordered_set_modifiers_test.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace {
using ::absl::container_internal::hash_internal::Enum;
using ::absl::container_internal::hash_internal::EnumClass;
+using ::testing::IsEmpty;
using ::testing::Pointee;
using ::testing::UnorderedElementsAre;
@@ -100,6 +102,42 @@
EXPECT_THAT(set2, UnorderedElementsAre(Pointee(7), Pointee(23)));
}
+bool IsEven(int k) { return k % 2 == 0; }
+
+TEST(NodeHashSet, EraseIf) {
+ // Erase all elements.
+ {
+ node_hash_set<int> s = {1, 2, 3, 4, 5};
+ erase_if(s, [](int) { return true; });
+ EXPECT_THAT(s, IsEmpty());
+ }
+ // Erase no elements.
+ {
+ node_hash_set<int> s = {1, 2, 3, 4, 5};
+ erase_if(s, [](int) { return false; });
+ EXPECT_THAT(s, UnorderedElementsAre(1, 2, 3, 4, 5));
+ }
+ // Erase specific elements.
+ {
+ node_hash_set<int> s = {1, 2, 3, 4, 5};
+ erase_if(s, [](int k) { return k % 2 == 1; });
+ EXPECT_THAT(s, UnorderedElementsAre(2, 4));
+ }
+ // Predicate is function reference.
+ {
+ node_hash_set<int> s = {1, 2, 3, 4, 5};
+ erase_if(s, IsEven);
+ EXPECT_THAT(s, UnorderedElementsAre(1, 3, 5));
+ }
+ // Predicate is function pointer.
+ {
+ node_hash_set<int> s = {1, 2, 3, 4, 5};
+ erase_if(s, &IsEven);
+ EXPECT_THAT(s, UnorderedElementsAre(1, 3, 5));
+ }
+}
+
} // namespace
} // namespace container_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/copts/AbseilConfigureCopts.cmake b/third_party/abseil/absl/copts/AbseilConfigureCopts.cmake
index b430873..acd46d0 100644
--- a/third_party/abseil/absl/copts/AbseilConfigureCopts.cmake
+++ b/third_party/abseil/absl/copts/AbseilConfigureCopts.cmake
@@ -5,10 +5,36 @@
set(ABSL_HAVE_LSAN OFF)
set(ABSL_DEFAULT_LINKOPTS "")
+if (BUILD_SHARED_LIBS AND MSVC)
+ set(ABSL_BUILD_DLL TRUE)
+ set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
+else()
+ set(ABSL_BUILD_DLL FALSE)
+endif()
+
+if("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "x86_64|amd64|AMD64")
+ if (MSVC)
+ set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_MSVC_X64_FLAGS}")
+ else()
+ set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_X64_FLAGS}")
+ endif()
+elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "arm.*|aarch64")
+ if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
+ set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_ARM64_FLAGS}")
+ elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4")
+ set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_ARM32_FLAGS}")
+ else()
+ message(WARNING "Value of CMAKE_SIZEOF_VOID_P (${CMAKE_SIZEOF_VOID_P}) is not supported.")
+ endif()
+else()
+ message(WARNING "Value of CMAKE_SYSTEM_PROCESSOR (${CMAKE_SYSTEM_PROCESSOR}) is unknown and cannot be used to set ABSL_RANDOM_RANDEN_COPTS")
+ set(ABSL_RANDOM_RANDEN_COPTS "")
+endif()
+
+
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(ABSL_DEFAULT_COPTS "${ABSL_GCC_FLAGS}")
set(ABSL_TEST_COPTS "${ABSL_GCC_FLAGS};${ABSL_GCC_TEST_FLAGS}")
- set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_X64_FLAGS}")
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
# MATCHES so we get both Clang and AppleClang
if(MSVC)
@@ -16,11 +42,9 @@
set(ABSL_DEFAULT_COPTS "${ABSL_CLANG_CL_FLAGS}")
set(ABSL_TEST_COPTS "${ABSL_CLANG_CL_FLAGS};${ABSL_CLANG_CL_TEST_FLAGS}")
set(ABSL_DEFAULT_LINKOPTS "${ABSL_MSVC_LINKOPTS}")
- set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_MSVC_X64_FLAGS}")
else()
set(ABSL_DEFAULT_COPTS "${ABSL_LLVM_FLAGS}")
set(ABSL_TEST_COPTS "${ABSL_LLVM_FLAGS};${ABSL_LLVM_TEST_FLAGS}")
- set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_X64_FLAGS}")
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# AppleClang doesn't have lsan
# https://developer.apple.com/documentation/code_diagnostics
@@ -34,19 +58,10 @@
set(ABSL_DEFAULT_COPTS "${ABSL_MSVC_FLAGS}")
set(ABSL_TEST_COPTS "${ABSL_MSVC_FLAGS};${ABSL_MSVC_TEST_FLAGS}")
set(ABSL_DEFAULT_LINKOPTS "${ABSL_MSVC_LINKOPTS}")
- set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_MSVC_X64_FLAGS}")
else()
message(WARNING "Unknown compiler: ${CMAKE_CXX_COMPILER}. Building with no default flags")
set(ABSL_DEFAULT_COPTS "")
set(ABSL_TEST_COPTS "")
- set(ABSL_RANDOM_RANDEN_COPTS "")
endif()
-if("${CMAKE_CXX_STANDARD}" EQUAL 98)
- message(FATAL_ERROR "Abseil requires at least C++11")
-elseif(NOT "${CMAKE_CXX_STANDARD}")
- message(STATUS "No CMAKE_CXX_STANDARD set, assuming 11")
- set(ABSL_CXX_STANDARD 11)
-else()
- set(ABSL_CXX_STANDARD "${CMAKE_CXX_STANDARD}")
-endif()
+set(ABSL_CXX_STANDARD "${CMAKE_CXX_STANDARD}")
diff --git a/third_party/abseil/absl/copts/GENERATED_AbseilCopts.cmake b/third_party/abseil/absl/copts/GENERATED_AbseilCopts.cmake
index 39b79c5..51742c9 100644
--- a/third_party/abseil/absl/copts/GENERATED_AbseilCopts.cmake
+++ b/third_party/abseil/absl/copts/GENERATED_AbseilCopts.cmake
@@ -5,48 +5,6 @@
list(APPEND ABSL_CLANG_CL_FLAGS
"/W3"
- "-Wno-c++98-compat-pedantic"
- "-Wno-conversion"
- "-Wno-covered-switch-default"
- "-Wno-deprecated"
- "-Wno-disabled-macro-expansion"
- "-Wno-double-promotion"
- "-Wno-comma"
- "-Wno-extra-semi"
- "-Wno-extra-semi-stmt"
- "-Wno-packed"
- "-Wno-padded"
- "-Wno-sign-compare"
- "-Wno-float-conversion"
- "-Wno-float-equal"
- "-Wno-format-nonliteral"
- "-Wno-gcc-compat"
- "-Wno-global-constructors"
- "-Wno-exit-time-destructors"
- "-Wno-nested-anon-types"
- "-Wno-non-modular-include-in-module"
- "-Wno-old-style-cast"
- "-Wno-range-loop-analysis"
- "-Wno-reserved-id-macro"
- "-Wno-shorten-64-to-32"
- "-Wno-switch-enum"
- "-Wno-thread-safety-negative"
- "-Wno-unknown-warning-option"
- "-Wno-unreachable-code"
- "-Wno-unused-macros"
- "-Wno-weak-vtables"
- "-Wno-zero-as-null-pointer-constant"
- "-Wbitfield-enum-conversion"
- "-Wbool-conversion"
- "-Wconstant-conversion"
- "-Wenum-conversion"
- "-Wint-conversion"
- "-Wliteral-conversion"
- "-Wnon-literal-null-conversion"
- "-Wnull-conversion"
- "-Wobjc-literal-conversion"
- "-Wno-sign-conversion"
- "-Wstring-conversion"
"/DNOMINMAX"
"/DWIN32_LEAN_AND_MEAN"
"/D_CRT_SECURE_NO_WARNINGS"
@@ -79,16 +37,17 @@
"-Wextra"
"-Wcast-qual"
"-Wconversion-null"
+ "-Wformat-security"
"-Wmissing-declarations"
"-Woverlength-strings"
"-Wpointer-arith"
+ "-Wundef"
"-Wunused-local-typedefs"
"-Wunused-result"
"-Wvarargs"
"-Wvla"
"-Wwrite-strings"
- "-Wno-missing-field-initializers"
- "-Wno-sign-compare"
+ "-DNOMINMAX"
)
list(APPEND ABSL_GCC_TEST_FLAGS
@@ -104,49 +63,37 @@
list(APPEND ABSL_LLVM_FLAGS
"-Wall"
"-Wextra"
- "-Weverything"
- "-Wno-c++98-compat-pedantic"
- "-Wno-conversion"
- "-Wno-covered-switch-default"
- "-Wno-deprecated"
- "-Wno-disabled-macro-expansion"
- "-Wno-double-promotion"
- "-Wno-comma"
- "-Wno-extra-semi"
- "-Wno-extra-semi-stmt"
- "-Wno-packed"
- "-Wno-padded"
- "-Wno-sign-compare"
- "-Wno-float-conversion"
- "-Wno-float-equal"
- "-Wno-format-nonliteral"
- "-Wno-gcc-compat"
- "-Wno-global-constructors"
- "-Wno-exit-time-destructors"
- "-Wno-nested-anon-types"
- "-Wno-non-modular-include-in-module"
- "-Wno-old-style-cast"
- "-Wno-range-loop-analysis"
- "-Wno-reserved-id-macro"
- "-Wno-shorten-64-to-32"
- "-Wno-switch-enum"
- "-Wno-thread-safety-negative"
- "-Wno-unknown-warning-option"
- "-Wno-unreachable-code"
- "-Wno-unused-macros"
- "-Wno-weak-vtables"
- "-Wno-zero-as-null-pointer-constant"
- "-Wbitfield-enum-conversion"
- "-Wbool-conversion"
- "-Wconstant-conversion"
- "-Wenum-conversion"
- "-Wint-conversion"
+ "-Wcast-qual"
+ "-Wconversion"
+ "-Wfloat-overflow-conversion"
+ "-Wfloat-zero-conversion"
+ "-Wfor-loop-analysis"
+ "-Wformat-security"
+ "-Wgnu-redeclared-enum"
+ "-Winfinite-recursion"
"-Wliteral-conversion"
- "-Wnon-literal-null-conversion"
- "-Wnull-conversion"
- "-Wobjc-literal-conversion"
- "-Wno-sign-conversion"
+ "-Wmissing-declarations"
+ "-Woverlength-strings"
+ "-Wpointer-arith"
+ "-Wself-assign"
+ "-Wshadow"
"-Wstring-conversion"
+ "-Wtautological-overlap-compare"
+ "-Wundef"
+ "-Wuninitialized"
+ "-Wunreachable-code"
+ "-Wunused-comparison"
+ "-Wunused-local-typedefs"
+ "-Wunused-result"
+ "-Wvla"
+ "-Wwrite-strings"
+ "-Wno-float-conversion"
+ "-Wno-implicit-float-conversion"
+ "-Wno-implicit-int-float-conversion"
+ "-Wno-implicit-int-conversion"
+ "-Wno-shorten-64-to-32"
+ "-Wno-sign-conversion"
+ "-DNOMINMAX"
)
list(APPEND ABSL_LLVM_TEST_FLAGS
diff --git a/third_party/abseil/absl/copts/GENERATED_copts.bzl b/third_party/abseil/absl/copts/GENERATED_copts.bzl
index 7d645cc..b1eb874 100644
--- a/third_party/abseil/absl/copts/GENERATED_copts.bzl
+++ b/third_party/abseil/absl/copts/GENERATED_copts.bzl
@@ -6,48 +6,6 @@
ABSL_CLANG_CL_FLAGS = [
"/W3",
- "-Wno-c++98-compat-pedantic",
- "-Wno-conversion",
- "-Wno-covered-switch-default",
- "-Wno-deprecated",
- "-Wno-disabled-macro-expansion",
- "-Wno-double-promotion",
- "-Wno-comma",
- "-Wno-extra-semi",
- "-Wno-extra-semi-stmt",
- "-Wno-packed",
- "-Wno-padded",
- "-Wno-sign-compare",
- "-Wno-float-conversion",
- "-Wno-float-equal",
- "-Wno-format-nonliteral",
- "-Wno-gcc-compat",
- "-Wno-global-constructors",
- "-Wno-exit-time-destructors",
- "-Wno-nested-anon-types",
- "-Wno-non-modular-include-in-module",
- "-Wno-old-style-cast",
- "-Wno-range-loop-analysis",
- "-Wno-reserved-id-macro",
- "-Wno-shorten-64-to-32",
- "-Wno-switch-enum",
- "-Wno-thread-safety-negative",
- "-Wno-unknown-warning-option",
- "-Wno-unreachable-code",
- "-Wno-unused-macros",
- "-Wno-weak-vtables",
- "-Wno-zero-as-null-pointer-constant",
- "-Wbitfield-enum-conversion",
- "-Wbool-conversion",
- "-Wconstant-conversion",
- "-Wenum-conversion",
- "-Wint-conversion",
- "-Wliteral-conversion",
- "-Wnon-literal-null-conversion",
- "-Wnull-conversion",
- "-Wobjc-literal-conversion",
- "-Wno-sign-conversion",
- "-Wstring-conversion",
"/DNOMINMAX",
"/DWIN32_LEAN_AND_MEAN",
"/D_CRT_SECURE_NO_WARNINGS",
@@ -80,16 +38,17 @@
"-Wextra",
"-Wcast-qual",
"-Wconversion-null",
+ "-Wformat-security",
"-Wmissing-declarations",
"-Woverlength-strings",
"-Wpointer-arith",
+ "-Wundef",
"-Wunused-local-typedefs",
"-Wunused-result",
"-Wvarargs",
"-Wvla",
"-Wwrite-strings",
- "-Wno-missing-field-initializers",
- "-Wno-sign-compare",
+ "-DNOMINMAX",
]
ABSL_GCC_TEST_FLAGS = [
@@ -105,49 +64,38 @@
ABSL_LLVM_FLAGS = [
"-Wall",
"-Wextra",
- "-Weverything",
- "-Wno-c++98-compat-pedantic",
+ "-Wcast-qual",
"-Wno-conversion",
- "-Wno-covered-switch-default",
- "-Wno-deprecated",
- "-Wno-disabled-macro-expansion",
- "-Wno-double-promotion",
- "-Wno-comma",
- "-Wno-extra-semi",
- "-Wno-extra-semi-stmt",
- "-Wno-packed",
- "-Wno-padded",
- "-Wno-sign-compare",
- "-Wno-float-conversion",
- "-Wno-float-equal",
- "-Wno-format-nonliteral",
- "-Wno-gcc-compat",
- "-Wno-global-constructors",
- "-Wno-exit-time-destructors",
- "-Wno-nested-anon-types",
- "-Wno-non-modular-include-in-module",
- "-Wno-old-style-cast",
- "-Wno-range-loop-analysis",
- "-Wno-reserved-id-macro",
- "-Wno-shorten-64-to-32",
- "-Wno-switch-enum",
- "-Wno-thread-safety-negative",
- "-Wno-unknown-warning-option",
- "-Wno-unreachable-code",
- "-Wno-unused-macros",
- "-Wno-weak-vtables",
- "-Wno-zero-as-null-pointer-constant",
- "-Wbitfield-enum-conversion",
- "-Wbool-conversion",
- "-Wconstant-conversion",
- "-Wenum-conversion",
- "-Wint-conversion",
+ "-Wfloat-overflow-conversion",
+ "-Wfloat-zero-conversion",
+ "-Wfor-loop-analysis",
+ "-Wformat-security",
+ "-Wgnu-redeclared-enum",
+ "-Winfinite-recursion",
"-Wliteral-conversion",
- "-Wnon-literal-null-conversion",
- "-Wnull-conversion",
- "-Wobjc-literal-conversion",
- "-Wno-sign-conversion",
+ "-Wmissing-declarations",
+ "-Woverlength-strings",
+ "-Wpointer-arith",
+ "-Wself-assign",
+ "-Wshadow",
"-Wstring-conversion",
+ "-Wtautological-overlap-compare",
+ "-Wundef",
+ "-Wuninitialized",
+ "-Wunreachable-code",
+ "-Wunused-comparison",
+ "-Wunused-local-typedefs",
+ "-Wunused-result",
+ "-Wvla",
+ "-Wwrite-strings",
+ "-Wno-float-conversion",
+ "-Wno-implicit-float-conversion",
+ "-Wno-implicit-int-float-conversion",
+ "-Wno-implicit-int-conversion",
+ "-Wno-shorten-64-to-32",
+ "-Wno-sign-conversion",
+ "-DNOMINMAX",
+ "-Wno-unknown-warning-option",
]
ABSL_LLVM_TEST_FLAGS = [
diff --git a/third_party/abseil/absl/copts/configure_copts.bzl b/third_party/abseil/absl/copts/configure_copts.bzl
index 2829e4e..4d34254 100644
--- a/third_party/abseil/absl/copts/configure_copts.bzl
+++ b/third_party/abseil/absl/copts/configure_copts.bzl
@@ -6,6 +6,8 @@
load(
"//absl:copts/GENERATED_copts.bzl",
+ "ABSL_CLANG_CL_FLAGS",
+ "ABSL_CLANG_CL_TEST_FLAGS",
"ABSL_GCC_FLAGS",
"ABSL_GCC_TEST_FLAGS",
"ABSL_LLVM_FLAGS",
@@ -21,15 +23,13 @@
ABSL_DEFAULT_COPTS = select({
"//absl:windows": ABSL_MSVC_FLAGS,
- "//absl:llvm_compiler": ABSL_LLVM_FLAGS,
+ "//absl:clang_compiler": ABSL_LLVM_FLAGS,
"//conditions:default": ABSL_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": ABSL_MSVC_TEST_FLAGS,
- "//absl:llvm_compiler": ABSL_LLVM_TEST_FLAGS,
+ "//absl:clang_compiler": ABSL_LLVM_TEST_FLAGS,
"//conditions:default": ABSL_GCC_TEST_FLAGS,
})
@@ -46,7 +46,7 @@
":cpu_darwin": ABSL_RANDOM_HWAES_X64_FLAGS,
":cpu_x64_windows_msvc": ABSL_RANDOM_HWAES_MSVC_X64_FLAGS,
":cpu_x64_windows": ABSL_RANDOM_HWAES_MSVC_X64_FLAGS,
- ":cpu_haswell": ABSL_RANDOM_HWAES_X64_FLAGS,
+ ":cpu_k8": ABSL_RANDOM_HWAES_X64_FLAGS,
":cpu_ppc": ["-mcrypto"],
# Supported by default or unsupported.
@@ -63,7 +63,7 @@
# These configs have consistent flags to enable HWAES intsructions.
cpu_configs = [
"ppc",
- "haswell",
+ "k8",
"darwin_x86_64",
"darwin",
"x64_windows_msvc",
diff --git a/third_party/abseil/absl/copts/copts.py b/third_party/abseil/absl/copts/copts.py
index a542541..cf52981 100644
--- a/third_party/abseil/absl/copts/copts.py
+++ b/third_party/abseil/absl/copts/copts.py
@@ -16,78 +16,6 @@
"/W3",
]
-LLVM_BIG_WARNING_FLAGS = [
- "-Wall",
- "-Wextra",
- "-Weverything",
-]
-
-# Docs on single flags is preceded by a comment.
-# Docs on groups of flags is preceded by ###.
-LLVM_DISABLE_WARNINGS_FLAGS = [
- # Abseil does not support C++98
- "-Wno-c++98-compat-pedantic",
- # Turns off all implicit conversion warnings. Most are re-enabled below.
- "-Wno-conversion",
- "-Wno-covered-switch-default",
- "-Wno-deprecated",
- "-Wno-disabled-macro-expansion",
- "-Wno-double-promotion",
- ###
- # Turned off as they include valid C++ code.
- "-Wno-comma",
- "-Wno-extra-semi",
- "-Wno-extra-semi-stmt",
- "-Wno-packed",
- "-Wno-padded",
- ###
- # Google style does not use unsigned integers, though STL containers
- # have unsigned types.
- "-Wno-sign-compare",
- ###
- "-Wno-float-conversion",
- "-Wno-float-equal",
- "-Wno-format-nonliteral",
- # Too aggressive: warns on Clang extensions enclosed in Clang-only
- # compilation paths.
- "-Wno-gcc-compat",
- ###
- # Some internal globals are necessary. Don't do this at home.
- "-Wno-global-constructors",
- "-Wno-exit-time-destructors",
- ###
- "-Wno-nested-anon-types",
- "-Wno-non-modular-include-in-module",
- "-Wno-old-style-cast",
- # Warns on preferred usage of non-POD types such as string_view
- "-Wno-range-loop-analysis",
- "-Wno-reserved-id-macro",
- "-Wno-shorten-64-to-32",
- "-Wno-switch-enum",
- "-Wno-thread-safety-negative",
- "-Wno-unknown-warning-option",
- "-Wno-unreachable-code",
- # Causes warnings on include guards
- "-Wno-unused-macros",
- "-Wno-weak-vtables",
- # Causes warnings on usage of types/compare.h comparison operators.
- "-Wno-zero-as-null-pointer-constant",
- ###
- # Implicit conversion warnings turned off by -Wno-conversion
- # which are re-enabled below.
- "-Wbitfield-enum-conversion",
- "-Wbool-conversion",
- "-Wconstant-conversion",
- "-Wenum-conversion",
- "-Wint-conversion",
- "-Wliteral-conversion",
- "-Wnon-literal-null-conversion",
- "-Wnull-conversion",
- "-Wobjc-literal-conversion",
- "-Wno-sign-conversion",
- "-Wstring-conversion",
-]
-
LLVM_TEST_DISABLE_WARNINGS_FLAGS = [
"-Wno-c99-extensions",
"-Wno-deprecated-declarations",
@@ -126,21 +54,18 @@
"-Wextra",
"-Wcast-qual",
"-Wconversion-null",
+ "-Wformat-security",
"-Wmissing-declarations",
"-Woverlength-strings",
"-Wpointer-arith",
+ "-Wundef",
"-Wunused-local-typedefs",
"-Wunused-result",
"-Wvarargs",
"-Wvla", # variable-length array
"-Wwrite-strings",
- # gcc-4.x has spurious missing field initializer warnings.
- # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36750
- # Remove when gcc-4.x is no longer supported.
- "-Wno-missing-field-initializers",
- # Google style does not use unsigned integers, though STL containers
- # have unsigned types.
- "-Wno-sign-compare",
+ # Don't define min and max macros (Build on Windows using gcc)
+ "-DNOMINMAX",
],
"ABSL_GCC_TEST_FLAGS": [
"-Wno-conversion-null",
@@ -151,12 +76,48 @@
"-Wno-unused-parameter",
"-Wno-unused-private-field",
],
- "ABSL_LLVM_FLAGS":
- LLVM_BIG_WARNING_FLAGS + LLVM_DISABLE_WARNINGS_FLAGS,
+ "ABSL_LLVM_FLAGS": [
+ "-Wall",
+ "-Wextra",
+ "-Wcast-qual",
+ "-Wconversion",
+ "-Wfloat-overflow-conversion",
+ "-Wfloat-zero-conversion",
+ "-Wfor-loop-analysis",
+ "-Wformat-security",
+ "-Wgnu-redeclared-enum",
+ "-Winfinite-recursion",
+ "-Wliteral-conversion",
+ "-Wmissing-declarations",
+ "-Woverlength-strings",
+ "-Wpointer-arith",
+ "-Wself-assign",
+ "-Wshadow",
+ "-Wstring-conversion",
+ "-Wtautological-overlap-compare",
+ "-Wundef",
+ "-Wuninitialized",
+ "-Wunreachable-code",
+ "-Wunused-comparison",
+ "-Wunused-local-typedefs",
+ "-Wunused-result",
+ "-Wvla",
+ "-Wwrite-strings",
+ # Warnings that are enabled by group warning flags like -Wall that we
+ # explicitly disable.
+ "-Wno-float-conversion",
+ "-Wno-implicit-float-conversion",
+ "-Wno-implicit-int-float-conversion",
+ "-Wno-implicit-int-conversion",
+ "-Wno-shorten-64-to-32",
+ "-Wno-sign-conversion",
+ # Don't define min and max macros (Build on Windows using clang)
+ "-DNOMINMAX",
+ ],
"ABSL_LLVM_TEST_FLAGS":
LLVM_TEST_DISABLE_WARNINGS_FLAGS,
"ABSL_CLANG_CL_FLAGS":
- (MSVC_BIG_WARNING_FLAGS + LLVM_DISABLE_WARNINGS_FLAGS + MSVC_DEFINES),
+ (MSVC_BIG_WARNING_FLAGS + MSVC_DEFINES),
"ABSL_CLANG_CL_TEST_FLAGS":
LLVM_TEST_DISABLE_WARNINGS_FLAGS,
"ABSL_MSVC_FLAGS":
diff --git a/third_party/abseil/absl/debugging/BUILD.bazel b/third_party/abseil/absl/debugging/BUILD.bazel
index 3df2a8f..cd6e454 100644
--- a/third_party/abseil/absl/debugging/BUILD.bazel
+++ b/third_party/abseil/absl/debugging/BUILD.bazel
@@ -14,7 +14,7 @@
# limitations under the License.
#
-#load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load(
"//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
@@ -26,11 +26,19 @@
default_visibility = ["//visibility:public"],
)
-licenses(["notice"]) # Apache 2.0
+licenses(["notice"])
cc_library(
name = "stacktrace",
srcs = [
+ "internal/stacktrace_aarch64-inl.inc",
+ "internal/stacktrace_arm-inl.inc",
+ "internal/stacktrace_config.h",
+ "internal/stacktrace_generic-inl.inc",
+ "internal/stacktrace_powerpc-inl.inc",
+ "internal/stacktrace_unimplemented-inl.inc",
+ "internal/stacktrace_win32-inl.inc",
+ "internal/stacktrace_x86-inl.inc",
"stacktrace.cc",
],
hdrs = ["stacktrace.h"],
@@ -38,6 +46,7 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":debugging_internal",
+ "//absl/base:config",
"//absl/base:core_headers",
],
)
@@ -46,6 +55,7 @@
name = "symbolize",
srcs = [
"symbolize.cc",
+ "symbolize_darwin.inc",
"symbolize_elf.inc",
"symbolize_unimplemented.inc",
"symbolize_win32.inc",
@@ -55,30 +65,43 @@
"symbolize.h",
],
copts = ABSL_DEFAULT_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS + select({
+ "//absl:windows": ["-DEFAULTLIB:dbghelp.lib"],
+ "//conditions:default": [],
+ }),
deps = [
":debugging_internal",
":demangle_internal",
"//absl/base",
+ "//absl/base:config",
"//absl/base:core_headers",
"//absl/base:dynamic_annotations",
"//absl/base:malloc_internal",
"//absl/base:raw_logging_internal",
+ "//absl/strings",
],
)
cc_test(
name = "symbolize_test",
srcs = ["symbolize_test.cc"],
- copts = ABSL_TEST_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
+ copts = ABSL_TEST_COPTS + select({
+ "//absl:windows": ["/Z7"],
+ "//conditions:default": [],
+ }),
+ linkopts = ABSL_DEFAULT_LINKOPTS + select({
+ "//absl:windows": ["/DEBUG"],
+ "//conditions:default": [],
+ }),
deps = [
":stack_consumption",
":symbolize",
"//absl/base",
+ "//absl/base:config",
"//absl/base:core_headers",
"//absl/base:raw_logging_internal",
"//absl/memory",
+ "//absl/strings",
"@com_google_googletest//:gtest",
],
)
@@ -97,6 +120,7 @@
deps = [
":stacktrace",
":symbolize",
+ "//absl/base:config",
"//absl/base:core_headers",
"//absl/base:raw_logging_internal",
],
@@ -114,6 +138,7 @@
"//absl/base",
"//absl/base:config",
"//absl/base:core_headers",
+ "//absl/base:errno_saver",
"//absl/base:raw_logging_internal",
],
)
@@ -122,7 +147,11 @@
name = "failure_signal_handler_test",
srcs = ["failure_signal_handler_test.cc"],
copts = ABSL_TEST_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
+ linkopts = select({
+ "//absl:windows": [],
+ "//absl:wasm": [],
+ "//conditions:default": ["-pthread"],
+ }) + ABSL_DEFAULT_LINKOPTS,
deps = [
":failure_signal_handler",
":stacktrace",
@@ -143,21 +172,15 @@
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_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,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
+ "//absl/base:config",
"//absl/base:core_headers",
"//absl/base:dynamic_annotations",
+ "//absl/base:errno_saver",
"//absl/base:raw_logging_internal",
],
)
@@ -169,6 +192,7 @@
copts = ABSL_DEFAULT_COPTS,
deps = [
"//absl/base",
+ "//absl/base:config",
"//absl/base:core_headers",
],
)
@@ -181,6 +205,7 @@
deps = [
":demangle_internal",
":stack_consumption",
+ "//absl/base:config",
"//absl/base:core_headers",
"//absl/base:raw_logging_internal",
"//absl/memory",
@@ -193,7 +218,10 @@
srcs = ["leak_check.cc"],
hdrs = ["leak_check.h"],
linkopts = ABSL_DEFAULT_LINKOPTS,
- deps = ["//absl/base:core_headers"],
+ deps = [
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ ],
)
# Adding a dependency to leak_check_disable will disable
@@ -204,13 +232,14 @@
srcs = ["leak_check_disable.cc"],
linkopts = ABSL_DEFAULT_LINKOPTS,
linkstatic = 1,
+ deps = ["//absl/base:config"],
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"],
+ "//absl:clang_compiler": ["-fsanitize=leak"],
"//conditions:default": [],
})
@@ -220,11 +249,14 @@
srcs = ["leak_check.cc"],
hdrs = ["leak_check.h"],
copts = select({
- "//absl:llvm_compiler": ["-DLEAK_SANITIZER"],
+ "//absl:clang_compiler": ["-DLEAK_SANITIZER"],
"//conditions:default": [],
}),
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = ["//visibility:private"],
+ deps = [
+ "//absl/base:config",
+ ],
)
cc_library(
@@ -235,13 +267,16 @@
copts = ["-ULEAK_SANITIZER"],
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = ["//visibility:private"],
+ deps = [
+ "//absl/base:config",
+ ],
)
cc_test(
name = "leak_check_test",
srcs = ["leak_check_test.cc"],
copts = select({
- "//absl:llvm_compiler": ["-DABSL_EXPECT_LEAK_SANITIZER"],
+ "//absl:clang_compiler": ["-DABSL_EXPECT_LEAK_SANITIZER"],
"//conditions:default": [],
}),
linkopts = ABSL_LSAN_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
@@ -292,6 +327,7 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = ["//visibility:private"],
deps = [
+ "//absl/base:config",
"//absl/base:core_headers",
"//absl/base:raw_logging_internal",
],
diff --git a/third_party/abseil/absl/debugging/CMakeLists.txt b/third_party/abseil/absl/debugging/CMakeLists.txt
index c409e33..074b44c 100644
--- a/third_party/abseil/absl/debugging/CMakeLists.txt
+++ b/third_party/abseil/absl/debugging/CMakeLists.txt
@@ -19,12 +19,21 @@
stacktrace
HDRS
"stacktrace.h"
+ "internal/stacktrace_aarch64-inl.inc"
+ "internal/stacktrace_arm-inl.inc"
+ "internal/stacktrace_config.h"
+ "internal/stacktrace_generic-inl.inc"
+ "internal/stacktrace_powerpc-inl.inc"
+ "internal/stacktrace_unimplemented-inl.inc"
+ "internal/stacktrace_win32-inl.inc"
+ "internal/stacktrace_x86-inl.inc"
SRCS
"stacktrace.cc"
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
absl::debugging_internal
+ absl::config
absl::core_headers
PUBLIC
)
@@ -37,6 +46,7 @@
"internal/symbolize.h"
SRCS
"symbolize.cc"
+ "symbolize_darwin.inc"
"symbolize_elf.inc"
"symbolize_unimplemented.inc"
"symbolize_win32.inc"
@@ -44,14 +54,17 @@
${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
+ $<$<BOOL:${MINGW}>:"dbghelp">
DEPS
absl::debugging_internal
absl::demangle_internal
absl::base
+ absl::config
absl::core_headers
absl::dynamic_annotations
absl::malloc_internal
absl::raw_logging_internal
+ absl::strings
PUBLIC
)
@@ -62,13 +75,18 @@
"symbolize_test.cc"
COPTS
${ABSL_TEST_COPTS}
+ $<$<BOOL:${MSVC}>:-Z7>
+ LINKOPTS
+ $<$<BOOL:${MSVC}>:-DEBUG>
DEPS
absl::stack_consumption
absl::symbolize
absl::base
+ absl::config
absl::core_headers
absl::memory
absl::raw_logging_internal
+ absl::strings
gmock
)
@@ -84,6 +102,7 @@
DEPS
absl::stacktrace
absl::symbolize
+ absl::config
absl::core_headers
absl::raw_logging_internal
)
@@ -103,6 +122,7 @@
absl::base
absl::config
absl::core_headers
+ absl::errno_saver
absl::raw_logging_internal
PUBLIC
)
@@ -130,14 +150,6 @@
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_powerpc-inl.inc"
- "internal/stacktrace_unimplemented-inl.inc"
- "internal/stacktrace_win32-inl.inc"
- "internal/stacktrace_x86-inl.inc"
"internal/vdso_support.h"
SRCS
"internal/address_is_readable.cc"
@@ -147,7 +159,9 @@
${ABSL_DEFAULT_COPTS}
DEPS
absl::core_headers
+ absl::config
absl::dynamic_annotations
+ absl::errno_saver
absl::raw_logging_internal
)
@@ -176,6 +190,7 @@
DEPS
absl::demangle_internal
absl::stack_consumption
+ absl::config
absl::core_headers
absl::memory
absl::raw_logging_internal
@@ -192,6 +207,7 @@
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
+ absl::config
absl::core_headers
PUBLIC
)
@@ -238,7 +254,7 @@
SRCS
"leak_check_test.cc"
COPTS
- ${ABSL_DEFAULT_COPTS}
+ ${ABSL_TEST_COPTS}
"$<$<BOOL:${ABSL_HAVE_LSAN}>:-DABSL_EXPECT_LEAK_SANITIZER>"
LINKOPTS
"${ABSL_LSAN_LINKOPTS}"
@@ -289,6 +305,7 @@
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
+ absl::config
absl::core_headers
absl::raw_logging_internal
TESTONLY
diff --git a/third_party/abseil/absl/debugging/failure_signal_handler.cc b/third_party/abseil/absl/debugging/failure_signal_handler.cc
index c6a4d96..5d13bdb 100644
--- a/third_party/abseil/absl/debugging/failure_signal_handler.cc
+++ b/third_party/abseil/absl/debugging/failure_signal_handler.cc
@@ -24,6 +24,10 @@
#include <unistd.h>
#endif
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
#ifdef ABSL_HAVE_MMAP
#include <sys/mman.h>
#endif
@@ -37,6 +41,7 @@
#include <ctime>
#include "absl/base/attributes.h"
+#include "absl/base/internal/errno_saver.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/sysinfo.h"
#include "absl/debugging/internal/examine_stack.h"
@@ -44,9 +49,15 @@
#ifndef _WIN32
#define ABSL_HAVE_SIGACTION
+// Apple WatchOS and TVOS don't allow sigaltstack
+#if !(defined(TARGET_OS_WATCH) && TARGET_OS_WATCH) && \
+ !(defined(TARGET_OS_TV) && TARGET_OS_TV)
+#define ABSL_HAVE_SIGALTSTACK
+#endif
#endif
namespace absl {
+ABSL_NAMESPACE_BEGIN
ABSL_CONST_INIT static FailureSignalHandlerOptions fsh_options;
@@ -116,7 +127,7 @@
} // namespace debugging_internal
-#ifndef _WIN32
+#ifdef ABSL_HAVE_SIGALTSTACK
static bool SetupAlternateStackOnce() {
#if defined(__wasm__) || defined (__asjms__)
@@ -125,8 +136,8 @@
const size_t page_mask = sysconf(_SC_PAGESIZE) - 1;
#endif
size_t stack_size = (std::max(SIGSTKSZ, 65536) + page_mask) & ~page_mask;
-#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
- defined(THREAD_SANITIZER)
+#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \
+ defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER)
// Account for sanitizer instrumentation requiring additional stack space.
stack_size *= 5;
#endif
@@ -168,7 +179,7 @@
// Returns the appropriate flag for sig_action.sa_flags
// if the system supports using an alternate stack.
static int MaybeSetupAlternateStack() {
-#ifndef _WIN32
+#ifdef ABSL_HAVE_SIGALTSTACK
ABSL_ATTRIBUTE_UNUSED static const bool kOnce = SetupAlternateStackOnce();
return SA_ONSTACK;
#else
@@ -204,9 +215,8 @@
#endif
static void WriteToStderr(const char* data) {
- int old_errno = errno;
+ absl::base_internal::ErrnoSaver errno_saver;
absl::raw_logging_internal::SafeWriteToStderr(data, strlen(data));
- errno = old_errno;
}
static void WriteSignalMessage(int signo, void (*writerfn)(const char*)) {
@@ -356,4 +366,5 @@
}
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/debugging/failure_signal_handler.h b/third_party/abseil/absl/debugging/failure_signal_handler.h
index 1beb78b..0c0f585 100644
--- a/third_party/abseil/absl/debugging/failure_signal_handler.h
+++ b/third_party/abseil/absl/debugging/failure_signal_handler.h
@@ -44,7 +44,10 @@
#ifndef ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_
#define ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
// FailureSignalHandlerOptions
//
@@ -85,7 +88,7 @@
bool call_previous_handler = false;
// If non-null, indicates a pointer to a callback function that will be called
- // upon failure, with a std::string argument containing failure data. This function
+ // upon failure, with a string argument containing failure data. This function
// may be used as a hook to write failure data to a secondary location, such
// as a log file. This function may also be called with null data, as a hint
// to flush any buffered data before the program may be terminated. Consider
@@ -112,6 +115,7 @@
const char* FailureSignalToString(int signo);
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_
diff --git a/third_party/abseil/absl/debugging/failure_signal_handler_test.cc b/third_party/abseil/absl/debugging/failure_signal_handler_test.cc
index bb2cc48..d8283b2 100644
--- a/third_party/abseil/absl/debugging/failure_signal_handler_test.cc
+++ b/third_party/abseil/absl/debugging/failure_signal_handler_test.cc
@@ -23,6 +23,7 @@
#include <fstream>
#include "gtest/gtest.h"
+#include "gmock/gmock.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/debugging/stacktrace.h"
#include "absl/debugging/symbolize.h"
@@ -31,6 +32,8 @@
namespace {
+using testing::StartsWith;
+
#if GTEST_HAS_DEATH_TEST
// For the parameterized death tests. GetParam() returns the signal number.
@@ -52,7 +55,7 @@
exit_regex);
#else
// Windows doesn't have testing::KilledBySignal().
- EXPECT_DEATH(InstallHandlerAndRaise(signo), exit_regex);
+ EXPECT_DEATH_IF_SUPPORTED(InstallHandlerAndRaise(signo), exit_regex);
#endif
}
@@ -104,8 +107,8 @@
testing::KilledBySignal(signo), exit_regex);
#else
// Windows doesn't have testing::KilledBySignal().
- EXPECT_DEATH(InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo),
- exit_regex);
+ EXPECT_DEATH_IF_SUPPORTED(
+ InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo), exit_regex);
#endif
// Open the file in this process and check its contents.
@@ -113,15 +116,15 @@
ASSERT_TRUE(error_output.is_open()) << file;
std::string error_line;
std::getline(error_output, error_line);
- EXPECT_TRUE(absl::StartsWith(
+ EXPECT_THAT(
error_line,
- absl::StrCat("*** ",
- absl::debugging_internal::FailureSignalToString(signo),
- " received at ")));
+ StartsWith(absl::StrCat(
+ "*** ", absl::debugging_internal::FailureSignalToString(signo),
+ " received at ")));
if (absl::debugging_internal::StackTraceWorksForTest()) {
std::getline(error_output, error_line);
- EXPECT_TRUE(absl::StartsWith(error_line, "PC: "));
+ EXPECT_THAT(error_line, StartsWith("PC: "));
}
}
diff --git a/third_party/abseil/absl/debugging/internal/address_is_readable.cc b/third_party/abseil/absl/debugging/internal/address_is_readable.cc
index 99c4c64..329c285 100644
--- a/third_party/abseil/absl/debugging/internal/address_is_readable.cc
+++ b/third_party/abseil/absl/debugging/internal/address_is_readable.cc
@@ -20,12 +20,14 @@
#if !defined(__linux__) || defined(__ANDROID__)
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
// On platforms other than Linux, just return true.
bool AddressIsReadable(const void* /* addr */) { return true; }
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#else
@@ -33,13 +35,16 @@
#include <fcntl.h>
#include <sys/syscall.h>
#include <unistd.h>
+
#include <atomic>
#include <cerrno>
#include <cstdint>
+#include "absl/base/internal/errno_saver.h"
#include "absl/base/internal/raw_logging.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
// Pack a pid and two file descriptors into a 64-bit word,
@@ -63,8 +68,9 @@
// 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;
+ absl::base_internal::ErrnoSaver errno_saver;
// 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
@@ -81,7 +87,7 @@
int pid;
int read_fd;
int write_fd;
- uint64_t local_pid_and_fds = pid_and_fds.load(std::memory_order_relaxed);
+ uint64_t local_pid_and_fds = pid_and_fds.load(std::memory_order_acquire);
Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd);
while (current_pid != pid) {
int p[2];
@@ -93,13 +99,13 @@
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,
+ local_pid_and_fds, new_pid_and_fds, std::memory_order_release,
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);
+ local_pid_and_fds = pid_and_fds.load(std::memory_order_acquire);
}
Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd);
}
@@ -119,15 +125,15 @@
// 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_release,
std::memory_order_relaxed);
}
} while (errno == EBADF);
- errno = save_errno;
return bytes_written == 1;
}
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif
diff --git a/third_party/abseil/absl/debugging/internal/address_is_readable.h b/third_party/abseil/absl/debugging/internal/address_is_readable.h
index ca8003e..4bbaf4d 100644
--- a/third_party/abseil/absl/debugging/internal/address_is_readable.h
+++ b/third_party/abseil/absl/debugging/internal/address_is_readable.h
@@ -15,7 +15,10 @@
#ifndef ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
#define ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
// Return whether the byte at *addr is readable, without faulting.
@@ -23,6 +26,7 @@
bool AddressIsReadable(const void *addr);
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
diff --git a/third_party/abseil/absl/debugging/internal/demangle.cc b/third_party/abseil/absl/debugging/internal/demangle.cc
index 52a553f..46cdb67 100644
--- a/third_party/abseil/absl/debugging/internal/demangle.cc
+++ b/third_party/abseil/absl/debugging/internal/demangle.cc
@@ -24,6 +24,7 @@
#include <limits>
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
typedef struct {
@@ -93,6 +94,8 @@
};
// List of builtin types from Itanium C++ ABI.
+//
+// Invariant: only one- or two-character type abbreviations here.
static const AbbrevPair kBuiltinTypeList[] = {
{"v", "void", 0},
{"w", "wchar_t", 0},
@@ -115,6 +118,17 @@
{"e", "long double", 0},
{"g", "__float128", 0},
{"z", "ellipsis", 0},
+
+ {"De", "decimal128", 0}, // IEEE 754r decimal floating point (128 bits)
+ {"Dd", "decimal64", 0}, // IEEE 754r decimal floating point (64 bits)
+ {"Dc", "decltype(auto)", 0},
+ {"Da", "auto", 0},
+ {"Dn", "std::nullptr_t", 0}, // i.e., decltype(nullptr)
+ {"Df", "decimal32", 0}, // IEEE 754r decimal floating point (32 bits)
+ {"Di", "char32_t", 0},
+ {"Du", "char8_t", 0},
+ {"Ds", "char16_t", 0},
+ {"Dh", "float16", 0}, // IEEE 754r half-precision float (16 bits)
{nullptr, nullptr, 0},
};
@@ -138,7 +152,7 @@
// frame, so every byte counts.
typedef struct {
int mangled_idx; // Cursor of mangled name.
- int out_cur_idx; // Cursor of output std::string.
+ int out_cur_idx; // Cursor of output string.
int prev_name_idx; // For constructors/destructors.
signed int prev_name_length : 16; // For constructors/destructors.
signed int nest_level : 15; // For nested names.
@@ -159,8 +173,8 @@
// Only one copy of this exists for each call to Demangle, so the size of this
// struct is nearly inconsequential.
typedef struct {
- const char *mangled_begin; // Beginning of input std::string.
- char *out; // Beginning of output std::string.
+ const char *mangled_begin; // Beginning of input string.
+ char *out; // Beginning of output string.
int out_end_idx; // One past last allowed output character.
int recursion_depth; // For stack exhaustion prevention.
int steps; // Cap how much work we'll do, regardless of depth.
@@ -396,6 +410,7 @@
static bool EndsWith(State *state, const char chr) {
return state->parse_state.out_cur_idx > 0 &&
+ state->parse_state.out_cur_idx < state->out_end_idx &&
chr == state->out[state->parse_state.out_cur_idx - 1];
}
@@ -408,8 +423,10 @@
if (str[0] == '<' && EndsWith(state, '<')) {
Append(state, " ", 1);
}
- // Remember the last identifier name for ctors/dtors.
- if (IsAlpha(str[0]) || str[0] == '_') {
+ // Remember the last identifier name for ctors/dtors,
+ // but only if we haven't yet overflown the buffer.
+ if (state->parse_state.out_cur_idx < state->out_end_idx &&
+ (IsAlpha(str[0]) || str[0] == '_')) {
state->parse_state.prev_name_idx = state->parse_state.out_cur_idx;
state->parse_state.prev_name_length = length;
}
@@ -949,6 +966,7 @@
// ::= TT <type>
// ::= TI <type>
// ::= TS <type>
+// ::= TH <type> # thread-local
// ::= Tc <call-offset> <call-offset> <(base) encoding>
// ::= GV <(object) name>
// ::= T <call-offset> <(base) encoding>
@@ -967,7 +985,7 @@
ComplexityGuard guard(state);
if (guard.IsTooComplex()) return false;
ParseState copy = state->parse_state;
- if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "VTIS") &&
+ if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "VTISH") &&
ParseType(state)) {
return true;
}
@@ -1064,20 +1082,28 @@
return false;
}
-// <ctor-dtor-name> ::= C1 | C2 | C3
+// <ctor-dtor-name> ::= C1 | C2 | C3 | CI1 <base-class-type> | CI2
+// <base-class-type>
// ::= D0 | D1 | D2
// # GCC extensions: "unified" constructor/destructor. See
-// # https://github.com/gcc-mirror/gcc/blob/7ad17b583c3643bd4557f29b8391ca7ef08391f5/gcc/cp/mangle.c#L1847
+// #
+// https://github.com/gcc-mirror/gcc/blob/7ad17b583c3643bd4557f29b8391ca7ef08391f5/gcc/cp/mangle.c#L1847
// ::= C4 | D4
static bool ParseCtorDtorName(State *state) {
ComplexityGuard guard(state);
if (guard.IsTooComplex()) return false;
ParseState copy = state->parse_state;
- if (ParseOneCharToken(state, 'C') && ParseCharClass(state, "1234")) {
- const char *const prev_name = state->out + state->parse_state.prev_name_idx;
- MaybeAppendWithLength(state, prev_name,
- state->parse_state.prev_name_length);
- return true;
+ if (ParseOneCharToken(state, 'C')) {
+ if (ParseCharClass(state, "1234")) {
+ const char *const prev_name =
+ state->out + state->parse_state.prev_name_idx;
+ MaybeAppendWithLength(state, prev_name,
+ state->parse_state.prev_name_length);
+ return true;
+ } else if (ParseOneCharToken(state, 'I') && ParseCharClass(state, "12") &&
+ ParseClassEnumType(state)) {
+ return true;
+ }
}
state->parse_state = copy;
@@ -1126,6 +1152,7 @@
// ::= <decltype>
// ::= <substitution>
// ::= Dp <type> # pack expansion of (C++0x)
+// ::= Dv <num-elems> _ # GNU vector extension
//
static bool ParseType(State *state) {
ComplexityGuard guard(state);
@@ -1168,12 +1195,6 @@
}
state->parse_state = copy;
- // nullptr_t, i.e. decltype(nullptr).
- if (ParseTwoCharToken(state, "Dn")) {
- return true;
- }
- state->parse_state = copy;
-
if (ParseOneCharToken(state, 'U') && ParseSourceName(state) &&
ParseType(state)) {
return true;
@@ -1198,6 +1219,12 @@
return true;
}
+ if (ParseTwoCharToken(state, "Dv") && ParseNumber(state, nullptr) &&
+ ParseOneCharToken(state, '_')) {
+ return true;
+ }
+ state->parse_state = copy;
+
return false;
}
@@ -1214,16 +1241,26 @@
return num_cv_qualifiers > 0;
}
-// <builtin-type> ::= v, etc.
+// <builtin-type> ::= v, etc. # single-character builtin types
// ::= u <source-name>
+// ::= Dd, etc. # two-character builtin types
+//
+// Not supported:
+// ::= DF <number> _ # _FloatN (N bits)
+//
static bool ParseBuiltinType(State *state) {
ComplexityGuard guard(state);
if (guard.IsTooComplex()) return false;
const AbbrevPair *p;
for (p = kBuiltinTypeList; p->abbrev != nullptr; ++p) {
- if (RemainingInput(state)[0] == p->abbrev[0]) {
+ // Guaranteed only 1- or 2-character strings in kBuiltinTypeList.
+ if (p->abbrev[1] == '\0') {
+ if (ParseOneCharToken(state, p->abbrev[0])) {
+ MaybeAppend(state, p->real_name);
+ return true;
+ }
+ } else if (p->abbrev[2] == '\0' && ParseTwoCharToken(state, p->abbrev)) {
MaybeAppend(state, p->real_name);
- ++state->parse_state.mangled_idx;
return true;
}
}
@@ -1236,13 +1273,42 @@
return false;
}
-// <function-type> ::= F [Y] <bare-function-type> E
+// <exception-spec> ::= Do # non-throwing
+// exception-specification (e.g.,
+// noexcept, throw())
+// ::= DO <expression> E # computed (instantiation-dependent)
+// noexcept
+// ::= Dw <type>+ E # dynamic exception specification
+// with instantiation-dependent types
+static bool ParseExceptionSpec(State *state) {
+ ComplexityGuard guard(state);
+ if (guard.IsTooComplex()) return false;
+
+ if (ParseTwoCharToken(state, "Do")) return true;
+
+ ParseState copy = state->parse_state;
+ if (ParseTwoCharToken(state, "DO") && ParseExpression(state) &&
+ ParseOneCharToken(state, 'E')) {
+ return true;
+ }
+ state->parse_state = copy;
+ if (ParseTwoCharToken(state, "Dw") && OneOrMore(ParseType, state) &&
+ ParseOneCharToken(state, 'E')) {
+ return true;
+ }
+ state->parse_state = copy;
+
+ return false;
+}
+
+// <function-type> ::= [exception-spec] F [Y] <bare-function-type> [O] E
static bool ParseFunctionType(State *state) {
ComplexityGuard guard(state);
if (guard.IsTooComplex()) return false;
ParseState copy = state->parse_state;
- if (ParseOneCharToken(state, 'F') &&
+ if (Optional(ParseExceptionSpec(state)) && ParseOneCharToken(state, 'F') &&
Optional(ParseOneCharToken(state, 'Y')) && ParseBareFunctionType(state) &&
+ Optional(ParseOneCharToken(state, 'O')) &&
ParseOneCharToken(state, 'E')) {
return true;
}
@@ -1870,8 +1936,10 @@
bool Demangle(const char *mangled, char *out, int out_size) {
State state;
InitState(&state, mangled, out, out_size);
- return ParseTopLevelMangledName(&state) && !Overflowed(&state);
+ return ParseTopLevelMangledName(&state) && !Overflowed(&state) &&
+ state.parse_state.out_cur_idx > 0;
}
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/debugging/internal/demangle.h b/third_party/abseil/absl/debugging/internal/demangle.h
index 81bb0df..c314d9b 100644
--- a/third_party/abseil/absl/debugging/internal/demangle.h
+++ b/third_party/abseil/absl/debugging/internal/demangle.h
@@ -53,7 +53,10 @@
#ifndef ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_
#define ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
// Demangle `mangled`. On success, return true and write the
@@ -62,6 +65,7 @@
bool Demangle(const char *mangled, char *out, int out_size);
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_
diff --git a/third_party/abseil/absl/debugging/internal/demangle_test.cc b/third_party/abseil/absl/debugging/internal/demangle_test.cc
index a68ce32..0bed735 100644
--- a/third_party/abseil/absl/debugging/internal/demangle_test.cc
+++ b/third_party/abseil/absl/debugging/internal/demangle_test.cc
@@ -18,11 +18,13 @@
#include <string>
#include "gtest/gtest.h"
+#include "absl/base/config.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/debugging/internal/stack_consumption.h"
#include "absl/memory/memory.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
namespace {
@@ -81,9 +83,10 @@
// Tests that verify that Demangle footprint is within some limit.
// They are not to be run under sanitizers as the sanitizers increase
// stack consumption by about 4x.
-#if defined(ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION) && \
- !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) && \
- !defined(THREAD_SANITIZER)
+#if defined(ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION) && \
+ !defined(ABSL_HAVE_ADDRESS_SANITIZER) && \
+ !defined(ABSL_HAVE_MEMORY_SANITIZER) && \
+ !defined(ABSL_HAVE_THREAD_SANITIZER)
static const char *g_mangled;
static char g_demangle_buffer[4096];
@@ -190,4 +193,5 @@
} // namespace
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/debugging/internal/elf_mem_image.cc b/third_party/abseil/absl/debugging/internal/elf_mem_image.cc
index e7408bc..24cc013 100644
--- a/third_party/abseil/absl/debugging/internal/elf_mem_image.cc
+++ b/third_party/abseil/absl/debugging/internal/elf_mem_image.cc
@@ -38,6 +38,7 @@
#define VERSYM_VERSION 0x7fff
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
namespace {
@@ -375,6 +376,7 @@
}
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_HAVE_ELF_MEM_IMAGE
diff --git a/third_party/abseil/absl/debugging/internal/elf_mem_image.h b/third_party/abseil/absl/debugging/internal/elf_mem_image.h
index d84200d..46bfade 100644
--- a/third_party/abseil/absl/debugging/internal/elf_mem_image.h
+++ b/third_party/abseil/absl/debugging/internal/elf_mem_image.h
@@ -23,6 +23,8 @@
// used.
#include <climits>
+#include "absl/base/config.h"
+
// 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
@@ -39,6 +41,7 @@
#include <link.h> // for ElfW
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
// An in-memory ELF image (may not exist on disk).
@@ -123,6 +126,7 @@
};
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_HAVE_ELF_MEM_IMAGE
diff --git a/third_party/abseil/absl/debugging/internal/examine_stack.cc b/third_party/abseil/absl/debugging/internal/examine_stack.cc
index 1ebc788..6e5ff1f 100644
--- a/third_party/abseil/absl/debugging/internal/examine_stack.cc
+++ b/third_party/abseil/absl/debugging/internal/examine_stack.cc
@@ -20,6 +20,10 @@
#include <unistd.h>
#endif
+#ifdef __APPLE__
+#include <sys/ucontext.h>
+#endif
+
#include <csignal>
#include <cstdio>
@@ -30,6 +34,7 @@
#include "absl/debugging/symbolize.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
// Returns the program counter from signal context, nullptr if
@@ -52,6 +57,8 @@
return reinterpret_cast<void*>(context->uc_mcontext.gp_regs[32]);
#elif defined(__powerpc__)
return reinterpret_cast<void*>(context->uc_mcontext.regs->nip);
+#elif defined(__riscv)
+ return reinterpret_cast<void*>(context->uc_mcontext.__gregs[REG_PC]);
#elif defined(__s390__) && !defined(__s390x__)
return reinterpret_cast<void*>(context->uc_mcontext.psw.addr & 0x7fffffff);
#elif defined(__s390__) && defined(__s390x__)
@@ -63,6 +70,32 @@
#error "Undefined Architecture."
#endif
}
+#elif defined(__APPLE__)
+ if (vuc != nullptr) {
+ ucontext_t* signal_ucontext = reinterpret_cast<ucontext_t*>(vuc);
+#if defined(__aarch64__)
+ return reinterpret_cast<void*>(
+ __darwin_arm_thread_state64_get_pc(signal_ucontext->uc_mcontext->__ss));
+#elif defined(__arm__)
+#if __DARWIN_UNIX03
+ return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->__ss.__pc);
+#else
+ return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->ss.pc);
+#endif
+#elif defined(__i386__)
+#if __DARWIN_UNIX03
+ return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->__ss.__eip);
+#else
+ return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->ss.eip);
+#endif
+#elif defined(__x86_64__)
+#if __DARWIN_UNIX03
+ return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->__ss.__rip);
+#else
+ return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->ss.rip);
+#endif
+#endif
+ }
#elif defined(__akaros__)
auto* ctx = reinterpret_cast<struct user_context*>(vuc);
return reinterpret_cast<void*>(get_user_ctx_pc(ctx));
@@ -150,4 +183,5 @@
}
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/debugging/internal/examine_stack.h b/third_party/abseil/absl/debugging/internal/examine_stack.h
index 56c9763..3933691 100644
--- a/third_party/abseil/absl/debugging/internal/examine_stack.h
+++ b/third_party/abseil/absl/debugging/internal/examine_stack.h
@@ -17,7 +17,10 @@
#ifndef ABSL_DEBUGGING_INTERNAL_EXAMINE_STACK_H_
#define ABSL_DEBUGGING_INTERNAL_EXAMINE_STACK_H_
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
// Returns the program counter from signal context, or nullptr if
@@ -33,6 +36,7 @@
void (*writerfn)(const char*, void*), void* writerfn_arg);
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_DEBUGGING_INTERNAL_EXAMINE_STACK_H_
diff --git a/third_party/abseil/absl/debugging/internal/stack_consumption.cc b/third_party/abseil/absl/debugging/internal/stack_consumption.cc
index 4b05f49..e3dd51c 100644
--- a/third_party/abseil/absl/debugging/internal/stack_consumption.cc
+++ b/third_party/abseil/absl/debugging/internal/stack_consumption.cc
@@ -27,6 +27,7 @@
#include "absl/base/internal/raw_logging.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
namespace {
@@ -41,7 +42,8 @@
// one of them is null, the results of p<q, p>q, p<=q, and p>=q are
// unspecified. Therefore, instead we hardcode the direction of the
// stack on platforms we know about.
-#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || \
+ defined(__aarch64__)
constexpr bool kStackGrowsDown = true;
#else
#error Need to define kStackGrowsDown
@@ -115,10 +117,11 @@
// Set up the alt-signal-stack (and save the older one).
stack_t sigstk;
memset(&sigstk, 0, sizeof(sigstk));
- stack_t old_sigstk;
sigstk.ss_sp = altstack;
sigstk.ss_size = kAlternateStackSize;
sigstk.ss_flags = 0;
+ stack_t old_sigstk;
+ memset(&old_sigstk, 0, sizeof(old_sigstk));
ABSL_RAW_CHECK(sigaltstack(&sigstk, &old_sigstk) == 0,
"sigaltstack() failed");
@@ -152,6 +155,15 @@
int signal_handler_stack_consumption = GetStackConsumption(altstack);
// Now restore the old alt-signal-stack and signal handlers.
+ if (old_sigstk.ss_sp == nullptr && old_sigstk.ss_size == 0 &&
+ (old_sigstk.ss_flags & SS_DISABLE)) {
+ // https://git.musl-libc.org/cgit/musl/commit/src/signal/sigaltstack.c?id=7829f42a2c8944555439380498ab8b924d0f2070
+ // The original stack has ss_size==0 and ss_flags==SS_DISABLE, but some
+ // versions of musl have a bug that rejects ss_size==0. Work around this by
+ // setting ss_size to MINSIGSTKSZ, which should be ignored by the kernel
+ // when SS_DISABLE is set.
+ old_sigstk.ss_size = MINSIGSTKSZ;
+ }
ABSL_RAW_CHECK(sigaltstack(&old_sigstk, nullptr) == 0,
"sigaltstack() failed");
ABSL_RAW_CHECK(sigaction(SIGUSR1, &old_sa1, nullptr) == 0,
@@ -167,6 +179,7 @@
}
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
diff --git a/third_party/abseil/absl/debugging/internal/stack_consumption.h b/third_party/abseil/absl/debugging/internal/stack_consumption.h
index b860a3c..2b5e715 100644
--- a/third_party/abseil/absl/debugging/internal/stack_consumption.h
+++ b/third_party/abseil/absl/debugging/internal/stack_consumption.h
@@ -18,15 +18,19 @@
#ifndef ABSL_DEBUGGING_INTERNAL_STACK_CONSUMPTION_H_
#define ABSL_DEBUGGING_INTERNAL_STACK_CONSUMPTION_H_
+#include "absl/base/config.h"
+
// The code in this module is not portable.
// Use this feature test macro to detect its availability.
#ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
#error ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION cannot be set directly
-#elif !defined(__APPLE__) && !defined(_WIN32) && \
- (defined(__i386__) || defined(__x86_64__) || defined(__ppc__))
+#elif !defined(__APPLE__) && !defined(_WIN32) && \
+ (defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || \
+ defined(__aarch64__))
#define ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION 1
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
// Returns the stack consumption in bytes for the code exercised by
@@ -38,6 +42,7 @@
int GetSignalHandlerStackConsumption(void (*signal_handler)(int));
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
diff --git a/third_party/abseil/absl/debugging/internal/stack_consumption_test.cc b/third_party/abseil/absl/debugging/internal/stack_consumption_test.cc
index 68bfa12..80445bf 100644
--- a/third_party/abseil/absl/debugging/internal/stack_consumption_test.cc
+++ b/third_party/abseil/absl/debugging/internal/stack_consumption_test.cc
@@ -23,6 +23,7 @@
#include "absl/base/internal/raw_logging.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
namespace {
@@ -43,6 +44,7 @@
} // namespace
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
diff --git a/third_party/abseil/absl/debugging/internal/stacktrace_aarch64-inl.inc b/third_party/abseil/absl/debugging/internal/stacktrace_aarch64-inl.inc
index 7ed6b3e..f4859d7 100644
--- a/third_party/abseil/absl/debugging/internal/stacktrace_aarch64-inl.inc
+++ b/third_party/abseil/absl/debugging/internal/stacktrace_aarch64-inl.inc
@@ -37,8 +37,11 @@
absl::debugging_internal::VDSOSupport vdso;
if (vdso.IsPresent()) {
absl::debugging_internal::VDSOSupport::SymbolInfo symbol_info;
- if (!vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.6.39", STT_FUNC,
- &symbol_info) ||
+ auto lookup = [&](int type) {
+ return vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.6.39", type,
+ &symbol_info);
+ };
+ if ((!lookup(STT_FUNC) && !lookup(STT_NOTYPE)) ||
symbol_info.address == nullptr) {
// Unexpected: VDSO is present, yet the expected symbol is missing
// or null.
@@ -74,6 +77,8 @@
// 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_frame_pointer, const void *uc) {
void **new_frame_pointer = reinterpret_cast<void**>(*old_frame_pointer);
bool check_frame_size = true;
@@ -123,6 +128,8 @@
}
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) {
#ifdef __GNUC__
@@ -180,11 +187,13 @@
}
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
bool StackTraceWorksForTest() {
return true;
}
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_AARCH64_INL_H_
diff --git a/third_party/abseil/absl/debugging/internal/stacktrace_arm-inl.inc b/third_party/abseil/absl/debugging/internal/stacktrace_arm-inl.inc
index c840833..2a1bf2e 100644
--- a/third_party/abseil/absl/debugging/internal/stacktrace_arm-inl.inc
+++ b/third_party/abseil/absl/debugging/internal/stacktrace_arm-inl.inc
@@ -1,9 +1,18 @@
-// Copyright 2011 and onwards Google Inc.
-// All rights reserved.
+// Copyright 2017 The Abseil Authors.
//
-// Author: Doug Kwan
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
// 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_
@@ -113,11 +122,13 @@
}
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
bool StackTraceWorksForTest() {
return false;
}
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_
diff --git a/third_party/abseil/absl/debugging/internal/stacktrace_config.h b/third_party/abseil/absl/debugging/internal/stacktrace_config.h
index d4e8480..cca410d 100644
--- a/third_party/abseil/absl/debugging/internal/stacktrace_config.h
+++ b/third_party/abseil/absl/debugging/internal/stacktrace_config.h
@@ -21,6 +21,8 @@
#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
+#include "absl/base/config.h"
+
#if defined(ABSL_STACKTRACE_INL_HEADER)
#error ABSL_STACKTRACE_INL_HEADER cannot be directly set
@@ -28,43 +30,51 @@
#define ABSL_STACKTRACE_INL_HEADER \
"absl/debugging/internal/stacktrace_win32-inl.inc"
+#elif defined(__APPLE__)
+#ifdef ABSL_HAVE_THREAD_LOCAL
+// Thread local support required for UnwindImpl.
+#define ABSL_STACKTRACE_INL_HEADER \
+ "absl/debugging/internal/stacktrace_generic-inl.inc"
+#endif
+
#elif defined(__linux__) && !defined(__ANDROID__)
-#if !defined(NO_FRAME_POINTER)
-# if defined(__i386__) || defined(__x86_64__)
+#if defined(NO_FRAME_POINTER) && \
+ (defined(__i386__) || defined(__x86_64__) || defined(__aarch64__))
+// Note: The libunwind-based implementation is not available to open-source
+// users.
#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__)
+ "absl/debugging/internal/stacktrace_libunwind-inl.inc"
+#define STACKTRACE_USES_LIBUNWIND 1
+#elif defined(NO_FRAME_POINTER) && defined(__has_include)
+#if __has_include(<execinfo.h>)
// Note: When using glibc this may require -funwind-tables to function properly.
#define ABSL_STACKTRACE_INL_HEADER \
"absl/debugging/internal/stacktrace_generic-inl.inc"
-# else
+#endif
+#elif defined(__i386__) || defined(__x86_64__)
#define ABSL_STACKTRACE_INL_HEADER \
- "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
-# endif
-#else // defined(NO_FRAME_POINTER)
-# if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
+ "absl/debugging/internal/stacktrace_x86-inl.inc"
+#elif defined(__ppc__) || defined(__PPC__)
#define ABSL_STACKTRACE_INL_HEADER \
- "absl/debugging/internal/stacktrace_generic-inl.inc"
-# elif defined(__ppc__) || defined(__PPC__)
+ "absl/debugging/internal/stacktrace_powerpc-inl.inc"
+#elif defined(__aarch64__)
#define ABSL_STACKTRACE_INL_HEADER \
- "absl/debugging/internal/stacktrace_generic-inl.inc"
-# else
+ "absl/debugging/internal/stacktrace_aarch64-inl.inc"
+#elif defined(__has_include)
+#if __has_include(<execinfo.h>)
+// Note: When using glibc this may require -funwind-tables to function properly.
#define ABSL_STACKTRACE_INL_HEADER \
- "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
-# endif
-#endif // NO_FRAME_POINTER
+ "absl/debugging/internal/stacktrace_generic-inl.inc"
+#endif
+#endif
-#else
+#endif
+
+// Fallback to the empty implementation.
+#if !defined(ABSL_STACKTRACE_INL_HEADER)
#define ABSL_STACKTRACE_INL_HEADER \
"absl/debugging/internal/stacktrace_unimplemented-inl.inc"
-
#endif
#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
diff --git a/third_party/abseil/absl/debugging/internal/stacktrace_generic-inl.inc b/third_party/abseil/absl/debugging/internal/stacktrace_generic-inl.inc
index 81a49ef..b2792a1 100644
--- a/third_party/abseil/absl/debugging/internal/stacktrace_generic-inl.inc
+++ b/third_party/abseil/absl/debugging/internal/stacktrace_generic-inl.inc
@@ -1,7 +1,16 @@
-// Copyright 2000 - 2007 Google Inc.
-// All rights reserved.
+// Copyright 2017 The Abseil Authors.
//
-// Author: Sanjay Ghemawat
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
//
// Portable implementation - just use glibc
//
@@ -87,11 +96,13 @@
}
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
bool StackTraceWorksForTest() {
return true;
}
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_
diff --git a/third_party/abseil/absl/debugging/internal/stacktrace_powerpc-inl.inc b/third_party/abseil/absl/debugging/internal/stacktrace_powerpc-inl.inc
index 3a070ee..2e7c2f4 100644
--- a/third_party/abseil/absl/debugging/internal/stacktrace_powerpc-inl.inc
+++ b/third_party/abseil/absl/debugging/internal/stacktrace_powerpc-inl.inc
@@ -236,11 +236,13 @@
}
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
bool StackTraceWorksForTest() {
return true;
}
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_POWERPC_INL_H_
diff --git a/third_party/abseil/absl/debugging/internal/stacktrace_unimplemented-inl.inc b/third_party/abseil/absl/debugging/internal/stacktrace_unimplemented-inl.inc
index e256fdd..5b8fb19 100644
--- a/third_party/abseil/absl/debugging/internal/stacktrace_unimplemented-inl.inc
+++ b/third_party/abseil/absl/debugging/internal/stacktrace_unimplemented-inl.inc
@@ -12,11 +12,13 @@
}
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
bool StackTraceWorksForTest() {
return false;
}
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_UNIMPLEMENTED_INL_H_
diff --git a/third_party/abseil/absl/debugging/internal/stacktrace_win32-inl.inc b/third_party/abseil/absl/debugging/internal/stacktrace_win32-inl.inc
index b46491f..1c666c8 100644
--- a/third_party/abseil/absl/debugging/internal/stacktrace_win32-inl.inc
+++ b/third_party/abseil/absl/debugging/internal/stacktrace_win32-inl.inc
@@ -46,15 +46,23 @@
OUT PVOID *backtrace,
OUT PULONG backtrace_hash);
+// It is not possible to load RtlCaptureStackBackTrace at static init time in
+// UWP. CaptureStackBackTrace is the public version of RtlCaptureStackBackTrace
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
+ !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn =
+ &::CaptureStackBackTrace;
+#else
// 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");
+ (RtlCaptureStackBackTrace_Function*)GetProcAddress(
+ GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace");
+#endif // WINAPI_PARTITION_APP && !WINAPI_PARTITION_DESKTOP
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) {
+ const void*, int* min_dropped_frames) {
int n = 0;
if (!RtlCaptureStackBackTrace_fn) {
// can't find a stacktrace with no function to call
@@ -73,11 +81,13 @@
}
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
bool StackTraceWorksForTest() {
return false;
}
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_
diff --git a/third_party/abseil/absl/debugging/internal/stacktrace_x86-inl.inc b/third_party/abseil/absl/debugging/internal/stacktrace_x86-inl.inc
index 9494441..bc320ff 100644
--- a/third_party/abseil/absl/debugging/internal/stacktrace_x86-inl.inc
+++ b/third_party/abseil/absl/debugging/internal/stacktrace_x86-inl.inc
@@ -173,6 +173,7 @@
static const unsigned char *kernel_rt_sigreturn_address = nullptr;
static const unsigned char *kernel_vsyscall_address = nullptr;
if (num_push_instructions == -1) {
+#ifdef ABSL_HAVE_VDSO_SUPPORT
absl::debugging_internal::VDSOSupport vdso;
if (vdso.IsPresent()) {
absl::debugging_internal::VDSOSupport::SymbolInfo
@@ -201,6 +202,9 @@
} else {
num_push_instructions = 0;
}
+#else // ABSL_HAVE_VDSO_SUPPORT
+ num_push_instructions = 0;
+#endif // ABSL_HAVE_VDSO_SUPPORT
}
if (num_push_instructions != 0 && kernel_rt_sigreturn_address != nullptr &&
old_fp[1] == kernel_rt_sigreturn_address) {
@@ -330,11 +334,13 @@
}
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
bool StackTraceWorksForTest() {
return true;
}
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_X86_INL_INC_
diff --git a/third_party/abseil/absl/debugging/internal/symbolize.h b/third_party/abseil/absl/debugging/internal/symbolize.h
index 3e53789..4f26130 100644
--- a/third_party/abseil/absl/debugging/internal/symbolize.h
+++ b/third_party/abseil/absl/debugging/internal/symbolize.h
@@ -18,9 +18,14 @@
#ifndef ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_
#define ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_
+#ifdef __cplusplus
+
#include <cstddef>
#include <cstdint>
+#include "absl/base/config.h"
+#include "absl/strings/string_view.h"
+
#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
#error ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE cannot be directly set
#elif defined(__ELF__) && defined(__GLIBC__) && !defined(__native_client__) && \
@@ -33,6 +38,7 @@
#include <string>
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
// Iterates over all sections, invoking callback on each with the section name
@@ -42,7 +48,7 @@
//
// This is not async-signal-safe.
bool ForEachSection(int fd,
- const std::function<bool(const std::string& name,
+ const std::function<bool(absl::string_view name,
const ElfW(Shdr) &)>& callback);
// Gets the section header for the given name, if it exists. Returns true on
@@ -51,11 +57,19 @@
ElfW(Shdr) *out);
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
+#ifdef ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE
+#error ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE cannot be directly set
+#elif defined(__APPLE__)
+#define ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE 1
+#endif
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
struct SymbolDecoratorArgs {
@@ -104,19 +118,30 @@
// filename != nullptr
//
// Returns true if the file was successfully registered.
-bool RegisterFileMappingHint(
- const void* start, const void* end, uint64_t offset, const char* filename);
+bool RegisterFileMappingHint(const void* start, const void* end,
+ uint64_t offset, const char* filename);
// Looks up the file mapping registered by RegisterFileMappingHint for an
// address range. If there is one, the file name is stored in *filename and
// *start and *end are modified to reflect the registered mapping. Returns
// whether any hint was found.
-bool GetFileMappingHint(const void** start,
- const void** end,
- uint64_t * offset,
+bool GetFileMappingHint(const void** start, const void** end, uint64_t* offset,
const char** filename);
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
+#endif // __cplusplus
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C"
+#endif // __cplusplus
+
+ bool
+ AbslInternalGetFileMappingHint(const void** start, const void** end,
+ uint64_t* offset, const char** filename);
+
#endif // ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_
diff --git a/third_party/abseil/absl/debugging/internal/vdso_support.cc b/third_party/abseil/absl/debugging/internal/vdso_support.cc
index d13ef25..6be16d9 100644
--- a/third_party/abseil/absl/debugging/internal/vdso_support.cc
+++ b/third_party/abseil/absl/debugging/internal/vdso_support.cc
@@ -38,6 +38,7 @@
#endif
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
ABSL_CONST_INIT
@@ -75,15 +76,6 @@
}
#endif // __GLIBC_PREREQ(2, 16)
if (vdso_base_.load(std::memory_order_relaxed) == 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.
@@ -174,19 +166,8 @@
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 debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_HAVE_VDSO_SUPPORT
diff --git a/third_party/abseil/absl/debugging/internal/vdso_support.h b/third_party/abseil/absl/debugging/internal/vdso_support.h
index 9895b48..6562c6c 100644
--- a/third_party/abseil/absl/debugging/internal/vdso_support.h
+++ b/third_party/abseil/absl/debugging/internal/vdso_support.h
@@ -53,6 +53,7 @@
#endif
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
// NOTE: this class may be used from within tcmalloc, and can not
@@ -149,6 +150,7 @@
int GetCPU();
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_HAVE_ELF_MEM_IMAGE
diff --git a/third_party/abseil/absl/debugging/leak_check.cc b/third_party/abseil/absl/debugging/leak_check.cc
index ffe3d1b..ff90495 100644
--- a/third_party/abseil/absl/debugging/leak_check.cc
+++ b/third_party/abseil/absl/debugging/leak_check.cc
@@ -21,12 +21,14 @@
#ifndef LEAK_SANITIZER
namespace absl {
+ABSL_NAMESPACE_BEGIN
bool HaveLeakSanitizer() { return false; }
void DoIgnoreLeak(const void*) { }
void RegisterLivePointers(const void*, size_t) { }
void UnRegisterLivePointers(const void*, size_t) { }
LeakCheckDisabler::LeakCheckDisabler() { }
LeakCheckDisabler::~LeakCheckDisabler() { }
+ABSL_NAMESPACE_END
} // namespace absl
#else
@@ -34,6 +36,7 @@
#include <sanitizer/lsan_interface.h>
namespace absl {
+ABSL_NAMESPACE_BEGIN
bool HaveLeakSanitizer() { return true; }
void DoIgnoreLeak(const void* ptr) { __lsan_ignore_object(ptr); }
void RegisterLivePointers(const void* ptr, size_t size) {
@@ -44,6 +47,7 @@
}
LeakCheckDisabler::LeakCheckDisabler() { __lsan_disable(); }
LeakCheckDisabler::~LeakCheckDisabler() { __lsan_enable(); }
+ABSL_NAMESPACE_END
} // namespace absl
#endif // LEAK_SANITIZER
diff --git a/third_party/abseil/absl/debugging/leak_check.h b/third_party/abseil/absl/debugging/leak_check.h
index 4d489c5..b66a81c 100644
--- a/third_party/abseil/absl/debugging/leak_check.h
+++ b/third_party/abseil/absl/debugging/leak_check.h
@@ -32,7 +32,10 @@
#include <cstddef>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
// HaveLeakSanitizer()
//
@@ -59,7 +62,8 @@
//
// 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.
+// allocated, leak sanitizer will assume this object is referenced even if
+// there is no actual reference in user memory.
//
template <typename T>
T* IgnoreLeak(T* ptr) {
@@ -104,6 +108,7 @@
// `RegisterLivePointers()`, enabling leak checking of those pointers.
void UnRegisterLivePointers(const void* ptr, size_t size);
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_DEBUGGING_LEAK_CHECK_H_
diff --git a/third_party/abseil/absl/debugging/leak_check_fail_test.cc b/third_party/abseil/absl/debugging/leak_check_fail_test.cc
index 2887cea..c49b81a 100644
--- a/third_party/abseil/absl/debugging/leak_check_fail_test.cc
+++ b/third_party/abseil/absl/debugging/leak_check_fail_test.cc
@@ -25,7 +25,7 @@
// failed exit code.
char* foo = strdup("lsan should complain about this leaked string");
- ABSL_RAW_LOG(INFO, "Should detect leaked std::string %s", foo);
+ ABSL_RAW_LOG(INFO, "Should detect leaked string %s", foo);
}
TEST(LeakCheckTest, LeakMemoryAfterDisablerScope) {
@@ -34,7 +34,7 @@
// 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",
+ ABSL_RAW_LOG(INFO, "Re-enabled leak detection.Should detect leaked string %s",
foo);
}
diff --git a/third_party/abseil/absl/debugging/leak_check_test.cc b/third_party/abseil/absl/debugging/leak_check_test.cc
index 93a7edd..b5cc487 100644
--- a/third_party/abseil/absl/debugging/leak_check_test.cc
+++ b/third_party/abseil/absl/debugging/leak_check_test.cc
@@ -30,13 +30,13 @@
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());
+ ABSL_RAW_LOG(INFO, "Ignoring leaked 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());
+ auto foo = new std::string("some string leaked while checks are disabled");
+ ABSL_RAW_LOG(INFO, "Ignoring leaked string %s", foo->c_str());
}
} // namespace
diff --git a/third_party/abseil/absl/debugging/stacktrace.cc b/third_party/abseil/absl/debugging/stacktrace.cc
index 9de8782..1f7c7d8 100644
--- a/third_party/abseil/absl/debugging/stacktrace.cc
+++ b/third_party/abseil/absl/debugging/stacktrace.cc
@@ -57,6 +57,7 @@
#endif
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
typedef int (*Unwinder)(void**, int*, int, int, const void*, int*);
@@ -135,4 +136,5 @@
return n;
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/debugging/stacktrace.h b/third_party/abseil/absl/debugging/stacktrace.h
index 3fc1c03..0ec0ffd 100644
--- a/third_party/abseil/absl/debugging/stacktrace.h
+++ b/third_party/abseil/absl/debugging/stacktrace.h
@@ -31,15 +31,18 @@
#ifndef ABSL_DEBUGGING_STACKTRACE_H_
#define ABSL_DEBUGGING_STACKTRACE_H_
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
// GetStackFrames()
//
// Records program counter values for up to `max_depth` frames, skipping the
-// most recent `skip_count` stack frames, and stores their corresponding values
-// and sizes in `results` and `sizes` buffers. (Note that the frame generated
-// for the `absl::GetStackFrames()` routine itself is also skipped.)
-// routine itself.
+// most recent `skip_count` stack frames, stores their corresponding values
+// and sizes in `results` and `sizes` buffers, and returns the number of frames
+// stored. (Note that the frame generated for the `absl::GetStackFrames()`
+// routine itself is also skipped.)
//
// Example:
//
@@ -54,8 +57,8 @@
// The current stack frame would consist of three function calls: `bar()`,
// `foo()`, and then `main()`; however, since the `GetStackFrames()` call sets
// `skip_count` to `1`, it will skip the frame for `bar()`, the most recently
-// invoked function call. It will therefore return two program counters and will
-// produce values that map to the following function calls:
+// invoked function call. It will therefore return 2 and fill `result` with
+// program counters within the following functions:
//
// result[0] foo()
// result[1] main()
@@ -82,9 +85,10 @@
//
// Records program counter values obtained from a signal handler. Records
// program counter values for up to `max_depth` frames, skipping the most recent
-// `skip_count` stack frames, and stores their corresponding values and sizes in
-// `results` and `sizes` buffers. (Note that the frame generated for the
-// `absl::GetStackFramesWithContext()` routine itself is also skipped.)
+// `skip_count` stack frames, stores their corresponding values and sizes in
+// `results` and `sizes` buffers, and returns the number of frames stored. (Note
+// that the frame generated for the `absl::GetStackFramesWithContext()` routine
+// itself is also skipped.)
//
// The `uc` parameter, if non-null, should be a pointer to a `ucontext_t` value
// passed to a signal handler registered via the `sa_sigaction` field of a
@@ -105,8 +109,9 @@
// GetStackTrace()
//
// Records program counter values for up to `max_depth` frames, skipping the
-// most recent `skip_count` stack frames, and stores their corresponding values
-// in `results`. Note that this function is similar to `absl::GetStackFrames()`
+// most recent `skip_count` stack frames, stores their corresponding values
+// in `results`, and returns the number of frames
+// stored. Note that this function is similar to `absl::GetStackFrames()`
// except that it returns the stack trace only, and not stack frame sizes.
//
// Example:
@@ -131,9 +136,9 @@
//
// Records program counter values obtained from a signal handler. Records
// program counter values for up to `max_depth` frames, skipping the most recent
-// `skip_count` stack frames, and stores their corresponding values in
-// `results`. (Note that the frame generated for the
-// `absl::GetStackFramesWithContext()` routine itself is also skipped.)
+// `skip_count` stack frames, stores their corresponding values in `results`,
+// and returns the number of frames stored. (Note that the frame generated for
+// the `absl::GetStackFramesWithContext()` routine itself is also skipped.)
//
// The `uc` parameter, if non-null, should be a pointer to a `ucontext_t` value
// passed to a signal handler registered via the `sa_sigaction` field of a
@@ -220,6 +225,7 @@
// working.
extern bool StackTraceWorksForTest();
} // namespace debugging_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_DEBUGGING_STACKTRACE_H_
diff --git a/third_party/abseil/absl/debugging/symbolize.cc b/third_party/abseil/absl/debugging/symbolize.cc
index 24e3a7f..5e4a25d 100644
--- a/third_party/abseil/absl/debugging/symbolize.cc
+++ b/third_party/abseil/absl/debugging/symbolize.cc
@@ -14,15 +14,23 @@
#include "absl/debugging/symbolize.h"
+#ifdef _WIN32
+#include <winapifamily.h>
+#if !(WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)) || \
+ WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+// UWP doesn't have access to win32 APIs.
+#define ABSL_INTERNAL_HAVE_SYMBOLIZE_WIN32
+#endif
+#endif
+
#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE)
#include "absl/debugging/symbolize_elf.inc"
-#elif defined(_WIN32) && defined(_DEBUG)
-// The Windows Symbolizer only works in debug mode. Note that _DEBUG
-// is the macro that defines whether or not MS C-Runtime debug info is
-// available. Note that the PDB files containing the debug info must
-// also be available to the program at runtime for the symbolizer to
-// work.
+#elif defined(ABSL_INTERNAL_HAVE_SYMBOLIZE_WIN32)
+// The Windows Symbolizer only works if PDB files containing the debug info
+// are available to the program at runtime.
#include "absl/debugging/symbolize_win32.inc"
+#elif defined(__APPLE__)
+#include "absl/debugging/symbolize_darwin.inc"
#else
#include "absl/debugging/symbolize_unimplemented.inc"
#endif
diff --git a/third_party/abseil/absl/debugging/symbolize.h b/third_party/abseil/absl/debugging/symbolize.h
index a73dbd9..43d93a8 100644
--- a/third_party/abseil/absl/debugging/symbolize.h
+++ b/third_party/abseil/absl/debugging/symbolize.h
@@ -55,6 +55,7 @@
#include "absl/debugging/internal/symbolize.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// InitializeSymbolizer()
//
@@ -70,7 +71,7 @@
// // Now you can use the symbolizer
// }
void InitializeSymbolizer(const char* argv0);
-
+//
// Symbolize()
//
// Symbolizes a program counter (instruction pointer value) `pc` and, on
@@ -88,10 +89,11 @@
// if (absl::Symbolize(pc, tmp, sizeof(tmp))) {
// symbol = tmp;
// }
-// absl::PrintF("%*p %s\n", pc, symbol);
+// absl::PrintF("%p %s\n", pc, symbol);
// }
bool Symbolize(const void *pc, char *out, int out_size);
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_DEBUGGING_SYMBOLIZE_H_
diff --git a/third_party/abseil/absl/debugging/symbolize_darwin.inc b/third_party/abseil/absl/debugging/symbolize_darwin.inc
new file mode 100644
index 0000000..443ce9e
--- /dev/null
+++ b/third_party/abseil/absl/debugging/symbolize_darwin.inc
@@ -0,0 +1,101 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <cxxabi.h>
+#include <execinfo.h>
+
+#include <algorithm>
+#include <cstring>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/debugging/internal/demangle.h"
+#include "absl/strings/numbers.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+void InitializeSymbolizer(const char*) {}
+
+namespace debugging_internal {
+namespace {
+
+static std::string GetSymbolString(absl::string_view backtrace_line) {
+ // Example Backtrace lines:
+ // 0 libimaging_shared.dylib 0x018c152a
+ // _ZNSt11_Deque_baseIN3nik7mediadb4PageESaIS2_EE17_M_initialize_mapEm + 3478
+ //
+ // or
+ // 0 libimaging_shared.dylib 0x0000000001895c39
+ // _ZN3nik4util19register_shared_ptrINS_3gpu7TextureEEEvPKvS5_ + 39
+ //
+ // or
+ // 0 mysterious_app 0x0124000120120009 main + 17
+ auto address_pos = backtrace_line.find(" 0x");
+ if (address_pos == absl::string_view::npos) return std::string();
+ absl::string_view symbol_view = backtrace_line.substr(address_pos + 1);
+
+ auto space_pos = symbol_view.find(" ");
+ if (space_pos == absl::string_view::npos) return std::string();
+ symbol_view = symbol_view.substr(space_pos + 1); // to mangled symbol
+
+ auto plus_pos = symbol_view.find(" + ");
+ if (plus_pos == absl::string_view::npos) return std::string();
+ symbol_view = symbol_view.substr(0, plus_pos); // strip remainng
+
+ return std::string(symbol_view);
+}
+
+} // namespace
+} // namespace debugging_internal
+
+bool Symbolize(const void* pc, char* out, int out_size) {
+ if (out_size <= 0 || pc == nullptr) {
+ out = nullptr;
+ return false;
+ }
+
+ // This allocates a char* array.
+ char** frame_strings = backtrace_symbols(const_cast<void**>(&pc), 1);
+
+ if (frame_strings == nullptr) return false;
+
+ std::string symbol = debugging_internal::GetSymbolString(frame_strings[0]);
+ free(frame_strings);
+
+ char tmp_buf[1024];
+ if (debugging_internal::Demangle(symbol.c_str(), tmp_buf, sizeof(tmp_buf))) {
+ size_t len = strlen(tmp_buf);
+ if (len + 1 <= static_cast<size_t>(out_size)) { // +1 for '\0'
+ assert(len < sizeof(tmp_buf));
+ memmove(out, tmp_buf, len + 1);
+ }
+ } else {
+ strncpy(out, symbol.c_str(), out_size);
+ }
+
+ if (out[out_size - 1] != '\0') {
+ // strncpy() does not '\0' terminate when it truncates.
+ static constexpr char kEllipsis[] = "...";
+ int ellipsis_size = std::min<int>(sizeof(kEllipsis) - 1, out_size - 1);
+ memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size);
+ out[out_size - 1] = '\0';
+ }
+
+ return true;
+}
+
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/debugging/symbolize_elf.inc b/third_party/abseil/absl/debugging/symbolize_elf.inc
index 14f0c97..f4d5727 100644
--- a/third_party/abseil/absl/debugging/symbolize_elf.inc
+++ b/third_party/abseil/absl/debugging/symbolize_elf.inc
@@ -57,6 +57,7 @@
#include <unistd.h>
#include <algorithm>
+#include <array>
#include <atomic>
#include <cerrno>
#include <cinttypes>
@@ -74,13 +75,21 @@
#include "absl/base/port.h"
#include "absl/debugging/internal/demangle.h"
#include "absl/debugging/internal/vdso_support.h"
+#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// Value of argv[0]. Used by MaybeInitializeObjFile().
static char *argv0_value = nullptr;
void InitializeSymbolizer(const char *argv0) {
+#ifdef ABSL_HAVE_VDSO_SUPPORT
+ // We need to make sure VDSOSupport::Init() is called before any setuid or
+ // chroot calls, so InitializeSymbolizer() should be called very early in the
+ // life of a program.
+ absl::debugging_internal::VDSOSupport::Init();
+#endif
if (argv0_value != nullptr) {
free(argv0_value);
argv0_value = nullptr;
@@ -148,13 +157,15 @@
// Moreover, we are using only TryLock(), if the decorator list
// is being modified (is busy), we skip all decorators, and possibly
// loose some info. Sorry, that's the best we could do.
-base_internal::SpinLock g_decorators_mu(base_internal::kLinkerInitialized);
+ABSL_CONST_INIT absl::base_internal::SpinLock g_decorators_mu(
+ absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY);
const int kMaxFileMappingHints = 8;
int g_num_file_mapping_hints;
FileMappingHint g_file_mapping_hints[kMaxFileMappingHints];
// Protects g_file_mapping_hints.
-base_internal::SpinLock g_file_mapping_mu(base_internal::kLinkerInitialized);
+ABSL_CONST_INIT absl::base_internal::SpinLock g_file_mapping_mu(
+ absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY);
// Async-signal-safe function to zero a buffer.
// memset() is not guaranteed to be async-signal-safe.
@@ -174,6 +185,7 @@
fd(-1),
elf_type(-1) {
SafeMemZero(&elf_header, sizeof(elf_header));
+ SafeMemZero(&phdr[0], sizeof(phdr));
}
char *filename;
@@ -186,6 +198,10 @@
int fd;
int elf_type;
ElfW(Ehdr) elf_header;
+
+ // PT_LOAD program header describing executable code.
+ // Normally we expect just one, but SWIFT binaries have two.
+ std::array<ElfW(Phdr), 2> phdr;
};
// Build 4-way associative cache for symbols. Within each cache line, symbols
@@ -495,7 +511,7 @@
const int kMaxSectionNameLen = 64;
bool ForEachSection(int fd,
- const std::function<bool(const std::string &name,
+ const std::function<bool(absl::string_view name,
const ElfW(Shdr) &)> &callback) {
ElfW(Ehdr) elf_header;
if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
@@ -517,7 +533,7 @@
return false;
}
off_t name_offset = shstrtab.sh_offset + out.sh_name;
- char header_name[kMaxSectionNameLen + 1];
+ char header_name[kMaxSectionNameLen];
ssize_t n_read =
ReadFromOffset(fd, &header_name, kMaxSectionNameLen, name_offset);
if (n_read == -1) {
@@ -526,9 +542,8 @@
// Long read?
return false;
}
- header_name[n_read] = '\0';
- std::string name(header_name);
+ absl::string_view name(header_name, strnlen(header_name, n_read));
if (!callback(name, out)) {
break;
}
@@ -1263,6 +1278,36 @@
ABSL_RAW_LOG(WARNING, "%s: failed to read elf header", obj->filename);
return false;
}
+ const int phnum = obj->elf_header.e_phnum;
+ const int phentsize = obj->elf_header.e_phentsize;
+ size_t phoff = obj->elf_header.e_phoff;
+ size_t num_executable_load_segments = 0;
+ for (int j = 0; j < phnum; j++) {
+ ElfW(Phdr) phdr;
+ if (!ReadFromOffsetExact(obj->fd, &phdr, sizeof(phdr), phoff)) {
+ ABSL_RAW_LOG(WARNING, "%s: failed to read program header %d",
+ obj->filename, j);
+ return false;
+ }
+ phoff += phentsize;
+ constexpr int rx = PF_X | PF_R;
+ if (phdr.p_type != PT_LOAD || (phdr.p_flags & rx) != rx) {
+ // Not a LOAD segment, or not executable code.
+ continue;
+ }
+ if (num_executable_load_segments < obj->phdr.size()) {
+ memcpy(&obj->phdr[num_executable_load_segments++], &phdr, sizeof(phdr));
+ } else {
+ ABSL_RAW_LOG(WARNING, "%s: too many executable LOAD segments",
+ obj->filename);
+ break;
+ }
+ }
+ if (num_executable_load_segments == 0) {
+ // This object has no "r-x" LOAD segments. That's unexpected.
+ ABSL_RAW_LOG(WARNING, "%s: no executable LOAD segments", obj->filename);
+ return false;
+ }
}
return true;
}
@@ -1286,23 +1331,52 @@
int fd = -1;
if (obj != nullptr) {
if (MaybeInitializeObjFile(obj)) {
- if (obj->elf_type == ET_DYN &&
- reinterpret_cast<uint64_t>(obj->start_addr) >= obj->offset) {
+ const size_t start_addr = reinterpret_cast<size_t>(obj->start_addr);
+ if (obj->elf_type == ET_DYN && start_addr >= obj->offset) {
// This object was relocated.
//
// For obj->offset > 0, adjust the relocation since a mapping at offset
// X in the file will have a start address of [true relocation]+X.
- relocation = reinterpret_cast<ptrdiff_t>(obj->start_addr) - obj->offset;
+ relocation = start_addr - obj->offset;
+
+ // Note: some binaries have multiple "rx" LOAD segments. We must
+ // find the right one.
+ ElfW(Phdr) *phdr = nullptr;
+ for (size_t j = 0; j < obj->phdr.size(); j++) {
+ ElfW(Phdr) &p = obj->phdr[j];
+ if (p.p_type != PT_LOAD) {
+ // We only expect PT_LOADs. This must be PT_NULL that we didn't
+ // write over (i.e. we exhausted all interesting PT_LOADs).
+ ABSL_RAW_CHECK(p.p_type == PT_NULL, "unexpected p_type");
+ break;
+ }
+ if (pc < reinterpret_cast<void *>(start_addr + p.p_memsz)) {
+ phdr = &p;
+ break;
+ }
+ }
+ if (phdr == nullptr) {
+ // That's unexpected. Hope for the best.
+ ABSL_RAW_LOG(
+ WARNING,
+ "%s: unable to find LOAD segment for pc: %p, start_addr: %zx",
+ obj->filename, pc, start_addr);
+ } else {
+ // Adjust relocation in case phdr.p_vaddr != 0.
+ // This happens for binaries linked with `lld --rosegment`, and for
+ // binaries linked with BFD `ld -z separate-code`.
+ relocation -= phdr->p_vaddr - phdr->p_offset;
+ }
}
fd = obj->fd;
- }
- if (GetSymbolFromObjectFile(*obj, pc, relocation, symbol_buf_,
- sizeof(symbol_buf_), tmp_buf_,
- sizeof(tmp_buf_)) == SYMBOL_FOUND) {
- // Only try to demangle the symbol name if it fit into symbol_buf_.
- DemangleInplace(symbol_buf_, sizeof(symbol_buf_), tmp_buf_,
- sizeof(tmp_buf_));
+ if (GetSymbolFromObjectFile(*obj, pc, relocation, symbol_buf_,
+ sizeof(symbol_buf_), tmp_buf_,
+ sizeof(tmp_buf_)) == SYMBOL_FOUND) {
+ // Only try to demangle the symbol name if it fit into symbol_buf_.
+ DemangleInplace(symbol_buf_, sizeof(symbol_buf_), tmp_buf_,
+ sizeof(tmp_buf_));
+ }
}
} else {
#if ABSL_HAVE_VDSO_SUPPORT
@@ -1373,7 +1447,7 @@
if (!g_decorators_mu.TryLock()) {
// Someone else is using decorators. Get out.
- return false;
+ return -2;
}
int ret = ticket;
if (g_num_decorators >= kMaxDecorators) {
@@ -1401,7 +1475,7 @@
if (g_num_file_mapping_hints >= kMaxFileMappingHints) {
ret = false;
} else {
- // TODO(ckennelly): Move this into a std::string copy routine.
+ // TODO(ckennelly): Move this into a string copy routine.
int len = strlen(filename);
char *dst = static_cast<char *>(
base_internal::LowLevelAlloc::AllocWithArena(len + 1, SigSafeArena()));
@@ -1452,7 +1526,7 @@
bool Symbolize(const void *pc, char *out, int out_size) {
// Symbolization is very slow under tsan.
- ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
+ ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
SAFE_ASSERT(out_size >= 0);
debugging_internal::Symbolizer *s = debugging_internal::AllocateSymbolizer();
const char *name = s->GetSymbol(pc);
@@ -1471,8 +1545,16 @@
}
}
debugging_internal::FreeSymbolizer(s);
- ANNOTATE_IGNORE_READS_AND_WRITES_END();
+ ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END();
return ok;
}
+ABSL_NAMESPACE_END
} // namespace absl
+
+extern "C" bool AbslInternalGetFileMappingHint(const void **start,
+ const void **end, uint64_t *offset,
+ const char **filename) {
+ return absl::debugging_internal::GetFileMappingHint(start, end, offset,
+ filename);
+}
diff --git a/third_party/abseil/absl/debugging/symbolize_test.cc b/third_party/abseil/absl/debugging/symbolize_test.cc
index 08068c3..a2dd495 100644
--- a/third_party/abseil/absl/debugging/symbolize_test.cc
+++ b/third_party/abseil/absl/debugging/symbolize_test.cc
@@ -27,18 +27,39 @@
#include "gtest/gtest.h"
#include "absl/base/attributes.h"
#include "absl/base/casts.h"
+#include "absl/base/config.h"
#include "absl/base/internal/per_thread_tls.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/optimization.h"
#include "absl/debugging/internal/stack_consumption.h"
#include "absl/memory/memory.h"
+#include "absl/strings/string_view.h"
using testing::Contains;
+#ifdef _WIN32
+#define ABSL_SYMBOLIZE_TEST_NOINLINE __declspec(noinline)
+#else
+#define ABSL_SYMBOLIZE_TEST_NOINLINE ABSL_ATTRIBUTE_NOINLINE
+#endif
+
// Functions to symbolize. Use C linkage to avoid mangled names.
extern "C" {
-void nonstatic_func() { ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); }
-static void static_func() { ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); }
+ABSL_SYMBOLIZE_TEST_NOINLINE void nonstatic_func() {
+ // The next line makes this a unique function to prevent the compiler from
+ // folding identical functions together.
+ volatile int x = __LINE__;
+ static_cast<void>(x);
+ ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
+}
+
+ABSL_SYMBOLIZE_TEST_NOINLINE static void static_func() {
+ // The next line makes this a unique function to prevent the compiler from
+ // folding identical functions together.
+ volatile int x = __LINE__;
+ static_cast<void>(x);
+ ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
+}
} // extern "C"
struct Foo {
@@ -46,7 +67,11 @@
};
// A C++ method that should have a mangled name.
-void ABSL_ATTRIBUTE_NOINLINE Foo::func(int) {
+ABSL_SYMBOLIZE_TEST_NOINLINE void Foo::func(int) {
+ // The next line makes this a unique function to prevent the compiler from
+ // folding identical functions together.
+ volatile int x = __LINE__;
+ static_cast<void>(x);
ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
}
@@ -80,6 +105,7 @@
symbolize_test_thread_big[2 * 1024 * 1024];
#endif
+#if !defined(__EMSCRIPTEN__)
// Used below to hopefully inhibit some compiler/linker optimizations
// that may remove kHpageTextPadding, kPadding0, and kPadding1 from
// the binary.
@@ -89,6 +115,7 @@
static constexpr size_t kHpageSize = 1 << 21;
const char kHpageTextPadding[kHpageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(
.text) = "";
+#endif // !defined(__EMSCRIPTEN__)
static char try_symbolize_buffer[4096];
@@ -119,7 +146,8 @@
return TrySymbolizeWithLimit(pc, sizeof(try_symbolize_buffer));
}
-#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
+#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) || \
+ defined(ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE)
TEST(Symbolize, Cached) {
// Compilers should give us pointers to them.
@@ -193,8 +221,8 @@
static int GetStackConsumptionUpperLimit() {
// Symbolize stack consumption should be within 2kB.
int stack_consumption_upper_limit = 2048;
-#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
- defined(THREAD_SANITIZER)
+#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \
+ defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER)
// Account for sanitizer instrumentation requiring additional stack space.
stack_consumption_upper_limit *= 5;
#endif
@@ -233,6 +261,7 @@
#endif // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
+#ifndef ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE
// Use a 64K page size for PPC.
const size_t kPageSize = 64 << 10;
// We place a read-only symbols into the .text section and verify that we can
@@ -374,8 +403,8 @@
std::vector<std::string> sections;
ASSERT_TRUE(absl::debugging_internal::ForEachSection(
- fd, [§ions](const std::string &name, const ElfW(Shdr) &) {
- sections.push_back(name);
+ fd, [§ions](const absl::string_view name, const ElfW(Shdr) &) {
+ sections.emplace_back(name);
return true;
}));
@@ -388,6 +417,7 @@
close(fd);
}
+#endif // !ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE
// x86 specific tests. Uses some inline assembler.
extern "C" {
@@ -447,14 +477,15 @@
#endif
}
-#elif defined(_WIN32) && defined(_DEBUG)
+#elif defined(_WIN32)
+#if !defined(ABSL_CONSUME_DLL)
TEST(Symbolize, Basics) {
EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
// The name of an internal linkage symbol is not specified; allow either a
// mangled or an unmangled name here.
- const char* static_func_symbol = TrySymbolize((void *)(&static_func));
+ const char *static_func_symbol = TrySymbolize((void *)(&static_func));
ASSERT_TRUE(static_func_symbol != nullptr);
EXPECT_TRUE(strstr(static_func_symbol, "static_func") != nullptr);
@@ -481,11 +512,12 @@
}
TEST(Symbolize, SymbolizeWithDemangling) {
- const char* result = TrySymbolize((void *)(&Foo::func));
+ const char *result = TrySymbolize((void *)(&Foo::func));
ASSERT_TRUE(result != nullptr);
EXPECT_TRUE(strstr(result, "Foo::func") != nullptr) << result;
}
+#endif // !defined(ABSL_CONSUME_DLL)
#else // Symbolizer unimplemented
TEST(Symbolize, Unimplemented) {
@@ -498,10 +530,12 @@
#endif
int main(int argc, char **argv) {
+#if !defined(__EMSCRIPTEN__)
// Make sure kHpageTextPadding is linked into the binary.
if (volatile_bool) {
ABSL_RAW_LOG(INFO, "%s", kHpageTextPadding);
}
+#endif // !defined(__EMSCRIPTEN__)
#if ABSL_PER_THREAD_TLS
// Touch the per-thread variables.
@@ -512,7 +546,8 @@
absl::InitializeSymbolizer(argv[0]);
testing::InitGoogleTest(&argc, argv);
-#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
+#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) || \
+ defined(ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE)
TestWithPCInsideInlineFunction();
TestWithPCInsideNonInlineFunction();
TestWithReturnAddress();
diff --git a/third_party/abseil/absl/debugging/symbolize_unimplemented.inc b/third_party/abseil/absl/debugging/symbolize_unimplemented.inc
index 7c580fe..db24456 100644
--- a/third_party/abseil/absl/debugging/symbolize_unimplemented.inc
+++ b/third_party/abseil/absl/debugging/symbolize_unimplemented.inc
@@ -17,6 +17,7 @@
#include "absl/base/internal/raw_logging.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace debugging_internal {
@@ -35,4 +36,5 @@
void InitializeSymbolizer(const char*) {}
bool Symbolize(const void *, char *, int) { return false; }
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/debugging/symbolize_win32.inc b/third_party/abseil/absl/debugging/symbolize_win32.inc
index 5a55f29..c3df46f 100644
--- a/third_party/abseil/absl/debugging/symbolize_win32.inc
+++ b/third_party/abseil/absl/debugging/symbolize_win32.inc
@@ -17,10 +17,10 @@
#include <windows.h>
-// MSVC header DbgHelp.h has a warning for an ignored typedef.
+// MSVC header dbghelp.h has a warning for an ignored typedef.
#pragma warning(push)
#pragma warning(disable:4091)
-#include <DbgHelp.h>
+#include <dbghelp.h>
#pragma warning(pop)
#pragma comment(lib, "dbghelp.lib")
@@ -31,10 +31,11 @@
#include "absl/base/internal/raw_logging.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
static HANDLE process = NULL;
-void InitializeSymbolizer(const char *argv0) {
+void InitializeSymbolizer(const char*) {
if (process != nullptr) {
return;
}
@@ -53,13 +54,12 @@
}
}
-bool Symbolize(const void *pc, char *out, int out_size) {
+bool Symbolize(const void* pc, char* out, int out_size) {
if (out_size <= 0) {
return false;
}
- std::aligned_storage<sizeof(SYMBOL_INFO) + MAX_SYM_NAME,
- alignof(SYMBOL_INFO)>::type buf;
- SYMBOL_INFO *symbol = reinterpret_cast<SYMBOL_INFO *>(&buf);
+ alignas(SYMBOL_INFO) char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
+ SYMBOL_INFO* symbol = reinterpret_cast<SYMBOL_INFO*>(buf);
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_SYM_NAME;
if (!SymFromAddr(process, reinterpret_cast<DWORD64>(pc), nullptr, symbol)) {
@@ -77,4 +77,5 @@
return true;
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/flags/BUILD.bazel b/third_party/abseil/absl/flags/BUILD.bazel
index 9a21bfb..1937609 100644
--- a/third_party/abseil/absl/flags/BUILD.bazel
+++ b/third_party/abseil/absl/flags/BUILD.bazel
@@ -14,7 +14,7 @@
# limitations under the License.
#
-#load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
load(
"//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
@@ -24,23 +24,21 @@
package(default_visibility = ["//visibility:public"])
-licenses(["notice"]) # Apache 2.0
+licenses(["notice"])
cc_library(
- name = "flag_internal",
- srcs = [
- "internal/flag.cc",
- ],
+ name = "path_util",
hdrs = [
- "internal/flag.h",
+ "internal/path_util.h",
],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
- visibility = ["//visibility:private"],
+ visibility = [
+ "//absl/flags:__pkg__",
+ ],
deps = [
- ":handle",
- ":registry",
- "//absl/synchronization",
+ "//absl/base:config",
+ "//absl/strings",
],
)
@@ -59,27 +57,14 @@
],
deps = [
":path_util",
+ "//absl/base:config",
+ "//absl/base:core_headers",
"//absl/strings",
"//absl/synchronization",
],
)
cc_library(
- name = "path_util",
- hdrs = [
- "internal/path_util.h",
- ],
- copts = ABSL_DEFAULT_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
- visibility = [
- "//absl/flags:__pkg__",
- ],
- deps = [
- "//absl/strings",
- ],
-)
-
-cc_library(
name = "config",
srcs = [
"usage_config.cc",
@@ -93,6 +78,7 @@
deps = [
":path_util",
":program_name",
+ "//absl/base:config",
"//absl/base:core_headers",
"//absl/strings",
"//absl/synchronization",
@@ -110,14 +96,16 @@
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
+ "//absl/base:config",
"//absl/base:core_headers",
+ "//absl/base:log_severity",
"//absl/strings",
"//absl/strings:str_format",
],
)
cc_library(
- name = "handle",
+ name = "commandlineflag_internal",
srcs = [
"internal/commandlineflag.cc",
],
@@ -126,29 +114,38 @@
],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
- visibility = [
- "//absl/flags:__pkg__",
- ],
deps = [
- ":config",
- ":marshalling",
- "//absl/base:core_headers",
- "//absl/base:raw_logging_internal",
+ "//absl/base:config",
+ "//absl/base:fast_type_id",
+ ],
+)
+
+cc_library(
+ name = "commandlineflag",
+ srcs = [
+ "commandlineflag.cc",
+ ],
+ hdrs = [
+ "commandlineflag.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":commandlineflag_internal",
+ "//absl/base:config",
+ "//absl/base:fast_type_id",
"//absl/strings",
- "//absl/synchronization",
"//absl/types:optional",
],
)
cc_library(
- name = "registry",
+ name = "private_handle_accessor",
srcs = [
- "internal/registry.cc",
- "internal/type_erased.cc",
+ "internal/private_handle_accessor.cc",
],
hdrs = [
- "internal/registry.h",
- "internal/type_erased.h",
+ "internal/private_handle_accessor.h",
],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
@@ -156,17 +153,67 @@
"//absl/flags:__pkg__",
],
deps = [
+ ":commandlineflag",
+ ":commandlineflag_internal",
+ "//absl/base:config",
+ "//absl/strings",
+ ],
+)
+
+cc_library(
+ name = "reflection",
+ srcs = [
+ "reflection.cc",
+ ],
+ hdrs = [
+ "internal/registry.h",
+ "reflection.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":commandlineflag",
+ ":commandlineflag_internal",
":config",
- ":handle",
+ ":private_handle_accessor",
+ "//absl/base:config",
"//absl/base:core_headers",
- "//absl/base:dynamic_annotations",
- "//absl/base:raw_logging_internal",
+ "//absl/container:flat_hash_map",
"//absl/strings",
"//absl/synchronization",
],
)
cc_library(
+ name = "flag_internal",
+ srcs = [
+ "internal/flag.cc",
+ ],
+ hdrs = [
+ "internal/flag.h",
+ "internal/sequence_lock.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = ["//absl/base:__subpackages__"],
+ deps = [
+ ":commandlineflag",
+ ":commandlineflag_internal",
+ ":config",
+ ":marshalling",
+ ":reflection",
+ "//absl/base",
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ "//absl/memory",
+ "//absl/meta:type_traits",
+ "//absl/strings",
+ "//absl/synchronization",
+ "//absl/utility",
+ ],
+)
+
+cc_library(
name = "flag",
srcs = [
"flag.cc",
@@ -180,9 +227,9 @@
deps = [
":config",
":flag_internal",
- ":handle",
- ":marshalling",
+ ":reflection",
"//absl/base",
+ "//absl/base:config",
"//absl/base:core_headers",
"//absl/strings",
],
@@ -202,13 +249,17 @@
"//absl/flags:__pkg__",
],
deps = [
+ ":commandlineflag",
":config",
":flag",
- ":handle",
+ ":flag_internal",
":path_util",
+ ":private_handle_accessor",
":program_name",
+ ":reflection",
+ "//absl/base:config",
+ "//absl/base:core_headers",
"//absl/strings",
- "//absl/synchronization",
],
)
@@ -224,6 +275,8 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":usage_internal",
+ "//absl/base:config",
+ "//absl/base:core_headers",
"//absl/strings",
"//absl/synchronization",
],
@@ -239,12 +292,18 @@
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
+ ":commandlineflag",
+ ":commandlineflag_internal",
":config",
":flag",
+ ":flag_internal",
+ ":private_handle_accessor",
":program_name",
- ":registry",
+ ":reflection",
":usage",
":usage_internal",
+ "//absl/base:config",
+ "//absl/base:core_headers",
"//absl/strings",
"//absl/synchronization",
],
@@ -257,15 +316,17 @@
name = "commandlineflag_test",
size = "small",
srcs = [
- "internal/commandlineflag_test.cc",
+ "commandlineflag_test.cc",
],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
+ ":commandlineflag",
+ ":commandlineflag_internal",
":config",
":flag",
- ":handle",
- ":registry",
+ ":private_handle_accessor",
+ ":reflection",
"//absl/memory",
"//absl/strings",
"@com_google_googletest//:gtest_main",
@@ -298,11 +359,42 @@
deps = [
":config",
":flag",
+ ":flag_internal",
+ ":marshalling",
+ ":reflection",
+ "//absl/base:core_headers",
+ "//absl/base:malloc_internal",
"//absl/strings",
+ "//absl/time",
"@com_google_googletest//:gtest_main",
],
)
+cc_binary(
+ name = "flag_benchmark",
+ testonly = 1,
+ srcs = [
+ "flag_benchmark.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = select({
+ "//conditions:default": [],
+ }) + ABSL_DEFAULT_LINKOPTS,
+ tags = ["benchmark"],
+ visibility = ["//visibility:private"],
+ deps = [
+ "flag_benchmark.lds",
+ ":flag",
+ ":marshalling",
+ ":parse",
+ ":reflection",
+ "//absl/strings",
+ "//absl/time",
+ "//absl/types:optional",
+ "@com_github_google_benchmark//:benchmark_main",
+ ],
+)
+
cc_test(
name = "marshalling_test",
size = "small",
@@ -318,20 +410,6 @@
)
cc_test(
- name = "path_util_test",
- size = "small",
- srcs = [
- "internal/path_util_test.cc",
- ],
- copts = ABSL_TEST_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
- deps = [
- ":path_util",
- "@com_google_googletest//:gtest_main",
- ],
-)
-
-cc_test(
name = "parse_test",
size = "small",
srcs = [
@@ -342,6 +420,8 @@
deps = [
":flag",
":parse",
+ ":reflection",
+ ":usage_internal",
"//absl/base:raw_logging_internal",
"//absl/base:scoped_set_env",
"//absl/strings",
@@ -351,6 +431,20 @@
)
cc_test(
+ name = "path_util_test",
+ size = "small",
+ srcs = [
+ "internal/path_util_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":path_util",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
name = "program_name_test",
size = "small",
srcs = [
@@ -366,16 +460,19 @@
)
cc_test(
- name = "type_erased_test",
+ name = "reflection_test",
size = "small",
srcs = [
- "internal/type_erased_test.cc",
+ "reflection_test.cc",
],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
+ ":commandlineflag_internal",
":flag",
- ":registry",
+ ":marshalling",
+ ":reflection",
+ ":usage_internal",
"//absl/memory",
"//absl/strings",
"@com_google_googletest//:gtest_main",
@@ -383,6 +480,25 @@
)
cc_test(
+ name = "sequence_lock_test",
+ size = "small",
+ timeout = "moderate",
+ srcs = [
+ "internal/sequence_lock_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ shard_count = 32,
+ deps = [
+ ":flag_internal",
+ "//absl/base",
+ "//absl/container:fixed_array",
+ "//absl/time",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
name = "usage_config_test",
size = "small",
srcs = [
@@ -413,9 +529,9 @@
":parse",
":path_util",
":program_name",
+ ":reflection",
":usage",
":usage_internal",
- "//absl/memory",
"//absl/strings",
"@com_google_googletest//:gtest",
],
diff --git a/third_party/abseil/absl/flags/CMakeLists.txt b/third_party/abseil/absl/flags/CMakeLists.txt
index 3a7162f..caac69c 100644
--- a/third_party/abseil/absl/flags/CMakeLists.txt
+++ b/third_party/abseil/absl/flags/CMakeLists.txt
@@ -17,19 +17,16 @@
# Internal-only target, do not depend on directly.
absl_cc_library(
NAME
- flags_internal
- SRCS
- "internal/flag.cc"
+ flags_path_util
HDRS
- "internal/flag.h"
+ "internal/path_util.h"
COPTS
${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
- absl::flags_handle
- absl::flags_registry
- absl::synchronization
+ absl::config
+ absl::strings
PUBLIC
)
@@ -46,27 +43,14 @@
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
+ absl::config
+ absl::core_headers
absl::flags_path_util
absl::strings
absl::synchronization
PUBLIC
)
-# Internal-only target, do not depend on directly.
-absl_cc_library(
- NAME
- flags_path_util
- HDRS
- "internal/path_util.h"
- COPTS
- ${ABSL_DEFAULT_COPTS}
- LINKOPTS
- ${ABSL_DEFAULT_LINKOPTS}
- DEPS
- absl::strings
- PUBLIC
-)
-
absl_cc_library(
NAME
flags_config
@@ -80,6 +64,7 @@
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
+ absl::config
absl::flags_path_util
absl::flags_program_name
absl::core_headers
@@ -99,7 +84,9 @@
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
+ absl::config
absl::core_headers
+ absl::log_severity
absl::strings
absl::str_format
)
@@ -107,7 +94,7 @@
# Internal-only target, do not depend on directly.
absl_cc_library(
NAME
- flags_handle
+ flags_commandlineflag_internal
SRCS
"internal/commandlineflag.cc"
HDRS
@@ -117,37 +104,94 @@
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
- absl::flags_config
- absl::flags_marshalling
- absl::core_headers
- absl::optional
- absl::raw_logging_internal
- absl::strings
- absl::synchronization
+ absl::config
+ absl::fast_type_id
)
-# Internal-only target, do not depend on directly.
absl_cc_library(
NAME
- flags_registry
+ flags_commandlineflag
SRCS
- "internal/registry.cc"
- "internal/type_erased.cc"
+ "commandlineflag.cc"
HDRS
- "internal/registry.h"
- "internal/type_erased.h"
+ "commandlineflag.h"
COPTS
${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
+ absl::config
+ absl::fast_type_id
+ absl::flags_commandlineflag_internal
+ absl::optional
+ absl::strings
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ flags_private_handle_accessor
+ SRCS
+ "internal/private_handle_accessor.cc"
+ HDRS
+ "internal/private_handle_accessor.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::config
+ absl::flags_commandlineflag
+ absl::flags_commandlineflag_internal
+ absl::strings
+)
+
+absl_cc_library(
+ NAME
+ flags_reflection
+ SRCS
+ "reflection.cc"
+ HDRS
+ "reflection.h"
+ "internal/registry.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::config
+ absl::flags_commandlineflag
+ absl::flags_private_handle_accessor
absl::flags_config
- absl::flags_handle
- absl::core_headers
- absl::dynamic_annotations
- absl::raw_logging_internal
absl::strings
absl::synchronization
+ absl::flat_hash_map
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ flags_internal
+ SRCS
+ "internal/flag.cc"
+ HDRS
+ "internal/flag.h"
+ "internal/sequence_lock.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::base
+ absl::config
+ absl::flags_commandlineflag
+ absl::flags_commandlineflag_internal
+ absl::flags_config
+ absl::flags_marshalling
+ absl::synchronization
+ absl::meta
+ absl::utility
+ PUBLIC
)
absl_cc_library(
@@ -163,10 +207,11 @@
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
+ absl::config
+ absl::flags_commandlineflag
absl::flags_config
- absl::flags_handle
absl::flags_internal
- absl::flags_marshalling
+ absl::flags_reflection
absl::base
absl::core_headers
absl::strings
@@ -185,11 +230,15 @@
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
+ absl::config
absl::flags_config
absl::flags
- absl::flags_handle
+ absl::flags_commandlineflag
+ absl::flags_internal
absl::flags_path_util
+ absl::flags_private_handle_accessor
absl::flags_program_name
+ absl::flags_reflection
absl::strings
absl::synchronization
)
@@ -206,6 +255,8 @@
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
+ absl::config
+ absl::core_headers
absl::flags_usage_internal
absl::strings
absl::synchronization
@@ -224,10 +275,16 @@
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
+ absl::config
+ absl::core_headers
absl::flags_config
absl::flags
+ absl::flags_commandlineflag
+ absl::flags_commandlineflag_internal
+ absl::flags_internal
+ absl::flags_private_handle_accessor
absl::flags_program_name
- absl::flags_registry
+ absl::flags_reflection
absl::flags_usage
absl::strings
absl::synchronization
@@ -240,14 +297,16 @@
NAME
flags_commandlineflag_test
SRCS
- "internal/commandlineflag_test.cc"
+ "commandlineflag_test.cc"
COPTS
${ABSL_TEST_COPTS}
DEPS
absl::flags
+ absl::flags_commandlineflag
+ absl::flags_commandlineflag_internal
absl::flags_config
- absl::flags_handle
- absl::flags_registry
+ absl::flags_private_handle_accessor
+ absl::flags_reflection
absl::memory
absl::strings
gtest_main
@@ -274,9 +333,14 @@
COPTS
${ABSL_TEST_COPTS}
DEPS
+ absl::core_headers
absl::flags
absl::flags_config
+ absl::flags_internal
+ absl::flags_marshalling
+ absl::flags_reflection
absl::strings
+ absl::time
gtest_main
)
@@ -302,6 +366,8 @@
DEPS
absl::flags
absl::flags_parse
+ absl::flags_reflection
+ absl::flags_usage_internal
absl::raw_logging_internal
absl::scoped_set_env
absl::span
@@ -336,17 +402,33 @@
absl_cc_test(
NAME
- flags_type_erased_test
+ flags_reflection_test
SRCS
- "internal/type_erased_test.cc"
+ "reflection_test.cc"
COPTS
${ABSL_TEST_COPTS}
DEPS
+ absl::flags_commandlineflag_internal
absl::flags
- absl::flags_registry
+ absl::flags_reflection
+ absl::flags_usage
absl::memory
absl::strings
- gtest_main
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ flags_sequence_lock_test
+ SRCS
+ "internal/sequence_lock_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::base
+ absl::flags_internal
+ absl::time
+ gmock_main
)
absl_cc_test(
@@ -377,8 +459,8 @@
absl::flags_path_util
absl::flags_program_name
absl::flags_parse
+ absl::flags_reflection
absl::flags_usage
- absl::memory
absl::strings
gtest
)
diff --git a/third_party/abseil/absl/flags/commandlineflag.cc b/third_party/abseil/absl/flags/commandlineflag.cc
new file mode 100644
index 0000000..9f3b4a5
--- /dev/null
+++ b/third_party/abseil/absl/flags/commandlineflag.cc
@@ -0,0 +1,34 @@
+//
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/flags/commandlineflag.h"
+
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+bool CommandLineFlag::IsRetired() const { return false; }
+bool CommandLineFlag::ParseFrom(absl::string_view value, std::string* error) {
+ return ParseFrom(value, flags_internal::SET_FLAGS_VALUE,
+ flags_internal::kProgrammaticChange, *error);
+}
+
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/flags/commandlineflag.h b/third_party/abseil/absl/flags/commandlineflag.h
new file mode 100644
index 0000000..f2fa089
--- /dev/null
+++ b/third_party/abseil/absl/flags/commandlineflag.h
@@ -0,0 +1,200 @@
+//
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: commandlineflag.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the `CommandLineFlag`, which acts as a type-erased
+// handle for accessing metadata about the Abseil Flag in question.
+//
+// Because an actual Abseil flag is of an unspecified type, you should not
+// manipulate or interact directly with objects of that type. Instead, use the
+// CommandLineFlag type as an intermediary.
+#ifndef ABSL_FLAGS_COMMANDLINEFLAG_H_
+#define ABSL_FLAGS_COMMANDLINEFLAG_H_
+
+#include <memory>
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/fast_type_id.h"
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace flags_internal {
+class PrivateHandleAccessor;
+} // namespace flags_internal
+
+// CommandLineFlag
+//
+// This type acts as a type-erased handle for an instance of an Abseil Flag and
+// holds reflection information pertaining to that flag. Use CommandLineFlag to
+// access a flag's name, location, help string etc.
+//
+// To obtain an absl::CommandLineFlag, invoke `absl::FindCommandLineFlag()`
+// passing it the flag name string.
+//
+// Example:
+//
+// // Obtain reflection handle for a flag named "flagname".
+// const absl::CommandLineFlag* my_flag_data =
+// absl::FindCommandLineFlag("flagname");
+//
+// // Now you can get flag info from that reflection handle.
+// std::string flag_location = my_flag_data->Filename();
+// ...
+class CommandLineFlag {
+ public:
+ constexpr CommandLineFlag() = default;
+
+ // Not copyable/assignable.
+ CommandLineFlag(const CommandLineFlag&) = delete;
+ CommandLineFlag& operator=(const CommandLineFlag&) = delete;
+
+ // absl::CommandLineFlag::IsOfType()
+ //
+ // Return true iff flag has type T.
+ template <typename T>
+ inline bool IsOfType() const {
+ return TypeId() == base_internal::FastTypeId<T>();
+ }
+
+ // absl::CommandLineFlag::TryGet()
+ //
+ // Attempts to retrieve the flag value. Returns value on success,
+ // absl::nullopt otherwise.
+ template <typename T>
+ absl::optional<T> TryGet() const {
+ if (IsRetired() || !IsOfType<T>()) {
+ return absl::nullopt;
+ }
+
+ // Implementation notes:
+ //
+ // We are wrapping a union around the value of `T` to serve three purposes:
+ //
+ // 1. `U.value` has correct size and alignment for a value of type `T`
+ // 2. The `U.value` constructor is not invoked since U's constructor does
+ // not do it explicitly.
+ // 3. The `U.value` destructor is invoked since U's destructor does it
+ // explicitly. This makes `U` a kind of RAII wrapper around non default
+ // constructible value of T, which is destructed when we leave the
+ // scope. We do need to destroy U.value, which is constructed by
+ // CommandLineFlag::Read even though we left it in a moved-from state
+ // after std::move.
+ //
+ // All of this serves to avoid requiring `T` being default constructible.
+ union U {
+ T value;
+ U() {}
+ ~U() { value.~T(); }
+ };
+ U u;
+
+ Read(&u.value);
+ // allow retired flags to be "read", so we can report invalid access.
+ if (IsRetired()) {
+ return absl::nullopt;
+ }
+ return std::move(u.value);
+ }
+
+ // absl::CommandLineFlag::Name()
+ //
+ // Returns name of this flag.
+ virtual absl::string_view Name() const = 0;
+
+ // absl::CommandLineFlag::Filename()
+ //
+ // Returns name of the file where this flag is defined.
+ virtual std::string Filename() const = 0;
+
+ // absl::CommandLineFlag::Help()
+ //
+ // Returns help message associated with this flag.
+ virtual std::string Help() const = 0;
+
+ // absl::CommandLineFlag::IsRetired()
+ //
+ // Returns true iff this object corresponds to retired flag.
+ virtual bool IsRetired() const;
+
+ // absl::CommandLineFlag::DefaultValue()
+ //
+ // Returns the default value for this flag.
+ virtual std::string DefaultValue() const = 0;
+
+ // absl::CommandLineFlag::CurrentValue()
+ //
+ // Returns the current value for this flag.
+ virtual std::string CurrentValue() const = 0;
+
+ // absl::CommandLineFlag::ParseFrom()
+ //
+ // Sets the value of the flag based on specified string `value`. If the flag
+ // was successfully set to new value, it returns true. Otherwise, sets `error`
+ // to indicate the error, leaves the flag unchanged, and returns false.
+ bool ParseFrom(absl::string_view value, std::string* error);
+
+ protected:
+ ~CommandLineFlag() = default;
+
+ private:
+ friend class flags_internal::PrivateHandleAccessor;
+
+ // Sets the value of the flag based on specified string `value`. If the flag
+ // was successfully set to new value, it returns true. Otherwise, sets `error`
+ // to indicate the error, leaves the flag unchanged, and returns false. There
+ // are three ways to set the flag's value:
+ // * Update the current flag value
+ // * Update the flag's default value
+ // * Update the current flag value if it was never set before
+ // The mode is selected based on `set_mode` parameter.
+ virtual bool ParseFrom(absl::string_view value,
+ flags_internal::FlagSettingMode set_mode,
+ flags_internal::ValueSource source,
+ std::string& error) = 0;
+
+ // Returns id of the flag's value type.
+ virtual flags_internal::FlagFastTypeId TypeId() const = 0;
+
+ // Interface to save flag to some persistent state. Returns current flag state
+ // or nullptr if flag does not support saving and restoring a state.
+ virtual std::unique_ptr<flags_internal::FlagStateInterface> SaveState() = 0;
+
+ // Copy-construct a new value of the flag's type in a memory referenced by
+ // the dst based on the current flag's value.
+ virtual void Read(void* dst) const = 0;
+
+ // To be deleted. Used to return true if flag's current value originated from
+ // command line.
+ virtual bool IsSpecifiedOnCommandLine() const = 0;
+
+ // Validates supplied value usign validator or parseflag routine
+ virtual bool ValidateInputValue(absl::string_view value) const = 0;
+
+ // Checks that flags default value can be converted to string and back to the
+ // flag's value type.
+ virtual void CheckDefaultValueParsingRoundtrip() const = 0;
+};
+
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_FLAGS_COMMANDLINEFLAG_H_
diff --git a/third_party/abseil/absl/flags/commandlineflag_test.cc b/third_party/abseil/absl/flags/commandlineflag_test.cc
new file mode 100644
index 0000000..585db4b
--- /dev/null
+++ b/third_party/abseil/absl/flags/commandlineflag_test.cc
@@ -0,0 +1,231 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/flags/commandlineflag.h"
+
+#include <memory>
+#include <string>
+
+#include "gtest/gtest.h"
+#include "absl/flags/flag.h"
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/flags/internal/private_handle_accessor.h"
+#include "absl/flags/reflection.h"
+#include "absl/flags/usage_config.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/match.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+
+ABSL_FLAG(int, int_flag, 201, "int_flag help");
+ABSL_FLAG(std::string, string_flag, "dflt",
+ absl::StrCat("string_flag", " help"));
+ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help");
+
+// These are only used to test default values.
+ABSL_FLAG(int, int_flag2, 201, "");
+ABSL_FLAG(std::string, string_flag2, "dflt", "");
+
+namespace {
+
+namespace flags = absl::flags_internal;
+
+class CommandLineFlagTest : public testing::Test {
+ protected:
+ static void SetUpTestSuite() {
+ // Install a function to normalize filenames before this test is run.
+ absl::FlagsUsageConfig default_config;
+ default_config.normalize_filename = &CommandLineFlagTest::NormalizeFileName;
+ absl::SetFlagsUsageConfig(default_config);
+ }
+
+ void SetUp() override { flag_saver_ = absl::make_unique<absl::FlagSaver>(); }
+ void TearDown() override { flag_saver_.reset(); }
+
+ private:
+ static std::string NormalizeFileName(absl::string_view fname) {
+#ifdef _WIN32
+ std::string normalized(fname);
+ std::replace(normalized.begin(), normalized.end(), '\\', '/');
+ fname = normalized;
+#endif
+ return std::string(fname);
+ }
+
+ std::unique_ptr<absl::FlagSaver> flag_saver_;
+};
+
+TEST_F(CommandLineFlagTest, TestAttributesAccessMethods) {
+ auto* flag_01 = absl::FindCommandLineFlag("int_flag");
+
+ ASSERT_TRUE(flag_01);
+ EXPECT_EQ(flag_01->Name(), "int_flag");
+ EXPECT_EQ(flag_01->Help(), "int_flag help");
+ EXPECT_TRUE(!flag_01->IsRetired());
+ EXPECT_TRUE(flag_01->IsOfType<int>());
+ EXPECT_TRUE(!flag_01->IsOfType<bool>());
+ EXPECT_TRUE(!flag_01->IsOfType<std::string>());
+ EXPECT_TRUE(absl::EndsWith(flag_01->Filename(),
+ "absl/flags/commandlineflag_test.cc"))
+ << flag_01->Filename();
+
+ auto* flag_02 = absl::FindCommandLineFlag("string_flag");
+
+ ASSERT_TRUE(flag_02);
+ EXPECT_EQ(flag_02->Name(), "string_flag");
+ EXPECT_EQ(flag_02->Help(), "string_flag help");
+ EXPECT_TRUE(!flag_02->IsRetired());
+ EXPECT_TRUE(flag_02->IsOfType<std::string>());
+ EXPECT_TRUE(!flag_02->IsOfType<bool>());
+ EXPECT_TRUE(!flag_02->IsOfType<int>());
+ EXPECT_TRUE(absl::EndsWith(flag_02->Filename(),
+ "absl/flags/commandlineflag_test.cc"))
+ << flag_02->Filename();
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(CommandLineFlagTest, TestValueAccessMethods) {
+ absl::SetFlag(&FLAGS_int_flag2, 301);
+ auto* flag_01 = absl::FindCommandLineFlag("int_flag2");
+
+ ASSERT_TRUE(flag_01);
+ EXPECT_EQ(flag_01->CurrentValue(), "301");
+ EXPECT_EQ(flag_01->DefaultValue(), "201");
+
+ absl::SetFlag(&FLAGS_string_flag2, "new_str_value");
+ auto* flag_02 = absl::FindCommandLineFlag("string_flag2");
+
+ ASSERT_TRUE(flag_02);
+ EXPECT_EQ(flag_02->CurrentValue(), "new_str_value");
+ EXPECT_EQ(flag_02->DefaultValue(), "dflt");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(CommandLineFlagTest, TestParseFromCurrentValue) {
+ std::string err;
+
+ auto* flag_01 = absl::FindCommandLineFlag("int_flag");
+ EXPECT_FALSE(
+ flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
+
+ EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+ *flag_01, "11", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, err));
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11);
+ EXPECT_FALSE(
+ flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
+
+ EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+ *flag_01, "-123", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
+ err));
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
+ EXPECT_FALSE(
+ flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
+
+ EXPECT_TRUE(!flags::PrivateHandleAccessor::ParseFrom(
+ *flag_01, "xyz", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
+ err));
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
+ EXPECT_EQ(err, "Illegal value 'xyz' specified for flag 'int_flag'");
+ EXPECT_FALSE(
+ flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
+
+ EXPECT_TRUE(!flags::PrivateHandleAccessor::ParseFrom(
+ *flag_01, "A1", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, err));
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
+ EXPECT_EQ(err, "Illegal value 'A1' specified for flag 'int_flag'");
+ EXPECT_FALSE(
+ flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
+
+ EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+ *flag_01, "0x10", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
+ err));
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 16);
+ EXPECT_FALSE(
+ flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
+
+ EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+ *flag_01, "011", flags::SET_FLAGS_VALUE, flags::kCommandLine, err));
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11);
+ EXPECT_TRUE(flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01));
+
+ EXPECT_TRUE(!flags::PrivateHandleAccessor::ParseFrom(
+ *flag_01, "", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, err));
+ EXPECT_EQ(err, "Illegal value '' specified for flag 'int_flag'");
+
+ auto* flag_02 = absl::FindCommandLineFlag("string_flag");
+ EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+ *flag_02, "xyz", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
+ err));
+ EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "xyz");
+
+ EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+ *flag_02, "", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, err));
+ EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(CommandLineFlagTest, TestParseFromDefaultValue) {
+ std::string err;
+
+ auto* flag_01 = absl::FindCommandLineFlag("int_flag");
+
+ EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+ *flag_01, "111", flags::SET_FLAGS_DEFAULT, flags::kProgrammaticChange,
+ err));
+ EXPECT_EQ(flag_01->DefaultValue(), "111");
+
+ auto* flag_02 = absl::FindCommandLineFlag("string_flag");
+
+ EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+ *flag_02, "abc", flags::SET_FLAGS_DEFAULT, flags::kProgrammaticChange,
+ err));
+ EXPECT_EQ(flag_02->DefaultValue(), "abc");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(CommandLineFlagTest, TestParseFromIfDefault) {
+ std::string err;
+
+ auto* flag_01 = absl::FindCommandLineFlag("int_flag");
+
+ EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+ *flag_01, "22", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange,
+ err))
+ << err;
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 22);
+
+ EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+ *flag_01, "33", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange,
+ err));
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 22);
+ // EXPECT_EQ(err, "ERROR: int_flag is already set to 22");
+
+ // Reset back to default value
+ EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+ *flag_01, "201", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange,
+ err));
+
+ EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom(
+ *flag_01, "33", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange,
+ err));
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 201);
+ // EXPECT_EQ(err, "ERROR: int_flag is already set to 201");
+}
+
+} // namespace
diff --git a/third_party/abseil/absl/flags/config.h b/third_party/abseil/absl/flags/config.h
index a9fd97a..5ab1f31 100644
--- a/third_party/abseil/absl/flags/config.h
+++ b/third_party/abseil/absl/flags/config.h
@@ -45,4 +45,32 @@
#define ABSL_FLAGS_STRIP_HELP ABSL_FLAGS_STRIP_NAMES
#endif
+// ABSL_FLAGS_INTERNAL_HAS_RTTI macro is used for selecting if we can use RTTI
+// for flag type identification.
+#ifdef ABSL_FLAGS_INTERNAL_HAS_RTTI
+#error ABSL_FLAGS_INTERNAL_HAS_RTTI cannot be directly set
+#elif !defined(__GNUC__) || defined(__GXX_RTTI)
+#define ABSL_FLAGS_INTERNAL_HAS_RTTI 1
+#endif // !defined(__GNUC__) || defined(__GXX_RTTI)
+
+// These macros represent the "source of truth" for the list of supported
+// built-in types.
+#define ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(A) \
+ A(bool, bool) \
+ A(short, short) \
+ A(unsigned short, unsigned_short) \
+ A(int, int) \
+ A(unsigned int, unsigned_int) \
+ A(long, long) \
+ A(unsigned long, unsigned_long) \
+ A(long long, long_long) \
+ A(unsigned long long, unsigned_long_long) \
+ A(double, double) \
+ A(float, float)
+
+#define ABSL_FLAGS_INTERNAL_SUPPORTED_TYPES(A) \
+ ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(A) \
+ A(std::string, std_string) \
+ A(std::vector<std::string>, std_vector_of_string)
+
#endif // ABSL_FLAGS_CONFIG_H_
diff --git a/third_party/abseil/absl/flags/declare.h b/third_party/abseil/absl/flags/declare.h
index 0a113a2..b9794d8 100644
--- a/third_party/abseil/absl/flags/declare.h
+++ b/third_party/abseil/absl/flags/declare.h
@@ -25,9 +25,10 @@
#ifndef ABSL_FLAGS_DECLARE_H_
#define ABSL_FLAGS_DECLARE_H_
-#include "absl/strings/string_view.h"
+#include "absl/base/config.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace flags_internal {
// absl::Flag<T> represents a flag of type 'T' created by ABSL_FLAG.
@@ -39,7 +40,7 @@
// Flag
//
// Forward declaration of the `absl::Flag` type for use in defining the macro.
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) && !defined(__clang__)
template <typename T>
class Flag;
#else
@@ -47,6 +48,7 @@
using Flag = flags_internal::Flag<T>;
#endif
+ABSL_NAMESPACE_END
} // namespace absl
// ABSL_DECLARE_FLAG()
diff --git a/third_party/abseil/absl/flags/flag.cc b/third_party/abseil/absl/flags/flag.cc
index a02d069..531df12 100644
--- a/third_party/abseil/absl/flags/flag.cc
+++ b/third_party/abseil/absl/flags/flag.cc
@@ -15,46 +15,24 @@
#include "absl/flags/flag.h"
-#include <cstring>
+#include "absl/base/config.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
-// We want to validate the type mismatch between type definition and
-// declaration. The lock-free implementation does not allow us to do it,
-// so in debug builds we always use the slower implementation, which always
-// validates the type.
-#ifndef NDEBUG
-#define ABSL_FLAGS_ATOMIC_GET(T) \
- T GetFlag(const absl::Flag<T>& flag) { return flag.Get(); }
-#else
-#define ABSL_FLAGS_ATOMIC_GET(T) \
- T GetFlag(const absl::Flag<T>& flag) { \
- T result; \
- if (flag.AtomicGet(&result)) { \
- return result; \
- } \
- return flag.Get(); \
- }
-#endif
-
-ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(ABSL_FLAGS_ATOMIC_GET)
-
-#undef ABSL_FLAGS_ATOMIC_GET
-
-// This global nutex protects on-demand construction of flag objects in MSVC
+// This global mutex protects on-demand construction of flag objects in MSVC
// builds.
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) && !defined(__clang__)
namespace flags_internal {
ABSL_CONST_INIT static absl::Mutex construction_guard(absl::kConstInit);
-void LockGlobalConstructionGuard() { construction_guard.Lock(); }
-
-void UnlockGlobalConstructionGuard() { construction_guard.Unlock(); }
+absl::Mutex* GetGlobalConstructionGuard() { return &construction_guard; }
} // namespace flags_internal
#endif
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/flags/flag.h b/third_party/abseil/absl/flags/flag.h
index 881f850..a9cb2b7 100644
--- a/third_party/abseil/absl/flags/flag.h
+++ b/third_party/abseil/absl/flags/flag.h
@@ -29,15 +29,19 @@
#ifndef ABSL_FLAGS_FLAG_H_
#define ABSL_FLAGS_FLAG_H_
+#include <string>
+#include <type_traits>
+
#include "absl/base/attributes.h"
-#include "absl/base/casts.h"
+#include "absl/base/config.h"
+#include "absl/base/optimization.h"
#include "absl/flags/config.h"
-#include "absl/flags/declare.h"
-#include "absl/flags/internal/commandlineflag.h"
#include "absl/flags/internal/flag.h"
-#include "absl/flags/marshalling.h"
+#include "absl/flags/internal/registry.h"
+#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// Flag
//
@@ -63,98 +67,104 @@
// ABSL_FLAG(int, count, 0, "Count of items to process");
//
// No public methods of `absl::Flag<T>` are part of the Abseil Flags API.
-#if !defined(_MSC_VER)
+#if !defined(_MSC_VER) || defined(__clang__)
template <typename T>
using Flag = flags_internal::Flag<T>;
#else
-// MSVC debug builds do not implement constexpr correctly for classes with
-// virtual methods. To work around this we adding level of indirection, so that
-// the class `absl::Flag` contains an `internal::Flag*` (instead of being an
-// alias to that class) and dynamically allocates an instance when necessary.
-// We also forward all calls to internal::Flag methods via trampoline methods.
-// In this setup the `absl::Flag` class does not have virtual methods and thus
-// MSVC is able to initialize it at link time. To deal with multiple threads
-// accessing the flag for the first time concurrently we use an atomic boolean
-// indicating if flag object is constructed. We also employ the double-checked
-// locking pattern where the second level of protection is a global Mutex, so
-// if two threads attempt to construct the flag concurrently only one wins.
+// MSVC debug builds do not implement initialization with constexpr constructors
+// correctly. To work around this we add a level of indirection, so that the
+// class `absl::Flag` contains an `internal::Flag*` (instead of being an alias
+// to that class) and dynamically allocates an instance when necessary. We also
+// forward all calls to internal::Flag methods via trampoline methods. In this
+// setup the `absl::Flag` class does not have constructor and virtual methods,
+// all the data members are public and thus MSVC is able to initialize it at
+// link time. To deal with multiple threads accessing the flag for the first
+// time concurrently we use an atomic boolean indicating if flag object is
+// initialized. We also employ the double-checked locking pattern where the
+// second level of protection is a global Mutex, so if two threads attempt to
+// construct the flag concurrently only one wins.
+// This solution is based on a recomendation here:
+// https://developercommunity.visualstudio.com/content/problem/336946/class-with-constexpr-constructor-not-using-static.html?childToView=648454#comment-648454
namespace flags_internal {
-void LockGlobalConstructionGuard();
-void UnlockGlobalConstructionGuard();
+absl::Mutex* GetGlobalConstructionGuard();
} // namespace flags_internal
template <typename T>
class Flag {
public:
- constexpr Flag(const char* name, const flags_internal::HelpGenFunc help_gen,
- const char* filename,
- const flags_internal::FlagMarshallingOpFn marshalling_op,
- const flags_internal::InitialValGenFunc initial_value_gen)
+ // No constructor and destructor to ensure this is an aggregate type.
+ // Visual Studio 2015 still requires the constructor for class to be
+ // constexpr initializable.
+#if _MSC_VER <= 1900
+ constexpr Flag(const char* name, const char* filename,
+ const flags_internal::HelpGenFunc help_gen,
+ const flags_internal::FlagDfltGenFunc default_value_gen)
: name_(name),
- help_gen_(help_gen),
filename_(filename),
- marshalling_op_(marshalling_op),
- initial_value_gen_(initial_value_gen),
- inited_(false) {}
+ help_gen_(help_gen),
+ default_value_gen_(default_value_gen),
+ inited_(false),
+ impl_(nullptr) {}
+#endif
- flags_internal::Flag<T>* GetImpl() const {
+ flags_internal::Flag<T>& GetImpl() const {
if (!inited_.load(std::memory_order_acquire)) {
- flags_internal::LockGlobalConstructionGuard();
+ absl::MutexLock l(flags_internal::GetGlobalConstructionGuard());
if (inited_.load(std::memory_order_acquire)) {
- return impl_;
+ return *impl_;
}
- impl_ = new flags_internal::Flag<T>(name_, help_gen_, filename_,
- marshalling_op_, initial_value_gen_);
+ impl_ = new flags_internal::Flag<T>(
+ name_, filename_,
+ {flags_internal::FlagHelpMsg(help_gen_),
+ flags_internal::FlagHelpKind::kGenFunc},
+ {flags_internal::FlagDefaultSrc(default_value_gen_),
+ flags_internal::FlagDefaultKind::kGenFunc});
inited_.store(true, std::memory_order_release);
-
- flags_internal::UnlockGlobalConstructionGuard();
}
- return impl_;
+ return *impl_;
}
- // absl::Flag API
- bool IsRetired() const { return GetImpl()->IsRetired(); }
- bool IsAbseilFlag() const { return GetImpl()->IsAbseilFlag(); }
- absl::string_view Name() const { return GetImpl()->Name(); }
- std::string Help() const { return GetImpl()->Help(); }
- bool IsModified() const { return GetImpl()->IsModified(); }
- void SetModified(bool is_modified) { GetImpl()->SetModified(is_modified); }
+ // Public methods of `absl::Flag<T>` are NOT part of the Abseil Flags API.
+ // See https://abseil.io/docs/cpp/guides/flags
+ bool IsRetired() const { return GetImpl().IsRetired(); }
+ absl::string_view Name() const { return GetImpl().Name(); }
+ std::string Help() const { return GetImpl().Help(); }
+ bool IsModified() const { return GetImpl().IsModified(); }
bool IsSpecifiedOnCommandLine() const {
- GetImpl()->IsSpecifiedOnCommandLine();
+ return GetImpl().IsSpecifiedOnCommandLine();
}
- absl::string_view Typename() const { return GetImpl()->Typename(); }
- std::string Filename() const { return GetImpl()->Filename(); }
- std::string DefaultValue() const { return GetImpl()->DefaultValue(); }
- std::string CurrentValue() const { return GetImpl()->CurrentValue(); }
- bool HasValidatorFn() const { return GetImpl()->HasValidatorFn(); }
- bool InvokeValidator(const void* value) const {
- return GetImpl()->InvokeValidator(value);
- }
- template <typename T>
+ std::string Filename() const { return GetImpl().Filename(); }
+ std::string DefaultValue() const { return GetImpl().DefaultValue(); }
+ std::string CurrentValue() const { return GetImpl().CurrentValue(); }
+ template <typename U>
inline bool IsOfType() const {
- return GetImpl()->IsOftype<T>();
+ return GetImpl().template IsOfType<U>();
}
- T Get() const { return GetImpl()->Get(); }
- bool AtomicGet(T* v) const { return GetImpl()->AtomicGet(v); }
- void Set(const T& v) { GetImpl()->Set(v); }
- void SetCallback(const flags_internal::FlagCallback mutation_callback) {
- GetImpl()->SetCallback(mutation_callback);
+ T Get() const {
+ return flags_internal::FlagImplPeer::InvokeGet<T>(GetImpl());
}
- void InvokeCallback() { GetImpl()->InvokeCallback(); }
+ void Set(const T& v) {
+ flags_internal::FlagImplPeer::InvokeSet(GetImpl(), v);
+ }
+ void InvokeCallback() { GetImpl().InvokeCallback(); }
- private:
+ const CommandLineFlag& Reflect() const {
+ return flags_internal::FlagImplPeer::InvokeReflect(GetImpl());
+ }
+
+ // The data members are logically private, but they need to be public for
+ // this to be an aggregate type.
const char* name_;
- const flags_internal::HelpGenFunc help_gen_;
const char* filename_;
- const flags_internal::FlagMarshallingOpFn marshalling_op_;
- const flags_internal::InitialValGenFunc initial_value_gen_;
+ const flags_internal::HelpGenFunc help_gen_;
+ const flags_internal::FlagDfltGenFunc default_value_gen_;
mutable std::atomic<bool> inited_;
- mutable flags_internal::Flag<T>* impl_ = nullptr;
+ mutable flags_internal::Flag<T>* impl_;
};
#endif
@@ -176,22 +186,9 @@
// std::string first_name = absl::GetFlag(FLAGS_firstname);
template <typename T>
ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag<T>& flag) {
-#define ABSL_FLAGS_INTERNAL_LOCK_FREE_VALIDATE(BIT) \
- static_assert( \
- !std::is_same<T, BIT>::value, \
- "Do not specify explicit template parameters to absl::GetFlag");
- ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(ABSL_FLAGS_INTERNAL_LOCK_FREE_VALIDATE)
-#undef ABSL_FLAGS_INTERNAL_LOCK_FREE_VALIDATE
-
- return flag.Get();
+ return flags_internal::FlagImplPeer::InvokeGet<T>(flag);
}
-// Overload for `GetFlag()` for types that support lock-free reads.
-#define ABSL_FLAGS_INTERNAL_LOCK_FREE_EXPORT(T) \
- ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag<T>& flag);
-ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(ABSL_FLAGS_INTERNAL_LOCK_FREE_EXPORT)
-#undef ABSL_FLAGS_INTERNAL_LOCK_FREE_EXPORT
-
// SetFlag()
//
// Sets the value of an `absl::Flag` to the value `v`. Do not construct an
@@ -201,7 +198,7 @@
// but especially within performance-critical code.
template <typename T>
void SetFlag(absl::Flag<T>* flag, const T& v) {
- flag->Set(v);
+ flags_internal::FlagImplPeer::InvokeSet(*flag, v);
}
// Overload of `SetFlag()` to allow callers to pass in a value that is
@@ -210,9 +207,25 @@
template <typename T, typename V>
void SetFlag(absl::Flag<T>* flag, const V& v) {
T value(v);
- flag->Set(value);
+ flags_internal::FlagImplPeer::InvokeSet(*flag, value);
}
+// GetFlagReflectionHandle()
+//
+// Returns the reflection handle corresponding to specified Abseil Flag
+// instance. Use this handle to access flag's reflection information, like name,
+// location, default value etc.
+//
+// Example:
+//
+// std::string = absl::GetFlagReflectionHandle(FLAGS_count).DefaultValue();
+
+template <typename T>
+const CommandLineFlag& GetFlagReflectionHandle(const absl::Flag<T>& f) {
+ return flags_internal::FlagImplPeer::InvokeReflect(f);
+}
+
+ABSL_NAMESPACE_END
} // namespace absl
@@ -272,27 +285,29 @@
// -----------------------------------------------------------------------------
// ABSL_FLAG_IMPL macro definition conditional on ABSL_FLAGS_STRIP_NAMES
+#if !defined(_MSC_VER) || defined(__clang__)
+#define ABSL_FLAG_IMPL_FLAG_PTR(flag) flag
+#define ABSL_FLAG_IMPL_HELP_ARG(name) \
+ absl::flags_internal::HelpArg<AbslFlagHelpGenFor##name>( \
+ FLAGS_help_storage_##name)
+#define ABSL_FLAG_IMPL_DEFAULT_ARG(Type, name) \
+ absl::flags_internal::DefaultArg<Type, AbslFlagDefaultGenFor##name>(0)
+#else
+#define ABSL_FLAG_IMPL_FLAG_PTR(flag) flag.GetImpl()
+#define ABSL_FLAG_IMPL_HELP_ARG(name) &AbslFlagHelpGenFor##name::NonConst
+#define ABSL_FLAG_IMPL_DEFAULT_ARG(Type, name) &AbslFlagDefaultGenFor##name::Gen
+#endif
#if ABSL_FLAGS_STRIP_NAMES
#define ABSL_FLAG_IMPL_FLAGNAME(txt) ""
#define ABSL_FLAG_IMPL_FILENAME() ""
-#if !defined(_MSC_VER)
#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
- absl::flags_internal::FlagRegistrar<T, false>(&flag)
-#else
-#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
- absl::flags_internal::FlagRegistrar<T, false>(flag.GetImpl())
-#endif
+ absl::flags_internal::FlagRegistrar<T, false>(ABSL_FLAG_IMPL_FLAG_PTR(flag))
#else
#define ABSL_FLAG_IMPL_FLAGNAME(txt) txt
#define ABSL_FLAG_IMPL_FILENAME() __FILE__
-#if !defined(_MSC_VER)
#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
- absl::flags_internal::FlagRegistrar<T, true>(&flag)
-#else
-#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
- absl::flags_internal::FlagRegistrar<T, true>(flag.GetImpl())
-#endif
+ absl::flags_internal::FlagRegistrar<T, true>(ABSL_FLAG_IMPL_FLAG_PTR(flag))
#endif
// ABSL_FLAG_IMPL macro definition conditional on ABSL_FLAGS_STRIP_HELP
@@ -303,32 +318,53 @@
#define ABSL_FLAG_IMPL_FLAGHELP(txt) txt
#endif
-#define ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, txt) \
- static std::string AbslFlagsWrapHelp##name() { \
- return ABSL_FLAG_IMPL_FLAGHELP(txt); \
- }
+// AbslFlagHelpGenFor##name is used to encapsulate both immediate (method Const)
+// and lazy (method NonConst) evaluation of help message expression. We choose
+// between the two via the call to HelpArg in absl::Flag instantiation below.
+// If help message expression is constexpr evaluable compiler will optimize
+// away this whole struct.
+// TODO(rogeeff): place these generated structs into local namespace and apply
+// ABSL_INTERNAL_UNIQUE_SHORT_NAME.
+// TODO(rogeeff): Apply __attribute__((nodebug)) to FLAGS_help_storage_##name
+#define ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, txt) \
+ struct AbslFlagHelpGenFor##name { \
+ /* The expression is run in the caller as part of the */ \
+ /* default value argument. That keeps temporaries alive */ \
+ /* long enough for NonConst to work correctly. */ \
+ static constexpr absl::string_view Value( \
+ absl::string_view v = ABSL_FLAG_IMPL_FLAGHELP(txt)) { \
+ return v; \
+ } \
+ static std::string NonConst() { return std::string(Value()); } \
+ }; \
+ constexpr auto FLAGS_help_storage_##name ABSL_INTERNAL_UNIQUE_SMALL_NAME() \
+ ABSL_ATTRIBUTE_SECTION_VARIABLE(flags_help_cold) = \
+ absl::flags_internal::HelpStringAsArray<AbslFlagHelpGenFor##name>( \
+ 0);
-#define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \
- static void* AbslFlagsInitFlag##name() { \
- return absl::flags_internal::MakeFromDefaultValue<Type>(default_value); \
- }
+#define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \
+ struct AbslFlagDefaultGenFor##name { \
+ Type value = absl::flags_internal::InitDefaultValue<Type>(default_value); \
+ static void Gen(void* p) { \
+ new (p) Type(AbslFlagDefaultGenFor##name{}.value); \
+ } \
+ };
// ABSL_FLAG_IMPL
//
// Note: Name of registrar object is not arbitrary. It is used to "grab"
// global name for FLAGS_no<flag_name> symbol, thus preventing the possibility
// of defining two flags with names foo and nofoo.
-#define ABSL_FLAG_IMPL(Type, name, default_value, help) \
- namespace absl /* block flags in namespaces */ {} \
- ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \
- ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help) \
- ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name( \
- ABSL_FLAG_IMPL_FLAGNAME(#name), &AbslFlagsWrapHelp##name, \
- ABSL_FLAG_IMPL_FILENAME(), \
- &absl::flags_internal::FlagMarshallingOps<Type>, \
- &AbslFlagsInitFlag##name); \
- extern bool FLAGS_no##name; \
- bool FLAGS_no##name = ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name)
+#define ABSL_FLAG_IMPL(Type, name, default_value, help) \
+ namespace absl /* block flags in namespaces */ {} \
+ ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \
+ ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help) \
+ ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{ \
+ ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(), \
+ ABSL_FLAG_IMPL_HELP_ARG(name), ABSL_FLAG_IMPL_DEFAULT_ARG(Type, name)}; \
+ extern absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name; \
+ absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name = \
+ ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name)
// ABSL_RETIRED_FLAG
//
@@ -349,11 +385,12 @@
//
// `default_value` is only used as a double check on the type. `explanation` is
// unused.
-// TODO(rogeeff): Return an anonymous struct instead of bool, and place it into
-// the unnamed namespace.
-#define ABSL_RETIRED_FLAG(type, flagname, default_value, explanation) \
- ABSL_ATTRIBUTE_UNUSED static const bool ignored_##flagname = \
- ([] { return type(default_value); }, \
- absl::flags_internal::RetiredFlag<type>(#flagname))
+// TODO(rogeeff): replace RETIRED_FLAGS with FLAGS once forward declarations of
+// retired flags are cleaned up.
+#define ABSL_RETIRED_FLAG(type, name, default_value, explanation) \
+ static absl::flags_internal::RetiredFlag<type> RETIRED_FLAGS_##name; \
+ ABSL_ATTRIBUTE_UNUSED static const auto RETIRED_FLAGS_REG_##name = \
+ (RETIRED_FLAGS_##name.Retire(#name), \
+ ::absl::flags_internal::FlagRegistrarEmpty{})
#endif // ABSL_FLAGS_FLAG_H_
diff --git a/third_party/abseil/absl/flags/flag_benchmark.cc b/third_party/abseil/absl/flags/flag_benchmark.cc
new file mode 100644
index 0000000..57584f8
--- /dev/null
+++ b/third_party/abseil/absl/flags/flag_benchmark.cc
@@ -0,0 +1,168 @@
+//
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "absl/flags/flag.h"
+#include "absl/flags/marshalling.h"
+#include "absl/flags/parse.h"
+#include "absl/flags/reflection.h"
+#include "absl/strings/string_view.h"
+#include "absl/time/time.h"
+#include "absl/types/optional.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+using String = std::string;
+using VectorOfStrings = std::vector<std::string>;
+using AbslDuration = absl::Duration;
+
+// We do not want to take over marshalling for the types absl::optional<int>,
+// absl::optional<std::string> which we do not own. Instead we introduce unique
+// "aliases" to these types, which we do.
+using AbslOptionalInt = absl::optional<int>;
+struct OptionalInt : AbslOptionalInt {
+ using AbslOptionalInt::AbslOptionalInt;
+};
+// Next two functions represent Abseil Flags marshalling for OptionalInt.
+bool AbslParseFlag(absl::string_view src, OptionalInt* flag,
+ std::string* error) {
+ int val;
+ if (src.empty())
+ flag->reset();
+ else if (!absl::ParseFlag(src, &val, error))
+ return false;
+ *flag = val;
+ return true;
+}
+std::string AbslUnparseFlag(const OptionalInt& flag) {
+ return !flag ? "" : absl::UnparseFlag(*flag);
+}
+
+using AbslOptionalString = absl::optional<std::string>;
+struct OptionalString : AbslOptionalString {
+ using AbslOptionalString::AbslOptionalString;
+};
+// Next two functions represent Abseil Flags marshalling for OptionalString.
+bool AbslParseFlag(absl::string_view src, OptionalString* flag,
+ std::string* error) {
+ std::string val;
+ if (src.empty())
+ flag->reset();
+ else if (!absl::ParseFlag(src, &val, error))
+ return false;
+ *flag = val;
+ return true;
+}
+std::string AbslUnparseFlag(const OptionalString& flag) {
+ return !flag ? "" : absl::UnparseFlag(*flag);
+}
+
+struct UDT {
+ UDT() = default;
+ UDT(const UDT&) {}
+ UDT& operator=(const UDT&) { return *this; }
+};
+// Next two functions represent Abseil Flags marshalling for UDT.
+bool AbslParseFlag(absl::string_view, UDT*, std::string*) { return true; }
+std::string AbslUnparseFlag(const UDT&) { return ""; }
+
+} // namespace
+
+#define BENCHMARKED_TYPES(A) \
+ A(bool) \
+ A(int16_t) \
+ A(uint16_t) \
+ A(int32_t) \
+ A(uint32_t) \
+ A(int64_t) \
+ A(uint64_t) \
+ A(double) \
+ A(float) \
+ A(String) \
+ A(VectorOfStrings) \
+ A(OptionalInt) \
+ A(OptionalString) \
+ A(AbslDuration) \
+ A(UDT)
+
+#define FLAG_DEF(T) ABSL_FLAG(T, T##_flag, {}, "");
+
+#if defined(__clang__) && defined(__linux__)
+// Force the flags used for benchmarks into a separate ELF section.
+// This ensures that, even when other parts of the code might change size,
+// the layout of the flags across cachelines is kept constant. This makes
+// benchmark results more reproducible across unrelated code changes.
+#pragma clang section data = ".benchmark_flags"
+#endif
+BENCHMARKED_TYPES(FLAG_DEF)
+#if defined(__clang__) && defined(__linux__)
+#pragma clang section data = ""
+#endif
+// Register thousands of flags to bloat up the size of the registry.
+// This mimics real life production binaries.
+#define DEFINE_FLAG_0(name) ABSL_FLAG(int, name, 0, "");
+#define DEFINE_FLAG_1(name) DEFINE_FLAG_0(name##0) DEFINE_FLAG_0(name##1)
+#define DEFINE_FLAG_2(name) DEFINE_FLAG_1(name##0) DEFINE_FLAG_1(name##1)
+#define DEFINE_FLAG_3(name) DEFINE_FLAG_2(name##0) DEFINE_FLAG_2(name##1)
+#define DEFINE_FLAG_4(name) DEFINE_FLAG_3(name##0) DEFINE_FLAG_3(name##1)
+#define DEFINE_FLAG_5(name) DEFINE_FLAG_4(name##0) DEFINE_FLAG_4(name##1)
+#define DEFINE_FLAG_6(name) DEFINE_FLAG_5(name##0) DEFINE_FLAG_5(name##1)
+#define DEFINE_FLAG_7(name) DEFINE_FLAG_6(name##0) DEFINE_FLAG_6(name##1)
+#define DEFINE_FLAG_8(name) DEFINE_FLAG_7(name##0) DEFINE_FLAG_7(name##1)
+#define DEFINE_FLAG_9(name) DEFINE_FLAG_8(name##0) DEFINE_FLAG_8(name##1)
+#define DEFINE_FLAG_10(name) DEFINE_FLAG_9(name##0) DEFINE_FLAG_9(name##1)
+#define DEFINE_FLAG_11(name) DEFINE_FLAG_10(name##0) DEFINE_FLAG_10(name##1)
+#define DEFINE_FLAG_12(name) DEFINE_FLAG_11(name##0) DEFINE_FLAG_11(name##1)
+DEFINE_FLAG_12(bloat_flag_);
+
+namespace {
+
+#define BM_GetFlag(T) \
+ void BM_GetFlag_##T(benchmark::State& state) { \
+ for (auto _ : state) { \
+ benchmark::DoNotOptimize(absl::GetFlag(FLAGS_##T##_flag)); \
+ } \
+ } \
+ BENCHMARK(BM_GetFlag_##T)->ThreadRange(1, 16);
+
+BENCHMARKED_TYPES(BM_GetFlag)
+
+void BM_ThreadedFindCommandLineFlag(benchmark::State& state) {
+ char dummy[] = "dummy";
+ char* argv[] = {dummy};
+ // We need to ensure that flags have been parsed. That is where the registry
+ // is finalized.
+ absl::ParseCommandLine(1, argv);
+
+ for (auto s : state) {
+ benchmark::DoNotOptimize(
+ absl::FindCommandLineFlag("bloat_flag_010101010101"));
+ }
+}
+BENCHMARK(BM_ThreadedFindCommandLineFlag)->ThreadRange(1, 16);
+
+} // namespace
+
+#define InvokeGetFlag(T) \
+ T AbslInvokeGetFlag##T() { return absl::GetFlag(FLAGS_##T##_flag); } \
+ int odr##T = (benchmark::DoNotOptimize(AbslInvokeGetFlag##T), 1);
+
+BENCHMARKED_TYPES(InvokeGetFlag)
+
+// To veiw disassembly use: gdb ${BINARY} -batch -ex "disassemble /s $FUNC"
diff --git a/third_party/abseil/absl/flags/flag_benchmark.lds b/third_party/abseil/absl/flags/flag_benchmark.lds
new file mode 100644
index 0000000..af115df
--- /dev/null
+++ b/third_party/abseil/absl/flags/flag_benchmark.lds
@@ -0,0 +1,13 @@
+/* This linker script forces the flags used by flags_benchmark
+ * into a separate page-aligned section. This isn't necessary for
+ * correctness but ensures that the benchmark results are more
+ * reproducible across unrelated code changes.
+ */
+SECTIONS {
+ .benchmark_flags : {
+ . = ALIGN(0x1000);
+ * (.benchmark_flags);
+ }
+}
+
+INSERT AFTER .data
diff --git a/third_party/abseil/absl/flags/flag_test.cc b/third_party/abseil/absl/flags/flag_test.cc
index a652042..72507b9 100644
--- a/third_party/abseil/absl/flags/flag_test.cc
+++ b/third_party/abseil/absl/flags/flag_test.cc
@@ -15,15 +15,31 @@
#include "absl/flags/flag.h"
-#include <algorithm>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <atomic>
+#include <cmath>
+#include <new>
#include <string>
+#include <thread> // NOLINT
+#include <vector>
#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+#include "absl/base/macros.h"
+#include "absl/flags/config.h"
+#include "absl/flags/declare.h"
+#include "absl/flags/internal/flag.h"
+#include "absl/flags/marshalling.h"
+#include "absl/flags/reflection.h"
#include "absl/flags/usage_config.h"
#include "absl/strings/match.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_split.h"
+#include "absl/strings/string_view.h"
+#include "absl/time/time.h"
ABSL_DECLARE_FLAG(int64_t, mistyped_int_flag);
ABSL_DECLARE_FLAG(std::vector<std::string>, mistyped_string_flag);
@@ -32,34 +48,16 @@
namespace flags = absl::flags_internal;
-std::string TestHelpMsg() { return "help"; }
+std::string TestHelpMsg() { return "dynamic help"; }
+#if defined(_MSC_VER) && !defined(__clang__)
+std::string TestLiteralHelpMsg() { return "literal help"; }
+#endif
template <typename T>
-void* TestMakeDflt() {
- return new T{};
+void TestMakeDflt(void* dst) {
+ new (dst) T{};
}
void TestCallback() {}
-template <typename T>
-bool TestConstructionFor() {
- constexpr flags::Flag<T> f1("f1", &TestHelpMsg, "file",
- &absl::flags_internal::FlagMarshallingOps<T>,
- &TestMakeDflt<T>);
- EXPECT_EQ(f1.Name(), "f1");
- EXPECT_EQ(f1.Help(), "help");
- EXPECT_EQ(f1.Filename(), "file");
-
- ABSL_CONST_INIT static flags::Flag<T> f2(
- "f2", &TestHelpMsg, "file", &absl::flags_internal::FlagMarshallingOps<T>,
- &TestMakeDflt<T>);
- flags::FlagRegistrar<T, false>(&f2).OnUpdate(TestCallback);
-
- EXPECT_EQ(f2.Name(), "f2");
- EXPECT_EQ(f2.Help(), "help");
- EXPECT_EQ(f2.Filename(), "file");
-
- return true;
-}
-
struct UDT {
UDT() = default;
UDT(const UDT&) = default;
@@ -85,21 +83,124 @@
#endif
return std::string(fname);
}
+ absl::FlagSaver flag_saver_;
};
-TEST_F(FlagTest, TestConstruction) {
- TestConstructionFor<bool>();
- TestConstructionFor<int16_t>();
- TestConstructionFor<uint16_t>();
- TestConstructionFor<int32_t>();
- TestConstructionFor<uint32_t>();
- TestConstructionFor<int64_t>();
- TestConstructionFor<uint64_t>();
- TestConstructionFor<double>();
- TestConstructionFor<float>();
- TestConstructionFor<std::string>();
+struct S1 {
+ S1() = default;
+ S1(const S1&) = default;
+ int32_t f1;
+ int64_t f2;
+};
- TestConstructionFor<UDT>();
+struct S2 {
+ S2() = default;
+ S2(const S2&) = default;
+ int64_t f1;
+ double f2;
+};
+
+TEST_F(FlagTest, Traits) {
+ EXPECT_EQ(flags::StorageKind<int>(),
+ flags::FlagValueStorageKind::kOneWordAtomic);
+ EXPECT_EQ(flags::StorageKind<bool>(),
+ flags::FlagValueStorageKind::kOneWordAtomic);
+ EXPECT_EQ(flags::StorageKind<double>(),
+ flags::FlagValueStorageKind::kOneWordAtomic);
+ EXPECT_EQ(flags::StorageKind<int64_t>(),
+ flags::FlagValueStorageKind::kOneWordAtomic);
+
+ EXPECT_EQ(flags::StorageKind<S1>(),
+ flags::FlagValueStorageKind::kSequenceLocked);
+ EXPECT_EQ(flags::StorageKind<S2>(),
+ flags::FlagValueStorageKind::kSequenceLocked);
+// Make sure absl::Duration uses the sequence-locked code path. MSVC 2015
+// doesn't consider absl::Duration to be trivially-copyable so we just
+// restrict this to clang as it seems to be a well-behaved compiler.
+#ifdef __clang__
+ EXPECT_EQ(flags::StorageKind<absl::Duration>(),
+ flags::FlagValueStorageKind::kSequenceLocked);
+#endif
+
+ EXPECT_EQ(flags::StorageKind<std::string>(),
+ flags::FlagValueStorageKind::kAlignedBuffer);
+ EXPECT_EQ(flags::StorageKind<std::vector<std::string>>(),
+ flags::FlagValueStorageKind::kAlignedBuffer);
+}
+
+// --------------------------------------------------------------------
+
+constexpr flags::FlagHelpArg help_arg{flags::FlagHelpMsg("literal help"),
+ flags::FlagHelpKind::kLiteral};
+
+using String = std::string;
+
+#if !defined(_MSC_VER) || defined(__clang__)
+#define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind) \
+ constexpr flags::FlagDefaultArg f1default##T{ \
+ flags::FlagDefaultSrc{dflt}, flags::FlagDefaultKind::dflt_kind}; \
+ constexpr absl::Flag<T> f1##T{"f1", "file", help_arg, f1default##T}; \
+ ABSL_CONST_INIT absl::Flag<T> f2##T { \
+ "f2", "file", \
+ {flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc}, \
+ flags::FlagDefaultArg { \
+ flags::FlagDefaultSrc(&TestMakeDflt<T>), \
+ flags::FlagDefaultKind::kGenFunc \
+ } \
+ }
+#else
+#define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind) \
+ constexpr flags::FlagDefaultArg f1default##T{ \
+ flags::FlagDefaultSrc{dflt}, flags::FlagDefaultKind::dflt_kind}; \
+ constexpr absl::Flag<T> f1##T{"f1", "file", &TestLiteralHelpMsg, \
+ &TestMakeDflt<T>}; \
+ ABSL_CONST_INIT absl::Flag<T> f2##T { \
+ "f2", "file", &TestHelpMsg, &TestMakeDflt<T> \
+ }
+#endif
+
+DEFINE_CONSTRUCTED_FLAG(bool, true, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(int16_t, 1, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(uint16_t, 2, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(int32_t, 3, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(uint32_t, 4, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(int64_t, 5, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(uint64_t, 6, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(float, 7.8, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(double, 9.10, kOneWord);
+DEFINE_CONSTRUCTED_FLAG(String, &TestMakeDflt<String>, kGenFunc);
+DEFINE_CONSTRUCTED_FLAG(UDT, &TestMakeDflt<UDT>, kGenFunc);
+
+template <typename T>
+bool TestConstructionFor(const absl::Flag<T>& f1, absl::Flag<T>& f2) {
+ EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Name(), "f1");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Help(), "literal help");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Filename(), "file");
+
+ flags::FlagRegistrar<T, false>(ABSL_FLAG_IMPL_FLAG_PTR(f2))
+ .OnUpdate(TestCallback);
+
+ EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Name(), "f2");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Help(), "dynamic help");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Filename(), "file");
+
+ return true;
+}
+
+#define TEST_CONSTRUCTED_FLAG(T) TestConstructionFor(f1##T, f2##T);
+
+TEST_F(FlagTest, TestConstruction) {
+ TEST_CONSTRUCTED_FLAG(bool);
+ TEST_CONSTRUCTED_FLAG(int16_t);
+ TEST_CONSTRUCTED_FLAG(uint16_t);
+ TEST_CONSTRUCTED_FLAG(int32_t);
+ TEST_CONSTRUCTED_FLAG(uint32_t);
+ TEST_CONSTRUCTED_FLAG(int64_t);
+ TEST_CONSTRUCTED_FLAG(uint64_t);
+ TEST_CONSTRUCTED_FLAG(float);
+ TEST_CONSTRUCTED_FLAG(double);
+ TEST_CONSTRUCTED_FLAG(String);
+ TEST_CONSTRUCTED_FLAG(UDT);
}
// --------------------------------------------------------------------
@@ -117,6 +218,7 @@
ABSL_DECLARE_FLAG(double, test_flag_09);
ABSL_DECLARE_FLAG(float, test_flag_10);
ABSL_DECLARE_FLAG(std::string, test_flag_11);
+ABSL_DECLARE_FLAG(absl::Duration, test_flag_12);
namespace {
@@ -124,17 +226,30 @@
TEST_F(FlagTest, TestFlagDeclaration) {
// test that we can access flag objects.
- EXPECT_EQ(FLAGS_test_flag_01.Name(), "test_flag_01");
- EXPECT_EQ(FLAGS_test_flag_02.Name(), "test_flag_02");
- EXPECT_EQ(FLAGS_test_flag_03.Name(), "test_flag_03");
- EXPECT_EQ(FLAGS_test_flag_04.Name(), "test_flag_04");
- EXPECT_EQ(FLAGS_test_flag_05.Name(), "test_flag_05");
- EXPECT_EQ(FLAGS_test_flag_06.Name(), "test_flag_06");
- EXPECT_EQ(FLAGS_test_flag_07.Name(), "test_flag_07");
- EXPECT_EQ(FLAGS_test_flag_08.Name(), "test_flag_08");
- EXPECT_EQ(FLAGS_test_flag_09.Name(), "test_flag_09");
- EXPECT_EQ(FLAGS_test_flag_10.Name(), "test_flag_10");
- EXPECT_EQ(FLAGS_test_flag_11.Name(), "test_flag_11");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Name(),
+ "test_flag_01");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Name(),
+ "test_flag_02");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Name(),
+ "test_flag_03");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Name(),
+ "test_flag_04");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Name(),
+ "test_flag_05");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Name(),
+ "test_flag_06");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Name(),
+ "test_flag_07");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Name(),
+ "test_flag_08");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Name(),
+ "test_flag_09");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Name(),
+ "test_flag_10");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Name(),
+ "test_flag_11");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Name(),
+ "test_flag_12");
}
#endif // !ABSL_FLAGS_STRIP_NAMES
@@ -153,6 +268,7 @@
ABSL_FLAG(double, test_flag_09, -9.876e-50, "test flag 09");
ABSL_FLAG(float, test_flag_10, 1.234e12f, "test flag 10");
ABSL_FLAG(std::string, test_flag_11, "", "test flag 11");
+ABSL_FLAG(absl::Duration, test_flag_12, absl::Minutes(10), "test flag 12");
namespace {
@@ -160,66 +276,169 @@
TEST_F(FlagTest, TestFlagDefinition) {
absl::string_view expected_file_name = "absl/flags/flag_test.cc";
- EXPECT_EQ(FLAGS_test_flag_01.Name(), "test_flag_01");
- EXPECT_EQ(FLAGS_test_flag_01.Help(), "test flag 01");
- EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_01.Filename(), expected_file_name))
- << FLAGS_test_flag_01.Filename();
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Name(),
+ "test_flag_01");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Help(),
+ "test flag 01");
+ EXPECT_TRUE(absl::EndsWith(
+ absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Filename(),
+ expected_file_name))
+ << absl::GetFlagReflectionHandle(FLAGS_test_flag_01).Filename();
- EXPECT_EQ(FLAGS_test_flag_02.Name(), "test_flag_02");
- EXPECT_EQ(FLAGS_test_flag_02.Help(), "test flag 02");
- EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_02.Filename(), expected_file_name))
- << FLAGS_test_flag_02.Filename();
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Name(),
+ "test_flag_02");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Help(),
+ "test flag 02");
+ EXPECT_TRUE(absl::EndsWith(
+ absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Filename(),
+ expected_file_name))
+ << absl::GetFlagReflectionHandle(FLAGS_test_flag_02).Filename();
- EXPECT_EQ(FLAGS_test_flag_03.Name(), "test_flag_03");
- EXPECT_EQ(FLAGS_test_flag_03.Help(), "test flag 03");
- EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_03.Filename(), expected_file_name))
- << FLAGS_test_flag_03.Filename();
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Name(),
+ "test_flag_03");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Help(),
+ "test flag 03");
+ EXPECT_TRUE(absl::EndsWith(
+ absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Filename(),
+ expected_file_name))
+ << absl::GetFlagReflectionHandle(FLAGS_test_flag_03).Filename();
- EXPECT_EQ(FLAGS_test_flag_04.Name(), "test_flag_04");
- EXPECT_EQ(FLAGS_test_flag_04.Help(), "test flag 04");
- EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_04.Filename(), expected_file_name))
- << FLAGS_test_flag_04.Filename();
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Name(),
+ "test_flag_04");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Help(),
+ "test flag 04");
+ EXPECT_TRUE(absl::EndsWith(
+ absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Filename(),
+ expected_file_name))
+ << absl::GetFlagReflectionHandle(FLAGS_test_flag_04).Filename();
- EXPECT_EQ(FLAGS_test_flag_05.Name(), "test_flag_05");
- EXPECT_EQ(FLAGS_test_flag_05.Help(), "test flag 05");
- EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_05.Filename(), expected_file_name))
- << FLAGS_test_flag_05.Filename();
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Name(),
+ "test_flag_05");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Help(),
+ "test flag 05");
+ EXPECT_TRUE(absl::EndsWith(
+ absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Filename(),
+ expected_file_name))
+ << absl::GetFlagReflectionHandle(FLAGS_test_flag_05).Filename();
- EXPECT_EQ(FLAGS_test_flag_06.Name(), "test_flag_06");
- EXPECT_EQ(FLAGS_test_flag_06.Help(), "test flag 06");
- EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_06.Filename(), expected_file_name))
- << FLAGS_test_flag_06.Filename();
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Name(),
+ "test_flag_06");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Help(),
+ "test flag 06");
+ EXPECT_TRUE(absl::EndsWith(
+ absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Filename(),
+ expected_file_name))
+ << absl::GetFlagReflectionHandle(FLAGS_test_flag_06).Filename();
- EXPECT_EQ(FLAGS_test_flag_07.Name(), "test_flag_07");
- EXPECT_EQ(FLAGS_test_flag_07.Help(), "test flag 07");
- EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_07.Filename(), expected_file_name))
- << FLAGS_test_flag_07.Filename();
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Name(),
+ "test_flag_07");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Help(),
+ "test flag 07");
+ EXPECT_TRUE(absl::EndsWith(
+ absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Filename(),
+ expected_file_name))
+ << absl::GetFlagReflectionHandle(FLAGS_test_flag_07).Filename();
- EXPECT_EQ(FLAGS_test_flag_08.Name(), "test_flag_08");
- EXPECT_EQ(FLAGS_test_flag_08.Help(), "test flag 08");
- EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_08.Filename(), expected_file_name))
- << FLAGS_test_flag_08.Filename();
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Name(),
+ "test_flag_08");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Help(),
+ "test flag 08");
+ EXPECT_TRUE(absl::EndsWith(
+ absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Filename(),
+ expected_file_name))
+ << absl::GetFlagReflectionHandle(FLAGS_test_flag_08).Filename();
- EXPECT_EQ(FLAGS_test_flag_09.Name(), "test_flag_09");
- EXPECT_EQ(FLAGS_test_flag_09.Help(), "test flag 09");
- EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_09.Filename(), expected_file_name))
- << FLAGS_test_flag_09.Filename();
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Name(),
+ "test_flag_09");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Help(),
+ "test flag 09");
+ EXPECT_TRUE(absl::EndsWith(
+ absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Filename(),
+ expected_file_name))
+ << absl::GetFlagReflectionHandle(FLAGS_test_flag_09).Filename();
- EXPECT_EQ(FLAGS_test_flag_10.Name(), "test_flag_10");
- EXPECT_EQ(FLAGS_test_flag_10.Help(), "test flag 10");
- EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_10.Filename(), expected_file_name))
- << FLAGS_test_flag_10.Filename();
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Name(),
+ "test_flag_10");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Help(),
+ "test flag 10");
+ EXPECT_TRUE(absl::EndsWith(
+ absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Filename(),
+ expected_file_name))
+ << absl::GetFlagReflectionHandle(FLAGS_test_flag_10).Filename();
- EXPECT_EQ(FLAGS_test_flag_11.Name(), "test_flag_11");
- EXPECT_EQ(FLAGS_test_flag_11.Help(), "test flag 11");
- EXPECT_TRUE(absl::EndsWith(FLAGS_test_flag_11.Filename(), expected_file_name))
- << FLAGS_test_flag_11.Filename();
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Name(),
+ "test_flag_11");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Help(),
+ "test flag 11");
+ EXPECT_TRUE(absl::EndsWith(
+ absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Filename(),
+ expected_file_name))
+ << absl::GetFlagReflectionHandle(FLAGS_test_flag_11).Filename();
+
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Name(),
+ "test_flag_12");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Help(),
+ "test flag 12");
+ EXPECT_TRUE(absl::EndsWith(
+ absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Filename(),
+ expected_file_name))
+ << absl::GetFlagReflectionHandle(FLAGS_test_flag_12).Filename();
}
#endif // !ABSL_FLAGS_STRIP_NAMES
// --------------------------------------------------------------------
TEST_F(FlagTest, TestDefault) {
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).DefaultValue(),
+ "true");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).DefaultValue(),
+ "1234");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).DefaultValue(),
+ "-34");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).DefaultValue(),
+ "189");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).DefaultValue(),
+ "10765");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).DefaultValue(),
+ "40000");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).DefaultValue(),
+ "-1234567");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).DefaultValue(),
+ "9876543");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).DefaultValue(),
+ "-9.876e-50");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).DefaultValue(),
+ "1.234e+12");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).DefaultValue(),
+ "");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).DefaultValue(),
+ "10m");
+
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_01).CurrentValue(),
+ "true");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_02).CurrentValue(),
+ "1234");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_03).CurrentValue(),
+ "-34");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_04).CurrentValue(),
+ "189");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_05).CurrentValue(),
+ "10765");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_06).CurrentValue(),
+ "40000");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_07).CurrentValue(),
+ "-1234567");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_08).CurrentValue(),
+ "9876543");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_09).CurrentValue(),
+ "-9.876e-50");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_10).CurrentValue(),
+ "1.234e+12");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_11).CurrentValue(),
+ "");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_12).CurrentValue(),
+ "10m");
+
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), true);
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234);
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_03), -34);
@@ -231,6 +450,68 @@
EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_09), -9.876e-50, 1e-55);
EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), 1.234e12f, 1e5f);
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "");
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Minutes(10));
+}
+
+// --------------------------------------------------------------------
+
+struct NonTriviallyCopyableAggregate {
+ NonTriviallyCopyableAggregate() = default;
+ NonTriviallyCopyableAggregate(const NonTriviallyCopyableAggregate& rhs)
+ : value(rhs.value) {}
+ NonTriviallyCopyableAggregate& operator=(
+ const NonTriviallyCopyableAggregate& rhs) {
+ value = rhs.value;
+ return *this;
+ }
+
+ int value;
+};
+bool AbslParseFlag(absl::string_view src, NonTriviallyCopyableAggregate* f,
+ std::string* e) {
+ return absl::ParseFlag(src, &f->value, e);
+}
+std::string AbslUnparseFlag(const NonTriviallyCopyableAggregate& ntc) {
+ return absl::StrCat(ntc.value);
+}
+
+bool operator==(const NonTriviallyCopyableAggregate& ntc1,
+ const NonTriviallyCopyableAggregate& ntc2) {
+ return ntc1.value == ntc2.value;
+}
+
+} // namespace
+
+ABSL_FLAG(bool, test_flag_eb_01, {}, "");
+ABSL_FLAG(int32_t, test_flag_eb_02, {}, "");
+ABSL_FLAG(int64_t, test_flag_eb_03, {}, "");
+ABSL_FLAG(double, test_flag_eb_04, {}, "");
+ABSL_FLAG(std::string, test_flag_eb_05, {}, "");
+ABSL_FLAG(NonTriviallyCopyableAggregate, test_flag_eb_06, {}, "");
+
+namespace {
+
+TEST_F(FlagTest, TestEmptyBracesDefault) {
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_01).DefaultValue(),
+ "false");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_02).DefaultValue(),
+ "0");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_03).DefaultValue(),
+ "0");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_04).DefaultValue(),
+ "0");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_05).DefaultValue(),
+ "");
+ EXPECT_EQ(absl::GetFlagReflectionHandle(FLAGS_test_flag_eb_06).DefaultValue(),
+ "0");
+
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_01), false);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_02), 0);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_03), 0);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_04), 0.0);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_05), "");
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_eb_06),
+ NonTriviallyCopyableAggregate{});
}
// --------------------------------------------------------------------
@@ -268,6 +549,75 @@
absl::SetFlag(&FLAGS_test_flag_11, "asdf");
EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "asdf");
+
+ absl::SetFlag(&FLAGS_test_flag_12, absl::Seconds(110));
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Seconds(110));
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(FlagTest, TestGetViaReflection) {
+ auto* handle = absl::FindCommandLineFlag("test_flag_01");
+ EXPECT_EQ(*handle->TryGet<bool>(), true);
+ handle = absl::FindCommandLineFlag("test_flag_02");
+ EXPECT_EQ(*handle->TryGet<int>(), 1234);
+ handle = absl::FindCommandLineFlag("test_flag_03");
+ EXPECT_EQ(*handle->TryGet<int16_t>(), -34);
+ handle = absl::FindCommandLineFlag("test_flag_04");
+ EXPECT_EQ(*handle->TryGet<uint16_t>(), 189);
+ handle = absl::FindCommandLineFlag("test_flag_05");
+ EXPECT_EQ(*handle->TryGet<int32_t>(), 10765);
+ handle = absl::FindCommandLineFlag("test_flag_06");
+ EXPECT_EQ(*handle->TryGet<uint32_t>(), 40000);
+ handle = absl::FindCommandLineFlag("test_flag_07");
+ EXPECT_EQ(*handle->TryGet<int64_t>(), -1234567);
+ handle = absl::FindCommandLineFlag("test_flag_08");
+ EXPECT_EQ(*handle->TryGet<uint64_t>(), 9876543);
+ handle = absl::FindCommandLineFlag("test_flag_09");
+ EXPECT_NEAR(*handle->TryGet<double>(), -9.876e-50, 1e-55);
+ handle = absl::FindCommandLineFlag("test_flag_10");
+ EXPECT_NEAR(*handle->TryGet<float>(), 1.234e12f, 1e5f);
+ handle = absl::FindCommandLineFlag("test_flag_11");
+ EXPECT_EQ(*handle->TryGet<std::string>(), "");
+ handle = absl::FindCommandLineFlag("test_flag_12");
+ EXPECT_EQ(*handle->TryGet<absl::Duration>(), absl::Minutes(10));
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(FlagTest, ConcurrentSetAndGet) {
+ static constexpr int kNumThreads = 8;
+ // Two arbitrary durations. One thread will concurrently flip the flag
+ // between these two values, while the other threads read it and verify
+ // that no other value is seen.
+ static const absl::Duration kValidDurations[] = {
+ absl::Seconds(int64_t{0x6cebf47a9b68c802}) + absl::Nanoseconds(229702057),
+ absl::Seconds(int64_t{0x23fec0307e4e9d3}) + absl::Nanoseconds(44555374)};
+ absl::SetFlag(&FLAGS_test_flag_12, kValidDurations[0]);
+
+ std::atomic<bool> stop{false};
+ std::vector<std::thread> threads;
+ auto* handle = absl::FindCommandLineFlag("test_flag_12");
+ for (int i = 0; i < kNumThreads; i++) {
+ threads.emplace_back([&]() {
+ while (!stop.load(std::memory_order_relaxed)) {
+ // Try loading the flag both directly and via a reflection
+ // handle.
+ absl::Duration v = absl::GetFlag(FLAGS_test_flag_12);
+ EXPECT_TRUE(v == kValidDurations[0] || v == kValidDurations[1]);
+ v = *handle->TryGet<absl::Duration>();
+ EXPECT_TRUE(v == kValidDurations[0] || v == kValidDurations[1]);
+ }
+ });
+ }
+ absl::Time end_time = absl::Now() + absl::Seconds(1);
+ int i = 0;
+ while (absl::Now() < end_time) {
+ absl::SetFlag(&FLAGS_test_flag_12,
+ kValidDurations[i++ % ABSL_ARRAYSIZE(kValidDurations)]);
+ }
+ stop.store(true, std::memory_order_relaxed);
+ for (auto& t : threads) t.join();
}
// --------------------------------------------------------------------
@@ -276,28 +626,33 @@
} // namespace
-ABSL_FLAG(int, test_flag_12, GetDflt1(), "test flag 12");
-ABSL_FLAG(std::string, test_flag_13, absl::StrCat("AAA", "BBB"),
- "test flag 13");
+ABSL_FLAG(int, test_int_flag_with_non_const_default, GetDflt1(),
+ "test int flag non const default");
+ABSL_FLAG(std::string, test_string_flag_with_non_const_default,
+ absl::StrCat("AAA", "BBB"), "test string flag non const default");
namespace {
TEST_F(FlagTest, TestNonConstexprDefault) {
- EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), 1);
- EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), "AAABBB");
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_int_flag_with_non_const_default), 1);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_string_flag_with_non_const_default),
+ "AAABBB");
}
// --------------------------------------------------------------------
} // namespace
-ABSL_FLAG(bool, test_flag_14, true, absl::StrCat("test ", "flag ", "14"));
+ABSL_FLAG(bool, test_flag_with_non_const_help, true,
+ absl::StrCat("test ", "flag ", "non const help"));
namespace {
#if !ABSL_FLAGS_STRIP_HELP
TEST_F(FlagTest, TestNonConstexprHelp) {
- EXPECT_EQ(FLAGS_test_flag_14.Help(), "test flag 14");
+ EXPECT_EQ(
+ absl::GetFlagReflectionHandle(FLAGS_test_flag_with_non_const_help).Help(),
+ "test flag non const help");
}
#endif //! ABSL_FLAGS_STRIP_HELP
@@ -363,34 +718,39 @@
} // namespace
-ABSL_FLAG(CustomUDT, test_flag_15, CustomUDT(), "test flag 15");
+ABSL_FLAG(CustomUDT, test_flag_custom_udt, CustomUDT(), "test flag custom UDT");
namespace {
TEST_F(FlagTest, TestCustomUDT) {
- EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_15), CustomUDT(1, 1));
- absl::SetFlag(&FLAGS_test_flag_15, CustomUDT(2, 3));
- EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_15), CustomUDT(2, 3));
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_custom_udt), CustomUDT(1, 1));
+ absl::SetFlag(&FLAGS_test_flag_custom_udt, CustomUDT(2, 3));
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_custom_udt), CustomUDT(2, 3));
}
// MSVC produces link error on the type mismatch.
// Linux does not have build errors and validations work as expected.
-#if 0 // !defined(_WIN32) && GTEST_HAS_DEATH_TEST
+#if !defined(_WIN32) && GTEST_HAS_DEATH_TEST
-TEST(Flagtest, TestTypeMismatchValidations) {
- // For builtin types, GetFlag() only does validation in debug mode.
- EXPECT_DEBUG_DEATH(
- absl::GetFlag(FLAGS_mistyped_int_flag),
+using FlagDeathTest = FlagTest;
+
+TEST_F(FlagDeathTest, TestTypeMismatchValidations) {
+#if !defined(NDEBUG)
+ EXPECT_DEATH_IF_SUPPORTED(
+ static_cast<void>(absl::GetFlag(FLAGS_mistyped_int_flag)),
"Flag 'mistyped_int_flag' is defined as one type and declared "
"as another");
- EXPECT_DEATH(absl::SetFlag(&FLAGS_mistyped_int_flag, 0),
- "Flag 'mistyped_int_flag' is defined as one type and declared "
- "as another");
+ EXPECT_DEATH_IF_SUPPORTED(
+ static_cast<void>(absl::GetFlag(FLAGS_mistyped_string_flag)),
+ "Flag 'mistyped_string_flag' is defined as one type and "
+ "declared as another");
+#endif
- EXPECT_DEATH(absl::GetFlag(FLAGS_mistyped_string_flag),
- "Flag 'mistyped_string_flag' is defined as one type and "
- "declared as another");
- EXPECT_DEATH(
+ EXPECT_DEATH_IF_SUPPORTED(
+ absl::SetFlag(&FLAGS_mistyped_int_flag, 1),
+ "Flag 'mistyped_int_flag' is defined as one type and declared "
+ "as another");
+ EXPECT_DEATH_IF_SUPPORTED(
absl::SetFlag(&FLAGS_mistyped_string_flag, std::vector<std::string>{}),
"Flag 'mistyped_string_flag' is defined as one type and declared as "
"another");
@@ -428,16 +788,17 @@
// Flag default values can be specified with a value that converts to the flag
// value type implicitly.
-ABSL_FLAG(ConversionTestVal, test_flag_16,
- ConversionTestVal::ViaImplicitConv::kTen, "test flag 16");
+ABSL_FLAG(ConversionTestVal, test_flag_implicit_conv,
+ ConversionTestVal::ViaImplicitConv::kTen,
+ "test flag init via implicit conversion");
namespace {
TEST_F(FlagTest, CanSetViaImplicitConversion) {
- EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_16).a, 10);
- absl::SetFlag(&FLAGS_test_flag_16,
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_implicit_conv).a, 10);
+ absl::SetFlag(&FLAGS_test_flag_implicit_conv,
ConversionTestVal::ViaImplicitConv::kEleven);
- EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_16).a, 11);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_implicit_conv).a, 11);
}
// --------------------------------------------------------------------
@@ -482,25 +843,103 @@
EXPECT_EQ(absl::GetFlag(FLAGS_ndc_flag2).value, 25);
}
-// --------------------------------------------------------------------
-
} // namespace
+// --------------------------------------------------------------------
+
ABSL_RETIRED_FLAG(bool, old_bool_flag, true, "old descr");
ABSL_RETIRED_FLAG(int, old_int_flag, (int)std::sqrt(10), "old descr");
ABSL_RETIRED_FLAG(std::string, old_str_flag, "", absl::StrCat("old ", "descr"));
+bool initializaion_order_fiasco_test = [] {
+ // Iterate over all the flags during static initialization.
+ // This should not trigger ASan's initialization-order-fiasco.
+ auto* handle1 = absl::FindCommandLineFlag("flag_on_separate_file");
+ auto* handle2 = absl::FindCommandLineFlag("retired_flag_on_separate_file");
+ if (handle1 != nullptr && handle2 != nullptr) {
+ return handle1->Name() == handle2->Name();
+ }
+ return true;
+}();
+
namespace {
TEST_F(FlagTest, TestRetiredFlagRegistration) {
- bool is_bool = false;
- EXPECT_TRUE(flags::IsRetiredFlag("old_bool_flag", &is_bool));
- EXPECT_TRUE(is_bool);
- EXPECT_TRUE(flags::IsRetiredFlag("old_int_flag", &is_bool));
- EXPECT_FALSE(is_bool);
- EXPECT_TRUE(flags::IsRetiredFlag("old_str_flag", &is_bool));
- EXPECT_FALSE(is_bool);
- EXPECT_FALSE(flags::IsRetiredFlag("some_other_flag", &is_bool));
+ auto* handle = absl::FindCommandLineFlag("old_bool_flag");
+ EXPECT_TRUE(handle->IsOfType<bool>());
+ EXPECT_TRUE(handle->IsRetired());
+ handle = absl::FindCommandLineFlag("old_int_flag");
+ EXPECT_TRUE(handle->IsOfType<int>());
+ EXPECT_TRUE(handle->IsRetired());
+ handle = absl::FindCommandLineFlag("old_str_flag");
+ EXPECT_TRUE(handle->IsOfType<std::string>());
+ EXPECT_TRUE(handle->IsRetired());
+}
+
+} // namespace
+
+// --------------------------------------------------------------------
+
+namespace {
+
+// User-defined type with small alignment, but size exceeding 16.
+struct SmallAlignUDT {
+ SmallAlignUDT() : c('A'), s(12) {}
+ char c;
+ int16_t s;
+ char bytes[14];
+};
+
+bool AbslParseFlag(absl::string_view, SmallAlignUDT*, std::string*) {
+ return true;
+}
+std::string AbslUnparseFlag(const SmallAlignUDT&) { return ""; }
+
+// User-defined type with small size, but not trivially copyable.
+struct NonTriviallyCopyableUDT {
+ NonTriviallyCopyableUDT() : c('A') {}
+ NonTriviallyCopyableUDT(const NonTriviallyCopyableUDT& rhs) : c(rhs.c) {}
+ NonTriviallyCopyableUDT& operator=(const NonTriviallyCopyableUDT& rhs) {
+ c = rhs.c;
+ return *this;
+ }
+
+ char c;
+};
+
+bool AbslParseFlag(absl::string_view, NonTriviallyCopyableUDT*, std::string*) {
+ return true;
+}
+std::string AbslUnparseFlag(const NonTriviallyCopyableUDT&) { return ""; }
+
+} // namespace
+
+ABSL_FLAG(SmallAlignUDT, test_flag_sa_udt, {}, "help");
+ABSL_FLAG(NonTriviallyCopyableUDT, test_flag_ntc_udt, {}, "help");
+
+namespace {
+
+TEST_F(FlagTest, TestSmallAlignUDT) {
+ SmallAlignUDT value = absl::GetFlag(FLAGS_test_flag_sa_udt);
+ EXPECT_EQ(value.c, 'A');
+ EXPECT_EQ(value.s, 12);
+
+ value.c = 'B';
+ value.s = 45;
+ absl::SetFlag(&FLAGS_test_flag_sa_udt, value);
+ value = absl::GetFlag(FLAGS_test_flag_sa_udt);
+ EXPECT_EQ(value.c, 'B');
+ EXPECT_EQ(value.s, 45);
+}
+
+TEST_F(FlagTest, TestNonTriviallyCopyableUDT) {
+ NonTriviallyCopyableUDT value = absl::GetFlag(FLAGS_test_flag_ntc_udt);
+ EXPECT_EQ(value.c, 'A');
+
+ value.c = 'B';
+ absl::SetFlag(&FLAGS_test_flag_ntc_udt, value);
+ value = absl::GetFlag(FLAGS_test_flag_ntc_udt);
+ EXPECT_EQ(value.c, 'B');
}
} // namespace
diff --git a/third_party/abseil/absl/flags/flag_test_defs.cc b/third_party/abseil/absl/flags/flag_test_defs.cc
index 3366c58..4e1693c 100644
--- a/third_party/abseil/absl/flags/flag_test_defs.cc
+++ b/third_party/abseil/absl/flags/flag_test_defs.cc
@@ -20,3 +20,5 @@
ABSL_FLAG(int, mistyped_int_flag, 0, "");
ABSL_FLAG(std::string, mistyped_string_flag, "", "");
+ABSL_FLAG(bool, flag_on_separate_file, false, "");
+ABSL_RETIRED_FLAG(bool, retired_flag_on_separate_file, false, "");
diff --git a/third_party/abseil/absl/flags/internal/commandlineflag.cc b/third_party/abseil/absl/flags/internal/commandlineflag.cc
index 53e2b84..4482955 100644
--- a/third_party/abseil/absl/flags/internal/commandlineflag.cc
+++ b/third_party/abseil/absl/flags/internal/commandlineflag.cc
@@ -1,5 +1,5 @@
//
-// Copyright 2019 The Abseil Authors.
+// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -15,380 +15,12 @@
#include "absl/flags/internal/commandlineflag.h"
-#include <cassert>
-
-#include "absl/base/internal/raw_logging.h"
-#include "absl/base/optimization.h"
-#include "absl/flags/config.h"
-#include "absl/flags/usage_config.h"
-#include "absl/strings/str_cat.h"
-#include "absl/synchronization/mutex.h"
-
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace flags_internal {
-// The help message indicating that the commandline flag has been
-// 'stripped'. It will not show up when doing "-help" and its
-// variants. The flag is stripped if ABSL_FLAGS_STRIP_HELP is set to 1
-// before including absl/flags/flag.h
-
-// This is used by this file, and also in commandlineflags_reporting.cc
-const char kStrippedFlagHelp[] = "\001\002\003\004 (unknown) \004\003\002\001";
-
-namespace {
-
-// Currently we only validate flag values for user-defined flag types.
-bool ShouldValidateFlagValue(const CommandLineFlag& flag) {
-#define DONT_VALIDATE(T) \
- if (flag.IsOfType<T>()) return false;
- ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(DONT_VALIDATE)
- DONT_VALIDATE(std::string)
- DONT_VALIDATE(std::vector<std::string>)
-#undef DONT_VALIDATE
-
- return true;
-}
-
-} // namespace
-
-absl::Mutex* InitFlag(CommandLineFlag* flag) {
- ABSL_CONST_INIT static absl::Mutex init_lock(absl::kConstInit);
- absl::Mutex* mu;
-
- {
- absl::MutexLock lock(&init_lock);
-
- if (flag->locks_ == nullptr) { // Must initialize Mutexes for this flag.
- flag->locks_ = new flags_internal::CommandLineFlagLocks;
- }
-
- mu = &flag->locks_->primary_mu;
- }
-
- {
- absl::MutexLock lock(mu);
-
- if (!flag->IsRetired() && flag->def_ == nullptr) {
- // Need to initialize def and cur fields.
- flag->def_ = (*flag->make_init_value_)();
- flag->cur_ = Clone(flag->op_, flag->def_);
- UpdateCopy(flag);
- flag->inited_.store(true, std::memory_order_release);
- flag->InvokeCallback();
- }
- }
-
- flag->inited_.store(true, std::memory_order_release);
- return mu;
-}
-
-// Ensure that the lazily initialized fields of *flag have been initialized,
-// and return &flag->locks_->primary_mu.
-absl::Mutex* CommandLineFlag::InitFlagIfNecessary() const
- ABSL_LOCK_RETURNED(locks_->primary_mu) {
- if (!inited_.load(std::memory_order_acquire)) {
- return InitFlag(const_cast<CommandLineFlag*>(this));
- }
-
- // All fields initialized; locks_ is therefore safe to read.
- return &locks_->primary_mu;
-}
-
-bool CommandLineFlag::IsModified() const {
- absl::MutexLock l(InitFlagIfNecessary());
- return modified_;
-}
-
-void CommandLineFlag::SetModified(bool is_modified) {
- absl::MutexLock l(InitFlagIfNecessary());
- modified_ = is_modified;
-}
-
-bool CommandLineFlag::IsSpecifiedOnCommandLine() const {
- absl::MutexLock l(InitFlagIfNecessary());
- return on_command_line_;
-}
-
-absl::string_view CommandLineFlag::Typename() const {
- // We do not store/report type in Abseil Flags, so that user do not rely on in
- // at runtime
- if (IsAbseilFlag() || IsRetired()) return "";
-
-#define HANDLE_V1_BUILTIN_TYPE(t) \
- if (IsOfType<t>()) { \
- return #t; \
- }
-
- HANDLE_V1_BUILTIN_TYPE(bool);
- HANDLE_V1_BUILTIN_TYPE(int32_t);
- HANDLE_V1_BUILTIN_TYPE(int64_t);
- HANDLE_V1_BUILTIN_TYPE(uint64_t);
- HANDLE_V1_BUILTIN_TYPE(double);
-#undef HANDLE_V1_BUILTIN_TYPE
-
- if (IsOfType<std::string>()) {
- return "string";
- }
-
- return "";
-}
-
-std::string CommandLineFlag::Filename() const {
- return flags_internal::GetUsageConfig().normalize_filename(filename_);
-}
-
-std::string CommandLineFlag::DefaultValue() const {
- absl::MutexLock l(InitFlagIfNecessary());
-
- return Unparse(marshalling_op_, def_);
-}
-
-std::string CommandLineFlag::CurrentValue() const {
- absl::MutexLock l(InitFlagIfNecessary());
-
- return Unparse(marshalling_op_, cur_);
-}
-
-// Attempts to parse supplied `value` string using parsing routine in the `flag`
-// argument. If parsing is successful, it will try to validate that the parsed
-// value is valid for the specified 'flag'. Finally this function stores the
-// parsed value in 'dst' assuming it is a pointer to the flag's value type. In
-// case if any error is encountered in either step, the error message is stored
-// in 'err'
-bool TryParseLocked(CommandLineFlag* flag, void* dst, absl::string_view value,
- std::string* err)
- ABSL_EXCLUSIVE_LOCKS_REQUIRED(flag->locks_->primary_mu) {
- void* tentative_value = Clone(flag->op_, flag->def_);
- std::string parse_err;
- if (!Parse(flag->marshalling_op_, value, tentative_value, &parse_err)) {
- auto type_name = flag->Typename();
- absl::string_view err_sep = parse_err.empty() ? "" : "; ";
- absl::string_view typename_sep = type_name.empty() ? "" : " ";
- *err = absl::StrCat("Illegal value '", value, "' specified for",
- typename_sep, type_name, " flag '", flag->Name(), "'",
- err_sep, parse_err);
- Delete(flag->op_, tentative_value);
- return false;
- }
-
- if (!flag->InvokeValidator(tentative_value)) {
- *err = absl::StrCat("Failed validation of new value '",
- Unparse(flag->marshalling_op_, tentative_value),
- "' for flag '", flag->Name(), "'");
- Delete(flag->op_, tentative_value);
- return false;
- }
-
- flag->counter_++;
- Copy(flag->op_, tentative_value, dst);
- Delete(flag->op_, tentative_value);
- return true;
-}
-
-// Sets the value of the flag based on specified string `value`. If the flag
-// was successfully set to new value, it returns true. Otherwise, sets `err`
-// to indicate the error, leaves the flag unchanged, and returns false. There
-// are three ways to set the flag's value:
-// * Update the current flag value
-// * Update the flag's default value
-// * Update the current flag value if it was never set before
-// The mode is selected based on 'set_mode' parameter.
-bool CommandLineFlag::SetFromString(absl::string_view value,
- FlagSettingMode set_mode,
- ValueSource source, std::string* err) {
- if (IsRetired()) return false;
-
- absl::MutexLock l(InitFlagIfNecessary());
-
- // Direct-access flags can be modified without going through the
- // flag API. Detect such changes and update the flag->modified_ bit.
- if (!IsAbseilFlag()) {
- if (!modified_ && ChangedDirectly(this, cur_, def_)) {
- modified_ = true;
- }
- }
-
- switch (set_mode) {
- case SET_FLAGS_VALUE: {
- // set or modify the flag's value
- if (!TryParseLocked(this, cur_, value, err)) return false;
- modified_ = true;
- UpdateCopy(this);
- InvokeCallback();
-
- if (source == kCommandLine) {
- on_command_line_ = true;
- }
- break;
- }
- case SET_FLAG_IF_DEFAULT: {
- // set the flag's value, but only if it hasn't been set by someone else
- if (!modified_) {
- if (!TryParseLocked(this, cur_, value, err)) return false;
- modified_ = true;
- UpdateCopy(this);
- InvokeCallback();
- } else {
- // TODO(rogeeff): review and fix this semantic. Currently we do not fail
- // in this case if flag is modified. This is misleading since the flag's
- // value is not updated even though we return true.
- // *err = absl::StrCat(Name(), " is already set to ",
- // CurrentValue(), "\n");
- // return false;
- return true;
- }
- break;
- }
- case SET_FLAGS_DEFAULT: {
- // modify the flag's default-value
- if (!TryParseLocked(this, def_, value, err)) return false;
-
- if (!modified_) {
- // Need to set both defvalue *and* current, in this case
- Copy(op_, def_, cur_);
- UpdateCopy(this);
- InvokeCallback();
- }
- break;
- }
- default: {
- // unknown set_mode
- assert(false);
- return false;
- }
- }
-
- return true;
-}
-
-void CommandLineFlag::CheckDefaultValueParsingRoundtrip() const {
- std::string v = DefaultValue();
-
- absl::MutexLock lock(InitFlagIfNecessary());
-
- void* dst = Clone(op_, def_);
- std::string error;
- if (!flags_internal::Parse(marshalling_op_, v, dst, &error)) {
- ABSL_INTERNAL_LOG(
- FATAL,
- absl::StrCat("Flag ", Name(), " (from ", Filename(),
- "): std::string form of default value '", v,
- "' could not be parsed; error=", error));
- }
-
- // We do not compare dst to def since parsing/unparsing may make
- // small changes, e.g., precision loss for floating point types.
- Delete(op_, dst);
-}
-
-bool CommandLineFlag::ValidateDefaultValue() const {
- absl::MutexLock lock(InitFlagIfNecessary());
- return InvokeValidator(def_);
-}
-
-bool CommandLineFlag::ValidateInputValue(absl::string_view value) const {
- absl::MutexLock l(InitFlagIfNecessary()); // protect default value access
-
- void* obj = Clone(op_, def_);
- std::string ignored_error;
- const bool result =
- flags_internal::Parse(marshalling_op_, value, obj, &ignored_error) &&
- InvokeValidator(obj);
- Delete(op_, obj);
- return result;
-}
-
-void CommandLineFlag::Read(void* dst,
- const flags_internal::FlagOpFn dst_op) const {
- absl::ReaderMutexLock l(InitFlagIfNecessary());
-
- // `dst_op` is the unmarshaling operation corresponding to the declaration
- // visibile at the call site. `op` is the Flag's defined unmarshalling
- // operation. They must match for this operation to be well-defined.
- if (ABSL_PREDICT_FALSE(dst_op != op_)) {
- ABSL_INTERNAL_LOG(
- ERROR,
- absl::StrCat("Flag '", Name(),
- "' is defined as one type and declared as another"));
- }
- CopyConstruct(op_, cur_, dst);
-}
-
-void CommandLineFlag::Write(const void* src,
- const flags_internal::FlagOpFn src_op) {
- absl::MutexLock l(InitFlagIfNecessary());
-
- // `src_op` is the marshalling operation corresponding to the declaration
- // visible at the call site. `op` is the Flag's defined marshalling operation.
- // They must match for this operation to be well-defined.
- if (ABSL_PREDICT_FALSE(src_op != op_)) {
- ABSL_INTERNAL_LOG(
- ERROR,
- absl::StrCat("Flag '", Name(),
- "' is defined as one type and declared as another"));
- }
-
- if (ShouldValidateFlagValue(*this)) {
- void* obj = Clone(op_, src);
- std::string ignored_error;
- std::string src_as_str = Unparse(marshalling_op_, src);
- if (!Parse(marshalling_op_, src_as_str, obj, &ignored_error) ||
- !InvokeValidator(obj)) {
- ABSL_INTERNAL_LOG(ERROR, absl::StrCat("Attempt to set flag '", Name(),
- "' to invalid value ", src_as_str));
- }
- Delete(op_, obj);
- }
-
- modified_ = true;
- counter_++;
- Copy(op_, src, cur_);
-
- UpdateCopy(this);
- InvokeCallback();
-}
-
-std::string HelpText::GetHelpText() const {
- if (help_function_) return help_function_();
- if (help_message_) return help_message_;
-
- return {};
-}
-
-// Update any copy of the flag value that is stored in an atomic word.
-// In addition if flag has a mutation callback this function invokes it.
-void UpdateCopy(CommandLineFlag* flag) {
-#define STORE_ATOMIC(T) \
- else if (flag->IsOfType<T>()) { \
- flag->StoreAtomic(); \
- }
-
- if (false) {
- }
- ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(STORE_ATOMIC)
-#undef STORE_ATOMIC
-}
-
-// Return true iff flag value was changed via direct-access.
-bool ChangedDirectly(CommandLineFlag* flag, const void* a, const void* b) {
- if (!flag->IsAbseilFlag()) {
-// Need to compare values for direct-access flags.
-#define CHANGED_FOR_TYPE(T) \
- if (flag->IsOfType<T>()) { \
- return *reinterpret_cast<const T*>(a) != *reinterpret_cast<const T*>(b); \
- }
-
- CHANGED_FOR_TYPE(bool);
- CHANGED_FOR_TYPE(int32_t);
- CHANGED_FOR_TYPE(int64_t);
- CHANGED_FOR_TYPE(uint64_t);
- CHANGED_FOR_TYPE(double);
- CHANGED_FOR_TYPE(std::string);
-#undef CHANGED_FOR_TYPE
- }
-
- return false;
-}
+FlagStateInterface::~FlagStateInterface() {}
} // namespace flags_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/flags/internal/commandlineflag.h b/third_party/abseil/absl/flags/internal/commandlineflag.h
index 284286b..ebfe81b 100644
--- a/third_party/abseil/absl/flags/internal/commandlineflag.h
+++ b/third_party/abseil/absl/flags/internal/commandlineflag.h
@@ -16,29 +16,19 @@
#ifndef ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
#define ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
-#include <atomic>
-
-#include "absl/base/macros.h"
-#include "absl/flags/marshalling.h"
-#include "absl/synchronization/mutex.h"
-#include "absl/types/optional.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/fast_type_id.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace flags_internal {
-// Type-specific operations, eg., parsing, copying, etc. are provided
-// by function specific to that type with a signature matching FlagOpFn.
-enum FlagOp {
- kDelete,
- kClone,
- kCopy,
- kCopyConstruct,
- kSizeof,
- kParse,
- kUnparse
-};
-using FlagOpFn = void* (*)(FlagOp, const void*, void*);
-using FlagMarshallingOpFn = void* (*)(FlagOp, const void*, void*, void*);
+// An alias for flag fast type id. This value identifies the flag value type
+// similarly to typeid(T), without relying on RTTI being available. In most
+// cases this id is enough to uniquely identify the flag's value type. In a few
+// cases we'll have to resort to using actual RTTI implementation if it is
+// available.
+using FlagFastTypeId = absl::base_internal::FastTypeIdType;
// Options that control SetCommandLineOptionWithMode.
enum FlagSettingMode {
@@ -53,7 +43,7 @@
SET_FLAGS_DEFAULT
};
-// Options that control SetFromString: Source of a value.
+// Options that control ParseFrom: Source of a value.
enum ValueSource {
// Flag is being set by value specified on a command line.
kCommandLine,
@@ -61,309 +51,18 @@
kProgrammaticChange,
};
-// Signature for the help generation function used as an argument for the
-// absl::Flag constructor.
-using HelpGenFunc = std::string (*)();
-
-// Signature for the function generating the initial flag value based (usually
-// based on default value supplied in flag's definition)
-using InitialValGenFunc = void* (*)();
-
-extern const char kStrippedFlagHelp[];
-
-// The per-type function
-template <typename T>
-void* FlagOps(FlagOp op, const void* v1, void* v2) {
- switch (op) {
- case kDelete:
- delete static_cast<const T*>(v1);
- return nullptr;
- case kClone:
- return new T(*static_cast<const T*>(v1));
- case kCopy:
- *static_cast<T*>(v2) = *static_cast<const T*>(v1);
- return nullptr;
- case kCopyConstruct:
- new (v2) T(*static_cast<const T*>(v1));
- return nullptr;
- case kSizeof:
- return reinterpret_cast<void*>(sizeof(T));
- default:
- return nullptr;
- }
-}
-
-template <typename T>
-void* FlagMarshallingOps(FlagOp op, const void* v1, void* v2, void* v3) {
- switch (op) {
- case kParse: {
- // initialize the temporary instance of type T based on current value in
- // destination (which is going to be flag's default value).
- T temp(*static_cast<T*>(v2));
- if (!absl::ParseFlag<T>(*static_cast<const absl::string_view*>(v1), &temp,
- static_cast<std::string*>(v3))) {
- return nullptr;
- }
- *static_cast<T*>(v2) = std::move(temp);
- return v2;
- }
- case kUnparse:
- *static_cast<std::string*>(v2) =
- absl::UnparseFlag<T>(*static_cast<const T*>(v1));
- return nullptr;
- default:
- return nullptr;
- }
-}
-
-// Functions that invoke flag-type-specific operations.
-inline void Delete(FlagOpFn op, const void* obj) {
- op(flags_internal::kDelete, obj, nullptr);
-}
-
-inline void* Clone(FlagOpFn op, const void* obj) {
- return op(flags_internal::kClone, obj, nullptr);
-}
-
-inline void Copy(FlagOpFn op, const void* src, void* dst) {
- op(flags_internal::kCopy, src, dst);
-}
-
-inline void CopyConstruct(FlagOpFn op, const void* src, void* dst) {
- op(flags_internal::kCopyConstruct, src, dst);
-}
-
-inline bool Parse(FlagMarshallingOpFn op, absl::string_view text, void* dst,
- std::string* error) {
- return op(flags_internal::kParse, &text, dst, error) != nullptr;
-}
-
-inline std::string Unparse(FlagMarshallingOpFn op, const void* val) {
- std::string result;
- op(flags_internal::kUnparse, val, &result, nullptr);
- return result;
-}
-
-inline size_t Sizeof(FlagOpFn op) {
- // This sequence of casts reverses the sequence from base::internal::FlagOps()
- return static_cast<size_t>(reinterpret_cast<intptr_t>(
- op(flags_internal::kSizeof, nullptr, nullptr)));
-}
-
-// The following struct contains the locks in a CommandLineFlag struct.
-// They are in a separate struct that is lazily allocated to avoid problems
-// with static initialization and to avoid multiple allocations.
-struct CommandLineFlagLocks {
- absl::Mutex primary_mu; // protects several fields in CommandLineFlag
- absl::Mutex callback_mu; // used to serialize callbacks
-};
-
-// Holds either a pointer to help text or a function which produces it. This is
-// needed for supporting both static initialization of Flags while supporting
-// the legacy registration framework. We can't use absl::variant<const char*,
-// const char*(*)()> since anybody passing 0 or nullptr in to a CommandLineFlag
-// would find an ambiguity.
-class HelpText {
+// Handle to FlagState objects. Specific flag state objects will restore state
+// of a flag produced this flag state from method CommandLineFlag::SaveState().
+class FlagStateInterface {
public:
- static constexpr HelpText FromFunctionPointer(const HelpGenFunc fn) {
- return HelpText(fn, nullptr);
- }
- static constexpr HelpText FromStaticCString(const char* msg) {
- return HelpText(nullptr, msg);
- }
+ virtual ~FlagStateInterface();
- std::string GetHelpText() const;
-
- HelpText() = delete;
- HelpText(const HelpText&) = default;
- HelpText(HelpText&&) = default;
-
- private:
- explicit constexpr HelpText(const HelpGenFunc fn, const char* msg)
- : help_function_(fn), help_message_(msg) {}
-
- HelpGenFunc help_function_;
- const char* help_message_;
+ // Restores the flag originated this object to the saved state.
+ virtual void Restore() const = 0;
};
-// Holds all information for a flag.
-class CommandLineFlag {
- public:
- constexpr CommandLineFlag(
- const char* name, HelpText help_text, const char* filename,
- const flags_internal::FlagOpFn op,
- const flags_internal::FlagMarshallingOpFn marshalling_op,
- const flags_internal::InitialValGenFunc initial_value_gen, void* def,
- void* cur)
- : name_(name),
- help_(help_text),
- filename_(filename),
- op_(op),
- marshalling_op_(marshalling_op),
- make_init_value_(initial_value_gen),
- inited_(false),
- modified_(false),
- on_command_line_(false),
- def_(def),
- cur_(cur),
- counter_(0),
- locks_(nullptr) {}
-
- // Virtual destructor
- virtual void Destroy() const = 0;
-
- // Not copyable/assignable.
- CommandLineFlag(const CommandLineFlag&) = delete;
- CommandLineFlag& operator=(const CommandLineFlag&) = delete;
-
- // Access methods.
-
- // Returns true iff this object corresponds to retired flag
- virtual bool IsRetired() const { return false; }
- // Returns true iff this is a handle to an Abseil Flag.
- virtual bool IsAbseilFlag() const { return true; }
-
- absl::string_view Name() const { return name_; }
- std::string Help() const { return help_.GetHelpText(); }
- bool IsModified() const;
- void SetModified(bool is_modified);
- bool IsSpecifiedOnCommandLine() const;
-
- absl::string_view Typename() const;
- std::string Filename() const;
- std::string DefaultValue() const;
- std::string CurrentValue() const;
-
- // Interface to store the value in atomic if one used. This is short term
- // interface. To be reworked once cur_ is moved.
- virtual void StoreAtomic() {}
-
- // Interfaces to operate on validators.
- virtual bool HasValidatorFn() const { return false; }
- virtual bool InvokeValidator(const void* /*value*/) const { return true; }
- // Invoke the flag validators for old flags.
- // TODO(rogeeff): implement proper validators for Abseil Flags
- bool ValidateDefaultValue() const;
- bool ValidateInputValue(absl::string_view value) const;
-
- // Return true iff flag has type T.
- template <typename T>
- inline bool IsOfType() const {
- return op_ == &flags_internal::FlagOps<T>;
- }
-
- // Attempts to retrieve the flag value. Returns value on success,
- // absl::nullopt otherwise.
- template <typename T>
- absl::optional<T> Get() const {
- if (IsRetired() || flags_internal::FlagOps<T> != op_) return absl::nullopt;
-
- T res;
- Read(&res, flags_internal::FlagOps<T>);
-
- return res;
- }
-
- // Interfaces to overate on callbacks.
- virtual void InvokeCallback() {}
-
- // Sets the value of the flag based on specified std::string `value`. If the flag
- // was successfully set to new value, it returns true. Otherwise, sets `error`
- // to indicate the error, leaves the flag unchanged, and returns false. There
- // are three ways to set the flag's value:
- // * Update the current flag value
- // * Update the flag's default value
- // * Update the current flag value if it was never set before
- // The mode is selected based on `set_mode` parameter.
- bool SetFromString(absl::string_view value,
- flags_internal::FlagSettingMode set_mode,
- flags_internal::ValueSource source, std::string* error);
-
- void CheckDefaultValueParsingRoundtrip() const;
-
- // Constant configuration for a particular flag.
- protected:
- ~CommandLineFlag() = default;
-
- const char* const name_;
- const HelpText help_;
- const char* const filename_;
-
- const FlagOpFn op_; // Type-specific handler
- const FlagMarshallingOpFn marshalling_op_; // Marshalling ops handler
- const InitialValGenFunc make_init_value_; // Makes initial value for the flag
- std::atomic<bool> inited_; // fields have been lazily initialized
-
- // Mutable state (guarded by locks_->primary_mu).
- bool modified_; // Has flag value been modified?
- bool on_command_line_; // Specified on command line.
- void* def_; // Lazily initialized pointer to default value
- void* cur_; // Lazily initialized pointer to current value
- int64_t counter_; // Mutation counter
-
- // Lazily initialized mutexes for this flag value. We cannot inline a
- // SpinLock or Mutex here because those have non-constexpr constructors and
- // so would prevent constant initialization of this type.
- // TODO(rogeeff): fix it once Mutex has constexpr constructor
- struct CommandLineFlagLocks* locks_; // locks, laziliy allocated.
-
- // Ensure that the lazily initialized fields of *flag have been initialized,
- // and return the lock which should be locked when flag's state is mutated.
- absl::Mutex* InitFlagIfNecessary() const ABSL_LOCK_RETURNED(locks_->primary_mu);
-
- // copy construct new value of flag's type in a memory referenced by dst
- // based on current flag's value
- void Read(void* dst, const flags_internal::FlagOpFn dst_op) const;
- // updates flag's value to *src (locked)
- void Write(const void* src, const flags_internal::FlagOpFn src_op);
-
- friend class FlagRegistry;
- friend class FlagPtrMap;
- friend class FlagSaverImpl;
- friend bool TryParseLocked(CommandLineFlag* flag, void* dst,
- absl::string_view value, std::string* err);
- friend absl::Mutex* InitFlag(CommandLineFlag* flag);
-
- // This is a short term, until we completely rework persistent state
- // storage API.
- virtual void* GetValidator() const { return nullptr; }
- virtual bool SetValidator(void*) { return false; }
-};
-
-// Update any copy of the flag value that is stored in an atomic word.
-// In addition if flag has a mutation callback this function invokes it. While
-// callback is being invoked the primary flag's mutex is unlocked and it is
-// re-locked back after call to callback is completed. Callback invocation is
-// guarded by flag's secondary mutex instead which prevents concurrent callback
-// invocation. Note that it is possible for other thread to grab the primary
-// lock and update flag's value at any time during the callback invocation.
-// This is by design. Callback can get a value of the flag if necessary, but it
-// might be different from the value initiated the callback and it also can be
-// different by the time the callback invocation is completed.
-// Requires that *primary_lock be held in exclusive mode; it may be released
-// and reacquired by the implementation.
-void UpdateCopy(CommandLineFlag* flag);
-// Return true iff flag value was changed via direct-access.
-bool ChangedDirectly(CommandLineFlag* flag, const void* a, const void* b);
-
-// This macro is the "source of truth" for the list of supported flag types we
-// expect to perform lock free operations on. Specifically it generates code,
-// a one argument macro operating on a type, supplied as a macro argument, for
-// each type in the list.
-#define ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(A) \
- A(bool) \
- A(short) \
- A(unsigned short) \
- A(int) \
- A(unsigned int) \
- A(long) \
- A(unsigned long) \
- A(long long) \
- A(unsigned long long) \
- A(double) \
- A(float)
-
} // namespace flags_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
diff --git a/third_party/abseil/absl/flags/internal/commandlineflag_test.cc b/third_party/abseil/absl/flags/internal/commandlineflag_test.cc
deleted file mode 100644
index 5a0c271..0000000
--- a/third_party/abseil/absl/flags/internal/commandlineflag_test.cc
+++ /dev/null
@@ -1,218 +0,0 @@
-//
-// Copyright 2019 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/flags/internal/commandlineflag.h"
-
-#include <algorithm>
-#include <string>
-
-#include "gtest/gtest.h"
-#include "absl/flags/flag.h"
-#include "absl/flags/internal/registry.h"
-#include "absl/flags/usage_config.h"
-#include "absl/memory/memory.h"
-#include "absl/strings/match.h"
-#include "absl/strings/str_cat.h"
-
-ABSL_FLAG(int, int_flag, 201, "int_flag help");
-ABSL_FLAG(std::string, string_flag, "dflt",
- absl::StrCat("string_flag", " help"));
-ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help");
-
-namespace {
-
-namespace flags = absl::flags_internal;
-
-class CommandLineFlagTest : public testing::Test {
- protected:
- static void SetUpTestSuite() {
- // Install a function to normalize filenames before this test is run.
- absl::FlagsUsageConfig default_config;
- default_config.normalize_filename = &CommandLineFlagTest::NormalizeFileName;
- absl::SetFlagsUsageConfig(default_config);
- }
-
- void SetUp() override { flag_saver_ = absl::make_unique<flags::FlagSaver>(); }
- void TearDown() override { flag_saver_.reset(); }
-
- private:
- static std::string NormalizeFileName(absl::string_view fname) {
-#ifdef _WIN32
- std::string normalized(fname);
- std::replace(normalized.begin(), normalized.end(), '\\', '/');
- fname = normalized;
-#endif
- return std::string(fname);
- }
-
- std::unique_ptr<flags::FlagSaver> flag_saver_;
-};
-
-TEST_F(CommandLineFlagTest, TestAttributesAccessMethods) {
- auto* flag_01 = flags::FindCommandLineFlag("int_flag");
-
- ASSERT_TRUE(flag_01);
- EXPECT_EQ(flag_01->Name(), "int_flag");
- EXPECT_EQ(flag_01->Help(), "int_flag help");
- EXPECT_EQ(flag_01->Typename(), "");
- EXPECT_TRUE(!flag_01->IsRetired());
- EXPECT_TRUE(flag_01->IsOfType<int>());
- EXPECT_TRUE(
- absl::EndsWith(flag_01->Filename(),
- "absl/flags/internal/commandlineflag_test.cc"))
- << flag_01->Filename();
-
- auto* flag_02 = flags::FindCommandLineFlag("string_flag");
-
- ASSERT_TRUE(flag_02);
- EXPECT_EQ(flag_02->Name(), "string_flag");
- EXPECT_EQ(flag_02->Help(), "string_flag help");
- EXPECT_EQ(flag_02->Typename(), "");
- EXPECT_TRUE(!flag_02->IsRetired());
- EXPECT_TRUE(flag_02->IsOfType<std::string>());
- EXPECT_TRUE(
- absl::EndsWith(flag_02->Filename(),
- "absl/flags/internal/commandlineflag_test.cc"))
- << flag_02->Filename();
-
- auto* flag_03 = flags::FindRetiredFlag("bool_retired_flag");
-
- ASSERT_TRUE(flag_03);
- EXPECT_EQ(flag_03->Name(), "bool_retired_flag");
- EXPECT_EQ(flag_03->Help(), "");
- EXPECT_EQ(flag_03->Typename(), "");
- EXPECT_TRUE(flag_03->IsRetired());
- EXPECT_TRUE(flag_03->IsOfType<bool>());
- EXPECT_EQ(flag_03->Filename(), "RETIRED");
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(CommandLineFlagTest, TestValueAccessMethods) {
- absl::SetFlag(&FLAGS_int_flag, 301);
- auto* flag_01 = flags::FindCommandLineFlag("int_flag");
-
- ASSERT_TRUE(flag_01);
- EXPECT_EQ(flag_01->CurrentValue(), "301");
- EXPECT_EQ(flag_01->DefaultValue(), "201");
-
- absl::SetFlag(&FLAGS_string_flag, "new_str_value");
- auto* flag_02 = flags::FindCommandLineFlag("string_flag");
-
- ASSERT_TRUE(flag_02);
- EXPECT_EQ(flag_02->CurrentValue(), "new_str_value");
- EXPECT_EQ(flag_02->DefaultValue(), "dflt");
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(CommandLineFlagTest, TestSetFromStringCurrentValue) {
- std::string err;
-
- auto* flag_01 = flags::FindCommandLineFlag("int_flag");
- EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
-
- EXPECT_TRUE(flag_01->SetFromString("11", flags::SET_FLAGS_VALUE,
- flags::kProgrammaticChange, &err));
- EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11);
- EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
-
- EXPECT_TRUE(flag_01->SetFromString("-123", flags::SET_FLAGS_VALUE,
- flags::kProgrammaticChange, &err));
- EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
- EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
-
- EXPECT_TRUE(!flag_01->SetFromString("xyz", flags::SET_FLAGS_VALUE,
- flags::kProgrammaticChange, &err));
- EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
- EXPECT_EQ(err, "Illegal value 'xyz' specified for flag 'int_flag'");
- EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
-
- EXPECT_TRUE(!flag_01->SetFromString("A1", flags::SET_FLAGS_VALUE,
- flags::kProgrammaticChange, &err));
- EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
- EXPECT_EQ(err, "Illegal value 'A1' specified for flag 'int_flag'");
- EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
-
- EXPECT_TRUE(flag_01->SetFromString("0x10", flags::SET_FLAGS_VALUE,
- flags::kProgrammaticChange, &err));
- EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 16);
- EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
-
- EXPECT_TRUE(flag_01->SetFromString("011", flags::SET_FLAGS_VALUE,
- flags::kCommandLine, &err));
- EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11);
- EXPECT_TRUE(flag_01->IsSpecifiedOnCommandLine());
-
- EXPECT_TRUE(!flag_01->SetFromString("", flags::SET_FLAGS_VALUE,
- flags::kProgrammaticChange, &err));
- EXPECT_EQ(err, "Illegal value '' specified for flag 'int_flag'");
-
- auto* flag_02 = flags::FindCommandLineFlag("string_flag");
- EXPECT_TRUE(flag_02->SetFromString("xyz", flags::SET_FLAGS_VALUE,
- flags::kProgrammaticChange, &err));
- EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "xyz");
-
- EXPECT_TRUE(flag_02->SetFromString("", flags::SET_FLAGS_VALUE,
- flags::kProgrammaticChange, &err));
- EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "");
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(CommandLineFlagTest, TestSetFromStringDefaultValue) {
- std::string err;
-
- auto* flag_01 = flags::FindCommandLineFlag("int_flag");
-
- EXPECT_TRUE(flag_01->SetFromString("111", flags::SET_FLAGS_DEFAULT,
- flags::kProgrammaticChange, &err));
- EXPECT_EQ(flag_01->DefaultValue(), "111");
-
- auto* flag_02 = flags::FindCommandLineFlag("string_flag");
-
- EXPECT_TRUE(flag_02->SetFromString("abc", flags::SET_FLAGS_DEFAULT,
- flags::kProgrammaticChange, &err));
- EXPECT_EQ(flag_02->DefaultValue(), "abc");
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(CommandLineFlagTest, TestSetFromStringIfDefault) {
- std::string err;
-
- auto* flag_01 = flags::FindCommandLineFlag("int_flag");
-
- EXPECT_TRUE(flag_01->SetFromString("22", flags::SET_FLAG_IF_DEFAULT,
- flags::kProgrammaticChange, &err))
- << err;
- EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 22);
-
- EXPECT_TRUE(flag_01->SetFromString("33", flags::SET_FLAG_IF_DEFAULT,
- flags::kProgrammaticChange, &err));
- EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 22);
- // EXPECT_EQ(err, "ERROR: int_flag is already set to 22");
-
- // Reset back to default value
- EXPECT_TRUE(flag_01->SetFromString("201", flags::SET_FLAGS_VALUE,
- flags::kProgrammaticChange, &err));
-
- EXPECT_TRUE(flag_01->SetFromString("33", flags::SET_FLAG_IF_DEFAULT,
- flags::kProgrammaticChange, &err));
- EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 201);
- // EXPECT_EQ(err, "ERROR: int_flag is already set to 201");
-}
-
-} // namespace
diff --git a/third_party/abseil/absl/flags/internal/flag.cc b/third_party/abseil/absl/flags/internal/flag.cc
index 0f40358..f83c1fe 100644
--- a/third_party/abseil/absl/flags/internal/flag.cc
+++ b/third_party/abseil/absl/flags/internal/flag.cc
@@ -15,37 +15,567 @@
#include "absl/flags/internal/flag.h"
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <array>
+#include <atomic>
+#include <memory>
+#include <new>
+#include <string>
+#include <typeinfo>
+
+#include "absl/base/call_once.h"
+#include "absl/base/casts.h"
+#include "absl/base/config.h"
+#include "absl/base/optimization.h"
+#include "absl/flags/config.h"
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/flags/usage_config.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace flags_internal {
-// If the flag has a mutation callback this function invokes it. While the
-// callback is being invoked the primary flag's mutex is unlocked and it is
-// re-locked back after call to callback is completed. Callback invocation is
-// guarded by flag's secondary mutex instead which prevents concurrent
-// callback invocation. Note that it is possible for other thread to grab the
-// primary lock and update flag's value at any time during the callback
-// invocation. This is by design. Callback can get a value of the flag if
-// necessary, but it might be different from the value initiated the callback
-// and it also can be different by the time the callback invocation is
-// completed. Requires that *primary_lock be held in exclusive mode; it may be
-// released and reacquired by the implementation.
-void InvokeCallback(absl::Mutex* primary_mu, absl::Mutex* callback_mu,
- FlagCallback cb) ABSL_EXCLUSIVE_LOCKS_REQUIRED(primary_mu) {
- if (!cb) return;
+// The help message indicating that the commandline flag has been
+// 'stripped'. It will not show up when doing "-help" and its
+// variants. The flag is stripped if ABSL_FLAGS_STRIP_HELP is set to 1
+// before including absl/flags/flag.h
+const char kStrippedFlagHelp[] = "\001\002\003\004 (unknown) \004\003\002\001";
- // When executing the callback we need the primary flag's mutex to be
- // unlocked so that callback can retrieve the flag's value.
- primary_mu->Unlock();
+namespace {
- {
- absl::MutexLock lock(callback_mu);
- cb();
+// Currently we only validate flag values for user-defined flag types.
+bool ShouldValidateFlagValue(FlagFastTypeId flag_type_id) {
+#define DONT_VALIDATE(T, _) \
+ if (flag_type_id == base_internal::FastTypeId<T>()) return false;
+ ABSL_FLAGS_INTERNAL_SUPPORTED_TYPES(DONT_VALIDATE)
+#undef DONT_VALIDATE
+
+ return true;
+}
+
+// RAII helper used to temporarily unlock and relock `absl::Mutex`.
+// This is used when we need to ensure that locks are released while
+// invoking user supplied callbacks and then reacquired, since callbacks may
+// need to acquire these locks themselves.
+class MutexRelock {
+ public:
+ explicit MutexRelock(absl::Mutex& mu) : mu_(mu) { mu_.Unlock(); }
+ ~MutexRelock() { mu_.Lock(); }
+
+ MutexRelock(const MutexRelock&) = delete;
+ MutexRelock& operator=(const MutexRelock&) = delete;
+
+ private:
+ absl::Mutex& mu_;
+};
+
+} // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+// Persistent state of the flag data.
+
+class FlagImpl;
+
+class FlagState : public flags_internal::FlagStateInterface {
+ public:
+ template <typename V>
+ FlagState(FlagImpl& flag_impl, const V& v, bool modified,
+ bool on_command_line, int64_t counter)
+ : flag_impl_(flag_impl),
+ value_(v),
+ modified_(modified),
+ on_command_line_(on_command_line),
+ counter_(counter) {}
+
+ ~FlagState() override {
+ if (flag_impl_.ValueStorageKind() != FlagValueStorageKind::kAlignedBuffer &&
+ flag_impl_.ValueStorageKind() != FlagValueStorageKind::kSequenceLocked)
+ return;
+ flags_internal::Delete(flag_impl_.op_, value_.heap_allocated);
}
- primary_mu->Lock();
+ private:
+ friend class FlagImpl;
+
+ // Restores the flag to the saved state.
+ void Restore() const override {
+ if (!flag_impl_.RestoreState(*this)) return;
+
+ ABSL_INTERNAL_LOG(INFO,
+ absl::StrCat("Restore saved value of ", flag_impl_.Name(),
+ " to: ", flag_impl_.CurrentValue()));
+ }
+
+ // Flag and saved flag data.
+ FlagImpl& flag_impl_;
+ union SavedValue {
+ explicit SavedValue(void* v) : heap_allocated(v) {}
+ explicit SavedValue(int64_t v) : one_word(v) {}
+
+ void* heap_allocated;
+ int64_t one_word;
+ } value_;
+ bool modified_;
+ bool on_command_line_;
+ int64_t counter_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Flag implementation, which does not depend on flag value type.
+
+DynValueDeleter::DynValueDeleter(FlagOpFn op_arg) : op(op_arg) {}
+
+void DynValueDeleter::operator()(void* ptr) const {
+ if (op == nullptr) return;
+
+ Delete(op, ptr);
+}
+
+void FlagImpl::Init() {
+ new (&data_guard_) absl::Mutex;
+
+ auto def_kind = static_cast<FlagDefaultKind>(def_kind_);
+
+ switch (ValueStorageKind()) {
+ case FlagValueStorageKind::kAlignedBuffer:
+ // For this storage kind the default_value_ always points to gen_func
+ // during initialization.
+ assert(def_kind == FlagDefaultKind::kGenFunc);
+ (*default_value_.gen_func)(AlignedBufferValue());
+ break;
+ case FlagValueStorageKind::kOneWordAtomic: {
+ alignas(int64_t) std::array<char, sizeof(int64_t)> buf{};
+ if (def_kind == FlagDefaultKind::kGenFunc) {
+ (*default_value_.gen_func)(buf.data());
+ } else {
+ assert(def_kind != FlagDefaultKind::kDynamicValue);
+ std::memcpy(buf.data(), &default_value_, Sizeof(op_));
+ }
+ OneWordValue().store(absl::bit_cast<int64_t>(buf),
+ std::memory_order_release);
+ break;
+ }
+ case FlagValueStorageKind::kSequenceLocked: {
+ // For this storage kind the default_value_ always points to gen_func
+ // during initialization.
+ assert(def_kind == FlagDefaultKind::kGenFunc);
+ (*default_value_.gen_func)(AtomicBufferValue());
+ break;
+ }
+ }
+ seq_lock_.MarkInitialized();
+}
+
+absl::Mutex* FlagImpl::DataGuard() const {
+ absl::call_once(const_cast<FlagImpl*>(this)->init_control_, &FlagImpl::Init,
+ const_cast<FlagImpl*>(this));
+
+ // data_guard_ is initialized inside Init.
+ return reinterpret_cast<absl::Mutex*>(&data_guard_);
+}
+
+void FlagImpl::AssertValidType(FlagFastTypeId rhs_type_id,
+ const std::type_info* (*gen_rtti)()) const {
+ FlagFastTypeId lhs_type_id = flags_internal::FastTypeId(op_);
+
+ // `rhs_type_id` is the fast type id corresponding to the declaration
+ // visibile at the call site. `lhs_type_id` is the fast type id
+ // corresponding to the type specified in flag definition. They must match
+ // for this operation to be well-defined.
+ if (ABSL_PREDICT_TRUE(lhs_type_id == rhs_type_id)) return;
+
+ const std::type_info* lhs_runtime_type_id =
+ flags_internal::RuntimeTypeId(op_);
+ const std::type_info* rhs_runtime_type_id = (*gen_rtti)();
+
+ if (lhs_runtime_type_id == rhs_runtime_type_id) return;
+
+#if defined(ABSL_FLAGS_INTERNAL_HAS_RTTI)
+ if (*lhs_runtime_type_id == *rhs_runtime_type_id) return;
+#endif
+
+ ABSL_INTERNAL_LOG(
+ FATAL, absl::StrCat("Flag '", Name(),
+ "' is defined as one type and declared as another"));
+}
+
+std::unique_ptr<void, DynValueDeleter> FlagImpl::MakeInitValue() const {
+ void* res = nullptr;
+ switch (DefaultKind()) {
+ case FlagDefaultKind::kDynamicValue:
+ res = flags_internal::Clone(op_, default_value_.dynamic_value);
+ break;
+ case FlagDefaultKind::kGenFunc:
+ res = flags_internal::Alloc(op_);
+ (*default_value_.gen_func)(res);
+ break;
+ default:
+ res = flags_internal::Clone(op_, &default_value_);
+ break;
+ }
+ return {res, DynValueDeleter{op_}};
+}
+
+void FlagImpl::StoreValue(const void* src) {
+ switch (ValueStorageKind()) {
+ case FlagValueStorageKind::kAlignedBuffer:
+ Copy(op_, src, AlignedBufferValue());
+ seq_lock_.IncrementModificationCount();
+ break;
+ case FlagValueStorageKind::kOneWordAtomic: {
+ int64_t one_word_val = 0;
+ std::memcpy(&one_word_val, src, Sizeof(op_));
+ OneWordValue().store(one_word_val, std::memory_order_release);
+ seq_lock_.IncrementModificationCount();
+ break;
+ }
+ case FlagValueStorageKind::kSequenceLocked: {
+ seq_lock_.Write(AtomicBufferValue(), src, Sizeof(op_));
+ break;
+ }
+ }
+ modified_ = true;
+ InvokeCallback();
+}
+
+absl::string_view FlagImpl::Name() const { return name_; }
+
+std::string FlagImpl::Filename() const {
+ return flags_internal::GetUsageConfig().normalize_filename(filename_);
+}
+
+std::string FlagImpl::Help() const {
+ return HelpSourceKind() == FlagHelpKind::kLiteral ? help_.literal
+ : help_.gen_func();
+}
+
+FlagFastTypeId FlagImpl::TypeId() const {
+ return flags_internal::FastTypeId(op_);
+}
+
+int64_t FlagImpl::ModificationCount() const {
+ return seq_lock_.ModificationCount();
+}
+
+bool FlagImpl::IsSpecifiedOnCommandLine() const {
+ absl::MutexLock l(DataGuard());
+ return on_command_line_;
+}
+
+std::string FlagImpl::DefaultValue() const {
+ absl::MutexLock l(DataGuard());
+
+ auto obj = MakeInitValue();
+ return flags_internal::Unparse(op_, obj.get());
+}
+
+std::string FlagImpl::CurrentValue() const {
+ auto* guard = DataGuard(); // Make sure flag initialized
+ switch (ValueStorageKind()) {
+ case FlagValueStorageKind::kAlignedBuffer: {
+ absl::MutexLock l(guard);
+ return flags_internal::Unparse(op_, AlignedBufferValue());
+ }
+ case FlagValueStorageKind::kOneWordAtomic: {
+ const auto one_word_val =
+ absl::bit_cast<std::array<char, sizeof(int64_t)>>(
+ OneWordValue().load(std::memory_order_acquire));
+ return flags_internal::Unparse(op_, one_word_val.data());
+ }
+ case FlagValueStorageKind::kSequenceLocked: {
+ std::unique_ptr<void, DynValueDeleter> cloned(flags_internal::Alloc(op_),
+ DynValueDeleter{op_});
+ ReadSequenceLockedData(cloned.get());
+ return flags_internal::Unparse(op_, cloned.get());
+ }
+ }
+
+ return "";
+}
+
+void FlagImpl::SetCallback(const FlagCallbackFunc mutation_callback) {
+ absl::MutexLock l(DataGuard());
+
+ if (callback_ == nullptr) {
+ callback_ = new FlagCallback;
+ }
+ callback_->func = mutation_callback;
+
+ InvokeCallback();
+}
+
+void FlagImpl::InvokeCallback() const {
+ if (!callback_) return;
+
+ // Make a copy of the C-style function pointer that we are about to invoke
+ // before we release the lock guarding it.
+ FlagCallbackFunc cb = callback_->func;
+
+ // If the flag has a mutation callback this function invokes it. While the
+ // callback is being invoked the primary flag's mutex is unlocked and it is
+ // re-locked back after call to callback is completed. Callback invocation is
+ // guarded by flag's secondary mutex instead which prevents concurrent
+ // callback invocation. Note that it is possible for other thread to grab the
+ // primary lock and update flag's value at any time during the callback
+ // invocation. This is by design. Callback can get a value of the flag if
+ // necessary, but it might be different from the value initiated the callback
+ // and it also can be different by the time the callback invocation is
+ // completed. Requires that *primary_lock be held in exclusive mode; it may be
+ // released and reacquired by the implementation.
+ MutexRelock relock(*DataGuard());
+ absl::MutexLock lock(&callback_->guard);
+ cb();
+}
+
+std::unique_ptr<FlagStateInterface> FlagImpl::SaveState() {
+ absl::MutexLock l(DataGuard());
+
+ bool modified = modified_;
+ bool on_command_line = on_command_line_;
+ switch (ValueStorageKind()) {
+ case FlagValueStorageKind::kAlignedBuffer: {
+ return absl::make_unique<FlagState>(
+ *this, flags_internal::Clone(op_, AlignedBufferValue()), modified,
+ on_command_line, ModificationCount());
+ }
+ case FlagValueStorageKind::kOneWordAtomic: {
+ return absl::make_unique<FlagState>(
+ *this, OneWordValue().load(std::memory_order_acquire), modified,
+ on_command_line, ModificationCount());
+ }
+ case FlagValueStorageKind::kSequenceLocked: {
+ void* cloned = flags_internal::Alloc(op_);
+ // Read is guaranteed to be successful because we hold the lock.
+ bool success =
+ seq_lock_.TryRead(cloned, AtomicBufferValue(), Sizeof(op_));
+ assert(success);
+ static_cast<void>(success);
+ return absl::make_unique<FlagState>(*this, cloned, modified,
+ on_command_line, ModificationCount());
+ }
+ }
+ return nullptr;
+}
+
+bool FlagImpl::RestoreState(const FlagState& flag_state) {
+ absl::MutexLock l(DataGuard());
+ if (flag_state.counter_ == ModificationCount()) {
+ return false;
+ }
+
+ switch (ValueStorageKind()) {
+ case FlagValueStorageKind::kAlignedBuffer:
+ case FlagValueStorageKind::kSequenceLocked:
+ StoreValue(flag_state.value_.heap_allocated);
+ break;
+ case FlagValueStorageKind::kOneWordAtomic:
+ StoreValue(&flag_state.value_.one_word);
+ break;
+ }
+
+ modified_ = flag_state.modified_;
+ on_command_line_ = flag_state.on_command_line_;
+
+ return true;
+}
+
+template <typename StorageT>
+StorageT* FlagImpl::OffsetValue() const {
+ char* p = reinterpret_cast<char*>(const_cast<FlagImpl*>(this));
+ // The offset is deduced via Flag value type specific op_.
+ size_t offset = flags_internal::ValueOffset(op_);
+
+ return reinterpret_cast<StorageT*>(p + offset);
+}
+
+void* FlagImpl::AlignedBufferValue() const {
+ assert(ValueStorageKind() == FlagValueStorageKind::kAlignedBuffer);
+ return OffsetValue<void>();
+}
+
+std::atomic<uint64_t>* FlagImpl::AtomicBufferValue() const {
+ assert(ValueStorageKind() == FlagValueStorageKind::kSequenceLocked);
+ return OffsetValue<std::atomic<uint64_t>>();
+}
+
+std::atomic<int64_t>& FlagImpl::OneWordValue() const {
+ assert(ValueStorageKind() == FlagValueStorageKind::kOneWordAtomic);
+ return OffsetValue<FlagOneWordValue>()->value;
+}
+
+// Attempts to parse supplied `value` string using parsing routine in the `flag`
+// argument. If parsing successful, this function replaces the dst with newly
+// parsed value. In case if any error is encountered in either step, the error
+// message is stored in 'err'
+std::unique_ptr<void, DynValueDeleter> FlagImpl::TryParse(
+ absl::string_view value, std::string& err) const {
+ std::unique_ptr<void, DynValueDeleter> tentative_value = MakeInitValue();
+
+ std::string parse_err;
+ if (!flags_internal::Parse(op_, value, tentative_value.get(), &parse_err)) {
+ absl::string_view err_sep = parse_err.empty() ? "" : "; ";
+ err = absl::StrCat("Illegal value '", value, "' specified for flag '",
+ Name(), "'", err_sep, parse_err);
+ return nullptr;
+ }
+
+ return tentative_value;
+}
+
+void FlagImpl::Read(void* dst) const {
+ auto* guard = DataGuard(); // Make sure flag initialized
+ switch (ValueStorageKind()) {
+ case FlagValueStorageKind::kAlignedBuffer: {
+ absl::MutexLock l(guard);
+ flags_internal::CopyConstruct(op_, AlignedBufferValue(), dst);
+ break;
+ }
+ case FlagValueStorageKind::kOneWordAtomic: {
+ const int64_t one_word_val =
+ OneWordValue().load(std::memory_order_acquire);
+ std::memcpy(dst, &one_word_val, Sizeof(op_));
+ break;
+ }
+ case FlagValueStorageKind::kSequenceLocked: {
+ ReadSequenceLockedData(dst);
+ break;
+ }
+ }
+}
+
+void FlagImpl::ReadSequenceLockedData(void* dst) const {
+ int size = Sizeof(op_);
+ // Attempt to read using the sequence lock.
+ if (ABSL_PREDICT_TRUE(seq_lock_.TryRead(dst, AtomicBufferValue(), size))) {
+ return;
+ }
+ // We failed due to contention. Acquire the lock to prevent contention
+ // and try again.
+ absl::ReaderMutexLock l(DataGuard());
+ bool success = seq_lock_.TryRead(dst, AtomicBufferValue(), size);
+ assert(success);
+ static_cast<void>(success);
+}
+
+void FlagImpl::Write(const void* src) {
+ absl::MutexLock l(DataGuard());
+
+ if (ShouldValidateFlagValue(flags_internal::FastTypeId(op_))) {
+ std::unique_ptr<void, DynValueDeleter> obj{flags_internal::Clone(op_, src),
+ DynValueDeleter{op_}};
+ std::string ignored_error;
+ std::string src_as_str = flags_internal::Unparse(op_, src);
+ if (!flags_internal::Parse(op_, src_as_str, obj.get(), &ignored_error)) {
+ ABSL_INTERNAL_LOG(ERROR, absl::StrCat("Attempt to set flag '", Name(),
+ "' to invalid value ", src_as_str));
+ }
+ }
+
+ StoreValue(src);
+}
+
+// Sets the value of the flag based on specified string `value`. If the flag
+// was successfully set to new value, it returns true. Otherwise, sets `err`
+// to indicate the error, leaves the flag unchanged, and returns false. There
+// are three ways to set the flag's value:
+// * Update the current flag value
+// * Update the flag's default value
+// * Update the current flag value if it was never set before
+// The mode is selected based on 'set_mode' parameter.
+bool FlagImpl::ParseFrom(absl::string_view value, FlagSettingMode set_mode,
+ ValueSource source, std::string& err) {
+ absl::MutexLock l(DataGuard());
+
+ switch (set_mode) {
+ case SET_FLAGS_VALUE: {
+ // set or modify the flag's value
+ auto tentative_value = TryParse(value, err);
+ if (!tentative_value) return false;
+
+ StoreValue(tentative_value.get());
+
+ if (source == kCommandLine) {
+ on_command_line_ = true;
+ }
+ break;
+ }
+ case SET_FLAG_IF_DEFAULT: {
+ // set the flag's value, but only if it hasn't been set by someone else
+ if (modified_) {
+ // TODO(rogeeff): review and fix this semantic. Currently we do not fail
+ // in this case if flag is modified. This is misleading since the flag's
+ // value is not updated even though we return true.
+ // *err = absl::StrCat(Name(), " is already set to ",
+ // CurrentValue(), "\n");
+ // return false;
+ return true;
+ }
+ auto tentative_value = TryParse(value, err);
+ if (!tentative_value) return false;
+
+ StoreValue(tentative_value.get());
+ break;
+ }
+ case SET_FLAGS_DEFAULT: {
+ auto tentative_value = TryParse(value, err);
+ if (!tentative_value) return false;
+
+ if (DefaultKind() == FlagDefaultKind::kDynamicValue) {
+ void* old_value = default_value_.dynamic_value;
+ default_value_.dynamic_value = tentative_value.release();
+ tentative_value.reset(old_value);
+ } else {
+ default_value_.dynamic_value = tentative_value.release();
+ def_kind_ = static_cast<uint8_t>(FlagDefaultKind::kDynamicValue);
+ }
+
+ if (!modified_) {
+ // Need to set both default value *and* current, in this case.
+ StoreValue(default_value_.dynamic_value);
+ modified_ = false;
+ }
+ break;
+ }
+ }
+
+ return true;
+}
+
+void FlagImpl::CheckDefaultValueParsingRoundtrip() const {
+ std::string v = DefaultValue();
+
+ absl::MutexLock lock(DataGuard());
+
+ auto dst = MakeInitValue();
+ std::string error;
+ if (!flags_internal::Parse(op_, v, dst.get(), &error)) {
+ ABSL_INTERNAL_LOG(
+ FATAL,
+ absl::StrCat("Flag ", Name(), " (from ", Filename(),
+ "): string form of default value '", v,
+ "' could not be parsed; error=", error));
+ }
+
+ // We do not compare dst to def since parsing/unparsing may make
+ // small changes, e.g., precision loss for floating point types.
+}
+
+bool FlagImpl::ValidateInputValue(absl::string_view value) const {
+ absl::MutexLock l(DataGuard());
+
+ auto obj = MakeInitValue();
+ std::string ignored_error;
+ return flags_internal::Parse(op_, value, obj.get(), &ignored_error);
}
} // namespace flags_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/flags/internal/flag.h b/third_party/abseil/absl/flags/internal/flag.h
index 1633038..8354814 100644
--- a/third_party/abseil/absl/flags/internal/flag.h
+++ b/third_party/abseil/absl/flags/internal/flag.h
@@ -16,58 +16,597 @@
#ifndef ABSL_FLAGS_INTERNAL_FLAG_H_
#define ABSL_FLAGS_INTERNAL_FLAG_H_
-#include <cstring>
+#include <stddef.h>
+#include <stdint.h>
+#include <atomic>
+#include <cstring>
+#include <memory>
+#include <new>
+#include <string>
+#include <type_traits>
+#include <typeinfo>
+
+#include "absl/base/attributes.h"
+#include "absl/base/call_once.h"
+#include "absl/base/config.h"
+#include "absl/base/optimization.h"
+#include "absl/base/thread_annotations.h"
+#include "absl/flags/commandlineflag.h"
+#include "absl/flags/config.h"
#include "absl/flags/internal/commandlineflag.h"
#include "absl/flags/internal/registry.h"
+#include "absl/flags/internal/sequence_lock.h"
+#include "absl/flags/marshalling.h"
+#include "absl/meta/type_traits.h"
+#include "absl/strings/string_view.h"
+#include "absl/synchronization/mutex.h"
+#include "absl/utility/utility.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// Forward declaration of absl::Flag<T> public API.
+namespace flags_internal {
+template <typename T>
+class Flag;
+} // namespace flags_internal
+
+#if defined(_MSC_VER) && !defined(__clang__)
+template <typename T>
+class Flag;
+#else
+template <typename T>
+using Flag = flags_internal::Flag<T>;
+#endif
+
+template <typename T>
+ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag<T>& flag);
+
+template <typename T>
+void SetFlag(absl::Flag<T>* flag, const T& v);
+
+template <typename T, typename V>
+void SetFlag(absl::Flag<T>* flag, const V& v);
+
+template <typename U>
+const CommandLineFlag& GetFlagReflectionHandle(const absl::Flag<U>& f);
+
+///////////////////////////////////////////////////////////////////////////////
+// Flag value type operations, eg., parsing, copying, etc. are provided
+// by function specific to that type with a signature matching FlagOpFn.
+
namespace flags_internal {
-constexpr int64_t AtomicInit() { return 0xababababababababll; }
+enum class FlagOp {
+ kAlloc,
+ kDelete,
+ kCopy,
+ kCopyConstruct,
+ kSizeof,
+ kFastTypeId,
+ kRuntimeTypeId,
+ kParse,
+ kUnparse,
+ kValueOffset,
+};
+using FlagOpFn = void* (*)(FlagOp, const void*, void*, void*);
+
+// Forward declaration for Flag value specific operations.
+template <typename T>
+void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3);
+
+// Allocate aligned memory for a flag value.
+inline void* Alloc(FlagOpFn op) {
+ return op(FlagOp::kAlloc, nullptr, nullptr, nullptr);
+}
+// Deletes memory interpreting obj as flag value type pointer.
+inline void Delete(FlagOpFn op, void* obj) {
+ op(FlagOp::kDelete, nullptr, obj, nullptr);
+}
+// Copies src to dst interpreting as flag value type pointers.
+inline void Copy(FlagOpFn op, const void* src, void* dst) {
+ op(FlagOp::kCopy, src, dst, nullptr);
+}
+// Construct a copy of flag value in a location pointed by dst
+// based on src - pointer to the flag's value.
+inline void CopyConstruct(FlagOpFn op, const void* src, void* dst) {
+ op(FlagOp::kCopyConstruct, src, dst, nullptr);
+}
+// Makes a copy of flag value pointed by obj.
+inline void* Clone(FlagOpFn op, const void* obj) {
+ void* res = flags_internal::Alloc(op);
+ flags_internal::CopyConstruct(op, obj, res);
+ return res;
+}
+// Returns true if parsing of input text is successfull.
+inline bool Parse(FlagOpFn op, absl::string_view text, void* dst,
+ std::string* error) {
+ return op(FlagOp::kParse, &text, dst, error) != nullptr;
+}
+// Returns string representing supplied value.
+inline std::string Unparse(FlagOpFn op, const void* val) {
+ std::string result;
+ op(FlagOp::kUnparse, val, &result, nullptr);
+ return result;
+}
+// Returns size of flag value type.
+inline size_t Sizeof(FlagOpFn op) {
+ // This sequence of casts reverses the sequence from
+ // `flags_internal::FlagOps()`
+ return static_cast<size_t>(reinterpret_cast<intptr_t>(
+ op(FlagOp::kSizeof, nullptr, nullptr, nullptr)));
+}
+// Returns fast type id coresponding to the value type.
+inline FlagFastTypeId FastTypeId(FlagOpFn op) {
+ return reinterpret_cast<FlagFastTypeId>(
+ op(FlagOp::kFastTypeId, nullptr, nullptr, nullptr));
+}
+// Returns fast type id coresponding to the value type.
+inline const std::type_info* RuntimeTypeId(FlagOpFn op) {
+ return reinterpret_cast<const std::type_info*>(
+ op(FlagOp::kRuntimeTypeId, nullptr, nullptr, nullptr));
+}
+// Returns offset of the field value_ from the field impl_ inside of
+// absl::Flag<T> data. Given FlagImpl pointer p you can get the
+// location of the corresponding value as:
+// reinterpret_cast<char*>(p) + ValueOffset().
+inline ptrdiff_t ValueOffset(FlagOpFn op) {
+ // This sequence of casts reverses the sequence from
+ // `flags_internal::FlagOps()`
+ return static_cast<ptrdiff_t>(reinterpret_cast<intptr_t>(
+ op(FlagOp::kValueOffset, nullptr, nullptr, nullptr)));
+}
+
+// Returns an address of RTTI's typeid(T).
+template <typename T>
+inline const std::type_info* GenRuntimeTypeId() {
+#if defined(ABSL_FLAGS_INTERNAL_HAS_RTTI)
+ return &typeid(T);
+#else
+ return nullptr;
+#endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Flag help auxiliary structs.
+
+// This is help argument for absl::Flag encapsulating the string literal pointer
+// or pointer to function generating it as well as enum descriminating two
+// cases.
+using HelpGenFunc = std::string (*)();
+
+template <size_t N>
+struct FixedCharArray {
+ char value[N];
+
+ template <size_t... I>
+ static constexpr FixedCharArray<N> FromLiteralString(
+ absl::string_view str, absl::index_sequence<I...>) {
+ return (void)str, FixedCharArray<N>({{str[I]..., '\0'}});
+ }
+};
+
+template <typename Gen, size_t N = Gen::Value().size()>
+constexpr FixedCharArray<N + 1> HelpStringAsArray(int) {
+ return FixedCharArray<N + 1>::FromLiteralString(
+ Gen::Value(), absl::make_index_sequence<N>{});
+}
+
+template <typename Gen>
+constexpr std::false_type HelpStringAsArray(char) {
+ return std::false_type{};
+}
+
+union FlagHelpMsg {
+ constexpr explicit FlagHelpMsg(const char* help_msg) : literal(help_msg) {}
+ constexpr explicit FlagHelpMsg(HelpGenFunc help_gen) : gen_func(help_gen) {}
+
+ const char* literal;
+ HelpGenFunc gen_func;
+};
+
+enum class FlagHelpKind : uint8_t { kLiteral = 0, kGenFunc = 1 };
+
+struct FlagHelpArg {
+ FlagHelpMsg source;
+ FlagHelpKind kind;
+};
+
+extern const char kStrippedFlagHelp[];
+
+// These two HelpArg overloads allows us to select at compile time one of two
+// way to pass Help argument to absl::Flag. We'll be passing
+// AbslFlagHelpGenFor##name as Gen and integer 0 as a single argument to prefer
+// first overload if possible. If help message is evaluatable on constexpr
+// context We'll be able to make FixedCharArray out of it and we'll choose first
+// overload. In this case the help message expression is immediately evaluated
+// and is used to construct the absl::Flag. No additionl code is generated by
+// ABSL_FLAG Otherwise SFINAE kicks in and first overload is dropped from the
+// consideration, in which case the second overload will be used. The second
+// overload does not attempt to evaluate the help message expression
+// immediately and instead delays the evaluation by returing the function
+// pointer (&T::NonConst) genering the help message when necessary. This is
+// evaluatable in constexpr context, but the cost is an extra function being
+// generated in the ABSL_FLAG code.
+template <typename Gen, size_t N>
+constexpr FlagHelpArg HelpArg(const FixedCharArray<N>& value) {
+ return {FlagHelpMsg(value.value), FlagHelpKind::kLiteral};
+}
+
+template <typename Gen>
+constexpr FlagHelpArg HelpArg(std::false_type) {
+ return {FlagHelpMsg(&Gen::NonConst), FlagHelpKind::kGenFunc};
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Flag default value auxiliary structs.
+
+// Signature for the function generating the initial flag value (usually
+// based on default value supplied in flag's definition)
+using FlagDfltGenFunc = void (*)(void*);
+
+union FlagDefaultSrc {
+ constexpr explicit FlagDefaultSrc(FlagDfltGenFunc gen_func_arg)
+ : gen_func(gen_func_arg) {}
+
+#define ABSL_FLAGS_INTERNAL_DFLT_FOR_TYPE(T, name) \
+ T name##_value; \
+ constexpr explicit FlagDefaultSrc(T value) : name##_value(value) {} // NOLINT
+ ABSL_FLAGS_INTERNAL_BUILTIN_TYPES(ABSL_FLAGS_INTERNAL_DFLT_FOR_TYPE)
+#undef ABSL_FLAGS_INTERNAL_DFLT_FOR_TYPE
+
+ void* dynamic_value;
+ FlagDfltGenFunc gen_func;
+};
+
+enum class FlagDefaultKind : uint8_t {
+ kDynamicValue = 0,
+ kGenFunc = 1,
+ kOneWord = 2 // for default values UP to one word in size
+};
+
+struct FlagDefaultArg {
+ FlagDefaultSrc source;
+ FlagDefaultKind kind;
+};
+
+// This struct and corresponding overload to InitDefaultValue are used to
+// facilitate usage of {} as default value in ABSL_FLAG macro.
+// TODO(rogeeff): Fix handling types with explicit constructors.
+struct EmptyBraces {};
+
+template <typename T>
+constexpr T InitDefaultValue(T t) {
+ return t;
+}
+
+template <typename T>
+constexpr T InitDefaultValue(EmptyBraces) {
+ return T{};
+}
+
+template <typename ValueT, typename GenT,
+ typename std::enable_if<std::is_integral<ValueT>::value, int>::type =
+ (GenT{}, 0)>
+constexpr FlagDefaultArg DefaultArg(int) {
+ return {FlagDefaultSrc(GenT{}.value), FlagDefaultKind::kOneWord};
+}
+
+template <typename ValueT, typename GenT>
+constexpr FlagDefaultArg DefaultArg(char) {
+ return {FlagDefaultSrc(&GenT::Gen), FlagDefaultKind::kGenFunc};
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Flag current value auxiliary structs.
+
+constexpr int64_t UninitializedFlagValue() { return 0xababababababababll; }
+
+template <typename T>
+using FlagUseOneWordStorage = std::integral_constant<
+ bool, absl::type_traits_internal::is_trivially_copyable<T>::value &&
+ (sizeof(T) <= 8)>;
+
+template <class T>
+using FlagShouldUseSequenceLock = std::integral_constant<
+ bool, absl::type_traits_internal::is_trivially_copyable<T>::value &&
+ (sizeof(T) > 8)>;
+
+enum class FlagValueStorageKind : uint8_t {
+ kAlignedBuffer = 0,
+ kOneWordAtomic = 1,
+ kSequenceLocked = 2,
+};
+
+template <typename T>
+static constexpr FlagValueStorageKind StorageKind() {
+ return FlagUseOneWordStorage<T>::value ? FlagValueStorageKind::kOneWordAtomic
+ : FlagShouldUseSequenceLock<T>::value
+ ? FlagValueStorageKind::kSequenceLocked
+ : FlagValueStorageKind::kAlignedBuffer;
+}
+
+struct FlagOneWordValue {
+ constexpr FlagOneWordValue() : value(UninitializedFlagValue()) {}
+
+ std::atomic<int64_t> value;
+};
+
+template <typename T,
+ FlagValueStorageKind Kind = flags_internal::StorageKind<T>()>
+struct FlagValue;
+
+template <typename T>
+struct FlagValue<T, FlagValueStorageKind::kAlignedBuffer> {
+ bool Get(const SequenceLock&, T&) const { return false; }
+
+ alignas(T) char value[sizeof(T)];
+};
+
+template <typename T>
+struct FlagValue<T, FlagValueStorageKind::kOneWordAtomic> : FlagOneWordValue {
+ bool Get(const SequenceLock&, T& dst) const {
+ int64_t one_word_val = value.load(std::memory_order_acquire);
+ if (ABSL_PREDICT_FALSE(one_word_val == UninitializedFlagValue())) {
+ return false;
+ }
+ std::memcpy(&dst, static_cast<const void*>(&one_word_val), sizeof(T));
+ return true;
+ }
+};
+
+template <typename T>
+struct FlagValue<T, FlagValueStorageKind::kSequenceLocked> {
+ bool Get(const SequenceLock& lock, T& dst) const {
+ return lock.TryRead(&dst, value_words, sizeof(T));
+ }
+
+ static constexpr int kNumWords =
+ flags_internal::AlignUp(sizeof(T), sizeof(uint64_t)) / sizeof(uint64_t);
+
+ alignas(T) alignas(
+ std::atomic<uint64_t>) std::atomic<uint64_t> value_words[kNumWords];
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Flag callback auxiliary structs.
// Signature for the mutation callback used by watched Flags
// The callback is noexcept.
// TODO(rogeeff): add noexcept after C++17 support is added.
-using FlagCallback = void (*)();
+using FlagCallbackFunc = void (*)();
-void InvokeCallback(absl::Mutex* primary_mu, absl::Mutex* callback_mu,
- FlagCallback cb) ABSL_EXCLUSIVE_LOCKS_REQUIRED(primary_mu);
+struct FlagCallback {
+ FlagCallbackFunc func;
+ absl::Mutex guard; // Guard for concurrent callback invocations.
+};
-// This is "unspecified" implementation of absl::Flag<T> type.
-template <typename T>
-class Flag final : public flags_internal::CommandLineFlag {
+///////////////////////////////////////////////////////////////////////////////
+// Flag implementation, which does not depend on flag value type.
+// The class encapsulates the Flag's data and access to it.
+
+struct DynValueDeleter {
+ explicit DynValueDeleter(FlagOpFn op_arg = nullptr);
+ void operator()(void* ptr) const;
+
+ FlagOpFn op;
+};
+
+class FlagState;
+
+class FlagImpl final : public CommandLineFlag {
public:
- constexpr Flag(const char* name, const flags_internal::HelpGenFunc help_gen,
- const char* filename,
- const flags_internal::FlagMarshallingOpFn marshalling_op,
- const flags_internal::InitialValGenFunc initial_value_gen)
- : flags_internal::CommandLineFlag(
- name, flags_internal::HelpText::FromFunctionPointer(help_gen),
- filename, &flags_internal::FlagOps<T>, marshalling_op,
- initial_value_gen,
- /*def=*/nullptr,
- /*cur=*/nullptr),
- atomic_(flags_internal::AtomicInit()),
- callback_(nullptr) {}
+ constexpr FlagImpl(const char* name, const char* filename, FlagOpFn op,
+ FlagHelpArg help, FlagValueStorageKind value_kind,
+ FlagDefaultArg default_arg)
+ : name_(name),
+ filename_(filename),
+ op_(op),
+ help_(help.source),
+ help_source_kind_(static_cast<uint8_t>(help.kind)),
+ value_storage_kind_(static_cast<uint8_t>(value_kind)),
+ def_kind_(static_cast<uint8_t>(default_arg.kind)),
+ modified_(false),
+ on_command_line_(false),
+ callback_(nullptr),
+ default_value_(default_arg.source),
+ data_guard_{} {}
+
+ // Constant access methods
+ void Read(void* dst) const override ABSL_LOCKS_EXCLUDED(*DataGuard());
+
+ // Mutating access methods
+ void Write(const void* src) ABSL_LOCKS_EXCLUDED(*DataGuard());
+
+ // Interfaces to operate on callbacks.
+ void SetCallback(const FlagCallbackFunc mutation_callback)
+ ABSL_LOCKS_EXCLUDED(*DataGuard());
+ void InvokeCallback() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
+
+ // Used in read/write operations to validate source/target has correct type.
+ // For example if flag is declared as absl::Flag<int> FLAGS_foo, a call to
+ // absl::GetFlag(FLAGS_foo) validates that the type of FLAGS_foo is indeed
+ // int. To do that we pass the "assumed" type id (which is deduced from type
+ // int) as an argument `type_id`, which is in turn is validated against the
+ // type id stored in flag object by flag definition statement.
+ void AssertValidType(FlagFastTypeId type_id,
+ const std::type_info* (*gen_rtti)()) const;
+
+ private:
+ template <typename T>
+ friend class Flag;
+ friend class FlagState;
+
+ // Ensures that `data_guard_` is initialized and returns it.
+ absl::Mutex* DataGuard() const
+ ABSL_LOCK_RETURNED(reinterpret_cast<absl::Mutex*>(data_guard_));
+ // Returns heap allocated value of type T initialized with default value.
+ std::unique_ptr<void, DynValueDeleter> MakeInitValue() const
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
+ // Flag initialization called via absl::call_once.
+ void Init();
+
+ // Offset value access methods. One per storage kind. These methods to not
+ // respect const correctness, so be very carefull using them.
+
+ // This is a shared helper routine which encapsulates most of the magic. Since
+ // it is only used inside the three routines below, which are defined in
+ // flag.cc, we can define it in that file as well.
+ template <typename StorageT>
+ StorageT* OffsetValue() const;
+ // This is an accessor for a value stored in an aligned buffer storage
+ // used for non-trivially-copyable data types.
+ // Returns a mutable pointer to the start of a buffer.
+ void* AlignedBufferValue() const;
+
+ // The same as above, but used for sequencelock-protected storage.
+ std::atomic<uint64_t>* AtomicBufferValue() const;
+
+ // This is an accessor for a value stored as one word atomic. Returns a
+ // mutable reference to an atomic value.
+ std::atomic<int64_t>& OneWordValue() const;
+
+ // Attempts to parse supplied `value` string. If parsing is successful,
+ // returns new value. Otherwise returns nullptr.
+ std::unique_ptr<void, DynValueDeleter> TryParse(absl::string_view value,
+ std::string& err) const
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
+ // Stores the flag value based on the pointer to the source.
+ void StoreValue(const void* src) ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
+
+ // Copy the flag data, protected by `seq_lock_` into `dst`.
+ //
+ // REQUIRES: ValueStorageKind() == kSequenceLocked.
+ void ReadSequenceLockedData(void* dst) const
+ ABSL_LOCKS_EXCLUDED(*DataGuard());
+
+ FlagHelpKind HelpSourceKind() const {
+ return static_cast<FlagHelpKind>(help_source_kind_);
+ }
+ FlagValueStorageKind ValueStorageKind() const {
+ return static_cast<FlagValueStorageKind>(value_storage_kind_);
+ }
+ FlagDefaultKind DefaultKind() const
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()) {
+ return static_cast<FlagDefaultKind>(def_kind_);
+ }
+
+ // CommandLineFlag interface implementation
+ absl::string_view Name() const override;
+ std::string Filename() const override;
+ std::string Help() const override;
+ FlagFastTypeId TypeId() const override;
+ bool IsSpecifiedOnCommandLine() const override
+ ABSL_LOCKS_EXCLUDED(*DataGuard());
+ std::string DefaultValue() const override ABSL_LOCKS_EXCLUDED(*DataGuard());
+ std::string CurrentValue() const override ABSL_LOCKS_EXCLUDED(*DataGuard());
+ bool ValidateInputValue(absl::string_view value) const override
+ ABSL_LOCKS_EXCLUDED(*DataGuard());
+ void CheckDefaultValueParsingRoundtrip() const override
+ ABSL_LOCKS_EXCLUDED(*DataGuard());
+
+ int64_t ModificationCount() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
+
+ // Interfaces to save and restore flags to/from persistent state.
+ // Returns current flag state or nullptr if flag does not support
+ // saving and restoring a state.
+ std::unique_ptr<FlagStateInterface> SaveState() override
+ ABSL_LOCKS_EXCLUDED(*DataGuard());
+
+ // Restores the flag state to the supplied state object. If there is
+ // nothing to restore returns false. Otherwise returns true.
+ bool RestoreState(const FlagState& flag_state)
+ ABSL_LOCKS_EXCLUDED(*DataGuard());
+
+ bool ParseFrom(absl::string_view value, FlagSettingMode set_mode,
+ ValueSource source, std::string& error) override
+ ABSL_LOCKS_EXCLUDED(*DataGuard());
+
+ // Immutable flag's state.
+
+ // Flags name passed to ABSL_FLAG as second arg.
+ const char* const name_;
+ // The file name where ABSL_FLAG resides.
+ const char* const filename_;
+ // Type-specific operations "vtable".
+ const FlagOpFn op_;
+ // Help message literal or function to generate it.
+ const FlagHelpMsg help_;
+ // Indicates if help message was supplied as literal or generator func.
+ const uint8_t help_source_kind_ : 1;
+ // Kind of storage this flag is using for the flag's value.
+ const uint8_t value_storage_kind_ : 2;
+
+ uint8_t : 0; // The bytes containing the const bitfields must not be
+ // shared with bytes containing the mutable bitfields.
+
+ // Mutable flag's state (guarded by `data_guard_`).
+
+ // def_kind_ is not guard by DataGuard() since it is accessed in Init without
+ // locks.
+ uint8_t def_kind_ : 2;
+ // Has this flag's value been modified?
+ bool modified_ : 1 ABSL_GUARDED_BY(*DataGuard());
+ // Has this flag been specified on command line.
+ bool on_command_line_ : 1 ABSL_GUARDED_BY(*DataGuard());
+
+ // Unique tag for absl::call_once call to initialize this flag.
+ absl::once_flag init_control_;
+
+ // Sequence lock / mutation counter.
+ flags_internal::SequenceLock seq_lock_;
+
+ // Optional flag's callback and absl::Mutex to guard the invocations.
+ FlagCallback* callback_ ABSL_GUARDED_BY(*DataGuard());
+ // Either a pointer to the function generating the default value based on the
+ // value specified in ABSL_FLAG or pointer to the dynamically set default
+ // value via SetCommandLineOptionWithMode. def_kind_ is used to distinguish
+ // these two cases.
+ FlagDefaultSrc default_value_;
+
+ // This is reserved space for an absl::Mutex to guard flag data. It will be
+ // initialized in FlagImpl::Init via placement new.
+ // We can't use "absl::Mutex data_guard_", since this class is not literal.
+ // We do not want to use "absl::Mutex* data_guard_", since this would require
+ // heap allocation during initialization, which is both slows program startup
+ // and can fail. Using reserved space + placement new allows us to avoid both
+ // problems.
+ alignas(absl::Mutex) mutable char data_guard_[sizeof(absl::Mutex)];
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// The Flag object parameterized by the flag's value type. This class implements
+// flag reflection handle interface.
+
+template <typename T>
+class Flag {
+ public:
+ constexpr Flag(const char* name, const char* filename, FlagHelpArg help,
+ const FlagDefaultArg default_arg)
+ : impl_(name, filename, &FlagOps<T>, help,
+ flags_internal::StorageKind<T>(), default_arg),
+ value_() {}
+
+ // CommandLineFlag interface
+ absl::string_view Name() const { return impl_.Name(); }
+ std::string Filename() const { return impl_.Filename(); }
+ std::string Help() const { return impl_.Help(); }
+ // Do not use. To be removed.
+ bool IsSpecifiedOnCommandLine() const {
+ return impl_.IsSpecifiedOnCommandLine();
+ }
+ std::string DefaultValue() const { return impl_.DefaultValue(); }
+ std::string CurrentValue() const { return impl_.CurrentValue(); }
+
+ private:
+ template <typename, bool>
+ friend class FlagRegistrar;
+ friend class FlagImplPeer;
T Get() const {
- // Implementation notes:
- //
- // We are wrapping a union around the value of `T` to serve three purposes:
- //
- // 1. `U.value` has correct size and alignment for a value of type `T`
- // 2. The `U.value` constructor is not invoked since U's constructor does
- // not
- // do it explicitly.
- // 3. The `U.value` destructor is invoked since U's destructor does it
- // explicitly. This makes `U` a kind of RAII wrapper around non default
- // constructible value of T, which is destructed when we leave the
- // scope. We do need to destroy U.value, which is constructed by
- // CommandLineFlag::Read even though we left it in a moved-from state
- // after std::move.
- //
- // All of this serves to avoid requiring `T` being default constructible.
+ // See implementation notes in CommandLineFlag::Get().
union U {
T value;
U() {}
@@ -75,97 +614,133 @@
};
U u;
- Read(&u.value, &flags_internal::FlagOps<T>);
+#if !defined(NDEBUG)
+ impl_.AssertValidType(base_internal::FastTypeId<T>(), &GenRuntimeTypeId<T>);
+#endif
+
+ if (ABSL_PREDICT_FALSE(!value_.Get(impl_.seq_lock_, u.value))) {
+ impl_.Read(&u.value);
+ }
return std::move(u.value);
}
-
- bool AtomicGet(T* v) const {
- const int64_t r = atomic_.load(std::memory_order_acquire);
- if (r != flags_internal::AtomicInit()) {
- std::memcpy(v, &r, sizeof(T));
- return true;
- }
-
- return false;
+ void Set(const T& v) {
+ impl_.AssertValidType(base_internal::FastTypeId<T>(), &GenRuntimeTypeId<T>);
+ impl_.Write(&v);
}
- void Set(const T& v) { Write(&v, &flags_internal::FlagOps<T>); }
-
- void SetCallback(const flags_internal::FlagCallback mutation_callback) {
- absl::MutexLock l(InitFlagIfNecessary());
-
- callback_ = mutation_callback;
-
- InvokeCallback();
- }
- void InvokeCallback() override
- ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) {
- flags_internal::InvokeCallback(&locks_->primary_mu, &locks_->callback_mu,
- callback_);
- }
-
- private:
- void Destroy() const override {
- // Values are heap allocated Abseil Flags.
- if (cur_) Delete(op_, cur_);
- if (def_) Delete(op_, def_);
-
- delete locks_;
- }
-
- void StoreAtomic() override {
- if (sizeof(T) <= sizeof(int64_t)) {
- int64_t t = 0;
- std::memcpy(&t, cur_, (std::min)(sizeof(T), sizeof(int64_t)));
- atomic_.store(t, std::memory_order_release);
- }
- }
+ // Access to the reflection.
+ const CommandLineFlag& Reflect() const { return impl_; }
// Flag's data
- // For some types, a copy of the current value is kept in an atomically
- // accessible field.
- std::atomic<int64_t> atomic_;
- FlagCallback callback_; // Mutation callback
+ // The implementation depends on value_ field to be placed exactly after the
+ // impl_ field, so that impl_ can figure out the offset to the value and
+ // access it.
+ FlagImpl impl_;
+ FlagValue<T> value_;
};
+///////////////////////////////////////////////////////////////////////////////
+// Trampoline for friend access
+
+class FlagImplPeer {
+ public:
+ template <typename T, typename FlagType>
+ static T InvokeGet(const FlagType& flag) {
+ return flag.Get();
+ }
+ template <typename FlagType, typename T>
+ static void InvokeSet(FlagType& flag, const T& v) {
+ flag.Set(v);
+ }
+ template <typename FlagType>
+ static const CommandLineFlag& InvokeReflect(const FlagType& f) {
+ return f.Reflect();
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Implementation of Flag value specific operations routine.
+template <typename T>
+void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3) {
+ switch (op) {
+ case FlagOp::kAlloc: {
+ std::allocator<T> alloc;
+ return std::allocator_traits<std::allocator<T>>::allocate(alloc, 1);
+ }
+ case FlagOp::kDelete: {
+ T* p = static_cast<T*>(v2);
+ p->~T();
+ std::allocator<T> alloc;
+ std::allocator_traits<std::allocator<T>>::deallocate(alloc, p, 1);
+ return nullptr;
+ }
+ case FlagOp::kCopy:
+ *static_cast<T*>(v2) = *static_cast<const T*>(v1);
+ return nullptr;
+ case FlagOp::kCopyConstruct:
+ new (v2) T(*static_cast<const T*>(v1));
+ return nullptr;
+ case FlagOp::kSizeof:
+ return reinterpret_cast<void*>(static_cast<uintptr_t>(sizeof(T)));
+ case FlagOp::kFastTypeId:
+ return const_cast<void*>(base_internal::FastTypeId<T>());
+ case FlagOp::kRuntimeTypeId:
+ return const_cast<std::type_info*>(GenRuntimeTypeId<T>());
+ case FlagOp::kParse: {
+ // Initialize the temporary instance of type T based on current value in
+ // destination (which is going to be flag's default value).
+ T temp(*static_cast<T*>(v2));
+ if (!absl::ParseFlag<T>(*static_cast<const absl::string_view*>(v1), &temp,
+ static_cast<std::string*>(v3))) {
+ return nullptr;
+ }
+ *static_cast<T*>(v2) = std::move(temp);
+ return v2;
+ }
+ case FlagOp::kUnparse:
+ *static_cast<std::string*>(v2) =
+ absl::UnparseFlag<T>(*static_cast<const T*>(v1));
+ return nullptr;
+ case FlagOp::kValueOffset: {
+ // Round sizeof(FlagImp) to a multiple of alignof(FlagValue<T>) to get the
+ // offset of the data.
+ ptrdiff_t round_to = alignof(FlagValue<T>);
+ ptrdiff_t offset =
+ (sizeof(FlagImpl) + round_to - 1) / round_to * round_to;
+ return reinterpret_cast<void*>(offset);
+ }
+ }
+ return nullptr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
// This class facilitates Flag object registration and tail expression-based
// flag definition, for example:
// ABSL_FLAG(int, foo, 42, "Foo help").OnUpdate(NotifyFooWatcher);
+struct FlagRegistrarEmpty {};
template <typename T, bool do_register>
class FlagRegistrar {
public:
- explicit FlagRegistrar(Flag<T>* flag) : flag_(flag) {
- if (do_register) flags_internal::RegisterCommandLineFlag(flag_);
+ explicit FlagRegistrar(Flag<T>& flag) : flag_(flag) {
+ if (do_register) flags_internal::RegisterCommandLineFlag(flag_.impl_);
}
- FlagRegistrar& OnUpdate(flags_internal::FlagCallback cb) && {
- flag_->SetCallback(cb);
+ FlagRegistrar OnUpdate(FlagCallbackFunc cb) && {
+ flag_.impl_.SetCallback(cb);
return *this;
}
- // Make the registrar "die" gracefully as a bool on a line where registration
- // happens. Registrar objects are intended to live only as temporary.
- operator bool() const { return true; } // NOLINT
+ // Make the registrar "die" gracefully as an empty struct on a line where
+ // registration happens. Registrar objects are intended to live only as
+ // temporary.
+ operator FlagRegistrarEmpty() const { return {}; } // NOLINT
private:
- Flag<T>* flag_; // Flag being registered (not owned).
+ Flag<T>& flag_; // Flag being registered (not owned).
};
-// This struct and corresponding overload to MakeDefaultValue are used to
-// facilitate usage of {} as default value in ABSL_FLAG macro.
-struct EmptyBraces {};
-
-template <typename T>
-T* MakeFromDefaultValue(T t) {
- return new T(std::move(t));
-}
-
-template <typename T>
-T* MakeFromDefaultValue(EmptyBraces) {
- return new T;
-}
-
} // namespace flags_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_FLAGS_INTERNAL_FLAG_H_
diff --git a/third_party/abseil/absl/flags/internal/parse.h b/third_party/abseil/absl/flags/internal/parse.h
index fd3aca6..de706c8 100644
--- a/third_party/abseil/absl/flags/internal/parse.h
+++ b/third_party/abseil/absl/flags/internal/parse.h
@@ -19,7 +19,9 @@
#include <string>
#include <vector>
+#include "absl/base/config.h"
#include "absl/flags/declare.h"
+#include "absl/strings/string_view.h"
ABSL_DECLARE_FLAG(std::vector<std::string>, flagfile);
ABSL_DECLARE_FLAG(std::vector<std::string>, fromenv);
@@ -27,6 +29,7 @@
ABSL_DECLARE_FLAG(std::vector<std::string>, undefok);
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace flags_internal {
enum class ArgvListAction { kRemoveParsedArgs, kKeepParsedArgs };
@@ -42,7 +45,15 @@
UsageFlagsAction usage_flag_act,
OnUndefinedFlag on_undef_flag);
+// --------------------------------------------------------------------
+// Inspect original command line
+
+// Returns true if flag with specified name was either present on the original
+// command line or specified in flag file present on the original command line.
+bool WasPresentOnCommandLine(absl::string_view flag_name);
+
} // namespace flags_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_FLAGS_INTERNAL_PARSE_H_
diff --git a/third_party/abseil/absl/flags/internal/path_util.h b/third_party/abseil/absl/flags/internal/path_util.h
index 5615c0e..a6594d3 100644
--- a/third_party/abseil/absl/flags/internal/path_util.h
+++ b/third_party/abseil/absl/flags/internal/path_util.h
@@ -16,10 +16,11 @@
#ifndef ABSL_FLAGS_INTERNAL_PATH_UTIL_H_
#define ABSL_FLAGS_INTERNAL_PATH_UTIL_H_
-#include "absl/strings/match.h"
+#include "absl/base/config.h"
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace flags_internal {
// A portable interface that returns the basename of the filename passed as an
@@ -55,6 +56,7 @@
}
} // namespace flags_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_FLAGS_INTERNAL_PATH_UTIL_H_
diff --git a/third_party/abseil/absl/flags/internal/private_handle_accessor.cc b/third_party/abseil/absl/flags/internal/private_handle_accessor.cc
new file mode 100644
index 0000000..a7eb58b
--- /dev/null
+++ b/third_party/abseil/absl/flags/internal/private_handle_accessor.cc
@@ -0,0 +1,65 @@
+//
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/flags/internal/private_handle_accessor.h"
+
+#include <memory>
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/flags/commandlineflag.h"
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace flags_internal {
+
+FlagFastTypeId PrivateHandleAccessor::TypeId(const CommandLineFlag& flag) {
+ return flag.TypeId();
+}
+
+std::unique_ptr<FlagStateInterface> PrivateHandleAccessor::SaveState(
+ CommandLineFlag& flag) {
+ return flag.SaveState();
+}
+
+bool PrivateHandleAccessor::IsSpecifiedOnCommandLine(
+ const CommandLineFlag& flag) {
+ return flag.IsSpecifiedOnCommandLine();
+}
+
+bool PrivateHandleAccessor::ValidateInputValue(const CommandLineFlag& flag,
+ absl::string_view value) {
+ return flag.ValidateInputValue(value);
+}
+
+void PrivateHandleAccessor::CheckDefaultValueParsingRoundtrip(
+ const CommandLineFlag& flag) {
+ flag.CheckDefaultValueParsingRoundtrip();
+}
+
+bool PrivateHandleAccessor::ParseFrom(CommandLineFlag& flag,
+ absl::string_view value,
+ flags_internal::FlagSettingMode set_mode,
+ flags_internal::ValueSource source,
+ std::string& error) {
+ return flag.ParseFrom(value, set_mode, source, error);
+}
+
+} // namespace flags_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
diff --git a/third_party/abseil/absl/flags/internal/private_handle_accessor.h b/third_party/abseil/absl/flags/internal/private_handle_accessor.h
new file mode 100644
index 0000000..c64435c
--- /dev/null
+++ b/third_party/abseil/absl/flags/internal/private_handle_accessor.h
@@ -0,0 +1,61 @@
+//
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_FLAGS_INTERNAL_PRIVATE_HANDLE_ACCESSOR_H_
+#define ABSL_FLAGS_INTERNAL_PRIVATE_HANDLE_ACCESSOR_H_
+
+#include <memory>
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/flags/commandlineflag.h"
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace flags_internal {
+
+// This class serves as a trampoline to access private methods of
+// CommandLineFlag. This class is intended for use exclusively internally inside
+// of the Abseil Flags implementation.
+class PrivateHandleAccessor {
+ public:
+ // Access to CommandLineFlag::TypeId.
+ static FlagFastTypeId TypeId(const CommandLineFlag& flag);
+
+ // Access to CommandLineFlag::SaveState.
+ static std::unique_ptr<FlagStateInterface> SaveState(CommandLineFlag& flag);
+
+ // Access to CommandLineFlag::IsSpecifiedOnCommandLine.
+ static bool IsSpecifiedOnCommandLine(const CommandLineFlag& flag);
+
+ // Access to CommandLineFlag::ValidateInputValue.
+ static bool ValidateInputValue(const CommandLineFlag& flag,
+ absl::string_view value);
+
+ // Access to CommandLineFlag::CheckDefaultValueParsingRoundtrip.
+ static void CheckDefaultValueParsingRoundtrip(const CommandLineFlag& flag);
+
+ static bool ParseFrom(CommandLineFlag& flag, absl::string_view value,
+ flags_internal::FlagSettingMode set_mode,
+ flags_internal::ValueSource source, std::string& error);
+};
+
+} // namespace flags_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_FLAGS_INTERNAL_PRIVATE_HANDLE_ACCESSOR_H_
diff --git a/third_party/abseil/absl/flags/internal/program_name.cc b/third_party/abseil/absl/flags/internal/program_name.cc
index f0811f1..51d698d 100644
--- a/third_party/abseil/absl/flags/internal/program_name.cc
+++ b/third_party/abseil/absl/flags/internal/program_name.cc
@@ -17,10 +17,16 @@
#include <string>
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/const_init.h"
+#include "absl/base/thread_annotations.h"
#include "absl/flags/internal/path_util.h"
+#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace flags_internal {
ABSL_CONST_INIT static absl::Mutex program_name_guard(absl::kConstInit);
@@ -50,4 +56,5 @@
}
} // namespace flags_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/flags/internal/program_name.h b/third_party/abseil/absl/flags/internal/program_name.h
index 326f24b..b99b94f 100644
--- a/third_party/abseil/absl/flags/internal/program_name.h
+++ b/third_party/abseil/absl/flags/internal/program_name.h
@@ -18,12 +18,14 @@
#include <string>
+#include "absl/base/config.h"
#include "absl/strings/string_view.h"
// --------------------------------------------------------------------
// Program name
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace flags_internal {
// Returns program invocation name or "UNKNOWN" if `SetProgramInvocationName()`
@@ -42,6 +44,7 @@
void SetProgramInvocationName(absl::string_view prog_name_str);
} // namespace flags_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_FLAGS_INTERNAL_PROGRAM_NAME_H_
diff --git a/third_party/abseil/absl/flags/internal/program_name_test.cc b/third_party/abseil/absl/flags/internal/program_name_test.cc
index ed69218..aff9f63 100644
--- a/third_party/abseil/absl/flags/internal/program_name_test.cc
+++ b/third_party/abseil/absl/flags/internal/program_name_test.cc
@@ -15,14 +15,17 @@
#include "absl/flags/internal/program_name.h"
+#include <string>
+
#include "gtest/gtest.h"
#include "absl/strings/match.h"
+#include "absl/strings/string_view.h"
namespace {
namespace flags = absl::flags_internal;
-TEST(FlagsPathUtilTest, TestInitialProgamName) {
+TEST(FlagsPathUtilTest, TestProgamNameInterfaces) {
flags::SetProgramInvocationName("absl/flags/program_name_test");
std::string program_name = flags::ProgramInvocationName();
for (char& c : program_name)
@@ -40,9 +43,7 @@
EXPECT_TRUE(absl::EndsWith(program_name, expect_name)) << program_name;
EXPECT_EQ(flags::ShortProgramInvocationName(), expect_basename);
-}
-TEST(FlagsPathUtilTest, TestProgamNameInterfaces) {
flags::SetProgramInvocationName("a/my_test");
EXPECT_EQ(flags::ProgramInvocationName(), "a/my_test");
diff --git a/third_party/abseil/absl/flags/internal/registry.cc b/third_party/abseil/absl/flags/internal/registry.cc
deleted file mode 100644
index 4bea313..0000000
--- a/third_party/abseil/absl/flags/internal/registry.cc
+++ /dev/null
@@ -1,404 +0,0 @@
-//
-// Copyright 2019 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/flags/internal/registry.h"
-
-#include "absl/base/dynamic_annotations.h"
-#include "absl/base/internal/raw_logging.h"
-#include "absl/flags/config.h"
-#include "absl/flags/usage_config.h"
-#include "absl/strings/str_cat.h"
-#include "absl/strings/string_view.h"
-#include "absl/synchronization/mutex.h"
-
-// --------------------------------------------------------------------
-// FlagRegistry implementation
-// A FlagRegistry holds all flag objects indexed
-// by their names so that if you know a flag's name you can access or
-// set it.
-
-namespace absl {
-namespace flags_internal {
-
-// --------------------------------------------------------------------
-// FlagRegistry
-// A FlagRegistry singleton object holds all flag objects indexed
-// by their names so that if you know a flag's name (as a C
-// string), you can access or set it. If the function is named
-// FooLocked(), you must own the registry lock before calling
-// the function; otherwise, you should *not* hold the lock, and
-// the function will acquire it itself if needed.
-// --------------------------------------------------------------------
-
-class FlagRegistry {
- public:
- FlagRegistry() = default;
- ~FlagRegistry() {
- for (auto& p : flags_) {
- p.second->Destroy();
- }
- }
-
- // Store a flag in this registry. Takes ownership of *flag.
- void RegisterFlag(CommandLineFlag* flag);
-
- void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION(lock_) { lock_.Lock(); }
- void Unlock() ABSL_UNLOCK_FUNCTION(lock_) { lock_.Unlock(); }
-
- // Returns the flag object for the specified name, or nullptr if not found.
- // Will emit a warning if a 'retired' flag is specified.
- CommandLineFlag* FindFlagLocked(absl::string_view name);
-
- // Returns the retired flag object for the specified name, or nullptr if not
- // found or not retired. Does not emit a warning.
- CommandLineFlag* FindRetiredFlagLocked(absl::string_view name);
-
- static FlagRegistry* GlobalRegistry(); // returns a singleton registry
-
- private:
- friend class FlagSaverImpl; // reads all the flags in order to copy them
- friend void ForEachFlagUnlocked(
- std::function<void(CommandLineFlag*)> visitor);
-
- // The map from name to flag, for FindFlagLocked().
- using FlagMap = std::map<absl::string_view, CommandLineFlag*>;
- using FlagIterator = FlagMap::iterator;
- using FlagConstIterator = FlagMap::const_iterator;
- FlagMap flags_;
-
- absl::Mutex lock_;
-
- // Disallow
- FlagRegistry(const FlagRegistry&);
- FlagRegistry& operator=(const FlagRegistry&);
-};
-
-FlagRegistry* FlagRegistry::GlobalRegistry() {
- static FlagRegistry* global_registry = new FlagRegistry;
- return global_registry;
-}
-
-namespace {
-
-class FlagRegistryLock {
- public:
- explicit FlagRegistryLock(FlagRegistry* fr) : fr_(fr) { fr_->Lock(); }
- ~FlagRegistryLock() { fr_->Unlock(); }
-
- private:
- FlagRegistry* const fr_;
-};
-
-} // namespace
-
-void FlagRegistry::RegisterFlag(CommandLineFlag* flag) {
- FlagRegistryLock registry_lock(this);
- std::pair<FlagIterator, bool> ins =
- flags_.insert(FlagMap::value_type(flag->Name(), flag));
- if (ins.second == false) { // means the name was already in the map
- CommandLineFlag* old_flag = ins.first->second;
- if (flag->IsRetired() != old_flag->IsRetired()) {
- // All registrations must agree on the 'retired' flag.
- flags_internal::ReportUsageError(
- absl::StrCat(
- "Retired flag '", flag->Name(),
- "' was defined normally in file '",
- (flag->IsRetired() ? old_flag->Filename() : flag->Filename()),
- "'."),
- true);
- } else if (flag->op_ != old_flag->op_) {
- flags_internal::ReportUsageError(
- absl::StrCat("Flag '", flag->Name(),
- "' was defined more than once but with "
- "differing types. Defined in files '",
- old_flag->Filename(), "' and '", flag->Filename(),
- "' with types '", old_flag->Typename(), "' and '",
- flag->Typename(), "', respectively."),
- true);
- } else if (old_flag->IsRetired()) {
- // Retired definitions are idempotent. Just keep the old one.
- flag->Destroy();
- return;
- } else if (old_flag->Filename() != flag->Filename()) {
- flags_internal::ReportUsageError(
- absl::StrCat("Flag '", flag->Name(),
- "' was defined more than once (in files '",
- old_flag->Filename(), "' and '", flag->Filename(),
- "')."),
- true);
- } else {
- flags_internal::ReportUsageError(
- absl::StrCat(
- "Something wrong with flag '", flag->Name(), "' in file '",
- flag->Filename(), "'. One possibility: file '", flag->Filename(),
- "' is being linked both statically and dynamically into this "
- "executable. e.g. some files listed as srcs to a test and also "
- "listed as srcs of some shared lib deps of the same test."),
- true);
- }
- // All cases above are fatal, except for the retired flags.
- std::exit(1);
- }
-}
-
-CommandLineFlag* FlagRegistry::FindFlagLocked(absl::string_view name) {
- FlagConstIterator i = flags_.find(name);
- if (i == flags_.end()) {
- return nullptr;
- }
-
- if (i->second->IsRetired()) {
- flags_internal::ReportUsageError(
- absl::StrCat("Accessing retired flag '", name, "'"), false);
- }
-
- return i->second;
-}
-
-CommandLineFlag* FlagRegistry::FindRetiredFlagLocked(absl::string_view name) {
- FlagConstIterator i = flags_.find(name);
- if (i == flags_.end() || !i->second->IsRetired()) {
- return nullptr;
- }
-
- return i->second;
-}
-
-// --------------------------------------------------------------------
-// FlagSaver
-// FlagSaverImpl
-// This class stores the states of all flags at construct time,
-// and restores all flags to that state at destruct time.
-// Its major implementation challenge is that it never modifies
-// pointers in the 'main' registry, so global FLAG_* vars always
-// point to the right place.
-// --------------------------------------------------------------------
-
-class FlagSaverImpl {
- public:
- // Constructs an empty FlagSaverImpl object.
- FlagSaverImpl() {}
- ~FlagSaverImpl() {
- // reclaim memory from each of our CommandLineFlags
- for (const SavedFlag& src : backup_registry_) {
- Delete(src.op, src.current);
- Delete(src.op, src.default_value);
- }
- }
-
- // Saves the flag states from the flag registry into this object.
- // It's an error to call this more than once.
- // Must be called when the registry mutex is not held.
- void SaveFromRegistry() {
- assert(backup_registry_.empty()); // call only once!
- SavedFlag saved;
- flags_internal::ForEachFlag([&](flags_internal::CommandLineFlag* flag) {
- if (flag->IsRetired()) return;
-
- saved.name = flag->Name();
- saved.op = flag->op_;
- saved.marshalling_op = flag->marshalling_op_;
- {
- absl::MutexLock l(flag->InitFlagIfNecessary());
- saved.validator = flag->GetValidator();
- saved.modified = flag->modified_;
- saved.on_command_line = flag->on_command_line_;
- saved.current = Clone(saved.op, flag->cur_);
- saved.default_value = Clone(saved.op, flag->def_);
- saved.counter = flag->counter_;
- }
- backup_registry_.push_back(saved);
- });
- }
-
- // Restores the saved flag states into the flag registry. We
- // assume no flags were added or deleted from the registry since
- // the SaveFromRegistry; if they were, that's trouble! Must be
- // called when the registry mutex is not held.
- void RestoreToRegistry() {
- FlagRegistry* const global_registry = FlagRegistry::GlobalRegistry();
- FlagRegistryLock frl(global_registry);
- for (const SavedFlag& src : backup_registry_) {
- CommandLineFlag* flag = global_registry->FindFlagLocked(src.name);
- // If null, flag got deleted from registry.
- if (!flag) continue;
-
- bool restored = false;
- {
- // This function encapsulate the lock.
- flag->SetValidator(src.validator);
-
- absl::MutexLock l(flag->InitFlagIfNecessary());
- flag->modified_ = src.modified;
- flag->on_command_line_ = src.on_command_line;
- if (flag->counter_ != src.counter ||
- ChangedDirectly(flag, src.default_value, flag->def_)) {
- restored = true;
- Copy(src.op, src.default_value, flag->def_);
- }
- if (flag->counter_ != src.counter ||
- ChangedDirectly(flag, src.current, flag->cur_)) {
- restored = true;
- Copy(src.op, src.current, flag->cur_);
- UpdateCopy(flag);
- flag->InvokeCallback();
- }
- }
-
- if (restored) {
- flag->counter_++;
-
- // Revalidate the flag because the validator might store state based
- // on the flag's value, which just changed due to the restore.
- // Failing validation is ignored because it's assumed that the flag
- // was valid previously and there's little that can be done about it
- // here, anyway.
- flag->ValidateInputValue(flag->CurrentValue());
-
- ABSL_INTERNAL_LOG(
- INFO, absl::StrCat("Restore saved value of ", flag->Name(), ": ",
- Unparse(src.marshalling_op, src.current)));
- }
- }
- }
-
- private:
- struct SavedFlag {
- absl::string_view name;
- FlagOpFn op;
- FlagMarshallingOpFn marshalling_op;
- int64_t counter;
- void* validator;
- bool modified;
- bool on_command_line;
- const void* current; // nullptr after restore
- const void* default_value; // nullptr after restore
- };
-
- std::vector<SavedFlag> backup_registry_;
-
- FlagSaverImpl(const FlagSaverImpl&); // no copying!
- void operator=(const FlagSaverImpl&);
-};
-
-FlagSaver::FlagSaver() : impl_(new FlagSaverImpl()) {
- impl_->SaveFromRegistry();
-}
-
-void FlagSaver::Ignore() {
- delete impl_;
- impl_ = nullptr;
-}
-
-FlagSaver::~FlagSaver() {
- if (!impl_) return;
-
- impl_->RestoreToRegistry();
- delete impl_;
-}
-
-// --------------------------------------------------------------------
-
-CommandLineFlag* FindCommandLineFlag(absl::string_view name) {
- if (name.empty()) return nullptr;
- FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
- FlagRegistryLock frl(registry);
-
- return registry->FindFlagLocked(name);
-}
-
-CommandLineFlag* FindRetiredFlag(absl::string_view name) {
- FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
- FlagRegistryLock frl(registry);
-
- return registry->FindRetiredFlagLocked(name);
-}
-
-// --------------------------------------------------------------------
-
-void ForEachFlagUnlocked(std::function<void(CommandLineFlag*)> visitor) {
- FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
- for (FlagRegistry::FlagConstIterator i = registry->flags_.begin();
- i != registry->flags_.end(); ++i) {
- visitor(i->second);
- }
-}
-
-void ForEachFlag(std::function<void(CommandLineFlag*)> visitor) {
- FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
- FlagRegistryLock frl(registry);
- ForEachFlagUnlocked(visitor);
-}
-
-// --------------------------------------------------------------------
-
-bool RegisterCommandLineFlag(CommandLineFlag* flag) {
- FlagRegistry::GlobalRegistry()->RegisterFlag(flag);
- return true;
-}
-
-// --------------------------------------------------------------------
-
-namespace {
-
-class RetiredFlagObj final : public flags_internal::CommandLineFlag {
- public:
- constexpr RetiredFlagObj(const char* name, FlagOpFn ops,
- FlagMarshallingOpFn marshalling_ops)
- : flags_internal::CommandLineFlag(
- name, flags_internal::HelpText::FromStaticCString(nullptr),
- /*filename=*/"RETIRED", ops, marshalling_ops,
- /*initial_value_gen=*/nullptr,
- /*def=*/nullptr,
- /*cur=*/nullptr) {}
-
- private:
- bool IsRetired() const override { return true; }
-
- void Destroy() const override {
- // Values are heap allocated for Retired Flags.
- if (cur_) Delete(op_, cur_);
- if (def_) Delete(op_, def_);
-
- if (locks_) delete locks_;
-
- delete this;
- }
-};
-
-} // namespace
-
-bool Retire(const char* name, FlagOpFn ops,
- FlagMarshallingOpFn marshalling_ops) {
- auto* flag = new flags_internal::RetiredFlagObj(name, ops, marshalling_ops);
- FlagRegistry::GlobalRegistry()->RegisterFlag(flag);
- return true;
-}
-
-// --------------------------------------------------------------------
-
-bool IsRetiredFlag(absl::string_view name, bool* type_is_bool) {
- assert(!name.empty());
- CommandLineFlag* flag = flags_internal::FindRetiredFlag(name);
- if (flag == nullptr) {
- return false;
- }
- assert(type_is_bool);
- *type_is_bool = flag->IsOfType<bool>();
- return true;
-}
-
-} // namespace flags_internal
-} // namespace absl
diff --git a/third_party/abseil/absl/flags/internal/registry.h b/third_party/abseil/absl/flags/internal/registry.h
index eb134a9..a8d9eb9 100644
--- a/third_party/abseil/absl/flags/internal/registry.h
+++ b/third_party/abseil/absl/flags/internal/registry.h
@@ -17,31 +17,28 @@
#define ABSL_FLAGS_INTERNAL_REGISTRY_H_
#include <functional>
-#include <map>
-#include <string>
-#include "absl/base/macros.h"
+#include "absl/base/config.h"
+#include "absl/flags/commandlineflag.h"
#include "absl/flags/internal/commandlineflag.h"
+#include "absl/strings/string_view.h"
// --------------------------------------------------------------------
// Global flags registry API.
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace flags_internal {
-CommandLineFlag* FindCommandLineFlag(absl::string_view name);
-CommandLineFlag* FindRetiredFlag(absl::string_view name);
-
-// Executes specified visitor for each non-retired flag in the registry.
-// Requires the caller hold the registry lock.
-void ForEachFlagUnlocked(std::function<void(CommandLineFlag*)> visitor);
// Executes specified visitor for each non-retired flag in the registry. While
// callback are executed, the registry is locked and can't be changed.
-void ForEachFlag(std::function<void(CommandLineFlag*)> visitor);
+void ForEachFlag(std::function<void(CommandLineFlag&)> visitor);
//-----------------------------------------------------------------------------
-bool RegisterCommandLineFlag(CommandLineFlag*);
+bool RegisterCommandLineFlag(CommandLineFlag&);
+
+void FinalizeRegistry();
//-----------------------------------------------------------------------------
// Retired registrations:
@@ -76,47 +73,25 @@
//
// Retire flag with name "name" and type indicated by ops.
-bool Retire(const char* name, FlagOpFn ops,
- FlagMarshallingOpFn marshalling_ops);
+void Retire(const char* name, FlagFastTypeId type_id, char* buf);
+
+constexpr size_t kRetiredFlagObjSize = 3 * sizeof(void*);
+constexpr size_t kRetiredFlagObjAlignment = alignof(void*);
// Registered a retired flag with name 'flag_name' and type 'T'.
template <typename T>
-inline bool RetiredFlag(const char* flag_name) {
- return flags_internal::Retire(flag_name, flags_internal::FlagOps<T>,
- flags_internal::FlagMarshallingOps<T>);
-}
-
-// If the flag is retired, returns true and indicates in |*type_is_bool|
-// whether the type of the retired flag is a bool.
-// Only to be called by code that needs to explicitly ignore retired flags.
-bool IsRetiredFlag(absl::string_view name, bool* type_is_bool);
-
-//-----------------------------------------------------------------------------
-// Saves the states (value, default value, whether the user has set
-// the flag, registered validators, etc) of all flags, and restores
-// them when the FlagSaver is destroyed.
-//
-// This class is thread-safe. However, its destructor writes to
-// exactly the set of flags that have changed value during its
-// lifetime, so concurrent _direct_ access to those flags
-// (i.e. FLAGS_foo instead of {Get,Set}CommandLineOption()) is unsafe.
-
-class FlagSaver {
+class RetiredFlag {
public:
- FlagSaver();
- ~FlagSaver();
-
- FlagSaver(const FlagSaver&) = delete;
- void operator=(const FlagSaver&) = delete;
-
- // Prevents saver from restoring the saved state of flags.
- void Ignore();
+ void Retire(const char* flag_name) {
+ flags_internal::Retire(flag_name, base_internal::FastTypeId<T>(), buf_);
+ }
private:
- class FlagSaverImpl* impl_; // we use pimpl here to keep API steady
+ alignas(kRetiredFlagObjAlignment) char buf_[kRetiredFlagObjSize];
};
} // namespace flags_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_FLAGS_INTERNAL_REGISTRY_H_
diff --git a/third_party/abseil/absl/flags/internal/sequence_lock.h b/third_party/abseil/absl/flags/internal/sequence_lock.h
new file mode 100644
index 0000000..807b2a7
--- /dev/null
+++ b/third_party/abseil/absl/flags/internal/sequence_lock.h
@@ -0,0 +1,187 @@
+//
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_FLAGS_INTERNAL_SEQUENCE_LOCK_H_
+#define ABSL_FLAGS_INTERNAL_SEQUENCE_LOCK_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <atomic>
+#include <cassert>
+#include <cstring>
+
+#include "absl/base/optimization.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace flags_internal {
+
+// Align 'x' up to the nearest 'align' bytes.
+inline constexpr size_t AlignUp(size_t x, size_t align) {
+ return align * ((x + align - 1) / align);
+}
+
+// A SequenceLock implements lock-free reads. A sequence counter is incremented
+// before and after each write, and readers access the counter before and after
+// accessing the protected data. If the counter is verified to not change during
+// the access, and the sequence counter value was even, then the reader knows
+// that the read was race-free and valid. Otherwise, the reader must fall back
+// to a Mutex-based code path.
+//
+// This particular SequenceLock starts in an "uninitialized" state in which
+// TryRead() returns false. It must be enabled by calling MarkInitialized().
+// This serves as a marker that the associated flag value has not yet been
+// initialized and a slow path needs to be taken.
+//
+// The memory reads and writes protected by this lock must use the provided
+// `TryRead()` and `Write()` functions. These functions behave similarly to
+// `memcpy()`, with one oddity: the protected data must be an array of
+// `std::atomic<int64>`. This is to comply with the C++ standard, which
+// considers data races on non-atomic objects to be undefined behavior. See "Can
+// Seqlocks Get Along With Programming Language Memory Models?"[1] by Hans J.
+// Boehm for more details.
+//
+// [1] https://www.hpl.hp.com/techreports/2012/HPL-2012-68.pdf
+class SequenceLock {
+ public:
+ constexpr SequenceLock() : lock_(kUninitialized) {}
+
+ // Mark that this lock is ready for use.
+ void MarkInitialized() {
+ assert(lock_.load(std::memory_order_relaxed) == kUninitialized);
+ lock_.store(0, std::memory_order_release);
+ }
+
+ // Copy "size" bytes of data from "src" to "dst", protected as a read-side
+ // critical section of the sequence lock.
+ //
+ // Unlike traditional sequence lock implementations which loop until getting a
+ // clean read, this implementation returns false in the case of concurrent
+ // calls to `Write`. In such a case, the caller should fall back to a
+ // locking-based slow path.
+ //
+ // Returns false if the sequence lock was not yet marked as initialized.
+ //
+ // NOTE: If this returns false, "dst" may be overwritten with undefined
+ // (potentially uninitialized) data.
+ bool TryRead(void* dst, const std::atomic<uint64_t>* src, size_t size) const {
+ // Acquire barrier ensures that no loads done by f() are reordered
+ // above the first load of the sequence counter.
+ int64_t seq_before = lock_.load(std::memory_order_acquire);
+ if (ABSL_PREDICT_FALSE(seq_before & 1) == 1) return false;
+ RelaxedCopyFromAtomic(dst, src, size);
+ // Another acquire fence ensures that the load of 'lock_' below is
+ // strictly ordered after the RelaxedCopyToAtomic call above.
+ std::atomic_thread_fence(std::memory_order_acquire);
+ int64_t seq_after = lock_.load(std::memory_order_relaxed);
+ return ABSL_PREDICT_TRUE(seq_before == seq_after);
+ }
+
+ // Copy "size" bytes from "src" to "dst" as a write-side critical section
+ // of the sequence lock. Any concurrent readers will be forced to retry
+ // until they get a read that does not conflict with this write.
+ //
+ // This call must be externally synchronized against other calls to Write,
+ // but may proceed concurrently with reads.
+ void Write(std::atomic<uint64_t>* dst, const void* src, size_t size) {
+ // We can use relaxed instructions to increment the counter since we
+ // are extenally synchronized. The std::atomic_thread_fence below
+ // ensures that the counter updates don't get interleaved with the
+ // copy to the data.
+ int64_t orig_seq = lock_.load(std::memory_order_relaxed);
+ assert((orig_seq & 1) == 0); // Must be initially unlocked.
+ lock_.store(orig_seq + 1, std::memory_order_relaxed);
+
+ // We put a release fence between update to lock_ and writes to shared data.
+ // Thus all stores to shared data are effectively release operations and
+ // update to lock_ 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);
+ RelaxedCopyToAtomic(dst, src, size);
+ // "Release" semantics ensure that none of the writes done by
+ // RelaxedCopyToAtomic() can be reordered after the following modification.
+ lock_.store(orig_seq + 2, std::memory_order_release);
+ }
+
+ // Return the number of times that Write() has been called.
+ //
+ // REQUIRES: This must be externally synchronized against concurrent calls to
+ // `Write()` or `IncrementModificationCount()`.
+ // REQUIRES: `MarkInitialized()` must have been previously called.
+ int64_t ModificationCount() const {
+ int64_t val = lock_.load(std::memory_order_relaxed);
+ assert(val != kUninitialized && (val & 1) == 0);
+ return val / 2;
+ }
+
+ // REQUIRES: This must be externally synchronized against concurrent calls to
+ // `Write()` or `ModificationCount()`.
+ // REQUIRES: `MarkInitialized()` must have been previously called.
+ void IncrementModificationCount() {
+ int64_t val = lock_.load(std::memory_order_relaxed);
+ assert(val != kUninitialized);
+ lock_.store(val + 2, std::memory_order_relaxed);
+ }
+
+ private:
+ // Perform the equivalent of "memcpy(dst, src, size)", but using relaxed
+ // atomics.
+ static void RelaxedCopyFromAtomic(void* dst, const std::atomic<uint64_t>* src,
+ size_t size) {
+ char* dst_byte = static_cast<char*>(dst);
+ while (size >= sizeof(uint64_t)) {
+ uint64_t word = src->load(std::memory_order_relaxed);
+ std::memcpy(dst_byte, &word, sizeof(word));
+ dst_byte += sizeof(word);
+ src++;
+ size -= sizeof(word);
+ }
+ if (size > 0) {
+ uint64_t word = src->load(std::memory_order_relaxed);
+ std::memcpy(dst_byte, &word, size);
+ }
+ }
+
+ // Perform the equivalent of "memcpy(dst, src, size)", but using relaxed
+ // atomics.
+ static void RelaxedCopyToAtomic(std::atomic<uint64_t>* dst, const void* src,
+ size_t size) {
+ const char* src_byte = static_cast<const char*>(src);
+ while (size >= sizeof(uint64_t)) {
+ uint64_t word;
+ std::memcpy(&word, src_byte, sizeof(word));
+ dst->store(word, std::memory_order_relaxed);
+ src_byte += sizeof(word);
+ dst++;
+ size -= sizeof(word);
+ }
+ if (size > 0) {
+ uint64_t word = 0;
+ std::memcpy(&word, src_byte, size);
+ dst->store(word, std::memory_order_relaxed);
+ }
+ }
+
+ static constexpr int64_t kUninitialized = -1;
+ std::atomic<int64_t> lock_;
+};
+
+} // namespace flags_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_FLAGS_INTERNAL_SEQUENCE_LOCK_H_
diff --git a/third_party/abseil/absl/flags/internal/sequence_lock_test.cc b/third_party/abseil/absl/flags/internal/sequence_lock_test.cc
new file mode 100644
index 0000000..9aff1ed
--- /dev/null
+++ b/third_party/abseil/absl/flags/internal/sequence_lock_test.cc
@@ -0,0 +1,146 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "absl/flags/internal/sequence_lock.h"
+
+#include <atomic>
+#include <thread> // NOLINT(build/c++11)
+#include <tuple>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/sysinfo.h"
+#include "absl/container/fixed_array.h"
+#include "absl/time/clock.h"
+
+namespace {
+
+namespace flags = absl::flags_internal;
+
+class ConcurrentSequenceLockTest
+ : public testing::TestWithParam<std::tuple<int, int>> {
+ public:
+ ConcurrentSequenceLockTest()
+ : buf_bytes_(std::get<0>(GetParam())),
+ num_threads_(std::get<1>(GetParam())) {}
+
+ protected:
+ const int buf_bytes_;
+ const int num_threads_;
+};
+
+TEST_P(ConcurrentSequenceLockTest, ReadAndWrite) {
+ const int buf_words =
+ flags::AlignUp(buf_bytes_, sizeof(uint64_t)) / sizeof(uint64_t);
+
+ // The buffer that will be protected by the SequenceLock.
+ absl::FixedArray<std::atomic<uint64_t>> protected_buf(buf_words);
+ for (auto& v : protected_buf) v = -1;
+
+ flags::SequenceLock seq_lock;
+ std::atomic<bool> stop{false};
+ std::atomic<int64_t> bad_reads{0};
+ std::atomic<int64_t> good_reads{0};
+ std::atomic<int64_t> unsuccessful_reads{0};
+
+ // Start a bunch of threads which read 'protected_buf' under the sequence
+ // lock. The main thread will concurrently update 'protected_buf'. The updates
+ // always consist of an array of identical integers. The reader ensures that
+ // any data it reads matches that pattern (i.e. the reads are not "torn").
+ std::vector<std::thread> threads;
+ for (int i = 0; i < num_threads_; i++) {
+ threads.emplace_back([&]() {
+ absl::FixedArray<char> local_buf(buf_bytes_);
+ while (!stop.load(std::memory_order_relaxed)) {
+ if (seq_lock.TryRead(local_buf.data(), protected_buf.data(),
+ buf_bytes_)) {
+ bool good = true;
+ for (const auto& v : local_buf) {
+ if (v != local_buf[0]) good = false;
+ }
+ if (good) {
+ good_reads.fetch_add(1, std::memory_order_relaxed);
+ } else {
+ bad_reads.fetch_add(1, std::memory_order_relaxed);
+ }
+ } else {
+ unsuccessful_reads.fetch_add(1, std::memory_order_relaxed);
+ }
+ }
+ });
+ }
+ while (unsuccessful_reads.load(std::memory_order_relaxed) < num_threads_) {
+ absl::SleepFor(absl::Milliseconds(1));
+ }
+ seq_lock.MarkInitialized();
+
+ // Run a maximum of 5 seconds. On Windows, the scheduler behavior seems
+ // somewhat unfair and without an explicit timeout for this loop, the tests
+ // can run a long time.
+ absl::Time deadline = absl::Now() + absl::Seconds(5);
+ for (int i = 0; i < 100 && absl::Now() < deadline; i++) {
+ absl::FixedArray<char> writer_buf(buf_bytes_);
+ for (auto& v : writer_buf) v = i;
+ seq_lock.Write(protected_buf.data(), writer_buf.data(), buf_bytes_);
+ absl::SleepFor(absl::Microseconds(10));
+ }
+ stop.store(true, std::memory_order_relaxed);
+ for (auto& t : threads) t.join();
+ ASSERT_GE(good_reads, 0);
+ ASSERT_EQ(bad_reads, 0);
+}
+
+// Simple helper for generating a range of thread counts.
+// Generates [low, low*scale, low*scale^2, ...high)
+// (even if high is between low*scale^k and low*scale^(k+1)).
+std::vector<int> MultiplicativeRange(int low, int high, int scale) {
+ std::vector<int> result;
+ for (int current = low; current < high; current *= scale) {
+ result.push_back(current);
+ }
+ result.push_back(high);
+ return result;
+}
+
+INSTANTIATE_TEST_SUITE_P(TestManyByteSizes, ConcurrentSequenceLockTest,
+ testing::Combine(
+ // Buffer size (bytes).
+ testing::Range(1, 128),
+ // Number of reader threads.
+ testing::ValuesIn(MultiplicativeRange(
+ 1, absl::base_internal::NumCPUs(), 2))));
+
+// Simple single-threaded test, parameterized by the size of the buffer to be
+// protected.
+class SequenceLockTest : public testing::TestWithParam<int> {};
+
+TEST_P(SequenceLockTest, SingleThreaded) {
+ const int size = GetParam();
+ absl::FixedArray<std::atomic<uint64_t>> protected_buf(
+ flags::AlignUp(size, sizeof(uint64_t)) / sizeof(uint64_t));
+
+ flags::SequenceLock seq_lock;
+ seq_lock.MarkInitialized();
+
+ std::vector<char> src_buf(size, 'x');
+ seq_lock.Write(protected_buf.data(), src_buf.data(), size);
+
+ std::vector<char> dst_buf(size, '0');
+ ASSERT_TRUE(seq_lock.TryRead(dst_buf.data(), protected_buf.data(), size));
+ ASSERT_EQ(src_buf, dst_buf);
+}
+INSTANTIATE_TEST_SUITE_P(TestManyByteSizes, SequenceLockTest,
+ // Buffer size (bytes).
+ testing::Range(1, 128));
+
+} // namespace
diff --git a/third_party/abseil/absl/flags/internal/type_erased.cc b/third_party/abseil/absl/flags/internal/type_erased.cc
deleted file mode 100644
index a1650fc..0000000
--- a/third_party/abseil/absl/flags/internal/type_erased.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-//
-// Copyright 2019 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/flags/internal/type_erased.h"
-
-#include "absl/base/internal/raw_logging.h"
-#include "absl/flags/config.h"
-#include "absl/flags/usage_config.h"
-#include "absl/strings/str_cat.h"
-
-namespace absl {
-namespace flags_internal {
-
-bool GetCommandLineOption(absl::string_view name, std::string* value) {
- if (name.empty()) return false;
- assert(value);
-
- CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
- if (flag == nullptr || flag->IsRetired()) {
- return false;
- }
-
- *value = flag->CurrentValue();
- return true;
-}
-
-bool SetCommandLineOption(absl::string_view name, absl::string_view value) {
- return SetCommandLineOptionWithMode(name, value,
- flags_internal::SET_FLAGS_VALUE);
-}
-
-bool SetCommandLineOptionWithMode(absl::string_view name,
- absl::string_view value,
- FlagSettingMode set_mode) {
- CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
-
- if (!flag || flag->IsRetired()) return false;
-
- std::string error;
- if (!flag->SetFromString(value, set_mode, kProgrammaticChange, &error)) {
- // Errors here are all of the form: the provided name was a recognized
- // flag, but the value was invalid (bad type, or validation failed).
- flags_internal::ReportUsageError(error, false);
- return false;
- }
-
- return true;
-}
-
-// --------------------------------------------------------------------
-
-bool IsValidFlagValue(absl::string_view name, absl::string_view value) {
- CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
-
- return flag != nullptr &&
- (flag->IsRetired() || flag->ValidateInputValue(value));
-}
-
-// --------------------------------------------------------------------
-
-bool SpecifiedOnCommandLine(absl::string_view name) {
- CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
- if (flag != nullptr && !flag->IsRetired()) {
- return flag->IsSpecifiedOnCommandLine();
- }
- return false;
-}
-
-} // namespace flags_internal
-} // namespace absl
diff --git a/third_party/abseil/absl/flags/internal/type_erased.h b/third_party/abseil/absl/flags/internal/type_erased.h
deleted file mode 100644
index a955116..0000000
--- a/third_party/abseil/absl/flags/internal/type_erased.h
+++ /dev/null
@@ -1,86 +0,0 @@
-//
-// Copyright 2019 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef ABSL_FLAGS_INTERNAL_TYPE_ERASED_H_
-#define ABSL_FLAGS_INTERNAL_TYPE_ERASED_H_
-
-#include <string>
-
-#include "absl/flags/internal/commandlineflag.h"
-#include "absl/flags/internal/registry.h"
-
-// --------------------------------------------------------------------
-// Registry interfaces operating on type erased handles.
-
-namespace absl {
-namespace flags_internal {
-
-// If a flag named "name" exists, store its current value in *OUTPUT
-// and return true. Else return false without changing *OUTPUT.
-// Thread-safe.
-bool GetCommandLineOption(absl::string_view name, std::string* value);
-
-// Set the value of the flag named "name" to value. If successful,
-// returns true. If not successful (e.g., the flag was not found or
-// the value is not a valid value), returns false.
-// Thread-safe.
-bool SetCommandLineOption(absl::string_view name, absl::string_view value);
-
-bool SetCommandLineOptionWithMode(absl::string_view name,
- absl::string_view value,
- FlagSettingMode set_mode);
-
-//-----------------------------------------------------------------------------
-
-// Returns true iff all of the following conditions are true:
-// (a) "name" names a registered flag
-// (b) "value" can be parsed succesfully according to the type of the flag
-// (c) parsed value passes any validator associated with the flag
-bool IsValidFlagValue(absl::string_view name, absl::string_view value);
-
-//-----------------------------------------------------------------------------
-
-// Returns true iff a flag named "name" was specified on the command line
-// (either directly, or via one of --flagfile or --fromenv or --tryfromenv).
-//
-// Any non-command-line modification of the flag does not affect the
-// result of this function. So for example, if a flag was passed on
-// the command line but then reset via SET_FLAGS_DEFAULT, this
-// function will still return true.
-bool SpecifiedOnCommandLine(absl::string_view name);
-
-//-----------------------------------------------------------------------------
-
-// If a flag with specified "name" exists and has type T, store
-// its current value in *dst and return true. Else return false
-// without touching *dst. T must obey all of the requirements for
-// types passed to DEFINE_FLAG.
-template <typename T>
-inline bool GetByName(absl::string_view name, T* dst) {
- CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
- if (!flag) return false;
-
- if (auto val = flag->Get<T>()) {
- *dst = *val;
- return true;
- }
-
- return false;
-}
-
-} // namespace flags_internal
-} // namespace absl
-
-#endif // ABSL_FLAGS_INTERNAL_TYPE_ERASED_H_
diff --git a/third_party/abseil/absl/flags/internal/type_erased_test.cc b/third_party/abseil/absl/flags/internal/type_erased_test.cc
deleted file mode 100644
index ac749a6..0000000
--- a/third_party/abseil/absl/flags/internal/type_erased_test.cc
+++ /dev/null
@@ -1,147 +0,0 @@
-//
-// Copyright 2019 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/flags/internal/type_erased.h"
-
-#include <cmath>
-
-#include "gtest/gtest.h"
-#include "absl/flags/flag.h"
-#include "absl/memory/memory.h"
-#include "absl/strings/str_cat.h"
-
-ABSL_FLAG(int, int_flag, 1, "int_flag help");
-ABSL_FLAG(std::string, string_flag, "dflt", "string_flag help");
-ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help");
-
-namespace {
-
-namespace flags = absl::flags_internal;
-
-class TypeErasedTest : public testing::Test {
- protected:
- void SetUp() override { flag_saver_ = absl::make_unique<flags::FlagSaver>(); }
- void TearDown() override { flag_saver_.reset(); }
-
- private:
- std::unique_ptr<flags::FlagSaver> flag_saver_;
-};
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestGetCommandLineOption) {
- std::string value;
- EXPECT_TRUE(flags::GetCommandLineOption("int_flag", &value));
- EXPECT_EQ(value, "1");
-
- EXPECT_TRUE(flags::GetCommandLineOption("string_flag", &value));
- EXPECT_EQ(value, "dflt");
-
- EXPECT_FALSE(flags::GetCommandLineOption("bool_retired_flag", &value));
-
- EXPECT_FALSE(flags::GetCommandLineOption("unknown_flag", &value));
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestSetCommandLineOption) {
- EXPECT_TRUE(flags::SetCommandLineOption("int_flag", "101"));
- EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101);
-
- EXPECT_TRUE(flags::SetCommandLineOption("string_flag", "asdfgh"));
- EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh");
-
- EXPECT_FALSE(flags::SetCommandLineOption("bool_retired_flag", "true"));
-
- EXPECT_FALSE(flags::SetCommandLineOption("unknown_flag", "true"));
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestSetCommandLineOptionWithMode_SET_FLAGS_VALUE) {
- EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "101",
- flags::SET_FLAGS_VALUE));
- EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101);
-
- EXPECT_TRUE(flags::SetCommandLineOptionWithMode("string_flag", "asdfgh",
- flags::SET_FLAGS_VALUE));
- EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh");
-
- EXPECT_FALSE(flags::SetCommandLineOptionWithMode("bool_retired_flag", "true",
- flags::SET_FLAGS_VALUE));
-
- EXPECT_FALSE(flags::SetCommandLineOptionWithMode("unknown_flag", "true",
- flags::SET_FLAGS_VALUE));
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestSetCommandLineOptionWithMode_SET_FLAG_IF_DEFAULT) {
- EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "101",
- flags::SET_FLAG_IF_DEFAULT));
- EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101);
-
- // This semantic is broken. We return true instead of false. Value is not
- // updated.
- EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "202",
- flags::SET_FLAG_IF_DEFAULT));
- EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101);
-
- EXPECT_TRUE(flags::SetCommandLineOptionWithMode("string_flag", "asdfgh",
- flags::SET_FLAG_IF_DEFAULT));
- EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh");
-
- EXPECT_FALSE(flags::SetCommandLineOptionWithMode("bool_retired_flag", "true",
- flags::SET_FLAG_IF_DEFAULT));
-
- EXPECT_FALSE(flags::SetCommandLineOptionWithMode("unknown_flag", "true",
- flags::SET_FLAG_IF_DEFAULT));
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestSetCommandLineOptionWithMode_SET_FLAGS_DEFAULT) {
- EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "101",
- flags::SET_FLAGS_DEFAULT));
-
- EXPECT_TRUE(flags::SetCommandLineOptionWithMode("string_flag", "asdfgh",
- flags::SET_FLAGS_DEFAULT));
- EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh");
-
- EXPECT_FALSE(flags::SetCommandLineOptionWithMode("bool_retired_flag", "true",
- flags::SET_FLAGS_DEFAULT));
-
- EXPECT_FALSE(flags::SetCommandLineOptionWithMode("unknown_flag", "true",
- flags::SET_FLAGS_DEFAULT));
-
- // This should be successfull, since flag is still is not set
- EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "202",
- flags::SET_FLAG_IF_DEFAULT));
- EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 202);
-}
-
-// --------------------------------------------------------------------
-
-TEST_F(TypeErasedTest, TestIsValidFlagValue) {
- EXPECT_TRUE(flags::IsValidFlagValue("int_flag", "57"));
- EXPECT_TRUE(flags::IsValidFlagValue("int_flag", "-101"));
- EXPECT_FALSE(flags::IsValidFlagValue("int_flag", "1.1"));
-
- EXPECT_TRUE(flags::IsValidFlagValue("string_flag", "#%^#%^$%DGHDG$W%adsf"));
-
- EXPECT_TRUE(flags::IsValidFlagValue("bool_retired_flag", "true"));
-}
-
-} // namespace
diff --git a/third_party/abseil/absl/flags/internal/usage.cc b/third_party/abseil/absl/flags/internal/usage.cc
index 0304851..a588c7f 100644
--- a/third_party/abseil/absl/flags/internal/usage.cc
+++ b/third_party/abseil/absl/flags/internal/usage.cc
@@ -15,38 +15,48 @@
#include "absl/flags/internal/usage.h"
-#include <map>
-#include <string>
+#include <stdint.h>
+#include <functional>
+#include <map>
+#include <ostream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/base/config.h"
+#include "absl/flags/commandlineflag.h"
#include "absl/flags/flag.h"
+#include "absl/flags/internal/flag.h"
#include "absl/flags/internal/path_util.h"
+#include "absl/flags/internal/private_handle_accessor.h"
#include "absl/flags/internal/program_name.h"
+#include "absl/flags/internal/registry.h"
#include "absl/flags/usage_config.h"
-#include "absl/strings/ascii.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
-#include "absl/synchronization/mutex.h"
-ABSL_FLAG(bool, help, false,
- "show help on important flags for this binary [tip: all flags can "
- "have two dashes]");
-ABSL_FLAG(bool, helpfull, false, "show help on all flags");
-ABSL_FLAG(bool, helpshort, false,
- "show help on only the main module for this program");
-ABSL_FLAG(bool, helppackage, false,
- "show help on all modules in the main package");
-ABSL_FLAG(bool, version, false, "show version and build info and exit");
-ABSL_FLAG(bool, only_check_args, false, "exit after checking all flags");
-ABSL_FLAG(std::string, helpon, "",
- "show help on the modules named by this flag value");
-ABSL_FLAG(std::string, helpmatch, "",
- "show help on modules whose name contains the specified substr");
+// Dummy global variables to prevent anyone else defining these.
+bool FLAGS_help = false;
+bool FLAGS_helpfull = false;
+bool FLAGS_helpshort = false;
+bool FLAGS_helppackage = false;
+bool FLAGS_version = false;
+bool FLAGS_only_check_args = false;
+bool FLAGS_helpon = false;
+bool FLAGS_helpmatch = false;
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace flags_internal {
namespace {
+using PerFlagFilter = std::function<bool(const absl::CommandLineFlag&)>;
+
+// Maximum length size in a human readable format.
+constexpr size_t kHrfMaxLineLength = 80;
+
// This class is used to emit an XML element with `tag` and `text`.
// It adds opening and closing tags and escapes special characters in the text.
// For example:
@@ -99,21 +109,24 @@
public:
// Pretty printer holds on to the std::ostream& reference to direct an output
// to that stream.
- FlagHelpPrettyPrinter(int max_line_len, std::ostream* out)
- : out_(*out),
+ FlagHelpPrettyPrinter(size_t max_line_len, size_t min_line_len,
+ size_t wrapped_line_indent, std::ostream& out)
+ : out_(out),
max_line_len_(max_line_len),
+ min_line_len_(min_line_len),
+ wrapped_line_indent_(wrapped_line_indent),
line_len_(0),
first_line_(true) {}
void Write(absl::string_view str, bool wrap_line = false) {
- // Empty std::string - do nothing.
+ // Empty string - do nothing.
if (str.empty()) return;
std::vector<absl::string_view> tokens;
if (wrap_line) {
for (auto line : absl::StrSplit(str, absl::ByAnyChar("\n\r"))) {
if (!tokens.empty()) {
- // Keep line separators in the input std::string.
+ // Keep line separators in the input string.
tokens.push_back("\n");
}
for (auto token :
@@ -128,14 +141,15 @@
for (auto token : tokens) {
bool new_line = (line_len_ == 0);
- // Respect line separators in the input std::string.
+ // Respect line separators in the input string.
if (token == "\n") {
EndLine();
continue;
}
- // Write the token, ending the std::string first if necessary/possible.
- if (!new_line && (line_len_ + token.size() >= max_line_len_)) {
+ // Write the token, ending the string first if necessary/possible.
+ if (!new_line &&
+ (line_len_ + static_cast<int>(token.size()) >= max_line_len_)) {
EndLine();
new_line = true;
}
@@ -154,13 +168,12 @@
void StartLine() {
if (first_line_) {
- out_ << " ";
- line_len_ = 4;
+ line_len_ = min_line_len_;
first_line_ = false;
} else {
- out_ << " ";
- line_len_ = 6;
+ line_len_ = min_line_len_ + wrapped_line_indent_;
}
+ out_ << std::string(line_len_, ' ');
}
void EndLine() {
out_ << '\n';
@@ -169,38 +182,36 @@
private:
std::ostream& out_;
- const int max_line_len_;
- int line_len_;
+ const size_t max_line_len_;
+ const size_t min_line_len_;
+ const size_t wrapped_line_indent_;
+ size_t line_len_;
bool first_line_;
};
-void FlagHelpHumanReadable(const flags_internal::CommandLineFlag& flag,
- std::ostream* out) {
- FlagHelpPrettyPrinter printer(80, out); // Max line length is 80.
+void FlagHelpHumanReadable(const CommandLineFlag& flag, std::ostream& out) {
+ FlagHelpPrettyPrinter printer(kHrfMaxLineLength, 4, 2, out);
// Flag name.
- printer.Write(absl::StrCat("-", flag.Name()));
+ printer.Write(absl::StrCat("--", flag.Name()));
// Flag help.
printer.Write(absl::StrCat("(", flag.Help(), ");"), /*wrap_line=*/true);
- // Flag data type (for V1 flags only).
- if (!flag.IsAbseilFlag() && !flag.IsRetired()) {
- printer.Write(absl::StrCat("type: ", flag.Typename(), ";"));
- }
-
// The listed default value will be the actual default from the flag
// definition in the originating source file, unless the value has
// subsequently been modified using SetCommandLineOption() with mode
// SET_FLAGS_DEFAULT.
std::string dflt_val = flag.DefaultValue();
+ std::string curr_val = flag.CurrentValue();
+ bool is_modified = curr_val != dflt_val;
+
if (flag.IsOfType<std::string>()) {
dflt_val = absl::StrCat("\"", dflt_val, "\"");
}
printer.Write(absl::StrCat("default: ", dflt_val, ";"));
- if (flag.IsModified()) {
- std::string curr_val = flag.CurrentValue();
+ if (is_modified) {
if (flag.IsOfType<std::string>()) {
curr_val = absl::StrCat("\"", curr_val, "\"");
}
@@ -215,7 +226,7 @@
// If a flag's help message has been stripped (e.g. by adding '#define
// STRIP_FLAG_HELP 1' then this flag will not be displayed by '--help'
// and its variants.
-void FlagsHelpImpl(std::ostream& out, flags_internal::FlagKindFilter filter_cb,
+void FlagsHelpImpl(std::ostream& out, PerFlagFilter filter_cb,
HelpFormat format, absl::string_view program_usage_message) {
if (format == HelpFormat::kHumanReadable) {
out << flags_internal::ShortProgramInvocationName() << ": "
@@ -223,6 +234,9 @@
} else {
// XML schema is not a part of our public API for now.
out << "<?xml version=\"1.0\"?>\n"
+ << "<!-- This output should be used with care. We do not report type "
+ "names for flags with user defined types -->\n"
+ << "<!-- Prefer flag only_check_args for validating flag inputs -->\n"
// The document.
<< "<AllFlags>\n"
// The program name and usage.
@@ -237,30 +251,28 @@
// This map is used to output matching flags grouped by package and file
// name.
std::map<std::string,
- std::map<std::string,
- std::vector<const flags_internal::CommandLineFlag*>>>
+ std::map<std::string, std::vector<const absl::CommandLineFlag*>>>
matching_flags;
- flags_internal::ForEachFlag([&](flags_internal::CommandLineFlag* flag) {
- std::string flag_filename = flag->Filename();
-
+ flags_internal::ForEachFlag([&](absl::CommandLineFlag& flag) {
// Ignore retired flags.
- if (flag->IsRetired()) return;
+ if (flag.IsRetired()) return;
// If the flag has been stripped, pretend that it doesn't exist.
- if (flag->Help() == flags_internal::kStrippedFlagHelp) return;
+ if (flag.Help() == flags_internal::kStrippedFlagHelp) return;
// Make sure flag satisfies the filter
- if (!filter_cb || !filter_cb(flag_filename)) return;
+ if (!filter_cb(flag)) return;
+
+ std::string flag_filename = flag.Filename();
matching_flags[std::string(flags_internal::Package(flag_filename))]
[flag_filename]
- .push_back(flag);
+ .push_back(&flag);
});
- absl::string_view
- package_separator; // controls blank lines between packages.
- absl::string_view file_separator; // controls blank lines between files.
+ absl::string_view package_separator; // controls blank lines between packages
+ absl::string_view file_separator; // controls blank lines between files
for (const auto& package : matching_flags) {
if (format == HelpFormat::kHumanReadable) {
out << package_separator;
@@ -282,27 +294,46 @@
}
if (format == HelpFormat::kHumanReadable) {
+ FlagHelpPrettyPrinter printer(kHrfMaxLineLength, 0, 0, out);
+
if (filter_cb && matching_flags.empty()) {
- out << " No modules matched: use -helpfull\n";
+ printer.Write("No flags matched.\n", true);
}
+ printer.EndLine();
+ printer.Write(
+ "Try --helpfull to get a list of all flags or --help=substring "
+ "shows help for flags which include specified substring in either "
+ "in the name, or description or path.\n",
+ true);
} else {
// The end of the document.
out << "</AllFlags>\n";
}
}
+void FlagsHelpImpl(std::ostream& out,
+ flags_internal::FlagKindFilter filename_filter_cb,
+ HelpFormat format, absl::string_view program_usage_message) {
+ FlagsHelpImpl(
+ out,
+ [&](const absl::CommandLineFlag& flag) {
+ return filename_filter_cb && filename_filter_cb(flag.Filename());
+ },
+ format, program_usage_message);
+}
+
} // namespace
// --------------------------------------------------------------------
// Produces the help message describing specific flag.
-void FlagHelp(std::ostream& out, const flags_internal::CommandLineFlag& flag,
+void FlagHelp(std::ostream& out, const CommandLineFlag& flag,
HelpFormat format) {
if (format == HelpFormat::kHumanReadable)
- flags_internal::FlagHelpHumanReadable(flag, &out);
+ flags_internal::FlagHelpHumanReadable(flag, out);
}
// --------------------------------------------------------------------
-// Produces the help messages for all flags matching the filter.
+// Produces the help messages for all flags matching the filename filter.
// If filter is empty produces help messages for all flags.
void FlagsHelp(std::ostream& out, absl::string_view filter, HelpFormat format,
absl::string_view program_usage_message) {
@@ -317,67 +348,171 @@
// If so, handles them appropriately.
int HandleUsageFlags(std::ostream& out,
absl::string_view program_usage_message) {
- if (absl::GetFlag(FLAGS_helpshort)) {
- flags_internal::FlagsHelpImpl(
- out, flags_internal::GetUsageConfig().contains_helpshort_flags,
- HelpFormat::kHumanReadable, program_usage_message);
- return 1;
- }
+ switch (GetFlagsHelpMode()) {
+ case HelpMode::kNone:
+ break;
+ case HelpMode::kImportant:
+ flags_internal::FlagsHelpImpl(
+ out, flags_internal::GetUsageConfig().contains_help_flags,
+ GetFlagsHelpFormat(), program_usage_message);
+ return 1;
- if (absl::GetFlag(FLAGS_helpfull)) {
- // show all options
- flags_internal::FlagsHelp(out, "", HelpFormat::kHumanReadable,
- program_usage_message);
- return 1;
- }
+ case HelpMode::kShort:
+ flags_internal::FlagsHelpImpl(
+ out, flags_internal::GetUsageConfig().contains_helpshort_flags,
+ GetFlagsHelpFormat(), program_usage_message);
+ return 1;
- if (!absl::GetFlag(FLAGS_helpon).empty()) {
- flags_internal::FlagsHelp(
- out, absl::StrCat("/", absl::GetFlag(FLAGS_helpon), "."),
- HelpFormat::kHumanReadable, program_usage_message);
- return 1;
- }
+ case HelpMode::kFull:
+ flags_internal::FlagsHelp(out, "", GetFlagsHelpFormat(),
+ program_usage_message);
+ return 1;
- if (!absl::GetFlag(FLAGS_helpmatch).empty()) {
- flags_internal::FlagsHelp(out, absl::GetFlag(FLAGS_helpmatch),
- HelpFormat::kHumanReadable,
- program_usage_message);
- return 1;
- }
+ case HelpMode::kPackage:
+ flags_internal::FlagsHelpImpl(
+ out, flags_internal::GetUsageConfig().contains_helppackage_flags,
+ GetFlagsHelpFormat(), program_usage_message);
- if (absl::GetFlag(FLAGS_help)) {
- flags_internal::FlagsHelpImpl(
- out, flags_internal::GetUsageConfig().contains_help_flags,
- HelpFormat::kHumanReadable, program_usage_message);
+ return 1;
- out << "\nTry --helpfull to get a list of all flags.\n";
+ case HelpMode::kMatch: {
+ std::string substr = GetFlagsHelpMatchSubstr();
+ if (substr.empty()) {
+ // show all options
+ flags_internal::FlagsHelp(out, substr, GetFlagsHelpFormat(),
+ program_usage_message);
+ } else {
+ auto filter_cb = [&substr](const absl::CommandLineFlag& flag) {
+ if (absl::StrContains(flag.Name(), substr)) return true;
+ if (absl::StrContains(flag.Filename(), substr)) return true;
+ if (absl::StrContains(flag.Help(), substr)) return true;
- return 1;
- }
+ return false;
+ };
+ flags_internal::FlagsHelpImpl(
+ out, filter_cb, HelpFormat::kHumanReadable, program_usage_message);
+ }
- if (absl::GetFlag(FLAGS_helppackage)) {
- flags_internal::FlagsHelpImpl(
- out, flags_internal::GetUsageConfig().contains_helppackage_flags,
- HelpFormat::kHumanReadable, program_usage_message);
+ return 1;
+ }
+ case HelpMode::kVersion:
+ if (flags_internal::GetUsageConfig().version_string)
+ out << flags_internal::GetUsageConfig().version_string();
+ // Unlike help, we may be asking for version in a script, so return 0
+ return 0;
- out << "\nTry --helpfull to get a list of all flags.\n";
-
- return 1;
- }
-
- if (absl::GetFlag(FLAGS_version)) {
- if (flags_internal::GetUsageConfig().version_string)
- out << flags_internal::GetUsageConfig().version_string();
- // Unlike help, we may be asking for version in a script, so return 0
- return 0;
- }
-
- if (absl::GetFlag(FLAGS_only_check_args)) {
- return 0;
+ case HelpMode::kOnlyCheckArgs:
+ return 0;
}
return -1;
}
+// --------------------------------------------------------------------
+// Globals representing usage reporting flags
+
+namespace {
+
+ABSL_CONST_INIT absl::Mutex help_attributes_guard(absl::kConstInit);
+ABSL_CONST_INIT std::string* match_substr
+ ABSL_GUARDED_BY(help_attributes_guard) = nullptr;
+ABSL_CONST_INIT HelpMode help_mode ABSL_GUARDED_BY(help_attributes_guard) =
+ HelpMode::kNone;
+ABSL_CONST_INIT HelpFormat help_format ABSL_GUARDED_BY(help_attributes_guard) =
+ HelpFormat::kHumanReadable;
+
+} // namespace
+
+std::string GetFlagsHelpMatchSubstr() {
+ absl::MutexLock l(&help_attributes_guard);
+ if (match_substr == nullptr) return "";
+ return *match_substr;
+}
+
+void SetFlagsHelpMatchSubstr(absl::string_view substr) {
+ absl::MutexLock l(&help_attributes_guard);
+ if (match_substr == nullptr) match_substr = new std::string;
+ match_substr->assign(substr.data(), substr.size());
+}
+
+HelpMode GetFlagsHelpMode() {
+ absl::MutexLock l(&help_attributes_guard);
+ return help_mode;
+}
+
+void SetFlagsHelpMode(HelpMode mode) {
+ absl::MutexLock l(&help_attributes_guard);
+ help_mode = mode;
+}
+
+HelpFormat GetFlagsHelpFormat() {
+ absl::MutexLock l(&help_attributes_guard);
+ return help_format;
+}
+
+void SetFlagsHelpFormat(HelpFormat format) {
+ absl::MutexLock l(&help_attributes_guard);
+ help_format = format;
+}
+
+// Deduces usage flags from the input argument in a form --name=value or
+// --name. argument is already split into name and value before we call this
+// function.
+bool DeduceUsageFlags(absl::string_view name, absl::string_view value) {
+ if (absl::ConsumePrefix(&name, "help")) {
+ if (name == "") {
+ if (value.empty()) {
+ SetFlagsHelpMode(HelpMode::kImportant);
+ } else {
+ SetFlagsHelpMode(HelpMode::kMatch);
+ SetFlagsHelpMatchSubstr(value);
+ }
+ return true;
+ }
+
+ if (name == "match") {
+ SetFlagsHelpMode(HelpMode::kMatch);
+ SetFlagsHelpMatchSubstr(value);
+ return true;
+ }
+
+ if (name == "on") {
+ SetFlagsHelpMode(HelpMode::kMatch);
+ SetFlagsHelpMatchSubstr(absl::StrCat("/", value, "."));
+ return true;
+ }
+
+ if (name == "full") {
+ SetFlagsHelpMode(HelpMode::kFull);
+ return true;
+ }
+
+ if (name == "short") {
+ SetFlagsHelpMode(HelpMode::kShort);
+ return true;
+ }
+
+ if (name == "package") {
+ SetFlagsHelpMode(HelpMode::kPackage);
+ return true;
+ }
+
+ return false;
+ }
+
+ if (name == "version") {
+ SetFlagsHelpMode(HelpMode::kVersion);
+ return true;
+ }
+
+ if (name == "only_check_args") {
+ SetFlagsHelpMode(HelpMode::kOnlyCheckArgs);
+ return true;
+ }
+
+ return false;
+}
+
} // namespace flags_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/flags/internal/usage.h b/third_party/abseil/absl/flags/internal/usage.h
index 76075b0..c0bcac5 100644
--- a/third_party/abseil/absl/flags/internal/usage.h
+++ b/third_party/abseil/absl/flags/internal/usage.h
@@ -19,14 +19,16 @@
#include <iosfwd>
#include <string>
+#include "absl/base/config.h"
+#include "absl/flags/commandlineflag.h"
#include "absl/flags/declare.h"
-#include "absl/flags/internal/commandlineflag.h"
#include "absl/strings/string_view.h"
// --------------------------------------------------------------------
// Usage reporting interfaces
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace flags_internal {
// The format to report the help messages in.
@@ -34,8 +36,9 @@
kHumanReadable,
};
-// Outputs the help message describing specific flag.
-void FlagHelp(std::ostream& out, const flags_internal::CommandLineFlag& flag,
+// Streams the help message describing `flag` to `out`.
+// The default value for `flag` is included in the output.
+void FlagHelp(std::ostream& out, const CommandLineFlag& flag,
HelpFormat format = HelpFormat::kHumanReadable);
// Produces the help messages for all flags matching the filter. A flag matches
@@ -63,16 +66,39 @@
int HandleUsageFlags(std::ostream& out,
absl::string_view program_usage_message);
-} // namespace flags_internal
-} // namespace absl
+// --------------------------------------------------------------------
+// Globals representing usage reporting flags
-ABSL_DECLARE_FLAG(bool, help);
-ABSL_DECLARE_FLAG(bool, helpfull);
-ABSL_DECLARE_FLAG(bool, helpshort);
-ABSL_DECLARE_FLAG(bool, helppackage);
-ABSL_DECLARE_FLAG(bool, version);
-ABSL_DECLARE_FLAG(bool, only_check_args);
-ABSL_DECLARE_FLAG(std::string, helpon);
-ABSL_DECLARE_FLAG(std::string, helpmatch);
+enum class HelpMode {
+ kNone,
+ kImportant,
+ kShort,
+ kFull,
+ kPackage,
+ kMatch,
+ kVersion,
+ kOnlyCheckArgs
+};
+
+// Returns substring to filter help output (--help=substr argument)
+std::string GetFlagsHelpMatchSubstr();
+// Returns the requested help mode.
+HelpMode GetFlagsHelpMode();
+// Returns the requested help format.
+HelpFormat GetFlagsHelpFormat();
+
+// These are corresponding setters to the attributes above.
+void SetFlagsHelpMatchSubstr(absl::string_view);
+void SetFlagsHelpMode(HelpMode);
+void SetFlagsHelpFormat(HelpFormat);
+
+// Deduces usage flags from the input argument in a form --name=value or
+// --name. argument is already split into name and value before we call this
+// function.
+bool DeduceUsageFlags(absl::string_view name, absl::string_view value);
+
+} // namespace flags_internal
+ABSL_NAMESPACE_END
+} // namespace absl
#endif // ABSL_FLAGS_INTERNAL_USAGE_H_
diff --git a/third_party/abseil/absl/flags/internal/usage_test.cc b/third_party/abseil/absl/flags/internal/usage_test.cc
index d15e448..b5c2487 100644
--- a/third_party/abseil/absl/flags/internal/usage_test.cc
+++ b/third_party/abseil/absl/flags/internal/usage_test.cc
@@ -15,17 +15,21 @@
#include "absl/flags/internal/usage.h"
+#include <stdint.h>
+
#include <sstream>
+#include <string>
#include "gtest/gtest.h"
#include "absl/flags/flag.h"
+#include "absl/flags/internal/parse.h"
#include "absl/flags/internal/path_util.h"
#include "absl/flags/internal/program_name.h"
-#include "absl/flags/parse.h"
+#include "absl/flags/reflection.h"
#include "absl/flags/usage.h"
#include "absl/flags/usage_config.h"
-#include "absl/memory/memory.h"
#include "absl/strings/match.h"
+#include "absl/strings/string_view.h"
ABSL_FLAG(int, usage_reporting_test_flag_01, 101,
"usage_reporting_test_flag_01 help message");
@@ -83,9 +87,14 @@
default_config.normalize_filename = &NormalizeFileName;
absl::SetFlagsUsageConfig(default_config);
}
+ ~UsageReportingTest() override {
+ flags::SetFlagsHelpMode(flags::HelpMode::kNone);
+ flags::SetFlagsHelpMatchSubstr("");
+ flags::SetFlagsHelpFormat(flags::HelpFormat::kHumanReadable);
+ }
private:
- flags::FlagSaver flag_saver_;
+ absl::FlagSaver flag_saver_;
};
// --------------------------------------------------------------------
@@ -97,69 +106,70 @@
#ifndef _WIN32
// TODO(rogeeff): figure out why this does not work on Windows.
- EXPECT_DEATH(absl::SetProgramUsageMessage("custom usage message"),
- ".*SetProgramUsageMessage\\(\\) called twice.*");
+ EXPECT_DEATH_IF_SUPPORTED(
+ absl::SetProgramUsageMessage("custom usage message"),
+ ".*SetProgramUsageMessage\\(\\) called twice.*");
#endif
}
// --------------------------------------------------------------------
TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_01) {
- const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_01");
+ const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_01");
std::stringstream test_buf;
flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
EXPECT_EQ(
test_buf.str(),
- R"( -usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
+ R"( --usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
default: 101;
)");
}
TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_02) {
- const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_02");
+ const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_02");
std::stringstream test_buf;
flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
EXPECT_EQ(
test_buf.str(),
- R"( -usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
+ R"( --usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
default: false;
)");
}
TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_03) {
- const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_03");
+ const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_03");
std::stringstream test_buf;
flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
EXPECT_EQ(
test_buf.str(),
- R"( -usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
+ R"( --usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
default: 1.03;
)");
}
TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_04) {
- const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_04");
+ const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_04");
std::stringstream test_buf;
flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
EXPECT_EQ(
test_buf.str(),
- R"( -usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
+ R"( --usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
default: 1000000000000004;
)");
}
TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_05) {
- const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_05");
+ const auto* flag = absl::FindCommandLineFlag("usage_reporting_test_flag_05");
std::stringstream test_buf;
flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
EXPECT_EQ(
test_buf.str(),
- R"( -usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
+ R"( --usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
default: UDT{};
)");
}
@@ -171,21 +181,25 @@
R"(usage_test: Custom usage message
Flags from absl/flags/internal/usage_test.cc:
- -usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
+ --usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
default: 101;
- -usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
+ --usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
default: false;
- -usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
+ --usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
default: 1.03;
- -usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
+ --usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
default: 1000000000000004;
- -usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
+ --usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
default: UDT{};
- -usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
+ --usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
Some more help.
Even more long long long long long long long long long long long long help
message.); default: "";
+
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
)";
std::stringstream test_buf_01;
@@ -209,7 +223,11 @@
EXPECT_EQ(test_buf_04.str(),
R"(usage_test: Custom usage message
- No modules matched: use -helpfull
+No flags matched.
+
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
)");
std::stringstream test_buf_05;
@@ -221,12 +239,8 @@
absl::StartsWith(test_out_str, "usage_test: Custom usage message"));
EXPECT_TRUE(absl::StrContains(
test_out_str, "Flags from absl/flags/internal/usage_test.cc:"));
- EXPECT_TRUE(absl::StrContains(test_out_str,
- "Flags from absl/flags/internal/usage.cc:"));
EXPECT_TRUE(
absl::StrContains(test_out_str, "-usage_reporting_test_flag_01 "));
- EXPECT_TRUE(absl::StrContains(test_out_str, "-help (show help"))
- << test_out_str;
}
// --------------------------------------------------------------------
@@ -239,7 +253,7 @@
// --------------------------------------------------------------------
TEST_F(UsageReportingTest, TestUsageFlag_helpshort) {
- absl::SetFlag(&FLAGS_helpshort, true);
+ flags::SetFlagsHelpMode(flags::HelpMode::kShort);
std::stringstream test_buf;
EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
@@ -247,28 +261,32 @@
R"(usage_test: Custom usage message
Flags from absl/flags/internal/usage_test.cc:
- -usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
+ --usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
default: 101;
- -usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
+ --usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
default: false;
- -usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
+ --usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
default: 1.03;
- -usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
+ --usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
default: 1000000000000004;
- -usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
+ --usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
default: UDT{};
- -usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
+ --usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
Some more help.
Even more long long long long long long long long long long long long help
message.); default: "";
+
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
)");
}
// --------------------------------------------------------------------
-TEST_F(UsageReportingTest, TestUsageFlag_help) {
- absl::SetFlag(&FLAGS_help, true);
+TEST_F(UsageReportingTest, TestUsageFlag_help_simple) {
+ flags::SetFlagsHelpMode(flags::HelpMode::kImportant);
std::stringstream test_buf;
EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
@@ -276,30 +294,90 @@
R"(usage_test: Custom usage message
Flags from absl/flags/internal/usage_test.cc:
- -usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
+ --usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
default: 101;
- -usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
+ --usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
default: false;
- -usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
+ --usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
default: 1.03;
- -usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
+ --usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
default: 1000000000000004;
- -usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
+ --usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
default: UDT{};
- -usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
+ --usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
Some more help.
Even more long long long long long long long long long long long long help
message.); default: "";
-Try --helpfull to get a list of all flags.
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
+)");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(UsageReportingTest, TestUsageFlag_help_one_flag) {
+ flags::SetFlagsHelpMode(flags::HelpMode::kMatch);
+ flags::SetFlagsHelpMatchSubstr("usage_reporting_test_flag_06");
+
+ std::stringstream test_buf;
+ EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
+ EXPECT_EQ(test_buf.str(),
+ R"(usage_test: Custom usage message
+
+ Flags from absl/flags/internal/usage_test.cc:
+ --usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
+
+ Some more help.
+ Even more long long long long long long long long long long long long help
+ message.); default: "";
+
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
+)");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(UsageReportingTest, TestUsageFlag_help_multiple_flag) {
+ flags::SetFlagsHelpMode(flags::HelpMode::kMatch);
+ flags::SetFlagsHelpMatchSubstr("test_flag");
+
+ std::stringstream test_buf;
+ EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
+ EXPECT_EQ(test_buf.str(),
+ R"(usage_test: Custom usage message
+
+ Flags from absl/flags/internal/usage_test.cc:
+ --usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
+ default: 101;
+ --usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
+ default: false;
+ --usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
+ default: 1.03;
+ --usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
+ default: 1000000000000004;
+ --usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
+ default: UDT{};
+ --usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
+
+ Some more help.
+ Even more long long long long long long long long long long long long help
+ message.); default: "";
+
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
)");
}
// --------------------------------------------------------------------
TEST_F(UsageReportingTest, TestUsageFlag_helppackage) {
- absl::SetFlag(&FLAGS_helppackage, true);
+ flags::SetFlagsHelpMode(flags::HelpMode::kPackage);
std::stringstream test_buf;
EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
@@ -307,30 +385,32 @@
R"(usage_test: Custom usage message
Flags from absl/flags/internal/usage_test.cc:
- -usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
+ --usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
default: 101;
- -usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
+ --usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
default: false;
- -usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
+ --usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
default: 1.03;
- -usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
+ --usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
default: 1000000000000004;
- -usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
+ --usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
default: UDT{};
- -usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
+ --usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
Some more help.
Even more long long long long long long long long long long long long help
message.); default: "";
-Try --helpfull to get a list of all flags.
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
)");
}
// --------------------------------------------------------------------
TEST_F(UsageReportingTest, TestUsageFlag_version) {
- absl::SetFlag(&FLAGS_version, true);
+ flags::SetFlagsHelpMode(flags::HelpMode::kVersion);
std::stringstream test_buf;
EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 0);
@@ -344,7 +424,7 @@
// --------------------------------------------------------------------
TEST_F(UsageReportingTest, TestUsageFlag_only_check_args) {
- absl::SetFlag(&FLAGS_only_check_args, true);
+ flags::SetFlagsHelpMode(flags::HelpMode::kOnlyCheckArgs);
std::stringstream test_buf;
EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 0);
@@ -354,17 +434,22 @@
// --------------------------------------------------------------------
TEST_F(UsageReportingTest, TestUsageFlag_helpon) {
- absl::SetFlag(&FLAGS_helpon, "bla-bla");
+ flags::SetFlagsHelpMode(flags::HelpMode::kMatch);
+ flags::SetFlagsHelpMatchSubstr("/bla-bla.");
std::stringstream test_buf_01;
EXPECT_EQ(flags::HandleUsageFlags(test_buf_01, kTestUsageMessage), 1);
EXPECT_EQ(test_buf_01.str(),
R"(usage_test: Custom usage message
- No modules matched: use -helpfull
+No flags matched.
+
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
)");
- absl::SetFlag(&FLAGS_helpon, "usage_test");
+ flags::SetFlagsHelpMatchSubstr("/usage_test.");
std::stringstream test_buf_02;
EXPECT_EQ(flags::HandleUsageFlags(test_buf_02, kTestUsageMessage), 1);
@@ -372,21 +457,25 @@
R"(usage_test: Custom usage message
Flags from absl/flags/internal/usage_test.cc:
- -usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
+ --usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
default: 101;
- -usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
+ --usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
default: false;
- -usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
+ --usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
default: 1.03;
- -usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
+ --usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
default: 1000000000000004;
- -usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
+ --usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
default: UDT{};
- -usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
+ --usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
Some more help.
Even more long long long long long long long long long long long long help
message.); default: "";
+
+Try --helpfull to get a list of all flags or --help=substring shows help for
+flags which include specified substring in either in the name, or description or
+path.
)");
}
diff --git a/third_party/abseil/absl/flags/marshalling.cc b/third_party/abseil/absl/flags/marshalling.cc
index f4ebe0e..81f9ceb 100644
--- a/third_party/abseil/absl/flags/marshalling.cc
+++ b/third_party/abseil/absl/flags/marshalling.cc
@@ -15,18 +15,28 @@
#include "absl/flags/marshalling.h"
-#include <limits>
-#include <type_traits>
+#include <stddef.h>
+#include <cmath>
+#include <limits>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "absl/base/config.h"
+#include "absl/base/log_severity.h"
#include "absl/base/macros.h"
+#include "absl/strings/ascii.h"
#include "absl/strings/match.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
#include "absl/strings/str_split.h"
+#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace flags_internal {
// --------------------------------------------------------------------
@@ -64,15 +74,16 @@
}
template <typename IntType>
-inline bool ParseFlagImpl(absl::string_view text, IntType* dst) {
+inline bool ParseFlagImpl(absl::string_view text, IntType& dst) {
text = absl::StripAsciiWhitespace(text);
- return absl::numbers_internal::safe_strtoi_base(text, dst, NumericBase(text));
+ return absl::numbers_internal::safe_strtoi_base(text, &dst,
+ NumericBase(text));
}
bool AbslParseFlag(absl::string_view text, short* dst, std::string*) {
int val;
- if (!ParseFlagImpl(text, &val)) return false;
+ if (!ParseFlagImpl(text, val)) return false;
if (static_cast<short>(val) != val) // worked, but number out of range
return false;
*dst = static_cast<short>(val);
@@ -81,7 +92,7 @@
bool AbslParseFlag(absl::string_view text, unsigned short* dst, std::string*) {
unsigned int val;
- if (!ParseFlagImpl(text, &val)) return false;
+ if (!ParseFlagImpl(text, val)) return false;
if (static_cast<unsigned short>(val) !=
val) // worked, but number out of range
return false;
@@ -90,28 +101,28 @@
}
bool AbslParseFlag(absl::string_view text, int* dst, std::string*) {
- return ParseFlagImpl(text, dst);
+ return ParseFlagImpl(text, *dst);
}
bool AbslParseFlag(absl::string_view text, unsigned int* dst, std::string*) {
- return ParseFlagImpl(text, dst);
+ return ParseFlagImpl(text, *dst);
}
bool AbslParseFlag(absl::string_view text, long* dst, std::string*) {
- return ParseFlagImpl(text, dst);
+ return ParseFlagImpl(text, *dst);
}
bool AbslParseFlag(absl::string_view text, unsigned long* dst, std::string*) {
- return ParseFlagImpl(text, dst);
+ return ParseFlagImpl(text, *dst);
}
bool AbslParseFlag(absl::string_view text, long long* dst, std::string*) {
- return ParseFlagImpl(text, dst);
+ return ParseFlagImpl(text, *dst);
}
bool AbslParseFlag(absl::string_view text, unsigned long long* dst,
std::string*) {
- return ParseFlagImpl(text, dst);
+ return ParseFlagImpl(text, *dst);
}
// --------------------------------------------------------------------
@@ -162,7 +173,7 @@
std::string Unparse(unsigned long long v) { return absl::StrCat(v); }
template <typename T>
std::string UnparseFloatingPointVal(T v) {
- // digits10 is guaranteed to roundtrip correctly in std::string -> value -> std::string
+ // digits10 is guaranteed to roundtrip correctly in string -> value -> string
// conversions, but may not be enough to represent all the values correctly.
std::string digit10_str =
absl::StrFormat("%.*g", std::numeric_limits<T>::digits10, v);
@@ -226,4 +237,5 @@
return absl::UnparseFlag(static_cast<int>(v));
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/flags/marshalling.h b/third_party/abseil/absl/flags/marshalling.h
index 6d39180..0b50335 100644
--- a/third_party/abseil/absl/flags/marshalling.h
+++ b/third_party/abseil/absl/flags/marshalling.h
@@ -33,16 +33,16 @@
// * `double`
// * `std::string`
// * `std::vector<std::string>`
-// * `absl::LogSeverity` (provided here due to dependency ordering)
+// * `absl::LogSeverity` (provided natively for layering reasons)
//
// Note that support for integral types is implemented using overloads for
// variable-width fundamental types (`short`, `int`, `long`, etc.). However,
// you should prefer the fixed-width integral types (`int32_t`, `uint64_t`,
// etc.) we've noted above within flag definitions.
-
//
// In addition, several Abseil libraries provide their own custom support for
-// Abseil flags.
+// Abseil flags. Documentation for these formats is provided in the type's
+// `AbslParseFlag()` definition.
//
// The Abseil time library provides the following support for civil time values:
//
@@ -165,9 +165,11 @@
#include <string>
#include <vector>
+#include "absl/base/config.h"
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace flags_internal {
// Overloads of `AbslParseFlag()` and `AbslUnparseFlag()` for fundamental types.
@@ -256,6 +258,7 @@
bool AbslParseFlag(absl::string_view, absl::LogSeverity*, std::string*);
std::string AbslUnparseFlag(absl::LogSeverity);
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_FLAGS_MARSHALLING_H_
diff --git a/third_party/abseil/absl/flags/marshalling_test.cc b/third_party/abseil/absl/flags/marshalling_test.cc
index 37cd194..4a64ce1 100644
--- a/third_party/abseil/absl/flags/marshalling_test.cc
+++ b/third_party/abseil/absl/flags/marshalling_test.cc
@@ -15,7 +15,12 @@
#include "absl/flags/marshalling.h"
+#include <stdint.h>
+
#include <cmath>
+#include <limits>
+#include <string>
+#include <vector>
#include "gtest/gtest.h"
diff --git a/third_party/abseil/absl/flags/parse.cc b/third_party/abseil/absl/flags/parse.cc
index 16c4d68..dd1a679 100644
--- a/third_party/abseil/absl/flags/parse.cc
+++ b/third_party/abseil/absl/flags/parse.cc
@@ -17,27 +17,45 @@
#include <stdlib.h>
+#include <algorithm>
#include <fstream>
#include <iostream>
+#include <iterator>
+#include <string>
#include <tuple>
+#include <utility>
+#include <vector>
#ifdef _WIN32
#include <windows.h>
#endif
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/const_init.h"
+#include "absl/base/thread_annotations.h"
+#include "absl/flags/commandlineflag.h"
+#include "absl/flags/config.h"
#include "absl/flags/flag.h"
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/flags/internal/flag.h"
+#include "absl/flags/internal/parse.h"
+#include "absl/flags/internal/private_handle_accessor.h"
#include "absl/flags/internal/program_name.h"
-#include "absl/flags/internal/registry.h"
#include "absl/flags/internal/usage.h"
+#include "absl/flags/reflection.h"
#include "absl/flags/usage.h"
#include "absl/flags/usage_config.h"
+#include "absl/strings/ascii.h"
#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
#include "absl/strings/strip.h"
#include "absl/synchronization/mutex.h"
// --------------------------------------------------------------------
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace flags_internal {
namespace {
@@ -50,8 +68,25 @@
ABSL_CONST_INIT bool tryfromenv_needs_processing
ABSL_GUARDED_BY(processing_checks_guard) = false;
+ABSL_CONST_INIT absl::Mutex specified_flags_guard(absl::kConstInit);
+ABSL_CONST_INIT std::vector<const CommandLineFlag*>* specified_flags
+ ABSL_GUARDED_BY(specified_flags_guard) = nullptr;
+
+struct SpecifiedFlagsCompare {
+ bool operator()(const CommandLineFlag* a, const CommandLineFlag* b) const {
+ return a->Name() < b->Name();
+ }
+ bool operator()(const CommandLineFlag* a, absl::string_view b) const {
+ return a->Name() < b;
+ }
+ bool operator()(absl::string_view a, const CommandLineFlag* b) const {
+ return a < b->Name();
+ }
+};
+
} // namespace
} // namespace flags_internal
+ABSL_NAMESPACE_END
} // namespace absl
ABSL_FLAG(std::vector<std::string>, flagfile, {},
@@ -109,6 +144,7 @@
"with that name");
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace flags_internal {
namespace {
@@ -187,7 +223,7 @@
// Reads the environment variable with name `name` and stores results in
// `value`. If variable is not present in environment returns false, otherwise
// returns true.
-bool GetEnvVar(const char* var_name, std::string* var_value) {
+bool GetEnvVar(const char* var_name, std::string& var_value) {
#ifdef _WIN32
char buf[1024];
auto get_res = GetEnvironmentVariableA(var_name, buf, sizeof(buf));
@@ -199,14 +235,14 @@
return false;
}
- *var_value = std::string(buf, get_res);
+ var_value = std::string(buf, get_res);
#else
const char* val = ::getenv(var_name);
if (val == nullptr) {
return false;
}
- *var_value = val;
+ var_value = val;
#endif
return true;
@@ -254,11 +290,11 @@
// found flag or nullptr
// is negative in case of --nofoo
std::tuple<CommandLineFlag*, bool> LocateFlag(absl::string_view flag_name) {
- CommandLineFlag* flag = flags_internal::FindCommandLineFlag(flag_name);
+ CommandLineFlag* flag = absl::FindCommandLineFlag(flag_name);
bool is_negative = false;
if (!flag && absl::ConsumePrefix(&flag_name, "no")) {
- flag = flags_internal::FindCommandLineFlag(flag_name);
+ flag = absl::FindCommandLineFlag(flag_name);
is_negative = true;
}
@@ -271,18 +307,17 @@
// back.
void CheckDefaultValuesParsingRoundtrip() {
#ifndef NDEBUG
- flags_internal::ForEachFlag([&](CommandLineFlag* flag) {
- if (flag->IsRetired()) return;
+ flags_internal::ForEachFlag([&](CommandLineFlag& flag) {
+ if (flag.IsRetired()) return;
-#define IGNORE_TYPE(T) \
- if (flag->IsOfType<T>()) return;
+#define ABSL_FLAGS_INTERNAL_IGNORE_TYPE(T, _) \
+ if (flag.IsOfType<T>()) return;
- ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(IGNORE_TYPE)
- IGNORE_TYPE(std::string)
- IGNORE_TYPE(std::vector<std::string>)
-#undef IGNORE_TYPE
+ ABSL_FLAGS_INTERNAL_SUPPORTED_TYPES(ABSL_FLAGS_INTERNAL_IGNORE_TYPE)
+#undef ABSL_FLAGS_INTERNAL_IGNORE_TYPE
- flag->CheckDefaultValueParsingRoundtrip();
+ flags_internal::PrivateHandleAccessor::CheckDefaultValueParsingRoundtrip(
+ flag);
});
#endif
}
@@ -295,13 +330,13 @@
// the first flagfile in the input list are processed before the second flagfile
// etc.
bool ReadFlagfiles(const std::vector<std::string>& flagfiles,
- std::vector<ArgsList>* input_args) {
+ std::vector<ArgsList>& input_args) {
bool success = true;
for (auto it = flagfiles.rbegin(); it != flagfiles.rend(); ++it) {
ArgsList al;
if (al.ReadFromFlagfile(*it)) {
- input_args->push_back(al);
+ input_args.push_back(al);
} else {
success = false;
}
@@ -316,7 +351,7 @@
// `flag_name` is a string from the input flag_names list. If successful we
// append a single ArgList at the end of the input_args.
bool ReadFlagsFromEnv(const std::vector<std::string>& flag_names,
- std::vector<ArgsList>* input_args,
+ std::vector<ArgsList>& input_args,
bool fail_on_absent_in_env) {
bool success = true;
std::vector<std::string> args;
@@ -337,7 +372,7 @@
const std::string envname = absl::StrCat("FLAGS_", flag_name);
std::string envval;
- if (!GetEnvVar(envname.c_str(), &envval)) {
+ if (!GetEnvVar(envname.c_str(), envval)) {
if (fail_on_absent_in_env) {
flags_internal::ReportUsageError(
absl::StrCat(envname, " not found in environment"), true);
@@ -352,7 +387,7 @@
}
if (success) {
- input_args->emplace_back(args);
+ input_args.emplace_back(args);
}
return success;
@@ -362,8 +397,8 @@
// Returns success status, which is true if were able to handle all generator
// flags (flagfile, fromenv, tryfromemv) successfully.
-bool HandleGeneratorFlags(std::vector<ArgsList>* input_args,
- std::vector<std::string>* flagfile_value) {
+bool HandleGeneratorFlags(std::vector<ArgsList>& input_args,
+ std::vector<std::string>& flagfile_value) {
bool success = true;
absl::MutexLock l(&flags_internal::processing_checks_guard);
@@ -388,9 +423,9 @@
if (flags_internal::flagfile_needs_processing) {
auto flagfiles = absl::GetFlag(FLAGS_flagfile);
- if (input_args->size() == 1) {
- flagfile_value->insert(flagfile_value->end(), flagfiles.begin(),
- flagfiles.end());
+ if (input_args.size() == 1) {
+ flagfile_value.insert(flagfile_value.end(), flagfiles.begin(),
+ flagfiles.end());
}
success &= ReadFlagfiles(flagfiles, input_args);
@@ -517,12 +552,12 @@
curr_list->PopFront();
value = curr_list->Front();
- // Heuristic to detect the case where someone treats a std::string arg
+ // Heuristic to detect the case where someone treats a string arg
// like a bool or just forgets to pass a value:
// --my_string_var --foo=bar
- // We look for a flag of std::string type, whose value begins with a
+ // We look for a flag of string type, whose value begins with a
// dash and corresponds to known flag or standalone --.
- if (value[0] == '-' && flag.IsOfType<std::string>()) {
+ if (!value.empty() && value[0] == '-' && flag.IsOfType<std::string>()) {
auto maybe_flag_name = std::get<0>(SplitNameAndValue(value.substr(1)));
if (maybe_flag_name.empty() ||
@@ -559,12 +594,28 @@
// --------------------------------------------------------------------
+bool WasPresentOnCommandLine(absl::string_view flag_name) {
+ absl::MutexLock l(&specified_flags_guard);
+ ABSL_INTERNAL_CHECK(specified_flags != nullptr,
+ "ParseCommandLine is not invoked yet");
+
+ return std::binary_search(specified_flags->begin(), specified_flags->end(),
+ flag_name, SpecifiedFlagsCompare{});
+}
+
+// --------------------------------------------------------------------
+
std::vector<char*> ParseCommandLineImpl(int argc, char* argv[],
ArgvListAction arg_list_act,
UsageFlagsAction usage_flag_act,
OnUndefinedFlag on_undef_flag) {
ABSL_INTERNAL_CHECK(argc > 0, "Missing argv[0]");
+ // Once parsing has started we will not have more flag registrations.
+ // If we did, they would be missing during parsing, which is a problem on
+ // itself.
+ flags_internal::FinalizeRegistry();
+
// This routine does not return anything since we abort on failure.
CheckDefaultValuesParsingRoundtrip();
@@ -589,13 +640,20 @@
}
output_args.push_back(argv[0]);
+ absl::MutexLock l(&specified_flags_guard);
+ if (specified_flags == nullptr) {
+ specified_flags = new std::vector<const CommandLineFlag*>;
+ } else {
+ specified_flags->clear();
+ }
+
// Iterate through the list of the input arguments. First level are arguments
// originated from argc/argv. Following levels are arguments originated from
// recursive parsing of flagfile(s).
bool success = true;
while (!input_args.empty()) {
// 10. First we process the built-in generator flags.
- success &= HandleGeneratorFlags(&input_args, &flagfile_value);
+ success &= HandleGeneratorFlags(input_args, flagfile_value);
// 30. Select top-most (most recent) arguments list. If it is empty drop it
// and re-try.
@@ -630,7 +688,7 @@
// 60. Split the current argument on '=' to figure out the argument
// name and value. If flag name is empty it means we've got "--". value
- // can be empty either if there were no '=' in argument std::string at all or
+ // can be empty either if there were no '=' in argument string at all or
// an argument looked like "--foo=". In a latter case is_empty_value is
// true.
absl::string_view flag_name;
@@ -655,6 +713,11 @@
std::tie(flag, is_negative) = LocateFlag(flag_name);
if (flag == nullptr) {
+ // Usage flags are not modeled as Abseil flags. Locate them separately.
+ if (flags_internal::DeduceUsageFlags(flag_name, value)) {
+ continue;
+ }
+
if (on_undef_flag != OnUndefinedFlag::kIgnoreUndefined) {
undefined_flag_names.emplace_back(arg_from_argv,
std::string(flag_name));
@@ -676,13 +739,17 @@
}
// 100. Set the located flag to a new new value, unless it is retired.
- // Setting retired flag fails, but we ignoring it here.
- if (flag->IsRetired()) continue;
-
+ // Setting retired flag fails, but we ignoring it here while also reporting
+ // access to retired flag.
std::string error;
- if (!flag->SetFromString(value, SET_FLAGS_VALUE, kCommandLine, &error)) {
+ if (!flags_internal::PrivateHandleAccessor::ParseFrom(
+ *flag, value, SET_FLAGS_VALUE, kCommandLine, error)) {
+ if (flag->IsRetired()) continue;
+
flags_internal::ReportUsageError(error, true);
success = false;
+ } else {
+ specified_flags->push_back(flag);
}
}
@@ -734,6 +801,10 @@
}
}
+ // Trim and sort the vector.
+ specified_flags->shrink_to_fit();
+ std::sort(specified_flags->begin(), specified_flags->end(),
+ SpecifiedFlagsCompare{});
return output_args;
}
@@ -748,4 +819,5 @@
flags_internal::OnUndefinedFlag::kAbortIfUndefined);
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/flags/parse.h b/third_party/abseil/absl/flags/parse.h
index dbb7510..929de2c 100644
--- a/third_party/abseil/absl/flags/parse.h
+++ b/third_party/abseil/absl/flags/parse.h
@@ -23,12 +23,13 @@
#ifndef ABSL_FLAGS_PARSE_H_
#define ABSL_FLAGS_PARSE_H_
-#include <string>
#include <vector>
+#include "absl/base/config.h"
#include "absl/flags/internal/parse.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// ParseCommandLine()
//
@@ -53,6 +54,7 @@
// help messages and then exits the program.
std::vector<char*> ParseCommandLine(int argc, char* argv[]);
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_FLAGS_PARSE_H_
diff --git a/third_party/abseil/absl/flags/parse_test.cc b/third_party/abseil/absl/flags/parse_test.cc
index 447a3bc..41bc0bc 100644
--- a/third_party/abseil/absl/flags/parse_test.cc
+++ b/third_party/abseil/absl/flags/parse_test.cc
@@ -15,14 +15,23 @@
#include "absl/flags/parse.h"
+#include <stdlib.h>
+
#include <fstream>
+#include <string>
+#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/scoped_set_env.h"
+#include "absl/flags/declare.h"
#include "absl/flags/flag.h"
+#include "absl/flags/internal/parse.h"
+#include "absl/flags/internal/usage.h"
+#include "absl/flags/reflection.h"
#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
#include "absl/strings/substitute.h"
#include "absl/types/span.h"
@@ -92,8 +101,11 @@
auto len = GetTempPathA(MAX_PATH, temp_path_buffer);
if (len < MAX_PATH && len != 0) {
- std::string temp_dir_name = absl::StrCat(
- temp_path_buffer, "\\parse_test.", GetCurrentProcessId());
+ std::string temp_dir_name = temp_path_buffer;
+ if (!absl::EndsWith(temp_dir_name, "\\")) {
+ temp_dir_name.push_back('\\');
+ }
+ absl::StrAppend(&temp_dir_name, "parse_test.", GetCurrentProcessId());
if (CreateDirectoryA(temp_dir_name.c_str(), nullptr)) {
*res = temp_dir_name;
}
@@ -104,11 +116,11 @@
*res = unique_name;
}
#endif
+ }
- if (res->empty()) {
- ABSL_INTERNAL_LOG(FATAL,
- "Failed to make temporary directory for data files");
- }
+ if (res->empty()) {
+ ABSL_INTERNAL_LOG(FATAL,
+ "Failed to make temporary directory for data files");
}
#ifdef _WIN32
@@ -160,8 +172,8 @@
// temporary directory location. This way we can test inclusion of one flagfile
// from another flagfile.
const char* GetFlagfileFlag(const std::vector<FlagfileData>& ffd,
- std::string* flagfile_flag) {
- *flagfile_flag = "--flagfile=";
+ std::string& flagfile_flag) {
+ flagfile_flag = "--flagfile=";
absl::string_view separator;
for (const auto& flagfile_data : ffd) {
std::string flagfile_name =
@@ -172,11 +184,11 @@
flagfile_out << absl::Substitute(line, GetTestTempDir()) << "\n";
}
- absl::StrAppend(flagfile_flag, separator, flagfile_name);
+ absl::StrAppend(&flagfile_flag, separator, flagfile_name);
separator = ",";
}
- return flagfile_flag->c_str();
+ return flagfile_flag.c_str();
}
} // namespace
@@ -196,8 +208,11 @@
using testing::ElementsAreArray;
class ParseTest : public testing::Test {
+ public:
+ ~ParseTest() override { flags::SetFlagsHelpMode(flags::HelpMode::kNone); }
+
private:
- flags::FlagSaver flag_saver_;
+ absl::FlagSaver flag_saver_;
};
// --------------------------------------------------------------------
@@ -470,21 +485,22 @@
"testbin",
"--undefined_flag",
};
- EXPECT_DEATH(InvokeParse(in_args1),
- "Unknown command line flag 'undefined_flag'");
+ EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1),
+ "Unknown command line flag 'undefined_flag'");
const char* in_args2[] = {
"testbin",
"--noprefixed_flag",
};
- EXPECT_DEATH(InvokeParse(in_args2),
- "Unknown command line flag 'noprefixed_flag'");
+ EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args2),
+ "Unknown command line flag 'noprefixed_flag'");
const char* in_args3[] = {
"testbin",
"--Int_flag=1",
};
- EXPECT_DEATH(InvokeParse(in_args3), "Unknown command line flag 'Int_flag'");
+ EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args3),
+ "Unknown command line flag 'Int_flag'");
}
// --------------------------------------------------------------------
@@ -494,7 +510,7 @@
"testbin",
"--bool_flag=",
};
- EXPECT_DEATH(
+ EXPECT_DEATH_IF_SUPPORTED(
InvokeParse(in_args1),
"Missing the value after assignment for the boolean flag 'bool_flag'");
@@ -502,7 +518,7 @@
"testbin",
"--nobool_flag=true",
};
- EXPECT_DEATH(InvokeParse(in_args2),
+ EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args2),
"Negative form with assignment is not valid for the boolean "
"flag 'bool_flag'");
}
@@ -514,14 +530,14 @@
"testbin",
"--nostring_flag",
};
- EXPECT_DEATH(InvokeParse(in_args1),
+ EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1),
"Negative form is not valid for the flag 'string_flag'");
const char* in_args2[] = {
"testbin",
"--int_flag",
};
- EXPECT_DEATH(InvokeParse(in_args2),
+ EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args2),
"Missing the value for the flag 'int_flag'");
}
@@ -532,7 +548,7 @@
"testbin",
"--udt_flag=1",
};
- EXPECT_DEATH(InvokeParse(in_args1),
+ EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1),
"Illegal value '1' specified for flag 'udt_flag'; Use values A, "
"AAA instead");
@@ -541,7 +557,7 @@
"--udt_flag",
"AA",
};
- EXPECT_DEATH(InvokeParse(in_args2),
+ EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args2),
"Illegal value 'AA' specified for flag 'udt_flag'; Use values "
"A, AAA instead");
}
@@ -576,14 +592,14 @@
const char* in_args1[] = {
"testbin",
GetFlagfileFlag({{"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
- &flagfile_flag),
+ flagfile_flag),
};
TestParse(in_args1, -1, 0.1, "q2w2 ", true);
const char* in_args2[] = {
"testbin",
GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)}},
- &flagfile_flag),
+ flagfile_flag),
};
TestParse(in_args2, 100, 0.1, "q2w2 ", false);
}
@@ -597,7 +613,7 @@
"testbin",
GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)},
{"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
- &flagfile_flag),
+ flagfile_flag),
};
TestParse(in_args1, -1, 0.1, "q2w2 ", true);
}
@@ -610,7 +626,7 @@
const char* in_args1[] = {
"testbin", "--int_flag=3",
GetFlagfileFlag({{"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
- &flagfile_flag),
+ flagfile_flag),
"-double_flag=0.2"};
TestParse(in_args1, -1, 0.2, "q2w2 ", true);
}
@@ -625,10 +641,14 @@
"--flagfile=$0/parse_test.ff2",
};
+ GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)},
+ {"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
+ flagfile_flag);
+
const char* in_args1[] = {
"testbin",
GetFlagfileFlag({{"parse_test.ff3", absl::MakeConstSpan(ff3_data)}},
- &flagfile_flag),
+ flagfile_flag),
};
TestParse(in_args1, 100, 0.1, "q2w2 ", false);
}
@@ -645,9 +665,9 @@
const char* in_args1[] = {
"testbin",
GetFlagfileFlag({{"parse_test.ff4",
- absl::MakeConstSpan(ff4_data)}}, &flagfile_flag),
+ absl::MakeConstSpan(ff4_data)}}, flagfile_flag),
};
- EXPECT_DEATH(InvokeParse(in_args1),
+ EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1),
"Unknown command line flag 'unknown_flag'");
constexpr const char* const ff5_data[] = {
@@ -657,9 +677,9 @@
const char* in_args2[] = {
"testbin",
GetFlagfileFlag({{"parse_test.ff5",
- absl::MakeConstSpan(ff5_data)}}, &flagfile_flag),
+ absl::MakeConstSpan(ff5_data)}}, flagfile_flag),
};
- EXPECT_DEATH(InvokeParse(in_args2),
+ EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args2),
"Unknown command line flag 'int_flag 10'");
constexpr const char* const ff6_data[] = {
@@ -669,16 +689,17 @@
const char* in_args3[] = {
"testbin",
GetFlagfileFlag({{"parse_test.ff6", absl::MakeConstSpan(ff6_data)}},
- &flagfile_flag),
+ flagfile_flag),
};
- EXPECT_DEATH(InvokeParse(in_args3),
+ EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args3),
"Flagfile can't contain position arguments or --");
const char* in_args4[] = {
"testbin",
"--flagfile=invalid_flag_file",
};
- EXPECT_DEATH(InvokeParse(in_args4), "Can't open flagfile invalid_flag_file");
+ EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args4),
+ "Can't open flagfile invalid_flag_file");
constexpr const char* const ff7_data[] = {
"--int_flag=10",
@@ -689,9 +710,9 @@
const char* in_args5[] = {
"testbin",
GetFlagfileFlag({{"parse_test.ff7", absl::MakeConstSpan(ff7_data)}},
- &flagfile_flag),
+ flagfile_flag),
};
- EXPECT_DEATH(InvokeParse(in_args5),
+ EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args5),
"Unexpected line in the flagfile .*: \\*bin\\*");
}
@@ -713,7 +734,7 @@
TEST_F(ParseDeathTest, TestReadingUnsetRequiredFlagsFromEnv) {
const char* in_args1[] = {"testbin", "--fromenv=int_flag"};
- EXPECT_DEATH(InvokeParse(in_args1),
+ EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1),
"FLAGS_int_flag not found in environment");
}
@@ -724,7 +745,8 @@
ScopedSetEnv set_tryfromenv("FLAGS_tryfromenv", "int_flag");
- EXPECT_DEATH(InvokeParse(in_args1), "Infinite recursion on flag tryfromenv");
+ EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1),
+ "Infinite recursion on flag tryfromenv");
}
// --------------------------------------------------------------------
@@ -833,7 +855,7 @@
// --------------------------------------------------------------------
-TEST_F(ParseDeathTest, TestHelpFlagHandling) {
+TEST_F(ParseDeathTest, TestSimpleHelpFlagHandling) {
const char* in_args1[] = {
"testbin",
"--help",
@@ -852,7 +874,56 @@
flags::UsageFlagsAction::kIgnoreUsage,
flags::OnUndefinedFlag::kAbortIfUndefined);
+ EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kImportant);
EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 3);
}
+// --------------------------------------------------------------------
+
+TEST_F(ParseDeathTest, TestSubstringHelpFlagHandling) {
+ const char* in_args1[] = {
+ "testbin",
+ "--help=abcd",
+ };
+
+ auto out_args1 = flags::ParseCommandLineImpl(
+ 2, const_cast<char**>(in_args1), flags::ArgvListAction::kRemoveParsedArgs,
+ flags::UsageFlagsAction::kIgnoreUsage,
+ flags::OnUndefinedFlag::kAbortIfUndefined);
+
+ EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kMatch);
+ EXPECT_EQ(flags::GetFlagsHelpMatchSubstr(), "abcd");
+
+ const char* in_args2[] = {"testbin", "--help", "some_positional_arg"};
+
+ auto out_args2 = flags::ParseCommandLineImpl(
+ 3, const_cast<char**>(in_args2), flags::ArgvListAction::kRemoveParsedArgs,
+ flags::UsageFlagsAction::kIgnoreUsage,
+ flags::OnUndefinedFlag::kAbortIfUndefined);
+
+ EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kImportant);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, WasPresentOnCommandLine) {
+ const char* in_args1[] = {
+ "testbin", "arg1", "--bool_flag",
+ "--int_flag=211", "arg2", "--double_flag=1.1",
+ "--string_flag", "asd", "--",
+ "--some_flag", "arg4",
+ };
+
+ InvokeParse(in_args1);
+
+ EXPECT_TRUE(flags::WasPresentOnCommandLine("bool_flag"));
+ EXPECT_TRUE(flags::WasPresentOnCommandLine("int_flag"));
+ EXPECT_TRUE(flags::WasPresentOnCommandLine("double_flag"));
+ EXPECT_TRUE(flags::WasPresentOnCommandLine("string_flag"));
+ EXPECT_FALSE(flags::WasPresentOnCommandLine("some_flag"));
+ EXPECT_FALSE(flags::WasPresentOnCommandLine("another_flag"));
+}
+
+// --------------------------------------------------------------------
+
} // namespace
diff --git a/third_party/abseil/absl/flags/reflection.cc b/third_party/abseil/absl/flags/reflection.cc
new file mode 100644
index 0000000..c976d46
--- /dev/null
+++ b/third_party/abseil/absl/flags/reflection.cc
@@ -0,0 +1,337 @@
+//
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/flags/reflection.h"
+
+#include <assert.h>
+
+#include <atomic>
+#include <map>
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/base/thread_annotations.h"
+#include "absl/flags/commandlineflag.h"
+#include "absl/flags/internal/private_handle_accessor.h"
+#include "absl/flags/internal/registry.h"
+#include "absl/flags/usage_config.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace flags_internal {
+
+// --------------------------------------------------------------------
+// FlagRegistry
+// A FlagRegistry singleton object holds all flag objects indexed by their
+// names so that if you know a flag's name, you can access or set it. If the
+// function is named FooLocked(), you must own the registry lock before
+// calling the function; otherwise, you should *not* hold the lock, and the
+// function will acquire it itself if needed.
+// --------------------------------------------------------------------
+
+class FlagRegistry {
+ public:
+ FlagRegistry() = default;
+ ~FlagRegistry() = default;
+
+ // Store a flag in this registry. Takes ownership of *flag.
+ void RegisterFlag(CommandLineFlag& flag);
+
+ void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION(lock_) { lock_.Lock(); }
+ void Unlock() ABSL_UNLOCK_FUNCTION(lock_) { lock_.Unlock(); }
+
+ // Returns the flag object for the specified name, or nullptr if not found.
+ // Will emit a warning if a 'retired' flag is specified.
+ CommandLineFlag* FindFlag(absl::string_view name);
+
+ static FlagRegistry& GlobalRegistry(); // returns a singleton registry
+
+ private:
+ friend class flags_internal::FlagSaverImpl; // reads all the flags in order
+ // to copy them
+ friend void ForEachFlag(std::function<void(CommandLineFlag&)> visitor);
+ friend void FinalizeRegistry();
+
+ // The map from name to flag, for FindFlag().
+ using FlagMap = std::map<absl::string_view, CommandLineFlag*>;
+ using FlagIterator = FlagMap::iterator;
+ using FlagConstIterator = FlagMap::const_iterator;
+ FlagMap flags_;
+ std::vector<CommandLineFlag*> flat_flags_;
+ std::atomic<bool> finalized_flags_{false};
+
+ absl::Mutex lock_;
+
+ // Disallow
+ FlagRegistry(const FlagRegistry&);
+ FlagRegistry& operator=(const FlagRegistry&);
+};
+
+namespace {
+
+class FlagRegistryLock {
+ public:
+ explicit FlagRegistryLock(FlagRegistry& fr) : fr_(fr) { fr_.Lock(); }
+ ~FlagRegistryLock() { fr_.Unlock(); }
+
+ private:
+ FlagRegistry& fr_;
+};
+
+} // namespace
+
+CommandLineFlag* FlagRegistry::FindFlag(absl::string_view name) {
+ if (finalized_flags_.load(std::memory_order_acquire)) {
+ // We could save some gcus here if we make `Name()` be non-virtual.
+ // We could move the `const char*` name to the base class.
+ auto it = std::partition_point(
+ flat_flags_.begin(), flat_flags_.end(),
+ [=](CommandLineFlag* f) { return f->Name() < name; });
+ if (it != flat_flags_.end() && (*it)->Name() == name) return *it;
+ }
+
+ FlagRegistryLock frl(*this);
+ auto it = flags_.find(name);
+ return it != flags_.end() ? it->second : nullptr;
+}
+
+void FlagRegistry::RegisterFlag(CommandLineFlag& flag) {
+ FlagRegistryLock registry_lock(*this);
+
+ std::pair<FlagIterator, bool> ins =
+ flags_.insert(FlagMap::value_type(flag.Name(), &flag));
+ if (ins.second == false) { // means the name was already in the map
+ CommandLineFlag& old_flag = *ins.first->second;
+ if (flag.IsRetired() != old_flag.IsRetired()) {
+ // All registrations must agree on the 'retired' flag.
+ flags_internal::ReportUsageError(
+ absl::StrCat(
+ "Retired flag '", flag.Name(), "' was defined normally in file '",
+ (flag.IsRetired() ? old_flag.Filename() : flag.Filename()), "'."),
+ true);
+ } else if (flags_internal::PrivateHandleAccessor::TypeId(flag) !=
+ flags_internal::PrivateHandleAccessor::TypeId(old_flag)) {
+ flags_internal::ReportUsageError(
+ absl::StrCat("Flag '", flag.Name(),
+ "' was defined more than once but with "
+ "differing types. Defined in files '",
+ old_flag.Filename(), "' and '", flag.Filename(), "'."),
+ true);
+ } else if (old_flag.IsRetired()) {
+ return;
+ } else if (old_flag.Filename() != flag.Filename()) {
+ flags_internal::ReportUsageError(
+ absl::StrCat("Flag '", flag.Name(),
+ "' was defined more than once (in files '",
+ old_flag.Filename(), "' and '", flag.Filename(), "')."),
+ true);
+ } else {
+ flags_internal::ReportUsageError(
+ absl::StrCat(
+ "Something is wrong with flag '", flag.Name(), "' in file '",
+ flag.Filename(), "'. One possibility: file '", flag.Filename(),
+ "' is being linked both statically and dynamically into this "
+ "executable. e.g. some files listed as srcs to a test and also "
+ "listed as srcs of some shared lib deps of the same test."),
+ true);
+ }
+ // All cases above are fatal, except for the retired flags.
+ std::exit(1);
+ }
+}
+
+FlagRegistry& FlagRegistry::GlobalRegistry() {
+ static FlagRegistry* global_registry = new FlagRegistry;
+ return *global_registry;
+}
+
+// --------------------------------------------------------------------
+
+void ForEachFlag(std::function<void(CommandLineFlag&)> visitor) {
+ FlagRegistry& registry = FlagRegistry::GlobalRegistry();
+
+ if (registry.finalized_flags_.load(std::memory_order_acquire)) {
+ for (const auto& i : registry.flat_flags_) visitor(*i);
+ }
+
+ FlagRegistryLock frl(registry);
+ for (const auto& i : registry.flags_) visitor(*i.second);
+}
+
+// --------------------------------------------------------------------
+
+bool RegisterCommandLineFlag(CommandLineFlag& flag) {
+ FlagRegistry::GlobalRegistry().RegisterFlag(flag);
+ return true;
+}
+
+void FinalizeRegistry() {
+ auto& registry = FlagRegistry::GlobalRegistry();
+ FlagRegistryLock frl(registry);
+ if (registry.finalized_flags_.load(std::memory_order_relaxed)) {
+ // Was already finalized. Ignore the second time.
+ return;
+ }
+ registry.flat_flags_.reserve(registry.flags_.size());
+ for (const auto& f : registry.flags_) {
+ registry.flat_flags_.push_back(f.second);
+ }
+ registry.flags_.clear();
+ registry.finalized_flags_.store(true, std::memory_order_release);
+}
+
+// --------------------------------------------------------------------
+
+namespace {
+
+class RetiredFlagObj final : public CommandLineFlag {
+ public:
+ constexpr RetiredFlagObj(const char* name, FlagFastTypeId type_id)
+ : name_(name), type_id_(type_id) {}
+
+ private:
+ absl::string_view Name() const override { return name_; }
+ std::string Filename() const override {
+ OnAccess();
+ return "RETIRED";
+ }
+ FlagFastTypeId TypeId() const override { return type_id_; }
+ std::string Help() const override {
+ OnAccess();
+ return "";
+ }
+ bool IsRetired() const override { return true; }
+ bool IsSpecifiedOnCommandLine() const override {
+ OnAccess();
+ return false;
+ }
+ std::string DefaultValue() const override {
+ OnAccess();
+ return "";
+ }
+ std::string CurrentValue() const override {
+ OnAccess();
+ return "";
+ }
+
+ // Any input is valid
+ bool ValidateInputValue(absl::string_view) const override {
+ OnAccess();
+ return true;
+ }
+
+ std::unique_ptr<flags_internal::FlagStateInterface> SaveState() override {
+ return nullptr;
+ }
+
+ bool ParseFrom(absl::string_view, flags_internal::FlagSettingMode,
+ flags_internal::ValueSource, std::string&) override {
+ OnAccess();
+ return false;
+ }
+
+ void CheckDefaultValueParsingRoundtrip() const override { OnAccess(); }
+
+ void Read(void*) const override { OnAccess(); }
+
+ void OnAccess() const {
+ flags_internal::ReportUsageError(
+ absl::StrCat("Accessing retired flag '", name_, "'"), false);
+ }
+
+ // Data members
+ const char* const name_;
+ const FlagFastTypeId type_id_;
+};
+
+} // namespace
+
+void Retire(const char* name, FlagFastTypeId type_id, char* buf) {
+ static_assert(sizeof(RetiredFlagObj) == kRetiredFlagObjSize, "");
+ static_assert(alignof(RetiredFlagObj) == kRetiredFlagObjAlignment, "");
+ auto* flag = ::new (static_cast<void*>(buf))
+ flags_internal::RetiredFlagObj(name, type_id);
+ FlagRegistry::GlobalRegistry().RegisterFlag(*flag);
+}
+
+// --------------------------------------------------------------------
+
+class FlagSaverImpl {
+ public:
+ FlagSaverImpl() = default;
+ FlagSaverImpl(const FlagSaverImpl&) = delete;
+ void operator=(const FlagSaverImpl&) = delete;
+
+ // Saves the flag states from the flag registry into this object.
+ // It's an error to call this more than once.
+ void SaveFromRegistry() {
+ assert(backup_registry_.empty()); // call only once!
+ flags_internal::ForEachFlag([&](CommandLineFlag& flag) {
+ if (auto flag_state =
+ flags_internal::PrivateHandleAccessor::SaveState(flag)) {
+ backup_registry_.emplace_back(std::move(flag_state));
+ }
+ });
+ }
+
+ // Restores the saved flag states into the flag registry.
+ void RestoreToRegistry() {
+ for (const auto& flag_state : backup_registry_) {
+ flag_state->Restore();
+ }
+ }
+
+ private:
+ std::vector<std::unique_ptr<flags_internal::FlagStateInterface>>
+ backup_registry_;
+};
+
+} // namespace flags_internal
+
+FlagSaver::FlagSaver() : impl_(new flags_internal::FlagSaverImpl) {
+ impl_->SaveFromRegistry();
+}
+
+FlagSaver::~FlagSaver() {
+ if (!impl_) return;
+
+ impl_->RestoreToRegistry();
+ delete impl_;
+}
+
+// --------------------------------------------------------------------
+
+CommandLineFlag* FindCommandLineFlag(absl::string_view name) {
+ if (name.empty()) return nullptr;
+ flags_internal::FlagRegistry& registry =
+ flags_internal::FlagRegistry::GlobalRegistry();
+ return registry.FindFlag(name);
+}
+
+// --------------------------------------------------------------------
+
+absl::flat_hash_map<absl::string_view, absl::CommandLineFlag*> GetAllFlags() {
+ absl::flat_hash_map<absl::string_view, absl::CommandLineFlag*> res;
+ flags_internal::ForEachFlag([&](CommandLineFlag& flag) {
+ if (!flag.IsRetired()) res.insert({flag.Name(), &flag});
+ });
+ return res;
+}
+
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/flags/reflection.h b/third_party/abseil/absl/flags/reflection.h
new file mode 100644
index 0000000..e6baf5d
--- /dev/null
+++ b/third_party/abseil/absl/flags/reflection.h
@@ -0,0 +1,90 @@
+//
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: reflection.h
+// -----------------------------------------------------------------------------
+//
+// This file defines the routines to access and operate on an Abseil Flag's
+// reflection handle.
+
+#ifndef ABSL_FLAGS_REFLECTION_H_
+#define ABSL_FLAGS_REFLECTION_H_
+
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/container/flat_hash_map.h"
+#include "absl/flags/commandlineflag.h"
+#include "absl/flags/internal/commandlineflag.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace flags_internal {
+class FlagSaverImpl;
+} // namespace flags_internal
+
+// FindCommandLineFlag()
+//
+// Returns the reflection handle of an Abseil flag of the specified name, or
+// `nullptr` if not found. This function will emit a warning if the name of a
+// 'retired' flag is specified.
+absl::CommandLineFlag* FindCommandLineFlag(absl::string_view name);
+
+// Returns current state of the Flags registry in a form of mapping from flag
+// name to a flag reflection handle.
+absl::flat_hash_map<absl::string_view, absl::CommandLineFlag*> GetAllFlags();
+
+//------------------------------------------------------------------------------
+// FlagSaver
+//------------------------------------------------------------------------------
+//
+// A FlagSaver object stores the state of flags in the scope where the FlagSaver
+// is defined, allowing modification of those flags within that scope and
+// automatic restoration of the flags to their previous state upon leaving the
+// scope.
+//
+// A FlagSaver can be used within tests to temporarily change the test
+// environment and restore the test case to its previous state.
+//
+// Example:
+//
+// void MyFunc() {
+// absl::FlagSaver fs;
+// ...
+// absl::SetFlag(&FLAGS_myFlag, otherValue);
+// ...
+// } // scope of FlagSaver left, flags return to previous state
+//
+// This class is thread-safe.
+
+class FlagSaver {
+ public:
+ FlagSaver();
+ ~FlagSaver();
+
+ FlagSaver(const FlagSaver&) = delete;
+ void operator=(const FlagSaver&) = delete;
+
+ private:
+ flags_internal::FlagSaverImpl* impl_;
+};
+
+//-----------------------------------------------------------------------------
+
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_FLAGS_REFLECTION_H_
diff --git a/third_party/abseil/absl/flags/reflection_test.cc b/third_party/abseil/absl/flags/reflection_test.cc
new file mode 100644
index 0000000..4c80900
--- /dev/null
+++ b/third_party/abseil/absl/flags/reflection_test.cc
@@ -0,0 +1,267 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/flags/reflection.h"
+
+#include <memory>
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/flags/declare.h"
+#include "absl/flags/flag.h"
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/flags/marshalling.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_split.h"
+
+ABSL_FLAG(int, int_flag, 1, "int_flag help");
+ABSL_FLAG(std::string, string_flag, "dflt", "string_flag help");
+ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help");
+
+namespace {
+
+namespace flags = absl::flags_internal;
+
+class ReflectionTest : public testing::Test {
+ protected:
+ void SetUp() override { flag_saver_ = absl::make_unique<absl::FlagSaver>(); }
+ void TearDown() override { flag_saver_.reset(); }
+
+ private:
+ std::unique_ptr<absl::FlagSaver> flag_saver_;
+};
+
+// --------------------------------------------------------------------
+
+TEST_F(ReflectionTest, TestFindCommandLineFlag) {
+ auto* handle = absl::FindCommandLineFlag("some_flag");
+ EXPECT_EQ(handle, nullptr);
+
+ handle = absl::FindCommandLineFlag("int_flag");
+ EXPECT_NE(handle, nullptr);
+
+ handle = absl::FindCommandLineFlag("string_flag");
+ EXPECT_NE(handle, nullptr);
+
+ handle = absl::FindCommandLineFlag("bool_retired_flag");
+ EXPECT_NE(handle, nullptr);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ReflectionTest, TestGetAllFlags) {
+ auto all_flags = absl::GetAllFlags();
+ EXPECT_NE(all_flags.find("int_flag"), all_flags.end());
+ EXPECT_EQ(all_flags.find("bool_retired_flag"), all_flags.end());
+ EXPECT_EQ(all_flags.find("some_undefined_flag"), all_flags.end());
+
+ std::vector<absl::string_view> flag_names_first_attempt;
+ auto all_flags_1 = absl::GetAllFlags();
+ for (auto f : all_flags_1) {
+ flag_names_first_attempt.push_back(f.first);
+ }
+
+ std::vector<absl::string_view> flag_names_second_attempt;
+ auto all_flags_2 = absl::GetAllFlags();
+ for (auto f : all_flags_2) {
+ flag_names_second_attempt.push_back(f.first);
+ }
+
+ EXPECT_THAT(flag_names_first_attempt,
+ ::testing::UnorderedElementsAreArray(flag_names_second_attempt));
+}
+
+// --------------------------------------------------------------------
+
+struct CustomUDT {
+ CustomUDT() : a(1), b(1) {}
+ CustomUDT(int a_, int b_) : a(a_), b(b_) {}
+
+ friend bool operator==(const CustomUDT& f1, const CustomUDT& f2) {
+ return f1.a == f2.a && f1.b == f2.b;
+ }
+
+ int a;
+ int b;
+};
+bool AbslParseFlag(absl::string_view in, CustomUDT* f, std::string*) {
+ std::vector<absl::string_view> parts =
+ absl::StrSplit(in, ':', absl::SkipWhitespace());
+
+ if (parts.size() != 2) return false;
+
+ if (!absl::SimpleAtoi(parts[0], &f->a)) return false;
+
+ if (!absl::SimpleAtoi(parts[1], &f->b)) return false;
+
+ return true;
+}
+std::string AbslUnparseFlag(const CustomUDT& f) {
+ return absl::StrCat(f.a, ":", f.b);
+}
+
+} // namespace
+
+// --------------------------------------------------------------------
+
+ABSL_FLAG(bool, test_flag_01, true, "");
+ABSL_FLAG(int, test_flag_02, 1234, "");
+ABSL_FLAG(int16_t, test_flag_03, -34, "");
+ABSL_FLAG(uint16_t, test_flag_04, 189, "");
+ABSL_FLAG(int32_t, test_flag_05, 10765, "");
+ABSL_FLAG(uint32_t, test_flag_06, 40000, "");
+ABSL_FLAG(int64_t, test_flag_07, -1234567, "");
+ABSL_FLAG(uint64_t, test_flag_08, 9876543, "");
+ABSL_FLAG(double, test_flag_09, -9.876e-50, "");
+ABSL_FLAG(float, test_flag_10, 1.234e12f, "");
+ABSL_FLAG(std::string, test_flag_11, "", "");
+ABSL_FLAG(absl::Duration, test_flag_12, absl::Minutes(10), "");
+static int counter = 0;
+ABSL_FLAG(int, test_flag_13, 200, "").OnUpdate([]() { counter++; });
+ABSL_FLAG(CustomUDT, test_flag_14, {}, "");
+
+namespace {
+
+TEST_F(ReflectionTest, TestFlagSaverInScope) {
+ {
+ absl::FlagSaver s;
+ counter = 0;
+ absl::SetFlag(&FLAGS_test_flag_01, false);
+ absl::SetFlag(&FLAGS_test_flag_02, -1021);
+ absl::SetFlag(&FLAGS_test_flag_03, 6009);
+ absl::SetFlag(&FLAGS_test_flag_04, 44);
+ absl::SetFlag(&FLAGS_test_flag_05, +800);
+ absl::SetFlag(&FLAGS_test_flag_06, -40978756);
+ absl::SetFlag(&FLAGS_test_flag_07, 23405);
+ absl::SetFlag(&FLAGS_test_flag_08, 975310);
+ absl::SetFlag(&FLAGS_test_flag_09, 1.00001);
+ absl::SetFlag(&FLAGS_test_flag_10, -3.54f);
+ absl::SetFlag(&FLAGS_test_flag_11, "asdf");
+ absl::SetFlag(&FLAGS_test_flag_12, absl::Hours(20));
+ absl::SetFlag(&FLAGS_test_flag_13, 4);
+ absl::SetFlag(&FLAGS_test_flag_14, CustomUDT{-1, -2});
+ }
+
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), true);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_03), -34);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_04), 189);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_05), 10765);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_06), 40000);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_07), -1234567);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 9876543);
+ EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_09), -9.876e-50, 1e-55);
+ EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), 1.234e12f, 1e5f);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "");
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Minutes(10));
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), 200);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_14), CustomUDT{});
+ EXPECT_EQ(counter, 2);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ReflectionTest, TestFlagSaverVsUpdateViaReflection) {
+ {
+ absl::FlagSaver s;
+ counter = 0;
+ std::string error;
+ EXPECT_TRUE(
+ absl::FindCommandLineFlag("test_flag_01")->ParseFrom("false", &error))
+ << error;
+ EXPECT_TRUE(
+ absl::FindCommandLineFlag("test_flag_02")->ParseFrom("-4536", &error))
+ << error;
+ EXPECT_TRUE(
+ absl::FindCommandLineFlag("test_flag_03")->ParseFrom("111", &error))
+ << error;
+ EXPECT_TRUE(
+ absl::FindCommandLineFlag("test_flag_04")->ParseFrom("909", &error))
+ << error;
+ EXPECT_TRUE(
+ absl::FindCommandLineFlag("test_flag_05")->ParseFrom("-2004", &error))
+ << error;
+ EXPECT_TRUE(
+ absl::FindCommandLineFlag("test_flag_06")->ParseFrom("1000023", &error))
+ << error;
+ EXPECT_TRUE(
+ absl::FindCommandLineFlag("test_flag_07")->ParseFrom("69305", &error))
+ << error;
+ EXPECT_TRUE(absl::FindCommandLineFlag("test_flag_08")
+ ->ParseFrom("1000000001", &error))
+ << error;
+ EXPECT_TRUE(
+ absl::FindCommandLineFlag("test_flag_09")->ParseFrom("2.09021", &error))
+ << error;
+ EXPECT_TRUE(
+ absl::FindCommandLineFlag("test_flag_10")->ParseFrom("-33.1", &error))
+ << error;
+ EXPECT_TRUE(
+ absl::FindCommandLineFlag("test_flag_11")->ParseFrom("ADD_FOO", &error))
+ << error;
+ EXPECT_TRUE(absl::FindCommandLineFlag("test_flag_12")
+ ->ParseFrom("3h11m16s", &error))
+ << error;
+ EXPECT_TRUE(
+ absl::FindCommandLineFlag("test_flag_13")->ParseFrom("0", &error))
+ << error;
+ EXPECT_TRUE(
+ absl::FindCommandLineFlag("test_flag_14")->ParseFrom("10:1", &error))
+ << error;
+ }
+
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), true);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_03), -34);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_04), 189);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_05), 10765);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_06), 40000);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_07), -1234567);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 9876543);
+ EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_09), -9.876e-50, 1e-55);
+ EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), 1.234e12f, 1e5f);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "");
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), absl::Minutes(10));
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), 200);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_14), CustomUDT{});
+ EXPECT_EQ(counter, 2);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ReflectionTest, TestMultipleFlagSaversInEnclosedScopes) {
+ {
+ absl::FlagSaver s;
+ absl::SetFlag(&FLAGS_test_flag_08, 10);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 10);
+ {
+ absl::FlagSaver s;
+ absl::SetFlag(&FLAGS_test_flag_08, 20);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 20);
+ {
+ absl::FlagSaver s;
+ absl::SetFlag(&FLAGS_test_flag_08, -200);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), -200);
+ }
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 20);
+ }
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 10);
+ }
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 9876543);
+}
+
+} // namespace
diff --git a/third_party/abseil/absl/flags/usage.cc b/third_party/abseil/absl/flags/usage.cc
index dff7a3d..452f667 100644
--- a/third_party/abseil/absl/flags/usage.cc
+++ b/third_party/abseil/absl/flags/usage.cc
@@ -14,12 +14,20 @@
// limitations under the License.
#include "absl/flags/usage.h"
+#include <stdlib.h>
+
#include <string>
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/const_init.h"
+#include "absl/base/thread_annotations.h"
#include "absl/flags/internal/usage.h"
+#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace flags_internal {
namespace {
ABSL_CONST_INIT absl::Mutex usage_message_guard(absl::kConstInit);
@@ -53,4 +61,5 @@
: "Warning: SetProgramUsageMessage() never called";
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/flags/usage.h b/third_party/abseil/absl/flags/usage.h
index 3a12107..ad12ab7 100644
--- a/third_party/abseil/absl/flags/usage.h
+++ b/third_party/abseil/absl/flags/usage.h
@@ -16,12 +16,14 @@
#ifndef ABSL_FLAGS_USAGE_H_
#define ABSL_FLAGS_USAGE_H_
+#include "absl/base/config.h"
#include "absl/strings/string_view.h"
// --------------------------------------------------------------------
// Usage reporting interfaces
namespace absl {
+ABSL_NAMESPACE_BEGIN
// Sets the "usage" message to be used by help reporting routines.
// For example:
@@ -35,6 +37,7 @@
// Returns the usage message set by SetProgramUsageMessage().
absl::string_view ProgramUsageMessage();
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_FLAGS_USAGE_H_
diff --git a/third_party/abseil/absl/flags/usage_config.cc b/third_party/abseil/absl/flags/usage_config.cc
index f97bf30..ae2f548 100644
--- a/third_party/abseil/absl/flags/usage_config.cc
+++ b/third_party/abseil/absl/flags/usage_config.cc
@@ -15,13 +15,18 @@
#include "absl/flags/usage_config.h"
+#include <functional>
#include <iostream>
-#include <memory>
+#include <string>
#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/const_init.h"
+#include "absl/base/thread_annotations.h"
#include "absl/flags/internal/path_util.h"
#include "absl/flags/internal/program_name.h"
-#include "absl/strings/str_cat.h"
+#include "absl/strings/match.h"
+#include "absl/strings/string_view.h"
#include "absl/strings/strip.h"
#include "absl/synchronization/mutex.h"
@@ -34,6 +39,7 @@
} // extern "C"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace flags_internal {
namespace {
@@ -45,10 +51,15 @@
bool ContainsHelpshortFlags(absl::string_view filename) {
// By default we only want flags in binary's main. We expect the main
// routine to reside in <program>.cc or <program>-main.cc or
- // <program>_main.cc, where the <program> is the name of the binary.
+ // <program>_main.cc, where the <program> is the name of the binary
+ // (without .exe on Windows).
auto suffix = flags_internal::Basename(filename);
- if (!absl::ConsumePrefix(&suffix,
- flags_internal::ShortProgramInvocationName()))
+ auto program_name = flags_internal::ShortProgramInvocationName();
+ absl::string_view program_name_ref = program_name;
+#if defined(_WIN32)
+ absl::ConsumeSuffix(&program_name_ref, ".exe");
+#endif
+ if (!absl::ConsumePrefix(&suffix, program_name_ref))
return false;
return absl::StartsWith(suffix, ".") || absl::StartsWith(suffix, "-main.") ||
absl::StartsWith(suffix, "_main.");
@@ -149,4 +160,5 @@
flags_internal::custom_usage_config = new FlagsUsageConfig(usage_config);
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/flags/usage_config.h b/third_party/abseil/absl/flags/usage_config.h
index bfd0eed..96eecea 100644
--- a/third_party/abseil/absl/flags/usage_config.h
+++ b/third_party/abseil/absl/flags/usage_config.h
@@ -27,6 +27,7 @@
#include <functional>
#include <string>
+#include "absl/base/config.h"
#include "absl/strings/string_view.h"
// -----------------------------------------------------------------------------
@@ -54,6 +55,7 @@
// Shows help on modules whose name contains the specified substring
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace flags_internal {
using FlagKindFilter = std::function<bool (absl::string_view)>;
@@ -88,7 +90,7 @@
// program output.
flags_internal::FlagKindFilter contains_helppackage_flags;
- // Generates std::string containing program version. This is the std::string reported
+ // Generates string containing program version. This is the string reported
// when user specifies --version in a command line.
std::function<std::string()> version_string;
@@ -118,6 +120,7 @@
void ReportUsageError(absl::string_view msg, bool is_fatal);
} // namespace flags_internal
+ABSL_NAMESPACE_END
} // namespace absl
extern "C" {
diff --git a/third_party/abseil/absl/flags/usage_config_test.cc b/third_party/abseil/absl/flags/usage_config_test.cc
index 3bde13a..e57a883 100644
--- a/third_party/abseil/absl/flags/usage_config_test.cc
+++ b/third_party/abseil/absl/flags/usage_config_test.cc
@@ -15,10 +15,13 @@
#include "absl/flags/usage_config.h"
+#include <string>
+
#include "gtest/gtest.h"
#include "absl/flags/internal/path_util.h"
#include "absl/flags/internal/program_name.h"
#include "absl/strings/match.h"
+#include "absl/strings/string_view.h"
namespace {
@@ -81,7 +84,11 @@
// --------------------------------------------------------------------
TEST_F(FlagsUsageConfigTest, TestContainsHelpshortFlags) {
+#if defined(_WIN32)
+ flags::SetProgramInvocationName("usage_config_test.exe");
+#else
flags::SetProgramInvocationName("usage_config_test");
+#endif
auto config = flags::GetUsageConfig();
EXPECT_TRUE(config.contains_helpshort_flags("adir/cd/usage_config_test.cc"));
diff --git a/third_party/abseil/absl/functional/BUILD.bazel b/third_party/abseil/absl/functional/BUILD.bazel
new file mode 100644
index 0000000..ebd9b99
--- /dev/null
+++ b/third_party/abseil/absl/functional/BUILD.bazel
@@ -0,0 +1,93 @@
+#
+# Copyright 2019 The Abseil Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+load(
+ "//absl:copts/configure_copts.bzl",
+ "ABSL_DEFAULT_COPTS",
+ "ABSL_DEFAULT_LINKOPTS",
+ "ABSL_TEST_COPTS",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])
+
+cc_library(
+ name = "bind_front",
+ srcs = ["internal/front_binder.h"],
+ hdrs = ["bind_front.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ "//absl/base:base_internal",
+ "//absl/container:compressed_tuple",
+ "//absl/meta:type_traits",
+ "//absl/utility",
+ ],
+)
+
+cc_test(
+ name = "bind_front_test",
+ srcs = ["bind_front_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":bind_front",
+ "//absl/memory",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_library(
+ name = "function_ref",
+ srcs = ["internal/function_ref.h"],
+ hdrs = ["function_ref.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ "//absl/base:base_internal",
+ "//absl/meta:type_traits",
+ ],
+)
+
+cc_test(
+ name = "function_ref_test",
+ size = "small",
+ srcs = ["function_ref_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":function_ref",
+ "//absl/container:test_instance_tracker",
+ "//absl/memory",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "function_ref_benchmark",
+ srcs = [
+ "function_ref_benchmark.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ tags = ["benchmark"],
+ visibility = ["//visibility:private"],
+ deps = [
+ ":function_ref",
+ "//absl/base:core_headers",
+ "@com_github_google_benchmark//:benchmark_main",
+ ],
+)
diff --git a/third_party/abseil/absl/functional/CMakeLists.txt b/third_party/abseil/absl/functional/CMakeLists.txt
new file mode 100644
index 0000000..cda914f
--- /dev/null
+++ b/third_party/abseil/absl/functional/CMakeLists.txt
@@ -0,0 +1,72 @@
+#
+# Copyright 2019 The Abseil Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+absl_cc_library(
+ NAME
+ bind_front
+ SRCS
+ "internal/front_binder.h"
+ HDRS
+ "bind_front.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::base_internal
+ absl::compressed_tuple
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
+ bind_front_test
+ SRCS
+ "bind_front_test.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::bind_front
+ absl::memory
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
+ function_ref
+ SRCS
+ "internal/function_ref.h"
+ HDRS
+ "function_ref.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::base_internal
+ absl::meta
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
+ function_ref_test
+ SRCS
+ "function_ref_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::function_ref
+ absl::memory
+ absl::test_instance_tracker
+ gmock_main
+)
diff --git a/third_party/abseil/absl/functional/bind_front.h b/third_party/abseil/absl/functional/bind_front.h
new file mode 100644
index 0000000..5b47970
--- /dev/null
+++ b/third_party/abseil/absl/functional/bind_front.h
@@ -0,0 +1,184 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: bind_front.h
+// -----------------------------------------------------------------------------
+//
+// `absl::bind_front()` returns a functor by binding a number of arguments to
+// the front of a provided (usually more generic) functor. Unlike `std::bind`,
+// it does not require the use of argument placeholders. The simpler syntax of
+// `absl::bind_front()` allows you to avoid known misuses with `std::bind()`.
+//
+// `absl::bind_front()` is meant as a drop-in replacement for C++20's upcoming
+// `std::bind_front()`, which similarly resolves these issues with
+// `std::bind()`. Both `bind_front()` alternatives, unlike `std::bind()`, allow
+// partial function application. (See
+// https://en.wikipedia.org/wiki/Partial_application).
+
+#ifndef ABSL_FUNCTIONAL_BIND_FRONT_H_
+#define ABSL_FUNCTIONAL_BIND_FRONT_H_
+
+#include "absl/functional/internal/front_binder.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// bind_front()
+//
+// Binds the first N arguments of an invocable object and stores them by value.
+//
+// Like `std::bind()`, `absl::bind_front()` is implicitly convertible to
+// `std::function`. In particular, it may be used as a simpler replacement for
+// `std::bind()` in most cases, as it does not require placeholders to be
+// specified. More importantly, it provides more reliable correctness guarantees
+// than `std::bind()`; while `std::bind()` will silently ignore passing more
+// parameters than expected, for example, `absl::bind_front()` will report such
+// mis-uses as errors.
+//
+// absl::bind_front(a...) can be seen as storing the results of
+// std::make_tuple(a...).
+//
+// Example: Binding a free function.
+//
+// int Minus(int a, int b) { return a - b; }
+//
+// assert(absl::bind_front(Minus)(3, 2) == 3 - 2);
+// assert(absl::bind_front(Minus, 3)(2) == 3 - 2);
+// assert(absl::bind_front(Minus, 3, 2)() == 3 - 2);
+//
+// Example: Binding a member function.
+//
+// struct Math {
+// int Double(int a) const { return 2 * a; }
+// };
+//
+// Math math;
+//
+// assert(absl::bind_front(&Math::Double)(&math, 3) == 2 * 3);
+// // Stores a pointer to math inside the functor.
+// assert(absl::bind_front(&Math::Double, &math)(3) == 2 * 3);
+// // Stores a copy of math inside the functor.
+// assert(absl::bind_front(&Math::Double, math)(3) == 2 * 3);
+// // Stores std::unique_ptr<Math> inside the functor.
+// assert(absl::bind_front(&Math::Double,
+// std::unique_ptr<Math>(new Math))(3) == 2 * 3);
+//
+// Example: Using `absl::bind_front()`, instead of `std::bind()`, with
+// `std::function`.
+//
+// class FileReader {
+// public:
+// void ReadFileAsync(const std::string& filename, std::string* content,
+// const std::function<void()>& done) {
+// // Calls Executor::Schedule(std::function<void()>).
+// Executor::DefaultExecutor()->Schedule(
+// absl::bind_front(&FileReader::BlockingRead, this,
+// filename, content, done));
+// }
+//
+// private:
+// void BlockingRead(const std::string& filename, std::string* content,
+// const std::function<void()>& done) {
+// CHECK_OK(file::GetContents(filename, content, {}));
+// done();
+// }
+// };
+//
+// `absl::bind_front()` stores bound arguments explicitly using the type passed
+// rather than implicitly based on the type accepted by its functor.
+//
+// Example: Binding arguments explicitly.
+//
+// void LogStringView(absl::string_view sv) {
+// LOG(INFO) << sv;
+// }
+//
+// Executor* e = Executor::DefaultExecutor();
+// std::string s = "hello";
+// absl::string_view sv = s;
+//
+// // absl::bind_front(LogStringView, arg) makes a copy of arg and stores it.
+// e->Schedule(absl::bind_front(LogStringView, sv)); // ERROR: dangling
+// // string_view.
+//
+// e->Schedule(absl::bind_front(LogStringView, s)); // OK: stores a copy of
+// // s.
+//
+// To store some of the arguments passed to `absl::bind_front()` by reference,
+// use std::ref()` and `std::cref()`.
+//
+// Example: Storing some of the bound arguments by reference.
+//
+// class Service {
+// public:
+// void Serve(const Request& req, std::function<void()>* done) {
+// // The request protocol buffer won't be deleted until done is called.
+// // It's safe to store a reference to it inside the functor.
+// Executor::DefaultExecutor()->Schedule(
+// absl::bind_front(&Service::BlockingServe, this, std::cref(req),
+// done));
+// }
+//
+// private:
+// void BlockingServe(const Request& req, std::function<void()>* done);
+// };
+//
+// Example: Storing bound arguments by reference.
+//
+// void Print(const std::string& a, const std::string& b) {
+// std::cerr << a << b;
+// }
+//
+// std::string hi = "Hello, ";
+// std::vector<std::string> names = {"Chuk", "Gek"};
+// // Doesn't copy hi.
+// for_each(names.begin(), names.end(),
+// absl::bind_front(Print, std::ref(hi)));
+//
+// // DO NOT DO THIS: the functor may outlive "hi", resulting in
+// // dangling references.
+// foo->DoInFuture(absl::bind_front(Print, std::ref(hi), "Guest")); // BAD!
+// auto f = absl::bind_front(Print, std::ref(hi), "Guest"); // BAD!
+//
+// Example: Storing reference-like types.
+//
+// void Print(absl::string_view a, const std::string& b) {
+// std::cerr << a << b;
+// }
+//
+// std::string hi = "Hello, ";
+// // Copies "hi".
+// absl::bind_front(Print, hi)("Chuk");
+//
+// // Compile error: std::reference_wrapper<const string> is not implicitly
+// // convertible to string_view.
+// // absl::bind_front(Print, std::cref(hi))("Chuk");
+//
+// // Doesn't copy "hi".
+// absl::bind_front(Print, absl::string_view(hi))("Chuk");
+//
+template <class F, class... BoundArgs>
+constexpr functional_internal::bind_front_t<F, BoundArgs...> bind_front(
+ F&& func, BoundArgs&&... args) {
+ return functional_internal::bind_front_t<F, BoundArgs...>(
+ absl::in_place, absl::forward<F>(func),
+ absl::forward<BoundArgs>(args)...);
+}
+
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_FUNCTIONAL_BIND_FRONT_H_
diff --git a/third_party/abseil/absl/functional/bind_front_test.cc b/third_party/abseil/absl/functional/bind_front_test.cc
new file mode 100644
index 0000000..4801a81
--- /dev/null
+++ b/third_party/abseil/absl/functional/bind_front_test.cc
@@ -0,0 +1,231 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/functional/bind_front.h"
+
+#include <stddef.h>
+
+#include <functional>
+#include <memory>
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/memory/memory.h"
+
+namespace {
+
+char CharAt(const char* s, size_t index) { return s[index]; }
+
+TEST(BindTest, Basics) {
+ EXPECT_EQ('C', absl::bind_front(CharAt)("ABC", 2));
+ EXPECT_EQ('C', absl::bind_front(CharAt, "ABC")(2));
+ EXPECT_EQ('C', absl::bind_front(CharAt, "ABC", 2)());
+}
+
+TEST(BindTest, Lambda) {
+ auto lambda = [](int x, int y, int z) { return x + y + z; };
+ EXPECT_EQ(6, absl::bind_front(lambda)(1, 2, 3));
+ EXPECT_EQ(6, absl::bind_front(lambda, 1)(2, 3));
+ EXPECT_EQ(6, absl::bind_front(lambda, 1, 2)(3));
+ EXPECT_EQ(6, absl::bind_front(lambda, 1, 2, 3)());
+}
+
+struct Functor {
+ std::string operator()() & { return "&"; }
+ std::string operator()() const& { return "const&"; }
+ std::string operator()() && { return "&&"; }
+ std::string operator()() const&& { return "const&&"; }
+};
+
+TEST(BindTest, PerfectForwardingOfBoundArgs) {
+ auto f = absl::bind_front(Functor());
+ const auto& cf = f;
+ EXPECT_EQ("&", f());
+ EXPECT_EQ("const&", cf());
+ EXPECT_EQ("&&", std::move(f)());
+ EXPECT_EQ("const&&", std::move(cf)());
+}
+
+struct ArgDescribe {
+ std::string operator()(int&) const { return "&"; } // NOLINT
+ std::string operator()(const int&) const { return "const&"; } // NOLINT
+ std::string operator()(int&&) const { return "&&"; }
+ std::string operator()(const int&&) const { return "const&&"; }
+};
+
+TEST(BindTest, PerfectForwardingOfFreeArgs) {
+ ArgDescribe f;
+ int i;
+ EXPECT_EQ("&", absl::bind_front(f)(static_cast<int&>(i)));
+ EXPECT_EQ("const&", absl::bind_front(f)(static_cast<const int&>(i)));
+ EXPECT_EQ("&&", absl::bind_front(f)(static_cast<int&&>(i)));
+ EXPECT_EQ("const&&", absl::bind_front(f)(static_cast<const int&&>(i)));
+}
+
+struct NonCopyableFunctor {
+ NonCopyableFunctor() = default;
+ NonCopyableFunctor(const NonCopyableFunctor&) = delete;
+ NonCopyableFunctor& operator=(const NonCopyableFunctor&) = delete;
+ const NonCopyableFunctor* operator()() const { return this; }
+};
+
+TEST(BindTest, RefToFunctor) {
+ // It won't copy/move the functor and use the original object.
+ NonCopyableFunctor ncf;
+ auto bound_ncf = absl::bind_front(std::ref(ncf));
+ auto bound_ncf_copy = bound_ncf;
+ EXPECT_EQ(&ncf, bound_ncf_copy());
+}
+
+struct Struct {
+ std::string value;
+};
+
+TEST(BindTest, StoreByCopy) {
+ Struct s = {"hello"};
+ auto f = absl::bind_front(&Struct::value, s);
+ auto g = f;
+ EXPECT_EQ("hello", f());
+ EXPECT_EQ("hello", g());
+ EXPECT_NE(&s.value, &f());
+ EXPECT_NE(&s.value, &g());
+ EXPECT_NE(&g(), &f());
+}
+
+struct NonCopyable {
+ explicit NonCopyable(const std::string& s) : value(s) {}
+ NonCopyable(const NonCopyable&) = delete;
+ NonCopyable& operator=(const NonCopyable&) = delete;
+
+ std::string value;
+};
+
+const std::string& GetNonCopyableValue(const NonCopyable& n) { return n.value; }
+
+TEST(BindTest, StoreByRef) {
+ NonCopyable s("hello");
+ auto f = absl::bind_front(&GetNonCopyableValue, std::ref(s));
+ EXPECT_EQ("hello", f());
+ EXPECT_EQ(&s.value, &f());
+ auto g = std::move(f); // NOLINT
+ EXPECT_EQ("hello", g());
+ EXPECT_EQ(&s.value, &g());
+ s.value = "goodbye";
+ EXPECT_EQ("goodbye", g());
+}
+
+TEST(BindTest, StoreByCRef) {
+ NonCopyable s("hello");
+ auto f = absl::bind_front(&GetNonCopyableValue, std::cref(s));
+ EXPECT_EQ("hello", f());
+ EXPECT_EQ(&s.value, &f());
+ auto g = std::move(f); // NOLINT
+ EXPECT_EQ("hello", g());
+ EXPECT_EQ(&s.value, &g());
+ s.value = "goodbye";
+ EXPECT_EQ("goodbye", g());
+}
+
+const std::string& GetNonCopyableValueByWrapper(
+ std::reference_wrapper<NonCopyable> n) {
+ return n.get().value;
+}
+
+TEST(BindTest, StoreByRefInvokeByWrapper) {
+ NonCopyable s("hello");
+ auto f = absl::bind_front(GetNonCopyableValueByWrapper, std::ref(s));
+ EXPECT_EQ("hello", f());
+ EXPECT_EQ(&s.value, &f());
+ auto g = std::move(f);
+ EXPECT_EQ("hello", g());
+ EXPECT_EQ(&s.value, &g());
+ s.value = "goodbye";
+ EXPECT_EQ("goodbye", g());
+}
+
+TEST(BindTest, StoreByPointer) {
+ NonCopyable s("hello");
+ auto f = absl::bind_front(&NonCopyable::value, &s);
+ EXPECT_EQ("hello", f());
+ EXPECT_EQ(&s.value, &f());
+ auto g = std::move(f);
+ EXPECT_EQ("hello", g());
+ EXPECT_EQ(&s.value, &g());
+}
+
+int Sink(std::unique_ptr<int> p) {
+ return *p;
+}
+
+std::unique_ptr<int> Factory(int n) { return absl::make_unique<int>(n); }
+
+TEST(BindTest, NonCopyableArg) {
+ EXPECT_EQ(42, absl::bind_front(Sink)(absl::make_unique<int>(42)));
+ EXPECT_EQ(42, absl::bind_front(Sink, absl::make_unique<int>(42))());
+}
+
+TEST(BindTest, NonCopyableResult) {
+ EXPECT_THAT(absl::bind_front(Factory)(42), ::testing::Pointee(42));
+ EXPECT_THAT(absl::bind_front(Factory, 42)(), ::testing::Pointee(42));
+}
+
+// is_copy_constructible<FalseCopyable<unique_ptr<T>> is true but an attempt to
+// instantiate the copy constructor leads to a compile error. This is similar
+// to how standard containers behave.
+template <class T>
+struct FalseCopyable {
+ FalseCopyable() {}
+ FalseCopyable(const FalseCopyable& other) : m(other.m) {}
+ FalseCopyable(FalseCopyable&& other) : m(std::move(other.m)) {}
+ T m;
+};
+
+int GetMember(FalseCopyable<std::unique_ptr<int>> x) { return *x.m; }
+
+TEST(BindTest, WrappedMoveOnly) {
+ FalseCopyable<std::unique_ptr<int>> x;
+ x.m = absl::make_unique<int>(42);
+ auto f = absl::bind_front(&GetMember, std::move(x));
+ EXPECT_EQ(42, std::move(f)());
+}
+
+int Plus(int a, int b) { return a + b; }
+
+TEST(BindTest, ConstExpr) {
+ constexpr auto f = absl::bind_front(CharAt);
+ EXPECT_EQ(f("ABC", 1), 'B');
+ static constexpr int five = 5;
+ constexpr auto plus5 = absl::bind_front(Plus, five);
+ EXPECT_EQ(plus5(1), 6);
+
+ // There seems to be a bug in MSVC dealing constexpr construction of
+ // char[]. Notice 'plus5' above; 'int' works just fine.
+#if !(defined(_MSC_VER) && _MSC_VER < 1910)
+ static constexpr char data[] = "DEF";
+ constexpr auto g = absl::bind_front(CharAt, data);
+ EXPECT_EQ(g(1), 'E');
+#endif
+}
+
+struct ManglingCall {
+ int operator()(int, double, std::string) const { return 0; }
+};
+
+TEST(BindTest, Mangling) {
+ // We just want to generate a particular instantiation to see its mangling.
+ absl::bind_front(ManglingCall{}, 1, 3.3)("A");
+}
+
+} // namespace
diff --git a/third_party/abseil/absl/functional/function_ref.h b/third_party/abseil/absl/functional/function_ref.h
new file mode 100644
index 0000000..6e03ac2
--- /dev/null
+++ b/third_party/abseil/absl/functional/function_ref.h
@@ -0,0 +1,139 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: function_ref.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the `absl::FunctionRef` type for holding a
+// non-owning reference to an object of any invocable type. This function
+// reference is typically most useful as a type-erased argument type for
+// accepting function types that neither take ownership nor copy the type; using
+// the reference type in this case avoids a copy and an allocation. Best
+// practices of other non-owning reference-like objects (such as
+// `absl::string_view`) apply here.
+//
+// An `absl::FunctionRef` is similar in usage to a `std::function` but has the
+// following differences:
+//
+// * It doesn't own the underlying object.
+// * It doesn't have a null or empty state.
+// * It never performs deep copies or allocations.
+// * It's much faster and cheaper to construct.
+// * It's trivially copyable and destructable.
+//
+// Generally, `absl::FunctionRef` should not be used as a return value, data
+// member, or to initialize a `std::function`. Such usages will often lead to
+// problematic lifetime issues. Once you convert something to an
+// `absl::FunctionRef` you cannot make a deep copy later.
+//
+// This class is suitable for use wherever a "const std::function<>&"
+// would be used without making a copy. ForEach functions and other versions of
+// the visitor pattern are a good example of when this class should be used.
+//
+// This class is trivial to copy and should be passed by value.
+#ifndef ABSL_FUNCTIONAL_FUNCTION_REF_H_
+#define ABSL_FUNCTIONAL_FUNCTION_REF_H_
+
+#include <cassert>
+#include <functional>
+#include <type_traits>
+
+#include "absl/functional/internal/function_ref.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// FunctionRef
+//
+// Dummy class declaration to allow the partial specialization based on function
+// types below.
+template <typename T>
+class FunctionRef;
+
+// FunctionRef
+//
+// An `absl::FunctionRef` is a lightweight wrapper to any invokable object with
+// a compatible signature. Generally, an `absl::FunctionRef` should only be used
+// as an argument type and should be preferred as an argument over a const
+// reference to a `std::function`.
+//
+// Example:
+//
+// // The following function takes a function callback by const reference
+// bool Visitor(const std::function<void(my_proto&,
+// absl::string_view)>& callback);
+//
+// // Assuming that the function is not stored or otherwise copied, it can be
+// // replaced by an `absl::FunctionRef`:
+// bool Visitor(absl::FunctionRef<void(my_proto&, absl::string_view)>
+// callback);
+//
+// Note: the assignment operator within an `absl::FunctionRef` is intentionally
+// deleted to prevent misuse; because the `absl::FunctionRef` does not own the
+// underlying type, assignment likely indicates misuse.
+template <typename R, typename... Args>
+class FunctionRef<R(Args...)> {
+ private:
+ // Used to disable constructors for objects that are not compatible with the
+ // signature of this FunctionRef.
+ template <typename F,
+ typename FR = absl::base_internal::invoke_result_t<F, Args&&...>>
+ using EnableIfCompatible =
+ typename std::enable_if<std::is_void<R>::value ||
+ std::is_convertible<FR, R>::value>::type;
+
+ public:
+ // Constructs a FunctionRef from any invokable type.
+ template <typename F, typename = EnableIfCompatible<const F&>>
+ FunctionRef(const F& f) // NOLINT(runtime/explicit)
+ : invoker_(&absl::functional_internal::InvokeObject<F, R, Args...>) {
+ absl::functional_internal::AssertNonNull(f);
+ ptr_.obj = &f;
+ }
+
+ // Overload for function pointers. This eliminates a level of indirection that
+ // would happen if the above overload was used (it lets us store the pointer
+ // instead of a pointer to a pointer).
+ //
+ // This overload is also used for references to functions, since references to
+ // functions can decay to function pointers implicitly.
+ template <
+ typename F, typename = EnableIfCompatible<F*>,
+ absl::functional_internal::EnableIf<absl::is_function<F>::value> = 0>
+ FunctionRef(F* f) // NOLINT(runtime/explicit)
+ : invoker_(&absl::functional_internal::InvokeFunction<F*, R, Args...>) {
+ assert(f != nullptr);
+ ptr_.fun = reinterpret_cast<decltype(ptr_.fun)>(f);
+ }
+
+ // To help prevent subtle lifetime bugs, FunctionRef is not assignable.
+ // Typically, it should only be used as an argument type.
+ FunctionRef& operator=(const FunctionRef& rhs) = delete;
+
+ // Call the underlying object.
+ R operator()(Args... args) const {
+ return invoker_(ptr_, std::forward<Args>(args)...);
+ }
+
+ private:
+ absl::functional_internal::VoidPtr ptr_;
+ absl::functional_internal::Invoker<R, Args...> invoker_;
+};
+
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_FUNCTIONAL_FUNCTION_REF_H_
diff --git a/third_party/abseil/absl/functional/function_ref_benchmark.cc b/third_party/abseil/absl/functional/function_ref_benchmark.cc
new file mode 100644
index 0000000..045305b
--- /dev/null
+++ b/third_party/abseil/absl/functional/function_ref_benchmark.cc
@@ -0,0 +1,142 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/functional/function_ref.h"
+
+#include <memory>
+
+#include "benchmark/benchmark.h"
+#include "absl/base/attributes.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace {
+
+int dummy = 0;
+
+void FreeFunction() { benchmark::DoNotOptimize(dummy); }
+
+struct TrivialFunctor {
+ void operator()() const { benchmark::DoNotOptimize(dummy); }
+};
+
+struct LargeFunctor {
+ void operator()() const { benchmark::DoNotOptimize(this); }
+ std::string a, b, c;
+};
+
+template <typename Function, typename... Args>
+void ABSL_ATTRIBUTE_NOINLINE CallFunction(Function f, Args&&... args) {
+ f(std::forward<Args>(args)...);
+}
+
+template <typename Function, typename Callable, typename... Args>
+void ConstructAndCallFunctionBenchmark(benchmark::State& state,
+ const Callable& c, Args&&... args) {
+ for (auto _ : state) {
+ CallFunction<Function>(c, std::forward<Args>(args)...);
+ }
+}
+
+void BM_TrivialStdFunction(benchmark::State& state) {
+ ConstructAndCallFunctionBenchmark<std::function<void()>>(state,
+ TrivialFunctor{});
+}
+BENCHMARK(BM_TrivialStdFunction);
+
+void BM_TrivialFunctionRef(benchmark::State& state) {
+ ConstructAndCallFunctionBenchmark<FunctionRef<void()>>(state,
+ TrivialFunctor{});
+}
+BENCHMARK(BM_TrivialFunctionRef);
+
+void BM_LargeStdFunction(benchmark::State& state) {
+ ConstructAndCallFunctionBenchmark<std::function<void()>>(state,
+ LargeFunctor{});
+}
+BENCHMARK(BM_LargeStdFunction);
+
+void BM_LargeFunctionRef(benchmark::State& state) {
+ ConstructAndCallFunctionBenchmark<FunctionRef<void()>>(state, LargeFunctor{});
+}
+BENCHMARK(BM_LargeFunctionRef);
+
+void BM_FunPtrStdFunction(benchmark::State& state) {
+ ConstructAndCallFunctionBenchmark<std::function<void()>>(state, FreeFunction);
+}
+BENCHMARK(BM_FunPtrStdFunction);
+
+void BM_FunPtrFunctionRef(benchmark::State& state) {
+ ConstructAndCallFunctionBenchmark<FunctionRef<void()>>(state, FreeFunction);
+}
+BENCHMARK(BM_FunPtrFunctionRef);
+
+// Doesn't include construction or copy overhead in the loop.
+template <typename Function, typename Callable, typename... Args>
+void CallFunctionBenchmark(benchmark::State& state, const Callable& c,
+ Args... args) {
+ Function f = c;
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(&f);
+ f(args...);
+ }
+}
+
+struct FunctorWithTrivialArgs {
+ void operator()(int a, int b, int c) const {
+ benchmark::DoNotOptimize(a);
+ benchmark::DoNotOptimize(b);
+ benchmark::DoNotOptimize(c);
+ }
+};
+
+void BM_TrivialArgsStdFunction(benchmark::State& state) {
+ CallFunctionBenchmark<std::function<void(int, int, int)>>(
+ state, FunctorWithTrivialArgs{}, 1, 2, 3);
+}
+BENCHMARK(BM_TrivialArgsStdFunction);
+
+void BM_TrivialArgsFunctionRef(benchmark::State& state) {
+ CallFunctionBenchmark<FunctionRef<void(int, int, int)>>(
+ state, FunctorWithTrivialArgs{}, 1, 2, 3);
+}
+BENCHMARK(BM_TrivialArgsFunctionRef);
+
+struct FunctorWithNonTrivialArgs {
+ void operator()(std::string a, std::string b, std::string c) const {
+ benchmark::DoNotOptimize(&a);
+ benchmark::DoNotOptimize(&b);
+ benchmark::DoNotOptimize(&c);
+ }
+};
+
+void BM_NonTrivialArgsStdFunction(benchmark::State& state) {
+ std::string a, b, c;
+ CallFunctionBenchmark<
+ std::function<void(std::string, std::string, std::string)>>(
+ state, FunctorWithNonTrivialArgs{}, a, b, c);
+}
+BENCHMARK(BM_NonTrivialArgsStdFunction);
+
+void BM_NonTrivialArgsFunctionRef(benchmark::State& state) {
+ std::string a, b, c;
+ CallFunctionBenchmark<
+ FunctionRef<void(std::string, std::string, std::string)>>(
+ state, FunctorWithNonTrivialArgs{}, a, b, c);
+}
+BENCHMARK(BM_NonTrivialArgsFunctionRef);
+
+} // namespace
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/functional/function_ref_test.cc b/third_party/abseil/absl/functional/function_ref_test.cc
new file mode 100644
index 0000000..3aa5974
--- /dev/null
+++ b/third_party/abseil/absl/functional/function_ref_test.cc
@@ -0,0 +1,257 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/functional/function_ref.h"
+
+#include <memory>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/container/internal/test_instance_tracker.h"
+#include "absl/memory/memory.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace {
+
+void RunFun(FunctionRef<void()> f) { f(); }
+
+TEST(FunctionRefTest, Lambda) {
+ bool ran = false;
+ RunFun([&] { ran = true; });
+ EXPECT_TRUE(ran);
+}
+
+int Function() { return 1337; }
+
+TEST(FunctionRefTest, Function1) {
+ FunctionRef<int()> ref(&Function);
+ EXPECT_EQ(1337, ref());
+}
+
+TEST(FunctionRefTest, Function2) {
+ FunctionRef<int()> ref(Function);
+ EXPECT_EQ(1337, ref());
+}
+
+int NoExceptFunction() noexcept { return 1337; }
+
+// TODO(jdennett): Add a test for noexcept member functions.
+TEST(FunctionRefTest, NoExceptFunction) {
+ FunctionRef<int()> ref(NoExceptFunction);
+ EXPECT_EQ(1337, ref());
+}
+
+TEST(FunctionRefTest, ForwardsArgs) {
+ auto l = [](std::unique_ptr<int> i) { return *i; };
+ FunctionRef<int(std::unique_ptr<int>)> ref(l);
+ EXPECT_EQ(42, ref(absl::make_unique<int>(42)));
+}
+
+TEST(FunctionRef, ReturnMoveOnly) {
+ auto l = [] { return absl::make_unique<int>(29); };
+ FunctionRef<std::unique_ptr<int>()> ref(l);
+ EXPECT_EQ(29, *ref());
+}
+
+TEST(FunctionRef, ManyArgs) {
+ auto l = [](int a, int b, int c) { return a + b + c; };
+ FunctionRef<int(int, int, int)> ref(l);
+ EXPECT_EQ(6, ref(1, 2, 3));
+}
+
+TEST(FunctionRef, VoidResultFromNonVoidFunctor) {
+ bool ran = false;
+ auto l = [&]() -> int {
+ ran = true;
+ return 2;
+ };
+ FunctionRef<void()> ref(l);
+ ref();
+ EXPECT_TRUE(ran);
+}
+
+TEST(FunctionRef, CastFromDerived) {
+ struct Base {};
+ struct Derived : public Base {};
+
+ Derived d;
+ auto l1 = [&](Base* b) { EXPECT_EQ(&d, b); };
+ FunctionRef<void(Derived*)> ref1(l1);
+ ref1(&d);
+
+ auto l2 = [&]() -> Derived* { return &d; };
+ FunctionRef<Base*()> ref2(l2);
+ EXPECT_EQ(&d, ref2());
+}
+
+TEST(FunctionRef, VoidResultFromNonVoidFuncton) {
+ FunctionRef<void()> ref(Function);
+ ref();
+}
+
+TEST(FunctionRef, MemberPtr) {
+ struct S {
+ int i;
+ };
+
+ S s{1100111};
+ auto mem_ptr = &S::i;
+ FunctionRef<int(const S& s)> ref(mem_ptr);
+ EXPECT_EQ(1100111, ref(s));
+}
+
+TEST(FunctionRef, MemberFun) {
+ struct S {
+ int i;
+ int get_i() const { return i; }
+ };
+
+ S s{22};
+ auto mem_fun_ptr = &S::get_i;
+ FunctionRef<int(const S& s)> ref(mem_fun_ptr);
+ EXPECT_EQ(22, ref(s));
+}
+
+TEST(FunctionRef, MemberFunRefqualified) {
+ struct S {
+ int i;
+ int get_i() && { return i; }
+ };
+ auto mem_fun_ptr = &S::get_i;
+ S s{22};
+ FunctionRef<int(S && s)> ref(mem_fun_ptr);
+ EXPECT_EQ(22, ref(std::move(s)));
+}
+
+#if !defined(_WIN32) && defined(GTEST_HAS_DEATH_TEST)
+
+TEST(FunctionRef, MemberFunRefqualifiedNull) {
+ struct S {
+ int i;
+ int get_i() && { return i; }
+ };
+ auto mem_fun_ptr = &S::get_i;
+ mem_fun_ptr = nullptr;
+ EXPECT_DEBUG_DEATH({ FunctionRef<int(S && s)> ref(mem_fun_ptr); }, "");
+}
+
+TEST(FunctionRef, NullMemberPtrAssertFails) {
+ struct S {
+ int i;
+ };
+ using MemberPtr = int S::*;
+ MemberPtr mem_ptr = nullptr;
+ EXPECT_DEBUG_DEATH({ FunctionRef<int(const S& s)> ref(mem_ptr); }, "");
+}
+
+#endif // GTEST_HAS_DEATH_TEST
+
+TEST(FunctionRef, CopiesAndMovesPerPassByValue) {
+ absl::test_internal::InstanceTracker tracker;
+ absl::test_internal::CopyableMovableInstance instance(0);
+ auto l = [](absl::test_internal::CopyableMovableInstance) {};
+ FunctionRef<void(absl::test_internal::CopyableMovableInstance)> ref(l);
+ ref(instance);
+ EXPECT_EQ(tracker.copies(), 1);
+ EXPECT_EQ(tracker.moves(), 1);
+}
+
+TEST(FunctionRef, CopiesAndMovesPerPassByRef) {
+ absl::test_internal::InstanceTracker tracker;
+ absl::test_internal::CopyableMovableInstance instance(0);
+ auto l = [](const absl::test_internal::CopyableMovableInstance&) {};
+ FunctionRef<void(const absl::test_internal::CopyableMovableInstance&)> ref(l);
+ ref(instance);
+ EXPECT_EQ(tracker.copies(), 0);
+ EXPECT_EQ(tracker.moves(), 0);
+}
+
+TEST(FunctionRef, CopiesAndMovesPerPassByValueCallByMove) {
+ absl::test_internal::InstanceTracker tracker;
+ absl::test_internal::CopyableMovableInstance instance(0);
+ auto l = [](absl::test_internal::CopyableMovableInstance) {};
+ FunctionRef<void(absl::test_internal::CopyableMovableInstance)> ref(l);
+ ref(std::move(instance));
+ EXPECT_EQ(tracker.copies(), 0);
+ EXPECT_EQ(tracker.moves(), 2);
+}
+
+TEST(FunctionRef, CopiesAndMovesPerPassByValueToRef) {
+ absl::test_internal::InstanceTracker tracker;
+ absl::test_internal::CopyableMovableInstance instance(0);
+ auto l = [](const absl::test_internal::CopyableMovableInstance&) {};
+ FunctionRef<void(absl::test_internal::CopyableMovableInstance)> ref(l);
+ ref(std::move(instance));
+ EXPECT_EQ(tracker.copies(), 0);
+ EXPECT_EQ(tracker.moves(), 1);
+}
+
+TEST(FunctionRef, PassByValueTypes) {
+ using absl::functional_internal::Invoker;
+ using absl::functional_internal::VoidPtr;
+ using absl::test_internal::CopyableMovableInstance;
+ struct Trivial {
+ void* p[2];
+ };
+ struct LargeTrivial {
+ void* p[3];
+ };
+
+ static_assert(std::is_same<Invoker<void, int>, void (*)(VoidPtr, int)>::value,
+ "Scalar types should be passed by value");
+ static_assert(
+ std::is_same<Invoker<void, Trivial>, void (*)(VoidPtr, Trivial)>::value,
+ "Small trivial types should be passed by value");
+ static_assert(std::is_same<Invoker<void, LargeTrivial>,
+ void (*)(VoidPtr, LargeTrivial &&)>::value,
+ "Large trivial types should be passed by rvalue reference");
+ static_assert(
+ std::is_same<Invoker<void, CopyableMovableInstance>,
+ void (*)(VoidPtr, CopyableMovableInstance &&)>::value,
+ "Types with copy/move ctor should be passed by rvalue reference");
+
+ // References are passed as references.
+ static_assert(
+ std::is_same<Invoker<void, int&>, void (*)(VoidPtr, int&)>::value,
+ "Reference types should be preserved");
+ static_assert(
+ std::is_same<Invoker<void, CopyableMovableInstance&>,
+ void (*)(VoidPtr, CopyableMovableInstance&)>::value,
+ "Reference types should be preserved");
+ static_assert(
+ std::is_same<Invoker<void, CopyableMovableInstance&&>,
+ void (*)(VoidPtr, CopyableMovableInstance &&)>::value,
+ "Reference types should be preserved");
+
+ // Make sure the address of an object received by reference is the same as the
+ // addess of the object passed by the caller.
+ {
+ LargeTrivial obj;
+ auto test = [&obj](LargeTrivial& input) { ASSERT_EQ(&input, &obj); };
+ absl::FunctionRef<void(LargeTrivial&)> ref(test);
+ ref(obj);
+ }
+
+ {
+ Trivial obj;
+ auto test = [&obj](Trivial& input) { ASSERT_EQ(&input, &obj); };
+ absl::FunctionRef<void(Trivial&)> ref(test);
+ ref(obj);
+ }
+}
+
+} // namespace
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/functional/internal/front_binder.h b/third_party/abseil/absl/functional/internal/front_binder.h
new file mode 100644
index 0000000..45f52de
--- /dev/null
+++ b/third_party/abseil/absl/functional/internal/front_binder.h
@@ -0,0 +1,95 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Implementation details for `absl::bind_front()`.
+
+#ifndef ABSL_FUNCTIONAL_INTERNAL_FRONT_BINDER_H_
+#define ABSL_FUNCTIONAL_INTERNAL_FRONT_BINDER_H_
+
+#include <cstddef>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/internal/invoke.h"
+#include "absl/container/internal/compressed_tuple.h"
+#include "absl/meta/type_traits.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace functional_internal {
+
+// Invoke the method, expanding the tuple of bound arguments.
+template <class R, class Tuple, size_t... Idx, class... Args>
+R Apply(Tuple&& bound, absl::index_sequence<Idx...>, Args&&... free) {
+ return base_internal::invoke(
+ absl::forward<Tuple>(bound).template get<Idx>()...,
+ absl::forward<Args>(free)...);
+}
+
+template <class F, class... BoundArgs>
+class FrontBinder {
+ using BoundArgsT = absl::container_internal::CompressedTuple<F, BoundArgs...>;
+ using Idx = absl::make_index_sequence<sizeof...(BoundArgs) + 1>;
+
+ BoundArgsT bound_args_;
+
+ public:
+ template <class... Ts>
+ constexpr explicit FrontBinder(absl::in_place_t, Ts&&... ts)
+ : bound_args_(absl::forward<Ts>(ts)...) {}
+
+ template <class... FreeArgs, class R = base_internal::invoke_result_t<
+ F&, BoundArgs&..., FreeArgs&&...>>
+ R operator()(FreeArgs&&... free_args) & {
+ return functional_internal::Apply<R>(bound_args_, Idx(),
+ absl::forward<FreeArgs>(free_args)...);
+ }
+
+ template <class... FreeArgs,
+ class R = base_internal::invoke_result_t<
+ const F&, const BoundArgs&..., FreeArgs&&...>>
+ R operator()(FreeArgs&&... free_args) const& {
+ return functional_internal::Apply<R>(bound_args_, Idx(),
+ absl::forward<FreeArgs>(free_args)...);
+ }
+
+ template <class... FreeArgs, class R = base_internal::invoke_result_t<
+ F&&, BoundArgs&&..., FreeArgs&&...>>
+ R operator()(FreeArgs&&... free_args) && {
+ // This overload is called when *this is an rvalue. If some of the bound
+ // arguments are stored by value or rvalue reference, we move them.
+ return functional_internal::Apply<R>(absl::move(bound_args_), Idx(),
+ absl::forward<FreeArgs>(free_args)...);
+ }
+
+ template <class... FreeArgs,
+ class R = base_internal::invoke_result_t<
+ const F&&, const BoundArgs&&..., FreeArgs&&...>>
+ R operator()(FreeArgs&&... free_args) const&& {
+ // This overload is called when *this is an rvalue. If some of the bound
+ // arguments are stored by value or rvalue reference, we move them.
+ return functional_internal::Apply<R>(absl::move(bound_args_), Idx(),
+ absl::forward<FreeArgs>(free_args)...);
+ }
+};
+
+template <class F, class... BoundArgs>
+using bind_front_t = FrontBinder<decay_t<F>, absl::decay_t<BoundArgs>...>;
+
+} // namespace functional_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_FUNCTIONAL_INTERNAL_FRONT_BINDER_H_
diff --git a/third_party/abseil/absl/functional/internal/function_ref.h b/third_party/abseil/absl/functional/internal/function_ref.h
new file mode 100644
index 0000000..b5bb8b4
--- /dev/null
+++ b/third_party/abseil/absl/functional/internal/function_ref.h
@@ -0,0 +1,106 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_FUNCTIONAL_INTERNAL_FUNCTION_REF_H_
+#define ABSL_FUNCTIONAL_INTERNAL_FUNCTION_REF_H_
+
+#include <cassert>
+#include <functional>
+#include <type_traits>
+
+#include "absl/base/internal/invoke.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace functional_internal {
+
+// Like a void* that can handle function pointers as well. The standard does not
+// allow function pointers to round-trip through void*, but void(*)() is fine.
+//
+// Note: It's important that this class remains trivial and is the same size as
+// a pointer, since this allows the compiler to perform tail-call optimizations
+// when the underlying function is a callable object with a matching signature.
+union VoidPtr {
+ const void* obj;
+ void (*fun)();
+};
+
+// Chooses the best type for passing T as an argument.
+// Attempt to be close to SystemV AMD64 ABI. Objects with trivial copy ctor are
+// passed by value.
+template <typename T>
+constexpr bool PassByValue() {
+ return !std::is_lvalue_reference<T>::value &&
+ 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 &&
+ sizeof(T) <= 2 * sizeof(void*);
+}
+
+template <typename T>
+struct ForwardT : std::conditional<PassByValue<T>(), T, T&&> {};
+
+// An Invoker takes a pointer to the type-erased invokable object, followed by
+// the arguments that the invokable object expects.
+//
+// Note: The order of arguments here is an optimization, since member functions
+// have an implicit "this" pointer as their first argument, putting VoidPtr
+// first allows the compiler to perform tail-call optimization in many cases.
+template <typename R, typename... Args>
+using Invoker = R (*)(VoidPtr, typename ForwardT<Args>::type...);
+
+//
+// InvokeObject and InvokeFunction provide static "Invoke" functions that can be
+// used as Invokers for objects or functions respectively.
+//
+// static_cast<R> handles the case the return type is void.
+template <typename Obj, typename R, typename... Args>
+R InvokeObject(VoidPtr ptr, typename ForwardT<Args>::type... args) {
+ auto o = static_cast<const Obj*>(ptr.obj);
+ return static_cast<R>(
+ absl::base_internal::invoke(*o, std::forward<Args>(args)...));
+}
+
+template <typename Fun, typename R, typename... Args>
+R InvokeFunction(VoidPtr ptr, typename ForwardT<Args>::type... args) {
+ auto f = reinterpret_cast<Fun>(ptr.fun);
+ return static_cast<R>(
+ absl::base_internal::invoke(f, std::forward<Args>(args)...));
+}
+
+template <typename Sig>
+void AssertNonNull(const std::function<Sig>& f) {
+ assert(f != nullptr);
+ (void)f;
+}
+
+template <typename F>
+void AssertNonNull(const F&) {}
+
+template <typename F, typename C>
+void AssertNonNull(F C::*f) {
+ assert(f != nullptr);
+ (void)f;
+}
+
+template <bool C>
+using EnableIf = typename ::std::enable_if<C, int>::type;
+
+} // namespace functional_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_FUNCTIONAL_INTERNAL_FUNCTION_REF_H_
diff --git a/third_party/abseil/absl/hash/BUILD.bazel b/third_party/abseil/absl/hash/BUILD.bazel
index 5d78dc5..90c6c8a 100644
--- a/third_party/abseil/absl/hash/BUILD.bazel
+++ b/third_party/abseil/absl/hash/BUILD.bazel
@@ -14,7 +14,7 @@
# limitations under the License.
#
-#load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load(
"//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
@@ -24,7 +24,7 @@
package(default_visibility = ["//visibility:public"])
-licenses(["notice"]) # Apache 2.0
+licenses(["notice"])
cc_library(
name = "hash",
@@ -37,6 +37,7 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":city",
+ ":wyhash",
"//absl/base:core_headers",
"//absl/base:endian",
"//absl/container:fixed_array",
@@ -71,15 +72,35 @@
deps = [
":hash",
":hash_testing",
+ ":spy_hash_state",
"//absl/base:core_headers",
"//absl/container:flat_hash_set",
- "//absl/hash:spy_hash_state",
"//absl/meta:type_traits",
"//absl/numeric:int128",
+ "//absl/strings:cord_test_helpers",
"@com_google_googletest//:gtest_main",
],
)
+cc_binary(
+ name = "hash_benchmark",
+ testonly = 1,
+ srcs = ["hash_benchmark.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ tags = ["benchmark"],
+ visibility = ["//visibility:private"],
+ deps = [
+ ":hash",
+ "//absl/base:core_headers",
+ "//absl/random",
+ "//absl/strings",
+ "//absl/strings:cord",
+ "//absl/strings:cord_test_helpers",
+ "@com_github_google_benchmark//:benchmark_main",
+ ],
+)
+
cc_library(
name = "spy_hash_state",
testonly = 1,
@@ -119,3 +140,30 @@
"@com_google_googletest//:gtest_main",
],
)
+
+cc_library(
+ name = "wyhash",
+ srcs = ["internal/wyhash.cc"],
+ hdrs = ["internal/wyhash.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = ["//visibility:private"],
+ deps = [
+ "//absl/base:config",
+ "//absl/base:endian",
+ "//absl/numeric:int128",
+ ],
+)
+
+cc_test(
+ name = "wyhash_test",
+ srcs = ["internal/wyhash_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = ["//visibility:private"],
+ deps = [
+ ":wyhash",
+ "//absl/strings",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/third_party/abseil/absl/hash/CMakeLists.txt b/third_party/abseil/absl/hash/CMakeLists.txt
index febc551..6d19877 100644
--- a/third_party/abseil/absl/hash/CMakeLists.txt
+++ b/third_party/abseil/absl/hash/CMakeLists.txt
@@ -24,7 +24,8 @@
"internal/hash.h"
COPTS
${ABSL_DEFAULT_COPTS}
- DEPS
+ DEPS
+ absl::city
absl::core_headers
absl::endian
absl::fixed_array
@@ -34,7 +35,7 @@
absl::optional
absl::variant
absl::utility
- absl::city
+ absl::wyhash
PUBLIC
)
@@ -62,6 +63,7 @@
COPTS
${ABSL_TEST_COPTS}
DEPS
+ absl::cord_test_helpers
absl::hash
absl::hash_testing
absl::core_headers
@@ -113,3 +115,30 @@
gmock_main
)
+absl_cc_library(
+ NAME
+ wyhash
+ HDRS
+ "internal/wyhash.h"
+ SRCS
+ "internal/wyhash.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::config
+ absl::endian
+ absl::int128
+)
+
+absl_cc_test(
+ NAME
+ wyhash_test
+ SRCS
+ "internal/wyhash_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::wyhash
+ absl::strings
+ gmock_main
+)
diff --git a/third_party/abseil/absl/hash/hash.h b/third_party/abseil/absl/hash/hash.h
index 297dc9c..5de132c 100644
--- a/third_party/abseil/absl/hash/hash.h
+++ b/third_party/abseil/absl/hash/hash.h
@@ -37,8 +37,11 @@
// types. Hashing of that combined state is separately done by `absl::Hash`.
//
// One should assume that a hash algorithm is chosen randomly at the start of
-// each process. E.g., absl::Hash<int>()(9) in one process and
-// absl::Hash<int>()(9) in another process are likely to differ.
+// each process. E.g., `absl::Hash<int>{}(9)` in one process and
+// `absl::Hash<int>{}(9)` in another process are likely to differ.
+//
+// `absl::Hash` is intended to strongly mix input bits with a target of passing
+// an [Avalanche Test](https://en.wikipedia.org/wiki/Avalanche_effect).
//
// Example:
//
@@ -73,6 +76,7 @@
#include "absl/hash/internal/hash.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// -----------------------------------------------------------------------------
// `absl::Hash`
@@ -84,7 +88,6 @@
// * T is an arithmetic or pointer type
// * T defines an overload for `AbslHashValue(H, const T&)` for an arbitrary
// hash state `H`.
-// - T defines a specialization of `HASH_NAMESPACE::hash<T>`
// - T defines a specialization of `std::hash<T>`
//
// `absl::Hash` intrinsically supports the following types:
@@ -97,6 +100,7 @@
// * std::tuple<Ts...>, if all the Ts... are hashable
// * std::unique_ptr and std::shared_ptr
// * All string-like types including:
+// * absl::Cord
// * std::string
// * std::string_view (as well as any instance of std::basic_string that
// uses char and std::char_traits)
@@ -123,8 +127,6 @@
// * Natively supported types out of the box (see above)
// * Types for which an `AbslHashValue()` overload is provided (such as
// user-defined types). See "Adding Type Support to `absl::Hash`" below.
-// * Types which define a `HASH_NAMESPACE::hash<T>` specialization (aka
-// `__gnu_cxx::hash<T>` for gcc/Clang or `stdext::hash<T>` for MSVC)
// * Types which define a `std::hash<T>` specialization
//
// The fallback to legacy hash functions exists mainly for backwards
@@ -317,6 +319,7 @@
void (*combine_contiguous_)(void*, const unsigned char*, size_t);
};
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_HASH_HASH_H_
diff --git a/third_party/abseil/absl/hash/hash_benchmark.cc b/third_party/abseil/absl/hash/hash_benchmark.cc
new file mode 100644
index 0000000..d498ac2
--- /dev/null
+++ b/third_party/abseil/absl/hash/hash_benchmark.cc
@@ -0,0 +1,254 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string>
+#include <type_traits>
+#include <typeindex>
+#include <utility>
+#include <vector>
+
+#include "absl/base/attributes.h"
+#include "absl/hash/hash.h"
+#include "absl/random/random.h"
+#include "absl/strings/cord.h"
+#include "absl/strings/cord_test_helpers.h"
+#include "absl/strings/string_view.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+
+using absl::Hash;
+
+template <template <typename> class H, typename T>
+void RunBenchmark(benchmark::State& state, T value) {
+ H<T> h;
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(value);
+ benchmark::DoNotOptimize(h(value));
+ }
+}
+
+} // namespace
+
+template <typename T>
+using AbslHash = absl::Hash<T>;
+
+class TypeErasedInterface {
+ public:
+ virtual ~TypeErasedInterface() = default;
+
+ template <typename H>
+ friend H AbslHashValue(H state, const TypeErasedInterface& wrapper) {
+ state = H::combine(std::move(state), std::type_index(typeid(wrapper)));
+ wrapper.HashValue(absl::HashState::Create(&state));
+ return state;
+ }
+
+ private:
+ virtual void HashValue(absl::HashState state) const = 0;
+};
+
+template <typename T>
+struct TypeErasedAbslHash {
+ class Wrapper : public TypeErasedInterface {
+ public:
+ explicit Wrapper(const T& value) : value_(value) {}
+
+ private:
+ void HashValue(absl::HashState state) const override {
+ absl::HashState::combine(std::move(state), value_);
+ }
+
+ const T& value_;
+ };
+
+ size_t operator()(const T& value) {
+ return absl::Hash<Wrapper>{}(Wrapper(value));
+ }
+};
+
+template <typename FuncType>
+inline FuncType* ODRUseFunction(FuncType* ptr) {
+ volatile FuncType* dummy = ptr;
+ return dummy;
+}
+
+absl::Cord FlatCord(size_t size) {
+ absl::Cord result(std::string(size, 'a'));
+ result.Flatten();
+ return result;
+}
+
+absl::Cord FragmentedCord(size_t size) {
+ const size_t orig_size = size;
+ std::vector<std::string> chunks;
+ size_t chunk_size = std::max<size_t>(1, size / 10);
+ while (size > chunk_size) {
+ chunks.push_back(std::string(chunk_size, 'a'));
+ size -= chunk_size;
+ }
+ if (size > 0) {
+ chunks.push_back(std::string(size, 'a'));
+ }
+ absl::Cord result = absl::MakeFragmentedCord(chunks);
+ (void) orig_size;
+ assert(result.size() == orig_size);
+ return result;
+}
+
+// Generates a benchmark and a codegen method for the provided types. The
+// codegen method provides a well known entrypoint for dumping assembly.
+#define MAKE_BENCHMARK(hash, name, ...) \
+ namespace { \
+ void BM_##hash##_##name(benchmark::State& state) { \
+ RunBenchmark<hash>(state, __VA_ARGS__); \
+ } \
+ BENCHMARK(BM_##hash##_##name); \
+ } \
+ size_t Codegen##hash##name(const decltype(__VA_ARGS__)& arg); \
+ size_t Codegen##hash##name(const decltype(__VA_ARGS__)& arg) { \
+ return hash<decltype(__VA_ARGS__)>{}(arg); \
+ } \
+ bool absl_hash_test_odr_use##hash##name = \
+ ODRUseFunction(&Codegen##hash##name);
+
+MAKE_BENCHMARK(AbslHash, Int32, int32_t{});
+MAKE_BENCHMARK(AbslHash, Int64, int64_t{});
+MAKE_BENCHMARK(AbslHash, Double, 1.2);
+MAKE_BENCHMARK(AbslHash, DoubleZero, 0.0);
+MAKE_BENCHMARK(AbslHash, PairInt32Int32, std::pair<int32_t, int32_t>{});
+MAKE_BENCHMARK(AbslHash, PairInt64Int64, std::pair<int64_t, int64_t>{});
+MAKE_BENCHMARK(AbslHash, TupleInt32BoolInt64,
+ std::tuple<int32_t, bool, int64_t>{});
+MAKE_BENCHMARK(AbslHash, String_0, std::string());
+MAKE_BENCHMARK(AbslHash, String_10, std::string(10, 'a'));
+MAKE_BENCHMARK(AbslHash, String_30, std::string(30, 'a'));
+MAKE_BENCHMARK(AbslHash, String_90, std::string(90, 'a'));
+MAKE_BENCHMARK(AbslHash, String_200, std::string(200, 'a'));
+MAKE_BENCHMARK(AbslHash, String_5000, std::string(5000, 'a'));
+MAKE_BENCHMARK(AbslHash, Cord_Flat_0, absl::Cord());
+MAKE_BENCHMARK(AbslHash, Cord_Flat_10, FlatCord(10));
+MAKE_BENCHMARK(AbslHash, Cord_Flat_30, FlatCord(30));
+MAKE_BENCHMARK(AbslHash, Cord_Flat_90, FlatCord(90));
+MAKE_BENCHMARK(AbslHash, Cord_Flat_200, FlatCord(200));
+MAKE_BENCHMARK(AbslHash, Cord_Flat_5000, FlatCord(5000));
+MAKE_BENCHMARK(AbslHash, Cord_Fragmented_200, FragmentedCord(200));
+MAKE_BENCHMARK(AbslHash, Cord_Fragmented_5000, FragmentedCord(5000));
+MAKE_BENCHMARK(AbslHash, VectorInt64_10, std::vector<int64_t>(10));
+MAKE_BENCHMARK(AbslHash, VectorInt64_100, std::vector<int64_t>(100));
+MAKE_BENCHMARK(AbslHash, VectorDouble_10, std::vector<double>(10, 1.1));
+MAKE_BENCHMARK(AbslHash, VectorDouble_100, std::vector<double>(100, 1.1));
+MAKE_BENCHMARK(AbslHash, PairStringString_0,
+ std::make_pair(std::string(), std::string()));
+MAKE_BENCHMARK(AbslHash, PairStringString_10,
+ std::make_pair(std::string(10, 'a'), std::string(10, 'b')));
+MAKE_BENCHMARK(AbslHash, PairStringString_30,
+ std::make_pair(std::string(30, 'a'), std::string(30, 'b')));
+MAKE_BENCHMARK(AbslHash, PairStringString_90,
+ std::make_pair(std::string(90, 'a'), std::string(90, 'b')));
+MAKE_BENCHMARK(AbslHash, PairStringString_200,
+ std::make_pair(std::string(200, 'a'), std::string(200, 'b')));
+MAKE_BENCHMARK(AbslHash, PairStringString_5000,
+ std::make_pair(std::string(5000, 'a'), std::string(5000, 'b')));
+
+MAKE_BENCHMARK(TypeErasedAbslHash, Int32, int32_t{});
+MAKE_BENCHMARK(TypeErasedAbslHash, Int64, int64_t{});
+MAKE_BENCHMARK(TypeErasedAbslHash, PairInt32Int32,
+ std::pair<int32_t, int32_t>{});
+MAKE_BENCHMARK(TypeErasedAbslHash, PairInt64Int64,
+ std::pair<int64_t, int64_t>{});
+MAKE_BENCHMARK(TypeErasedAbslHash, TupleInt32BoolInt64,
+ std::tuple<int32_t, bool, int64_t>{});
+MAKE_BENCHMARK(TypeErasedAbslHash, String_0, std::string());
+MAKE_BENCHMARK(TypeErasedAbslHash, String_10, std::string(10, 'a'));
+MAKE_BENCHMARK(TypeErasedAbslHash, String_30, std::string(30, 'a'));
+MAKE_BENCHMARK(TypeErasedAbslHash, String_90, std::string(90, 'a'));
+MAKE_BENCHMARK(TypeErasedAbslHash, String_200, std::string(200, 'a'));
+MAKE_BENCHMARK(TypeErasedAbslHash, String_5000, std::string(5000, 'a'));
+MAKE_BENCHMARK(TypeErasedAbslHash, VectorDouble_10,
+ std::vector<double>(10, 1.1));
+MAKE_BENCHMARK(TypeErasedAbslHash, VectorDouble_100,
+ std::vector<double>(100, 1.1));
+
+// The latency benchmark attempts to model the speed of the hash function in
+// production. When a hash function is used for hashtable lookups it is rarely
+// used to hash N items in a tight loop nor on constant sized strings. Instead,
+// after hashing there is a potential equality test plus a (usually) large
+// amount of user code. To simulate this effectively we introduce a data
+// dependency between elements we hash by using the hash of the Nth element as
+// the selector of the N+1th element to hash. This isolates the hash function
+// code much like in production. As a bonus we use the hash to generate strings
+// of size [1,N] (instead of fixed N) to disable perfect branch predictions in
+// hash function implementations.
+namespace {
+// 16kb fits in L1 cache of most CPUs we care about. Keeping memory latency low
+// will allow us to attribute most time to CPU which means more accurate
+// measurements.
+static constexpr size_t kEntropySize = 16 << 10;
+static char entropy[kEntropySize + 1024];
+ABSL_ATTRIBUTE_UNUSED static const bool kInitialized = [] {
+ absl::BitGen gen;
+ static_assert(sizeof(entropy) % sizeof(uint64_t) == 0, "");
+ for (int i = 0; i != sizeof(entropy); i += sizeof(uint64_t)) {
+ auto rand = absl::Uniform<uint64_t>(gen);
+ memcpy(&entropy[i], &rand, sizeof(uint64_t));
+ }
+ return true;
+}();
+} // namespace
+
+template <class T>
+struct PodRand {
+ static_assert(std::is_pod<T>::value, "");
+ static_assert(kEntropySize + sizeof(T) < sizeof(entropy), "");
+
+ T Get(size_t i) const {
+ T v;
+ memcpy(&v, &entropy[i % kEntropySize], sizeof(T));
+ return v;
+ }
+};
+
+template <size_t N>
+struct StringRand {
+ static_assert(kEntropySize + N < sizeof(entropy), "");
+
+ absl::string_view Get(size_t i) const {
+ // This has a small bias towards small numbers. Because max N is ~200 this
+ // is very small and prefer to be very fast instead of absolutely accurate.
+ // Also we pass N = 2^K+1 so that mod reduces to a bitand.
+ size_t s = (i % (N - 1)) + 1;
+ return {&entropy[i % kEntropySize], s};
+ }
+};
+
+#define MAKE_LATENCY_BENCHMARK(hash, name, ...) \
+ namespace { \
+ void BM_latency_##hash##_##name(benchmark::State& state) { \
+ __VA_ARGS__ r; \
+ hash<decltype(r.Get(0))> h; \
+ size_t i = 871401241; \
+ for (auto _ : state) { \
+ benchmark::DoNotOptimize(i = h(r.Get(i))); \
+ } \
+ } \
+ BENCHMARK(BM_latency_##hash##_##name); \
+ } // namespace
+
+MAKE_LATENCY_BENCHMARK(AbslHash, Int32, PodRand<int32_t>);
+MAKE_LATENCY_BENCHMARK(AbslHash, Int64, PodRand<int64_t>);
+MAKE_LATENCY_BENCHMARK(AbslHash, String9, StringRand<9>);
+MAKE_LATENCY_BENCHMARK(AbslHash, String33, StringRand<33>);
+MAKE_LATENCY_BENCHMARK(AbslHash, String65, StringRand<65>);
+MAKE_LATENCY_BENCHMARK(AbslHash, String257, StringRand<257>);
diff --git a/third_party/abseil/absl/hash/hash_test.cc b/third_party/abseil/absl/hash/hash_test.cc
index 9a667ba..1d2e6cf 100644
--- a/third_party/abseil/absl/hash/hash_test.cc
+++ b/third_party/abseil/absl/hash/hash_test.cc
@@ -42,6 +42,7 @@
#include "absl/hash/internal/spy_hash_state.h"
#include "absl/meta/type_traits.h"
#include "absl/numeric/int128.h"
+#include "absl/strings/cord_test_helpers.h"
namespace {
@@ -81,8 +82,8 @@
}
REGISTER_TYPED_TEST_CASE_P(HashValueIntTest, BasicUsage, FastPath);
-using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t, uint32_t,
- uint64_t, size_t>;
+using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t,
+ uint32_t, uint64_t, size_t>;
INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueIntTest, IntTypes);
enum LegacyEnum { kValue1, kValue2, kValue3 };
@@ -269,37 +270,84 @@
}
};
+absl::Cord FlatCord(absl::string_view sv) {
+ absl::Cord c(sv);
+ c.Flatten();
+ return c;
+}
+
+absl::Cord FragmentedCord(absl::string_view sv) {
+ if (sv.size() < 2) {
+ return absl::Cord(sv);
+ }
+ size_t halfway = sv.size() / 2;
+ std::vector<absl::string_view> parts = {sv.substr(0, halfway),
+ sv.substr(halfway)};
+ return absl::MakeFragmentedCord(parts);
+}
+
TEST(HashValueTest, Strings) {
EXPECT_TRUE((is_hashable<std::string>::value));
const std::string small = "foo";
const std::string dup = "foofoo";
- const std::string large = "large";
- const std::string huge = std::string(5000, 'a');
+ const std::string large = std::string(2048, 'x'); // multiple of chunk size
+ const std::string huge = std::string(5000, 'a'); // not a multiple
- EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
- std::string(), absl::string_view(),
- std::string(""), absl::string_view(""),
- std::string(small), absl::string_view(small),
- std::string(dup), absl::string_view(dup),
- std::string(large), absl::string_view(large),
- std::string(huge), absl::string_view(huge))));
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( //
+ std::string(), absl::string_view(), absl::Cord(), //
+ std::string(""), absl::string_view(""), absl::Cord(""), //
+ std::string(small), absl::string_view(small), absl::Cord(small), //
+ std::string(dup), absl::string_view(dup), absl::Cord(dup), //
+ std::string(large), absl::string_view(large), absl::Cord(large), //
+ std::string(huge), absl::string_view(huge), FlatCord(huge), //
+ FragmentedCord(huge))));
// Also check that nested types maintain the same hash.
const WrapInTuple t{};
- EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
- t(std::string()), t(absl::string_view()),
- t(std::string("")), t(absl::string_view("")),
- t(std::string(small)), t(absl::string_view(small)),
- t(std::string(dup)), t(absl::string_view(dup)),
- t(std::string(large)), t(absl::string_view(large)),
- t(std::string(huge)), t(absl::string_view(huge)))));
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( //
+ t(std::string()), t(absl::string_view()), t(absl::Cord()), //
+ t(std::string("")), t(absl::string_view("")), t(absl::Cord("")), //
+ t(std::string(small)), t(absl::string_view(small)), //
+ t(absl::Cord(small)), //
+ t(std::string(dup)), t(absl::string_view(dup)), t(absl::Cord(dup)), //
+ t(std::string(large)), t(absl::string_view(large)), //
+ t(absl::Cord(large)), //
+ t(std::string(huge)), t(absl::string_view(huge)), //
+ t(FlatCord(huge)), t(FragmentedCord(huge)))));
- // Make sure that hashing a `const char*` does not use its std::string-value.
+ // Make sure that hashing a `const char*` does not use its string-value.
EXPECT_NE(SpyHash(static_cast<const char*>("ABC")),
SpyHash(absl::string_view("ABC")));
}
+TEST(HashValueTest, WString) {
+ EXPECT_TRUE((is_hashable<std::wstring>::value));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ std::wstring(), std::wstring(L"ABC"), std::wstring(L"ABC"),
+ std::wstring(L"Some other different string"),
+ std::wstring(L"Iñtërnâtiônàlizætiøn"))));
+}
+
+TEST(HashValueTest, U16String) {
+ EXPECT_TRUE((is_hashable<std::u16string>::value));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ std::u16string(), std::u16string(u"ABC"), std::u16string(u"ABC"),
+ std::u16string(u"Some other different string"),
+ std::u16string(u"Iñtërnâtiônàlizætiøn"))));
+}
+
+TEST(HashValueTest, U32String) {
+ EXPECT_TRUE((is_hashable<std::u32string>::value));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ std::u32string(), std::u32string(U"ABC"), std::u32string(U"ABC"),
+ std::u32string(U"Some other different string"),
+ std::u32string(U"Iñtërnâtiônàlizætiøn"))));
+}
+
TEST(HashValueTest, StdArray) {
EXPECT_TRUE((is_hashable<std::array<int, 3>>::value));
@@ -359,7 +407,7 @@
INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueSequenceTest, IntSequenceTypes);
// Private type that only supports AbslHashValue to make sure our chosen hash
-// implentation is recursive within absl::Hash.
+// implementation is recursive within absl::Hash.
// It uses std::abs() on the value to provide different bitwise representations
// of the same logical value.
struct Private {
@@ -378,6 +426,116 @@
}
};
+// Test helper for combine_piecewise_buffer. It holds a string_view to the
+// buffer-to-be-hashed. Its AbslHashValue specialization will split up its
+// contents at the character offsets requested.
+class PiecewiseHashTester {
+ public:
+ // Create a hash view of a buffer to be hashed contiguously.
+ explicit PiecewiseHashTester(absl::string_view buf)
+ : buf_(buf), piecewise_(false), split_locations_() {}
+
+ // Create a hash view of a buffer to be hashed piecewise, with breaks at the
+ // given locations.
+ PiecewiseHashTester(absl::string_view buf, std::set<size_t> split_locations)
+ : buf_(buf),
+ piecewise_(true),
+ split_locations_(std::move(split_locations)) {}
+
+ template <typename H>
+ friend H AbslHashValue(H h, const PiecewiseHashTester& p) {
+ if (!p.piecewise_) {
+ return H::combine_contiguous(std::move(h), p.buf_.data(), p.buf_.size());
+ }
+ absl::hash_internal::PiecewiseCombiner combiner;
+ if (p.split_locations_.empty()) {
+ h = combiner.add_buffer(std::move(h), p.buf_.data(), p.buf_.size());
+ return combiner.finalize(std::move(h));
+ }
+ size_t begin = 0;
+ for (size_t next : p.split_locations_) {
+ absl::string_view chunk = p.buf_.substr(begin, next - begin);
+ h = combiner.add_buffer(std::move(h), chunk.data(), chunk.size());
+ begin = next;
+ }
+ absl::string_view last_chunk = p.buf_.substr(begin);
+ if (!last_chunk.empty()) {
+ h = combiner.add_buffer(std::move(h), last_chunk.data(),
+ last_chunk.size());
+ }
+ return combiner.finalize(std::move(h));
+ }
+
+ private:
+ absl::string_view buf_;
+ bool piecewise_;
+ std::set<size_t> split_locations_;
+};
+
+// Dummy object that hashes as two distinct contiguous buffers, "foo" followed
+// by "bar"
+struct DummyFooBar {
+ template <typename H>
+ friend H AbslHashValue(H h, const DummyFooBar&) {
+ const char* foo = "foo";
+ const char* bar = "bar";
+ h = H::combine_contiguous(std::move(h), foo, 3);
+ h = H::combine_contiguous(std::move(h), bar, 3);
+ return h;
+ }
+};
+
+TEST(HashValueTest, CombinePiecewiseBuffer) {
+ absl::Hash<PiecewiseHashTester> hash;
+
+ // Check that hashing an empty buffer through the piecewise API works.
+ EXPECT_EQ(hash(PiecewiseHashTester("")), hash(PiecewiseHashTester("", {})));
+
+ // Similarly, small buffers should give consistent results
+ EXPECT_EQ(hash(PiecewiseHashTester("foobar")),
+ hash(PiecewiseHashTester("foobar", {})));
+ EXPECT_EQ(hash(PiecewiseHashTester("foobar")),
+ hash(PiecewiseHashTester("foobar", {3})));
+
+ // But hashing "foobar" in pieces gives a different answer than hashing "foo"
+ // contiguously, then "bar" contiguously.
+ EXPECT_NE(hash(PiecewiseHashTester("foobar", {3})),
+ absl::Hash<DummyFooBar>()(DummyFooBar{}));
+
+ // Test hashing a large buffer incrementally, broken up in several different
+ // ways. Arrange for breaks on and near the stride boundaries to look for
+ // off-by-one errors in the implementation.
+ //
+ // This test is run on a buffer that is a multiple of the stride size, and one
+ // that isn't.
+ for (size_t big_buffer_size : {1024 * 2 + 512, 1024 * 3}) {
+ SCOPED_TRACE(big_buffer_size);
+ std::string big_buffer;
+ for (int i = 0; i < big_buffer_size; ++i) {
+ // Arbitrary string
+ big_buffer.push_back(32 + (i * (i / 3)) % 64);
+ }
+ auto big_buffer_hash = hash(PiecewiseHashTester(big_buffer));
+
+ const int possible_breaks = 9;
+ size_t breaks[possible_breaks] = {1, 512, 1023, 1024, 1025,
+ 1536, 2047, 2048, 2049};
+ for (unsigned test_mask = 0; test_mask < (1u << possible_breaks);
+ ++test_mask) {
+ SCOPED_TRACE(test_mask);
+ std::set<size_t> break_locations;
+ for (int j = 0; j < possible_breaks; ++j) {
+ if (test_mask & (1u << j)) {
+ break_locations.insert(breaks[j]);
+ }
+ }
+ EXPECT_EQ(
+ hash(PiecewiseHashTester(big_buffer, std::move(break_locations))),
+ big_buffer_hash);
+ }
+ }
+}
+
TEST(HashValueTest, PrivateSanity) {
// Sanity check that Private is working as the tests below expect it to work.
EXPECT_TRUE(is_hashable<Private>::value);
@@ -423,6 +581,24 @@
MM{{1, "foo"}, {1, "foo"}, {43, "bar"}}, MM{{1, "foo"}, {43, "baz"}})));
}
+TEST(HashValueTest, ReferenceWrapper) {
+ EXPECT_TRUE(is_hashable<std::reference_wrapper<Private>>::value);
+
+ Private p1{1}, p10{10};
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ p1, p10, std::ref(p1), std::ref(p10), std::cref(p1), std::cref(p10))));
+
+ EXPECT_TRUE(is_hashable<std::reference_wrapper<int>>::value);
+ int one = 1, ten = 10;
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ one, ten, std::ref(one), std::ref(ten), std::cref(one), std::cref(ten))));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(std::tuple<std::reference_wrapper<int>>(std::ref(one)),
+ std::tuple<std::reference_wrapper<int>>(std::ref(ten)),
+ std::tuple<int>(one), std::tuple<int>(ten))));
+}
+
template <typename T, typename = void>
struct IsHashCallable : std::false_type {};
@@ -458,7 +634,10 @@
EXPECT_FALSE(absl::is_copy_assignable<absl::Hash<X>>::value);
EXPECT_FALSE(absl::is_move_assignable<absl::Hash<X>>::value);
EXPECT_FALSE(IsHashCallable<X>::value);
+#if !defined(__GNUC__) || __GNUC__ < 9
+ // This doesn't compile on GCC 9.
EXPECT_FALSE(IsAggregateInitializable<absl::Hash<X>>::value);
+#endif
}
#endif // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
@@ -544,6 +723,7 @@
} // namespace
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace hash_internal {
template <InvokeTag... Tags>
struct is_uniquely_represented<
@@ -551,6 +731,7 @@
typename EnableIfContained<InvokeTag::kUniquelyRepresented, Tags...>::type>
: std::true_type {};
} // namespace hash_internal
+ABSL_NAMESPACE_END
} // namespace absl
#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
@@ -638,8 +819,8 @@
}
REGISTER_TYPED_TEST_CASE_P(HashIntTest, BasicUsage);
-using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t, uint32_t,
- uint64_t, size_t>;
+using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t,
+ uint32_t, uint64_t, size_t>;
INSTANTIATE_TYPED_TEST_CASE_P(My, HashIntTest, IntTypes);
struct StructWithPadding {
diff --git a/third_party/abseil/absl/hash/hash_testing.h b/third_party/abseil/absl/hash/hash_testing.h
index c45bc15..1e1c574 100644
--- a/third_party/abseil/absl/hash/hash_testing.h
+++ b/third_party/abseil/absl/hash/hash_testing.h
@@ -28,6 +28,7 @@
#include "absl/types/variant.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// Run the absl::Hash algorithm over all the elements passed in and verify that
// their hash expansion is congruent with their `==` operator.
@@ -371,6 +372,7 @@
equals);
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_HASH_HASH_TESTING_H_
diff --git a/third_party/abseil/absl/hash/internal/city.cc b/third_party/abseil/absl/hash/internal/city.cc
index dc7650a..5460134 100644
--- a/third_party/abseil/absl/hash/internal/city.cc
+++ b/third_party/abseil/absl/hash/internal/city.cc
@@ -30,6 +30,7 @@
#include "absl/base/optimization.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace hash_internal {
#ifdef ABSL_IS_BIG_ENDIAN
@@ -199,10 +200,6 @@
static uint64_t ShiftMix(uint64_t val) { return val ^ (val >> 47); }
-static uint64_t HashLen16(uint64_t u, uint64_t v) {
- return Hash128to64(uint128(u, v));
-}
-
static uint64_t HashLen16(uint64_t u, uint64_t v, uint64_t mul) {
// Murmur-inspired hashing.
uint64_t a = (u ^ v) * mul;
@@ -213,6 +210,11 @@
return b;
}
+static uint64_t HashLen16(uint64_t u, uint64_t v) {
+ const uint64_t kMul = 0x9ddfea08eb382d69ULL;
+ return HashLen16(u, v, kMul);
+}
+
static uint64_t HashLen0to16(const char *s, size_t len) {
if (len >= 8) {
uint64_t mul = k2 + len * 2;
@@ -252,9 +254,8 @@
// Return a 16-byte hash for 48 bytes. Quick and dirty.
// Callers do best to use "random-looking" values for a and b.
-static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(uint64_t w, uint64_t x,
- uint64_t y, uint64_t z,
- uint64_t a, uint64_t b) {
+static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(
+ uint64_t w, uint64_t x, uint64_t y, uint64_t z, uint64_t a, uint64_t b) {
a += w;
b = Rotate(b + a + z, 21);
uint64_t c = a;
@@ -265,8 +266,9 @@
}
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
-static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(const char *s, uint64_t a,
- uint64_t b) {
+static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(const char *s,
+ uint64_t a,
+ uint64_t b) {
return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16),
Fetch64(s + 24), a, b);
}
@@ -309,8 +311,10 @@
uint64_t x = Fetch64(s + len - 40);
uint64_t y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
uint64_t z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
- std::pair<uint64_t, uint64_t> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
- std::pair<uint64_t, uint64_t> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
+ std::pair<uint64_t, uint64_t> v =
+ WeakHashLen32WithSeeds(s + len - 64, len, z);
+ std::pair<uint64_t, uint64_t> w =
+ WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
x = x * k1 + Fetch64(s);
// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
@@ -336,9 +340,10 @@
}
uint64_t CityHash64WithSeeds(const char *s, size_t len, uint64_t seed0,
- uint64_t seed1) {
+ uint64_t seed1) {
return HashLen16(CityHash64(s, len) - seed0, seed1);
}
} // namespace hash_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/hash/internal/city.h b/third_party/abseil/absl/hash/internal/city.h
index b43d340..393da0b 100644
--- a/third_party/abseil/absl/hash/internal/city.h
+++ b/third_party/abseil/absl/hash/internal/city.h
@@ -47,16 +47,15 @@
#include <stdint.h>
#include <stdlib.h> // for size_t.
+
#include <utility>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace hash_internal {
-typedef std::pair<uint64_t, uint64_t> uint128;
-
-inline uint64_t Uint128Low64(const uint128 &x) { return x.first; }
-inline uint64_t Uint128High64(const uint128 &x) { return x.second; }
-
// Hash function for a byte array.
uint64_t CityHash64(const char *s, size_t len);
@@ -67,25 +66,13 @@
// Hash function for a byte array. For convenience, two seeds are also
// hashed into the result.
uint64_t CityHash64WithSeeds(const char *s, size_t len, uint64_t seed0,
- uint64_t seed1);
+ uint64_t seed1);
// Hash function for a byte array. Most useful in 32-bit binaries.
uint32_t CityHash32(const char *s, size_t len);
-// Hash 128 input bits down to 64 bits of output.
-// This is intended to be a reasonably good hash function.
-inline uint64_t Hash128to64(const uint128 &x) {
- // Murmur-inspired hashing.
- const uint64_t kMul = 0x9ddfea08eb382d69ULL;
- uint64_t a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul;
- a ^= (a >> 47);
- uint64_t b = (Uint128High64(x) ^ a) * kMul;
- b ^= (b >> 47);
- b *= kMul;
- return b;
-}
-
} // namespace hash_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_HASH_INTERNAL_CITY_H_
diff --git a/third_party/abseil/absl/hash/internal/city_test.cc b/third_party/abseil/absl/hash/internal/city_test.cc
index 71b4ecc..251d381 100644
--- a/third_party/abseil/absl/hash/internal/city_test.cc
+++ b/third_party/abseil/absl/hash/internal/city_test.cc
@@ -20,6 +20,7 @@
#include "gtest/gtest.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace hash_internal {
static const uint64_t k0 = 0xc3a5c85c97cb3127ULL;
@@ -590,4 +591,5 @@
}
} // namespace hash_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/hash/internal/hash.cc b/third_party/abseil/absl/hash/internal/hash.cc
index 4ab7a9f..1433eb9 100644
--- a/third_party/abseil/absl/hash/internal/hash.cc
+++ b/third_party/abseil/absl/hash/internal/hash.cc
@@ -15,9 +15,56 @@
#include "absl/hash/internal/hash.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace hash_internal {
-ABSL_CONST_INIT const void* const CityHashState::kSeed = &kSeed;
+uint64_t HashState::CombineLargeContiguousImpl32(uint64_t state,
+ const unsigned char* first,
+ size_t len) {
+ while (len >= PiecewiseChunkSize()) {
+ state =
+ Mix(state, absl::hash_internal::CityHash32(reinterpret_cast<const char*>(first),
+ PiecewiseChunkSize()));
+ len -= PiecewiseChunkSize();
+ first += PiecewiseChunkSize();
+ }
+ // Handle the remainder.
+ return CombineContiguousImpl(state, first, len,
+ std::integral_constant<int, 4>{});
+}
+
+uint64_t HashState::CombineLargeContiguousImpl64(uint64_t state,
+ const unsigned char* first,
+ size_t len) {
+ while (len >= PiecewiseChunkSize()) {
+ state = Mix(state, Hash64(first, PiecewiseChunkSize()));
+ len -= PiecewiseChunkSize();
+ first += PiecewiseChunkSize();
+ }
+ // Handle the remainder.
+ return CombineContiguousImpl(state, first, len,
+ std::integral_constant<int, 8>{});
+}
+
+ABSL_CONST_INIT const void* const HashState::kSeed = &kSeed;
+
+// The salt array used by Wyhash. This array is NOT the mechanism used to make
+// absl::Hash non-deterministic between program invocations. See `Seed()` for
+// that mechanism.
+//
+// Any random values are fine. These values are just digits from the decimal
+// part of pi.
+// https://en.wikipedia.org/wiki/Nothing-up-my-sleeve_number
+constexpr uint64_t kWyhashSalt[5] = {
+ uint64_t{0x243F6A8885A308D3}, uint64_t{0x13198A2E03707344},
+ uint64_t{0xA4093822299F31D0}, uint64_t{0x082EFA98EC4E6C89},
+ uint64_t{0x452821E638D01377},
+};
+
+uint64_t HashState::WyhashImpl(const unsigned char* data, size_t len) {
+ return Wyhash(data, len, Seed(), kWyhashSalt);
+}
} // namespace hash_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/hash/internal/hash.h b/third_party/abseil/absl/hash/internal/hash.h
index 4ff4a12..eb3471d 100644
--- a/third_party/abseil/absl/hash/internal/hash.h
+++ b/third_party/abseil/absl/hash/internal/hash.h
@@ -41,6 +41,7 @@
#include "absl/base/internal/endian.h"
#include "absl/base/port.h"
#include "absl/container/fixed_array.h"
+#include "absl/hash/internal/wyhash.h"
#include "absl/meta/type_traits.h"
#include "absl/numeric/int128.h"
#include "absl/strings/string_view.h"
@@ -50,8 +51,68 @@
#include "absl/hash/internal/city.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace hash_internal {
+// Internal detail: Large buffers are hashed in smaller chunks. This function
+// returns the size of these chunks.
+constexpr size_t PiecewiseChunkSize() { return 1024; }
+
+// PiecewiseCombiner
+//
+// PiecewiseCombiner is an internal-only helper class for hashing a piecewise
+// buffer of `char` or `unsigned char` as though it were contiguous. This class
+// provides two methods:
+//
+// H add_buffer(state, data, size)
+// H finalize(state)
+//
+// `add_buffer` can be called zero or more times, followed by a single call to
+// `finalize`. This will produce the same hash expansion as concatenating each
+// buffer piece into a single contiguous buffer, and passing this to
+// `H::combine_contiguous`.
+//
+// Example usage:
+// PiecewiseCombiner combiner;
+// for (const auto& piece : pieces) {
+// state = combiner.add_buffer(std::move(state), piece.data, piece.size);
+// }
+// return combiner.finalize(std::move(state));
+class PiecewiseCombiner {
+ public:
+ PiecewiseCombiner() : position_(0) {}
+ PiecewiseCombiner(const PiecewiseCombiner&) = delete;
+ PiecewiseCombiner& operator=(const PiecewiseCombiner&) = delete;
+
+ // PiecewiseCombiner::add_buffer()
+ //
+ // Appends the given range of bytes to the sequence to be hashed, which may
+ // modify the provided hash state.
+ template <typename H>
+ H add_buffer(H state, const unsigned char* data, size_t size);
+ template <typename H>
+ H add_buffer(H state, const char* data, size_t size) {
+ return add_buffer(std::move(state),
+ reinterpret_cast<const unsigned char*>(data), size);
+ }
+
+ // PiecewiseCombiner::finalize()
+ //
+ // Finishes combining the hash sequence, which may may modify the provided
+ // hash state.
+ //
+ // Once finalize() is called, add_buffer() may no longer be called. The
+ // resulting hash state will be the same as if the pieces passed to
+ // add_buffer() were concatenated into a single flat buffer, and then provided
+ // to H::combine_contiguous().
+ template <typename H>
+ H finalize(H state);
+
+ private:
+ unsigned char buf_[PiecewiseChunkSize()];
+ size_t position_;
+};
+
// HashStateBase
//
// A hash state object represents an intermediate state in the computation
@@ -68,7 +129,7 @@
//
// `static H combine_contiguous(H state, const unsigned char*, size_t)`.
//
-// `HashStateBase` will provide a complete implementations for a hash state
+// `HashStateBase` will provide a complete implementation for a hash state
// object in terms of this method.
//
// Example:
@@ -117,6 +178,8 @@
// for-loop instead.
template <typename T>
static H combine_contiguous(H state, const T* data, size_t size);
+
+ using AbslInternalPiecewiseCombiner = PiecewiseCombiner;
};
// is_uniquely_represented
@@ -348,6 +411,7 @@
// All the string-like types supported here provide the same hash expansion for
// the same character sequence. These types are:
//
+// - `absl::Cord`
// - `std::string` (and std::basic_string<char, std::char_traits<char>, A> for
// any allocator A)
// - `absl::string_view` and `std::string_view`
@@ -363,6 +427,19 @@
str.size());
}
+// Support std::wstring, std::u16string and std::u32string.
+template <typename Char, typename Alloc, typename H,
+ typename = absl::enable_if_t<std::is_same<Char, wchar_t>::value ||
+ std::is_same<Char, char16_t>::value ||
+ std::is_same<Char, char32_t>::value>>
+H AbslHashValue(
+ H hash_state,
+ const std::basic_string<Char, std::char_traits<Char>, Alloc>& str) {
+ return H::combine(
+ H::combine_contiguous(std::move(hash_state), str.data(), str.size()),
+ str.size());
+}
+
// -----------------------------------------------------------------------------
// AbslHashValue for Sequence Containers
// -----------------------------------------------------------------------------
@@ -475,6 +552,13 @@
// AbslHashValue for Wrapper Types
// -----------------------------------------------------------------------------
+// AbslHashValue for hashing std::reference_wrapper
+template <typename H, typename T>
+typename std::enable_if<is_hashable<T>::value, H>::type AbslHashValue(
+ H hash_state, std::reference_wrapper<T> opt) {
+ return H::combine(std::move(hash_state), opt.get());
+}
+
// AbslHashValue for hashing absl::optional
template <typename H, typename T>
typename std::enable_if<is_hashable<T>::value, H>::type AbslHashValue(
@@ -629,8 +713,8 @@
struct is_hashable
: std::integral_constant<bool, HashSelect::template Apply<T>::value> {};
-// CityHashState
-class CityHashState : public HashStateBase<CityHashState> {
+// HashState
+class ABSL_DLL HashState : public HashStateBase<HashState> {
// absl::uint128 is not an alias or a thin wrapper around the intrinsic.
// We use the intrinsic when available to improve performance.
#ifdef ABSL_HAVE_INTRINSIC_INT128
@@ -649,23 +733,22 @@
public:
// Move only
- CityHashState(CityHashState&&) = default;
- CityHashState& operator=(CityHashState&&) = default;
+ HashState(HashState&&) = default;
+ HashState& operator=(HashState&&) = default;
- // CityHashState::combine_contiguous()
+ // HashState::combine_contiguous()
//
// Fundamental base case for hash recursion: mixes the given range of bytes
// into the hash state.
- static CityHashState combine_contiguous(CityHashState hash_state,
- const unsigned char* first,
- size_t size) {
- return CityHashState(
+ static HashState combine_contiguous(HashState hash_state,
+ const unsigned char* first, size_t size) {
+ return HashState(
CombineContiguousImpl(hash_state.state_, first, size,
std::integral_constant<int, sizeof(size_t)>{}));
}
- using CityHashState::HashStateBase::combine_contiguous;
+ using HashState::HashStateBase::combine_contiguous;
- // CityHashState::hash()
+ // HashState::hash()
//
// For performance reasons in non-opt mode, we specialize this for
// integral types.
@@ -677,24 +760,24 @@
return static_cast<size_t>(Mix(Seed(), static_cast<uint64_t>(value)));
}
- // Overload of CityHashState::hash()
+ // Overload of HashState::hash()
template <typename T, absl::enable_if_t<!IntegralFastPath<T>::value, int> = 0>
static size_t hash(const T& value) {
- return static_cast<size_t>(combine(CityHashState{}, value).state_);
+ return static_cast<size_t>(combine(HashState{}, value).state_);
}
private:
// Invoked only once for a given argument; that plus the fact that this is
// move-only ensures that there is only one non-moved-from object.
- CityHashState() : state_(Seed()) {}
+ HashState() : state_(Seed()) {}
// Workaround for MSVC bug.
// We make the type copyable to fix the calling convention, even though we
// never actually copy it. Keep it private to not affect the public API of the
// type.
- CityHashState(const CityHashState&) = default;
+ HashState(const HashState&) = default;
- explicit CityHashState(uint64_t state) : state_(state) {}
+ explicit HashState(uint64_t state) : state_(state) {}
// Implementation of the base case for combine_contiguous where we actually
// mix the bytes into the state.
@@ -707,7 +790,18 @@
static uint64_t CombineContiguousImpl(uint64_t state,
const unsigned char* first, size_t len,
std::integral_constant<int, 8>
- /* sizeof_size_t*/);
+ /* sizeof_size_t */);
+
+
+ // Slow dispatch path for calls to CombineContiguousImpl with a size argument
+ // larger than PiecewiseChunkSize(). Has the same effect as calling
+ // CombineContiguousImpl() repeatedly with the chunk stride size.
+ static uint64_t CombineLargeContiguousImpl32(uint64_t state,
+ const unsigned char* first,
+ size_t len);
+ static uint64_t CombineLargeContiguousImpl64(uint64_t state,
+ const unsigned char* first,
+ size_t len);
// Reads 9 to 16 bytes from p.
// The first 8 bytes are in .first, the rest (zero padded) bytes are in
@@ -744,6 +838,19 @@
return static_cast<uint64_t>(m ^ (m >> (sizeof(m) * 8 / 2)));
}
+ // An extern to avoid bloat on a direct call to Wyhash() with fixed values for
+ // both the seed and salt parameters.
+ static uint64_t WyhashImpl(const unsigned char* data, size_t len);
+
+ ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t Hash64(const unsigned char* data,
+ size_t len) {
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+ return WyhashImpl(data, len);
+#else
+ return absl::hash_internal::CityHash64(reinterpret_cast<const char*>(data), len);
+#endif
+ }
+
// Seed()
//
// A non-deterministic seed.
@@ -761,21 +868,31 @@
// On other platforms this is still going to be non-deterministic but most
// probably per-build and not per-process.
ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t Seed() {
+#if (!defined(__clang__) || __clang_major__ > 11) && \
+ !defined(__apple_build_version__)
+ return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(&kSeed));
+#else
+ // Workaround the absence of
+ // https://github.com/llvm/llvm-project/commit/bc15bf66dcca76cc06fe71fca35b74dc4d521021.
return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(kSeed));
+#endif
}
static const void* const kSeed;
uint64_t state_;
};
-// CityHashState::CombineContiguousImpl()
-inline uint64_t CityHashState::CombineContiguousImpl(
+// HashState::CombineContiguousImpl()
+inline uint64_t HashState::CombineContiguousImpl(
uint64_t state, const unsigned char* first, size_t len,
std::integral_constant<int, 4> /* sizeof_size_t */) {
// For large values we use CityHash, for small ones we just use a
// multiplicative hash.
uint64_t v;
if (len > 8) {
+ if (ABSL_PREDICT_FALSE(len > PiecewiseChunkSize())) {
+ return CombineLargeContiguousImpl32(state, first, len);
+ }
v = absl::hash_internal::CityHash32(reinterpret_cast<const char*>(first), len);
} else if (len >= 4) {
v = Read4To8(first, len);
@@ -788,15 +905,18 @@
return Mix(state, v);
}
-// Overload of CityHashState::CombineContiguousImpl()
-inline uint64_t CityHashState::CombineContiguousImpl(
+// Overload of HashState::CombineContiguousImpl()
+inline uint64_t HashState::CombineContiguousImpl(
uint64_t state, const unsigned char* first, size_t len,
std::integral_constant<int, 8> /* sizeof_size_t */) {
- // For large values we use CityHash, for small ones we just use a
- // multiplicative hash.
+ // For large values we use Wyhash or CityHash depending on the platform, for
+ // small ones we just use a multiplicative hash.
uint64_t v;
if (len > 16) {
- v = absl::hash_internal::CityHash64(reinterpret_cast<const char*>(first), len);
+ if (ABSL_PREDICT_FALSE(len > PiecewiseChunkSize())) {
+ return CombineLargeContiguousImpl64(state, first, len);
+ }
+ v = Hash64(first, len);
} else if (len > 8) {
auto p = Read9To16(first, len);
state = Mix(state, p.first);
@@ -812,7 +932,6 @@
return Mix(state, v);
}
-
struct AggregateBarrier {};
// HashImpl
@@ -828,7 +947,7 @@
template <typename T>
struct HashImpl {
- size_t operator()(const T& value) const { return CityHashState::hash(value); }
+ size_t operator()(const T& value) const { return HashState::hash(value); }
};
template <typename T>
@@ -849,7 +968,49 @@
H HashStateBase<H>::combine_contiguous(H state, const T* data, size_t size) {
return hash_internal::hash_range_or_bytes(std::move(state), data, size);
}
+
+// HashStateBase::PiecewiseCombiner::add_buffer()
+template <typename H>
+H PiecewiseCombiner::add_buffer(H state, const unsigned char* data,
+ size_t size) {
+ if (position_ + size < PiecewiseChunkSize()) {
+ // This partial chunk does not fill our existing buffer
+ memcpy(buf_ + position_, data, size);
+ position_ += size;
+ return state;
+ }
+
+ // If the buffer is partially filled we need to complete the buffer
+ // and hash it.
+ if (position_ != 0) {
+ const size_t bytes_needed = PiecewiseChunkSize() - position_;
+ memcpy(buf_ + position_, data, bytes_needed);
+ state = H::combine_contiguous(std::move(state), buf_, PiecewiseChunkSize());
+ data += bytes_needed;
+ size -= bytes_needed;
+ }
+
+ // Hash whatever chunks we can without copying
+ while (size >= PiecewiseChunkSize()) {
+ state = H::combine_contiguous(std::move(state), data, PiecewiseChunkSize());
+ data += PiecewiseChunkSize();
+ size -= PiecewiseChunkSize();
+ }
+ // Fill the buffer with the remainder
+ memcpy(buf_, data, size);
+ position_ = size;
+ return state;
+}
+
+// HashStateBase::PiecewiseCombiner::finalize()
+template <typename H>
+H PiecewiseCombiner::finalize(H state) {
+ // Hash the remainder left in the buffer, which may be empty
+ return H::combine_contiguous(std::move(state), buf_, position_);
+}
+
} // namespace hash_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_HASH_INTERNAL_HASH_H_
diff --git a/third_party/abseil/absl/hash/internal/spy_hash_state.h b/third_party/abseil/absl/hash/internal/spy_hash_state.h
index c4cc8d0..c083120 100644
--- a/third_party/abseil/absl/hash/internal/spy_hash_state.h
+++ b/third_party/abseil/absl/hash/internal/spy_hash_state.h
@@ -25,6 +25,7 @@
#include "absl/strings/str_join.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace hash_internal {
// SpyHashState is an implementation of the HashState API that simply
@@ -146,6 +147,19 @@
static SpyHashStateImpl combine_contiguous(SpyHashStateImpl hash_state,
const unsigned char* begin,
size_t size) {
+ const size_t large_chunk_stride = PiecewiseChunkSize();
+ if (size > large_chunk_stride) {
+ // Combining a large contiguous buffer must have the same effect as
+ // doing it piecewise by the stride length, followed by the (possibly
+ // empty) remainder.
+ while (size >= large_chunk_stride) {
+ hash_state = SpyHashStateImpl::combine_contiguous(
+ std::move(hash_state), begin, large_chunk_stride);
+ begin += large_chunk_stride;
+ size -= large_chunk_stride;
+ }
+ }
+
hash_state.hash_representation_.emplace_back(
reinterpret_cast<const char*>(begin), size);
return hash_state;
@@ -211,6 +225,7 @@
using SpyHashState = SpyHashStateImpl<void>;
} // namespace hash_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_HASH_INTERNAL_SPY_HASH_STATE_H_
diff --git a/third_party/abseil/absl/hash/internal/wyhash.cc b/third_party/abseil/absl/hash/internal/wyhash.cc
new file mode 100644
index 0000000..642bde4
--- /dev/null
+++ b/third_party/abseil/absl/hash/internal/wyhash.cc
@@ -0,0 +1,111 @@
+// Copyright 2020 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/hash/internal/wyhash.h"
+
+#include "absl/base/internal/unaligned_access.h"
+#include "absl/numeric/int128.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace hash_internal {
+
+static uint64_t WyhashMix(uint64_t v0, uint64_t v1) {
+ absl::uint128 p = v0;
+ p *= v1;
+ return absl::Uint128Low64(p) ^ absl::Uint128High64(p);
+}
+
+uint64_t Wyhash(const void* data, size_t len, uint64_t seed,
+ const uint64_t salt[]) {
+ const uint8_t* ptr = static_cast<const uint8_t*>(data);
+ uint64_t starting_length = static_cast<uint64_t>(len);
+ uint64_t current_state = seed ^ salt[0];
+
+ if (len > 64) {
+ // If we have more than 64 bytes, we're going to handle chunks of 64
+ // bytes at a time. We're going to build up two separate hash states
+ // which we will then hash together.
+ uint64_t duplicated_state = current_state;
+
+ do {
+ uint64_t a = absl::base_internal::UnalignedLoad64(ptr);
+ uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8);
+ uint64_t c = absl::base_internal::UnalignedLoad64(ptr + 16);
+ uint64_t d = absl::base_internal::UnalignedLoad64(ptr + 24);
+ uint64_t e = absl::base_internal::UnalignedLoad64(ptr + 32);
+ uint64_t f = absl::base_internal::UnalignedLoad64(ptr + 40);
+ uint64_t g = absl::base_internal::UnalignedLoad64(ptr + 48);
+ uint64_t h = absl::base_internal::UnalignedLoad64(ptr + 56);
+
+ uint64_t cs0 = WyhashMix(a ^ salt[1], b ^ current_state);
+ uint64_t cs1 = WyhashMix(c ^ salt[2], d ^ current_state);
+ current_state = (cs0 ^ cs1);
+
+ uint64_t ds0 = WyhashMix(e ^ salt[3], f ^ duplicated_state);
+ uint64_t ds1 = WyhashMix(g ^ salt[4], h ^ duplicated_state);
+ duplicated_state = (ds0 ^ ds1);
+
+ ptr += 64;
+ len -= 64;
+ } while (len > 64);
+
+ current_state = current_state ^ duplicated_state;
+ }
+
+ // We now have a data `ptr` with at most 64 bytes and the current state
+ // of the hashing state machine stored in current_state.
+ while (len > 16) {
+ uint64_t a = absl::base_internal::UnalignedLoad64(ptr);
+ uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8);
+
+ current_state = WyhashMix(a ^ salt[1], b ^ current_state);
+
+ ptr += 16;
+ len -= 16;
+ }
+
+ // We now have a data `ptr` with at most 16 bytes.
+ uint64_t a = 0;
+ uint64_t b = 0;
+ if (len > 8) {
+ // When we have at least 9 and at most 16 bytes, set A to the first 64
+ // bits of the input and B to the last 64 bits of the input. Yes, they will
+ // overlap in the middle if we are working with less than the full 16
+ // bytes.
+ a = absl::base_internal::UnalignedLoad64(ptr);
+ b = absl::base_internal::UnalignedLoad64(ptr + len - 8);
+ } else if (len > 3) {
+ // If we have at least 4 and at most 8 bytes, set A to the first 32
+ // bits and B to the last 32 bits.
+ a = absl::base_internal::UnalignedLoad32(ptr);
+ b = absl::base_internal::UnalignedLoad32(ptr + len - 4);
+ } else if (len > 0) {
+ // If we have at least 1 and at most 3 bytes, read all of the provided
+ // bits into A, with some adjustments.
+ a = ((ptr[0] << 16) | (ptr[len >> 1] << 8) | ptr[len - 1]);
+ b = 0;
+ } else {
+ a = 0;
+ b = 0;
+ }
+
+ uint64_t w = WyhashMix(a ^ salt[1], b ^ current_state);
+ uint64_t z = salt[1] ^ starting_length;
+ return WyhashMix(w, z);
+}
+
+} // namespace hash_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/hash/internal/wyhash.h b/third_party/abseil/absl/hash/internal/wyhash.h
new file mode 100644
index 0000000..4aff4e9
--- /dev/null
+++ b/third_party/abseil/absl/hash/internal/wyhash.h
@@ -0,0 +1,48 @@
+// Copyright 2020 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This file provides the Google-internal implementation of the Wyhash
+// algorithm.
+//
+// Wyhash is a fast hash function for hash tables, the fastest we've currently
+// (late 2020) found that passes the SMHasher tests. The algorithm relies on
+// intrinsic 128-bit multiplication for speed. This is not meant to be secure -
+// just fast.
+
+#ifndef ABSL_HASH_INTERNAL_WYHASH_H_
+#define ABSL_HASH_INTERNAL_WYHASH_H_
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace hash_internal {
+
+// Hash function for a byte array. A 64-bit seed and a set of five 64-bit
+// integers are hashed into the result.
+//
+// To allow all hashable types (including string_view and Span) to depend on
+// this algoritm, we keep the API low-level, with as few dependencies as
+// possible.
+uint64_t Wyhash(const void* data, size_t len, uint64_t seed,
+ const uint64_t salt[5]);
+
+} // namespace hash_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_HASH_INTERNAL_WYHASH_H_
diff --git a/third_party/abseil/absl/hash/internal/wyhash_test.cc b/third_party/abseil/absl/hash/internal/wyhash_test.cc
new file mode 100644
index 0000000..30dc9e3
--- /dev/null
+++ b/third_party/abseil/absl/hash/internal/wyhash_test.cc
@@ -0,0 +1,486 @@
+// Copyright 2020 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in cokSaltliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or ikSaltlied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/hash/internal/wyhash.h"
+
+#include "absl/strings/escaping.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace {
+
+static const uint64_t kCurrentSeed = 0;
+static const uint64_t kSalt[5] = {0xa0761d6478bd642f, 0xe7037ed1a0b428dbl,
+ 0x8ebc6af09c88c6e3, 0x589965cc75374cc3l,
+ 0x1d8e4e27c47d124f};
+
+// Note: We don't account for endianness, so the values here are only correct if
+// you're also running on a little endian platform.
+
+TEST(WyhashTest, EmptyString) {
+ const std::string s = "";
+ EXPECT_EQ(
+ absl::hash_internal::Wyhash(s.c_str(), s.length(), kCurrentSeed, kSalt),
+ 4808886099364463827);
+}
+
+TEST(WyhashTest, Spaces) {
+ const std::string s = " ";
+ EXPECT_EQ(
+ absl::hash_internal::Wyhash(s.c_str(), s.length(), kCurrentSeed, kSalt),
+ 1686201463024549249);
+}
+
+TEST(WyhashTest, RepeatingString) {
+ const std::string s = "aaaa";
+ EXPECT_EQ(
+ absl::hash_internal::Wyhash(s.c_str(), s.length(), kCurrentSeed, kSalt),
+ 6646112255271966632);
+}
+
+TEST(WyhashTest, HexString) {
+ const std::string small = "\x01\x02\x03";
+ const std::string med = "\x01\x02\x03\x04";
+
+ EXPECT_EQ(absl::hash_internal::Wyhash(small.c_str(), small.length(),
+ kCurrentSeed, kSalt),
+ 11989428023081740911ULL);
+ EXPECT_EQ(absl::hash_internal::Wyhash(med.c_str(), med.length(), kCurrentSeed,
+ kSalt),
+ 9765997711188871556ULL);
+}
+
+TEST(WyhashTest, Words) {
+ const std::string s = "third_party|wyhash|64";
+ EXPECT_EQ(
+ absl::hash_internal::Wyhash(s.c_str(), s.length(), kCurrentSeed, kSalt),
+ 3702018632387611330);
+}
+
+TEST(WyhashTest, LongString) {
+ const std::string s =
+ "AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKlMnOpQrStUvWxYz"
+ "0123456789AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKlMnOp"
+ "QrStUvWxYz0123456789AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEf"
+ "GhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKlMnOpQrStUvWxYz012345"
+ "6789AbCdEfGhIjKlMnOpQrStUvWxYz0123456789";
+
+ EXPECT_EQ(
+ absl::hash_internal::Wyhash(s.c_str(), s.length(), kCurrentSeed, kSalt),
+ 9245411362605796064ULL);
+}
+
+TEST(WyhashTest, BigReference) {
+ struct ExpectedResult {
+ absl::string_view base64_data;
+ uint64_t seed;
+ uint64_t hash;
+ } expected_results[] = {
+ {"", uint64_t{0xec42b7ab404b8acb}, uint64_t{0xe5a40d39ab796423}},
+ {"Zw==", uint64_t{0xeeee074043a3ee0f}, uint64_t{0xa6564b468248c683}},
+ {"xmk=", uint64_t{0x857902089c393de}, uint64_t{0xef192f401b116e1c}},
+ {"c1H/", uint64_t{0x993df040024ca3af}, uint64_t{0xbe8dc0c54617639d}},
+ {"SuwpzQ==", uint64_t{0xc4e4c2acea740e96}, uint64_t{0x93d7f665b5521c8e}},
+ {"uqvy++M=", uint64_t{0x6a214b3db872d0cf}, uint64_t{0x646d70bb42445f28}},
+ {"RnzCVPgb", uint64_t{0x44343db6a89dba4d}, uint64_t{0x96a7b1e3cc9bd426}},
+ {"6OeNdlouYw==", uint64_t{0x77b5d6d1ae1dd483},
+ uint64_t{0x76020289ab0790c4}},
+ {"M5/JmmYyDbc=", uint64_t{0x89ab8ecb44d221f1},
+ uint64_t{0x39f842e4133b9b44}},
+ {"MVijWiVdBRdY", uint64_t{0x60244b17577ca81b},
+ uint64_t{0x2b8d7047be4bcaab}},
+ {"6V7Uq7LNxpu0VA==", uint64_t{0x59a08dcee0717067},
+ uint64_t{0x99628abef6716a97}},
+ {"EQ6CdEEhPdyHcOk=", uint64_t{0xf5f20db3ade57396},
+ uint64_t{0x4432e02ba42b2740}},
+ {"PqFB4fxnPgF+l+rc", uint64_t{0xbf8dee0751ad3efb},
+ uint64_t{0x74d810efcad7918a}},
+ {"a5aPOFwq7LA7+zKvPA==", uint64_t{0x6b7a06b268d63e30},
+ uint64_t{0x88c84e986002507f}},
+ {"VOwY21wCGv5D+/qqOvs=", uint64_t{0xb8c37f0ae0f54c82},
+ uint64_t{0x4f99acf193cf39b9}},
+ {"KdHmBTx8lHXYvmGJ+Vy7", uint64_t{0x9fcbed0c38e50eef},
+ uint64_t{0xd90e7a3655891e37}},
+ {"qJkPlbHr8bMF7/cA6aE65Q==", uint64_t{0x2af4bade1d8e3a1d},
+ uint64_t{0x3bb378b1d4df8fcf}},
+ {"ygvL0EhHZL0fIx6oHHtkxRQ=", uint64_t{0x714e3aa912da2f2c},
+ uint64_t{0xf78e94045c052d47}},
+ {"c1rFXkt5YztwZCQRngncqtSs", uint64_t{0xf5ee75e3cbb82c1c},
+ uint64_t{0x26da0b2130da6b40}},
+ {"8hsQrzszzeNQSEcVXLtvIhm6mw==", uint64_t{0x620e7007321b93b9},
+ uint64_t{0x30b4d426af8c6986}},
+ {"ffUL4RocfyP4KfikGxO1yk7omDI=", uint64_t{0xc08528cac2e551fc},
+ uint64_t{0x5413b4aaf3baaeae}},
+ {"OOB5TT00vF9Od/rLbAWshiErqhpV", uint64_t{0x6a1debf9cc3ad39},
+ uint64_t{0x756ab265370a1597}},
+ {"or5wtXM7BFzTNpSzr+Lw5J5PMhVJ/Q==", uint64_t{0x7e0a3c88111fc226},
+ uint64_t{0xdaf5f4b7d09814fb}},
+ {"gk6pCHDUsoopVEiaCrzVDhioRKxb844=", uint64_t{0x1301fef15df39edb},
+ uint64_t{0x8f874ae37742b75e}},
+ {"TNctmwlC5QbEM6/No4R/La3UdkfeMhzs", uint64_t{0x64e181f3d5817ab},
+ uint64_t{0x8fecd03956121ce8}},
+ {"SsQw9iAjhWz7sgcE9OwLuSC6hsM+BfHs2Q==", uint64_t{0xafafc44961078ecb},
+ uint64_t{0x229c292ea7a08285}},
+ {"ZzO3mVCj4xTT2TT3XqDyEKj2BZQBvrS8RHg=", uint64_t{0x4f7bb45549250094},
+ uint64_t{0xbb4bf0692d14bae}},
+ {"+klp5iPQGtppan5MflEls0iEUzqU+zGZkDJX", uint64_t{0xa30061abaa2818c},
+ uint64_t{0x207b24ca3bdac1db}},
+ {"RO6bvOnlJc8I9eniXlNgqtKy0IX6VNg16NRmgg==", uint64_t{0xd902ee3e44a5705f},
+ uint64_t{0x64f6cd6745d3825b}},
+ {"ZJjZqId1ZXBaij9igClE3nyliU5XWdNRrayGlYA=", uint64_t{0x316d36da516f583},
+ uint64_t{0xa2b2e1656b58df1e}},
+ {"7BfkhfGMDGbxfMB8uyL85GbaYQtjr2K8g7RpLzr/", uint64_t{0x402d83f9f834f616},
+ uint64_t{0xd01d30d9ee7a148}},
+ {"rycWk6wHH7htETQtje9PidS2YzXBx+Qkg2fY7ZYS7A==",
+ uint64_t{0x9c604164c016b72c}, uint64_t{0x1cb4cd00ab804e3b}},
+ {"RTkC2OUK+J13CdGllsH0H5WqgspsSa6QzRZouqx6pvI=",
+ uint64_t{0x3f4507e01f9e73ba}, uint64_t{0x4697f2637fd90999}},
+ {"tKjKmbLCNyrLCM9hycOAXm4DKNpM12oZ7dLTmUx5iwAi",
+ uint64_t{0xc3fe0d5be8d2c7c7}, uint64_t{0x8383a756b5688c07}},
+ {"VprUGNH+5NnNRaORxgH/ySrZFQFDL+4VAodhfBNinmn8cg==",
+ uint64_t{0x531858a40bfa7ea1}, uint64_t{0x695c29cb3696a975}},
+ {"gc1xZaY+q0nPcUvOOnWnT3bqfmT/geth/f7Dm2e/DemMfk4=",
+ uint64_t{0x86689478a7a7e8fa}, uint64_t{0xda2e5a5a5e971521}},
+ {"Mr35fIxqx1ukPAL0su1yFuzzAU3wABCLZ8+ZUFsXn47UmAph",
+ uint64_t{0x4ec948b8e7f27288}, uint64_t{0x7935d4befa056b2b}},
+ {"A9G8pw2+m7+rDtWYAdbl8tb2fT7FFo4hLi2vAsa5Y8mKH3CX3g==",
+ uint64_t{0xce46c7213c10032}, uint64_t{0x38dd541ca95420fe}},
+ {"DFaJGishGwEHDdj9ixbCoaTjz9KS0phLNWHVVdFsM93CvPft3hM=",
+ uint64_t{0xf63e96ee6f32a8b6}, uint64_t{0xcc06c7a4963f967f}},
+ {"7+Ugx+Kr3aRNgYgcUxru62YkTDt5Hqis+2po81hGBkcrJg4N0uuy",
+ uint64_t{0x1cfe85e65fc5225}, uint64_t{0xbf0f6f66e232fb20}},
+ {"H2w6O8BUKqu6Tvj2xxaecxEI2wRgIgqnTTG1WwOgDSINR13Nm4d4Vg==",
+ uint64_t{0x45c474f1cee1d2e8}, uint64_t{0xf7efb32d373fe71a}},
+ {"1XBMnIbqD5jy65xTDaf6WtiwtdtQwv1dCVoqpeKj+7cTR1SaMWMyI04=",
+ uint64_t{0x6e024e14015f329c}, uint64_t{0xe2e64634b1c12660}},
+ {"znZbdXG2TSFrKHEuJc83gPncYpzXGbAebUpP0XxzH0rpe8BaMQ17nDbt",
+ uint64_t{0x760c40502103ae1c}, uint64_t{0x285b8fd1638e306d}},
+ {"ylu8Atu13j1StlcC1MRMJJXIl7USgDDS22HgVv0WQ8hx/8pNtaiKB17hCQ==",
+ uint64_t{0x17fd05c3c560c320}, uint64_t{0x658e8a4e3b714d6c}},
+ {"M6ZVVzsd7vAvbiACSYHioH/440dp4xG2mLlBnxgiqEvI/aIEGpD0Sf4VS0g=",
+ uint64_t{0x8b34200a6f8e90d9}, uint64_t{0xf391fb968e0eb398}},
+ {"li3oFSXLXI+ubUVGJ4blP6mNinGKLHWkvGruun85AhVn6iuMtocbZPVhqxzn",
+ uint64_t{0x6be89e50818bdf69}, uint64_t{0x744a9ea0cc144bf2}},
+ {"kFuQHuUCqBF3Tc3hO4dgdIp223ShaCoog48d5Do5zMqUXOh5XpGK1t5XtxnfGA==",
+ uint64_t{0xfb389773315b47d8}, uint64_t{0x12636f2be11012f1}},
+ {"jWmOad0v0QhXVJd1OdGuBZtDYYS8wBVHlvOeTQx9ZZnm8wLEItPMeihj72E0nWY=",
+ uint64_t{0x4f2512a23f61efee}, uint64_t{0x29c57de825948f80}},
+ {"z+DHU52HaOQdW4JrZwDQAebEA6rm13Zg/9lPYA3txt3NjTBqFZlOMvTRnVzRbl23",
+ uint64_t{0x59ccd92fc16c6fda}, uint64_t{0x58c6f99ab0d1c021}},
+ {"MmBiGDfYeTayyJa/tVycg+rN7f9mPDFaDc+23j0TlW9094er0ADigsl4QX7V3gG/qw==",
+ uint64_t{0x25c5a7f5bd330919}, uint64_t{0x13e7b5a7b82fe3bb}},
+ {"774RK+9rOL4iFvs1q2qpo/JVc/I39buvNjqEFDtDvyoB0FXxPI2vXqOrk08VPfIHkmU=",
+ uint64_t{0x51df4174d34c97d7}, uint64_t{0x10fbc87901e02b63}},
+ {"+slatXiQ7/2lK0BkVUI1qzNxOOLP3I1iK6OfHaoxgqT63FpzbElwEXSwdsryq3UlHK0I",
+ uint64_t{0x80ce6d76f89cb57}, uint64_t{0xa24c9184901b748b}},
+ {"64mVTbQ47dHjHlOHGS/hjJwr/"
+ "K2frCNpn87exOqMzNUVYiPKmhCbfS7vBUce5tO6Ec9osQ==",
+ uint64_t{0x20961c911965f684}, uint64_t{0xcac4fd4c5080e581}},
+ {"fIsaG1r530SFrBqaDj1kqE0AJnvvK8MNEZbII2Yw1OK77v0V59xabIh0B5axaz/"
+ "+a2V5WpA=",
+ uint64_t{0x4e5b926ec83868e7}, uint64_t{0xc38bdb7483ba68e1}},
+ {"PGih0zDEOWCYGxuHGDFu9Ivbff/"
+ "iE7BNUq65tycTR2R76TerrXALRosnzaNYO5fjFhTi+CiS",
+ uint64_t{0x3927b30b922eecef}, uint64_t{0xdb2a8069b2ceaffa}},
+ {"RnpA/"
+ "zJnEnnLjmICORByRVb9bCOgxF44p3VMiW10G7PvW7IhwsWajlP9kIwNA9FjAD2GoQHk2Q="
+ "=",
+ uint64_t{0xbd0291284a49b61c}, uint64_t{0xdf9fe91d0d1c7887}},
+ {"qFklMceaTHqJpy2qavJE+EVBiNFOi6OxjOA3LeIcBop1K7w8xQi3TrDk+"
+ "BrWPRIbfprszSaPfrI=",
+ uint64_t{0x73a77c575bcc956}, uint64_t{0xe83f49e96e2e6a08}},
+ {"cLbfUtLl3EcQmITWoTskUR8da/VafRDYF/ylPYwk7/"
+ "zazk6ssyrzxMN3mmSyvrXR2yDGNZ3WDrTT",
+ uint64_t{0x766a0e2ade6d09a6}, uint64_t{0xc69e61b62ca2b62}},
+ {"s/"
+ "Jf1+"
+ "FbsbCpXWPTUSeWyMH6e4CvTFvPE5Fs6Z8hvFITGyr0dtukHzkI84oviVLxhM1xMxrMAy1db"
+ "w==",
+ uint64_t{0x2599f4f905115869}, uint64_t{0xb4a4f3f85f8298fe}},
+ {"FvyQ00+j7nmYZVQ8hI1Edxd0AWplhTfWuFGiu34AK5X8u2hLX1bE97sZM0CmeLe+"
+ "7LgoUT1fJ/axybE=",
+ uint64_t{0xd8256e5444d21e53}, uint64_t{0x167a1b39e1e95f41}},
+ {"L8ncxMaYLBH3g9buPu8hfpWZNlOF7nvWLNv9IozH07uQsIBWSKxoPy8+"
+ "LW4tTuzC6CIWbRGRRD1sQV/4",
+ uint64_t{0xf664a91333fb8dfd}, uint64_t{0xf8a2a5649855ee41}},
+ {"CDK0meI07yrgV2kQlZZ+"
+ "wuVqhc2NmzqeLH7bmcA6kchsRWFPeVF5Wqjjaj556ABeUoUr3yBmfU3kWOakkg==",
+ uint64_t{0x9625b859be372cd1}, uint64_t{0x27992565b595c498}},
+ {"d23/vc5ONh/"
+ "HkMiq+gYk4gaCNYyuFKwUkvn46t+dfVcKfBTYykr4kdvAPNXGYLjM4u1YkAEFpJP+"
+ "nX7eOvs=",
+ uint64_t{0x7b99940782e29898}, uint64_t{0x3e08cca5b71f9346}},
+ {"NUR3SRxBkxTSbtQORJpu/GdR6b/h6sSGfsMj/KFd99ahbh+9r7LSgSGmkGVB/"
+ "mGoT0pnMTQst7Lv2q6QN6Vm",
+ uint64_t{0x4fe12fa5383b51a8}, uint64_t{0xad406b10c770a6d2}},
+ {"2BOFlcI3Z0RYDtS9T9Ie9yJoXlOdigpPeeT+CRujb/"
+ "O39Ih5LPC9hP6RQk1kYESGyaLZZi3jtabHs7DiVx/VDg==",
+ uint64_t{0xe2ccb09ac0f5b4b6}, uint64_t{0xd1713ce6e552bcf2}},
+ {"FF2HQE1FxEvWBpg6Z9zAMH+Zlqx8S1JD/"
+ "wIlViL6ZDZY63alMDrxB0GJQahmAtjlm26RGLnjW7jmgQ4Ie3I+014=",
+ uint64_t{0x7d0a37adbd7b753b}, uint64_t{0x753b287194c73ad3}},
+ {"tHmO7mqVL/PX11nZrz50Hc+M17Poj5lpnqHkEN+4bpMx/"
+ "YGbkrGOaYjoQjgmt1X2QyypK7xClFrjeWrCMdlVYtbW",
+ uint64_t{0xd3ae96ef9f7185f2}, uint64_t{0x5ae41a95f600af1c}},
+ {"/WiHi9IQcxRImsudkA/KOTqGe8/"
+ "gXkhKIHkjddv5S9hi02M049dIK3EUyAEjkjpdGLUs+BN0QzPtZqjIYPOgwsYE9g==",
+ uint64_t{0x4fb88ea63f79a0d8}, uint64_t{0x4a61163b86a8bb4c}},
+ {"qds+1ExSnU11L4fTSDz/QE90g4Jh6ioqSh3KDOTOAo2pQGL1k/"
+ "9CCC7J23YF27dUTzrWsCQA2m4epXoCc3yPHb3xElA=",
+ uint64_t{0xed564e259bb5ebe9}, uint64_t{0x42eeaa79e760c7e4}},
+ {"8FVYHx40lSQPTHheh08Oq0/"
+ "pGm2OlG8BEf8ezvAxHuGGdgCkqpXIueJBF2mQJhTfDy5NncO8ntS7vaKs7sCNdDaNGOEi",
+ uint64_t{0x3e3256b60c428000}, uint64_t{0x698df622ef465b0a}},
+ {"4ZoEIrJtstiCkeew3oRzmyJHVt/pAs2pj0HgHFrBPztbQ10NsQ/"
+ "lM6DM439QVxpznnBSiHMgMQJhER+70l72LqFTO1JiIQ==",
+ uint64_t{0xfb05bad59ec8705}, uint64_t{0x157583111e1a6026}},
+ {"hQPtaYI+wJyxXgwD5n8jGIKFKaFA/"
+ "P83KqCKZfPthnjwdOFysqEOYwAaZuaaiv4cDyi9TyS8hk5cEbNP/jrI7q6pYGBLbsM=",
+ uint64_t{0xafdc251dbf97b5f8}, uint64_t{0xaa1388f078e793e0}},
+ {"S4gpMSKzMD7CWPsSfLeYyhSpfWOntyuVZdX1xSBjiGvsspwOZcxNKCRIOqAA0moUfOh3I5+"
+ "juQV4rsqYElMD/gWfDGpsWZKQ",
+ uint64_t{0x10ec9c92ddb5dcbc}, uint64_t{0xf10d68d0f3309360}},
+ {"oswxop+"
+ "bthuDLT4j0PcoSKby4LhF47ZKg8K17xxHf74UsGCzTBbOz0MM8hQEGlyqDT1iUiAYnaPaUp"
+ "L2mRK0rcIUYA4qLt5uOw==",
+ uint64_t{0x9a767d5822c7dac4}, uint64_t{0x2af056184457a3de}},
+ {"0II/"
+ "697p+"
+ "BtLSjxj5989OXI004TogEb94VUnDzOVSgMXie72cuYRvTFNIBgtXlKfkiUjeqVpd4a+"
+ "n5bxNOD1TGrjQtzKU5r7obo=",
+ uint64_t{0xee46254080d6e2db}, uint64_t{0x6d0058e1590b2489}},
+ {"E84YZW2qipAlMPmctrg7TKlwLZ68l4L+c0xRDUfyyFrA4MAti0q9sHq3TDFviH0Y+"
+ "Kq3tEE5srWFA8LM9oomtmvm5PYxoaarWPLc",
+ uint64_t{0xbbb669588d8bf398}, uint64_t{0x638f287f68817f12}},
+ {"x3pa4HIElyZG0Nj7Vdy9IdJIR4izLmypXw5PCmZB5y68QQ4uRaVVi3UthsoJROvbjDJkP2D"
+ "Q6L/eN8pFeLFzNPKBYzcmuMOb5Ull7w==",
+ uint64_t{0xdc2afaa529beef44}, uint64_t{0xc46b71fecefd5467}},
+ {"jVDKGYIuWOP/"
+ "QKLdd2wi8B2VJA8Wh0c8PwrXJVM8FOGM3voPDVPyDJOU6QsBDPseoR8uuKd19OZ/"
+ "zAvSCB+zlf6upAsBlheUKgCfKww=",
+ uint64_t{0xf1f67391d45013a8}, uint64_t{0x2c8e94679d964e0a}},
+ {"mkquunhmYe1aR2wmUz4vcvLEcKBoe6H+kjUok9VUn2+eTSkWs4oDDtJvNCWtY5efJwg/"
+ "j4PgjRYWtqnrCkhaqJaEvkkOwVfgMIwF3e+d",
+ uint64_t{0x16fce2b8c65a3429}, uint64_t{0x8612b797ce22503a}},
+ {"fRelvKYonTQ+s+rnnvQw+JzGfFoPixtna0vzcSjiDqX5s2Kg2//"
+ "UGrK+AVCyMUhO98WoB1DDbrsOYSw2QzrcPe0+3ck9sePvb+Q/IRaHbw==",
+ uint64_t{0xf4b096699f49fe67}, uint64_t{0x59f929babfba7170}},
+ {"DUwXFJzagljo44QeJ7/"
+ "6ZKw4QXV18lhkYT2jglMr8WB3CHUU4vdsytvw6AKv42ZcG6fRkZkq9fpnmXy6xG0aO3WPT1"
+ "eHuyFirAlkW+zKtwg=",
+ uint64_t{0xca584c4bc8198682}, uint64_t{0x9527556923fb49a0}},
+ {"cYmZCrOOBBongNTr7e4nYn52uQUy2mfe48s50JXx2AZ6cRAt/"
+ "xRHJ5QbEoEJOeOHsJyM4nbzwFm++SlT6gFZZHJpkXJ92JkR86uS/eV1hJUR",
+ uint64_t{0xed269fc3818b6aad}, uint64_t{0x1039ab644f5e150b}},
+ {"EXeHBDfhwzAKFhsMcH9+2RHwV+mJaN01+9oacF6vgm8mCXRd6jeN9U2oAb0of5c5cO4i+"
+ "Vb/LlHZSMI490SnHU0bejhSCC2gsC5d2K30ER3iNA==",
+ uint64_t{0x33f253cbb8fe66a8}, uint64_t{0x7816c83f3aa05e6d}},
+ {"FzkzRYoNjkxFhZDso94IHRZaJUP61nFYrh5MwDwv9FNoJ5jyNCY/"
+ "eazPZk+tbmzDyJIGw2h3GxaWZ9bSlsol/vK98SbkMKCQ/wbfrXRLcDzdd/8=",
+ uint64_t{0xd0b76b2c1523d99c}, uint64_t{0xf51d2f564518c619}},
+ {"Re4aXISCMlYY/XsX7zkIFR04ta03u4zkL9dVbLXMa/q6hlY/CImVIIYRN3VKP4pnd0AUr/"
+ "ugkyt36JcstAInb4h9rpAGQ7GMVOgBniiMBZ/MGU7H",
+ uint64_t{0xfd28f0811a2a237f}, uint64_t{0x67d494cff03ac004}},
+ {"ueLyMcqJXX+MhO4UApylCN9WlTQ+"
+ "ltJmItgG7vFUtqs2qNwBMjmAvr5u0sAKd8jpzV0dDPTwchbIeAW5zbtkA2NABJV6hFM48ib"
+ "4/J3A5mseA3cS8w==",
+ uint64_t{0x6261fb136482e84}, uint64_t{0x2802d636ced1cfbb}},
+ {"6Si7Yi11L+jZMkwaN+GUuzXMrlvEqviEkGOilNq0h8TdQyYKuFXzkYc/"
+ "q74gP3pVCyiwz9KpVGMM9vfnq36riMHRknkmhQutxLZs5fbmOgEO69HglCU=",
+ uint64_t{0x458efc750bca7c3a}, uint64_t{0xf64e20bad771cb12}},
+ {"Q6AbOofGuTJOegPh9Clm/"
+ "9crtUMQqylKrTc1fhfJo1tqvpXxhU4k08kntL1RG7woRnFrVh2UoMrL1kjin+s9CanT+"
+ "y4hHwLqRranl9FjvxfVKm3yvg68",
+ uint64_t{0xa7e69ff84e5e7c27}, uint64_t{0xb9a6cf84a83e15e}},
+ {"ieQEbIPvqY2YfIjHnqfJiO1/MIVRk0RoaG/WWi3kFrfIGiNLCczYoklgaecHMm/"
+ "1sZ96AjO+a5stQfZbJQwS7Sc1ODABEdJKcTsxeW2hbh9A6CFzpowP1A==",
+ uint64_t{0x3c59bfd0c29efe9e}, uint64_t{0x8da6630319609301}},
+ {"zQUv8hFB3zh2GGl3KTvCmnfzE+"
+ "SUgQPVaSVIELFX5H9cE3FuVFGmymkPQZJLAyzC90Cmi8GqYCvPqTuAAB//"
+ "XTJxy4bCcVArgZG9zJXpjowpNBfr3ngWrSE=",
+ uint64_t{0x10befacc6afd298d}, uint64_t{0x40946a86e2a996f3}},
+ {"US4hcC1+op5JKGC7eIs8CUgInjKWKlvKQkapulxW262E/"
+ "B2ye79QxOexf188u2mFwwe3WTISJHRZzS61IwljqAWAWoBAqkUnW8SHmIDwHUP31J0p5sGd"
+ "P47L",
+ uint64_t{0x41d5320b0a38efa7}, uint64_t{0xcab7f5997953fa76}},
+ {"9bHUWFna2LNaGF6fQLlkx1Hkt24nrkLE2CmFdWgTQV3FFbUe747SSqYw6ebpTa07MWSpWRP"
+ "sHesVo2B9tqHbe7eQmqYebPDFnNqrhSdZwFm9arLQVs+7a3Ic6A==",
+ uint64_t{0x58db1c7450fe17f3}, uint64_t{0x39129ca0e04fc465}},
+ {"Kb3DpHRUPhtyqgs3RuXjzA08jGb59hjKTOeFt1qhoINfYyfTt2buKhD6YVffRCPsgK9SeqZ"
+ "qRPJSyaqsa0ovyq1WnWW8jI/NhvAkZTVHUrX2pC+cD3OPYT05Dag=",
+ uint64_t{0x6098c055a335b7a6}, uint64_t{0x5238221fd685e1b8}},
+ {"gzxyMJIPlU+bJBwhFUCHSofZ/"
+ "319LxqMoqnt3+L6h2U2+ZXJCSsYpE80xmR0Ta77Jq54o92SMH87HV8dGOaCTuAYF+"
+ "lDL42SY1P316Cl0sZTS2ow3ZqwGbcPNs/1",
+ uint64_t{0x1bbacec67845a801}, uint64_t{0x175130c407dbcaab}},
+ {"uR7V0TW+FGVMpsifnaBAQ3IGlr1wx5sKd7TChuqRe6OvUXTlD4hKWy8S+"
+ "8yyOw8lQabism19vOQxfmocEOW/"
+ "vzY0pEa87qHrAZy4s9fH2Bltu8vaOIe+agYohhYORQ==",
+ uint64_t{0xc419cfc7442190}, uint64_t{0x2f20e7536c0b0df}},
+ {"1UR5eoo2aCwhacjZHaCh9bkOsITp6QunUxHQ2SfeHv0imHetzt/"
+ "Z70mhyWZBalv6eAx+YfWKCUib2SHDtz/"
+ "A2dc3hqUWX5VfAV7FQsghPUAtu6IiRatq4YSLpDvKZBQ=",
+ uint64_t{0xc95e510d94ba270c}, uint64_t{0x2742cb488a04ad56}},
+ {"opubR7H63BH7OtY+Avd7QyQ25UZ8kLBdFDsBTwZlY6gA/"
+ "u+x+"
+ "czC9AaZMgmQrUy15DH7YMGsvdXnviTtI4eVI4aF1H9Rl3NXMKZgwFOsdTfdcZeeHVRzBBKX"
+ "8jUfh1il",
+ uint64_t{0xff1ae05c98089c3f}, uint64_t{0xd6afb593879ff93b}},
+ {"DC0kXcSXtfQ9FbSRwirIn5tgPri0sbzHSa78aDZVDUKCMaBGyFU6BmrulywYX8yzvwprdLs"
+ "oOwTWN2wMjHlPDqrvVHNEjnmufRDblW+nSS+xtKNs3N5xsxXdv6JXDrAB/Q==",
+ uint64_t{0x90c02b8dceced493}, uint64_t{0xf50ad64caac0ca7f}},
+ {"BXRBk+3wEP3Lpm1y75wjoz+PgB0AMzLe8tQ1AYU2/"
+ "oqrQB2YMC6W+9QDbcOfkGbeH+b7IBkt/"
+ "gwCMw2HaQsRFEsurXtcQ3YwRuPz5XNaw5NAvrNa67Fm7eRzdE1+hWLKtA8=",
+ uint64_t{0x9f8a76697ab1aa36}, uint64_t{0x2ade95c4261364ae}},
+ {"RRBSvEGYnzR9E45Aps/+WSnpCo/X7gJLO4DRnUqFrJCV/kzWlusLE/"
+ "6ZU6RoUf2ROwcgEvUiXTGjLs7ts3t9SXnJHxC1KiOzxHdYLMhVvgNd3hVSAXODpKFSkVXND"
+ "55G2L1W",
+ uint64_t{0x6ba1bf3d811a531d}, uint64_t{0x5c4f3299faacd07a}},
+ {"jeh6Qazxmdi57pa9S3XSnnZFIRrnc6s8QLrah5OX3SB/V2ErSPoEAumavzQPkdKF1/"
+ "SfvmdL+qgF1C+Yawy562QaFqwVGq7+tW0yxP8FStb56ZRgNI4IOmI30s1Ei7iops9Uuw==",
+ uint64_t{0x6a418974109c67b4}, uint64_t{0xfffe3bff0ae5e9bc}},
+ {"6QO5nnDrY2/"
+ "wrUXpltlKy2dSBcmK15fOY092CR7KxAjNfaY+"
+ "aAmtWbbzQk3MjBg03x39afSUN1fkrWACdyQKRaGxgwq6MGNxI6W+8DLWJBHzIXrntrE/"
+ "ml6fnNXEpxplWJ1vEs4=",
+ uint64_t{0x8472f1c2b3d230a3}, uint64_t{0x1db785c0005166e4}},
+ {"0oPxeEHhqhcFuwonNfLd5jF3RNATGZS6NPoS0WklnzyokbTqcl4BeBkMn07+fDQv83j/"
+ "BpGUwcWO05f3+DYzocfnizpFjLJemFGsls3gxcBYxcbqWYev51tG3lN9EvRE+X9+Pwww",
+ uint64_t{0x5e06068f884e73a7}, uint64_t{0xea000d962ad18418}},
+ {"naSBSjtOKgAOg8XVbR5cHAW3Y+QL4Pb/JO9/"
+ "oy6L08wvVRZqo0BrssMwhzBP401Um7A4ppAupbQeJFdMrysY34AuSSNvtNUy5VxjNECwiNt"
+ "gwYHw7yakDUv8WvonctmnoSPKENegQg==",
+ uint64_t{0x55290b1a8f170f59}, uint64_t{0xe42aef38359362d9}},
+ {"vPyl8DxVeRe1OpilKb9KNwpGkQRtA94UpAHetNh+"
+ "95V7nIW38v7PpzhnTWIml5kw3So1Si0TXtIUPIbsu32BNhoH7QwFvLM+"
+ "JACgSpc5e3RjsL6Qwxxi11npwxRmRUqATDeMUfRAjxg=",
+ uint64_t{0x5501cfd83dfe706a}, uint64_t{0xc8e95657348a3891}},
+ {"QC9i2GjdTMuNC1xQJ74ngKfrlA4w3o58FhvNCltdIpuMhHP1YsDA78scQPLbZ3OCUgeQguY"
+ "f/vw6zAaVKSgwtaykqg5ka/4vhz4hYqWU5ficdXqClHl+zkWEY26slCNYOM5nnDlly8Cj",
+ uint64_t{0xe43ed13d13a66990}, uint64_t{0xc162eca864f238c6}},
+ {"7CNIgQhAHX27nxI0HeB5oUTnTdgKpRDYDKwRcXfSFGP1XeT9nQF6WKCMjL1tBV6x7KuJ91G"
+ "Zz11F4c+8s+MfqEAEpd4FHzamrMNjGcjCyrVtU6y+7HscMVzr7Q/"
+ "ODLcPEFztFnwjvCjmHw==",
+ uint64_t{0xdf43bc375cf5283f}, uint64_t{0xbe1fb373e20579ad}},
+ {"Qa/hC2RPXhANSospe+gUaPfjdK/yhQvfm4cCV6/pdvCYWPv8p1kMtKOX3h5/"
+ "8oZ31fsmx4Axphu5qXJokuhZKkBUJueuMpxRyXpwSWz2wELx5glxF7CM0Fn+"
+ "OevnkhUn5jsPlG2r5jYlVn8=",
+ uint64_t{0x8112b806d288d7b5}, uint64_t{0x628a1d4f40aa6ffd}},
+ {"kUw/0z4l3a89jTwN5jpG0SHY5km/"
+ "IVhTjgM5xCiPRLncg40aqWrJ5vcF891AOq5hEpSq0bUCJUMFXgct7kvnys905HjerV7Vs1G"
+ "y84tgVJ70/2+pAZTsB/PzNOE/G6sOj4+GbTzkQu819OLB",
+ uint64_t{0xd52a18abb001cb46}, uint64_t{0xa87bdb7456340f90}},
+ {"VDdfSDbO8Tdj3T5W0XM3EI7iHh5xpIutiM6dvcJ/fhe23V/srFEkDy5iZf/"
+ "VnA9kfi2C79ENnFnbOReeuZW1b3MUXB9lgC6U4pOTuC+"
+ "jHK3Qnpyiqzj7h3ISJSuo2pob7vY6VHZo6Fn7exEqHg==",
+ uint64_t{0xe12b76a2433a1236}, uint64_t{0x5960ef3ba982c801}},
+ {"Ldfvy3ORdquM/R2fIkhH/ONi69mcP1AEJ6n/"
+ "oropwecAsLJzQSgezSY8bEiEs0VnFTBBsW+RtZY6tDj03fnb3amNUOq1b7jbqyQkL9hpl+"
+ "2Z2J8IaVSeownWl+bQcsR5/xRktIMckC5AtF4YHfU=",
+ uint64_t{0x175bf7319cf1fa00}, uint64_t{0x5026586df9a431ec}},
+ {"BrbNpb42+"
+ "VzZAjJw6QLirXzhweCVRfwlczzZ0VX2xluskwBqyfnGovz5EuX79JJ31VNXa5hTkAyQat3l"
+ "YKRADTdAdwE5PqM1N7YaMqqsqoAAAeuYVXuk5eWCykYmClNdSspegwgCuT+403JigBzi",
+ uint64_t{0xd63d57b3f67525ae}, uint64_t{0xfe4b8a20fdf0840b}},
+ {"gB3NGHJJvVcuPyF0ZSvHwnWSIfmaI7La24VMPQVoIIWF7Z74NltPZZpx2f+cocESM+"
+ "ILzQW9p+BC8x5IWz7N4Str2WLGKMdgmaBfNkEhSHQDU0IJEOnpUt0HmjhFaBlx0/"
+ "LTmhua+rQ6Wup8ezLwfg==",
+ uint64_t{0x933faea858832b73}, uint64_t{0xdcb761867da7072f}},
+ {"hTKHlRxx6Pl4gjG+6ksvvj0CWFicUg3WrPdSJypDpq91LUWRni2KF6+"
+ "81ZoHBFhEBrCdogKqeK+hy9bLDnx7g6rAFUjtn1+cWzQ2YjiOpz4+"
+ "ROBB7lnwjyTGWzJD1rXtlso1g2qVH8XJVigC5M9AIxM=",
+ uint64_t{0x53d061e5f8e7c04f}, uint64_t{0xc10d4653667275b7}},
+ {"IWQBelSQnhrr0F3BhUpXUIDauhX6f95Qp+A0diFXiUK7irwPG1oqBiqHyK/SH/"
+ "9S+"
+ "rln9DlFROAmeFdH0OCJi2tFm4afxYzJTFR4HnR4cG4x12JqHaZLQx6iiu6CE3rtWBVz99oA"
+ "wCZUOEXIsLU24o2Y",
+ uint64_t{0xdb4124556dd515e0}, uint64_t{0x727720deec13110b}},
+ {"TKo+l+"
+ "1dOXdLvIrFqeLaHdm0HZnbcdEgOoLVcGRiCbAMR0j5pIFw8D36tefckAS1RCFOH5IgP8yiF"
+ "T0Gd0a2hI3+"
+ "fTKA7iK96NekxWeoeqzJyctc6QsoiyBlkZerRxs5RplrxoeNg29kKDTM0K94mnhD9g==",
+ uint64_t{0x4fb31a0dd681ee71}, uint64_t{0x710b009662858dc9}},
+ {"YU4e7G6EfQYvxCFoCrrT0EFgVLHFfOWRTJQJ5gxM3G2b+"
+ "1kJf9YPrpsxF6Xr6nYtS8reEEbDoZJYqnlk9lXSkVArm88Cqn6d25VCx3+"
+ "49MqC0trIlXtb7SXUUhwpJK16T0hJUfPH7s5cMZXc6YmmbFuBNPE=",
+ uint64_t{0x27cc72eefa138e4c}, uint64_t{0xfbf8f7a3ecac1eb7}},
+ {"/I/"
+ "eImMwPo1U6wekNFD1Jxjk9XQVi1D+"
+ "FPdqcHifYXQuP5aScNQfxMAmaPR2XhuOQhADV5tTVbBKwCDCX4E3jcDNHzCiPvViZF1W27t"
+ "xaf2BbFQdwKrNCmrtzcluBFYu0XZfc7RU1RmxK/RtnF1qHsq/O4pp",
+ uint64_t{0x44bc2dfba4bd3ced}, uint64_t{0xb6fc4fcd0722e3df}},
+ {"CJTT9WGcY2XykTdo8KodRIA29qsqY0iHzWZRjKHb9alwyJ7RZAE3V5Juv4MY3MeYEr1EPCC"
+ "MxO7yFXqT8XA8YTjaMp3bafRt17Pw8JC4iKJ1zN+WWKOESrj+"
+ "3aluGQqn8z1EzqY4PH7rLG575PYeWsP98BugdA==",
+ uint64_t{0x242da1e3a439bed8}, uint64_t{0x7cb86dcc55104aac}},
+ {"ZlhyQwLhXQyIUEnMH/"
+ "AEW27vh9xrbNKJxpWGtrEmKhd+nFqAfbeNBQjW0SfG1YI0xQkQMHXjuTt4P/"
+ "EpZRtA47ibZDVS8TtaxwyBjuIDwqcN09eCtpC+Ls+"
+ "vWDTLmBeDM3u4hmzz4DQAYsLiZYSJcldg9Q3wszw=",
+ uint64_t{0xdc559c746e35c139}, uint64_t{0x19e71e9b45c3a51e}},
+ {"v2KU8y0sCrBghmnm8lzGJlwo6D6ObccAxCf10heoDtYLosk4ztTpLlpSFEyu23MLA1tJkcg"
+ "Rko04h19QMG0mOw/"
+ "wc93EXAweriBqXfvdaP85sZABwiKO+6rtS9pacRVpYYhHJeVTQ5NzrvBvi1huxAr+"
+ "xswhVMfL",
+ uint64_t{0xd0b0350275b9989}, uint64_t{0x51de38573c2bea48}},
+ {"QhKlnIS6BuVCTQsnoE67E/"
+ "yrgogE8EwO7xLaEGei26m0gEU4OksefJgppDh3X0x0Cs78Dr9IHK5b977CmZlrTRmwhlP8p"
+ "M+UzXPNRNIZuN3ntOum/QhUWP8SGpirheXENWsXMQ/"
+ "nxtxakyEtrNkKk471Oov9juP8oQ==",
+ uint64_t{0xb04489e41d17730c}, uint64_t{0xa73ab6996d6df158}},
+ {"/ZRMgnoRt+Uo6fUPr9FqQvKX7syhgVqWu+"
+ "WUSsiQ68UlN0efSP6Eced5gJZL6tg9gcYJIkhjuQNITU0Q3TjVAnAcobgbJikCn6qZ6pRxK"
+ "BY4MTiAlfGD3T7R7hwJwx554MAy++Zb/YUFlnCaCJiwQMnowF7aQzwYFCo=",
+ uint64_t{0x2217285eb4572156}, uint64_t{0x55ef2b8c930817b2}},
+ {"NB7tU5fNE8nI+SXGfipc7sRkhnSkUF1krjeo6k+8FITaAtdyz+"
+ "o7mONgXmGLulBPH9bEwyYhKNVY0L+njNQrZ9YC2aXsFD3PdZsxAFaBT3VXEzh+"
+ "NGBTjDASNL3mXyS8Yv1iThGfHoY7T4aR0NYGJ+k+pR6f+KrPC96M",
+ uint64_t{0x12c2e8e68aede73b}, uint64_t{0xb2850bf5fae87157}},
+ {"8T6wrqCtEO6/rwxF6lvMeyuigVOLwPipX/FULvwyu+1wa5sQGav/"
+ "2FsLHUVn6cGSi0LlFwLewGHPFJDLR0u4t7ZUyM//"
+ "x6da0sWgOa5hzDqjsVGmjxEHXiaXKW3i4iSZNuxoNbMQkIbVML+"
+ "DkYu9ND0O2swg4itGeVSzXA==",
+ uint64_t{0x4d612125bdc4fd00}, uint64_t{0xecf3de1acd04651f}},
+ {"Ntf1bMRdondtMv1CYr3G80iDJ4WSAlKy5H34XdGruQiCrnRGDBa+"
+ "eUi7vKp4gp3BBcVGl8eYSasVQQjn7MLvb3BjtXx6c/"
+ "bCL7JtpzQKaDnPr9GWRxpBXVxKREgMM7d8lm35EODv0w+"
+ "hQLfVSh8OGs7fsBb68nNWPLeeSOo=",
+ uint64_t{0x81826b553954464e}, uint64_t{0xcc0a40552559ff32}},
+ {"VsSAw72Ro6xks02kaiLuiTEIWBC5bgqr4WDnmP8vglXzAhixk7td926rm9jNimL+"
+ "kroPSygZ9gl63aF5DCPOACXmsbmhDrAQuUzoh9ZKhWgElLQsrqo1KIjWoZT5b5QfVUXY9lS"
+ "IBg3U75SqORoTPq7HalxxoIT5diWOcJQi",
+ uint64_t{0xc2e5d345dc0ddd2d}, uint64_t{0xc385c374f20315b1}},
+ {"j+loZ+C87+"
+ "bJxNVebg94gU0mSLeDulcHs84tQT7BZM2rzDSLiCNxUedHr1ZWJ9ejTiBa0dqy2I2ABc++"
+ "xzOLcv+//YfibtjKtYggC6/3rv0XCc7xu6d/"
+ "O6xO+XOBhOWAQ+IHJVHf7wZnDxIXB8AUHsnjEISKj7823biqXjyP3g==",
+ uint64_t{0x3da6830a9e32631e}, uint64_t{0xb90208a4c7234183}},
+ {"f3LlpcPElMkspNtDq5xXyWU62erEaKn7RWKlo540gR6mZsNpK1czV/"
+ "sOmqaq8XAQLEn68LKj6/"
+ "cFkJukxRzCa4OF1a7cCAXYFp9+wZDu0bw4y63qbpjhdCl8GO6Z2lkcXy7KOzbPE01ukg7+"
+ "gN+7uKpoohgAhIwpAKQXmX5xtd0=",
+ uint64_t{0xc9ae5c8759b4877a}, uint64_t{0x58aa1ca7a4c075d9}},
+ };
+
+ for (const auto& expected_result : expected_results) {
+ std::string str;
+ ASSERT_TRUE(absl::Base64Unescape(expected_result.base64_data, &str));
+ EXPECT_EQ(absl::hash_internal::Wyhash(str.data(), str.size(),
+ expected_result.seed, kSalt),
+ expected_result.hash);
+ }
+}
+
+} // namespace
diff --git a/third_party/abseil/absl/memory/BUILD.bazel b/third_party/abseil/absl/memory/BUILD.bazel
index 8bc88d6..d2824a0 100644
--- a/third_party/abseil/absl/memory/BUILD.bazel
+++ b/third_party/abseil/absl/memory/BUILD.bazel
@@ -14,7 +14,7 @@
# limitations under the License.
#
-#load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load(
"//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
@@ -24,7 +24,7 @@
package(default_visibility = ["//visibility:public"])
-licenses(["notice"]) # Apache 2.0
+licenses(["notice"])
cc_library(
name = "memory",
diff --git a/third_party/abseil/absl/memory/memory.h b/third_party/abseil/absl/memory/memory.h
index 5a4a1a1..2b5ff62 100644
--- a/third_party/abseil/absl/memory/memory.h
+++ b/third_party/abseil/absl/memory/memory.h
@@ -34,6 +34,7 @@
#include "absl/meta/type_traits.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// -----------------------------------------------------------------------------
// Function Template: WrapUnique()
@@ -92,11 +93,12 @@
} // namespace memory_internal
-// gcc 4.8 has __cplusplus at 201301 but doesn't define make_unique. Other
-// supported compilers either just define __cplusplus as 201103 but have
-// make_unique (msvc), or have make_unique whenever __cplusplus > 201103 (clang)
+// gcc 4.8 has __cplusplus at 201301 but the libstdc++ shipped with it doesn't
+// define make_unique. Other supported compilers either just define __cplusplus
+// as 201103 but have make_unique (msvc), or have make_unique whenever
+// __cplusplus > 201103 (clang).
#if (__cplusplus > 201103L || defined(_MSC_VER)) && \
- !(defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 8)
+ !(defined(__GLIBCXX__) && !defined(__cpp_lib_make_unique))
using std::make_unique;
#else
// -----------------------------------------------------------------------------
@@ -418,6 +420,9 @@
//
// A C++11 compatible implementation of C++17's std::allocator_traits.
//
+#if __cplusplus >= 201703L
+using std::allocator_traits;
+#else // __cplusplus >= 201703L
template <typename Alloc>
struct allocator_traits {
using allocator_type = Alloc;
@@ -607,6 +612,7 @@
return a;
}
};
+#endif // __cplusplus >= 201703L
namespace memory_internal {
@@ -687,6 +693,7 @@
}
}
} // namespace memory_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_MEMORY_MEMORY_H_
diff --git a/third_party/abseil/absl/memory/memory_exception_safety_test.cc b/third_party/abseil/absl/memory/memory_exception_safety_test.cc
index 729507e..1df7261 100644
--- a/third_party/abseil/absl/memory/memory_exception_safety_test.cc
+++ b/third_party/abseil/absl/memory/memory_exception_safety_test.cc
@@ -22,13 +22,11 @@
#include "absl/base/internal/exception_safety_testing.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
constexpr int kLength = 50;
using Thrower = testing::ThrowingValue<testing::TypeSpec::kEverythingThrows>;
-using ThrowerStorage =
- absl::aligned_storage_t<sizeof(Thrower), alignof(Thrower)>;
-using ThrowerList = std::array<ThrowerStorage, kLength>;
TEST(MakeUnique, CheckForLeaks) {
constexpr int kValue = 321;
@@ -53,6 +51,7 @@
}
} // namespace
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_HAVE_EXCEPTIONS
diff --git a/third_party/abseil/absl/memory/memory_test.cc b/third_party/abseil/absl/memory/memory_test.cc
index c47820e..1990c7b 100644
--- a/third_party/abseil/absl/memory/memory_test.cc
+++ b/third_party/abseil/absl/memory/memory_test.cc
@@ -17,6 +17,7 @@
#include "absl/memory/memory.h"
#include <sys/types.h>
+
#include <cstddef>
#include <memory>
#include <string>
@@ -36,10 +37,10 @@
// been called, via the instance_count variable.
class DestructorVerifier {
public:
- DestructorVerifier() { ++instance_count_; }
+ DestructorVerifier() { ++instance_count_; }
DestructorVerifier(const DestructorVerifier&) = delete;
DestructorVerifier& operator=(const DestructorVerifier&) = delete;
- ~DestructorVerifier() { --instance_count_; }
+ ~DestructorVerifier() { --instance_count_; }
// The number of instances of this class currently active.
static int instance_count() { return instance_count_; }
@@ -156,9 +157,7 @@
allocs().push_back(n);
return ::operator new[](n);
}
- void operator delete[](void* p) {
- return ::operator delete[](p);
- }
+ 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;
@@ -171,8 +170,7 @@
ArrayWatch::allocs().clear();
auto p = absl::make_unique<ArrayWatch[]>(5);
- static_assert(std::is_same<decltype(p),
- std::unique_ptr<ArrayWatch[]>>::value,
+ static_assert(std::is_same<decltype(p), std::unique_ptr<ArrayWatch[]>>::value,
"unexpected return type");
EXPECT_THAT(ArrayWatch::allocs(), ElementsAre(5 * sizeof(ArrayWatch)));
}
@@ -181,7 +179,7 @@
// Ensure that absl::make_unique is not ambiguous with std::make_unique.
// In C++14 mode, the below call to make_unique has both types as candidates.
struct TakesStdType {
- explicit TakesStdType(const std::vector<int> &vec) {}
+ explicit TakesStdType(const std::vector<int>& vec) {}
};
using absl::make_unique;
(void)make_unique<TakesStdType>(std::vector<int>());
@@ -541,8 +539,8 @@
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));
+ MOCK_METHOD(value_type*, allocate, (size_t));
+ MOCK_METHOD(void, deallocate, (value_type*, size_t));
int value;
};
@@ -557,7 +555,7 @@
EXPECT_CALL(mock, deallocate(&x, 7));
EXPECT_EQ(&x, Traits::allocate(mock, 7));
- Traits::allocate(mock, 7, static_cast<const void*>(&hint));
+ static_cast<void>(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);
@@ -579,13 +577,14 @@
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());
+ MOCK_METHOD(value_type*, allocate, (size_t));
+ MOCK_METHOD(value_type*, allocate, (size_t, const void*));
+ MOCK_METHOD(void, construct, (value_type*, int*));
+ MOCK_METHOD(void, destroy, (value_type*));
+ MOCK_METHOD(size_t, max_size, (),
+ (const));
+ MOCK_METHOD(FullMockAllocator, select_on_container_copy_construction, (),
+ (const));
int value;
};
@@ -642,8 +641,7 @@
struct CanThrowAllocator {
using is_nothrow = std::false_type;
};
- struct UnspecifiedAllocator {
- };
+ 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);
diff --git a/third_party/abseil/absl/meta/BUILD.bazel b/third_party/abseil/absl/meta/BUILD.bazel
index 594e6aa..5585fcc 100644
--- a/third_party/abseil/absl/meta/BUILD.bazel
+++ b/third_party/abseil/absl/meta/BUILD.bazel
@@ -14,7 +14,7 @@
# limitations under the License.
#
-#load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load(
"//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
@@ -24,7 +24,7 @@
package(default_visibility = ["//visibility:public"])
-licenses(["notice"]) # Apache 2.0
+licenses(["notice"])
cc_library(
name = "type_traits",
diff --git a/third_party/abseil/absl/meta/type_traits.h b/third_party/abseil/absl/meta/type_traits.h
index 927244e..d5cb5f3 100644
--- a/third_party/abseil/absl/meta/type_traits.h
+++ b/third_party/abseil/absl/meta/type_traits.h
@@ -41,7 +41,18 @@
#include "absl/base/config.h"
+// MSVC constructibility traits do not detect destructor properties and so our
+// implementations should not use them as a source-of-truth.
+#if defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__)
+#define ABSL_META_INTERNAL_STD_CONSTRUCTION_TRAITS_DONT_CHECK_DESTRUCTION 1
+#endif
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// Defined and documented later on in this file.
+template <typename T>
+struct is_trivially_destructible;
// Defined and documented later on in this file.
template <typename T>
@@ -66,6 +77,20 @@
#endif // defined(_MSC_VER) && !defined(__GNUC__)
template <class T>
+struct IsTriviallyMoveConstructibleObject
+ : std::integral_constant<
+ bool, std::is_move_constructible<
+ type_traits_internal::SingleMemberUnion<T>>::value &&
+ absl::is_trivially_destructible<T>::value> {};
+
+template <class T>
+struct IsTriviallyCopyConstructibleObject
+ : std::integral_constant<
+ bool, std::is_copy_constructible<
+ type_traits_internal::SingleMemberUnion<T>>::value &&
+ absl::is_trivially_destructible<T>::value> {};
+
+template <class T>
struct IsTriviallyMoveAssignableReference : std::false_type {};
template <class T>
@@ -145,6 +170,18 @@
} // namespace type_traits_internal
+// MSVC 19.20 has a regression that causes our workarounds to fail, but their
+// std forms now appear to be compliant.
+#if defined(_MSC_VER) && !defined(__clang__) && (_MSC_VER >= 1920)
+
+template <typename T>
+using is_copy_assignable = std::is_copy_assignable<T>;
+
+template <typename T>
+using is_move_assignable = std::is_move_assignable<T>;
+
+#else
+
template <typename T>
struct is_copy_assignable : type_traits_internal::is_detected<
type_traits_internal::IsCopyAssignableImpl, T> {
@@ -155,6 +192,8 @@
type_traits_internal::IsMoveAssignableImpl, T> {
};
+#endif
+
// void_t()
//
// Ignores the type of any its arguments and returns `void`. In general, this
@@ -180,7 +219,7 @@
// This metafunction is designed to be a drop-in replacement for the C++17
// `std::conjunction` metafunction.
template <typename... Ts>
-struct conjunction;
+struct conjunction : std::true_type {};
template <typename T, typename... Ts>
struct conjunction<T, Ts...>
@@ -189,9 +228,6 @@
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
@@ -202,7 +238,7 @@
// This metafunction is designed to be a drop-in replacement for the C++17
// `std::disjunction` metafunction.
template <typename... Ts>
-struct disjunction;
+struct disjunction : std::false_type {};
template <typename T, typename... Ts>
struct disjunction<T, Ts...> :
@@ -211,9 +247,6 @@
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
@@ -243,7 +276,7 @@
// is_trivially_destructible()
//
-// Determines whether the passed type `T` is trivially destructable.
+// Determines whether the passed type `T` is trivially destructible.
//
// This metafunction is designed to be a drop-in replacement for the C++11
// `std::is_trivially_destructible()` metafunction for platforms that have
@@ -309,7 +342,9 @@
: 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
+#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE) && \
+ !defined( \
+ ABSL_META_INTERNAL_STD_CONSTRUCTION_TRAITS_DONT_CHECK_DESTRUCTION)
private:
static constexpr bool compliant =
std::is_trivially_default_constructible<T>::value ==
@@ -340,10 +375,11 @@
struct is_trivially_move_constructible
: std::conditional<
std::is_object<T>::value && !std::is_array<T>::value,
- std::is_move_constructible<
- type_traits_internal::SingleMemberUnion<T>>,
+ type_traits_internal::IsTriviallyMoveConstructibleObject<T>,
std::is_reference<T>>::type::type {
-#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE) && \
+ !defined( \
+ ABSL_META_INTERNAL_STD_CONSTRUCTION_TRAITS_DONT_CHECK_DESTRUCTION)
private:
static constexpr bool compliant =
std::is_trivially_move_constructible<T>::value ==
@@ -374,10 +410,11 @@
struct is_trivially_copy_constructible
: std::conditional<
std::is_object<T>::value && !std::is_array<T>::value,
- std::is_copy_constructible<
- type_traits_internal::SingleMemberUnion<T>>,
+ type_traits_internal::IsTriviallyCopyConstructibleObject<T>,
std::is_lvalue_reference<T>>::type::type {
-#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE) && \
+ !defined( \
+ ABSL_META_INTERNAL_STD_CONSTRUCTION_TRAITS_DONT_CHECK_DESTRUCTION)
private:
static constexpr bool compliant =
std::is_trivially_copy_constructible<T>::value ==
@@ -409,7 +446,8 @@
template <typename T>
struct is_trivially_move_assignable
: std::conditional<
- std::is_object<T>::value && !std::is_array<T>::value,
+ std::is_object<T>::value && !std::is_array<T>::value &&
+ std::is_move_assignable<T>::value,
std::is_move_assignable<type_traits_internal::SingleMemberUnion<T>>,
type_traits_internal::IsTriviallyMoveAssignableReference<T>>::type::
type {
@@ -572,8 +610,22 @@
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 type_traits_internal {
+
+#if __cplusplus >= 201703L
+// std::result_of is deprecated (C++17) or removed (C++20)
+template<typename> struct result_of;
+template<typename F, typename... Args>
+struct result_of<F(Args...)> : std::invoke_result<F, Args...> {};
+#else
+template<typename F> using result_of = std::result_of<F>;
+#endif
+
+} // namespace type_traits_internal
+
+template<typename F>
+using result_of_t = typename type_traits_internal::result_of<F>::type;
namespace type_traits_internal {
// In MSVC we can't probe std::hash or stdext::hash because it triggers a
@@ -709,6 +761,7 @@
using swap_internal::StdSwapIsUnconstrained;
} // namespace type_traits_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_META_TYPE_TRAITS_H_
diff --git a/third_party/abseil/absl/meta/type_traits_test.cc b/third_party/abseil/absl/meta/type_traits_test.cc
index 6fbb42f..1aafd0d 100644
--- a/third_party/abseil/absl/meta/type_traits_test.cc
+++ b/third_party/abseil/absl/meta/type_traits_test.cc
@@ -347,21 +347,6 @@
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
-#ifndef _MSC_VER
-#define ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE 1
-#endif
-
// Old versions of libc++, around Clang 3.5 to 3.6, consider deleted destructors
// as also being trivial. With the resolution of CWG 1928 and CWG 1734, this
// is no longer considered true and has thus been amended.
@@ -499,11 +484,9 @@
EXPECT_FALSE(
absl::is_trivially_default_constructible<DeletedDefaultCtor>::value);
-#ifdef ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE
// types with nontrivial destructor are nontrivial
EXPECT_FALSE(
absl::is_trivially_default_constructible<NontrivialDestructor>::value);
-#endif
// types with vtables
EXPECT_FALSE(absl::is_trivially_default_constructible<Base>::value);
@@ -607,11 +590,9 @@
EXPECT_FALSE(
absl::is_trivially_move_constructible<NonCopyableOrMovable>::value);
-#ifdef ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE
// type with nontrivial destructor are nontrivial move construbtible
EXPECT_FALSE(
absl::is_trivially_move_constructible<NontrivialDestructor>::value);
-#endif
// types with vtables
EXPECT_FALSE(absl::is_trivially_move_constructible<Base>::value);
@@ -682,11 +663,9 @@
EXPECT_FALSE(
absl::is_trivially_copy_constructible<NonCopyableOrMovable>::value);
-#ifdef ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE
// type with nontrivial destructor are nontrivial copy construbtible
EXPECT_FALSE(
absl::is_trivially_copy_constructible<NontrivialDestructor>::value);
-#endif
// types with vtables
EXPECT_FALSE(absl::is_trivially_copy_constructible<Base>::value);
diff --git a/third_party/abseil/absl/numeric/BUILD.bazel b/third_party/abseil/absl/numeric/BUILD.bazel
index 9ad673d..5d7b185 100644
--- a/third_party/abseil/absl/numeric/BUILD.bazel
+++ b/third_party/abseil/absl/numeric/BUILD.bazel
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-#load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load(
"//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
@@ -22,7 +22,36 @@
package(default_visibility = ["//visibility:public"])
-licenses(["notice"]) # Apache 2.0
+licenses(["notice"])
+
+cc_library(
+ name = "bits",
+ hdrs = [
+ "bits.h",
+ "internal/bits.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ ],
+)
+
+cc_test(
+ name = "bits_test",
+ size = "small",
+ srcs = [
+ "bits_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":bits",
+ "//absl/random",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
cc_library(
name = "int128",
@@ -35,6 +64,7 @@
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
+ ":bits",
"//absl/base:config",
"//absl/base:core_headers",
],
diff --git a/third_party/abseil/absl/numeric/CMakeLists.txt b/third_party/abseil/absl/numeric/CMakeLists.txt
index 242889f..be94352 100644
--- a/third_party/abseil/absl/numeric/CMakeLists.txt
+++ b/third_party/abseil/absl/numeric/CMakeLists.txt
@@ -16,6 +16,33 @@
absl_cc_library(
NAME
+ bits
+ HDRS
+ "bits.h"
+ "internal/bits.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::core_headers
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
+ bits_test
+ SRCS
+ "bits_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::bits
+ absl::core_headers
+ absl::random_random
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
int128
HDRS
"int128.h"
@@ -28,6 +55,7 @@
DEPS
absl::config
absl::core_headers
+ absl::bits
PUBLIC
)
diff --git a/third_party/abseil/absl/numeric/bits.h b/third_party/abseil/absl/numeric/bits.h
new file mode 100644
index 0000000..52013ad
--- /dev/null
+++ b/third_party/abseil/absl/numeric/bits.h
@@ -0,0 +1,177 @@
+// Copyright 2020 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: bits.h
+// -----------------------------------------------------------------------------
+//
+// This file contains implementations of C++20's bitwise math functions, as
+// defined by:
+//
+// P0553R4:
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0553r4.html
+// P0556R3:
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0556r3.html
+// P1355R2:
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1355r2.html
+// P1956R1:
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1956r1.pdf
+//
+// When using a standard library that implements these functions, we use the
+// standard library's implementation.
+
+#ifndef ABSL_NUMERIC_BITS_H_
+#define ABSL_NUMERIC_BITS_H_
+
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+
+#if (defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L) || \
+ (defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L)
+#include <bit>
+#endif
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/numeric/internal/bits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+#if !(defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L)
+// rotating
+template <class T>
+ABSL_MUST_USE_RESULT constexpr
+ typename std::enable_if<std::is_unsigned<T>::value, T>::type
+ rotl(T x, int s) noexcept {
+ return numeric_internal::RotateLeft(x, s);
+}
+
+template <class T>
+ABSL_MUST_USE_RESULT constexpr
+ typename std::enable_if<std::is_unsigned<T>::value, T>::type
+ rotr(T x, int s) noexcept {
+ return numeric_internal::RotateRight(x, s);
+}
+
+// Counting functions
+//
+// While these functions are typically constexpr, on some platforms, they may
+// not be marked as constexpr due to constraints of the compiler/available
+// intrinsics.
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CLZ inline
+ typename std::enable_if<std::is_unsigned<T>::value, int>::type
+ countl_zero(T x) noexcept {
+ return numeric_internal::CountLeadingZeroes(x);
+}
+
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CLZ inline
+ typename std::enable_if<std::is_unsigned<T>::value, int>::type
+ countl_one(T x) noexcept {
+ // Avoid integer promotion to a wider type
+ return countl_zero(static_cast<T>(~x));
+}
+
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CTZ inline
+ typename std::enable_if<std::is_unsigned<T>::value, int>::type
+ countr_zero(T x) noexcept {
+ return numeric_internal::CountTrailingZeroes(x);
+}
+
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CTZ inline
+ typename std::enable_if<std::is_unsigned<T>::value, int>::type
+ countr_one(T x) noexcept {
+ // Avoid integer promotion to a wider type
+ return countr_zero(static_cast<T>(~x));
+}
+
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline
+ typename std::enable_if<std::is_unsigned<T>::value, int>::type
+ popcount(T x) noexcept {
+ return numeric_internal::Popcount(x);
+}
+#else // defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L
+
+using std::countl_one;
+using std::countl_zero;
+using std::countr_one;
+using std::countr_zero;
+using std::popcount;
+using std::rotl;
+using std::rotr;
+
+#endif
+
+#if !(defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L)
+// Returns: true if x is an integral power of two; false otherwise.
+template <class T>
+constexpr inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type
+has_single_bit(T x) noexcept {
+ return x != 0 && (x & (x - 1)) == 0;
+}
+
+// Returns: If x == 0, 0; otherwise one plus the base-2 logarithm of x, with any
+// fractional part discarded.
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CLZ inline
+ typename std::enable_if<std::is_unsigned<T>::value, T>::type
+ bit_width(T x) noexcept {
+ return std::numeric_limits<T>::digits - countl_zero(x);
+}
+
+// Returns: If x == 0, 0; otherwise the maximal value y such that
+// has_single_bit(y) is true and y <= x.
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CLZ inline
+ typename std::enable_if<std::is_unsigned<T>::value, T>::type
+ bit_floor(T x) noexcept {
+ return x == 0 ? 0 : T{1} << (bit_width(x) - 1);
+}
+
+// Returns: N, where N is the smallest power of 2 greater than or equal to x.
+//
+// Preconditions: N is representable as a value of type T.
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CLZ inline
+ typename std::enable_if<std::is_unsigned<T>::value, T>::type
+ bit_ceil(T x) {
+ // If T is narrower than unsigned, T{1} << bit_width will be promoted. We
+ // want to force it to wraparound so that bit_ceil of an invalid value are not
+ // core constant expressions.
+ //
+ // BitCeilNonPowerOf2 triggers an overflow in constexpr contexts if we would
+ // undergo promotion to unsigned but not fit the result into T without
+ // truncation.
+ return has_single_bit(x) ? T{1} << (bit_width(x) - 1)
+ : numeric_internal::BitCeilNonPowerOf2(x);
+}
+#else // defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L
+
+using std::bit_ceil;
+using std::bit_floor;
+using std::bit_width;
+using std::has_single_bit;
+
+#endif
+
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_NUMERIC_BITS_H_
diff --git a/third_party/abseil/absl/numeric/bits_test.cc b/third_party/abseil/absl/numeric/bits_test.cc
new file mode 100644
index 0000000..8bf7bc9
--- /dev/null
+++ b/third_party/abseil/absl/numeric/bits_test.cc
@@ -0,0 +1,565 @@
+// Copyright 2020 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/numeric/bits.h"
+
+#include <limits>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/random/random.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace {
+
+TEST(Rotate, Left) {
+ static_assert(rotl(uint8_t{0x12}, 0) == uint8_t{0x12}, "");
+ static_assert(rotl(uint16_t{0x1234}, 0) == uint16_t{0x1234}, "");
+ static_assert(rotl(uint32_t{0x12345678UL}, 0) == uint32_t{0x12345678UL}, "");
+ static_assert(rotl(uint64_t{0x12345678ABCDEF01ULL}, 0) ==
+ uint64_t{0x12345678ABCDEF01ULL},
+ "");
+
+ EXPECT_EQ(rotl(uint8_t{0x12}, 0), uint8_t{0x12});
+ EXPECT_EQ(rotl(uint16_t{0x1234}, 0), uint16_t{0x1234});
+ EXPECT_EQ(rotl(uint32_t{0x12345678UL}, 0), uint32_t{0x12345678UL});
+ EXPECT_EQ(rotl(uint64_t{0x12345678ABCDEF01ULL}, 0),
+ uint64_t{0x12345678ABCDEF01ULL});
+
+ EXPECT_EQ(rotl(uint8_t{0x12}, 8), uint8_t{0x12});
+ EXPECT_EQ(rotl(uint16_t{0x1234}, 16), uint16_t{0x1234});
+ EXPECT_EQ(rotl(uint32_t{0x12345678UL}, 32), uint32_t{0x12345678UL});
+ EXPECT_EQ(rotl(uint64_t{0x12345678ABCDEF01ULL}, 64),
+ uint64_t{0x12345678ABCDEF01ULL});
+
+ EXPECT_EQ(rotl(uint8_t{0x12}, -8), uint8_t{0x12});
+ EXPECT_EQ(rotl(uint16_t{0x1234}, -16), uint16_t{0x1234});
+ EXPECT_EQ(rotl(uint32_t{0x12345678UL}, -32), uint32_t{0x12345678UL});
+ EXPECT_EQ(rotl(uint64_t{0x12345678ABCDEF01ULL}, -64),
+ uint64_t{0x12345678ABCDEF01ULL});
+
+ EXPECT_EQ(rotl(uint8_t{0x12}, 4), uint8_t{0x21});
+ EXPECT_EQ(rotl(uint16_t{0x1234}, 4), uint16_t{0x2341});
+ EXPECT_EQ(rotl(uint32_t{0x12345678UL}, 4), uint32_t{0x23456781UL});
+ EXPECT_EQ(rotl(uint64_t{0x12345678ABCDEF01ULL}, 4),
+ uint64_t{0x2345678ABCDEF011ULL});
+
+ EXPECT_EQ(rotl(uint8_t{0x12}, -4), uint8_t{0x21});
+ EXPECT_EQ(rotl(uint16_t{0x1234}, -4), uint16_t{0x4123});
+ EXPECT_EQ(rotl(uint32_t{0x12345678UL}, -4), uint32_t{0x81234567UL});
+ EXPECT_EQ(rotl(uint64_t{0x12345678ABCDEF01ULL}, -4),
+ uint64_t{0x112345678ABCDEF0ULL});
+}
+
+TEST(Rotate, Right) {
+ static_assert(rotr(uint8_t{0x12}, 0) == uint8_t{0x12}, "");
+ static_assert(rotr(uint16_t{0x1234}, 0) == uint16_t{0x1234}, "");
+ static_assert(rotr(uint32_t{0x12345678UL}, 0) == uint32_t{0x12345678UL}, "");
+ static_assert(rotr(uint64_t{0x12345678ABCDEF01ULL}, 0) ==
+ uint64_t{0x12345678ABCDEF01ULL},
+ "");
+
+ EXPECT_EQ(rotr(uint8_t{0x12}, 0), uint8_t{0x12});
+ EXPECT_EQ(rotr(uint16_t{0x1234}, 0), uint16_t{0x1234});
+ EXPECT_EQ(rotr(uint32_t{0x12345678UL}, 0), uint32_t{0x12345678UL});
+ EXPECT_EQ(rotr(uint64_t{0x12345678ABCDEF01ULL}, 0),
+ uint64_t{0x12345678ABCDEF01ULL});
+
+ EXPECT_EQ(rotr(uint8_t{0x12}, 8), uint8_t{0x12});
+ EXPECT_EQ(rotr(uint16_t{0x1234}, 16), uint16_t{0x1234});
+ EXPECT_EQ(rotr(uint32_t{0x12345678UL}, 32), uint32_t{0x12345678UL});
+ EXPECT_EQ(rotr(uint64_t{0x12345678ABCDEF01ULL}, 64),
+ uint64_t{0x12345678ABCDEF01ULL});
+
+ EXPECT_EQ(rotr(uint8_t{0x12}, -8), uint8_t{0x12});
+ EXPECT_EQ(rotr(uint16_t{0x1234}, -16), uint16_t{0x1234});
+ EXPECT_EQ(rotr(uint32_t{0x12345678UL}, -32), uint32_t{0x12345678UL});
+ EXPECT_EQ(rotr(uint64_t{0x12345678ABCDEF01ULL}, -64),
+ uint64_t{0x12345678ABCDEF01ULL});
+
+ EXPECT_EQ(rotr(uint8_t{0x12}, 4), uint8_t{0x21});
+ EXPECT_EQ(rotr(uint16_t{0x1234}, 4), uint16_t{0x4123});
+ EXPECT_EQ(rotr(uint32_t{0x12345678UL}, 4), uint32_t{0x81234567UL});
+ EXPECT_EQ(rotr(uint64_t{0x12345678ABCDEF01ULL}, 4),
+ uint64_t{0x112345678ABCDEF0ULL});
+
+ EXPECT_EQ(rotr(uint8_t{0x12}, -4), uint8_t{0x21});
+ EXPECT_EQ(rotr(uint16_t{0x1234}, -4), uint16_t{0x2341});
+ EXPECT_EQ(rotr(uint32_t{0x12345678UL}, -4), uint32_t{0x23456781UL});
+ EXPECT_EQ(rotr(uint64_t{0x12345678ABCDEF01ULL}, -4),
+ uint64_t{0x2345678ABCDEF011ULL});
+}
+
+TEST(Rotate, Symmetry) {
+ // rotr(x, s) is equivalent to rotl(x, -s)
+ absl::BitGen rng;
+ constexpr int kTrials = 100;
+
+ for (int i = 0; i < kTrials; ++i) {
+ uint8_t value = absl::Uniform(rng, std::numeric_limits<uint8_t>::min(),
+ std::numeric_limits<uint8_t>::max());
+ int shift = absl::Uniform(rng, -2 * std::numeric_limits<uint8_t>::digits,
+ 2 * std::numeric_limits<uint8_t>::digits);
+
+ EXPECT_EQ(rotl(value, shift), rotr(value, -shift));
+ }
+
+ for (int i = 0; i < kTrials; ++i) {
+ uint16_t value = absl::Uniform(rng, std::numeric_limits<uint16_t>::min(),
+ std::numeric_limits<uint16_t>::max());
+ int shift = absl::Uniform(rng, -2 * std::numeric_limits<uint16_t>::digits,
+ 2 * std::numeric_limits<uint16_t>::digits);
+
+ EXPECT_EQ(rotl(value, shift), rotr(value, -shift));
+ }
+
+ for (int i = 0; i < kTrials; ++i) {
+ uint32_t value = absl::Uniform(rng, std::numeric_limits<uint32_t>::min(),
+ std::numeric_limits<uint32_t>::max());
+ int shift = absl::Uniform(rng, -2 * std::numeric_limits<uint32_t>::digits,
+ 2 * std::numeric_limits<uint32_t>::digits);
+
+ EXPECT_EQ(rotl(value, shift), rotr(value, -shift));
+ }
+
+ for (int i = 0; i < kTrials; ++i) {
+ uint64_t value = absl::Uniform(rng, std::numeric_limits<uint64_t>::min(),
+ std::numeric_limits<uint64_t>::max());
+ int shift = absl::Uniform(rng, -2 * std::numeric_limits<uint64_t>::digits,
+ 2 * std::numeric_limits<uint64_t>::digits);
+
+ EXPECT_EQ(rotl(value, shift), rotr(value, -shift));
+ }
+}
+
+TEST(Counting, LeadingZeroes) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_CLZ
+ static_assert(countl_zero(uint8_t{}) == 8, "");
+ static_assert(countl_zero(static_cast<uint8_t>(-1)) == 0, "");
+ static_assert(countl_zero(uint16_t{}) == 16, "");
+ static_assert(countl_zero(static_cast<uint16_t>(-1)) == 0, "");
+ static_assert(countl_zero(uint32_t{}) == 32, "");
+ static_assert(countl_zero(~uint32_t{}) == 0, "");
+ static_assert(countl_zero(uint64_t{}) == 64, "");
+ static_assert(countl_zero(~uint64_t{}) == 0, "");
+#endif
+
+ EXPECT_EQ(countl_zero(uint8_t{}), 8);
+ EXPECT_EQ(countl_zero(static_cast<uint8_t>(-1)), 0);
+ EXPECT_EQ(countl_zero(uint16_t{}), 16);
+ EXPECT_EQ(countl_zero(static_cast<uint16_t>(-1)), 0);
+ EXPECT_EQ(countl_zero(uint32_t{}), 32);
+ EXPECT_EQ(countl_zero(~uint32_t{}), 0);
+ EXPECT_EQ(countl_zero(uint64_t{}), 64);
+ EXPECT_EQ(countl_zero(~uint64_t{}), 0);
+
+ for (int i = 0; i < 8; i++) {
+ EXPECT_EQ(countl_zero(static_cast<uint8_t>(1u << i)), 7 - i);
+ }
+
+ for (int i = 0; i < 16; i++) {
+ EXPECT_EQ(countl_zero(static_cast<uint16_t>(1u << i)), 15 - i);
+ }
+
+ for (int i = 0; i < 32; i++) {
+ EXPECT_EQ(countl_zero(uint32_t{1} << i), 31 - i);
+ }
+
+ for (int i = 0; i < 64; i++) {
+ EXPECT_EQ(countl_zero(uint64_t{1} << i), 63 - i);
+ }
+}
+
+TEST(Counting, LeadingOnes) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_CLZ
+ static_assert(countl_one(uint8_t{}) == 0, "");
+ static_assert(countl_one(static_cast<uint8_t>(-1)) == 8, "");
+ static_assert(countl_one(uint16_t{}) == 0, "");
+ static_assert(countl_one(static_cast<uint16_t>(-1)) == 16, "");
+ static_assert(countl_one(uint32_t{}) == 0, "");
+ static_assert(countl_one(~uint32_t{}) == 32, "");
+ static_assert(countl_one(uint64_t{}) == 0, "");
+ static_assert(countl_one(~uint64_t{}) == 64, "");
+#endif
+
+ EXPECT_EQ(countl_one(uint8_t{}), 0);
+ EXPECT_EQ(countl_one(static_cast<uint8_t>(-1)), 8);
+ EXPECT_EQ(countl_one(uint16_t{}), 0);
+ EXPECT_EQ(countl_one(static_cast<uint16_t>(-1)), 16);
+ EXPECT_EQ(countl_one(uint32_t{}), 0);
+ EXPECT_EQ(countl_one(~uint32_t{}), 32);
+ EXPECT_EQ(countl_one(uint64_t{}), 0);
+ EXPECT_EQ(countl_one(~uint64_t{}), 64);
+}
+
+TEST(Counting, TrailingZeroes) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_CTZ
+ static_assert(countr_zero(uint8_t{}) == 8, "");
+ static_assert(countr_zero(static_cast<uint8_t>(-1)) == 0, "");
+ static_assert(countr_zero(uint16_t{}) == 16, "");
+ static_assert(countr_zero(static_cast<uint16_t>(-1)) == 0, "");
+ static_assert(countr_zero(uint32_t{}) == 32, "");
+ static_assert(countr_zero(~uint32_t{}) == 0, "");
+ static_assert(countr_zero(uint64_t{}) == 64, "");
+ static_assert(countr_zero(~uint64_t{}) == 0, "");
+#endif
+
+ EXPECT_EQ(countr_zero(uint8_t{}), 8);
+ EXPECT_EQ(countr_zero(static_cast<uint8_t>(-1)), 0);
+ EXPECT_EQ(countr_zero(uint16_t{}), 16);
+ EXPECT_EQ(countr_zero(static_cast<uint16_t>(-1)), 0);
+ EXPECT_EQ(countr_zero(uint32_t{}), 32);
+ EXPECT_EQ(countr_zero(~uint32_t{}), 0);
+ EXPECT_EQ(countr_zero(uint64_t{}), 64);
+ EXPECT_EQ(countr_zero(~uint64_t{}), 0);
+}
+
+TEST(Counting, TrailingOnes) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_CTZ
+ static_assert(countr_one(uint8_t{}) == 0, "");
+ static_assert(countr_one(static_cast<uint8_t>(-1)) == 8, "");
+ static_assert(countr_one(uint16_t{}) == 0, "");
+ static_assert(countr_one(static_cast<uint16_t>(-1)) == 16, "");
+ static_assert(countr_one(uint32_t{}) == 0, "");
+ static_assert(countr_one(~uint32_t{}) == 32, "");
+ static_assert(countr_one(uint64_t{}) == 0, "");
+ static_assert(countr_one(~uint64_t{}) == 64, "");
+#endif
+
+ EXPECT_EQ(countr_one(uint8_t{}), 0);
+ EXPECT_EQ(countr_one(static_cast<uint8_t>(-1)), 8);
+ EXPECT_EQ(countr_one(uint16_t{}), 0);
+ EXPECT_EQ(countr_one(static_cast<uint16_t>(-1)), 16);
+ EXPECT_EQ(countr_one(uint32_t{}), 0);
+ EXPECT_EQ(countr_one(~uint32_t{}), 32);
+ EXPECT_EQ(countr_one(uint64_t{}), 0);
+ EXPECT_EQ(countr_one(~uint64_t{}), 64);
+}
+
+TEST(Counting, Popcount) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT
+ static_assert(popcount(uint8_t{}) == 0, "");
+ static_assert(popcount(uint8_t{1}) == 1, "");
+ static_assert(popcount(static_cast<uint8_t>(-1)) == 8, "");
+ static_assert(popcount(uint16_t{}) == 0, "");
+ static_assert(popcount(uint16_t{1}) == 1, "");
+ static_assert(popcount(static_cast<uint16_t>(-1)) == 16, "");
+ static_assert(popcount(uint32_t{}) == 0, "");
+ static_assert(popcount(uint32_t{1}) == 1, "");
+ static_assert(popcount(~uint32_t{}) == 32, "");
+ static_assert(popcount(uint64_t{}) == 0, "");
+ static_assert(popcount(uint64_t{1}) == 1, "");
+ static_assert(popcount(~uint64_t{}) == 64, "");
+#endif // ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT
+
+ EXPECT_EQ(popcount(uint8_t{}), 0);
+ EXPECT_EQ(popcount(uint8_t{1}), 1);
+ EXPECT_EQ(popcount(static_cast<uint8_t>(-1)), 8);
+ EXPECT_EQ(popcount(uint16_t{}), 0);
+ EXPECT_EQ(popcount(uint16_t{1}), 1);
+ EXPECT_EQ(popcount(static_cast<uint16_t>(-1)), 16);
+ EXPECT_EQ(popcount(uint32_t{}), 0);
+ EXPECT_EQ(popcount(uint32_t{1}), 1);
+ EXPECT_EQ(popcount(~uint32_t{}), 32);
+ EXPECT_EQ(popcount(uint64_t{}), 0);
+ EXPECT_EQ(popcount(uint64_t{1}), 1);
+ EXPECT_EQ(popcount(~uint64_t{}), 64);
+
+ for (int i = 0; i < 8; i++) {
+ EXPECT_EQ(popcount(static_cast<uint8_t>(uint8_t{1} << i)), 1);
+ EXPECT_EQ(popcount(static_cast<uint8_t>(static_cast<uint8_t>(-1) ^
+ (uint8_t{1} << i))),
+ 7);
+ }
+
+ for (int i = 0; i < 16; i++) {
+ EXPECT_EQ(popcount(static_cast<uint16_t>(uint16_t{1} << i)), 1);
+ EXPECT_EQ(popcount(static_cast<uint16_t>(static_cast<uint16_t>(-1) ^
+ (uint16_t{1} << i))),
+ 15);
+ }
+
+ for (int i = 0; i < 32; i++) {
+ EXPECT_EQ(popcount(uint32_t{1} << i), 1);
+ EXPECT_EQ(popcount(static_cast<uint32_t>(-1) ^ (uint32_t{1} << i)), 31);
+ }
+
+ for (int i = 0; i < 64; i++) {
+ EXPECT_EQ(popcount(uint64_t{1} << i), 1);
+ EXPECT_EQ(popcount(static_cast<uint64_t>(-1) ^ (uint64_t{1} << i)), 63);
+ }
+}
+
+template <typename T>
+struct PopcountInput {
+ T value = 0;
+ int expected = 0;
+};
+
+template <typename T>
+PopcountInput<T> GeneratePopcountInput(absl::BitGen& gen) {
+ PopcountInput<T> ret;
+ for (int i = 0; i < std::numeric_limits<T>::digits; i++) {
+ bool coin = absl::Bernoulli(gen, 0.2);
+ if (coin) {
+ ret.value |= T{1} << i;
+ ret.expected++;
+ }
+ }
+ return ret;
+}
+
+TEST(Counting, PopcountFuzz) {
+ absl::BitGen rng;
+ constexpr int kTrials = 100;
+
+ for (int i = 0; i < kTrials; ++i) {
+ auto input = GeneratePopcountInput<uint8_t>(rng);
+ EXPECT_EQ(popcount(input.value), input.expected);
+ }
+
+ for (int i = 0; i < kTrials; ++i) {
+ auto input = GeneratePopcountInput<uint16_t>(rng);
+ EXPECT_EQ(popcount(input.value), input.expected);
+ }
+
+ for (int i = 0; i < kTrials; ++i) {
+ auto input = GeneratePopcountInput<uint32_t>(rng);
+ EXPECT_EQ(popcount(input.value), input.expected);
+ }
+
+ for (int i = 0; i < kTrials; ++i) {
+ auto input = GeneratePopcountInput<uint64_t>(rng);
+ EXPECT_EQ(popcount(input.value), input.expected);
+ }
+}
+
+TEST(IntegralPowersOfTwo, SingleBit) {
+ EXPECT_FALSE(has_single_bit(uint8_t{}));
+ EXPECT_FALSE(has_single_bit(static_cast<uint8_t>(-1)));
+ EXPECT_FALSE(has_single_bit(uint16_t{}));
+ EXPECT_FALSE(has_single_bit(static_cast<uint16_t>(-1)));
+ EXPECT_FALSE(has_single_bit(uint32_t{}));
+ EXPECT_FALSE(has_single_bit(~uint32_t{}));
+ EXPECT_FALSE(has_single_bit(uint64_t{}));
+ EXPECT_FALSE(has_single_bit(~uint64_t{}));
+
+ static_assert(!has_single_bit(0u), "");
+ static_assert(has_single_bit(1u), "");
+ static_assert(has_single_bit(2u), "");
+ static_assert(!has_single_bit(3u), "");
+ static_assert(has_single_bit(4u), "");
+ static_assert(!has_single_bit(1337u), "");
+ static_assert(has_single_bit(65536u), "");
+ static_assert(has_single_bit(uint32_t{1} << 30), "");
+ static_assert(has_single_bit(uint64_t{1} << 42), "");
+
+ EXPECT_FALSE(has_single_bit(0u));
+ EXPECT_TRUE(has_single_bit(1u));
+ EXPECT_TRUE(has_single_bit(2u));
+ EXPECT_FALSE(has_single_bit(3u));
+ EXPECT_TRUE(has_single_bit(4u));
+ EXPECT_FALSE(has_single_bit(1337u));
+ EXPECT_TRUE(has_single_bit(65536u));
+ EXPECT_TRUE(has_single_bit(uint32_t{1} << 30));
+ EXPECT_TRUE(has_single_bit(uint64_t{1} << 42));
+
+ EXPECT_TRUE(has_single_bit(
+ static_cast<uint8_t>(std::numeric_limits<uint8_t>::max() / 2 + 1)));
+ EXPECT_TRUE(has_single_bit(
+ static_cast<uint16_t>(std::numeric_limits<uint16_t>::max() / 2 + 1)));
+ EXPECT_TRUE(has_single_bit(
+ static_cast<uint32_t>(std::numeric_limits<uint32_t>::max() / 2 + 1)));
+ EXPECT_TRUE(has_single_bit(
+ static_cast<uint64_t>(std::numeric_limits<uint64_t>::max() / 2 + 1)));
+}
+
+template <typename T, T arg, T = bit_ceil(arg)>
+bool IsBitCeilConstantExpression(int) {
+ return true;
+}
+template <typename T, T arg>
+bool IsBitCeilConstantExpression(char) {
+ return false;
+}
+
+TEST(IntegralPowersOfTwo, Ceiling) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_CLZ
+ static_assert(bit_ceil(0u) == 1, "");
+ static_assert(bit_ceil(1u) == 1, "");
+ static_assert(bit_ceil(2u) == 2, "");
+ static_assert(bit_ceil(3u) == 4, "");
+ static_assert(bit_ceil(4u) == 4, "");
+ static_assert(bit_ceil(1337u) == 2048, "");
+ static_assert(bit_ceil(65536u) == 65536, "");
+ static_assert(bit_ceil(65536u - 1337u) == 65536, "");
+ static_assert(bit_ceil(uint32_t{0x80000000}) == uint32_t{0x80000000}, "");
+ static_assert(bit_ceil(uint64_t{0x40000000000}) == uint64_t{0x40000000000},
+ "");
+ static_assert(
+ bit_ceil(uint64_t{0x8000000000000000}) == uint64_t{0x8000000000000000},
+ "");
+
+ EXPECT_TRUE((IsBitCeilConstantExpression<uint8_t, uint8_t{0x0}>(0)));
+ EXPECT_TRUE((IsBitCeilConstantExpression<uint8_t, uint8_t{0x80}>(0)));
+ EXPECT_FALSE((IsBitCeilConstantExpression<uint8_t, uint8_t{0x81}>(0)));
+ EXPECT_FALSE((IsBitCeilConstantExpression<uint8_t, uint8_t{0xff}>(0)));
+
+ EXPECT_TRUE((IsBitCeilConstantExpression<uint16_t, uint16_t{0x0}>(0)));
+ EXPECT_TRUE((IsBitCeilConstantExpression<uint16_t, uint16_t{0x8000}>(0)));
+ EXPECT_FALSE((IsBitCeilConstantExpression<uint16_t, uint16_t{0x8001}>(0)));
+ EXPECT_FALSE((IsBitCeilConstantExpression<uint16_t, uint16_t{0xffff}>(0)));
+
+ EXPECT_TRUE((IsBitCeilConstantExpression<uint32_t, uint32_t{0x0}>(0)));
+ EXPECT_TRUE((IsBitCeilConstantExpression<uint32_t, uint32_t{0x80000000}>(0)));
+ EXPECT_FALSE(
+ (IsBitCeilConstantExpression<uint32_t, uint32_t{0x80000001}>(0)));
+ EXPECT_FALSE(
+ (IsBitCeilConstantExpression<uint32_t, uint32_t{0xffffffff}>(0)));
+
+ EXPECT_TRUE((IsBitCeilConstantExpression<uint64_t, uint64_t{0x0}>(0)));
+ EXPECT_TRUE(
+ (IsBitCeilConstantExpression<uint64_t, uint64_t{0x8000000000000000}>(0)));
+ EXPECT_FALSE(
+ (IsBitCeilConstantExpression<uint64_t, uint64_t{0x8000000000000001}>(0)));
+ EXPECT_FALSE(
+ (IsBitCeilConstantExpression<uint64_t, uint64_t{0xffffffffffffffff}>(0)));
+#endif
+
+ EXPECT_EQ(bit_ceil(0u), 1);
+ EXPECT_EQ(bit_ceil(1u), 1);
+ EXPECT_EQ(bit_ceil(2u), 2);
+ EXPECT_EQ(bit_ceil(3u), 4);
+ EXPECT_EQ(bit_ceil(4u), 4);
+ EXPECT_EQ(bit_ceil(1337u), 2048);
+ EXPECT_EQ(bit_ceil(65536u), 65536);
+ EXPECT_EQ(bit_ceil(65536u - 1337u), 65536);
+ EXPECT_EQ(bit_ceil(uint64_t{0x40000000000}), uint64_t{0x40000000000});
+}
+
+TEST(IntegralPowersOfTwo, Floor) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_CLZ
+ static_assert(bit_floor(0u) == 0, "");
+ static_assert(bit_floor(1u) == 1, "");
+ static_assert(bit_floor(2u) == 2, "");
+ static_assert(bit_floor(3u) == 2, "");
+ static_assert(bit_floor(4u) == 4, "");
+ static_assert(bit_floor(1337u) == 1024, "");
+ static_assert(bit_floor(65536u) == 65536, "");
+ static_assert(bit_floor(65536u - 1337u) == 32768, "");
+ static_assert(bit_floor(uint64_t{0x40000000000}) == uint64_t{0x40000000000},
+ "");
+#endif
+
+ EXPECT_EQ(bit_floor(0u), 0);
+ EXPECT_EQ(bit_floor(1u), 1);
+ EXPECT_EQ(bit_floor(2u), 2);
+ EXPECT_EQ(bit_floor(3u), 2);
+ EXPECT_EQ(bit_floor(4u), 4);
+ EXPECT_EQ(bit_floor(1337u), 1024);
+ EXPECT_EQ(bit_floor(65536u), 65536);
+ EXPECT_EQ(bit_floor(65536u - 1337u), 32768);
+ EXPECT_EQ(bit_floor(uint64_t{0x40000000000}), uint64_t{0x40000000000});
+
+ for (int i = 0; i < 8; i++) {
+ uint8_t input = uint8_t{1} << i;
+ EXPECT_EQ(bit_floor(input), input);
+ if (i > 0) {
+ EXPECT_EQ(bit_floor(static_cast<uint8_t>(input + 1)), input);
+ }
+ }
+
+ for (int i = 0; i < 16; i++) {
+ uint16_t input = uint16_t{1} << i;
+ EXPECT_EQ(bit_floor(input), input);
+ if (i > 0) {
+ EXPECT_EQ(bit_floor(static_cast<uint16_t>(input + 1)), input);
+ }
+ }
+
+ for (int i = 0; i < 32; i++) {
+ uint32_t input = uint32_t{1} << i;
+ EXPECT_EQ(bit_floor(input), input);
+ if (i > 0) {
+ EXPECT_EQ(bit_floor(input + 1), input);
+ }
+ }
+
+ for (int i = 0; i < 64; i++) {
+ uint64_t input = uint64_t{1} << i;
+ EXPECT_EQ(bit_floor(input), input);
+ if (i > 0) {
+ EXPECT_EQ(bit_floor(input + 1), input);
+ }
+ }
+}
+
+TEST(IntegralPowersOfTwo, Width) {
+#if ABSL_INTERNAL_HAS_CONSTEXPR_CLZ
+ static_assert(bit_width(uint8_t{}) == 0, "");
+ static_assert(bit_width(uint8_t{1}) == 1, "");
+ static_assert(bit_width(uint8_t{3}) == 2, "");
+ static_assert(bit_width(static_cast<uint8_t>(-1)) == 8, "");
+ static_assert(bit_width(uint16_t{}) == 0, "");
+ static_assert(bit_width(uint16_t{1}) == 1, "");
+ static_assert(bit_width(uint16_t{3}) == 2, "");
+ static_assert(bit_width(static_cast<uint16_t>(-1)) == 16, "");
+ static_assert(bit_width(uint32_t{}) == 0, "");
+ static_assert(bit_width(uint32_t{1}) == 1, "");
+ static_assert(bit_width(uint32_t{3}) == 2, "");
+ static_assert(bit_width(~uint32_t{}) == 32, "");
+ static_assert(bit_width(uint64_t{}) == 0, "");
+ static_assert(bit_width(uint64_t{1}) == 1, "");
+ static_assert(bit_width(uint64_t{3}) == 2, "");
+ static_assert(bit_width(~uint64_t{}) == 64, "");
+#endif
+
+ EXPECT_EQ(bit_width(uint8_t{}), 0);
+ EXPECT_EQ(bit_width(uint8_t{1}), 1);
+ EXPECT_EQ(bit_width(uint8_t{3}), 2);
+ EXPECT_EQ(bit_width(static_cast<uint8_t>(-1)), 8);
+ EXPECT_EQ(bit_width(uint16_t{}), 0);
+ EXPECT_EQ(bit_width(uint16_t{1}), 1);
+ EXPECT_EQ(bit_width(uint16_t{3}), 2);
+ EXPECT_EQ(bit_width(static_cast<uint16_t>(-1)), 16);
+ EXPECT_EQ(bit_width(uint32_t{}), 0);
+ EXPECT_EQ(bit_width(uint32_t{1}), 1);
+ EXPECT_EQ(bit_width(uint32_t{3}), 2);
+ EXPECT_EQ(bit_width(~uint32_t{}), 32);
+ EXPECT_EQ(bit_width(uint64_t{}), 0);
+ EXPECT_EQ(bit_width(uint64_t{1}), 1);
+ EXPECT_EQ(bit_width(uint64_t{3}), 2);
+ EXPECT_EQ(bit_width(~uint64_t{}), 64);
+
+ for (int i = 0; i < 8; i++) {
+ EXPECT_EQ(bit_width(static_cast<uint8_t>(uint8_t{1} << i)), i + 1);
+ }
+
+ for (int i = 0; i < 16; i++) {
+ EXPECT_EQ(bit_width(static_cast<uint16_t>(uint16_t{1} << i)), i + 1);
+ }
+
+ for (int i = 0; i < 32; i++) {
+ EXPECT_EQ(bit_width(uint32_t{1} << i), i + 1);
+ }
+
+ for (int i = 0; i < 64; i++) {
+ EXPECT_EQ(bit_width(uint64_t{1} << i), i + 1);
+ }
+}
+
+} // namespace
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/numeric/int128.cc b/third_party/abseil/absl/numeric/int128.cc
index 93b62c5..5160df7 100644
--- a/third_party/abseil/absl/numeric/int128.cc
+++ b/third_party/abseil/absl/numeric/int128.cc
@@ -15,6 +15,7 @@
#include "absl/numeric/int128.h"
#include <stddef.h>
+
#include <cassert>
#include <iomanip>
#include <ostream> // NOLINT(readability/streams)
@@ -22,52 +23,38 @@
#include <string>
#include <type_traits>
-namespace absl {
+#include "absl/base/optimization.h"
+#include "absl/numeric/bits.h"
-const uint128 kuint128max = MakeUint128(std::numeric_limits<uint64_t>::max(),
- std::numeric_limits<uint64_t>::max());
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+ABSL_DLL 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.
+// in the given uint128. The argument is not 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) {
+inline ABSL_ATTRIBUTE_ALWAYS_INLINE int Fls128(uint128 n) {
if (uint64_t hi = Uint128High64(n)) {
- return Fls64(hi) + 64;
+ ABSL_INTERNAL_ASSUME(hi != 0);
+ return 127 - countl_zero(hi);
}
- return Fls64(Uint128Low64(n));
+ const uint64_t low = Uint128Low64(n);
+ ABSL_INTERNAL_ASSUME(low != 0);
+ return 63 - countl_zero(low);
}
// Long division/modulo for uint128 implemented using the shift-subtract
// division algorithm adapted from:
// https://stackoverflow.com/questions/5386377/division-without-using
-void DivModImpl(uint128 dividend, uint128 divisor, uint128* quotient_ret,
- uint128* remainder_ret) {
+inline void DivModImpl(uint128 dividend, uint128 divisor, uint128* quotient_ret,
+ uint128* remainder_ret) {
assert(divisor != 0);
if (divisor > dividend) {
@@ -244,6 +231,112 @@
return os << rep;
}
+namespace {
+
+uint128 UnsignedAbsoluteValue(int128 v) {
+ // Cast to uint128 before possibly negating because -Int128Min() is undefined.
+ return Int128High64(v) < 0 ? -uint128(v) : uint128(v);
+}
+
+} // namespace
+
+#if !defined(ABSL_HAVE_INTRINSIC_INT128)
+namespace {
+
+template <typename T>
+int128 MakeInt128FromFloat(T v) {
+ // Conversion when v is NaN or cannot fit into int128 would be undefined
+ // behavior if using an intrinsic 128-bit integer.
+ assert(std::isfinite(v) && (std::numeric_limits<T>::max_exponent <= 127 ||
+ (v >= -std::ldexp(static_cast<T>(1), 127) &&
+ v < std::ldexp(static_cast<T>(1), 127))));
+
+ // We must convert the absolute value and then negate as needed, because
+ // floating point types are typically sign-magnitude. Otherwise, the
+ // difference between the high and low 64 bits when interpreted as two's
+ // complement overwhelms the precision of the mantissa.
+ uint128 result = v < 0 ? -MakeUint128FromFloat(-v) : MakeUint128FromFloat(v);
+ return MakeInt128(int128_internal::BitCastToSigned(Uint128High64(result)),
+ Uint128Low64(result));
+}
+
+} // namespace
+
+int128::int128(float v) : int128(MakeInt128FromFloat(v)) {}
+int128::int128(double v) : int128(MakeInt128FromFloat(v)) {}
+int128::int128(long double v) : int128(MakeInt128FromFloat(v)) {}
+
+int128 operator/(int128 lhs, int128 rhs) {
+ assert(lhs != Int128Min() || rhs != -1); // UB on two's complement.
+
+ uint128 quotient = 0;
+ uint128 remainder = 0;
+ DivModImpl(UnsignedAbsoluteValue(lhs), UnsignedAbsoluteValue(rhs),
+ "ient, &remainder);
+ if ((Int128High64(lhs) < 0) != (Int128High64(rhs) < 0)) quotient = -quotient;
+ return MakeInt128(int128_internal::BitCastToSigned(Uint128High64(quotient)),
+ Uint128Low64(quotient));
+}
+
+int128 operator%(int128 lhs, int128 rhs) {
+ assert(lhs != Int128Min() || rhs != -1); // UB on two's complement.
+
+ uint128 quotient = 0;
+ uint128 remainder = 0;
+ DivModImpl(UnsignedAbsoluteValue(lhs), UnsignedAbsoluteValue(rhs),
+ "ient, &remainder);
+ if (Int128High64(lhs) < 0) remainder = -remainder;
+ return MakeInt128(int128_internal::BitCastToSigned(Uint128High64(remainder)),
+ Uint128Low64(remainder));
+}
+#endif // ABSL_HAVE_INTRINSIC_INT128
+
+std::ostream& operator<<(std::ostream& os, int128 v) {
+ std::ios_base::fmtflags flags = os.flags();
+ std::string rep;
+
+ // Add the sign if needed.
+ bool print_as_decimal =
+ (flags & std::ios::basefield) == std::ios::dec ||
+ (flags & std::ios::basefield) == std::ios_base::fmtflags();
+ if (print_as_decimal) {
+ if (Int128High64(v) < 0) {
+ rep = "-";
+ } else if (flags & std::ios::showpos) {
+ rep = "+";
+ }
+ }
+
+ rep.append(Uint128ToFormattedString(
+ print_as_decimal ? UnsignedAbsoluteValue(v) : uint128(v), os.flags()));
+
+ // Add the requisite padding.
+ std::streamsize width = os.width(0);
+ if (static_cast<size_t>(width) > rep.size()) {
+ switch (flags & std::ios::adjustfield) {
+ case std::ios::left:
+ rep.append(width - rep.size(), os.fill());
+ break;
+ case std::ios::internal:
+ if (print_as_decimal && (rep[0] == '+' || rep[0] == '-')) {
+ rep.insert(1, width - rep.size(), os.fill());
+ } else if ((flags & std::ios::basefield) == std::ios::hex &&
+ (flags & std::ios::showbase) && v != 0) {
+ rep.insert(2, width - rep.size(), os.fill());
+ } else {
+ rep.insert(0, width - rep.size(), os.fill());
+ }
+ break;
+ default: // std::ios::right
+ rep.insert(0, width - rep.size(), os.fill());
+ break;
+ }
+ }
+
+ return os << rep;
+}
+
+ABSL_NAMESPACE_END
} // namespace absl
namespace std {
@@ -270,4 +363,28 @@
constexpr int numeric_limits<absl::uint128>::max_exponent10;
constexpr bool numeric_limits<absl::uint128>::traps;
constexpr bool numeric_limits<absl::uint128>::tinyness_before;
+
+constexpr bool numeric_limits<absl::int128>::is_specialized;
+constexpr bool numeric_limits<absl::int128>::is_signed;
+constexpr bool numeric_limits<absl::int128>::is_integer;
+constexpr bool numeric_limits<absl::int128>::is_exact;
+constexpr bool numeric_limits<absl::int128>::has_infinity;
+constexpr bool numeric_limits<absl::int128>::has_quiet_NaN;
+constexpr bool numeric_limits<absl::int128>::has_signaling_NaN;
+constexpr float_denorm_style numeric_limits<absl::int128>::has_denorm;
+constexpr bool numeric_limits<absl::int128>::has_denorm_loss;
+constexpr float_round_style numeric_limits<absl::int128>::round_style;
+constexpr bool numeric_limits<absl::int128>::is_iec559;
+constexpr bool numeric_limits<absl::int128>::is_bounded;
+constexpr bool numeric_limits<absl::int128>::is_modulo;
+constexpr int numeric_limits<absl::int128>::digits;
+constexpr int numeric_limits<absl::int128>::digits10;
+constexpr int numeric_limits<absl::int128>::max_digits10;
+constexpr int numeric_limits<absl::int128>::radix;
+constexpr int numeric_limits<absl::int128>::min_exponent;
+constexpr int numeric_limits<absl::int128>::min_exponent10;
+constexpr int numeric_limits<absl::int128>::max_exponent;
+constexpr int numeric_limits<absl::int128>::max_exponent10;
+constexpr bool numeric_limits<absl::int128>::traps;
+constexpr bool numeric_limits<absl::int128>::tinyness_before;
} // namespace std
diff --git a/third_party/abseil/absl/numeric/int128.h b/third_party/abseil/absl/numeric/int128.h
index 10be8ec..0dd814a 100644
--- a/third_party/abseil/absl/numeric/int128.h
+++ b/third_party/abseil/absl/numeric/int128.h
@@ -17,10 +17,7 @@
// 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.
+// This header file defines 128-bit integer types, `uint128` and `int128`.
#ifndef ABSL_NUMERIC_INT128_H_
#define ABSL_NUMERIC_INT128_H_
@@ -52,6 +49,9 @@
#endif // defined(_MSC_VER)
namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+class int128;
// uint128
//
@@ -116,6 +116,7 @@
constexpr uint128(__int128 v); // NOLINT(runtime/explicit)
constexpr uint128(unsigned __int128 v); // NOLINT(runtime/explicit)
#endif // ABSL_HAVE_INTRINSIC_INT128
+ constexpr uint128(int128 v); // NOLINT(runtime/explicit)
explicit uint128(float v);
explicit uint128(double v);
explicit uint128(long double v);
@@ -131,6 +132,7 @@
uint128& operator=(__int128 v);
uint128& operator=(unsigned __int128 v);
#endif // ABSL_HAVE_INTRINSIC_INT128
+ uint128& operator=(int128 v);
// Conversion operators to other arithmetic types
constexpr explicit operator bool() const;
@@ -232,7 +234,7 @@
// Prefer to use the constexpr `Uint128Max()`.
//
// TODO(absl-team) deprecate kuint128max once migration tool is released.
-extern const uint128 kuint128max;
+ABSL_DLL extern const uint128 kuint128max;
// allow uint128 to be logged
std::ostream& operator<<(std::ostream& os, uint128 v);
@@ -244,6 +246,7 @@
(std::numeric_limits<uint64_t>::max)());
}
+ABSL_NAMESPACE_END
} // namespace absl
// Specialized numeric_limits for uint128.
@@ -291,12 +294,246 @@
};
} // namespace std
-// TODO(absl-team): Implement signed 128-bit type
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// int128
+//
+// A signed 128-bit integer type. The API is meant to mimic an intrinsic
+// integral type as closely as is practical, including exhibiting undefined
+// behavior in analogous cases (e.g. division by zero).
+//
+// An `int128` supports the following:
+//
+// * Implicit construction from integral types
+// * Explicit conversion to integral types
+//
+// However, an `int128` differs from intrinsic integral types in the following
+// ways:
+//
+// * It is not implicitly convertible to other integral types.
+// * Requires explicit construction from and conversion to floating point
+// types.
+
+// Additionally, if your compiler supports `__int128`, `int128` is
+// interoperable with that type. (Abseil checks for this compatibility through
+// the `ABSL_HAVE_INTRINSIC_INT128` macro.)
+//
+// The design goal for `int128` is that it will be compatible with a future
+// `int128_t`, if that type becomes a part of the standard.
+//
+// Example:
+//
+// float y = absl::int128(17); // Error. int128 cannot be implicitly
+// // converted to float.
+//
+// absl::int128 v;
+// int64_t i = v; // Error
+// int64_t i = static_cast<int64_t>(v); // OK
+//
+class int128 {
+ public:
+ int128() = default;
+
+ // Constructors from arithmetic types
+ constexpr int128(int v); // NOLINT(runtime/explicit)
+ constexpr int128(unsigned int v); // NOLINT(runtime/explicit)
+ constexpr int128(long v); // NOLINT(runtime/int)
+ constexpr int128(unsigned long v); // NOLINT(runtime/int)
+ constexpr int128(long long v); // NOLINT(runtime/int)
+ constexpr int128(unsigned long long v); // NOLINT(runtime/int)
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+ constexpr int128(__int128 v); // NOLINT(runtime/explicit)
+ constexpr explicit int128(unsigned __int128 v);
+#endif // ABSL_HAVE_INTRINSIC_INT128
+ constexpr explicit int128(uint128 v);
+ explicit int128(float v);
+ explicit int128(double v);
+ explicit int128(long double v);
+
+ // Assignment operators from arithmetic types
+ int128& operator=(int v);
+ int128& operator=(unsigned int v);
+ int128& operator=(long v); // NOLINT(runtime/int)
+ int128& operator=(unsigned long v); // NOLINT(runtime/int)
+ int128& operator=(long long v); // NOLINT(runtime/int)
+ int128& operator=(unsigned long long v); // NOLINT(runtime/int)
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+ int128& operator=(__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 ABSL_INTERNAL_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
+ int128& operator+=(int128 other);
+ int128& operator-=(int128 other);
+ int128& operator*=(int128 other);
+ int128& operator/=(int128 other);
+ int128& operator%=(int128 other);
+ int128 operator++(int); // postfix increment: i++
+ int128 operator--(int); // postfix decrement: i--
+ int128& operator++(); // prefix increment: ++i
+ int128& operator--(); // prefix decrement: --i
+ int128& operator&=(int128 other);
+ int128& operator|=(int128 other);
+ int128& operator^=(int128 other);
+ int128& operator<<=(int amount);
+ int128& operator>>=(int amount);
+
+ // Int128Low64()
+ //
+ // Returns the lower 64-bit value of a `int128` value.
+ friend constexpr uint64_t Int128Low64(int128 v);
+
+ // Int128High64()
+ //
+ // Returns the higher 64-bit value of a `int128` value.
+ friend constexpr int64_t Int128High64(int128 v);
+
+ // MakeInt128()
+ //
+ // Constructs a `int128` numeric value from two 64-bit integers. Note that
+ // signedness is conveyed in the upper `high` value.
+ //
+ // (absl::int128(1) << 64) * high + low
+ //
+ // Note that this factory function is the only way to construct a `int128`
+ // from integer values greater than 2^64 or less than -2^64.
+ //
+ // Example:
+ //
+ // absl::int128 big = absl::MakeInt128(1, 0);
+ // absl::int128 big_n = absl::MakeInt128(-1, 0);
+ friend constexpr int128 MakeInt128(int64_t high, uint64_t low);
+
+ // Int128Max()
+ //
+ // Returns the maximum value for a 128-bit signed integer.
+ friend constexpr int128 Int128Max();
+
+ // Int128Min()
+ //
+ // Returns the minimum value for a 128-bit signed integer.
+ friend constexpr int128 Int128Min();
+
+ // Support for absl::Hash.
+ template <typename H>
+ friend H AbslHashValue(H h, int128 v) {
+ return H::combine(std::move(h), Int128High64(v), Int128Low64(v));
+ }
+
+ private:
+ constexpr int128(int64_t high, uint64_t low);
+
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+ __int128 v_;
+#else // ABSL_HAVE_INTRINSIC_INT128
+#if defined(ABSL_IS_LITTLE_ENDIAN)
+ uint64_t lo_;
+ int64_t hi_;
+#elif defined(ABSL_IS_BIG_ENDIAN)
+ int64_t hi_;
+ uint64_t lo_;
+#else // byte order
+#error "Unsupported byte order: must be little-endian or big-endian."
+#endif // byte order
+#endif // ABSL_HAVE_INTRINSIC_INT128
+};
+
+std::ostream& operator<<(std::ostream& os, int128 v);
+
+// TODO(absl-team) add operator>>(std::istream&, int128)
+
+constexpr int128 Int128Max() {
+ return int128((std::numeric_limits<int64_t>::max)(),
+ (std::numeric_limits<uint64_t>::max)());
+}
+
+constexpr int128 Int128Min() {
+ return int128((std::numeric_limits<int64_t>::min)(), 0);
+}
+
+ABSL_NAMESPACE_END
+} // namespace absl
+
+// Specialized numeric_limits for int128.
+namespace std {
+template <>
+class numeric_limits<absl::int128> {
+ public:
+ static constexpr bool is_specialized = true;
+ static constexpr bool is_signed = true;
+ static constexpr bool is_integer = true;
+ static constexpr bool is_exact = true;
+ static constexpr bool has_infinity = false;
+ static constexpr bool has_quiet_NaN = false;
+ static constexpr bool has_signaling_NaN = false;
+ static constexpr float_denorm_style has_denorm = denorm_absent;
+ static constexpr bool has_denorm_loss = false;
+ static constexpr float_round_style round_style = round_toward_zero;
+ static constexpr bool is_iec559 = false;
+ static constexpr bool is_bounded = true;
+ static constexpr bool is_modulo = false;
+ static constexpr int digits = 127;
+ static constexpr int digits10 = 38;
+ static constexpr int max_digits10 = 0;
+ static constexpr int radix = 2;
+ static constexpr int min_exponent = 0;
+ static constexpr int min_exponent10 = 0;
+ static constexpr int max_exponent = 0;
+ static constexpr int max_exponent10 = 0;
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+ static constexpr bool traps = numeric_limits<__int128>::traps;
+#else // ABSL_HAVE_INTRINSIC_INT128
+ static constexpr bool traps = numeric_limits<uint64_t>::traps;
+#endif // ABSL_HAVE_INTRINSIC_INT128
+ static constexpr bool tinyness_before = false;
+
+ static constexpr absl::int128 (min)() { return absl::Int128Min(); }
+ static constexpr absl::int128 lowest() { return absl::Int128Min(); }
+ static constexpr absl::int128 (max)() { return absl::Int128Max(); }
+ static constexpr absl::int128 epsilon() { return 0; }
+ static constexpr absl::int128 round_error() { return 0; }
+ static constexpr absl::int128 infinity() { return 0; }
+ static constexpr absl::int128 quiet_NaN() { return 0; }
+ static constexpr absl::int128 signaling_NaN() { return 0; }
+ static constexpr absl::int128 denorm_min() { return 0; }
+};
+} // namespace std
// --------------------------------------------------------------------------
// Implementation details follow
// --------------------------------------------------------------------------
namespace absl {
+ABSL_NAMESPACE_BEGIN
constexpr uint128 MakeUint128(uint64_t high, uint64_t low) {
return uint128(high, low);
@@ -339,6 +576,10 @@
}
#endif // ABSL_HAVE_INTRINSIC_INT128
+inline uint128& uint128::operator=(int128 v) {
+ return *this = uint128(v);
+}
+
// Arithmetic operators.
uint128 operator<<(uint128 lhs, int amount);
@@ -420,6 +661,9 @@
hi_{static_cast<uint64_t>(v >> 64)} {}
#endif // ABSL_HAVE_INTRINSIC_INT128
+constexpr uint128::uint128(int128 v)
+ : lo_{Int128Low64(v)}, hi_{static_cast<uint64_t>(Int128High64(v))} {}
+
#elif defined(ABSL_IS_BIG_ENDIAN)
constexpr uint128::uint128(uint64_t high, uint64_t low)
@@ -450,6 +694,9 @@
lo_{static_cast<uint64_t>(v & ~uint64_t{0})} {}
#endif // ABSL_HAVE_INTRINSIC_INT128
+constexpr uint128::uint128(int128 v)
+ : hi_{static_cast<uint64_t>(Int128High64(v))}, lo_{Int128Low64(v)} {}
+
#else // byte order
#error "Unsupported byte order: must be little-endian or big-endian."
#endif // byte order
@@ -545,28 +792,21 @@
}
inline bool operator<(uint128 lhs, uint128 rhs) {
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+ return static_cast<unsigned __int128>(lhs) <
+ static_cast<unsigned __int128>(rhs);
+#else
return (Uint128High64(lhs) == Uint128High64(rhs))
? (Uint128Low64(lhs) < Uint128Low64(rhs))
: (Uint128High64(lhs) < Uint128High64(rhs));
+#endif
}
-inline bool operator>(uint128 lhs, uint128 rhs) {
- return (Uint128High64(lhs) == Uint128High64(rhs))
- ? (Uint128Low64(lhs) > Uint128Low64(rhs))
- : (Uint128High64(lhs) > Uint128High64(rhs));
-}
+inline bool operator>(uint128 lhs, uint128 rhs) { return rhs < lhs; }
-inline bool operator<=(uint128 lhs, uint128 rhs) {
- return (Uint128High64(lhs) == Uint128High64(rhs))
- ? (Uint128Low64(lhs) <= Uint128Low64(rhs))
- : (Uint128High64(lhs) <= Uint128High64(rhs));
-}
+inline bool operator<=(uint128 lhs, uint128 rhs) { return !(rhs < lhs); }
-inline bool operator>=(uint128 lhs, uint128 rhs) {
- return (Uint128High64(lhs) == Uint128High64(rhs))
- ? (Uint128Low64(lhs) >= Uint128Low64(rhs))
- : (Uint128High64(lhs) >= Uint128High64(rhs));
-}
+inline bool operator>=(uint128 lhs, uint128 rhs) { return !(lhs < rhs); }
// Unary operators.
@@ -623,6 +863,9 @@
// Arithmetic operators.
inline uint128 operator<<(uint128 lhs, int amount) {
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+ return static_cast<unsigned __int128>(lhs) << amount;
+#else
// uint64_t shifts of >= 64 are undefined, so we will need some
// special-casing.
if (amount < 64) {
@@ -634,9 +877,13 @@
return lhs;
}
return MakeUint128(Uint128Low64(lhs) << (amount - 64), 0);
+#endif
}
inline uint128 operator>>(uint128 lhs, int amount) {
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+ return static_cast<unsigned __int128>(lhs) >> amount;
+#else
// uint64_t shifts of >= 64 are undefined, so we will need some
// special-casing.
if (amount < 64) {
@@ -648,6 +895,7 @@
return lhs;
}
return MakeUint128(0, Uint128High64(lhs) >> (amount - 64));
+#endif
}
inline uint128 operator+(uint128 lhs, uint128 rhs) {
@@ -719,12 +967,124 @@
return *this;
}
+constexpr int128 MakeInt128(int64_t high, uint64_t low) {
+ return int128(high, low);
+}
+
+// Assignment from integer types.
+inline int128& int128::operator=(int v) {
+ return *this = int128(v);
+}
+
+inline int128& int128::operator=(unsigned int v) {
+ return *this = int128(v);
+}
+
+inline int128& int128::operator=(long v) { // NOLINT(runtime/int)
+ return *this = int128(v);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+inline int128& int128::operator=(unsigned long v) {
+ return *this = int128(v);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+inline int128& int128::operator=(long long v) {
+ return *this = int128(v);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+inline int128& int128::operator=(unsigned long long v) {
+ return *this = int128(v);
+}
+
+// Arithmetic operators.
+
+int128 operator+(int128 lhs, int128 rhs);
+int128 operator-(int128 lhs, int128 rhs);
+int128 operator*(int128 lhs, int128 rhs);
+int128 operator/(int128 lhs, int128 rhs);
+int128 operator%(int128 lhs, int128 rhs);
+int128 operator|(int128 lhs, int128 rhs);
+int128 operator&(int128 lhs, int128 rhs);
+int128 operator^(int128 lhs, int128 rhs);
+int128 operator<<(int128 lhs, int amount);
+int128 operator>>(int128 lhs, int amount);
+
+inline int128& int128::operator+=(int128 other) {
+ *this = *this + other;
+ return *this;
+}
+
+inline int128& int128::operator-=(int128 other) {
+ *this = *this - other;
+ return *this;
+}
+
+inline int128& int128::operator*=(int128 other) {
+ *this = *this * other;
+ return *this;
+}
+
+inline int128& int128::operator/=(int128 other) {
+ *this = *this / other;
+ return *this;
+}
+
+inline int128& int128::operator%=(int128 other) {
+ *this = *this % other;
+ return *this;
+}
+
+inline int128& int128::operator|=(int128 other) {
+ *this = *this | other;
+ return *this;
+}
+
+inline int128& int128::operator&=(int128 other) {
+ *this = *this & other;
+ return *this;
+}
+
+inline int128& int128::operator^=(int128 other) {
+ *this = *this ^ other;
+ return *this;
+}
+
+inline int128& int128::operator<<=(int amount) {
+ *this = *this << amount;
+ return *this;
+}
+
+inline int128& int128::operator>>=(int amount) {
+ *this = *this >> amount;
+ return *this;
+}
+
+namespace int128_internal {
+
+// Casts from unsigned to signed while preserving the underlying binary
+// representation.
+constexpr int64_t BitCastToSigned(uint64_t v) {
+ // Casting an unsigned integer to a signed integer of the same
+ // width is implementation defined behavior if the source value would not fit
+ // in the destination type. We step around it with a roundtrip bitwise not
+ // operation to make sure this function remains constexpr. Clang, GCC, and
+ // MSVC optimize this to a no-op on x86-64.
+ return v & (uint64_t{1} << 63) ? ~static_cast<int64_t>(~v)
+ : static_cast<int64_t>(v);
+}
+
+} // namespace int128_internal
+
#if defined(ABSL_HAVE_INTRINSIC_INT128)
-#include "absl/numeric/int128_have_intrinsic.inc"
+#include "absl/numeric/int128_have_intrinsic.inc" // IWYU pragma: export
#else // ABSL_HAVE_INTRINSIC_INT128
-#include "absl/numeric/int128_no_intrinsic.inc"
+#include "absl/numeric/int128_no_intrinsic.inc" // IWYU pragma: export
#endif // ABSL_HAVE_INTRINSIC_INT128
+ABSL_NAMESPACE_END
} // namespace absl
#undef ABSL_INTERNAL_WCHAR_T
diff --git a/third_party/abseil/absl/numeric/int128_benchmark.cc b/third_party/abseil/absl/numeric/int128_benchmark.cc
index a5502d9..eab1515 100644
--- a/third_party/abseil/absl/numeric/int128_benchmark.cc
+++ b/third_party/abseil/absl/numeric/int128_benchmark.cc
@@ -12,15 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "absl/numeric/int128.h"
-
#include <algorithm>
#include <cstdint>
+#include <limits>
#include <random>
#include <vector>
#include "benchmark/benchmark.h"
#include "absl/base/config.h"
+#include "absl/numeric/int128.h"
namespace {
@@ -32,57 +32,85 @@
return std::mt19937(seed);
}
-std::vector<std::pair<absl::uint128, absl::uint128>>
-GetRandomClass128SampleUniformDivisor() {
- std::vector<std::pair<absl::uint128, absl::uint128>> values;
+template <typename T,
+ typename H = typename std::conditional<
+ std::numeric_limits<T>::is_signed, int64_t, uint64_t>::type>
+std::vector<std::pair<T, T>> GetRandomClass128SampleUniformDivisor() {
+ std::vector<std::pair<T, T>> values;
std::mt19937 random = MakeRandomEngine();
- std::uniform_int_distribution<uint64_t> uniform_uint64;
+ std::uniform_int_distribution<H> uniform_h;
values.reserve(kSampleSize);
for (size_t i = 0; i < kSampleSize; ++i) {
- absl::uint128 a =
- absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
- absl::uint128 b =
- absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
- values.emplace_back(std::max(a, b),
- std::max(absl::uint128(2), std::min(a, b)));
+ T a{absl::MakeUint128(uniform_h(random), uniform_h(random))};
+ T b{absl::MakeUint128(uniform_h(random), uniform_h(random))};
+ values.emplace_back(std::max(a, b), std::max(T(2), std::min(a, b)));
}
return values;
}
+template <typename T>
void BM_DivideClass128UniformDivisor(benchmark::State& state) {
- auto values = GetRandomClass128SampleUniformDivisor();
+ auto values = GetRandomClass128SampleUniformDivisor<T>();
while (state.KeepRunningBatch(values.size())) {
for (const auto& pair : values) {
benchmark::DoNotOptimize(pair.first / pair.second);
}
}
}
-BENCHMARK(BM_DivideClass128UniformDivisor);
+BENCHMARK_TEMPLATE(BM_DivideClass128UniformDivisor, absl::uint128);
+BENCHMARK_TEMPLATE(BM_DivideClass128UniformDivisor, absl::int128);
-std::vector<std::pair<absl::uint128, uint64_t>>
-GetRandomClass128SampleSmallDivisor() {
- std::vector<std::pair<absl::uint128, uint64_t>> values;
+template <typename T>
+void BM_RemainderClass128UniformDivisor(benchmark::State& state) {
+ auto values = GetRandomClass128SampleUniformDivisor<T>();
+ while (state.KeepRunningBatch(values.size())) {
+ for (const auto& pair : values) {
+ benchmark::DoNotOptimize(pair.first % pair.second);
+ }
+ }
+}
+BENCHMARK_TEMPLATE(BM_RemainderClass128UniformDivisor, absl::uint128);
+BENCHMARK_TEMPLATE(BM_RemainderClass128UniformDivisor, absl::int128);
+
+template <typename T,
+ typename H = typename std::conditional<
+ std::numeric_limits<T>::is_signed, int64_t, uint64_t>::type>
+std::vector<std::pair<T, H>> GetRandomClass128SampleSmallDivisor() {
+ std::vector<std::pair<T, H>> values;
std::mt19937 random = MakeRandomEngine();
- std::uniform_int_distribution<uint64_t> uniform_uint64;
+ std::uniform_int_distribution<H> uniform_h;
values.reserve(kSampleSize);
for (size_t i = 0; i < kSampleSize; ++i) {
- absl::uint128 a =
- absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
- uint64_t b = std::max(uint64_t{2}, uniform_uint64(random));
- values.emplace_back(std::max(a, absl::uint128(b)), b);
+ T a{absl::MakeUint128(uniform_h(random), uniform_h(random))};
+ H b{std::max(H{2}, uniform_h(random))};
+ values.emplace_back(std::max(a, T(b)), b);
}
return values;
}
+template <typename T>
void BM_DivideClass128SmallDivisor(benchmark::State& state) {
- auto values = GetRandomClass128SampleSmallDivisor();
+ auto values = GetRandomClass128SampleSmallDivisor<T>();
while (state.KeepRunningBatch(values.size())) {
for (const auto& pair : values) {
benchmark::DoNotOptimize(pair.first / pair.second);
}
}
}
-BENCHMARK(BM_DivideClass128SmallDivisor);
+BENCHMARK_TEMPLATE(BM_DivideClass128SmallDivisor, absl::uint128);
+BENCHMARK_TEMPLATE(BM_DivideClass128SmallDivisor, absl::int128);
+
+template <typename T>
+void BM_RemainderClass128SmallDivisor(benchmark::State& state) {
+ auto values = GetRandomClass128SampleSmallDivisor<T>();
+ while (state.KeepRunningBatch(values.size())) {
+ for (const auto& pair : values) {
+ benchmark::DoNotOptimize(pair.first % pair.second);
+ }
+ }
+}
+BENCHMARK_TEMPLATE(BM_RemainderClass128SmallDivisor, absl::uint128);
+BENCHMARK_TEMPLATE(BM_RemainderClass128SmallDivisor, absl::int128);
std::vector<std::pair<absl::uint128, absl::uint128>> GetRandomClass128Sample() {
std::vector<std::pair<absl::uint128, absl::uint128>> values;
@@ -121,74 +149,107 @@
// Some implementations of <random> do not support __int128 when it is
// available, so we make our own uniform_int_distribution-like type.
+template <typename T,
+ typename H = typename std::conditional<
+ std::is_same<T, __int128>::value, int64_t, uint64_t>::type>
class UniformIntDistribution128 {
public:
// NOLINTNEXTLINE: mimicking std::uniform_int_distribution API
- unsigned __int128 operator()(std::mt19937& generator) {
- return (static_cast<unsigned __int128>(dist64_(generator)) << 64) |
- dist64_(generator);
+ T operator()(std::mt19937& generator) {
+ return (static_cast<T>(dist64_(generator)) << 64) | dist64_(generator);
}
private:
- std::uniform_int_distribution<uint64_t> dist64_;
+ std::uniform_int_distribution<H> dist64_;
};
-std::vector<std::pair<unsigned __int128, unsigned __int128>>
-GetRandomIntrinsic128SampleUniformDivisor() {
- std::vector<std::pair<unsigned __int128, unsigned __int128>> values;
+template <typename T,
+ typename H = typename std::conditional<
+ std::is_same<T, __int128>::value, int64_t, uint64_t>::type>
+std::vector<std::pair<T, T>> GetRandomIntrinsic128SampleUniformDivisor() {
+ std::vector<std::pair<T, T>> values;
std::mt19937 random = MakeRandomEngine();
- UniformIntDistribution128 uniform_uint128;
+ UniformIntDistribution128<T> uniform_128;
values.reserve(kSampleSize);
for (size_t i = 0; i < kSampleSize; ++i) {
- unsigned __int128 a = uniform_uint128(random);
- unsigned __int128 b = uniform_uint128(random);
- values.emplace_back(
- std::max(a, b),
- std::max(static_cast<unsigned __int128>(2), std::min(a, b)));
+ T a = uniform_128(random);
+ T b = uniform_128(random);
+ values.emplace_back(std::max(a, b),
+ std::max(static_cast<T>(2), std::min(a, b)));
}
return values;
}
+template <typename T>
void BM_DivideIntrinsic128UniformDivisor(benchmark::State& state) {
- auto values = GetRandomIntrinsic128SampleUniformDivisor();
+ auto values = GetRandomIntrinsic128SampleUniformDivisor<T>();
while (state.KeepRunningBatch(values.size())) {
for (const auto& pair : values) {
benchmark::DoNotOptimize(pair.first / pair.second);
}
}
}
-BENCHMARK(BM_DivideIntrinsic128UniformDivisor);
+BENCHMARK_TEMPLATE(BM_DivideIntrinsic128UniformDivisor, unsigned __int128);
+BENCHMARK_TEMPLATE(BM_DivideIntrinsic128UniformDivisor, __int128);
-std::vector<std::pair<unsigned __int128, uint64_t>>
-GetRandomIntrinsic128SampleSmallDivisor() {
- std::vector<std::pair<unsigned __int128, uint64_t>> values;
+template <typename T>
+void BM_RemainderIntrinsic128UniformDivisor(benchmark::State& state) {
+ auto values = GetRandomIntrinsic128SampleUniformDivisor<T>();
+ while (state.KeepRunningBatch(values.size())) {
+ for (const auto& pair : values) {
+ benchmark::DoNotOptimize(pair.first % pair.second);
+ }
+ }
+}
+BENCHMARK_TEMPLATE(BM_RemainderIntrinsic128UniformDivisor, unsigned __int128);
+BENCHMARK_TEMPLATE(BM_RemainderIntrinsic128UniformDivisor, __int128);
+
+template <typename T,
+ typename H = typename std::conditional<
+ std::is_same<T, __int128>::value, int64_t, uint64_t>::type>
+std::vector<std::pair<T, H>> GetRandomIntrinsic128SampleSmallDivisor() {
+ std::vector<std::pair<T, H>> values;
std::mt19937 random = MakeRandomEngine();
- UniformIntDistribution128 uniform_uint128;
- std::uniform_int_distribution<uint64_t> uniform_uint64;
+ UniformIntDistribution128<T> uniform_int128;
+ std::uniform_int_distribution<H> uniform_int64;
values.reserve(kSampleSize);
for (size_t i = 0; i < kSampleSize; ++i) {
- unsigned __int128 a = uniform_uint128(random);
- uint64_t b = std::max(uint64_t{2}, uniform_uint64(random));
- values.emplace_back(std::max(a, static_cast<unsigned __int128>(b)), b);
+ T a = uniform_int128(random);
+ H b = std::max(H{2}, uniform_int64(random));
+ values.emplace_back(std::max(a, static_cast<T>(b)), b);
}
return values;
}
+template <typename T>
void BM_DivideIntrinsic128SmallDivisor(benchmark::State& state) {
- auto values = GetRandomIntrinsic128SampleSmallDivisor();
+ auto values = GetRandomIntrinsic128SampleSmallDivisor<T>();
while (state.KeepRunningBatch(values.size())) {
for (const auto& pair : values) {
benchmark::DoNotOptimize(pair.first / pair.second);
}
}
}
-BENCHMARK(BM_DivideIntrinsic128SmallDivisor);
+BENCHMARK_TEMPLATE(BM_DivideIntrinsic128SmallDivisor, unsigned __int128);
+BENCHMARK_TEMPLATE(BM_DivideIntrinsic128SmallDivisor, __int128);
+
+template <typename T>
+void BM_RemainderIntrinsic128SmallDivisor(benchmark::State& state) {
+ auto values = GetRandomIntrinsic128SampleSmallDivisor<T>();
+ while (state.KeepRunningBatch(values.size())) {
+ for (const auto& pair : values) {
+ benchmark::DoNotOptimize(pair.first % pair.second);
+ }
+ }
+}
+BENCHMARK_TEMPLATE(BM_RemainderIntrinsic128SmallDivisor, unsigned __int128);
+BENCHMARK_TEMPLATE(BM_RemainderIntrinsic128SmallDivisor, __int128);
std::vector<std::pair<unsigned __int128, unsigned __int128>>
GetRandomIntrinsic128Sample() {
std::vector<std::pair<unsigned __int128, unsigned __int128>> values;
std::mt19937 random = MakeRandomEngine();
- UniformIntDistribution128 uniform_uint128;
+ UniformIntDistribution128<unsigned __int128> uniform_uint128;
values.reserve(kSampleSize);
for (size_t i = 0; i < kSampleSize; ++i) {
values.emplace_back(uniform_uint128(random), uniform_uint128(random));
diff --git a/third_party/abseil/absl/numeric/int128_have_intrinsic.inc b/third_party/abseil/absl/numeric/int128_have_intrinsic.inc
index c7ea683..d6c76dd 100644
--- a/third_party/abseil/absl/numeric/int128_have_intrinsic.inc
+++ b/third_party/abseil/absl/numeric/int128_have_intrinsic.inc
@@ -16,3 +16,287 @@
// This file contains :int128 implementation details that depend on internal
// representation when ABSL_HAVE_INTRINSIC_INT128 is defined. This file is
// included by int128.h and relies on ABSL_INTERNAL_WCHAR_T being defined.
+
+namespace int128_internal {
+
+// Casts from unsigned to signed while preserving the underlying binary
+// representation.
+constexpr __int128 BitCastToSigned(unsigned __int128 v) {
+ // Casting an unsigned integer to a signed integer of the same
+ // width is implementation defined behavior if the source value would not fit
+ // in the destination type. We step around it with a roundtrip bitwise not
+ // operation to make sure this function remains constexpr. Clang and GCC
+ // optimize this to a no-op on x86-64.
+ return v & (static_cast<unsigned __int128>(1) << 127)
+ ? ~static_cast<__int128>(~v)
+ : static_cast<__int128>(v);
+}
+
+} // namespace int128_internal
+
+inline int128& int128::operator=(__int128 v) {
+ v_ = v;
+ return *this;
+}
+
+constexpr uint64_t Int128Low64(int128 v) {
+ return static_cast<uint64_t>(v.v_ & ~uint64_t{0});
+}
+
+constexpr int64_t Int128High64(int128 v) {
+ // Initially cast to unsigned to prevent a right shift on a negative value.
+ return int128_internal::BitCastToSigned(
+ static_cast<uint64_t>(static_cast<unsigned __int128>(v.v_) >> 64));
+}
+
+constexpr int128::int128(int64_t high, uint64_t low)
+ // Initially cast to unsigned to prevent a left shift that overflows.
+ : v_(int128_internal::BitCastToSigned(static_cast<unsigned __int128>(high)
+ << 64) |
+ low) {}
+
+
+constexpr int128::int128(int v) : v_{v} {}
+
+constexpr int128::int128(long v) : v_{v} {} // NOLINT(runtime/int)
+
+constexpr int128::int128(long long v) : v_{v} {} // NOLINT(runtime/int)
+
+constexpr int128::int128(__int128 v) : v_{v} {}
+
+constexpr int128::int128(unsigned int v) : v_{v} {}
+
+constexpr int128::int128(unsigned long v) : v_{v} {} // NOLINT(runtime/int)
+
+// NOLINTNEXTLINE(runtime/int)
+constexpr int128::int128(unsigned long long v) : v_{v} {}
+
+constexpr int128::int128(unsigned __int128 v) : v_{static_cast<__int128>(v)} {}
+
+inline int128::int128(float v) {
+ v_ = static_cast<__int128>(v);
+}
+
+inline int128::int128(double v) {
+ v_ = static_cast<__int128>(v);
+}
+
+inline int128::int128(long double v) {
+ v_ = static_cast<__int128>(v);
+}
+
+constexpr int128::int128(uint128 v) : v_{static_cast<__int128>(v)} {}
+
+constexpr int128::operator bool() const { return static_cast<bool>(v_); }
+
+constexpr int128::operator char() const { return static_cast<char>(v_); }
+
+constexpr int128::operator signed char() const {
+ return static_cast<signed char>(v_);
+}
+
+constexpr int128::operator unsigned char() const {
+ return static_cast<unsigned char>(v_);
+}
+
+constexpr int128::operator char16_t() const {
+ return static_cast<char16_t>(v_);
+}
+
+constexpr int128::operator char32_t() const {
+ return static_cast<char32_t>(v_);
+}
+
+constexpr int128::operator ABSL_INTERNAL_WCHAR_T() const {
+ return static_cast<ABSL_INTERNAL_WCHAR_T>(v_);
+}
+
+constexpr int128::operator short() const { // NOLINT(runtime/int)
+ return static_cast<short>(v_); // NOLINT(runtime/int)
+}
+
+constexpr int128::operator unsigned short() const { // NOLINT(runtime/int)
+ return static_cast<unsigned short>(v_); // NOLINT(runtime/int)
+}
+
+constexpr int128::operator int() const {
+ return static_cast<int>(v_);
+}
+
+constexpr int128::operator unsigned int() const {
+ return static_cast<unsigned int>(v_);
+}
+
+constexpr int128::operator long() const { // NOLINT(runtime/int)
+ return static_cast<long>(v_); // NOLINT(runtime/int)
+}
+
+constexpr int128::operator unsigned long() const { // NOLINT(runtime/int)
+ return static_cast<unsigned long>(v_); // NOLINT(runtime/int)
+}
+
+constexpr int128::operator long long() const { // NOLINT(runtime/int)
+ return static_cast<long long>(v_); // NOLINT(runtime/int)
+}
+
+constexpr int128::operator unsigned long long() const { // NOLINT(runtime/int)
+ return static_cast<unsigned long long>(v_); // NOLINT(runtime/int)
+}
+
+constexpr int128::operator __int128() const { return v_; }
+
+constexpr int128::operator unsigned __int128() const {
+ return static_cast<unsigned __int128>(v_);
+}
+
+// Clang on PowerPC sometimes produces incorrect __int128 to floating point
+// conversions. In that case, we do the conversion with a similar implementation
+// to the conversion operators in int128_no_intrinsic.inc.
+#if defined(__clang__) && !defined(__ppc64__)
+inline int128::operator float() const { return static_cast<float>(v_); }
+
+inline int128::operator double () const { return static_cast<double>(v_); }
+
+inline int128::operator long double() const {
+ return static_cast<long double>(v_);
+}
+
+#else // Clang on PowerPC
+// Forward declaration for conversion operators to floating point types.
+int128 operator-(int128 v);
+bool operator!=(int128 lhs, int128 rhs);
+
+inline int128::operator float() const {
+ // We must convert the absolute value and then negate as needed, because
+ // floating point types are typically sign-magnitude. Otherwise, the
+ // difference between the high and low 64 bits when interpreted as two's
+ // complement overwhelms the precision of the mantissa.
+ //
+ // Also check to make sure we don't negate Int128Min()
+ return v_ < 0 && *this != Int128Min()
+ ? -static_cast<float>(-*this)
+ : static_cast<float>(Int128Low64(*this)) +
+ std::ldexp(static_cast<float>(Int128High64(*this)), 64);
+}
+
+inline int128::operator double() const {
+ // See comment in int128::operator float() above.
+ return v_ < 0 && *this != Int128Min()
+ ? -static_cast<double>(-*this)
+ : static_cast<double>(Int128Low64(*this)) +
+ std::ldexp(static_cast<double>(Int128High64(*this)), 64);
+}
+
+inline int128::operator long double() const {
+ // See comment in int128::operator float() above.
+ return v_ < 0 && *this != Int128Min()
+ ? -static_cast<long double>(-*this)
+ : static_cast<long double>(Int128Low64(*this)) +
+ std::ldexp(static_cast<long double>(Int128High64(*this)),
+ 64);
+}
+#endif // Clang on PowerPC
+
+// Comparison operators.
+
+inline bool operator==(int128 lhs, int128 rhs) {
+ return static_cast<__int128>(lhs) == static_cast<__int128>(rhs);
+}
+
+inline bool operator!=(int128 lhs, int128 rhs) {
+ return static_cast<__int128>(lhs) != static_cast<__int128>(rhs);
+}
+
+inline bool operator<(int128 lhs, int128 rhs) {
+ return static_cast<__int128>(lhs) < static_cast<__int128>(rhs);
+}
+
+inline bool operator>(int128 lhs, int128 rhs) {
+ return static_cast<__int128>(lhs) > static_cast<__int128>(rhs);
+}
+
+inline bool operator<=(int128 lhs, int128 rhs) {
+ return static_cast<__int128>(lhs) <= static_cast<__int128>(rhs);
+}
+
+inline bool operator>=(int128 lhs, int128 rhs) {
+ return static_cast<__int128>(lhs) >= static_cast<__int128>(rhs);
+}
+
+// Unary operators.
+
+inline int128 operator-(int128 v) {
+ return -static_cast<__int128>(v);
+}
+
+inline bool operator!(int128 v) {
+ return !static_cast<__int128>(v);
+}
+
+inline int128 operator~(int128 val) {
+ return ~static_cast<__int128>(val);
+}
+
+// Arithmetic operators.
+
+inline int128 operator+(int128 lhs, int128 rhs) {
+ return static_cast<__int128>(lhs) + static_cast<__int128>(rhs);
+}
+
+inline int128 operator-(int128 lhs, int128 rhs) {
+ return static_cast<__int128>(lhs) - static_cast<__int128>(rhs);
+}
+
+inline int128 operator*(int128 lhs, int128 rhs) {
+ return static_cast<__int128>(lhs) * static_cast<__int128>(rhs);
+}
+
+inline int128 operator/(int128 lhs, int128 rhs) {
+ return static_cast<__int128>(lhs) / static_cast<__int128>(rhs);
+}
+
+inline int128 operator%(int128 lhs, int128 rhs) {
+ return static_cast<__int128>(lhs) % static_cast<__int128>(rhs);
+}
+
+inline int128 int128::operator++(int) {
+ int128 tmp(*this);
+ ++v_;
+ return tmp;
+}
+
+inline int128 int128::operator--(int) {
+ int128 tmp(*this);
+ --v_;
+ return tmp;
+}
+
+inline int128& int128::operator++() {
+ ++v_;
+ return *this;
+}
+
+inline int128& int128::operator--() {
+ --v_;
+ return *this;
+}
+
+inline int128 operator|(int128 lhs, int128 rhs) {
+ return static_cast<__int128>(lhs) | static_cast<__int128>(rhs);
+}
+
+inline int128 operator&(int128 lhs, int128 rhs) {
+ return static_cast<__int128>(lhs) & static_cast<__int128>(rhs);
+}
+
+inline int128 operator^(int128 lhs, int128 rhs) {
+ return static_cast<__int128>(lhs) ^ static_cast<__int128>(rhs);
+}
+
+inline int128 operator<<(int128 lhs, int amount) {
+ return static_cast<__int128>(lhs) << amount;
+}
+
+inline int128 operator>>(int128 lhs, int amount) {
+ return static_cast<__int128>(lhs) >> amount;
+}
diff --git a/third_party/abseil/absl/numeric/int128_no_intrinsic.inc b/third_party/abseil/absl/numeric/int128_no_intrinsic.inc
index 046cb9b..c753771 100644
--- a/third_party/abseil/absl/numeric/int128_no_intrinsic.inc
+++ b/third_party/abseil/absl/numeric/int128_no_intrinsic.inc
@@ -16,3 +16,293 @@
// This file contains :int128 implementation details that depend on internal
// representation when ABSL_HAVE_INTRINSIC_INT128 is *not* defined. This file
// is included by int128.h and relies on ABSL_INTERNAL_WCHAR_T being defined.
+
+constexpr uint64_t Int128Low64(int128 v) { return v.lo_; }
+
+constexpr int64_t Int128High64(int128 v) { return v.hi_; }
+
+#if defined(ABSL_IS_LITTLE_ENDIAN)
+
+constexpr int128::int128(int64_t high, uint64_t low) :
+ lo_(low), hi_(high) {}
+
+constexpr int128::int128(int v)
+ : lo_{static_cast<uint64_t>(v)}, hi_{v < 0 ? ~int64_t{0} : 0} {}
+constexpr int128::int128(long v) // NOLINT(runtime/int)
+ : lo_{static_cast<uint64_t>(v)}, hi_{v < 0 ? ~int64_t{0} : 0} {}
+constexpr int128::int128(long long v) // NOLINT(runtime/int)
+ : lo_{static_cast<uint64_t>(v)}, hi_{v < 0 ? ~int64_t{0} : 0} {}
+
+constexpr int128::int128(unsigned int v) : lo_{v}, hi_{0} {}
+// NOLINTNEXTLINE(runtime/int)
+constexpr int128::int128(unsigned long v) : lo_{v}, hi_{0} {}
+// NOLINTNEXTLINE(runtime/int)
+constexpr int128::int128(unsigned long long v) : lo_{v}, hi_{0} {}
+
+constexpr int128::int128(uint128 v)
+ : lo_{Uint128Low64(v)}, hi_{static_cast<int64_t>(Uint128High64(v))} {}
+
+#elif defined(ABSL_IS_BIG_ENDIAN)
+
+constexpr int128::int128(int64_t high, uint64_t low) :
+ hi_{high}, lo_{low} {}
+
+constexpr int128::int128(int v)
+ : hi_{v < 0 ? ~int64_t{0} : 0}, lo_{static_cast<uint64_t>(v)} {}
+constexpr int128::int128(long v) // NOLINT(runtime/int)
+ : hi_{v < 0 ? ~int64_t{0} : 0}, lo_{static_cast<uint64_t>(v)} {}
+constexpr int128::int128(long long v) // NOLINT(runtime/int)
+ : hi_{v < 0 ? ~int64_t{0} : 0}, lo_{static_cast<uint64_t>(v)} {}
+
+constexpr int128::int128(unsigned int v) : hi_{0}, lo_{v} {}
+// NOLINTNEXTLINE(runtime/int)
+constexpr int128::int128(unsigned long v) : hi_{0}, lo_{v} {}
+// NOLINTNEXTLINE(runtime/int)
+constexpr int128::int128(unsigned long long v) : hi_{0}, lo_{v} {}
+
+constexpr int128::int128(uint128 v)
+ : hi_{static_cast<int64_t>(Uint128High64(v))}, lo_{Uint128Low64(v)} {}
+
+#else // byte order
+#error "Unsupported byte order: must be little-endian or big-endian."
+#endif // byte order
+
+constexpr int128::operator bool() const { return lo_ || hi_; }
+
+constexpr int128::operator char() const {
+ // NOLINTNEXTLINE(runtime/int)
+ return static_cast<char>(static_cast<long long>(*this));
+}
+
+constexpr int128::operator signed char() const {
+ // NOLINTNEXTLINE(runtime/int)
+ return static_cast<signed char>(static_cast<long long>(*this));
+}
+
+constexpr int128::operator unsigned char() const {
+ return static_cast<unsigned char>(lo_);
+}
+
+constexpr int128::operator char16_t() const {
+ return static_cast<char16_t>(lo_);
+}
+
+constexpr int128::operator char32_t() const {
+ return static_cast<char32_t>(lo_);
+}
+
+constexpr int128::operator ABSL_INTERNAL_WCHAR_T() const {
+ // NOLINTNEXTLINE(runtime/int)
+ return static_cast<ABSL_INTERNAL_WCHAR_T>(static_cast<long long>(*this));
+}
+
+constexpr int128::operator short() const { // NOLINT(runtime/int)
+ // NOLINTNEXTLINE(runtime/int)
+ return static_cast<short>(static_cast<long long>(*this));
+}
+
+constexpr int128::operator unsigned short() const { // NOLINT(runtime/int)
+ return static_cast<unsigned short>(lo_); // NOLINT(runtime/int)
+}
+
+constexpr int128::operator int() const {
+ // NOLINTNEXTLINE(runtime/int)
+ return static_cast<int>(static_cast<long long>(*this));
+}
+
+constexpr int128::operator unsigned int() const {
+ return static_cast<unsigned int>(lo_);
+}
+
+constexpr int128::operator long() const { // NOLINT(runtime/int)
+ // NOLINTNEXTLINE(runtime/int)
+ return static_cast<long>(static_cast<long long>(*this));
+}
+
+constexpr int128::operator unsigned long() const { // NOLINT(runtime/int)
+ return static_cast<unsigned long>(lo_); // NOLINT(runtime/int)
+}
+
+constexpr int128::operator long long() const { // NOLINT(runtime/int)
+ // We don't bother checking the value of hi_. If *this < 0, lo_'s high bit
+ // must be set in order for the value to fit into a long long. Conversely, if
+ // lo_'s high bit is set, *this must be < 0 for the value to fit.
+ return int128_internal::BitCastToSigned(lo_);
+}
+
+constexpr int128::operator unsigned long long() const { // NOLINT(runtime/int)
+ return static_cast<unsigned long long>(lo_); // NOLINT(runtime/int)
+}
+
+// Forward declaration for conversion operators to floating point types.
+int128 operator-(int128 v);
+bool operator!=(int128 lhs, int128 rhs);
+
+inline int128::operator float() const {
+ // We must convert the absolute value and then negate as needed, because
+ // floating point types are typically sign-magnitude. Otherwise, the
+ // difference between the high and low 64 bits when interpreted as two's
+ // complement overwhelms the precision of the mantissa.
+ //
+ // Also check to make sure we don't negate Int128Min()
+ return hi_ < 0 && *this != Int128Min()
+ ? -static_cast<float>(-*this)
+ : static_cast<float>(lo_) +
+ std::ldexp(static_cast<float>(hi_), 64);
+}
+
+inline int128::operator double() const {
+ // See comment in int128::operator float() above.
+ return hi_ < 0 && *this != Int128Min()
+ ? -static_cast<double>(-*this)
+ : static_cast<double>(lo_) +
+ std::ldexp(static_cast<double>(hi_), 64);
+}
+
+inline int128::operator long double() const {
+ // See comment in int128::operator float() above.
+ return hi_ < 0 && *this != Int128Min()
+ ? -static_cast<long double>(-*this)
+ : static_cast<long double>(lo_) +
+ std::ldexp(static_cast<long double>(hi_), 64);
+}
+
+// Comparison operators.
+
+inline bool operator==(int128 lhs, int128 rhs) {
+ return (Int128Low64(lhs) == Int128Low64(rhs) &&
+ Int128High64(lhs) == Int128High64(rhs));
+}
+
+inline bool operator!=(int128 lhs, int128 rhs) {
+ return !(lhs == rhs);
+}
+
+inline bool operator<(int128 lhs, int128 rhs) {
+ return (Int128High64(lhs) == Int128High64(rhs))
+ ? (Int128Low64(lhs) < Int128Low64(rhs))
+ : (Int128High64(lhs) < Int128High64(rhs));
+}
+
+inline bool operator>(int128 lhs, int128 rhs) {
+ return (Int128High64(lhs) == Int128High64(rhs))
+ ? (Int128Low64(lhs) > Int128Low64(rhs))
+ : (Int128High64(lhs) > Int128High64(rhs));
+}
+
+inline bool operator<=(int128 lhs, int128 rhs) {
+ return !(lhs > rhs);
+}
+
+inline bool operator>=(int128 lhs, int128 rhs) {
+ return !(lhs < rhs);
+}
+
+// Unary operators.
+
+inline int128 operator-(int128 v) {
+ int64_t hi = ~Int128High64(v);
+ uint64_t lo = ~Int128Low64(v) + 1;
+ if (lo == 0) ++hi; // carry
+ return MakeInt128(hi, lo);
+}
+
+inline bool operator!(int128 v) {
+ return !Int128Low64(v) && !Int128High64(v);
+}
+
+inline int128 operator~(int128 val) {
+ return MakeInt128(~Int128High64(val), ~Int128Low64(val));
+}
+
+// Arithmetic operators.
+
+inline int128 operator+(int128 lhs, int128 rhs) {
+ int128 result = MakeInt128(Int128High64(lhs) + Int128High64(rhs),
+ Int128Low64(lhs) + Int128Low64(rhs));
+ if (Int128Low64(result) < Int128Low64(lhs)) { // check for carry
+ return MakeInt128(Int128High64(result) + 1, Int128Low64(result));
+ }
+ return result;
+}
+
+inline int128 operator-(int128 lhs, int128 rhs) {
+ int128 result = MakeInt128(Int128High64(lhs) - Int128High64(rhs),
+ Int128Low64(lhs) - Int128Low64(rhs));
+ if (Int128Low64(lhs) < Int128Low64(rhs)) { // check for carry
+ return MakeInt128(Int128High64(result) - 1, Int128Low64(result));
+ }
+ return result;
+}
+
+inline int128 operator*(int128 lhs, int128 rhs) {
+ uint128 result = uint128(lhs) * rhs;
+ return MakeInt128(int128_internal::BitCastToSigned(Uint128High64(result)),
+ Uint128Low64(result));
+}
+
+inline int128 int128::operator++(int) {
+ int128 tmp(*this);
+ *this += 1;
+ return tmp;
+}
+
+inline int128 int128::operator--(int) {
+ int128 tmp(*this);
+ *this -= 1;
+ return tmp;
+}
+
+inline int128& int128::operator++() {
+ *this += 1;
+ return *this;
+}
+
+inline int128& int128::operator--() {
+ *this -= 1;
+ return *this;
+}
+
+inline int128 operator|(int128 lhs, int128 rhs) {
+ return MakeInt128(Int128High64(lhs) | Int128High64(rhs),
+ Int128Low64(lhs) | Int128Low64(rhs));
+}
+
+inline int128 operator&(int128 lhs, int128 rhs) {
+ return MakeInt128(Int128High64(lhs) & Int128High64(rhs),
+ Int128Low64(lhs) & Int128Low64(rhs));
+}
+
+inline int128 operator^(int128 lhs, int128 rhs) {
+ return MakeInt128(Int128High64(lhs) ^ Int128High64(rhs),
+ Int128Low64(lhs) ^ Int128Low64(rhs));
+}
+
+inline int128 operator<<(int128 lhs, int amount) {
+ // uint64_t shifts of >= 64 are undefined, so we need some special-casing.
+ if (amount < 64) {
+ if (amount != 0) {
+ return MakeInt128(
+ (Int128High64(lhs) << amount) |
+ static_cast<int64_t>(Int128Low64(lhs) >> (64 - amount)),
+ Int128Low64(lhs) << amount);
+ }
+ return lhs;
+ }
+ return MakeInt128(static_cast<int64_t>(Int128Low64(lhs) << (amount - 64)), 0);
+}
+
+inline int128 operator>>(int128 lhs, int amount) {
+ // uint64_t shifts of >= 64 are undefined, so we need some special-casing.
+ if (amount < 64) {
+ if (amount != 0) {
+ return MakeInt128(
+ Int128High64(lhs) >> amount,
+ (Int128Low64(lhs) >> amount) |
+ (static_cast<uint64_t>(Int128High64(lhs)) << (64 - amount)));
+ }
+ return lhs;
+ }
+ return MakeInt128(0,
+ static_cast<uint64_t>(Int128High64(lhs) >> (amount - 64)));
+}
diff --git a/third_party/abseil/absl/numeric/int128_stream_test.cc b/third_party/abseil/absl/numeric/int128_stream_test.cc
index 3cfa9dc..479ad66 100644
--- a/third_party/abseil/absl/numeric/int128_stream_test.cc
+++ b/third_party/abseil/absl/numeric/int128_stream_test.cc
@@ -147,6 +147,735 @@
}
}
+struct Int128TestCase {
+ absl::int128 value;
+ std::ios_base::fmtflags flags;
+ std::streamsize width;
+ const char* expected;
+};
+
+void CheckInt128Case(const Int128TestCase& test_case) {
+ std::ostringstream os;
+ os.flags(test_case.flags);
+ os.width(test_case.width);
+ os.fill(kFill);
+ os << test_case.value;
+ SCOPED_TRACE(StreamFormatToString(test_case.flags, test_case.width));
+ EXPECT_EQ(test_case.expected, os.str());
+}
+
+TEST(Int128, OStreamValueTest) {
+ CheckInt128Case({1, kDec, /*width = */ 0, "1"});
+ CheckInt128Case({1, kOct, /*width = */ 0, "1"});
+ CheckInt128Case({1, kHex, /*width = */ 0, "1"});
+ CheckInt128Case({9, kDec, /*width = */ 0, "9"});
+ CheckInt128Case({9, kOct, /*width = */ 0, "11"});
+ CheckInt128Case({9, kHex, /*width = */ 0, "9"});
+ CheckInt128Case({12345, kDec, /*width = */ 0, "12345"});
+ CheckInt128Case({12345, kOct, /*width = */ 0, "30071"});
+ CheckInt128Case({12345, kHex, /*width = */ 0, "3039"});
+ CheckInt128Case(
+ {0x8000000000000000, kDec, /*width = */ 0, "9223372036854775808"});
+ CheckInt128Case(
+ {0x8000000000000000, kOct, /*width = */ 0, "1000000000000000000000"});
+ CheckInt128Case(
+ {0x8000000000000000, kHex, /*width = */ 0, "8000000000000000"});
+ CheckInt128Case({std::numeric_limits<uint64_t>::max(), kDec,
+ /*width = */ 0, "18446744073709551615"});
+ CheckInt128Case({std::numeric_limits<uint64_t>::max(), kOct,
+ /*width = */ 0, "1777777777777777777777"});
+ CheckInt128Case({std::numeric_limits<uint64_t>::max(), kHex,
+ /*width = */ 0, "ffffffffffffffff"});
+ CheckInt128Case(
+ {absl::MakeInt128(1, 0), kDec, /*width = */ 0, "18446744073709551616"});
+ CheckInt128Case(
+ {absl::MakeInt128(1, 0), kOct, /*width = */ 0, "2000000000000000000000"});
+ CheckInt128Case(
+ {absl::MakeInt128(1, 0), kHex, /*width = */ 0, "10000000000000000"});
+ CheckInt128Case({absl::MakeInt128(std::numeric_limits<int64_t>::max(),
+ std::numeric_limits<uint64_t>::max()),
+ std::ios::dec, /*width = */ 0,
+ "170141183460469231731687303715884105727"});
+ CheckInt128Case({absl::MakeInt128(std::numeric_limits<int64_t>::max(),
+ std::numeric_limits<uint64_t>::max()),
+ std::ios::oct, /*width = */ 0,
+ "1777777777777777777777777777777777777777777"});
+ CheckInt128Case({absl::MakeInt128(std::numeric_limits<int64_t>::max(),
+ std::numeric_limits<uint64_t>::max()),
+ std::ios::hex, /*width = */ 0,
+ "7fffffffffffffffffffffffffffffff"});
+ CheckInt128Case({absl::MakeInt128(std::numeric_limits<int64_t>::min(), 0),
+ std::ios::dec, /*width = */ 0,
+ "-170141183460469231731687303715884105728"});
+ CheckInt128Case({absl::MakeInt128(std::numeric_limits<int64_t>::min(), 0),
+ std::ios::oct, /*width = */ 0,
+ "2000000000000000000000000000000000000000000"});
+ CheckInt128Case({absl::MakeInt128(std::numeric_limits<int64_t>::min(), 0),
+ std::ios::hex, /*width = */ 0,
+ "80000000000000000000000000000000"});
+ CheckInt128Case({-1, std::ios::dec, /*width = */ 0, "-1"});
+ CheckInt128Case({-1, std::ios::oct, /*width = */ 0,
+ "3777777777777777777777777777777777777777777"});
+ CheckInt128Case(
+ {-1, std::ios::hex, /*width = */ 0, "ffffffffffffffffffffffffffffffff"});
+ CheckInt128Case({-12345, std::ios::dec, /*width = */ 0, "-12345"});
+ CheckInt128Case({-12345, std::ios::oct, /*width = */ 0,
+ "3777777777777777777777777777777777777747707"});
+ CheckInt128Case({-12345, std::ios::hex, /*width = */ 0,
+ "ffffffffffffffffffffffffffffcfc7"});
+}
+
+std::vector<Int128TestCase> GetInt128FormatCases();
+TEST(Int128, OStreamFormatTest) {
+ for (const Int128TestCase& test_case : GetInt128FormatCases()) {
+ CheckInt128Case(test_case);
+ }
+}
+
+std::vector<Int128TestCase> GetInt128FormatCases() {
+ return {
+ {0, std::ios_base::fmtflags(), /*width = */ 0, "0"},
+ {0, std::ios_base::fmtflags(), /*width = */ 6, "_____0"},
+ {0, kPos, /*width = */ 0, "+0"},
+ {0, kPos, /*width = */ 6, "____+0"},
+ {0, kBase, /*width = */ 0, "0"},
+ {0, kBase, /*width = */ 6, "_____0"},
+ {0, kBase | kPos, /*width = */ 0, "+0"},
+ {0, kBase | kPos, /*width = */ 6, "____+0"},
+ {0, kUpper, /*width = */ 0, "0"},
+ {0, kUpper, /*width = */ 6, "_____0"},
+ {0, kUpper | kPos, /*width = */ 0, "+0"},
+ {0, kUpper | kPos, /*width = */ 6, "____+0"},
+ {0, kUpper | kBase, /*width = */ 0, "0"},
+ {0, kUpper | kBase, /*width = */ 6, "_____0"},
+ {0, kUpper | kBase | kPos, /*width = */ 0, "+0"},
+ {0, kUpper | kBase | kPos, /*width = */ 6, "____+0"},
+ {0, kLeft, /*width = */ 0, "0"},
+ {0, kLeft, /*width = */ 6, "0_____"},
+ {0, kLeft | kPos, /*width = */ 0, "+0"},
+ {0, kLeft | kPos, /*width = */ 6, "+0____"},
+ {0, kLeft | kBase, /*width = */ 0, "0"},
+ {0, kLeft | kBase, /*width = */ 6, "0_____"},
+ {0, kLeft | kBase | kPos, /*width = */ 0, "+0"},
+ {0, kLeft | kBase | kPos, /*width = */ 6, "+0____"},
+ {0, kLeft | kUpper, /*width = */ 0, "0"},
+ {0, kLeft | kUpper, /*width = */ 6, "0_____"},
+ {0, kLeft | kUpper | kPos, /*width = */ 0, "+0"},
+ {0, kLeft | kUpper | kPos, /*width = */ 6, "+0____"},
+ {0, kLeft | kUpper | kBase, /*width = */ 0, "0"},
+ {0, kLeft | kUpper | kBase, /*width = */ 6, "0_____"},
+ {0, kLeft | kUpper | kBase | kPos, /*width = */ 0, "+0"},
+ {0, kLeft | kUpper | kBase | kPos, /*width = */ 6, "+0____"},
+ {0, kInt, /*width = */ 0, "0"},
+ {0, kInt, /*width = */ 6, "_____0"},
+ {0, kInt | kPos, /*width = */ 0, "+0"},
+ {0, kInt | kPos, /*width = */ 6, "+____0"},
+ {0, kInt | kBase, /*width = */ 0, "0"},
+ {0, kInt | kBase, /*width = */ 6, "_____0"},
+ {0, kInt | kBase | kPos, /*width = */ 0, "+0"},
+ {0, kInt | kBase | kPos, /*width = */ 6, "+____0"},
+ {0, kInt | kUpper, /*width = */ 0, "0"},
+ {0, kInt | kUpper, /*width = */ 6, "_____0"},
+ {0, kInt | kUpper | kPos, /*width = */ 0, "+0"},
+ {0, kInt | kUpper | kPos, /*width = */ 6, "+____0"},
+ {0, kInt | kUpper | kBase, /*width = */ 0, "0"},
+ {0, kInt | kUpper | kBase, /*width = */ 6, "_____0"},
+ {0, kInt | kUpper | kBase | kPos, /*width = */ 0, "+0"},
+ {0, kInt | kUpper | kBase | kPos, /*width = */ 6, "+____0"},
+ {0, kRight, /*width = */ 0, "0"},
+ {0, kRight, /*width = */ 6, "_____0"},
+ {0, kRight | kPos, /*width = */ 0, "+0"},
+ {0, kRight | kPos, /*width = */ 6, "____+0"},
+ {0, kRight | kBase, /*width = */ 0, "0"},
+ {0, kRight | kBase, /*width = */ 6, "_____0"},
+ {0, kRight | kBase | kPos, /*width = */ 0, "+0"},
+ {0, kRight | kBase | kPos, /*width = */ 6, "____+0"},
+ {0, kRight | kUpper, /*width = */ 0, "0"},
+ {0, kRight | kUpper, /*width = */ 6, "_____0"},
+ {0, kRight | kUpper | kPos, /*width = */ 0, "+0"},
+ {0, kRight | kUpper | kPos, /*width = */ 6, "____+0"},
+ {0, kRight | kUpper | kBase, /*width = */ 0, "0"},
+ {0, kRight | kUpper | kBase, /*width = */ 6, "_____0"},
+ {0, kRight | kUpper | kBase | kPos, /*width = */ 0, "+0"},
+ {0, kRight | kUpper | kBase | kPos, /*width = */ 6, "____+0"},
+ {0, kDec, /*width = */ 0, "0"},
+ {0, kDec, /*width = */ 6, "_____0"},
+ {0, kDec | kPos, /*width = */ 0, "+0"},
+ {0, kDec | kPos, /*width = */ 6, "____+0"},
+ {0, kDec | kBase, /*width = */ 0, "0"},
+ {0, kDec | kBase, /*width = */ 6, "_____0"},
+ {0, kDec | kBase | kPos, /*width = */ 0, "+0"},
+ {0, kDec | kBase | kPos, /*width = */ 6, "____+0"},
+ {0, kDec | kUpper, /*width = */ 0, "0"},
+ {0, kDec | kUpper, /*width = */ 6, "_____0"},
+ {0, kDec | kUpper | kPos, /*width = */ 0, "+0"},
+ {0, kDec | kUpper | kPos, /*width = */ 6, "____+0"},
+ {0, kDec | kUpper | kBase, /*width = */ 0, "0"},
+ {0, kDec | kUpper | kBase, /*width = */ 6, "_____0"},
+ {0, kDec | kUpper | kBase | kPos, /*width = */ 0, "+0"},
+ {0, kDec | kUpper | kBase | kPos, /*width = */ 6, "____+0"},
+ {0, kDec | kLeft, /*width = */ 0, "0"},
+ {0, kDec | kLeft, /*width = */ 6, "0_____"},
+ {0, kDec | kLeft | kPos, /*width = */ 0, "+0"},
+ {0, kDec | kLeft | kPos, /*width = */ 6, "+0____"},
+ {0, kDec | kLeft | kBase, /*width = */ 0, "0"},
+ {0, kDec | kLeft | kBase, /*width = */ 6, "0_____"},
+ {0, kDec | kLeft | kBase | kPos, /*width = */ 0, "+0"},
+ {0, kDec | kLeft | kBase | kPos, /*width = */ 6, "+0____"},
+ {0, kDec | kLeft | kUpper, /*width = */ 0, "0"},
+ {0, kDec | kLeft | kUpper, /*width = */ 6, "0_____"},
+ {0, kDec | kLeft | kUpper | kPos, /*width = */ 0, "+0"},
+ {0, kDec | kLeft | kUpper | kPos, /*width = */ 6, "+0____"},
+ {0, kDec | kLeft | kUpper | kBase, /*width = */ 0, "0"},
+ {0, kDec | kLeft | kUpper | kBase, /*width = */ 6, "0_____"},
+ {0, kDec | kLeft | kUpper | kBase | kPos, /*width = */ 0, "+0"},
+ {0, kDec | kLeft | kUpper | kBase | kPos, /*width = */ 6, "+0____"},
+ {0, kDec | kInt, /*width = */ 0, "0"},
+ {0, kDec | kInt, /*width = */ 6, "_____0"},
+ {0, kDec | kInt | kPos, /*width = */ 0, "+0"},
+ {0, kDec | kInt | kPos, /*width = */ 6, "+____0"},
+ {0, kDec | kInt | kBase, /*width = */ 0, "0"},
+ {0, kDec | kInt | kBase, /*width = */ 6, "_____0"},
+ {0, kDec | kInt | kBase | kPos, /*width = */ 0, "+0"},
+ {0, kDec | kInt | kBase | kPos, /*width = */ 6, "+____0"},
+ {0, kDec | kInt | kUpper, /*width = */ 0, "0"},
+ {0, kDec | kInt | kUpper, /*width = */ 6, "_____0"},
+ {0, kDec | kInt | kUpper | kPos, /*width = */ 0, "+0"},
+ {0, kDec | kInt | kUpper | kPos, /*width = */ 6, "+____0"},
+ {0, kDec | kInt | kUpper | kBase, /*width = */ 0, "0"},
+ {0, kDec | kInt | kUpper | kBase, /*width = */ 6, "_____0"},
+ {0, kDec | kInt | kUpper | kBase | kPos, /*width = */ 0, "+0"},
+ {0, kDec | kInt | kUpper | kBase | kPos, /*width = */ 6, "+____0"},
+ {0, kDec | kRight, /*width = */ 0, "0"},
+ {0, kDec | kRight, /*width = */ 6, "_____0"},
+ {0, kDec | kRight | kPos, /*width = */ 0, "+0"},
+ {0, kDec | kRight | kPos, /*width = */ 6, "____+0"},
+ {0, kDec | kRight | kBase, /*width = */ 0, "0"},
+ {0, kDec | kRight | kBase, /*width = */ 6, "_____0"},
+ {0, kDec | kRight | kBase | kPos, /*width = */ 0, "+0"},
+ {0, kDec | kRight | kBase | kPos, /*width = */ 6, "____+0"},
+ {0, kDec | kRight | kUpper, /*width = */ 0, "0"},
+ {0, kDec | kRight | kUpper, /*width = */ 6, "_____0"},
+ {0, kDec | kRight | kUpper | kPos, /*width = */ 0, "+0"},
+ {0, kDec | kRight | kUpper | kPos, /*width = */ 6, "____+0"},
+ {0, kDec | kRight | kUpper | kBase, /*width = */ 0, "0"},
+ {0, kDec | kRight | kUpper | kBase, /*width = */ 6, "_____0"},
+ {0, kDec | kRight | kUpper | kBase | kPos, /*width = */ 0, "+0"},
+ {0, kDec | kRight | kUpper | kBase | kPos, /*width = */ 6, "____+0"},
+ {0, kOct, /*width = */ 0, "0"},
+ {0, kOct, /*width = */ 6, "_____0"},
+ {0, kOct | kPos, /*width = */ 0, "0"},
+ {0, kOct | kPos, /*width = */ 6, "_____0"},
+ {0, kOct | kBase, /*width = */ 0, "0"},
+ {0, kOct | kBase, /*width = */ 6, "_____0"},
+ {0, kOct | kBase | kPos, /*width = */ 0, "0"},
+ {0, kOct | kBase | kPos, /*width = */ 6, "_____0"},
+ {0, kOct | kUpper, /*width = */ 0, "0"},
+ {0, kOct | kUpper, /*width = */ 6, "_____0"},
+ {0, kOct | kUpper | kPos, /*width = */ 0, "0"},
+ {0, kOct | kUpper | kPos, /*width = */ 6, "_____0"},
+ {0, kOct | kUpper | kBase, /*width = */ 0, "0"},
+ {0, kOct | kUpper | kBase, /*width = */ 6, "_____0"},
+ {0, kOct | kUpper | kBase | kPos, /*width = */ 0, "0"},
+ {0, kOct | kUpper | kBase | kPos, /*width = */ 6, "_____0"},
+ {0, kOct | kLeft, /*width = */ 0, "0"},
+ {0, kOct | kLeft, /*width = */ 6, "0_____"},
+ {0, kOct | kLeft | kPos, /*width = */ 0, "0"},
+ {0, kOct | kLeft | kPos, /*width = */ 6, "0_____"},
+ {0, kOct | kLeft | kBase, /*width = */ 0, "0"},
+ {0, kOct | kLeft | kBase, /*width = */ 6, "0_____"},
+ {0, kOct | kLeft | kBase | kPos, /*width = */ 0, "0"},
+ {0, kOct | kLeft | kBase | kPos, /*width = */ 6, "0_____"},
+ {0, kOct | kLeft | kUpper, /*width = */ 0, "0"},
+ {0, kOct | kLeft | kUpper, /*width = */ 6, "0_____"},
+ {0, kOct | kLeft | kUpper | kPos, /*width = */ 0, "0"},
+ {0, kOct | kLeft | kUpper | kPos, /*width = */ 6, "0_____"},
+ {0, kOct | kLeft | kUpper | kBase, /*width = */ 0, "0"},
+ {0, kOct | kLeft | kUpper | kBase, /*width = */ 6, "0_____"},
+ {0, kOct | kLeft | kUpper | kBase | kPos, /*width = */ 0, "0"},
+ {0, kOct | kLeft | kUpper | kBase | kPos, /*width = */ 6, "0_____"},
+ {0, kOct | kInt, /*width = */ 0, "0"},
+ {0, kOct | kInt, /*width = */ 6, "_____0"},
+ {0, kOct | kInt | kPos, /*width = */ 0, "0"},
+ {0, kOct | kInt | kPos, /*width = */ 6, "_____0"},
+ {0, kOct | kInt | kBase, /*width = */ 0, "0"},
+ {0, kOct | kInt | kBase, /*width = */ 6, "_____0"},
+ {0, kOct | kInt | kBase | kPos, /*width = */ 0, "0"},
+ {0, kOct | kInt | kBase | kPos, /*width = */ 6, "_____0"},
+ {0, kOct | kInt | kUpper, /*width = */ 0, "0"},
+ {0, kOct | kInt | kUpper, /*width = */ 6, "_____0"},
+ {0, kOct | kInt | kUpper | kPos, /*width = */ 0, "0"},
+ {0, kOct | kInt | kUpper | kPos, /*width = */ 6, "_____0"},
+ {0, kOct | kInt | kUpper | kBase, /*width = */ 0, "0"},
+ {0, kOct | kInt | kUpper | kBase, /*width = */ 6, "_____0"},
+ {0, kOct | kInt | kUpper | kBase | kPos, /*width = */ 0, "0"},
+ {0, kOct | kInt | kUpper | kBase | kPos, /*width = */ 6, "_____0"},
+ {0, kOct | kRight, /*width = */ 0, "0"},
+ {0, kOct | kRight, /*width = */ 6, "_____0"},
+ {0, kOct | kRight | kPos, /*width = */ 0, "0"},
+ {0, kOct | kRight | kPos, /*width = */ 6, "_____0"},
+ {0, kOct | kRight | kBase, /*width = */ 0, "0"},
+ {0, kOct | kRight | kBase, /*width = */ 6, "_____0"},
+ {0, kOct | kRight | kBase | kPos, /*width = */ 0, "0"},
+ {0, kOct | kRight | kBase | kPos, /*width = */ 6, "_____0"},
+ {0, kOct | kRight | kUpper, /*width = */ 0, "0"},
+ {0, kOct | kRight | kUpper, /*width = */ 6, "_____0"},
+ {0, kOct | kRight | kUpper | kPos, /*width = */ 0, "0"},
+ {0, kOct | kRight | kUpper | kPos, /*width = */ 6, "_____0"},
+ {0, kOct | kRight | kUpper | kBase, /*width = */ 0, "0"},
+ {0, kOct | kRight | kUpper | kBase, /*width = */ 6, "_____0"},
+ {0, kOct | kRight | kUpper | kBase | kPos, /*width = */ 0, "0"},
+ {0, kOct | kRight | kUpper | kBase | kPos, /*width = */ 6, "_____0"},
+ {0, kHex, /*width = */ 0, "0"},
+ {0, kHex, /*width = */ 6, "_____0"},
+ {0, kHex | kPos, /*width = */ 0, "0"},
+ {0, kHex | kPos, /*width = */ 6, "_____0"},
+ {0, kHex | kBase, /*width = */ 0, "0"},
+ {0, kHex | kBase, /*width = */ 6, "_____0"},
+ {0, kHex | kBase | kPos, /*width = */ 0, "0"},
+ {0, kHex | kBase | kPos, /*width = */ 6, "_____0"},
+ {0, kHex | kUpper, /*width = */ 0, "0"},
+ {0, kHex | kUpper, /*width = */ 6, "_____0"},
+ {0, kHex | kUpper | kPos, /*width = */ 0, "0"},
+ {0, kHex | kUpper | kPos, /*width = */ 6, "_____0"},
+ {0, kHex | kUpper | kBase, /*width = */ 0, "0"},
+ {0, kHex | kUpper | kBase, /*width = */ 6, "_____0"},
+ {0, kHex | kUpper | kBase | kPos, /*width = */ 0, "0"},
+ {0, kHex | kUpper | kBase | kPos, /*width = */ 6, "_____0"},
+ {0, kHex | kLeft, /*width = */ 0, "0"},
+ {0, kHex | kLeft, /*width = */ 6, "0_____"},
+ {0, kHex | kLeft | kPos, /*width = */ 0, "0"},
+ {0, kHex | kLeft | kPos, /*width = */ 6, "0_____"},
+ {0, kHex | kLeft | kBase, /*width = */ 0, "0"},
+ {0, kHex | kLeft | kBase, /*width = */ 6, "0_____"},
+ {0, kHex | kLeft | kBase | kPos, /*width = */ 0, "0"},
+ {0, kHex | kLeft | kBase | kPos, /*width = */ 6, "0_____"},
+ {0, kHex | kLeft | kUpper, /*width = */ 0, "0"},
+ {0, kHex | kLeft | kUpper, /*width = */ 6, "0_____"},
+ {0, kHex | kLeft | kUpper | kPos, /*width = */ 0, "0"},
+ {0, kHex | kLeft | kUpper | kPos, /*width = */ 6, "0_____"},
+ {0, kHex | kLeft | kUpper | kBase, /*width = */ 0, "0"},
+ {0, kHex | kLeft | kUpper | kBase, /*width = */ 6, "0_____"},
+ {0, kHex | kLeft | kUpper | kBase | kPos, /*width = */ 0, "0"},
+ {0, kHex | kLeft | kUpper | kBase | kPos, /*width = */ 6, "0_____"},
+ {0, kHex | kInt, /*width = */ 0, "0"},
+ {0, kHex | kInt, /*width = */ 6, "_____0"},
+ {0, kHex | kInt | kPos, /*width = */ 0, "0"},
+ {0, kHex | kInt | kPos, /*width = */ 6, "_____0"},
+ {0, kHex | kInt | kBase, /*width = */ 0, "0"},
+ {0, kHex | kInt | kBase, /*width = */ 6, "_____0"},
+ {0, kHex | kInt | kBase | kPos, /*width = */ 0, "0"},
+ {0, kHex | kInt | kBase | kPos, /*width = */ 6, "_____0"},
+ {0, kHex | kInt | kUpper, /*width = */ 0, "0"},
+ {0, kHex | kInt | kUpper, /*width = */ 6, "_____0"},
+ {0, kHex | kInt | kUpper | kPos, /*width = */ 0, "0"},
+ {0, kHex | kInt | kUpper | kPos, /*width = */ 6, "_____0"},
+ {0, kHex | kInt | kUpper | kBase, /*width = */ 0, "0"},
+ {0, kHex | kInt | kUpper | kBase, /*width = */ 6, "_____0"},
+ {0, kHex | kInt | kUpper | kBase | kPos, /*width = */ 0, "0"},
+ {0, kHex | kInt | kUpper | kBase | kPos, /*width = */ 6, "_____0"},
+ {0, kHex | kRight, /*width = */ 0, "0"},
+ {0, kHex | kRight, /*width = */ 6, "_____0"},
+ {0, kHex | kRight | kPos, /*width = */ 0, "0"},
+ {0, kHex | kRight | kPos, /*width = */ 6, "_____0"},
+ {0, kHex | kRight | kBase, /*width = */ 0, "0"},
+ {0, kHex | kRight | kBase, /*width = */ 6, "_____0"},
+ {0, kHex | kRight | kBase | kPos, /*width = */ 0, "0"},
+ {0, kHex | kRight | kBase | kPos, /*width = */ 6, "_____0"},
+ {0, kHex | kRight | kUpper, /*width = */ 0, "0"},
+ {0, kHex | kRight | kUpper, /*width = */ 6, "_____0"},
+ {0, kHex | kRight | kUpper | kPos, /*width = */ 0, "0"},
+ {0, kHex | kRight | kUpper | kPos, /*width = */ 6, "_____0"},
+ {0, kHex | kRight | kUpper | kBase, /*width = */ 0, "0"},
+ {0, kHex | kRight | kUpper | kBase, /*width = */ 6, "_____0"},
+ {0, kHex | kRight | kUpper | kBase | kPos, /*width = */ 0, "0"},
+ {0, kHex | kRight | kUpper | kBase | kPos, /*width = */ 6, "_____0"},
+ {42, std::ios_base::fmtflags(), /*width = */ 0, "42"},
+ {42, std::ios_base::fmtflags(), /*width = */ 6, "____42"},
+ {42, kPos, /*width = */ 0, "+42"},
+ {42, kPos, /*width = */ 6, "___+42"},
+ {42, kBase, /*width = */ 0, "42"},
+ {42, kBase, /*width = */ 6, "____42"},
+ {42, kBase | kPos, /*width = */ 0, "+42"},
+ {42, kBase | kPos, /*width = */ 6, "___+42"},
+ {42, kUpper, /*width = */ 0, "42"},
+ {42, kUpper, /*width = */ 6, "____42"},
+ {42, kUpper | kPos, /*width = */ 0, "+42"},
+ {42, kUpper | kPos, /*width = */ 6, "___+42"},
+ {42, kUpper | kBase, /*width = */ 0, "42"},
+ {42, kUpper | kBase, /*width = */ 6, "____42"},
+ {42, kUpper | kBase | kPos, /*width = */ 0, "+42"},
+ {42, kUpper | kBase | kPos, /*width = */ 6, "___+42"},
+ {42, kLeft, /*width = */ 0, "42"},
+ {42, kLeft, /*width = */ 6, "42____"},
+ {42, kLeft | kPos, /*width = */ 0, "+42"},
+ {42, kLeft | kPos, /*width = */ 6, "+42___"},
+ {42, kLeft | kBase, /*width = */ 0, "42"},
+ {42, kLeft | kBase, /*width = */ 6, "42____"},
+ {42, kLeft | kBase | kPos, /*width = */ 0, "+42"},
+ {42, kLeft | kBase | kPos, /*width = */ 6, "+42___"},
+ {42, kLeft | kUpper, /*width = */ 0, "42"},
+ {42, kLeft | kUpper, /*width = */ 6, "42____"},
+ {42, kLeft | kUpper | kPos, /*width = */ 0, "+42"},
+ {42, kLeft | kUpper | kPos, /*width = */ 6, "+42___"},
+ {42, kLeft | kUpper | kBase, /*width = */ 0, "42"},
+ {42, kLeft | kUpper | kBase, /*width = */ 6, "42____"},
+ {42, kLeft | kUpper | kBase | kPos, /*width = */ 0, "+42"},
+ {42, kLeft | kUpper | kBase | kPos, /*width = */ 6, "+42___"},
+ {42, kInt, /*width = */ 0, "42"},
+ {42, kInt, /*width = */ 6, "____42"},
+ {42, kInt | kPos, /*width = */ 0, "+42"},
+ {42, kInt | kPos, /*width = */ 6, "+___42"},
+ {42, kInt | kBase, /*width = */ 0, "42"},
+ {42, kInt | kBase, /*width = */ 6, "____42"},
+ {42, kInt | kBase | kPos, /*width = */ 0, "+42"},
+ {42, kInt | kBase | kPos, /*width = */ 6, "+___42"},
+ {42, kInt | kUpper, /*width = */ 0, "42"},
+ {42, kInt | kUpper, /*width = */ 6, "____42"},
+ {42, kInt | kUpper | kPos, /*width = */ 0, "+42"},
+ {42, kInt | kUpper | kPos, /*width = */ 6, "+___42"},
+ {42, kInt | kUpper | kBase, /*width = */ 0, "42"},
+ {42, kInt | kUpper | kBase, /*width = */ 6, "____42"},
+ {42, kInt | kUpper | kBase | kPos, /*width = */ 0, "+42"},
+ {42, kInt | kUpper | kBase | kPos, /*width = */ 6, "+___42"},
+ {42, kRight, /*width = */ 0, "42"},
+ {42, kRight, /*width = */ 6, "____42"},
+ {42, kRight | kPos, /*width = */ 0, "+42"},
+ {42, kRight | kPos, /*width = */ 6, "___+42"},
+ {42, kRight | kBase, /*width = */ 0, "42"},
+ {42, kRight | kBase, /*width = */ 6, "____42"},
+ {42, kRight | kBase | kPos, /*width = */ 0, "+42"},
+ {42, kRight | kBase | kPos, /*width = */ 6, "___+42"},
+ {42, kRight | kUpper, /*width = */ 0, "42"},
+ {42, kRight | kUpper, /*width = */ 6, "____42"},
+ {42, kRight | kUpper | kPos, /*width = */ 0, "+42"},
+ {42, kRight | kUpper | kPos, /*width = */ 6, "___+42"},
+ {42, kRight | kUpper | kBase, /*width = */ 0, "42"},
+ {42, kRight | kUpper | kBase, /*width = */ 6, "____42"},
+ {42, kRight | kUpper | kBase | kPos, /*width = */ 0, "+42"},
+ {42, kRight | kUpper | kBase | kPos, /*width = */ 6, "___+42"},
+ {42, kDec, /*width = */ 0, "42"},
+ {42, kDec, /*width = */ 6, "____42"},
+ {42, kDec | kPos, /*width = */ 0, "+42"},
+ {42, kDec | kPos, /*width = */ 6, "___+42"},
+ {42, kDec | kBase, /*width = */ 0, "42"},
+ {42, kDec | kBase, /*width = */ 6, "____42"},
+ {42, kDec | kBase | kPos, /*width = */ 0, "+42"},
+ {42, kDec | kBase | kPos, /*width = */ 6, "___+42"},
+ {42, kDec | kUpper, /*width = */ 0, "42"},
+ {42, kDec | kUpper, /*width = */ 6, "____42"},
+ {42, kDec | kUpper | kPos, /*width = */ 0, "+42"},
+ {42, kDec | kUpper | kPos, /*width = */ 6, "___+42"},
+ {42, kDec | kUpper | kBase, /*width = */ 0, "42"},
+ {42, kDec | kUpper | kBase, /*width = */ 6, "____42"},
+ {42, kDec | kUpper | kBase | kPos, /*width = */ 0, "+42"},
+ {42, kDec | kUpper | kBase | kPos, /*width = */ 6, "___+42"},
+ {42, kDec | kLeft, /*width = */ 0, "42"},
+ {42, kDec | kLeft, /*width = */ 6, "42____"},
+ {42, kDec | kLeft | kPos, /*width = */ 0, "+42"},
+ {42, kDec | kLeft | kPos, /*width = */ 6, "+42___"},
+ {42, kDec | kLeft | kBase, /*width = */ 0, "42"},
+ {42, kDec | kLeft | kBase, /*width = */ 6, "42____"},
+ {42, kDec | kLeft | kBase | kPos, /*width = */ 0, "+42"},
+ {42, kDec | kLeft | kBase | kPos, /*width = */ 6, "+42___"},
+ {42, kDec | kLeft | kUpper, /*width = */ 0, "42"},
+ {42, kDec | kLeft | kUpper, /*width = */ 6, "42____"},
+ {42, kDec | kLeft | kUpper | kPos, /*width = */ 0, "+42"},
+ {42, kDec | kLeft | kUpper | kPos, /*width = */ 6, "+42___"},
+ {42, kDec | kLeft | kUpper | kBase, /*width = */ 0, "42"},
+ {42, kDec | kLeft | kUpper | kBase, /*width = */ 6, "42____"},
+ {42, kDec | kLeft | kUpper | kBase | kPos, /*width = */ 0, "+42"},
+ {42, kDec | kLeft | kUpper | kBase | kPos, /*width = */ 6, "+42___"},
+ {42, kDec | kInt, /*width = */ 0, "42"},
+ {42, kDec | kInt, /*width = */ 6, "____42"},
+ {42, kDec | kInt | kPos, /*width = */ 0, "+42"},
+ {42, kDec | kInt | kPos, /*width = */ 6, "+___42"},
+ {42, kDec | kInt | kBase, /*width = */ 0, "42"},
+ {42, kDec | kInt | kBase, /*width = */ 6, "____42"},
+ {42, kDec | kInt | kBase | kPos, /*width = */ 0, "+42"},
+ {42, kDec | kInt | kBase | kPos, /*width = */ 6, "+___42"},
+ {42, kDec | kInt | kUpper, /*width = */ 0, "42"},
+ {42, kDec | kInt | kUpper, /*width = */ 6, "____42"},
+ {42, kDec | kInt | kUpper | kPos, /*width = */ 0, "+42"},
+ {42, kDec | kInt | kUpper | kPos, /*width = */ 6, "+___42"},
+ {42, kDec | kInt | kUpper | kBase, /*width = */ 0, "42"},
+ {42, kDec | kInt | kUpper | kBase, /*width = */ 6, "____42"},
+ {42, kDec | kInt | kUpper | kBase | kPos, /*width = */ 0, "+42"},
+ {42, kDec | kInt | kUpper | kBase | kPos, /*width = */ 6, "+___42"},
+ {42, kDec | kRight, /*width = */ 0, "42"},
+ {42, kDec | kRight, /*width = */ 6, "____42"},
+ {42, kDec | kRight | kPos, /*width = */ 0, "+42"},
+ {42, kDec | kRight | kPos, /*width = */ 6, "___+42"},
+ {42, kDec | kRight | kBase, /*width = */ 0, "42"},
+ {42, kDec | kRight | kBase, /*width = */ 6, "____42"},
+ {42, kDec | kRight | kBase | kPos, /*width = */ 0, "+42"},
+ {42, kDec | kRight | kBase | kPos, /*width = */ 6, "___+42"},
+ {42, kDec | kRight | kUpper, /*width = */ 0, "42"},
+ {42, kDec | kRight | kUpper, /*width = */ 6, "____42"},
+ {42, kDec | kRight | kUpper | kPos, /*width = */ 0, "+42"},
+ {42, kDec | kRight | kUpper | kPos, /*width = */ 6, "___+42"},
+ {42, kDec | kRight | kUpper | kBase, /*width = */ 0, "42"},
+ {42, kDec | kRight | kUpper | kBase, /*width = */ 6, "____42"},
+ {42, kDec | kRight | kUpper | kBase | kPos, /*width = */ 0, "+42"},
+ {42, kDec | kRight | kUpper | kBase | kPos, /*width = */ 6, "___+42"},
+ {42, kOct, /*width = */ 0, "52"},
+ {42, kOct, /*width = */ 6, "____52"},
+ {42, kOct | kPos, /*width = */ 0, "52"},
+ {42, kOct | kPos, /*width = */ 6, "____52"},
+ {42, kOct | kBase, /*width = */ 0, "052"},
+ {42, kOct | kBase, /*width = */ 6, "___052"},
+ {42, kOct | kBase | kPos, /*width = */ 0, "052"},
+ {42, kOct | kBase | kPos, /*width = */ 6, "___052"},
+ {42, kOct | kUpper, /*width = */ 0, "52"},
+ {42, kOct | kUpper, /*width = */ 6, "____52"},
+ {42, kOct | kUpper | kPos, /*width = */ 0, "52"},
+ {42, kOct | kUpper | kPos, /*width = */ 6, "____52"},
+ {42, kOct | kUpper | kBase, /*width = */ 0, "052"},
+ {42, kOct | kUpper | kBase, /*width = */ 6, "___052"},
+ {42, kOct | kUpper | kBase | kPos, /*width = */ 0, "052"},
+ {42, kOct | kUpper | kBase | kPos, /*width = */ 6, "___052"},
+ {42, kOct | kLeft, /*width = */ 0, "52"},
+ {42, kOct | kLeft, /*width = */ 6, "52____"},
+ {42, kOct | kLeft | kPos, /*width = */ 0, "52"},
+ {42, kOct | kLeft | kPos, /*width = */ 6, "52____"},
+ {42, kOct | kLeft | kBase, /*width = */ 0, "052"},
+ {42, kOct | kLeft | kBase, /*width = */ 6, "052___"},
+ {42, kOct | kLeft | kBase | kPos, /*width = */ 0, "052"},
+ {42, kOct | kLeft | kBase | kPos, /*width = */ 6, "052___"},
+ {42, kOct | kLeft | kUpper, /*width = */ 0, "52"},
+ {42, kOct | kLeft | kUpper, /*width = */ 6, "52____"},
+ {42, kOct | kLeft | kUpper | kPos, /*width = */ 0, "52"},
+ {42, kOct | kLeft | kUpper | kPos, /*width = */ 6, "52____"},
+ {42, kOct | kLeft | kUpper | kBase, /*width = */ 0, "052"},
+ {42, kOct | kLeft | kUpper | kBase, /*width = */ 6, "052___"},
+ {42, kOct | kLeft | kUpper | kBase | kPos, /*width = */ 0, "052"},
+ {42, kOct | kLeft | kUpper | kBase | kPos, /*width = */ 6, "052___"},
+ {42, kOct | kInt, /*width = */ 0, "52"},
+ {42, kOct | kInt, /*width = */ 6, "____52"},
+ {42, kOct | kInt | kPos, /*width = */ 0, "52"},
+ {42, kOct | kInt | kPos, /*width = */ 6, "____52"},
+ {42, kOct | kInt | kBase, /*width = */ 0, "052"},
+ {42, kOct | kInt | kBase, /*width = */ 6, "___052"},
+ {42, kOct | kInt | kBase | kPos, /*width = */ 0, "052"},
+ {42, kOct | kInt | kBase | kPos, /*width = */ 6, "___052"},
+ {42, kOct | kInt | kUpper, /*width = */ 0, "52"},
+ {42, kOct | kInt | kUpper, /*width = */ 6, "____52"},
+ {42, kOct | kInt | kUpper | kPos, /*width = */ 0, "52"},
+ {42, kOct | kInt | kUpper | kPos, /*width = */ 6, "____52"},
+ {42, kOct | kInt | kUpper | kBase, /*width = */ 0, "052"},
+ {42, kOct | kInt | kUpper | kBase, /*width = */ 6, "___052"},
+ {42, kOct | kInt | kUpper | kBase | kPos, /*width = */ 0, "052"},
+ {42, kOct | kInt | kUpper | kBase | kPos, /*width = */ 6, "___052"},
+ {42, kOct | kRight, /*width = */ 0, "52"},
+ {42, kOct | kRight, /*width = */ 6, "____52"},
+ {42, kOct | kRight | kPos, /*width = */ 0, "52"},
+ {42, kOct | kRight | kPos, /*width = */ 6, "____52"},
+ {42, kOct | kRight | kBase, /*width = */ 0, "052"},
+ {42, kOct | kRight | kBase, /*width = */ 6, "___052"},
+ {42, kOct | kRight | kBase | kPos, /*width = */ 0, "052"},
+ {42, kOct | kRight | kBase | kPos, /*width = */ 6, "___052"},
+ {42, kOct | kRight | kUpper, /*width = */ 0, "52"},
+ {42, kOct | kRight | kUpper, /*width = */ 6, "____52"},
+ {42, kOct | kRight | kUpper | kPos, /*width = */ 0, "52"},
+ {42, kOct | kRight | kUpper | kPos, /*width = */ 6, "____52"},
+ {42, kOct | kRight | kUpper | kBase, /*width = */ 0, "052"},
+ {42, kOct | kRight | kUpper | kBase, /*width = */ 6, "___052"},
+ {42, kOct | kRight | kUpper | kBase | kPos, /*width = */ 0, "052"},
+ {42, kOct | kRight | kUpper | kBase | kPos, /*width = */ 6, "___052"},
+ {42, kHex, /*width = */ 0, "2a"},
+ {42, kHex, /*width = */ 6, "____2a"},
+ {42, kHex | kPos, /*width = */ 0, "2a"},
+ {42, kHex | kPos, /*width = */ 6, "____2a"},
+ {42, kHex | kBase, /*width = */ 0, "0x2a"},
+ {42, kHex | kBase, /*width = */ 6, "__0x2a"},
+ {42, kHex | kBase | kPos, /*width = */ 0, "0x2a"},
+ {42, kHex | kBase | kPos, /*width = */ 6, "__0x2a"},
+ {42, kHex | kUpper, /*width = */ 0, "2A"},
+ {42, kHex | kUpper, /*width = */ 6, "____2A"},
+ {42, kHex | kUpper | kPos, /*width = */ 0, "2A"},
+ {42, kHex | kUpper | kPos, /*width = */ 6, "____2A"},
+ {42, kHex | kUpper | kBase, /*width = */ 0, "0X2A"},
+ {42, kHex | kUpper | kBase, /*width = */ 6, "__0X2A"},
+ {42, kHex | kUpper | kBase | kPos, /*width = */ 0, "0X2A"},
+ {42, kHex | kUpper | kBase | kPos, /*width = */ 6, "__0X2A"},
+ {42, kHex | kLeft, /*width = */ 0, "2a"},
+ {42, kHex | kLeft, /*width = */ 6, "2a____"},
+ {42, kHex | kLeft | kPos, /*width = */ 0, "2a"},
+ {42, kHex | kLeft | kPos, /*width = */ 6, "2a____"},
+ {42, kHex | kLeft | kBase, /*width = */ 0, "0x2a"},
+ {42, kHex | kLeft | kBase, /*width = */ 6, "0x2a__"},
+ {42, kHex | kLeft | kBase | kPos, /*width = */ 0, "0x2a"},
+ {42, kHex | kLeft | kBase | kPos, /*width = */ 6, "0x2a__"},
+ {42, kHex | kLeft | kUpper, /*width = */ 0, "2A"},
+ {42, kHex | kLeft | kUpper, /*width = */ 6, "2A____"},
+ {42, kHex | kLeft | kUpper | kPos, /*width = */ 0, "2A"},
+ {42, kHex | kLeft | kUpper | kPos, /*width = */ 6, "2A____"},
+ {42, kHex | kLeft | kUpper | kBase, /*width = */ 0, "0X2A"},
+ {42, kHex | kLeft | kUpper | kBase, /*width = */ 6, "0X2A__"},
+ {42, kHex | kLeft | kUpper | kBase | kPos, /*width = */ 0, "0X2A"},
+ {42, kHex | kLeft | kUpper | kBase | kPos, /*width = */ 6, "0X2A__"},
+ {42, kHex | kInt, /*width = */ 0, "2a"},
+ {42, kHex | kInt, /*width = */ 6, "____2a"},
+ {42, kHex | kInt | kPos, /*width = */ 0, "2a"},
+ {42, kHex | kInt | kPos, /*width = */ 6, "____2a"},
+ {42, kHex | kInt | kBase, /*width = */ 0, "0x2a"},
+ {42, kHex | kInt | kBase, /*width = */ 6, "0x__2a"},
+ {42, kHex | kInt | kBase | kPos, /*width = */ 0, "0x2a"},
+ {42, kHex | kInt | kBase | kPos, /*width = */ 6, "0x__2a"},
+ {42, kHex | kInt | kUpper, /*width = */ 0, "2A"},
+ {42, kHex | kInt | kUpper, /*width = */ 6, "____2A"},
+ {42, kHex | kInt | kUpper | kPos, /*width = */ 0, "2A"},
+ {42, kHex | kInt | kUpper | kPos, /*width = */ 6, "____2A"},
+ {42, kHex | kInt | kUpper | kBase, /*width = */ 0, "0X2A"},
+ {42, kHex | kInt | kUpper | kBase, /*width = */ 6, "0X__2A"},
+ {42, kHex | kInt | kUpper | kBase | kPos, /*width = */ 0, "0X2A"},
+ {42, kHex | kInt | kUpper | kBase | kPos, /*width = */ 6, "0X__2A"},
+ {42, kHex | kRight, /*width = */ 0, "2a"},
+ {42, kHex | kRight, /*width = */ 6, "____2a"},
+ {42, kHex | kRight | kPos, /*width = */ 0, "2a"},
+ {42, kHex | kRight | kPos, /*width = */ 6, "____2a"},
+ {42, kHex | kRight | kBase, /*width = */ 0, "0x2a"},
+ {42, kHex | kRight | kBase, /*width = */ 6, "__0x2a"},
+ {42, kHex | kRight | kBase | kPos, /*width = */ 0, "0x2a"},
+ {42, kHex | kRight | kBase | kPos, /*width = */ 6, "__0x2a"},
+ {42, kHex | kRight | kUpper, /*width = */ 0, "2A"},
+ {42, kHex | kRight | kUpper, /*width = */ 6, "____2A"},
+ {42, kHex | kRight | kUpper | kPos, /*width = */ 0, "2A"},
+ {42, kHex | kRight | kUpper | kPos, /*width = */ 6, "____2A"},
+ {42, kHex | kRight | kUpper | kBase, /*width = */ 0, "0X2A"},
+ {42, kHex | kRight | kUpper | kBase, /*width = */ 6, "__0X2A"},
+ {42, kHex | kRight | kUpper | kBase | kPos, /*width = */ 0, "0X2A"},
+ {42, kHex | kRight | kUpper | kBase | kPos, /*width = */ 6, "__0X2A"},
+ {-321, std::ios_base::fmtflags(), /*width = */ 0, "-321"},
+ {-321, std::ios_base::fmtflags(), /*width = */ 6, "__-321"},
+ {-321, kPos, /*width = */ 0, "-321"},
+ {-321, kPos, /*width = */ 6, "__-321"},
+ {-321, kBase, /*width = */ 0, "-321"},
+ {-321, kBase, /*width = */ 6, "__-321"},
+ {-321, kBase | kPos, /*width = */ 0, "-321"},
+ {-321, kBase | kPos, /*width = */ 6, "__-321"},
+ {-321, kUpper, /*width = */ 0, "-321"},
+ {-321, kUpper, /*width = */ 6, "__-321"},
+ {-321, kUpper | kPos, /*width = */ 0, "-321"},
+ {-321, kUpper | kPos, /*width = */ 6, "__-321"},
+ {-321, kUpper | kBase, /*width = */ 0, "-321"},
+ {-321, kUpper | kBase, /*width = */ 6, "__-321"},
+ {-321, kUpper | kBase | kPos, /*width = */ 0, "-321"},
+ {-321, kUpper | kBase | kPos, /*width = */ 6, "__-321"},
+ {-321, kLeft, /*width = */ 0, "-321"},
+ {-321, kLeft, /*width = */ 6, "-321__"},
+ {-321, kLeft | kPos, /*width = */ 0, "-321"},
+ {-321, kLeft | kPos, /*width = */ 6, "-321__"},
+ {-321, kLeft | kBase, /*width = */ 0, "-321"},
+ {-321, kLeft | kBase, /*width = */ 6, "-321__"},
+ {-321, kLeft | kBase | kPos, /*width = */ 0, "-321"},
+ {-321, kLeft | kBase | kPos, /*width = */ 6, "-321__"},
+ {-321, kLeft | kUpper, /*width = */ 0, "-321"},
+ {-321, kLeft | kUpper, /*width = */ 6, "-321__"},
+ {-321, kLeft | kUpper | kPos, /*width = */ 0, "-321"},
+ {-321, kLeft | kUpper | kPos, /*width = */ 6, "-321__"},
+ {-321, kLeft | kUpper | kBase, /*width = */ 0, "-321"},
+ {-321, kLeft | kUpper | kBase, /*width = */ 6, "-321__"},
+ {-321, kLeft | kUpper | kBase | kPos, /*width = */ 0, "-321"},
+ {-321, kLeft | kUpper | kBase | kPos, /*width = */ 6, "-321__"},
+ {-321, kInt, /*width = */ 0, "-321"},
+ {-321, kInt, /*width = */ 6, "-__321"},
+ {-321, kInt | kPos, /*width = */ 0, "-321"},
+ {-321, kInt | kPos, /*width = */ 6, "-__321"},
+ {-321, kInt | kBase, /*width = */ 0, "-321"},
+ {-321, kInt | kBase, /*width = */ 6, "-__321"},
+ {-321, kInt | kBase | kPos, /*width = */ 0, "-321"},
+ {-321, kInt | kBase | kPos, /*width = */ 6, "-__321"},
+ {-321, kInt | kUpper, /*width = */ 0, "-321"},
+ {-321, kInt | kUpper, /*width = */ 6, "-__321"},
+ {-321, kInt | kUpper | kPos, /*width = */ 0, "-321"},
+ {-321, kInt | kUpper | kPos, /*width = */ 6, "-__321"},
+ {-321, kInt | kUpper | kBase, /*width = */ 0, "-321"},
+ {-321, kInt | kUpper | kBase, /*width = */ 6, "-__321"},
+ {-321, kInt | kUpper | kBase | kPos, /*width = */ 0, "-321"},
+ {-321, kInt | kUpper | kBase | kPos, /*width = */ 6, "-__321"},
+ {-321, kRight, /*width = */ 0, "-321"},
+ {-321, kRight, /*width = */ 6, "__-321"},
+ {-321, kRight | kPos, /*width = */ 0, "-321"},
+ {-321, kRight | kPos, /*width = */ 6, "__-321"},
+ {-321, kRight | kBase, /*width = */ 0, "-321"},
+ {-321, kRight | kBase, /*width = */ 6, "__-321"},
+ {-321, kRight | kBase | kPos, /*width = */ 0, "-321"},
+ {-321, kRight | kBase | kPos, /*width = */ 6, "__-321"},
+ {-321, kRight | kUpper, /*width = */ 0, "-321"},
+ {-321, kRight | kUpper, /*width = */ 6, "__-321"},
+ {-321, kRight | kUpper | kPos, /*width = */ 0, "-321"},
+ {-321, kRight | kUpper | kPos, /*width = */ 6, "__-321"},
+ {-321, kRight | kUpper | kBase, /*width = */ 0, "-321"},
+ {-321, kRight | kUpper | kBase, /*width = */ 6, "__-321"},
+ {-321, kRight | kUpper | kBase | kPos, /*width = */ 0, "-321"},
+ {-321, kRight | kUpper | kBase | kPos, /*width = */ 6, "__-321"},
+ {-321, kDec, /*width = */ 0, "-321"},
+ {-321, kDec, /*width = */ 6, "__-321"},
+ {-321, kDec | kPos, /*width = */ 0, "-321"},
+ {-321, kDec | kPos, /*width = */ 6, "__-321"},
+ {-321, kDec | kBase, /*width = */ 0, "-321"},
+ {-321, kDec | kBase, /*width = */ 6, "__-321"},
+ {-321, kDec | kBase | kPos, /*width = */ 0, "-321"},
+ {-321, kDec | kBase | kPos, /*width = */ 6, "__-321"},
+ {-321, kDec | kUpper, /*width = */ 0, "-321"},
+ {-321, kDec | kUpper, /*width = */ 6, "__-321"},
+ {-321, kDec | kUpper | kPos, /*width = */ 0, "-321"},
+ {-321, kDec | kUpper | kPos, /*width = */ 6, "__-321"},
+ {-321, kDec | kUpper | kBase, /*width = */ 0, "-321"},
+ {-321, kDec | kUpper | kBase, /*width = */ 6, "__-321"},
+ {-321, kDec | kUpper | kBase | kPos, /*width = */ 0, "-321"},
+ {-321, kDec | kUpper | kBase | kPos, /*width = */ 6, "__-321"},
+ {-321, kDec | kLeft, /*width = */ 0, "-321"},
+ {-321, kDec | kLeft, /*width = */ 6, "-321__"},
+ {-321, kDec | kLeft | kPos, /*width = */ 0, "-321"},
+ {-321, kDec | kLeft | kPos, /*width = */ 6, "-321__"},
+ {-321, kDec | kLeft | kBase, /*width = */ 0, "-321"},
+ {-321, kDec | kLeft | kBase, /*width = */ 6, "-321__"},
+ {-321, kDec | kLeft | kBase | kPos, /*width = */ 0, "-321"},
+ {-321, kDec | kLeft | kBase | kPos, /*width = */ 6, "-321__"},
+ {-321, kDec | kLeft | kUpper, /*width = */ 0, "-321"},
+ {-321, kDec | kLeft | kUpper, /*width = */ 6, "-321__"},
+ {-321, kDec | kLeft | kUpper | kPos, /*width = */ 0, "-321"},
+ {-321, kDec | kLeft | kUpper | kPos, /*width = */ 6, "-321__"},
+ {-321, kDec | kLeft | kUpper | kBase, /*width = */ 0, "-321"},
+ {-321, kDec | kLeft | kUpper | kBase, /*width = */ 6, "-321__"},
+ {-321, kDec | kLeft | kUpper | kBase | kPos, /*width = */ 0, "-321"},
+ {-321, kDec | kLeft | kUpper | kBase | kPos, /*width = */ 6, "-321__"},
+ {-321, kDec | kInt, /*width = */ 0, "-321"},
+ {-321, kDec | kInt, /*width = */ 6, "-__321"},
+ {-321, kDec | kInt | kPos, /*width = */ 0, "-321"},
+ {-321, kDec | kInt | kPos, /*width = */ 6, "-__321"},
+ {-321, kDec | kInt | kBase, /*width = */ 0, "-321"},
+ {-321, kDec | kInt | kBase, /*width = */ 6, "-__321"},
+ {-321, kDec | kInt | kBase | kPos, /*width = */ 0, "-321"},
+ {-321, kDec | kInt | kBase | kPos, /*width = */ 6, "-__321"},
+ {-321, kDec | kInt | kUpper, /*width = */ 0, "-321"},
+ {-321, kDec | kInt | kUpper, /*width = */ 6, "-__321"},
+ {-321, kDec | kInt | kUpper | kPos, /*width = */ 0, "-321"},
+ {-321, kDec | kInt | kUpper | kPos, /*width = */ 6, "-__321"},
+ {-321, kDec | kInt | kUpper | kBase, /*width = */ 0, "-321"},
+ {-321, kDec | kInt | kUpper | kBase, /*width = */ 6, "-__321"},
+ {-321, kDec | kInt | kUpper | kBase | kPos, /*width = */ 0, "-321"},
+ {-321, kDec | kInt | kUpper | kBase | kPos, /*width = */ 6, "-__321"},
+ {-321, kDec | kRight, /*width = */ 0, "-321"},
+ {-321, kDec | kRight, /*width = */ 6, "__-321"},
+ {-321, kDec | kRight | kPos, /*width = */ 0, "-321"},
+ {-321, kDec | kRight | kPos, /*width = */ 6, "__-321"},
+ {-321, kDec | kRight | kBase, /*width = */ 0, "-321"},
+ {-321, kDec | kRight | kBase, /*width = */ 6, "__-321"},
+ {-321, kDec | kRight | kBase | kPos, /*width = */ 0, "-321"},
+ {-321, kDec | kRight | kBase | kPos, /*width = */ 6, "__-321"},
+ {-321, kDec | kRight | kUpper, /*width = */ 0, "-321"},
+ {-321, kDec | kRight | kUpper, /*width = */ 6, "__-321"},
+ {-321, kDec | kRight | kUpper | kPos, /*width = */ 0, "-321"},
+ {-321, kDec | kRight | kUpper | kPos, /*width = */ 6, "__-321"},
+ {-321, kDec | kRight | kUpper | kBase, /*width = */ 0, "-321"},
+ {-321, kDec | kRight | kUpper | kBase, /*width = */ 6, "__-321"},
+ {-321, kDec | kRight | kUpper | kBase | kPos, /*width = */ 0, "-321"},
+ {-321, kDec | kRight | kUpper | kBase | kPos, /*width = */ 6, "__-321"}};
+}
+
std::vector<Uint128TestCase> GetUint128FormatCases() {
return {
{0, std::ios_base::fmtflags(), /*width = */ 0, "0"},
diff --git a/third_party/abseil/absl/numeric/int128_test.cc b/third_party/abseil/absl/numeric/int128_test.cc
index 5e1b5ec..bc86c71 100644
--- a/third_party/abseil/absl/numeric/int128_test.cc
+++ b/third_party/abseil/absl/numeric/int128_test.cc
@@ -479,4 +479,747 @@
}));
}
+
+TEST(Int128Uint128, ConversionTest) {
+ absl::int128 nonnegative_signed_values[] = {
+ 0,
+ 1,
+ 0xffeeddccbbaa9988,
+ absl::MakeInt128(0x7766554433221100, 0),
+ absl::MakeInt128(0x1234567890abcdef, 0xfedcba0987654321),
+ absl::Int128Max()};
+ for (absl::int128 value : nonnegative_signed_values) {
+ EXPECT_EQ(value, absl::int128(absl::uint128(value)));
+
+ absl::uint128 assigned_value;
+ assigned_value = value;
+ EXPECT_EQ(value, absl::int128(assigned_value));
+ }
+
+ absl::int128 negative_values[] = {
+ -1, -0x1234567890abcdef,
+ absl::MakeInt128(-0x5544332211ffeedd, 0),
+ -absl::MakeInt128(0x76543210fedcba98, 0xabcdef0123456789)};
+ for (absl::int128 value : negative_values) {
+ EXPECT_EQ(absl::uint128(-value), -absl::uint128(value));
+
+ absl::uint128 assigned_value;
+ assigned_value = value;
+ EXPECT_EQ(absl::uint128(-value), -assigned_value);
+ }
+}
+
+template <typename T>
+class Int128IntegerTraitsTest : public ::testing::Test {};
+
+TYPED_TEST_SUITE(Int128IntegerTraitsTest, IntegerTypes);
+
+TYPED_TEST(Int128IntegerTraitsTest, ConstructAssignTest) {
+ static_assert(std::is_constructible<absl::int128, TypeParam>::value,
+ "absl::int128 must be constructible from TypeParam");
+ static_assert(std::is_assignable<absl::int128&, TypeParam>::value,
+ "absl::int128 must be assignable from TypeParam");
+ static_assert(!std::is_assignable<TypeParam&, absl::int128>::value,
+ "TypeParam must not be assignable from absl::int128");
+}
+
+template <typename T>
+class Int128FloatTraitsTest : public ::testing::Test {};
+
+TYPED_TEST_SUITE(Int128FloatTraitsTest, FloatingPointTypes);
+
+TYPED_TEST(Int128FloatTraitsTest, ConstructAssignTest) {
+ static_assert(std::is_constructible<absl::int128, TypeParam>::value,
+ "absl::int128 must be constructible from TypeParam");
+ static_assert(!std::is_assignable<absl::int128&, TypeParam>::value,
+ "absl::int128 must not be assignable from TypeParam");
+ static_assert(!std::is_assignable<TypeParam&, absl::int128>::value,
+ "TypeParam must not be assignable from absl::int128");
+}
+
+#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(Int128, IntrinsicTypeTraitsTest) {
+ static_assert(std::is_constructible<absl::int128, __int128>::value,
+ "absl::int128 must be constructible from __int128");
+ static_assert(std::is_assignable<absl::int128&, __int128>::value,
+ "absl::int128 must be assignable from __int128");
+ static_assert(!std::is_assignable<__int128&, absl::int128>::value,
+ "__int128 must not be assignable from absl::int128");
+
+ static_assert(std::is_constructible<absl::int128, unsigned __int128>::value,
+ "absl::int128 must be constructible from unsigned __int128");
+ static_assert(!std::is_assignable<absl::int128&, unsigned __int128>::value,
+ "absl::int128 must be assignable from unsigned __int128");
+ static_assert(!std::is_assignable<unsigned __int128&, absl::int128>::value,
+ "unsigned __int128 must not be assignable from absl::int128");
+}
+#endif // ABSL_HAVE_INTRINSIC_INT128
+
+TEST(Int128, TrivialTraitsTest) {
+ static_assert(absl::is_trivially_default_constructible<absl::int128>::value,
+ "");
+ static_assert(absl::is_trivially_copy_constructible<absl::int128>::value, "");
+ static_assert(absl::is_trivially_copy_assignable<absl::int128>::value, "");
+ static_assert(std::is_trivially_destructible<absl::int128>::value, "");
+}
+
+TEST(Int128, BoolConversionTest) {
+ EXPECT_FALSE(absl::int128(0));
+ for (int i = 0; i < 64; ++i) {
+ EXPECT_TRUE(absl::MakeInt128(0, uint64_t{1} << i));
+ }
+ for (int i = 0; i < 63; ++i) {
+ EXPECT_TRUE(absl::MakeInt128(int64_t{1} << i, 0));
+ }
+ EXPECT_TRUE(absl::Int128Min());
+
+ EXPECT_EQ(absl::int128(1), absl::int128(true));
+ EXPECT_EQ(absl::int128(0), absl::int128(false));
+}
+
+template <typename T>
+class Int128IntegerConversionTest : public ::testing::Test {};
+
+TYPED_TEST_SUITE(Int128IntegerConversionTest, IntegerTypes);
+
+TYPED_TEST(Int128IntegerConversionTest, RoundTripTest) {
+ EXPECT_EQ(TypeParam{0}, static_cast<TypeParam>(absl::int128(0)));
+ EXPECT_EQ(std::numeric_limits<TypeParam>::min(),
+ static_cast<TypeParam>(
+ absl::int128(std::numeric_limits<TypeParam>::min())));
+ EXPECT_EQ(std::numeric_limits<TypeParam>::max(),
+ static_cast<TypeParam>(
+ absl::int128(std::numeric_limits<TypeParam>::max())));
+}
+
+template <typename T>
+class Int128FloatConversionTest : public ::testing::Test {};
+
+TYPED_TEST_SUITE(Int128FloatConversionTest, FloatingPointTypes);
+
+TYPED_TEST(Int128FloatConversionTest, ConstructAndCastTest) {
+ // Conversions where the floating point values should be exactly the same.
+ // 0x9f5b is a randomly chosen small value.
+ for (int i = 0; i < 110; ++i) { // 110 = 126 - #bits in 0x9f5b
+ SCOPED_TRACE(::testing::Message() << "i = " << i);
+
+ TypeParam float_value = std::ldexp(static_cast<TypeParam>(0x9f5b), i);
+ absl::int128 int_value = absl::int128(0x9f5b) << i;
+
+ EXPECT_EQ(float_value, static_cast<TypeParam>(int_value));
+ EXPECT_EQ(-float_value, static_cast<TypeParam>(-int_value));
+ EXPECT_EQ(int_value, absl::int128(float_value));
+ EXPECT_EQ(-int_value, absl::int128(-float_value));
+ }
+
+ // Round trip conversions with a small sample of randomly generated uint64_t
+ // values (less than int64_t max so that value * 2^64 fits into int128).
+ uint64_t values[] = {0x6d4492c24fb86199, 0x26ead65e4cb359b5,
+ 0x2c43407433ba3fd1, 0x3b574ec668df6b55,
+ 0x1c750e55a29f4f0f};
+ for (uint64_t value : values) {
+ for (int i = 0; i <= 64; ++i) {
+ SCOPED_TRACE(::testing::Message()
+ << "value = " << value << "; i = " << i);
+
+ TypeParam fvalue = std::ldexp(static_cast<TypeParam>(value), i);
+ EXPECT_DOUBLE_EQ(fvalue, static_cast<TypeParam>(absl::int128(fvalue)));
+ EXPECT_DOUBLE_EQ(-fvalue, static_cast<TypeParam>(-absl::int128(fvalue)));
+ EXPECT_DOUBLE_EQ(-fvalue, static_cast<TypeParam>(absl::int128(-fvalue)));
+ EXPECT_DOUBLE_EQ(fvalue, static_cast<TypeParam>(-absl::int128(-fvalue)));
+ }
+ }
+
+ // Round trip conversions with a small sample of random large positive values.
+ absl::int128 large_values[] = {
+ absl::MakeInt128(0x5b0640d96c7b3d9f, 0xb7a7189e51d18622),
+ absl::MakeInt128(0x34bed042c6f65270, 0x73b236570669a089),
+ absl::MakeInt128(0x43deba9e6da12724, 0xf7f0f83da686797d),
+ absl::MakeInt128(0x71e8d383be4e5589, 0x75c3f96fb00752b6)};
+ for (absl::int128 value : large_values) {
+ // Make value have as many significant bits as can be represented by
+ // the mantissa, also making sure the highest and lowest bit in the range
+ // are set.
+ value >>= (127 - std::numeric_limits<TypeParam>::digits);
+ value |= absl::int128(1) << (std::numeric_limits<TypeParam>::digits - 1);
+ value |= 1;
+ for (int i = 0; i < 127 - std::numeric_limits<TypeParam>::digits; ++i) {
+ absl::int128 int_value = value << i;
+ EXPECT_EQ(int_value,
+ static_cast<absl::int128>(static_cast<TypeParam>(int_value)));
+ EXPECT_EQ(-int_value,
+ static_cast<absl::int128>(static_cast<TypeParam>(-int_value)));
+ }
+ }
+
+ // Small sample of checks that rounding is toward zero
+ EXPECT_EQ(0, absl::int128(TypeParam(0.1)));
+ EXPECT_EQ(17, absl::int128(TypeParam(17.8)));
+ EXPECT_EQ(0, absl::int128(TypeParam(-0.8)));
+ EXPECT_EQ(-53, absl::int128(TypeParam(-53.1)));
+ EXPECT_EQ(0, absl::int128(TypeParam(0.5)));
+ EXPECT_EQ(0, absl::int128(TypeParam(-0.5)));
+ TypeParam just_lt_one = std::nexttoward(TypeParam(1), TypeParam(0));
+ EXPECT_EQ(0, absl::int128(just_lt_one));
+ TypeParam just_gt_minus_one = std::nexttoward(TypeParam(-1), TypeParam(0));
+ EXPECT_EQ(0, absl::int128(just_gt_minus_one));
+
+ // Check limits
+ EXPECT_DOUBLE_EQ(std::ldexp(static_cast<TypeParam>(1), 127),
+ static_cast<TypeParam>(absl::Int128Max()));
+ EXPECT_DOUBLE_EQ(-std::ldexp(static_cast<TypeParam>(1), 127),
+ static_cast<TypeParam>(absl::Int128Min()));
+}
+
+TEST(Int128, FactoryTest) {
+ EXPECT_EQ(absl::int128(-1), absl::MakeInt128(-1, -1));
+ EXPECT_EQ(absl::int128(-31), absl::MakeInt128(-1, -31));
+ EXPECT_EQ(absl::int128(std::numeric_limits<int64_t>::min()),
+ absl::MakeInt128(-1, std::numeric_limits<int64_t>::min()));
+ EXPECT_EQ(absl::int128(0), absl::MakeInt128(0, 0));
+ EXPECT_EQ(absl::int128(1), absl::MakeInt128(0, 1));
+ EXPECT_EQ(absl::int128(std::numeric_limits<int64_t>::max()),
+ absl::MakeInt128(0, std::numeric_limits<int64_t>::max()));
+}
+
+TEST(Int128, HighLowTest) {
+ struct HighLowPair {
+ int64_t high;
+ uint64_t low;
+ };
+ HighLowPair values[]{{0, 0}, {0, 1}, {1, 0}, {123, 456}, {-654, 321}};
+ for (const HighLowPair& pair : values) {
+ absl::int128 value = absl::MakeInt128(pair.high, pair.low);
+ EXPECT_EQ(pair.low, absl::Int128Low64(value));
+ EXPECT_EQ(pair.high, absl::Int128High64(value));
+ }
+}
+
+TEST(Int128, LimitsTest) {
+ EXPECT_EQ(absl::MakeInt128(0x7fffffffffffffff, 0xffffffffffffffff),
+ absl::Int128Max());
+ EXPECT_EQ(absl::Int128Max(), ~absl::Int128Min());
+}
+
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+TEST(Int128, IntrinsicConversionTest) {
+ __int128 intrinsic =
+ (static_cast<__int128>(0x3a5b76c209de76f6) << 64) + 0x1f25e1d63a2b46c5;
+ absl::int128 custom =
+ absl::MakeInt128(0x3a5b76c209de76f6, 0x1f25e1d63a2b46c5);
+
+ EXPECT_EQ(custom, absl::int128(intrinsic));
+ EXPECT_EQ(intrinsic, static_cast<__int128>(custom));
+}
+#endif // ABSL_HAVE_INTRINSIC_INT128
+
+TEST(Int128, ConstexprTest) {
+ constexpr absl::int128 zero = absl::int128();
+ constexpr absl::int128 one = 1;
+ constexpr absl::int128 minus_two = -2;
+ constexpr absl::int128 min = absl::Int128Min();
+ constexpr absl::int128 max = absl::Int128Max();
+ EXPECT_EQ(zero, absl::int128(0));
+ EXPECT_EQ(one, absl::int128(1));
+ EXPECT_EQ(minus_two, absl::MakeInt128(-1, -2));
+ EXPECT_GT(max, one);
+ EXPECT_LT(min, minus_two);
+}
+
+TEST(Int128, ComparisonTest) {
+ struct TestCase {
+ absl::int128 smaller;
+ absl::int128 larger;
+ };
+ TestCase cases[] = {
+ {absl::int128(0), absl::int128(123)},
+ {absl::MakeInt128(-12, 34), absl::MakeInt128(12, 34)},
+ {absl::MakeInt128(1, 1000), absl::MakeInt128(1000, 1)},
+ {absl::MakeInt128(-1000, 1000), absl::MakeInt128(-1, 1)},
+ };
+ for (const TestCase& pair : cases) {
+ SCOPED_TRACE(::testing::Message() << "pair.smaller = " << pair.smaller
+ << "; pair.larger = " << pair.larger);
+
+ EXPECT_TRUE(pair.smaller == pair.smaller); // NOLINT(readability/check)
+ EXPECT_TRUE(pair.larger == pair.larger); // NOLINT(readability/check)
+ EXPECT_FALSE(pair.smaller == pair.larger); // NOLINT(readability/check)
+
+ EXPECT_TRUE(pair.smaller != pair.larger); // NOLINT(readability/check)
+ EXPECT_FALSE(pair.smaller != pair.smaller); // NOLINT(readability/check)
+ EXPECT_FALSE(pair.larger != pair.larger); // NOLINT(readability/check)
+
+ EXPECT_TRUE(pair.smaller < pair.larger); // NOLINT(readability/check)
+ EXPECT_FALSE(pair.larger < pair.smaller); // NOLINT(readability/check)
+
+ EXPECT_TRUE(pair.larger > pair.smaller); // NOLINT(readability/check)
+ EXPECT_FALSE(pair.smaller > pair.larger); // NOLINT(readability/check)
+
+ EXPECT_TRUE(pair.smaller <= pair.larger); // NOLINT(readability/check)
+ EXPECT_FALSE(pair.larger <= pair.smaller); // NOLINT(readability/check)
+ EXPECT_TRUE(pair.smaller <= pair.smaller); // NOLINT(readability/check)
+ EXPECT_TRUE(pair.larger <= pair.larger); // NOLINT(readability/check)
+
+ EXPECT_TRUE(pair.larger >= pair.smaller); // NOLINT(readability/check)
+ EXPECT_FALSE(pair.smaller >= pair.larger); // NOLINT(readability/check)
+ EXPECT_TRUE(pair.smaller >= pair.smaller); // NOLINT(readability/check)
+ EXPECT_TRUE(pair.larger >= pair.larger); // NOLINT(readability/check)
+ }
+}
+
+TEST(Int128, UnaryNegationTest) {
+ int64_t values64[] = {0, 1, 12345, 0x4000000000000000,
+ std::numeric_limits<int64_t>::max()};
+ for (int64_t value : values64) {
+ SCOPED_TRACE(::testing::Message() << "value = " << value);
+
+ EXPECT_EQ(absl::int128(-value), -absl::int128(value));
+ EXPECT_EQ(absl::int128(value), -absl::int128(-value));
+ EXPECT_EQ(absl::MakeInt128(-value, 0), -absl::MakeInt128(value, 0));
+ EXPECT_EQ(absl::MakeInt128(value, 0), -absl::MakeInt128(-value, 0));
+ }
+}
+
+TEST(Int128, LogicalNotTest) {
+ EXPECT_TRUE(!absl::int128(0));
+ for (int i = 0; i < 64; ++i) {
+ EXPECT_FALSE(!absl::MakeInt128(0, uint64_t{1} << i));
+ }
+ for (int i = 0; i < 63; ++i) {
+ EXPECT_FALSE(!absl::MakeInt128(int64_t{1} << i, 0));
+ }
+}
+
+TEST(Int128, AdditionSubtractionTest) {
+ // 64 bit pairs that will not cause overflow / underflow. These test negative
+ // carry; positive carry must be checked separately.
+ std::pair<int64_t, int64_t> cases[]{
+ {0, 0}, // 0, 0
+ {0, 2945781290834}, // 0, +
+ {1908357619234, 0}, // +, 0
+ {0, -1204895918245}, // 0, -
+ {-2957928523560, 0}, // -, 0
+ {89023982312461, 98346012567134}, // +, +
+ {-63454234568239, -23456235230773}, // -, -
+ {98263457263502, -21428561935925}, // +, -
+ {-88235237438467, 15923659234573}, // -, +
+ };
+ for (const auto& pair : cases) {
+ SCOPED_TRACE(::testing::Message()
+ << "pair = {" << pair.first << ", " << pair.second << '}');
+
+ EXPECT_EQ(absl::int128(pair.first + pair.second),
+ absl::int128(pair.first) + absl::int128(pair.second));
+ EXPECT_EQ(absl::int128(pair.second + pair.first),
+ absl::int128(pair.second) += absl::int128(pair.first));
+
+ EXPECT_EQ(absl::int128(pair.first - pair.second),
+ absl::int128(pair.first) - absl::int128(pair.second));
+ EXPECT_EQ(absl::int128(pair.second - pair.first),
+ absl::int128(pair.second) -= absl::int128(pair.first));
+
+ EXPECT_EQ(
+ absl::MakeInt128(pair.second + pair.first, 0),
+ absl::MakeInt128(pair.second, 0) + absl::MakeInt128(pair.first, 0));
+ EXPECT_EQ(
+ absl::MakeInt128(pair.first + pair.second, 0),
+ absl::MakeInt128(pair.first, 0) += absl::MakeInt128(pair.second, 0));
+
+ EXPECT_EQ(
+ absl::MakeInt128(pair.second - pair.first, 0),
+ absl::MakeInt128(pair.second, 0) - absl::MakeInt128(pair.first, 0));
+ EXPECT_EQ(
+ absl::MakeInt128(pair.first - pair.second, 0),
+ absl::MakeInt128(pair.first, 0) -= absl::MakeInt128(pair.second, 0));
+ }
+
+ // check positive carry
+ EXPECT_EQ(absl::MakeInt128(31, 0),
+ absl::MakeInt128(20, 1) +
+ absl::MakeInt128(10, std::numeric_limits<uint64_t>::max()));
+}
+
+TEST(Int128, IncrementDecrementTest) {
+ absl::int128 value = 0;
+ EXPECT_EQ(0, value++);
+ EXPECT_EQ(1, value);
+ EXPECT_EQ(1, value--);
+ EXPECT_EQ(0, value);
+ EXPECT_EQ(-1, --value);
+ EXPECT_EQ(-1, value);
+ EXPECT_EQ(0, ++value);
+ EXPECT_EQ(0, value);
+}
+
+TEST(Int128, MultiplicationTest) {
+ // 1 bit x 1 bit, and negative combinations
+ for (int i = 0; i < 64; ++i) {
+ for (int j = 0; j < 127 - i; ++j) {
+ SCOPED_TRACE(::testing::Message() << "i = " << i << "; j = " << j);
+ absl::int128 a = absl::int128(1) << i;
+ absl::int128 b = absl::int128(1) << j;
+ absl::int128 c = absl::int128(1) << (i + j);
+
+ EXPECT_EQ(c, a * b);
+ EXPECT_EQ(-c, -a * b);
+ EXPECT_EQ(-c, a * -b);
+ EXPECT_EQ(c, -a * -b);
+
+ EXPECT_EQ(c, absl::int128(a) *= b);
+ EXPECT_EQ(-c, absl::int128(-a) *= b);
+ EXPECT_EQ(-c, absl::int128(a) *= -b);
+ EXPECT_EQ(c, absl::int128(-a) *= -b);
+ }
+ }
+
+ // Pairs of random values that will not overflow signed 64-bit multiplication
+ std::pair<int64_t, int64_t> small_values[] = {
+ {0x5e61, 0xf29f79ca14b4}, // +, +
+ {0x3e033b, -0x612c0ee549}, // +, -
+ {-0x052ce7e8, 0x7c728f0f}, // -, +
+ {-0x3af7054626, -0xfb1e1d}, // -, -
+ };
+ for (const std::pair<int64_t, int64_t>& pair : small_values) {
+ SCOPED_TRACE(::testing::Message()
+ << "pair = {" << pair.first << ", " << pair.second << '}');
+
+ EXPECT_EQ(absl::int128(pair.first * pair.second),
+ absl::int128(pair.first) * absl::int128(pair.second));
+ EXPECT_EQ(absl::int128(pair.first * pair.second),
+ absl::int128(pair.first) *= absl::int128(pair.second));
+
+ EXPECT_EQ(absl::MakeInt128(pair.first * pair.second, 0),
+ absl::MakeInt128(pair.first, 0) * absl::int128(pair.second));
+ EXPECT_EQ(absl::MakeInt128(pair.first * pair.second, 0),
+ absl::MakeInt128(pair.first, 0) *= absl::int128(pair.second));
+ }
+
+ // Pairs of positive random values that will not overflow 64-bit
+ // multiplication and can be left shifted by 32 without overflow
+ std::pair<int64_t, int64_t> small_values2[] = {
+ {0x1bb0a110, 0x31487671},
+ {0x4792784e, 0x28add7d7},
+ {0x7b66553a, 0x11dff8ef},
+ };
+ for (const std::pair<int64_t, int64_t>& pair : small_values2) {
+ SCOPED_TRACE(::testing::Message()
+ << "pair = {" << pair.first << ", " << pair.second << '}');
+
+ absl::int128 a = absl::int128(pair.first << 32);
+ absl::int128 b = absl::int128(pair.second << 32);
+ absl::int128 c = absl::MakeInt128(pair.first * pair.second, 0);
+
+ EXPECT_EQ(c, a * b);
+ EXPECT_EQ(-c, -a * b);
+ EXPECT_EQ(-c, a * -b);
+ EXPECT_EQ(c, -a * -b);
+
+ EXPECT_EQ(c, absl::int128(a) *= b);
+ EXPECT_EQ(-c, absl::int128(-a) *= b);
+ EXPECT_EQ(-c, absl::int128(a) *= -b);
+ EXPECT_EQ(c, absl::int128(-a) *= -b);
+ }
+
+ // check 0, 1, and -1 behavior with large values
+ absl::int128 large_values[] = {
+ {absl::MakeInt128(0xd66f061af02d0408, 0x727d2846cb475b53)},
+ {absl::MakeInt128(0x27b8d5ed6104452d, 0x03f8a33b0ee1df4f)},
+ {-absl::MakeInt128(0x621b6626b9e8d042, 0x27311ac99df00938)},
+ {-absl::MakeInt128(0x34e0656f1e95fb60, 0x4281cfd731257a47)},
+ };
+ for (absl::int128 value : large_values) {
+ EXPECT_EQ(0, 0 * value);
+ EXPECT_EQ(0, value * 0);
+ EXPECT_EQ(0, absl::int128(0) *= value);
+ EXPECT_EQ(0, value *= 0);
+
+ EXPECT_EQ(value, 1 * value);
+ EXPECT_EQ(value, value * 1);
+ EXPECT_EQ(value, absl::int128(1) *= value);
+ EXPECT_EQ(value, value *= 1);
+
+ EXPECT_EQ(-value, -1 * value);
+ EXPECT_EQ(-value, value * -1);
+ EXPECT_EQ(-value, absl::int128(-1) *= value);
+ EXPECT_EQ(-value, value *= -1);
+ }
+
+ // Manually calculated random large value cases
+ EXPECT_EQ(absl::MakeInt128(0xcd0efd3442219bb, 0xde47c05bcd9df6e1),
+ absl::MakeInt128(0x7c6448, 0x3bc4285c47a9d253) * 0x1a6037537b);
+ EXPECT_EQ(-absl::MakeInt128(0x1f8f149850b1e5e6, 0x1e50d6b52d272c3e),
+ -absl::MakeInt128(0x23, 0x2e68a513ca1b8859) * 0xe5a434cd14866e);
+ EXPECT_EQ(-absl::MakeInt128(0x55cae732029d1fce, 0xca6474b6423263e4),
+ 0xa9b98a8ddf66bc * -absl::MakeInt128(0x81, 0x672e58231e2469d7));
+ EXPECT_EQ(absl::MakeInt128(0x19c8b7620b507dc4, 0xfec042b71a5f29a4),
+ -0x3e39341147 * -absl::MakeInt128(0x6a14b2, 0x5ed34cca42327b3c));
+
+ EXPECT_EQ(absl::MakeInt128(0xcd0efd3442219bb, 0xde47c05bcd9df6e1),
+ absl::MakeInt128(0x7c6448, 0x3bc4285c47a9d253) *= 0x1a6037537b);
+ EXPECT_EQ(-absl::MakeInt128(0x1f8f149850b1e5e6, 0x1e50d6b52d272c3e),
+ -absl::MakeInt128(0x23, 0x2e68a513ca1b8859) *= 0xe5a434cd14866e);
+ EXPECT_EQ(-absl::MakeInt128(0x55cae732029d1fce, 0xca6474b6423263e4),
+ absl::int128(0xa9b98a8ddf66bc) *=
+ -absl::MakeInt128(0x81, 0x672e58231e2469d7));
+ EXPECT_EQ(absl::MakeInt128(0x19c8b7620b507dc4, 0xfec042b71a5f29a4),
+ absl::int128(-0x3e39341147) *=
+ -absl::MakeInt128(0x6a14b2, 0x5ed34cca42327b3c));
+}
+
+TEST(Int128, DivisionAndModuloTest) {
+ // Check against 64 bit division and modulo operators with a sample of
+ // randomly generated pairs.
+ std::pair<int64_t, int64_t> small_pairs[] = {
+ {0x15f2a64138, 0x67da05}, {0x5e56d194af43045f, 0xcf1543fb99},
+ {0x15e61ed052036a, -0xc8e6}, {0x88125a341e85, -0xd23fb77683},
+ {-0xc06e20, 0x5a}, {-0x4f100219aea3e85d, 0xdcc56cb4efe993},
+ {-0x168d629105, -0xa7}, {-0x7b44e92f03ab2375, -0x6516},
+ };
+ for (const std::pair<int64_t, int64_t>& pair : small_pairs) {
+ SCOPED_TRACE(::testing::Message()
+ << "pair = {" << pair.first << ", " << pair.second << '}');
+
+ absl::int128 dividend = pair.first;
+ absl::int128 divisor = pair.second;
+ int64_t quotient = pair.first / pair.second;
+ int64_t remainder = pair.first % pair.second;
+
+ EXPECT_EQ(quotient, dividend / divisor);
+ EXPECT_EQ(quotient, absl::int128(dividend) /= divisor);
+ EXPECT_EQ(remainder, dividend % divisor);
+ EXPECT_EQ(remainder, absl::int128(dividend) %= divisor);
+ }
+
+ // Test behavior with 0, 1, and -1 with a sample of randomly generated large
+ // values.
+ absl::int128 values[] = {
+ absl::MakeInt128(0x63d26ee688a962b2, 0x9e1411abda5c1d70),
+ absl::MakeInt128(0x152f385159d6f986, 0xbf8d48ef63da395d),
+ -absl::MakeInt128(0x3098d7567030038c, 0x14e7a8a098dc2164),
+ -absl::MakeInt128(0x49a037aca35c809f, 0xa6a87525480ef330),
+ };
+ for (absl::int128 value : values) {
+ SCOPED_TRACE(::testing::Message() << "value = " << value);
+
+ EXPECT_EQ(0, 0 / value);
+ EXPECT_EQ(0, absl::int128(0) /= value);
+ EXPECT_EQ(0, 0 % value);
+ EXPECT_EQ(0, absl::int128(0) %= value);
+
+ EXPECT_EQ(value, value / 1);
+ EXPECT_EQ(value, absl::int128(value) /= 1);
+ EXPECT_EQ(0, value % 1);
+ EXPECT_EQ(0, absl::int128(value) %= 1);
+
+ EXPECT_EQ(-value, value / -1);
+ EXPECT_EQ(-value, absl::int128(value) /= -1);
+ EXPECT_EQ(0, value % -1);
+ EXPECT_EQ(0, absl::int128(value) %= -1);
+ }
+
+ // Min and max values
+ EXPECT_EQ(0, absl::Int128Max() / absl::Int128Min());
+ EXPECT_EQ(absl::Int128Max(), absl::Int128Max() % absl::Int128Min());
+ EXPECT_EQ(-1, absl::Int128Min() / absl::Int128Max());
+ EXPECT_EQ(-1, absl::Int128Min() % absl::Int128Max());
+
+ // Power of two division and modulo of random large dividends
+ absl::int128 positive_values[] = {
+ absl::MakeInt128(0x21e1a1cc69574620, 0xe7ac447fab2fc869),
+ absl::MakeInt128(0x32c2ff3ab89e66e8, 0x03379a613fd1ce74),
+ absl::MakeInt128(0x6f32ca786184dcaf, 0x046f9c9ecb3a9ce1),
+ absl::MakeInt128(0x1aeb469dd990e0ee, 0xda2740f243cd37eb),
+ };
+ for (absl::int128 value : positive_values) {
+ for (int i = 0; i < 127; ++i) {
+ SCOPED_TRACE(::testing::Message()
+ << "value = " << value << "; i = " << i);
+ absl::int128 power_of_two = absl::int128(1) << i;
+
+ EXPECT_EQ(value >> i, value / power_of_two);
+ EXPECT_EQ(value >> i, absl::int128(value) /= power_of_two);
+ EXPECT_EQ(value & (power_of_two - 1), value % power_of_two);
+ EXPECT_EQ(value & (power_of_two - 1),
+ absl::int128(value) %= power_of_two);
+ }
+ }
+
+ // Manually calculated cases with random large dividends
+ struct DivisionModCase {
+ absl::int128 dividend;
+ absl::int128 divisor;
+ absl::int128 quotient;
+ absl::int128 remainder;
+ };
+ DivisionModCase manual_cases[] = {
+ {absl::MakeInt128(0x6ada48d489007966, 0x3c9c5c98150d5d69),
+ absl::MakeInt128(0x8bc308fb, 0x8cb9cc9a3b803344), 0xc3b87e08,
+ absl::MakeInt128(0x1b7db5e1, 0xd9eca34b7af04b49)},
+ {absl::MakeInt128(0xd6946511b5b, 0x4886c5c96546bf5f),
+ -absl::MakeInt128(0x263b, 0xfd516279efcfe2dc), -0x59cbabf0,
+ absl::MakeInt128(0x622, 0xf462909155651d1f)},
+ {-absl::MakeInt128(0x33db734f9e8d1399, 0x8447ac92482bca4d), 0x37495078240,
+ -absl::MakeInt128(0xf01f1, 0xbc0368bf9a77eae8), -0x21a508f404d},
+ {-absl::MakeInt128(0x13f837b409a07e7d, 0x7fc8e248a7d73560), -0x1b9f,
+ absl::MakeInt128(0xb9157556d724, 0xb14f635714d7563e), -0x1ade},
+ };
+ for (const DivisionModCase test_case : manual_cases) {
+ EXPECT_EQ(test_case.quotient, test_case.dividend / test_case.divisor);
+ EXPECT_EQ(test_case.quotient,
+ absl::int128(test_case.dividend) /= test_case.divisor);
+ EXPECT_EQ(test_case.remainder, test_case.dividend % test_case.divisor);
+ EXPECT_EQ(test_case.remainder,
+ absl::int128(test_case.dividend) %= test_case.divisor);
+ }
+}
+
+TEST(Int128, BitwiseLogicTest) {
+ EXPECT_EQ(absl::int128(-1), ~absl::int128(0));
+
+ absl::int128 values[]{
+ 0, -1, 0xde400bee05c3ff6b, absl::MakeInt128(0x7f32178dd81d634a, 0),
+ absl::MakeInt128(0xaf539057055613a9, 0x7d104d7d946c2e4d)};
+ for (absl::int128 value : values) {
+ EXPECT_EQ(value, ~~value);
+
+ EXPECT_EQ(value, value | value);
+ EXPECT_EQ(value, value & value);
+ EXPECT_EQ(0, value ^ value);
+
+ EXPECT_EQ(value, absl::int128(value) |= value);
+ EXPECT_EQ(value, absl::int128(value) &= value);
+ EXPECT_EQ(0, absl::int128(value) ^= value);
+
+ EXPECT_EQ(value, value | 0);
+ EXPECT_EQ(0, value & 0);
+ EXPECT_EQ(value, value ^ 0);
+
+ EXPECT_EQ(absl::int128(-1), value | absl::int128(-1));
+ EXPECT_EQ(value, value & absl::int128(-1));
+ EXPECT_EQ(~value, value ^ absl::int128(-1));
+ }
+
+ // small sample of randomly generated int64_t's
+ std::pair<int64_t, int64_t> pairs64[]{
+ {0x7f86797f5e991af4, 0x1ee30494fb007c97},
+ {0x0b278282bacf01af, 0x58780e0a57a49e86},
+ {0x059f266ccb93a666, 0x3d5b731bae9286f5},
+ {0x63c0c4820f12108c, 0x58166713c12e1c3a},
+ {0x381488bb2ed2a66e, 0x2220a3eb76a3698c},
+ {0x2a0a0dfb81e06f21, 0x4b60585927f5523c},
+ {0x555b1c3a03698537, 0x25478cd19d8e53cb},
+ {0x4750f6f27d779225, 0x16397553c6ff05fc},
+ };
+ for (const std::pair<int64_t, int64_t>& pair : pairs64) {
+ SCOPED_TRACE(::testing::Message()
+ << "pair = {" << pair.first << ", " << pair.second << '}');
+
+ EXPECT_EQ(absl::MakeInt128(~pair.first, ~pair.second),
+ ~absl::MakeInt128(pair.first, pair.second));
+
+ EXPECT_EQ(absl::int128(pair.first & pair.second),
+ absl::int128(pair.first) & absl::int128(pair.second));
+ EXPECT_EQ(absl::int128(pair.first | pair.second),
+ absl::int128(pair.first) | absl::int128(pair.second));
+ EXPECT_EQ(absl::int128(pair.first ^ pair.second),
+ absl::int128(pair.first) ^ absl::int128(pair.second));
+
+ EXPECT_EQ(absl::int128(pair.first & pair.second),
+ absl::int128(pair.first) &= absl::int128(pair.second));
+ EXPECT_EQ(absl::int128(pair.first | pair.second),
+ absl::int128(pair.first) |= absl::int128(pair.second));
+ EXPECT_EQ(absl::int128(pair.first ^ pair.second),
+ absl::int128(pair.first) ^= absl::int128(pair.second));
+
+ EXPECT_EQ(
+ absl::MakeInt128(pair.first & pair.second, 0),
+ absl::MakeInt128(pair.first, 0) & absl::MakeInt128(pair.second, 0));
+ EXPECT_EQ(
+ absl::MakeInt128(pair.first | pair.second, 0),
+ absl::MakeInt128(pair.first, 0) | absl::MakeInt128(pair.second, 0));
+ EXPECT_EQ(
+ absl::MakeInt128(pair.first ^ pair.second, 0),
+ absl::MakeInt128(pair.first, 0) ^ absl::MakeInt128(pair.second, 0));
+
+ EXPECT_EQ(
+ absl::MakeInt128(pair.first & pair.second, 0),
+ absl::MakeInt128(pair.first, 0) &= absl::MakeInt128(pair.second, 0));
+ EXPECT_EQ(
+ absl::MakeInt128(pair.first | pair.second, 0),
+ absl::MakeInt128(pair.first, 0) |= absl::MakeInt128(pair.second, 0));
+ EXPECT_EQ(
+ absl::MakeInt128(pair.first ^ pair.second, 0),
+ absl::MakeInt128(pair.first, 0) ^= absl::MakeInt128(pair.second, 0));
+ }
+}
+
+TEST(Int128, BitwiseShiftTest) {
+ for (int i = 0; i < 64; ++i) {
+ for (int j = 0; j <= i; ++j) {
+ // Left shift from j-th bit to i-th bit.
+ SCOPED_TRACE(::testing::Message() << "i = " << i << "; j = " << j);
+ EXPECT_EQ(uint64_t{1} << i, absl::int128(uint64_t{1} << j) << (i - j));
+ EXPECT_EQ(uint64_t{1} << i, absl::int128(uint64_t{1} << j) <<= (i - j));
+ }
+ }
+ for (int i = 0; i < 63; ++i) {
+ for (int j = 0; j < 64; ++j) {
+ // Left shift from j-th bit to (i + 64)-th bit.
+ SCOPED_TRACE(::testing::Message() << "i = " << i << "; j = " << j);
+ EXPECT_EQ(absl::MakeInt128(uint64_t{1} << i, 0),
+ absl::int128(uint64_t{1} << j) << (i + 64 - j));
+ EXPECT_EQ(absl::MakeInt128(uint64_t{1} << i, 0),
+ absl::int128(uint64_t{1} << j) <<= (i + 64 - j));
+ }
+ for (int j = 0; j <= i; ++j) {
+ // Left shift from (j + 64)-th bit to (i + 64)-th bit.
+ SCOPED_TRACE(::testing::Message() << "i = " << i << "; j = " << j);
+ EXPECT_EQ(absl::MakeInt128(uint64_t{1} << i, 0),
+ absl::MakeInt128(uint64_t{1} << j, 0) << (i - j));
+ EXPECT_EQ(absl::MakeInt128(uint64_t{1} << i, 0),
+ absl::MakeInt128(uint64_t{1} << j, 0) <<= (i - j));
+ }
+ }
+
+ for (int i = 0; i < 64; ++i) {
+ for (int j = i; j < 64; ++j) {
+ // Right shift from j-th bit to i-th bit.
+ SCOPED_TRACE(::testing::Message() << "i = " << i << "; j = " << j);
+ EXPECT_EQ(uint64_t{1} << i, absl::int128(uint64_t{1} << j) >> (j - i));
+ EXPECT_EQ(uint64_t{1} << i, absl::int128(uint64_t{1} << j) >>= (j - i));
+ }
+ for (int j = 0; j < 63; ++j) {
+ // Right shift from (j + 64)-th bit to i-th bit.
+ SCOPED_TRACE(::testing::Message() << "i = " << i << "; j = " << j);
+ EXPECT_EQ(uint64_t{1} << i,
+ absl::MakeInt128(uint64_t{1} << j, 0) >> (j + 64 - i));
+ EXPECT_EQ(uint64_t{1} << i,
+ absl::MakeInt128(uint64_t{1} << j, 0) >>= (j + 64 - i));
+ }
+ }
+ for (int i = 0; i < 63; ++i) {
+ for (int j = i; j < 63; ++j) {
+ // Right shift from (j + 64)-th bit to (i + 64)-th bit.
+ SCOPED_TRACE(::testing::Message() << "i = " << i << "; j = " << j);
+ EXPECT_EQ(absl::MakeInt128(uint64_t{1} << i, 0),
+ absl::MakeInt128(uint64_t{1} << j, 0) >> (j - i));
+ EXPECT_EQ(absl::MakeInt128(uint64_t{1} << i, 0),
+ absl::MakeInt128(uint64_t{1} << j, 0) >>= (j - i));
+ }
+ }
+}
+
+TEST(Int128, NumericLimitsTest) {
+ static_assert(std::numeric_limits<absl::int128>::is_specialized, "");
+ static_assert(std::numeric_limits<absl::int128>::is_signed, "");
+ static_assert(std::numeric_limits<absl::int128>::is_integer, "");
+ EXPECT_EQ(static_cast<int>(127 * std::log10(2)),
+ std::numeric_limits<absl::int128>::digits10);
+ EXPECT_EQ(absl::Int128Min(), std::numeric_limits<absl::int128>::min());
+ EXPECT_EQ(absl::Int128Min(), std::numeric_limits<absl::int128>::lowest());
+ EXPECT_EQ(absl::Int128Max(), std::numeric_limits<absl::int128>::max());
+}
+
} // namespace
diff --git a/third_party/abseil/absl/numeric/internal/bits.h b/third_party/abseil/absl/numeric/internal/bits.h
new file mode 100644
index 0000000..af45700
--- /dev/null
+++ b/third_party/abseil/absl/numeric/internal/bits.h
@@ -0,0 +1,349 @@
+// Copyright 2020 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_NUMERIC_INTERNAL_BITS_H_
+#define ABSL_NUMERIC_INTERNAL_BITS_H_
+
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+
+// Clang on Windows has __builtin_clzll; otherwise we need to use the
+// windows intrinsic functions.
+#if defined(_MSC_VER) && !defined(__clang__)
+#include <intrin.h>
+#endif
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+
+#if ABSL_HAVE_BUILTIN(__builtin_popcountl) && \
+ ABSL_HAVE_BUILTIN(__builtin_popcountll)
+#define ABSL_INTERNAL_CONSTEXPR_POPCOUNT constexpr
+#define ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT 1
+#else
+#define ABSL_INTERNAL_CONSTEXPR_POPCOUNT
+#define ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT 0
+#endif
+
+#if ABSL_HAVE_BUILTIN(__builtin_clz) && ABSL_HAVE_BUILTIN(__builtin_clzll)
+#define ABSL_INTERNAL_CONSTEXPR_CLZ constexpr
+#define ABSL_INTERNAL_HAS_CONSTEXPR_CLZ 1
+#else
+#define ABSL_INTERNAL_CONSTEXPR_CLZ
+#define ABSL_INTERNAL_HAS_CONSTEXPR_CLZ 0
+#endif
+
+#if ABSL_HAVE_BUILTIN(__builtin_ctz) && ABSL_HAVE_BUILTIN(__builtin_ctzll)
+#define ABSL_INTERNAL_CONSTEXPR_CTZ constexpr
+#define ABSL_INTERNAL_HAS_CONSTEXPR_CTZ 1
+#else
+#define ABSL_INTERNAL_CONSTEXPR_CTZ
+#define ABSL_INTERNAL_HAS_CONSTEXPR_CTZ 0
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace numeric_internal {
+
+constexpr bool IsPowerOf2(unsigned int x) noexcept {
+ return x != 0 && (x & (x - 1)) == 0;
+}
+
+template <class T>
+ABSL_MUST_USE_RESULT ABSL_ATTRIBUTE_ALWAYS_INLINE constexpr T RotateRight(
+ T x, int s) noexcept {
+ static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+ static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
+ "T must have a power-of-2 size");
+
+ return static_cast<T>(x >> (s & (std::numeric_limits<T>::digits - 1))) |
+ static_cast<T>(x << ((-s) & (std::numeric_limits<T>::digits - 1)));
+}
+
+template <class T>
+ABSL_MUST_USE_RESULT ABSL_ATTRIBUTE_ALWAYS_INLINE constexpr T RotateLeft(
+ T x, int s) noexcept {
+ static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+ static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
+ "T must have a power-of-2 size");
+
+ return static_cast<T>(x << (s & (std::numeric_limits<T>::digits - 1))) |
+ static_cast<T>(x >> ((-s) & (std::numeric_limits<T>::digits - 1)));
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline int
+Popcount32(uint32_t x) noexcept {
+#if ABSL_HAVE_BUILTIN(__builtin_popcount)
+ static_assert(sizeof(unsigned int) == sizeof(x),
+ "__builtin_popcount does not take 32-bit arg");
+ return __builtin_popcount(x);
+#else
+ x -= ((x >> 1) & 0x55555555);
+ x = ((x >> 2) & 0x33333333) + (x & 0x33333333);
+ return static_cast<int>((((x + (x >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24);
+#endif
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline int
+Popcount64(uint64_t x) noexcept {
+#if ABSL_HAVE_BUILTIN(__builtin_popcountll)
+ static_assert(sizeof(unsigned long long) == sizeof(x), // NOLINT(runtime/int)
+ "__builtin_popcount does not take 64-bit arg");
+ return __builtin_popcountll(x);
+#else
+ x -= (x >> 1) & 0x5555555555555555ULL;
+ x = ((x >> 2) & 0x3333333333333333ULL) + (x & 0x3333333333333333ULL);
+ return static_cast<int>(
+ (((x + (x >> 4)) & 0xF0F0F0F0F0F0F0FULL) * 0x101010101010101ULL) >> 56);
+#endif
+}
+
+template <class T>
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline int
+Popcount(T x) noexcept {
+ static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+ static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
+ "T must have a power-of-2 size");
+ static_assert(sizeof(x) <= sizeof(uint64_t), "T is too large");
+ return sizeof(x) <= sizeof(uint32_t) ? Popcount32(x) : Popcount64(x);
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int
+CountLeadingZeroes32(uint32_t x) {
+#if ABSL_HAVE_BUILTIN(__builtin_clz)
+ // Use __builtin_clz, which uses the following instructions:
+ // x86: bsr, lzcnt
+ // ARM64: clz
+ // PPC: cntlzd
+
+ static_assert(sizeof(unsigned int) == sizeof(x),
+ "__builtin_clz does not take 32-bit arg");
+ // Handle 0 as a special case because __builtin_clz(0) is undefined.
+ return x == 0 ? 32 : __builtin_clz(x);
+#elif defined(_MSC_VER) && !defined(__clang__)
+ unsigned long result = 0; // NOLINT(runtime/int)
+ if (_BitScanReverse(&result, x)) {
+ return 31 - result;
+ }
+ return 32;
+#else
+ int zeroes = 28;
+ if (x >> 16) {
+ zeroes -= 16;
+ x >>= 16;
+ }
+ if (x >> 8) {
+ zeroes -= 8;
+ x >>= 8;
+ }
+ if (x >> 4) {
+ zeroes -= 4;
+ x >>= 4;
+ }
+ return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[x] + zeroes;
+#endif
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int
+CountLeadingZeroes16(uint16_t x) {
+#if ABSL_HAVE_BUILTIN(__builtin_clzs)
+ static_assert(sizeof(unsigned short) == sizeof(x), // NOLINT(runtime/int)
+ "__builtin_clzs does not take 16-bit arg");
+ return x == 0 ? 16 : __builtin_clzs(x);
+#else
+ return CountLeadingZeroes32(x) - 16;
+#endif
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int
+CountLeadingZeroes64(uint64_t x) {
+#if ABSL_HAVE_BUILTIN(__builtin_clzll)
+ // Use __builtin_clzll, which uses the following instructions:
+ // x86: bsr, lzcnt
+ // ARM64: clz
+ // PPC: cntlzd
+ static_assert(sizeof(unsigned long long) == sizeof(x), // NOLINT(runtime/int)
+ "__builtin_clzll does not take 64-bit arg");
+
+ // Handle 0 as a special case because __builtin_clzll(0) is undefined.
+ return x == 0 ? 64 : __builtin_clzll(x);
+#elif defined(_MSC_VER) && !defined(__clang__) && \
+ (defined(_M_X64) || defined(_M_ARM64))
+ // MSVC does not have __buitin_clzll. Use _BitScanReverse64.
+ unsigned long result = 0; // NOLINT(runtime/int)
+ if (_BitScanReverse64(&result, x)) {
+ return 63 - result;
+ }
+ return 64;
+#elif defined(_MSC_VER) && !defined(__clang__)
+ // MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse
+ unsigned long result = 0; // NOLINT(runtime/int)
+ if ((x >> 32) &&
+ _BitScanReverse(&result, static_cast<unsigned long>(x >> 32))) {
+ return 31 - result;
+ }
+ if (_BitScanReverse(&result, static_cast<unsigned long>(x))) {
+ return 63 - result;
+ }
+ return 64;
+#else
+ int zeroes = 60;
+ if (x >> 32) {
+ zeroes -= 32;
+ x >>= 32;
+ }
+ if (x >> 16) {
+ zeroes -= 16;
+ x >>= 16;
+ }
+ if (x >> 8) {
+ zeroes -= 8;
+ x >>= 8;
+ }
+ if (x >> 4) {
+ zeroes -= 4;
+ x >>= 4;
+ }
+ return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[x] + zeroes;
+#endif
+}
+
+template <typename T>
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int
+CountLeadingZeroes(T x) {
+ static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+ static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
+ "T must have a power-of-2 size");
+ static_assert(sizeof(T) <= sizeof(uint64_t), "T too large");
+ return sizeof(T) <= sizeof(uint16_t)
+ ? CountLeadingZeroes16(static_cast<uint16_t>(x)) -
+ (std::numeric_limits<uint16_t>::digits -
+ std::numeric_limits<T>::digits)
+ : (sizeof(T) <= sizeof(uint32_t)
+ ? CountLeadingZeroes32(static_cast<uint32_t>(x)) -
+ (std::numeric_limits<uint32_t>::digits -
+ std::numeric_limits<T>::digits)
+ : CountLeadingZeroes64(x));
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int
+CountTrailingZeroesNonzero32(uint32_t x) {
+#if ABSL_HAVE_BUILTIN(__builtin_ctz)
+ static_assert(sizeof(unsigned int) == sizeof(x),
+ "__builtin_ctz does not take 32-bit arg");
+ return __builtin_ctz(x);
+#elif defined(_MSC_VER) && !defined(__clang__)
+ unsigned long result = 0; // NOLINT(runtime/int)
+ _BitScanForward(&result, x);
+ return result;
+#else
+ int c = 31;
+ x &= ~x + 1;
+ if (x & 0x0000FFFF) c -= 16;
+ if (x & 0x00FF00FF) c -= 8;
+ if (x & 0x0F0F0F0F) c -= 4;
+ if (x & 0x33333333) c -= 2;
+ if (x & 0x55555555) c -= 1;
+ return c;
+#endif
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int
+CountTrailingZeroesNonzero64(uint64_t x) {
+#if ABSL_HAVE_BUILTIN(__builtin_ctzll)
+ static_assert(sizeof(unsigned long long) == sizeof(x), // NOLINT(runtime/int)
+ "__builtin_ctzll does not take 64-bit arg");
+ return __builtin_ctzll(x);
+#elif defined(_MSC_VER) && !defined(__clang__) && \
+ (defined(_M_X64) || defined(_M_ARM64))
+ unsigned long result = 0; // NOLINT(runtime/int)
+ _BitScanForward64(&result, x);
+ return result;
+#elif defined(_MSC_VER) && !defined(__clang__)
+ unsigned long result = 0; // NOLINT(runtime/int)
+ if (static_cast<uint32_t>(x) == 0) {
+ _BitScanForward(&result, static_cast<unsigned long>(x >> 32));
+ return result + 32;
+ }
+ _BitScanForward(&result, static_cast<unsigned long>(x));
+ return result;
+#else
+ int c = 63;
+ x &= ~x + 1;
+ if (x & 0x00000000FFFFFFFF) c -= 32;
+ if (x & 0x0000FFFF0000FFFF) c -= 16;
+ if (x & 0x00FF00FF00FF00FF) c -= 8;
+ if (x & 0x0F0F0F0F0F0F0F0F) c -= 4;
+ if (x & 0x3333333333333333) c -= 2;
+ if (x & 0x5555555555555555) c -= 1;
+ return c;
+#endif
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int
+CountTrailingZeroesNonzero16(uint16_t x) {
+#if ABSL_HAVE_BUILTIN(__builtin_ctzs)
+ static_assert(sizeof(unsigned short) == sizeof(x), // NOLINT(runtime/int)
+ "__builtin_ctzs does not take 16-bit arg");
+ return __builtin_ctzs(x);
+#else
+ return CountTrailingZeroesNonzero32(x);
+#endif
+}
+
+template <class T>
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int
+CountTrailingZeroes(T x) noexcept {
+ static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+ static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
+ "T must have a power-of-2 size");
+ static_assert(sizeof(T) <= sizeof(uint64_t), "T too large");
+ return x == 0 ? std::numeric_limits<T>::digits
+ : (sizeof(T) <= sizeof(uint16_t)
+ ? CountTrailingZeroesNonzero16(static_cast<uint16_t>(x))
+ : (sizeof(T) <= sizeof(uint32_t)
+ ? CountTrailingZeroesNonzero32(
+ static_cast<uint32_t>(x))
+ : CountTrailingZeroesNonzero64(x)));
+}
+
+// If T is narrower than unsigned, T{1} << bit_width will be promoted. We
+// want to force it to wraparound so that bit_ceil of an invalid value are not
+// core constant expressions.
+template <class T>
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline
+ typename std::enable_if<std::is_unsigned<T>::value, T>::type
+ BitCeilPromotionHelper(T x, T promotion) {
+ return (T{1} << (x + promotion)) >> promotion;
+}
+
+template <class T>
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline
+ typename std::enable_if<std::is_unsigned<T>::value, T>::type
+ BitCeilNonPowerOf2(T x) {
+ // If T is narrower than unsigned, it undergoes promotion to unsigned when we
+ // shift. We calcualte the number of bits added by the wider type.
+ return BitCeilPromotionHelper(
+ static_cast<T>(std::numeric_limits<T>::digits - CountLeadingZeroes(x)),
+ T{sizeof(T) >= sizeof(unsigned) ? 0
+ : std::numeric_limits<unsigned>::digits -
+ std::numeric_limits<T>::digits});
+}
+
+} // namespace numeric_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_NUMERIC_INTERNAL_BITS_H_
diff --git a/third_party/abseil/absl/random/BUILD.bazel b/third_party/abseil/absl/random/BUILD.bazel
index fc63797..d97b2c4 100644
--- a/third_party/abseil/absl/random/BUILD.bazel
+++ b/third_party/abseil/absl/random/BUILD.bazel
@@ -16,7 +16,7 @@
# ABSL random-number generation libraries.
-#load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
+load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
load(
"//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
@@ -26,7 +26,7 @@
package(default_visibility = ["//visibility:public"])
-licenses(["notice"]) # Apache 2.0
+licenses(["notice"])
cc_library(
name = "random",
@@ -53,7 +53,6 @@
"bernoulli_distribution.h",
"beta_distribution.h",
"discrete_distribution.h",
- "distribution_format_traits.h",
"distributions.h",
"exponential_distribution.h",
"gaussian_distribution.h",
@@ -67,17 +66,19 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/base:base_internal",
+ "//absl/base:config",
"//absl/base:core_headers",
"//absl/meta:type_traits",
- "//absl/random/internal:distribution_impl",
- "//absl/random/internal:distributions",
+ "//absl/numeric:bits",
+ "//absl/random/internal:distribution_caller",
"//absl/random/internal:fast_uniform_bits",
"//absl/random/internal:fastmath",
+ "//absl/random/internal:generate_real",
"//absl/random/internal:iostream_state_saver",
"//absl/random/internal:traits",
"//absl/random/internal:uniform_helper",
+ "//absl/random/internal:wide_multiply",
"//absl/strings",
- "//absl/types:span",
],
)
@@ -109,6 +110,56 @@
],
)
+cc_library(
+ name = "bit_gen_ref",
+ hdrs = ["bit_gen_ref.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":random",
+ "//absl/base:core_headers",
+ "//absl/base:fast_type_id",
+ "//absl/meta:type_traits",
+ "//absl/random/internal:distribution_caller",
+ "//absl/random/internal:fast_uniform_bits",
+ ],
+)
+
+cc_library(
+ name = "mock_distributions",
+ testonly = 1,
+ hdrs = ["mock_distributions.h"],
+ deps = [
+ ":distributions",
+ ":mocking_bit_gen",
+ "//absl/meta:type_traits",
+ "//absl/random/internal:mock_overload_set",
+ "@com_google_googletest//:gtest",
+ ],
+)
+
+cc_library(
+ name = "mocking_bit_gen",
+ testonly = 1,
+ hdrs = [
+ "mocking_bit_gen.h",
+ ],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":distributions",
+ ":random",
+ "//absl/base:fast_type_id",
+ "//absl/container:flat_hash_map",
+ "//absl/meta:type_traits",
+ "//absl/random/internal:distribution_caller",
+ "//absl/strings",
+ "//absl/types:span",
+ "//absl/types:variant",
+ "//absl/utility",
+ "@com_google_googletest//:gtest",
+ ],
+)
+
cc_test(
name = "bernoulli_distribution_test",
size = "small",
@@ -119,6 +170,7 @@
deps = [
":distributions",
":random",
+ "//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"@com_google_googletest//:gtest_main",
],
@@ -130,12 +182,14 @@
timeout = "eternal", # Android can take a very long time
srcs = ["beta_distribution_test.cc"],
copts = ABSL_TEST_COPTS,
+ flaky = 1,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":distributions",
":random",
"//absl/base:raw_logging_internal",
"//absl/random/internal:distribution_test_util",
+ "//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"//absl/strings",
"//absl/strings:str_format",
@@ -146,6 +200,7 @@
cc_test(
name = "distributions_test",
size = "small",
+ timeout = "moderate",
srcs = [
"distributions_test.cc",
],
@@ -183,9 +238,9 @@
deps = [
":distributions",
":random",
- "//absl/base:core_headers",
"//absl/base:raw_logging_internal",
"//absl/random/internal:distribution_test_util",
+ "//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"//absl/strings",
"//absl/strings:str_format",
@@ -206,6 +261,7 @@
":random",
"//absl/base:raw_logging_internal",
"//absl/random/internal:distribution_test_util",
+ "//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"//absl/strings",
"@com_google_googletest//:gtest_main",
@@ -233,6 +289,7 @@
"//absl/base:raw_logging_internal",
"//absl/container:flat_hash_map",
"//absl/random/internal:distribution_test_util",
+ "//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"//absl/strings",
"//absl/strings:str_format",
@@ -252,6 +309,7 @@
"//absl/base:core_headers",
"//absl/base:raw_logging_internal",
"//absl/random/internal:distribution_test_util",
+ "//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"//absl/strings",
"//absl/strings:str_format",
@@ -295,6 +353,7 @@
":random",
"//absl/base:raw_logging_internal",
"//absl/random/internal:distribution_test_util",
+ "//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"//absl/strings",
"@com_google_googletest//:gtest_main",
@@ -319,6 +378,7 @@
":random",
"//absl/base:raw_logging_internal",
"//absl/random/internal:distribution_test_util",
+ "//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"//absl/strings",
"@com_google_googletest//:gtest_main",
@@ -338,6 +398,7 @@
":random",
"//absl/base:raw_logging_internal",
"//absl/random/internal:distribution_test_util",
+ "//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"//absl/strings",
"@com_google_googletest//:gtest_main",
@@ -345,6 +406,50 @@
)
cc_test(
+ name = "bit_gen_ref_test",
+ size = "small",
+ srcs = ["bit_gen_ref_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":bit_gen_ref",
+ ":random",
+ "//absl/base:fast_type_id",
+ "//absl/random/internal:sequence_urbg",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "mocking_bit_gen_test",
+ size = "small",
+ srcs = ["mocking_bit_gen_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":bit_gen_ref",
+ ":mock_distributions",
+ ":mocking_bit_gen",
+ ":random",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "mock_distributions_test",
+ size = "small",
+ srcs = ["mock_distributions_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":mock_distributions",
+ ":mocking_bit_gen",
+ ":random",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
name = "examples_test",
size = "small",
srcs = ["examples_test.cc"],
diff --git a/third_party/abseil/absl/random/CMakeLists.txt b/third_party/abseil/absl/random/CMakeLists.txt
index 151cefa..7d7bec8 100644
--- a/third_party/abseil/absl/random/CMakeLists.txt
+++ b/third_party/abseil/absl/random/CMakeLists.txt
@@ -34,6 +34,131 @@
absl_cc_library(
NAME
+ random_bit_gen_ref
+ HDRS
+ "bit_gen_ref.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::core_headers
+ absl::random_internal_distribution_caller
+ absl::random_internal_fast_uniform_bits
+ absl::type_traits
+)
+
+absl_cc_test(
+ NAME
+ random_bit_gen_ref_test
+ SRCS
+ "bit_gen_ref_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_bit_gen_ref
+ absl::random_random
+ absl::random_internal_sequence_urbg
+ absl::fast_type_id
+ gmock
+ gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_mock_helpers
+ HDRS
+ "internal/mock_helpers.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::fast_type_id
+ absl::optional
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_mock_overload_set
+ HDRS
+ "internal/mock_overload_set.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_mocking_bit_gen
+ absl::random_internal_mock_helpers
+ TESTONLY
+)
+
+absl_cc_library(
+ NAME
+ random_mocking_bit_gen
+ HDRS
+ "mock_distributions.h"
+ "mocking_bit_gen.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::flat_hash_map
+ absl::raw_logging_internal
+ absl::random_distributions
+ absl::random_internal_distribution_caller
+ absl::random_internal_mock_overload_set
+ absl::random_random
+ absl::strings
+ absl::span
+ absl::type_traits
+ absl::utility
+ absl::variant
+ gmock
+ gtest
+ TESTONLY
+)
+
+absl_cc_test(
+ NAME
+ random_mock_distributions_test
+ SRCS
+ "mock_distributions_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_mocking_bit_gen
+ absl::random_random
+ gmock
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ random_mocking_bit_gen_test
+ SRCS
+ "mocking_bit_gen_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_bit_gen_ref
+ absl::random_mocking_bit_gen
+ absl::random_random
+ gmock
+ gtest_main
+)
+
+absl_cc_library(
+ NAME
random_distributions
SRCS
"discrete_distribution.cc"
@@ -42,7 +167,6 @@
"bernoulli_distribution.h"
"beta_distribution.h"
"discrete_distribution.h"
- "distribution_format_traits.h"
"distributions.h"
"exponential_distribution.h"
"gaussian_distribution.h"
@@ -57,16 +181,17 @@
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::base_internal
+ absl::config
absl::core_headers
- absl::random_internal_distribution_impl
- absl::random_internal_distributions
+ absl::random_internal_generate_real
+ absl::random_internal_distribution_caller
absl::random_internal_fast_uniform_bits
absl::random_internal_fastmath
absl::random_internal_iostream_state_saver
absl::random_internal_traits
absl::random_internal_uniform_helper
+ absl::random_internal_wide_multiply
absl::strings
- absl::span
absl::type_traits
)
@@ -119,6 +244,7 @@
absl::random_distributions
absl::random_random
absl::random_internal_sequence_urbg
+ absl::random_internal_pcg_engine
gmock
gtest_main
)
@@ -137,6 +263,7 @@
absl::random_random
absl::random_internal_distribution_test_util
absl::random_internal_sequence_urbg
+ absl::random_internal_pcg_engine
absl::raw_logging_internal
absl::strings
absl::str_format
@@ -186,9 +313,9 @@
${ABSL_TEST_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
- absl::core_headers
absl::random_distributions
absl::random_internal_distribution_test_util
+ absl::random_internal_pcg_engine
absl::random_internal_sequence_urbg
absl::random_random
absl::raw_logging_internal
@@ -210,6 +337,7 @@
DEPS
absl::random_distributions
absl::random_internal_distribution_test_util
+ absl::random_internal_pcg_engine
absl::random_internal_sequence_urbg
absl::random_random
absl::raw_logging_internal
@@ -233,6 +361,7 @@
absl::core_headers
absl::flat_hash_map
absl::random_internal_distribution_test_util
+ absl::random_internal_pcg_engine
absl::random_internal_sequence_urbg
absl::raw_logging_internal
absl::strings
@@ -254,6 +383,7 @@
absl::core_headers
absl::random_distributions
absl::random_internal_distribution_test_util
+ absl::random_internal_pcg_engine
absl::random_internal_sequence_urbg
absl::random_random
absl::raw_logging_internal
@@ -297,6 +427,7 @@
DEPS
absl::random_distributions
absl::random_internal_distribution_test_util
+ absl::random_internal_pcg_engine
absl::random_internal_sequence_urbg
absl::random_random
absl::raw_logging_internal
@@ -317,6 +448,7 @@
DEPS
absl::random_distributions
absl::random_internal_distribution_test_util
+ absl::random_internal_pcg_engine
absl::random_internal_sequence_urbg
absl::random_random
absl::strings
@@ -336,6 +468,7 @@
DEPS
absl::random_distributions
absl::random_internal_distribution_test_util
+ absl::random_internal_pcg_engine
absl::random_internal_sequence_urbg
absl::random_random
absl::raw_logging_internal
@@ -399,27 +532,10 @@
${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
-)
-
-# Internal-only target, do not depend on directly.
-absl_cc_library(
- NAME
- random_internal_distributions
- HDRS
- "internal/distributions.h"
- COPTS
- ${ABSL_DEFAULT_COPTS}
- LINKOPTS
- ${ABSL_DEFAULT_LINKOPTS}
DEPS
- absl::random_internal_distribution_caller
- absl::random_internal_fast_uniform_bits
- absl::random_internal_fastmath
- absl::random_internal_traits
- absl::random_internal_uniform_helper
- absl::span
- absl::strings
- absl::type_traits
+ absl::config
+ absl::utility
+ absl::fast_type_id
)
# Internal-only target, do not depend on directly.
@@ -432,6 +548,8 @@
${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::config
)
# Internal-only target, do not depend on directly.
@@ -446,6 +564,7 @@
${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
+ $<$<BOOL:${MINGW}>:"bcrypt">
DEPS
absl::core_headers
absl::optional
@@ -490,6 +609,8 @@
${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::config
TESTONLY
)
@@ -503,6 +624,8 @@
${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::config
TESTONLY
)
@@ -542,9 +665,26 @@
# Internal-only target, do not depend on directly.
absl_cc_library(
NAME
- random_internal_distribution_impl
+ random_internal_generate_real
HDRS
- "internal/distribution_impl.h"
+ "internal/generate_real.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::bits
+ absl::random_internal_fastmath
+ absl::random_internal_traits
+ absl::type_traits
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_wide_multiply
+ HDRS
+ "internal/wide_multiply.h"
COPTS
${ABSL_DEFAULT_COPTS}
LINKOPTS
@@ -553,8 +693,6 @@
absl::bits
absl::config
absl::int128
- absl::random_internal_fastmath
- absl::random_internal_traits
)
# Internal-only target, do not depend on directly.
@@ -588,7 +726,6 @@
absl::random_internal_salted_seed_seq
absl::random_internal_seed_material
absl::span
- absl::strings
absl::type_traits
)
@@ -633,12 +770,15 @@
random_internal_platform
HDRS
"internal/randen_traits.h"
- "internal/randen-keys.inc"
"internal/platform.h"
+ SRCS
+ "internal/randen_round_keys.cc"
COPTS
${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::config
)
# Internal-only target, do not depend on directly.
@@ -673,6 +813,7 @@
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::random_internal_platform
+ absl::config
)
# Internal-only target, do not depend on directly.
@@ -692,6 +833,7 @@
DEPS
absl::random_internal_platform
absl::random_internal_randen_hwaes_impl
+ absl::config
)
# Internal-only target, do not depend on directly.
@@ -708,6 +850,7 @@
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::random_internal_platform
+ absl::config
)
# Internal-only target, do not depend on directly.
@@ -725,6 +868,7 @@
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
+ absl::config
absl::core_headers
absl::raw_logging_internal
absl::strings
@@ -750,9 +894,9 @@
# Internal-only target, do not depend on directly.
absl_cc_test(
NAME
- random_internal_distribution_impl_test
+ random_internal_generate_real_test
SRCS
- "internal/distribution_impl_test.cc"
+ "internal/generate_real_test.cc"
COPTS
${ABSL_TEST_COPTS}
LINKOPTS
@@ -760,8 +904,7 @@
DEPS
absl::bits
absl::flags
- absl::int128
- absl::random_internal_distribution_impl
+ absl::random_internal_generate_real
gtest_main
)
@@ -1011,10 +1154,7 @@
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
- absl::core_headers
- absl::random_internal_distribution_impl
- absl::random_internal_fast_uniform_bits
- absl::random_internal_iostream_state_saver
+ absl::config
absl::random_internal_traits
absl::type_traits
)
@@ -1022,6 +1162,21 @@
# Internal-only target, do not depend on directly.
absl_cc_test(
NAME
+ random_internal_uniform_helper_test
+ SRCS
+ "internal/uniform_helper_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_internal_uniform_helper
+ gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_test(
+ NAME
random_internal_iostream_state_saver_test
SRCS
"internal/iostream_state_saver_test.cc"
@@ -1033,3 +1188,20 @@
absl::random_internal_iostream_state_saver
gtest_main
)
+
+# Internal-only target, do not depend on directly.
+absl_cc_test(
+ NAME
+ random_internal_wide_multiply_test
+ SRCS
+ internal/wide_multiply_test.cc
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_internal_wide_multiply
+ absl::bits
+ absl::int128
+ gtest_main
+)
diff --git a/third_party/abseil/absl/random/bernoulli_distribution.h b/third_party/abseil/absl/random/bernoulli_distribution.h
index 326fcb6..25bd0d5 100644
--- a/third_party/abseil/absl/random/bernoulli_distribution.h
+++ b/third_party/abseil/absl/random/bernoulli_distribution.h
@@ -24,6 +24,7 @@
#include "absl/random/internal/iostream_state_saver.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// absl::bernoulli_distribution is a drop in replacement for
// std::bernoulli_distribution. It guarantees that (given a perfect
@@ -193,6 +194,7 @@
}
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_BERNOULLI_DISTRIBUTION_H_
diff --git a/third_party/abseil/absl/random/bernoulli_distribution_test.cc b/third_party/abseil/absl/random/bernoulli_distribution_test.cc
index f2c3b99..b250f87 100644
--- a/third_party/abseil/absl/random/bernoulli_distribution_test.cc
+++ b/third_party/abseil/absl/random/bernoulli_distribution_test.cc
@@ -21,6 +21,7 @@
#include <utility>
#include "gtest/gtest.h"
+#include "absl/random/internal/pcg_engine.h"
#include "absl/random/internal/sequence_urbg.h"
#include "absl/random/random.h"
@@ -63,7 +64,10 @@
size_t trials = para.second;
double p = para.first;
- absl::InsecureBitGen rng;
+ // We use a fixed bit generator for distribution accuracy tests. This allows
+ // these tests to be deterministic, while still testing the qualify of the
+ // implementation.
+ absl::random_internal::pcg64_2018_engine rng(0x2B7E151628AED2A6);
size_t yes = 0;
absl::bernoulli_distribution dist(p);
@@ -131,7 +135,7 @@
0x275b0dc7e0a18acfull, 0x36cebe0d2653682eull, 0x0361e9b23861596bull,
});
- // Generate a std::string of '0' and '1' for the distribution output.
+ // Generate a string of '0' and '1' for the distribution output.
auto generate = [&urbg](absl::bernoulli_distribution& dist) {
std::string output;
output.reserve(36);
@@ -176,7 +180,7 @@
0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull});
- // Generate a std::string of '0' and '1' for the distribution output.
+ // Generate a string of '0' and '1' for the distribution output.
auto generate = [&urbg](absl::bernoulli_distribution& dist) {
std::string output;
output.reserve(13);
diff --git a/third_party/abseil/absl/random/beta_distribution.h b/third_party/abseil/absl/random/beta_distribution.h
index e29894f..c154066 100644
--- a/third_party/abseil/absl/random/beta_distribution.h
+++ b/third_party/abseil/absl/random/beta_distribution.h
@@ -22,12 +22,14 @@
#include <ostream>
#include <type_traits>
-#include "absl/random/internal/distribution_impl.h"
+#include "absl/meta/type_traits.h"
#include "absl/random/internal/fast_uniform_bits.h"
#include "absl/random/internal/fastmath.h"
+#include "absl/random/internal/generate_real.h"
#include "absl/random/internal/iostream_state_saver.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// absl::beta_distribution:
// Generate a floating-point variate conforming to a Beta distribution:
@@ -275,15 +277,21 @@
beta_distribution<RealType>::AlgorithmJoehnk(
URBG& g, // NOLINT(runtime/references)
const param_type& p) {
+ using random_internal::GeneratePositiveTag;
+ using random_internal::GenerateRealFromBits;
+ using real_type =
+ absl::conditional_t<std::is_same<RealType, float>::value, float, double>;
+
// Based on Joehnk, M. D. Erzeugung von betaverteilten und gammaverteilten
// Zufallszahlen. Metrika 8.1 (1964): 5-15.
// This method is described in Knuth, Vol 2 (Third Edition), pp 134.
- using RandU64ToReal = typename random_internal::RandU64ToReal<result_type>;
- using random_internal::PositiveValueT;
+
result_type u, v, x, y, z;
for (;;) {
- u = RandU64ToReal::template Value<PositiveValueT, false>(fast_u64_(g));
- v = RandU64ToReal::template Value<PositiveValueT, false>(fast_u64_(g));
+ u = GenerateRealFromBits<real_type, GeneratePositiveTag, false>(
+ fast_u64_(g));
+ v = GenerateRealFromBits<real_type, GeneratePositiveTag, false>(
+ fast_u64_(g));
// Direct method. std::pow is slow for float, so rely on the optimizer to
// remove the std::pow() path for that case.
@@ -327,12 +335,14 @@
beta_distribution<RealType>::AlgorithmCheng(
URBG& g, // NOLINT(runtime/references)
const param_type& p) {
+ using random_internal::GeneratePositiveTag;
+ using random_internal::GenerateRealFromBits;
+ using real_type =
+ absl::conditional_t<std::is_same<RealType, float>::value, float, double>;
+
// Based on Cheng, Russell CH. Generating beta variates with nonintegral
// shape parameters. Communications of the ACM 21.4 (1978): 317-322.
// (https://dl.acm.org/citation.cfm?id=359482).
- using RandU64ToReal = typename random_internal::RandU64ToReal<result_type>;
- using random_internal::PositiveValueT;
-
static constexpr result_type kLogFour =
result_type(1.3862943611198906188344642429163531361); // log(4)
static constexpr result_type kS =
@@ -341,8 +351,10 @@
const bool use_algorithm_ba = (p.method_ == param_type::CHENG_BA);
result_type u1, u2, v, w, z, r, s, t, bw_inv, lhs;
for (;;) {
- u1 = RandU64ToReal::template Value<PositiveValueT, false>(fast_u64_(g));
- u2 = RandU64ToReal::template Value<PositiveValueT, false>(fast_u64_(g));
+ u1 = GenerateRealFromBits<real_type, GeneratePositiveTag, false>(
+ fast_u64_(g));
+ u2 = GenerateRealFromBits<real_type, GeneratePositiveTag, false>(
+ fast_u64_(g));
v = p.y_ * std::log(u1 / (1 - u1));
w = p.a_ * std::exp(v);
bw_inv = result_type(1) / (p.b_ + w);
@@ -409,6 +421,7 @@
return is;
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_BETA_DISTRIBUTION_H_
diff --git a/third_party/abseil/absl/random/beta_distribution_test.cc b/third_party/abseil/absl/random/beta_distribution_test.cc
index 966ad08..277e4dc 100644
--- a/third_party/abseil/absl/random/beta_distribution_test.cc
+++ b/third_party/abseil/absl/random/beta_distribution_test.cc
@@ -29,6 +29,7 @@
#include "absl/base/internal/raw_logging.h"
#include "absl/random/internal/chi_square.h"
#include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/pcg_engine.h"
#include "absl/random/internal/sequence_urbg.h"
#include "absl/random/random.h"
#include "absl/strings/str_cat.h"
@@ -92,7 +93,7 @@
for (TypeParam alpha : kValues) {
for (TypeParam beta : kValues) {
ABSL_INTERNAL_LOG(
- INFO, absl::StrFormat("Smoke test for Beta(%f, %f)", alpha, beta));
+ INFO, absl::StrFormat("Smoke test for Beta(%a, %a)", alpha, beta));
param_type param(alpha, beta);
absl::beta_distribution<TypeParam> before(alpha, beta);
@@ -159,8 +160,12 @@
}
TYPED_TEST(BetaDistributionInterfaceTest, DegenerateCases) {
+ // We use a fixed bit generator for distribution accuracy tests. This allows
+ // these tests to be deterministic, while still testing the qualify of the
+ // implementation.
+ absl::random_internal::pcg64_2018_engine rng(0x2B7E151628AED2A6);
+
// Extreme cases when the params are abnormal.
- absl::InsecureBitGen gen;
constexpr int kCount = 1000;
const TypeParam kSmallValues[] = {
std::numeric_limits<TypeParam>::min(),
@@ -186,7 +191,7 @@
int ones = 0;
absl::beta_distribution<TypeParam> d(alpha, beta);
for (int i = 0; i < kCount; ++i) {
- TypeParam x = d(gen);
+ TypeParam x = d(rng);
if (x == 0.0) {
zeros++;
} else if (x == 1.0) {
@@ -212,7 +217,7 @@
for (TypeParam beta : kLargeValues) {
absl::beta_distribution<TypeParam> d(alpha, beta);
for (int i = 0; i < kCount; ++i) {
- EXPECT_EQ(d(gen), 0.0);
+ EXPECT_EQ(d(rng), 0.0);
}
}
}
@@ -227,7 +232,7 @@
for (TypeParam beta : kSmallValues) {
absl::beta_distribution<TypeParam> d(alpha, beta);
for (int i = 0; i < kCount; ++i) {
- EXPECT_EQ(d(gen), 1.0);
+ EXPECT_EQ(d(rng), 1.0);
}
}
}
@@ -237,7 +242,7 @@
absl::beta_distribution<TypeParam> d(std::numeric_limits<TypeParam>::max(),
std::numeric_limits<TypeParam>::max());
for (int i = 0; i < kCount; ++i) {
- EXPECT_EQ(d(gen), 0.5);
+ EXPECT_EQ(d(rng), 0.5);
}
}
{
@@ -246,7 +251,7 @@
std::numeric_limits<TypeParam>::max(),
std::numeric_limits<TypeParam>::max() * 0.9999);
for (int i = 0; i < kCount; ++i) {
- TypeParam x = d(gen);
+ TypeParam x = d(rng);
EXPECT_NE(x, 0.5f);
EXPECT_FLOAT_EQ(x, 0.500025f);
}
diff --git a/third_party/abseil/absl/random/bit_gen_ref.h b/third_party/abseil/absl/random/bit_gen_ref.h
new file mode 100644
index 0000000..9555460
--- /dev/null
+++ b/third_party/abseil/absl/random/bit_gen_ref.h
@@ -0,0 +1,181 @@
+//
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: bit_gen_ref.h
+// -----------------------------------------------------------------------------
+//
+// This header defines a bit generator "reference" class, for use in interfaces
+// that take both Abseil (e.g. `absl::BitGen`) and standard library (e.g.
+// `std::mt19937`) bit generators.
+
+#ifndef ABSL_RANDOM_BIT_GEN_REF_H_
+#define ABSL_RANDOM_BIT_GEN_REF_H_
+
+#include "absl/base/internal/fast_type_id.h"
+#include "absl/base/macros.h"
+#include "absl/meta/type_traits.h"
+#include "absl/random/internal/distribution_caller.h"
+#include "absl/random/internal/fast_uniform_bits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace random_internal {
+
+template <typename URBG, typename = void, typename = void, typename = void>
+struct is_urbg : std::false_type {};
+
+template <typename URBG>
+struct is_urbg<
+ URBG,
+ absl::enable_if_t<std::is_same<
+ typename URBG::result_type,
+ typename std::decay<decltype((URBG::min)())>::type>::value>,
+ absl::enable_if_t<std::is_same<
+ typename URBG::result_type,
+ typename std::decay<decltype((URBG::max)())>::type>::value>,
+ absl::enable_if_t<std::is_same<
+ typename URBG::result_type,
+ typename std::decay<decltype(std::declval<URBG>()())>::type>::value>>
+ : std::true_type {};
+
+template <typename>
+struct DistributionCaller;
+class MockHelpers;
+
+} // namespace random_internal
+
+// -----------------------------------------------------------------------------
+// absl::BitGenRef
+// -----------------------------------------------------------------------------
+//
+// `absl::BitGenRef` is a type-erasing class that provides a generator-agnostic
+// non-owning "reference" interface for use in place of any specific uniform
+// random bit generator (URBG). This class may be used for both Abseil
+// (e.g. `absl::BitGen`, `absl::InsecureBitGen`) and Standard library (e.g
+// `std::mt19937`, `std::minstd_rand`) bit generators.
+//
+// Like other reference classes, `absl::BitGenRef` does not own the
+// underlying bit generator, and the underlying instance must outlive the
+// `absl::BitGenRef`.
+//
+// `absl::BitGenRef` is particularly useful when used with an
+// `absl::MockingBitGen` to test specific paths in functions which use random
+// values.
+//
+// Example:
+// void TakesBitGenRef(absl::BitGenRef gen) {
+// int x = absl::Uniform<int>(gen, 0, 1000);
+// }
+//
+class BitGenRef {
+ // SFINAE to detect whether the URBG type includes a member matching
+ // bool InvokeMock(base_internal::FastTypeIdType, void*, void*).
+ //
+ // These live inside BitGenRef so that they have friend access
+ // to MockingBitGen. (see similar methods in DistributionCaller).
+ template <template <class...> class Trait, class AlwaysVoid, class... Args>
+ struct detector : std::false_type {};
+ template <template <class...> class Trait, class... Args>
+ struct detector<Trait, absl::void_t<Trait<Args...>>, Args...>
+ : std::true_type {};
+
+ template <class T>
+ using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock(
+ std::declval<base_internal::FastTypeIdType>(), std::declval<void*>(),
+ std::declval<void*>()));
+
+ template <typename T>
+ using HasInvokeMock = typename detector<invoke_mock_t, void, T>::type;
+
+ public:
+ BitGenRef(const BitGenRef&) = default;
+ BitGenRef(BitGenRef&&) = default;
+ BitGenRef& operator=(const BitGenRef&) = default;
+ BitGenRef& operator=(BitGenRef&&) = default;
+
+ template <typename URBG, typename absl::enable_if_t<
+ (!std::is_same<URBG, BitGenRef>::value &&
+ random_internal::is_urbg<URBG>::value &&
+ !HasInvokeMock<URBG>::value)>* = nullptr>
+ BitGenRef(URBG& gen) // NOLINT
+ : t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),
+ mock_call_(NotAMock),
+ generate_impl_fn_(ImplFn<URBG>) {}
+
+ template <typename URBG,
+ typename absl::enable_if_t<(!std::is_same<URBG, BitGenRef>::value &&
+ random_internal::is_urbg<URBG>::value &&
+ HasInvokeMock<URBG>::value)>* = nullptr>
+ BitGenRef(URBG& gen) // NOLINT
+ : t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),
+ mock_call_(&MockCall<URBG>),
+ generate_impl_fn_(ImplFn<URBG>) {}
+
+ using result_type = uint64_t;
+
+ static constexpr result_type(min)() {
+ return (std::numeric_limits<result_type>::min)();
+ }
+
+ static constexpr result_type(max)() {
+ return (std::numeric_limits<result_type>::max)();
+ }
+
+ result_type operator()() { return generate_impl_fn_(t_erased_gen_ptr_); }
+
+ private:
+ using impl_fn = result_type (*)(uintptr_t);
+ using mock_call_fn = bool (*)(uintptr_t, base_internal::FastTypeIdType, void*,
+ void*);
+
+ template <typename URBG>
+ static result_type ImplFn(uintptr_t ptr) {
+ // Ensure that the return values from operator() fill the entire
+ // range promised by result_type, min() and max().
+ absl::random_internal::FastUniformBits<result_type> fast_uniform_bits;
+ return fast_uniform_bits(*reinterpret_cast<URBG*>(ptr));
+ }
+
+ // Get a type-erased InvokeMock pointer.
+ template <typename URBG>
+ static bool MockCall(uintptr_t gen_ptr, base_internal::FastTypeIdType type,
+ void* result, void* arg_tuple) {
+ return reinterpret_cast<URBG*>(gen_ptr)->InvokeMock(type, result,
+ arg_tuple);
+ }
+ static bool NotAMock(uintptr_t, base_internal::FastTypeIdType, void*, void*) {
+ return false;
+ }
+
+ inline bool InvokeMock(base_internal::FastTypeIdType type, void* args_tuple,
+ void* result) {
+ if (mock_call_ == NotAMock) return false; // avoids an indirect call.
+ return mock_call_(t_erased_gen_ptr_, type, args_tuple, result);
+ }
+
+ uintptr_t t_erased_gen_ptr_;
+ mock_call_fn mock_call_;
+ impl_fn generate_impl_fn_;
+
+ template <typename>
+ friend struct ::absl::random_internal::DistributionCaller; // for InvokeMock
+ friend class ::absl::random_internal::MockHelpers; // for InvokeMock
+};
+
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_RANDOM_BIT_GEN_REF_H_
diff --git a/third_party/abseil/absl/random/bit_gen_ref_test.cc b/third_party/abseil/absl/random/bit_gen_ref_test.cc
new file mode 100644
index 0000000..1135cf2
--- /dev/null
+++ b/third_party/abseil/absl/random/bit_gen_ref_test.cc
@@ -0,0 +1,102 @@
+//
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#include "absl/random/bit_gen_ref.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/fast_type_id.h"
+#include "absl/random/internal/sequence_urbg.h"
+#include "absl/random/random.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+class ConstBitGen {
+ public:
+ // URBG interface
+ using result_type = absl::BitGen::result_type;
+
+ static constexpr result_type(min)() { return (absl::BitGen::min)(); }
+ static constexpr result_type(max)() { return (absl::BitGen::max)(); }
+ result_type operator()() { return 1; }
+
+ // InvokeMock method
+ bool InvokeMock(base_internal::FastTypeIdType index, void*, void* result) {
+ *static_cast<int*>(result) = 42;
+ return true;
+ }
+};
+
+namespace {
+
+int FnTest(absl::BitGenRef gen_ref) { return absl::Uniform(gen_ref, 1, 7); }
+
+template <typename T>
+class BitGenRefTest : public testing::Test {};
+
+using BitGenTypes =
+ ::testing::Types<absl::BitGen, absl::InsecureBitGen, std::mt19937,
+ std::mt19937_64, std::minstd_rand>;
+TYPED_TEST_SUITE(BitGenRefTest, BitGenTypes);
+
+TYPED_TEST(BitGenRefTest, BasicTest) {
+ TypeParam gen;
+ auto x = FnTest(gen);
+ EXPECT_NEAR(x, 4, 3);
+}
+
+TYPED_TEST(BitGenRefTest, Copyable) {
+ TypeParam gen;
+ absl::BitGenRef gen_ref(gen);
+ FnTest(gen_ref); // Copy
+}
+
+TEST(BitGenRefTest, PassThroughEquivalence) {
+ // sequence_urbg returns 64-bit results.
+ absl::random_internal::sequence_urbg urbg(
+ {0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
+ 0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
+ 0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
+ 0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull});
+
+ std::vector<uint64_t> output(12);
+
+ {
+ absl::BitGenRef view(urbg);
+ for (auto& v : output) {
+ v = view();
+ }
+ }
+
+ std::vector<uint64_t> expected(
+ {0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
+ 0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
+ 0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
+ 0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull});
+
+ EXPECT_THAT(output, testing::Eq(expected));
+}
+
+TEST(BitGenRefTest, MockingBitGenBaseOverrides) {
+ ConstBitGen const_gen;
+ EXPECT_EQ(FnTest(const_gen), 42);
+
+ absl::BitGenRef gen_ref(const_gen);
+ EXPECT_EQ(FnTest(gen_ref), 42); // Copy
+}
+} // namespace
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/random/discrete_distribution.cc b/third_party/abseil/absl/random/discrete_distribution.cc
index e6c09c5..081acce 100644
--- a/third_party/abseil/absl/random/discrete_distribution.cc
+++ b/third_party/abseil/absl/random/discrete_distribution.cc
@@ -15,6 +15,7 @@
#include "absl/random/discrete_distribution.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
// Initializes the distribution table for Walker's Aliasing algorithm, described
@@ -93,4 +94,5 @@
}
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/random/discrete_distribution.h b/third_party/abseil/absl/random/discrete_distribution.h
index 1560f03..171aa11 100644
--- a/third_party/abseil/absl/random/discrete_distribution.h
+++ b/third_party/abseil/absl/random/discrete_distribution.h
@@ -29,6 +29,7 @@
#include "absl/random/uniform_int_distribution.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// absl::discrete_distribution
//
@@ -240,6 +241,7 @@
return is;
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_DISCRETE_DISTRIBUTION_H_
diff --git a/third_party/abseil/absl/random/discrete_distribution_test.cc b/third_party/abseil/absl/random/discrete_distribution_test.cc
index 7296f0a..6d00700 100644
--- a/third_party/abseil/absl/random/discrete_distribution_test.cc
+++ b/third_party/abseil/absl/random/discrete_distribution_test.cc
@@ -29,6 +29,7 @@
#include "absl/base/internal/raw_logging.h"
#include "absl/random/internal/chi_square.h"
#include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/pcg_engine.h"
#include "absl/random/internal/sequence_urbg.h"
#include "absl/random/random.h"
#include "absl/strings/str_cat.h"
@@ -156,7 +157,10 @@
std::iota(std::begin(weights), std::end(weights), 1);
absl::discrete_distribution<int> dist(std::begin(weights), std::end(weights));
- absl::InsecureBitGen rng;
+ // We use a fixed bit generator for distribution accuracy tests. This allows
+ // these tests to be deterministic, while still testing the qualify of the
+ // implementation.
+ absl::random_internal::pcg64_2018_engine rng(0x2B7E151628AED2A6);
std::vector<int32_t> counts(kBuckets, 0);
for (size_t i = 0; i < kTrials; i++) {
diff --git a/third_party/abseil/absl/random/distribution_format_traits.h b/third_party/abseil/absl/random/distribution_format_traits.h
deleted file mode 100644
index 3298c2c..0000000
--- a/third_party/abseil/absl/random/distribution_format_traits.h
+++ /dev/null
@@ -1,288 +0,0 @@
-//
-// Copyright 2018 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-#ifndef ABSL_RANDOM_DISTRIBUTION_FORMAT_TRAITS_H_
-#define ABSL_RANDOM_DISTRIBUTION_FORMAT_TRAITS_H_
-
-#include <string>
-#include <tuple>
-#include <typeinfo>
-
-#include "absl/meta/type_traits.h"
-#include "absl/random/bernoulli_distribution.h"
-#include "absl/random/beta_distribution.h"
-#include "absl/random/exponential_distribution.h"
-#include "absl/random/gaussian_distribution.h"
-#include "absl/random/log_uniform_int_distribution.h"
-#include "absl/random/poisson_distribution.h"
-#include "absl/random/uniform_int_distribution.h"
-#include "absl/random/uniform_real_distribution.h"
-#include "absl/random/zipf_distribution.h"
-#include "absl/strings/str_cat.h"
-#include "absl/strings/str_join.h"
-#include "absl/strings/string_view.h"
-#include "absl/types/span.h"
-
-namespace absl {
-
-struct IntervalClosedClosedTag;
-struct IntervalClosedOpenTag;
-struct IntervalOpenClosedTag;
-struct IntervalOpenOpenTag;
-
-namespace random_internal {
-
-// ScalarTypeName defines a preferred hierarchy of preferred type names for
-// scalars, and is evaluated at compile time for the specific type
-// specialization.
-template <typename T>
-constexpr const char* ScalarTypeName() {
- static_assert(std::is_integral<T>() || std::is_floating_point<T>(), "");
- // clang-format off
- return
- std::is_same<T, float>::value ? "float" :
- std::is_same<T, double>::value ? "double" :
- std::is_same<T, long double>::value ? "long double" :
- std::is_same<T, bool>::value ? "bool" :
- std::is_signed<T>::value && sizeof(T) == 1 ? "int8_t" :
- std::is_signed<T>::value && sizeof(T) == 2 ? "int16_t" :
- std::is_signed<T>::value && sizeof(T) == 4 ? "int32_t" :
- std::is_signed<T>::value && sizeof(T) == 8 ? "int64_t" :
- std::is_unsigned<T>::value && sizeof(T) == 1 ? "uint8_t" :
- std::is_unsigned<T>::value && sizeof(T) == 2 ? "uint16_t" :
- std::is_unsigned<T>::value && sizeof(T) == 4 ? "uint32_t" :
- std::is_unsigned<T>::value && sizeof(T) == 8 ? "uint64_t" :
- "undefined";
- // clang-format on
-
- // NOTE: It would be nice to use typeid(T).name(), but that's an
- // implementation-defined attribute which does not necessarily
- // correspond to a name. We could potentially demangle it
- // using, e.g. abi::__cxa_demangle.
-}
-
-// Distribution traits used by DistributionCaller and internal implementation
-// details of the mocking framework.
-/*
-struct DistributionFormatTraits {
- // Returns the parameterized name of the distribution function.
- static constexpr const char* FunctionName()
- // Format DistrT parameters.
- static std::string FormatArgs(DistrT& dist);
- // Format DistrT::result_type results.
- static std::string FormatResults(DistrT& dist);
-};
-*/
-template <typename DistrT>
-struct DistributionFormatTraits;
-
-template <typename R>
-struct DistributionFormatTraits<absl::uniform_int_distribution<R>> {
- using distribution_t = absl::uniform_int_distribution<R>;
- using result_t = typename distribution_t::result_type;
-
- static constexpr const char* Name() { return "Uniform"; }
-
- static std::string FunctionName() {
- return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
- }
- static std::string FormatArgs(const distribution_t& d) {
- return absl::StrCat("absl::IntervalClosedClosed, ", (d.min)(), ", ",
- (d.max)());
- }
- static std::string FormatResults(absl::Span<const result_t> results) {
- return absl::StrJoin(results, ", ");
- }
-};
-
-template <typename R>
-struct DistributionFormatTraits<absl::uniform_real_distribution<R>> {
- using distribution_t = absl::uniform_real_distribution<R>;
- using result_t = typename distribution_t::result_type;
-
- static constexpr const char* Name() { return "Uniform"; }
-
- static std::string FunctionName() {
- return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
- }
- static std::string FormatArgs(const distribution_t& d) {
- return absl::StrCat((d.min)(), ", ", (d.max)());
- }
- static std::string FormatResults(absl::Span<const result_t> results) {
- return absl::StrJoin(results, ", ");
- }
-};
-
-template <typename R>
-struct DistributionFormatTraits<absl::exponential_distribution<R>> {
- using distribution_t = absl::exponential_distribution<R>;
- using result_t = typename distribution_t::result_type;
-
- static constexpr const char* Name() { return "Exponential"; }
-
- static std::string FunctionName() {
- return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
- }
- static std::string FormatArgs(const distribution_t& d) {
- return absl::StrCat(d.lambda());
- }
- static std::string FormatResults(absl::Span<const result_t> results) {
- return absl::StrJoin(results, ", ");
- }
-};
-
-template <typename R>
-struct DistributionFormatTraits<absl::poisson_distribution<R>> {
- using distribution_t = absl::poisson_distribution<R>;
- using result_t = typename distribution_t::result_type;
-
- static constexpr const char* Name() { return "Poisson"; }
-
- static std::string FunctionName() {
- return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
- }
- static std::string FormatArgs(const distribution_t& d) {
- return absl::StrCat(d.mean());
- }
- static std::string FormatResults(absl::Span<const result_t> results) {
- return absl::StrJoin(results, ", ");
- }
-};
-
-template <>
-struct DistributionFormatTraits<absl::bernoulli_distribution> {
- using distribution_t = absl::bernoulli_distribution;
- using result_t = typename distribution_t::result_type;
-
- static constexpr const char* Name() { return "Bernoulli"; }
-
- static constexpr const char* FunctionName() { return Name(); }
- static std::string FormatArgs(const distribution_t& d) {
- return absl::StrCat(d.p());
- }
- static std::string FormatResults(absl::Span<const result_t> results) {
- return absl::StrJoin(results, ", ");
- }
-};
-
-template <typename R>
-struct DistributionFormatTraits<absl::beta_distribution<R>> {
- using distribution_t = absl::beta_distribution<R>;
- using result_t = typename distribution_t::result_type;
-
- static constexpr const char* Name() { return "Beta"; }
-
- static std::string FunctionName() {
- return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
- }
- static std::string FormatArgs(const distribution_t& d) {
- return absl::StrCat(d.alpha(), ", ", d.beta());
- }
- static std::string FormatResults(absl::Span<const result_t> results) {
- return absl::StrJoin(results, ", ");
- }
-};
-
-template <typename R>
-struct DistributionFormatTraits<absl::zipf_distribution<R>> {
- using distribution_t = absl::zipf_distribution<R>;
- using result_t = typename distribution_t::result_type;
-
- static constexpr const char* Name() { return "Zipf"; }
-
- static std::string FunctionName() {
- return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
- }
- static std::string FormatArgs(const distribution_t& d) {
- return absl::StrCat(d.k(), ", ", d.v(), ", ", d.q());
- }
- static std::string FormatResults(absl::Span<const result_t> results) {
- return absl::StrJoin(results, ", ");
- }
-};
-
-template <typename R>
-struct DistributionFormatTraits<absl::gaussian_distribution<R>> {
- using distribution_t = absl::gaussian_distribution<R>;
- using result_t = typename distribution_t::result_type;
-
- static constexpr const char* Name() { return "Gaussian"; }
-
- static std::string FunctionName() {
- return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
- }
- static std::string FormatArgs(const distribution_t& d) {
- return absl::StrJoin(std::make_tuple(d.mean(), d.stddev()), ", ");
- }
- static std::string FormatResults(absl::Span<const result_t> results) {
- return absl::StrJoin(results, ", ");
- }
-};
-
-template <typename R>
-struct DistributionFormatTraits<absl::log_uniform_int_distribution<R>> {
- using distribution_t = absl::log_uniform_int_distribution<R>;
- using result_t = typename distribution_t::result_type;
-
- static constexpr const char* Name() { return "LogUniform"; }
-
- static std::string FunctionName() {
- return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
- }
- static std::string FormatArgs(const distribution_t& d) {
- return absl::StrJoin(std::make_tuple((d.min)(), (d.max)(), d.base()), ", ");
- }
- static std::string FormatResults(absl::Span<const result_t> results) {
- return absl::StrJoin(results, ", ");
- }
-};
-
-template <typename TagType, typename NumType>
-struct UniformDistributionWrapper;
-
-template <typename TagType, typename NumType>
-struct DistributionFormatTraits<UniformDistributionWrapper<TagType, NumType>> {
- using distribution_t = UniformDistributionWrapper<TagType, NumType>;
- using result_t = NumType;
-
- static constexpr const char* Name() { return "Uniform"; }
-
- static std::string FunctionName() {
- return absl::StrCat(Name(), "<", ScalarTypeName<NumType>(), ">");
- }
- static std::string FormatArgs(const distribution_t& d) {
- absl::string_view tag;
- if (std::is_same<TagType, IntervalClosedClosedTag>::value) {
- tag = "IntervalClosedClosed";
- } else if (std::is_same<TagType, IntervalClosedOpenTag>::value) {
- tag = "IntervalClosedOpen";
- } else if (std::is_same<TagType, IntervalOpenClosedTag>::value) {
- tag = "IntervalOpenClosed";
- } else if (std::is_same<TagType, IntervalOpenOpenTag>::value) {
- tag = "IntervalOpenOpen";
- } else {
- tag = "[[unknown tag type]]";
- }
- return absl::StrCat(tag, ", ", (d.min)(), ", ", (d.max)());
- }
- static std::string FormatResults(absl::Span<const result_t> results) {
- return absl::StrJoin(results, ", ");
- }
-};
-
-} // namespace random_internal
-} // namespace absl
-
-#endif // ABSL_RANDOM_DISTRIBUTION_FORMAT_TRAITS_H_
diff --git a/third_party/abseil/absl/random/distributions.h b/third_party/abseil/absl/random/distributions.h
index 18ff248..31c7969 100644
--- a/third_party/abseil/absl/random/distributions.h
+++ b/third_party/abseil/absl/random/distributions.h
@@ -55,10 +55,9 @@
#include "absl/base/internal/inline_variable.h"
#include "absl/random/bernoulli_distribution.h"
#include "absl/random/beta_distribution.h"
-#include "absl/random/distribution_format_traits.h"
#include "absl/random/exponential_distribution.h"
#include "absl/random/gaussian_distribution.h"
-#include "absl/random/internal/distributions.h" // IWYU pragma: export
+#include "absl/random/internal/distribution_caller.h" // IWYU pragma: export
#include "absl/random/internal/uniform_helper.h" // IWYU pragma: export
#include "absl/random/log_uniform_int_distribution.h"
#include "absl/random/poisson_distribution.h"
@@ -67,6 +66,7 @@
#include "absl/random/zipf_distribution.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalClosedClosedTag, IntervalClosedClosed,
{});
@@ -96,7 +96,7 @@
// the return type based on the provided endpoint arguments {A lo, B hi}.
// Given these endpoints, one of {A, B} will be chosen as the return type, if
// a type can be implicitly converted into the other in a lossless way. The
-// lack of any such implcit conversion between {A, B} will produce a
+// lack of any such implicit conversion between {A, B} will produce a
// compile-time error
//
// See https://en.wikipedia.org/wiki/Uniform_distribution_(continuous)
@@ -124,7 +124,14 @@
URBG&& urbg, // NOLINT(runtime/references)
R lo, R hi) {
using gen_t = absl::decay_t<URBG>;
- return random_internal::UniformImpl<R, TagType, gen_t>(tag, urbg, lo, hi);
+ using distribution_t = random_internal::UniformDistributionWrapper<R>;
+
+ auto a = random_internal::uniform_lower_bound(tag, lo, hi);
+ auto b = random_internal::uniform_upper_bound(tag, lo, hi);
+ if (!random_internal::is_uniform_range_valid(a, b)) return lo;
+
+ return random_internal::DistributionCaller<gen_t>::template Call<
+ distribution_t>(&urbg, tag, lo, hi);
}
// absl::Uniform<T>(bitgen, lo, hi)
@@ -135,11 +142,16 @@
typename absl::enable_if_t<!std::is_same<R, void>::value, R> //
Uniform(URBG&& urbg, // NOLINT(runtime/references)
R lo, R hi) {
- constexpr auto tag = absl::IntervalClosedOpen;
- using tag_t = decltype(tag);
using gen_t = absl::decay_t<URBG>;
+ using distribution_t = random_internal::UniformDistributionWrapper<R>;
+ constexpr auto tag = absl::IntervalClosedOpen;
- return random_internal::UniformImpl<R, tag_t, gen_t>(tag, urbg, lo, hi);
+ auto a = random_internal::uniform_lower_bound(tag, lo, hi);
+ auto b = random_internal::uniform_upper_bound(tag, lo, hi);
+ if (!random_internal::is_uniform_range_valid(a, b)) return lo;
+
+ return random_internal::DistributionCaller<gen_t>::template Call<
+ distribution_t>(&urbg, lo, hi);
}
// absl::Uniform(tag, bitgen, lo, hi)
@@ -156,9 +168,15 @@
A lo, B hi) {
using gen_t = absl::decay_t<URBG>;
using return_t = typename random_internal::uniform_inferred_return_t<A, B>;
+ using distribution_t = random_internal::UniformDistributionWrapper<return_t>;
- return random_internal::UniformImpl<return_t, TagType, gen_t>(tag, urbg, lo,
- hi);
+ auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi);
+ auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi);
+ if (!random_internal::is_uniform_range_valid(a, b)) return lo;
+
+ return random_internal::DistributionCaller<gen_t>::template Call<
+ distribution_t>(&urbg, tag, static_cast<return_t>(lo),
+ static_cast<return_t>(hi));
}
// absl::Uniform(bitgen, lo, hi)
@@ -171,13 +189,18 @@
random_internal::uniform_inferred_return_t<A, B>>
Uniform(URBG&& urbg, // NOLINT(runtime/references)
A lo, B hi) {
- constexpr auto tag = absl::IntervalClosedOpen;
- using tag_t = decltype(tag);
using gen_t = absl::decay_t<URBG>;
using return_t = typename random_internal::uniform_inferred_return_t<A, B>;
+ using distribution_t = random_internal::UniformDistributionWrapper<return_t>;
- return random_internal::UniformImpl<return_t, tag_t, gen_t>(tag, urbg, lo,
- hi);
+ constexpr auto tag = absl::IntervalClosedOpen;
+ auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi);
+ auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi);
+ if (!random_internal::is_uniform_range_valid(a, b)) return lo;
+
+ return random_internal::DistributionCaller<gen_t>::template Call<
+ distribution_t>(&urbg, static_cast<return_t>(lo),
+ static_cast<return_t>(hi));
}
// absl::Uniform<unsigned T>(bitgen)
@@ -187,13 +210,11 @@
template <typename R, typename URBG>
typename absl::enable_if_t<!std::is_signed<R>::value, R> //
Uniform(URBG&& urbg) { // NOLINT(runtime/references)
- constexpr auto tag = absl::IntervalClosedClosed;
- constexpr auto lo = std::numeric_limits<R>::lowest();
- constexpr auto hi = (std::numeric_limits<R>::max)();
- using tag_t = decltype(tag);
using gen_t = absl::decay_t<URBG>;
+ using distribution_t = random_internal::UniformDistributionWrapper<R>;
- return random_internal::UniformImpl<R, tag_t, gen_t>(tag, urbg, lo, hi);
+ return random_internal::DistributionCaller<gen_t>::template Call<
+ distribution_t>(&urbg);
}
// -----------------------------------------------------------------------------
@@ -221,10 +242,9 @@
double p) {
using gen_t = absl::decay_t<URBG>;
using distribution_t = absl::bernoulli_distribution;
- using format_t = random_internal::DistributionFormatTraits<distribution_t>;
return random_internal::DistributionCaller<gen_t>::template Call<
- distribution_t, format_t>(&urbg, p);
+ distribution_t>(&urbg, p);
}
// -----------------------------------------------------------------------------
@@ -254,20 +274,19 @@
using gen_t = absl::decay_t<URBG>;
using distribution_t = typename absl::beta_distribution<RealType>;
- using format_t = random_internal::DistributionFormatTraits<distribution_t>;
return random_internal::DistributionCaller<gen_t>::template Call<
- distribution_t, format_t>(&urbg, alpha, beta);
+ distribution_t>(&urbg, alpha, beta);
}
// -----------------------------------------------------------------------------
// absl::Exponential<T>(bitgen, lambda = 1)
// -----------------------------------------------------------------------------
//
-// `absl::Exponential` produces a floating point number for discrete
-// distributions of events occurring continuously and independently at a
-// constant average rate. `T` must be a floating point type, but may be inferred
-// from the type of `lambda`.
+// `absl::Exponential` produces a floating point number representing the
+// distance (time) between two consecutive events in a point process of events
+// occurring continuously and independently at a constant average rate. `T` must
+// be a floating point type, but may be inferred from the type of `lambda`.
//
// See https://en.wikipedia.org/wiki/Exponential_distribution.
//
@@ -287,10 +306,9 @@
using gen_t = absl::decay_t<URBG>;
using distribution_t = typename absl::exponential_distribution<RealType>;
- using format_t = random_internal::DistributionFormatTraits<distribution_t>;
return random_internal::DistributionCaller<gen_t>::template Call<
- distribution_t, format_t>(&urbg, lambda);
+ distribution_t>(&urbg, lambda);
}
// -----------------------------------------------------------------------------
@@ -319,10 +337,9 @@
using gen_t = absl::decay_t<URBG>;
using distribution_t = typename absl::gaussian_distribution<RealType>;
- using format_t = random_internal::DistributionFormatTraits<distribution_t>;
return random_internal::DistributionCaller<gen_t>::template Call<
- distribution_t, format_t>(&urbg, mean, stddev);
+ distribution_t>(&urbg, mean, stddev);
}
// -----------------------------------------------------------------------------
@@ -362,10 +379,9 @@
using gen_t = absl::decay_t<URBG>;
using distribution_t = typename absl::log_uniform_int_distribution<IntType>;
- using format_t = random_internal::DistributionFormatTraits<distribution_t>;
return random_internal::DistributionCaller<gen_t>::template Call<
- distribution_t, format_t>(&urbg, lo, hi, base);
+ distribution_t>(&urbg, lo, hi, base);
}
// -----------------------------------------------------------------------------
@@ -393,10 +409,9 @@
using gen_t = absl::decay_t<URBG>;
using distribution_t = typename absl::poisson_distribution<IntType>;
- using format_t = random_internal::DistributionFormatTraits<distribution_t>;
return random_internal::DistributionCaller<gen_t>::template Call<
- distribution_t, format_t>(&urbg, mean);
+ distribution_t>(&urbg, mean);
}
// -----------------------------------------------------------------------------
@@ -426,12 +441,12 @@
using gen_t = absl::decay_t<URBG>;
using distribution_t = typename absl::zipf_distribution<IntType>;
- using format_t = random_internal::DistributionFormatTraits<distribution_t>;
return random_internal::DistributionCaller<gen_t>::template Call<
- distribution_t, format_t>(&urbg, hi, q, v);
+ distribution_t>(&urbg, hi, q, v);
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_DISTRIBUTIONS_H_
diff --git a/third_party/abseil/absl/random/distributions_test.cc b/third_party/abseil/absl/random/distributions_test.cc
index 2d92723..5866a07 100644
--- a/third_party/abseil/absl/random/distributions_test.cc
+++ b/third_party/abseil/absl/random/distributions_test.cc
@@ -29,94 +29,6 @@
class RandomDistributionsTest : public testing::Test {};
-TEST_F(RandomDistributionsTest, UniformBoundFunctions) {
- using absl::IntervalClosedClosed;
- using absl::IntervalClosedOpen;
- using absl::IntervalOpenClosed;
- using absl::IntervalOpenOpen;
- using absl::random_internal::uniform_lower_bound;
- using absl::random_internal::uniform_upper_bound;
-
- // absl::uniform_int_distribution natively assumes IntervalClosedClosed
- // absl::uniform_real_distribution natively assumes IntervalClosedOpen
-
- EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, 0, 100), 1);
- EXPECT_EQ(uniform_lower_bound(IntervalOpenOpen, 0, 100), 1);
- EXPECT_GT(uniform_lower_bound<float>(IntervalOpenClosed, 0, 1.0), 0);
- EXPECT_GT(uniform_lower_bound<float>(IntervalOpenOpen, 0, 1.0), 0);
- EXPECT_GT(uniform_lower_bound<double>(IntervalOpenClosed, 0, 1.0), 0);
- EXPECT_GT(uniform_lower_bound<double>(IntervalOpenOpen, 0, 1.0), 0);
-
- EXPECT_EQ(uniform_lower_bound(IntervalClosedClosed, 0, 100), 0);
- EXPECT_EQ(uniform_lower_bound(IntervalClosedOpen, 0, 100), 0);
- EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedClosed, 0, 1.0), 0);
- EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedOpen, 0, 1.0), 0);
- EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedClosed, 0, 1.0), 0);
- EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedOpen, 0, 1.0), 0);
-
- EXPECT_EQ(uniform_upper_bound(IntervalOpenOpen, 0, 100), 99);
- EXPECT_EQ(uniform_upper_bound(IntervalClosedOpen, 0, 100), 99);
- EXPECT_EQ(uniform_upper_bound<float>(IntervalOpenOpen, 0, 1.0), 1.0);
- EXPECT_EQ(uniform_upper_bound<float>(IntervalClosedOpen, 0, 1.0), 1.0);
- EXPECT_EQ(uniform_upper_bound<double>(IntervalOpenOpen, 0, 1.0), 1.0);
- EXPECT_EQ(uniform_upper_bound<double>(IntervalClosedOpen, 0, 1.0), 1.0);
-
- EXPECT_EQ(uniform_upper_bound(IntervalOpenClosed, 0, 100), 100);
- EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, 0, 100), 100);
- EXPECT_GT(uniform_upper_bound<float>(IntervalOpenClosed, 0, 1.0), 1.0);
- EXPECT_GT(uniform_upper_bound<float>(IntervalClosedClosed, 0, 1.0), 1.0);
- EXPECT_GT(uniform_upper_bound<double>(IntervalOpenClosed, 0, 1.0), 1.0);
- EXPECT_GT(uniform_upper_bound<double>(IntervalClosedClosed, 0, 1.0), 1.0);
-
- // Negative value tests
- EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, -100, -1), -99);
- EXPECT_EQ(uniform_lower_bound(IntervalOpenOpen, -100, -1), -99);
- EXPECT_GT(uniform_lower_bound<float>(IntervalOpenClosed, -2.0, -1.0), -2.0);
- EXPECT_GT(uniform_lower_bound<float>(IntervalOpenOpen, -2.0, -1.0), -2.0);
- EXPECT_GT(uniform_lower_bound<double>(IntervalOpenClosed, -2.0, -1.0), -2.0);
- EXPECT_GT(uniform_lower_bound<double>(IntervalOpenOpen, -2.0, -1.0), -2.0);
-
- EXPECT_EQ(uniform_lower_bound(IntervalClosedClosed, -100, -1), -100);
- EXPECT_EQ(uniform_lower_bound(IntervalClosedOpen, -100, -1), -100);
- EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedClosed, -2.0, -1.0), -2.0);
- EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedOpen, -2.0, -1.0), -2.0);
- EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedClosed, -2.0, -1.0),
- -2.0);
- EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedOpen, -2.0, -1.0), -2.0);
-
- EXPECT_EQ(uniform_upper_bound(IntervalOpenOpen, -100, -1), -2);
- EXPECT_EQ(uniform_upper_bound(IntervalClosedOpen, -100, -1), -2);
- EXPECT_EQ(uniform_upper_bound<float>(IntervalOpenOpen, -2.0, -1.0), -1.0);
- EXPECT_EQ(uniform_upper_bound<float>(IntervalClosedOpen, -2.0, -1.0), -1.0);
- EXPECT_EQ(uniform_upper_bound<double>(IntervalOpenOpen, -2.0, -1.0), -1.0);
- EXPECT_EQ(uniform_upper_bound<double>(IntervalClosedOpen, -2.0, -1.0), -1.0);
-
- EXPECT_EQ(uniform_upper_bound(IntervalOpenClosed, -100, -1), -1);
- EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, -100, -1), -1);
- EXPECT_GT(uniform_upper_bound<float>(IntervalOpenClosed, -2.0, -1.0), -1.0);
- EXPECT_GT(uniform_upper_bound<float>(IntervalClosedClosed, -2.0, -1.0), -1.0);
- EXPECT_GT(uniform_upper_bound<double>(IntervalOpenClosed, -2.0, -1.0), -1.0);
- EXPECT_GT(uniform_upper_bound<double>(IntervalClosedClosed, -2.0, -1.0),
- -1.0);
-
- // Edge cases: the next value toward itself is itself.
- const double d = 1.0;
- const float f = 1.0;
- EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, d, d), d);
- EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, f, f), f);
-
- EXPECT_GT(uniform_lower_bound(IntervalOpenClosed, 1.0, 2.0), 1.0);
- EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, +0.0), 1.0);
- EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, -0.0), 1.0);
- EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, -1.0), 1.0);
-
- EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, 0.0f,
- std::numeric_limits<float>::max()),
- std::numeric_limits<float>::max());
- EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, 0.0,
- std::numeric_limits<double>::max()),
- std::numeric_limits<double>::max());
-}
struct Invalid {};
@@ -284,7 +196,9 @@
// Properly promotes float.
CheckArgsInferType<float, double, double>();
+}
+TEST_F(RandomDistributionsTest, UniformExamples) {
// Examples.
absl::InsecureBitGen gen;
EXPECT_NE(1, absl::Uniform(gen, static_cast<uint16_t>(0), 1.0f));
@@ -307,6 +221,58 @@
absl::Uniform<uint64_t>(gen);
}
+TEST_F(RandomDistributionsTest, UniformNonsenseRanges) {
+ // The ranges used in this test are undefined behavior.
+ // The results are arbitrary and subject to future changes.
+ absl::InsecureBitGen gen;
+
+ // <uint>
+ EXPECT_EQ(0, absl::Uniform<uint64_t>(gen, 0, 0));
+ EXPECT_EQ(1, absl::Uniform<uint64_t>(gen, 1, 0));
+ EXPECT_EQ(0, absl::Uniform<uint64_t>(absl::IntervalOpenOpen, gen, 0, 0));
+ EXPECT_EQ(1, absl::Uniform<uint64_t>(absl::IntervalOpenOpen, gen, 1, 0));
+
+ constexpr auto m = (std::numeric_limits<uint64_t>::max)();
+
+ EXPECT_EQ(m, absl::Uniform(gen, m, m));
+ EXPECT_EQ(m, absl::Uniform(gen, m, m - 1));
+ EXPECT_EQ(m - 1, absl::Uniform(gen, m - 1, m));
+ EXPECT_EQ(m, absl::Uniform(absl::IntervalOpenOpen, gen, m, m));
+ EXPECT_EQ(m, absl::Uniform(absl::IntervalOpenOpen, gen, m, m - 1));
+ EXPECT_EQ(m - 1, absl::Uniform(absl::IntervalOpenOpen, gen, m - 1, m));
+
+ // <int>
+ EXPECT_EQ(0, absl::Uniform<int64_t>(gen, 0, 0));
+ EXPECT_EQ(1, absl::Uniform<int64_t>(gen, 1, 0));
+ EXPECT_EQ(0, absl::Uniform<int64_t>(absl::IntervalOpenOpen, gen, 0, 0));
+ EXPECT_EQ(1, absl::Uniform<int64_t>(absl::IntervalOpenOpen, gen, 1, 0));
+
+ constexpr auto l = (std::numeric_limits<int64_t>::min)();
+ constexpr auto r = (std::numeric_limits<int64_t>::max)();
+
+ EXPECT_EQ(l, absl::Uniform(gen, l, l));
+ EXPECT_EQ(r, absl::Uniform(gen, r, r));
+ EXPECT_EQ(r, absl::Uniform(gen, r, r - 1));
+ EXPECT_EQ(r - 1, absl::Uniform(gen, r - 1, r));
+ EXPECT_EQ(l, absl::Uniform(absl::IntervalOpenOpen, gen, l, l));
+ EXPECT_EQ(r, absl::Uniform(absl::IntervalOpenOpen, gen, r, r));
+ EXPECT_EQ(r, absl::Uniform(absl::IntervalOpenOpen, gen, r, r - 1));
+ EXPECT_EQ(r - 1, absl::Uniform(absl::IntervalOpenOpen, gen, r - 1, r));
+
+ // <double>
+ const double e = std::nextafter(1.0, 2.0); // 1 + epsilon
+ const double f = std::nextafter(1.0, 0.0); // 1 - epsilon
+ const double g = std::numeric_limits<double>::denorm_min();
+
+ EXPECT_EQ(1.0, absl::Uniform(gen, 1.0, e));
+ EXPECT_EQ(1.0, absl::Uniform(gen, 1.0, f));
+ EXPECT_EQ(0.0, absl::Uniform(gen, 0.0, g));
+
+ EXPECT_EQ(e, absl::Uniform(absl::IntervalOpenOpen, gen, 1.0, e));
+ EXPECT_EQ(f, absl::Uniform(absl::IntervalOpenOpen, gen, 1.0, f));
+ EXPECT_EQ(g, absl::Uniform(absl::IntervalOpenOpen, gen, 0.0, g));
+}
+
// TODO(lar): Validate properties of non-default interval-semantics.
TEST_F(RandomDistributionsTest, UniformReal) {
std::vector<double> values(kSize);
diff --git a/third_party/abseil/absl/random/exponential_distribution.h b/third_party/abseil/absl/random/exponential_distribution.h
index c8af197..b5caf8a 100644
--- a/third_party/abseil/absl/random/exponential_distribution.h
+++ b/third_party/abseil/absl/random/exponential_distribution.h
@@ -21,11 +21,13 @@
#include <limits>
#include <type_traits>
-#include "absl/random/internal/distribution_impl.h"
+#include "absl/meta/type_traits.h"
#include "absl/random/internal/fast_uniform_bits.h"
+#include "absl/random/internal/generate_real.h"
#include "absl/random/internal/iostream_state_saver.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// absl::exponential_distribution:
// Generates a number conforming to an exponential distribution and is
@@ -118,9 +120,14 @@
exponential_distribution<RealType>::operator()(
URBG& g, // NOLINT(runtime/references)
const param_type& p) {
- using random_internal::NegativeValueT;
- const result_type u = random_internal::RandU64ToReal<
- result_type>::template Value<NegativeValueT, false>(fast_u64_(g));
+ using random_internal::GenerateNegativeTag;
+ using random_internal::GenerateRealFromBits;
+ using real_type =
+ absl::conditional_t<std::is_same<RealType, float>::value, float, double>;
+
+ const result_type u = GenerateRealFromBits<real_type, GenerateNegativeTag,
+ false>(fast_u64_(g)); // U(-1, 0)
+
// log1p(-x) is mathematically equivalent to log(1 - x) but has more
// accuracy for x near zero.
return p.neg_inv_lambda_ * std::log1p(u);
@@ -152,6 +159,7 @@
return is;
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_EXPONENTIAL_DISTRIBUTION_H_
diff --git a/third_party/abseil/absl/random/exponential_distribution_test.cc b/third_party/abseil/absl/random/exponential_distribution_test.cc
index dc49044..5a8afde 100644
--- a/third_party/abseil/absl/random/exponential_distribution_test.cc
+++ b/third_party/abseil/absl/random/exponential_distribution_test.cc
@@ -32,6 +32,7 @@
#include "absl/base/macros.h"
#include "absl/random/internal/chi_square.h"
#include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/pcg_engine.h"
#include "absl/random/internal/sequence_urbg.h"
#include "absl/random/random.h"
#include "absl/strings/str_cat.h"
@@ -201,7 +202,10 @@
template <typename D>
double SingleChiSquaredTest();
- absl::InsecureBitGen rng_;
+ // We use a fixed bit generator for distribution accuracy tests. This allows
+ // these tests to be deterministic, while still testing the qualify of the
+ // implementation.
+ absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
};
template <typename D>
diff --git a/third_party/abseil/absl/random/gaussian_distribution.cc b/third_party/abseil/absl/random/gaussian_distribution.cc
index 5dd8461..c7a72cb 100644
--- a/third_party/abseil/absl/random/gaussian_distribution.cc
+++ b/third_party/abseil/absl/random/gaussian_distribution.cc
@@ -4,6 +4,7 @@
#include "absl/random/gaussian_distribution.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
const gaussian_distribution_base::Tables
@@ -96,6 +97,7 @@
0.9362826816850632339, 0.9635996931270905952, 1}};
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
// clang-format on
diff --git a/third_party/abseil/absl/random/gaussian_distribution.h b/third_party/abseil/absl/random/gaussian_distribution.h
index 1d1347b..4b07a5c 100644
--- a/third_party/abseil/absl/random/gaussian_distribution.h
+++ b/third_party/abseil/absl/random/gaussian_distribution.h
@@ -28,11 +28,13 @@
#include <limits>
#include <type_traits>
-#include "absl/random/internal/distribution_impl.h"
+#include "absl/base/config.h"
#include "absl/random/internal/fast_uniform_bits.h"
+#include "absl/random/internal/generate_real.h"
#include "absl/random/internal/iostream_state_saver.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
// absl::gaussian_distribution_base implements the underlying ziggurat algorithm
@@ -42,7 +44,7 @@
// The specific algorithm has some of the improvements suggested by the
// 2005 paper, "An Improved Ziggurat Method to Generate Normal Random Samples",
// Jurgen A Doornik. (https://www.doornik.com/research/ziggurat.pdf)
-class gaussian_distribution_base {
+class ABSL_DLL gaussian_distribution_base {
public:
template <typename URBG>
inline double zignor(URBG& g); // NOLINT(runtime/references)
@@ -207,12 +209,18 @@
template <typename URBG>
inline double gaussian_distribution_base::zignor_fallback(URBG& g, bool neg) {
+ using random_internal::GeneratePositiveTag;
+ using random_internal::GenerateRealFromBits;
+
// This fallback path happens approximately 0.05% of the time.
double x, y;
do {
// kRInv = 1/r, U(0, 1)
- x = kRInv * std::log(RandU64ToDouble<PositiveValueT, false>(fast_u64_(g)));
- y = -std::log(RandU64ToDouble<PositiveValueT, false>(fast_u64_(g)));
+ x = kRInv *
+ std::log(GenerateRealFromBits<double, GeneratePositiveTag, false>(
+ fast_u64_(g)));
+ y = -std::log(
+ GenerateRealFromBits<double, GeneratePositiveTag, false>(fast_u64_(g)));
} while ((y + y) < (x * x));
return neg ? (x - kR) : (kR - x);
}
@@ -220,6 +228,10 @@
template <typename URBG>
inline double gaussian_distribution_base::zignor(
URBG& g) { // NOLINT(runtime/references)
+ using random_internal::GeneratePositiveTag;
+ using random_internal::GenerateRealFromBits;
+ using random_internal::GenerateSignedTag;
+
while (true) {
// We use a single uint64_t to generate both a double and a strip.
// These bits are unused when the generated double is > 1/2^5.
@@ -227,7 +239,8 @@
// values (those smaller than 1/2^5, which all end up on the left tail).
uint64_t bits = fast_u64_(g);
int i = static_cast<int>(bits & kMask); // pick a random strip
- double j = RandU64ToDouble<SignedValueT, false>(bits); // U(-1, 1)
+ double j = GenerateRealFromBits<double, GenerateSignedTag, false>(
+ bits); // U(-1, 1)
const double x = j * zg_.x[i];
// Retangular box. Handles >97% of all cases.
@@ -244,7 +257,8 @@
}
// i > 0: Wedge samples using precomputed values.
- double v = RandU64ToDouble<PositiveValueT, false>(fast_u64_(g)); // U(0, 1)
+ double v = GenerateRealFromBits<double, GeneratePositiveTag, false>(
+ fast_u64_(g)); // U(0, 1)
if ((zg_.f[i + 1] + v * (zg_.f[i] - zg_.f[i + 1])) <
std::exp(-0.5 * x * x)) {
return x;
@@ -255,6 +269,7 @@
}
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_GAUSSIAN_DISTRIBUTION_H_
diff --git a/third_party/abseil/absl/random/gaussian_distribution_test.cc b/third_party/abseil/absl/random/gaussian_distribution_test.cc
index 49c0751..2aa7caf 100644
--- a/third_party/abseil/absl/random/gaussian_distribution_test.cc
+++ b/third_party/abseil/absl/random/gaussian_distribution_test.cc
@@ -213,7 +213,10 @@
template <typename D>
double SingleChiSquaredTest();
- absl::InsecureBitGen rng_;
+ // We use a fixed bit generator for distribution accuracy tests. This allows
+ // these tests to be deterministic, while still testing the qualify of the
+ // implementation.
+ absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
};
template <typename D>
diff --git a/third_party/abseil/absl/random/internal/BUILD.bazel b/third_party/abseil/absl/random/internal/BUILD.bazel
index d394045..2c1a5f4 100644
--- a/third_party/abseil/absl/random/internal/BUILD.bazel
+++ b/third_party/abseil/absl/random/internal/BUILD.bazel
@@ -14,7 +14,7 @@
# limitations under the License.
#
-#load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
+load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
# Internal-only implementation classes for Abseil Random
load(
@@ -30,16 +30,13 @@
"//absl/random:__pkg__",
])
-licenses(["notice"]) # Apache 2.0
+licenses(["notice"])
cc_library(
name = "traits",
hdrs = ["traits.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
- visibility = [
- "//absl/random:__pkg__",
- ],
deps = ["//absl/base:config"],
)
@@ -48,23 +45,10 @@
hdrs = ["distribution_caller.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
- visibility = [
- "//absl/random:__pkg__",
- ],
-)
-
-cc_library(
- name = "distributions",
- hdrs = ["distributions.h"],
- copts = ABSL_DEFAULT_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
- ":distribution_caller",
- ":traits",
- ":uniform_helper",
- "//absl/base",
- "//absl/meta:type_traits",
- "//absl/strings",
+ "//absl/base:config",
+ "//absl/base:fast_type_id",
+ "//absl/utility",
],
)
@@ -75,8 +59,9 @@
],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
- visibility = [
- "//absl/random:__pkg__",
+ deps = [
+ "//absl/base:config",
+ "//absl/meta:type_traits",
],
)
@@ -89,7 +74,10 @@
"seed_material.h",
],
copts = ABSL_DEFAULT_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS + select({
+ "//absl:windows": ["-DEFAULTLIB:bcrypt.lib"],
+ "//conditions:default": [],
+ }),
deps = [
":fast_uniform_bits",
"//absl/base:core_headers",
@@ -109,7 +97,11 @@
"pool_urbg.h",
],
copts = ABSL_DEFAULT_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
+ linkopts = select({
+ "//absl:windows": [],
+ "//absl:wasm": [],
+ "//conditions:default": ["-pthread"],
+ }) + ABSL_DEFAULT_LINKOPTS,
deps = [
":randen",
":seed_material",
@@ -132,6 +124,7 @@
],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = ["//absl/base:config"],
)
cc_library(
@@ -142,6 +135,7 @@
],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = ["//absl/base:config"],
)
cc_library(
@@ -172,18 +166,17 @@
)
cc_library(
- name = "distribution_impl",
+ name = "generate_real",
hdrs = [
- "distribution_impl.h",
+ "generate_real.h",
],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":fastmath",
":traits",
- "//absl/base:bits",
- "//absl/base:config",
- "//absl/numeric:int128",
+ "//absl/meta:type_traits",
+ "//absl/numeric:bits",
],
)
@@ -194,7 +187,20 @@
],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
- deps = ["//absl/base:bits"],
+ deps = ["//absl/numeric:bits"],
+)
+
+cc_library(
+ name = "wide_multiply",
+ hdrs = ["wide_multiply.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":traits",
+ "//absl/base:config",
+ "//absl/numeric:bits",
+ "//absl/numeric:int128",
+ ],
)
cc_library(
@@ -208,7 +214,6 @@
":seed_material",
"//absl/base:core_headers",
"//absl/meta:type_traits",
- "//absl/strings",
"//absl/types:optional",
"//absl/types:span",
],
@@ -224,6 +229,7 @@
":iostream_state_saver",
"//absl/base:config",
"//absl/meta:type_traits",
+ "//absl/numeric:bits",
"//absl/numeric:int128",
],
)
@@ -242,15 +248,18 @@
cc_library(
name = "platform",
+ srcs = [
+ "randen_round_keys.cc",
+ ],
hdrs = [
"randen_traits.h",
],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
textual_hdrs = [
- "randen-keys.inc",
"platform.h",
],
+ deps = ["//absl/base:config"],
)
cc_library(
@@ -279,6 +288,8 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":platform",
+ "//absl/base:config",
+ "//absl/base:core_headers",
],
)
@@ -298,6 +309,7 @@
deps = [
":platform",
":randen_hwaes_impl",
+ "//absl/base:config",
],
)
@@ -312,13 +324,10 @@
"//absl:windows": [],
"//conditions:default": ["-Wno-pass-failed"],
}),
- # copts in RANDEN_HWAES_COPTS can make this target unusable as a module
- # leading to a Clang diagnostic. Furthermore, it only has a private header
- # anyway and thus there wouldn't be any gain from using it as a module.
- features = ["-header_modules"],
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":platform",
+ "//absl/base:config",
"//absl/base:core_headers",
],
)
@@ -349,6 +358,7 @@
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
+ "//absl/base:config",
"//absl/base:core_headers",
"//absl/base:raw_logging_internal",
"//absl/strings",
@@ -382,16 +392,17 @@
)
cc_test(
- name = "distribution_impl_test",
+ name = "generate_real_test",
size = "small",
- srcs = ["distribution_impl_test.cc"],
+ srcs = [
+ "generate_real_test.cc",
+ ],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
- ":distribution_impl",
- "//absl/base:bits",
+ ":generate_real",
"//absl/flags:flag",
- "//absl/numeric:int128",
+ "//absl/numeric:bits",
"@com_google_googletest//:gtest_main",
],
)
@@ -474,6 +485,26 @@
],
)
+cc_library(
+ name = "mock_helpers",
+ hdrs = ["mock_helpers.h"],
+ deps = [
+ "//absl/base:fast_type_id",
+ "//absl/types:optional",
+ ],
+)
+
+cc_library(
+ name = "mock_overload_set",
+ testonly = 1,
+ hdrs = ["mock_overload_set.h"],
+ deps = [
+ ":mock_helpers",
+ "//absl/random:mocking_bit_gen",
+ "@com_google_googletest//:gtest",
+ ],
+)
+
cc_test(
name = "nonsecure_base_test",
size = "small",
@@ -573,6 +604,7 @@
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
+ ":platform",
":randen_slow",
"@com_google_googletest//:gtest_main",
],
@@ -595,6 +627,20 @@
],
)
+cc_test(
+ name = "wide_multiply_test",
+ size = "small",
+ srcs = ["wide_multiply_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":wide_multiply",
+ "//absl/numeric:bits",
+ "//absl/numeric:int128",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
cc_library(
name = "nanobenchmark",
srcs = ["nanobenchmark.cc"],
@@ -603,6 +649,8 @@
deps = [
":platform",
":randen_engine",
+ "//absl/base:config",
+ "//absl/base:core_headers",
"//absl/base:raw_logging_internal",
],
)
@@ -613,6 +661,8 @@
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
+ ":traits",
+ "//absl/base:config",
"//absl/meta:type_traits",
],
)
@@ -638,6 +688,7 @@
cc_test(
name = "randen_benchmarks",
size = "medium",
+ timeout = "long",
srcs = ["randen_benchmarks.cc"],
copts = ABSL_TEST_COPTS + ABSL_RANDOM_RANDEN_COPTS,
flaky = 1,
@@ -666,3 +717,15 @@
"@com_google_googletest//:gtest_main",
],
)
+
+cc_test(
+ name = "uniform_helper_test",
+ size = "small",
+ srcs = ["uniform_helper_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":uniform_helper",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/third_party/abseil/absl/random/internal/chi_square.cc b/third_party/abseil/absl/random/internal/chi_square.cc
index c0acc94..640d48c 100644
--- a/third_party/abseil/absl/random/internal/chi_square.cc
+++ b/third_party/abseil/absl/random/internal/chi_square.cc
@@ -19,6 +19,7 @@
#include "absl/random/internal/distribution_test_util.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
namespace {
@@ -227,4 +228,5 @@
}
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/random/internal/chi_square.h b/third_party/abseil/absl/random/internal/chi_square.h
index fa8646f..07f4fbe 100644
--- a/third_party/abseil/absl/random/internal/chi_square.h
+++ b/third_party/abseil/absl/random/internal/chi_square.h
@@ -26,7 +26,10 @@
#include <cassert>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
constexpr const char kChiSquared[] = "chi-squared";
@@ -80,6 +83,7 @@
double ChiSquarePValue(double chi_square, int dof);
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_CHI_SQUARE_H_
diff --git a/third_party/abseil/absl/random/internal/distribution_caller.h b/third_party/abseil/absl/random/internal/distribution_caller.h
index 0318e1f..fc81b78 100644
--- a/third_party/abseil/absl/random/internal/distribution_caller.h
+++ b/third_party/abseil/absl/random/internal/distribution_caller.h
@@ -19,7 +19,12 @@
#include <utility>
+#include "absl/base/config.h"
+#include "absl/base/internal/fast_type_id.h"
+#include "absl/utility/utility.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
// DistributionCaller provides an opportunity to overload the general
@@ -27,30 +32,61 @@
// to intercept such calls.
template <typename URBG>
struct DistributionCaller {
- // Call the provided distribution type. The parameters are expected
- // to be explicitly specified.
- // DistrT is the distribution type.
- // FormatT is the formatter type:
+ // SFINAE to detect whether the URBG type includes a member matching
+ // bool InvokeMock(base_internal::FastTypeIdType, void*, void*).
//
- // struct FormatT {
- // using result_type = distribution_t::result_type;
- // static std::string FormatCall(
- // const distribution_t& distr,
- // absl::Span<const result_type>);
- //
- // static std::string FormatExpectation(
- // absl::string_view match_args,
- // absl::Span<const result_t> results);
- // }
- //
- template <typename DistrT, typename FormatT, typename... Args>
- static typename DistrT::result_type Call(URBG* urbg, Args&&... args) {
+ // These live inside BitGenRef so that they have friend access
+ // to MockingBitGen. (see similar methods in DistributionCaller).
+ template <template <class...> class Trait, class AlwaysVoid, class... Args>
+ struct detector : std::false_type {};
+ template <template <class...> class Trait, class... Args>
+ struct detector<Trait, absl::void_t<Trait<Args...>>, Args...>
+ : std::true_type {};
+
+ template <class T>
+ using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock(
+ std::declval<::absl::base_internal::FastTypeIdType>(),
+ std::declval<void*>(), std::declval<void*>()));
+
+ using HasInvokeMock = typename detector<invoke_mock_t, void, URBG>::type;
+
+ // Default implementation of distribution caller.
+ template <typename DistrT, typename... Args>
+ static typename DistrT::result_type Impl(std::false_type, URBG* urbg,
+ Args&&... args) {
DistrT dist(std::forward<Args>(args)...);
return dist(*urbg);
}
+
+ // Mock implementation of distribution caller.
+ // The underlying KeyT must match the KeyT constructed by MockOverloadSet.
+ template <typename DistrT, typename... Args>
+ static typename DistrT::result_type Impl(std::true_type, URBG* urbg,
+ Args&&... args) {
+ using ResultT = typename DistrT::result_type;
+ using ArgTupleT = std::tuple<absl::decay_t<Args>...>;
+ using KeyT = ResultT(DistrT, ArgTupleT);
+
+ ArgTupleT arg_tuple(std::forward<Args>(args)...);
+ ResultT result;
+ if (!urbg->InvokeMock(::absl::base_internal::FastTypeId<KeyT>(), &arg_tuple,
+ &result)) {
+ auto dist = absl::make_from_tuple<DistrT>(arg_tuple);
+ result = dist(*urbg);
+ }
+ return result;
+ }
+
+ // Default implementation of distribution caller.
+ template <typename DistrT, typename... Args>
+ static typename DistrT::result_type Call(URBG* urbg, Args&&... args) {
+ return Impl<DistrT, Args...>(HasInvokeMock{}, urbg,
+ std::forward<Args>(args)...);
+ }
};
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_DISTRIBUTION_CALLER_H_
diff --git a/third_party/abseil/absl/random/internal/distribution_impl.h b/third_party/abseil/absl/random/internal/distribution_impl.h
deleted file mode 100644
index 9b6ffb0..0000000
--- a/third_party/abseil/absl/random/internal/distribution_impl.h
+++ /dev/null
@@ -1,260 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef ABSL_RANDOM_INTERNAL_DISTRIBUTION_IMPL_H_
-#define ABSL_RANDOM_INTERNAL_DISTRIBUTION_IMPL_H_
-
-// This file contains some implementation details which are used by one or more
-// of the absl random number distributions.
-
-#include <cfloat>
-#include <cstddef>
-#include <cstdint>
-#include <cstring>
-#include <limits>
-#include <type_traits>
-
-#if (defined(_WIN32) || defined(_WIN64)) && defined(_M_IA64)
-#include <intrin.h> // NOLINT(build/include_order)
-#pragma intrinsic(_umul128)
-#define ABSL_INTERNAL_USE_UMUL128 1
-#endif
-
-#include "absl/base/config.h"
-#include "absl/base/internal/bits.h"
-#include "absl/numeric/int128.h"
-#include "absl/random/internal/fastmath.h"
-#include "absl/random/internal/traits.h"
-
-namespace absl {
-namespace random_internal {
-
-// Creates a double from `bits`, with the template fields controlling the
-// output.
-//
-// RandU64To is both more efficient and generates more unique values in the
-// result interval than known implementations of std::generate_canonical().
-//
-// The `Signed` parameter controls whether positive, negative, or both are
-// returned (thus affecting the output interval).
-// When Signed == SignedValueT, range is U(-1, 1)
-// When Signed == NegativeValueT, range is U(-1, 0)
-// When Signed == PositiveValueT, range is U(0, 1)
-//
-// When the `IncludeZero` parameter is true, the function may return 0 for some
-// inputs, otherwise it never returns 0.
-//
-// The `ExponentBias` parameter determines the scale of the output range by
-// adjusting the exponent.
-//
-// When a value in U(0,1) is required, use:
-// RandU64ToDouble<PositiveValueT, true, 0>();
-//
-// When a value in U(-1,1) is required, use:
-// RandU64ToDouble<SignedValueT, false, 0>() => U(-1, 1)
-// This generates more distinct values than the mathematically equivalent
-// expression `U(0, 1) * 2.0 - 1.0`, and is preferable.
-//
-// Scaling the result by powers of 2 (and avoiding a multiply) is also possible:
-// RandU64ToDouble<PositiveValueT, false, 1>(); => U(0, 2)
-// RandU64ToDouble<PositiveValueT, false, -1>(); => U(0, 0.5)
-//
-
-// Tristate types controlling the output.
-struct PositiveValueT {};
-struct NegativeValueT {};
-struct SignedValueT {};
-
-// RandU64ToDouble is the double-result variant of RandU64To, described above.
-template <typename Signed, bool IncludeZero, int ExponentBias = 0>
-inline double RandU64ToDouble(uint64_t bits) {
- static_assert(std::is_same<Signed, PositiveValueT>::value ||
- std::is_same<Signed, NegativeValueT>::value ||
- std::is_same<Signed, SignedValueT>::value,
- "");
-
- // Maybe use the left-most bit for a sign bit.
- uint64_t sign = std::is_same<Signed, NegativeValueT>::value
- ? 0x8000000000000000ull
- : 0; // Sign bits.
-
- if (std::is_same<Signed, SignedValueT>::value) {
- sign = bits & 0x8000000000000000ull;
- bits = bits & 0x7FFFFFFFFFFFFFFFull;
- }
- if (IncludeZero) {
- if (bits == 0u) return 0;
- }
-
- // Number of leading zeros is mapped to the exponent: 2^-clz
- int clz = base_internal::CountLeadingZeros64(bits);
- // Shift number left to erase leading zeros.
- bits <<= IncludeZero ? clz : (clz & 63);
-
- // Shift number right to remove bits that overflow double mantissa. The
- // direction of the shift depends on `clz`.
- bits >>= (64 - DBL_MANT_DIG);
-
- // Compute IEEE 754 double exponent.
- // In the Signed case, bits is a 63-bit number with a 0 msb. Adjust the
- // exponent to account for that.
- const uint64_t exp =
- (std::is_same<Signed, SignedValueT>::value ? 1023U : 1022U) +
- static_cast<uint64_t>(ExponentBias - clz);
- constexpr int kExp = DBL_MANT_DIG - 1;
- // Construct IEEE 754 double from exponent and mantissa.
- const uint64_t val = sign | (exp << kExp) | (bits & ((1ULL << kExp) - 1U));
-
- double res;
- static_assert(sizeof(res) == sizeof(val), "double is not 64 bit");
- // Memcpy value from "val" to "res" to avoid aliasing problems. Assumes that
- // endian-ness is same for double and uint64_t.
- std::memcpy(&res, &val, sizeof(res));
-
- return res;
-}
-
-// RandU64ToFloat is the float-result variant of RandU64To, described above.
-template <typename Signed, bool IncludeZero, int ExponentBias = 0>
-inline float RandU64ToFloat(uint64_t bits) {
- static_assert(std::is_same<Signed, PositiveValueT>::value ||
- std::is_same<Signed, NegativeValueT>::value ||
- std::is_same<Signed, SignedValueT>::value,
- "");
-
- // Maybe use the left-most bit for a sign bit.
- uint64_t sign = std::is_same<Signed, NegativeValueT>::value
- ? 0x80000000ul
- : 0; // Sign bits.
-
- if (std::is_same<Signed, SignedValueT>::value) {
- uint64_t a = bits & 0x8000000000000000ull;
- sign = static_cast<uint32_t>(a >> 32);
- bits = bits & 0x7FFFFFFFFFFFFFFFull;
- }
- if (IncludeZero) {
- if (bits == 0u) return 0;
- }
-
- // Number of leading zeros is mapped to the exponent: 2^-clz
- int clz = base_internal::CountLeadingZeros64(bits);
- // Shift number left to erase leading zeros.
- bits <<= IncludeZero ? clz : (clz & 63);
- // Shift number right to remove bits that overflow double mantissa. The
- // direction of the shift depends on `clz`.
- bits >>= (64 - FLT_MANT_DIG);
-
- // Construct IEEE 754 float exponent.
- // In the Signed case, bits is a 63-bit number with a 0 msb. Adjust the
- // exponent to account for that.
- const uint32_t exp =
- (std::is_same<Signed, SignedValueT>::value ? 127U : 126U) +
- static_cast<uint32_t>(ExponentBias - clz);
- constexpr int kExp = FLT_MANT_DIG - 1;
- const uint32_t val = sign | (exp << kExp) | (bits & ((1U << kExp) - 1U));
-
- float res;
- static_assert(sizeof(res) == sizeof(val), "float is not 32 bit");
- // Assumes that endian-ness is same for float and uint32_t.
- std::memcpy(&res, &val, sizeof(res));
-
- return res;
-}
-
-template <typename Result>
-struct RandU64ToReal {
- template <typename Signed, bool IncludeZero, int ExponentBias = 0>
- static inline Result Value(uint64_t bits) {
- return RandU64ToDouble<Signed, IncludeZero, ExponentBias>(bits);
- }
-};
-
-template <>
-struct RandU64ToReal<float> {
- template <typename Signed, bool IncludeZero, int ExponentBias = 0>
- static inline float Value(uint64_t bits) {
- return RandU64ToFloat<Signed, IncludeZero, ExponentBias>(bits);
- }
-};
-
-inline uint128 MultiplyU64ToU128(uint64_t a, uint64_t b) {
-#if defined(ABSL_HAVE_INTRINSIC_INT128)
- return uint128(static_cast<__uint128_t>(a) * b);
-#elif defined(ABSL_INTERNAL_USE_UMUL128)
- // uint64_t * uint64_t => uint128 multiply using imul intrinsic on MSVC.
- uint64_t high = 0;
- const uint64_t low = _umul128(a, b, &high);
- return absl::MakeUint128(high, low);
-#else
- // uint128(a) * uint128(b) in emulated mode computes a full 128-bit x 128-bit
- // multiply. However there are many cases where that is not necessary, and it
- // is only necessary to support a 64-bit x 64-bit = 128-bit multiply. This is
- // for those cases.
- const uint64_t a00 = static_cast<uint32_t>(a);
- const uint64_t a32 = a >> 32;
- const uint64_t b00 = static_cast<uint32_t>(b);
- const uint64_t b32 = b >> 32;
-
- const uint64_t c00 = a00 * b00;
- const uint64_t c32a = a00 * b32;
- const uint64_t c32b = a32 * b00;
- const uint64_t c64 = a32 * b32;
-
- const uint32_t carry =
- static_cast<uint32_t>(((c00 >> 32) + static_cast<uint32_t>(c32a) +
- static_cast<uint32_t>(c32b)) >>
- 32);
-
- return absl::MakeUint128(c64 + (c32a >> 32) + (c32b >> 32) + carry,
- c00 + (c32a << 32) + (c32b << 32));
-#endif
-}
-
-// wide_multiply<T> multiplies two N-bit values to a 2N-bit result.
-template <typename UIntType>
-struct wide_multiply {
- static constexpr size_t kN = std::numeric_limits<UIntType>::digits;
- using input_type = UIntType;
- using result_type = typename random_internal::unsigned_bits<kN * 2>::type;
-
- static result_type multiply(input_type a, input_type b) {
- return static_cast<result_type>(a) * b;
- }
-
- static input_type hi(result_type r) { return r >> kN; }
- static input_type lo(result_type r) { return r; }
-
- static_assert(std::is_unsigned<UIntType>::value,
- "Class-template wide_multiply<> argument must be unsigned.");
-};
-
-#ifndef ABSL_HAVE_INTRINSIC_INT128
-template <>
-struct wide_multiply<uint64_t> {
- using input_type = uint64_t;
- using result_type = uint128;
-
- static result_type multiply(uint64_t a, uint64_t b) {
- return MultiplyU64ToU128(a, b);
- }
-
- static uint64_t hi(result_type r) { return Uint128High64(r); }
- static uint64_t lo(result_type r) { return Uint128Low64(r); }
-};
-#endif
-
-} // namespace random_internal
-} // namespace absl
-
-#endif // ABSL_RANDOM_INTERNAL_DISTRIBUTION_IMPL_H_
diff --git a/third_party/abseil/absl/random/internal/distribution_test_util.cc b/third_party/abseil/absl/random/internal/distribution_test_util.cc
index 85c8d59..e900565 100644
--- a/third_party/abseil/absl/random/internal/distribution_test_util.cc
+++ b/third_party/abseil/absl/random/internal/distribution_test_util.cc
@@ -25,6 +25,7 @@
#include "absl/strings/str_format.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
namespace {
@@ -413,4 +414,5 @@
}
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/random/internal/distribution_test_util.h b/third_party/abseil/absl/random/internal/distribution_test_util.h
index b5ba49f..6d94cf6 100644
--- a/third_party/abseil/absl/random/internal/distribution_test_util.h
+++ b/third_party/abseil/absl/random/internal/distribution_test_util.h
@@ -26,6 +26,7 @@
// non-test code.
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
// http://webspace.ship.edu/pgmarr/Geo441/Lectures/Lec%205%20-%20Normality%20Testing.pdf
@@ -106,6 +107,7 @@
double BetaIncompleteInv(double p, double q, double alpha);
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_DISTRIBUTION_TEST_UTIL_H_
diff --git a/third_party/abseil/absl/random/internal/distributions.h b/third_party/abseil/absl/random/internal/distributions.h
deleted file mode 100644
index 96f8bae..0000000
--- a/third_party/abseil/absl/random/internal/distributions.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2019 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef ABSL_RANDOM_INTERNAL_DISTRIBUTIONS_H_
-#define ABSL_RANDOM_INTERNAL_DISTRIBUTIONS_H_
-
-#include <type_traits>
-
-#include "absl/meta/type_traits.h"
-#include "absl/random/internal/distribution_caller.h"
-#include "absl/random/internal/traits.h"
-#include "absl/random/internal/uniform_helper.h"
-
-namespace absl {
-namespace random_internal {
-template <typename D>
-struct DistributionFormatTraits;
-
-// UniformImpl implements the core logic of the Uniform<T> call, which is to
-// select the correct distribution type, compute the bounds based on the
-// interval tag, and then generate a value.
-template <typename NumType, typename TagType, typename URBG>
-NumType UniformImpl(TagType tag,
- URBG& urbg, // NOLINT(runtime/references)
- NumType lo, NumType hi) {
- static_assert(
- std::is_arithmetic<NumType>::value,
- "absl::Uniform<T>() must use an integer or real parameter type.");
-
- using distribution_t =
- UniformDistributionWrapper<absl::decay_t<TagType>, NumType>;
- using format_t = random_internal::DistributionFormatTraits<distribution_t>;
- auto a = uniform_lower_bound(tag, lo, hi);
- auto b = uniform_upper_bound(tag, lo, hi);
-
- // TODO(lar): it doesn't make a lot of sense to ask for a random number in an
- // empty range. Right now we just return a boundary--even though that
- // boundary is not an acceptable value! Is there something better we can do
- // here?
- if (a > b) return a;
-
- using gen_t = absl::decay_t<URBG>;
- return DistributionCaller<gen_t>::template Call<distribution_t, format_t>(
- &urbg, tag, lo, hi);
-}
-
-// In the absence of an explicitly provided return-type, the template
-// "uniform_inferred_return_t<A, B>" is used to derive a suitable type, based on
-// the data-types of the endpoint-arguments {A lo, B hi}.
-//
-// Given endpoints {A lo, B hi}, one of {A, B} will be chosen as the
-// return-type, if one type can be implicitly converted into the other, in a
-// lossless way. The template "is_widening_convertible" implements the
-// compile-time logic for deciding if such a conversion is possible.
-//
-// If no such conversion between {A, B} exists, then the overload for
-// absl::Uniform() will be discarded, and the call will be ill-formed.
-// Return-type for absl::Uniform() when the return-type is inferred.
-template <typename A, typename B>
-using uniform_inferred_return_t =
- absl::enable_if_t<absl::disjunction<is_widening_convertible<A, B>,
- is_widening_convertible<B, A>>::value,
- typename std::conditional<
- is_widening_convertible<A, B>::value, B, A>::type>;
-
-} // namespace random_internal
-} // namespace absl
-
-#endif // ABSL_RANDOM_INTERNAL_DISTRIBUTIONS_H_
diff --git a/third_party/abseil/absl/random/internal/explicit_seed_seq.h b/third_party/abseil/absl/random/internal/explicit_seed_seq.h
index b660ece..6a743ea 100644
--- a/third_party/abseil/absl/random/internal/explicit_seed_seq.h
+++ b/third_party/abseil/absl/random/internal/explicit_seed_seq.h
@@ -22,7 +22,10 @@
#include <iterator>
#include <vector>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
// This class conforms to the C++ Standard "Seed Sequence" concept
@@ -82,6 +85,7 @@
};
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_EXPLICIT_SEED_SEQ_H_
diff --git a/third_party/abseil/absl/random/internal/fast_uniform_bits.h b/third_party/abseil/absl/random/internal/fast_uniform_bits.h
index e8df92f..425aaf7 100644
--- a/third_party/abseil/absl/random/internal/fast_uniform_bits.h
+++ b/third_party/abseil/absl/random/internal/fast_uniform_bits.h
@@ -20,7 +20,11 @@
#include <limits>
#include <type_traits>
+#include "absl/base/config.h"
+#include "absl/meta/type_traits.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
// Returns true if the input value is zero or a power of two. Useful for
// determining if the range of output values in a URBG
@@ -35,28 +39,17 @@
template <typename URBG>
constexpr typename URBG::result_type RangeSize() {
using result_type = typename URBG::result_type;
+ static_assert((URBG::max)() != (URBG::min)(), "URBG range cannot be 0.");
return ((URBG::max)() == (std::numeric_limits<result_type>::max)() &&
(URBG::min)() == std::numeric_limits<result_type>::lowest())
? result_type{0}
- : (URBG::max)() - (URBG::min)() + result_type{1};
-}
-
-template <typename UIntType>
-constexpr UIntType LargestPowerOfTwoLessThanOrEqualTo(UIntType n) {
- return n < 2 ? n : 2 * LargestPowerOfTwoLessThanOrEqualTo(n / 2);
-}
-
-// Given a URBG generating values in the closed interval [Lo, Hi], returns the
-// largest power of two less than or equal to `Hi - Lo + 1`.
-template <typename URBG>
-constexpr typename URBG::result_type PowerOfTwoSubRangeSize() {
- return LargestPowerOfTwoLessThanOrEqualTo(RangeSize<URBG>());
+ : ((URBG::max)() - (URBG::min)() + result_type{1});
}
// Computes the floor of the log. (i.e., std::floor(std::log2(N));
template <typename UIntType>
constexpr UIntType IntegerLog2(UIntType n) {
- return (n <= 1) ? 0 : 1 + IntegerLog2(n / 2);
+ return (n <= 1) ? 0 : 1 + IntegerLog2(n >> 1);
}
// Returns the number of bits of randomness returned through
@@ -65,18 +58,23 @@
constexpr size_t NumBits() {
return RangeSize<URBG>() == 0
? std::numeric_limits<typename URBG::result_type>::digits
- : IntegerLog2(PowerOfTwoSubRangeSize<URBG>());
+ : IntegerLog2(RangeSize<URBG>());
}
// Given a shift value `n`, constructs a mask with exactly the low `n` bits set.
// If `n == 0`, all bits are set.
template <typename UIntType>
-constexpr UIntType MaskFromShift(UIntType n) {
+constexpr UIntType MaskFromShift(size_t n) {
return ((n % std::numeric_limits<UIntType>::digits) == 0)
? ~UIntType{0}
: (UIntType{1} << n) - UIntType{1};
}
+// Tags used to dispatch FastUniformBits::generate to the simple or more complex
+// entropy extraction algorithm.
+struct SimplifiedLoopTag {};
+struct RejectionLoopTag {};
+
// FastUniformBits implements a fast path to acquire uniform independent bits
// from a type which conforms to the [rand.req.urbg] concept.
// Parameterized by:
@@ -104,50 +102,16 @@
"Class-template FastUniformBits<> must be parameterized using "
"an unsigned type.");
- // PowerOfTwoVariate() generates a single random variate, always returning a
- // value in the half-open interval `[0, PowerOfTwoSubRangeSize<URBG>())`. If
- // the URBG already generates values in a power-of-two range, the generator
- // itself is used. Otherwise, we use rejection sampling on the largest
- // possible power-of-two-sized subrange.
- struct PowerOfTwoTag {};
- struct RejectionSamplingTag {};
- template <typename URBG>
- static typename URBG::result_type PowerOfTwoVariate(
- URBG& g) { // NOLINT(runtime/references)
- using tag =
- typename std::conditional<IsPowerOfTwoOrZero(RangeSize<URBG>()),
- PowerOfTwoTag, RejectionSamplingTag>::type;
- return PowerOfTwoVariate(g, tag{});
- }
-
- template <typename URBG>
- static typename URBG::result_type PowerOfTwoVariate(
- URBG& g, // NOLINT(runtime/references)
- PowerOfTwoTag) {
- return g() - (URBG::min)();
- }
-
- template <typename URBG>
- static typename URBG::result_type PowerOfTwoVariate(
- URBG& g, // NOLINT(runtime/references)
- RejectionSamplingTag) {
- // Use rejection sampling to ensure uniformity across the range.
- typename URBG::result_type u;
- do {
- u = g() - (URBG::min)();
- } while (u >= PowerOfTwoSubRangeSize<URBG>());
- return u;
- }
-
// Generate() generates a random value, dispatched on whether
- // the underlying URBG must loop over multiple calls or not.
+ // the underlying URBG must use rejection sampling to generate a value,
+ // or whether a simplified loop will suffice.
template <typename URBG>
result_type Generate(URBG& g, // NOLINT(runtime/references)
- std::true_type /* avoid_looping */);
+ SimplifiedLoopTag);
template <typename URBG>
result_type Generate(URBG& g, // NOLINT(runtime/references)
- std::false_type /* avoid_looping */);
+ RejectionLoopTag);
};
template <typename UIntType>
@@ -159,31 +123,47 @@
// Y = (2 ^ kRange) - 1
static_assert((URBG::max)() > (URBG::min)(),
"URBG::max and URBG::min may not be equal.");
+
+ using tag = absl::conditional_t<IsPowerOfTwoOrZero(RangeSize<URBG>()),
+ SimplifiedLoopTag, RejectionLoopTag>;
+ return Generate(g, tag{});
+}
+
+template <typename UIntType>
+template <typename URBG>
+typename FastUniformBits<UIntType>::result_type
+FastUniformBits<UIntType>::Generate(URBG& g, // NOLINT(runtime/references)
+ SimplifiedLoopTag) {
+ // The simplified version of FastUniformBits works only on URBGs that have
+ // a range that is a power of 2. In this case we simply loop and shift without
+ // attempting to balance the bits across calls.
+ static_assert(IsPowerOfTwoOrZero(RangeSize<URBG>()),
+ "incorrect Generate tag for URBG instance");
+
+ static constexpr size_t kResultBits =
+ std::numeric_limits<result_type>::digits;
+ static constexpr size_t kUrbgBits = NumBits<URBG>();
+ static constexpr size_t kIters =
+ (kResultBits / kUrbgBits) + (kResultBits % kUrbgBits != 0);
+ static constexpr size_t kShift = (kIters == 1) ? 0 : kUrbgBits;
+ static constexpr auto kMin = (URBG::min)();
+
+ result_type r = static_cast<result_type>(g() - kMin);
+ for (size_t n = 1; n < kIters; ++n) {
+ r = (r << kShift) + static_cast<result_type>(g() - kMin);
+ }
+ return r;
+}
+
+template <typename UIntType>
+template <typename URBG>
+typename FastUniformBits<UIntType>::result_type
+FastUniformBits<UIntType>::Generate(URBG& g, // NOLINT(runtime/references)
+ RejectionLoopTag) {
+ static_assert(!IsPowerOfTwoOrZero(RangeSize<URBG>()),
+ "incorrect Generate tag for URBG instance");
using urbg_result_type = typename URBG::result_type;
- constexpr urbg_result_type kRangeMask =
- RangeSize<URBG>() == 0
- ? (std::numeric_limits<urbg_result_type>::max)()
- : static_cast<urbg_result_type>(PowerOfTwoSubRangeSize<URBG>() - 1);
- return Generate(g, std::integral_constant<bool, (kRangeMask >= (max)())>{});
-}
-template <typename UIntType>
-template <typename URBG>
-typename FastUniformBits<UIntType>::result_type
-FastUniformBits<UIntType>::Generate(URBG& g, // NOLINT(runtime/references)
- std::true_type /* avoid_looping */) {
- // The width of the result_type is less than than the width of the random bits
- // provided by URBG. Thus, generate a single value and then simply mask off
- // the required bits.
-
- return PowerOfTwoVariate(g) & (max)();
-}
-
-template <typename UIntType>
-template <typename URBG>
-typename FastUniformBits<UIntType>::result_type
-FastUniformBits<UIntType>::Generate(URBG& g, // NOLINT(runtime/references)
- std::false_type /* avoid_looping */) {
// See [rand.adapt.ibits] for more details on the constants calculated below.
//
// It is preferable to use roughly the same number of bits from each generator
@@ -196,21 +176,44 @@
// `kSmallIters` and `kLargeIters` times respectively such
// that
//
- // `kTotalWidth == kSmallIters * kSmallWidth
- // + kLargeIters * kLargeWidth`
+ // `kResultBits == kSmallIters * kSmallBits
+ // + kLargeIters * kLargeBits`
//
- // where `kTotalWidth` is the total number of bits in `result_type`.
+ // where `kResultBits` is the total number of bits in `result_type`.
//
- constexpr size_t kTotalWidth = std::numeric_limits<result_type>::digits;
- constexpr size_t kUrbgWidth = NumBits<URBG>();
- constexpr size_t kTotalIters =
- kTotalWidth / kUrbgWidth + (kTotalWidth % kUrbgWidth != 0);
- constexpr size_t kSmallWidth = kTotalWidth / kTotalIters;
- constexpr size_t kLargeWidth = kSmallWidth + 1;
+ static constexpr size_t kResultBits =
+ std::numeric_limits<result_type>::digits; // w
+ static constexpr urbg_result_type kUrbgRange = RangeSize<URBG>(); // R
+ static constexpr size_t kUrbgBits = NumBits<URBG>(); // m
+
+ // compute the initial estimate of the bits used.
+ // [rand.adapt.ibits] 2 (c)
+ static constexpr size_t kA = // ceil(w/m)
+ (kResultBits / kUrbgBits) + ((kResultBits % kUrbgBits) != 0); // n'
+
+ static constexpr size_t kABits = kResultBits / kA; // w0'
+ static constexpr urbg_result_type kARejection =
+ ((kUrbgRange >> kABits) << kABits); // y0'
+
+ // refine the selection to reduce the rejection frequency.
+ static constexpr size_t kTotalIters =
+ ((kUrbgRange - kARejection) <= (kARejection / kA)) ? kA : (kA + 1); // n
+
+ // [rand.adapt.ibits] 2 (b)
+ static constexpr size_t kSmallIters =
+ kTotalIters - (kResultBits % kTotalIters); // n0
+ static constexpr size_t kSmallBits = kResultBits / kTotalIters; // w0
+ static constexpr urbg_result_type kSmallRejection =
+ ((kUrbgRange >> kSmallBits) << kSmallBits); // y0
+
+ static constexpr size_t kLargeBits = kSmallBits + 1; // w0+1
+ static constexpr urbg_result_type kLargeRejection =
+ ((kUrbgRange >> kLargeBits) << kLargeBits); // y1
+
//
- // Because `kLargeWidth == kSmallWidth + 1`, it follows that
+ // Because `kLargeBits == kSmallBits + 1`, it follows that
//
- // `kTotalWidth == kTotalIters * kSmallWidth + kLargeIters`
+ // `kResultBits == kSmallIters * kSmallBits + kLargeIters`
//
// and therefore
//
@@ -221,40 +224,45 @@
// mentioned above, if the URBG width is a divisor of `kTotalWidth`, then
// there would be no need for any large iterations (i.e., one loop would
// suffice), and indeed, in this case, `kLargeIters` would be zero.
- constexpr size_t kLargeIters = kTotalWidth % kSmallWidth;
- constexpr size_t kSmallIters =
- (kTotalWidth - (kLargeWidth * kLargeIters)) / kSmallWidth;
+ static_assert(kResultBits == kSmallIters * kSmallBits +
+ (kTotalIters - kSmallIters) * kLargeBits,
+ "Error in looping constant calculations.");
- static_assert(
- kTotalWidth == kSmallIters * kSmallWidth + kLargeIters * kLargeWidth,
- "Error in looping constant calculations.");
+ // The small shift is essentially small bits, but due to the potential
+ // of generating a smaller result_type from a larger urbg type, the actual
+ // shift might be 0.
+ static constexpr size_t kSmallShift = kSmallBits % kResultBits;
+ static constexpr auto kSmallMask =
+ MaskFromShift<urbg_result_type>(kSmallShift);
+ static constexpr size_t kLargeShift = kLargeBits % kResultBits;
+ static constexpr auto kLargeMask =
+ MaskFromShift<urbg_result_type>(kLargeShift);
+
+ static constexpr auto kMin = (URBG::min)();
result_type s = 0;
-
- constexpr size_t kSmallShift = kSmallWidth % kTotalWidth;
- constexpr result_type kSmallMask = MaskFromShift(result_type{kSmallShift});
for (size_t n = 0; n < kSmallIters; ++n) {
- s = (s << kSmallShift) +
- (static_cast<result_type>(PowerOfTwoVariate(g)) & kSmallMask);
+ urbg_result_type v;
+ do {
+ v = g() - kMin;
+ } while (v >= kSmallRejection);
+
+ s = (s << kSmallShift) + static_cast<result_type>(v & kSmallMask);
}
- constexpr size_t kLargeShift = kLargeWidth % kTotalWidth;
- constexpr result_type kLargeMask = MaskFromShift(result_type{kLargeShift});
- for (size_t n = 0; n < kLargeIters; ++n) {
- s = (s << kLargeShift) +
- (static_cast<result_type>(PowerOfTwoVariate(g)) & kLargeMask);
+ for (size_t n = kSmallIters; n < kTotalIters; ++n) {
+ urbg_result_type v;
+ do {
+ v = g() - kMin;
+ } while (v >= kLargeRejection);
+
+ s = (s << kLargeShift) + static_cast<result_type>(v & kLargeMask);
}
-
- static_assert(
- kLargeShift == kSmallShift + 1 ||
- (kLargeShift == 0 &&
- kSmallShift == std::numeric_limits<result_type>::digits - 1),
- "Error in looping constant calculations");
-
return s;
}
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_FAST_UNIFORM_BITS_H_
diff --git a/third_party/abseil/absl/random/internal/fast_uniform_bits_test.cc b/third_party/abseil/absl/random/internal/fast_uniform_bits_test.cc
index 9f2e826..cee702d 100644
--- a/third_party/abseil/absl/random/internal/fast_uniform_bits_test.cc
+++ b/third_party/abseil/absl/random/internal/fast_uniform_bits_test.cc
@@ -19,6 +19,7 @@
#include "gtest/gtest.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
namespace {
@@ -33,8 +34,8 @@
using Limits = std::numeric_limits<TypeParam>;
using FastBits = FastUniformBits<TypeParam>;
- EXPECT_EQ(0, FastBits::min());
- EXPECT_EQ(Limits::max(), FastBits::max());
+ EXPECT_EQ(0, (FastBits::min)());
+ EXPECT_EQ((Limits::max)(), (FastBits::max)());
constexpr int kIters = 10000;
std::random_device rd;
@@ -42,8 +43,8 @@
FastBits fast;
for (int i = 0; i < kIters; i++) {
const auto v = fast(gen);
- EXPECT_LE(v, FastBits::max());
- EXPECT_GE(v, FastBits::min());
+ EXPECT_LE(v, (FastBits::max)());
+ EXPECT_GE(v, (FastBits::min)());
}
}
@@ -51,21 +52,26 @@
struct FakeUrbg {
using result_type = UIntType;
+ FakeUrbg() = default;
+ explicit FakeUrbg(bool r) : reject(r) {}
+
static constexpr result_type(max)() { return Hi; }
static constexpr result_type(min)() { return Lo; }
- result_type operator()() { return Val; }
-};
+ result_type operator()() {
+ // when reject is set, return Hi half the time.
+ return ((++calls % 2) == 1 && reject) ? Hi : Val;
+ }
-using UrngOddbits = FakeUrbg<uint8_t, 1, 0xfe, 0x73>;
-using Urng4bits = FakeUrbg<uint8_t, 1, 0x10, 2>;
-using Urng31bits = FakeUrbg<uint32_t, 1, 0xfffffffe, 0x60070f03>;
-using Urng32bits = FakeUrbg<uint32_t, 0, 0xffffffff, 0x74010f01>;
+ bool reject = false;
+ size_t calls = 0;
+};
TEST(FastUniformBitsTest, IsPowerOfTwoOrZero) {
EXPECT_TRUE(IsPowerOfTwoOrZero(uint8_t{0}));
EXPECT_TRUE(IsPowerOfTwoOrZero(uint8_t{1}));
EXPECT_TRUE(IsPowerOfTwoOrZero(uint8_t{2}));
EXPECT_FALSE(IsPowerOfTwoOrZero(uint8_t{3}));
+ EXPECT_TRUE(IsPowerOfTwoOrZero(uint8_t{4}));
EXPECT_TRUE(IsPowerOfTwoOrZero(uint8_t{16}));
EXPECT_FALSE(IsPowerOfTwoOrZero(uint8_t{17}));
EXPECT_FALSE(IsPowerOfTwoOrZero((std::numeric_limits<uint8_t>::max)()));
@@ -74,6 +80,7 @@
EXPECT_TRUE(IsPowerOfTwoOrZero(uint16_t{1}));
EXPECT_TRUE(IsPowerOfTwoOrZero(uint16_t{2}));
EXPECT_FALSE(IsPowerOfTwoOrZero(uint16_t{3}));
+ EXPECT_TRUE(IsPowerOfTwoOrZero(uint16_t{4}));
EXPECT_TRUE(IsPowerOfTwoOrZero(uint16_t{16}));
EXPECT_FALSE(IsPowerOfTwoOrZero(uint16_t{17}));
EXPECT_FALSE(IsPowerOfTwoOrZero((std::numeric_limits<uint16_t>::max)()));
@@ -90,183 +97,240 @@
EXPECT_TRUE(IsPowerOfTwoOrZero(uint64_t{1}));
EXPECT_TRUE(IsPowerOfTwoOrZero(uint64_t{2}));
EXPECT_FALSE(IsPowerOfTwoOrZero(uint64_t{3}));
+ EXPECT_TRUE(IsPowerOfTwoOrZero(uint64_t{4}));
EXPECT_TRUE(IsPowerOfTwoOrZero(uint64_t{64}));
EXPECT_FALSE(IsPowerOfTwoOrZero(uint64_t{17}));
EXPECT_FALSE(IsPowerOfTwoOrZero((std::numeric_limits<uint64_t>::max)()));
}
TEST(FastUniformBitsTest, IntegerLog2) {
- EXPECT_EQ(IntegerLog2(uint16_t{0}), 0);
- EXPECT_EQ(IntegerLog2(uint16_t{1}), 0);
- EXPECT_EQ(IntegerLog2(uint16_t{2}), 1);
- EXPECT_EQ(IntegerLog2(uint16_t{3}), 1);
- EXPECT_EQ(IntegerLog2(uint16_t{4}), 2);
- EXPECT_EQ(IntegerLog2(uint16_t{5}), 2);
- EXPECT_EQ(IntegerLog2(std::numeric_limits<uint64_t>::max()), 63);
+ EXPECT_EQ(0, IntegerLog2(uint16_t{0}));
+ EXPECT_EQ(0, IntegerLog2(uint16_t{1}));
+ EXPECT_EQ(1, IntegerLog2(uint16_t{2}));
+ EXPECT_EQ(1, IntegerLog2(uint16_t{3}));
+ EXPECT_EQ(2, IntegerLog2(uint16_t{4}));
+ EXPECT_EQ(2, IntegerLog2(uint16_t{5}));
+ EXPECT_EQ(2, IntegerLog2(uint16_t{7}));
+ EXPECT_EQ(3, IntegerLog2(uint16_t{8}));
+ EXPECT_EQ(63, IntegerLog2((std::numeric_limits<uint64_t>::max)()));
}
TEST(FastUniformBitsTest, RangeSize) {
- EXPECT_EQ((RangeSize<FakeUrbg<uint8_t, 0, 3>>()), 4);
- EXPECT_EQ((RangeSize<FakeUrbg<uint8_t, 2, 2>>()), 1);
- EXPECT_EQ((RangeSize<FakeUrbg<uint8_t, 2, 5>>()), 4);
- EXPECT_EQ((RangeSize<FakeUrbg<uint8_t, 2, 6>>()), 5);
- EXPECT_EQ((RangeSize<FakeUrbg<uint8_t, 2, 10>>()), 9);
+ EXPECT_EQ(2, (RangeSize<FakeUrbg<uint8_t, 0, 1>>()));
+ EXPECT_EQ(3, (RangeSize<FakeUrbg<uint8_t, 0, 2>>()));
+ EXPECT_EQ(4, (RangeSize<FakeUrbg<uint8_t, 0, 3>>()));
+ // EXPECT_EQ(0, (RangeSize<FakeUrbg<uint8_t, 2, 2>>()));
+ EXPECT_EQ(4, (RangeSize<FakeUrbg<uint8_t, 2, 5>>()));
+ EXPECT_EQ(5, (RangeSize<FakeUrbg<uint8_t, 2, 6>>()));
+ EXPECT_EQ(9, (RangeSize<FakeUrbg<uint8_t, 2, 10>>()));
EXPECT_EQ(
- (RangeSize<FakeUrbg<uint8_t, 0, std::numeric_limits<uint8_t>::max()>>()),
- 0);
+ 0, (RangeSize<
+ FakeUrbg<uint8_t, 0, (std::numeric_limits<uint8_t>::max)()>>()));
- EXPECT_EQ((RangeSize<FakeUrbg<uint16_t, 0, 3>>()), 4);
- EXPECT_EQ((RangeSize<FakeUrbg<uint16_t, 2, 2>>()), 1);
- EXPECT_EQ((RangeSize<FakeUrbg<uint16_t, 2, 5>>()), 4);
- EXPECT_EQ((RangeSize<FakeUrbg<uint16_t, 2, 6>>()), 5);
- EXPECT_EQ((RangeSize<FakeUrbg<uint16_t, 1000, 1017>>()), 18);
- EXPECT_EQ((RangeSize<
- FakeUrbg<uint16_t, 0, std::numeric_limits<uint16_t>::max()>>()),
- 0);
+ EXPECT_EQ(4, (RangeSize<FakeUrbg<uint16_t, 0, 3>>()));
+ EXPECT_EQ(4, (RangeSize<FakeUrbg<uint16_t, 2, 5>>()));
+ EXPECT_EQ(5, (RangeSize<FakeUrbg<uint16_t, 2, 6>>()));
+ EXPECT_EQ(18, (RangeSize<FakeUrbg<uint16_t, 1000, 1017>>()));
+ EXPECT_EQ(
+ 0, (RangeSize<
+ FakeUrbg<uint16_t, 0, (std::numeric_limits<uint16_t>::max)()>>()));
- EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 0, 3>>()), 4);
- EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 2, 2>>()), 1);
- EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 2, 5>>()), 4);
- EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 2, 6>>()), 5);
- EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 1000, 1017>>()), 18);
- EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 0, 0xffffffff>>()), 0);
- EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 1, 0xffffffff>>()), 0xffffffff);
- EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 1, 0xfffffffe>>()), 0xfffffffe);
- EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 2, 0xfffffffe>>()), 0xfffffffd);
- EXPECT_EQ((RangeSize<
- FakeUrbg<uint32_t, 0, std::numeric_limits<uint32_t>::max()>>()),
- 0);
+ EXPECT_EQ(4, (RangeSize<FakeUrbg<uint32_t, 0, 3>>()));
+ EXPECT_EQ(4, (RangeSize<FakeUrbg<uint32_t, 2, 5>>()));
+ EXPECT_EQ(5, (RangeSize<FakeUrbg<uint32_t, 2, 6>>()));
+ EXPECT_EQ(18, (RangeSize<FakeUrbg<uint32_t, 1000, 1017>>()));
+ EXPECT_EQ(0, (RangeSize<FakeUrbg<uint32_t, 0, 0xffffffff>>()));
+ EXPECT_EQ(0xffffffff, (RangeSize<FakeUrbg<uint32_t, 1, 0xffffffff>>()));
+ EXPECT_EQ(0xfffffffe, (RangeSize<FakeUrbg<uint32_t, 1, 0xfffffffe>>()));
+ EXPECT_EQ(0xfffffffd, (RangeSize<FakeUrbg<uint32_t, 2, 0xfffffffe>>()));
+ EXPECT_EQ(
+ 0, (RangeSize<
+ FakeUrbg<uint32_t, 0, (std::numeric_limits<uint32_t>::max)()>>()));
- EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 0, 3>>()), 4);
- EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 2, 2>>()), 1);
- EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 2, 5>>()), 4);
- EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 2, 6>>()), 5);
- EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 1000, 1017>>()), 18);
- EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 0, 0xffffffff>>()), 0x100000000ull);
- EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 1, 0xffffffff>>()), 0xffffffffull);
- EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 1, 0xfffffffe>>()), 0xfffffffeull);
- EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 2, 0xfffffffe>>()), 0xfffffffdull);
- EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 0, 0xffffffffffffffffull>>()), 0ull);
- EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 1, 0xffffffffffffffffull>>()),
- 0xffffffffffffffffull);
- EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 1, 0xfffffffffffffffeull>>()),
- 0xfffffffffffffffeull);
- EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 2, 0xfffffffffffffffeull>>()),
- 0xfffffffffffffffdull);
- EXPECT_EQ((RangeSize<
- FakeUrbg<uint64_t, 0, std::numeric_limits<uint64_t>::max()>>()),
- 0);
+ EXPECT_EQ(4, (RangeSize<FakeUrbg<uint64_t, 0, 3>>()));
+ EXPECT_EQ(4, (RangeSize<FakeUrbg<uint64_t, 2, 5>>()));
+ EXPECT_EQ(5, (RangeSize<FakeUrbg<uint64_t, 2, 6>>()));
+ EXPECT_EQ(18, (RangeSize<FakeUrbg<uint64_t, 1000, 1017>>()));
+ EXPECT_EQ(0x100000000, (RangeSize<FakeUrbg<uint64_t, 0, 0xffffffff>>()));
+ EXPECT_EQ(0xffffffff, (RangeSize<FakeUrbg<uint64_t, 1, 0xffffffff>>()));
+ EXPECT_EQ(0xfffffffe, (RangeSize<FakeUrbg<uint64_t, 1, 0xfffffffe>>()));
+ EXPECT_EQ(0xfffffffd, (RangeSize<FakeUrbg<uint64_t, 2, 0xfffffffe>>()));
+ EXPECT_EQ(0, (RangeSize<FakeUrbg<uint64_t, 0, 0xffffffffffffffff>>()));
+ EXPECT_EQ(0xffffffffffffffff,
+ (RangeSize<FakeUrbg<uint64_t, 1, 0xffffffffffffffff>>()));
+ EXPECT_EQ(0xfffffffffffffffe,
+ (RangeSize<FakeUrbg<uint64_t, 1, 0xfffffffffffffffe>>()));
+ EXPECT_EQ(0xfffffffffffffffd,
+ (RangeSize<FakeUrbg<uint64_t, 2, 0xfffffffffffffffe>>()));
+ EXPECT_EQ(
+ 0, (RangeSize<
+ FakeUrbg<uint64_t, 0, (std::numeric_limits<uint64_t>::max)()>>()));
}
-TEST(FastUniformBitsTest, PowerOfTwoSubRangeSize) {
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint8_t, 0, 3>>()), 4);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint8_t, 2, 2>>()), 1);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint8_t, 2, 5>>()), 4);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint8_t, 2, 6>>()), 4);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint8_t, 2, 10>>()), 8);
- EXPECT_EQ((PowerOfTwoSubRangeSize<
- FakeUrbg<uint8_t, 0, std::numeric_limits<uint8_t>::max()>>()),
- 0);
+// The constants need to be choosen so that an infinite rejection loop doesn't
+// happen...
+using Urng1_5bit = FakeUrbg<uint8_t, 0, 2, 0>; // ~1.5 bits (range 3)
+using Urng4bits = FakeUrbg<uint8_t, 1, 0x10, 2>;
+using Urng22bits = FakeUrbg<uint32_t, 0, 0x3fffff, 0x301020>;
+using Urng31bits = FakeUrbg<uint32_t, 1, 0xfffffffe, 0x60070f03>; // ~31.9 bits
+using Urng32bits = FakeUrbg<uint32_t, 0, 0xffffffff, 0x74010f01>;
+using Urng33bits =
+ FakeUrbg<uint64_t, 1, 0x1ffffffff, 0x013301033>; // ~32.9 bits
+using Urng63bits = FakeUrbg<uint64_t, 1, 0xfffffffffffffffe,
+ 0xfedcba9012345678>; // ~63.9 bits
+using Urng64bits =
+ FakeUrbg<uint64_t, 0, 0xffffffffffffffff, 0x123456780fedcba9>;
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint16_t, 0, 3>>()), 4);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint16_t, 2, 2>>()), 1);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint16_t, 2, 5>>()), 4);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint16_t, 2, 6>>()), 4);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint16_t, 1000, 1017>>()), 16);
- EXPECT_EQ((PowerOfTwoSubRangeSize<
- FakeUrbg<uint16_t, 0, std::numeric_limits<uint16_t>::max()>>()),
- 0);
-
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 0, 3>>()), 4);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 2, 2>>()), 1);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 2, 5>>()), 4);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 2, 6>>()), 4);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 1000, 1017>>()), 16);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 0, 0xffffffff>>()), 0);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 1, 0xffffffff>>()),
- 0x80000000);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 1, 0xfffffffe>>()),
- 0x80000000);
- EXPECT_EQ((PowerOfTwoSubRangeSize<
- FakeUrbg<uint32_t, 0, std::numeric_limits<uint32_t>::max()>>()),
- 0);
-
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 0, 3>>()), 4);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 2, 2>>()), 1);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 2, 5>>()), 4);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 2, 6>>()), 4);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 1000, 1017>>()), 16);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 0, 0xffffffff>>()),
- 0x100000000ull);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 1, 0xffffffff>>()),
- 0x80000000ull);
- EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 1, 0xfffffffe>>()),
- 0x80000000ull);
- EXPECT_EQ(
- (PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 0, 0xffffffffffffffffull>>()),
- 0);
- EXPECT_EQ(
- (PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 1, 0xffffffffffffffffull>>()),
- 0x8000000000000000ull);
- EXPECT_EQ(
- (PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 1, 0xfffffffffffffffeull>>()),
- 0x8000000000000000ull);
- EXPECT_EQ((PowerOfTwoSubRangeSize<
- FakeUrbg<uint64_t, 0, std::numeric_limits<uint64_t>::max()>>()),
- 0);
-}
-
-TEST(FastUniformBitsTest, Urng4_VariousOutputs) {
+TEST(FastUniformBitsTest, OutputsUpTo32Bits) {
// Tests that how values are composed; the single-bit deltas should be spread
// across each invocation.
+ Urng1_5bit urng1_5;
Urng4bits urng4;
+ Urng22bits urng22;
Urng31bits urng31;
Urng32bits urng32;
+ Urng33bits urng33;
+ Urng63bits urng63;
+ Urng64bits urng64;
// 8-bit types
{
FastUniformBits<uint8_t> fast8;
+ EXPECT_EQ(0x0, fast8(urng1_5));
EXPECT_EQ(0x11, fast8(urng4));
+ EXPECT_EQ(0x20, fast8(urng22));
EXPECT_EQ(0x2, fast8(urng31));
EXPECT_EQ(0x1, fast8(urng32));
+ EXPECT_EQ(0x32, fast8(urng33));
+ EXPECT_EQ(0x77, fast8(urng63));
+ EXPECT_EQ(0xa9, fast8(urng64));
}
// 16-bit types
{
FastUniformBits<uint16_t> fast16;
+ EXPECT_EQ(0x0, fast16(urng1_5));
EXPECT_EQ(0x1111, fast16(urng4));
- EXPECT_EQ(0xf02, fast16(urng31));
- EXPECT_EQ(0xf01, fast16(urng32));
+ EXPECT_EQ(0x1020, fast16(urng22));
+ EXPECT_EQ(0x0f02, fast16(urng31));
+ EXPECT_EQ(0x0f01, fast16(urng32));
+ EXPECT_EQ(0x1032, fast16(urng33));
+ EXPECT_EQ(0x5677, fast16(urng63));
+ EXPECT_EQ(0xcba9, fast16(urng64));
}
// 32-bit types
{
FastUniformBits<uint32_t> fast32;
+ EXPECT_EQ(0x0, fast32(urng1_5));
EXPECT_EQ(0x11111111, fast32(urng4));
+ EXPECT_EQ(0x08301020, fast32(urng22));
EXPECT_EQ(0x0f020f02, fast32(urng31));
EXPECT_EQ(0x74010f01, fast32(urng32));
+ EXPECT_EQ(0x13301032, fast32(urng33));
+ EXPECT_EQ(0x12345677, fast32(urng63));
+ EXPECT_EQ(0x0fedcba9, fast32(urng64));
+ }
+}
+
+TEST(FastUniformBitsTest, Outputs64Bits) {
+ // Tests that how values are composed; the single-bit deltas should be spread
+ // across each invocation.
+ FastUniformBits<uint64_t> fast64;
+
+ {
+ FakeUrbg<uint8_t, 0, 1, 0> urng0;
+ FakeUrbg<uint8_t, 0, 1, 1> urng1;
+ Urng4bits urng4;
+ Urng22bits urng22;
+ Urng31bits urng31;
+ Urng32bits urng32;
+ Urng33bits urng33;
+ Urng63bits urng63;
+ Urng64bits urng64;
+
+ // somewhat degenerate cases only create a single bit.
+ EXPECT_EQ(0x0, fast64(urng0));
+ EXPECT_EQ(64, urng0.calls);
+ EXPECT_EQ(0xffffffffffffffff, fast64(urng1));
+ EXPECT_EQ(64, urng1.calls);
+
+ // less degenerate cases.
+ EXPECT_EQ(0x1111111111111111, fast64(urng4));
+ EXPECT_EQ(16, urng4.calls);
+ EXPECT_EQ(0x01020c0408301020, fast64(urng22));
+ EXPECT_EQ(3, urng22.calls);
+ EXPECT_EQ(0x387811c3c0870f02, fast64(urng31));
+ EXPECT_EQ(3, urng31.calls);
+ EXPECT_EQ(0x74010f0174010f01, fast64(urng32));
+ EXPECT_EQ(2, urng32.calls);
+ EXPECT_EQ(0x808194040cb01032, fast64(urng33));
+ EXPECT_EQ(3, urng33.calls);
+ EXPECT_EQ(0x1234567712345677, fast64(urng63));
+ EXPECT_EQ(2, urng63.calls);
+ EXPECT_EQ(0x123456780fedcba9, fast64(urng64));
+ EXPECT_EQ(1, urng64.calls);
}
- // 64-bit types
+ // The 1.5 bit case is somewhat interesting in that the algorithm refinement
+ // causes one extra small sample. Comments here reference the names used in
+ // [rand.adapt.ibits] that correspond to this case.
{
- FastUniformBits<uint64_t> fast64;
- EXPECT_EQ(0x1111111111111111, fast64(urng4));
+ Urng1_5bit urng1_5;
+
+ // w = 64
+ // R = 3
+ // m = 1
+ // n' = 64
+ // w0' = 1
+ // y0' = 2
+ // n = (1 <= 0) > 64 : 65 = 65
+ // n0 = 65 - (64%65) = 1
+ // n1 = 64
+ // w0 = 0
+ // y0 = 3
+ // w1 = 1
+ // y1 = 2
+ EXPECT_EQ(0x0, fast64(urng1_5));
+ EXPECT_EQ(65, urng1_5.calls);
+ }
+
+ // Validate rejections for non-power-of-2 cases.
+ {
+ Urng1_5bit urng1_5(true);
+ Urng31bits urng31(true);
+ Urng33bits urng33(true);
+ Urng63bits urng63(true);
+
+ // For 1.5 bits, there would be 1+2*64, except the first
+ // value was accepted and shifted off the end.
+ EXPECT_EQ(0, fast64(urng1_5));
+ EXPECT_EQ(128, urng1_5.calls);
EXPECT_EQ(0x387811c3c0870f02, fast64(urng31));
- EXPECT_EQ(0x74010f0174010f01, fast64(urng32));
+ EXPECT_EQ(6, urng31.calls);
+ EXPECT_EQ(0x808194040cb01032, fast64(urng33));
+ EXPECT_EQ(6, urng33.calls);
+ EXPECT_EQ(0x1234567712345677, fast64(urng63));
+ EXPECT_EQ(4, urng63.calls);
}
}
TEST(FastUniformBitsTest, URBG32bitRegression) {
// Validate with deterministic 32-bit std::minstd_rand
// to ensure that operator() performs as expected.
+
+ EXPECT_EQ(2147483646, RangeSize<std::minstd_rand>());
+ EXPECT_EQ(30, IntegerLog2(RangeSize<std::minstd_rand>()));
+
std::minstd_rand gen(1);
FastUniformBits<uint64_t> fast64;
- EXPECT_EQ(0x05e47095f847c122ull, fast64(gen));
- EXPECT_EQ(0x8f82c1ba30b64d22ull, fast64(gen));
- EXPECT_EQ(0x3b971a3558155039ull, fast64(gen));
+ EXPECT_EQ(0x05e47095f8791f45, fast64(gen));
+ EXPECT_EQ(0x028be17e3c07c122, fast64(gen));
+ EXPECT_EQ(0x55d2847c1626e8c2, fast64(gen));
}
} // namespace
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/random/internal/fastmath.h b/third_party/abseil/absl/random/internal/fastmath.h
index 4bd1841..963b769 100644
--- a/third_party/abseil/absl/random/internal/fastmath.h
+++ b/third_party/abseil/absl/random/internal/fastmath.h
@@ -22,26 +22,22 @@
#include <cmath>
#include <cstdint>
-#include "absl/base/internal/bits.h"
+#include "absl/numeric/bits.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
-// Returns the position of the first bit set.
-inline int LeadingSetBit(uint64_t n) {
- return 64 - base_internal::CountLeadingZeros64(n);
-}
-
// Compute log2(n) using integer operations.
// While std::log2 is more accurate than std::log(n) / std::log(2), for
// very large numbers--those close to std::numeric_limits<uint64_t>::max() - 2,
// for instance--std::log2 rounds up rather than down, which introduces
// definite skew in the results.
inline int IntLog2Floor(uint64_t n) {
- return (n <= 1) ? 0 : (63 - base_internal::CountLeadingZeros64(n));
+ return (n <= 1) ? 0 : (63 - countl_zero(n));
}
inline int IntLog2Ceil(uint64_t n) {
- return (n <= 1) ? 0 : (64 - base_internal::CountLeadingZeros64(n - 1));
+ return (n <= 1) ? 0 : (64 - countl_zero(n - 1));
}
inline double StirlingLogFactorial(double n) {
@@ -54,19 +50,8 @@
(1.0 / 360.0) * ninv * ninv * ninv;
}
-// Rotate value right.
-//
-// We only implement the uint32_t / uint64_t versions because
-// 1) those are the only ones we use, and
-// 2) those are the only ones where clang detects the rotate idiom correctly.
-inline constexpr uint32_t rotr(uint32_t value, uint8_t bits) {
- return (value >> (bits & 31)) | (value << ((-bits) & 31));
-}
-inline constexpr uint64_t rotr(uint64_t value, uint8_t bits) {
- return (value >> (bits & 63)) | (value << ((-bits) & 63));
-}
-
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_FASTMATH_H_
diff --git a/third_party/abseil/absl/random/internal/fastmath_test.cc b/third_party/abseil/absl/random/internal/fastmath_test.cc
index 65859c2..0d6f9dc 100644
--- a/third_party/abseil/absl/random/internal/fastmath_test.cc
+++ b/third_party/abseil/absl/random/internal/fastmath_test.cc
@@ -27,19 +27,6 @@
namespace {
-TEST(DistributionImplTest, LeadingSetBit) {
- using absl::random_internal::LeadingSetBit;
- constexpr uint64_t kZero = 0;
- EXPECT_EQ(0, LeadingSetBit(kZero));
- EXPECT_EQ(64, LeadingSetBit(~kZero));
-
- for (int index = 0; index < 64; index++) {
- uint64_t x = static_cast<uint64_t>(1) << index;
- EXPECT_EQ(index + 1, LeadingSetBit(x)) << index;
- EXPECT_EQ(index + 1, LeadingSetBit(x + x - 1)) << index;
- }
-}
-
TEST(FastMathTest, IntLog2FloorTest) {
using absl::random_internal::IntLog2Floor;
constexpr uint64_t kZero = 0;
diff --git a/third_party/abseil/absl/random/internal/gaussian_distribution_gentables.cc b/third_party/abseil/absl/random/internal/gaussian_distribution_gentables.cc
index 16a23cb..a95333d 100644
--- a/third_party/abseil/absl/random/internal/gaussian_distribution_gentables.cc
+++ b/third_party/abseil/absl/random/internal/gaussian_distribution_gentables.cc
@@ -27,6 +27,7 @@
#include "absl/base/macros.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
namespace {
@@ -110,12 +111,9 @@
"\n"
"#include \"absl/random/gaussian_distribution.h\"\n"
"\n"
- // "namespace " and "absl" are broken apart so as not to conflict with
- // script that adds the LTS inline namespace.
- "namespace "
- "absl {\n"
- "namespace "
- "random_internal {\n"
+ "namespace absl {\n"
+ "ABSL_NAMESPACE_BEGIN\n"
+ "namespace random_internal {\n"
"\n"
"const gaussian_distribution_base::Tables\n"
" gaussian_distribution_base::zg_ = {\n";
@@ -124,10 +122,9 @@
FormatArrayContents(os, tables_.f);
*os << "};\n"
"\n"
- "} // namespace "
- "random_internal\n"
- "} // namespace "
- "absl\n"
+ "} // namespace random_internal\n"
+ "ABSL_NAMESPACE_END\n"
+ "} // namespace absl\n"
"\n"
"// clang-format on\n"
"// END GENERATED CODE";
@@ -135,6 +132,7 @@
}
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
int main(int, char**) {
diff --git a/third_party/abseil/absl/random/internal/generate_real.h b/third_party/abseil/absl/random/internal/generate_real.h
new file mode 100644
index 0000000..4f62873
--- /dev/null
+++ b/third_party/abseil/absl/random/internal/generate_real.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
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_RANDOM_INTERNAL_GENERATE_REAL_H_
+#define ABSL_RANDOM_INTERNAL_GENERATE_REAL_H_
+
+// This file contains some implementation details which are used by one or more
+// of the absl random number distributions.
+
+#include <cstdint>
+#include <cstring>
+#include <limits>
+#include <type_traits>
+
+#include "absl/meta/type_traits.h"
+#include "absl/numeric/bits.h"
+#include "absl/random/internal/fastmath.h"
+#include "absl/random/internal/traits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace random_internal {
+
+// Tristate tag types controlling the output of GenerateRealFromBits.
+struct GeneratePositiveTag {};
+struct GenerateNegativeTag {};
+struct GenerateSignedTag {};
+
+// GenerateRealFromBits generates a single real value from a single 64-bit
+// `bits` with template fields controlling the output.
+//
+// The `SignedTag` parameter controls whether positive, negative,
+// or either signed/unsigned may be returned.
+// When SignedTag == GeneratePositiveTag, range is U(0, 1)
+// When SignedTag == GenerateNegativeTag, range is U(-1, 0)
+// When SignedTag == GenerateSignedTag, range is U(-1, 1)
+//
+// When the `IncludeZero` parameter is true, the function may return 0 for some
+// inputs, otherwise it never returns 0.
+//
+// When a value in U(0,1) is required, use:
+// Uniform64ToReal<double, PositiveValueT, true>;
+//
+// When a value in U(-1,1) is required, use:
+// Uniform64ToReal<double, SignedValueT, false>;
+//
+// This generates more distinct values than the mathematical equivalent
+// `U(0, 1) * 2.0 - 1.0`.
+//
+// Scaling the result by powers of 2 (and avoiding a multiply) is also possible:
+// GenerateRealFromBits<double>(..., -1); => U(0, 0.5)
+// GenerateRealFromBits<double>(..., 1); => U(0, 2)
+//
+template <typename RealType, // Real type, either float or double.
+ typename SignedTag = GeneratePositiveTag, // Whether a positive,
+ // negative, or signed
+ // value is generated.
+ bool IncludeZero = true>
+inline RealType GenerateRealFromBits(uint64_t bits, int exp_bias = 0) {
+ using real_type = RealType;
+ using uint_type = absl::conditional_t<std::is_same<real_type, float>::value,
+ uint32_t, uint64_t>;
+
+ static_assert(
+ (std::is_same<double, real_type>::value ||
+ std::is_same<float, real_type>::value),
+ "GenerateRealFromBits must be parameterized by either float or double.");
+
+ static_assert(sizeof(uint_type) == sizeof(real_type),
+ "Mismatched unsinged and real types.");
+
+ static_assert((std::numeric_limits<real_type>::is_iec559 &&
+ std::numeric_limits<real_type>::radix == 2),
+ "RealType representation is not IEEE 754 binary.");
+
+ static_assert((std::is_same<SignedTag, GeneratePositiveTag>::value ||
+ std::is_same<SignedTag, GenerateNegativeTag>::value ||
+ std::is_same<SignedTag, GenerateSignedTag>::value),
+ "");
+
+ static constexpr int kExp = std::numeric_limits<real_type>::digits - 1;
+ static constexpr uint_type kMask = (static_cast<uint_type>(1) << kExp) - 1u;
+ static constexpr int kUintBits = sizeof(uint_type) * 8;
+
+ int exp = exp_bias + int{std::numeric_limits<real_type>::max_exponent - 2};
+
+ // Determine the sign bit.
+ // Depending on the SignedTag, this may use the left-most bit
+ // or it may be a constant value.
+ uint_type sign = std::is_same<SignedTag, GenerateNegativeTag>::value
+ ? (static_cast<uint_type>(1) << (kUintBits - 1))
+ : 0;
+ if (std::is_same<SignedTag, GenerateSignedTag>::value) {
+ if (std::is_same<uint_type, uint64_t>::value) {
+ sign = bits & uint64_t{0x8000000000000000};
+ }
+ if (std::is_same<uint_type, uint32_t>::value) {
+ const uint64_t tmp = bits & uint64_t{0x8000000000000000};
+ sign = static_cast<uint32_t>(tmp >> 32);
+ }
+ // adjust the bits and the exponent to account for removing
+ // the leading bit.
+ bits = bits & uint64_t{0x7FFFFFFFFFFFFFFF};
+ exp++;
+ }
+ if (IncludeZero) {
+ if (bits == 0u) return 0;
+ }
+
+ // Number of leading zeros is mapped to the exponent: 2^-clz
+ // bits is 0..01xxxxxx. After shifting, we're left with 1xxx...0..0
+ int clz = countl_zero(bits);
+ bits <<= (IncludeZero ? clz : (clz & 63)); // remove 0-bits.
+ exp -= clz; // set the exponent.
+ bits >>= (63 - kExp);
+
+ // Construct the 32-bit or 64-bit IEEE 754 floating-point value from
+ // the individual fields: sign, exp, mantissa(bits).
+ uint_type val =
+ (std::is_same<SignedTag, GeneratePositiveTag>::value ? 0u : sign) |
+ (static_cast<uint_type>(exp) << kExp) |
+ (static_cast<uint_type>(bits) & kMask);
+
+ // bit_cast to the output-type
+ real_type result;
+ memcpy(static_cast<void*>(&result), static_cast<const void*>(&val),
+ sizeof(result));
+ return result;
+}
+
+} // namespace random_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_GENERATE_REAL_H_
diff --git a/third_party/abseil/absl/random/internal/distribution_impl_test.cc b/third_party/abseil/absl/random/internal/generate_real_test.cc
similarity index 79%
rename from third_party/abseil/absl/random/internal/distribution_impl_test.cc
rename to third_party/abseil/absl/random/internal/generate_real_test.cc
index 09e7a31..b099dbf 100644
--- a/third_party/abseil/absl/random/internal/distribution_impl_test.cc
+++ b/third_party/abseil/absl/random/internal/generate_real_test.cc
@@ -12,57 +12,74 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "absl/random/internal/distribution_impl.h"
+#include "absl/random/internal/generate_real.h"
+
+#include <cfloat>
+#include <cstddef>
+#include <cstdint>
+#include <string>
#include "gtest/gtest.h"
-#include "absl/base/internal/bits.h"
#include "absl/flags/flag.h"
-#include "absl/numeric/int128.h"
+#include "absl/numeric/bits.h"
ABSL_FLAG(int64_t, absl_random_test_trials, 50000,
"Number of trials for the probability tests.");
-using absl::random_internal::NegativeValueT;
-using absl::random_internal::PositiveValueT;
-using absl::random_internal::RandU64ToDouble;
-using absl::random_internal::RandU64ToFloat;
-using absl::random_internal::SignedValueT;
+using absl::random_internal::GenerateNegativeTag;
+using absl::random_internal::GeneratePositiveTag;
+using absl::random_internal::GenerateRealFromBits;
+using absl::random_internal::GenerateSignedTag;
namespace {
-TEST(DistributionImplTest, U64ToFloat_Positive_NoZero_Test) {
+TEST(GenerateRealTest, U64ToFloat_Positive_NoZero_Test) {
auto ToFloat = [](uint64_t a) {
- return RandU64ToFloat<PositiveValueT, false>(a);
+ return GenerateRealFromBits<float, GeneratePositiveTag, false>(a);
};
EXPECT_EQ(ToFloat(0x0000000000000000), 2.710505431e-20f);
EXPECT_EQ(ToFloat(0x0000000000000001), 5.421010862e-20f);
EXPECT_EQ(ToFloat(0x8000000000000000), 0.5);
+ EXPECT_EQ(ToFloat(0x8000000000000001), 0.5);
EXPECT_EQ(ToFloat(0xFFFFFFFFFFFFFFFF), 0.9999999404f);
}
-TEST(DistributionImplTest, U64ToFloat_Positive_Zero_Test) {
+TEST(GenerateRealTest, U64ToFloat_Positive_Zero_Test) {
auto ToFloat = [](uint64_t a) {
- return RandU64ToFloat<PositiveValueT, true>(a);
+ return GenerateRealFromBits<float, GeneratePositiveTag, true>(a);
};
EXPECT_EQ(ToFloat(0x0000000000000000), 0.0);
EXPECT_EQ(ToFloat(0x0000000000000001), 5.421010862e-20f);
EXPECT_EQ(ToFloat(0x8000000000000000), 0.5);
+ EXPECT_EQ(ToFloat(0x8000000000000001), 0.5);
EXPECT_EQ(ToFloat(0xFFFFFFFFFFFFFFFF), 0.9999999404f);
}
-TEST(DistributionImplTest, U64ToFloat_Negative_NoZero_Test) {
+TEST(GenerateRealTest, U64ToFloat_Negative_NoZero_Test) {
auto ToFloat = [](uint64_t a) {
- return RandU64ToFloat<NegativeValueT, false>(a);
+ return GenerateRealFromBits<float, GenerateNegativeTag, false>(a);
};
EXPECT_EQ(ToFloat(0x0000000000000000), -2.710505431e-20f);
EXPECT_EQ(ToFloat(0x0000000000000001), -5.421010862e-20f);
EXPECT_EQ(ToFloat(0x8000000000000000), -0.5);
+ EXPECT_EQ(ToFloat(0x8000000000000001), -0.5);
EXPECT_EQ(ToFloat(0xFFFFFFFFFFFFFFFF), -0.9999999404f);
}
-TEST(DistributionImplTest, U64ToFloat_Signed_NoZero_Test) {
+TEST(GenerateRealTest, U64ToFloat_Negative_Zero_Test) {
auto ToFloat = [](uint64_t a) {
- return RandU64ToFloat<SignedValueT, false>(a);
+ return GenerateRealFromBits<float, GenerateNegativeTag, true>(a);
+ };
+ EXPECT_EQ(ToFloat(0x0000000000000000), 0.0);
+ EXPECT_EQ(ToFloat(0x0000000000000001), -5.421010862e-20f);
+ EXPECT_EQ(ToFloat(0x8000000000000000), -0.5);
+ EXPECT_EQ(ToFloat(0x8000000000000001), -0.5);
+ EXPECT_EQ(ToFloat(0xFFFFFFFFFFFFFFFF), -0.9999999404f);
+}
+
+TEST(GenerateRealTest, U64ToFloat_Signed_NoZero_Test) {
+ auto ToFloat = [](uint64_t a) {
+ return GenerateRealFromBits<float, GenerateSignedTag, false>(a);
};
EXPECT_EQ(ToFloat(0x0000000000000000), 5.421010862e-20f);
EXPECT_EQ(ToFloat(0x0000000000000001), 1.084202172e-19f);
@@ -72,9 +89,9 @@
EXPECT_EQ(ToFloat(0xFFFFFFFFFFFFFFFF), -0.9999999404f);
}
-TEST(DistributionImplTest, U64ToFloat_Signed_Zero_Test) {
+TEST(GenerateRealTest, U64ToFloat_Signed_Zero_Test) {
auto ToFloat = [](uint64_t a) {
- return RandU64ToFloat<SignedValueT, true>(a);
+ return GenerateRealFromBits<float, GenerateSignedTag, true>(a);
};
EXPECT_EQ(ToFloat(0x0000000000000000), 0);
EXPECT_EQ(ToFloat(0x0000000000000001), 1.084202172e-19f);
@@ -84,9 +101,9 @@
EXPECT_EQ(ToFloat(0xFFFFFFFFFFFFFFFF), -0.9999999404f);
}
-TEST(DistributionImplTest, U64ToFloat_Signed_Bias_Test) {
+TEST(GenerateRealTest, U64ToFloat_Signed_Bias_Test) {
auto ToFloat = [](uint64_t a) {
- return RandU64ToFloat<SignedValueT, true, 1>(a);
+ return GenerateRealFromBits<float, GenerateSignedTag, true>(a, 1);
};
EXPECT_EQ(ToFloat(0x0000000000000000), 0);
EXPECT_EQ(ToFloat(0x0000000000000001), 2 * 1.084202172e-19f);
@@ -96,9 +113,9 @@
EXPECT_EQ(ToFloat(0xFFFFFFFFFFFFFFFF), 2 * -0.9999999404f);
}
-TEST(DistributionImplTest, U64ToFloatTest) {
+TEST(GenerateRealTest, U64ToFloatTest) {
auto ToFloat = [](uint64_t a) -> float {
- return RandU64ToFloat<PositiveValueT, true>(a);
+ return GenerateRealFromBits<float, GeneratePositiveTag, true>(a);
};
EXPECT_EQ(ToFloat(0x0000000000000000), 0.0f);
@@ -150,44 +167,60 @@
}
}
-TEST(DistributionImplTest, U64ToDouble_Positive_NoZero_Test) {
+TEST(GenerateRealTest, U64ToDouble_Positive_NoZero_Test) {
auto ToDouble = [](uint64_t a) {
- return RandU64ToDouble<PositiveValueT, false>(a);
+ return GenerateRealFromBits<double, GeneratePositiveTag, false>(a);
};
EXPECT_EQ(ToDouble(0x0000000000000000), 2.710505431213761085e-20);
EXPECT_EQ(ToDouble(0x0000000000000001), 5.42101086242752217004e-20);
EXPECT_EQ(ToDouble(0x0000000000000002), 1.084202172485504434e-19);
EXPECT_EQ(ToDouble(0x8000000000000000), 0.5);
+ EXPECT_EQ(ToDouble(0x8000000000000001), 0.5);
EXPECT_EQ(ToDouble(0xFFFFFFFFFFFFFFFF), 0.999999999999999888978);
}
-TEST(DistributionImplTest, U64ToDouble_Positive_Zero_Test) {
+TEST(GenerateRealTest, U64ToDouble_Positive_Zero_Test) {
auto ToDouble = [](uint64_t a) {
- return RandU64ToDouble<PositiveValueT, true>(a);
+ return GenerateRealFromBits<double, GeneratePositiveTag, true>(a);
};
EXPECT_EQ(ToDouble(0x0000000000000000), 0.0);
EXPECT_EQ(ToDouble(0x0000000000000001), 5.42101086242752217004e-20);
EXPECT_EQ(ToDouble(0x8000000000000000), 0.5);
+ EXPECT_EQ(ToDouble(0x8000000000000001), 0.5);
EXPECT_EQ(ToDouble(0xFFFFFFFFFFFFFFFF), 0.999999999999999888978);
}
-TEST(DistributionImplTest, U64ToDouble_Negative_NoZero_Test) {
+TEST(GenerateRealTest, U64ToDouble_Negative_NoZero_Test) {
auto ToDouble = [](uint64_t a) {
- return RandU64ToDouble<NegativeValueT, false>(a);
+ return GenerateRealFromBits<double, GenerateNegativeTag, false>(a);
};
EXPECT_EQ(ToDouble(0x0000000000000000), -2.710505431213761085e-20);
EXPECT_EQ(ToDouble(0x0000000000000001), -5.42101086242752217004e-20);
EXPECT_EQ(ToDouble(0x0000000000000002), -1.084202172485504434e-19);
EXPECT_EQ(ToDouble(0x8000000000000000), -0.5);
+ EXPECT_EQ(ToDouble(0x8000000000000001), -0.5);
EXPECT_EQ(ToDouble(0xFFFFFFFFFFFFFFFF), -0.999999999999999888978);
}
-TEST(DistributionImplTest, U64ToDouble_Signed_NoZero_Test) {
+TEST(GenerateRealTest, U64ToDouble_Negative_Zero_Test) {
auto ToDouble = [](uint64_t a) {
- return RandU64ToDouble<SignedValueT, false>(a);
+ return GenerateRealFromBits<double, GenerateNegativeTag, true>(a);
+ };
+
+ EXPECT_EQ(ToDouble(0x0000000000000000), 0.0);
+ EXPECT_EQ(ToDouble(0x0000000000000001), -5.42101086242752217004e-20);
+ EXPECT_EQ(ToDouble(0x0000000000000002), -1.084202172485504434e-19);
+ EXPECT_EQ(ToDouble(0x8000000000000000), -0.5);
+ EXPECT_EQ(ToDouble(0x8000000000000001), -0.5);
+ EXPECT_EQ(ToDouble(0xFFFFFFFFFFFFFFFF), -0.999999999999999888978);
+}
+
+TEST(GenerateRealTest, U64ToDouble_Signed_NoZero_Test) {
+ auto ToDouble = [](uint64_t a) {
+ return GenerateRealFromBits<double, GenerateSignedTag, false>(a);
};
EXPECT_EQ(ToDouble(0x0000000000000000), 5.42101086242752217004e-20);
@@ -198,9 +231,9 @@
EXPECT_EQ(ToDouble(0xFFFFFFFFFFFFFFFF), -0.999999999999999888978);
}
-TEST(DistributionImplTest, U64ToDouble_Signed_Zero_Test) {
+TEST(GenerateRealTest, U64ToDouble_Signed_Zero_Test) {
auto ToDouble = [](uint64_t a) {
- return RandU64ToDouble<SignedValueT, true>(a);
+ return GenerateRealFromBits<double, GenerateSignedTag, true>(a);
};
EXPECT_EQ(ToDouble(0x0000000000000000), 0);
EXPECT_EQ(ToDouble(0x0000000000000001), 1.084202172485504434e-19);
@@ -210,9 +243,9 @@
EXPECT_EQ(ToDouble(0xFFFFFFFFFFFFFFFF), -0.999999999999999888978);
}
-TEST(DistributionImplTest, U64ToDouble_Signed_Bias_Test) {
+TEST(GenerateRealTest, U64ToDouble_GenerateSignedTag_Bias_Test) {
auto ToDouble = [](uint64_t a) {
- return RandU64ToDouble<SignedValueT, true, -1>(a);
+ return GenerateRealFromBits<double, GenerateSignedTag, true>(a, -1);
};
EXPECT_EQ(ToDouble(0x0000000000000000), 0);
EXPECT_EQ(ToDouble(0x0000000000000001), 1.084202172485504434e-19 / 2);
@@ -222,9 +255,9 @@
EXPECT_EQ(ToDouble(0xFFFFFFFFFFFFFFFF), -0.999999999999999888978 / 2);
}
-TEST(DistributionImplTest, U64ToDoubleTest) {
+TEST(GenerateRealTest, U64ToDoubleTest) {
auto ToDouble = [](uint64_t a) {
- return RandU64ToDouble<PositiveValueT, true>(a);
+ return GenerateRealFromBits<double, GeneratePositiveTag, true>(a);
};
EXPECT_EQ(ToDouble(0x0000000000000000), 0.0);
@@ -296,9 +329,9 @@
}
}
-TEST(DistributionImplTest, U64ToDoubleSignedTest) {
+TEST(GenerateRealTest, U64ToDoubleSignedTest) {
auto ToDouble = [](uint64_t a) {
- return RandU64ToDouble<SignedValueT, false>(a);
+ return GenerateRealFromBits<double, GenerateSignedTag, false>(a);
};
EXPECT_EQ(ToDouble(0x0000000000000000), 5.42101086242752217004e-20);
@@ -379,15 +412,14 @@
}
}
-TEST(DistributionImplTest, ExhaustiveFloat) {
- using absl::base_internal::CountLeadingZeros64;
+TEST(GenerateRealTest, ExhaustiveFloat) {
auto ToFloat = [](uint64_t a) {
- return RandU64ToFloat<PositiveValueT, true>(a);
+ return GenerateRealFromBits<float, GeneratePositiveTag, true>(a);
};
// Rely on RandU64ToFloat generating values from greatest to least when
- // supplied with uint64_t values from greatest (0xfff...) to least (0x0). Thus,
- // this algorithm stores the previous value, and if the new value is at
+ // supplied with uint64_t values from greatest (0xfff...) to least (0x0).
+ // Thus, this algorithm stores the previous value, and if the new value is at
// greater than or equal to the previous value, then there is a collision in
// the generation algorithm.
//
@@ -431,7 +463,7 @@
// Adjust decrement and check value based on how many leading 0
// bits are set in the current value.
- const int clz = CountLeadingZeros64(x);
+ const int clz = absl::countl_zero(x);
if (clz < kDig) {
dec <<= (kDig - clz);
chk = (~uint64_t(0)) >> (clz + 1);
@@ -461,46 +493,4 @@
}
}
-TEST(DistributionImplTest, MultiplyU64ToU128Test) {
- using absl::random_internal::MultiplyU64ToU128;
- constexpr uint64_t k1 = 1;
- constexpr uint64_t kMax = ~static_cast<uint64_t>(0);
-
- EXPECT_EQ(absl::uint128(0), MultiplyU64ToU128(0, 0));
-
- // Max uint64
- EXPECT_EQ(MultiplyU64ToU128(kMax, kMax),
- absl::MakeUint128(0xfffffffffffffffe, 0x0000000000000001));
- EXPECT_EQ(absl::MakeUint128(0, kMax), MultiplyU64ToU128(kMax, 1));
- EXPECT_EQ(absl::MakeUint128(0, kMax), MultiplyU64ToU128(1, kMax));
- for (int i = 0; i < 64; ++i) {
- EXPECT_EQ(absl::MakeUint128(0, kMax) << i,
- MultiplyU64ToU128(kMax, k1 << i));
- EXPECT_EQ(absl::MakeUint128(0, kMax) << i,
- MultiplyU64ToU128(k1 << i, kMax));
- }
-
- // 1-bit x 1-bit.
- for (int i = 0; i < 64; ++i) {
- for (int j = 0; j < 64; ++j) {
- EXPECT_EQ(absl::MakeUint128(0, 1) << (i + j),
- MultiplyU64ToU128(k1 << i, k1 << j));
- EXPECT_EQ(absl::MakeUint128(0, 1) << (i + j),
- MultiplyU64ToU128(k1 << i, k1 << j));
- }
- }
-
- // Verified multiplies
- EXPECT_EQ(MultiplyU64ToU128(0xffffeeeeddddcccc, 0xbbbbaaaa99998888),
- absl::MakeUint128(0xbbbb9e2692c5dddc, 0xc28f7531048d2c60));
- EXPECT_EQ(MultiplyU64ToU128(0x0123456789abcdef, 0xfedcba9876543210),
- absl::MakeUint128(0x0121fa00ad77d742, 0x2236d88fe5618cf0));
- EXPECT_EQ(MultiplyU64ToU128(0x0123456789abcdef, 0xfdb97531eca86420),
- absl::MakeUint128(0x0120ae99d26725fc, 0xce197f0ecac319e0));
- EXPECT_EQ(MultiplyU64ToU128(0x97a87f4f261ba3f2, 0xfedcba9876543210),
- absl::MakeUint128(0x96fbf1a8ae78d0ba, 0x5a6dd4b71f278320));
- EXPECT_EQ(MultiplyU64ToU128(0xfedcba9876543210, 0xfdb97531eca86420),
- absl::MakeUint128(0xfc98c6981a413e22, 0x342d0bbf48948200));
-}
-
} // namespace
diff --git a/third_party/abseil/absl/random/internal/iostream_state_saver.h b/third_party/abseil/absl/random/internal/iostream_state_saver.h
index df88fa7..e6e242e 100644
--- a/third_party/abseil/absl/random/internal/iostream_state_saver.h
+++ b/third_party/abseil/absl/random/internal/iostream_state_saver.h
@@ -24,6 +24,7 @@
#include "absl/numeric/int128.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
// The null_state_saver does nothing.
@@ -191,8 +192,8 @@
template <typename OStream>
inline void write(absl::uint128 val, OStream& out) {
- uint64_t h = Uint128High64(val);
- uint64_t l = Uint128Low64(val);
+ uint64_t h = absl::Uint128High64(val);
+ uint64_t l = absl::Uint128Low64(val);
out << h << out.fill() << l;
}
};
@@ -238,6 +239,7 @@
}
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_IOSTREAM_STATE_SAVER_H_
diff --git a/third_party/abseil/absl/random/internal/iostream_state_saver_test.cc b/third_party/abseil/absl/random/internal/iostream_state_saver_test.cc
index 2ecbaac..6e66266 100644
--- a/third_party/abseil/absl/random/internal/iostream_state_saver_test.cc
+++ b/third_party/abseil/absl/random/internal/iostream_state_saver_test.cc
@@ -14,6 +14,9 @@
#include "absl/random/internal/iostream_state_saver.h"
+#include <errno.h>
+#include <stdio.h>
+
#include <sstream>
#include <string>
@@ -196,8 +199,8 @@
EXPECT_EQ(-d, StreamRoundTrip<double>(-d));
// Avoid undefined behavior (overflow/underflow).
- if (d <= std::numeric_limits<int64_t>::max() &&
- d >= std::numeric_limits<int64_t>::lowest()) {
+ if (f <= static_cast<float>(std::numeric_limits<int64_t>::max()) &&
+ f >= static_cast<float>(std::numeric_limits<int64_t>::lowest())) {
int64_t x = static_cast<int64_t>(f);
EXPECT_EQ(x, StreamRoundTrip<int64_t>(x));
}
@@ -264,8 +267,8 @@
}
// Avoid undefined behavior (overflow/underflow).
- if (d <= std::numeric_limits<int64_t>::max() &&
- d >= std::numeric_limits<int64_t>::lowest()) {
+ if (d <= static_cast<double>(std::numeric_limits<int64_t>::max()) &&
+ d >= static_cast<double>(std::numeric_limits<int64_t>::lowest())) {
int64_t x = static_cast<int64_t>(d);
EXPECT_EQ(x, StreamRoundTrip<int64_t>(x));
}
diff --git a/third_party/abseil/absl/random/internal/mock_helpers.h b/third_party/abseil/absl/random/internal/mock_helpers.h
new file mode 100644
index 0000000..9af27ab
--- /dev/null
+++ b/third_party/abseil/absl/random/internal/mock_helpers.h
@@ -0,0 +1,127 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_RANDOM_INTERNAL_MOCK_HELPERS_H_
+#define ABSL_RANDOM_INTERNAL_MOCK_HELPERS_H_
+
+#include <tuple>
+#include <type_traits>
+
+#include "absl/base/internal/fast_type_id.h"
+#include "absl/types/optional.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace random_internal {
+
+// MockHelpers works in conjunction with MockOverloadSet, MockingBitGen, and
+// BitGenRef to enable the mocking capability for absl distribution functions.
+//
+// MockingBitGen registers mocks based on the typeid of a mock signature, KeyT,
+// which is used to generate a unique id.
+//
+// KeyT is a signature of the form:
+// result_type(discriminator_type, std::tuple<args...>)
+// The mocked function signature will be composed from KeyT as:
+// result_type(args...)
+//
+class MockHelpers {
+ using IdType = ::absl::base_internal::FastTypeIdType;
+
+ // Given a key signature type used to index the mock, extract the components.
+ // KeyT is expected to have the form:
+ // result_type(discriminator_type, arg_tuple_type)
+ template <typename KeyT>
+ struct KeySignature;
+
+ template <typename ResultT, typename DiscriminatorT, typename ArgTupleT>
+ struct KeySignature<ResultT(DiscriminatorT, ArgTupleT)> {
+ using result_type = ResultT;
+ using discriminator_type = DiscriminatorT;
+ using arg_tuple_type = ArgTupleT;
+ };
+
+ // Detector for InvokeMock.
+ template <class T>
+ using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock(
+ std::declval<IdType>(), std::declval<void*>(), std::declval<void*>()));
+
+ // Empty implementation of InvokeMock.
+ template <typename KeyT, typename ReturnT, typename ArgTupleT, typename URBG,
+ typename... Args>
+ static absl::optional<ReturnT> InvokeMockImpl(char, URBG*, Args&&...) {
+ return absl::nullopt;
+ }
+
+ // Non-empty implementation of InvokeMock.
+ template <typename KeyT, typename ReturnT, typename ArgTupleT, typename URBG,
+ typename = invoke_mock_t<URBG>, typename... Args>
+ static absl::optional<ReturnT> InvokeMockImpl(int, URBG* urbg,
+ Args&&... args) {
+ ArgTupleT arg_tuple(std::forward<Args>(args)...);
+ ReturnT result;
+ if (urbg->InvokeMock(::absl::base_internal::FastTypeId<KeyT>(), &arg_tuple,
+ &result)) {
+ return result;
+ }
+ return absl::nullopt;
+ }
+
+ public:
+ // Invoke a mock for the KeyT (may or may not be a signature).
+ //
+ // KeyT is used to generate a typeid-based lookup key for the mock.
+ // KeyT is a signature of the form:
+ // result_type(discriminator_type, std::tuple<args...>)
+ // The mocked function signature will be composed from KeyT as:
+ // result_type(args...)
+ //
+ // An instance of arg_tuple_type must be constructable from Args..., since
+ // the underlying mechanism requires a pointer to an argument tuple.
+ template <typename KeyT, typename URBG, typename... Args>
+ static auto MaybeInvokeMock(URBG* urbg, Args&&... args)
+ -> absl::optional<typename KeySignature<KeyT>::result_type> {
+ // Use function overloading to dispatch to the implemenation since
+ // more modern patterns (e.g. require + constexpr) are not supported in all
+ // compiler configurations.
+ return InvokeMockImpl<KeyT, typename KeySignature<KeyT>::result_type,
+ typename KeySignature<KeyT>::arg_tuple_type, URBG>(
+ 0, urbg, std::forward<Args>(args)...);
+ }
+
+ // Acquire a mock for the KeyT (may or may not be a signature).
+ //
+ // KeyT is used to generate a typeid-based lookup for the mock.
+ // KeyT is a signature of the form:
+ // result_type(discriminator_type, std::tuple<args...>)
+ // The mocked function signature will be composed from KeyT as:
+ // result_type(args...)
+ template <typename KeyT, typename MockURBG>
+ static auto MockFor(MockURBG& m) -> decltype(
+ std::declval<MockURBG>()
+ .template RegisterMock<typename KeySignature<KeyT>::result_type,
+ typename KeySignature<KeyT>::arg_tuple_type>(
+ std::declval<IdType>())) {
+ return m.template RegisterMock<typename KeySignature<KeyT>::result_type,
+ typename KeySignature<KeyT>::arg_tuple_type>(
+ ::absl::base_internal::FastTypeId<KeyT>());
+ }
+};
+
+} // namespace random_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_MOCK_HELPERS_H_
diff --git a/third_party/abseil/absl/random/internal/mock_overload_set.h b/third_party/abseil/absl/random/internal/mock_overload_set.h
new file mode 100644
index 0000000..dccc6ce
--- /dev/null
+++ b/third_party/abseil/absl/random/internal/mock_overload_set.h
@@ -0,0 +1,97 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_RANDOM_INTERNAL_MOCK_OVERLOAD_SET_H_
+#define ABSL_RANDOM_INTERNAL_MOCK_OVERLOAD_SET_H_
+
+#include <type_traits>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/random/internal/mock_helpers.h"
+#include "absl/random/mocking_bit_gen.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace random_internal {
+
+template <typename DistrT, typename Fn>
+struct MockSingleOverload;
+
+// MockSingleOverload
+//
+// MockSingleOverload hooks in to gMock's `ON_CALL` and `EXPECT_CALL` macros.
+// EXPECT_CALL(mock_single_overload, Call(...))` will expand to a call to
+// `mock_single_overload.gmock_Call(...)`. Because expectations are stored on
+// the MockingBitGen (an argument passed inside `Call(...)`), this forwards to
+// arguments to MockingBitGen::Register.
+//
+// The underlying KeyT must match the KeyT constructed by DistributionCaller.
+template <typename DistrT, typename Ret, typename... Args>
+struct MockSingleOverload<DistrT, Ret(MockingBitGen&, Args...)> {
+ static_assert(std::is_same<typename DistrT::result_type, Ret>::value,
+ "Overload signature must have return type matching the "
+ "distribution result_type.");
+ using KeyT = Ret(DistrT, std::tuple<Args...>);
+ auto gmock_Call(
+ absl::MockingBitGen& gen, // NOLINT(google-runtime-references)
+ const ::testing::Matcher<Args>&... matchers)
+ -> decltype(MockHelpers::MockFor<KeyT>(gen).gmock_Call(matchers...)) {
+ return MockHelpers::MockFor<KeyT>(gen).gmock_Call(matchers...);
+ }
+};
+
+template <typename DistrT, typename Ret, typename Arg, typename... Args>
+struct MockSingleOverload<DistrT, Ret(Arg, MockingBitGen&, Args...)> {
+ static_assert(std::is_same<typename DistrT::result_type, Ret>::value,
+ "Overload signature must have return type matching the "
+ "distribution result_type.");
+ using KeyT = Ret(DistrT, std::tuple<Arg, Args...>);
+ auto gmock_Call(
+ const ::testing::Matcher<Arg>& matcher,
+ absl::MockingBitGen& gen, // NOLINT(google-runtime-references)
+ const ::testing::Matcher<Args>&... matchers)
+ -> decltype(MockHelpers::MockFor<KeyT>(gen).gmock_Call(matcher,
+ matchers...)) {
+ return MockHelpers::MockFor<KeyT>(gen).gmock_Call(matcher, matchers...);
+ }
+};
+
+// MockOverloadSet
+//
+// MockOverloadSet takes a distribution and a collection of signatures and
+// performs overload resolution amongst all the overloads. This makes
+// `EXPECT_CALL(mock_overload_set, Call(...))` expand and do overload resolution
+// correctly.
+template <typename DistrT, typename... Signatures>
+struct MockOverloadSet;
+
+template <typename DistrT, typename Sig>
+struct MockOverloadSet<DistrT, Sig> : public MockSingleOverload<DistrT, Sig> {
+ using MockSingleOverload<DistrT, Sig>::gmock_Call;
+};
+
+template <typename DistrT, typename FirstSig, typename... Rest>
+struct MockOverloadSet<DistrT, FirstSig, Rest...>
+ : public MockSingleOverload<DistrT, FirstSig>,
+ public MockOverloadSet<DistrT, Rest...> {
+ using MockSingleOverload<DistrT, FirstSig>::gmock_Call;
+ using MockOverloadSet<DistrT, Rest...>::gmock_Call;
+};
+
+} // namespace random_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+#endif // ABSL_RANDOM_INTERNAL_MOCK_OVERLOAD_SET_H_
diff --git a/third_party/abseil/absl/random/internal/nanobenchmark.cc b/third_party/abseil/absl/random/internal/nanobenchmark.cc
index 7f37800..c918181 100644
--- a/third_party/abseil/absl/random/internal/nanobenchmark.cc
+++ b/third_party/abseil/absl/random/internal/nanobenchmark.cc
@@ -27,6 +27,7 @@
#include <utility>
#include <vector>
+#include "absl/base/attributes.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/random/internal/platform.h"
#include "absl/random/internal/randen_engine.h"
@@ -59,15 +60,6 @@
#include <time.h> // NOLINT
#endif
-// ABSL_HAVE_ATTRIBUTE
-#if !defined(ABSL_HAVE_ATTRIBUTE)
-#ifdef __has_attribute
-#define ABSL_HAVE_ATTRIBUTE(x) __has_attribute(x)
-#else
-#define ABSL_HAVE_ATTRIBUTE(x) 0
-#endif
-#endif
-
// ABSL_RANDOM_INTERNAL_ATTRIBUTE_NEVER_INLINE prevents inlining of the method.
#if ABSL_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__))
#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_NEVER_INLINE __attribute__((noinline))
@@ -78,6 +70,7 @@
#endif
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal_nanobenchmark {
namespace {
@@ -108,7 +101,7 @@
char brand_string[49];
uint32_t abcd[4];
- // Check if brand std::string is supported (it is on all reasonable Intel/AMD)
+ // Check if brand string is supported (it is on all reasonable Intel/AMD)
Cpuid(0x80000000U, 0, abcd);
if (abcd[0] < 0x80000004U) {
return std::string();
@@ -807,4 +800,5 @@
}
} // namespace random_internal_nanobenchmark
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/random/internal/nanobenchmark.h b/third_party/abseil/absl/random/internal/nanobenchmark.h
index c2b650d..a5097ba 100644
--- a/third_party/abseil/absl/random/internal/nanobenchmark.h
+++ b/third_party/abseil/absl/random/internal/nanobenchmark.h
@@ -50,7 +50,10 @@
#include <stddef.h>
#include <stdint.h>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal_nanobenchmark {
// Input influencing the function being measured (e.g. number of bytes to copy).
@@ -163,6 +166,7 @@
}
} // namespace random_internal_nanobenchmark
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_NANOBENCHMARK_H_
diff --git a/third_party/abseil/absl/random/internal/nanobenchmark_test.cc b/third_party/abseil/absl/random/internal/nanobenchmark_test.cc
index 383345a..f1571e2 100644
--- a/third_party/abseil/absl/random/internal/nanobenchmark_test.cc
+++ b/third_party/abseil/absl/random/internal/nanobenchmark_test.cc
@@ -18,6 +18,7 @@
#include "absl/strings/numbers.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal_nanobenchmark {
namespace {
@@ -52,7 +53,7 @@
// Avoid migrating between cores - important on multi-socket systems.
int cpu = -1;
if (argc == 2) {
- if (!SimpleAtoi(argv[1], &cpu)) {
+ if (!absl::SimpleAtoi(argv[1], &cpu)) {
ABSL_RAW_LOG(FATAL, "The optional argument must be a CPU number >= 0.\n");
}
}
@@ -67,6 +68,7 @@
} // namespace
} // namespace random_internal_nanobenchmark
+ABSL_NAMESPACE_END
} // namespace absl
int main(int argc, char* argv[]) {
diff --git a/third_party/abseil/absl/random/internal/nonsecure_base.h b/third_party/abseil/absl/random/internal/nonsecure_base.h
index 8847e74..730fa2e 100644
--- a/third_party/abseil/absl/random/internal/nonsecure_base.h
+++ b/third_party/abseil/absl/random/internal/nonsecure_base.h
@@ -33,6 +33,7 @@
#include "absl/types/span.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
// Each instance of NonsecureURBGBase<URBG> will be seeded by variates produced
@@ -143,6 +144,7 @@
};
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_NONSECURE_BASE_H_
diff --git a/third_party/abseil/absl/random/internal/nonsecure_base_test.cc b/third_party/abseil/absl/random/internal/nonsecure_base_test.cc
index d9de990..698027f 100644
--- a/third_party/abseil/absl/random/internal/nonsecure_base_test.cc
+++ b/third_party/abseil/absl/random/internal/nonsecure_base_test.cc
@@ -154,9 +154,10 @@
TEST(NonsecureURBGBase, CompatibleWithStdDistributions) {
ExampleNonsecureURBG rbg;
- std::uniform_int_distribution<uint32_t>(0, 100)(rbg);
- std::uniform_real_distribution<float>()(rbg);
- std::bernoulli_distribution(0.2)(rbg);
+ // Cast to void to suppress [[nodiscard]] warnings
+ static_cast<void>(std::uniform_int_distribution<uint32_t>(0, 100)(rbg));
+ static_cast<void>(std::uniform_real_distribution<float>()(rbg));
+ static_cast<void>(std::bernoulli_distribution(0.2)(rbg));
}
TEST(NonsecureURBGBase, ConsecutiveDefaultInstancesYieldUniqueVariates) {
diff --git a/third_party/abseil/absl/random/internal/pcg_engine.h b/third_party/abseil/absl/random/internal/pcg_engine.h
index b5df4ea..8efaf2e 100644
--- a/third_party/abseil/absl/random/internal/pcg_engine.h
+++ b/third_party/abseil/absl/random/internal/pcg_engine.h
@@ -19,11 +19,13 @@
#include "absl/base/config.h"
#include "absl/meta/type_traits.h"
+#include "absl/numeric/bits.h"
#include "absl/numeric/int128.h"
#include "absl/random/internal/fastmath.h"
#include "absl/random/internal/iostream_state_saver.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
// pcg_engine is a simplified implementation of Melissa O'Neil's PCG engine in
@@ -260,7 +262,7 @@
uint64_t rotate = h >> 58u;
uint64_t s = Uint128Low64(state) ^ h;
#endif
- return random_internal::rotr(s, rotate);
+ return rotr(s, rotate);
}
};
@@ -280,8 +282,8 @@
using state_type = uint64_t;
using result_type = uint32_t;
inline uint32_t operator()(uint64_t state) {
- return random_internal::rotr(
- static_cast<uint32_t>(((state >> 18) ^ state) >> 27), state >> 59);
+ return rotr(static_cast<uint32_t>(((state >> 18) ^ state) >> 27),
+ state >> 59);
}
};
@@ -300,6 +302,7 @@
random_internal::pcg_xsh_rr_64_32>;
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_PCG_ENGINE_H_
diff --git a/third_party/abseil/absl/random/internal/platform.h b/third_party/abseil/absl/random/internal/platform.h
index a5a42cb..bbdb4e6 100644
--- a/third_party/abseil/absl/random/internal/platform.h
+++ b/third_party/abseil/absl/random/internal/platform.h
@@ -162,7 +162,8 @@
// iOS does not support dispatch, even on x86, since applications
// should be bundled as fat binaries, with a different build tailored for
// each specific supported platform/architecture.
-#if defined(__APPLE__) && (TARGET_OS_IPHONE || TARGET_OS_IPHONE_SIMULATOR)
+#if (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || \
+ (defined(TARGET_OS_IPHONE_SIMULATOR) && TARGET_OS_IPHONE_SIMULATOR)
#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH
#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 0
#endif
diff --git a/third_party/abseil/absl/random/internal/pool_urbg.cc b/third_party/abseil/absl/random/internal/pool_urbg.cc
index f2e1c1f..5bee530 100644
--- a/third_party/abseil/absl/random/internal/pool_urbg.cc
+++ b/third_party/abseil/absl/random/internal/pool_urbg.cc
@@ -37,6 +37,7 @@
using absl::base_internal::SpinLockHolder;
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
namespace {
@@ -249,4 +250,5 @@
template class RandenPool<uint64_t>;
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/random/internal/pool_urbg.h b/third_party/abseil/absl/random/internal/pool_urbg.h
index 9b2dd4b..0572192 100644
--- a/third_party/abseil/absl/random/internal/pool_urbg.h
+++ b/third_party/abseil/absl/random/internal/pool_urbg.h
@@ -22,6 +22,7 @@
#include "absl/types/span.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
// RandenPool is a thread-safe random number generator [random.req.urbg] that
@@ -124,6 +125,7 @@
};
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_POOL_URBG_H_
diff --git a/third_party/abseil/absl/random/internal/randen-keys.inc b/third_party/abseil/absl/random/internal/randen-keys.inc
deleted file mode 100644
index fa4b166..0000000
--- a/third_party/abseil/absl/random/internal/randen-keys.inc
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef ABSL_RANDOM_INTERNAL_RANDEN_KEYS_INC_
-#define ABSL_RANDOM_INTERNAL_RANDEN_KEYS_INC_
-
-// Textual header to include the randen_keys where necessary.
-// REQUIRES: struct u64x2{}
-//
-// PROVIDES: kKeys
-// PROVIDES: round_keys[]
-
-// "Nothing up my sleeve" numbers from the first hex digits of Pi, obtained
-// from http://hexpi.sourceforge.net/. The array was generated by following
-// Python script:
-/*
-python << EOF
-"""Generates Randen round keys array from pi-hex.62500.txt file."""
-import binascii
-
-KEYS = 136
-
-def chunks(l, n):
- """Yield successive n-sized chunks from l."""
- for i in range(0, len(l), n):
- yield l[i:i + n]
-
-def pairwise(t):
- """Transforms sequence into sequence of pairs."""
- it = iter(t)
- return zip(it,it)
-
-def digits_from_pi():
- """Reads digits from hexpi.sourceforge.net file."""
- with open("pi-hex.62500.txt") as file:
- return file.read()
-
-def digits_from_urandom():
- """Reads digits from /dev/urandom."""
- with open("/dev/urandom") as file:
- return binascii.hexlify(file.read(KEYS * 16))
-
-digits = digits_from_pi()
-print("static constexpr const size_t kRoundKeys = {0};\n".format(KEYS))
-print("alignas(16) constexpr const u64x2 round_keys[kRoundKeys] = {")
-
-for i, (hi, lo) in zip(range(KEYS), pairwise(chunks(digits, 16))):
- hi = "0x{0}ull".format(hi)
- lo = "0x{0}ull".format(lo)
- print(" u64x2({0}, {1}){2}".format(hi, lo, ',' if i+1 < KEYS else ''))
-
-print("};")
-EOF
-*/
-
-static constexpr const size_t kRoundKeys = 136;
-
-alignas(16) constexpr u64x2 round_keys[kRoundKeys] = {
- u64x2(0x243F6A8885A308D3ull, 0x13198A2E03707344ull),
- u64x2(0xA4093822299F31D0ull, 0x082EFA98EC4E6C89ull),
- u64x2(0x452821E638D01377ull, 0xBE5466CF34E90C6Cull),
- u64x2(0xC0AC29B7C97C50DDull, 0x3F84D5B5B5470917ull),
- u64x2(0x9216D5D98979FB1Bull, 0xD1310BA698DFB5ACull),
- u64x2(0x2FFD72DBD01ADFB7ull, 0xB8E1AFED6A267E96ull),
- u64x2(0xBA7C9045F12C7F99ull, 0x24A19947B3916CF7ull),
- u64x2(0x0801F2E2858EFC16ull, 0x636920D871574E69ull),
- u64x2(0xA458FEA3F4933D7Eull, 0x0D95748F728EB658ull),
- u64x2(0x718BCD5882154AEEull, 0x7B54A41DC25A59B5ull),
- u64x2(0x9C30D5392AF26013ull, 0xC5D1B023286085F0ull),
- u64x2(0xCA417918B8DB38EFull, 0x8E79DCB0603A180Eull),
- u64x2(0x6C9E0E8BB01E8A3Eull, 0xD71577C1BD314B27ull),
- u64x2(0x78AF2FDA55605C60ull, 0xE65525F3AA55AB94ull),
- u64x2(0x5748986263E81440ull, 0x55CA396A2AAB10B6ull),
- u64x2(0xB4CC5C341141E8CEull, 0xA15486AF7C72E993ull),
- u64x2(0xB3EE1411636FBC2Aull, 0x2BA9C55D741831F6ull),
- u64x2(0xCE5C3E169B87931Eull, 0xAFD6BA336C24CF5Cull),
- u64x2(0x7A32538128958677ull, 0x3B8F48986B4BB9AFull),
- u64x2(0xC4BFE81B66282193ull, 0x61D809CCFB21A991ull),
- u64x2(0x487CAC605DEC8032ull, 0xEF845D5DE98575B1ull),
- u64x2(0xDC262302EB651B88ull, 0x23893E81D396ACC5ull),
- u64x2(0x0F6D6FF383F44239ull, 0x2E0B4482A4842004ull),
- u64x2(0x69C8F04A9E1F9B5Eull, 0x21C66842F6E96C9Aull),
- u64x2(0x670C9C61ABD388F0ull, 0x6A51A0D2D8542F68ull),
- u64x2(0x960FA728AB5133A3ull, 0x6EEF0B6C137A3BE4ull),
- u64x2(0xBA3BF0507EFB2A98ull, 0xA1F1651D39AF0176ull),
- u64x2(0x66CA593E82430E88ull, 0x8CEE8619456F9FB4ull),
- u64x2(0x7D84A5C33B8B5EBEull, 0xE06F75D885C12073ull),
- u64x2(0x401A449F56C16AA6ull, 0x4ED3AA62363F7706ull),
- u64x2(0x1BFEDF72429B023Dull, 0x37D0D724D00A1248ull),
- u64x2(0xDB0FEAD349F1C09Bull, 0x075372C980991B7Bull),
- u64x2(0x25D479D8F6E8DEF7ull, 0xE3FE501AB6794C3Bull),
- u64x2(0x976CE0BD04C006BAull, 0xC1A94FB6409F60C4ull),
- u64x2(0x5E5C9EC2196A2463ull, 0x68FB6FAF3E6C53B5ull),
- u64x2(0x1339B2EB3B52EC6Full, 0x6DFC511F9B30952Cull),
- u64x2(0xCC814544AF5EBD09ull, 0xBEE3D004DE334AFDull),
- u64x2(0x660F2807192E4BB3ull, 0xC0CBA85745C8740Full),
- u64x2(0xD20B5F39B9D3FBDBull, 0x5579C0BD1A60320Aull),
- u64x2(0xD6A100C6402C7279ull, 0x679F25FEFB1FA3CCull),
- u64x2(0x8EA5E9F8DB3222F8ull, 0x3C7516DFFD616B15ull),
- u64x2(0x2F501EC8AD0552ABull, 0x323DB5FAFD238760ull),
- u64x2(0x53317B483E00DF82ull, 0x9E5C57BBCA6F8CA0ull),
- u64x2(0x1A87562EDF1769DBull, 0xD542A8F6287EFFC3ull),
- u64x2(0xAC6732C68C4F5573ull, 0x695B27B0BBCA58C8ull),
- u64x2(0xE1FFA35DB8F011A0ull, 0x10FA3D98FD2183B8ull),
- u64x2(0x4AFCB56C2DD1D35Bull, 0x9A53E479B6F84565ull),
- u64x2(0xD28E49BC4BFB9790ull, 0xE1DDF2DAA4CB7E33ull),
- u64x2(0x62FB1341CEE4C6E8ull, 0xEF20CADA36774C01ull),
- u64x2(0xD07E9EFE2BF11FB4ull, 0x95DBDA4DAE909198ull),
- u64x2(0xEAAD8E716B93D5A0ull, 0xD08ED1D0AFC725E0ull),
- u64x2(0x8E3C5B2F8E7594B7ull, 0x8FF6E2FBF2122B64ull),
- u64x2(0x8888B812900DF01Cull, 0x4FAD5EA0688FC31Cull),
- u64x2(0xD1CFF191B3A8C1ADull, 0x2F2F2218BE0E1777ull),
- u64x2(0xEA752DFE8B021FA1ull, 0xE5A0CC0FB56F74E8ull),
- u64x2(0x18ACF3D6CE89E299ull, 0xB4A84FE0FD13E0B7ull),
- u64x2(0x7CC43B81D2ADA8D9ull, 0x165FA26680957705ull),
- u64x2(0x93CC7314211A1477ull, 0xE6AD206577B5FA86ull),
- u64x2(0xC75442F5FB9D35CFull, 0xEBCDAF0C7B3E89A0ull),
- u64x2(0xD6411BD3AE1E7E49ull, 0x00250E2D2071B35Eull),
- u64x2(0x226800BB57B8E0AFull, 0x2464369BF009B91Eull),
- u64x2(0x5563911D59DFA6AAull, 0x78C14389D95A537Full),
- u64x2(0x207D5BA202E5B9C5ull, 0x832603766295CFA9ull),
- u64x2(0x11C819684E734A41ull, 0xB3472DCA7B14A94Aull),
- u64x2(0x1B5100529A532915ull, 0xD60F573FBC9BC6E4ull),
- u64x2(0x2B60A47681E67400ull, 0x08BA6FB5571BE91Full),
- u64x2(0xF296EC6B2A0DD915ull, 0xB6636521E7B9F9B6ull),
- u64x2(0xFF34052EC5855664ull, 0x53B02D5DA99F8FA1ull),
- u64x2(0x08BA47996E85076Aull, 0x4B7A70E9B5B32944ull),
- u64x2(0xDB75092EC4192623ull, 0xAD6EA6B049A7DF7Dull),
- u64x2(0x9CEE60B88FEDB266ull, 0xECAA8C71699A18FFull),
- u64x2(0x5664526CC2B19EE1ull, 0x193602A575094C29ull),
- u64x2(0xA0591340E4183A3Eull, 0x3F54989A5B429D65ull),
- u64x2(0x6B8FE4D699F73FD6ull, 0xA1D29C07EFE830F5ull),
- u64x2(0x4D2D38E6F0255DC1ull, 0x4CDD20868470EB26ull),
- u64x2(0x6382E9C6021ECC5Eull, 0x09686B3F3EBAEFC9ull),
- u64x2(0x3C9718146B6A70A1ull, 0x687F358452A0E286ull),
- u64x2(0xB79C5305AA500737ull, 0x3E07841C7FDEAE5Cull),
- u64x2(0x8E7D44EC5716F2B8ull, 0xB03ADA37F0500C0Dull),
- u64x2(0xF01C1F040200B3FFull, 0xAE0CF51A3CB574B2ull),
- u64x2(0x25837A58DC0921BDull, 0xD19113F97CA92FF6ull),
- u64x2(0x9432477322F54701ull, 0x3AE5E58137C2DADCull),
- u64x2(0xC8B576349AF3DDA7ull, 0xA94461460FD0030Eull),
- u64x2(0xECC8C73EA4751E41ull, 0xE238CD993BEA0E2Full),
- u64x2(0x3280BBA1183EB331ull, 0x4E548B384F6DB908ull),
- u64x2(0x6F420D03F60A04BFull, 0x2CB8129024977C79ull),
- u64x2(0x5679B072BCAF89AFull, 0xDE9A771FD9930810ull),
- u64x2(0xB38BAE12DCCF3F2Eull, 0x5512721F2E6B7124ull),
- u64x2(0x501ADDE69F84CD87ull, 0x7A5847187408DA17ull),
- u64x2(0xBC9F9ABCE94B7D8Cull, 0xEC7AEC3ADB851DFAull),
- u64x2(0x63094366C464C3D2ull, 0xEF1C18473215D808ull),
- u64x2(0xDD433B3724C2BA16ull, 0x12A14D432A65C451ull),
- u64x2(0x50940002133AE4DDull, 0x71DFF89E10314E55ull),
- u64x2(0x81AC77D65F11199Bull, 0x043556F1D7A3C76Bull),
- u64x2(0x3C11183B5924A509ull, 0xF28FE6ED97F1FBFAull),
- u64x2(0x9EBABF2C1E153C6Eull, 0x86E34570EAE96FB1ull),
- u64x2(0x860E5E0A5A3E2AB3ull, 0x771FE71C4E3D06FAull),
- u64x2(0x2965DCB999E71D0Full, 0x803E89D65266C825ull),
- u64x2(0x2E4CC9789C10B36Aull, 0xC6150EBA94E2EA78ull),
- u64x2(0xA6FC3C531E0A2DF4ull, 0xF2F74EA7361D2B3Dull),
- u64x2(0x1939260F19C27960ull, 0x5223A708F71312B6ull),
- u64x2(0xEBADFE6EEAC31F66ull, 0xE3BC4595A67BC883ull),
- u64x2(0xB17F37D1018CFF28ull, 0xC332DDEFBE6C5AA5ull),
- u64x2(0x6558218568AB9702ull, 0xEECEA50FDB2F953Bull),
- u64x2(0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull),
- u64x2(0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull),
- u64x2(0x0334FE1EAA0363CFull, 0xB5735C904C70A239ull),
- u64x2(0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull),
- u64x2(0x9CAB5CABB2F3846Eull, 0x648B1EAF19BDF0CAull),
- u64x2(0xA02369B9655ABB50ull, 0x40685A323C2AB4B3ull),
- u64x2(0x319EE9D5C021B8F7ull, 0x9B540B19875FA099ull),
- u64x2(0x95F7997E623D7DA8ull, 0xF837889A97E32D77ull),
- u64x2(0x11ED935F16681281ull, 0x0E358829C7E61FD6ull),
- u64x2(0x96DEDFA17858BA99ull, 0x57F584A51B227263ull),
- u64x2(0x9B83C3FF1AC24696ull, 0xCDB30AEB532E3054ull),
- u64x2(0x8FD948E46DBC3128ull, 0x58EBF2EF34C6FFEAull),
- u64x2(0xFE28ED61EE7C3C73ull, 0x5D4A14D9E864B7E3ull),
- u64x2(0x42105D14203E13E0ull, 0x45EEE2B6A3AAABEAull),
- u64x2(0xDB6C4F15FACB4FD0ull, 0xC742F442EF6ABBB5ull),
- u64x2(0x654F3B1D41CD2105ull, 0xD81E799E86854DC7ull),
- u64x2(0xE44B476A3D816250ull, 0xCF62A1F25B8D2646ull),
- u64x2(0xFC8883A0C1C7B6A3ull, 0x7F1524C369CB7492ull),
- u64x2(0x47848A0B5692B285ull, 0x095BBF00AD19489Dull),
- u64x2(0x1462B17423820D00ull, 0x58428D2A0C55F5EAull),
- u64x2(0x1DADF43E233F7061ull, 0x3372F0928D937E41ull),
- u64x2(0xD65FECF16C223BDBull, 0x7CDE3759CBEE7460ull),
- u64x2(0x4085F2A7CE77326Eull, 0xA607808419F8509Eull),
- u64x2(0xE8EFD85561D99735ull, 0xA969A7AAC50C06C2ull),
- u64x2(0x5A04ABFC800BCADCull, 0x9E447A2EC3453484ull),
- u64x2(0xFDD567050E1E9EC9ull, 0xDB73DBD3105588CDull),
- u64x2(0x675FDA79E3674340ull, 0xC5C43465713E38D8ull),
- u64x2(0x3D28F89EF16DFF20ull, 0x153E21E78FB03D4Aull),
- u64x2(0xE6E39F2BDB83ADF7ull, 0xE93D5A68948140F7ull),
- u64x2(0xF64C261C94692934ull, 0x411520F77602D4F7ull),
- u64x2(0xBCF46B2ED4A10068ull, 0xD40824713320F46Aull),
- u64x2(0x43B7D4B7500061AFull, 0x1E39F62E97244546ull)};
-
-#endif // ABSL_RANDOM_INTERNAL_RANDEN_KEYS_INC_
diff --git a/third_party/abseil/absl/random/internal/randen.cc b/third_party/abseil/absl/random/internal/randen.cc
index bab8075..c1bc044 100644
--- a/third_party/abseil/absl/random/internal/randen.cc
+++ b/third_party/abseil/absl/random/internal/randen.cc
@@ -17,7 +17,7 @@
#include "absl/base/internal/raw_logging.h"
#include "absl/random/internal/randen_detect.h"
-// RANDen = RANDom generator or beetroots in Swiss German.
+// RANDen = RANDom generator or beetroots in Swiss High German.
// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
//
@@ -41,6 +41,7 @@
// structured/low-entropy counters to digits of Pi.
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
namespace {
@@ -86,4 +87,5 @@
}
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/random/internal/randen.h b/third_party/abseil/absl/random/internal/randen.h
index a4ff254..9a3840b 100644
--- a/third_party/abseil/absl/random/internal/randen.h
+++ b/third_party/abseil/absl/random/internal/randen.h
@@ -23,9 +23,10 @@
#include "absl/random/internal/randen_traits.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
-// RANDen = RANDom generator or beetroots in Swiss German.
+// RANDen = RANDom generator or beetroots in Swiss High German.
// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
//
@@ -95,6 +96,7 @@
};
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_RANDEN_H_
diff --git a/third_party/abseil/absl/random/internal/randen_detect.cc b/third_party/abseil/absl/random/internal/randen_detect.cc
index d5946b2..bbe7b96 100644
--- a/third_party/abseil/absl/random/internal/randen_detect.cc
+++ b/third_party/abseil/absl/random/internal/randen_detect.cc
@@ -1,13 +1,13 @@
// Copyright 2017 The Abseil Authors.
//
-// Licensed under the Apache License, Version 2.0 (the"License");
+// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an"AS IS" BASIS,
+// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
@@ -95,6 +95,7 @@
#endif
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
// The default return at the end of the function might be unreachable depending
@@ -216,4 +217,5 @@
#endif
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/random/internal/randen_detect.h b/third_party/abseil/absl/random/internal/randen_detect.h
index 44c5c66..f283f43 100644
--- a/third_party/abseil/absl/random/internal/randen_detect.h
+++ b/third_party/abseil/absl/random/internal/randen_detect.h
@@ -15,7 +15,10 @@
#ifndef ABSL_RANDOM_INTERNAL_RANDEN_DETECT_H_
#define ABSL_RANDOM_INTERNAL_RANDEN_DETECT_H_
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
// Returns whether the current CPU supports RandenHwAes implementation.
@@ -24,6 +27,7 @@
bool CPUSupportsRandenHwAes();
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_RANDEN_DETECT_H_
diff --git a/third_party/abseil/absl/random/internal/randen_engine.h b/third_party/abseil/absl/random/internal/randen_engine.h
index 02212a1..6b33731 100644
--- a/third_party/abseil/absl/random/internal/randen_engine.h
+++ b/third_party/abseil/absl/random/internal/randen_engine.h
@@ -28,6 +28,7 @@
#include "absl/random/internal/randen.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
// Deterministic pseudorandom byte generator with backtracking resistance
@@ -223,6 +224,7 @@
};
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_RANDEN_ENGINE_H_
diff --git a/third_party/abseil/absl/random/internal/randen_hwaes.cc b/third_party/abseil/absl/random/internal/randen_hwaes.cc
index 7d5b2b7..b5a3f90 100644
--- a/third_party/abseil/absl/random/internal/randen_hwaes.cc
+++ b/third_party/abseil/absl/random/internal/randen_hwaes.cc
@@ -24,6 +24,7 @@
#include "absl/base/attributes.h"
#include "absl/random/internal/platform.h"
+#include "absl/random/internal/randen_traits.h"
// ABSL_RANDEN_HWAES_IMPL indicates whether this file will contain
// a hardware accelerated implementation of randen, or whether it
@@ -75,6 +76,7 @@
#include <cstdlib>
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
// No accelerated implementation.
@@ -106,6 +108,7 @@
}
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#else // defined(ABSL_RANDEN_HWAES_IMPL)
@@ -113,8 +116,16 @@
// Accelerated implementations are supported.
// We need the per-architecture includes and defines.
//
+namespace {
-#include "absl/random/internal/randen_traits.h"
+using absl::random_internal::RandenTraits;
+
+// Randen operates on 128-bit vectors.
+struct alignas(16) u64x2 {
+ uint64_t data[2];
+};
+
+} // namespace
// TARGET_CRYPTO defines a crypto attribute for each architecture.
//
@@ -139,6 +150,7 @@
#include <altivec.h>
// <altivec.h> #defines vector __vector; in C++, this is bad form.
#undef vector
+#undef bool
// Rely on the PowerPC AltiVec vector operations for accelerated AES
// instructions. GCC support of the PPC vector types is described in:
@@ -148,7 +160,6 @@
using Vector128 = __vector unsigned long long; // NOLINT(runtime/int)
namespace {
-
inline ABSL_TARGET_CRYPTO Vector128 ReverseBytes(const Vector128& v) {
// Reverses the bytes of the vector.
const __vector unsigned char perm = {15, 14, 13, 12, 11, 10, 9, 8,
@@ -159,13 +170,11 @@
// WARNING: these load/store in native byte order. It is OK to load and then
// store an unchanged vector, but interpreting the bits as a number or input
// to AES will have undefined results.
-inline ABSL_TARGET_CRYPTO Vector128
-Vector128Load(const void* ABSL_RANDOM_INTERNAL_RESTRICT from) {
+inline ABSL_TARGET_CRYPTO Vector128 Vector128Load(const void* from) {
return vec_vsx_ld(0, reinterpret_cast<const Vector128*>(from));
}
-inline ABSL_TARGET_CRYPTO void Vector128Store(
- const Vector128& v, void* ABSL_RANDOM_INTERNAL_RESTRICT to) {
+inline ABSL_TARGET_CRYPTO void Vector128Store(const Vector128& v, void* to) {
vec_vsx_st(v, 0, reinterpret_cast<Vector128*>(to));
}
@@ -177,15 +186,9 @@
}
// Enables native loads in the round loop by pre-swapping.
-inline ABSL_TARGET_CRYPTO void SwapEndian(
- uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state) {
- using absl::random_internal::RandenTraits;
- constexpr size_t kLanes = 2;
- constexpr size_t kFeistelBlocks = RandenTraits::kFeistelBlocks;
-
- for (uint32_t branch = 0; branch < kFeistelBlocks; ++branch) {
- const Vector128 v = ReverseBytes(Vector128Load(state + kLanes * branch));
- Vector128Store(v, state + kLanes * branch);
+inline ABSL_TARGET_CRYPTO void SwapEndian(u64x2* state) {
+ for (uint32_t block = 0; block < RandenTraits::kFeistelBlocks; ++block) {
+ Vector128Store(ReverseBytes(Vector128Load(state + block)), state + block);
}
}
@@ -230,13 +233,11 @@
namespace {
-inline ABSL_TARGET_CRYPTO Vector128
-Vector128Load(const void* ABSL_RANDOM_INTERNAL_RESTRICT from) {
+inline ABSL_TARGET_CRYPTO Vector128 Vector128Load(const void* from) {
return vld1q_u8(reinterpret_cast<const uint8_t*>(from));
}
-inline ABSL_TARGET_CRYPTO void Vector128Store(
- const Vector128& v, void* ABSL_RANDOM_INTERNAL_RESTRICT to) {
+inline ABSL_TARGET_CRYPTO void Vector128Store(const Vector128& v, void* to) {
vst1q_u8(reinterpret_cast<uint8_t*>(to), v);
}
@@ -254,8 +255,7 @@
return vaesmcq_u8(vaeseq_u8(state, uint8x16_t{})) ^ round_key;
}
-inline ABSL_TARGET_CRYPTO void SwapEndian(
- uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT) {}
+inline ABSL_TARGET_CRYPTO void SwapEndian(void*) {}
} // namespace
@@ -283,15 +283,12 @@
__m128i data_;
};
-inline ABSL_TARGET_CRYPTO Vector128
-Vector128Load(const void* ABSL_RANDOM_INTERNAL_RESTRICT from) {
+inline ABSL_TARGET_CRYPTO Vector128 Vector128Load(const void* from) {
return Vector128(_mm_load_si128(reinterpret_cast<const __m128i*>(from)));
}
-inline ABSL_TARGET_CRYPTO void Vector128Store(
- const Vector128& v, void* ABSL_RANDOM_INTERNAL_RESTRICT to) {
- _mm_store_si128(reinterpret_cast<__m128i * ABSL_RANDOM_INTERNAL_RESTRICT>(to),
- v.data());
+inline ABSL_TARGET_CRYPTO void Vector128Store(const Vector128& v, void* to) {
+ _mm_store_si128(reinterpret_cast<__m128i*>(to), v.data());
}
// One round of AES. "round_key" is a public constant for breaking the
@@ -304,40 +301,12 @@
return Vector128(_mm_aesenc_si128(state.data(), round_key.data()));
}
-inline ABSL_TARGET_CRYPTO void SwapEndian(
- uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT) {}
+inline ABSL_TARGET_CRYPTO void SwapEndian(void*) {}
} // namespace
#endif
-namespace {
-
-// u64x2 is a 128-bit, (2 x uint64_t lanes) struct used to store
-// the randen_keys.
-struct alignas(16) u64x2 {
- constexpr u64x2(uint64_t hi, uint64_t lo)
-#if defined(ABSL_ARCH_PPC)
- // This has been tested with PPC running in little-endian mode;
- // We byte-swap the u64x2 structure from little-endian to big-endian
- // because altivec always runs in big-endian mode.
- : v{__builtin_bswap64(hi), __builtin_bswap64(lo)} {
-#else
- : v{lo, hi} {
-#endif
- }
-
- constexpr bool operator==(const u64x2& other) const {
- return v[0] == other.v[0] && v[1] == other.v[1];
- }
-
- constexpr bool operator!=(const u64x2& other) const {
- return !(*this == other);
- }
-
- uint64_t v[2];
-}; // namespace
-
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunknown-pragmas"
@@ -346,7 +315,6 @@
// At this point, all of the platform-specific features have been defined /
// implemented.
//
-// REQUIRES: using u64x2 = ...
// REQUIRES: using Vector128 = ...
// REQUIRES: Vector128 Vector128Load(void*) {...}
// REQUIRES: void Vector128Store(Vector128, void*) {...}
@@ -355,95 +323,50 @@
//
// PROVIDES: absl::random_internal::RandenHwAes::Absorb
// PROVIDES: absl::random_internal::RandenHwAes::Generate
-
-// RANDen = RANDom generator or beetroots in Swiss German.
-// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
-// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
-//
-// High-level summary:
-// 1) Reverie (see "A Robust and Sponge-Like PRNG with Improved Efficiency") is
-// a sponge-like random generator that requires a cryptographic permutation.
-// It improves upon "Provably Robust Sponge-Based PRNGs and KDFs" by
-// achieving backtracking resistance with only one Permute() per buffer.
-//
-// 2) "Simpira v2: A Family of Efficient Permutations Using the AES Round
-// Function" constructs up to 1024-bit permutations using an improved
-// Generalized Feistel network with 2-round AES-128 functions. This Feistel
-// block shuffle achieves diffusion faster and is less vulnerable to
-// sliced-biclique attacks than the Type-2 cyclic shuffle.
-//
-// 3) "Improving the Generalized Feistel" and "New criterion for diffusion
-// property" extends the same kind of improved Feistel block shuffle to 16
-// branches, which enables a 2048-bit permutation.
-//
-// We combine these three ideas and also change Simpira's subround keys from
-// structured/low-entropy counters to digits of Pi.
-
-// Randen constants.
-using absl::random_internal::RandenTraits;
-constexpr size_t kStateBytes = RandenTraits::kStateBytes;
-constexpr size_t kCapacityBytes = RandenTraits::kCapacityBytes;
-constexpr size_t kFeistelBlocks = RandenTraits::kFeistelBlocks;
-constexpr size_t kFeistelRounds = RandenTraits::kFeistelRounds;
-constexpr size_t kFeistelFunctions = RandenTraits::kFeistelFunctions;
-
-// Independent keys (272 = 2.1 KiB) for the first AES subround of each function.
-constexpr size_t kKeys = kFeistelRounds * kFeistelFunctions;
-
-// INCLUDE keys.
-#include "absl/random/internal/randen-keys.inc"
-
-static_assert(kKeys == kRoundKeys, "kKeys and kRoundKeys must be equal");
-static_assert(round_keys[kKeys - 1] != u64x2(0, 0),
- "Too few round_keys initializers");
-
-// Number of uint64_t lanes per 128-bit vector;
-constexpr size_t kLanes = 2;
+namespace {
// Block shuffles applies a shuffle to the entire state between AES rounds.
// Improved odd-even shuffle from "New criterion for diffusion property".
-inline ABSL_TARGET_CRYPTO void BlockShuffle(
- uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state) {
- static_assert(kFeistelBlocks == 16, "Expecting 16 FeistelBlocks.");
+inline ABSL_TARGET_CRYPTO void BlockShuffle(u64x2* state) {
+ static_assert(RandenTraits::kFeistelBlocks == 16,
+ "Expecting 16 FeistelBlocks.");
- constexpr size_t shuffle[kFeistelBlocks] = {7, 2, 13, 4, 11, 8, 3, 6,
- 15, 0, 9, 10, 1, 14, 5, 12};
+ constexpr size_t shuffle[RandenTraits::kFeistelBlocks] = {
+ 7, 2, 13, 4, 11, 8, 3, 6, 15, 0, 9, 10, 1, 14, 5, 12};
- // The fully unrolled loop without the memcpy improves the speed by about
- // 30% over the equivalent loop.
- const Vector128 v0 = Vector128Load(state + kLanes * shuffle[0]);
- const Vector128 v1 = Vector128Load(state + kLanes * shuffle[1]);
- const Vector128 v2 = Vector128Load(state + kLanes * shuffle[2]);
- const Vector128 v3 = Vector128Load(state + kLanes * shuffle[3]);
- const Vector128 v4 = Vector128Load(state + kLanes * shuffle[4]);
- const Vector128 v5 = Vector128Load(state + kLanes * shuffle[5]);
- const Vector128 v6 = Vector128Load(state + kLanes * shuffle[6]);
- const Vector128 v7 = Vector128Load(state + kLanes * shuffle[7]);
- const Vector128 w0 = Vector128Load(state + kLanes * shuffle[8]);
- const Vector128 w1 = Vector128Load(state + kLanes * shuffle[9]);
- const Vector128 w2 = Vector128Load(state + kLanes * shuffle[10]);
- const Vector128 w3 = Vector128Load(state + kLanes * shuffle[11]);
- const Vector128 w4 = Vector128Load(state + kLanes * shuffle[12]);
- const Vector128 w5 = Vector128Load(state + kLanes * shuffle[13]);
- const Vector128 w6 = Vector128Load(state + kLanes * shuffle[14]);
- const Vector128 w7 = Vector128Load(state + kLanes * shuffle[15]);
+ const Vector128 v0 = Vector128Load(state + shuffle[0]);
+ const Vector128 v1 = Vector128Load(state + shuffle[1]);
+ const Vector128 v2 = Vector128Load(state + shuffle[2]);
+ const Vector128 v3 = Vector128Load(state + shuffle[3]);
+ const Vector128 v4 = Vector128Load(state + shuffle[4]);
+ const Vector128 v5 = Vector128Load(state + shuffle[5]);
+ const Vector128 v6 = Vector128Load(state + shuffle[6]);
+ const Vector128 v7 = Vector128Load(state + shuffle[7]);
+ const Vector128 w0 = Vector128Load(state + shuffle[8]);
+ const Vector128 w1 = Vector128Load(state + shuffle[9]);
+ const Vector128 w2 = Vector128Load(state + shuffle[10]);
+ const Vector128 w3 = Vector128Load(state + shuffle[11]);
+ const Vector128 w4 = Vector128Load(state + shuffle[12]);
+ const Vector128 w5 = Vector128Load(state + shuffle[13]);
+ const Vector128 w6 = Vector128Load(state + shuffle[14]);
+ const Vector128 w7 = Vector128Load(state + shuffle[15]);
- Vector128Store(v0, state + kLanes * 0);
- Vector128Store(v1, state + kLanes * 1);
- Vector128Store(v2, state + kLanes * 2);
- Vector128Store(v3, state + kLanes * 3);
- Vector128Store(v4, state + kLanes * 4);
- Vector128Store(v5, state + kLanes * 5);
- Vector128Store(v6, state + kLanes * 6);
- Vector128Store(v7, state + kLanes * 7);
- Vector128Store(w0, state + kLanes * 8);
- Vector128Store(w1, state + kLanes * 9);
- Vector128Store(w2, state + kLanes * 10);
- Vector128Store(w3, state + kLanes * 11);
- Vector128Store(w4, state + kLanes * 12);
- Vector128Store(w5, state + kLanes * 13);
- Vector128Store(w6, state + kLanes * 14);
- Vector128Store(w7, state + kLanes * 15);
+ Vector128Store(v0, state + 0);
+ Vector128Store(v1, state + 1);
+ Vector128Store(v2, state + 2);
+ Vector128Store(v3, state + 3);
+ Vector128Store(v4, state + 4);
+ Vector128Store(v5, state + 5);
+ Vector128Store(v6, state + 6);
+ Vector128Store(v7, state + 7);
+ Vector128Store(w0, state + 8);
+ Vector128Store(w1, state + 9);
+ Vector128Store(w2, state + 10);
+ Vector128Store(w3, state + 11);
+ Vector128Store(w4, state + 12);
+ Vector128Store(w5, state + 13);
+ Vector128Store(w6, state + 14);
+ Vector128Store(w7, state + 15);
}
// Feistel round function using two AES subrounds. Very similar to F()
@@ -452,28 +375,28 @@
// parallel hides the 7-cycle AESNI latency on HSW. Note that the Feistel
// XORs are 'free' (included in the second AES instruction).
inline ABSL_TARGET_CRYPTO const u64x2* FeistelRound(
- uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state,
- const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys) {
- static_assert(kFeistelBlocks == 16, "Expecting 16 FeistelBlocks.");
+ u64x2* state, const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys) {
+ static_assert(RandenTraits::kFeistelBlocks == 16,
+ "Expecting 16 FeistelBlocks.");
// MSVC does a horrible job at unrolling loops.
// So we unroll the loop by hand to improve the performance.
- const Vector128 s0 = Vector128Load(state + kLanes * 0);
- const Vector128 s1 = Vector128Load(state + kLanes * 1);
- const Vector128 s2 = Vector128Load(state + kLanes * 2);
- const Vector128 s3 = Vector128Load(state + kLanes * 3);
- const Vector128 s4 = Vector128Load(state + kLanes * 4);
- const Vector128 s5 = Vector128Load(state + kLanes * 5);
- const Vector128 s6 = Vector128Load(state + kLanes * 6);
- const Vector128 s7 = Vector128Load(state + kLanes * 7);
- const Vector128 s8 = Vector128Load(state + kLanes * 8);
- const Vector128 s9 = Vector128Load(state + kLanes * 9);
- const Vector128 s10 = Vector128Load(state + kLanes * 10);
- const Vector128 s11 = Vector128Load(state + kLanes * 11);
- const Vector128 s12 = Vector128Load(state + kLanes * 12);
- const Vector128 s13 = Vector128Load(state + kLanes * 13);
- const Vector128 s14 = Vector128Load(state + kLanes * 14);
- const Vector128 s15 = Vector128Load(state + kLanes * 15);
+ const Vector128 s0 = Vector128Load(state + 0);
+ const Vector128 s1 = Vector128Load(state + 1);
+ const Vector128 s2 = Vector128Load(state + 2);
+ const Vector128 s3 = Vector128Load(state + 3);
+ const Vector128 s4 = Vector128Load(state + 4);
+ const Vector128 s5 = Vector128Load(state + 5);
+ const Vector128 s6 = Vector128Load(state + 6);
+ const Vector128 s7 = Vector128Load(state + 7);
+ const Vector128 s8 = Vector128Load(state + 8);
+ const Vector128 s9 = Vector128Load(state + 9);
+ const Vector128 s10 = Vector128Load(state + 10);
+ const Vector128 s11 = Vector128Load(state + 11);
+ const Vector128 s12 = Vector128Load(state + 12);
+ const Vector128 s13 = Vector128Load(state + 13);
+ const Vector128 s14 = Vector128Load(state + 14);
+ const Vector128 s15 = Vector128Load(state + 15);
// Encode even blocks with keys.
const Vector128 e0 = AesRound(s0, Vector128Load(keys + 0));
@@ -496,14 +419,14 @@
const Vector128 o15 = AesRound(e14, s15);
// Store odd blocks. (These will be shuffled later).
- Vector128Store(o1, state + kLanes * 1);
- Vector128Store(o3, state + kLanes * 3);
- Vector128Store(o5, state + kLanes * 5);
- Vector128Store(o7, state + kLanes * 7);
- Vector128Store(o9, state + kLanes * 9);
- Vector128Store(o11, state + kLanes * 11);
- Vector128Store(o13, state + kLanes * 13);
- Vector128Store(o15, state + kLanes * 15);
+ Vector128Store(o1, state + 1);
+ Vector128Store(o3, state + 3);
+ Vector128Store(o5, state + 5);
+ Vector128Store(o7, state + 7);
+ Vector128Store(o9, state + 9);
+ Vector128Store(o11, state + 11);
+ Vector128Store(o13, state + 13);
+ Vector128Store(o15, state + 15);
return keys + 8;
}
@@ -513,17 +436,13 @@
// 2^64 queries if the round function is a PRF. This is similar to the b=8 case
// of Simpira v2, but more efficient than its generic construction for b=16.
inline ABSL_TARGET_CRYPTO void Permute(
- const void* ABSL_RANDOM_INTERNAL_RESTRICT keys,
- uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state) {
- const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys128 =
- static_cast<const u64x2*>(keys);
-
+ u64x2* state, const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys) {
// (Successfully unrolled; the first iteration jumps into the second half)
#ifdef __clang__
#pragma clang loop unroll_count(2)
#endif
- for (size_t round = 0; round < kFeistelRounds; ++round) {
- keys128 = FeistelRound(state, keys128);
+ for (size_t round = 0; round < RandenTraits::kFeistelRounds; ++round) {
+ keys = FeistelRound(state, keys);
BlockShuffle(state);
}
}
@@ -531,6 +450,7 @@
} // namespace
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
bool HasRandenHwAesImplementation() { return true; }
@@ -538,99 +458,101 @@
const void* ABSL_TARGET_CRYPTO RandenHwAes::GetKeys() {
// Round keys for one AES per Feistel round and branch.
// The canonical implementation uses first digits of Pi.
- return round_keys;
+#if defined(ABSL_ARCH_PPC)
+ return kRandenRoundKeysBE;
+#else
+ return kRandenRoundKeys;
+#endif
}
// NOLINTNEXTLINE
void ABSL_TARGET_CRYPTO RandenHwAes::Absorb(const void* seed_void,
void* state_void) {
- uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state =
- reinterpret_cast<uint64_t*>(state_void);
- const uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT seed =
- reinterpret_cast<const uint64_t*>(seed_void);
+ static_assert(RandenTraits::kCapacityBytes / sizeof(Vector128) == 1,
+ "Unexpected Randen kCapacityBlocks");
+ static_assert(RandenTraits::kStateBytes / sizeof(Vector128) == 16,
+ "Unexpected Randen kStateBlocks");
- constexpr size_t kCapacityBlocks = kCapacityBytes / sizeof(Vector128);
- constexpr size_t kStateBlocks = kStateBytes / sizeof(Vector128);
+ auto* state =
+ reinterpret_cast<u64x2 * ABSL_RANDOM_INTERNAL_RESTRICT>(state_void);
+ const auto* seed =
+ reinterpret_cast<const u64x2 * ABSL_RANDOM_INTERNAL_RESTRICT>(seed_void);
- static_assert(kCapacityBlocks * sizeof(Vector128) == kCapacityBytes,
- "Not i*V");
- static_assert(kCapacityBlocks == 1, "Unexpected Randen kCapacityBlocks");
- static_assert(kStateBlocks == 16, "Unexpected Randen kStateBlocks");
+ Vector128 b1 = Vector128Load(state + 1);
+ b1 ^= Vector128Load(seed + 0);
+ Vector128Store(b1, state + 1);
- Vector128 b1 = Vector128Load(state + kLanes * 1);
- b1 ^= Vector128Load(seed + kLanes * 0);
- Vector128Store(b1, state + kLanes * 1);
+ Vector128 b2 = Vector128Load(state + 2);
+ b2 ^= Vector128Load(seed + 1);
+ Vector128Store(b2, state + 2);
- Vector128 b2 = Vector128Load(state + kLanes * 2);
- b2 ^= Vector128Load(seed + kLanes * 1);
- Vector128Store(b2, state + kLanes * 2);
+ Vector128 b3 = Vector128Load(state + 3);
+ b3 ^= Vector128Load(seed + 2);
+ Vector128Store(b3, state + 3);
- Vector128 b3 = Vector128Load(state + kLanes * 3);
- b3 ^= Vector128Load(seed + kLanes * 2);
- Vector128Store(b3, state + kLanes * 3);
+ Vector128 b4 = Vector128Load(state + 4);
+ b4 ^= Vector128Load(seed + 3);
+ Vector128Store(b4, state + 4);
- Vector128 b4 = Vector128Load(state + kLanes * 4);
- b4 ^= Vector128Load(seed + kLanes * 3);
- Vector128Store(b4, state + kLanes * 4);
+ Vector128 b5 = Vector128Load(state + 5);
+ b5 ^= Vector128Load(seed + 4);
+ Vector128Store(b5, state + 5);
- Vector128 b5 = Vector128Load(state + kLanes * 5);
- b5 ^= Vector128Load(seed + kLanes * 4);
- Vector128Store(b5, state + kLanes * 5);
+ Vector128 b6 = Vector128Load(state + 6);
+ b6 ^= Vector128Load(seed + 5);
+ Vector128Store(b6, state + 6);
- Vector128 b6 = Vector128Load(state + kLanes * 6);
- b6 ^= Vector128Load(seed + kLanes * 5);
- Vector128Store(b6, state + kLanes * 6);
+ Vector128 b7 = Vector128Load(state + 7);
+ b7 ^= Vector128Load(seed + 6);
+ Vector128Store(b7, state + 7);
- Vector128 b7 = Vector128Load(state + kLanes * 7);
- b7 ^= Vector128Load(seed + kLanes * 6);
- Vector128Store(b7, state + kLanes * 7);
+ Vector128 b8 = Vector128Load(state + 8);
+ b8 ^= Vector128Load(seed + 7);
+ Vector128Store(b8, state + 8);
- Vector128 b8 = Vector128Load(state + kLanes * 8);
- b8 ^= Vector128Load(seed + kLanes * 7);
- Vector128Store(b8, state + kLanes * 8);
+ Vector128 b9 = Vector128Load(state + 9);
+ b9 ^= Vector128Load(seed + 8);
+ Vector128Store(b9, state + 9);
- Vector128 b9 = Vector128Load(state + kLanes * 9);
- b9 ^= Vector128Load(seed + kLanes * 8);
- Vector128Store(b9, state + kLanes * 9);
+ Vector128 b10 = Vector128Load(state + 10);
+ b10 ^= Vector128Load(seed + 9);
+ Vector128Store(b10, state + 10);
- Vector128 b10 = Vector128Load(state + kLanes * 10);
- b10 ^= Vector128Load(seed + kLanes * 9);
- Vector128Store(b10, state + kLanes * 10);
+ Vector128 b11 = Vector128Load(state + 11);
+ b11 ^= Vector128Load(seed + 10);
+ Vector128Store(b11, state + 11);
- Vector128 b11 = Vector128Load(state + kLanes * 11);
- b11 ^= Vector128Load(seed + kLanes * 10);
- Vector128Store(b11, state + kLanes * 11);
+ Vector128 b12 = Vector128Load(state + 12);
+ b12 ^= Vector128Load(seed + 11);
+ Vector128Store(b12, state + 12);
- Vector128 b12 = Vector128Load(state + kLanes * 12);
- b12 ^= Vector128Load(seed + kLanes * 11);
- Vector128Store(b12, state + kLanes * 12);
+ Vector128 b13 = Vector128Load(state + 13);
+ b13 ^= Vector128Load(seed + 12);
+ Vector128Store(b13, state + 13);
- Vector128 b13 = Vector128Load(state + kLanes * 13);
- b13 ^= Vector128Load(seed + kLanes * 12);
- Vector128Store(b13, state + kLanes * 13);
+ Vector128 b14 = Vector128Load(state + 14);
+ b14 ^= Vector128Load(seed + 13);
+ Vector128Store(b14, state + 14);
- Vector128 b14 = Vector128Load(state + kLanes * 14);
- b14 ^= Vector128Load(seed + kLanes * 13);
- Vector128Store(b14, state + kLanes * 14);
-
- Vector128 b15 = Vector128Load(state + kLanes * 15);
- b15 ^= Vector128Load(seed + kLanes * 14);
- Vector128Store(b15, state + kLanes * 15);
+ Vector128 b15 = Vector128Load(state + 15);
+ b15 ^= Vector128Load(seed + 14);
+ Vector128Store(b15, state + 15);
}
// NOLINTNEXTLINE
-void ABSL_TARGET_CRYPTO RandenHwAes::Generate(const void* keys,
+void ABSL_TARGET_CRYPTO RandenHwAes::Generate(const void* keys_void,
void* state_void) {
- static_assert(kCapacityBytes == sizeof(Vector128), "Capacity mismatch");
+ static_assert(RandenTraits::kCapacityBytes == sizeof(Vector128),
+ "Capacity mismatch");
- uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state =
- reinterpret_cast<uint64_t*>(state_void);
+ auto* state = reinterpret_cast<u64x2*>(state_void);
+ const auto* keys = reinterpret_cast<const u64x2*>(keys_void);
const Vector128 prev_inner = Vector128Load(state);
SwapEndian(state);
- Permute(keys, state);
+ Permute(state, keys);
SwapEndian(state);
@@ -645,6 +567,7 @@
#endif
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // (ABSL_RANDEN_HWAES_IMPL)
diff --git a/third_party/abseil/absl/random/internal/randen_hwaes.h b/third_party/abseil/absl/random/internal/randen_hwaes.h
index d8e6055..71a7f69 100644
--- a/third_party/abseil/absl/random/internal/randen_hwaes.h
+++ b/third_party/abseil/absl/random/internal/randen_hwaes.h
@@ -15,15 +15,18 @@
#ifndef ABSL_RANDOM_INTERNAL_RANDEN_HWAES_H_
#define ABSL_RANDOM_INTERNAL_RANDEN_HWAES_H_
+#include "absl/base/config.h"
+
// HERMETIC NOTE: The randen_hwaes target must not introduce duplicate
// symbols from arbitrary system and other headers, since it may be built
// with different flags from other targets, using different levels of
// optimization, potentially introducing ODR violations.
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
-// RANDen = RANDom generator or beetroots in Swiss German.
+// RANDen = RANDom generator or beetroots in Swiss High German.
// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
//
@@ -41,6 +44,7 @@
bool HasRandenHwAesImplementation();
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_RANDEN_HWAES_H_
diff --git a/third_party/abseil/absl/random/internal/randen_hwaes_test.cc b/third_party/abseil/absl/random/internal/randen_hwaes_test.cc
index a7cbd46..66ddb43 100644
--- a/third_party/abseil/absl/random/internal/randen_hwaes_test.cc
+++ b/third_party/abseil/absl/random/internal/randen_hwaes_test.cc
@@ -27,12 +27,14 @@
using absl::random_internal::RandenHwAes;
using absl::random_internal::RandenTraits;
-struct randen {
- static constexpr size_t kStateSizeT =
- RandenTraits::kStateBytes / sizeof(uint64_t);
+// Local state parameters.
+constexpr size_t kSeedBytes =
+ RandenTraits::kStateBytes - RandenTraits::kCapacityBytes;
+constexpr size_t kStateSizeT = RandenTraits::kStateBytes / sizeof(uint64_t);
+constexpr size_t kSeedSizeT = kSeedBytes / sizeof(uint32_t);
+
+struct alignas(16) randen {
uint64_t state[kStateSizeT];
- static constexpr size_t kSeedSizeT =
- RandenTraits::kSeedBytes / sizeof(uint32_t);
uint32_t seed[kSeedSizeT];
};
diff --git a/third_party/abseil/absl/random/internal/randen_round_keys.cc b/third_party/abseil/absl/random/internal/randen_round_keys.cc
new file mode 100644
index 0000000..5fb3ca5
--- /dev/null
+++ b/third_party/abseil/absl/random/internal/randen_round_keys.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
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/random/internal/randen_traits.h"
+
+// This file contains only the round keys for randen.
+//
+// "Nothing up my sleeve" numbers from the first hex digits of Pi, obtained
+// from http://hexpi.sourceforge.net/. The array was generated by following
+// Python script:
+
+/*
+python >tmp.cc << EOF
+"""Generates Randen round keys array from pi-hex.62500.txt file."""
+import binascii
+
+KEYS = 17 * 8
+
+def chunks(l, n):
+ """Yield successive n-sized chunks from l."""
+ for i in range(0, len(l), n):
+ yield l[i:i + n]
+
+def pairwise(t):
+ """Transforms sequence into sequence of pairs."""
+ it = iter(t)
+ return zip(it,it)
+
+def digits_from_pi():
+ """Reads digits from hexpi.sourceforge.net file."""
+ with open("pi-hex.62500.txt") as file:
+ return file.read()
+
+def digits_from_urandom():
+ """Reads digits from /dev/urandom."""
+ with open("/dev/urandom") as file:
+ return binascii.hexlify(file.read(KEYS * 16))
+
+def print_row(b)
+ print(" 0x{0}, 0x{1}, 0x{2}, 0x{3}, 0x{4}, 0x{5}, 0x{6}, 0x{7}, 0x{8}, 0x{9},
+0x{10}, 0x{11}, 0x{12}, 0x{13}, 0x{14}, 0x{15},".format(*b))
+
+
+digits = digits_from_pi()
+#digits = digits_from_urandom()
+
+print("namespace {")
+print("static constexpr size_t kKeyBytes = {0};\n".format(KEYS * 16))
+print("}")
+
+print("alignas(16) const unsigned char kRandenRoundKeysBE[kKeyBytes] = {")
+
+for i, u16 in zip(range(KEYS), chunks(digits, 32)):
+ b = list(chunks(u16, 2))
+ print_row(b)
+
+print("};")
+
+print("alignas(16) const unsigned char kRandenRoundKeys[kKeyBytes] = {")
+
+for i, u16 in zip(range(KEYS), chunks(digits, 32)):
+ b = list(chunks(u16, 2))
+ b.reverse()
+ print_row(b)
+
+print("};")
+
+EOF
+
+*/
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace random_internal {
+namespace {
+static constexpr size_t kKeyBytes = 2176;
+}
+
+alignas(16) const unsigned char kRandenRoundKeysBE[kKeyBytes] = {
+ 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, 0x13, 0x19, 0x8A, 0x2E,
+ 0x03, 0x70, 0x73, 0x44, 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
+ 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89, 0x45, 0x28, 0x21, 0xE6,
+ 0x38, 0xD0, 0x13, 0x77, 0xBE, 0x54, 0x66, 0xCF, 0x34, 0xE9, 0x0C, 0x6C,
+ 0xC0, 0xAC, 0x29, 0xB7, 0xC9, 0x7C, 0x50, 0xDD, 0x3F, 0x84, 0xD5, 0xB5,
+ 0xB5, 0x47, 0x09, 0x17, 0x92, 0x16, 0xD5, 0xD9, 0x89, 0x79, 0xFB, 0x1B,
+ 0xD1, 0x31, 0x0B, 0xA6, 0x98, 0xDF, 0xB5, 0xAC, 0x2F, 0xFD, 0x72, 0xDB,
+ 0xD0, 0x1A, 0xDF, 0xB7, 0xB8, 0xE1, 0xAF, 0xED, 0x6A, 0x26, 0x7E, 0x96,
+ 0xBA, 0x7C, 0x90, 0x45, 0xF1, 0x2C, 0x7F, 0x99, 0x24, 0xA1, 0x99, 0x47,
+ 0xB3, 0x91, 0x6C, 0xF7, 0x08, 0x01, 0xF2, 0xE2, 0x85, 0x8E, 0xFC, 0x16,
+ 0x63, 0x69, 0x20, 0xD8, 0x71, 0x57, 0x4E, 0x69, 0xA4, 0x58, 0xFE, 0xA3,
+ 0xF4, 0x93, 0x3D, 0x7E, 0x0D, 0x95, 0x74, 0x8F, 0x72, 0x8E, 0xB6, 0x58,
+ 0x71, 0x8B, 0xCD, 0x58, 0x82, 0x15, 0x4A, 0xEE, 0x7B, 0x54, 0xA4, 0x1D,
+ 0xC2, 0x5A, 0x59, 0xB5, 0x9C, 0x30, 0xD5, 0x39, 0x2A, 0xF2, 0x60, 0x13,
+ 0xC5, 0xD1, 0xB0, 0x23, 0x28, 0x60, 0x85, 0xF0, 0xCA, 0x41, 0x79, 0x18,
+ 0xB8, 0xDB, 0x38, 0xEF, 0x8E, 0x79, 0xDC, 0xB0, 0x60, 0x3A, 0x18, 0x0E,
+ 0x6C, 0x9E, 0x0E, 0x8B, 0xB0, 0x1E, 0x8A, 0x3E, 0xD7, 0x15, 0x77, 0xC1,
+ 0xBD, 0x31, 0x4B, 0x27, 0x78, 0xAF, 0x2F, 0xDA, 0x55, 0x60, 0x5C, 0x60,
+ 0xE6, 0x55, 0x25, 0xF3, 0xAA, 0x55, 0xAB, 0x94, 0x57, 0x48, 0x98, 0x62,
+ 0x63, 0xE8, 0x14, 0x40, 0x55, 0xCA, 0x39, 0x6A, 0x2A, 0xAB, 0x10, 0xB6,
+ 0xB4, 0xCC, 0x5C, 0x34, 0x11, 0x41, 0xE8, 0xCE, 0xA1, 0x54, 0x86, 0xAF,
+ 0x7C, 0x72, 0xE9, 0x93, 0xB3, 0xEE, 0x14, 0x11, 0x63, 0x6F, 0xBC, 0x2A,
+ 0x2B, 0xA9, 0xC5, 0x5D, 0x74, 0x18, 0x31, 0xF6, 0xCE, 0x5C, 0x3E, 0x16,
+ 0x9B, 0x87, 0x93, 0x1E, 0xAF, 0xD6, 0xBA, 0x33, 0x6C, 0x24, 0xCF, 0x5C,
+ 0x7A, 0x32, 0x53, 0x81, 0x28, 0x95, 0x86, 0x77, 0x3B, 0x8F, 0x48, 0x98,
+ 0x6B, 0x4B, 0xB9, 0xAF, 0xC4, 0xBF, 0xE8, 0x1B, 0x66, 0x28, 0x21, 0x93,
+ 0x61, 0xD8, 0x09, 0xCC, 0xFB, 0x21, 0xA9, 0x91, 0x48, 0x7C, 0xAC, 0x60,
+ 0x5D, 0xEC, 0x80, 0x32, 0xEF, 0x84, 0x5D, 0x5D, 0xE9, 0x85, 0x75, 0xB1,
+ 0xDC, 0x26, 0x23, 0x02, 0xEB, 0x65, 0x1B, 0x88, 0x23, 0x89, 0x3E, 0x81,
+ 0xD3, 0x96, 0xAC, 0xC5, 0x0F, 0x6D, 0x6F, 0xF3, 0x83, 0xF4, 0x42, 0x39,
+ 0x2E, 0x0B, 0x44, 0x82, 0xA4, 0x84, 0x20, 0x04, 0x69, 0xC8, 0xF0, 0x4A,
+ 0x9E, 0x1F, 0x9B, 0x5E, 0x21, 0xC6, 0x68, 0x42, 0xF6, 0xE9, 0x6C, 0x9A,
+ 0x67, 0x0C, 0x9C, 0x61, 0xAB, 0xD3, 0x88, 0xF0, 0x6A, 0x51, 0xA0, 0xD2,
+ 0xD8, 0x54, 0x2F, 0x68, 0x96, 0x0F, 0xA7, 0x28, 0xAB, 0x51, 0x33, 0xA3,
+ 0x6E, 0xEF, 0x0B, 0x6C, 0x13, 0x7A, 0x3B, 0xE4, 0xBA, 0x3B, 0xF0, 0x50,
+ 0x7E, 0xFB, 0x2A, 0x98, 0xA1, 0xF1, 0x65, 0x1D, 0x39, 0xAF, 0x01, 0x76,
+ 0x66, 0xCA, 0x59, 0x3E, 0x82, 0x43, 0x0E, 0x88, 0x8C, 0xEE, 0x86, 0x19,
+ 0x45, 0x6F, 0x9F, 0xB4, 0x7D, 0x84, 0xA5, 0xC3, 0x3B, 0x8B, 0x5E, 0xBE,
+ 0xE0, 0x6F, 0x75, 0xD8, 0x85, 0xC1, 0x20, 0x73, 0x40, 0x1A, 0x44, 0x9F,
+ 0x56, 0xC1, 0x6A, 0xA6, 0x4E, 0xD3, 0xAA, 0x62, 0x36, 0x3F, 0x77, 0x06,
+ 0x1B, 0xFE, 0xDF, 0x72, 0x42, 0x9B, 0x02, 0x3D, 0x37, 0xD0, 0xD7, 0x24,
+ 0xD0, 0x0A, 0x12, 0x48, 0xDB, 0x0F, 0xEA, 0xD3, 0x49, 0xF1, 0xC0, 0x9B,
+ 0x07, 0x53, 0x72, 0xC9, 0x80, 0x99, 0x1B, 0x7B, 0x25, 0xD4, 0x79, 0xD8,
+ 0xF6, 0xE8, 0xDE, 0xF7, 0xE3, 0xFE, 0x50, 0x1A, 0xB6, 0x79, 0x4C, 0x3B,
+ 0x97, 0x6C, 0xE0, 0xBD, 0x04, 0xC0, 0x06, 0xBA, 0xC1, 0xA9, 0x4F, 0xB6,
+ 0x40, 0x9F, 0x60, 0xC4, 0x5E, 0x5C, 0x9E, 0xC2, 0x19, 0x6A, 0x24, 0x63,
+ 0x68, 0xFB, 0x6F, 0xAF, 0x3E, 0x6C, 0x53, 0xB5, 0x13, 0x39, 0xB2, 0xEB,
+ 0x3B, 0x52, 0xEC, 0x6F, 0x6D, 0xFC, 0x51, 0x1F, 0x9B, 0x30, 0x95, 0x2C,
+ 0xCC, 0x81, 0x45, 0x44, 0xAF, 0x5E, 0xBD, 0x09, 0xBE, 0xE3, 0xD0, 0x04,
+ 0xDE, 0x33, 0x4A, 0xFD, 0x66, 0x0F, 0x28, 0x07, 0x19, 0x2E, 0x4B, 0xB3,
+ 0xC0, 0xCB, 0xA8, 0x57, 0x45, 0xC8, 0x74, 0x0F, 0xD2, 0x0B, 0x5F, 0x39,
+ 0xB9, 0xD3, 0xFB, 0xDB, 0x55, 0x79, 0xC0, 0xBD, 0x1A, 0x60, 0x32, 0x0A,
+ 0xD6, 0xA1, 0x00, 0xC6, 0x40, 0x2C, 0x72, 0x79, 0x67, 0x9F, 0x25, 0xFE,
+ 0xFB, 0x1F, 0xA3, 0xCC, 0x8E, 0xA5, 0xE9, 0xF8, 0xDB, 0x32, 0x22, 0xF8,
+ 0x3C, 0x75, 0x16, 0xDF, 0xFD, 0x61, 0x6B, 0x15, 0x2F, 0x50, 0x1E, 0xC8,
+ 0xAD, 0x05, 0x52, 0xAB, 0x32, 0x3D, 0xB5, 0xFA, 0xFD, 0x23, 0x87, 0x60,
+ 0x53, 0x31, 0x7B, 0x48, 0x3E, 0x00, 0xDF, 0x82, 0x9E, 0x5C, 0x57, 0xBB,
+ 0xCA, 0x6F, 0x8C, 0xA0, 0x1A, 0x87, 0x56, 0x2E, 0xDF, 0x17, 0x69, 0xDB,
+ 0xD5, 0x42, 0xA8, 0xF6, 0x28, 0x7E, 0xFF, 0xC3, 0xAC, 0x67, 0x32, 0xC6,
+ 0x8C, 0x4F, 0x55, 0x73, 0x69, 0x5B, 0x27, 0xB0, 0xBB, 0xCA, 0x58, 0xC8,
+ 0xE1, 0xFF, 0xA3, 0x5D, 0xB8, 0xF0, 0x11, 0xA0, 0x10, 0xFA, 0x3D, 0x98,
+ 0xFD, 0x21, 0x83, 0xB8, 0x4A, 0xFC, 0xB5, 0x6C, 0x2D, 0xD1, 0xD3, 0x5B,
+ 0x9A, 0x53, 0xE4, 0x79, 0xB6, 0xF8, 0x45, 0x65, 0xD2, 0x8E, 0x49, 0xBC,
+ 0x4B, 0xFB, 0x97, 0x90, 0xE1, 0xDD, 0xF2, 0xDA, 0xA4, 0xCB, 0x7E, 0x33,
+ 0x62, 0xFB, 0x13, 0x41, 0xCE, 0xE4, 0xC6, 0xE8, 0xEF, 0x20, 0xCA, 0xDA,
+ 0x36, 0x77, 0x4C, 0x01, 0xD0, 0x7E, 0x9E, 0xFE, 0x2B, 0xF1, 0x1F, 0xB4,
+ 0x95, 0xDB, 0xDA, 0x4D, 0xAE, 0x90, 0x91, 0x98, 0xEA, 0xAD, 0x8E, 0x71,
+ 0x6B, 0x93, 0xD5, 0xA0, 0xD0, 0x8E, 0xD1, 0xD0, 0xAF, 0xC7, 0x25, 0xE0,
+ 0x8E, 0x3C, 0x5B, 0x2F, 0x8E, 0x75, 0x94, 0xB7, 0x8F, 0xF6, 0xE2, 0xFB,
+ 0xF2, 0x12, 0x2B, 0x64, 0x88, 0x88, 0xB8, 0x12, 0x90, 0x0D, 0xF0, 0x1C,
+ 0x4F, 0xAD, 0x5E, 0xA0, 0x68, 0x8F, 0xC3, 0x1C, 0xD1, 0xCF, 0xF1, 0x91,
+ 0xB3, 0xA8, 0xC1, 0xAD, 0x2F, 0x2F, 0x22, 0x18, 0xBE, 0x0E, 0x17, 0x77,
+ 0xEA, 0x75, 0x2D, 0xFE, 0x8B, 0x02, 0x1F, 0xA1, 0xE5, 0xA0, 0xCC, 0x0F,
+ 0xB5, 0x6F, 0x74, 0xE8, 0x18, 0xAC, 0xF3, 0xD6, 0xCE, 0x89, 0xE2, 0x99,
+ 0xB4, 0xA8, 0x4F, 0xE0, 0xFD, 0x13, 0xE0, 0xB7, 0x7C, 0xC4, 0x3B, 0x81,
+ 0xD2, 0xAD, 0xA8, 0xD9, 0x16, 0x5F, 0xA2, 0x66, 0x80, 0x95, 0x77, 0x05,
+ 0x93, 0xCC, 0x73, 0x14, 0x21, 0x1A, 0x14, 0x77, 0xE6, 0xAD, 0x20, 0x65,
+ 0x77, 0xB5, 0xFA, 0x86, 0xC7, 0x54, 0x42, 0xF5, 0xFB, 0x9D, 0x35, 0xCF,
+ 0xEB, 0xCD, 0xAF, 0x0C, 0x7B, 0x3E, 0x89, 0xA0, 0xD6, 0x41, 0x1B, 0xD3,
+ 0xAE, 0x1E, 0x7E, 0x49, 0x00, 0x25, 0x0E, 0x2D, 0x20, 0x71, 0xB3, 0x5E,
+ 0x22, 0x68, 0x00, 0xBB, 0x57, 0xB8, 0xE0, 0xAF, 0x24, 0x64, 0x36, 0x9B,
+ 0xF0, 0x09, 0xB9, 0x1E, 0x55, 0x63, 0x91, 0x1D, 0x59, 0xDF, 0xA6, 0xAA,
+ 0x78, 0xC1, 0x43, 0x89, 0xD9, 0x5A, 0x53, 0x7F, 0x20, 0x7D, 0x5B, 0xA2,
+ 0x02, 0xE5, 0xB9, 0xC5, 0x83, 0x26, 0x03, 0x76, 0x62, 0x95, 0xCF, 0xA9,
+ 0x11, 0xC8, 0x19, 0x68, 0x4E, 0x73, 0x4A, 0x41, 0xB3, 0x47, 0x2D, 0xCA,
+ 0x7B, 0x14, 0xA9, 0x4A, 0x1B, 0x51, 0x00, 0x52, 0x9A, 0x53, 0x29, 0x15,
+ 0xD6, 0x0F, 0x57, 0x3F, 0xBC, 0x9B, 0xC6, 0xE4, 0x2B, 0x60, 0xA4, 0x76,
+ 0x81, 0xE6, 0x74, 0x00, 0x08, 0xBA, 0x6F, 0xB5, 0x57, 0x1B, 0xE9, 0x1F,
+ 0xF2, 0x96, 0xEC, 0x6B, 0x2A, 0x0D, 0xD9, 0x15, 0xB6, 0x63, 0x65, 0x21,
+ 0xE7, 0xB9, 0xF9, 0xB6, 0xFF, 0x34, 0x05, 0x2E, 0xC5, 0x85, 0x56, 0x64,
+ 0x53, 0xB0, 0x2D, 0x5D, 0xA9, 0x9F, 0x8F, 0xA1, 0x08, 0xBA, 0x47, 0x99,
+ 0x6E, 0x85, 0x07, 0x6A, 0x4B, 0x7A, 0x70, 0xE9, 0xB5, 0xB3, 0x29, 0x44,
+ 0xDB, 0x75, 0x09, 0x2E, 0xC4, 0x19, 0x26, 0x23, 0xAD, 0x6E, 0xA6, 0xB0,
+ 0x49, 0xA7, 0xDF, 0x7D, 0x9C, 0xEE, 0x60, 0xB8, 0x8F, 0xED, 0xB2, 0x66,
+ 0xEC, 0xAA, 0x8C, 0x71, 0x69, 0x9A, 0x18, 0xFF, 0x56, 0x64, 0x52, 0x6C,
+ 0xC2, 0xB1, 0x9E, 0xE1, 0x19, 0x36, 0x02, 0xA5, 0x75, 0x09, 0x4C, 0x29,
+ 0xA0, 0x59, 0x13, 0x40, 0xE4, 0x18, 0x3A, 0x3E, 0x3F, 0x54, 0x98, 0x9A,
+ 0x5B, 0x42, 0x9D, 0x65, 0x6B, 0x8F, 0xE4, 0xD6, 0x99, 0xF7, 0x3F, 0xD6,
+ 0xA1, 0xD2, 0x9C, 0x07, 0xEF, 0xE8, 0x30, 0xF5, 0x4D, 0x2D, 0x38, 0xE6,
+ 0xF0, 0x25, 0x5D, 0xC1, 0x4C, 0xDD, 0x20, 0x86, 0x84, 0x70, 0xEB, 0x26,
+ 0x63, 0x82, 0xE9, 0xC6, 0x02, 0x1E, 0xCC, 0x5E, 0x09, 0x68, 0x6B, 0x3F,
+ 0x3E, 0xBA, 0xEF, 0xC9, 0x3C, 0x97, 0x18, 0x14, 0x6B, 0x6A, 0x70, 0xA1,
+ 0x68, 0x7F, 0x35, 0x84, 0x52, 0xA0, 0xE2, 0x86, 0xB7, 0x9C, 0x53, 0x05,
+ 0xAA, 0x50, 0x07, 0x37, 0x3E, 0x07, 0x84, 0x1C, 0x7F, 0xDE, 0xAE, 0x5C,
+ 0x8E, 0x7D, 0x44, 0xEC, 0x57, 0x16, 0xF2, 0xB8, 0xB0, 0x3A, 0xDA, 0x37,
+ 0xF0, 0x50, 0x0C, 0x0D, 0xF0, 0x1C, 0x1F, 0x04, 0x02, 0x00, 0xB3, 0xFF,
+ 0xAE, 0x0C, 0xF5, 0x1A, 0x3C, 0xB5, 0x74, 0xB2, 0x25, 0x83, 0x7A, 0x58,
+ 0xDC, 0x09, 0x21, 0xBD, 0xD1, 0x91, 0x13, 0xF9, 0x7C, 0xA9, 0x2F, 0xF6,
+ 0x94, 0x32, 0x47, 0x73, 0x22, 0xF5, 0x47, 0x01, 0x3A, 0xE5, 0xE5, 0x81,
+ 0x37, 0xC2, 0xDA, 0xDC, 0xC8, 0xB5, 0x76, 0x34, 0x9A, 0xF3, 0xDD, 0xA7,
+ 0xA9, 0x44, 0x61, 0x46, 0x0F, 0xD0, 0x03, 0x0E, 0xEC, 0xC8, 0xC7, 0x3E,
+ 0xA4, 0x75, 0x1E, 0x41, 0xE2, 0x38, 0xCD, 0x99, 0x3B, 0xEA, 0x0E, 0x2F,
+ 0x32, 0x80, 0xBB, 0xA1, 0x18, 0x3E, 0xB3, 0x31, 0x4E, 0x54, 0x8B, 0x38,
+ 0x4F, 0x6D, 0xB9, 0x08, 0x6F, 0x42, 0x0D, 0x03, 0xF6, 0x0A, 0x04, 0xBF,
+ 0x2C, 0xB8, 0x12, 0x90, 0x24, 0x97, 0x7C, 0x79, 0x56, 0x79, 0xB0, 0x72,
+ 0xBC, 0xAF, 0x89, 0xAF, 0xDE, 0x9A, 0x77, 0x1F, 0xD9, 0x93, 0x08, 0x10,
+ 0xB3, 0x8B, 0xAE, 0x12, 0xDC, 0xCF, 0x3F, 0x2E, 0x55, 0x12, 0x72, 0x1F,
+ 0x2E, 0x6B, 0x71, 0x24, 0x50, 0x1A, 0xDD, 0xE6, 0x9F, 0x84, 0xCD, 0x87,
+ 0x7A, 0x58, 0x47, 0x18, 0x74, 0x08, 0xDA, 0x17, 0xBC, 0x9F, 0x9A, 0xBC,
+ 0xE9, 0x4B, 0x7D, 0x8C, 0xEC, 0x7A, 0xEC, 0x3A, 0xDB, 0x85, 0x1D, 0xFA,
+ 0x63, 0x09, 0x43, 0x66, 0xC4, 0x64, 0xC3, 0xD2, 0xEF, 0x1C, 0x18, 0x47,
+ 0x32, 0x15, 0xD8, 0x08, 0xDD, 0x43, 0x3B, 0x37, 0x24, 0xC2, 0xBA, 0x16,
+ 0x12, 0xA1, 0x4D, 0x43, 0x2A, 0x65, 0xC4, 0x51, 0x50, 0x94, 0x00, 0x02,
+ 0x13, 0x3A, 0xE4, 0xDD, 0x71, 0xDF, 0xF8, 0x9E, 0x10, 0x31, 0x4E, 0x55,
+ 0x81, 0xAC, 0x77, 0xD6, 0x5F, 0x11, 0x19, 0x9B, 0x04, 0x35, 0x56, 0xF1,
+ 0xD7, 0xA3, 0xC7, 0x6B, 0x3C, 0x11, 0x18, 0x3B, 0x59, 0x24, 0xA5, 0x09,
+ 0xF2, 0x8F, 0xE6, 0xED, 0x97, 0xF1, 0xFB, 0xFA, 0x9E, 0xBA, 0xBF, 0x2C,
+ 0x1E, 0x15, 0x3C, 0x6E, 0x86, 0xE3, 0x45, 0x70, 0xEA, 0xE9, 0x6F, 0xB1,
+ 0x86, 0x0E, 0x5E, 0x0A, 0x5A, 0x3E, 0x2A, 0xB3, 0x77, 0x1F, 0xE7, 0x1C,
+ 0x4E, 0x3D, 0x06, 0xFA, 0x29, 0x65, 0xDC, 0xB9, 0x99, 0xE7, 0x1D, 0x0F,
+ 0x80, 0x3E, 0x89, 0xD6, 0x52, 0x66, 0xC8, 0x25, 0x2E, 0x4C, 0xC9, 0x78,
+ 0x9C, 0x10, 0xB3, 0x6A, 0xC6, 0x15, 0x0E, 0xBA, 0x94, 0xE2, 0xEA, 0x78,
+ 0xA6, 0xFC, 0x3C, 0x53, 0x1E, 0x0A, 0x2D, 0xF4, 0xF2, 0xF7, 0x4E, 0xA7,
+ 0x36, 0x1D, 0x2B, 0x3D, 0x19, 0x39, 0x26, 0x0F, 0x19, 0xC2, 0x79, 0x60,
+ 0x52, 0x23, 0xA7, 0x08, 0xF7, 0x13, 0x12, 0xB6, 0xEB, 0xAD, 0xFE, 0x6E,
+ 0xEA, 0xC3, 0x1F, 0x66, 0xE3, 0xBC, 0x45, 0x95, 0xA6, 0x7B, 0xC8, 0x83,
+ 0xB1, 0x7F, 0x37, 0xD1, 0x01, 0x8C, 0xFF, 0x28, 0xC3, 0x32, 0xDD, 0xEF,
+ 0xBE, 0x6C, 0x5A, 0xA5, 0x65, 0x58, 0x21, 0x85, 0x68, 0xAB, 0x97, 0x02,
+ 0xEE, 0xCE, 0xA5, 0x0F, 0xDB, 0x2F, 0x95, 0x3B, 0x2A, 0xEF, 0x7D, 0xAD,
+ 0x5B, 0x6E, 0x2F, 0x84, 0x15, 0x21, 0xB6, 0x28, 0x29, 0x07, 0x61, 0x70,
+ 0xEC, 0xDD, 0x47, 0x75, 0x61, 0x9F, 0x15, 0x10, 0x13, 0xCC, 0xA8, 0x30,
+ 0xEB, 0x61, 0xBD, 0x96, 0x03, 0x34, 0xFE, 0x1E, 0xAA, 0x03, 0x63, 0xCF,
+ 0xB5, 0x73, 0x5C, 0x90, 0x4C, 0x70, 0xA2, 0x39, 0xD5, 0x9E, 0x9E, 0x0B,
+ 0xCB, 0xAA, 0xDE, 0x14, 0xEE, 0xCC, 0x86, 0xBC, 0x60, 0x62, 0x2C, 0xA7,
+ 0x9C, 0xAB, 0x5C, 0xAB, 0xB2, 0xF3, 0x84, 0x6E, 0x64, 0x8B, 0x1E, 0xAF,
+ 0x19, 0xBD, 0xF0, 0xCA, 0xA0, 0x23, 0x69, 0xB9, 0x65, 0x5A, 0xBB, 0x50,
+ 0x40, 0x68, 0x5A, 0x32, 0x3C, 0x2A, 0xB4, 0xB3, 0x31, 0x9E, 0xE9, 0xD5,
+ 0xC0, 0x21, 0xB8, 0xF7, 0x9B, 0x54, 0x0B, 0x19, 0x87, 0x5F, 0xA0, 0x99,
+ 0x95, 0xF7, 0x99, 0x7E, 0x62, 0x3D, 0x7D, 0xA8, 0xF8, 0x37, 0x88, 0x9A,
+ 0x97, 0xE3, 0x2D, 0x77, 0x11, 0xED, 0x93, 0x5F, 0x16, 0x68, 0x12, 0x81,
+ 0x0E, 0x35, 0x88, 0x29, 0xC7, 0xE6, 0x1F, 0xD6, 0x96, 0xDE, 0xDF, 0xA1,
+ 0x78, 0x58, 0xBA, 0x99, 0x57, 0xF5, 0x84, 0xA5, 0x1B, 0x22, 0x72, 0x63,
+ 0x9B, 0x83, 0xC3, 0xFF, 0x1A, 0xC2, 0x46, 0x96, 0xCD, 0xB3, 0x0A, 0xEB,
+ 0x53, 0x2E, 0x30, 0x54, 0x8F, 0xD9, 0x48, 0xE4, 0x6D, 0xBC, 0x31, 0x28,
+ 0x58, 0xEB, 0xF2, 0xEF, 0x34, 0xC6, 0xFF, 0xEA, 0xFE, 0x28, 0xED, 0x61,
+ 0xEE, 0x7C, 0x3C, 0x73, 0x5D, 0x4A, 0x14, 0xD9, 0xE8, 0x64, 0xB7, 0xE3,
+ 0x42, 0x10, 0x5D, 0x14, 0x20, 0x3E, 0x13, 0xE0, 0x45, 0xEE, 0xE2, 0xB6,
+ 0xA3, 0xAA, 0xAB, 0xEA, 0xDB, 0x6C, 0x4F, 0x15, 0xFA, 0xCB, 0x4F, 0xD0,
+ 0xC7, 0x42, 0xF4, 0x42, 0xEF, 0x6A, 0xBB, 0xB5, 0x65, 0x4F, 0x3B, 0x1D,
+ 0x41, 0xCD, 0x21, 0x05, 0xD8, 0x1E, 0x79, 0x9E, 0x86, 0x85, 0x4D, 0xC7,
+ 0xE4, 0x4B, 0x47, 0x6A, 0x3D, 0x81, 0x62, 0x50, 0xCF, 0x62, 0xA1, 0xF2,
+ 0x5B, 0x8D, 0x26, 0x46, 0xFC, 0x88, 0x83, 0xA0, 0xC1, 0xC7, 0xB6, 0xA3,
+ 0x7F, 0x15, 0x24, 0xC3, 0x69, 0xCB, 0x74, 0x92, 0x47, 0x84, 0x8A, 0x0B,
+ 0x56, 0x92, 0xB2, 0x85, 0x09, 0x5B, 0xBF, 0x00, 0xAD, 0x19, 0x48, 0x9D,
+ 0x14, 0x62, 0xB1, 0x74, 0x23, 0x82, 0x0D, 0x00, 0x58, 0x42, 0x8D, 0x2A,
+ 0x0C, 0x55, 0xF5, 0xEA, 0x1D, 0xAD, 0xF4, 0x3E, 0x23, 0x3F, 0x70, 0x61,
+ 0x33, 0x72, 0xF0, 0x92, 0x8D, 0x93, 0x7E, 0x41, 0xD6, 0x5F, 0xEC, 0xF1,
+ 0x6C, 0x22, 0x3B, 0xDB, 0x7C, 0xDE, 0x37, 0x59, 0xCB, 0xEE, 0x74, 0x60,
+ 0x40, 0x85, 0xF2, 0xA7, 0xCE, 0x77, 0x32, 0x6E, 0xA6, 0x07, 0x80, 0x84,
+ 0x19, 0xF8, 0x50, 0x9E, 0xE8, 0xEF, 0xD8, 0x55, 0x61, 0xD9, 0x97, 0x35,
+ 0xA9, 0x69, 0xA7, 0xAA, 0xC5, 0x0C, 0x06, 0xC2, 0x5A, 0x04, 0xAB, 0xFC,
+ 0x80, 0x0B, 0xCA, 0xDC, 0x9E, 0x44, 0x7A, 0x2E, 0xC3, 0x45, 0x34, 0x84,
+ 0xFD, 0xD5, 0x67, 0x05, 0x0E, 0x1E, 0x9E, 0xC9, 0xDB, 0x73, 0xDB, 0xD3,
+ 0x10, 0x55, 0x88, 0xCD, 0x67, 0x5F, 0xDA, 0x79, 0xE3, 0x67, 0x43, 0x40,
+ 0xC5, 0xC4, 0x34, 0x65, 0x71, 0x3E, 0x38, 0xD8, 0x3D, 0x28, 0xF8, 0x9E,
+ 0xF1, 0x6D, 0xFF, 0x20, 0x15, 0x3E, 0x21, 0xE7, 0x8F, 0xB0, 0x3D, 0x4A,
+ 0xE6, 0xE3, 0x9F, 0x2B, 0xDB, 0x83, 0xAD, 0xF7, 0xE9, 0x3D, 0x5A, 0x68,
+ 0x94, 0x81, 0x40, 0xF7, 0xF6, 0x4C, 0x26, 0x1C, 0x94, 0x69, 0x29, 0x34,
+ 0x41, 0x15, 0x20, 0xF7, 0x76, 0x02, 0xD4, 0xF7, 0xBC, 0xF4, 0x6B, 0x2E,
+ 0xD4, 0xA1, 0x00, 0x68, 0xD4, 0x08, 0x24, 0x71, 0x33, 0x20, 0xF4, 0x6A,
+ 0x43, 0xB7, 0xD4, 0xB7, 0x50, 0x00, 0x61, 0xAF, 0x1E, 0x39, 0xF6, 0x2E,
+ 0x97, 0x24, 0x45, 0x46,
+};
+
+alignas(16) const unsigned char kRandenRoundKeys[kKeyBytes] = {
+ 0x44, 0x73, 0x70, 0x03, 0x2E, 0x8A, 0x19, 0x13, 0xD3, 0x08, 0xA3, 0x85,
+ 0x88, 0x6A, 0x3F, 0x24, 0x89, 0x6C, 0x4E, 0xEC, 0x98, 0xFA, 0x2E, 0x08,
+ 0xD0, 0x31, 0x9F, 0x29, 0x22, 0x38, 0x09, 0xA4, 0x6C, 0x0C, 0xE9, 0x34,
+ 0xCF, 0x66, 0x54, 0xBE, 0x77, 0x13, 0xD0, 0x38, 0xE6, 0x21, 0x28, 0x45,
+ 0x17, 0x09, 0x47, 0xB5, 0xB5, 0xD5, 0x84, 0x3F, 0xDD, 0x50, 0x7C, 0xC9,
+ 0xB7, 0x29, 0xAC, 0xC0, 0xAC, 0xB5, 0xDF, 0x98, 0xA6, 0x0B, 0x31, 0xD1,
+ 0x1B, 0xFB, 0x79, 0x89, 0xD9, 0xD5, 0x16, 0x92, 0x96, 0x7E, 0x26, 0x6A,
+ 0xED, 0xAF, 0xE1, 0xB8, 0xB7, 0xDF, 0x1A, 0xD0, 0xDB, 0x72, 0xFD, 0x2F,
+ 0xF7, 0x6C, 0x91, 0xB3, 0x47, 0x99, 0xA1, 0x24, 0x99, 0x7F, 0x2C, 0xF1,
+ 0x45, 0x90, 0x7C, 0xBA, 0x69, 0x4E, 0x57, 0x71, 0xD8, 0x20, 0x69, 0x63,
+ 0x16, 0xFC, 0x8E, 0x85, 0xE2, 0xF2, 0x01, 0x08, 0x58, 0xB6, 0x8E, 0x72,
+ 0x8F, 0x74, 0x95, 0x0D, 0x7E, 0x3D, 0x93, 0xF4, 0xA3, 0xFE, 0x58, 0xA4,
+ 0xB5, 0x59, 0x5A, 0xC2, 0x1D, 0xA4, 0x54, 0x7B, 0xEE, 0x4A, 0x15, 0x82,
+ 0x58, 0xCD, 0x8B, 0x71, 0xF0, 0x85, 0x60, 0x28, 0x23, 0xB0, 0xD1, 0xC5,
+ 0x13, 0x60, 0xF2, 0x2A, 0x39, 0xD5, 0x30, 0x9C, 0x0E, 0x18, 0x3A, 0x60,
+ 0xB0, 0xDC, 0x79, 0x8E, 0xEF, 0x38, 0xDB, 0xB8, 0x18, 0x79, 0x41, 0xCA,
+ 0x27, 0x4B, 0x31, 0xBD, 0xC1, 0x77, 0x15, 0xD7, 0x3E, 0x8A, 0x1E, 0xB0,
+ 0x8B, 0x0E, 0x9E, 0x6C, 0x94, 0xAB, 0x55, 0xAA, 0xF3, 0x25, 0x55, 0xE6,
+ 0x60, 0x5C, 0x60, 0x55, 0xDA, 0x2F, 0xAF, 0x78, 0xB6, 0x10, 0xAB, 0x2A,
+ 0x6A, 0x39, 0xCA, 0x55, 0x40, 0x14, 0xE8, 0x63, 0x62, 0x98, 0x48, 0x57,
+ 0x93, 0xE9, 0x72, 0x7C, 0xAF, 0x86, 0x54, 0xA1, 0xCE, 0xE8, 0x41, 0x11,
+ 0x34, 0x5C, 0xCC, 0xB4, 0xF6, 0x31, 0x18, 0x74, 0x5D, 0xC5, 0xA9, 0x2B,
+ 0x2A, 0xBC, 0x6F, 0x63, 0x11, 0x14, 0xEE, 0xB3, 0x5C, 0xCF, 0x24, 0x6C,
+ 0x33, 0xBA, 0xD6, 0xAF, 0x1E, 0x93, 0x87, 0x9B, 0x16, 0x3E, 0x5C, 0xCE,
+ 0xAF, 0xB9, 0x4B, 0x6B, 0x98, 0x48, 0x8F, 0x3B, 0x77, 0x86, 0x95, 0x28,
+ 0x81, 0x53, 0x32, 0x7A, 0x91, 0xA9, 0x21, 0xFB, 0xCC, 0x09, 0xD8, 0x61,
+ 0x93, 0x21, 0x28, 0x66, 0x1B, 0xE8, 0xBF, 0xC4, 0xB1, 0x75, 0x85, 0xE9,
+ 0x5D, 0x5D, 0x84, 0xEF, 0x32, 0x80, 0xEC, 0x5D, 0x60, 0xAC, 0x7C, 0x48,
+ 0xC5, 0xAC, 0x96, 0xD3, 0x81, 0x3E, 0x89, 0x23, 0x88, 0x1B, 0x65, 0xEB,
+ 0x02, 0x23, 0x26, 0xDC, 0x04, 0x20, 0x84, 0xA4, 0x82, 0x44, 0x0B, 0x2E,
+ 0x39, 0x42, 0xF4, 0x83, 0xF3, 0x6F, 0x6D, 0x0F, 0x9A, 0x6C, 0xE9, 0xF6,
+ 0x42, 0x68, 0xC6, 0x21, 0x5E, 0x9B, 0x1F, 0x9E, 0x4A, 0xF0, 0xC8, 0x69,
+ 0x68, 0x2F, 0x54, 0xD8, 0xD2, 0xA0, 0x51, 0x6A, 0xF0, 0x88, 0xD3, 0xAB,
+ 0x61, 0x9C, 0x0C, 0x67, 0xE4, 0x3B, 0x7A, 0x13, 0x6C, 0x0B, 0xEF, 0x6E,
+ 0xA3, 0x33, 0x51, 0xAB, 0x28, 0xA7, 0x0F, 0x96, 0x76, 0x01, 0xAF, 0x39,
+ 0x1D, 0x65, 0xF1, 0xA1, 0x98, 0x2A, 0xFB, 0x7E, 0x50, 0xF0, 0x3B, 0xBA,
+ 0xB4, 0x9F, 0x6F, 0x45, 0x19, 0x86, 0xEE, 0x8C, 0x88, 0x0E, 0x43, 0x82,
+ 0x3E, 0x59, 0xCA, 0x66, 0x73, 0x20, 0xC1, 0x85, 0xD8, 0x75, 0x6F, 0xE0,
+ 0xBE, 0x5E, 0x8B, 0x3B, 0xC3, 0xA5, 0x84, 0x7D, 0x06, 0x77, 0x3F, 0x36,
+ 0x62, 0xAA, 0xD3, 0x4E, 0xA6, 0x6A, 0xC1, 0x56, 0x9F, 0x44, 0x1A, 0x40,
+ 0x48, 0x12, 0x0A, 0xD0, 0x24, 0xD7, 0xD0, 0x37, 0x3D, 0x02, 0x9B, 0x42,
+ 0x72, 0xDF, 0xFE, 0x1B, 0x7B, 0x1B, 0x99, 0x80, 0xC9, 0x72, 0x53, 0x07,
+ 0x9B, 0xC0, 0xF1, 0x49, 0xD3, 0xEA, 0x0F, 0xDB, 0x3B, 0x4C, 0x79, 0xB6,
+ 0x1A, 0x50, 0xFE, 0xE3, 0xF7, 0xDE, 0xE8, 0xF6, 0xD8, 0x79, 0xD4, 0x25,
+ 0xC4, 0x60, 0x9F, 0x40, 0xB6, 0x4F, 0xA9, 0xC1, 0xBA, 0x06, 0xC0, 0x04,
+ 0xBD, 0xE0, 0x6C, 0x97, 0xB5, 0x53, 0x6C, 0x3E, 0xAF, 0x6F, 0xFB, 0x68,
+ 0x63, 0x24, 0x6A, 0x19, 0xC2, 0x9E, 0x5C, 0x5E, 0x2C, 0x95, 0x30, 0x9B,
+ 0x1F, 0x51, 0xFC, 0x6D, 0x6F, 0xEC, 0x52, 0x3B, 0xEB, 0xB2, 0x39, 0x13,
+ 0xFD, 0x4A, 0x33, 0xDE, 0x04, 0xD0, 0xE3, 0xBE, 0x09, 0xBD, 0x5E, 0xAF,
+ 0x44, 0x45, 0x81, 0xCC, 0x0F, 0x74, 0xC8, 0x45, 0x57, 0xA8, 0xCB, 0xC0,
+ 0xB3, 0x4B, 0x2E, 0x19, 0x07, 0x28, 0x0F, 0x66, 0x0A, 0x32, 0x60, 0x1A,
+ 0xBD, 0xC0, 0x79, 0x55, 0xDB, 0xFB, 0xD3, 0xB9, 0x39, 0x5F, 0x0B, 0xD2,
+ 0xCC, 0xA3, 0x1F, 0xFB, 0xFE, 0x25, 0x9F, 0x67, 0x79, 0x72, 0x2C, 0x40,
+ 0xC6, 0x00, 0xA1, 0xD6, 0x15, 0x6B, 0x61, 0xFD, 0xDF, 0x16, 0x75, 0x3C,
+ 0xF8, 0x22, 0x32, 0xDB, 0xF8, 0xE9, 0xA5, 0x8E, 0x60, 0x87, 0x23, 0xFD,
+ 0xFA, 0xB5, 0x3D, 0x32, 0xAB, 0x52, 0x05, 0xAD, 0xC8, 0x1E, 0x50, 0x2F,
+ 0xA0, 0x8C, 0x6F, 0xCA, 0xBB, 0x57, 0x5C, 0x9E, 0x82, 0xDF, 0x00, 0x3E,
+ 0x48, 0x7B, 0x31, 0x53, 0xC3, 0xFF, 0x7E, 0x28, 0xF6, 0xA8, 0x42, 0xD5,
+ 0xDB, 0x69, 0x17, 0xDF, 0x2E, 0x56, 0x87, 0x1A, 0xC8, 0x58, 0xCA, 0xBB,
+ 0xB0, 0x27, 0x5B, 0x69, 0x73, 0x55, 0x4F, 0x8C, 0xC6, 0x32, 0x67, 0xAC,
+ 0xB8, 0x83, 0x21, 0xFD, 0x98, 0x3D, 0xFA, 0x10, 0xA0, 0x11, 0xF0, 0xB8,
+ 0x5D, 0xA3, 0xFF, 0xE1, 0x65, 0x45, 0xF8, 0xB6, 0x79, 0xE4, 0x53, 0x9A,
+ 0x5B, 0xD3, 0xD1, 0x2D, 0x6C, 0xB5, 0xFC, 0x4A, 0x33, 0x7E, 0xCB, 0xA4,
+ 0xDA, 0xF2, 0xDD, 0xE1, 0x90, 0x97, 0xFB, 0x4B, 0xBC, 0x49, 0x8E, 0xD2,
+ 0x01, 0x4C, 0x77, 0x36, 0xDA, 0xCA, 0x20, 0xEF, 0xE8, 0xC6, 0xE4, 0xCE,
+ 0x41, 0x13, 0xFB, 0x62, 0x98, 0x91, 0x90, 0xAE, 0x4D, 0xDA, 0xDB, 0x95,
+ 0xB4, 0x1F, 0xF1, 0x2B, 0xFE, 0x9E, 0x7E, 0xD0, 0xE0, 0x25, 0xC7, 0xAF,
+ 0xD0, 0xD1, 0x8E, 0xD0, 0xA0, 0xD5, 0x93, 0x6B, 0x71, 0x8E, 0xAD, 0xEA,
+ 0x64, 0x2B, 0x12, 0xF2, 0xFB, 0xE2, 0xF6, 0x8F, 0xB7, 0x94, 0x75, 0x8E,
+ 0x2F, 0x5B, 0x3C, 0x8E, 0x1C, 0xC3, 0x8F, 0x68, 0xA0, 0x5E, 0xAD, 0x4F,
+ 0x1C, 0xF0, 0x0D, 0x90, 0x12, 0xB8, 0x88, 0x88, 0x77, 0x17, 0x0E, 0xBE,
+ 0x18, 0x22, 0x2F, 0x2F, 0xAD, 0xC1, 0xA8, 0xB3, 0x91, 0xF1, 0xCF, 0xD1,
+ 0xE8, 0x74, 0x6F, 0xB5, 0x0F, 0xCC, 0xA0, 0xE5, 0xA1, 0x1F, 0x02, 0x8B,
+ 0xFE, 0x2D, 0x75, 0xEA, 0xB7, 0xE0, 0x13, 0xFD, 0xE0, 0x4F, 0xA8, 0xB4,
+ 0x99, 0xE2, 0x89, 0xCE, 0xD6, 0xF3, 0xAC, 0x18, 0x05, 0x77, 0x95, 0x80,
+ 0x66, 0xA2, 0x5F, 0x16, 0xD9, 0xA8, 0xAD, 0xD2, 0x81, 0x3B, 0xC4, 0x7C,
+ 0x86, 0xFA, 0xB5, 0x77, 0x65, 0x20, 0xAD, 0xE6, 0x77, 0x14, 0x1A, 0x21,
+ 0x14, 0x73, 0xCC, 0x93, 0xA0, 0x89, 0x3E, 0x7B, 0x0C, 0xAF, 0xCD, 0xEB,
+ 0xCF, 0x35, 0x9D, 0xFB, 0xF5, 0x42, 0x54, 0xC7, 0x5E, 0xB3, 0x71, 0x20,
+ 0x2D, 0x0E, 0x25, 0x00, 0x49, 0x7E, 0x1E, 0xAE, 0xD3, 0x1B, 0x41, 0xD6,
+ 0x1E, 0xB9, 0x09, 0xF0, 0x9B, 0x36, 0x64, 0x24, 0xAF, 0xE0, 0xB8, 0x57,
+ 0xBB, 0x00, 0x68, 0x22, 0x7F, 0x53, 0x5A, 0xD9, 0x89, 0x43, 0xC1, 0x78,
+ 0xAA, 0xA6, 0xDF, 0x59, 0x1D, 0x91, 0x63, 0x55, 0xA9, 0xCF, 0x95, 0x62,
+ 0x76, 0x03, 0x26, 0x83, 0xC5, 0xB9, 0xE5, 0x02, 0xA2, 0x5B, 0x7D, 0x20,
+ 0x4A, 0xA9, 0x14, 0x7B, 0xCA, 0x2D, 0x47, 0xB3, 0x41, 0x4A, 0x73, 0x4E,
+ 0x68, 0x19, 0xC8, 0x11, 0xE4, 0xC6, 0x9B, 0xBC, 0x3F, 0x57, 0x0F, 0xD6,
+ 0x15, 0x29, 0x53, 0x9A, 0x52, 0x00, 0x51, 0x1B, 0x1F, 0xE9, 0x1B, 0x57,
+ 0xB5, 0x6F, 0xBA, 0x08, 0x00, 0x74, 0xE6, 0x81, 0x76, 0xA4, 0x60, 0x2B,
+ 0xB6, 0xF9, 0xB9, 0xE7, 0x21, 0x65, 0x63, 0xB6, 0x15, 0xD9, 0x0D, 0x2A,
+ 0x6B, 0xEC, 0x96, 0xF2, 0xA1, 0x8F, 0x9F, 0xA9, 0x5D, 0x2D, 0xB0, 0x53,
+ 0x64, 0x56, 0x85, 0xC5, 0x2E, 0x05, 0x34, 0xFF, 0x44, 0x29, 0xB3, 0xB5,
+ 0xE9, 0x70, 0x7A, 0x4B, 0x6A, 0x07, 0x85, 0x6E, 0x99, 0x47, 0xBA, 0x08,
+ 0x7D, 0xDF, 0xA7, 0x49, 0xB0, 0xA6, 0x6E, 0xAD, 0x23, 0x26, 0x19, 0xC4,
+ 0x2E, 0x09, 0x75, 0xDB, 0xFF, 0x18, 0x9A, 0x69, 0x71, 0x8C, 0xAA, 0xEC,
+ 0x66, 0xB2, 0xED, 0x8F, 0xB8, 0x60, 0xEE, 0x9C, 0x29, 0x4C, 0x09, 0x75,
+ 0xA5, 0x02, 0x36, 0x19, 0xE1, 0x9E, 0xB1, 0xC2, 0x6C, 0x52, 0x64, 0x56,
+ 0x65, 0x9D, 0x42, 0x5B, 0x9A, 0x98, 0x54, 0x3F, 0x3E, 0x3A, 0x18, 0xE4,
+ 0x40, 0x13, 0x59, 0xA0, 0xF5, 0x30, 0xE8, 0xEF, 0x07, 0x9C, 0xD2, 0xA1,
+ 0xD6, 0x3F, 0xF7, 0x99, 0xD6, 0xE4, 0x8F, 0x6B, 0x26, 0xEB, 0x70, 0x84,
+ 0x86, 0x20, 0xDD, 0x4C, 0xC1, 0x5D, 0x25, 0xF0, 0xE6, 0x38, 0x2D, 0x4D,
+ 0xC9, 0xEF, 0xBA, 0x3E, 0x3F, 0x6B, 0x68, 0x09, 0x5E, 0xCC, 0x1E, 0x02,
+ 0xC6, 0xE9, 0x82, 0x63, 0x86, 0xE2, 0xA0, 0x52, 0x84, 0x35, 0x7F, 0x68,
+ 0xA1, 0x70, 0x6A, 0x6B, 0x14, 0x18, 0x97, 0x3C, 0x5C, 0xAE, 0xDE, 0x7F,
+ 0x1C, 0x84, 0x07, 0x3E, 0x37, 0x07, 0x50, 0xAA, 0x05, 0x53, 0x9C, 0xB7,
+ 0x0D, 0x0C, 0x50, 0xF0, 0x37, 0xDA, 0x3A, 0xB0, 0xB8, 0xF2, 0x16, 0x57,
+ 0xEC, 0x44, 0x7D, 0x8E, 0xB2, 0x74, 0xB5, 0x3C, 0x1A, 0xF5, 0x0C, 0xAE,
+ 0xFF, 0xB3, 0x00, 0x02, 0x04, 0x1F, 0x1C, 0xF0, 0xF6, 0x2F, 0xA9, 0x7C,
+ 0xF9, 0x13, 0x91, 0xD1, 0xBD, 0x21, 0x09, 0xDC, 0x58, 0x7A, 0x83, 0x25,
+ 0xDC, 0xDA, 0xC2, 0x37, 0x81, 0xE5, 0xE5, 0x3A, 0x01, 0x47, 0xF5, 0x22,
+ 0x73, 0x47, 0x32, 0x94, 0x0E, 0x03, 0xD0, 0x0F, 0x46, 0x61, 0x44, 0xA9,
+ 0xA7, 0xDD, 0xF3, 0x9A, 0x34, 0x76, 0xB5, 0xC8, 0x2F, 0x0E, 0xEA, 0x3B,
+ 0x99, 0xCD, 0x38, 0xE2, 0x41, 0x1E, 0x75, 0xA4, 0x3E, 0xC7, 0xC8, 0xEC,
+ 0x08, 0xB9, 0x6D, 0x4F, 0x38, 0x8B, 0x54, 0x4E, 0x31, 0xB3, 0x3E, 0x18,
+ 0xA1, 0xBB, 0x80, 0x32, 0x79, 0x7C, 0x97, 0x24, 0x90, 0x12, 0xB8, 0x2C,
+ 0xBF, 0x04, 0x0A, 0xF6, 0x03, 0x0D, 0x42, 0x6F, 0x10, 0x08, 0x93, 0xD9,
+ 0x1F, 0x77, 0x9A, 0xDE, 0xAF, 0x89, 0xAF, 0xBC, 0x72, 0xB0, 0x79, 0x56,
+ 0x24, 0x71, 0x6B, 0x2E, 0x1F, 0x72, 0x12, 0x55, 0x2E, 0x3F, 0xCF, 0xDC,
+ 0x12, 0xAE, 0x8B, 0xB3, 0x17, 0xDA, 0x08, 0x74, 0x18, 0x47, 0x58, 0x7A,
+ 0x87, 0xCD, 0x84, 0x9F, 0xE6, 0xDD, 0x1A, 0x50, 0xFA, 0x1D, 0x85, 0xDB,
+ 0x3A, 0xEC, 0x7A, 0xEC, 0x8C, 0x7D, 0x4B, 0xE9, 0xBC, 0x9A, 0x9F, 0xBC,
+ 0x08, 0xD8, 0x15, 0x32, 0x47, 0x18, 0x1C, 0xEF, 0xD2, 0xC3, 0x64, 0xC4,
+ 0x66, 0x43, 0x09, 0x63, 0x51, 0xC4, 0x65, 0x2A, 0x43, 0x4D, 0xA1, 0x12,
+ 0x16, 0xBA, 0xC2, 0x24, 0x37, 0x3B, 0x43, 0xDD, 0x55, 0x4E, 0x31, 0x10,
+ 0x9E, 0xF8, 0xDF, 0x71, 0xDD, 0xE4, 0x3A, 0x13, 0x02, 0x00, 0x94, 0x50,
+ 0x6B, 0xC7, 0xA3, 0xD7, 0xF1, 0x56, 0x35, 0x04, 0x9B, 0x19, 0x11, 0x5F,
+ 0xD6, 0x77, 0xAC, 0x81, 0xFA, 0xFB, 0xF1, 0x97, 0xED, 0xE6, 0x8F, 0xF2,
+ 0x09, 0xA5, 0x24, 0x59, 0x3B, 0x18, 0x11, 0x3C, 0xB1, 0x6F, 0xE9, 0xEA,
+ 0x70, 0x45, 0xE3, 0x86, 0x6E, 0x3C, 0x15, 0x1E, 0x2C, 0xBF, 0xBA, 0x9E,
+ 0xFA, 0x06, 0x3D, 0x4E, 0x1C, 0xE7, 0x1F, 0x77, 0xB3, 0x2A, 0x3E, 0x5A,
+ 0x0A, 0x5E, 0x0E, 0x86, 0x25, 0xC8, 0x66, 0x52, 0xD6, 0x89, 0x3E, 0x80,
+ 0x0F, 0x1D, 0xE7, 0x99, 0xB9, 0xDC, 0x65, 0x29, 0x78, 0xEA, 0xE2, 0x94,
+ 0xBA, 0x0E, 0x15, 0xC6, 0x6A, 0xB3, 0x10, 0x9C, 0x78, 0xC9, 0x4C, 0x2E,
+ 0x3D, 0x2B, 0x1D, 0x36, 0xA7, 0x4E, 0xF7, 0xF2, 0xF4, 0x2D, 0x0A, 0x1E,
+ 0x53, 0x3C, 0xFC, 0xA6, 0xB6, 0x12, 0x13, 0xF7, 0x08, 0xA7, 0x23, 0x52,
+ 0x60, 0x79, 0xC2, 0x19, 0x0F, 0x26, 0x39, 0x19, 0x83, 0xC8, 0x7B, 0xA6,
+ 0x95, 0x45, 0xBC, 0xE3, 0x66, 0x1F, 0xC3, 0xEA, 0x6E, 0xFE, 0xAD, 0xEB,
+ 0xA5, 0x5A, 0x6C, 0xBE, 0xEF, 0xDD, 0x32, 0xC3, 0x28, 0xFF, 0x8C, 0x01,
+ 0xD1, 0x37, 0x7F, 0xB1, 0x3B, 0x95, 0x2F, 0xDB, 0x0F, 0xA5, 0xCE, 0xEE,
+ 0x02, 0x97, 0xAB, 0x68, 0x85, 0x21, 0x58, 0x65, 0x70, 0x61, 0x07, 0x29,
+ 0x28, 0xB6, 0x21, 0x15, 0x84, 0x2F, 0x6E, 0x5B, 0xAD, 0x7D, 0xEF, 0x2A,
+ 0x96, 0xBD, 0x61, 0xEB, 0x30, 0xA8, 0xCC, 0x13, 0x10, 0x15, 0x9F, 0x61,
+ 0x75, 0x47, 0xDD, 0xEC, 0x39, 0xA2, 0x70, 0x4C, 0x90, 0x5C, 0x73, 0xB5,
+ 0xCF, 0x63, 0x03, 0xAA, 0x1E, 0xFE, 0x34, 0x03, 0xA7, 0x2C, 0x62, 0x60,
+ 0xBC, 0x86, 0xCC, 0xEE, 0x14, 0xDE, 0xAA, 0xCB, 0x0B, 0x9E, 0x9E, 0xD5,
+ 0xCA, 0xF0, 0xBD, 0x19, 0xAF, 0x1E, 0x8B, 0x64, 0x6E, 0x84, 0xF3, 0xB2,
+ 0xAB, 0x5C, 0xAB, 0x9C, 0xB3, 0xB4, 0x2A, 0x3C, 0x32, 0x5A, 0x68, 0x40,
+ 0x50, 0xBB, 0x5A, 0x65, 0xB9, 0x69, 0x23, 0xA0, 0x99, 0xA0, 0x5F, 0x87,
+ 0x19, 0x0B, 0x54, 0x9B, 0xF7, 0xB8, 0x21, 0xC0, 0xD5, 0xE9, 0x9E, 0x31,
+ 0x77, 0x2D, 0xE3, 0x97, 0x9A, 0x88, 0x37, 0xF8, 0xA8, 0x7D, 0x3D, 0x62,
+ 0x7E, 0x99, 0xF7, 0x95, 0xD6, 0x1F, 0xE6, 0xC7, 0x29, 0x88, 0x35, 0x0E,
+ 0x81, 0x12, 0x68, 0x16, 0x5F, 0x93, 0xED, 0x11, 0x63, 0x72, 0x22, 0x1B,
+ 0xA5, 0x84, 0xF5, 0x57, 0x99, 0xBA, 0x58, 0x78, 0xA1, 0xDF, 0xDE, 0x96,
+ 0x54, 0x30, 0x2E, 0x53, 0xEB, 0x0A, 0xB3, 0xCD, 0x96, 0x46, 0xC2, 0x1A,
+ 0xFF, 0xC3, 0x83, 0x9B, 0xEA, 0xFF, 0xC6, 0x34, 0xEF, 0xF2, 0xEB, 0x58,
+ 0x28, 0x31, 0xBC, 0x6D, 0xE4, 0x48, 0xD9, 0x8F, 0xE3, 0xB7, 0x64, 0xE8,
+ 0xD9, 0x14, 0x4A, 0x5D, 0x73, 0x3C, 0x7C, 0xEE, 0x61, 0xED, 0x28, 0xFE,
+ 0xEA, 0xAB, 0xAA, 0xA3, 0xB6, 0xE2, 0xEE, 0x45, 0xE0, 0x13, 0x3E, 0x20,
+ 0x14, 0x5D, 0x10, 0x42, 0xB5, 0xBB, 0x6A, 0xEF, 0x42, 0xF4, 0x42, 0xC7,
+ 0xD0, 0x4F, 0xCB, 0xFA, 0x15, 0x4F, 0x6C, 0xDB, 0xC7, 0x4D, 0x85, 0x86,
+ 0x9E, 0x79, 0x1E, 0xD8, 0x05, 0x21, 0xCD, 0x41, 0x1D, 0x3B, 0x4F, 0x65,
+ 0x46, 0x26, 0x8D, 0x5B, 0xF2, 0xA1, 0x62, 0xCF, 0x50, 0x62, 0x81, 0x3D,
+ 0x6A, 0x47, 0x4B, 0xE4, 0x92, 0x74, 0xCB, 0x69, 0xC3, 0x24, 0x15, 0x7F,
+ 0xA3, 0xB6, 0xC7, 0xC1, 0xA0, 0x83, 0x88, 0xFC, 0x9D, 0x48, 0x19, 0xAD,
+ 0x00, 0xBF, 0x5B, 0x09, 0x85, 0xB2, 0x92, 0x56, 0x0B, 0x8A, 0x84, 0x47,
+ 0xEA, 0xF5, 0x55, 0x0C, 0x2A, 0x8D, 0x42, 0x58, 0x00, 0x0D, 0x82, 0x23,
+ 0x74, 0xB1, 0x62, 0x14, 0x41, 0x7E, 0x93, 0x8D, 0x92, 0xF0, 0x72, 0x33,
+ 0x61, 0x70, 0x3F, 0x23, 0x3E, 0xF4, 0xAD, 0x1D, 0x60, 0x74, 0xEE, 0xCB,
+ 0x59, 0x37, 0xDE, 0x7C, 0xDB, 0x3B, 0x22, 0x6C, 0xF1, 0xEC, 0x5F, 0xD6,
+ 0x9E, 0x50, 0xF8, 0x19, 0x84, 0x80, 0x07, 0xA6, 0x6E, 0x32, 0x77, 0xCE,
+ 0xA7, 0xF2, 0x85, 0x40, 0xC2, 0x06, 0x0C, 0xC5, 0xAA, 0xA7, 0x69, 0xA9,
+ 0x35, 0x97, 0xD9, 0x61, 0x55, 0xD8, 0xEF, 0xE8, 0x84, 0x34, 0x45, 0xC3,
+ 0x2E, 0x7A, 0x44, 0x9E, 0xDC, 0xCA, 0x0B, 0x80, 0xFC, 0xAB, 0x04, 0x5A,
+ 0xCD, 0x88, 0x55, 0x10, 0xD3, 0xDB, 0x73, 0xDB, 0xC9, 0x9E, 0x1E, 0x0E,
+ 0x05, 0x67, 0xD5, 0xFD, 0xD8, 0x38, 0x3E, 0x71, 0x65, 0x34, 0xC4, 0xC5,
+ 0x40, 0x43, 0x67, 0xE3, 0x79, 0xDA, 0x5F, 0x67, 0x4A, 0x3D, 0xB0, 0x8F,
+ 0xE7, 0x21, 0x3E, 0x15, 0x20, 0xFF, 0x6D, 0xF1, 0x9E, 0xF8, 0x28, 0x3D,
+ 0xF7, 0x40, 0x81, 0x94, 0x68, 0x5A, 0x3D, 0xE9, 0xF7, 0xAD, 0x83, 0xDB,
+ 0x2B, 0x9F, 0xE3, 0xE6, 0xF7, 0xD4, 0x02, 0x76, 0xF7, 0x20, 0x15, 0x41,
+ 0x34, 0x29, 0x69, 0x94, 0x1C, 0x26, 0x4C, 0xF6, 0x6A, 0xF4, 0x20, 0x33,
+ 0x71, 0x24, 0x08, 0xD4, 0x68, 0x00, 0xA1, 0xD4, 0x2E, 0x6B, 0xF4, 0xBC,
+ 0x46, 0x45, 0x24, 0x97, 0x2E, 0xF6, 0x39, 0x1E, 0xAF, 0x61, 0x00, 0x50,
+ 0xB7, 0xD4, 0xB7, 0x43,
+};
+
+} // namespace random_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/random/internal/randen_slow.cc b/third_party/abseil/absl/random/internal/randen_slow.cc
index 7a2e2da..4e5f3dc 100644
--- a/third_party/abseil/absl/random/internal/randen_slow.cc
+++ b/third_party/abseil/absl/random/internal/randen_slow.cc
@@ -18,16 +18,9 @@
#include <cstdint>
#include <cstring>
+#include "absl/base/attributes.h"
#include "absl/random/internal/platform.h"
-
-// ABSL_HAVE_ATTRIBUTE
-#if !defined(ABSL_HAVE_ATTRIBUTE)
-#ifdef __has_attribute
-#define ABSL_HAVE_ATTRIBUTE(x) __has_attribute(x)
-#else
-#define ABSL_HAVE_ATTRIBUTE(x) 0
-#endif
-#endif
+#include "absl/random/internal/randen_traits.h"
#if ABSL_HAVE_ATTRIBUTE(always_inline) || \
(defined(__GNUC__) && !defined(__clang__))
@@ -233,35 +226,16 @@
0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c,
};
-struct alignas(16) u64x2 {
- constexpr u64x2() : v{0, 0} {};
- constexpr u64x2(uint64_t hi, uint64_t lo) : v{lo, hi} {}
-
- uint64_t v[2];
-};
-
// Software implementation of the Vector128 class, using uint32_t
// as an underlying vector register.
-//
-struct Vector128 {
- inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128& operator^=(
- const Vector128& other) {
- s[0] ^= other.s[0];
- s[1] ^= other.s[1];
- s[2] ^= other.s[2];
- s[3] ^= other.s[3];
- return *this;
- }
-
+struct alignas(16) Vector128 {
uint32_t s[4];
};
inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128
-Vector128Load(const void* ABSL_RANDOM_INTERNAL_RESTRICT from) {
+Vector128Load(const void* from) {
Vector128 result;
- const uint8_t* ABSL_RANDOM_INTERNAL_RESTRICT src =
- reinterpret_cast<const uint8_t*>(from);
-
+ const uint8_t* src = reinterpret_cast<const uint8_t*>(from);
result.s[0] = static_cast<uint32_t>(src[0]) << 24 |
static_cast<uint32_t>(src[1]) << 16 |
static_cast<uint32_t>(src[2]) << 8 |
@@ -282,7 +256,7 @@
}
inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void Vector128Store(
- const Vector128& v, void* ABSL_RANDOM_INTERNAL_RESTRICT to) {
+ const Vector128& v, void* to) {
uint8_t* dst = reinterpret_cast<uint8_t*>(to);
dst[0] = static_cast<uint8_t>(v.s[0] >> 24);
dst[1] = static_cast<uint8_t>(v.s[0] >> 16);
@@ -306,91 +280,57 @@
// symmetry of AES (ensures previously equal columns differ afterwards).
inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128
AesRound(const Vector128& state, const Vector128& round_key) {
- // clang-format off
Vector128 result;
- result.s[0] = round_key.s[0] ^
- te0[uint8_t(state.s[0] >> 24)] ^
- te1[uint8_t(state.s[1] >> 16)] ^
- te2[uint8_t(state.s[2] >> 8)] ^
+ result.s[0] = round_key.s[0] ^ //
+ te0[uint8_t(state.s[0] >> 24)] ^ //
+ te1[uint8_t(state.s[1] >> 16)] ^ //
+ te2[uint8_t(state.s[2] >> 8)] ^ //
te3[uint8_t(state.s[3])];
- result.s[1] = round_key.s[1] ^
- te0[uint8_t(state.s[1] >> 24)] ^
- te1[uint8_t(state.s[2] >> 16)] ^
- te2[uint8_t(state.s[3] >> 8)] ^
+ result.s[1] = round_key.s[1] ^ //
+ te0[uint8_t(state.s[1] >> 24)] ^ //
+ te1[uint8_t(state.s[2] >> 16)] ^ //
+ te2[uint8_t(state.s[3] >> 8)] ^ //
te3[uint8_t(state.s[0])];
- result.s[2] = round_key.s[2] ^
- te0[uint8_t(state.s[2] >> 24)] ^
- te1[uint8_t(state.s[3] >> 16)] ^
- te2[uint8_t(state.s[0] >> 8)] ^
+ result.s[2] = round_key.s[2] ^ //
+ te0[uint8_t(state.s[2] >> 24)] ^ //
+ te1[uint8_t(state.s[3] >> 16)] ^ //
+ te2[uint8_t(state.s[0] >> 8)] ^ //
te3[uint8_t(state.s[1])];
- result.s[3] = round_key.s[3] ^
- te0[uint8_t(state.s[3] >> 24)] ^
- te1[uint8_t(state.s[0] >> 16)] ^
- te2[uint8_t(state.s[1] >> 8)] ^
+ result.s[3] = round_key.s[3] ^ //
+ te0[uint8_t(state.s[3] >> 24)] ^ //
+ te1[uint8_t(state.s[0] >> 16)] ^ //
+ te2[uint8_t(state.s[1] >> 8)] ^ //
te3[uint8_t(state.s[2])];
return result;
- // clang-format on
}
-// RANDen = RANDom generator or beetroots in Swiss German.
-// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
-// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
-//
-// High-level summary:
-// 1) Reverie (see "A Robust and Sponge-Like PRNG with Improved Efficiency") is
-// a sponge-like random generator that requires a cryptographic permutation.
-// It improves upon "Provably Robust Sponge-Based PRNGs and KDFs" by
-// achieving backtracking resistance with only one Permute() per buffer.
-//
-// 2) "Simpira v2: A Family of Efficient Permutations Using the AES Round
-// Function" constructs up to 1024-bit permutations using an improved
-// Generalized Feistel network with 2-round AES-128 functions. This Feistel
-// block shuffle achieves diffusion faster and is less vulnerable to
-// sliced-biclique attacks than the Type-2 cyclic shuffle.
-//
-// 3) "Improving the Generalized Feistel" and "New criterion for diffusion
-// property" extends the same kind of improved Feistel block shuffle to 16
-// branches, which enables a 2048-bit permutation.
-//
-// Combine these three ideas and also change Simpira's subround keys from
-// structured/low-entropy counters to digits of Pi.
+using ::absl::random_internal::RandenTraits;
-// Randen constants.
-constexpr size_t kFeistelBlocks = 16;
-constexpr size_t kFeistelFunctions = kFeistelBlocks / 2; // = 8
-constexpr size_t kFeistelRounds = 16 + 1; // > 4 * log2(kFeistelBlocks)
-constexpr size_t kKeys = kFeistelRounds * kFeistelFunctions;
-
-// INCLUDE keys.
-#include "absl/random/internal/randen-keys.inc"
-
-static_assert(kKeys == kRoundKeys, "kKeys and kRoundKeys must be equal");
-
-// 2 uint64_t lanes per Vector128
-static constexpr size_t kLanes = 2;
+// Randen operates on 128-bit vectors.
+struct alignas(16) u64x2 {
+ uint64_t data[2];
+};
// The improved Feistel block shuffle function for 16 blocks.
inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void BlockShuffle(
- uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state_u64) {
- static_assert(kFeistelBlocks == 16,
+ u64x2* state) {
+ static_assert(RandenTraits::kFeistelBlocks == 16,
"Feistel block shuffle only works for 16 blocks.");
- constexpr size_t shuffle[kFeistelBlocks] = {7, 2, 13, 4, 11, 8, 3, 6,
- 15, 0, 9, 10, 1, 14, 5, 12};
-
- u64x2* ABSL_RANDOM_INTERNAL_RESTRICT state =
- reinterpret_cast<u64x2*>(state_u64);
+ constexpr size_t shuffle[RandenTraits::kFeistelBlocks] = {
+ 7, 2, 13, 4, 11, 8, 3, 6, 15, 0, 9, 10, 1, 14, 5, 12};
// The fully unrolled loop without the memcpy improves the speed by about
- // 30% over the equivalent (leaving code here as a comment):
- if (false) {
- u64x2 source[kFeistelBlocks];
- std::memcpy(source, state, sizeof(source));
- for (size_t i = 0; i < kFeistelBlocks; i++) {
- const u64x2 v0 = source[shuffle[i]];
- state[i] = v0;
- }
+ // 30% over the equivalent:
+#if 0
+ u64x2 source[RandenTraits::kFeistelBlocks];
+ std::memcpy(source, state, sizeof(source));
+ for (size_t i = 0; i < RandenTraits::kFeistelBlocks; i++) {
+ const u64x2 v0 = source[shuffle[i]];
+ state[i] = v0;
}
+ return;
+#endif
const u64x2 v0 = state[shuffle[0]];
const u64x2 v1 = state[shuffle[1]];
@@ -432,23 +372,23 @@
// parallel hides the 7-cycle AESNI latency on HSW. Note that the Feistel
// XORs are 'free' (included in the second AES instruction).
inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE const u64x2* FeistelRound(
- uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state,
+ u64x2* ABSL_RANDOM_INTERNAL_RESTRICT state,
const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys) {
- for (size_t branch = 0; branch < kFeistelBlocks; branch += 4) {
- const Vector128 s0 = Vector128Load(state + kLanes * branch);
- const Vector128 s1 = Vector128Load(state + kLanes * (branch + 1));
+ for (size_t branch = 0; branch < RandenTraits::kFeistelBlocks; branch += 4) {
+ const Vector128 s0 = Vector128Load(state + branch);
+ const Vector128 s1 = Vector128Load(state + branch + 1);
const Vector128 f0 = AesRound(s0, Vector128Load(keys));
keys++;
const Vector128 o1 = AesRound(f0, s1);
- Vector128Store(o1, state + kLanes * (branch + 1));
+ Vector128Store(o1, state + branch + 1);
// Manually unroll this loop once. about 10% better than not unrolled.
- const Vector128 s2 = Vector128Load(state + kLanes * (branch + 2));
- const Vector128 s3 = Vector128Load(state + kLanes * (branch + 3));
+ const Vector128 s2 = Vector128Load(state + branch + 2);
+ const Vector128 s3 = Vector128Load(state + branch + 3);
const Vector128 f2 = AesRound(s2, Vector128Load(keys));
keys++;
const Vector128 o3 = AesRound(f2, s3);
- Vector128Store(o3, state + kLanes * (branch + 3));
+ Vector128Store(o3, state + branch + 3);
}
return keys;
}
@@ -458,11 +398,9 @@
// 2^64 queries if the round function is a PRF. This is similar to the b=8 case
// of Simpira v2, but more efficient than its generic construction for b=16.
inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void Permute(
- const void* keys, uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state) {
- const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys128 =
- static_cast<const u64x2*>(keys);
- for (size_t round = 0; round < kFeistelRounds; ++round) {
- keys128 = FeistelRound(state, keys128);
+ u64x2* state, const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys) {
+ for (size_t round = 0; round < RandenTraits::kFeistelRounds; ++round) {
+ keys = FeistelRound(state, keys);
BlockShuffle(state);
}
}
@@ -470,43 +408,50 @@
} // namespace
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
const void* RandenSlow::GetKeys() {
// Round keys for one AES per Feistel round and branch.
// The canonical implementation uses first digits of Pi.
- return round_keys;
+ return kRandenRoundKeys;
}
void RandenSlow::Absorb(const void* seed_void, void* state_void) {
- uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state =
- reinterpret_cast<uint64_t*>(state_void);
- const uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT seed =
- reinterpret_cast<const uint64_t*>(seed_void);
+ auto* state =
+ reinterpret_cast<uint64_t * ABSL_RANDOM_INTERNAL_RESTRICT>(state_void);
+ const auto* seed =
+ reinterpret_cast<const uint64_t * ABSL_RANDOM_INTERNAL_RESTRICT>(
+ seed_void);
- constexpr size_t kCapacityBlocks = kCapacityBytes / sizeof(uint64_t);
- static_assert(kCapacityBlocks * sizeof(uint64_t) == kCapacityBytes,
- "Not i*V");
- for (size_t i = kCapacityBlocks; i < kStateBytes / sizeof(uint64_t); ++i) {
+ constexpr size_t kCapacityBlocks =
+ RandenTraits::kCapacityBytes / sizeof(uint64_t);
+ static_assert(
+ kCapacityBlocks * sizeof(uint64_t) == RandenTraits::kCapacityBytes,
+ "Not i*V");
+
+ for (size_t i = kCapacityBlocks;
+ i < RandenTraits::kStateBytes / sizeof(uint64_t); ++i) {
state[i] ^= seed[i - kCapacityBlocks];
}
}
-void RandenSlow::Generate(const void* keys, void* state_void) {
- static_assert(kCapacityBytes == sizeof(Vector128), "Capacity mismatch");
+void RandenSlow::Generate(const void* keys_void, void* state_void) {
+ static_assert(RandenTraits::kCapacityBytes == sizeof(u64x2),
+ "Capacity mismatch");
- uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state =
- reinterpret_cast<uint64_t*>(state_void);
+ auto* state = reinterpret_cast<u64x2*>(state_void);
+ const auto* keys = reinterpret_cast<const u64x2*>(keys_void);
- const Vector128 prev_inner = Vector128Load(state);
+ const u64x2 prev_inner = state[0];
- Permute(keys, state);
+ Permute(state, keys);
// Ensure backtracking resistance.
- Vector128 inner = Vector128Load(state);
- inner ^= prev_inner;
- Vector128Store(inner, state);
+ state[0].data[0] ^= prev_inner.data[0];
+ state[0].data[1] ^= prev_inner.data[1];
}
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/random/internal/randen_slow.h b/third_party/abseil/absl/random/internal/randen_slow.h
index 3058613..532c3a8 100644
--- a/third_party/abseil/absl/random/internal/randen_slow.h
+++ b/third_party/abseil/absl/random/internal/randen_slow.h
@@ -17,27 +17,24 @@
#include <cstddef>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
-// RANDen = RANDom generator or beetroots in Swiss German.
+// RANDen = RANDom generator or beetroots in Swiss High German.
// RandenSlow implements the basic state manipulation methods for
// architectures lacking AES hardware acceleration intrinsics.
class RandenSlow {
public:
- // Size of the entire sponge / state for the randen PRNG.
- static constexpr size_t kStateBytes = 256; // 2048-bit
-
- // Size of the 'inner' (inaccessible) part of the sponge. Larger values would
- // require more frequent calls to RandenGenerate.
- static constexpr size_t kCapacityBytes = 16; // 128-bit
-
static void Generate(const void* keys, void* state_void);
static void Absorb(const void* seed_void, void* state_void);
static const void* GetKeys();
};
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_RANDEN_SLOW_H_
diff --git a/third_party/abseil/absl/random/internal/randen_slow_test.cc b/third_party/abseil/absl/random/internal/randen_slow_test.cc
index c07155d..4a53583 100644
--- a/third_party/abseil/absl/random/internal/randen_slow_test.cc
+++ b/third_party/abseil/absl/random/internal/randen_slow_test.cc
@@ -17,18 +17,20 @@
#include <cstring>
#include "gtest/gtest.h"
+#include "absl/random/internal/randen_traits.h"
namespace {
using absl::random_internal::RandenSlow;
+using absl::random_internal::RandenTraits;
// Local state parameters.
constexpr size_t kSeedBytes =
- RandenSlow::kStateBytes - RandenSlow::kCapacityBytes;
-constexpr size_t kStateSizeT = RandenSlow::kStateBytes / sizeof(uint64_t);
+ RandenTraits::kStateBytes - RandenTraits::kCapacityBytes;
+constexpr size_t kStateSizeT = RandenTraits::kStateBytes / sizeof(uint64_t);
constexpr size_t kSeedSizeT = kSeedBytes / sizeof(uint32_t);
-struct randen {
+struct alignas(16) randen {
uint64_t state[kStateSizeT];
uint32_t seed[kSeedSizeT];
};
diff --git a/third_party/abseil/absl/random/internal/randen_traits.h b/third_party/abseil/absl/random/internal/randen_traits.h
index 4f1f408..120022c 100644
--- a/third_party/abseil/absl/random/internal/randen_traits.h
+++ b/third_party/abseil/absl/random/internal/randen_traits.h
@@ -22,13 +22,35 @@
#include <cstddef>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
-// RANDen = RANDom generator or beetroots in Swiss German.
+// RANDen = RANDom generator or beetroots in Swiss High German.
// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
//
+// High-level summary:
+// 1) Reverie (see "A Robust and Sponge-Like PRNG with Improved Efficiency") is
+// a sponge-like random generator that requires a cryptographic permutation.
+// It improves upon "Provably Robust Sponge-Based PRNGs and KDFs" by
+// achieving backtracking resistance with only one Permute() per buffer.
+//
+// 2) "Simpira v2: A Family of Efficient Permutations Using the AES Round
+// Function" constructs up to 1024-bit permutations using an improved
+// Generalized Feistel network with 2-round AES-128 functions. This Feistel
+// block shuffle achieves diffusion faster and is less vulnerable to
+// sliced-biclique attacks than the Type-2 cyclic shuffle.
+//
+// 3) "Improving the Generalized Feistel" and "New criterion for diffusion
+// property" extends the same kind of improved Feistel block shuffle to 16
+// branches, which enables a 2048-bit permutation.
+//
+// Combine these three ideas and also change Simpira's subround keys from
+// structured/low-entropy counters to digits of Pi (or other random source).
+
// RandenTraits contains the basic algorithm traits, such as the size of the
// state, seed, sponge, etc.
struct RandenTraits {
@@ -42,18 +64,25 @@
// Size of the default seed consumed by the sponge.
static constexpr size_t kSeedBytes = kStateBytes - kCapacityBytes;
+ // Assuming 128-bit blocks, the number of blocks in the state.
// Largest size for which security proofs are known.
static constexpr size_t kFeistelBlocks = 16;
- // Type-2 generalized Feistel => one round function for every two blocks.
- static constexpr size_t kFeistelFunctions = kFeistelBlocks / 2; // = 8
-
// Ensures SPRP security and two full subblock diffusions.
// Must be > 4 * log2(kFeistelBlocks).
static constexpr size_t kFeistelRounds = 16 + 1;
+
+ // Size of the key. A 128-bit key block is used for every-other
+ // feistel block (Type-2 generalized Feistel network) in each round.
+ static constexpr size_t kKeyBytes = 16 * kFeistelRounds * kFeistelBlocks / 2;
};
+// Randen key arrays. In randen_round_keys.cc
+extern const unsigned char kRandenRoundKeys[RandenTraits::kKeyBytes];
+extern const unsigned char kRandenRoundKeysBE[RandenTraits::kKeyBytes];
+
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_RANDEN_TRAITS_H_
diff --git a/third_party/abseil/absl/random/internal/salted_seed_seq.h b/third_party/abseil/absl/random/internal/salted_seed_seq.h
index 8648700..5953a09 100644
--- a/third_party/abseil/absl/random/internal/salted_seed_seq.h
+++ b/third_party/abseil/absl/random/internal/salted_seed_seq.h
@@ -30,6 +30,7 @@
#include "absl/types/span.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
// This class conforms to the C++ Standard "Seed Sequence" concept
@@ -160,6 +161,7 @@
}
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_SALTED_SEED_SEQ_H_
diff --git a/third_party/abseil/absl/random/internal/seed_material.cc b/third_party/abseil/absl/random/internal/seed_material.cc
index 85dd535..4d38a57 100644
--- a/third_party/abseil/absl/random/internal/seed_material.cc
+++ b/third_party/abseil/absl/random/internal/seed_material.cc
@@ -45,6 +45,9 @@
#define ABSL_RANDOM_USE_BCRYPT 1
#pragma comment(lib, "bcrypt.lib")
+#elif defined(__Fuchsia__)
+#include <zircon/syscalls.h>
+
#endif
#if defined(ABSL_RANDOM_USE_BCRYPT)
@@ -58,6 +61,7 @@
#endif
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
namespace {
@@ -107,6 +111,15 @@
return true;
}
+#elif defined(__Fuchsia__)
+
+bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) {
+ auto buffer = reinterpret_cast<uint8_t*>(values.data());
+ size_t buffer_size = sizeof(uint32_t) * values.size();
+ zx_cprng_draw(buffer, buffer_size);
+ return true;
+}
+
#else
// On *nix, read entropy from /dev/urandom.
@@ -202,4 +215,5 @@
}
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/random/internal/seed_material.h b/third_party/abseil/absl/random/internal/seed_material.h
index 57de8a2..4be10e9 100644
--- a/third_party/abseil/absl/random/internal/seed_material.h
+++ b/third_party/abseil/absl/random/internal/seed_material.h
@@ -27,6 +27,7 @@
#include "absl/types/span.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
// Returns the number of 32-bit blocks needed to contain the given number of
@@ -97,6 +98,7 @@
absl::optional<uint32_t> GetSaltMaterial();
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_SEED_MATERIAL_H_
diff --git a/third_party/abseil/absl/random/internal/seed_salting_sequence_generator.cc b/third_party/abseil/absl/random/internal/seed_salting_sequence_generator.cc
deleted file mode 100644
index 31fdcfe..0000000
--- a/third_party/abseil/absl/random/internal/seed_salting_sequence_generator.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <iostream>
-#include <random>
-
-#include "absl/random/random.h"
-
-// This program is used in integration tests.
-
-int main() {
- std::seed_seq seed_seq{1234};
- absl::BitGen rng(seed_seq);
- constexpr size_t kSequenceLength = 8;
- for (size_t i = 0; i < kSequenceLength; i++) {
- std::cout << rng() << "\n";
- }
- return 0;
-}
diff --git a/third_party/abseil/absl/random/internal/sequence_urbg.h b/third_party/abseil/absl/random/internal/sequence_urbg.h
index 9a9b577..bc96a12 100644
--- a/third_party/abseil/absl/random/internal/sequence_urbg.h
+++ b/third_party/abseil/absl/random/internal/sequence_urbg.h
@@ -21,7 +21,10 @@
#include <type_traits>
#include <vector>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
// `sequence_urbg` is a simple random number generator which meets the
@@ -51,6 +54,7 @@
};
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_SEQUENCE_URBG_H_
diff --git a/third_party/abseil/absl/random/internal/traits.h b/third_party/abseil/absl/random/internal/traits.h
index 40eb011..75772bd 100644
--- a/third_party/abseil/absl/random/internal/traits.h
+++ b/third_party/abseil/absl/random/internal/traits.h
@@ -22,6 +22,7 @@
#include "absl/base/config.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace random_internal {
// random_internal::is_widening_convertible<A, B>
@@ -94,6 +95,7 @@
};
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_TRAITS_H_
diff --git a/third_party/abseil/absl/random/internal/uniform_helper.h b/third_party/abseil/absl/random/internal/uniform_helper.h
index 2929407..1243bc1 100644
--- a/third_party/abseil/absl/random/internal/uniform_helper.h
+++ b/third_party/abseil/absl/random/internal/uniform_helper.h
@@ -19,9 +19,13 @@
#include <limits>
#include <type_traits>
+#include "absl/base/config.h"
#include "absl/meta/type_traits.h"
+#include "absl/random/internal/traits.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
+
template <typename IntType>
class uniform_int_distribution;
@@ -57,6 +61,26 @@
: public random_internal::TagTypeCompare<IntervalOpenOpenTag> {};
namespace random_internal {
+
+// In the absence of an explicitly provided return-type, the template
+// "uniform_inferred_return_t<A, B>" is used to derive a suitable type, based on
+// the data-types of the endpoint-arguments {A lo, B hi}.
+//
+// Given endpoints {A lo, B hi}, one of {A, B} will be chosen as the
+// return-type, if one type can be implicitly converted into the other, in a
+// lossless way. The template "is_widening_convertible" implements the
+// compile-time logic for deciding if such a conversion is possible.
+//
+// If no such conversion between {A, B} exists, then the overload for
+// absl::Uniform() will be discarded, and the call will be ill-formed.
+// Return-type for absl::Uniform() when the return-type is inferred.
+template <typename A, typename B>
+using uniform_inferred_return_t =
+ absl::enable_if_t<absl::disjunction<is_widening_convertible<A, B>,
+ is_widening_convertible<B, A>>::value,
+ typename std::conditional<
+ is_widening_convertible<A, B>::value, B, A>::type>;
+
// The functions
// uniform_lower_bound(tag, a, b)
// and
@@ -81,7 +105,7 @@
std::is_same<Tag, IntervalOpenOpenTag>>>::value,
IntType>
uniform_lower_bound(Tag, IntType a, IntType) {
- return a + 1;
+ return a < (std::numeric_limits<IntType>::max)() ? (a + 1) : a;
}
template <typename FloatType, typename Tag>
@@ -112,7 +136,7 @@
std::is_same<Tag, IntervalOpenOpenTag>>>::value,
IntType>
uniform_upper_bound(Tag, IntType, IntType b) {
- return b - 1;
+ return b > (std::numeric_limits<IntType>::min)() ? (b - 1) : b;
}
template <typename FloatType, typename Tag>
@@ -148,21 +172,73 @@
return std::nextafter(b, (std::numeric_limits<FloatType>::max)());
}
+// Returns whether the bounds are valid for the underlying distribution.
+// Inputs must have already been resolved via uniform_*_bound calls.
+//
+// The c++ standard constraints in [rand.dist.uni.int] are listed as:
+// requires: lo <= hi.
+//
+// In the uniform_int_distrubtion, {lo, hi} are closed, closed. Thus:
+// [0, 0] is legal.
+// [0, 0) is not legal, but [0, 1) is, which translates to [0, 0].
+// (0, 1) is not legal, but (0, 2) is, which translates to [1, 1].
+// (0, 0] is not legal, but (0, 1] is, which translates to [1, 1].
+//
+// The c++ standard constraints in [rand.dist.uni.real] are listed as:
+// requires: lo <= hi.
+// requires: (hi - lo) <= numeric_limits<T>::max()
+//
+// In the uniform_real_distribution, {lo, hi} are closed, open, Thus:
+// [0, 0] is legal, which is [0, 0+epsilon).
+// [0, 0) is legal.
+// (0, 0) is not legal, but (0-epsilon, 0+epsilon) is.
+// (0, 0] is not legal, but (0, 0+epsilon] is.
+//
+template <typename FloatType>
+absl::enable_if_t<std::is_floating_point<FloatType>::value, bool>
+is_uniform_range_valid(FloatType a, FloatType b) {
+ return a <= b && std::isfinite(b - a);
+}
+
+template <typename IntType>
+absl::enable_if_t<std::is_integral<IntType>::value, bool>
+is_uniform_range_valid(IntType a, IntType b) {
+ return a <= b;
+}
+
+// UniformDistribution selects either absl::uniform_int_distribution
+// or absl::uniform_real_distribution depending on the NumType parameter.
template <typename NumType>
using UniformDistribution =
typename std::conditional<std::is_integral<NumType>::value,
absl::uniform_int_distribution<NumType>,
absl::uniform_real_distribution<NumType>>::type;
-template <typename TagType, typename NumType>
+// UniformDistributionWrapper is used as the underlying distribution type
+// by the absl::Uniform template function. It selects the proper Abseil
+// uniform distribution and provides constructor overloads that match the
+// expected parameter order as well as adjusting distribtuion bounds based
+// on the tag.
+template <typename NumType>
struct UniformDistributionWrapper : public UniformDistribution<NumType> {
+ template <typename TagType>
explicit UniformDistributionWrapper(TagType, NumType lo, NumType hi)
: UniformDistribution<NumType>(
uniform_lower_bound<NumType>(TagType{}, lo, hi),
uniform_upper_bound<NumType>(TagType{}, lo, hi)) {}
+
+ explicit UniformDistributionWrapper(NumType lo, NumType hi)
+ : UniformDistribution<NumType>(
+ uniform_lower_bound<NumType>(IntervalClosedOpenTag(), lo, hi),
+ uniform_upper_bound<NumType>(IntervalClosedOpenTag(), lo, hi)) {}
+
+ explicit UniformDistributionWrapper()
+ : UniformDistribution<NumType>(std::numeric_limits<NumType>::lowest(),
+ (std::numeric_limits<NumType>::max)()) {}
};
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_UNIFORM_HELPER_H_
diff --git a/third_party/abseil/absl/random/internal/uniform_helper_test.cc b/third_party/abseil/absl/random/internal/uniform_helper_test.cc
new file mode 100644
index 0000000..173c49b
--- /dev/null
+++ b/third_party/abseil/absl/random/internal/uniform_helper_test.cc
@@ -0,0 +1,279 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/random/internal/uniform_helper.h"
+
+#include <cmath>
+#include <cstdint>
+#include <random>
+
+#include "gtest/gtest.h"
+
+namespace {
+
+using absl::IntervalClosedClosedTag;
+using absl::IntervalClosedOpenTag;
+using absl::IntervalOpenClosedTag;
+using absl::IntervalOpenOpenTag;
+using absl::random_internal::uniform_inferred_return_t;
+using absl::random_internal::uniform_lower_bound;
+using absl::random_internal::uniform_upper_bound;
+
+class UniformHelperTest : public testing::Test {};
+
+TEST_F(UniformHelperTest, UniformBoundFunctionsGeneral) {
+ constexpr IntervalClosedClosedTag IntervalClosedClosed;
+ constexpr IntervalClosedOpenTag IntervalClosedOpen;
+ constexpr IntervalOpenClosedTag IntervalOpenClosed;
+ constexpr IntervalOpenOpenTag IntervalOpenOpen;
+
+ // absl::uniform_int_distribution natively assumes IntervalClosedClosed
+ // absl::uniform_real_distribution natively assumes IntervalClosedOpen
+
+ EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, 0, 100), 1);
+ EXPECT_EQ(uniform_lower_bound(IntervalOpenOpen, 0, 100), 1);
+ EXPECT_GT(uniform_lower_bound<float>(IntervalOpenClosed, 0, 1.0), 0);
+ EXPECT_GT(uniform_lower_bound<float>(IntervalOpenOpen, 0, 1.0), 0);
+ EXPECT_GT(uniform_lower_bound<double>(IntervalOpenClosed, 0, 1.0), 0);
+ EXPECT_GT(uniform_lower_bound<double>(IntervalOpenOpen, 0, 1.0), 0);
+
+ EXPECT_EQ(uniform_lower_bound(IntervalClosedClosed, 0, 100), 0);
+ EXPECT_EQ(uniform_lower_bound(IntervalClosedOpen, 0, 100), 0);
+ EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedClosed, 0, 1.0), 0);
+ EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedOpen, 0, 1.0), 0);
+ EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedClosed, 0, 1.0), 0);
+ EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedOpen, 0, 1.0), 0);
+
+ EXPECT_EQ(uniform_upper_bound(IntervalOpenOpen, 0, 100), 99);
+ EXPECT_EQ(uniform_upper_bound(IntervalClosedOpen, 0, 100), 99);
+ EXPECT_EQ(uniform_upper_bound<float>(IntervalOpenOpen, 0, 1.0), 1.0);
+ EXPECT_EQ(uniform_upper_bound<float>(IntervalClosedOpen, 0, 1.0), 1.0);
+ EXPECT_EQ(uniform_upper_bound<double>(IntervalOpenOpen, 0, 1.0), 1.0);
+ EXPECT_EQ(uniform_upper_bound<double>(IntervalClosedOpen, 0, 1.0), 1.0);
+
+ EXPECT_EQ(uniform_upper_bound(IntervalOpenClosed, 0, 100), 100);
+ EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, 0, 100), 100);
+ EXPECT_GT(uniform_upper_bound<float>(IntervalOpenClosed, 0, 1.0), 1.0);
+ EXPECT_GT(uniform_upper_bound<float>(IntervalClosedClosed, 0, 1.0), 1.0);
+ EXPECT_GT(uniform_upper_bound<double>(IntervalOpenClosed, 0, 1.0), 1.0);
+ EXPECT_GT(uniform_upper_bound<double>(IntervalClosedClosed, 0, 1.0), 1.0);
+
+ // Negative value tests
+ EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, -100, -1), -99);
+ EXPECT_EQ(uniform_lower_bound(IntervalOpenOpen, -100, -1), -99);
+ EXPECT_GT(uniform_lower_bound<float>(IntervalOpenClosed, -2.0, -1.0), -2.0);
+ EXPECT_GT(uniform_lower_bound<float>(IntervalOpenOpen, -2.0, -1.0), -2.0);
+ EXPECT_GT(uniform_lower_bound<double>(IntervalOpenClosed, -2.0, -1.0), -2.0);
+ EXPECT_GT(uniform_lower_bound<double>(IntervalOpenOpen, -2.0, -1.0), -2.0);
+
+ EXPECT_EQ(uniform_lower_bound(IntervalClosedClosed, -100, -1), -100);
+ EXPECT_EQ(uniform_lower_bound(IntervalClosedOpen, -100, -1), -100);
+ EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedClosed, -2.0, -1.0), -2.0);
+ EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedOpen, -2.0, -1.0), -2.0);
+ EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedClosed, -2.0, -1.0),
+ -2.0);
+ EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedOpen, -2.0, -1.0), -2.0);
+
+ EXPECT_EQ(uniform_upper_bound(IntervalOpenOpen, -100, -1), -2);
+ EXPECT_EQ(uniform_upper_bound(IntervalClosedOpen, -100, -1), -2);
+ EXPECT_EQ(uniform_upper_bound<float>(IntervalOpenOpen, -2.0, -1.0), -1.0);
+ EXPECT_EQ(uniform_upper_bound<float>(IntervalClosedOpen, -2.0, -1.0), -1.0);
+ EXPECT_EQ(uniform_upper_bound<double>(IntervalOpenOpen, -2.0, -1.0), -1.0);
+ EXPECT_EQ(uniform_upper_bound<double>(IntervalClosedOpen, -2.0, -1.0), -1.0);
+
+ EXPECT_EQ(uniform_upper_bound(IntervalOpenClosed, -100, -1), -1);
+ EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, -100, -1), -1);
+ EXPECT_GT(uniform_upper_bound<float>(IntervalOpenClosed, -2.0, -1.0), -1.0);
+ EXPECT_GT(uniform_upper_bound<float>(IntervalClosedClosed, -2.0, -1.0), -1.0);
+ EXPECT_GT(uniform_upper_bound<double>(IntervalOpenClosed, -2.0, -1.0), -1.0);
+ EXPECT_GT(uniform_upper_bound<double>(IntervalClosedClosed, -2.0, -1.0),
+ -1.0);
+
+ EXPECT_GT(uniform_lower_bound(IntervalOpenClosed, 1.0, 2.0), 1.0);
+ EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, +0.0), 1.0);
+ EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, -0.0), 1.0);
+ EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, -1.0), 1.0);
+}
+
+TEST_F(UniformHelperTest, UniformBoundFunctionsIntBounds) {
+ // Verifies the saturating nature of uniform_lower_bound and
+ // uniform_upper_bound
+ constexpr IntervalOpenOpenTag IntervalOpenOpen;
+
+ // uint max.
+ constexpr auto m = (std::numeric_limits<uint64_t>::max)();
+
+ EXPECT_EQ(1, uniform_lower_bound(IntervalOpenOpen, 0u, 0u));
+ EXPECT_EQ(m, uniform_lower_bound(IntervalOpenOpen, m, m));
+ EXPECT_EQ(m, uniform_lower_bound(IntervalOpenOpen, m - 1, m - 1));
+ EXPECT_EQ(0, uniform_upper_bound(IntervalOpenOpen, 0u, 0u));
+ EXPECT_EQ(m - 1, uniform_upper_bound(IntervalOpenOpen, m, m));
+
+ // int min/max
+ constexpr auto l = (std::numeric_limits<int64_t>::min)();
+ constexpr auto r = (std::numeric_limits<int64_t>::max)();
+ EXPECT_EQ(1, uniform_lower_bound(IntervalOpenOpen, 0, 0));
+ EXPECT_EQ(l + 1, uniform_lower_bound(IntervalOpenOpen, l, l));
+ EXPECT_EQ(r, uniform_lower_bound(IntervalOpenOpen, r - 1, r - 1));
+ EXPECT_EQ(r, uniform_lower_bound(IntervalOpenOpen, r, r));
+ EXPECT_EQ(-1, uniform_upper_bound(IntervalOpenOpen, 0, 0));
+ EXPECT_EQ(l, uniform_upper_bound(IntervalOpenOpen, l, l));
+ EXPECT_EQ(r - 1, uniform_upper_bound(IntervalOpenOpen, r, r));
+}
+
+TEST_F(UniformHelperTest, UniformBoundFunctionsRealBounds) {
+ // absl::uniform_real_distribution natively assumes IntervalClosedOpen;
+ // use the inverse here so each bound has to change.
+ constexpr IntervalOpenClosedTag IntervalOpenClosed;
+
+ // Edge cases: the next value toward itself is itself.
+ EXPECT_EQ(1.0, uniform_lower_bound(IntervalOpenClosed, 1.0, 1.0));
+ EXPECT_EQ(1.0f, uniform_lower_bound(IntervalOpenClosed, 1.0f, 1.0f));
+
+ // rightmost and leftmost finite values.
+ constexpr auto r = (std::numeric_limits<double>::max)();
+ const auto re = std::nexttoward(r, 0.0);
+ constexpr auto l = -r;
+ const auto le = std::nexttoward(l, 0.0);
+
+ EXPECT_EQ(l, uniform_lower_bound(IntervalOpenClosed, l, l)); // (l,l)
+ EXPECT_EQ(r, uniform_lower_bound(IntervalOpenClosed, r, r)); // (r,r)
+ EXPECT_EQ(le, uniform_lower_bound(IntervalOpenClosed, l, r)); // (l,r)
+ EXPECT_EQ(le, uniform_lower_bound(IntervalOpenClosed, l, 0.0)); // (l, 0)
+ EXPECT_EQ(le, uniform_lower_bound(IntervalOpenClosed, l, le)); // (l, le)
+ EXPECT_EQ(r, uniform_lower_bound(IntervalOpenClosed, re, r)); // (re, r)
+
+ EXPECT_EQ(le, uniform_upper_bound(IntervalOpenClosed, l, l)); // (l,l)
+ EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, r, r)); // (r,r)
+ EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, l, r)); // (l,r)
+ EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, l, re)); // (l,re)
+ EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, 0.0, r)); // (0, r)
+ EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, re, r)); // (re, r)
+ EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, le, re)); // (le, re)
+
+ const double e = std::nextafter(1.0, 2.0); // 1 + epsilon
+ const double f = std::nextafter(1.0, 0.0); // 1 - epsilon
+
+ // (1.0, 1.0 + epsilon)
+ EXPECT_EQ(e, uniform_lower_bound(IntervalOpenClosed, 1.0, e));
+ EXPECT_EQ(std::nextafter(e, 2.0),
+ uniform_upper_bound(IntervalOpenClosed, 1.0, e));
+
+ // (1.0-epsilon, 1.0)
+ EXPECT_EQ(1.0, uniform_lower_bound(IntervalOpenClosed, f, 1.0));
+ EXPECT_EQ(e, uniform_upper_bound(IntervalOpenClosed, f, 1.0));
+
+ // denorm cases.
+ const double g = std::numeric_limits<double>::denorm_min();
+ const double h = std::nextafter(g, 1.0);
+
+ // (0, denorm_min)
+ EXPECT_EQ(g, uniform_lower_bound(IntervalOpenClosed, 0.0, g));
+ EXPECT_EQ(h, uniform_upper_bound(IntervalOpenClosed, 0.0, g));
+
+ // (denorm_min, 1.0)
+ EXPECT_EQ(h, uniform_lower_bound(IntervalOpenClosed, g, 1.0));
+ EXPECT_EQ(e, uniform_upper_bound(IntervalOpenClosed, g, 1.0));
+
+ // Edge cases: invalid bounds.
+ EXPECT_EQ(f, uniform_lower_bound(IntervalOpenClosed, 1.0, -1.0));
+}
+
+struct Invalid {};
+
+template <typename A, typename B>
+auto InferredUniformReturnT(int) -> uniform_inferred_return_t<A, B>;
+
+template <typename, typename>
+Invalid InferredUniformReturnT(...);
+
+// Given types <A, B, Expect>, CheckArgsInferType() verifies that
+//
+// uniform_inferred_return_t<A, B> and
+// uniform_inferred_return_t<B, A>
+//
+// returns the type "Expect".
+//
+// This interface can also be used to assert that a given inferred return types
+// are invalid. Writing:
+//
+// CheckArgsInferType<float, int, Invalid>()
+//
+// will assert that this overload does not exist.
+template <typename A, typename B, typename Expect>
+void CheckArgsInferType() {
+ static_assert(
+ absl::conjunction<
+ std::is_same<Expect, decltype(InferredUniformReturnT<A, B>(0))>,
+ std::is_same<Expect,
+ decltype(InferredUniformReturnT<B, A>(0))>>::value,
+ "");
+}
+
+TEST_F(UniformHelperTest, UniformTypeInference) {
+ // Infers common types.
+ CheckArgsInferType<uint16_t, uint16_t, uint16_t>();
+ CheckArgsInferType<uint32_t, uint32_t, uint32_t>();
+ CheckArgsInferType<uint64_t, uint64_t, uint64_t>();
+ CheckArgsInferType<int16_t, int16_t, int16_t>();
+ CheckArgsInferType<int32_t, int32_t, int32_t>();
+ CheckArgsInferType<int64_t, int64_t, int64_t>();
+ CheckArgsInferType<float, float, float>();
+ CheckArgsInferType<double, double, double>();
+
+ // Properly promotes uint16_t.
+ CheckArgsInferType<uint16_t, uint32_t, uint32_t>();
+ CheckArgsInferType<uint16_t, uint64_t, uint64_t>();
+ CheckArgsInferType<uint16_t, int32_t, int32_t>();
+ CheckArgsInferType<uint16_t, int64_t, int64_t>();
+ CheckArgsInferType<uint16_t, float, float>();
+ CheckArgsInferType<uint16_t, double, double>();
+
+ // Properly promotes int16_t.
+ CheckArgsInferType<int16_t, int32_t, int32_t>();
+ CheckArgsInferType<int16_t, int64_t, int64_t>();
+ CheckArgsInferType<int16_t, float, float>();
+ CheckArgsInferType<int16_t, double, double>();
+
+ // Invalid (u)int16_t-pairings do not compile.
+ // See "CheckArgsInferType" comments above, for how this is achieved.
+ CheckArgsInferType<uint16_t, int16_t, Invalid>();
+ CheckArgsInferType<int16_t, uint32_t, Invalid>();
+ CheckArgsInferType<int16_t, uint64_t, Invalid>();
+
+ // Properly promotes uint32_t.
+ CheckArgsInferType<uint32_t, uint64_t, uint64_t>();
+ CheckArgsInferType<uint32_t, int64_t, int64_t>();
+ CheckArgsInferType<uint32_t, double, double>();
+
+ // Properly promotes int32_t.
+ CheckArgsInferType<int32_t, int64_t, int64_t>();
+ CheckArgsInferType<int32_t, double, double>();
+
+ // Invalid (u)int32_t-pairings do not compile.
+ CheckArgsInferType<uint32_t, int32_t, Invalid>();
+ CheckArgsInferType<int32_t, uint64_t, Invalid>();
+ CheckArgsInferType<int32_t, float, Invalid>();
+ CheckArgsInferType<uint32_t, float, Invalid>();
+
+ // Invalid (u)int64_t-pairings do not compile.
+ CheckArgsInferType<uint64_t, int64_t, Invalid>();
+ CheckArgsInferType<int64_t, float, Invalid>();
+ CheckArgsInferType<int64_t, double, Invalid>();
+
+ // Properly promotes float.
+ CheckArgsInferType<float, double, double>();
+}
+
+} // namespace
diff --git a/third_party/abseil/absl/random/internal/wide_multiply.h b/third_party/abseil/absl/random/internal/wide_multiply.h
new file mode 100644
index 0000000..b6e6c4b
--- /dev/null
+++ b/third_party/abseil/absl/random/internal/wide_multiply.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
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_RANDOM_INTERNAL_WIDE_MULTIPLY_H_
+#define ABSL_RANDOM_INTERNAL_WIDE_MULTIPLY_H_
+
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+
+#if (defined(_WIN32) || defined(_WIN64)) && defined(_M_IA64)
+#include <intrin.h> // NOLINT(build/include_order)
+#pragma intrinsic(_umul128)
+#define ABSL_INTERNAL_USE_UMUL128 1
+#endif
+
+#include "absl/base/config.h"
+#include "absl/numeric/bits.h"
+#include "absl/numeric/int128.h"
+#include "absl/random/internal/traits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace random_internal {
+
+// Helper object to multiply two 64-bit values to a 128-bit value.
+// MultiplyU64ToU128 multiplies two 64-bit values to a 128-bit value.
+// If an intrinsic is available, it is used, otherwise use native 32-bit
+// multiplies to construct the result.
+inline absl::uint128 MultiplyU64ToU128(uint64_t a, uint64_t b) {
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+ return absl::uint128(static_cast<__uint128_t>(a) * b);
+#elif defined(ABSL_INTERNAL_USE_UMUL128)
+ // uint64_t * uint64_t => uint128 multiply using imul intrinsic on MSVC.
+ uint64_t high = 0;
+ const uint64_t low = _umul128(a, b, &high);
+ return absl::MakeUint128(high, low);
+#else
+ // uint128(a) * uint128(b) in emulated mode computes a full 128-bit x 128-bit
+ // multiply. However there are many cases where that is not necessary, and it
+ // is only necessary to support a 64-bit x 64-bit = 128-bit multiply. This is
+ // for those cases.
+ const uint64_t a00 = static_cast<uint32_t>(a);
+ const uint64_t a32 = a >> 32;
+ const uint64_t b00 = static_cast<uint32_t>(b);
+ const uint64_t b32 = b >> 32;
+
+ const uint64_t c00 = a00 * b00;
+ const uint64_t c32a = a00 * b32;
+ const uint64_t c32b = a32 * b00;
+ const uint64_t c64 = a32 * b32;
+
+ const uint32_t carry =
+ static_cast<uint32_t>(((c00 >> 32) + static_cast<uint32_t>(c32a) +
+ static_cast<uint32_t>(c32b)) >>
+ 32);
+
+ return absl::MakeUint128(c64 + (c32a >> 32) + (c32b >> 32) + carry,
+ c00 + (c32a << 32) + (c32b << 32));
+#endif
+}
+
+// wide_multiply<T> multiplies two N-bit values to a 2N-bit result.
+template <typename UIntType>
+struct wide_multiply {
+ static constexpr size_t kN = std::numeric_limits<UIntType>::digits;
+ using input_type = UIntType;
+ using result_type = typename random_internal::unsigned_bits<kN * 2>::type;
+
+ static result_type multiply(input_type a, input_type b) {
+ return static_cast<result_type>(a) * b;
+ }
+
+ static input_type hi(result_type r) { return r >> kN; }
+ static input_type lo(result_type r) { return r; }
+
+ static_assert(std::is_unsigned<UIntType>::value,
+ "Class-template wide_multiply<> argument must be unsigned.");
+};
+
+#ifndef ABSL_HAVE_INTRINSIC_INT128
+template <>
+struct wide_multiply<uint64_t> {
+ using input_type = uint64_t;
+ using result_type = absl::uint128;
+
+ static result_type multiply(uint64_t a, uint64_t b) {
+ return MultiplyU64ToU128(a, b);
+ }
+
+ static uint64_t hi(result_type r) { return absl::Uint128High64(r); }
+ static uint64_t lo(result_type r) { return absl::Uint128Low64(r); }
+};
+#endif
+
+} // namespace random_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_WIDE_MULTIPLY_H_
diff --git a/third_party/abseil/absl/random/internal/wide_multiply_test.cc b/third_party/abseil/absl/random/internal/wide_multiply_test.cc
new file mode 100644
index 0000000..e276cb5
--- /dev/null
+++ b/third_party/abseil/absl/random/internal/wide_multiply_test.cc
@@ -0,0 +1,65 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/random/internal/wide_multiply.h"
+
+#include "gtest/gtest.h"
+#include "absl/numeric/int128.h"
+
+using absl::random_internal::MultiplyU64ToU128;
+
+namespace {
+
+TEST(WideMultiplyTest, MultiplyU64ToU128Test) {
+ constexpr uint64_t k1 = 1;
+ constexpr uint64_t kMax = ~static_cast<uint64_t>(0);
+
+ EXPECT_EQ(absl::uint128(0), MultiplyU64ToU128(0, 0));
+
+ // Max uint64_t
+ EXPECT_EQ(MultiplyU64ToU128(kMax, kMax),
+ absl::MakeUint128(0xfffffffffffffffe, 0x0000000000000001));
+ EXPECT_EQ(absl::MakeUint128(0, kMax), MultiplyU64ToU128(kMax, 1));
+ EXPECT_EQ(absl::MakeUint128(0, kMax), MultiplyU64ToU128(1, kMax));
+ for (int i = 0; i < 64; ++i) {
+ EXPECT_EQ(absl::MakeUint128(0, kMax) << i,
+ MultiplyU64ToU128(kMax, k1 << i));
+ EXPECT_EQ(absl::MakeUint128(0, kMax) << i,
+ MultiplyU64ToU128(k1 << i, kMax));
+ }
+
+ // 1-bit x 1-bit.
+ for (int i = 0; i < 64; ++i) {
+ for (int j = 0; j < 64; ++j) {
+ EXPECT_EQ(absl::MakeUint128(0, 1) << (i + j),
+ MultiplyU64ToU128(k1 << i, k1 << j));
+ EXPECT_EQ(absl::MakeUint128(0, 1) << (i + j),
+ MultiplyU64ToU128(k1 << i, k1 << j));
+ }
+ }
+
+ // Verified multiplies
+ EXPECT_EQ(MultiplyU64ToU128(0xffffeeeeddddcccc, 0xbbbbaaaa99998888),
+ absl::MakeUint128(0xbbbb9e2692c5dddc, 0xc28f7531048d2c60));
+ EXPECT_EQ(MultiplyU64ToU128(0x0123456789abcdef, 0xfedcba9876543210),
+ absl::MakeUint128(0x0121fa00ad77d742, 0x2236d88fe5618cf0));
+ EXPECT_EQ(MultiplyU64ToU128(0x0123456789abcdef, 0xfdb97531eca86420),
+ absl::MakeUint128(0x0120ae99d26725fc, 0xce197f0ecac319e0));
+ EXPECT_EQ(MultiplyU64ToU128(0x97a87f4f261ba3f2, 0xfedcba9876543210),
+ absl::MakeUint128(0x96fbf1a8ae78d0ba, 0x5a6dd4b71f278320));
+ EXPECT_EQ(MultiplyU64ToU128(0xfedcba9876543210, 0xfdb97531eca86420),
+ absl::MakeUint128(0xfc98c6981a413e22, 0x342d0bbf48948200));
+}
+
+} // namespace
diff --git a/third_party/abseil/absl/random/log_uniform_int_distribution.h b/third_party/abseil/absl/random/log_uniform_int_distribution.h
index ac43416..43e1011 100644
--- a/third_party/abseil/absl/random/log_uniform_int_distribution.h
+++ b/third_party/abseil/absl/random/log_uniform_int_distribution.h
@@ -23,13 +23,15 @@
#include <ostream>
#include <type_traits>
-#include "absl/random/internal/distribution_impl.h"
+#include "absl/numeric/bits.h"
#include "absl/random/internal/fastmath.h"
+#include "absl/random/internal/generate_real.h"
#include "absl/random/internal/iostream_state_saver.h"
#include "absl/random/internal/traits.h"
#include "absl/random/uniform_int_distribution.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// log_uniform_int_distribution:
//
@@ -67,8 +69,10 @@
if (base_ == 2) {
// Determine where the first set bit is on range(), giving a log2(range)
// value which can be used to construct bounds.
- log_range_ = (std::min)(random_internal::LeadingSetBit(range()),
- std::numeric_limits<unsigned_type>::digits);
+ log_range_ =
+ (std::min)(bit_width(range()),
+ static_cast<unsigned_type>(
+ std::numeric_limits<unsigned_type>::digits));
} else {
// NOTE: Computing the logN(x) introduces error from 2 sources:
// 1. Conversion of int to double loses precision for values >=
@@ -192,13 +196,15 @@
const double r = std::pow(p.base(), d);
const double s = (r * p.base()) - 1.0;
- base_e = (r > (std::numeric_limits<unsigned_type>::max)())
- ? (std::numeric_limits<unsigned_type>::max)()
- : static_cast<unsigned_type>(r);
+ base_e =
+ (r > static_cast<double>((std::numeric_limits<unsigned_type>::max)()))
+ ? (std::numeric_limits<unsigned_type>::max)()
+ : static_cast<unsigned_type>(r);
- top_e = (s > (std::numeric_limits<unsigned_type>::max)())
- ? (std::numeric_limits<unsigned_type>::max)()
- : static_cast<unsigned_type>(s);
+ top_e =
+ (s > static_cast<double>((std::numeric_limits<unsigned_type>::max)()))
+ ? (std::numeric_limits<unsigned_type>::max)()
+ : static_cast<unsigned_type>(s);
}
const unsigned_type lo = (base_e >= p.range()) ? p.range() : base_e;
@@ -245,6 +251,7 @@
return is;
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_LOG_UNIFORM_INT_DISTRIBUTION_H_
diff --git a/third_party/abseil/absl/random/log_uniform_int_distribution_test.cc b/third_party/abseil/absl/random/log_uniform_int_distribution_test.cc
index 5270531..5e780d9 100644
--- a/third_party/abseil/absl/random/log_uniform_int_distribution_test.cc
+++ b/third_party/abseil/absl/random/log_uniform_int_distribution_test.cc
@@ -27,6 +27,7 @@
#include "absl/base/internal/raw_logging.h"
#include "absl/random/internal/chi_square.h"
#include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/pcg_engine.h"
#include "absl/random/internal/sequence_urbg.h"
#include "absl/random/random.h"
#include "absl/strings/str_cat.h"
@@ -121,7 +122,10 @@
// data generated by the log-uniform-int distribution.
double ChiSquaredTestImpl();
- absl::InsecureBitGen rng_;
+ // We use a fixed bit generator for distribution accuracy tests. This allows
+ // these tests to be deterministic, while still testing the qualify of the
+ // implementation.
+ absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
};
double LogUniformIntChiSquaredTest::ChiSquaredTestImpl() {
@@ -194,7 +198,6 @@
TEST_P(LogUniformIntChiSquaredTest, MultiTest) {
const int kTrials = 5;
-
int failures = 0;
for (int i = 0; i < kTrials; i++) {
double p_value = ChiSquaredTestImpl();
diff --git a/third_party/abseil/absl/random/mock_distributions.h b/third_party/abseil/absl/random/mock_distributions.h
new file mode 100644
index 0000000..764ab37
--- /dev/null
+++ b/third_party/abseil/absl/random/mock_distributions.h
@@ -0,0 +1,266 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: mock_distributions.h
+// -----------------------------------------------------------------------------
+//
+// This file contains mock distribution functions for use alongside an
+// `absl::MockingBitGen` object within the Googletest testing framework. Such
+// mocks are useful to provide deterministic values as return values within
+// (otherwise random) Abseil distribution functions.
+//
+// The return type of each function is a mock expectation object which
+// is used to set the match result.
+//
+// More information about the Googletest testing framework is available at
+// https://github.com/google/googletest
+//
+// EXPECT_CALL and ON_CALL need to be made within the same DLL component as
+// the call to absl::Uniform and related methods, otherwise mocking will fail
+// since the underlying implementation creates a type-specific pointer which
+// will be distinct across different DLL boundaries.
+//
+// Example:
+//
+// absl::MockingBitGen mock;
+// EXPECT_CALL(absl::MockUniform<int>(), Call(mock, 1, 1000))
+// .WillRepeatedly(testing::ReturnRoundRobin({20, 40}));
+//
+// EXPECT_EQ(absl::Uniform<int>(gen, 1, 1000), 20);
+// EXPECT_EQ(absl::Uniform<int>(gen, 1, 1000), 40);
+// EXPECT_EQ(absl::Uniform<int>(gen, 1, 1000), 20);
+// EXPECT_EQ(absl::Uniform<int>(gen, 1, 1000), 40);
+
+#ifndef ABSL_RANDOM_MOCK_DISTRIBUTIONS_H_
+#define ABSL_RANDOM_MOCK_DISTRIBUTIONS_H_
+
+#include <limits>
+#include <type_traits>
+#include <utility>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/meta/type_traits.h"
+#include "absl/random/distributions.h"
+#include "absl/random/internal/mock_overload_set.h"
+#include "absl/random/mocking_bit_gen.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// -----------------------------------------------------------------------------
+// absl::MockUniform
+// -----------------------------------------------------------------------------
+//
+// Matches calls to absl::Uniform.
+//
+// `absl::MockUniform` is a class template used in conjunction with Googletest's
+// `ON_CALL()` and `EXPECT_CALL()` macros. To use it, default-construct an
+// instance of it inside `ON_CALL()` or `EXPECT_CALL()`, and use `Call(...)` the
+// same way one would define mocks on a Googletest `MockFunction()`.
+//
+// Example:
+//
+// absl::MockingBitGen mock;
+// EXPECT_CALL(absl::MockUniform<uint32_t>(), Call(mock))
+// .WillOnce(Return(123456));
+// auto x = absl::Uniform<uint32_t>(mock);
+// assert(x == 123456)
+//
+template <typename R>
+using MockUniform = random_internal::MockOverloadSet<
+ random_internal::UniformDistributionWrapper<R>,
+ R(IntervalClosedOpenTag, MockingBitGen&, R, R),
+ R(IntervalClosedClosedTag, MockingBitGen&, R, R),
+ R(IntervalOpenOpenTag, MockingBitGen&, R, R),
+ R(IntervalOpenClosedTag, MockingBitGen&, R, R), R(MockingBitGen&, R, R),
+ R(MockingBitGen&)>;
+
+// -----------------------------------------------------------------------------
+// absl::MockBernoulli
+// -----------------------------------------------------------------------------
+//
+// Matches calls to absl::Bernoulli.
+//
+// `absl::MockBernoulli` is a class used in conjunction with Googletest's
+// `ON_CALL()` and `EXPECT_CALL()` macros. To use it, default-construct an
+// instance of it inside `ON_CALL()` or `EXPECT_CALL()`, and use `Call(...)` the
+// same way one would define mocks on a Googletest `MockFunction()`.
+//
+// Example:
+//
+// absl::MockingBitGen mock;
+// EXPECT_CALL(absl::MockBernoulli(), Call(mock, testing::_))
+// .WillOnce(Return(false));
+// assert(absl::Bernoulli(mock, 0.5) == false);
+//
+using MockBernoulli =
+ random_internal::MockOverloadSet<absl::bernoulli_distribution,
+ bool(MockingBitGen&, double)>;
+
+// -----------------------------------------------------------------------------
+// absl::MockBeta
+// -----------------------------------------------------------------------------
+//
+// Matches calls to absl::Beta.
+//
+// `absl::MockBeta` is a class used in conjunction with Googletest's `ON_CALL()`
+// and `EXPECT_CALL()` macros. To use it, default-construct an instance of it
+// inside `ON_CALL()` or `EXPECT_CALL()`, and use `Call(...)` the same way one
+// would define mocks on a Googletest `MockFunction()`.
+//
+// Example:
+//
+// absl::MockingBitGen mock;
+// EXPECT_CALL(absl::MockBeta(), Call(mock, 3.0, 2.0))
+// .WillOnce(Return(0.567));
+// auto x = absl::Beta<double>(mock, 3.0, 2.0);
+// assert(x == 0.567);
+//
+template <typename RealType>
+using MockBeta =
+ random_internal::MockOverloadSet<absl::beta_distribution<RealType>,
+ RealType(MockingBitGen&, RealType,
+ RealType)>;
+
+// -----------------------------------------------------------------------------
+// absl::MockExponential
+// -----------------------------------------------------------------------------
+//
+// Matches calls to absl::Exponential.
+//
+// `absl::MockExponential` is a class template used in conjunction with
+// Googletest's `ON_CALL()` and `EXPECT_CALL()` macros. To use it,
+// default-construct an instance of it inside `ON_CALL()` or `EXPECT_CALL()`,
+// and use `Call(...)` the same way one would define mocks on a
+// Googletest `MockFunction()`.
+//
+// Example:
+//
+// absl::MockingBitGen mock;
+// EXPECT_CALL(absl::MockExponential<double>(), Call(mock, 0.5))
+// .WillOnce(Return(12.3456789));
+// auto x = absl::Exponential<double>(mock, 0.5);
+// assert(x == 12.3456789)
+//
+template <typename RealType>
+using MockExponential =
+ random_internal::MockOverloadSet<absl::exponential_distribution<RealType>,
+ RealType(MockingBitGen&, RealType)>;
+
+// -----------------------------------------------------------------------------
+// absl::MockGaussian
+// -----------------------------------------------------------------------------
+//
+// Matches calls to absl::Gaussian.
+//
+// `absl::MockGaussian` is a class template used in conjunction with
+// Googletest's `ON_CALL()` and `EXPECT_CALL()` macros. To use it,
+// default-construct an instance of it inside `ON_CALL()` or `EXPECT_CALL()`,
+// and use `Call(...)` the same way one would define mocks on a
+// Googletest `MockFunction()`.
+//
+// Example:
+//
+// absl::MockingBitGen mock;
+// EXPECT_CALL(absl::MockGaussian<double>(), Call(mock, 16.3, 3.3))
+// .WillOnce(Return(12.3456789));
+// auto x = absl::Gaussian<double>(mock, 16.3, 3.3);
+// assert(x == 12.3456789)
+//
+template <typename RealType>
+using MockGaussian =
+ random_internal::MockOverloadSet<absl::gaussian_distribution<RealType>,
+ RealType(MockingBitGen&, RealType,
+ RealType)>;
+
+// -----------------------------------------------------------------------------
+// absl::MockLogUniform
+// -----------------------------------------------------------------------------
+//
+// Matches calls to absl::LogUniform.
+//
+// `absl::MockLogUniform` is a class template used in conjunction with
+// Googletest's `ON_CALL()` and `EXPECT_CALL()` macros. To use it,
+// default-construct an instance of it inside `ON_CALL()` or `EXPECT_CALL()`,
+// and use `Call(...)` the same way one would define mocks on a
+// Googletest `MockFunction()`.
+//
+// Example:
+//
+// absl::MockingBitGen mock;
+// EXPECT_CALL(absl::MockLogUniform<int>(), Call(mock, 10, 10000, 10))
+// .WillOnce(Return(1221));
+// auto x = absl::LogUniform<int>(mock, 10, 10000, 10);
+// assert(x == 1221)
+//
+template <typename IntType>
+using MockLogUniform = random_internal::MockOverloadSet<
+ absl::log_uniform_int_distribution<IntType>,
+ IntType(MockingBitGen&, IntType, IntType, IntType)>;
+
+// -----------------------------------------------------------------------------
+// absl::MockPoisson
+// -----------------------------------------------------------------------------
+//
+// Matches calls to absl::Poisson.
+//
+// `absl::MockPoisson` is a class template used in conjunction with Googletest's
+// `ON_CALL()` and `EXPECT_CALL()` macros. To use it, default-construct an
+// instance of it inside `ON_CALL()` or `EXPECT_CALL()`, and use `Call(...)` the
+// same way one would define mocks on a Googletest `MockFunction()`.
+//
+// Example:
+//
+// absl::MockingBitGen mock;
+// EXPECT_CALL(absl::MockPoisson<int>(), Call(mock, 2.0))
+// .WillOnce(Return(1221));
+// auto x = absl::Poisson<int>(mock, 2.0);
+// assert(x == 1221)
+//
+template <typename IntType>
+using MockPoisson =
+ random_internal::MockOverloadSet<absl::poisson_distribution<IntType>,
+ IntType(MockingBitGen&, double)>;
+
+// -----------------------------------------------------------------------------
+// absl::MockZipf
+// -----------------------------------------------------------------------------
+//
+// Matches calls to absl::Zipf.
+//
+// `absl::MockZipf` is a class template used in conjunction with Googletest's
+// `ON_CALL()` and `EXPECT_CALL()` macros. To use it, default-construct an
+// instance of it inside `ON_CALL()` or `EXPECT_CALL()`, and use `Call(...)` the
+// same way one would define mocks on a Googletest `MockFunction()`.
+//
+// Example:
+//
+// absl::MockingBitGen mock;
+// EXPECT_CALL(absl::MockZipf<int>(), Call(mock, 1000000, 2.0, 1.0))
+// .WillOnce(Return(1221));
+// auto x = absl::Zipf<int>(mock, 1000000, 2.0, 1.0);
+// assert(x == 1221)
+//
+template <typename IntType>
+using MockZipf =
+ random_internal::MockOverloadSet<absl::zipf_distribution<IntType>,
+ IntType(MockingBitGen&, IntType, double,
+ double)>;
+
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_RANDOM_MOCK_DISTRIBUTIONS_H_
diff --git a/third_party/abseil/absl/random/mock_distributions_test.cc b/third_party/abseil/absl/random/mock_distributions_test.cc
new file mode 100644
index 0000000..de23baf
--- /dev/null
+++ b/third_party/abseil/absl/random/mock_distributions_test.cc
@@ -0,0 +1,72 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/random/mock_distributions.h"
+
+#include "gtest/gtest.h"
+#include "absl/random/mocking_bit_gen.h"
+#include "absl/random/random.h"
+
+namespace {
+using ::testing::Return;
+
+TEST(MockDistributions, Examples) {
+ absl::MockingBitGen gen;
+
+ EXPECT_NE(absl::Uniform<int>(gen, 1, 1000000), 20);
+ EXPECT_CALL(absl::MockUniform<int>(), Call(gen, 1, 1000000))
+ .WillOnce(Return(20));
+ EXPECT_EQ(absl::Uniform<int>(gen, 1, 1000000), 20);
+
+ EXPECT_NE(absl::Uniform<double>(gen, 0.0, 100.0), 5.0);
+ EXPECT_CALL(absl::MockUniform<double>(), Call(gen, 0.0, 100.0))
+ .WillOnce(Return(5.0));
+ EXPECT_EQ(absl::Uniform<double>(gen, 0.0, 100.0), 5.0);
+
+ EXPECT_NE(absl::Exponential<double>(gen, 1.0), 42);
+ EXPECT_CALL(absl::MockExponential<double>(), Call(gen, 1.0))
+ .WillOnce(Return(42));
+ EXPECT_EQ(absl::Exponential<double>(gen, 1.0), 42);
+
+ EXPECT_NE(absl::Poisson<int>(gen, 1.0), 500);
+ EXPECT_CALL(absl::MockPoisson<int>(), Call(gen, 1.0)).WillOnce(Return(500));
+ EXPECT_EQ(absl::Poisson<int>(gen, 1.0), 500);
+
+ EXPECT_NE(absl::Bernoulli(gen, 0.000001), true);
+ EXPECT_CALL(absl::MockBernoulli(), Call(gen, 0.000001))
+ .WillOnce(Return(true));
+ EXPECT_EQ(absl::Bernoulli(gen, 0.000001), true);
+
+ EXPECT_NE(absl::Beta<double>(gen, 3.0, 2.0), 0.567);
+ EXPECT_CALL(absl::MockBeta<double>(), Call(gen, 3.0, 2.0))
+ .WillOnce(Return(0.567));
+ EXPECT_EQ(absl::Beta<double>(gen, 3.0, 2.0), 0.567);
+
+ EXPECT_NE(absl::Zipf<int>(gen, 1000000, 2.0, 1.0), 1221);
+ EXPECT_CALL(absl::MockZipf<int>(), Call(gen, 1000000, 2.0, 1.0))
+ .WillOnce(Return(1221));
+ EXPECT_EQ(absl::Zipf<int>(gen, 1000000, 2.0, 1.0), 1221);
+
+ EXPECT_NE(absl::Gaussian<double>(gen, 0.0, 1.0), 0.001);
+ EXPECT_CALL(absl::MockGaussian<double>(), Call(gen, 0.0, 1.0))
+ .WillOnce(Return(0.001));
+ EXPECT_EQ(absl::Gaussian<double>(gen, 0.0, 1.0), 0.001);
+
+ EXPECT_NE(absl::LogUniform<int>(gen, 0, 1000000, 2), 2040);
+ EXPECT_CALL(absl::MockLogUniform<int>(), Call(gen, 0, 1000000, 2))
+ .WillOnce(Return(2040));
+ EXPECT_EQ(absl::LogUniform<int>(gen, 0, 1000000, 2), 2040);
+}
+
+} // namespace
diff --git a/third_party/abseil/absl/random/mocking_bit_gen.h b/third_party/abseil/absl/random/mocking_bit_gen.h
new file mode 100644
index 0000000..6d2f2c8
--- /dev/null
+++ b/third_party/abseil/absl/random/mocking_bit_gen.h
@@ -0,0 +1,228 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// mocking_bit_gen.h
+// -----------------------------------------------------------------------------
+//
+// This file includes an `absl::MockingBitGen` class to use as a mock within the
+// Googletest testing framework. Such a mock is useful to provide deterministic
+// values as return values within (otherwise random) Abseil distribution
+// functions. Such determinism within a mock is useful within testing frameworks
+// to test otherwise indeterminate APIs.
+//
+// More information about the Googletest testing framework is available at
+// https://github.com/google/googletest
+
+#ifndef ABSL_RANDOM_MOCKING_BIT_GEN_H_
+#define ABSL_RANDOM_MOCKING_BIT_GEN_H_
+
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/fast_type_id.h"
+#include "absl/container/flat_hash_map.h"
+#include "absl/meta/type_traits.h"
+#include "absl/random/distributions.h"
+#include "absl/random/internal/distribution_caller.h"
+#include "absl/random/random.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_join.h"
+#include "absl/types/span.h"
+#include "absl/types/variant.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+namespace random_internal {
+template <typename>
+struct DistributionCaller;
+class MockHelpers;
+
+} // namespace random_internal
+class BitGenRef;
+
+// MockingBitGen
+//
+// `absl::MockingBitGen` is a mock Uniform Random Bit Generator (URBG) class
+// which can act in place of an `absl::BitGen` URBG within tests using the
+// Googletest testing framework.
+//
+// Usage:
+//
+// Use an `absl::MockingBitGen` along with a mock distribution object (within
+// mock_distributions.h) inside Googletest constructs such as ON_CALL(),
+// EXPECT_TRUE(), etc. to produce deterministic results conforming to the
+// distribution's API contract.
+//
+// Example:
+//
+// // Mock a call to an `absl::Bernoulli` distribution using Googletest
+// absl::MockingBitGen bitgen;
+//
+// ON_CALL(absl::MockBernoulli(), Call(bitgen, 0.5))
+// .WillByDefault(testing::Return(true));
+// EXPECT_TRUE(absl::Bernoulli(bitgen, 0.5));
+//
+// // Mock a call to an `absl::Uniform` distribution within Googletest
+// absl::MockingBitGen bitgen;
+//
+// ON_CALL(absl::MockUniform<int>(), Call(bitgen, testing::_, testing::_))
+// .WillByDefault([] (int low, int high) {
+// return (low + high) / 2;
+// });
+//
+// EXPECT_EQ(absl::Uniform<int>(gen, 0, 10), 5);
+// EXPECT_EQ(absl::Uniform<int>(gen, 30, 40), 35);
+//
+// At this time, only mock distributions supplied within the Abseil random
+// library are officially supported.
+//
+// EXPECT_CALL and ON_CALL need to be made within the same DLL component as
+// the call to absl::Uniform and related methods, otherwise mocking will fail
+// since the underlying implementation creates a type-specific pointer which
+// will be distinct across different DLL boundaries.
+//
+class MockingBitGen {
+ public:
+ MockingBitGen() = default;
+
+ ~MockingBitGen() {
+ for (const auto& del : deleters_) del();
+ }
+
+ // URBG interface
+ using result_type = absl::BitGen::result_type;
+
+ static constexpr result_type(min)() { return (absl::BitGen::min)(); }
+ static constexpr result_type(max)() { return (absl::BitGen::max)(); }
+ result_type operator()() { return gen_(); }
+
+ private:
+ using match_impl_fn = void (*)(void* mock_fn, void* t_erased_arg_tuple,
+ void* t_erased_result);
+
+ struct MockData {
+ void* mock_fn = nullptr;
+ match_impl_fn match_impl = nullptr;
+ };
+
+ // GetMockFnType returns the testing::MockFunction for a result and tuple.
+ // This method only exists for type deduction and is otherwise unimplemented.
+ template <typename ResultT, typename... Args>
+ static auto GetMockFnType(ResultT, std::tuple<Args...>)
+ -> ::testing::MockFunction<ResultT(Args...)>;
+
+ // MockFnCaller is a helper method for use with absl::apply to
+ // apply an ArgTupleT to a compatible MockFunction.
+ // NOTE: MockFnCaller is essentially equivalent to the lambda:
+ // [fn](auto... args) { return fn->Call(std::move(args)...)}
+ // however that fails to build on some supported platforms.
+ template <typename ResultT, typename MockFnType, typename Tuple>
+ struct MockFnCaller;
+ // specialization for std::tuple.
+ template <typename ResultT, typename MockFnType, typename... Args>
+ struct MockFnCaller<ResultT, MockFnType, std::tuple<Args...>> {
+ MockFnType* fn;
+ inline ResultT operator()(Args... args) {
+ return fn->Call(std::move(args)...);
+ }
+ };
+
+ // MockingBitGen::RegisterMock
+ //
+ // RegisterMock<ResultT, ArgTupleT>(FastTypeIdType) is the main extension
+ // point for extending the MockingBitGen framework. It provides a mechanism to
+ // install a mock expectation for a function like ResultT(Args...) keyed by
+ // type_idex onto the MockingBitGen context. The key is that the type_index
+ // used to register must match the type index used to call the mock.
+ //
+ // The returned MockFunction<...> type can be used to setup additional
+ // distribution parameters of the expectation.
+ template <typename ResultT, typename ArgTupleT>
+ auto RegisterMock(base_internal::FastTypeIdType type)
+ -> decltype(GetMockFnType(std::declval<ResultT>(),
+ std::declval<ArgTupleT>()))& {
+ using MockFnType = decltype(
+ GetMockFnType(std::declval<ResultT>(), std::declval<ArgTupleT>()));
+ auto& mock = mocks_[type];
+ if (!mock.mock_fn) {
+ auto* mock_fn = new MockFnType;
+ mock.mock_fn = mock_fn;
+ mock.match_impl = &MatchImpl<ResultT, ArgTupleT>;
+ deleters_.emplace_back([mock_fn] { delete mock_fn; });
+ }
+ return *static_cast<MockFnType*>(mock.mock_fn);
+ }
+
+ // MockingBitGen::MatchImpl<> is a dispatch function which converts the
+ // generic type-erased parameters into a specific mock invocation call.
+ // Requires tuple_args to point to a ArgTupleT, which is a std::tuple<Args...>
+ // used to invoke the mock function.
+ // Requires result to point to a ResultT, which is the result of the call.
+ template <typename ResultT, typename ArgTupleT>
+ static void MatchImpl(/*MockFnType<ResultT, Args...>*/ void* mock_fn,
+ /*ArgTupleT*/ void* args_tuple,
+ /*ResultT*/ void* result) {
+ using MockFnType = decltype(
+ GetMockFnType(std::declval<ResultT>(), std::declval<ArgTupleT>()));
+ *static_cast<ResultT*>(result) = absl::apply(
+ MockFnCaller<ResultT, MockFnType, ArgTupleT>{
+ static_cast<MockFnType*>(mock_fn)},
+ *static_cast<ArgTupleT*>(args_tuple));
+ }
+
+ // MockingBitGen::InvokeMock
+ //
+ // InvokeMock(FastTypeIdType, args, result) is the entrypoint for invoking
+ // mocks registered on MockingBitGen.
+ //
+ // When no mocks are registered on the provided FastTypeIdType, returns false.
+ // Otherwise attempts to invoke the mock function ResultT(Args...) that
+ // was previously registered via the type_index.
+ // Requires tuple_args to point to a ArgTupleT, which is a std::tuple<Args...>
+ // used to invoke the mock function.
+ // Requires result to point to a ResultT, which is the result of the call.
+ inline bool InvokeMock(base_internal::FastTypeIdType type, void* args_tuple,
+ void* result) {
+ // Trigger a mock, if there exists one that matches `param`.
+ auto it = mocks_.find(type);
+ if (it == mocks_.end()) return false;
+ auto* mock_data = static_cast<MockData*>(&it->second);
+ mock_data->match_impl(mock_data->mock_fn, args_tuple, result);
+ return true;
+ }
+
+ absl::flat_hash_map<base_internal::FastTypeIdType, MockData> mocks_;
+ std::vector<std::function<void()>> deleters_;
+ absl::BitGen gen_;
+
+ template <typename>
+ friend struct ::absl::random_internal::DistributionCaller; // for InvokeMock
+ friend class ::absl::BitGenRef; // for InvokeMock
+ friend class ::absl::random_internal::MockHelpers; // for RegisterMock,
+ // InvokeMock
+};
+
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_RANDOM_MOCKING_BIT_GEN_H_
diff --git a/third_party/abseil/absl/random/mocking_bit_gen_test.cc b/third_party/abseil/absl/random/mocking_bit_gen_test.cc
new file mode 100644
index 0000000..f0ffc9a
--- /dev/null
+++ b/third_party/abseil/absl/random/mocking_bit_gen_test.cc
@@ -0,0 +1,347 @@
+//
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#include "absl/random/mocking_bit_gen.h"
+
+#include <numeric>
+#include <random>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest-spi.h"
+#include "gtest/gtest.h"
+#include "absl/random/bit_gen_ref.h"
+#include "absl/random/mock_distributions.h"
+#include "absl/random/random.h"
+
+namespace {
+using ::testing::Ne;
+using ::testing::Return;
+
+TEST(BasicMocking, AllDistributionsAreOverridable) {
+ absl::MockingBitGen gen;
+
+ EXPECT_NE(absl::Uniform<int>(gen, 1, 1000000), 20);
+ EXPECT_CALL(absl::MockUniform<int>(), Call(gen, 1, 1000000))
+ .WillOnce(Return(20));
+ EXPECT_EQ(absl::Uniform<int>(gen, 1, 1000000), 20);
+
+ EXPECT_NE(absl::Uniform<double>(gen, 0.0, 100.0), 5.0);
+ EXPECT_CALL(absl::MockUniform<double>(), Call(gen, 0.0, 100.0))
+ .WillOnce(Return(5.0));
+ EXPECT_EQ(absl::Uniform<double>(gen, 0.0, 100.0), 5.0);
+
+ EXPECT_NE(absl::Exponential<double>(gen, 1.0), 42);
+ EXPECT_CALL(absl::MockExponential<double>(), Call(gen, 1.0))
+ .WillOnce(Return(42));
+ EXPECT_EQ(absl::Exponential<double>(gen, 1.0), 42);
+
+ EXPECT_NE(absl::Poisson<int>(gen, 1.0), 500);
+ EXPECT_CALL(absl::MockPoisson<int>(), Call(gen, 1.0)).WillOnce(Return(500));
+ EXPECT_EQ(absl::Poisson<int>(gen, 1.0), 500);
+
+ EXPECT_NE(absl::Bernoulli(gen, 0.000001), true);
+ EXPECT_CALL(absl::MockBernoulli(), Call(gen, 0.000001))
+ .WillOnce(Return(true));
+ EXPECT_EQ(absl::Bernoulli(gen, 0.000001), true);
+
+ EXPECT_NE(absl::Zipf<int>(gen, 1000000, 2.0, 1.0), 1221);
+ EXPECT_CALL(absl::MockZipf<int>(), Call(gen, 1000000, 2.0, 1.0))
+ .WillOnce(Return(1221));
+ EXPECT_EQ(absl::Zipf<int>(gen, 1000000, 2.0, 1.0), 1221);
+
+ EXPECT_NE(absl::Gaussian<double>(gen, 0.0, 1.0), 0.001);
+ EXPECT_CALL(absl::MockGaussian<double>(), Call(gen, 0.0, 1.0))
+ .WillOnce(Return(0.001));
+ EXPECT_EQ(absl::Gaussian<double>(gen, 0.0, 1.0), 0.001);
+
+ EXPECT_NE(absl::LogUniform<int>(gen, 0, 1000000, 2), 500000);
+ EXPECT_CALL(absl::MockLogUniform<int>(), Call(gen, 0, 1000000, 2))
+ .WillOnce(Return(500000));
+ EXPECT_EQ(absl::LogUniform<int>(gen, 0, 1000000, 2), 500000);
+}
+
+TEST(BasicMocking, OnDistribution) {
+ absl::MockingBitGen gen;
+
+ EXPECT_NE(absl::Uniform<int>(gen, 1, 1000000), 20);
+ ON_CALL(absl::MockUniform<int>(), Call(gen, 1, 1000000))
+ .WillByDefault(Return(20));
+ EXPECT_EQ(absl::Uniform<int>(gen, 1, 1000000), 20);
+
+ EXPECT_NE(absl::Uniform<double>(gen, 0.0, 100.0), 5.0);
+ ON_CALL(absl::MockUniform<double>(), Call(gen, 0.0, 100.0))
+ .WillByDefault(Return(5.0));
+ EXPECT_EQ(absl::Uniform<double>(gen, 0.0, 100.0), 5.0);
+
+ EXPECT_NE(absl::Exponential<double>(gen, 1.0), 42);
+ ON_CALL(absl::MockExponential<double>(), Call(gen, 1.0))
+ .WillByDefault(Return(42));
+ EXPECT_EQ(absl::Exponential<double>(gen, 1.0), 42);
+
+ EXPECT_NE(absl::Poisson<int>(gen, 1.0), 500);
+ ON_CALL(absl::MockPoisson<int>(), Call(gen, 1.0)).WillByDefault(Return(500));
+ EXPECT_EQ(absl::Poisson<int>(gen, 1.0), 500);
+
+ EXPECT_NE(absl::Bernoulli(gen, 0.000001), true);
+ ON_CALL(absl::MockBernoulli(), Call(gen, 0.000001))
+ .WillByDefault(Return(true));
+ EXPECT_EQ(absl::Bernoulli(gen, 0.000001), true);
+
+ EXPECT_NE(absl::Zipf<int>(gen, 1000000, 2.0, 1.0), 1221);
+ ON_CALL(absl::MockZipf<int>(), Call(gen, 1000000, 2.0, 1.0))
+ .WillByDefault(Return(1221));
+ EXPECT_EQ(absl::Zipf<int>(gen, 1000000, 2.0, 1.0), 1221);
+
+ EXPECT_NE(absl::Gaussian<double>(gen, 0.0, 1.0), 0.001);
+ ON_CALL(absl::MockGaussian<double>(), Call(gen, 0.0, 1.0))
+ .WillByDefault(Return(0.001));
+ EXPECT_EQ(absl::Gaussian<double>(gen, 0.0, 1.0), 0.001);
+
+ EXPECT_NE(absl::LogUniform<int>(gen, 0, 1000000, 2), 2040);
+ ON_CALL(absl::MockLogUniform<int>(), Call(gen, 0, 1000000, 2))
+ .WillByDefault(Return(2040));
+ EXPECT_EQ(absl::LogUniform<int>(gen, 0, 1000000, 2), 2040);
+}
+
+TEST(BasicMocking, GMockMatchers) {
+ absl::MockingBitGen gen;
+
+ EXPECT_NE(absl::Zipf<int>(gen, 1000000, 2.0, 1.0), 1221);
+ ON_CALL(absl::MockZipf<int>(), Call(gen, 1000000, 2.0, 1.0))
+ .WillByDefault(Return(1221));
+ EXPECT_EQ(absl::Zipf<int>(gen, 1000000, 2.0, 1.0), 1221);
+}
+
+TEST(BasicMocking, OverridesWithMultipleGMockExpectations) {
+ absl::MockingBitGen gen;
+
+ EXPECT_CALL(absl::MockUniform<int>(), Call(gen, 1, 10000))
+ .WillOnce(Return(20))
+ .WillOnce(Return(40))
+ .WillOnce(Return(60));
+ EXPECT_EQ(absl::Uniform(gen, 1, 10000), 20);
+ EXPECT_EQ(absl::Uniform(gen, 1, 10000), 40);
+ EXPECT_EQ(absl::Uniform(gen, 1, 10000), 60);
+}
+
+TEST(BasicMocking, DefaultArgument) {
+ absl::MockingBitGen gen;
+
+ ON_CALL(absl::MockExponential<double>(), Call(gen, 1.0))
+ .WillByDefault(Return(200));
+
+ EXPECT_EQ(absl::Exponential<double>(gen), 200);
+ EXPECT_EQ(absl::Exponential<double>(gen, 1.0), 200);
+}
+
+TEST(BasicMocking, MultipleGenerators) {
+ auto get_value = [](absl::BitGenRef gen_ref) {
+ return absl::Uniform(gen_ref, 1, 1000000);
+ };
+ absl::MockingBitGen unmocked_generator;
+ absl::MockingBitGen mocked_with_3;
+ absl::MockingBitGen mocked_with_11;
+
+ EXPECT_CALL(absl::MockUniform<int>(), Call(mocked_with_3, 1, 1000000))
+ .WillOnce(Return(3))
+ .WillRepeatedly(Return(17));
+ EXPECT_CALL(absl::MockUniform<int>(), Call(mocked_with_11, 1, 1000000))
+ .WillOnce(Return(11))
+ .WillRepeatedly(Return(17));
+
+ // Ensure that unmocked generator generates neither value.
+ int unmocked_value = get_value(unmocked_generator);
+ EXPECT_NE(unmocked_value, 3);
+ EXPECT_NE(unmocked_value, 11);
+ // Mocked generators should generate their mocked values.
+ EXPECT_EQ(get_value(mocked_with_3), 3);
+ EXPECT_EQ(get_value(mocked_with_11), 11);
+ // Ensure that the mocks have expired.
+ EXPECT_NE(get_value(mocked_with_3), 3);
+ EXPECT_NE(get_value(mocked_with_11), 11);
+}
+
+TEST(BasicMocking, MocksNotTrigeredForIncorrectTypes) {
+ absl::MockingBitGen gen;
+ EXPECT_CALL(absl::MockUniform<uint32_t>(), Call(gen)).WillOnce(Return(42));
+
+ EXPECT_NE(absl::Uniform<uint16_t>(gen), 42); // Not mocked
+ EXPECT_EQ(absl::Uniform<uint32_t>(gen), 42); // Mock triggered
+}
+
+TEST(BasicMocking, FailsOnUnsatisfiedMocks) {
+ EXPECT_NONFATAL_FAILURE(
+ []() {
+ absl::MockingBitGen gen;
+ EXPECT_CALL(absl::MockExponential<double>(), Call(gen, 1.0))
+ .WillOnce(Return(3.0));
+ // Does not call absl::Exponential().
+ }(),
+ "unsatisfied and active");
+}
+
+TEST(OnUniform, RespectsUniformIntervalSemantics) {
+ absl::MockingBitGen gen;
+
+ EXPECT_CALL(absl::MockUniform<int>(),
+ Call(absl::IntervalClosed, gen, 1, 1000000))
+ .WillOnce(Return(301));
+ EXPECT_NE(absl::Uniform(gen, 1, 1000000), 301); // Not mocked
+ EXPECT_EQ(absl::Uniform(absl::IntervalClosed, gen, 1, 1000000), 301);
+}
+
+TEST(OnUniform, RespectsNoArgUnsignedShorthand) {
+ absl::MockingBitGen gen;
+ EXPECT_CALL(absl::MockUniform<uint32_t>(), Call(gen)).WillOnce(Return(42));
+ EXPECT_EQ(absl::Uniform<uint32_t>(gen), 42);
+}
+
+TEST(RepeatedlyModifier, ForceSnakeEyesForManyDice) {
+ auto roll_some_dice = [](absl::BitGenRef gen_ref) {
+ std::vector<int> results(16);
+ for (auto& r : results) {
+ r = absl::Uniform(absl::IntervalClosed, gen_ref, 1, 6);
+ }
+ return results;
+ };
+ std::vector<int> results;
+ absl::MockingBitGen gen;
+
+ // Without any mocked calls, not all dice roll a "6".
+ results = roll_some_dice(gen);
+ EXPECT_LT(std::accumulate(std::begin(results), std::end(results), 0),
+ results.size() * 6);
+
+ // Verify that we can force all "6"-rolls, with mocking.
+ ON_CALL(absl::MockUniform<int>(), Call(absl::IntervalClosed, gen, 1, 6))
+ .WillByDefault(Return(6));
+ results = roll_some_dice(gen);
+ EXPECT_EQ(std::accumulate(std::begin(results), std::end(results), 0),
+ results.size() * 6);
+}
+
+TEST(WillOnce, DistinctCounters) {
+ absl::MockingBitGen gen;
+ EXPECT_CALL(absl::MockUniform<int>(), Call(gen, 1, 1000000))
+ .Times(3)
+ .WillRepeatedly(Return(0));
+ EXPECT_CALL(absl::MockUniform<int>(), Call(gen, 1000001, 2000000))
+ .Times(3)
+ .WillRepeatedly(Return(1));
+ EXPECT_EQ(absl::Uniform(gen, 1000001, 2000000), 1);
+ EXPECT_EQ(absl::Uniform(gen, 1, 1000000), 0);
+ EXPECT_EQ(absl::Uniform(gen, 1000001, 2000000), 1);
+ EXPECT_EQ(absl::Uniform(gen, 1, 1000000), 0);
+ EXPECT_EQ(absl::Uniform(gen, 1000001, 2000000), 1);
+ EXPECT_EQ(absl::Uniform(gen, 1, 1000000), 0);
+}
+
+TEST(TimesModifier, ModifierSaturatesAndExpires) {
+ EXPECT_NONFATAL_FAILURE(
+ []() {
+ absl::MockingBitGen gen;
+ EXPECT_CALL(absl::MockUniform<int>(), Call(gen, 1, 1000000))
+ .Times(3)
+ .WillRepeatedly(Return(15))
+ .RetiresOnSaturation();
+
+ EXPECT_EQ(absl::Uniform(gen, 1, 1000000), 15);
+ EXPECT_EQ(absl::Uniform(gen, 1, 1000000), 15);
+ EXPECT_EQ(absl::Uniform(gen, 1, 1000000), 15);
+ // Times(3) has expired - Should get a different value now.
+
+ EXPECT_NE(absl::Uniform(gen, 1, 1000000), 15);
+ }(),
+ "");
+}
+
+TEST(TimesModifier, Times0) {
+ absl::MockingBitGen gen;
+ EXPECT_CALL(absl::MockBernoulli(), Call(gen, 0.0)).Times(0);
+ EXPECT_CALL(absl::MockPoisson<int>(), Call(gen, 1.0)).Times(0);
+}
+
+TEST(AnythingMatcher, MatchesAnyArgument) {
+ using testing::_;
+
+ {
+ absl::MockingBitGen gen;
+ ON_CALL(absl::MockUniform<int>(), Call(absl::IntervalClosed, gen, _, 1000))
+ .WillByDefault(Return(11));
+ ON_CALL(absl::MockUniform<int>(),
+ Call(absl::IntervalClosed, gen, _, Ne(1000)))
+ .WillByDefault(Return(99));
+
+ EXPECT_EQ(absl::Uniform(absl::IntervalClosed, gen, 10, 1000000), 99);
+ EXPECT_EQ(absl::Uniform(absl::IntervalClosed, gen, 10, 1000), 11);
+ }
+
+ {
+ absl::MockingBitGen gen;
+ ON_CALL(absl::MockUniform<int>(), Call(gen, 1, _))
+ .WillByDefault(Return(25));
+ ON_CALL(absl::MockUniform<int>(), Call(gen, Ne(1), _))
+ .WillByDefault(Return(99));
+ EXPECT_EQ(absl::Uniform(gen, 3, 1000000), 99);
+ EXPECT_EQ(absl::Uniform(gen, 1, 1000000), 25);
+ }
+
+ {
+ absl::MockingBitGen gen;
+ ON_CALL(absl::MockUniform<int>(), Call(gen, _, _))
+ .WillByDefault(Return(145));
+ EXPECT_EQ(absl::Uniform(gen, 1, 1000), 145);
+ EXPECT_EQ(absl::Uniform(gen, 10, 1000), 145);
+ EXPECT_EQ(absl::Uniform(gen, 100, 1000), 145);
+ }
+}
+
+TEST(AnythingMatcher, WithWillByDefault) {
+ using testing::_;
+ absl::MockingBitGen gen;
+ std::vector<int> values = {11, 22, 33, 44, 55, 66, 77, 88, 99, 1010};
+
+ ON_CALL(absl::MockUniform<size_t>(), Call(gen, 0, _))
+ .WillByDefault(Return(0));
+ for (int i = 0; i < 100; i++) {
+ auto& elem = values[absl::Uniform(gen, 0u, values.size())];
+ EXPECT_EQ(elem, 11);
+ }
+}
+
+TEST(BasicMocking, WillByDefaultWithArgs) {
+ using testing::_;
+
+ absl::MockingBitGen gen;
+ ON_CALL(absl::MockPoisson<int>(), Call(gen, _))
+ .WillByDefault(
+ [](double lambda) { return static_cast<int>(lambda * 10); });
+ EXPECT_EQ(absl::Poisson<int>(gen, 1.7), 17);
+ EXPECT_EQ(absl::Poisson<int>(gen, 0.03), 0);
+}
+
+TEST(MockingBitGen, InSequenceSucceedsInOrder) {
+ absl::MockingBitGen gen;
+
+ testing::InSequence seq;
+
+ EXPECT_CALL(absl::MockPoisson<int>(), Call(gen, 1.0)).WillOnce(Return(3));
+ EXPECT_CALL(absl::MockPoisson<int>(), Call(gen, 2.0)).WillOnce(Return(4));
+
+ EXPECT_EQ(absl::Poisson<int>(gen, 1.0), 3);
+ EXPECT_EQ(absl::Poisson<int>(gen, 2.0), 4);
+}
+
+} // namespace
diff --git a/third_party/abseil/absl/random/poisson_distribution.h b/third_party/abseil/absl/random/poisson_distribution.h
index 7750b1c..cb5f5d5 100644
--- a/third_party/abseil/absl/random/poisson_distribution.h
+++ b/third_party/abseil/absl/random/poisson_distribution.h
@@ -22,12 +22,13 @@
#include <ostream>
#include <type_traits>
-#include "absl/random/internal/distribution_impl.h"
#include "absl/random/internal/fast_uniform_bits.h"
#include "absl/random/internal/fastmath.h"
+#include "absl/random/internal/generate_real.h"
#include "absl/random/internal/iostream_state_saver.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// absl::poisson_distribution:
// Generates discrete variates conforming to a Poisson distribution.
@@ -164,9 +165,9 @@
poisson_distribution<IntType>::operator()(
URBG& g, // NOLINT(runtime/references)
const param_type& p) {
- using random_internal::PositiveValueT;
- using random_internal::RandU64ToDouble;
- using random_internal::SignedValueT;
+ using random_internal::GeneratePositiveTag;
+ using random_internal::GenerateRealFromBits;
+ using random_internal::GenerateSignedTag;
if (p.split_ != 0) {
// Use Knuth's algorithm with range splitting to avoid floating-point
@@ -186,7 +187,8 @@
for (int split = p.split_; split > 0; --split) {
double r = 1.0;
do {
- r *= RandU64ToDouble<PositiveValueT, true>(fast_u64_(g));
+ r *= GenerateRealFromBits<double, GeneratePositiveTag, true>(
+ fast_u64_(g)); // U(-1, 0)
++n;
} while (r > p.emu_);
--n;
@@ -205,10 +207,11 @@
// and k = max(f).
const double a = p.mean_ + 0.5;
for (;;) {
- const double u =
- RandU64ToDouble<PositiveValueT, false>(fast_u64_(g)); // (0, 1)
- const double v =
- RandU64ToDouble<SignedValueT, false>(fast_u64_(g)); // (-1, 1)
+ const double u = GenerateRealFromBits<double, GeneratePositiveTag, false>(
+ fast_u64_(g)); // U(0, 1)
+ const double v = GenerateRealFromBits<double, GenerateSignedTag, false>(
+ fast_u64_(g)); // U(-1, 1)
+
const double x = std::floor(p.s_ * v / u + a);
if (x < 0) continue; // f(negative) = 0
const double rhs = x * p.lmu_;
@@ -249,6 +252,7 @@
return is;
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_POISSON_DISTRIBUTION_H_
diff --git a/third_party/abseil/absl/random/poisson_distribution_test.cc b/third_party/abseil/absl/random/poisson_distribution_test.cc
index 9d215fb..8baabd1 100644
--- a/third_party/abseil/absl/random/poisson_distribution_test.cc
+++ b/third_party/abseil/absl/random/poisson_distribution_test.cc
@@ -30,6 +30,7 @@
#include "absl/container/flat_hash_map.h"
#include "absl/random/internal/chi_square.h"
#include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/pcg_engine.h"
#include "absl/random/internal/sequence_urbg.h"
#include "absl/random/random.h"
#include "absl/strings/str_cat.h"
@@ -257,7 +258,10 @@
template <typename D>
bool SingleZTest(const double p, const size_t samples);
- absl::InsecureBitGen rng_;
+ // We use a fixed bit generator for distribution accuracy tests. This allows
+ // these tests to be deterministic, while still testing the qualify of the
+ // implementation.
+ absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
};
template <typename D>
@@ -357,9 +361,13 @@
private:
void InitChiSquaredTest(const double buckets);
- absl::InsecureBitGen rng_;
std::vector<size_t> cutoffs_;
std::vector<double> expected_;
+
+ // We use a fixed bit generator for distribution accuracy tests. This allows
+ // these tests to be deterministic, while still testing the qualify of the
+ // implementation.
+ absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
};
void PoissonDistributionChiSquaredTest::InitChiSquaredTest(
diff --git a/third_party/abseil/absl/random/random.h b/third_party/abseil/absl/random/random.h
index dc6852f..71b6309 100644
--- a/third_party/abseil/absl/random/random.h
+++ b/third_party/abseil/absl/random/random.h
@@ -41,6 +41,7 @@
#include "absl/random/seed_sequences.h" // IWYU pragma: export
namespace absl {
+ABSL_NAMESPACE_BEGIN
// -----------------------------------------------------------------------------
// absl::BitGen
@@ -108,7 +109,7 @@
// absl::BitGen::max()
//
-// Returns the largest possible value from this bit generator., and
+// Returns the largest possible value from this bit generator.
// absl::BitGen::discard(num)
//
@@ -182,6 +183,7 @@
// discards the intermediate results.
// ---------------------------------------------------------------------------
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_RANDOM_H_
diff --git a/third_party/abseil/absl/random/seed_gen_exception.cc b/third_party/abseil/absl/random/seed_gen_exception.cc
index e4271ba..fdcb54a 100644
--- a/third_party/abseil/absl/random/seed_gen_exception.cc
+++ b/third_party/abseil/absl/random/seed_gen_exception.cc
@@ -19,6 +19,7 @@
#include "absl/base/config.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
static constexpr const char kExceptionMessage[] =
"Failed generating seed-material for URBG.";
@@ -41,4 +42,5 @@
}
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/random/seed_gen_exception.h b/third_party/abseil/absl/random/seed_gen_exception.h
index b464d52..5353900 100644
--- a/third_party/abseil/absl/random/seed_gen_exception.h
+++ b/third_party/abseil/absl/random/seed_gen_exception.h
@@ -28,7 +28,10 @@
#include <exception>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
//------------------------------------------------------------------------------
// SeedGenException
@@ -46,6 +49,7 @@
[[noreturn]] void ThrowSeedGenException();
} // namespace random_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_SEED_GEN_EXCEPTION_H_
diff --git a/third_party/abseil/absl/random/seed_sequences.cc b/third_party/abseil/absl/random/seed_sequences.cc
index 9f31961..426eafd 100644
--- a/third_party/abseil/absl/random/seed_sequences.cc
+++ b/third_party/abseil/absl/random/seed_sequences.cc
@@ -17,6 +17,7 @@
#include "absl/random/internal/pool_urbg.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
SeedSeq MakeSeedSeq() {
SeedSeq::result_type seed_material[8];
@@ -24,4 +25,5 @@
return SeedSeq(std::begin(seed_material), std::end(seed_material));
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/random/seed_sequences.h b/third_party/abseil/absl/random/seed_sequences.h
index 631d1ec..ff1340c 100644
--- a/third_party/abseil/absl/random/seed_sequences.h
+++ b/third_party/abseil/absl/random/seed_sequences.h
@@ -34,6 +34,7 @@
#include "absl/types/span.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// -----------------------------------------------------------------------------
// absl::SeedSeq
@@ -103,6 +104,7 @@
//
SeedSeq MakeSeedSeq();
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_SEED_SEQUENCES_H_
diff --git a/third_party/abseil/absl/random/seed_sequences_test.cc b/third_party/abseil/absl/random/seed_sequences_test.cc
index 2cc8b0e..fe1100b 100644
--- a/third_party/abseil/absl/random/seed_sequences_test.cc
+++ b/third_party/abseil/absl/random/seed_sequences_test.cc
@@ -96,7 +96,6 @@
void TestReproducibleVariateSequencesForNonsecureURBG() {
const size_t kNumVariates = 1000;
- // Master RNG instance.
URBG rng;
// Reused for both RNG instances.
auto reusable_seed = absl::CreateSeedSeqFrom(&rng);
diff --git a/third_party/abseil/absl/random/uniform_int_distribution.h b/third_party/abseil/absl/random/uniform_int_distribution.h
index 4970486..c1f54cc 100644
--- a/third_party/abseil/absl/random/uniform_int_distribution.h
+++ b/third_party/abseil/absl/random/uniform_int_distribution.h
@@ -34,12 +34,13 @@
#include <type_traits>
#include "absl/base/optimization.h"
-#include "absl/random/internal/distribution_impl.h"
#include "absl/random/internal/fast_uniform_bits.h"
#include "absl/random/internal/iostream_state_saver.h"
#include "absl/random/internal/traits.h"
+#include "absl/random/internal/wide_multiply.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// absl::uniform_int_distribution<T>
//
@@ -195,7 +196,7 @@
uniform_int_distribution<IntType>::Generate(
URBG& g, // NOLINT(runtime/references)
typename random_internal::make_unsigned_bits<IntType>::type R) {
- random_internal::FastUniformBits<unsigned_type> fast_bits;
+ random_internal::FastUniformBits<unsigned_type> fast_bits;
unsigned_type bits = fast_bits(g);
const unsigned_type Lim = R + 1;
if ((R & Lim) == 0) {
@@ -268,6 +269,7 @@
return helper::hi(product);
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_UNIFORM_INT_DISTRIBUTION_H_
diff --git a/third_party/abseil/absl/random/uniform_int_distribution_test.cc b/third_party/abseil/absl/random/uniform_int_distribution_test.cc
index aacff88..276d72a 100644
--- a/third_party/abseil/absl/random/uniform_int_distribution_test.cc
+++ b/third_party/abseil/absl/random/uniform_int_distribution_test.cc
@@ -26,6 +26,7 @@
#include "absl/base/internal/raw_logging.h"
#include "absl/random/internal/chi_square.h"
#include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/pcg_engine.h"
#include "absl/random/internal/sequence_urbg.h"
#include "absl/random/random.h"
#include "absl/strings/str_cat.h"
@@ -123,7 +124,7 @@
absl::uniform_int_distribution<TypeParam> dist(10, 1);
auto x = dist(gen);
- // Any value will generate a non-empty std::string.
+ // Any value will generate a non-empty string.
EXPECT_FALSE(absl::StrCat(+x).empty()) << x;
#endif // NDEBUG
}
@@ -134,7 +135,11 @@
using param_type =
typename absl::uniform_int_distribution<TypeParam>::param_type;
- absl::InsecureBitGen rng;
+ // We use a fixed bit generator for distribution accuracy tests. This allows
+ // these tests to be deterministic, while still testing the qualify of the
+ // implementation.
+ absl::random_internal::pcg64_2018_engine rng{0x2B7E151628AED2A6};
+
std::vector<double> values(kSize);
for (const auto& param :
{param_type(0, Limits::max()), param_type(13, 127)}) {
@@ -178,7 +183,11 @@
const TypeParam min = std::is_unsigned<TypeParam>::value ? 37 : -37;
const TypeParam max = min + kBuckets;
- absl::InsecureBitGen rng;
+ // We use a fixed bit generator for distribution accuracy tests. This allows
+ // these tests to be deterministic, while still testing the qualify of the
+ // implementation.
+ absl::random_internal::pcg64_2018_engine rng{0x2B7E151628AED2A6};
+
absl::uniform_int_distribution<TypeParam> dist(min, max);
std::vector<int32_t> counts(kBuckets + 1, 0);
diff --git a/third_party/abseil/absl/random/uniform_real_distribution.h b/third_party/abseil/absl/random/uniform_real_distribution.h
index 600f915..5ba17b2 100644
--- a/third_party/abseil/absl/random/uniform_real_distribution.h
+++ b/third_party/abseil/absl/random/uniform_real_distribution.h
@@ -39,11 +39,13 @@
#include <limits>
#include <type_traits>
-#include "absl/random/internal/distribution_impl.h"
+#include "absl/meta/type_traits.h"
#include "absl/random/internal/fast_uniform_bits.h"
+#include "absl/random/internal/generate_real.h"
#include "absl/random/internal/iostream_state_saver.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// absl::uniform_real_distribution<T>
//
@@ -56,7 +58,7 @@
//
// // Use the distribution to produce a value between 0.0 (inclusive)
// // and 1.0 (exclusive).
-// int value = absl::uniform_real_distribution<double>(0, 1)(gen);
+// double value = absl::uniform_real_distribution<double>(0, 1)(gen);
//
template <typename RealType = double>
class uniform_real_distribution {
@@ -76,6 +78,7 @@
// is not possible, so value generation cannot use the full range of the
// real type.
assert(range_ <= (std::numeric_limits<result_type>::max)());
+ assert(std::isfinite(range_));
}
result_type a() const { return lo_; }
@@ -151,10 +154,15 @@
typename uniform_real_distribution<RealType>::result_type
uniform_real_distribution<RealType>::operator()(
URBG& gen, const param_type& p) { // NOLINT(runtime/references)
- using random_internal::PositiveValueT;
+ using random_internal::GeneratePositiveTag;
+ using random_internal::GenerateRealFromBits;
+ using real_type =
+ absl::conditional_t<std::is_same<RealType, float>::value, float, double>;
+
while (true) {
- const result_type sample = random_internal::RandU64ToReal<
- result_type>::template Value<PositiveValueT, true>(fast_u64_(gen));
+ const result_type sample =
+ GenerateRealFromBits<real_type, GeneratePositiveTag, true>(
+ fast_u64_(gen));
const result_type res = p.a() + (sample * p.range_);
if (res < p.b() || p.range_ <= 0 || !std::isfinite(p.range_)) {
return res;
@@ -188,6 +196,7 @@
}
return is;
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_UNIFORM_REAL_DISTRIBUTION_H_
diff --git a/third_party/abseil/absl/random/uniform_real_distribution_test.cc b/third_party/abseil/absl/random/uniform_real_distribution_test.cc
index 597f0ee..8cf874d 100644
--- a/third_party/abseil/absl/random/uniform_real_distribution_test.cc
+++ b/third_party/abseil/absl/random/uniform_real_distribution_test.cc
@@ -27,6 +27,7 @@
#include "absl/base/internal/raw_logging.h"
#include "absl/random/internal/chi_square.h"
#include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/pcg_engine.h"
#include "absl/random/internal/sequence_urbg.h"
#include "absl/random/random.h"
#include "absl/strings/str_cat.h"
@@ -55,6 +56,7 @@
class UniformRealDistributionTest : public ::testing::Test {};
using RealTypes = ::testing::Types<float, double, long double>;
+
TYPED_TEST_SUITE(UniformRealDistributionTest, RealTypes);
TYPED_TEST(UniformRealDistributionTest, ParamSerializeTest) {
@@ -156,6 +158,10 @@
}
}
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4756) // Constant arithmetic overflow.
+#endif
TYPED_TEST(UniformRealDistributionTest, ViolatesPreconditionsDeathTest) {
#if GTEST_HAS_DEATH_TEST
// Hi < Lo
@@ -190,12 +196,19 @@
}
#endif // NDEBUG
}
+#ifdef _MSC_VER
+#pragma warning(pop) // warning(disable:4756)
+#endif
TYPED_TEST(UniformRealDistributionTest, TestMoments) {
constexpr int kSize = 1000000;
std::vector<double> values(kSize);
- absl::InsecureBitGen rng;
+ // We use a fixed bit generator for distribution accuracy tests. This allows
+ // these tests to be deterministic, while still testing the qualify of the
+ // implementation.
+ absl::random_internal::pcg64_2018_engine rng{0x2B7E151628AED2A6};
+
absl::uniform_real_distribution<TypeParam> dist;
for (int i = 0; i < kSize; i++) {
values[i] = dist(rng);
@@ -225,7 +238,11 @@
const int kThreshold =
absl::random_internal::ChiSquareValue(kBuckets - 1, 0.999999);
- absl::InsecureBitGen rng;
+ // We use a fixed bit generator for distribution accuracy tests. This allows
+ // these tests to be deterministic, while still testing the qualify of the
+ // implementation.
+ absl::random_internal::pcg64_2018_engine rng{0x2B7E151628AED2A6};
+
for (const auto& param : {param_type(0, 1), param_type(5, 12),
param_type(-5, 13), param_type(-5, -2)}) {
const double min_val = param.a();
diff --git a/third_party/abseil/absl/random/zipf_distribution.h b/third_party/abseil/absl/random/zipf_distribution.h
index d7b4ac3..22ebc75 100644
--- a/third_party/abseil/absl/random/zipf_distribution.h
+++ b/third_party/abseil/absl/random/zipf_distribution.h
@@ -26,6 +26,7 @@
#include "absl/random/uniform_real_distribution.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// absl::zipf_distribution produces random integer-values in the range [0, k],
// distributed according to the discrete probability function:
@@ -264,6 +265,7 @@
return is;
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_ZIPF_DISTRIBUTION_H_
diff --git a/third_party/abseil/absl/random/zipf_distribution_test.cc b/third_party/abseil/absl/random/zipf_distribution_test.cc
index 4d4a0fc..f8cf70e 100644
--- a/third_party/abseil/absl/random/zipf_distribution_test.cc
+++ b/third_party/abseil/absl/random/zipf_distribution_test.cc
@@ -27,6 +27,7 @@
#include "gtest/gtest.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/random/internal/chi_square.h"
+#include "absl/random/internal/pcg_engine.h"
#include "absl/random/internal/sequence_urbg.h"
#include "absl/random/random.h"
#include "absl/strings/str_cat.h"
@@ -213,7 +214,10 @@
public:
ZipfTest() : ZipfModel(GetParam().k(), GetParam().q(), GetParam().v()) {}
- absl::InsecureBitGen rng_;
+ // We use a fixed bit generator for distribution accuracy tests. This allows
+ // these tests to be deterministic, while still testing the qualify of the
+ // implementation.
+ absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
};
TEST_P(ZipfTest, ChiSquaredTest) {
diff --git a/third_party/abseil/absl/status/BUILD.bazel b/third_party/abseil/absl/status/BUILD.bazel
new file mode 100644
index 0000000..189bd73
--- /dev/null
+++ b/third_party/abseil/absl/status/BUILD.bazel
@@ -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
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This package contains `absl::Status`.
+# It will expand later to have utilities around `Status` like `StatusOr`,
+# `StatusBuilder` and macros.
+
+load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+load(
+ "//absl:copts/configure_copts.bzl",
+ "ABSL_DEFAULT_COPTS",
+ "ABSL_TEST_COPTS",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])
+
+cc_library(
+ name = "status",
+ srcs = [
+ "internal/status_internal.h",
+ "status.cc",
+ "status_payload_printer.cc",
+ ],
+ hdrs = [
+ "status.h",
+ "status_payload_printer.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ "//absl/base:atomic_hook",
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ "//absl/base:raw_logging_internal",
+ "//absl/container:inlined_vector",
+ "//absl/debugging:stacktrace",
+ "//absl/debugging:symbolize",
+ "//absl/strings",
+ "//absl/strings:cord",
+ "//absl/strings:str_format",
+ "//absl/types:optional",
+ ],
+)
+
+cc_test(
+ name = "status_test",
+ srcs = ["status_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":status",
+ "//absl/strings",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_library(
+ name = "statusor",
+ srcs = [
+ "internal/statusor_internal.h",
+ "statusor.cc",
+ ],
+ hdrs = [
+ "statusor.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ ":status",
+ "//absl/base:core_headers",
+ "//absl/base:raw_logging_internal",
+ "//absl/meta:type_traits",
+ "//absl/strings",
+ "//absl/types:variant",
+ "//absl/utility",
+ ],
+)
+
+cc_test(
+ name = "statusor_test",
+ size = "small",
+ srcs = ["statusor_test.cc"],
+ deps = [
+ ":status",
+ ":statusor",
+ "//absl/base",
+ "//absl/memory",
+ "//absl/types:any",
+ "//absl/utility",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/third_party/abseil/absl/status/CMakeLists.txt b/third_party/abseil/absl/status/CMakeLists.txt
new file mode 100644
index 0000000..f0d798a
--- /dev/null
+++ b/third_party/abseil/absl/status/CMakeLists.txt
@@ -0,0 +1,88 @@
+#
+# Copyright 2020 The Abseil Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+absl_cc_library(
+ NAME
+ status
+ HDRS
+ "status.h"
+ SRCS
+ "internal/status_internal.h"
+ "status.cc"
+ "status_payload_printer.h"
+ "status_payload_printer.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::atomic_hook
+ absl::config
+ absl::core_headers
+ absl::raw_logging_internal
+ absl::inlined_vector
+ absl::stacktrace
+ absl::symbolize
+ absl::strings
+ absl::cord
+ absl::str_format
+ absl::optional
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
+ status_test
+ SRCS
+ "status_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::status
+ absl::strings
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
+ statusor
+ HDRS
+ "statusor.h"
+ SRCS
+ "statusor.cc"
+ "internal/statusor_internal.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::status
+ absl::core_headers
+ absl::raw_logging_internal
+ absl::type_traits
+ absl::strings
+ absl::utility
+ absl::variant
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
+ statusor_test
+ SRCS
+ "statusor_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::status
+ absl::statusor
+ gmock_main
+)
diff --git a/third_party/abseil/absl/status/internal/status_internal.h b/third_party/abseil/absl/status/internal/status_internal.h
new file mode 100644
index 0000000..279f8f5
--- /dev/null
+++ b/third_party/abseil/absl/status/internal/status_internal.h
@@ -0,0 +1,58 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef ABSL_STATUS_INTERNAL_STATUS_INTERNAL_H_
+#define ABSL_STATUS_INTERNAL_STATUS_INTERNAL_H_
+
+#include <string>
+
+#include "absl/container/inlined_vector.h"
+#include "absl/strings/cord.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+enum class StatusCode : int;
+
+namespace status_internal {
+
+// Container for status payloads.
+struct Payload {
+ std::string type_url;
+ absl::Cord payload;
+};
+
+using Payloads = absl::InlinedVector<Payload, 1>;
+
+// Reference-counted representation of Status data.
+struct StatusRep {
+ StatusRep(absl::StatusCode code, std::string message,
+ std::unique_ptr<status_internal::Payloads> payloads)
+ : ref(int32_t{1}),
+ code(code),
+ message(std::move(message)),
+ payloads(std::move(payloads)) {}
+
+ std::atomic<int32_t> ref;
+ absl::StatusCode code;
+ std::string message;
+ std::unique_ptr<status_internal::Payloads> payloads;
+};
+
+absl::StatusCode MapToLocalCode(int value);
+} // namespace status_internal
+
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_STATUS_INTERNAL_STATUS_INTERNAL_H_
diff --git a/third_party/abseil/absl/status/internal/statusor_internal.h b/third_party/abseil/absl/status/internal/statusor_internal.h
new file mode 100644
index 0000000..eaac2c0
--- /dev/null
+++ b/third_party/abseil/absl/status/internal/statusor_internal.h
@@ -0,0 +1,396 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_
+#define ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_
+
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/attributes.h"
+#include "absl/meta/type_traits.h"
+#include "absl/status/status.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+template <typename T>
+class ABSL_MUST_USE_RESULT StatusOr;
+
+namespace internal_statusor {
+
+// Detects whether `U` has conversion operator to `StatusOr<T>`, i.e. `operator
+// StatusOr<T>()`.
+template <typename T, typename U, typename = void>
+struct HasConversionOperatorToStatusOr : std::false_type {};
+
+template <typename T, typename U>
+void test(char (*)[sizeof(std::declval<U>().operator absl::StatusOr<T>())]);
+
+template <typename T, typename U>
+struct HasConversionOperatorToStatusOr<T, U, decltype(test<T, U>(0))>
+ : std::true_type {};
+
+// Detects whether `T` is constructible or convertible from `StatusOr<U>`.
+template <typename T, typename U>
+using IsConstructibleOrConvertibleFromStatusOr =
+ absl::disjunction<std::is_constructible<T, StatusOr<U>&>,
+ std::is_constructible<T, const StatusOr<U>&>,
+ std::is_constructible<T, StatusOr<U>&&>,
+ std::is_constructible<T, const StatusOr<U>&&>,
+ std::is_convertible<StatusOr<U>&, T>,
+ std::is_convertible<const StatusOr<U>&, T>,
+ std::is_convertible<StatusOr<U>&&, T>,
+ std::is_convertible<const StatusOr<U>&&, T>>;
+
+// Detects whether `T` is constructible or convertible or assignable from
+// `StatusOr<U>`.
+template <typename T, typename U>
+using IsConstructibleOrConvertibleOrAssignableFromStatusOr =
+ absl::disjunction<IsConstructibleOrConvertibleFromStatusOr<T, U>,
+ std::is_assignable<T&, StatusOr<U>&>,
+ std::is_assignable<T&, const StatusOr<U>&>,
+ std::is_assignable<T&, StatusOr<U>&&>,
+ std::is_assignable<T&, const StatusOr<U>&&>>;
+
+// Detects whether direct initializing `StatusOr<T>` from `U` is ambiguous, i.e.
+// when `U` is `StatusOr<V>` and `T` is constructible or convertible from `V`.
+template <typename T, typename U>
+struct IsDirectInitializationAmbiguous
+ : public absl::conditional_t<
+ std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>,
+ U>::value,
+ std::false_type,
+ IsDirectInitializationAmbiguous<
+ T, absl::remove_cv_t<absl::remove_reference_t<U>>>> {};
+
+template <typename T, typename V>
+struct IsDirectInitializationAmbiguous<T, absl::StatusOr<V>>
+ : public IsConstructibleOrConvertibleFromStatusOr<T, V> {};
+
+// Checks against the constraints of the direction initialization, i.e. when
+// `StatusOr<T>::StatusOr(U&&)` should participate in overload resolution.
+template <typename T, typename U>
+using IsDirectInitializationValid = absl::disjunction<
+ // Short circuits if T is basically U.
+ std::is_same<T, absl::remove_cv_t<absl::remove_reference_t<U>>>,
+ absl::negation<absl::disjunction<
+ std::is_same<absl::StatusOr<T>,
+ absl::remove_cv_t<absl::remove_reference_t<U>>>,
+ std::is_same<absl::Status,
+ absl::remove_cv_t<absl::remove_reference_t<U>>>,
+ std::is_same<absl::in_place_t,
+ absl::remove_cv_t<absl::remove_reference_t<U>>>,
+ IsDirectInitializationAmbiguous<T, U>>>>;
+
+// This trait detects whether `StatusOr<T>::operator=(U&&)` is ambiguous, which
+// is equivalent to whether all the following conditions are met:
+// 1. `U` is `StatusOr<V>`.
+// 2. `T` is constructible and assignable from `V`.
+// 3. `T` is constructible and assignable from `U` (i.e. `StatusOr<V>`).
+// For example, the following code is considered ambiguous:
+// (`T` is `bool`, `U` is `StatusOr<bool>`, `V` is `bool`)
+// StatusOr<bool> s1 = true; // s1.ok() && s1.ValueOrDie() == true
+// StatusOr<bool> s2 = false; // s2.ok() && s2.ValueOrDie() == false
+// s1 = s2; // ambiguous, `s1 = s2.ValueOrDie()` or `s1 = bool(s2)`?
+template <typename T, typename U>
+struct IsForwardingAssignmentAmbiguous
+ : public absl::conditional_t<
+ std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>,
+ U>::value,
+ std::false_type,
+ IsForwardingAssignmentAmbiguous<
+ T, absl::remove_cv_t<absl::remove_reference_t<U>>>> {};
+
+template <typename T, typename U>
+struct IsForwardingAssignmentAmbiguous<T, absl::StatusOr<U>>
+ : public IsConstructibleOrConvertibleOrAssignableFromStatusOr<T, U> {};
+
+// Checks against the constraints of the forwarding assignment, i.e. whether
+// `StatusOr<T>::operator(U&&)` should participate in overload resolution.
+template <typename T, typename U>
+using IsForwardingAssignmentValid = absl::disjunction<
+ // Short circuits if T is basically U.
+ std::is_same<T, absl::remove_cv_t<absl::remove_reference_t<U>>>,
+ absl::negation<absl::disjunction<
+ std::is_same<absl::StatusOr<T>,
+ absl::remove_cv_t<absl::remove_reference_t<U>>>,
+ std::is_same<absl::Status,
+ absl::remove_cv_t<absl::remove_reference_t<U>>>,
+ std::is_same<absl::in_place_t,
+ absl::remove_cv_t<absl::remove_reference_t<U>>>,
+ IsForwardingAssignmentAmbiguous<T, U>>>>;
+
+class Helper {
+ public:
+ // Move type-agnostic error handling to the .cc.
+ static void HandleInvalidStatusCtorArg(Status*);
+ ABSL_ATTRIBUTE_NORETURN static void Crash(const absl::Status& status);
+};
+
+// Construct an instance of T in `p` through placement new, passing Args... to
+// the constructor.
+// This abstraction is here mostly for the gcc performance fix.
+template <typename T, typename... Args>
+ABSL_ATTRIBUTE_NONNULL(1) void PlacementNew(void* p, Args&&... args) {
+ new (p) T(std::forward<Args>(args)...);
+}
+
+// Helper base class to hold the data and all operations.
+// We move all this to a base class to allow mixing with the appropriate
+// TraitsBase specialization.
+template <typename T>
+class StatusOrData {
+ template <typename U>
+ friend class StatusOrData;
+
+ public:
+ StatusOrData() = delete;
+
+ StatusOrData(const StatusOrData& other) {
+ if (other.ok()) {
+ MakeValue(other.data_);
+ MakeStatus();
+ } else {
+ MakeStatus(other.status_);
+ }
+ }
+
+ StatusOrData(StatusOrData&& other) noexcept {
+ if (other.ok()) {
+ MakeValue(std::move(other.data_));
+ MakeStatus();
+ } else {
+ MakeStatus(std::move(other.status_));
+ }
+ }
+
+ template <typename U>
+ explicit StatusOrData(const StatusOrData<U>& other) {
+ if (other.ok()) {
+ MakeValue(other.data_);
+ MakeStatus();
+ } else {
+ MakeStatus(other.status_);
+ }
+ }
+
+ template <typename U>
+ explicit StatusOrData(StatusOrData<U>&& other) {
+ if (other.ok()) {
+ MakeValue(std::move(other.data_));
+ MakeStatus();
+ } else {
+ MakeStatus(std::move(other.status_));
+ }
+ }
+
+ template <typename... Args>
+ explicit StatusOrData(absl::in_place_t, Args&&... args)
+ : data_(std::forward<Args>(args)...) {
+ MakeStatus();
+ }
+
+ explicit StatusOrData(const T& value) : data_(value) {
+ MakeStatus();
+ }
+ explicit StatusOrData(T&& value) : data_(std::move(value)) {
+ MakeStatus();
+ }
+
+ template <typename U,
+ absl::enable_if_t<std::is_constructible<absl::Status, U&&>::value,
+ int> = 0>
+ explicit StatusOrData(U&& v) : status_(std::forward<U>(v)) {
+ EnsureNotOk();
+ }
+
+ StatusOrData& operator=(const StatusOrData& other) {
+ if (this == &other) return *this;
+ if (other.ok())
+ Assign(other.data_);
+ else
+ AssignStatus(other.status_);
+ return *this;
+ }
+
+ StatusOrData& operator=(StatusOrData&& other) {
+ if (this == &other) return *this;
+ if (other.ok())
+ Assign(std::move(other.data_));
+ else
+ AssignStatus(std::move(other.status_));
+ return *this;
+ }
+
+ ~StatusOrData() {
+ if (ok()) {
+ status_.~Status();
+ data_.~T();
+ } else {
+ status_.~Status();
+ }
+ }
+
+ template <typename U>
+ void Assign(U&& value) {
+ if (ok()) {
+ data_ = std::forward<U>(value);
+ } else {
+ MakeValue(std::forward<U>(value));
+ status_ = OkStatus();
+ }
+ }
+
+ template <typename U>
+ void AssignStatus(U&& v) {
+ Clear();
+ status_ = static_cast<absl::Status>(std::forward<U>(v));
+ EnsureNotOk();
+ }
+
+ bool ok() const { return status_.ok(); }
+
+ protected:
+ // status_ will always be active after the constructor.
+ // We make it a union to be able to initialize exactly how we need without
+ // waste.
+ // Eg. in the copy constructor we use the default constructor of Status in
+ // the ok() path to avoid an extra Ref call.
+ union {
+ Status status_;
+ };
+
+ // data_ is active iff status_.ok()==true
+ struct Dummy {};
+ union {
+ // When T is const, we need some non-const object we can cast to void* for
+ // the placement new. dummy_ is that object.
+ Dummy dummy_;
+ T data_;
+ };
+
+ void Clear() {
+ if (ok()) data_.~T();
+ }
+
+ void EnsureOk() const {
+ if (ABSL_PREDICT_FALSE(!ok())) Helper::Crash(status_);
+ }
+
+ void EnsureNotOk() {
+ if (ABSL_PREDICT_FALSE(ok())) Helper::HandleInvalidStatusCtorArg(&status_);
+ }
+
+ // Construct the value (ie. data_) through placement new with the passed
+ // argument.
+ template <typename... Arg>
+ void MakeValue(Arg&&... arg) {
+ internal_statusor::PlacementNew<T>(&dummy_, std::forward<Arg>(arg)...);
+ }
+
+ // Construct the status (ie. status_) through placement new with the passed
+ // argument.
+ template <typename... Args>
+ void MakeStatus(Args&&... args) {
+ internal_statusor::PlacementNew<Status>(&status_,
+ std::forward<Args>(args)...);
+ }
+};
+
+// Helper base classes to allow implicitly deleted constructors and assignment
+// operators in `StatusOr`. For example, `CopyCtorBase` will explicitly delete
+// the copy constructor when T is not copy constructible and `StatusOr` will
+// inherit that behavior implicitly.
+template <typename T, bool = std::is_copy_constructible<T>::value>
+struct CopyCtorBase {
+ CopyCtorBase() = default;
+ CopyCtorBase(const CopyCtorBase&) = default;
+ CopyCtorBase(CopyCtorBase&&) = default;
+ CopyCtorBase& operator=(const CopyCtorBase&) = default;
+ CopyCtorBase& operator=(CopyCtorBase&&) = default;
+};
+
+template <typename T>
+struct CopyCtorBase<T, false> {
+ CopyCtorBase() = default;
+ CopyCtorBase(const CopyCtorBase&) = delete;
+ CopyCtorBase(CopyCtorBase&&) = default;
+ CopyCtorBase& operator=(const CopyCtorBase&) = default;
+ CopyCtorBase& operator=(CopyCtorBase&&) = default;
+};
+
+template <typename T, bool = std::is_move_constructible<T>::value>
+struct MoveCtorBase {
+ MoveCtorBase() = default;
+ MoveCtorBase(const MoveCtorBase&) = default;
+ MoveCtorBase(MoveCtorBase&&) = default;
+ MoveCtorBase& operator=(const MoveCtorBase&) = default;
+ MoveCtorBase& operator=(MoveCtorBase&&) = default;
+};
+
+template <typename T>
+struct MoveCtorBase<T, false> {
+ MoveCtorBase() = default;
+ MoveCtorBase(const MoveCtorBase&) = default;
+ MoveCtorBase(MoveCtorBase&&) = delete;
+ MoveCtorBase& operator=(const MoveCtorBase&) = default;
+ MoveCtorBase& operator=(MoveCtorBase&&) = default;
+};
+
+template <typename T, bool = std::is_copy_constructible<T>::value&&
+ std::is_copy_assignable<T>::value>
+struct CopyAssignBase {
+ CopyAssignBase() = default;
+ CopyAssignBase(const CopyAssignBase&) = default;
+ CopyAssignBase(CopyAssignBase&&) = default;
+ CopyAssignBase& operator=(const CopyAssignBase&) = default;
+ CopyAssignBase& operator=(CopyAssignBase&&) = default;
+};
+
+template <typename T>
+struct CopyAssignBase<T, false> {
+ CopyAssignBase() = default;
+ CopyAssignBase(const CopyAssignBase&) = default;
+ CopyAssignBase(CopyAssignBase&&) = default;
+ CopyAssignBase& operator=(const CopyAssignBase&) = delete;
+ CopyAssignBase& operator=(CopyAssignBase&&) = default;
+};
+
+template <typename T, bool = std::is_move_constructible<T>::value&&
+ std::is_move_assignable<T>::value>
+struct MoveAssignBase {
+ MoveAssignBase() = default;
+ MoveAssignBase(const MoveAssignBase&) = default;
+ MoveAssignBase(MoveAssignBase&&) = default;
+ MoveAssignBase& operator=(const MoveAssignBase&) = default;
+ MoveAssignBase& operator=(MoveAssignBase&&) = default;
+};
+
+template <typename T>
+struct MoveAssignBase<T, false> {
+ MoveAssignBase() = default;
+ MoveAssignBase(const MoveAssignBase&) = default;
+ MoveAssignBase(MoveAssignBase&&) = default;
+ MoveAssignBase& operator=(const MoveAssignBase&) = default;
+ MoveAssignBase& operator=(MoveAssignBase&&) = delete;
+};
+
+ABSL_ATTRIBUTE_NORETURN void ThrowBadStatusOrAccess(absl::Status status);
+
+} // namespace internal_statusor
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_
diff --git a/third_party/abseil/absl/status/status.cc b/third_party/abseil/absl/status/status.cc
new file mode 100644
index 0000000..c71de84
--- /dev/null
+++ b/third_party/abseil/absl/status/status.cc
@@ -0,0 +1,442 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "absl/status/status.h"
+
+#include <cassert>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/debugging/stacktrace.h"
+#include "absl/debugging/symbolize.h"
+#include "absl/status/status_payload_printer.h"
+#include "absl/strings/escaping.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/str_split.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+std::string StatusCodeToString(StatusCode code) {
+ switch (code) {
+ case StatusCode::kOk:
+ return "OK";
+ case StatusCode::kCancelled:
+ return "CANCELLED";
+ case StatusCode::kUnknown:
+ return "UNKNOWN";
+ case StatusCode::kInvalidArgument:
+ return "INVALID_ARGUMENT";
+ case StatusCode::kDeadlineExceeded:
+ return "DEADLINE_EXCEEDED";
+ case StatusCode::kNotFound:
+ return "NOT_FOUND";
+ case StatusCode::kAlreadyExists:
+ return "ALREADY_EXISTS";
+ case StatusCode::kPermissionDenied:
+ return "PERMISSION_DENIED";
+ case StatusCode::kUnauthenticated:
+ return "UNAUTHENTICATED";
+ case StatusCode::kResourceExhausted:
+ return "RESOURCE_EXHAUSTED";
+ case StatusCode::kFailedPrecondition:
+ return "FAILED_PRECONDITION";
+ case StatusCode::kAborted:
+ return "ABORTED";
+ case StatusCode::kOutOfRange:
+ return "OUT_OF_RANGE";
+ case StatusCode::kUnimplemented:
+ return "UNIMPLEMENTED";
+ case StatusCode::kInternal:
+ return "INTERNAL";
+ case StatusCode::kUnavailable:
+ return "UNAVAILABLE";
+ case StatusCode::kDataLoss:
+ return "DATA_LOSS";
+ default:
+ return "";
+ }
+}
+
+std::ostream& operator<<(std::ostream& os, StatusCode code) {
+ return os << StatusCodeToString(code);
+}
+
+namespace status_internal {
+
+static int FindPayloadIndexByUrl(const Payloads* payloads,
+ absl::string_view type_url) {
+ if (payloads == nullptr) return -1;
+
+ for (size_t i = 0; i < payloads->size(); ++i) {
+ if ((*payloads)[i].type_url == type_url) return i;
+ }
+
+ return -1;
+}
+
+// Convert canonical code to a value known to this binary.
+absl::StatusCode MapToLocalCode(int value) {
+ absl::StatusCode code = static_cast<absl::StatusCode>(value);
+ switch (code) {
+ case absl::StatusCode::kOk:
+ case absl::StatusCode::kCancelled:
+ case absl::StatusCode::kUnknown:
+ case absl::StatusCode::kInvalidArgument:
+ case absl::StatusCode::kDeadlineExceeded:
+ case absl::StatusCode::kNotFound:
+ case absl::StatusCode::kAlreadyExists:
+ case absl::StatusCode::kPermissionDenied:
+ case absl::StatusCode::kResourceExhausted:
+ case absl::StatusCode::kFailedPrecondition:
+ case absl::StatusCode::kAborted:
+ case absl::StatusCode::kOutOfRange:
+ case absl::StatusCode::kUnimplemented:
+ case absl::StatusCode::kInternal:
+ case absl::StatusCode::kUnavailable:
+ case absl::StatusCode::kDataLoss:
+ case absl::StatusCode::kUnauthenticated:
+ return code;
+ default:
+ return absl::StatusCode::kUnknown;
+ }
+}
+} // namespace status_internal
+
+absl::optional<absl::Cord> Status::GetPayload(
+ absl::string_view type_url) const {
+ const auto* payloads = GetPayloads();
+ int index = status_internal::FindPayloadIndexByUrl(payloads, type_url);
+ if (index != -1) return (*payloads)[index].payload;
+
+ return absl::nullopt;
+}
+
+void Status::SetPayload(absl::string_view type_url, absl::Cord payload) {
+ if (ok()) return;
+
+ PrepareToModify();
+
+ status_internal::StatusRep* rep = RepToPointer(rep_);
+ if (!rep->payloads) {
+ rep->payloads = absl::make_unique<status_internal::Payloads>();
+ }
+
+ int index =
+ status_internal::FindPayloadIndexByUrl(rep->payloads.get(), type_url);
+ if (index != -1) {
+ (*rep->payloads)[index].payload = std::move(payload);
+ return;
+ }
+
+ rep->payloads->push_back({std::string(type_url), std::move(payload)});
+}
+
+bool Status::ErasePayload(absl::string_view type_url) {
+ int index = status_internal::FindPayloadIndexByUrl(GetPayloads(), type_url);
+ if (index != -1) {
+ PrepareToModify();
+ GetPayloads()->erase(GetPayloads()->begin() + index);
+ if (GetPayloads()->empty() && message().empty()) {
+ // Special case: If this can be represented inlined, it MUST be
+ // inlined (EqualsSlow depends on this behavior).
+ StatusCode c = static_cast<StatusCode>(raw_code());
+ Unref(rep_);
+ rep_ = CodeToInlinedRep(c);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+void Status::ForEachPayload(
+ const std::function<void(absl::string_view, const absl::Cord&)>& visitor)
+ const {
+ if (auto* payloads = GetPayloads()) {
+ bool in_reverse =
+ payloads->size() > 1 && reinterpret_cast<uintptr_t>(payloads) % 13 > 6;
+
+ for (size_t index = 0; index < payloads->size(); ++index) {
+ const auto& elem =
+ (*payloads)[in_reverse ? payloads->size() - 1 - index : index];
+
+#ifdef NDEBUG
+ visitor(elem.type_url, elem.payload);
+#else
+ // In debug mode invalidate the type url to prevent users from relying on
+ // this string lifetime.
+
+ // NOLINTNEXTLINE intentional extra conversion to force temporary.
+ visitor(std::string(elem.type_url), elem.payload);
+#endif // NDEBUG
+ }
+ }
+}
+
+const std::string* Status::EmptyString() {
+ static std::string* empty_string = new std::string();
+ return empty_string;
+}
+
+constexpr const char Status::kMovedFromString[];
+
+const std::string* Status::MovedFromString() {
+ static std::string* moved_from_string = new std::string(kMovedFromString);
+ return moved_from_string;
+}
+
+void Status::UnrefNonInlined(uintptr_t rep) {
+ status_internal::StatusRep* r = RepToPointer(rep);
+ // Fast path: if ref==1, there is no need for a RefCountDec (since
+ // this is the only reference and therefore no other thread is
+ // allowed to be mucking with r).
+ if (r->ref.load(std::memory_order_acquire) == 1 ||
+ r->ref.fetch_sub(1, std::memory_order_acq_rel) - 1 == 0) {
+ delete r;
+ }
+}
+
+uintptr_t Status::NewRep(absl::StatusCode code, absl::string_view msg,
+ std::unique_ptr<status_internal::Payloads> payloads) {
+ status_internal::StatusRep* rep = new status_internal::StatusRep(
+ code, std::string(msg.data(), msg.size()), std::move(payloads));
+ return PointerToRep(rep);
+}
+
+Status::Status(absl::StatusCode code, absl::string_view msg)
+ : rep_(CodeToInlinedRep(code)) {
+ if (code != absl::StatusCode::kOk && !msg.empty()) {
+ rep_ = NewRep(code, msg, nullptr);
+ }
+}
+
+int Status::raw_code() const {
+ if (IsInlined(rep_)) {
+ return static_cast<int>(InlinedRepToCode(rep_));
+ }
+ status_internal::StatusRep* rep = RepToPointer(rep_);
+ return static_cast<int>(rep->code);
+}
+
+absl::StatusCode Status::code() const {
+ return status_internal::MapToLocalCode(raw_code());
+}
+
+void Status::PrepareToModify() {
+ ABSL_RAW_CHECK(!ok(), "PrepareToModify shouldn't be called on OK status.");
+ if (IsInlined(rep_)) {
+ rep_ = NewRep(static_cast<absl::StatusCode>(raw_code()),
+ absl::string_view(), nullptr);
+ return;
+ }
+
+ uintptr_t rep_i = rep_;
+ status_internal::StatusRep* rep = RepToPointer(rep_);
+ if (rep->ref.load(std::memory_order_acquire) != 1) {
+ std::unique_ptr<status_internal::Payloads> payloads;
+ if (rep->payloads) {
+ payloads = absl::make_unique<status_internal::Payloads>(*rep->payloads);
+ }
+ rep_ = NewRep(rep->code, message(), std::move(payloads));
+ UnrefNonInlined(rep_i);
+ }
+}
+
+bool Status::EqualsSlow(const absl::Status& a, const absl::Status& b) {
+ if (IsInlined(a.rep_) != IsInlined(b.rep_)) return false;
+ if (a.message() != b.message()) return false;
+ if (a.raw_code() != b.raw_code()) return false;
+ if (a.GetPayloads() == b.GetPayloads()) return true;
+
+ const status_internal::Payloads no_payloads;
+ const status_internal::Payloads* larger_payloads =
+ a.GetPayloads() ? a.GetPayloads() : &no_payloads;
+ const status_internal::Payloads* smaller_payloads =
+ b.GetPayloads() ? b.GetPayloads() : &no_payloads;
+ if (larger_payloads->size() < smaller_payloads->size()) {
+ std::swap(larger_payloads, smaller_payloads);
+ }
+ if ((larger_payloads->size() - smaller_payloads->size()) > 1) return false;
+ // Payloads can be ordered differently, so we can't just compare payload
+ // vectors.
+ for (const auto& payload : *larger_payloads) {
+
+ bool found = false;
+ for (const auto& other_payload : *smaller_payloads) {
+ if (payload.type_url == other_payload.type_url) {
+ if (payload.payload != other_payload.payload) {
+ return false;
+ }
+ found = true;
+ break;
+ }
+ }
+ if (!found) return false;
+ }
+ return true;
+}
+
+std::string Status::ToStringSlow() const {
+ std::string text;
+ absl::StrAppend(&text, absl::StatusCodeToString(code()), ": ", message());
+ status_internal::StatusPayloadPrinter printer =
+ status_internal::GetStatusPayloadPrinter();
+ this->ForEachPayload([&](absl::string_view type_url,
+ const absl::Cord& payload) {
+ absl::optional<std::string> result;
+ if (printer) result = printer(type_url, payload);
+ absl::StrAppend(
+ &text, " [", type_url, "='",
+ result.has_value() ? *result : absl::CHexEscape(std::string(payload)),
+ "']");
+ });
+
+ return text;
+}
+
+std::ostream& operator<<(std::ostream& os, const Status& x) {
+ os << x.ToString();
+ return os;
+}
+
+Status AbortedError(absl::string_view message) {
+ return Status(absl::StatusCode::kAborted, message);
+}
+
+Status AlreadyExistsError(absl::string_view message) {
+ return Status(absl::StatusCode::kAlreadyExists, message);
+}
+
+Status CancelledError(absl::string_view message) {
+ return Status(absl::StatusCode::kCancelled, message);
+}
+
+Status DataLossError(absl::string_view message) {
+ return Status(absl::StatusCode::kDataLoss, message);
+}
+
+Status DeadlineExceededError(absl::string_view message) {
+ return Status(absl::StatusCode::kDeadlineExceeded, message);
+}
+
+Status FailedPreconditionError(absl::string_view message) {
+ return Status(absl::StatusCode::kFailedPrecondition, message);
+}
+
+Status InternalError(absl::string_view message) {
+ return Status(absl::StatusCode::kInternal, message);
+}
+
+Status InvalidArgumentError(absl::string_view message) {
+ return Status(absl::StatusCode::kInvalidArgument, message);
+}
+
+Status NotFoundError(absl::string_view message) {
+ return Status(absl::StatusCode::kNotFound, message);
+}
+
+Status OutOfRangeError(absl::string_view message) {
+ return Status(absl::StatusCode::kOutOfRange, message);
+}
+
+Status PermissionDeniedError(absl::string_view message) {
+ return Status(absl::StatusCode::kPermissionDenied, message);
+}
+
+Status ResourceExhaustedError(absl::string_view message) {
+ return Status(absl::StatusCode::kResourceExhausted, message);
+}
+
+Status UnauthenticatedError(absl::string_view message) {
+ return Status(absl::StatusCode::kUnauthenticated, message);
+}
+
+Status UnavailableError(absl::string_view message) {
+ return Status(absl::StatusCode::kUnavailable, message);
+}
+
+Status UnimplementedError(absl::string_view message) {
+ return Status(absl::StatusCode::kUnimplemented, message);
+}
+
+Status UnknownError(absl::string_view message) {
+ return Status(absl::StatusCode::kUnknown, message);
+}
+
+bool IsAborted(const Status& status) {
+ return status.code() == absl::StatusCode::kAborted;
+}
+
+bool IsAlreadyExists(const Status& status) {
+ return status.code() == absl::StatusCode::kAlreadyExists;
+}
+
+bool IsCancelled(const Status& status) {
+ return status.code() == absl::StatusCode::kCancelled;
+}
+
+bool IsDataLoss(const Status& status) {
+ return status.code() == absl::StatusCode::kDataLoss;
+}
+
+bool IsDeadlineExceeded(const Status& status) {
+ return status.code() == absl::StatusCode::kDeadlineExceeded;
+}
+
+bool IsFailedPrecondition(const Status& status) {
+ return status.code() == absl::StatusCode::kFailedPrecondition;
+}
+
+bool IsInternal(const Status& status) {
+ return status.code() == absl::StatusCode::kInternal;
+}
+
+bool IsInvalidArgument(const Status& status) {
+ return status.code() == absl::StatusCode::kInvalidArgument;
+}
+
+bool IsNotFound(const Status& status) {
+ return status.code() == absl::StatusCode::kNotFound;
+}
+
+bool IsOutOfRange(const Status& status) {
+ return status.code() == absl::StatusCode::kOutOfRange;
+}
+
+bool IsPermissionDenied(const Status& status) {
+ return status.code() == absl::StatusCode::kPermissionDenied;
+}
+
+bool IsResourceExhausted(const Status& status) {
+ return status.code() == absl::StatusCode::kResourceExhausted;
+}
+
+bool IsUnauthenticated(const Status& status) {
+ return status.code() == absl::StatusCode::kUnauthenticated;
+}
+
+bool IsUnavailable(const Status& status) {
+ return status.code() == absl::StatusCode::kUnavailable;
+}
+
+bool IsUnimplemented(const Status& status) {
+ return status.code() == absl::StatusCode::kUnimplemented;
+}
+
+bool IsUnknown(const Status& status) {
+ return status.code() == absl::StatusCode::kUnknown;
+}
+
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/status/status.h b/third_party/abseil/absl/status/status.h
new file mode 100644
index 0000000..08d3e80
--- /dev/null
+++ b/third_party/abseil/absl/status/status.h
@@ -0,0 +1,820 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: status.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the Abseil `status` library, consisting of:
+//
+// * An `absl::Status` class for holding error handling information
+// * A set of canonical `absl::StatusCode` error codes, and associated
+// utilities for generating and propagating status codes.
+// * A set of helper functions for creating status codes and checking their
+// values
+//
+// Within Google, `absl::Status` is the primary mechanism for gracefully
+// handling errors across API boundaries (and in particular across RPC
+// boundaries). Some of these errors may be recoverable, but others may not.
+// Most functions that can produce a recoverable error should be designed to
+// return an `absl::Status` (or `absl::StatusOr`).
+//
+// Example:
+//
+// absl::Status myFunction(absl::string_view fname, ...) {
+// ...
+// // encounter error
+// if (error condition) {
+// return absl::InvalidArgumentError("bad mode");
+// }
+// // else, return OK
+// return absl::OkStatus();
+// }
+//
+// An `absl::Status` is designed to either return "OK" or one of a number of
+// different error codes, corresponding to typical error conditions.
+// In almost all cases, when using `absl::Status` you should use the canonical
+// error codes (of type `absl::StatusCode`) enumerated in this header file.
+// These canonical codes are understood across the codebase and will be
+// accepted across all API and RPC boundaries.
+#ifndef ABSL_STATUS_STATUS_H_
+#define ABSL_STATUS_STATUS_H_
+
+#include <iostream>
+#include <string>
+
+#include "absl/container/inlined_vector.h"
+#include "absl/status/internal/status_internal.h"
+#include "absl/strings/cord.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// absl::StatusCode
+//
+// An `absl::StatusCode` is an enumerated type indicating either no error ("OK")
+// or an error condition. In most cases, an `absl::Status` indicates a
+// recoverable error, and the purpose of signalling an error is to indicate what
+// action to take in response to that error. These error codes map to the proto
+// RPC error codes indicated in https://cloud.google.com/apis/design/errors.
+//
+// The errors listed below are the canonical errors associated with
+// `absl::Status` and are used throughout the codebase. As a result, these
+// error codes are somewhat generic.
+//
+// In general, try to return the most specific error that applies if more than
+// one error may pertain. For example, prefer `kOutOfRange` over
+// `kFailedPrecondition` if both codes apply. Similarly prefer `kNotFound` or
+// `kAlreadyExists` over `kFailedPrecondition`.
+//
+// Because these errors may travel RPC boundaries, these codes are tied to the
+// `google.rpc.Code` definitions within
+// https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto
+// The string value of these RPC codes is denoted within each enum below.
+//
+// If your error handling code requires more context, you can attach payloads
+// to your status. See `absl::Status::SetPayload()` and
+// `absl::Status::GetPayload()` below.
+enum class StatusCode : int {
+ // StatusCode::kOk
+ //
+ // kOK (gRPC code "OK") does not indicate an error; this value is returned on
+ // success. It is typical to check for this value before proceeding on any
+ // given call across an API or RPC boundary. To check this value, use the
+ // `absl::Status::ok()` member function rather than inspecting the raw code.
+ kOk = 0,
+
+ // StatusCode::kCancelled
+ //
+ // kCancelled (gRPC code "CANCELLED") indicates the operation was cancelled,
+ // typically by the caller.
+ kCancelled = 1,
+
+ // StatusCode::kUnknown
+ //
+ // kUnknown (gRPC code "UNKNOWN") indicates an unknown error occurred. In
+ // general, more specific errors should be raised, if possible. Errors raised
+ // by APIs that do not return enough error information may be converted to
+ // this error.
+ kUnknown = 2,
+
+ // StatusCode::kInvalidArgument
+ //
+ // kInvalidArgument (gRPC code "INVALID_ARGUMENT") indicates the caller
+ // specified an invalid argument, such a malformed filename. Note that such
+ // errors should be narrowly limited to indicate to the invalid nature of the
+ // arguments themselves. Errors with validly formed arguments that may cause
+ // errors with the state of the receiving system should be denoted with
+ // `kFailedPrecondition` instead.
+ kInvalidArgument = 3,
+
+ // StatusCode::kDeadlineExceeded
+ //
+ // kDeadlineExceeded (gRPC code "DEADLINE_EXCEEDED") indicates a deadline
+ // expired before the operation could complete. For operations that may change
+ // state within a system, this error may be returned even if the operation has
+ // completed successfully. For example, a successful response from a server
+ // could have been delayed long enough for the deadline to expire.
+ kDeadlineExceeded = 4,
+
+ // StatusCode::kNotFound
+ //
+ // kNotFound (gRPC code "NOT_FOUND") indicates some requested entity (such as
+ // a file or directory) was not found.
+ //
+ // `kNotFound` is useful if a request should be denied for an entire class of
+ // users, such as during a gradual feature rollout or undocumented allow list.
+ // If, instead, a request should be denied for specific sets of users, such as
+ // through user-based access control, use `kPermissionDenied` instead.
+ kNotFound = 5,
+
+ // StatusCode::kAlreadyExists
+ //
+ // kAlreadyExists (gRPC code "ALREADY_EXISTS") indicates the entity that a
+ // caller attempted to create (such as file or directory) is already present.
+ kAlreadyExists = 6,
+
+ // StatusCode::kPermissionDenied
+ //
+ // kPermissionDenied (gRPC code "PERMISSION_DENIED") indicates that the caller
+ // does not have permission to execute the specified operation. Note that this
+ // error is different than an error due to an *un*authenticated user. This
+ // error code does not imply the request is valid or the requested entity
+ // exists or satisfies any other pre-conditions.
+ //
+ // `kPermissionDenied` must not be used for rejections caused by exhausting
+ // some resource. Instead, use `kResourceExhausted` for those errors.
+ // `kPermissionDenied` must not be used if the caller cannot be identified.
+ // Instead, use `kUnauthenticated` for those errors.
+ kPermissionDenied = 7,
+
+ // StatusCode::kResourceExhausted
+ //
+ // kResourceExhausted (gRPC code "RESOURCE_EXHAUSTED") indicates some resource
+ // has been exhausted, perhaps a per-user quota, or perhaps the entire file
+ // system is out of space.
+ kResourceExhausted = 8,
+
+ // StatusCode::kFailedPrecondition
+ //
+ // kFailedPrecondition (gRPC code "FAILED_PRECONDITION") indicates that the
+ // operation was rejected because the system is not in a state required for
+ // the operation's execution. For example, a directory to be deleted may be
+ // non-empty, an "rmdir" operation is applied to a non-directory, etc.
+ //
+ // Some guidelines that may help a service implementer in deciding between
+ // `kFailedPrecondition`, `kAborted`, and `kUnavailable`:
+ //
+ // (a) Use `kUnavailable` if the client can retry just the failing call.
+ // (b) Use `kAborted` if the client should retry at a higher transaction
+ // level (such as when a client-specified test-and-set fails, indicating
+ // the client should restart a read-modify-write sequence).
+ // (c) Use `kFailedPrecondition` if the client should not retry until
+ // the system state has been explicitly fixed. For example, if an "rmdir"
+ // fails because the directory is non-empty, `kFailedPrecondition`
+ // should be returned since the client should not retry unless
+ // the files are deleted from the directory.
+ kFailedPrecondition = 9,
+
+ // StatusCode::kAborted
+ //
+ // kAborted (gRPC code "ABORTED") indicates the operation was aborted,
+ // typically due to a concurrency issue such as a sequencer check failure or a
+ // failed transaction.
+ //
+ // See the guidelines above for deciding between `kFailedPrecondition`,
+ // `kAborted`, and `kUnavailable`.
+ kAborted = 10,
+
+ // StatusCode::kOutOfRange
+ //
+ // kOutOfRange (gRPC code "OUT_OF_RANGE") indicates the operation was
+ // attempted past the valid range, such as seeking or reading past an
+ // end-of-file.
+ //
+ // Unlike `kInvalidArgument`, this error indicates a problem that may
+ // be fixed if the system state changes. For example, a 32-bit file
+ // system will generate `kInvalidArgument` if asked to read at an
+ // offset that is not in the range [0,2^32-1], but it will generate
+ // `kOutOfRange` if asked to read from an offset past the current
+ // file size.
+ //
+ // There is a fair bit of overlap between `kFailedPrecondition` and
+ // `kOutOfRange`. We recommend using `kOutOfRange` (the more specific
+ // error) when it applies so that callers who are iterating through
+ // a space can easily look for an `kOutOfRange` error to detect when
+ // they are done.
+ kOutOfRange = 11,
+
+ // StatusCode::kUnimplemented
+ //
+ // kUnimplemented (gRPC code "UNIMPLEMENTED") indicates the operation is not
+ // implemented or supported in this service. In this case, the operation
+ // should not be re-attempted.
+ kUnimplemented = 12,
+
+ // StatusCode::kInternal
+ //
+ // kInternal (gRPC code "INTERNAL") indicates an internal error has occurred
+ // and some invariants expected by the underlying system have not been
+ // satisfied. This error code is reserved for serious errors.
+ kInternal = 13,
+
+ // StatusCode::kUnavailable
+ //
+ // kUnavailable (gRPC code "UNAVAILABLE") indicates the service is currently
+ // unavailable and that this is most likely a transient condition. An error
+ // such as this can be corrected by retrying with a backoff scheme. Note that
+ // it is not always safe to retry non-idempotent operations.
+ //
+ // See the guidelines above for deciding between `kFailedPrecondition`,
+ // `kAborted`, and `kUnavailable`.
+ kUnavailable = 14,
+
+ // StatusCode::kDataLoss
+ //
+ // kDataLoss (gRPC code "DATA_LOSS") indicates that unrecoverable data loss or
+ // corruption has occurred. As this error is serious, proper alerting should
+ // be attached to errors such as this.
+ kDataLoss = 15,
+
+ // StatusCode::kUnauthenticated
+ //
+ // kUnauthenticated (gRPC code "UNAUTHENTICATED") indicates that the request
+ // does not have valid authentication credentials for the operation. Correct
+ // the authentication and try again.
+ kUnauthenticated = 16,
+
+ // StatusCode::DoNotUseReservedForFutureExpansionUseDefaultInSwitchInstead_
+ //
+ // NOTE: this error code entry should not be used and you should not rely on
+ // its value, which may change.
+ //
+ // The purpose of this enumerated value is to force people who handle status
+ // codes with `switch()` statements to *not* simply enumerate all possible
+ // values, but instead provide a "default:" case. Providing such a default
+ // case ensures that code will compile when new codes are added.
+ kDoNotUseReservedForFutureExpansionUseDefaultInSwitchInstead_ = 20
+};
+
+// StatusCodeToString()
+//
+// Returns the name for the status code, or "" if it is an unknown value.
+std::string StatusCodeToString(StatusCode code);
+
+// operator<<
+//
+// Streams StatusCodeToString(code) to `os`.
+std::ostream& operator<<(std::ostream& os, StatusCode code);
+
+// absl::Status
+//
+// The `absl::Status` class is generally used to gracefully handle errors
+// across API boundaries (and in particular across RPC boundaries). Some of
+// these errors may be recoverable, but others may not. Most
+// functions which can produce a recoverable error should be designed to return
+// either an `absl::Status` (or the similar `absl::StatusOr<T>`, which holds
+// either an object of type `T` or an error).
+//
+// API developers should construct their functions to return `absl::OkStatus()`
+// upon success, or an `absl::StatusCode` upon another type of error (e.g
+// an `absl::StatusCode::kInvalidArgument` error). The API provides convenience
+// functions to constuct each status code.
+//
+// Example:
+//
+// absl::Status myFunction(absl::string_view fname, ...) {
+// ...
+// // encounter error
+// if (error condition) {
+// // Construct an absl::StatusCode::kInvalidArgument error
+// return absl::InvalidArgumentError("bad mode");
+// }
+// // else, return OK
+// return absl::OkStatus();
+// }
+//
+// Users handling status error codes should prefer checking for an OK status
+// using the `ok()` member function. Handling multiple error codes may justify
+// use of switch statement, but only check for error codes you know how to
+// handle; do not try to exhaustively match against all canonical error codes.
+// Errors that cannot be handled should be logged and/or propagated for higher
+// levels to deal with. If you do use a switch statement, make sure that you
+// also provide a `default:` switch case, so that code does not break as other
+// canonical codes are added to the API.
+//
+// Example:
+//
+// absl::Status result = DoSomething();
+// if (!result.ok()) {
+// LOG(ERROR) << result;
+// }
+//
+// // Provide a default if switching on multiple error codes
+// switch (result.code()) {
+// // The user hasn't authenticated. Ask them to reauth
+// case absl::StatusCode::kUnauthenticated:
+// DoReAuth();
+// break;
+// // The user does not have permission. Log an error.
+// case absl::StatusCode::kPermissionDenied:
+// LOG(ERROR) << result;
+// break;
+// // Propagate the error otherwise.
+// default:
+// return true;
+// }
+//
+// An `absl::Status` can optionally include a payload with more information
+// about the error. Typically, this payload serves one of several purposes:
+//
+// * It may provide more fine-grained semantic information about the error to
+// facilitate actionable remedies.
+// * It may provide human-readable contexual information that is more
+// appropriate to display to an end user.
+//
+// Example:
+//
+// absl::Status result = DoSomething();
+// // Inform user to retry after 30 seconds
+// // See more error details in googleapis/google/rpc/error_details.proto
+// if (absl::IsResourceExhausted(result)) {
+// google::rpc::RetryInfo info;
+// info.retry_delay().seconds() = 30;
+// // Payloads require a unique key (a URL to ensure no collisions with
+// // other payloads), and an `absl::Cord` to hold the encoded data.
+// absl::string_view url = "type.googleapis.com/google.rpc.RetryInfo";
+// result.SetPayload(url, info.SerializeAsCord());
+// return result;
+// }
+//
+class ABSL_MUST_USE_RESULT Status final {
+ public:
+ // Constructors
+
+ // This default constructor creates an OK status with no message or payload.
+ // Avoid this constructor and prefer explicit construction of an OK status
+ // with `absl::OkStatus()`.
+ Status();
+
+ // Creates a status in the canonical error space with the specified
+ // `absl::StatusCode` and error message. If `code == absl::StatusCode::kOk`,
+ // `msg` is ignored and an object identical to an OK status is constructed.
+ //
+ // The `msg` string must be in UTF-8. The implementation may complain (e.g.,
+ // by printing a warning) if it is not.
+ Status(absl::StatusCode code, absl::string_view msg);
+
+ Status(const Status&);
+ Status& operator=(const Status& x);
+
+ // Move operators
+
+ // The moved-from state is valid but unspecified.
+ Status(Status&&) noexcept;
+ Status& operator=(Status&&);
+
+ ~Status();
+
+ // Status::Update()
+ //
+ // Updates the existing status with `new_status` provided that `this->ok()`.
+ // If the existing status already contains a non-OK error, this update has no
+ // effect and preserves the current data. Note that this behavior may change
+ // in the future to augment a current non-ok status with additional
+ // information about `new_status`.
+ //
+ // `Update()` provides a convenient way of keeping track of the first error
+ // encountered.
+ //
+ // Example:
+ // // Instead of "if (overall_status.ok()) overall_status = new_status"
+ // overall_status.Update(new_status);
+ //
+ void Update(const Status& new_status);
+ void Update(Status&& new_status);
+
+ // Status::ok()
+ //
+ // Returns `true` if `this->ok()`. Prefer checking for an OK status using this
+ // member function.
+ ABSL_MUST_USE_RESULT bool ok() const;
+
+ // Status::code()
+ //
+ // Returns the canonical error code of type `absl::StatusCode` of this status.
+ absl::StatusCode code() const;
+
+ // Status::raw_code()
+ //
+ // Returns a raw (canonical) error code corresponding to the enum value of
+ // `google.rpc.Code` definitions within
+ // https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto.
+ // These values could be out of the range of canonical `absl::StatusCode`
+ // enum values.
+ //
+ // NOTE: This function should only be called when converting to an associated
+ // wire format. Use `Status::code()` for error handling.
+ int raw_code() const;
+
+ // Status::message()
+ //
+ // Returns the error message associated with this error code, if available.
+ // Note that this message rarely describes the error code. It is not unusual
+ // for the error message to be the empty string. As a result, prefer
+ // `Status::ToString()` for debug logging.
+ absl::string_view message() const;
+
+ friend bool operator==(const Status&, const Status&);
+ friend bool operator!=(const Status&, const Status&);
+
+ // Status::ToString()
+ //
+ // Returns a combination of the error code name, the message and any
+ // associated payload messages. This string is designed simply to be human
+ // readable and its exact format should not be load bearing. Do not depend on
+ // the exact format of the result of `ToString()` which is subject to change.
+ //
+ // The printed code name and the message are generally substrings of the
+ // result, and the payloads to be printed use the status payload printer
+ // mechanism (which is internal).
+ std::string ToString() const;
+
+ // Status::IgnoreError()
+ //
+ // Ignores any errors. This method does nothing except potentially suppress
+ // complaints from any tools that are checking that errors are not dropped on
+ // the floor.
+ void IgnoreError() const;
+
+ // swap()
+ //
+ // Swap the contents of one status with another.
+ friend void swap(Status& a, Status& b);
+
+ //----------------------------------------------------------------------------
+ // Payload Management APIs
+ //----------------------------------------------------------------------------
+
+ // A payload may be attached to a status to provide additional context to an
+ // error that may not be satisifed by an existing `absl::StatusCode`.
+ // Typically, this payload serves one of several purposes:
+ //
+ // * It may provide more fine-grained semantic information about the error
+ // to facilitate actionable remedies.
+ // * It may provide human-readable contexual information that is more
+ // appropriate to display to an end user.
+ //
+ // A payload consists of a [key,value] pair, where the key is a string
+ // referring to a unique "type URL" and the value is an object of type
+ // `absl::Cord` to hold the contextual data.
+ //
+ // The "type URL" should be unique and follow the format of a URL
+ // (https://en.wikipedia.org/wiki/URL) and, ideally, provide some
+ // documentation or schema on how to interpret its associated data. For
+ // example, the default type URL for a protobuf message type is
+ // "type.googleapis.com/packagename.messagename". Other custom wire formats
+ // should define the format of type URL in a similar practice so as to
+ // minimize the chance of conflict between type URLs.
+ // Users should ensure that the type URL can be mapped to a concrete
+ // C++ type if they want to deserialize the payload and read it effectively.
+ //
+ // To attach a payload to a status object, call `Status::SetPayload()`,
+ // passing it the type URL and an `absl::Cord` of associated data. Similarly,
+ // to extract the payload from a status, call `Status::GetPayload()`. You
+ // may attach multiple payloads (with differing type URLs) to any given
+ // status object, provided that the status is currently exhibiting an error
+ // code (i.e. is not OK).
+
+ // Status::GetPayload()
+ //
+ // Gets the payload of a status given its unique `type_url` key, if present.
+ absl::optional<absl::Cord> GetPayload(absl::string_view type_url) const;
+
+ // Status::SetPayload()
+ //
+ // Sets the payload for a non-ok status using a `type_url` key, overwriting
+ // any existing payload for that `type_url`.
+ //
+ // NOTE: This function does nothing if the Status is ok.
+ void SetPayload(absl::string_view type_url, absl::Cord payload);
+
+ // Status::ErasePayload()
+ //
+ // Erases the payload corresponding to the `type_url` key. Returns `true` if
+ // the payload was present.
+ bool ErasePayload(absl::string_view type_url);
+
+ // Status::ForEachPayload()
+ //
+ // Iterates over the stored payloads and calls the
+ // `visitor(type_key, payload)` callable for each one.
+ //
+ // NOTE: The order of calls to `visitor()` is not specified and may change at
+ // any time.
+ //
+ // NOTE: Any mutation on the same 'absl::Status' object during visitation is
+ // forbidden and could result in undefined behavior.
+ void ForEachPayload(
+ const std::function<void(absl::string_view, const absl::Cord&)>& visitor)
+ const;
+
+ private:
+ friend Status CancelledError();
+
+ // Creates a status in the canonical error space with the specified
+ // code, and an empty error message.
+ explicit Status(absl::StatusCode code);
+
+ static void UnrefNonInlined(uintptr_t rep);
+ static void Ref(uintptr_t rep);
+ static void Unref(uintptr_t rep);
+
+ // REQUIRES: !ok()
+ // Ensures rep_ is not shared with any other Status.
+ void PrepareToModify();
+
+ const status_internal::Payloads* GetPayloads() const;
+ status_internal::Payloads* GetPayloads();
+
+ // Takes ownership of payload.
+ static uintptr_t NewRep(absl::StatusCode code, absl::string_view msg,
+ std::unique_ptr<status_internal::Payloads> payload);
+ static bool EqualsSlow(const absl::Status& a, const absl::Status& b);
+
+ // MSVC 14.0 limitation requires the const.
+ static constexpr const char kMovedFromString[] =
+ "Status accessed after move.";
+
+ static const std::string* EmptyString();
+ static const std::string* MovedFromString();
+
+ // Returns whether rep contains an inlined representation.
+ // See rep_ for details.
+ static bool IsInlined(uintptr_t rep);
+
+ // Indicates whether this Status was the rhs of a move operation. See rep_
+ // for details.
+ static bool IsMovedFrom(uintptr_t rep);
+ static uintptr_t MovedFromRep();
+
+ // Convert between error::Code and the inlined uintptr_t representation used
+ // by rep_. See rep_ for details.
+ static uintptr_t CodeToInlinedRep(absl::StatusCode code);
+ static absl::StatusCode InlinedRepToCode(uintptr_t rep);
+
+ // Converts between StatusRep* and the external uintptr_t representation used
+ // by rep_. See rep_ for details.
+ static uintptr_t PointerToRep(status_internal::StatusRep* r);
+ static status_internal::StatusRep* RepToPointer(uintptr_t r);
+
+ // Returns string for non-ok Status.
+ std::string ToStringSlow() const;
+
+ // Status supports two different representations.
+ // - When the low bit is off it is an inlined representation.
+ // It uses the canonical error space, no message or payload.
+ // The error code is (rep_ >> 2).
+ // The (rep_ & 2) bit is the "moved from" indicator, used in IsMovedFrom().
+ // - When the low bit is on it is an external representation.
+ // In this case all the data comes from a heap allocated Rep object.
+ // (rep_ - 1) is a status_internal::StatusRep* pointer to that structure.
+ uintptr_t rep_;
+};
+
+// OkStatus()
+//
+// Returns an OK status, equivalent to a default constructed instance. Prefer
+// usage of `absl::OkStatus()` when constructing such an OK status.
+Status OkStatus();
+
+// operator<<()
+//
+// Prints a human-readable representation of `x` to `os`.
+std::ostream& operator<<(std::ostream& os, const Status& x);
+
+// IsAborted()
+// IsAlreadyExists()
+// IsCancelled()
+// IsDataLoss()
+// IsDeadlineExceeded()
+// IsFailedPrecondition()
+// IsInternal()
+// IsInvalidArgument()
+// IsNotFound()
+// IsOutOfRange()
+// IsPermissionDenied()
+// IsResourceExhausted()
+// IsUnauthenticated()
+// IsUnavailable()
+// IsUnimplemented()
+// IsUnknown()
+//
+// These convenience functions return `true` if a given status matches the
+// `absl::StatusCode` error code of its associated function.
+ABSL_MUST_USE_RESULT bool IsAborted(const Status& status);
+ABSL_MUST_USE_RESULT bool IsAlreadyExists(const Status& status);
+ABSL_MUST_USE_RESULT bool IsCancelled(const Status& status);
+ABSL_MUST_USE_RESULT bool IsDataLoss(const Status& status);
+ABSL_MUST_USE_RESULT bool IsDeadlineExceeded(const Status& status);
+ABSL_MUST_USE_RESULT bool IsFailedPrecondition(const Status& status);
+ABSL_MUST_USE_RESULT bool IsInternal(const Status& status);
+ABSL_MUST_USE_RESULT bool IsInvalidArgument(const Status& status);
+ABSL_MUST_USE_RESULT bool IsNotFound(const Status& status);
+ABSL_MUST_USE_RESULT bool IsOutOfRange(const Status& status);
+ABSL_MUST_USE_RESULT bool IsPermissionDenied(const Status& status);
+ABSL_MUST_USE_RESULT bool IsResourceExhausted(const Status& status);
+ABSL_MUST_USE_RESULT bool IsUnauthenticated(const Status& status);
+ABSL_MUST_USE_RESULT bool IsUnavailable(const Status& status);
+ABSL_MUST_USE_RESULT bool IsUnimplemented(const Status& status);
+ABSL_MUST_USE_RESULT bool IsUnknown(const Status& status);
+
+// AbortedError()
+// AlreadyExistsError()
+// CancelledError()
+// DataLossError()
+// DeadlineExceededError()
+// FailedPreconditionError()
+// InternalError()
+// InvalidArgumentError()
+// NotFoundError()
+// OutOfRangeError()
+// PermissionDeniedError()
+// ResourceExhaustedError()
+// UnauthenticatedError()
+// UnavailableError()
+// UnimplementedError()
+// UnknownError()
+//
+// These convenience functions create an `absl::Status` object with an error
+// code as indicated by the associated function name, using the error message
+// passed in `message`.
+Status AbortedError(absl::string_view message);
+Status AlreadyExistsError(absl::string_view message);
+Status CancelledError(absl::string_view message);
+Status DataLossError(absl::string_view message);
+Status DeadlineExceededError(absl::string_view message);
+Status FailedPreconditionError(absl::string_view message);
+Status InternalError(absl::string_view message);
+Status InvalidArgumentError(absl::string_view message);
+Status NotFoundError(absl::string_view message);
+Status OutOfRangeError(absl::string_view message);
+Status PermissionDeniedError(absl::string_view message);
+Status ResourceExhaustedError(absl::string_view message);
+Status UnauthenticatedError(absl::string_view message);
+Status UnavailableError(absl::string_view message);
+Status UnimplementedError(absl::string_view message);
+Status UnknownError(absl::string_view message);
+
+//------------------------------------------------------------------------------
+// Implementation details follow
+//------------------------------------------------------------------------------
+
+inline Status::Status() : rep_(CodeToInlinedRep(absl::StatusCode::kOk)) {}
+
+inline Status::Status(absl::StatusCode code) : rep_(CodeToInlinedRep(code)) {}
+
+inline Status::Status(const Status& x) : rep_(x.rep_) { Ref(rep_); }
+
+inline Status& Status::operator=(const Status& x) {
+ uintptr_t old_rep = rep_;
+ if (x.rep_ != old_rep) {
+ Ref(x.rep_);
+ rep_ = x.rep_;
+ Unref(old_rep);
+ }
+ return *this;
+}
+
+inline Status::Status(Status&& x) noexcept : rep_(x.rep_) {
+ x.rep_ = MovedFromRep();
+}
+
+inline Status& Status::operator=(Status&& x) {
+ uintptr_t old_rep = rep_;
+ if (x.rep_ != old_rep) {
+ rep_ = x.rep_;
+ x.rep_ = MovedFromRep();
+ Unref(old_rep);
+ }
+ return *this;
+}
+
+inline void Status::Update(const Status& new_status) {
+ if (ok()) {
+ *this = new_status;
+ }
+}
+
+inline void Status::Update(Status&& new_status) {
+ if (ok()) {
+ *this = std::move(new_status);
+ }
+}
+
+inline Status::~Status() { Unref(rep_); }
+
+inline bool Status::ok() const {
+ return rep_ == CodeToInlinedRep(absl::StatusCode::kOk);
+}
+
+inline absl::string_view Status::message() const {
+ return !IsInlined(rep_)
+ ? RepToPointer(rep_)->message
+ : (IsMovedFrom(rep_) ? absl::string_view(kMovedFromString)
+ : absl::string_view());
+}
+
+inline bool operator==(const Status& lhs, const Status& rhs) {
+ return lhs.rep_ == rhs.rep_ || Status::EqualsSlow(lhs, rhs);
+}
+
+inline bool operator!=(const Status& lhs, const Status& rhs) {
+ return !(lhs == rhs);
+}
+
+inline std::string Status::ToString() const {
+ return ok() ? "OK" : ToStringSlow();
+}
+
+inline void Status::IgnoreError() const {
+ // no-op
+}
+
+inline void swap(absl::Status& a, absl::Status& b) {
+ using std::swap;
+ swap(a.rep_, b.rep_);
+}
+
+inline const status_internal::Payloads* Status::GetPayloads() const {
+ return IsInlined(rep_) ? nullptr : RepToPointer(rep_)->payloads.get();
+}
+
+inline status_internal::Payloads* Status::GetPayloads() {
+ return IsInlined(rep_) ? nullptr : RepToPointer(rep_)->payloads.get();
+}
+
+inline bool Status::IsInlined(uintptr_t rep) { return (rep & 1) == 0; }
+
+inline bool Status::IsMovedFrom(uintptr_t rep) {
+ return IsInlined(rep) && (rep & 2) != 0;
+}
+
+inline uintptr_t Status::MovedFromRep() {
+ return CodeToInlinedRep(absl::StatusCode::kInternal) | 2;
+}
+
+inline uintptr_t Status::CodeToInlinedRep(absl::StatusCode code) {
+ return static_cast<uintptr_t>(code) << 2;
+}
+
+inline absl::StatusCode Status::InlinedRepToCode(uintptr_t rep) {
+ assert(IsInlined(rep));
+ return static_cast<absl::StatusCode>(rep >> 2);
+}
+
+inline status_internal::StatusRep* Status::RepToPointer(uintptr_t rep) {
+ assert(!IsInlined(rep));
+ return reinterpret_cast<status_internal::StatusRep*>(rep - 1);
+}
+
+inline uintptr_t Status::PointerToRep(status_internal::StatusRep* rep) {
+ return reinterpret_cast<uintptr_t>(rep) + 1;
+}
+
+inline void Status::Ref(uintptr_t rep) {
+ if (!IsInlined(rep)) {
+ RepToPointer(rep)->ref.fetch_add(1, std::memory_order_relaxed);
+ }
+}
+
+inline void Status::Unref(uintptr_t rep) {
+ if (!IsInlined(rep)) {
+ UnrefNonInlined(rep);
+ }
+}
+
+inline Status OkStatus() { return Status(); }
+
+// Creates a `Status` object with the `absl::StatusCode::kCancelled` error code
+// and an empty message. It is provided only for efficiency, given that
+// message-less kCancelled errors are common in the infrastructure.
+inline Status CancelledError() { return Status(absl::StatusCode::kCancelled); }
+
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_STATUS_STATUS_H_
diff --git a/third_party/abseil/absl/status/status_payload_printer.cc b/third_party/abseil/absl/status/status_payload_printer.cc
new file mode 100644
index 0000000..a47aea1
--- /dev/null
+++ b/third_party/abseil/absl/status/status_payload_printer.cc
@@ -0,0 +1,38 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "absl/status/status_payload_printer.h"
+
+#include <atomic>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/atomic_hook.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace status_internal {
+
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
+static absl::base_internal::AtomicHook<StatusPayloadPrinter> storage;
+
+void SetStatusPayloadPrinter(StatusPayloadPrinter printer) {
+ storage.Store(printer);
+}
+
+StatusPayloadPrinter GetStatusPayloadPrinter() {
+ return storage.Load();
+}
+
+} // namespace status_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/status/status_payload_printer.h b/third_party/abseil/absl/status/status_payload_printer.h
new file mode 100644
index 0000000..5e0937f
--- /dev/null
+++ b/third_party/abseil/absl/status/status_payload_printer.h
@@ -0,0 +1,51 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef ABSL_STATUS_STATUS_PAYLOAD_PRINTER_H_
+#define ABSL_STATUS_STATUS_PAYLOAD_PRINTER_H_
+
+#include <string>
+
+#include "absl/strings/cord.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace status_internal {
+
+// By default, `Status::ToString` and `operator<<(Status)` print a payload by
+// dumping the type URL and the raw bytes. To help debugging, we provide an
+// extension point, which is a global printer function that can be set by users
+// to specify how to print payloads. The function takes the type URL and the
+// payload as input, and should return a valid human-readable string on success
+// or `absl::nullopt` on failure (in which case it falls back to the default
+// approach of printing the raw bytes).
+// NOTE: This is an internal API and the design is subject to change in the
+// future in a non-backward-compatible way. Since it's only meant for debugging
+// purpose, you should not rely on it in any critical logic.
+using StatusPayloadPrinter = absl::optional<std::string> (*)(absl::string_view,
+ const absl::Cord&);
+
+// Sets the global payload printer. Only one printer should be set per process.
+// If multiple printers are set, it's undefined which one will be used.
+void SetStatusPayloadPrinter(StatusPayloadPrinter);
+
+// Returns the global payload printer if previously set, otherwise `nullptr`.
+StatusPayloadPrinter GetStatusPayloadPrinter();
+
+} // namespace status_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_STATUS_STATUS_PAYLOAD_PRINTER_H_
diff --git a/third_party/abseil/absl/status/status_test.cc b/third_party/abseil/absl/status/status_test.cc
new file mode 100644
index 0000000..25333fa
--- /dev/null
+++ b/third_party/abseil/absl/status/status_test.cc
@@ -0,0 +1,464 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/status/status.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/strings/str_cat.h"
+
+namespace {
+
+using ::testing::Eq;
+using ::testing::HasSubstr;
+using ::testing::Optional;
+using ::testing::UnorderedElementsAreArray;
+
+TEST(StatusCode, InsertionOperator) {
+ const absl::StatusCode code = absl::StatusCode::kUnknown;
+ std::ostringstream oss;
+ oss << code;
+ EXPECT_EQ(oss.str(), absl::StatusCodeToString(code));
+}
+
+// This structure holds the details for testing a single error code,
+// its creator, and its classifier.
+struct ErrorTest {
+ absl::StatusCode code;
+ using Creator = absl::Status (*)(absl::string_view);
+ using Classifier = bool (*)(const absl::Status&);
+ Creator creator;
+ Classifier classifier;
+};
+
+constexpr ErrorTest kErrorTests[]{
+ {absl::StatusCode::kCancelled, absl::CancelledError, absl::IsCancelled},
+ {absl::StatusCode::kUnknown, absl::UnknownError, absl::IsUnknown},
+ {absl::StatusCode::kInvalidArgument, absl::InvalidArgumentError,
+ absl::IsInvalidArgument},
+ {absl::StatusCode::kDeadlineExceeded, absl::DeadlineExceededError,
+ absl::IsDeadlineExceeded},
+ {absl::StatusCode::kNotFound, absl::NotFoundError, absl::IsNotFound},
+ {absl::StatusCode::kAlreadyExists, absl::AlreadyExistsError,
+ absl::IsAlreadyExists},
+ {absl::StatusCode::kPermissionDenied, absl::PermissionDeniedError,
+ absl::IsPermissionDenied},
+ {absl::StatusCode::kResourceExhausted, absl::ResourceExhaustedError,
+ absl::IsResourceExhausted},
+ {absl::StatusCode::kFailedPrecondition, absl::FailedPreconditionError,
+ absl::IsFailedPrecondition},
+ {absl::StatusCode::kAborted, absl::AbortedError, absl::IsAborted},
+ {absl::StatusCode::kOutOfRange, absl::OutOfRangeError, absl::IsOutOfRange},
+ {absl::StatusCode::kUnimplemented, absl::UnimplementedError,
+ absl::IsUnimplemented},
+ {absl::StatusCode::kInternal, absl::InternalError, absl::IsInternal},
+ {absl::StatusCode::kUnavailable, absl::UnavailableError,
+ absl::IsUnavailable},
+ {absl::StatusCode::kDataLoss, absl::DataLossError, absl::IsDataLoss},
+ {absl::StatusCode::kUnauthenticated, absl::UnauthenticatedError,
+ absl::IsUnauthenticated},
+};
+
+TEST(Status, CreateAndClassify) {
+ for (const auto& test : kErrorTests) {
+ SCOPED_TRACE(absl::StatusCodeToString(test.code));
+
+ // Ensure that the creator does, in fact, create status objects with the
+ // expected error code and message.
+ std::string message =
+ absl::StrCat("error code ", test.code, " test message");
+ absl::Status status = test.creator(message);
+ EXPECT_EQ(test.code, status.code());
+ EXPECT_EQ(message, status.message());
+
+ // Ensure that the classifier returns true for a status produced by the
+ // creator.
+ EXPECT_TRUE(test.classifier(status));
+
+ // Ensure that the classifier returns false for status with a different
+ // code.
+ for (const auto& other : kErrorTests) {
+ if (other.code != test.code) {
+ EXPECT_FALSE(test.classifier(absl::Status(other.code, "")))
+ << " other.code = " << other.code;
+ }
+ }
+ }
+}
+
+TEST(Status, DefaultConstructor) {
+ absl::Status status;
+ EXPECT_TRUE(status.ok());
+ EXPECT_EQ(absl::StatusCode::kOk, status.code());
+ EXPECT_EQ("", status.message());
+}
+
+TEST(Status, OkStatus) {
+ absl::Status status = absl::OkStatus();
+ EXPECT_TRUE(status.ok());
+ EXPECT_EQ(absl::StatusCode::kOk, status.code());
+ EXPECT_EQ("", status.message());
+}
+
+TEST(Status, ConstructorWithCodeMessage) {
+ {
+ absl::Status status(absl::StatusCode::kCancelled, "");
+ EXPECT_FALSE(status.ok());
+ EXPECT_EQ(absl::StatusCode::kCancelled, status.code());
+ EXPECT_EQ("", status.message());
+ }
+ {
+ absl::Status status(absl::StatusCode::kInternal, "message");
+ EXPECT_FALSE(status.ok());
+ EXPECT_EQ(absl::StatusCode::kInternal, status.code());
+ EXPECT_EQ("message", status.message());
+ }
+}
+
+TEST(Status, ConstructOutOfRangeCode) {
+ const int kRawCode = 9999;
+ absl::Status status(static_cast<absl::StatusCode>(kRawCode), "");
+ EXPECT_EQ(absl::StatusCode::kUnknown, status.code());
+ EXPECT_EQ(kRawCode, status.raw_code());
+}
+
+constexpr char kUrl1[] = "url.payload.1";
+constexpr char kUrl2[] = "url.payload.2";
+constexpr char kUrl3[] = "url.payload.3";
+constexpr char kUrl4[] = "url.payload.xx";
+
+constexpr char kPayload1[] = "aaaaa";
+constexpr char kPayload2[] = "bbbbb";
+constexpr char kPayload3[] = "ccccc";
+
+using PayloadsVec = std::vector<std::pair<std::string, absl::Cord>>;
+
+TEST(Status, TestGetSetPayload) {
+ absl::Status ok_status = absl::OkStatus();
+ ok_status.SetPayload(kUrl1, absl::Cord(kPayload1));
+ ok_status.SetPayload(kUrl2, absl::Cord(kPayload2));
+
+ EXPECT_FALSE(ok_status.GetPayload(kUrl1));
+ EXPECT_FALSE(ok_status.GetPayload(kUrl2));
+
+ absl::Status bad_status(absl::StatusCode::kInternal, "fail");
+ bad_status.SetPayload(kUrl1, absl::Cord(kPayload1));
+ bad_status.SetPayload(kUrl2, absl::Cord(kPayload2));
+
+ EXPECT_THAT(bad_status.GetPayload(kUrl1), Optional(Eq(kPayload1)));
+ EXPECT_THAT(bad_status.GetPayload(kUrl2), Optional(Eq(kPayload2)));
+
+ EXPECT_FALSE(bad_status.GetPayload(kUrl3));
+
+ bad_status.SetPayload(kUrl1, absl::Cord(kPayload3));
+ EXPECT_THAT(bad_status.GetPayload(kUrl1), Optional(Eq(kPayload3)));
+
+ // Testing dynamically generated type_url
+ bad_status.SetPayload(absl::StrCat(kUrl1, ".1"), absl::Cord(kPayload1));
+ EXPECT_THAT(bad_status.GetPayload(absl::StrCat(kUrl1, ".1")),
+ Optional(Eq(kPayload1)));
+}
+
+TEST(Status, TestErasePayload) {
+ absl::Status bad_status(absl::StatusCode::kInternal, "fail");
+ bad_status.SetPayload(kUrl1, absl::Cord(kPayload1));
+ bad_status.SetPayload(kUrl2, absl::Cord(kPayload2));
+ bad_status.SetPayload(kUrl3, absl::Cord(kPayload3));
+
+ EXPECT_FALSE(bad_status.ErasePayload(kUrl4));
+
+ EXPECT_TRUE(bad_status.GetPayload(kUrl2));
+ EXPECT_TRUE(bad_status.ErasePayload(kUrl2));
+ EXPECT_FALSE(bad_status.GetPayload(kUrl2));
+ EXPECT_FALSE(bad_status.ErasePayload(kUrl2));
+
+ EXPECT_TRUE(bad_status.ErasePayload(kUrl1));
+ EXPECT_TRUE(bad_status.ErasePayload(kUrl3));
+
+ bad_status.SetPayload(kUrl1, absl::Cord(kPayload1));
+ EXPECT_TRUE(bad_status.ErasePayload(kUrl1));
+}
+
+TEST(Status, TestComparePayloads) {
+ absl::Status bad_status1(absl::StatusCode::kInternal, "fail");
+ bad_status1.SetPayload(kUrl1, absl::Cord(kPayload1));
+ bad_status1.SetPayload(kUrl2, absl::Cord(kPayload2));
+ bad_status1.SetPayload(kUrl3, absl::Cord(kPayload3));
+
+ absl::Status bad_status2(absl::StatusCode::kInternal, "fail");
+ bad_status2.SetPayload(kUrl2, absl::Cord(kPayload2));
+ bad_status2.SetPayload(kUrl3, absl::Cord(kPayload3));
+ bad_status2.SetPayload(kUrl1, absl::Cord(kPayload1));
+
+ EXPECT_EQ(bad_status1, bad_status2);
+}
+
+TEST(Status, TestComparePayloadsAfterErase) {
+ absl::Status payload_status(absl::StatusCode::kInternal, "");
+ payload_status.SetPayload(kUrl1, absl::Cord(kPayload1));
+ payload_status.SetPayload(kUrl2, absl::Cord(kPayload2));
+
+ absl::Status empty_status(absl::StatusCode::kInternal, "");
+
+ // Different payloads, not equal
+ EXPECT_NE(payload_status, empty_status);
+ EXPECT_TRUE(payload_status.ErasePayload(kUrl1));
+
+ // Still Different payloads, still not equal.
+ EXPECT_NE(payload_status, empty_status);
+ EXPECT_TRUE(payload_status.ErasePayload(kUrl2));
+
+ // Both empty payloads, should be equal
+ EXPECT_EQ(payload_status, empty_status);
+}
+
+PayloadsVec AllVisitedPayloads(const absl::Status& s) {
+ PayloadsVec result;
+
+ s.ForEachPayload([&](absl::string_view type_url, const absl::Cord& payload) {
+ result.push_back(std::make_pair(std::string(type_url), payload));
+ });
+
+ return result;
+}
+
+TEST(Status, TestForEachPayload) {
+ absl::Status bad_status(absl::StatusCode::kInternal, "fail");
+ bad_status.SetPayload(kUrl1, absl::Cord(kPayload1));
+ bad_status.SetPayload(kUrl2, absl::Cord(kPayload2));
+ bad_status.SetPayload(kUrl3, absl::Cord(kPayload3));
+
+ int count = 0;
+
+ bad_status.ForEachPayload(
+ [&count](absl::string_view, const absl::Cord&) { ++count; });
+
+ EXPECT_EQ(count, 3);
+
+ PayloadsVec expected_payloads = {{kUrl1, absl::Cord(kPayload1)},
+ {kUrl2, absl::Cord(kPayload2)},
+ {kUrl3, absl::Cord(kPayload3)}};
+
+ // Test that we visit all the payloads in the status.
+ PayloadsVec visited_payloads = AllVisitedPayloads(bad_status);
+ EXPECT_THAT(visited_payloads, UnorderedElementsAreArray(expected_payloads));
+
+ // Test that visitation order is not consistent between run.
+ std::vector<absl::Status> scratch;
+ while (true) {
+ scratch.emplace_back(absl::StatusCode::kInternal, "fail");
+
+ scratch.back().SetPayload(kUrl1, absl::Cord(kPayload1));
+ scratch.back().SetPayload(kUrl2, absl::Cord(kPayload2));
+ scratch.back().SetPayload(kUrl3, absl::Cord(kPayload3));
+
+ if (AllVisitedPayloads(scratch.back()) != visited_payloads) {
+ break;
+ }
+ }
+}
+
+TEST(Status, ToString) {
+ absl::Status s(absl::StatusCode::kInternal, "fail");
+ EXPECT_EQ("INTERNAL: fail", s.ToString());
+ s.SetPayload("foo", absl::Cord("bar"));
+ EXPECT_EQ("INTERNAL: fail [foo='bar']", s.ToString());
+ s.SetPayload("bar", absl::Cord("\377"));
+ EXPECT_THAT(s.ToString(),
+ AllOf(HasSubstr("INTERNAL: fail"), HasSubstr("[foo='bar']"),
+ HasSubstr("[bar='\\xff']")));
+}
+
+absl::Status EraseAndReturn(const absl::Status& base) {
+ absl::Status copy = base;
+ EXPECT_TRUE(copy.ErasePayload(kUrl1));
+ return copy;
+}
+
+TEST(Status, CopyOnWriteForErasePayload) {
+ {
+ absl::Status base(absl::StatusCode::kInvalidArgument, "fail");
+ base.SetPayload(kUrl1, absl::Cord(kPayload1));
+ EXPECT_TRUE(base.GetPayload(kUrl1).has_value());
+ absl::Status copy = EraseAndReturn(base);
+ EXPECT_TRUE(base.GetPayload(kUrl1).has_value());
+ EXPECT_FALSE(copy.GetPayload(kUrl1).has_value());
+ }
+ {
+ absl::Status base(absl::StatusCode::kInvalidArgument, "fail");
+ base.SetPayload(kUrl1, absl::Cord(kPayload1));
+ absl::Status copy = base;
+
+ EXPECT_TRUE(base.GetPayload(kUrl1).has_value());
+ EXPECT_TRUE(copy.GetPayload(kUrl1).has_value());
+
+ EXPECT_TRUE(base.ErasePayload(kUrl1));
+
+ EXPECT_FALSE(base.GetPayload(kUrl1).has_value());
+ EXPECT_TRUE(copy.GetPayload(kUrl1).has_value());
+ }
+}
+
+TEST(Status, CopyConstructor) {
+ {
+ absl::Status status;
+ absl::Status copy(status);
+ EXPECT_EQ(copy, status);
+ }
+ {
+ absl::Status status(absl::StatusCode::kInvalidArgument, "message");
+ absl::Status copy(status);
+ EXPECT_EQ(copy, status);
+ }
+ {
+ absl::Status status(absl::StatusCode::kInvalidArgument, "message");
+ status.SetPayload(kUrl1, absl::Cord(kPayload1));
+ absl::Status copy(status);
+ EXPECT_EQ(copy, status);
+ }
+}
+
+TEST(Status, CopyAssignment) {
+ absl::Status assignee;
+ {
+ absl::Status status;
+ assignee = status;
+ EXPECT_EQ(assignee, status);
+ }
+ {
+ absl::Status status(absl::StatusCode::kInvalidArgument, "message");
+ assignee = status;
+ EXPECT_EQ(assignee, status);
+ }
+ {
+ absl::Status status(absl::StatusCode::kInvalidArgument, "message");
+ status.SetPayload(kUrl1, absl::Cord(kPayload1));
+ assignee = status;
+ EXPECT_EQ(assignee, status);
+ }
+}
+
+TEST(Status, CopyAssignmentIsNotRef) {
+ const absl::Status status_orig(absl::StatusCode::kInvalidArgument, "message");
+ absl::Status status_copy = status_orig;
+ EXPECT_EQ(status_orig, status_copy);
+ status_copy.SetPayload(kUrl1, absl::Cord(kPayload1));
+ EXPECT_NE(status_orig, status_copy);
+}
+
+TEST(Status, MoveConstructor) {
+ {
+ absl::Status status;
+ absl::Status copy(absl::Status{});
+ EXPECT_EQ(copy, status);
+ }
+ {
+ absl::Status status(absl::StatusCode::kInvalidArgument, "message");
+ absl::Status copy(
+ absl::Status(absl::StatusCode::kInvalidArgument, "message"));
+ EXPECT_EQ(copy, status);
+ }
+ {
+ absl::Status status(absl::StatusCode::kInvalidArgument, "message");
+ status.SetPayload(kUrl1, absl::Cord(kPayload1));
+ absl::Status copy1(status);
+ absl::Status copy2(std::move(status));
+ EXPECT_EQ(copy1, copy2);
+ }
+}
+
+TEST(Status, MoveAssignment) {
+ absl::Status assignee;
+ {
+ absl::Status status;
+ assignee = absl::Status();
+ EXPECT_EQ(assignee, status);
+ }
+ {
+ absl::Status status(absl::StatusCode::kInvalidArgument, "message");
+ assignee = absl::Status(absl::StatusCode::kInvalidArgument, "message");
+ EXPECT_EQ(assignee, status);
+ }
+ {
+ absl::Status status(absl::StatusCode::kInvalidArgument, "message");
+ status.SetPayload(kUrl1, absl::Cord(kPayload1));
+ absl::Status copy(status);
+ assignee = std::move(status);
+ EXPECT_EQ(assignee, copy);
+ }
+ {
+ absl::Status status(absl::StatusCode::kInvalidArgument, "message");
+ absl::Status copy(status);
+ status = static_cast<absl::Status&&>(status);
+ EXPECT_EQ(status, copy);
+ }
+}
+
+TEST(Status, Update) {
+ absl::Status s;
+ s.Update(absl::OkStatus());
+ EXPECT_TRUE(s.ok());
+ const absl::Status a(absl::StatusCode::kCancelled, "message");
+ s.Update(a);
+ EXPECT_EQ(s, a);
+ const absl::Status b(absl::StatusCode::kInternal, "other message");
+ s.Update(b);
+ EXPECT_EQ(s, a);
+ s.Update(absl::OkStatus());
+ EXPECT_EQ(s, a);
+ EXPECT_FALSE(s.ok());
+}
+
+TEST(Status, Equality) {
+ absl::Status ok;
+ absl::Status no_payload = absl::CancelledError("no payload");
+ absl::Status one_payload = absl::InvalidArgumentError("one payload");
+ one_payload.SetPayload(kUrl1, absl::Cord(kPayload1));
+ absl::Status two_payloads = one_payload;
+ two_payloads.SetPayload(kUrl2, absl::Cord(kPayload2));
+ const std::array<absl::Status, 4> status_arr = {ok, no_payload, one_payload,
+ two_payloads};
+ for (int i = 0; i < status_arr.size(); i++) {
+ for (int j = 0; j < status_arr.size(); j++) {
+ if (i == j) {
+ EXPECT_TRUE(status_arr[i] == status_arr[j]);
+ EXPECT_FALSE(status_arr[i] != status_arr[j]);
+ } else {
+ EXPECT_TRUE(status_arr[i] != status_arr[j]);
+ EXPECT_FALSE(status_arr[i] == status_arr[j]);
+ }
+ }
+ }
+}
+
+TEST(Status, Swap) {
+ auto test_swap = [](const absl::Status& s1, const absl::Status& s2) {
+ absl::Status copy1 = s1, copy2 = s2;
+ swap(copy1, copy2);
+ EXPECT_EQ(copy1, s2);
+ EXPECT_EQ(copy2, s1);
+ };
+ const absl::Status ok;
+ const absl::Status no_payload(absl::StatusCode::kAlreadyExists, "no payload");
+ absl::Status with_payload(absl::StatusCode::kInternal, "with payload");
+ with_payload.SetPayload(kUrl1, absl::Cord(kPayload1));
+ test_swap(ok, no_payload);
+ test_swap(no_payload, ok);
+ test_swap(ok, with_payload);
+ test_swap(with_payload, ok);
+ test_swap(no_payload, with_payload);
+ test_swap(with_payload, no_payload);
+}
+
+} // namespace
diff --git a/third_party/abseil/absl/status/statusor.cc b/third_party/abseil/absl/status/statusor.cc
new file mode 100644
index 0000000..b954b45
--- /dev/null
+++ b/third_party/abseil/absl/status/statusor.cc
@@ -0,0 +1,71 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "absl/status/statusor.h"
+
+#include <cstdlib>
+#include <utility>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/status/status.h"
+#include "absl/strings/str_cat.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+BadStatusOrAccess::BadStatusOrAccess(absl::Status status)
+ : status_(std::move(status)) {}
+
+BadStatusOrAccess::~BadStatusOrAccess() = default;
+const char* BadStatusOrAccess::what() const noexcept {
+ return "Bad StatusOr access";
+}
+
+const absl::Status& BadStatusOrAccess::status() const { return status_; }
+
+namespace internal_statusor {
+
+void Helper::HandleInvalidStatusCtorArg(absl::Status* status) {
+ const char* kMessage =
+ "An OK status is not a valid constructor argument to StatusOr<T>";
+#ifdef NDEBUG
+ ABSL_INTERNAL_LOG(ERROR, kMessage);
+#else
+ ABSL_INTERNAL_LOG(FATAL, kMessage);
+#endif
+ // In optimized builds, we will fall back to InternalError.
+ *status = absl::InternalError(kMessage);
+}
+
+void Helper::Crash(const absl::Status& status) {
+ ABSL_INTERNAL_LOG(
+ FATAL,
+ absl::StrCat("Attempting to fetch value instead of handling error ",
+ status.ToString()));
+}
+
+void ThrowBadStatusOrAccess(absl::Status status) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+ throw absl::BadStatusOrAccess(std::move(status));
+#else
+ ABSL_INTERNAL_LOG(
+ FATAL,
+ absl::StrCat("Attempting to fetch value instead of handling error ",
+ status.ToString()));
+ std::abort();
+#endif
+}
+
+} // namespace internal_statusor
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/status/statusor.h b/third_party/abseil/absl/status/statusor.h
new file mode 100644
index 0000000..469d486
--- /dev/null
+++ b/third_party/abseil/absl/status/statusor.h
@@ -0,0 +1,760 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: statusor.h
+// -----------------------------------------------------------------------------
+//
+// An `absl::StatusOr<T>` represents a union of an `absl::Status` object
+// and an object of type `T`. The `absl::StatusOr<T>` will either contain an
+// object of type `T` (indicating a successful operation), or an error (of type
+// `absl::Status`) explaining why such a value is not present.
+//
+// In general, check the success of an operation returning an
+// `absl::StatusOr<T>` like you would an `absl::Status` by using the `ok()`
+// member function.
+//
+// Example:
+//
+// StatusOr<Foo> result = Calculation();
+// if (result.ok()) {
+// result->DoSomethingCool();
+// } else {
+// LOG(ERROR) << result.status();
+// }
+#ifndef ABSL_STATUS_STATUSOR_H_
+#define ABSL_STATUS_STATUSOR_H_
+
+#include <exception>
+#include <initializer_list>
+#include <new>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/attributes.h"
+#include "absl/meta/type_traits.h"
+#include "absl/status/internal/statusor_internal.h"
+#include "absl/status/status.h"
+#include "absl/types/variant.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// BadStatusOrAccess
+//
+// This class defines the type of object to throw (if exceptions are enabled),
+// when accessing the value of an `absl::StatusOr<T>` object that does not
+// contain a value. This behavior is analogous to that of
+// `std::bad_optional_access` in the case of accessing an invalid
+// `std::optional` value.
+//
+// Example:
+//
+// try {
+// absl::StatusOr<int> v = FetchInt();
+// DoWork(v.value()); // Accessing value() when not "OK" may throw
+// } catch (absl::BadStatusOrAccess& ex) {
+// LOG(ERROR) << ex.status();
+// }
+class BadStatusOrAccess : public std::exception {
+ public:
+ explicit BadStatusOrAccess(absl::Status status);
+ ~BadStatusOrAccess() override;
+
+ // BadStatusOrAccess::what()
+ //
+ // Returns the associated explanatory string of the `absl::StatusOr<T>`
+ // object's error code. This function only returns the string literal "Bad
+ // StatusOr Access" for cases when evaluating general exceptions.
+ //
+ // The pointer of this string is guaranteed to be valid until any non-const
+ // function is invoked on the exception object.
+ const char* what() const noexcept override;
+
+ // BadStatusOrAccess::status()
+ //
+ // Returns the associated `absl::Status` of the `absl::StatusOr<T>` object's
+ // error.
+ const absl::Status& status() const;
+
+ private:
+ absl::Status status_;
+};
+
+// Returned StatusOr objects may not be ignored.
+template <typename T>
+class ABSL_MUST_USE_RESULT StatusOr;
+
+// absl::StatusOr<T>
+//
+// The `absl::StatusOr<T>` class template is a union of an `absl::Status` object
+// and an object of type `T`. The `absl::StatusOr<T>` models an object that is
+// either a usable object, or an error (of type `absl::Status`) explaining why
+// such an object is not present. An `absl::StatusOr<T>` is typically the return
+// value of a function which may fail.
+//
+// An `absl::StatusOr<T>` can never hold an "OK" status (an
+// `absl::StatusCode::kOk` value); instead, the presence of an object of type
+// `T` indicates success. Instead of checking for a `kOk` value, use the
+// `absl::StatusOr<T>::ok()` member function. (It is for this reason, and code
+// readability, that using the `ok()` function is preferred for `absl::Status`
+// as well.)
+//
+// Example:
+//
+// StatusOr<Foo> result = DoBigCalculationThatCouldFail();
+// if (result.ok()) {
+// result->DoSomethingCool();
+// } else {
+// LOG(ERROR) << result.status();
+// }
+//
+// Accessing the object held by an `absl::StatusOr<T>` should be performed via
+// `operator*` or `operator->`, after a call to `ok()` confirms that the
+// `absl::StatusOr<T>` holds an object of type `T`:
+//
+// Example:
+//
+// absl::StatusOr<int> i = GetCount();
+// if (i.ok()) {
+// updated_total += *i
+// }
+//
+// NOTE: using `absl::StatusOr<T>::value()` when no valid value is present will
+// throw an exception if exceptions are enabled or terminate the process when
+// execeptions are not enabled.
+//
+// Example:
+//
+// StatusOr<Foo> result = DoBigCalculationThatCouldFail();
+// const Foo& foo = result.value(); // Crash/exception if no value present
+// foo.DoSomethingCool();
+//
+// A `absl::StatusOr<T*>` can be constructed from a null pointer like any other
+// pointer value, and the result will be that `ok()` returns `true` and
+// `value()` returns `nullptr`. Checking the value of pointer in an
+// `absl::StatusOr<T>` generally requires a bit more care, to ensure both that a
+// value is present and that value is not null:
+//
+// StatusOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg);
+// if (!result.ok()) {
+// LOG(ERROR) << result.status();
+// } else if (*result == nullptr) {
+// LOG(ERROR) << "Unexpected null pointer";
+// } else {
+// (*result)->DoSomethingCool();
+// }
+//
+// Example factory implementation returning StatusOr<T>:
+//
+// StatusOr<Foo> FooFactory::MakeFoo(int arg) {
+// if (arg <= 0) {
+// return absl::Status(absl::StatusCode::kInvalidArgument,
+// "Arg must be positive");
+// }
+// return Foo(arg);
+// }
+template <typename T>
+class StatusOr : private internal_statusor::StatusOrData<T>,
+ private internal_statusor::CopyCtorBase<T>,
+ private internal_statusor::MoveCtorBase<T>,
+ private internal_statusor::CopyAssignBase<T>,
+ private internal_statusor::MoveAssignBase<T> {
+ template <typename U>
+ friend class StatusOr;
+
+ typedef internal_statusor::StatusOrData<T> Base;
+
+ public:
+ // StatusOr<T>::value_type
+ //
+ // This instance data provides a generic `value_type` member for use within
+ // generic programming. This usage is analogous to that of
+ // `optional::value_type` in the case of `std::optional`.
+ typedef T value_type;
+
+ // Constructors
+
+ // Constructs a new `absl::StatusOr` with an `absl::StatusCode::kUnknown`
+ // status. This constructor is marked 'explicit' to prevent usages in return
+ // values such as 'return {};', under the misconception that
+ // `absl::StatusOr<std::vector<int>>` will be initialized with an empty
+ // vector, instead of an `absl::StatusCode::kUnknown` error code.
+ explicit StatusOr();
+
+ // `StatusOr<T>` is copy constructible if `T` is copy constructible.
+ StatusOr(const StatusOr&) = default;
+ // `StatusOr<T>` is copy assignable if `T` is copy constructible and copy
+ // assignable.
+ StatusOr& operator=(const StatusOr&) = default;
+
+ // `StatusOr<T>` is move constructible if `T` is move constructible.
+ StatusOr(StatusOr&&) = default;
+ // `StatusOr<T>` is moveAssignable if `T` is move constructible and move
+ // assignable.
+ StatusOr& operator=(StatusOr&&) = default;
+
+ // Converting Constructors
+
+ // Constructs a new `absl::StatusOr<T>` from an `absl::StatusOr<U>`, when `T`
+ // is constructible from `U`. To avoid ambiguity, these constructors are
+ // disabled if `T` is also constructible from `StatusOr<U>.`. This constructor
+ // is explicit if and only if the corresponding construction of `T` from `U`
+ // is explicit. (This constructor inherits its explicitness from the
+ // underlying constructor.)
+ template <
+ typename U,
+ absl::enable_if_t<
+ absl::conjunction<
+ absl::negation<std::is_same<T, U>>,
+ std::is_constructible<T, const U&>,
+ std::is_convertible<const U&, T>,
+ absl::negation<
+ internal_statusor::IsConstructibleOrConvertibleFromStatusOr<
+ T, U>>>::value,
+ int> = 0>
+ StatusOr(const StatusOr<U>& other) // NOLINT
+ : Base(static_cast<const typename StatusOr<U>::Base&>(other)) {}
+ template <
+ typename U,
+ absl::enable_if_t<
+ absl::conjunction<
+ absl::negation<std::is_same<T, U>>,
+ std::is_constructible<T, const U&>,
+ absl::negation<std::is_convertible<const U&, T>>,
+ absl::negation<
+ internal_statusor::IsConstructibleOrConvertibleFromStatusOr<
+ T, U>>>::value,
+ int> = 0>
+ explicit StatusOr(const StatusOr<U>& other)
+ : Base(static_cast<const typename StatusOr<U>::Base&>(other)) {}
+
+ template <
+ typename U,
+ absl::enable_if_t<
+ absl::conjunction<
+ absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
+ std::is_convertible<U&&, T>,
+ absl::negation<
+ internal_statusor::IsConstructibleOrConvertibleFromStatusOr<
+ T, U>>>::value,
+ int> = 0>
+ StatusOr(StatusOr<U>&& other) // NOLINT
+ : Base(static_cast<typename StatusOr<U>::Base&&>(other)) {}
+ template <
+ typename U,
+ absl::enable_if_t<
+ absl::conjunction<
+ absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
+ absl::negation<std::is_convertible<U&&, T>>,
+ absl::negation<
+ internal_statusor::IsConstructibleOrConvertibleFromStatusOr<
+ T, U>>>::value,
+ int> = 0>
+ explicit StatusOr(StatusOr<U>&& other)
+ : Base(static_cast<typename StatusOr<U>::Base&&>(other)) {}
+
+ // Converting Assignment Operators
+
+ // Creates an `absl::StatusOr<T>` through assignment from an
+ // `absl::StatusOr<U>` when:
+ //
+ // * Both `absl::StatusOr<T>` and `absl::StatusOr<U>` are OK by assigning
+ // `U` to `T` directly.
+ // * `absl::StatusOr<T>` is OK and `absl::StatusOr<U>` contains an error
+ // code by destroying `absl::StatusOr<T>`'s value and assigning from
+ // `absl::StatusOr<U>'
+ // * `absl::StatusOr<T>` contains an error code and `absl::StatusOr<U>` is
+ // OK by directly initializing `T` from `U`.
+ // * Both `absl::StatusOr<T>` and `absl::StatusOr<U>` contain an error
+ // code by assigning the `Status` in `absl::StatusOr<U>` to
+ // `absl::StatusOr<T>`
+ //
+ // These overloads only apply if `absl::StatusOr<T>` is constructible and
+ // assignable from `absl::StatusOr<U>` and `StatusOr<T>` cannot be directly
+ // assigned from `StatusOr<U>`.
+ template <
+ typename U,
+ absl::enable_if_t<
+ absl::conjunction<
+ absl::negation<std::is_same<T, U>>,
+ std::is_constructible<T, const U&>,
+ std::is_assignable<T, const U&>,
+ absl::negation<
+ internal_statusor::
+ IsConstructibleOrConvertibleOrAssignableFromStatusOr<
+ T, U>>>::value,
+ int> = 0>
+ StatusOr& operator=(const StatusOr<U>& other) {
+ this->Assign(other);
+ return *this;
+ }
+ template <
+ typename U,
+ absl::enable_if_t<
+ absl::conjunction<
+ absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
+ std::is_assignable<T, U&&>,
+ absl::negation<
+ internal_statusor::
+ IsConstructibleOrConvertibleOrAssignableFromStatusOr<
+ T, U>>>::value,
+ int> = 0>
+ StatusOr& operator=(StatusOr<U>&& other) {
+ this->Assign(std::move(other));
+ return *this;
+ }
+
+ // Constructs a new `absl::StatusOr<T>` with a non-ok status. After calling
+ // this constructor, `this->ok()` will be `false` and calls to `value()` will
+ // crash, or produce an exception if exceptions are enabled.
+ //
+ // The constructor also takes any type `U` that is convertible to
+ // `absl::Status`. This constructor is explicit if an only if `U` is not of
+ // type `absl::Status` and the conversion from `U` to `Status` is explicit.
+ //
+ // REQUIRES: !Status(std::forward<U>(v)).ok(). This requirement is DCHECKed.
+ // In optimized builds, passing absl::OkStatus() here will have the effect
+ // of passing absl::StatusCode::kInternal as a fallback.
+ template <
+ typename U = absl::Status,
+ absl::enable_if_t<
+ absl::conjunction<
+ std::is_convertible<U&&, absl::Status>,
+ std::is_constructible<absl::Status, U&&>,
+ absl::negation<std::is_same<absl::decay_t<U>, absl::StatusOr<T>>>,
+ absl::negation<std::is_same<absl::decay_t<U>, T>>,
+ absl::negation<std::is_same<absl::decay_t<U>, absl::in_place_t>>,
+ absl::negation<internal_statusor::HasConversionOperatorToStatusOr<
+ T, U&&>>>::value,
+ int> = 0>
+ StatusOr(U&& v) : Base(std::forward<U>(v)) {}
+
+ template <
+ typename U = absl::Status,
+ absl::enable_if_t<
+ absl::conjunction<
+ absl::negation<std::is_convertible<U&&, absl::Status>>,
+ std::is_constructible<absl::Status, U&&>,
+ absl::negation<std::is_same<absl::decay_t<U>, absl::StatusOr<T>>>,
+ absl::negation<std::is_same<absl::decay_t<U>, T>>,
+ absl::negation<std::is_same<absl::decay_t<U>, absl::in_place_t>>,
+ absl::negation<internal_statusor::HasConversionOperatorToStatusOr<
+ T, U&&>>>::value,
+ int> = 0>
+ explicit StatusOr(U&& v) : Base(std::forward<U>(v)) {}
+
+ template <
+ typename U = absl::Status,
+ absl::enable_if_t<
+ absl::conjunction<
+ std::is_convertible<U&&, absl::Status>,
+ std::is_constructible<absl::Status, U&&>,
+ absl::negation<std::is_same<absl::decay_t<U>, absl::StatusOr<T>>>,
+ absl::negation<std::is_same<absl::decay_t<U>, T>>,
+ absl::negation<std::is_same<absl::decay_t<U>, absl::in_place_t>>,
+ absl::negation<internal_statusor::HasConversionOperatorToStatusOr<
+ T, U&&>>>::value,
+ int> = 0>
+ StatusOr& operator=(U&& v) {
+ this->AssignStatus(std::forward<U>(v));
+ return *this;
+ }
+
+ // Perfect-forwarding value assignment operator.
+
+ // If `*this` contains a `T` value before the call, the contained value is
+ // assigned from `std::forward<U>(v)`; Otherwise, it is directly-initialized
+ // from `std::forward<U>(v)`.
+ // This function does not participate in overload unless:
+ // 1. `std::is_constructible_v<T, U>` is true,
+ // 2. `std::is_assignable_v<T&, U>` is true.
+ // 3. `std::is_same_v<StatusOr<T>, std::remove_cvref_t<U>>` is false.
+ // 4. Assigning `U` to `T` is not ambiguous:
+ // If `U` is `StatusOr<V>` and `T` is constructible and assignable from
+ // both `StatusOr<V>` and `V`, the assignment is considered bug-prone and
+ // ambiguous thus will fail to compile. For example:
+ // StatusOr<bool> s1 = true; // s1.ok() && *s1 == true
+ // StatusOr<bool> s2 = false; // s2.ok() && *s2 == false
+ // s1 = s2; // ambiguous, `s1 = *s2` or `s1 = bool(s2)`?
+ template <
+ typename U = T,
+ typename = typename std::enable_if<absl::conjunction<
+ std::is_constructible<T, U&&>, std::is_assignable<T&, U&&>,
+ absl::disjunction<
+ std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>, T>,
+ absl::conjunction<
+ absl::negation<std::is_convertible<U&&, absl::Status>>,
+ absl::negation<internal_statusor::
+ HasConversionOperatorToStatusOr<T, U&&>>>>,
+ internal_statusor::IsForwardingAssignmentValid<T, U&&>>::value>::type>
+ StatusOr& operator=(U&& v) {
+ this->Assign(std::forward<U>(v));
+ return *this;
+ }
+
+ // Constructs the inner value `T` in-place using the provided args, using the
+ // `T(args...)` constructor.
+ template <typename... Args>
+ explicit StatusOr(absl::in_place_t, Args&&... args);
+ template <typename U, typename... Args>
+ explicit StatusOr(absl::in_place_t, std::initializer_list<U> ilist,
+ Args&&... args);
+
+ // Constructs the inner value `T` in-place using the provided args, using the
+ // `T(U)` (direct-initialization) constructor. This constructor is only valid
+ // if `T` can be constructed from a `U`. Can accept move or copy constructors.
+ //
+ // This constructor is explicit if `U` is not convertible to `T`. To avoid
+ // ambiguity, this constuctor is disabled if `U` is a `StatusOr<J>`, where `J`
+ // is convertible to `T`.
+ template <
+ typename U = T,
+ absl::enable_if_t<
+ absl::conjunction<
+ internal_statusor::IsDirectInitializationValid<T, U&&>,
+ std::is_constructible<T, U&&>, std::is_convertible<U&&, T>,
+ absl::disjunction<
+ std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>,
+ T>,
+ absl::conjunction<
+ absl::negation<std::is_convertible<U&&, absl::Status>>,
+ absl::negation<
+ internal_statusor::HasConversionOperatorToStatusOr<
+ T, U&&>>>>>::value,
+ int> = 0>
+ StatusOr(U&& u) // NOLINT
+ : StatusOr(absl::in_place, std::forward<U>(u)) {
+ }
+
+ template <
+ typename U = T,
+ absl::enable_if_t<
+ absl::conjunction<
+ internal_statusor::IsDirectInitializationValid<T, U&&>,
+ absl::disjunction<
+ std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>,
+ T>,
+ absl::conjunction<
+ absl::negation<std::is_constructible<absl::Status, U&&>>,
+ absl::negation<
+ internal_statusor::HasConversionOperatorToStatusOr<
+ T, U&&>>>>,
+ std::is_constructible<T, U&&>,
+ absl::negation<std::is_convertible<U&&, T>>>::value,
+ int> = 0>
+ explicit StatusOr(U&& u) // NOLINT
+ : StatusOr(absl::in_place, std::forward<U>(u)) {
+ }
+
+ // StatusOr<T>::ok()
+ //
+ // Returns whether or not this `absl::StatusOr<T>` holds a `T` value. This
+ // member function is analagous to `absl::Status::ok()` and should be used
+ // similarly to check the status of return values.
+ //
+ // Example:
+ //
+ // StatusOr<Foo> result = DoBigCalculationThatCouldFail();
+ // if (result.ok()) {
+ // // Handle result
+ // else {
+ // // Handle error
+ // }
+ ABSL_MUST_USE_RESULT bool ok() const { return this->status_.ok(); }
+
+ // StatusOr<T>::status()
+ //
+ // Returns a reference to the current `absl::Status` contained within the
+ // `absl::StatusOr<T>`. If `absl::StatusOr<T>` contains a `T`, then this
+ // function returns `absl::OkStatus()`.
+ const Status& status() const &;
+ Status status() &&;
+
+ // StatusOr<T>::value()
+ //
+ // Returns a reference to the held value if `this->ok()`. Otherwise, throws
+ // `absl::BadStatusOrAccess` if exceptions are enabled, or is guaranteed to
+ // terminate the process if exceptions are disabled.
+ //
+ // If you have already checked the status using `this->ok()`, you probably
+ // want to use `operator*()` or `operator->()` to access the value instead of
+ // `value`.
+ //
+ // Note: for value types that are cheap to copy, prefer simple code:
+ //
+ // T value = statusor.value();
+ //
+ // Otherwise, if the value type is expensive to copy, but can be left
+ // in the StatusOr, simply assign to a reference:
+ //
+ // T& value = statusor.value(); // or `const T&`
+ //
+ // Otherwise, if the value type supports an efficient move, it can be
+ // used as follows:
+ //
+ // T value = std::move(statusor).value();
+ //
+ // The `std::move` on statusor instead of on the whole expression enables
+ // warnings about possible uses of the statusor object after the move.
+ const T& value() const&;
+ T& value() &;
+ const T&& value() const&&;
+ T&& value() &&;
+
+ // StatusOr<T>:: operator*()
+ //
+ // Returns a reference to the current value.
+ //
+ // REQUIRES: `this->ok() == true`, otherwise the behavior is undefined.
+ //
+ // Use `this->ok()` to verify that there is a current value within the
+ // `absl::StatusOr<T>`. Alternatively, see the `value()` member function for a
+ // similar API that guarantees crashing or throwing an exception if there is
+ // no current value.
+ const T& operator*() const&;
+ T& operator*() &;
+ const T&& operator*() const&&;
+ T&& operator*() &&;
+
+ // StatusOr<T>::operator->()
+ //
+ // Returns a pointer to the current value.
+ //
+ // REQUIRES: `this->ok() == true`, otherwise the behavior is undefined.
+ //
+ // Use `this->ok()` to verify that there is a current value.
+ const T* operator->() const;
+ T* operator->();
+
+ // StatusOr<T>::value_or()
+ //
+ // Returns the current value if `this->ok() == true`. Otherwise constructs a
+ // value using the provided `default_value`.
+ //
+ // Unlike `value`, this function returns by value, copying the current value
+ // if necessary. If the value type supports an efficient move, it can be used
+ // as follows:
+ //
+ // T value = std::move(statusor).value_or(def);
+ //
+ // Unlike with `value`, calling `std::move()` on the result of `value_or` will
+ // still trigger a copy.
+ template <typename U>
+ T value_or(U&& default_value) const&;
+ template <typename U>
+ T value_or(U&& default_value) &&;
+
+ // StatusOr<T>::IgnoreError()
+ //
+ // Ignores any errors. This method does nothing except potentially suppress
+ // complaints from any tools that are checking that errors are not dropped on
+ // the floor.
+ void IgnoreError() const;
+
+ // StatusOr<T>::emplace()
+ //
+ // Reconstructs the inner value T in-place using the provided args, using the
+ // T(args...) constructor. Returns reference to the reconstructed `T`.
+ template <typename... Args>
+ T& emplace(Args&&... args) {
+ if (ok()) {
+ this->Clear();
+ this->MakeValue(std::forward<Args>(args)...);
+ } else {
+ this->MakeValue(std::forward<Args>(args)...);
+ this->status_ = absl::OkStatus();
+ }
+ return this->data_;
+ }
+
+ template <
+ typename U, typename... Args,
+ absl::enable_if_t<
+ std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value,
+ int> = 0>
+ T& emplace(std::initializer_list<U> ilist, Args&&... args) {
+ if (ok()) {
+ this->Clear();
+ this->MakeValue(ilist, std::forward<Args>(args)...);
+ } else {
+ this->MakeValue(ilist, std::forward<Args>(args)...);
+ this->status_ = absl::OkStatus();
+ }
+ return this->data_;
+ }
+
+ private:
+ using internal_statusor::StatusOrData<T>::Assign;
+ template <typename U>
+ void Assign(const absl::StatusOr<U>& other);
+ template <typename U>
+ void Assign(absl::StatusOr<U>&& other);
+};
+
+// operator==()
+//
+// This operator checks the equality of two `absl::StatusOr<T>` objects.
+template <typename T>
+bool operator==(const StatusOr<T>& lhs, const StatusOr<T>& rhs) {
+ if (lhs.ok() && rhs.ok()) return *lhs == *rhs;
+ return lhs.status() == rhs.status();
+}
+
+// operator!=()
+//
+// This operator checks the inequality of two `absl::StatusOr<T>` objects.
+template <typename T>
+bool operator!=(const StatusOr<T>& lhs, const StatusOr<T>& rhs) {
+ return !(lhs == rhs);
+}
+
+//------------------------------------------------------------------------------
+// Implementation details for StatusOr<T>
+//------------------------------------------------------------------------------
+
+// TODO(sbenza): avoid the string here completely.
+template <typename T>
+StatusOr<T>::StatusOr() : Base(Status(absl::StatusCode::kUnknown, "")) {}
+
+template <typename T>
+template <typename U>
+inline void StatusOr<T>::Assign(const StatusOr<U>& other) {
+ if (other.ok()) {
+ this->Assign(*other);
+ } else {
+ this->AssignStatus(other.status());
+ }
+}
+
+template <typename T>
+template <typename U>
+inline void StatusOr<T>::Assign(StatusOr<U>&& other) {
+ if (other.ok()) {
+ this->Assign(*std::move(other));
+ } else {
+ this->AssignStatus(std::move(other).status());
+ }
+}
+template <typename T>
+template <typename... Args>
+StatusOr<T>::StatusOr(absl::in_place_t, Args&&... args)
+ : Base(absl::in_place, std::forward<Args>(args)...) {}
+
+template <typename T>
+template <typename U, typename... Args>
+StatusOr<T>::StatusOr(absl::in_place_t, std::initializer_list<U> ilist,
+ Args&&... args)
+ : Base(absl::in_place, ilist, std::forward<Args>(args)...) {}
+
+template <typename T>
+const Status& StatusOr<T>::status() const & { return this->status_; }
+template <typename T>
+Status StatusOr<T>::status() && {
+ return ok() ? OkStatus() : std::move(this->status_);
+}
+
+template <typename T>
+const T& StatusOr<T>::value() const& {
+ if (!this->ok()) internal_statusor::ThrowBadStatusOrAccess(this->status_);
+ return this->data_;
+}
+
+template <typename T>
+T& StatusOr<T>::value() & {
+ if (!this->ok()) internal_statusor::ThrowBadStatusOrAccess(this->status_);
+ return this->data_;
+}
+
+template <typename T>
+const T&& StatusOr<T>::value() const&& {
+ if (!this->ok()) {
+ internal_statusor::ThrowBadStatusOrAccess(std::move(this->status_));
+ }
+ return std::move(this->data_);
+}
+
+template <typename T>
+T&& StatusOr<T>::value() && {
+ if (!this->ok()) {
+ internal_statusor::ThrowBadStatusOrAccess(std::move(this->status_));
+ }
+ return std::move(this->data_);
+}
+
+template <typename T>
+const T& StatusOr<T>::operator*() const& {
+ this->EnsureOk();
+ return this->data_;
+}
+
+template <typename T>
+T& StatusOr<T>::operator*() & {
+ this->EnsureOk();
+ return this->data_;
+}
+
+template <typename T>
+const T&& StatusOr<T>::operator*() const&& {
+ this->EnsureOk();
+ return std::move(this->data_);
+}
+
+template <typename T>
+T&& StatusOr<T>::operator*() && {
+ this->EnsureOk();
+ return std::move(this->data_);
+}
+
+template <typename T>
+const T* StatusOr<T>::operator->() const {
+ this->EnsureOk();
+ return &this->data_;
+}
+
+template <typename T>
+T* StatusOr<T>::operator->() {
+ this->EnsureOk();
+ return &this->data_;
+}
+
+template <typename T>
+template <typename U>
+T StatusOr<T>::value_or(U&& default_value) const& {
+ if (ok()) {
+ return this->data_;
+ }
+ return std::forward<U>(default_value);
+}
+
+template <typename T>
+template <typename U>
+T StatusOr<T>::value_or(U&& default_value) && {
+ if (ok()) {
+ return std::move(this->data_);
+ }
+ return std::forward<U>(default_value);
+}
+
+template <typename T>
+void StatusOr<T>::IgnoreError() const {
+ // no-op
+}
+
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_STATUS_STATUSOR_H_
diff --git a/third_party/abseil/absl/status/statusor_test.cc b/third_party/abseil/absl/status/statusor_test.cc
new file mode 100644
index 0000000..c2e8fb7
--- /dev/null
+++ b/third_party/abseil/absl/status/statusor_test.cc
@@ -0,0 +1,1811 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/status/statusor.h"
+
+#include <array>
+#include <initializer_list>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/casts.h"
+#include "absl/memory/memory.h"
+#include "absl/status/status.h"
+#include "absl/types/any.h"
+#include "absl/utility/utility.h"
+
+namespace {
+
+using ::testing::AllOf;
+using ::testing::AnyWith;
+using ::testing::ElementsAre;
+using ::testing::Field;
+using ::testing::Ne;
+using ::testing::Not;
+using ::testing::Pointee;
+using ::testing::VariantWith;
+
+#ifdef GTEST_HAS_STATUS_MATCHERS
+using ::testing::status::IsOk;
+using ::testing::status::IsOkAndHolds;
+#else // GTEST_HAS_STATUS_MATCHERS
+inline const ::absl::Status& GetStatus(const ::absl::Status& status) {
+ return status;
+}
+
+template <typename T>
+inline const ::absl::Status& GetStatus(const ::absl::StatusOr<T>& status) {
+ return status.status();
+}
+
+// Monomorphic implementation of matcher IsOkAndHolds(m). StatusOrType is a
+// reference to StatusOr<T>.
+template <typename StatusOrType>
+class IsOkAndHoldsMatcherImpl
+ : public ::testing::MatcherInterface<StatusOrType> {
+ public:
+ typedef
+ typename std::remove_reference<StatusOrType>::type::value_type value_type;
+
+ template <typename InnerMatcher>
+ explicit IsOkAndHoldsMatcherImpl(InnerMatcher&& inner_matcher)
+ : inner_matcher_(::testing::SafeMatcherCast<const value_type&>(
+ std::forward<InnerMatcher>(inner_matcher))) {}
+
+ void DescribeTo(std::ostream* os) const override {
+ *os << "is OK and has a value that ";
+ inner_matcher_.DescribeTo(os);
+ }
+
+ void DescribeNegationTo(std::ostream* os) const override {
+ *os << "isn't OK or has a value that ";
+ inner_matcher_.DescribeNegationTo(os);
+ }
+
+ bool MatchAndExplain(
+ StatusOrType actual_value,
+ ::testing::MatchResultListener* result_listener) const override {
+ if (!actual_value.ok()) {
+ *result_listener << "which has status " << actual_value.status();
+ return false;
+ }
+
+ ::testing::StringMatchResultListener inner_listener;
+ const bool matches =
+ inner_matcher_.MatchAndExplain(*actual_value, &inner_listener);
+ const std::string inner_explanation = inner_listener.str();
+ if (!inner_explanation.empty()) {
+ *result_listener << "which contains value "
+ << ::testing::PrintToString(*actual_value) << ", "
+ << inner_explanation;
+ }
+ return matches;
+ }
+
+ private:
+ const ::testing::Matcher<const value_type&> inner_matcher_;
+};
+
+// Implements IsOkAndHolds(m) as a polymorphic matcher.
+template <typename InnerMatcher>
+class IsOkAndHoldsMatcher {
+ public:
+ explicit IsOkAndHoldsMatcher(InnerMatcher inner_matcher)
+ : inner_matcher_(std::move(inner_matcher)) {}
+
+ // Converts this polymorphic matcher to a monomorphic matcher of the
+ // given type. StatusOrType can be either StatusOr<T> or a
+ // reference to StatusOr<T>.
+ template <typename StatusOrType>
+ operator ::testing::Matcher<StatusOrType>() const { // NOLINT
+ return ::testing::Matcher<StatusOrType>(
+ new IsOkAndHoldsMatcherImpl<const StatusOrType&>(inner_matcher_));
+ }
+
+ private:
+ const InnerMatcher inner_matcher_;
+};
+
+// Monomorphic implementation of matcher IsOk() for a given type T.
+// T can be Status, StatusOr<>, or a reference to either of them.
+template <typename T>
+class MonoIsOkMatcherImpl : public ::testing::MatcherInterface<T> {
+ public:
+ void DescribeTo(std::ostream* os) const override { *os << "is OK"; }
+ void DescribeNegationTo(std::ostream* os) const override {
+ *os << "is not OK";
+ }
+ bool MatchAndExplain(T actual_value,
+ ::testing::MatchResultListener*) const override {
+ return GetStatus(actual_value).ok();
+ }
+};
+
+// Implements IsOk() as a polymorphic matcher.
+class IsOkMatcher {
+ public:
+ template <typename T>
+ operator ::testing::Matcher<T>() const { // NOLINT
+ return ::testing::Matcher<T>(new MonoIsOkMatcherImpl<T>());
+ }
+};
+
+// Macros for testing the results of functions that return absl::Status or
+// absl::StatusOr<T> (for any type T).
+#define EXPECT_OK(expression) EXPECT_THAT(expression, IsOk())
+
+// Returns a gMock matcher that matches a StatusOr<> whose status is
+// OK and whose value matches the inner matcher.
+template <typename InnerMatcher>
+IsOkAndHoldsMatcher<typename std::decay<InnerMatcher>::type> IsOkAndHolds(
+ InnerMatcher&& inner_matcher) {
+ return IsOkAndHoldsMatcher<typename std::decay<InnerMatcher>::type>(
+ std::forward<InnerMatcher>(inner_matcher));
+}
+
+// Returns a gMock matcher that matches a Status or StatusOr<> which is OK.
+inline IsOkMatcher IsOk() { return IsOkMatcher(); }
+#endif // GTEST_HAS_STATUS_MATCHERS
+
+struct CopyDetector {
+ CopyDetector() = default;
+ explicit CopyDetector(int xx) : x(xx) {}
+ CopyDetector(CopyDetector&& d) noexcept
+ : x(d.x), copied(false), moved(true) {}
+ CopyDetector(const CopyDetector& d) : x(d.x), copied(true), moved(false) {}
+ CopyDetector& operator=(const CopyDetector& c) {
+ x = c.x;
+ copied = true;
+ moved = false;
+ return *this;
+ }
+ CopyDetector& operator=(CopyDetector&& c) noexcept {
+ x = c.x;
+ copied = false;
+ moved = true;
+ return *this;
+ }
+ int x = 0;
+ bool copied = false;
+ bool moved = false;
+};
+
+testing::Matcher<const CopyDetector&> CopyDetectorHas(int a, bool b, bool c) {
+ return AllOf(Field(&CopyDetector::x, a), Field(&CopyDetector::moved, b),
+ Field(&CopyDetector::copied, c));
+}
+
+class Base1 {
+ public:
+ virtual ~Base1() {}
+ int pad;
+};
+
+class Base2 {
+ public:
+ virtual ~Base2() {}
+ int yetotherpad;
+};
+
+class Derived : public Base1, public Base2 {
+ public:
+ virtual ~Derived() {}
+ int evenmorepad;
+};
+
+class CopyNoAssign {
+ public:
+ explicit CopyNoAssign(int value) : foo(value) {}
+ CopyNoAssign(const CopyNoAssign& other) : foo(other.foo) {}
+ int foo;
+
+ private:
+ const CopyNoAssign& operator=(const CopyNoAssign&);
+};
+
+absl::StatusOr<std::unique_ptr<int>> ReturnUniquePtr() {
+ // Uses implicit constructor from T&&
+ return absl::make_unique<int>(0);
+}
+
+TEST(StatusOr, ElementType) {
+ static_assert(std::is_same<absl::StatusOr<int>::value_type, int>(), "");
+ static_assert(std::is_same<absl::StatusOr<char>::value_type, char>(), "");
+}
+
+TEST(StatusOr, TestMoveOnlyInitialization) {
+ absl::StatusOr<std::unique_ptr<int>> thing(ReturnUniquePtr());
+ ASSERT_TRUE(thing.ok());
+ EXPECT_EQ(0, **thing);
+ int* previous = thing->get();
+
+ thing = ReturnUniquePtr();
+ EXPECT_TRUE(thing.ok());
+ EXPECT_EQ(0, **thing);
+ EXPECT_NE(previous, thing->get());
+}
+
+TEST(StatusOr, TestMoveOnlyValueExtraction) {
+ absl::StatusOr<std::unique_ptr<int>> thing(ReturnUniquePtr());
+ ASSERT_TRUE(thing.ok());
+ std::unique_ptr<int> ptr = *std::move(thing);
+ EXPECT_EQ(0, *ptr);
+
+ thing = std::move(ptr);
+ ptr = std::move(*thing);
+ EXPECT_EQ(0, *ptr);
+}
+
+TEST(StatusOr, TestMoveOnlyInitializationFromTemporaryByValueOrDie) {
+ std::unique_ptr<int> ptr(*ReturnUniquePtr());
+ EXPECT_EQ(0, *ptr);
+}
+
+TEST(StatusOr, TestValueOrDieOverloadForConstTemporary) {
+ static_assert(
+ std::is_same<const int&&,
+ decltype(
+ std::declval<const absl::StatusOr<int>&&>().value())>(),
+ "value() for const temporaries should return const T&&");
+}
+
+TEST(StatusOr, TestMoveOnlyConversion) {
+ absl::StatusOr<std::unique_ptr<const int>> const_thing(ReturnUniquePtr());
+ EXPECT_TRUE(const_thing.ok());
+ EXPECT_EQ(0, **const_thing);
+
+ // Test rvalue converting assignment
+ const int* const_previous = const_thing->get();
+ const_thing = ReturnUniquePtr();
+ EXPECT_TRUE(const_thing.ok());
+ EXPECT_EQ(0, **const_thing);
+ EXPECT_NE(const_previous, const_thing->get());
+}
+
+TEST(StatusOr, TestMoveOnlyVector) {
+ // Sanity check that absl::StatusOr<MoveOnly> works in vector.
+ std::vector<absl::StatusOr<std::unique_ptr<int>>> vec;
+ vec.push_back(ReturnUniquePtr());
+ vec.resize(2);
+ auto another_vec = std::move(vec);
+ EXPECT_EQ(0, **another_vec[0]);
+ EXPECT_EQ(absl::UnknownError(""), another_vec[1].status());
+}
+
+TEST(StatusOr, TestDefaultCtor) {
+ absl::StatusOr<int> thing;
+ EXPECT_FALSE(thing.ok());
+ EXPECT_EQ(thing.status().code(), absl::StatusCode::kUnknown);
+}
+
+TEST(StatusOr, StatusCtorForwards) {
+ absl::Status status(absl::StatusCode::kInternal, "Some error");
+
+ EXPECT_EQ(absl::StatusOr<int>(status).status().message(), "Some error");
+ EXPECT_EQ(status.message(), "Some error");
+
+ EXPECT_EQ(absl::StatusOr<int>(std::move(status)).status().message(),
+ "Some error");
+ EXPECT_NE(status.message(), "Some error");
+}
+
+// Define `EXPECT_DEATH_OR_THROW` to test the behavior of `StatusOr::value`,
+// which either throws `BadStatusOrAccess` or `LOG(FATAL)` based on whether
+// exceptions are enabled.
+#ifdef ABSL_HAVE_EXCEPTIONS
+#define EXPECT_DEATH_OR_THROW(statement, status_) \
+ EXPECT_THROW( \
+ { \
+ try { \
+ statement; \
+ } catch (const absl::BadStatusOrAccess& e) { \
+ EXPECT_EQ(e.status(), status_); \
+ throw; \
+ } \
+ }, \
+ absl::BadStatusOrAccess);
+#else // ABSL_HAVE_EXCEPTIONS
+#define EXPECT_DEATH_OR_THROW(statement, status) \
+ EXPECT_DEATH_IF_SUPPORTED(statement, status.ToString());
+#endif // ABSL_HAVE_EXCEPTIONS
+
+TEST(StatusOrDeathTest, TestDefaultCtorValue) {
+ absl::StatusOr<int> thing;
+ EXPECT_DEATH_OR_THROW(thing.value(), absl::UnknownError(""));
+ const absl::StatusOr<int> thing2;
+ EXPECT_DEATH_OR_THROW(thing2.value(), absl::UnknownError(""));
+}
+
+TEST(StatusOrDeathTest, TestValueNotOk) {
+ absl::StatusOr<int> thing(absl::CancelledError());
+ EXPECT_DEATH_OR_THROW(thing.value(), absl::CancelledError());
+}
+
+TEST(StatusOrDeathTest, TestValueNotOkConst) {
+ const absl::StatusOr<int> thing(absl::UnknownError(""));
+ EXPECT_DEATH_OR_THROW(thing.value(), absl::UnknownError(""));
+}
+
+TEST(StatusOrDeathTest, TestPointerDefaultCtorValue) {
+ absl::StatusOr<int*> thing;
+ EXPECT_DEATH_OR_THROW(thing.value(), absl::UnknownError(""));
+}
+
+TEST(StatusOrDeathTest, TestPointerValueNotOk) {
+ absl::StatusOr<int*> thing(absl::CancelledError());
+ EXPECT_DEATH_OR_THROW(thing.value(), absl::CancelledError());
+}
+
+TEST(StatusOrDeathTest, TestPointerValueNotOkConst) {
+ const absl::StatusOr<int*> thing(absl::CancelledError());
+ EXPECT_DEATH_OR_THROW(thing.value(), absl::CancelledError());
+}
+
+#if GTEST_HAS_DEATH_TEST
+TEST(StatusOrDeathTest, TestStatusCtorStatusOk) {
+ EXPECT_DEBUG_DEATH(
+ {
+ // This will DCHECK
+ absl::StatusOr<int> thing(absl::OkStatus());
+ // In optimized mode, we are actually going to get error::INTERNAL for
+ // status here, rather than crashing, so check that.
+ EXPECT_FALSE(thing.ok());
+ EXPECT_EQ(thing.status().code(), absl::StatusCode::kInternal);
+ },
+ "An OK status is not a valid constructor argument");
+}
+
+TEST(StatusOrDeathTest, TestPointerStatusCtorStatusOk) {
+ EXPECT_DEBUG_DEATH(
+ {
+ absl::StatusOr<int*> thing(absl::OkStatus());
+ // In optimized mode, we are actually going to get error::INTERNAL for
+ // status here, rather than crashing, so check that.
+ EXPECT_FALSE(thing.ok());
+ EXPECT_EQ(thing.status().code(), absl::StatusCode::kInternal);
+ },
+ "An OK status is not a valid constructor argument");
+}
+#endif
+
+TEST(StatusOr, ValueAccessor) {
+ const int kIntValue = 110;
+ {
+ absl::StatusOr<int> status_or(kIntValue);
+ EXPECT_EQ(kIntValue, status_or.value());
+ EXPECT_EQ(kIntValue, std::move(status_or).value());
+ }
+ {
+ absl::StatusOr<CopyDetector> status_or(kIntValue);
+ EXPECT_THAT(status_or,
+ IsOkAndHolds(CopyDetectorHas(kIntValue, false, false)));
+ CopyDetector copy_detector = status_or.value();
+ EXPECT_THAT(copy_detector, CopyDetectorHas(kIntValue, false, true));
+ copy_detector = std::move(status_or).value();
+ EXPECT_THAT(copy_detector, CopyDetectorHas(kIntValue, true, false));
+ }
+}
+
+TEST(StatusOr, BadValueAccess) {
+ const absl::Status kError = absl::CancelledError("message");
+ absl::StatusOr<int> status_or(kError);
+ EXPECT_DEATH_OR_THROW(status_or.value(), kError);
+}
+
+TEST(StatusOr, TestStatusCtor) {
+ absl::StatusOr<int> thing(absl::CancelledError());
+ EXPECT_FALSE(thing.ok());
+ EXPECT_EQ(thing.status().code(), absl::StatusCode::kCancelled);
+}
+
+
+
+TEST(StatusOr, TestValueCtor) {
+ const int kI = 4;
+ const absl::StatusOr<int> thing(kI);
+ EXPECT_TRUE(thing.ok());
+ EXPECT_EQ(kI, *thing);
+}
+
+struct Foo {
+ const int x;
+ explicit Foo(int y) : x(y) {}
+};
+
+TEST(StatusOr, InPlaceConstruction) {
+ EXPECT_THAT(absl::StatusOr<Foo>(absl::in_place, 10),
+ IsOkAndHolds(Field(&Foo::x, 10)));
+}
+
+struct InPlaceHelper {
+ InPlaceHelper(std::initializer_list<int> xs, std::unique_ptr<int> yy)
+ : x(xs), y(std::move(yy)) {}
+ const std::vector<int> x;
+ std::unique_ptr<int> y;
+};
+
+TEST(StatusOr, InPlaceInitListConstruction) {
+ absl::StatusOr<InPlaceHelper> status_or(absl::in_place, {10, 11, 12},
+ absl::make_unique<int>(13));
+ EXPECT_THAT(status_or, IsOkAndHolds(AllOf(
+ Field(&InPlaceHelper::x, ElementsAre(10, 11, 12)),
+ Field(&InPlaceHelper::y, Pointee(13)))));
+}
+
+TEST(StatusOr, Emplace) {
+ absl::StatusOr<Foo> status_or_foo(10);
+ status_or_foo.emplace(20);
+ EXPECT_THAT(status_or_foo, IsOkAndHolds(Field(&Foo::x, 20)));
+ status_or_foo = absl::InvalidArgumentError("msg");
+ EXPECT_FALSE(status_or_foo.ok());
+ EXPECT_EQ(status_or_foo.status().code(), absl::StatusCode::kInvalidArgument);
+ EXPECT_EQ(status_or_foo.status().message(), "msg");
+ status_or_foo.emplace(20);
+ EXPECT_THAT(status_or_foo, IsOkAndHolds(Field(&Foo::x, 20)));
+}
+
+TEST(StatusOr, EmplaceInitializerList) {
+ absl::StatusOr<InPlaceHelper> status_or(absl::in_place, {10, 11, 12},
+ absl::make_unique<int>(13));
+ status_or.emplace({1, 2, 3}, absl::make_unique<int>(4));
+ EXPECT_THAT(status_or,
+ IsOkAndHolds(AllOf(Field(&InPlaceHelper::x, ElementsAre(1, 2, 3)),
+ Field(&InPlaceHelper::y, Pointee(4)))));
+ status_or = absl::InvalidArgumentError("msg");
+ EXPECT_FALSE(status_or.ok());
+ EXPECT_EQ(status_or.status().code(), absl::StatusCode::kInvalidArgument);
+ EXPECT_EQ(status_or.status().message(), "msg");
+ status_or.emplace({1, 2, 3}, absl::make_unique<int>(4));
+ EXPECT_THAT(status_or,
+ IsOkAndHolds(AllOf(Field(&InPlaceHelper::x, ElementsAre(1, 2, 3)),
+ Field(&InPlaceHelper::y, Pointee(4)))));
+}
+
+TEST(StatusOr, TestCopyCtorStatusOk) {
+ const int kI = 4;
+ const absl::StatusOr<int> original(kI);
+ const absl::StatusOr<int> copy(original);
+ EXPECT_OK(copy.status());
+ EXPECT_EQ(*original, *copy);
+}
+
+TEST(StatusOr, TestCopyCtorStatusNotOk) {
+ absl::StatusOr<int> original(absl::CancelledError());
+ absl::StatusOr<int> copy(original);
+ EXPECT_EQ(copy.status().code(), absl::StatusCode::kCancelled);
+}
+
+TEST(StatusOr, TestCopyCtorNonAssignable) {
+ const int kI = 4;
+ CopyNoAssign value(kI);
+ absl::StatusOr<CopyNoAssign> original(value);
+ absl::StatusOr<CopyNoAssign> copy(original);
+ EXPECT_OK(copy.status());
+ EXPECT_EQ(original->foo, copy->foo);
+}
+
+TEST(StatusOr, TestCopyCtorStatusOKConverting) {
+ const int kI = 4;
+ absl::StatusOr<int> original(kI);
+ absl::StatusOr<double> copy(original);
+ EXPECT_OK(copy.status());
+ EXPECT_DOUBLE_EQ(*original, *copy);
+}
+
+TEST(StatusOr, TestCopyCtorStatusNotOkConverting) {
+ absl::StatusOr<int> original(absl::CancelledError());
+ absl::StatusOr<double> copy(original);
+ EXPECT_EQ(copy.status(), original.status());
+}
+
+TEST(StatusOr, TestAssignmentStatusOk) {
+ // Copy assignmment
+ {
+ const auto p = std::make_shared<int>(17);
+ absl::StatusOr<std::shared_ptr<int>> source(p);
+
+ absl::StatusOr<std::shared_ptr<int>> target;
+ target = source;
+
+ ASSERT_TRUE(target.ok());
+ EXPECT_OK(target.status());
+ EXPECT_EQ(p, *target);
+
+ ASSERT_TRUE(source.ok());
+ EXPECT_OK(source.status());
+ EXPECT_EQ(p, *source);
+ }
+
+ // Move asssignment
+ {
+ const auto p = std::make_shared<int>(17);
+ absl::StatusOr<std::shared_ptr<int>> source(p);
+
+ absl::StatusOr<std::shared_ptr<int>> target;
+ target = std::move(source);
+
+ ASSERT_TRUE(target.ok());
+ EXPECT_OK(target.status());
+ EXPECT_EQ(p, *target);
+
+ ASSERT_TRUE(source.ok());
+ EXPECT_OK(source.status());
+ EXPECT_EQ(nullptr, *source);
+ }
+}
+
+TEST(StatusOr, TestAssignmentStatusNotOk) {
+ // Copy assignment
+ {
+ const absl::Status expected = absl::CancelledError();
+ absl::StatusOr<int> source(expected);
+
+ absl::StatusOr<int> target;
+ target = source;
+
+ EXPECT_FALSE(target.ok());
+ EXPECT_EQ(expected, target.status());
+
+ EXPECT_FALSE(source.ok());
+ EXPECT_EQ(expected, source.status());
+ }
+
+ // Move assignment
+ {
+ const absl::Status expected = absl::CancelledError();
+ absl::StatusOr<int> source(expected);
+
+ absl::StatusOr<int> target;
+ target = std::move(source);
+
+ EXPECT_FALSE(target.ok());
+ EXPECT_EQ(expected, target.status());
+
+ EXPECT_FALSE(source.ok());
+ EXPECT_EQ(source.status().code(), absl::StatusCode::kInternal);
+ }
+}
+
+TEST(StatusOr, TestAssignmentStatusOKConverting) {
+ // Copy assignment
+ {
+ const int kI = 4;
+ absl::StatusOr<int> source(kI);
+
+ absl::StatusOr<double> target;
+ target = source;
+
+ ASSERT_TRUE(target.ok());
+ EXPECT_OK(target.status());
+ EXPECT_DOUBLE_EQ(kI, *target);
+
+ ASSERT_TRUE(source.ok());
+ EXPECT_OK(source.status());
+ EXPECT_DOUBLE_EQ(kI, *source);
+ }
+
+ // Move assignment
+ {
+ const auto p = new int(17);
+ absl::StatusOr<std::unique_ptr<int>> source(absl::WrapUnique(p));
+
+ absl::StatusOr<std::shared_ptr<int>> target;
+ target = std::move(source);
+
+ ASSERT_TRUE(target.ok());
+ EXPECT_OK(target.status());
+ EXPECT_EQ(p, target->get());
+
+ ASSERT_TRUE(source.ok());
+ EXPECT_OK(source.status());
+ EXPECT_EQ(nullptr, source->get());
+ }
+}
+
+struct A {
+ int x;
+};
+
+struct ImplicitConstructibleFromA {
+ int x;
+ bool moved;
+ ImplicitConstructibleFromA(const A& a) // NOLINT
+ : x(a.x), moved(false) {}
+ ImplicitConstructibleFromA(A&& a) // NOLINT
+ : x(a.x), moved(true) {}
+};
+
+TEST(StatusOr, ImplicitConvertingConstructor) {
+ EXPECT_THAT(
+ absl::implicit_cast<absl::StatusOr<ImplicitConstructibleFromA>>(
+ absl::StatusOr<A>(A{11})),
+ IsOkAndHolds(AllOf(Field(&ImplicitConstructibleFromA::x, 11),
+ Field(&ImplicitConstructibleFromA::moved, true))));
+ absl::StatusOr<A> a(A{12});
+ EXPECT_THAT(
+ absl::implicit_cast<absl::StatusOr<ImplicitConstructibleFromA>>(a),
+ IsOkAndHolds(AllOf(Field(&ImplicitConstructibleFromA::x, 12),
+ Field(&ImplicitConstructibleFromA::moved, false))));
+}
+
+struct ExplicitConstructibleFromA {
+ int x;
+ bool moved;
+ explicit ExplicitConstructibleFromA(const A& a) : x(a.x), moved(false) {}
+ explicit ExplicitConstructibleFromA(A&& a) : x(a.x), moved(true) {}
+};
+
+TEST(StatusOr, ExplicitConvertingConstructor) {
+ EXPECT_FALSE(
+ (std::is_convertible<const absl::StatusOr<A>&,
+ absl::StatusOr<ExplicitConstructibleFromA>>::value));
+ EXPECT_FALSE(
+ (std::is_convertible<absl::StatusOr<A>&&,
+ absl::StatusOr<ExplicitConstructibleFromA>>::value));
+ EXPECT_THAT(
+ absl::StatusOr<ExplicitConstructibleFromA>(absl::StatusOr<A>(A{11})),
+ IsOkAndHolds(AllOf(Field(&ExplicitConstructibleFromA::x, 11),
+ Field(&ExplicitConstructibleFromA::moved, true))));
+ absl::StatusOr<A> a(A{12});
+ EXPECT_THAT(
+ absl::StatusOr<ExplicitConstructibleFromA>(a),
+ IsOkAndHolds(AllOf(Field(&ExplicitConstructibleFromA::x, 12),
+ Field(&ExplicitConstructibleFromA::moved, false))));
+}
+
+struct ImplicitConstructibleFromBool {
+ ImplicitConstructibleFromBool(bool y) : x(y) {} // NOLINT
+ bool x = false;
+};
+
+struct ConvertibleToBool {
+ explicit ConvertibleToBool(bool y) : x(y) {}
+ operator bool() const { return x; } // NOLINT
+ bool x = false;
+};
+
+TEST(StatusOr, ImplicitBooleanConstructionWithImplicitCasts) {
+ EXPECT_THAT(absl::StatusOr<bool>(absl::StatusOr<ConvertibleToBool>(true)),
+ IsOkAndHolds(true));
+ EXPECT_THAT(absl::StatusOr<bool>(absl::StatusOr<ConvertibleToBool>(false)),
+ IsOkAndHolds(false));
+ EXPECT_THAT(
+ absl::implicit_cast<absl::StatusOr<ImplicitConstructibleFromBool>>(
+ absl::StatusOr<bool>(false)),
+ IsOkAndHolds(Field(&ImplicitConstructibleFromBool::x, false)));
+ EXPECT_FALSE((std::is_convertible<
+ absl::StatusOr<ConvertibleToBool>,
+ absl::StatusOr<ImplicitConstructibleFromBool>>::value));
+}
+
+TEST(StatusOr, BooleanConstructionWithImplicitCasts) {
+ EXPECT_THAT(absl::StatusOr<bool>(absl::StatusOr<ConvertibleToBool>(true)),
+ IsOkAndHolds(true));
+ EXPECT_THAT(absl::StatusOr<bool>(absl::StatusOr<ConvertibleToBool>(false)),
+ IsOkAndHolds(false));
+ EXPECT_THAT(
+ absl::StatusOr<ImplicitConstructibleFromBool>{
+ absl::StatusOr<bool>(false)},
+ IsOkAndHolds(Field(&ImplicitConstructibleFromBool::x, false)));
+ EXPECT_THAT(
+ absl::StatusOr<ImplicitConstructibleFromBool>{
+ absl::StatusOr<bool>(absl::InvalidArgumentError(""))},
+ Not(IsOk()));
+
+ EXPECT_THAT(
+ absl::StatusOr<ImplicitConstructibleFromBool>{
+ absl::StatusOr<ConvertibleToBool>(ConvertibleToBool{false})},
+ IsOkAndHolds(Field(&ImplicitConstructibleFromBool::x, false)));
+ EXPECT_THAT(
+ absl::StatusOr<ImplicitConstructibleFromBool>{
+ absl::StatusOr<ConvertibleToBool>(absl::InvalidArgumentError(""))},
+ Not(IsOk()));
+}
+
+TEST(StatusOr, ConstImplicitCast) {
+ EXPECT_THAT(absl::implicit_cast<absl::StatusOr<bool>>(
+ absl::StatusOr<const bool>(true)),
+ IsOkAndHolds(true));
+ EXPECT_THAT(absl::implicit_cast<absl::StatusOr<bool>>(
+ absl::StatusOr<const bool>(false)),
+ IsOkAndHolds(false));
+ EXPECT_THAT(absl::implicit_cast<absl::StatusOr<const bool>>(
+ absl::StatusOr<bool>(true)),
+ IsOkAndHolds(true));
+ EXPECT_THAT(absl::implicit_cast<absl::StatusOr<const bool>>(
+ absl::StatusOr<bool>(false)),
+ IsOkAndHolds(false));
+ EXPECT_THAT(absl::implicit_cast<absl::StatusOr<const std::string>>(
+ absl::StatusOr<std::string>("foo")),
+ IsOkAndHolds("foo"));
+ EXPECT_THAT(absl::implicit_cast<absl::StatusOr<std::string>>(
+ absl::StatusOr<const std::string>("foo")),
+ IsOkAndHolds("foo"));
+ EXPECT_THAT(
+ absl::implicit_cast<absl::StatusOr<std::shared_ptr<const std::string>>>(
+ absl::StatusOr<std::shared_ptr<std::string>>(
+ std::make_shared<std::string>("foo"))),
+ IsOkAndHolds(Pointee(std::string("foo"))));
+}
+
+TEST(StatusOr, ConstExplicitConstruction) {
+ EXPECT_THAT(absl::StatusOr<bool>(absl::StatusOr<const bool>(true)),
+ IsOkAndHolds(true));
+ EXPECT_THAT(absl::StatusOr<bool>(absl::StatusOr<const bool>(false)),
+ IsOkAndHolds(false));
+ EXPECT_THAT(absl::StatusOr<const bool>(absl::StatusOr<bool>(true)),
+ IsOkAndHolds(true));
+ EXPECT_THAT(absl::StatusOr<const bool>(absl::StatusOr<bool>(false)),
+ IsOkAndHolds(false));
+}
+
+struct ExplicitConstructibleFromInt {
+ int x;
+ explicit ExplicitConstructibleFromInt(int y) : x(y) {}
+};
+
+TEST(StatusOr, ExplicitConstruction) {
+ EXPECT_THAT(absl::StatusOr<ExplicitConstructibleFromInt>(10),
+ IsOkAndHolds(Field(&ExplicitConstructibleFromInt::x, 10)));
+}
+
+TEST(StatusOr, ImplicitConstruction) {
+ // Check implicit casting works.
+ auto status_or =
+ absl::implicit_cast<absl::StatusOr<absl::variant<int, std::string>>>(10);
+ EXPECT_THAT(status_or, IsOkAndHolds(VariantWith<int>(10)));
+}
+
+TEST(StatusOr, ImplicitConstructionFromInitliazerList) {
+ // Note: dropping the explicit std::initializer_list<int> is not supported
+ // by absl::StatusOr or absl::optional.
+ auto status_or =
+ absl::implicit_cast<absl::StatusOr<std::vector<int>>>({{10, 20, 30}});
+ EXPECT_THAT(status_or, IsOkAndHolds(ElementsAre(10, 20, 30)));
+}
+
+TEST(StatusOr, UniquePtrImplicitConstruction) {
+ auto status_or = absl::implicit_cast<absl::StatusOr<std::unique_ptr<Base1>>>(
+ absl::make_unique<Derived>());
+ EXPECT_THAT(status_or, IsOkAndHolds(Ne(nullptr)));
+}
+
+TEST(StatusOr, NestedStatusOrCopyAndMoveConstructorTests) {
+ absl::StatusOr<absl::StatusOr<CopyDetector>> status_or = CopyDetector(10);
+ absl::StatusOr<absl::StatusOr<CopyDetector>> status_error =
+ absl::InvalidArgumentError("foo");
+ EXPECT_THAT(status_or,
+ IsOkAndHolds(IsOkAndHolds(CopyDetectorHas(10, true, false))));
+ absl::StatusOr<absl::StatusOr<CopyDetector>> a = status_or;
+ EXPECT_THAT(a, IsOkAndHolds(IsOkAndHolds(CopyDetectorHas(10, false, true))));
+ absl::StatusOr<absl::StatusOr<CopyDetector>> a_err = status_error;
+ EXPECT_THAT(a_err, Not(IsOk()));
+
+ const absl::StatusOr<absl::StatusOr<CopyDetector>>& cref = status_or;
+ absl::StatusOr<absl::StatusOr<CopyDetector>> b = cref; // NOLINT
+ EXPECT_THAT(b, IsOkAndHolds(IsOkAndHolds(CopyDetectorHas(10, false, true))));
+ const absl::StatusOr<absl::StatusOr<CopyDetector>>& cref_err = status_error;
+ absl::StatusOr<absl::StatusOr<CopyDetector>> b_err = cref_err; // NOLINT
+ EXPECT_THAT(b_err, Not(IsOk()));
+
+ absl::StatusOr<absl::StatusOr<CopyDetector>> c = std::move(status_or);
+ EXPECT_THAT(c, IsOkAndHolds(IsOkAndHolds(CopyDetectorHas(10, true, false))));
+ absl::StatusOr<absl::StatusOr<CopyDetector>> c_err = std::move(status_error);
+ EXPECT_THAT(c_err, Not(IsOk()));
+}
+
+TEST(StatusOr, NestedStatusOrCopyAndMoveAssignment) {
+ absl::StatusOr<absl::StatusOr<CopyDetector>> status_or = CopyDetector(10);
+ absl::StatusOr<absl::StatusOr<CopyDetector>> status_error =
+ absl::InvalidArgumentError("foo");
+ absl::StatusOr<absl::StatusOr<CopyDetector>> a;
+ a = status_or;
+ EXPECT_THAT(a, IsOkAndHolds(IsOkAndHolds(CopyDetectorHas(10, false, true))));
+ a = status_error;
+ EXPECT_THAT(a, Not(IsOk()));
+
+ const absl::StatusOr<absl::StatusOr<CopyDetector>>& cref = status_or;
+ a = cref;
+ EXPECT_THAT(a, IsOkAndHolds(IsOkAndHolds(CopyDetectorHas(10, false, true))));
+ const absl::StatusOr<absl::StatusOr<CopyDetector>>& cref_err = status_error;
+ a = cref_err;
+ EXPECT_THAT(a, Not(IsOk()));
+ a = std::move(status_or);
+ EXPECT_THAT(a, IsOkAndHolds(IsOkAndHolds(CopyDetectorHas(10, true, false))));
+ a = std::move(status_error);
+ EXPECT_THAT(a, Not(IsOk()));
+}
+
+struct Copyable {
+ Copyable() {}
+ Copyable(const Copyable&) {}
+ Copyable& operator=(const Copyable&) { return *this; }
+};
+
+struct MoveOnly {
+ MoveOnly() {}
+ MoveOnly(MoveOnly&&) {}
+ MoveOnly& operator=(MoveOnly&&) { return *this; }
+};
+
+struct NonMovable {
+ NonMovable() {}
+ NonMovable(const NonMovable&) = delete;
+ NonMovable(NonMovable&&) = delete;
+ NonMovable& operator=(const NonMovable&) = delete;
+ NonMovable& operator=(NonMovable&&) = delete;
+};
+
+TEST(StatusOr, CopyAndMoveAbility) {
+ EXPECT_TRUE(std::is_copy_constructible<Copyable>::value);
+ EXPECT_TRUE(std::is_copy_assignable<Copyable>::value);
+ EXPECT_TRUE(std::is_move_constructible<Copyable>::value);
+ EXPECT_TRUE(std::is_move_assignable<Copyable>::value);
+ EXPECT_FALSE(std::is_copy_constructible<MoveOnly>::value);
+ EXPECT_FALSE(std::is_copy_assignable<MoveOnly>::value);
+ EXPECT_TRUE(std::is_move_constructible<MoveOnly>::value);
+ EXPECT_TRUE(std::is_move_assignable<MoveOnly>::value);
+ EXPECT_FALSE(std::is_copy_constructible<NonMovable>::value);
+ EXPECT_FALSE(std::is_copy_assignable<NonMovable>::value);
+ EXPECT_FALSE(std::is_move_constructible<NonMovable>::value);
+ EXPECT_FALSE(std::is_move_assignable<NonMovable>::value);
+}
+
+TEST(StatusOr, StatusOrAnyCopyAndMoveConstructorTests) {
+ absl::StatusOr<absl::any> status_or = CopyDetector(10);
+ absl::StatusOr<absl::any> status_error = absl::InvalidArgumentError("foo");
+ EXPECT_THAT(
+ status_or,
+ IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, true, false))));
+ absl::StatusOr<absl::any> a = status_or;
+ EXPECT_THAT(
+ a, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, false, true))));
+ absl::StatusOr<absl::any> a_err = status_error;
+ EXPECT_THAT(a_err, Not(IsOk()));
+
+ const absl::StatusOr<absl::any>& cref = status_or;
+ // No lint for no-change copy.
+ absl::StatusOr<absl::any> b = cref; // NOLINT
+ EXPECT_THAT(
+ b, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, false, true))));
+ const absl::StatusOr<absl::any>& cref_err = status_error;
+ // No lint for no-change copy.
+ absl::StatusOr<absl::any> b_err = cref_err; // NOLINT
+ EXPECT_THAT(b_err, Not(IsOk()));
+
+ absl::StatusOr<absl::any> c = std::move(status_or);
+ EXPECT_THAT(
+ c, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, true, false))));
+ absl::StatusOr<absl::any> c_err = std::move(status_error);
+ EXPECT_THAT(c_err, Not(IsOk()));
+}
+
+TEST(StatusOr, StatusOrAnyCopyAndMoveAssignment) {
+ absl::StatusOr<absl::any> status_or = CopyDetector(10);
+ absl::StatusOr<absl::any> status_error = absl::InvalidArgumentError("foo");
+ absl::StatusOr<absl::any> a;
+ a = status_or;
+ EXPECT_THAT(
+ a, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, false, true))));
+ a = status_error;
+ EXPECT_THAT(a, Not(IsOk()));
+
+ const absl::StatusOr<absl::any>& cref = status_or;
+ a = cref;
+ EXPECT_THAT(
+ a, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, false, true))));
+ const absl::StatusOr<absl::any>& cref_err = status_error;
+ a = cref_err;
+ EXPECT_THAT(a, Not(IsOk()));
+ a = std::move(status_or);
+ EXPECT_THAT(
+ a, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, true, false))));
+ a = std::move(status_error);
+ EXPECT_THAT(a, Not(IsOk()));
+}
+
+TEST(StatusOr, StatusOrCopyAndMoveTestsConstructor) {
+ absl::StatusOr<CopyDetector> status_or(10);
+ ASSERT_THAT(status_or, IsOkAndHolds(CopyDetectorHas(10, false, false)));
+ absl::StatusOr<CopyDetector> a(status_or);
+ EXPECT_THAT(a, IsOkAndHolds(CopyDetectorHas(10, false, true)));
+ const absl::StatusOr<CopyDetector>& cref = status_or;
+ absl::StatusOr<CopyDetector> b(cref); // NOLINT
+ EXPECT_THAT(b, IsOkAndHolds(CopyDetectorHas(10, false, true)));
+ absl::StatusOr<CopyDetector> c(std::move(status_or));
+ EXPECT_THAT(c, IsOkAndHolds(CopyDetectorHas(10, true, false)));
+}
+
+TEST(StatusOr, StatusOrCopyAndMoveTestsAssignment) {
+ absl::StatusOr<CopyDetector> status_or(10);
+ ASSERT_THAT(status_or, IsOkAndHolds(CopyDetectorHas(10, false, false)));
+ absl::StatusOr<CopyDetector> a;
+ a = status_or;
+ EXPECT_THAT(a, IsOkAndHolds(CopyDetectorHas(10, false, true)));
+ const absl::StatusOr<CopyDetector>& cref = status_or;
+ absl::StatusOr<CopyDetector> b;
+ b = cref;
+ EXPECT_THAT(b, IsOkAndHolds(CopyDetectorHas(10, false, true)));
+ absl::StatusOr<CopyDetector> c;
+ c = std::move(status_or);
+ EXPECT_THAT(c, IsOkAndHolds(CopyDetectorHas(10, true, false)));
+}
+
+TEST(StatusOr, AbslAnyAssignment) {
+ EXPECT_FALSE((std::is_assignable<absl::StatusOr<absl::any>,
+ absl::StatusOr<int>>::value));
+ absl::StatusOr<absl::any> status_or;
+ status_or = absl::InvalidArgumentError("foo");
+ EXPECT_THAT(status_or, Not(IsOk()));
+}
+
+TEST(StatusOr, ImplicitAssignment) {
+ absl::StatusOr<absl::variant<int, std::string>> status_or;
+ status_or = 10;
+ EXPECT_THAT(status_or, IsOkAndHolds(VariantWith<int>(10)));
+}
+
+TEST(StatusOr, SelfDirectInitAssignment) {
+ absl::StatusOr<std::vector<int>> status_or = {{10, 20, 30}};
+ status_or = *status_or;
+ EXPECT_THAT(status_or, IsOkAndHolds(ElementsAre(10, 20, 30)));
+}
+
+TEST(StatusOr, ImplicitCastFromInitializerList) {
+ absl::StatusOr<std::vector<int>> status_or = {{10, 20, 30}};
+ EXPECT_THAT(status_or, IsOkAndHolds(ElementsAre(10, 20, 30)));
+}
+
+TEST(StatusOr, UniquePtrImplicitAssignment) {
+ absl::StatusOr<std::unique_ptr<Base1>> status_or;
+ status_or = absl::make_unique<Derived>();
+ EXPECT_THAT(status_or, IsOkAndHolds(Ne(nullptr)));
+}
+
+TEST(StatusOr, Pointer) {
+ struct A {};
+ struct B : public A {};
+ struct C : private A {};
+
+ EXPECT_TRUE((std::is_constructible<absl::StatusOr<A*>, B*>::value));
+ EXPECT_TRUE((std::is_convertible<B*, absl::StatusOr<A*>>::value));
+ EXPECT_FALSE((std::is_constructible<absl::StatusOr<A*>, C*>::value));
+ EXPECT_FALSE((std::is_convertible<C*, absl::StatusOr<A*>>::value));
+}
+
+TEST(StatusOr, TestAssignmentStatusNotOkConverting) {
+ // Copy assignment
+ {
+ const absl::Status expected = absl::CancelledError();
+ absl::StatusOr<int> source(expected);
+
+ absl::StatusOr<double> target;
+ target = source;
+
+ EXPECT_FALSE(target.ok());
+ EXPECT_EQ(expected, target.status());
+
+ EXPECT_FALSE(source.ok());
+ EXPECT_EQ(expected, source.status());
+ }
+
+ // Move assignment
+ {
+ const absl::Status expected = absl::CancelledError();
+ absl::StatusOr<int> source(expected);
+
+ absl::StatusOr<double> target;
+ target = std::move(source);
+
+ EXPECT_FALSE(target.ok());
+ EXPECT_EQ(expected, target.status());
+
+ EXPECT_FALSE(source.ok());
+ EXPECT_EQ(source.status().code(), absl::StatusCode::kInternal);
+ }
+}
+
+TEST(StatusOr, SelfAssignment) {
+ // Copy-assignment, status OK
+ {
+ // A string long enough that it's likely to defeat any inline representation
+ // optimization.
+ const std::string long_str(128, 'a');
+
+ absl::StatusOr<std::string> so = long_str;
+ so = *&so;
+
+ ASSERT_TRUE(so.ok());
+ EXPECT_OK(so.status());
+ EXPECT_EQ(long_str, *so);
+ }
+
+ // Copy-assignment, error status
+ {
+ absl::StatusOr<int> so = absl::NotFoundError("taco");
+ so = *&so;
+
+ EXPECT_FALSE(so.ok());
+ EXPECT_EQ(so.status().code(), absl::StatusCode::kNotFound);
+ EXPECT_EQ(so.status().message(), "taco");
+ }
+
+ // Move-assignment with copyable type, status OK
+ {
+ absl::StatusOr<int> so = 17;
+
+ // Fool the compiler, which otherwise complains.
+ auto& same = so;
+ so = std::move(same);
+
+ ASSERT_TRUE(so.ok());
+ EXPECT_OK(so.status());
+ EXPECT_EQ(17, *so);
+ }
+
+ // Move-assignment with copyable type, error status
+ {
+ absl::StatusOr<int> so = absl::NotFoundError("taco");
+
+ // Fool the compiler, which otherwise complains.
+ auto& same = so;
+ so = std::move(same);
+
+ EXPECT_FALSE(so.ok());
+ EXPECT_EQ(so.status().code(), absl::StatusCode::kNotFound);
+ EXPECT_EQ(so.status().message(), "taco");
+ }
+
+ // Move-assignment with non-copyable type, status OK
+ {
+ const auto raw = new int(17);
+ absl::StatusOr<std::unique_ptr<int>> so = absl::WrapUnique(raw);
+
+ // Fool the compiler, which otherwise complains.
+ auto& same = so;
+ so = std::move(same);
+
+ ASSERT_TRUE(so.ok());
+ EXPECT_OK(so.status());
+ EXPECT_EQ(raw, so->get());
+ }
+
+ // Move-assignment with non-copyable type, error status
+ {
+ absl::StatusOr<std::unique_ptr<int>> so = absl::NotFoundError("taco");
+
+ // Fool the compiler, which otherwise complains.
+ auto& same = so;
+ so = std::move(same);
+
+ EXPECT_FALSE(so.ok());
+ EXPECT_EQ(so.status().code(), absl::StatusCode::kNotFound);
+ EXPECT_EQ(so.status().message(), "taco");
+ }
+}
+
+// These types form the overload sets of the constructors and the assignment
+// operators of `MockValue`. They distinguish construction from assignment,
+// lvalue from rvalue.
+struct FromConstructibleAssignableLvalue {};
+struct FromConstructibleAssignableRvalue {};
+struct FromImplicitConstructibleOnly {};
+struct FromAssignableOnly {};
+
+// This class is for testing the forwarding value assignments of `StatusOr`.
+// `from_rvalue` indicates whether the constructor or the assignment taking
+// rvalue reference is called. `from_assignment` indicates whether any
+// assignment is called.
+struct MockValue {
+ // Constructs `MockValue` from `FromConstructibleAssignableLvalue`.
+ MockValue(const FromConstructibleAssignableLvalue&) // NOLINT
+ : from_rvalue(false), assigned(false) {}
+ // Constructs `MockValue` from `FromConstructibleAssignableRvalue`.
+ MockValue(FromConstructibleAssignableRvalue&&) // NOLINT
+ : from_rvalue(true), assigned(false) {}
+ // Constructs `MockValue` from `FromImplicitConstructibleOnly`.
+ // `MockValue` is not assignable from `FromImplicitConstructibleOnly`.
+ MockValue(const FromImplicitConstructibleOnly&) // NOLINT
+ : from_rvalue(false), assigned(false) {}
+ // Assigns `FromConstructibleAssignableLvalue`.
+ MockValue& operator=(const FromConstructibleAssignableLvalue&) {
+ from_rvalue = false;
+ assigned = true;
+ return *this;
+ }
+ // Assigns `FromConstructibleAssignableRvalue` (rvalue only).
+ MockValue& operator=(FromConstructibleAssignableRvalue&&) {
+ from_rvalue = true;
+ assigned = true;
+ return *this;
+ }
+ // Assigns `FromAssignableOnly`, but not constructible from
+ // `FromAssignableOnly`.
+ MockValue& operator=(const FromAssignableOnly&) {
+ from_rvalue = false;
+ assigned = true;
+ return *this;
+ }
+ bool from_rvalue;
+ bool assigned;
+};
+
+// operator=(U&&)
+TEST(StatusOr, PerfectForwardingAssignment) {
+ // U == T
+ constexpr int kValue1 = 10, kValue2 = 20;
+ absl::StatusOr<CopyDetector> status_or;
+ CopyDetector lvalue(kValue1);
+ status_or = lvalue;
+ EXPECT_THAT(status_or, IsOkAndHolds(CopyDetectorHas(kValue1, false, true)));
+ status_or = CopyDetector(kValue2);
+ EXPECT_THAT(status_or, IsOkAndHolds(CopyDetectorHas(kValue2, true, false)));
+
+ // U != T
+ EXPECT_TRUE(
+ (std::is_assignable<absl::StatusOr<MockValue>&,
+ const FromConstructibleAssignableLvalue&>::value));
+ EXPECT_TRUE((std::is_assignable<absl::StatusOr<MockValue>&,
+ FromConstructibleAssignableLvalue&&>::value));
+ EXPECT_FALSE(
+ (std::is_assignable<absl::StatusOr<MockValue>&,
+ const FromConstructibleAssignableRvalue&>::value));
+ EXPECT_TRUE((std::is_assignable<absl::StatusOr<MockValue>&,
+ FromConstructibleAssignableRvalue&&>::value));
+ EXPECT_TRUE(
+ (std::is_assignable<absl::StatusOr<MockValue>&,
+ const FromImplicitConstructibleOnly&>::value));
+ EXPECT_FALSE((std::is_assignable<absl::StatusOr<MockValue>&,
+ const FromAssignableOnly&>::value));
+
+ absl::StatusOr<MockValue> from_lvalue(FromConstructibleAssignableLvalue{});
+ EXPECT_FALSE(from_lvalue->from_rvalue);
+ EXPECT_FALSE(from_lvalue->assigned);
+ from_lvalue = FromConstructibleAssignableLvalue{};
+ EXPECT_FALSE(from_lvalue->from_rvalue);
+ EXPECT_TRUE(from_lvalue->assigned);
+
+ absl::StatusOr<MockValue> from_rvalue(FromConstructibleAssignableRvalue{});
+ EXPECT_TRUE(from_rvalue->from_rvalue);
+ EXPECT_FALSE(from_rvalue->assigned);
+ from_rvalue = FromConstructibleAssignableRvalue{};
+ EXPECT_TRUE(from_rvalue->from_rvalue);
+ EXPECT_TRUE(from_rvalue->assigned);
+
+ absl::StatusOr<MockValue> from_implicit_constructible(
+ FromImplicitConstructibleOnly{});
+ EXPECT_FALSE(from_implicit_constructible->from_rvalue);
+ EXPECT_FALSE(from_implicit_constructible->assigned);
+ // construct a temporary `StatusOr` object and invoke the `StatusOr` move
+ // assignment operator.
+ from_implicit_constructible = FromImplicitConstructibleOnly{};
+ EXPECT_FALSE(from_implicit_constructible->from_rvalue);
+ EXPECT_FALSE(from_implicit_constructible->assigned);
+}
+
+TEST(StatusOr, TestStatus) {
+ absl::StatusOr<int> good(4);
+ EXPECT_TRUE(good.ok());
+ absl::StatusOr<int> bad(absl::CancelledError());
+ EXPECT_FALSE(bad.ok());
+ EXPECT_EQ(bad.status().code(), absl::StatusCode::kCancelled);
+}
+
+TEST(StatusOr, OperatorStarRefQualifiers) {
+ static_assert(
+ std::is_same<const int&,
+ decltype(*std::declval<const absl::StatusOr<int>&>())>(),
+ "Unexpected ref-qualifiers");
+ static_assert(
+ std::is_same<int&, decltype(*std::declval<absl::StatusOr<int>&>())>(),
+ "Unexpected ref-qualifiers");
+ static_assert(
+ std::is_same<const int&&,
+ decltype(*std::declval<const absl::StatusOr<int>&&>())>(),
+ "Unexpected ref-qualifiers");
+ static_assert(
+ std::is_same<int&&, decltype(*std::declval<absl::StatusOr<int>&&>())>(),
+ "Unexpected ref-qualifiers");
+}
+
+TEST(StatusOr, OperatorStar) {
+ const absl::StatusOr<std::string> const_lvalue("hello");
+ EXPECT_EQ("hello", *const_lvalue);
+
+ absl::StatusOr<std::string> lvalue("hello");
+ EXPECT_EQ("hello", *lvalue);
+
+ // Note: Recall that std::move() is equivalent to a static_cast to an rvalue
+ // reference type.
+ const absl::StatusOr<std::string> const_rvalue("hello");
+ EXPECT_EQ("hello", *std::move(const_rvalue)); // NOLINT
+
+ absl::StatusOr<std::string> rvalue("hello");
+ EXPECT_EQ("hello", *std::move(rvalue));
+}
+
+TEST(StatusOr, OperatorArrowQualifiers) {
+ static_assert(
+ std::is_same<
+ const int*,
+ decltype(std::declval<const absl::StatusOr<int>&>().operator->())>(),
+ "Unexpected qualifiers");
+ static_assert(
+ std::is_same<
+ int*, decltype(std::declval<absl::StatusOr<int>&>().operator->())>(),
+ "Unexpected qualifiers");
+ static_assert(
+ std::is_same<
+ const int*,
+ decltype(std::declval<const absl::StatusOr<int>&&>().operator->())>(),
+ "Unexpected qualifiers");
+ static_assert(
+ std::is_same<
+ int*, decltype(std::declval<absl::StatusOr<int>&&>().operator->())>(),
+ "Unexpected qualifiers");
+}
+
+TEST(StatusOr, OperatorArrow) {
+ const absl::StatusOr<std::string> const_lvalue("hello");
+ EXPECT_EQ(std::string("hello"), const_lvalue->c_str());
+
+ absl::StatusOr<std::string> lvalue("hello");
+ EXPECT_EQ(std::string("hello"), lvalue->c_str());
+}
+
+TEST(StatusOr, RValueStatus) {
+ absl::StatusOr<int> so(absl::NotFoundError("taco"));
+ const absl::Status s = std::move(so).status();
+
+ EXPECT_EQ(s.code(), absl::StatusCode::kNotFound);
+ EXPECT_EQ(s.message(), "taco");
+
+ // Check that !ok() still implies !status().ok(), even after moving out of the
+ // object. See the note on the rvalue ref-qualified status method.
+ EXPECT_FALSE(so.ok()); // NOLINT
+ EXPECT_FALSE(so.status().ok());
+ EXPECT_EQ(so.status().code(), absl::StatusCode::kInternal);
+ EXPECT_EQ(so.status().message(), "Status accessed after move.");
+}
+
+TEST(StatusOr, TestValue) {
+ const int kI = 4;
+ absl::StatusOr<int> thing(kI);
+ EXPECT_EQ(kI, *thing);
+}
+
+TEST(StatusOr, TestValueConst) {
+ const int kI = 4;
+ const absl::StatusOr<int> thing(kI);
+ EXPECT_EQ(kI, *thing);
+}
+
+TEST(StatusOr, TestPointerDefaultCtor) {
+ absl::StatusOr<int*> thing;
+ EXPECT_FALSE(thing.ok());
+ EXPECT_EQ(thing.status().code(), absl::StatusCode::kUnknown);
+}
+
+
+
+TEST(StatusOr, TestPointerStatusCtor) {
+ absl::StatusOr<int*> thing(absl::CancelledError());
+ EXPECT_FALSE(thing.ok());
+ EXPECT_EQ(thing.status().code(), absl::StatusCode::kCancelled);
+}
+
+TEST(StatusOr, TestPointerValueCtor) {
+ const int kI = 4;
+
+ // Construction from a non-null pointer
+ {
+ absl::StatusOr<const int*> so(&kI);
+ EXPECT_TRUE(so.ok());
+ EXPECT_OK(so.status());
+ EXPECT_EQ(&kI, *so);
+ }
+
+ // Construction from a null pointer constant
+ {
+ absl::StatusOr<const int*> so(nullptr);
+ EXPECT_TRUE(so.ok());
+ EXPECT_OK(so.status());
+ EXPECT_EQ(nullptr, *so);
+ }
+
+ // Construction from a non-literal null pointer
+ {
+ const int* const p = nullptr;
+
+ absl::StatusOr<const int*> so(p);
+ EXPECT_TRUE(so.ok());
+ EXPECT_OK(so.status());
+ EXPECT_EQ(nullptr, *so);
+ }
+}
+
+TEST(StatusOr, TestPointerCopyCtorStatusOk) {
+ const int kI = 0;
+ absl::StatusOr<const int*> original(&kI);
+ absl::StatusOr<const int*> copy(original);
+ EXPECT_OK(copy.status());
+ EXPECT_EQ(*original, *copy);
+}
+
+TEST(StatusOr, TestPointerCopyCtorStatusNotOk) {
+ absl::StatusOr<int*> original(absl::CancelledError());
+ absl::StatusOr<int*> copy(original);
+ EXPECT_EQ(copy.status().code(), absl::StatusCode::kCancelled);
+}
+
+TEST(StatusOr, TestPointerCopyCtorStatusOKConverting) {
+ Derived derived;
+ absl::StatusOr<Derived*> original(&derived);
+ absl::StatusOr<Base2*> copy(original);
+ EXPECT_OK(copy.status());
+ EXPECT_EQ(static_cast<const Base2*>(*original), *copy);
+}
+
+TEST(StatusOr, TestPointerCopyCtorStatusNotOkConverting) {
+ absl::StatusOr<Derived*> original(absl::CancelledError());
+ absl::StatusOr<Base2*> copy(original);
+ EXPECT_EQ(copy.status().code(), absl::StatusCode::kCancelled);
+}
+
+TEST(StatusOr, TestPointerAssignmentStatusOk) {
+ const int kI = 0;
+ absl::StatusOr<const int*> source(&kI);
+ absl::StatusOr<const int*> target;
+ target = source;
+ EXPECT_OK(target.status());
+ EXPECT_EQ(*source, *target);
+}
+
+TEST(StatusOr, TestPointerAssignmentStatusNotOk) {
+ absl::StatusOr<int*> source(absl::CancelledError());
+ absl::StatusOr<int*> target;
+ target = source;
+ EXPECT_EQ(target.status().code(), absl::StatusCode::kCancelled);
+}
+
+TEST(StatusOr, TestPointerAssignmentStatusOKConverting) {
+ Derived derived;
+ absl::StatusOr<Derived*> source(&derived);
+ absl::StatusOr<Base2*> target;
+ target = source;
+ EXPECT_OK(target.status());
+ EXPECT_EQ(static_cast<const Base2*>(*source), *target);
+}
+
+TEST(StatusOr, TestPointerAssignmentStatusNotOkConverting) {
+ absl::StatusOr<Derived*> source(absl::CancelledError());
+ absl::StatusOr<Base2*> target;
+ target = source;
+ EXPECT_EQ(target.status(), source.status());
+}
+
+TEST(StatusOr, TestPointerStatus) {
+ const int kI = 0;
+ absl::StatusOr<const int*> good(&kI);
+ EXPECT_TRUE(good.ok());
+ absl::StatusOr<const int*> bad(absl::CancelledError());
+ EXPECT_EQ(bad.status().code(), absl::StatusCode::kCancelled);
+}
+
+TEST(StatusOr, TestPointerValue) {
+ const int kI = 0;
+ absl::StatusOr<const int*> thing(&kI);
+ EXPECT_EQ(&kI, *thing);
+}
+
+TEST(StatusOr, TestPointerValueConst) {
+ const int kI = 0;
+ const absl::StatusOr<const int*> thing(&kI);
+ EXPECT_EQ(&kI, *thing);
+}
+
+TEST(StatusOr, StatusOrVectorOfUniquePointerCanReserveAndResize) {
+ using EvilType = std::vector<std::unique_ptr<int>>;
+ static_assert(std::is_copy_constructible<EvilType>::value, "");
+ std::vector<::absl::StatusOr<EvilType>> v(5);
+ v.reserve(v.capacity() + 10);
+ v.resize(v.capacity() + 10);
+}
+
+TEST(StatusOr, ConstPayload) {
+ // A reduced version of a problematic type found in the wild. All of the
+ // operations below should compile.
+ absl::StatusOr<const int> a;
+
+ // Copy-construction
+ absl::StatusOr<const int> b(a);
+
+ // Copy-assignment
+ EXPECT_FALSE(std::is_copy_assignable<absl::StatusOr<const int>>::value);
+
+ // Move-construction
+ absl::StatusOr<const int> c(std::move(a));
+
+ // Move-assignment
+ EXPECT_FALSE(std::is_move_assignable<absl::StatusOr<const int>>::value);
+}
+
+TEST(StatusOr, MapToStatusOrUniquePtr) {
+ // A reduced version of a problematic type found in the wild. All of the
+ // operations below should compile.
+ using MapType = std::map<std::string, absl::StatusOr<std::unique_ptr<int>>>;
+
+ MapType a;
+
+ // Move-construction
+ MapType b(std::move(a));
+
+ // Move-assignment
+ a = std::move(b);
+}
+
+TEST(StatusOr, ValueOrOk) {
+ const absl::StatusOr<int> status_or = 0;
+ EXPECT_EQ(status_or.value_or(-1), 0);
+}
+
+TEST(StatusOr, ValueOrDefault) {
+ const absl::StatusOr<int> status_or = absl::CancelledError();
+ EXPECT_EQ(status_or.value_or(-1), -1);
+}
+
+TEST(StatusOr, MoveOnlyValueOrOk) {
+ EXPECT_THAT(absl::StatusOr<std::unique_ptr<int>>(absl::make_unique<int>(0))
+ .value_or(absl::make_unique<int>(-1)),
+ Pointee(0));
+}
+
+TEST(StatusOr, MoveOnlyValueOrDefault) {
+ EXPECT_THAT(absl::StatusOr<std::unique_ptr<int>>(absl::CancelledError())
+ .value_or(absl::make_unique<int>(-1)),
+ Pointee(-1));
+}
+
+static absl::StatusOr<int> MakeStatus() { return 100; }
+
+TEST(StatusOr, TestIgnoreError) { MakeStatus().IgnoreError(); }
+
+TEST(StatusOr, EqualityOperator) {
+ constexpr int kNumCases = 4;
+ std::array<absl::StatusOr<int>, kNumCases> group1 = {
+ absl::StatusOr<int>(1), absl::StatusOr<int>(2),
+ absl::StatusOr<int>(absl::InvalidArgumentError("msg")),
+ absl::StatusOr<int>(absl::InternalError("msg"))};
+ std::array<absl::StatusOr<int>, kNumCases> group2 = {
+ absl::StatusOr<int>(1), absl::StatusOr<int>(2),
+ absl::StatusOr<int>(absl::InvalidArgumentError("msg")),
+ absl::StatusOr<int>(absl::InternalError("msg"))};
+ for (int i = 0; i < kNumCases; ++i) {
+ for (int j = 0; j < kNumCases; ++j) {
+ if (i == j) {
+ EXPECT_TRUE(group1[i] == group2[j]);
+ EXPECT_FALSE(group1[i] != group2[j]);
+ } else {
+ EXPECT_FALSE(group1[i] == group2[j]);
+ EXPECT_TRUE(group1[i] != group2[j]);
+ }
+ }
+ }
+}
+
+struct MyType {
+ bool operator==(const MyType&) const { return true; }
+};
+
+enum class ConvTraits { kNone = 0, kImplicit = 1, kExplicit = 2 };
+
+// This class has conversion operator to `StatusOr<T>` based on value of
+// `conv_traits`.
+template <typename T, ConvTraits conv_traits = ConvTraits::kNone>
+struct StatusOrConversionBase {};
+
+template <typename T>
+struct StatusOrConversionBase<T, ConvTraits::kImplicit> {
+ operator absl::StatusOr<T>() const& { // NOLINT
+ return absl::InvalidArgumentError("conversion to absl::StatusOr");
+ }
+ operator absl::StatusOr<T>() && { // NOLINT
+ return absl::InvalidArgumentError("conversion to absl::StatusOr");
+ }
+};
+
+template <typename T>
+struct StatusOrConversionBase<T, ConvTraits::kExplicit> {
+ explicit operator absl::StatusOr<T>() const& {
+ return absl::InvalidArgumentError("conversion to absl::StatusOr");
+ }
+ explicit operator absl::StatusOr<T>() && {
+ return absl::InvalidArgumentError("conversion to absl::StatusOr");
+ }
+};
+
+// This class has conversion operator to `T` based on the value of
+// `conv_traits`.
+template <typename T, ConvTraits conv_traits = ConvTraits::kNone>
+struct ConversionBase {};
+
+template <typename T>
+struct ConversionBase<T, ConvTraits::kImplicit> {
+ operator T() const& { return t; } // NOLINT
+ operator T() && { return std::move(t); } // NOLINT
+ T t;
+};
+
+template <typename T>
+struct ConversionBase<T, ConvTraits::kExplicit> {
+ explicit operator T() const& { return t; }
+ explicit operator T() && { return std::move(t); }
+ T t;
+};
+
+// This class has conversion operator to `absl::Status` based on the value of
+// `conv_traits`.
+template <ConvTraits conv_traits = ConvTraits::kNone>
+struct StatusConversionBase {};
+
+template <>
+struct StatusConversionBase<ConvTraits::kImplicit> {
+ operator absl::Status() const& { // NOLINT
+ return absl::InternalError("conversion to Status");
+ }
+ operator absl::Status() && { // NOLINT
+ return absl::InternalError("conversion to Status");
+ }
+};
+
+template <>
+struct StatusConversionBase<ConvTraits::kExplicit> {
+ explicit operator absl::Status() const& { // NOLINT
+ return absl::InternalError("conversion to Status");
+ }
+ explicit operator absl::Status() && { // NOLINT
+ return absl::InternalError("conversion to Status");
+ }
+};
+
+static constexpr int kConvToStatus = 1;
+static constexpr int kConvToStatusOr = 2;
+static constexpr int kConvToT = 4;
+static constexpr int kConvExplicit = 8;
+
+constexpr ConvTraits GetConvTraits(int bit, int config) {
+ return (config & bit) == 0
+ ? ConvTraits::kNone
+ : ((config & kConvExplicit) == 0 ? ConvTraits::kImplicit
+ : ConvTraits::kExplicit);
+}
+
+// This class conditionally has conversion operator to `absl::Status`, `T`,
+// `StatusOr<T>`, based on values of the template parameters.
+template <typename T, int config>
+struct CustomType
+ : StatusOrConversionBase<T, GetConvTraits(kConvToStatusOr, config)>,
+ ConversionBase<T, GetConvTraits(kConvToT, config)>,
+ StatusConversionBase<GetConvTraits(kConvToStatus, config)> {};
+
+struct ConvertibleToAnyStatusOr {
+ template <typename T>
+ operator absl::StatusOr<T>() const { // NOLINT
+ return absl::InvalidArgumentError("Conversion to absl::StatusOr");
+ }
+};
+
+// Test the rank of overload resolution for `StatusOr<T>` constructor and
+// assignment, from highest to lowest:
+// 1. T/Status
+// 2. U that has conversion operator to absl::StatusOr<T>
+// 3. U that is convertible to Status
+// 4. U that is convertible to T
+TEST(StatusOr, ConstructionFromT) {
+ // Construct absl::StatusOr<T> from T when T is convertible to
+ // absl::StatusOr<T>
+ {
+ ConvertibleToAnyStatusOr v;
+ absl::StatusOr<ConvertibleToAnyStatusOr> statusor(v);
+ EXPECT_TRUE(statusor.ok());
+ }
+ {
+ ConvertibleToAnyStatusOr v;
+ absl::StatusOr<ConvertibleToAnyStatusOr> statusor = v;
+ EXPECT_TRUE(statusor.ok());
+ }
+ // Construct absl::StatusOr<T> from T when T is explicitly convertible to
+ // Status
+ {
+ CustomType<MyType, kConvToStatus | kConvExplicit> v;
+ absl::StatusOr<CustomType<MyType, kConvToStatus | kConvExplicit>> statusor(
+ v);
+ EXPECT_TRUE(statusor.ok());
+ }
+ {
+ CustomType<MyType, kConvToStatus | kConvExplicit> v;
+ absl::StatusOr<CustomType<MyType, kConvToStatus | kConvExplicit>> statusor =
+ v;
+ EXPECT_TRUE(statusor.ok());
+ }
+}
+
+// Construct absl::StatusOr<T> from U when U is explicitly convertible to T
+TEST(StatusOr, ConstructionFromTypeConvertibleToT) {
+ {
+ CustomType<MyType, kConvToT | kConvExplicit> v;
+ absl::StatusOr<MyType> statusor(v);
+ EXPECT_TRUE(statusor.ok());
+ }
+ {
+ CustomType<MyType, kConvToT> v;
+ absl::StatusOr<MyType> statusor = v;
+ EXPECT_TRUE(statusor.ok());
+ }
+}
+
+// Construct absl::StatusOr<T> from U when U has explicit conversion operator to
+// absl::StatusOr<T>
+TEST(StatusOr, ConstructionFromTypeWithConversionOperatorToStatusOrT) {
+ {
+ CustomType<MyType, kConvToStatusOr | kConvExplicit> v;
+ absl::StatusOr<MyType> statusor(v);
+ EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+ }
+ {
+ CustomType<MyType, kConvToT | kConvToStatusOr | kConvExplicit> v;
+ absl::StatusOr<MyType> statusor(v);
+ EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+ }
+ {
+ CustomType<MyType, kConvToStatusOr | kConvToStatus | kConvExplicit> v;
+ absl::StatusOr<MyType> statusor(v);
+ EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+ }
+ {
+ CustomType<MyType,
+ kConvToT | kConvToStatusOr | kConvToStatus | kConvExplicit>
+ v;
+ absl::StatusOr<MyType> statusor(v);
+ EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+ }
+ {
+ CustomType<MyType, kConvToStatusOr> v;
+ absl::StatusOr<MyType> statusor = v;
+ EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+ }
+ {
+ CustomType<MyType, kConvToT | kConvToStatusOr> v;
+ absl::StatusOr<MyType> statusor = v;
+ EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+ }
+ {
+ CustomType<MyType, kConvToStatusOr | kConvToStatus> v;
+ absl::StatusOr<MyType> statusor = v;
+ EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+ }
+ {
+ CustomType<MyType, kConvToT | kConvToStatusOr | kConvToStatus> v;
+ absl::StatusOr<MyType> statusor = v;
+ EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+ }
+}
+
+TEST(StatusOr, ConstructionFromTypeConvertibleToStatus) {
+ // Construction fails because conversion to `Status` is explicit.
+ {
+ CustomType<MyType, kConvToStatus | kConvExplicit> v;
+ absl::StatusOr<MyType> statusor(v);
+ EXPECT_FALSE(statusor.ok());
+ EXPECT_EQ(statusor.status(), static_cast<absl::Status>(v));
+ }
+ {
+ CustomType<MyType, kConvToT | kConvToStatus | kConvExplicit> v;
+ absl::StatusOr<MyType> statusor(v);
+ EXPECT_FALSE(statusor.ok());
+ EXPECT_EQ(statusor.status(), static_cast<absl::Status>(v));
+ }
+ {
+ CustomType<MyType, kConvToStatus> v;
+ absl::StatusOr<MyType> statusor = v;
+ EXPECT_FALSE(statusor.ok());
+ EXPECT_EQ(statusor.status(), static_cast<absl::Status>(v));
+ }
+ {
+ CustomType<MyType, kConvToT | kConvToStatus> v;
+ absl::StatusOr<MyType> statusor = v;
+ EXPECT_FALSE(statusor.ok());
+ EXPECT_EQ(statusor.status(), static_cast<absl::Status>(v));
+ }
+}
+
+TEST(StatusOr, AssignmentFromT) {
+ // Assign to absl::StatusOr<T> from T when T is convertible to
+ // absl::StatusOr<T>
+ {
+ ConvertibleToAnyStatusOr v;
+ absl::StatusOr<ConvertibleToAnyStatusOr> statusor;
+ statusor = v;
+ EXPECT_TRUE(statusor.ok());
+ }
+ // Assign to absl::StatusOr<T> from T when T is convertible to Status
+ {
+ CustomType<MyType, kConvToStatus> v;
+ absl::StatusOr<CustomType<MyType, kConvToStatus>> statusor;
+ statusor = v;
+ EXPECT_TRUE(statusor.ok());
+ }
+}
+
+TEST(StatusOr, AssignmentFromTypeConvertibleToT) {
+ // Assign to absl::StatusOr<T> from U when U is convertible to T
+ {
+ CustomType<MyType, kConvToT> v;
+ absl::StatusOr<MyType> statusor;
+ statusor = v;
+ EXPECT_TRUE(statusor.ok());
+ }
+}
+
+TEST(StatusOr, AssignmentFromTypeWithConversionOperatortoStatusOrT) {
+ // Assign to absl::StatusOr<T> from U when U has conversion operator to
+ // absl::StatusOr<T>
+ {
+ CustomType<MyType, kConvToStatusOr> v;
+ absl::StatusOr<MyType> statusor;
+ statusor = v;
+ EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+ }
+ {
+ CustomType<MyType, kConvToT | kConvToStatusOr> v;
+ absl::StatusOr<MyType> statusor;
+ statusor = v;
+ EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+ }
+ {
+ CustomType<MyType, kConvToStatusOr | kConvToStatus> v;
+ absl::StatusOr<MyType> statusor;
+ statusor = v;
+ EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+ }
+ {
+ CustomType<MyType, kConvToT | kConvToStatusOr | kConvToStatus> v;
+ absl::StatusOr<MyType> statusor;
+ statusor = v;
+ EXPECT_EQ(statusor, v.operator absl::StatusOr<MyType>());
+ }
+}
+
+TEST(StatusOr, AssignmentFromTypeConvertibleToStatus) {
+ // Assign to absl::StatusOr<T> from U when U is convertible to Status
+ {
+ CustomType<MyType, kConvToStatus> v;
+ absl::StatusOr<MyType> statusor;
+ statusor = v;
+ EXPECT_FALSE(statusor.ok());
+ EXPECT_EQ(statusor.status(), static_cast<absl::Status>(v));
+ }
+ {
+ CustomType<MyType, kConvToT | kConvToStatus> v;
+ absl::StatusOr<MyType> statusor;
+ statusor = v;
+ EXPECT_FALSE(statusor.ok());
+ EXPECT_EQ(statusor.status(), static_cast<absl::Status>(v));
+ }
+}
+
+} // namespace
diff --git a/third_party/abseil/absl/strings/BUILD.bazel b/third_party/abseil/absl/strings/BUILD.bazel
index 3ecef1f..12c9054 100644
--- a/third_party/abseil/absl/strings/BUILD.bazel
+++ b/third_party/abseil/absl/strings/BUILD.bazel
@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-#load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load(
"//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
@@ -25,7 +25,7 @@
features = ["parse_headers"],
)
-licenses(["notice"]) # Apache 2.0
+licenses(["notice"])
cc_library(
name = "strings",
@@ -54,6 +54,7 @@
"ascii.h",
"charconv.h",
"escaping.h",
+ "internal/string_constant.h",
"match.h",
"numbers.h",
"str_cat.h",
@@ -68,7 +69,6 @@
deps = [
":internal",
"//absl/base",
- "//absl/base:bits",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:endian",
@@ -76,6 +76,7 @@
"//absl/base:throw_delegate",
"//absl/memory",
"//absl/meta:type_traits",
+ "//absl/numeric:bits",
"//absl/numeric:int128",
],
)
@@ -83,19 +84,23 @@
cc_library(
name = "internal",
srcs = [
+ "internal/escaping.cc",
"internal/ostringstream.cc",
"internal/utf8.cc",
],
hdrs = [
"internal/char_map.h",
+ "internal/escaping.h",
"internal/ostringstream.h",
"internal/resize_uninitialized.h",
"internal/utf8.h",
],
copts = ABSL_DEFAULT_COPTS,
deps = [
+ "//absl/base:config",
"//absl/base:core_headers",
"//absl/base:endian",
+ "//absl/base:raw_logging_internal",
"//absl/meta:type_traits",
],
)
@@ -122,6 +127,7 @@
copts = ABSL_TEST_COPTS,
visibility = ["//visibility:private"],
deps = [
+ ":cord",
":strings",
"//absl/base:core_headers",
"//absl/container:fixed_array",
@@ -218,6 +224,19 @@
)
cc_test(
+ name = "string_constant_test",
+ size = "small",
+ srcs = ["internal/string_constant_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ visibility = ["//visibility:private"],
+ deps = [
+ ":strings",
+ "//absl/meta:type_traits",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
name = "string_view_benchmark",
srcs = ["string_view_benchmark.cc"],
copts = ABSL_TEST_COPTS,
@@ -246,6 +265,88 @@
],
)
+cc_library(
+ name = "cord_internal",
+ srcs = [
+ "internal/cord_internal.cc",
+ ],
+ hdrs = [
+ "internal/cord_internal.h",
+ "internal/cord_rep_flat.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ visibility = [
+ "//visibility:private",
+ ],
+ deps = [
+ ":strings",
+ "//absl/base:base_internal",
+ "//absl/base:core_headers",
+ "//absl/container:compressed_tuple",
+ "//absl/container:inlined_vector",
+ "//absl/meta:type_traits",
+ ],
+)
+
+cc_library(
+ name = "cord",
+ srcs = [
+ "cord.cc",
+ ],
+ hdrs = [
+ "cord.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ ":cord_internal",
+ ":internal",
+ ":str_format",
+ ":strings",
+ "//absl/base",
+ "//absl/base:core_headers",
+ "//absl/base:endian",
+ "//absl/base:raw_logging_internal",
+ "//absl/container:fixed_array",
+ "//absl/container:inlined_vector",
+ "//absl/functional:function_ref",
+ "//absl/meta:type_traits",
+ "//absl/types:optional",
+ ],
+)
+
+cc_library(
+ name = "cord_test_helpers",
+ testonly = 1,
+ hdrs = [
+ "cord_test_helpers.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ ":cord",
+ ],
+)
+
+cc_test(
+ name = "cord_test",
+ size = "medium",
+ srcs = ["cord_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ visibility = ["//visibility:private"],
+ deps = [
+ ":cord",
+ ":cord_test_helpers",
+ ":str_format",
+ ":strings",
+ "//absl/base",
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ "//absl/base:endian",
+ "//absl/base:raw_logging_internal",
+ "//absl/container:fixed_array",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
cc_test(
name = "substitute_test",
size = "small",
@@ -293,6 +394,8 @@
":strings",
"//absl/base:core_headers",
"//absl/base:dynamic_annotations",
+ "//absl/container:flat_hash_map",
+ "//absl/container:node_hash_map",
"@com_google_googletest//:gtest_main",
],
)
@@ -411,10 +514,13 @@
copts = ABSL_TEST_COPTS,
visibility = ["//visibility:private"],
deps = [
+ ":internal",
":pow10_helper",
":strings",
- "//absl/base:core_headers",
+ "//absl/base:config",
"//absl/base:raw_logging_internal",
+ "//absl/random",
+ "//absl/random:distributions",
"@com_google_googletest//:gtest_main",
],
)
@@ -428,6 +534,8 @@
deps = [
":strings",
"//absl/base:raw_logging_internal",
+ "//absl/random",
+ "//absl/random:distributions",
"@com_github_google_benchmark//:benchmark_main",
],
)
@@ -486,6 +594,7 @@
copts = ABSL_TEST_COPTS,
deps = [
":strings",
+ "//absl/base:config",
"//absl/base:raw_logging_internal",
"@com_google_googletest//:gtest_main",
],
@@ -501,6 +610,7 @@
copts = ABSL_TEST_COPTS,
deps = [
":strings",
+ "//absl/base:config",
"@com_google_googletest//:gtest_main",
],
)
@@ -555,8 +665,11 @@
":strings",
"//absl/base:config",
"//absl/base:core_headers",
+ "//absl/functional:function_ref",
"//absl/meta:type_traits",
+ "//absl/numeric:bits",
"//absl/numeric:int128",
+ "//absl/types:optional",
"//absl/types:span",
],
)
@@ -567,6 +680,7 @@
copts = ABSL_TEST_COPTS + ["-Wno-format-nonliteral"],
visibility = ["//visibility:private"],
deps = [
+ ":cord",
":str_format",
":strings",
"//absl/base:core_headers",
@@ -584,6 +698,7 @@
deps = [
":str_format",
":str_format_internal",
+ ":strings",
"@com_google_googletest//:gtest_main",
],
)
@@ -630,7 +745,9 @@
visibility = ["//visibility:private"],
deps = [
":str_format_internal",
- "//absl/numeric:int128",
+ ":strings",
+ "//absl/base:raw_logging_internal",
+ "//absl/types:optional",
"@com_google_googletest//:gtest_main",
],
)
@@ -641,6 +758,7 @@
copts = ABSL_TEST_COPTS,
visibility = ["//visibility:private"],
deps = [
+ ":cord",
":str_format_internal",
"@com_google_googletest//:gtest_main",
],
@@ -664,6 +782,7 @@
srcs = ["internal/pow10_helper.cc"],
hdrs = ["internal/pow10_helper.h"],
visibility = ["//visibility:private"],
+ deps = ["//absl/base:config"],
)
cc_test(
diff --git a/third_party/abseil/absl/strings/CMakeLists.txt b/third_party/abseil/absl/strings/CMakeLists.txt
index ccff444..654d0fd 100644
--- a/third_party/abseil/absl/strings/CMakeLists.txt
+++ b/third_party/abseil/absl/strings/CMakeLists.txt
@@ -21,6 +21,7 @@
"ascii.h"
"charconv.h"
"escaping.h"
+ "internal/string_constant.h"
"match.h"
"numbers.h"
"str_cat.h"
@@ -72,6 +73,8 @@
strings_internal
HDRS
"internal/char_map.h"
+ "internal/escaping.cc"
+ "internal/escaping.h"
"internal/ostringstream.h"
"internal/resize_uninitialized.h"
"internal/utf8.h"
@@ -81,8 +84,10 @@
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
+ absl::config
absl::core_headers
absl::endian
+ absl::raw_logging_internal
absl::type_traits
)
@@ -156,6 +161,19 @@
absl_cc_test(
NAME
+ string_constant_test
+ SRCS
+ "internal/string_constant_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::type_traits
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
string_view_test
SRCS
"string_view_test.cc"
@@ -206,6 +224,8 @@
absl::base
absl::core_headers
absl::dynamic_annotations
+ absl::flat_hash_map
+ absl::node_hash_map
gmock_main
)
@@ -276,7 +296,11 @@
absl::strings
absl::core_headers
absl::pow10_helper
+ absl::config
absl::raw_logging_internal
+ absl::random_random
+ absl::random_distributions
+ absl::strings_internal
gmock_main
)
@@ -329,6 +353,7 @@
${ABSL_TEST_COPTS}
DEPS
absl::strings
+ absl::config
absl::raw_logging_internal
gmock_main
)
@@ -344,6 +369,7 @@
${ABSL_TEST_COPTS}
DEPS
absl::strings
+ absl::config
gmock_main
)
@@ -380,6 +406,7 @@
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
+ absl::bits
absl::strings
absl::config
absl::core_headers
@@ -397,6 +424,7 @@
${ABSL_TEST_COPTS}
DEPS
absl::str_format
+ absl::cord
absl::strings
absl::core_headers
gmock_main
@@ -412,6 +440,7 @@
DEPS
absl::str_format
absl::str_format_internal
+ absl::strings
gmock_main
)
@@ -460,7 +489,9 @@
COPTS
${ABSL_TEST_COPTS}
DEPS
+ absl::strings
absl::str_format_internal
+ absl::raw_logging_internal
absl::int128
gmock_main
)
@@ -474,6 +505,7 @@
${ABSL_TEST_COPTS}
DEPS
absl::str_format_internal
+ absl::cord
gmock_main
)
@@ -499,6 +531,8 @@
"internal/pow10_helper.cc"
COPTS
${ABSL_TEST_COPTS}
+ DEPS
+ absl::config
TESTONLY
)
@@ -514,3 +548,64 @@
absl::str_format
gmock_main
)
+
+absl_cc_library(
+ NAME
+ cord
+ HDRS
+ "cord.h"
+ SRCS
+ "cord.cc"
+ "internal/cord_internal.cc"
+ "internal/cord_internal.h"
+ "internal/cord_rep_flat.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::base
+ absl::base_internal
+ absl::compressed_tuple
+ absl::core_headers
+ absl::endian
+ absl::fixed_array
+ absl::function_ref
+ absl::inlined_vector
+ absl::optional
+ absl::raw_logging_internal
+ absl::strings
+ absl::strings_internal
+ absl::type_traits
+ PUBLIC
+)
+
+absl_cc_library(
+ NAME
+ cord_test_helpers
+ HDRS
+ "cord_test_helpers.h"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::cord
+ TESTONLY
+)
+
+absl_cc_test(
+ NAME
+ cord_test
+ SRCS
+ "cord_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::cord
+ absl::str_format
+ absl::strings
+ absl::base
+ absl::config
+ absl::core_headers
+ absl::endian
+ absl::raw_logging_internal
+ absl::fixed_array
+ gmock_main
+)
diff --git a/third_party/abseil/absl/strings/ascii.cc b/third_party/abseil/absl/strings/ascii.cc
index 3f7c581..93bb03e 100644
--- a/third_party/abseil/absl/strings/ascii.cc
+++ b/third_party/abseil/absl/strings/ascii.cc
@@ -15,6 +15,7 @@
#include "absl/strings/ascii.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace ascii_internal {
// # Table generated by this Python code (bit 0x02 is currently unused):
@@ -56,7 +57,7 @@
// 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] = {
+ABSL_DLL 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
@@ -78,7 +79,7 @@
// 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] = {
+ABSL_DLL 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',
@@ -116,7 +117,7 @@
// 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] = {
+ABSL_DLL 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',
@@ -195,4 +196,5 @@
str->erase(output_it - &(*str)[0]);
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/ascii.h b/third_party/abseil/absl/strings/ascii.h
index f9e4fd1..b46bc71 100644
--- a/third_party/abseil/absl/strings/ascii.h
+++ b/third_party/abseil/absl/strings/ascii.h
@@ -56,19 +56,21 @@
#include <string>
#include "absl/base/attributes.h"
+#include "absl/base/config.h"
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace ascii_internal {
// Declaration for an array of bitfields holding character information.
-extern const unsigned char kPropertyBits[256];
+ABSL_DLL extern const unsigned char kPropertyBits[256];
// Declaration for the array of characters to upper-case characters.
-extern const char kToUpper[256];
+ABSL_DLL extern const char kToUpper[256];
// Declaration for the array of characters to lower-case characters.
-extern const char kToLower[256];
+ABSL_DLL extern const char kToLower[256];
} // namespace ascii_internal
@@ -234,6 +236,7 @@
// Removes leading, trailing, and consecutive internal whitespace.
void RemoveExtraAsciiWhitespace(std::string*);
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_ASCII_H_
diff --git a/third_party/abseil/absl/strings/charconv.cc b/third_party/abseil/absl/strings/charconv.cc
index bc07e7a..b8674c2 100644
--- a/third_party/abseil/absl/strings/charconv.cc
+++ b/third_party/abseil/absl/strings/charconv.cc
@@ -20,7 +20,7 @@
#include <cstring>
#include "absl/base/casts.h"
-#include "absl/base/internal/bits.h"
+#include "absl/numeric/bits.h"
#include "absl/numeric/int128.h"
#include "absl/strings/internal/charconv_bigint.h"
#include "absl/strings/internal/charconv_parse.h"
@@ -57,6 +57,7 @@
// narrower mantissas.
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
template <typename FloatType>
@@ -241,11 +242,11 @@
// Returns the bit width of the given uint128. (Equivalently, returns 128
// minus the number of leading zero bits.)
-int BitWidth(uint128 value) {
+unsigned BitWidth(uint128 value) {
if (Uint128High64(value) == 0) {
- return 64 - base_internal::CountLeadingZeros64(Uint128Low64(value));
+ return static_cast<unsigned>(bit_width(Uint128Low64(value)));
}
- return 128 - base_internal::CountLeadingZeros64(Uint128High64(value));
+ return 128 - countl_zero(Uint128High64(value));
}
// Calculates how far to the right a mantissa needs to be shifted to create a
@@ -518,7 +519,7 @@
const strings_internal::ParsedFloat& parsed_hex) {
uint64_t mantissa = parsed_hex.mantissa;
int exponent = parsed_hex.exponent;
- int mantissa_width = 64 - base_internal::CountLeadingZeros64(mantissa);
+ auto mantissa_width = static_cast<unsigned>(bit_width(mantissa));
const int shift = NormalizedShiftSize<FloatType>(mantissa_width, exponent);
bool result_exact;
exponent += shift;
@@ -618,10 +619,10 @@
// Either we failed to parse a hex float after the "0x", or we read
// "0xinf" or "0xnan" which we don't want to match.
//
- // However, a std::string that begins with "0x" also begins with "0", which
+ // However, a string that begins with "0x" also begins with "0", which
// is normally a valid match for the number zero. So we want these
// strings to match zero unless fmt_flags is `scientific`. (This flag
- // means an exponent is required, which the std::string "0" does not have.)
+ // means an exponent is required, which the string "0" does not have.)
if (fmt_flags == chars_format::scientific) {
result.ec = std::errc::invalid_argument;
} else {
@@ -672,7 +673,6 @@
EncodeResult(calculated, negative, &result, &value);
return result;
}
- return result;
}
} // namespace
@@ -980,4 +980,5 @@
};
} // namespace
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/charconv.h b/third_party/abseil/absl/strings/charconv.h
index 3f5891b..e04be32 100644
--- a/third_party/abseil/absl/strings/charconv.h
+++ b/third_party/abseil/absl/strings/charconv.h
@@ -17,7 +17,10 @@
#include <system_error> // NOLINT(build/c++11)
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
// Workalike compatibilty version of std::chars_format from C++17.
//
@@ -110,6 +113,7 @@
return lhs;
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_CHARCONV_H_
diff --git a/third_party/abseil/absl/strings/charconv_benchmark.cc b/third_party/abseil/absl/strings/charconv_benchmark.cc
index 644b2ab..e8c7371 100644
--- a/third_party/abseil/absl/strings/charconv_benchmark.cc
+++ b/third_party/abseil/absl/strings/charconv_benchmark.cc
@@ -132,7 +132,7 @@
std::string MakeHardCase(int length) {
// The number 1.1521...e-297 is exactly halfway between 12345 * 2**-1000 and
// the next larger representable number. The digits of this number are in
- // the std::string below.
+ // the string below.
const std::string digits =
"1."
"152113937042223790993097181572444900347587985074226836242307364987727724"
diff --git a/third_party/abseil/absl/strings/charconv_test.cc b/third_party/abseil/absl/strings/charconv_test.cc
index b58fad2..b83de5a 100644
--- a/third_party/abseil/absl/strings/charconv_test.cc
+++ b/third_party/abseil/absl/strings/charconv_test.cc
@@ -511,6 +511,13 @@
EXPECT_EQ(f, std::numeric_limits<float>::max());
}
+TEST(FromChars, RegressionTestsFromFuzzer) {
+ absl::string_view src = "0x21900000p00000000099";
+ float f;
+ auto result = absl::from_chars(src.data(), src.data() + src.size(), f);
+ EXPECT_EQ(result.ec, std::errc::result_out_of_range);
+}
+
TEST(FromChars, ReturnValuePtr) {
// Check that `ptr` points one past the number scanned, even if that number
// is not representable.
@@ -646,7 +653,9 @@
negative_from_chars_float);
EXPECT_TRUE(std::signbit(negative_from_chars_float));
EXPECT_FALSE(Identical(negative_from_chars_float, from_chars_float));
- from_chars_float = std::copysign(from_chars_float, -1.0);
+ // Use the (float, float) overload of std::copysign to prevent narrowing;
+ // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98251.
+ from_chars_float = std::copysign(from_chars_float, -1.0f);
EXPECT_TRUE(Identical(negative_from_chars_float, from_chars_float));
}
}
diff --git a/third_party/abseil/absl/strings/cord.cc b/third_party/abseil/absl/strings/cord.cc
new file mode 100644
index 0000000..7cadf75
--- /dev/null
+++ b/third_party/abseil/absl/strings/cord.cc
@@ -0,0 +1,1825 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/cord.h"
+
+#include <algorithm>
+#include <atomic>
+#include <cstddef>
+#include <cstdio>
+#include <cstdlib>
+#include <iomanip>
+#include <iostream>
+#include <limits>
+#include <ostream>
+#include <sstream>
+#include <type_traits>
+#include <unordered_set>
+#include <vector>
+
+#include "absl/base/casts.h"
+#include "absl/base/internal/raw_logging.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/escaping.h"
+#include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_flat.h"
+#include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/str_join.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+using ::absl::cord_internal::CordRep;
+using ::absl::cord_internal::CordRepConcat;
+using ::absl::cord_internal::CordRepExternal;
+using ::absl::cord_internal::CordRepFlat;
+using ::absl::cord_internal::CordRepSubstring;
+
+using ::absl::cord_internal::kMinFlatLength;
+using ::absl::cord_internal::kMaxFlatLength;
+
+using ::absl::cord_internal::CONCAT;
+using ::absl::cord_internal::EXTERNAL;
+using ::absl::cord_internal::FLAT;
+using ::absl::cord_internal::RING;
+using ::absl::cord_internal::SUBSTRING;
+
+using ::absl::cord_internal::kInlinedVectorSize;
+using ::absl::cord_internal::kMaxBytesToCopy;
+
+constexpr uint64_t Fibonacci(unsigned char n, uint64_t a = 0, uint64_t b = 1) {
+ return n == 0 ? a : Fibonacci(n - 1, b, a + b);
+}
+
+static_assert(Fibonacci(63) == 6557470319842,
+ "Fibonacci values computed incorrectly");
+
+// Minimum length required for a given depth tree -- a tree is considered
+// balanced if
+// length(t) >= min_length[depth(t)]
+// The root node depth is allowed to become twice as large to reduce rebalancing
+// for larger strings (see IsRootBalanced).
+static constexpr uint64_t min_length[] = {
+ Fibonacci(2), Fibonacci(3), Fibonacci(4), Fibonacci(5),
+ Fibonacci(6), Fibonacci(7), Fibonacci(8), Fibonacci(9),
+ Fibonacci(10), Fibonacci(11), Fibonacci(12), Fibonacci(13),
+ Fibonacci(14), Fibonacci(15), Fibonacci(16), Fibonacci(17),
+ Fibonacci(18), Fibonacci(19), Fibonacci(20), Fibonacci(21),
+ Fibonacci(22), Fibonacci(23), Fibonacci(24), Fibonacci(25),
+ Fibonacci(26), Fibonacci(27), Fibonacci(28), Fibonacci(29),
+ Fibonacci(30), Fibonacci(31), Fibonacci(32), Fibonacci(33),
+ Fibonacci(34), Fibonacci(35), Fibonacci(36), Fibonacci(37),
+ Fibonacci(38), Fibonacci(39), Fibonacci(40), Fibonacci(41),
+ Fibonacci(42), Fibonacci(43), Fibonacci(44), Fibonacci(45),
+ Fibonacci(46), Fibonacci(47),
+ 0xffffffffffffffffull, // Avoid overflow
+};
+
+static const int kMinLengthSize = ABSL_ARRAYSIZE(min_length);
+
+static inline bool IsRootBalanced(CordRep* node) {
+ if (node->tag != CONCAT) {
+ return true;
+ } else if (node->concat()->depth() <= 15) {
+ return true;
+ } else if (node->concat()->depth() > kMinLengthSize) {
+ return false;
+ } else {
+ // Allow depth to become twice as large as implied by fibonacci rule to
+ // reduce rebalancing for larger strings.
+ return (node->length >= min_length[node->concat()->depth() / 2]);
+ }
+}
+
+static CordRep* Rebalance(CordRep* node);
+static void DumpNode(CordRep* rep, bool include_data, std::ostream* os);
+static bool VerifyNode(CordRep* root, CordRep* start_node,
+ bool full_validation);
+
+static inline CordRep* VerifyTree(CordRep* node) {
+ // Verification is expensive, so only do it in debug mode.
+ // Even in debug mode we normally do only light validation.
+ // If you are debugging Cord itself, you should define the
+ // macro EXTRA_CORD_VALIDATION, e.g. by adding
+ // --copt=-DEXTRA_CORD_VALIDATION to the blaze line.
+#ifdef EXTRA_CORD_VALIDATION
+ assert(node == nullptr || VerifyNode(node, node, /*full_validation=*/true));
+#else // EXTRA_CORD_VALIDATION
+ assert(node == nullptr || VerifyNode(node, node, /*full_validation=*/false));
+#endif // EXTRA_CORD_VALIDATION
+ static_cast<void>(&VerifyNode);
+
+ return node;
+}
+
+// Return the depth of a node
+static int Depth(const CordRep* rep) {
+ if (rep->tag == CONCAT) {
+ return rep->concat()->depth();
+ } else {
+ return 0;
+ }
+}
+
+static void SetConcatChildren(CordRepConcat* concat, CordRep* left,
+ CordRep* right) {
+ concat->left = left;
+ concat->right = right;
+
+ concat->length = left->length + right->length;
+ concat->set_depth(1 + std::max(Depth(left), Depth(right)));
+}
+
+// Create a concatenation of the specified nodes.
+// Does not change the refcounts of "left" and "right".
+// The returned node has a refcount of 1.
+static CordRep* RawConcat(CordRep* left, CordRep* right) {
+ // Avoid making degenerate concat nodes (one child is empty)
+ if (left == nullptr) return right;
+ if (right == nullptr) return left;
+ if (left->length == 0) {
+ CordRep::Unref(left);
+ return right;
+ }
+ if (right->length == 0) {
+ CordRep::Unref(right);
+ return left;
+ }
+
+ CordRepConcat* rep = new CordRepConcat();
+ rep->tag = CONCAT;
+ SetConcatChildren(rep, left, right);
+
+ return rep;
+}
+
+static CordRep* Concat(CordRep* left, CordRep* right) {
+ CordRep* rep = RawConcat(left, right);
+ if (rep != nullptr && !IsRootBalanced(rep)) {
+ rep = Rebalance(rep);
+ }
+ return VerifyTree(rep);
+}
+
+// Make a balanced tree out of an array of leaf nodes.
+static CordRep* MakeBalancedTree(CordRep** reps, size_t n) {
+ // Make repeated passes over the array, merging adjacent pairs
+ // until we are left with just a single node.
+ while (n > 1) {
+ size_t dst = 0;
+ for (size_t src = 0; src < n; src += 2) {
+ if (src + 1 < n) {
+ reps[dst] = Concat(reps[src], reps[src + 1]);
+ } else {
+ reps[dst] = reps[src];
+ }
+ dst++;
+ }
+ n = dst;
+ }
+
+ return reps[0];
+}
+
+// Create a new tree out of the specified array.
+// The returned node has a refcount of 1.
+static CordRep* NewTree(const char* data,
+ size_t length,
+ size_t alloc_hint) {
+ if (length == 0) return nullptr;
+ absl::FixedArray<CordRep*> reps((length - 1) / kMaxFlatLength + 1);
+ size_t n = 0;
+ do {
+ const size_t len = std::min(length, kMaxFlatLength);
+ CordRep* rep = CordRepFlat::New(len + alloc_hint);
+ rep->length = len;
+ memcpy(rep->data, data, len);
+ reps[n++] = VerifyTree(rep);
+ data += len;
+ length -= len;
+ } while (length != 0);
+ return MakeBalancedTree(reps.data(), n);
+}
+
+namespace cord_internal {
+
+void InitializeCordRepExternal(absl::string_view data, CordRepExternal* rep) {
+ assert(!data.empty());
+ rep->length = data.size();
+ rep->tag = EXTERNAL;
+ rep->base = data.data();
+ VerifyTree(rep);
+}
+
+} // namespace cord_internal
+
+static CordRep* NewSubstring(CordRep* child, size_t offset, size_t length) {
+ // Never create empty substring nodes
+ if (length == 0) {
+ CordRep::Unref(child);
+ return nullptr;
+ } else {
+ CordRepSubstring* rep = new CordRepSubstring();
+ assert((offset + length) <= child->length);
+ rep->length = length;
+ rep->tag = SUBSTRING;
+ rep->start = offset;
+ rep->child = child;
+ return VerifyTree(rep);
+ }
+}
+
+// --------------------------------------------------------------------
+// Cord::InlineRep functions
+
+constexpr unsigned char Cord::InlineRep::kMaxInline;
+
+inline void Cord::InlineRep::set_data(const char* data, size_t n,
+ bool nullify_tail) {
+ static_assert(kMaxInline == 15, "set_data is hard-coded for a length of 15");
+
+ cord_internal::SmallMemmove(data_.as_chars, data, n, nullify_tail);
+ set_tagged_size(static_cast<char>(n));
+}
+
+inline char* Cord::InlineRep::set_data(size_t n) {
+ assert(n <= kMaxInline);
+ ResetToEmpty();
+ set_tagged_size(static_cast<char>(n));
+ return data_.as_chars;
+}
+
+inline CordRep* Cord::InlineRep::force_tree(size_t extra_hint) {
+ size_t len = tagged_size();
+ if (len > kMaxInline) {
+ return data_.as_tree.rep;
+ }
+
+ CordRep* result = CordRepFlat::New(len + extra_hint);
+ result->length = len;
+ static_assert(kMinFlatLength >= sizeof(data_.as_chars), "");
+ memcpy(result->data, data_.as_chars, sizeof(data_.as_chars));
+ set_tree(result);
+ return result;
+}
+
+inline void Cord::InlineRep::reduce_size(size_t n) {
+ size_t tag = tagged_size();
+ assert(tag <= kMaxInline);
+ assert(tag >= n);
+ tag -= n;
+ memset(data_.as_chars + tag, 0, n);
+ set_tagged_size(static_cast<char>(tag));
+}
+
+inline void Cord::InlineRep::remove_prefix(size_t n) {
+ cord_internal::SmallMemmove(data_.as_chars, data_.as_chars + n,
+ tagged_size() - n);
+ reduce_size(n);
+}
+
+void Cord::InlineRep::AppendTree(CordRep* tree) {
+ if (tree == nullptr) return;
+ size_t len = tagged_size();
+ if (len == 0) {
+ set_tree(tree);
+ } else {
+ set_tree(Concat(force_tree(0), tree));
+ }
+}
+
+void Cord::InlineRep::PrependTree(CordRep* tree) {
+ assert(tree != nullptr);
+ size_t len = tagged_size();
+ if (len == 0) {
+ set_tree(tree);
+ } else {
+ set_tree(Concat(tree, force_tree(0)));
+ }
+}
+
+// Searches for a non-full flat node at the rightmost leaf of the tree. If a
+// suitable leaf is found, the function will update the length field for all
+// nodes to account for the size increase. The append region address will be
+// written to region and the actual size increase will be written to size.
+static inline bool PrepareAppendRegion(CordRep* root, char** region,
+ size_t* size, size_t max_length) {
+ // Search down the right-hand path for a non-full FLAT node.
+ CordRep* dst = root;
+ while (dst->tag == CONCAT && dst->refcount.IsOne()) {
+ dst = dst->concat()->right;
+ }
+
+ if (dst->tag < FLAT || !dst->refcount.IsOne()) {
+ *region = nullptr;
+ *size = 0;
+ return false;
+ }
+
+ const size_t in_use = dst->length;
+ const size_t capacity = dst->flat()->Capacity();
+ if (in_use == capacity) {
+ *region = nullptr;
+ *size = 0;
+ return false;
+ }
+
+ size_t size_increase = std::min(capacity - in_use, max_length);
+
+ // We need to update the length fields for all nodes, including the leaf node.
+ for (CordRep* rep = root; rep != dst; rep = rep->concat()->right) {
+ rep->length += size_increase;
+ }
+ dst->length += size_increase;
+
+ *region = dst->data + in_use;
+ *size = size_increase;
+ return true;
+}
+
+void Cord::InlineRep::GetAppendRegion(char** region, size_t* size,
+ size_t max_length) {
+ if (max_length == 0) {
+ *region = nullptr;
+ *size = 0;
+ return;
+ }
+
+ // Try to fit in the inline buffer if possible.
+ size_t inline_length = tagged_size();
+ if (inline_length < kMaxInline && max_length <= kMaxInline - inline_length) {
+ *region = data_.as_chars + inline_length;
+ *size = max_length;
+ set_tagged_size(static_cast<char>(inline_length + max_length));
+ return;
+ }
+
+ CordRep* root = force_tree(max_length);
+
+ if (PrepareAppendRegion(root, region, size, max_length)) {
+ return;
+ }
+
+ // Allocate new node.
+ CordRepFlat* new_node =
+ CordRepFlat::New(std::max(static_cast<size_t>(root->length), max_length));
+ new_node->length = std::min(new_node->Capacity(), max_length);
+ *region = new_node->data;
+ *size = new_node->length;
+ replace_tree(Concat(root, new_node));
+}
+
+void Cord::InlineRep::GetAppendRegion(char** region, size_t* size) {
+ const size_t max_length = std::numeric_limits<size_t>::max();
+
+ // Try to fit in the inline buffer if possible.
+ size_t inline_length = tagged_size();
+ if (inline_length < kMaxInline) {
+ *region = data_.as_chars + inline_length;
+ *size = kMaxInline - inline_length;
+ set_tagged_size(kMaxInline);
+ return;
+ }
+
+ CordRep* root = force_tree(max_length);
+
+ if (PrepareAppendRegion(root, region, size, max_length)) {
+ return;
+ }
+
+ // Allocate new node.
+ CordRepFlat* new_node = CordRepFlat::New(root->length);
+ new_node->length = new_node->Capacity();
+ *region = new_node->data;
+ *size = new_node->length;
+ replace_tree(Concat(root, new_node));
+}
+
+// If the rep is a leaf, this will increment the value at total_mem_usage and
+// will return true.
+static bool RepMemoryUsageLeaf(const CordRep* rep, size_t* total_mem_usage) {
+ if (rep->tag >= FLAT) {
+ *total_mem_usage += rep->flat()->AllocatedSize();
+ return true;
+ }
+ if (rep->tag == EXTERNAL) {
+ *total_mem_usage += sizeof(CordRepConcat) + rep->length;
+ return true;
+ }
+ return false;
+}
+
+void Cord::InlineRep::AssignSlow(const Cord::InlineRep& src) {
+ ClearSlow();
+
+ data_ = src.data_;
+ if (is_tree()) {
+ CordRep::Ref(tree());
+ }
+}
+
+void Cord::InlineRep::ClearSlow() {
+ if (is_tree()) {
+ CordRep::Unref(tree());
+ }
+ ResetToEmpty();
+}
+
+// --------------------------------------------------------------------
+// Constructors and destructors
+
+Cord::Cord(const Cord& src) : contents_(src.contents_) {
+ if (CordRep* tree = contents_.tree()) {
+ CordRep::Ref(tree);
+ }
+}
+
+Cord::Cord(absl::string_view src) {
+ const size_t n = src.size();
+ if (n <= InlineRep::kMaxInline) {
+ contents_.set_data(src.data(), n, false);
+ } else {
+ contents_.set_tree(NewTree(src.data(), n, 0));
+ }
+}
+
+template <typename T, Cord::EnableIfString<T>>
+Cord::Cord(T&& src) {
+ if (
+ // String is short: copy data to avoid external block overhead.
+ src.size() <= kMaxBytesToCopy ||
+ // String is wasteful: copy data to avoid pinning too much unused memory.
+ src.size() < src.capacity() / 2
+ ) {
+ if (src.size() <= InlineRep::kMaxInline) {
+ contents_.set_data(src.data(), src.size(), false);
+ } else {
+ contents_.set_tree(NewTree(src.data(), src.size(), 0));
+ }
+ } else {
+ struct StringReleaser {
+ void operator()(absl::string_view /* data */) {}
+ std::string data;
+ };
+ const absl::string_view original_data = src;
+ auto* rep = static_cast<
+ ::absl::cord_internal::CordRepExternalImpl<StringReleaser>*>(
+ absl::cord_internal::NewExternalRep(
+ original_data, StringReleaser{std::forward<T>(src)}));
+ // Moving src may have invalidated its data pointer, so adjust it.
+ rep->base = rep->template get<0>().data.data();
+ contents_.set_tree(rep);
+ }
+}
+
+template Cord::Cord(std::string&& src);
+
+// The destruction code is separate so that the compiler can determine
+// that it does not need to call the destructor on a moved-from Cord.
+void Cord::DestroyCordSlow() {
+ if (CordRep* tree = contents_.tree()) {
+ CordRep::Unref(VerifyTree(tree));
+ }
+}
+
+// --------------------------------------------------------------------
+// Mutators
+
+void Cord::Clear() {
+ if (CordRep* tree = contents_.clear()) {
+ CordRep::Unref(tree);
+ }
+}
+
+Cord& Cord::operator=(absl::string_view src) {
+
+ const char* data = src.data();
+ size_t length = src.size();
+ CordRep* tree = contents_.tree();
+ if (length <= InlineRep::kMaxInline) {
+ // Embed into this->contents_
+ contents_.set_data(data, length, true);
+ if (tree) CordRep::Unref(tree);
+ return *this;
+ }
+ if (tree != nullptr && tree->tag >= FLAT &&
+ tree->flat()->Capacity() >= length &&
+ tree->refcount.IsOne()) {
+ // Copy in place if the existing FLAT node is reusable.
+ memmove(tree->data, data, length);
+ tree->length = length;
+ VerifyTree(tree);
+ return *this;
+ }
+ contents_.set_tree(NewTree(data, length, 0));
+ if (tree) CordRep::Unref(tree);
+ return *this;
+}
+
+template <typename T, Cord::EnableIfString<T>>
+Cord& Cord::operator=(T&& src) {
+ if (src.size() <= kMaxBytesToCopy) {
+ *this = absl::string_view(src);
+ } else {
+ *this = Cord(std::forward<T>(src));
+ }
+ return *this;
+}
+
+template Cord& Cord::operator=(std::string&& src);
+
+// TODO(sanjay): Move to Cord::InlineRep section of file. For now,
+// we keep it here to make diffs easier.
+void Cord::InlineRep::AppendArray(const char* src_data, size_t src_size) {
+ if (src_size == 0) return; // memcpy(_, nullptr, 0) is undefined.
+ // Try to fit in the inline buffer if possible.
+ size_t inline_length = tagged_size();
+ if (inline_length < kMaxInline && src_size <= kMaxInline - inline_length) {
+ // Append new data to embedded array
+ set_tagged_size(static_cast<char>(inline_length + src_size));
+ memcpy(data_.as_chars + inline_length, src_data, src_size);
+ return;
+ }
+
+ CordRep* root = tree();
+
+ size_t appended = 0;
+ if (root) {
+ char* region;
+ if (PrepareAppendRegion(root, ®ion, &appended, src_size)) {
+ memcpy(region, src_data, appended);
+ }
+ } else {
+ // It is possible that src_data == data_, but when we transition from an
+ // InlineRep to a tree we need to assign data_ = root via set_tree. To
+ // avoid corrupting the source data before we copy it, delay calling
+ // set_tree until after we've copied data.
+ // We are going from an inline size to beyond inline size. Make the new size
+ // either double the inlined size, or the added size + 10%.
+ const size_t size1 = inline_length * 2 + src_size;
+ const size_t size2 = inline_length + src_size / 10;
+ root = CordRepFlat::New(std::max<size_t>(size1, size2));
+ appended = std::min(
+ src_size, root->flat()->Capacity() - inline_length);
+ memcpy(root->data, data_.as_chars, inline_length);
+ memcpy(root->data + inline_length, src_data, appended);
+ root->length = inline_length + appended;
+ set_tree(root);
+ }
+
+ src_data += appended;
+ src_size -= appended;
+ if (src_size == 0) {
+ return;
+ }
+
+ // Use new block(s) for any remaining bytes that were not handled above.
+ // Alloc extra memory only if the right child of the root of the new tree is
+ // going to be a FLAT node, which will permit further inplace appends.
+ size_t length = src_size;
+ if (src_size < kMaxFlatLength) {
+ // The new length is either
+ // - old size + 10%
+ // - old_size + src_size
+ // This will cause a reasonable conservative step-up in size that is still
+ // large enough to avoid excessive amounts of small fragments being added.
+ length = std::max<size_t>(root->length / 10, src_size);
+ }
+ set_tree(Concat(root, NewTree(src_data, src_size, length - src_size)));
+}
+
+inline CordRep* Cord::TakeRep() const& {
+ return CordRep::Ref(contents_.tree());
+}
+
+inline CordRep* Cord::TakeRep() && {
+ CordRep* rep = contents_.tree();
+ contents_.clear();
+ return rep;
+}
+
+template <typename C>
+inline void Cord::AppendImpl(C&& src) {
+ if (empty()) {
+ // In case of an empty destination avoid allocating a new node, do not copy
+ // data.
+ *this = std::forward<C>(src);
+ return;
+ }
+
+ // For short cords, it is faster to copy data if there is room in dst.
+ const size_t src_size = src.contents_.size();
+ if (src_size <= kMaxBytesToCopy) {
+ CordRep* src_tree = src.contents_.tree();
+ if (src_tree == nullptr) {
+ // src has embedded data.
+ contents_.AppendArray(src.contents_.data(), src_size);
+ return;
+ }
+ if (src_tree->tag >= FLAT) {
+ // src tree just has one flat node.
+ contents_.AppendArray(src_tree->data, src_size);
+ return;
+ }
+ if (&src == this) {
+ // ChunkIterator below assumes that src is not modified during traversal.
+ Append(Cord(src));
+ return;
+ }
+ // TODO(mec): Should we only do this if "dst" has space?
+ for (absl::string_view chunk : src.Chunks()) {
+ Append(chunk);
+ }
+ return;
+ }
+
+ // Guaranteed to be a tree (kMaxBytesToCopy > kInlinedSize)
+ contents_.AppendTree(std::forward<C>(src).TakeRep());
+}
+
+void Cord::Append(const Cord& src) { AppendImpl(src); }
+
+void Cord::Append(Cord&& src) { AppendImpl(std::move(src)); }
+
+template <typename T, Cord::EnableIfString<T>>
+void Cord::Append(T&& src) {
+ if (src.size() <= kMaxBytesToCopy) {
+ Append(absl::string_view(src));
+ } else {
+ Append(Cord(std::forward<T>(src)));
+ }
+}
+
+template void Cord::Append(std::string&& src);
+
+void Cord::Prepend(const Cord& src) {
+ CordRep* src_tree = src.contents_.tree();
+ if (src_tree != nullptr) {
+ CordRep::Ref(src_tree);
+ contents_.PrependTree(src_tree);
+ return;
+ }
+
+ // `src` cord is inlined.
+ absl::string_view src_contents(src.contents_.data(), src.contents_.size());
+ return Prepend(src_contents);
+}
+
+void Cord::Prepend(absl::string_view src) {
+ if (src.empty()) return; // memcpy(_, nullptr, 0) is undefined.
+ size_t cur_size = contents_.size();
+ if (!contents_.is_tree() && cur_size + src.size() <= InlineRep::kMaxInline) {
+ // Use embedded storage.
+ char data[InlineRep::kMaxInline + 1] = {0};
+ data[InlineRep::kMaxInline] = cur_size + src.size(); // set size
+ memcpy(data, src.data(), src.size());
+ memcpy(data + src.size(), contents_.data(), cur_size);
+ memcpy(reinterpret_cast<void*>(&contents_), data,
+ InlineRep::kMaxInline + 1);
+ } else {
+ contents_.PrependTree(NewTree(src.data(), src.size(), 0));
+ }
+}
+
+template <typename T, Cord::EnableIfString<T>>
+inline void Cord::Prepend(T&& src) {
+ if (src.size() <= kMaxBytesToCopy) {
+ Prepend(absl::string_view(src));
+ } else {
+ Prepend(Cord(std::forward<T>(src)));
+ }
+}
+
+template void Cord::Prepend(std::string&& src);
+
+static CordRep* RemovePrefixFrom(CordRep* node, size_t n) {
+ if (n >= node->length) return nullptr;
+ if (n == 0) return CordRep::Ref(node);
+ absl::InlinedVector<CordRep*, kInlinedVectorSize> rhs_stack;
+
+ while (node->tag == CONCAT) {
+ assert(n <= node->length);
+ if (n < node->concat()->left->length) {
+ // Push right to stack, descend left.
+ rhs_stack.push_back(node->concat()->right);
+ node = node->concat()->left;
+ } else {
+ // Drop left, descend right.
+ n -= node->concat()->left->length;
+ node = node->concat()->right;
+ }
+ }
+ assert(n <= node->length);
+
+ if (n == 0) {
+ CordRep::Ref(node);
+ } else {
+ size_t start = n;
+ size_t len = node->length - n;
+ if (node->tag == SUBSTRING) {
+ // Consider in-place update of node, similar to in RemoveSuffixFrom().
+ start += node->substring()->start;
+ node = node->substring()->child;
+ }
+ node = NewSubstring(CordRep::Ref(node), start, len);
+ }
+ while (!rhs_stack.empty()) {
+ node = Concat(node, CordRep::Ref(rhs_stack.back()));
+ rhs_stack.pop_back();
+ }
+ return node;
+}
+
+// RemoveSuffixFrom() is very similar to RemovePrefixFrom(), with the
+// exception that removing a suffix has an optimization where a node may be
+// edited in place iff that node and all its ancestors have a refcount of 1.
+static CordRep* RemoveSuffixFrom(CordRep* node, size_t n) {
+ if (n >= node->length) return nullptr;
+ if (n == 0) return CordRep::Ref(node);
+ absl::InlinedVector<CordRep*, kInlinedVectorSize> lhs_stack;
+ bool inplace_ok = node->refcount.IsOne();
+
+ while (node->tag == CONCAT) {
+ assert(n <= node->length);
+ if (n < node->concat()->right->length) {
+ // Push left to stack, descend right.
+ lhs_stack.push_back(node->concat()->left);
+ node = node->concat()->right;
+ } else {
+ // Drop right, descend left.
+ n -= node->concat()->right->length;
+ node = node->concat()->left;
+ }
+ inplace_ok = inplace_ok && node->refcount.IsOne();
+ }
+ assert(n <= node->length);
+
+ if (n == 0) {
+ CordRep::Ref(node);
+ } else if (inplace_ok && node->tag != EXTERNAL) {
+ // Consider making a new buffer if the current node capacity is much
+ // larger than the new length.
+ CordRep::Ref(node);
+ node->length -= n;
+ } else {
+ size_t start = 0;
+ size_t len = node->length - n;
+ if (node->tag == SUBSTRING) {
+ start = node->substring()->start;
+ node = node->substring()->child;
+ }
+ node = NewSubstring(CordRep::Ref(node), start, len);
+ }
+ while (!lhs_stack.empty()) {
+ node = Concat(CordRep::Ref(lhs_stack.back()), node);
+ lhs_stack.pop_back();
+ }
+ return node;
+}
+
+void Cord::RemovePrefix(size_t n) {
+ ABSL_INTERNAL_CHECK(n <= size(),
+ absl::StrCat("Requested prefix size ", n,
+ " exceeds Cord's size ", size()));
+ CordRep* tree = contents_.tree();
+ if (tree == nullptr) {
+ contents_.remove_prefix(n);
+ } else {
+ CordRep* newrep = RemovePrefixFrom(tree, n);
+ CordRep::Unref(tree);
+ contents_.replace_tree(VerifyTree(newrep));
+ }
+}
+
+void Cord::RemoveSuffix(size_t n) {
+ ABSL_INTERNAL_CHECK(n <= size(),
+ absl::StrCat("Requested suffix size ", n,
+ " exceeds Cord's size ", size()));
+ CordRep* tree = contents_.tree();
+ if (tree == nullptr) {
+ contents_.reduce_size(n);
+ } else {
+ CordRep* newrep = RemoveSuffixFrom(tree, n);
+ CordRep::Unref(tree);
+ contents_.replace_tree(VerifyTree(newrep));
+ }
+}
+
+// Work item for NewSubRange().
+struct SubRange {
+ SubRange(CordRep* a_node, size_t a_pos, size_t a_n)
+ : node(a_node), pos(a_pos), n(a_n) {}
+ CordRep* node; // nullptr means concat last 2 results.
+ size_t pos;
+ size_t n;
+};
+
+static CordRep* NewSubRange(CordRep* node, size_t pos, size_t n) {
+ absl::InlinedVector<CordRep*, kInlinedVectorSize> results;
+ absl::InlinedVector<SubRange, kInlinedVectorSize> todo;
+ todo.push_back(SubRange(node, pos, n));
+ do {
+ const SubRange& sr = todo.back();
+ node = sr.node;
+ pos = sr.pos;
+ n = sr.n;
+ todo.pop_back();
+
+ if (node == nullptr) {
+ assert(results.size() >= 2);
+ CordRep* right = results.back();
+ results.pop_back();
+ CordRep* left = results.back();
+ results.pop_back();
+ results.push_back(Concat(left, right));
+ } else if (pos == 0 && n == node->length) {
+ results.push_back(CordRep::Ref(node));
+ } else if (node->tag != CONCAT) {
+ if (node->tag == SUBSTRING) {
+ pos += node->substring()->start;
+ node = node->substring()->child;
+ }
+ results.push_back(NewSubstring(CordRep::Ref(node), pos, n));
+ } else if (pos + n <= node->concat()->left->length) {
+ todo.push_back(SubRange(node->concat()->left, pos, n));
+ } else if (pos >= node->concat()->left->length) {
+ pos -= node->concat()->left->length;
+ todo.push_back(SubRange(node->concat()->right, pos, n));
+ } else {
+ size_t left_n = node->concat()->left->length - pos;
+ todo.push_back(SubRange(nullptr, 0, 0)); // Concat()
+ todo.push_back(SubRange(node->concat()->right, 0, n - left_n));
+ todo.push_back(SubRange(node->concat()->left, pos, left_n));
+ }
+ } while (!todo.empty());
+ assert(results.size() == 1);
+ return results[0];
+}
+
+Cord Cord::Subcord(size_t pos, size_t new_size) const {
+ Cord sub_cord;
+ size_t length = size();
+ if (pos > length) pos = length;
+ if (new_size > length - pos) new_size = length - pos;
+ CordRep* tree = contents_.tree();
+ if (tree == nullptr) {
+ // sub_cord is newly constructed, no need to re-zero-out the tail of
+ // contents_ memory.
+ sub_cord.contents_.set_data(contents_.data() + pos, new_size, false);
+ } else if (new_size == 0) {
+ // We want to return empty subcord, so nothing to do.
+ } else if (new_size <= InlineRep::kMaxInline) {
+ Cord::ChunkIterator it = chunk_begin();
+ it.AdvanceBytes(pos);
+ char* dest = sub_cord.contents_.data_.as_chars;
+ size_t remaining_size = new_size;
+ while (remaining_size > it->size()) {
+ cord_internal::SmallMemmove(dest, it->data(), it->size());
+ remaining_size -= it->size();
+ dest += it->size();
+ ++it;
+ }
+ cord_internal::SmallMemmove(dest, it->data(), remaining_size);
+ sub_cord.contents_.set_tagged_size(new_size);
+ } else {
+ sub_cord.contents_.set_tree(NewSubRange(tree, pos, new_size));
+ }
+ return sub_cord;
+}
+
+// --------------------------------------------------------------------
+// Balancing
+
+class CordForest {
+ public:
+ explicit CordForest(size_t length)
+ : root_length_(length), trees_(kMinLengthSize, nullptr) {}
+
+ void Build(CordRep* cord_root) {
+ std::vector<CordRep*> pending = {cord_root};
+
+ while (!pending.empty()) {
+ CordRep* node = pending.back();
+ pending.pop_back();
+ CheckNode(node);
+ if (ABSL_PREDICT_FALSE(node->tag != CONCAT)) {
+ AddNode(node);
+ continue;
+ }
+
+ CordRepConcat* concat_node = node->concat();
+ if (concat_node->depth() >= kMinLengthSize ||
+ concat_node->length < min_length[concat_node->depth()]) {
+ pending.push_back(concat_node->right);
+ pending.push_back(concat_node->left);
+
+ if (concat_node->refcount.IsOne()) {
+ concat_node->left = concat_freelist_;
+ concat_freelist_ = concat_node;
+ } else {
+ CordRep::Ref(concat_node->right);
+ CordRep::Ref(concat_node->left);
+ CordRep::Unref(concat_node);
+ }
+ } else {
+ AddNode(node);
+ }
+ }
+ }
+
+ CordRep* ConcatNodes() {
+ CordRep* sum = nullptr;
+ for (auto* node : trees_) {
+ if (node == nullptr) continue;
+
+ sum = PrependNode(node, sum);
+ root_length_ -= node->length;
+ if (root_length_ == 0) break;
+ }
+ ABSL_INTERNAL_CHECK(sum != nullptr, "Failed to locate sum node");
+ return VerifyTree(sum);
+ }
+
+ private:
+ CordRep* AppendNode(CordRep* node, CordRep* sum) {
+ return (sum == nullptr) ? node : MakeConcat(sum, node);
+ }
+
+ CordRep* PrependNode(CordRep* node, CordRep* sum) {
+ return (sum == nullptr) ? node : MakeConcat(node, sum);
+ }
+
+ void AddNode(CordRep* node) {
+ CordRep* sum = nullptr;
+
+ // Collect together everything with which we will merge with node
+ int i = 0;
+ for (; node->length > min_length[i + 1]; ++i) {
+ auto& tree_at_i = trees_[i];
+
+ if (tree_at_i == nullptr) continue;
+ sum = PrependNode(tree_at_i, sum);
+ tree_at_i = nullptr;
+ }
+
+ sum = AppendNode(node, sum);
+
+ // Insert sum into appropriate place in the forest
+ for (; sum->length >= min_length[i]; ++i) {
+ auto& tree_at_i = trees_[i];
+ if (tree_at_i == nullptr) continue;
+
+ sum = MakeConcat(tree_at_i, sum);
+ tree_at_i = nullptr;
+ }
+
+ // min_length[0] == 1, which means sum->length >= min_length[0]
+ assert(i > 0);
+ trees_[i - 1] = sum;
+ }
+
+ // Make concat node trying to resue existing CordRepConcat nodes we
+ // already collected in the concat_freelist_.
+ CordRep* MakeConcat(CordRep* left, CordRep* right) {
+ if (concat_freelist_ == nullptr) return RawConcat(left, right);
+
+ CordRepConcat* rep = concat_freelist_;
+ if (concat_freelist_->left == nullptr) {
+ concat_freelist_ = nullptr;
+ } else {
+ concat_freelist_ = concat_freelist_->left->concat();
+ }
+ SetConcatChildren(rep, left, right);
+
+ return rep;
+ }
+
+ static void CheckNode(CordRep* node) {
+ ABSL_INTERNAL_CHECK(node->length != 0u, "");
+ if (node->tag == CONCAT) {
+ ABSL_INTERNAL_CHECK(node->concat()->left != nullptr, "");
+ ABSL_INTERNAL_CHECK(node->concat()->right != nullptr, "");
+ ABSL_INTERNAL_CHECK(node->length == (node->concat()->left->length +
+ node->concat()->right->length),
+ "");
+ }
+ }
+
+ size_t root_length_;
+
+ // use an inlined vector instead of a flat array to get bounds checking
+ absl::InlinedVector<CordRep*, kInlinedVectorSize> trees_;
+
+ // List of concat nodes we can re-use for Cord balancing.
+ CordRepConcat* concat_freelist_ = nullptr;
+};
+
+static CordRep* Rebalance(CordRep* node) {
+ VerifyTree(node);
+ assert(node->tag == CONCAT);
+
+ if (node->length == 0) {
+ return nullptr;
+ }
+
+ CordForest forest(node->length);
+ forest.Build(node);
+ return forest.ConcatNodes();
+}
+
+// --------------------------------------------------------------------
+// Comparators
+
+namespace {
+
+int ClampResult(int memcmp_res) {
+ return static_cast<int>(memcmp_res > 0) - static_cast<int>(memcmp_res < 0);
+}
+
+int CompareChunks(absl::string_view* lhs, absl::string_view* rhs,
+ size_t* size_to_compare) {
+ size_t compared_size = std::min(lhs->size(), rhs->size());
+ assert(*size_to_compare >= compared_size);
+ *size_to_compare -= compared_size;
+
+ int memcmp_res = ::memcmp(lhs->data(), rhs->data(), compared_size);
+ if (memcmp_res != 0) return memcmp_res;
+
+ lhs->remove_prefix(compared_size);
+ rhs->remove_prefix(compared_size);
+
+ return 0;
+}
+
+// This overload set computes comparison results from memcmp result. This
+// interface is used inside GenericCompare below. Differet implementations
+// are specialized for int and bool. For int we clamp result to {-1, 0, 1}
+// set. For bool we just interested in "value == 0".
+template <typename ResultType>
+ResultType ComputeCompareResult(int memcmp_res) {
+ return ClampResult(memcmp_res);
+}
+template <>
+bool ComputeCompareResult<bool>(int memcmp_res) {
+ return memcmp_res == 0;
+}
+
+} // namespace
+
+// Helper routine. Locates the first flat chunk of the Cord without
+// initializing the iterator.
+inline absl::string_view Cord::InlineRep::FindFlatStartPiece() const {
+ size_t n = tagged_size();
+ if (n <= kMaxInline) {
+ return absl::string_view(data_.as_chars, n);
+ }
+
+ CordRep* node = tree();
+ if (node->tag >= FLAT) {
+ return absl::string_view(node->data, node->length);
+ }
+
+ if (node->tag == EXTERNAL) {
+ return absl::string_view(node->external()->base, node->length);
+ }
+
+ // Walk down the left branches until we hit a non-CONCAT node.
+ while (node->tag == CONCAT) {
+ node = node->concat()->left;
+ }
+
+ // Get the child node if we encounter a SUBSTRING.
+ size_t offset = 0;
+ size_t length = node->length;
+ assert(length != 0);
+
+ if (node->tag == SUBSTRING) {
+ offset = node->substring()->start;
+ node = node->substring()->child;
+ }
+
+ if (node->tag >= FLAT) {
+ return absl::string_view(node->data + offset, length);
+ }
+
+ assert((node->tag == EXTERNAL) && "Expect FLAT or EXTERNAL node here");
+
+ return absl::string_view(node->external()->base + offset, length);
+}
+
+inline int Cord::CompareSlowPath(absl::string_view rhs, size_t compared_size,
+ size_t size_to_compare) const {
+ auto advance = [](Cord::ChunkIterator* it, absl::string_view* chunk) {
+ if (!chunk->empty()) return true;
+ ++*it;
+ if (it->bytes_remaining_ == 0) return false;
+ *chunk = **it;
+ return true;
+ };
+
+ Cord::ChunkIterator lhs_it = chunk_begin();
+
+ // compared_size is inside first chunk.
+ absl::string_view lhs_chunk =
+ (lhs_it.bytes_remaining_ != 0) ? *lhs_it : absl::string_view();
+ assert(compared_size <= lhs_chunk.size());
+ assert(compared_size <= rhs.size());
+ lhs_chunk.remove_prefix(compared_size);
+ rhs.remove_prefix(compared_size);
+ size_to_compare -= compared_size; // skip already compared size.
+
+ while (advance(&lhs_it, &lhs_chunk) && !rhs.empty()) {
+ int comparison_result = CompareChunks(&lhs_chunk, &rhs, &size_to_compare);
+ if (comparison_result != 0) return comparison_result;
+ if (size_to_compare == 0) return 0;
+ }
+
+ return static_cast<int>(rhs.empty()) - static_cast<int>(lhs_chunk.empty());
+}
+
+inline int Cord::CompareSlowPath(const Cord& rhs, size_t compared_size,
+ size_t size_to_compare) const {
+ auto advance = [](Cord::ChunkIterator* it, absl::string_view* chunk) {
+ if (!chunk->empty()) return true;
+ ++*it;
+ if (it->bytes_remaining_ == 0) return false;
+ *chunk = **it;
+ return true;
+ };
+
+ Cord::ChunkIterator lhs_it = chunk_begin();
+ Cord::ChunkIterator rhs_it = rhs.chunk_begin();
+
+ // compared_size is inside both first chunks.
+ absl::string_view lhs_chunk =
+ (lhs_it.bytes_remaining_ != 0) ? *lhs_it : absl::string_view();
+ absl::string_view rhs_chunk =
+ (rhs_it.bytes_remaining_ != 0) ? *rhs_it : absl::string_view();
+ assert(compared_size <= lhs_chunk.size());
+ assert(compared_size <= rhs_chunk.size());
+ lhs_chunk.remove_prefix(compared_size);
+ rhs_chunk.remove_prefix(compared_size);
+ size_to_compare -= compared_size; // skip already compared size.
+
+ while (advance(&lhs_it, &lhs_chunk) && advance(&rhs_it, &rhs_chunk)) {
+ int memcmp_res = CompareChunks(&lhs_chunk, &rhs_chunk, &size_to_compare);
+ if (memcmp_res != 0) return memcmp_res;
+ if (size_to_compare == 0) return 0;
+ }
+
+ return static_cast<int>(rhs_chunk.empty()) -
+ static_cast<int>(lhs_chunk.empty());
+}
+
+inline absl::string_view Cord::GetFirstChunk(const Cord& c) {
+ return c.contents_.FindFlatStartPiece();
+}
+inline absl::string_view Cord::GetFirstChunk(absl::string_view sv) {
+ return sv;
+}
+
+// Compares up to 'size_to_compare' bytes of 'lhs' with 'rhs'. It is assumed
+// that 'size_to_compare' is greater that size of smallest of first chunks.
+template <typename ResultType, typename RHS>
+ResultType GenericCompare(const Cord& lhs, const RHS& rhs,
+ size_t size_to_compare) {
+ absl::string_view lhs_chunk = Cord::GetFirstChunk(lhs);
+ absl::string_view rhs_chunk = Cord::GetFirstChunk(rhs);
+
+ size_t compared_size = std::min(lhs_chunk.size(), rhs_chunk.size());
+ assert(size_to_compare >= compared_size);
+ int memcmp_res = ::memcmp(lhs_chunk.data(), rhs_chunk.data(), compared_size);
+ if (compared_size == size_to_compare || memcmp_res != 0) {
+ return ComputeCompareResult<ResultType>(memcmp_res);
+ }
+
+ return ComputeCompareResult<ResultType>(
+ lhs.CompareSlowPath(rhs, compared_size, size_to_compare));
+}
+
+bool Cord::EqualsImpl(absl::string_view rhs, size_t size_to_compare) const {
+ return GenericCompare<bool>(*this, rhs, size_to_compare);
+}
+
+bool Cord::EqualsImpl(const Cord& rhs, size_t size_to_compare) const {
+ return GenericCompare<bool>(*this, rhs, size_to_compare);
+}
+
+template <typename RHS>
+inline int SharedCompareImpl(const Cord& lhs, const RHS& rhs) {
+ size_t lhs_size = lhs.size();
+ size_t rhs_size = rhs.size();
+ if (lhs_size == rhs_size) {
+ return GenericCompare<int>(lhs, rhs, lhs_size);
+ }
+ if (lhs_size < rhs_size) {
+ auto data_comp_res = GenericCompare<int>(lhs, rhs, lhs_size);
+ return data_comp_res == 0 ? -1 : data_comp_res;
+ }
+
+ auto data_comp_res = GenericCompare<int>(lhs, rhs, rhs_size);
+ return data_comp_res == 0 ? +1 : data_comp_res;
+}
+
+int Cord::Compare(absl::string_view rhs) const {
+ return SharedCompareImpl(*this, rhs);
+}
+
+int Cord::CompareImpl(const Cord& rhs) const {
+ return SharedCompareImpl(*this, rhs);
+}
+
+bool Cord::EndsWith(absl::string_view rhs) const {
+ size_t my_size = size();
+ size_t rhs_size = rhs.size();
+
+ if (my_size < rhs_size) return false;
+
+ Cord tmp(*this);
+ tmp.RemovePrefix(my_size - rhs_size);
+ return tmp.EqualsImpl(rhs, rhs_size);
+}
+
+bool Cord::EndsWith(const Cord& rhs) const {
+ size_t my_size = size();
+ size_t rhs_size = rhs.size();
+
+ if (my_size < rhs_size) return false;
+
+ Cord tmp(*this);
+ tmp.RemovePrefix(my_size - rhs_size);
+ return tmp.EqualsImpl(rhs, rhs_size);
+}
+
+// --------------------------------------------------------------------
+// Misc.
+
+Cord::operator std::string() const {
+ std::string s;
+ absl::CopyCordToString(*this, &s);
+ return s;
+}
+
+void CopyCordToString(const Cord& src, std::string* dst) {
+ if (!src.contents_.is_tree()) {
+ src.contents_.CopyTo(dst);
+ } else {
+ absl::strings_internal::STLStringResizeUninitialized(dst, src.size());
+ src.CopyToArraySlowPath(&(*dst)[0]);
+ }
+}
+
+void Cord::CopyToArraySlowPath(char* dst) const {
+ assert(contents_.is_tree());
+ absl::string_view fragment;
+ if (GetFlatAux(contents_.tree(), &fragment)) {
+ memcpy(dst, fragment.data(), fragment.size());
+ return;
+ }
+ for (absl::string_view chunk : Chunks()) {
+ memcpy(dst, chunk.data(), chunk.size());
+ dst += chunk.size();
+ }
+}
+
+Cord::ChunkIterator& Cord::ChunkIterator::AdvanceStack() {
+ auto& stack_of_right_children = stack_of_right_children_;
+ if (stack_of_right_children.empty()) {
+ assert(!current_chunk_.empty()); // Called on invalid iterator.
+ // We have reached the end of the Cord.
+ return *this;
+ }
+
+ // Process the next node on the stack.
+ CordRep* node = stack_of_right_children.back();
+ stack_of_right_children.pop_back();
+
+ // Walk down the left branches until we hit a non-CONCAT node. Save the
+ // right children to the stack for subsequent traversal.
+ while (node->tag == CONCAT) {
+ stack_of_right_children.push_back(node->concat()->right);
+ node = node->concat()->left;
+ }
+
+ // Get the child node if we encounter a SUBSTRING.
+ size_t offset = 0;
+ size_t length = node->length;
+ if (node->tag == SUBSTRING) {
+ offset = node->substring()->start;
+ node = node->substring()->child;
+ }
+
+ assert(node->tag == EXTERNAL || node->tag >= FLAT);
+ assert(length != 0);
+ const char* data =
+ node->tag == EXTERNAL ? node->external()->base : node->data;
+ current_chunk_ = absl::string_view(data + offset, length);
+ current_leaf_ = node;
+ return *this;
+}
+
+Cord Cord::ChunkIterator::AdvanceAndReadBytes(size_t n) {
+ ABSL_HARDENING_ASSERT(bytes_remaining_ >= n &&
+ "Attempted to iterate past `end()`");
+ Cord subcord;
+
+ if (n <= InlineRep::kMaxInline) {
+ // Range to read fits in inline data. Flatten it.
+ char* data = subcord.contents_.set_data(n);
+ while (n > current_chunk_.size()) {
+ memcpy(data, current_chunk_.data(), current_chunk_.size());
+ data += current_chunk_.size();
+ n -= current_chunk_.size();
+ ++*this;
+ }
+ memcpy(data, current_chunk_.data(), n);
+ if (n < current_chunk_.size()) {
+ RemoveChunkPrefix(n);
+ } else if (n > 0) {
+ ++*this;
+ }
+ return subcord;
+ }
+ auto& stack_of_right_children = stack_of_right_children_;
+ if (n < current_chunk_.size()) {
+ // Range to read is a proper subrange of the current chunk.
+ assert(current_leaf_ != nullptr);
+ CordRep* subnode = CordRep::Ref(current_leaf_);
+ const char* data =
+ subnode->tag == EXTERNAL ? subnode->external()->base : subnode->data;
+ subnode = NewSubstring(subnode, current_chunk_.data() - data, n);
+ subcord.contents_.set_tree(VerifyTree(subnode));
+ RemoveChunkPrefix(n);
+ return subcord;
+ }
+
+ // Range to read begins with a proper subrange of the current chunk.
+ assert(!current_chunk_.empty());
+ assert(current_leaf_ != nullptr);
+ CordRep* subnode = CordRep::Ref(current_leaf_);
+ if (current_chunk_.size() < subnode->length) {
+ const char* data =
+ subnode->tag == EXTERNAL ? subnode->external()->base : subnode->data;
+ subnode = NewSubstring(subnode, current_chunk_.data() - data,
+ current_chunk_.size());
+ }
+ n -= current_chunk_.size();
+ bytes_remaining_ -= current_chunk_.size();
+
+ // Process the next node(s) on the stack, reading whole subtrees depending on
+ // their length and how many bytes we are advancing.
+ CordRep* node = nullptr;
+ while (!stack_of_right_children.empty()) {
+ node = stack_of_right_children.back();
+ stack_of_right_children.pop_back();
+ if (node->length > n) break;
+ // TODO(qrczak): This might unnecessarily recreate existing concat nodes.
+ // Avoiding that would need pretty complicated logic (instead of
+ // current_leaf, keep current_subtree_ which points to the highest node
+ // such that the current leaf can be found on the path of left children
+ // starting from current_subtree_; delay creating subnode while node is
+ // below current_subtree_; find the proper node along the path of left
+ // children starting from current_subtree_ if this loop exits while staying
+ // below current_subtree_; etc.; alternatively, push parents instead of
+ // right children on the stack).
+ subnode = Concat(subnode, CordRep::Ref(node));
+ n -= node->length;
+ bytes_remaining_ -= node->length;
+ node = nullptr;
+ }
+
+ if (node == nullptr) {
+ // We have reached the end of the Cord.
+ assert(bytes_remaining_ == 0);
+ subcord.contents_.set_tree(VerifyTree(subnode));
+ return subcord;
+ }
+
+ // Walk down the appropriate branches until we hit a non-CONCAT node. Save the
+ // right children to the stack for subsequent traversal.
+ while (node->tag == CONCAT) {
+ if (node->concat()->left->length > n) {
+ // Push right, descend left.
+ stack_of_right_children.push_back(node->concat()->right);
+ node = node->concat()->left;
+ } else {
+ // Read left, descend right.
+ subnode = Concat(subnode, CordRep::Ref(node->concat()->left));
+ n -= node->concat()->left->length;
+ bytes_remaining_ -= node->concat()->left->length;
+ node = node->concat()->right;
+ }
+ }
+
+ // Get the child node if we encounter a SUBSTRING.
+ size_t offset = 0;
+ size_t length = node->length;
+ if (node->tag == SUBSTRING) {
+ offset = node->substring()->start;
+ node = node->substring()->child;
+ }
+
+ // Range to read ends with a proper (possibly empty) subrange of the current
+ // chunk.
+ assert(node->tag == EXTERNAL || node->tag >= FLAT);
+ assert(length > n);
+ if (n > 0) {
+ subnode = Concat(subnode, NewSubstring(CordRep::Ref(node), offset, n));
+ }
+ const char* data =
+ node->tag == EXTERNAL ? node->external()->base : node->data;
+ current_chunk_ = absl::string_view(data + offset + n, length - n);
+ current_leaf_ = node;
+ bytes_remaining_ -= n;
+ subcord.contents_.set_tree(VerifyTree(subnode));
+ return subcord;
+}
+
+void Cord::ChunkIterator::AdvanceBytesSlowPath(size_t n) {
+ assert(bytes_remaining_ >= n && "Attempted to iterate past `end()`");
+ assert(n >= current_chunk_.size()); // This should only be called when
+ // iterating to a new node.
+
+ n -= current_chunk_.size();
+ bytes_remaining_ -= current_chunk_.size();
+
+ if (stack_of_right_children_.empty()) {
+ // We have reached the end of the Cord.
+ assert(bytes_remaining_ == 0);
+ return;
+ }
+
+ // Process the next node(s) on the stack, skipping whole subtrees depending on
+ // their length and how many bytes we are advancing.
+ CordRep* node = nullptr;
+ auto& stack_of_right_children = stack_of_right_children_;
+ while (!stack_of_right_children.empty()) {
+ node = stack_of_right_children.back();
+ stack_of_right_children.pop_back();
+ if (node->length > n) break;
+ n -= node->length;
+ bytes_remaining_ -= node->length;
+ node = nullptr;
+ }
+
+ if (node == nullptr) {
+ // We have reached the end of the Cord.
+ assert(bytes_remaining_ == 0);
+ return;
+ }
+
+ // Walk down the appropriate branches until we hit a non-CONCAT node. Save the
+ // right children to the stack for subsequent traversal.
+ while (node->tag == CONCAT) {
+ if (node->concat()->left->length > n) {
+ // Push right, descend left.
+ stack_of_right_children.push_back(node->concat()->right);
+ node = node->concat()->left;
+ } else {
+ // Skip left, descend right.
+ n -= node->concat()->left->length;
+ bytes_remaining_ -= node->concat()->left->length;
+ node = node->concat()->right;
+ }
+ }
+
+ // Get the child node if we encounter a SUBSTRING.
+ size_t offset = 0;
+ size_t length = node->length;
+ if (node->tag == SUBSTRING) {
+ offset = node->substring()->start;
+ node = node->substring()->child;
+ }
+
+ assert(node->tag == EXTERNAL || node->tag >= FLAT);
+ assert(length > n);
+ const char* data =
+ node->tag == EXTERNAL ? node->external()->base : node->data;
+ current_chunk_ = absl::string_view(data + offset + n, length - n);
+ current_leaf_ = node;
+ bytes_remaining_ -= n;
+}
+
+char Cord::operator[](size_t i) const {
+ ABSL_HARDENING_ASSERT(i < size());
+ size_t offset = i;
+ const CordRep* rep = contents_.tree();
+ if (rep == nullptr) {
+ return contents_.data()[i];
+ }
+ while (true) {
+ assert(rep != nullptr);
+ assert(offset < rep->length);
+ if (rep->tag >= FLAT) {
+ // Get the "i"th character directly from the flat array.
+ return rep->data[offset];
+ } else if (rep->tag == EXTERNAL) {
+ // Get the "i"th character from the external array.
+ return rep->external()->base[offset];
+ } else if (rep->tag == CONCAT) {
+ // Recursively branch to the side of the concatenation that the "i"th
+ // character is on.
+ size_t left_length = rep->concat()->left->length;
+ if (offset < left_length) {
+ rep = rep->concat()->left;
+ } else {
+ offset -= left_length;
+ rep = rep->concat()->right;
+ }
+ } else {
+ // This must be a substring a node, so bypass it to get to the child.
+ assert(rep->tag == SUBSTRING);
+ offset += rep->substring()->start;
+ rep = rep->substring()->child;
+ }
+ }
+}
+
+absl::string_view Cord::FlattenSlowPath() {
+ size_t total_size = size();
+ CordRep* new_rep;
+ char* new_buffer;
+
+ // Try to put the contents into a new flat rep. If they won't fit in the
+ // biggest possible flat node, use an external rep instead.
+ if (total_size <= kMaxFlatLength) {
+ new_rep = CordRepFlat::New(total_size);
+ new_rep->length = total_size;
+ new_buffer = new_rep->data;
+ CopyToArraySlowPath(new_buffer);
+ } else {
+ new_buffer = std::allocator<char>().allocate(total_size);
+ CopyToArraySlowPath(new_buffer);
+ new_rep = absl::cord_internal::NewExternalRep(
+ absl::string_view(new_buffer, total_size), [](absl::string_view s) {
+ std::allocator<char>().deallocate(const_cast<char*>(s.data()),
+ s.size());
+ });
+ }
+ if (CordRep* tree = contents_.tree()) {
+ CordRep::Unref(tree);
+ }
+ contents_.set_tree(new_rep);
+ return absl::string_view(new_buffer, total_size);
+}
+
+/* static */ bool Cord::GetFlatAux(CordRep* rep, absl::string_view* fragment) {
+ assert(rep != nullptr);
+ if (rep->tag >= FLAT) {
+ *fragment = absl::string_view(rep->data, rep->length);
+ return true;
+ } else if (rep->tag == EXTERNAL) {
+ *fragment = absl::string_view(rep->external()->base, rep->length);
+ return true;
+ } else if (rep->tag == SUBSTRING) {
+ CordRep* child = rep->substring()->child;
+ if (child->tag >= FLAT) {
+ *fragment =
+ absl::string_view(child->data + rep->substring()->start, rep->length);
+ return true;
+ } else if (child->tag == EXTERNAL) {
+ *fragment = absl::string_view(
+ child->external()->base + rep->substring()->start, rep->length);
+ return true;
+ }
+ }
+ return false;
+}
+
+/* static */ void Cord::ForEachChunkAux(
+ absl::cord_internal::CordRep* rep,
+ absl::FunctionRef<void(absl::string_view)> callback) {
+ assert(rep != nullptr);
+ int stack_pos = 0;
+ constexpr int stack_max = 128;
+ // Stack of right branches for tree traversal
+ absl::cord_internal::CordRep* stack[stack_max];
+ absl::cord_internal::CordRep* current_node = rep;
+ while (true) {
+ if (current_node->tag == CONCAT) {
+ if (stack_pos == stack_max) {
+ // There's no more room on our stack array to add another right branch,
+ // and the idea is to avoid allocations, so call this function
+ // recursively to navigate this subtree further. (This is not something
+ // we expect to happen in practice).
+ ForEachChunkAux(current_node, callback);
+
+ // Pop the next right branch and iterate.
+ current_node = stack[--stack_pos];
+ continue;
+ } else {
+ // Save the right branch for later traversal and continue down the left
+ // branch.
+ stack[stack_pos++] = current_node->concat()->right;
+ current_node = current_node->concat()->left;
+ continue;
+ }
+ }
+ // This is a leaf node, so invoke our callback.
+ absl::string_view chunk;
+ bool success = GetFlatAux(current_node, &chunk);
+ assert(success);
+ if (success) {
+ callback(chunk);
+ }
+ if (stack_pos == 0) {
+ // end of traversal
+ return;
+ }
+ current_node = stack[--stack_pos];
+ }
+}
+
+static void DumpNode(CordRep* rep, bool include_data, std::ostream* os) {
+ const int kIndentStep = 1;
+ int indent = 0;
+ absl::InlinedVector<CordRep*, kInlinedVectorSize> stack;
+ absl::InlinedVector<int, kInlinedVectorSize> indents;
+ for (;;) {
+ *os << std::setw(3) << rep->refcount.Get();
+ *os << " " << std::setw(7) << rep->length;
+ *os << " [";
+ if (include_data) *os << static_cast<void*>(rep);
+ *os << "]";
+ *os << " " << (IsRootBalanced(rep) ? 'b' : 'u');
+ *os << " " << std::setw(indent) << "";
+ if (rep->tag == CONCAT) {
+ *os << "CONCAT depth=" << Depth(rep) << "\n";
+ indent += kIndentStep;
+ indents.push_back(indent);
+ stack.push_back(rep->concat()->right);
+ rep = rep->concat()->left;
+ } else if (rep->tag == SUBSTRING) {
+ *os << "SUBSTRING @ " << rep->substring()->start << "\n";
+ indent += kIndentStep;
+ rep = rep->substring()->child;
+ } else { // Leaf
+ if (rep->tag == EXTERNAL) {
+ *os << "EXTERNAL [";
+ if (include_data)
+ *os << absl::CEscape(std::string(rep->external()->base, rep->length));
+ *os << "]\n";
+ } else {
+ *os << "FLAT cap=" << rep->flat()->Capacity()
+ << " [";
+ if (include_data)
+ *os << absl::CEscape(std::string(rep->data, rep->length));
+ *os << "]\n";
+ }
+ if (stack.empty()) break;
+ rep = stack.back();
+ stack.pop_back();
+ indent = indents.back();
+ indents.pop_back();
+ }
+ }
+ ABSL_INTERNAL_CHECK(indents.empty(), "");
+}
+
+static std::string ReportError(CordRep* root, CordRep* node) {
+ std::ostringstream buf;
+ buf << "Error at node " << node << " in:";
+ DumpNode(root, true, &buf);
+ return buf.str();
+}
+
+static bool VerifyNode(CordRep* root, CordRep* start_node,
+ bool full_validation) {
+ absl::InlinedVector<CordRep*, 2> worklist;
+ worklist.push_back(start_node);
+ do {
+ CordRep* node = worklist.back();
+ worklist.pop_back();
+
+ ABSL_INTERNAL_CHECK(node != nullptr, ReportError(root, node));
+ if (node != root) {
+ ABSL_INTERNAL_CHECK(node->length != 0, ReportError(root, node));
+ }
+
+ if (node->tag == CONCAT) {
+ ABSL_INTERNAL_CHECK(node->concat()->left != nullptr,
+ ReportError(root, node));
+ ABSL_INTERNAL_CHECK(node->concat()->right != nullptr,
+ ReportError(root, node));
+ ABSL_INTERNAL_CHECK((node->length == node->concat()->left->length +
+ node->concat()->right->length),
+ ReportError(root, node));
+ if (full_validation) {
+ worklist.push_back(node->concat()->right);
+ worklist.push_back(node->concat()->left);
+ }
+ } else if (node->tag >= FLAT) {
+ ABSL_INTERNAL_CHECK(
+ node->length <= node->flat()->Capacity(),
+ ReportError(root, node));
+ } else if (node->tag == EXTERNAL) {
+ ABSL_INTERNAL_CHECK(node->external()->base != nullptr,
+ ReportError(root, node));
+ } else if (node->tag == SUBSTRING) {
+ ABSL_INTERNAL_CHECK(
+ node->substring()->start < node->substring()->child->length,
+ ReportError(root, node));
+ ABSL_INTERNAL_CHECK(node->substring()->start + node->length <=
+ node->substring()->child->length,
+ ReportError(root, node));
+ }
+ } while (!worklist.empty());
+ return true;
+}
+
+// Traverses the tree and computes the total memory allocated.
+/* static */ size_t Cord::MemoryUsageAux(const CordRep* rep) {
+ size_t total_mem_usage = 0;
+
+ // Allow a quick exit for the common case that the root is a leaf.
+ if (RepMemoryUsageLeaf(rep, &total_mem_usage)) {
+ return total_mem_usage;
+ }
+
+ // Iterate over the tree. cur_node is never a leaf node and leaf nodes will
+ // never be appended to tree_stack. This reduces overhead from manipulating
+ // tree_stack.
+ absl::InlinedVector<const CordRep*, kInlinedVectorSize> tree_stack;
+ const CordRep* cur_node = rep;
+ while (true) {
+ const CordRep* next_node = nullptr;
+
+ if (cur_node->tag == CONCAT) {
+ total_mem_usage += sizeof(CordRepConcat);
+ const CordRep* left = cur_node->concat()->left;
+ if (!RepMemoryUsageLeaf(left, &total_mem_usage)) {
+ next_node = left;
+ }
+
+ const CordRep* right = cur_node->concat()->right;
+ if (!RepMemoryUsageLeaf(right, &total_mem_usage)) {
+ if (next_node) {
+ tree_stack.push_back(next_node);
+ }
+ next_node = right;
+ }
+ } else {
+ // Since cur_node is not a leaf or a concat node it must be a substring.
+ assert(cur_node->tag == SUBSTRING);
+ total_mem_usage += sizeof(CordRepSubstring);
+ next_node = cur_node->substring()->child;
+ if (RepMemoryUsageLeaf(next_node, &total_mem_usage)) {
+ next_node = nullptr;
+ }
+ }
+
+ if (!next_node) {
+ if (tree_stack.empty()) {
+ return total_mem_usage;
+ }
+ next_node = tree_stack.back();
+ tree_stack.pop_back();
+ }
+ cur_node = next_node;
+ }
+}
+
+std::ostream& operator<<(std::ostream& out, const Cord& cord) {
+ for (absl::string_view chunk : cord.Chunks()) {
+ out.write(chunk.data(), chunk.size());
+ }
+ return out;
+}
+
+namespace strings_internal {
+size_t CordTestAccess::FlatOverhead() { return cord_internal::kFlatOverhead; }
+size_t CordTestAccess::MaxFlatLength() { return cord_internal::kMaxFlatLength; }
+size_t CordTestAccess::FlatTagToLength(uint8_t tag) {
+ return cord_internal::TagToLength(tag);
+}
+uint8_t CordTestAccess::LengthToTag(size_t s) {
+ ABSL_INTERNAL_CHECK(s <= kMaxFlatLength, absl::StrCat("Invalid length ", s));
+ return cord_internal::AllocatedSizeToTag(s + cord_internal::kFlatOverhead);
+}
+size_t CordTestAccess::SizeofCordRepConcat() { return sizeof(CordRepConcat); }
+size_t CordTestAccess::SizeofCordRepExternal() {
+ return sizeof(CordRepExternal);
+}
+size_t CordTestAccess::SizeofCordRepSubstring() {
+ return sizeof(CordRepSubstring);
+}
+} // namespace strings_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/strings/cord.h b/third_party/abseil/absl/strings/cord.h
new file mode 100644
index 0000000..7136f03
--- /dev/null
+++ b/third_party/abseil/absl/strings/cord.h
@@ -0,0 +1,1322 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: cord.h
+// -----------------------------------------------------------------------------
+//
+// This file defines the `absl::Cord` data structure and operations on that data
+// structure. A Cord is a string-like sequence of characters optimized for
+// specific use cases. Unlike a `std::string`, which stores an array of
+// contiguous characters, Cord data is stored in a structure consisting of
+// separate, reference-counted "chunks." (Currently, this implementation is a
+// tree structure, though that implementation may change.)
+//
+// Because a Cord consists of these chunks, data can be added to or removed from
+// a Cord during its lifetime. Chunks may also be shared between Cords. Unlike a
+// `std::string`, a Cord can therefore accomodate data that changes over its
+// lifetime, though it's not quite "mutable"; it can change only in the
+// attachment, detachment, or rearrangement of chunks of its constituent data.
+//
+// A Cord provides some benefit over `std::string` under the following (albeit
+// narrow) circumstances:
+//
+// * Cord data is designed to grow and shrink over a Cord's lifetime. Cord
+// provides efficient insertions and deletions at the start and end of the
+// character sequences, avoiding copies in those cases. Static data should
+// generally be stored as strings.
+// * External memory consisting of string-like data can be directly added to
+// a Cord without requiring copies or allocations.
+// * Cord data may be shared and copied cheaply. Cord provides a copy-on-write
+// implementation and cheap sub-Cord operations. Copying a Cord is an O(1)
+// operation.
+//
+// As a consequence to the above, Cord data is generally large. Small data
+// should generally use strings, as construction of a Cord requires some
+// overhead. Small Cords (<= 15 bytes) are represented inline, but most small
+// Cords are expected to grow over their lifetimes.
+//
+// Note that because a Cord is made up of separate chunked data, random access
+// to character data within a Cord is slower than within a `std::string`.
+//
+// Thread Safety
+//
+// Cord has the same thread-safety properties as many other types like
+// std::string, std::vector<>, int, etc -- it is thread-compatible. In
+// particular, if threads do not call non-const methods, then it is safe to call
+// const methods without synchronization. Copying a Cord produces a new instance
+// that can be used concurrently with the original in arbitrary ways.
+
+#ifndef ABSL_STRINGS_CORD_H_
+#define ABSL_STRINGS_CORD_H_
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <iosfwd>
+#include <iterator>
+#include <string>
+#include <type_traits>
+
+#include "absl/base/internal/endian.h"
+#include "absl/base/internal/per_thread_tls.h"
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/container/inlined_vector.h"
+#include "absl/functional/function_ref.h"
+#include "absl/meta/type_traits.h"
+#include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/internal/string_constant.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+class Cord;
+class CordTestPeer;
+template <typename Releaser>
+Cord MakeCordFromExternal(absl::string_view, Releaser&&);
+void CopyCordToString(const Cord& src, std::string* dst);
+
+// Cord
+//
+// A Cord is a sequence of characters, designed to be more efficient than a
+// `std::string` in certain circumstances: namely, large string data that needs
+// to change over its lifetime or shared, especially when such data is shared
+// across API boundaries.
+//
+// A Cord stores its character data in a structure that allows efficient prepend
+// and append operations. This makes a Cord useful for large string data sent
+// over in a wire format that may need to be prepended or appended at some point
+// during the data exchange (e.g. HTTP, protocol buffers). For example, a
+// Cord is useful for storing an HTTP request, and prepending an HTTP header to
+// such a request.
+//
+// Cords should not be used for storing general string data, however. They
+// require overhead to construct and are slower than strings for random access.
+//
+// The Cord API provides the following common API operations:
+//
+// * Create or assign Cords out of existing string data, memory, or other Cords
+// * Append and prepend data to an existing Cord
+// * Create new Sub-Cords from existing Cord data
+// * Swap Cord data and compare Cord equality
+// * Write out Cord data by constructing a `std::string`
+//
+// Additionally, the API provides iterator utilities to iterate through Cord
+// data via chunks or character bytes.
+//
+class Cord {
+ private:
+ template <typename T>
+ using EnableIfString =
+ absl::enable_if_t<std::is_same<T, std::string>::value, int>;
+
+ public:
+ // Cord::Cord() Constructors.
+
+ // Creates an empty Cord.
+ constexpr Cord() noexcept;
+
+ // Creates a Cord from an existing Cord. Cord is copyable and efficiently
+ // movable. The moved-from state is valid but unspecified.
+ Cord(const Cord& src);
+ Cord(Cord&& src) noexcept;
+ Cord& operator=(const Cord& x);
+ Cord& operator=(Cord&& x) noexcept;
+
+ // Creates a Cord from a `src` string. This constructor is marked explicit to
+ // prevent implicit Cord constructions from arguments convertible to an
+ // `absl::string_view`.
+ explicit Cord(absl::string_view src);
+ Cord& operator=(absl::string_view src);
+
+ // Creates a Cord from a `std::string&&` rvalue. These constructors are
+ // templated to avoid ambiguities for types that are convertible to both
+ // `absl::string_view` and `std::string`, such as `const char*`.
+ template <typename T, EnableIfString<T> = 0>
+ explicit Cord(T&& src);
+ template <typename T, EnableIfString<T> = 0>
+ Cord& operator=(T&& src);
+
+ // Cord::~Cord()
+ //
+ // Destructs the Cord.
+ ~Cord() {
+ if (contents_.is_tree()) DestroyCordSlow();
+ }
+
+ // MakeCordFromExternal()
+ //
+ // Creates a Cord that takes ownership of external string memory. The
+ // contents of `data` are not copied to the Cord; instead, the external
+ // memory is added to the Cord and reference-counted. This data may not be
+ // changed for the life of the Cord, though it may be prepended or appended
+ // to.
+ //
+ // `MakeCordFromExternal()` takes a callable "releaser" that is invoked when
+ // the reference count for `data` reaches zero. As noted above, this data must
+ // remain live until the releaser is invoked. The callable releaser also must:
+ //
+ // * be move constructible
+ // * support `void operator()(absl::string_view) const` or `void operator()`
+ //
+ // Example:
+ //
+ // Cord MakeCord(BlockPool* pool) {
+ // Block* block = pool->NewBlock();
+ // FillBlock(block);
+ // return absl::MakeCordFromExternal(
+ // block->ToStringView(),
+ // [pool, block](absl::string_view v) {
+ // pool->FreeBlock(block, v);
+ // });
+ // }
+ //
+ // WARNING: Because a Cord can be reference-counted, it's likely a bug if your
+ // releaser doesn't do anything. For example, consider the following:
+ //
+ // void Foo(const char* buffer, int len) {
+ // auto c = absl::MakeCordFromExternal(absl::string_view(buffer, len),
+ // [](absl::string_view) {});
+ //
+ // // BUG: If Bar() copies its cord for any reason, including keeping a
+ // // substring of it, the lifetime of buffer might be extended beyond
+ // // when Foo() returns.
+ // Bar(c);
+ // }
+ template <typename Releaser>
+ friend Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser);
+
+ // Cord::Clear()
+ //
+ // Releases the Cord data. Any nodes that share data with other Cords, if
+ // applicable, will have their reference counts reduced by 1.
+ void Clear();
+
+ // Cord::Append()
+ //
+ // Appends data to the Cord, which may come from another Cord or other string
+ // data.
+ void Append(const Cord& src);
+ void Append(Cord&& src);
+ void Append(absl::string_view src);
+ template <typename T, EnableIfString<T> = 0>
+ void Append(T&& src);
+
+ // Cord::Prepend()
+ //
+ // Prepends data to the Cord, which may come from another Cord or other string
+ // data.
+ void Prepend(const Cord& src);
+ void Prepend(absl::string_view src);
+ template <typename T, EnableIfString<T> = 0>
+ void Prepend(T&& src);
+
+ // Cord::RemovePrefix()
+ //
+ // Removes the first `n` bytes of a Cord.
+ void RemovePrefix(size_t n);
+ void RemoveSuffix(size_t n);
+
+ // Cord::Subcord()
+ //
+ // Returns a new Cord representing the subrange [pos, pos + new_size) of
+ // *this. If pos >= size(), the result is empty(). If
+ // (pos + new_size) >= size(), the result is the subrange [pos, size()).
+ Cord Subcord(size_t pos, size_t new_size) const;
+
+ // Cord::swap()
+ //
+ // Swaps the contents of the Cord with `other`.
+ void swap(Cord& other) noexcept;
+
+ // swap()
+ //
+ // Swaps the contents of two Cords.
+ friend void swap(Cord& x, Cord& y) noexcept {
+ x.swap(y);
+ }
+
+ // Cord::size()
+ //
+ // Returns the size of the Cord.
+ size_t size() const;
+
+ // Cord::empty()
+ //
+ // Determines whether the given Cord is empty, returning `true` is so.
+ bool empty() const;
+
+ // Cord::EstimatedMemoryUsage()
+ //
+ // Returns the *approximate* number of bytes held in full or in part by this
+ // Cord (which may not remain the same between invocations). Note that Cords
+ // that share memory could each be "charged" independently for the same shared
+ // memory.
+ size_t EstimatedMemoryUsage() const;
+
+ // Cord::Compare()
+ //
+ // Compares 'this' Cord with rhs. This function and its relatives treat Cords
+ // as sequences of unsigned bytes. The comparison is a straightforward
+ // lexicographic comparison. `Cord::Compare()` returns values as follows:
+ //
+ // -1 'this' Cord is smaller
+ // 0 two Cords are equal
+ // 1 'this' Cord is larger
+ int Compare(absl::string_view rhs) const;
+ int Compare(const Cord& rhs) const;
+
+ // Cord::StartsWith()
+ //
+ // Determines whether the Cord starts with the passed string data `rhs`.
+ bool StartsWith(const Cord& rhs) const;
+ bool StartsWith(absl::string_view rhs) const;
+
+ // Cord::EndsWidth()
+ //
+ // Determines whether the Cord ends with the passed string data `rhs`.
+ bool EndsWith(absl::string_view rhs) const;
+ bool EndsWith(const Cord& rhs) const;
+
+ // Cord::operator std::string()
+ //
+ // Converts a Cord into a `std::string()`. This operator is marked explicit to
+ // prevent unintended Cord usage in functions that take a string.
+ explicit operator std::string() const;
+
+ // CopyCordToString()
+ //
+ // Copies the contents of a `src` Cord into a `*dst` string.
+ //
+ // This function optimizes the case of reusing the destination string since it
+ // can reuse previously allocated capacity. However, this function does not
+ // guarantee that pointers previously returned by `dst->data()` remain valid
+ // even if `*dst` had enough capacity to hold `src`. If `*dst` is a new
+ // object, prefer to simply use the conversion operator to `std::string`.
+ friend void CopyCordToString(const Cord& src, std::string* dst);
+
+ class CharIterator;
+
+ //----------------------------------------------------------------------------
+ // Cord::ChunkIterator
+ //----------------------------------------------------------------------------
+ //
+ // A `Cord::ChunkIterator` allows iteration over the constituent chunks of its
+ // Cord. Such iteration allows you to perform non-const operatons on the data
+ // of a Cord without modifying it.
+ //
+ // Generally, you do not instantiate a `Cord::ChunkIterator` directly;
+ // instead, you create one implicitly through use of the `Cord::Chunks()`
+ // member function.
+ //
+ // The `Cord::ChunkIterator` has the following properties:
+ //
+ // * The iterator is invalidated after any non-const operation on the
+ // Cord object over which it iterates.
+ // * The `string_view` returned by dereferencing a valid, non-`end()`
+ // iterator is guaranteed to be non-empty.
+ // * Two `ChunkIterator` objects can be compared equal if and only if they
+ // remain valid and iterate over the same Cord.
+ // * The iterator in this case is a proxy iterator; the `string_view`
+ // returned by the iterator does not live inside the Cord, and its
+ // lifetime is limited to the lifetime of the iterator itself. To help
+ // prevent lifetime issues, `ChunkIterator::reference` is not a true
+ // reference type and is equivalent to `value_type`.
+ // * The iterator keeps state that can grow for Cords that contain many
+ // nodes and are imbalanced due to sharing. Prefer to pass this type by
+ // const reference instead of by value.
+ class ChunkIterator {
+ 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 = value_type;
+
+ ChunkIterator() = default;
+
+ ChunkIterator& operator++();
+ ChunkIterator operator++(int);
+ bool operator==(const ChunkIterator& other) const;
+ bool operator!=(const ChunkIterator& other) const;
+ reference operator*() const;
+ pointer operator->() const;
+
+ friend class Cord;
+ friend class CharIterator;
+
+ private:
+ // Stack of right children of concat nodes that we have to visit.
+ // Keep this at the end of the structure to avoid cache-thrashing.
+ // TODO(jgm): Benchmark to see if there's a more optimal value than 47 for
+ // the inlined vector size (47 exists for backward compatibility).
+ using Stack = absl::InlinedVector<absl::cord_internal::CordRep*, 47>;
+
+ // Constructs a `begin()` iterator from `cord`.
+ explicit ChunkIterator(const Cord* cord);
+
+ // Removes `n` bytes from `current_chunk_`. Expects `n` to be smaller than
+ // `current_chunk_.size()`.
+ void RemoveChunkPrefix(size_t n);
+ Cord AdvanceAndReadBytes(size_t n);
+ void AdvanceBytes(size_t n);
+
+ // Stack specific operator++
+ ChunkIterator& AdvanceStack();
+
+ // Iterates `n` bytes, where `n` is expected to be greater than or equal to
+ // `current_chunk_.size()`.
+ void AdvanceBytesSlowPath(size_t n);
+
+ // A view into bytes of the current `CordRep`. It may only be a view to a
+ // suffix of bytes if this is being used by `CharIterator`.
+ absl::string_view current_chunk_;
+ // The current leaf, or `nullptr` if the iterator points to short data.
+ // If the current chunk is a substring node, current_leaf_ points to the
+ // underlying flat or external node.
+ absl::cord_internal::CordRep* current_leaf_ = nullptr;
+ // The number of bytes left in the `Cord` over which we are iterating.
+ size_t bytes_remaining_ = 0;
+ // See 'Stack' alias definition.
+ Stack stack_of_right_children_;
+ };
+
+ // Cord::ChunkIterator::chunk_begin()
+ //
+ // Returns an iterator to the first chunk of the `Cord`.
+ //
+ // Generally, prefer using `Cord::Chunks()` within a range-based for loop for
+ // iterating over the chunks of a Cord. This method may be useful for getting
+ // a `ChunkIterator` where range-based for-loops are not useful.
+ //
+ // Example:
+ //
+ // absl::Cord::ChunkIterator FindAsChunk(const absl::Cord& c,
+ // absl::string_view s) {
+ // return std::find(c.chunk_begin(), c.chunk_end(), s);
+ // }
+ ChunkIterator chunk_begin() const;
+
+ // Cord::ChunkItertator::chunk_end()
+ //
+ // Returns an iterator one increment past the last chunk of the `Cord`.
+ //
+ // Generally, prefer using `Cord::Chunks()` within a range-based for loop for
+ // iterating over the chunks of a Cord. This method may be useful for getting
+ // a `ChunkIterator` where range-based for-loops may not be available.
+ ChunkIterator chunk_end() const;
+
+ //----------------------------------------------------------------------------
+ // Cord::ChunkIterator::ChunkRange
+ //----------------------------------------------------------------------------
+ //
+ // `ChunkRange` is a helper class for iterating over the chunks of the `Cord`,
+ // producing an iterator which can be used within a range-based for loop.
+ // Construction of a `ChunkRange` will return an iterator pointing to the
+ // first chunk of the Cord. Generally, do not construct a `ChunkRange`
+ // directly; instead, prefer to use the `Cord::Chunks()` method.
+ //
+ // Implementation note: `ChunkRange` is simply a convenience wrapper over
+ // `Cord::chunk_begin()` and `Cord::chunk_end()`.
+ class ChunkRange {
+ public:
+ explicit ChunkRange(const Cord* cord) : cord_(cord) {}
+
+ ChunkIterator begin() const;
+ ChunkIterator end() const;
+
+ private:
+ const Cord* cord_;
+ };
+
+ // Cord::Chunks()
+ //
+ // Returns a `Cord::ChunkIterator::ChunkRange` for iterating over the chunks
+ // of a `Cord` with a range-based for-loop. For most iteration tasks on a
+ // Cord, use `Cord::Chunks()` to retrieve this iterator.
+ //
+ // Example:
+ //
+ // void ProcessChunks(const Cord& cord) {
+ // for (absl::string_view chunk : cord.Chunks()) { ... }
+ // }
+ //
+ // Note that the ordinary caveats of temporary lifetime extension apply:
+ //
+ // void Process() {
+ // for (absl::string_view chunk : CordFactory().Chunks()) {
+ // // The temporary Cord returned by CordFactory has been destroyed!
+ // }
+ // }
+ ChunkRange Chunks() const;
+
+ //----------------------------------------------------------------------------
+ // Cord::CharIterator
+ //----------------------------------------------------------------------------
+ //
+ // A `Cord::CharIterator` allows iteration over the constituent characters of
+ // a `Cord`.
+ //
+ // Generally, you do not instantiate a `Cord::CharIterator` directly; instead,
+ // you create one implicitly through use of the `Cord::Chars()` member
+ // function.
+ //
+ // A `Cord::CharIterator` has the following properties:
+ //
+ // * The iterator is invalidated after any non-const operation on the
+ // Cord object over which it iterates.
+ // * Two `CharIterator` objects can be compared equal if and only if they
+ // remain valid and iterate over the same Cord.
+ // * The iterator keeps state that can grow for Cords that contain many
+ // nodes and are imbalanced due to sharing. Prefer to pass this type by
+ // const reference instead of by value.
+ // * This type cannot act as a forward iterator because a `Cord` can reuse
+ // sections of memory. This fact violates the requirement for forward
+ // iterators to compare equal if dereferencing them returns the same
+ // object.
+ class CharIterator {
+ public:
+ using iterator_category = std::input_iterator_tag;
+ using value_type = char;
+ using difference_type = ptrdiff_t;
+ using pointer = const char*;
+ using reference = const char&;
+
+ CharIterator() = default;
+
+ CharIterator& operator++();
+ CharIterator operator++(int);
+ bool operator==(const CharIterator& other) const;
+ bool operator!=(const CharIterator& other) const;
+ reference operator*() const;
+ pointer operator->() const;
+
+ friend Cord;
+
+ private:
+ explicit CharIterator(const Cord* cord) : chunk_iterator_(cord) {}
+
+ ChunkIterator chunk_iterator_;
+ };
+
+ // Cord::CharIterator::AdvanceAndRead()
+ //
+ // Advances the `Cord::CharIterator` by `n_bytes` and returns the bytes
+ // advanced as a separate `Cord`. `n_bytes` must be less than or equal to the
+ // number of bytes within the Cord; otherwise, behavior is undefined. It is
+ // valid to pass `char_end()` and `0`.
+ static Cord AdvanceAndRead(CharIterator* it, size_t n_bytes);
+
+ // Cord::CharIterator::Advance()
+ //
+ // Advances the `Cord::CharIterator` by `n_bytes`. `n_bytes` must be less than
+ // or equal to the number of bytes remaining within the Cord; otherwise,
+ // behavior is undefined. It is valid to pass `char_end()` and `0`.
+ static void Advance(CharIterator* it, size_t n_bytes);
+
+ // Cord::CharIterator::ChunkRemaining()
+ //
+ // Returns the longest contiguous view starting at the iterator's position.
+ //
+ // `it` must be dereferenceable.
+ static absl::string_view ChunkRemaining(const CharIterator& it);
+
+ // Cord::CharIterator::char_begin()
+ //
+ // Returns an iterator to the first character of the `Cord`.
+ //
+ // Generally, prefer using `Cord::Chars()` within a range-based for loop for
+ // iterating over the chunks of a Cord. This method may be useful for getting
+ // a `CharIterator` where range-based for-loops may not be available.
+ CharIterator char_begin() const;
+
+ // Cord::CharIterator::char_end()
+ //
+ // Returns an iterator to one past the last character of the `Cord`.
+ //
+ // Generally, prefer using `Cord::Chars()` within a range-based for loop for
+ // iterating over the chunks of a Cord. This method may be useful for getting
+ // a `CharIterator` where range-based for-loops are not useful.
+ CharIterator char_end() const;
+
+ // Cord::CharIterator::CharRange
+ //
+ // `CharRange` is a helper class for iterating over the characters of a
+ // producing an iterator which can be used within a range-based for loop.
+ // Construction of a `CharRange` will return an iterator pointing to the first
+ // character of the Cord. Generally, do not construct a `CharRange` directly;
+ // instead, prefer to use the `Cord::Chars()` method show below.
+ //
+ // Implementation note: `CharRange` is simply a convenience wrapper over
+ // `Cord::char_begin()` and `Cord::char_end()`.
+ class CharRange {
+ public:
+ explicit CharRange(const Cord* cord) : cord_(cord) {}
+
+ CharIterator begin() const;
+ CharIterator end() const;
+
+ private:
+ const Cord* cord_;
+ };
+
+ // Cord::CharIterator::Chars()
+ //
+ // Returns a `Cord::CharIterator` for iterating over the characters of a
+ // `Cord` with a range-based for-loop. For most character-based iteration
+ // tasks on a Cord, use `Cord::Chars()` to retrieve this iterator.
+ //
+ // Example:
+ //
+ // void ProcessCord(const Cord& cord) {
+ // for (char c : cord.Chars()) { ... }
+ // }
+ //
+ // Note that the ordinary caveats of temporary lifetime extension apply:
+ //
+ // void Process() {
+ // for (char c : CordFactory().Chars()) {
+ // // The temporary Cord returned by CordFactory has been destroyed!
+ // }
+ // }
+ CharRange Chars() const;
+
+ // Cord::operator[]
+ //
+ // Gets the "i"th character of the Cord and returns it, provided that
+ // 0 <= i < Cord.size().
+ //
+ // NOTE: This routine is reasonably efficient. It is roughly
+ // logarithmic based on the number of chunks that make up the cord. Still,
+ // if you need to iterate over the contents of a cord, you should
+ // use a CharIterator/ChunkIterator rather than call operator[] or Get()
+ // repeatedly in a loop.
+ char operator[](size_t i) const;
+
+ // Cord::TryFlat()
+ //
+ // If this cord's representation is a single flat array, returns a
+ // string_view referencing that array. Otherwise returns nullopt.
+ absl::optional<absl::string_view> TryFlat() const;
+
+ // Cord::Flatten()
+ //
+ // Flattens the cord into a single array and returns a view of the data.
+ //
+ // If the cord was already flat, the contents are not modified.
+ absl::string_view Flatten();
+
+ // Supports absl::Cord as a sink object for absl::Format().
+ friend void AbslFormatFlush(absl::Cord* cord, absl::string_view part) {
+ cord->Append(part);
+ }
+
+ template <typename H>
+ friend H AbslHashValue(H hash_state, const absl::Cord& c) {
+ absl::optional<absl::string_view> maybe_flat = c.TryFlat();
+ if (maybe_flat.has_value()) {
+ return H::combine(std::move(hash_state), *maybe_flat);
+ }
+ return c.HashFragmented(std::move(hash_state));
+ }
+
+ // Create a Cord with the contents of StringConstant<T>::value.
+ // No allocations will be done and no data will be copied.
+ // This is an INTERNAL API and subject to change or removal. This API can only
+ // be used by spelling absl::strings_internal::MakeStringConstant, which is
+ // also an internal API.
+ template <typename T>
+ explicit constexpr Cord(strings_internal::StringConstant<T>);
+
+ private:
+ friend class CordTestPeer;
+ friend bool operator==(const Cord& lhs, const Cord& rhs);
+ friend bool operator==(const Cord& lhs, absl::string_view rhs);
+
+ // Calls the provided function once for each cord chunk, in order. Unlike
+ // Chunks(), this API will not allocate memory.
+ void ForEachChunk(absl::FunctionRef<void(absl::string_view)>) const;
+
+ // Allocates new contiguous storage for the contents of the cord. This is
+ // called by Flatten() when the cord was not already flat.
+ absl::string_view FlattenSlowPath();
+
+ // Actual cord contents are hidden inside the following simple
+ // class so that we can isolate the bulk of cord.cc from changes
+ // to the representation.
+ //
+ // InlineRep holds either a tree pointer, or an array of kMaxInline bytes.
+ class InlineRep {
+ public:
+ static constexpr unsigned char kMaxInline = cord_internal::kMaxInline;
+ static_assert(kMaxInline >= sizeof(absl::cord_internal::CordRep*), "");
+ static constexpr unsigned char kTreeFlag = cord_internal::kTreeFlag;
+ static constexpr unsigned char kProfiledFlag = cord_internal::kProfiledFlag;
+
+ constexpr InlineRep() : data_() {}
+ InlineRep(const InlineRep& src);
+ InlineRep(InlineRep&& src);
+ InlineRep& operator=(const InlineRep& src);
+ InlineRep& operator=(InlineRep&& src) noexcept;
+
+ explicit constexpr InlineRep(cord_internal::InlineData data);
+
+ void Swap(InlineRep* rhs);
+ bool empty() const;
+ size_t size() const;
+ const char* data() const; // Returns nullptr if holding pointer
+ void set_data(const char* data, size_t n,
+ bool nullify_tail); // Discards pointer, if any
+ char* set_data(size_t n); // Write data to the result
+ // Returns nullptr if holding bytes
+ absl::cord_internal::CordRep* tree() const;
+ // Discards old pointer, if any
+ void set_tree(absl::cord_internal::CordRep* rep);
+ // Replaces a tree with a new root. This is faster than set_tree, but it
+ // should only be used when it's clear that the old rep was a tree.
+ void replace_tree(absl::cord_internal::CordRep* rep);
+ // Returns non-null iff was holding a pointer
+ absl::cord_internal::CordRep* clear();
+ // Converts to pointer if necessary.
+ absl::cord_internal::CordRep* force_tree(size_t extra_hint);
+ void reduce_size(size_t n); // REQUIRES: holding data
+ void remove_prefix(size_t n); // REQUIRES: holding data
+ void AppendArray(const char* src_data, size_t src_size);
+ absl::string_view FindFlatStartPiece() const;
+ void AppendTree(absl::cord_internal::CordRep* tree);
+ void PrependTree(absl::cord_internal::CordRep* tree);
+ void GetAppendRegion(char** region, size_t* size, size_t max_length);
+ void GetAppendRegion(char** region, size_t* size);
+ bool IsSame(const InlineRep& other) const {
+ return memcmp(&data_, &other.data_, sizeof(data_)) == 0;
+ }
+ int BitwiseCompare(const InlineRep& other) const {
+ uint64_t x, y;
+ // Use memcpy to avoid aliasing issues.
+ memcpy(&x, &data_, sizeof(x));
+ memcpy(&y, &other.data_, sizeof(y));
+ if (x == y) {
+ memcpy(&x, reinterpret_cast<const char*>(&data_) + 8, sizeof(x));
+ memcpy(&y, reinterpret_cast<const char*>(&other.data_) + 8, sizeof(y));
+ if (x == y) return 0;
+ }
+ return absl::big_endian::FromHost64(x) < absl::big_endian::FromHost64(y)
+ ? -1
+ : 1;
+ }
+ void CopyTo(std::string* dst) const {
+ // memcpy is much faster when operating on a known size. On most supported
+ // platforms, the small string optimization is large enough that resizing
+ // to 15 bytes does not cause a memory allocation.
+ absl::strings_internal::STLStringResizeUninitialized(dst,
+ sizeof(data_) - 1);
+ memcpy(&(*dst)[0], &data_, sizeof(data_) - 1);
+ // erase is faster than resize because the logic for memory allocation is
+ // not needed.
+ dst->erase(tagged_size());
+ }
+
+ // Copies the inline contents into `dst`. Assumes the cord is not empty.
+ void CopyToArray(char* dst) const;
+
+ bool is_tree() const { return tagged_size() > kMaxInline; }
+
+ private:
+ friend class Cord;
+
+ void AssignSlow(const InlineRep& src);
+ // Unrefs the tree, stops profiling, and zeroes the contents
+ void ClearSlow();
+
+ void ResetToEmpty() { data_ = {}; }
+
+ // This uses reinterpret_cast instead of the union to avoid accessing the
+ // inactive union element. The tagged size is not a common prefix.
+ void set_tagged_size(char new_tag) {
+ reinterpret_cast<char*>(&data_)[kMaxInline] = new_tag;
+ }
+ char tagged_size() const {
+ return reinterpret_cast<const char*>(&data_)[kMaxInline];
+ }
+
+ cord_internal::InlineData data_;
+ };
+ InlineRep contents_;
+
+ // Helper for MemoryUsage().
+ static size_t MemoryUsageAux(const absl::cord_internal::CordRep* rep);
+
+ // Helper for GetFlat() and TryFlat().
+ static bool GetFlatAux(absl::cord_internal::CordRep* rep,
+ absl::string_view* fragment);
+
+ // Helper for ForEachChunk().
+ static void ForEachChunkAux(
+ absl::cord_internal::CordRep* rep,
+ absl::FunctionRef<void(absl::string_view)> callback);
+
+ // The destructor for non-empty Cords.
+ void DestroyCordSlow();
+
+ // Out-of-line implementation of slower parts of logic.
+ void CopyToArraySlowPath(char* dst) const;
+ int CompareSlowPath(absl::string_view rhs, size_t compared_size,
+ size_t size_to_compare) const;
+ int CompareSlowPath(const Cord& rhs, size_t compared_size,
+ size_t size_to_compare) const;
+ bool EqualsImpl(absl::string_view rhs, size_t size_to_compare) const;
+ bool EqualsImpl(const Cord& rhs, size_t size_to_compare) const;
+ int CompareImpl(const Cord& rhs) const;
+
+ template <typename ResultType, typename RHS>
+ friend ResultType GenericCompare(const Cord& lhs, const RHS& rhs,
+ size_t size_to_compare);
+ static absl::string_view GetFirstChunk(const Cord& c);
+ static absl::string_view GetFirstChunk(absl::string_view sv);
+
+ // Returns a new reference to contents_.tree(), or steals an existing
+ // reference if called on an rvalue.
+ absl::cord_internal::CordRep* TakeRep() const&;
+ absl::cord_internal::CordRep* TakeRep() &&;
+
+ // Helper for Append().
+ template <typename C>
+ void AppendImpl(C&& src);
+
+ // Helper for AbslHashValue().
+ template <typename H>
+ H HashFragmented(H hash_state) const {
+ typename H::AbslInternalPiecewiseCombiner combiner;
+ ForEachChunk([&combiner, &hash_state](absl::string_view chunk) {
+ hash_state = combiner.add_buffer(std::move(hash_state), chunk.data(),
+ chunk.size());
+ });
+ return H::combine(combiner.finalize(std::move(hash_state)), size());
+ }
+};
+
+ABSL_NAMESPACE_END
+} // namespace absl
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// allow a Cord to be logged
+extern std::ostream& operator<<(std::ostream& out, const Cord& cord);
+
+// ------------------------------------------------------------------
+// Internal details follow. Clients should ignore.
+
+namespace cord_internal {
+
+// Fast implementation of memmove for up to 15 bytes. This implementation is
+// safe for overlapping regions. If nullify_tail is true, the destination is
+// padded with '\0' up to 16 bytes.
+inline void SmallMemmove(char* dst, const char* src, size_t n,
+ bool nullify_tail = false) {
+ if (n >= 8) {
+ assert(n <= 16);
+ uint64_t buf1;
+ uint64_t buf2;
+ memcpy(&buf1, src, 8);
+ memcpy(&buf2, src + n - 8, 8);
+ if (nullify_tail) {
+ memset(dst + 8, 0, 8);
+ }
+ memcpy(dst, &buf1, 8);
+ memcpy(dst + n - 8, &buf2, 8);
+ } else if (n >= 4) {
+ uint32_t buf1;
+ uint32_t buf2;
+ memcpy(&buf1, src, 4);
+ memcpy(&buf2, src + n - 4, 4);
+ if (nullify_tail) {
+ memset(dst + 4, 0, 4);
+ memset(dst + 8, 0, 8);
+ }
+ memcpy(dst, &buf1, 4);
+ memcpy(dst + n - 4, &buf2, 4);
+ } else {
+ if (n != 0) {
+ dst[0] = src[0];
+ dst[n / 2] = src[n / 2];
+ dst[n - 1] = src[n - 1];
+ }
+ if (nullify_tail) {
+ memset(dst + 8, 0, 8);
+ memset(dst + n, 0, 8);
+ }
+ }
+}
+
+// Does non-template-specific `CordRepExternal` initialization.
+// Expects `data` to be non-empty.
+void InitializeCordRepExternal(absl::string_view data, CordRepExternal* rep);
+
+// Creates a new `CordRep` that owns `data` and `releaser` and returns a pointer
+// to it, or `nullptr` if `data` was empty.
+template <typename Releaser>
+// NOLINTNEXTLINE - suppress clang-tidy raw pointer return.
+CordRep* NewExternalRep(absl::string_view data, Releaser&& releaser) {
+ using ReleaserType = absl::decay_t<Releaser>;
+ if (data.empty()) {
+ // Never create empty external nodes.
+ InvokeReleaser(Rank0{}, ReleaserType(std::forward<Releaser>(releaser)),
+ data);
+ return nullptr;
+ }
+
+ CordRepExternal* rep = new CordRepExternalImpl<ReleaserType>(
+ std::forward<Releaser>(releaser), 0);
+ InitializeCordRepExternal(data, rep);
+ return rep;
+}
+
+// Overload for function reference types that dispatches using a function
+// pointer because there are no `alignof()` or `sizeof()` a function reference.
+// NOLINTNEXTLINE - suppress clang-tidy raw pointer return.
+inline CordRep* NewExternalRep(absl::string_view data,
+ void (&releaser)(absl::string_view)) {
+ return NewExternalRep(data, &releaser);
+}
+
+} // namespace cord_internal
+
+template <typename Releaser>
+Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser) {
+ Cord cord;
+ cord.contents_.set_tree(::absl::cord_internal::NewExternalRep(
+ data, std::forward<Releaser>(releaser)));
+ return cord;
+}
+
+constexpr Cord::InlineRep::InlineRep(cord_internal::InlineData data)
+ : data_(data) {}
+
+inline Cord::InlineRep::InlineRep(const Cord::InlineRep& src) {
+ data_ = src.data_;
+}
+
+inline Cord::InlineRep::InlineRep(Cord::InlineRep&& src) {
+ data_ = src.data_;
+ src.ResetToEmpty();
+}
+
+inline Cord::InlineRep& Cord::InlineRep::operator=(const Cord::InlineRep& src) {
+ if (this == &src) {
+ return *this;
+ }
+ if (!is_tree() && !src.is_tree()) {
+ data_ = src.data_;
+ return *this;
+ }
+ AssignSlow(src);
+ return *this;
+}
+
+inline Cord::InlineRep& Cord::InlineRep::operator=(
+ Cord::InlineRep&& src) noexcept {
+ if (is_tree()) {
+ ClearSlow();
+ }
+ data_ = src.data_;
+ src.ResetToEmpty();
+ return *this;
+}
+
+inline void Cord::InlineRep::Swap(Cord::InlineRep* rhs) {
+ if (rhs == this) {
+ return;
+ }
+
+ std::swap(data_, rhs->data_);
+}
+
+inline const char* Cord::InlineRep::data() const {
+ return is_tree() ? nullptr : data_.as_chars;
+}
+
+inline absl::cord_internal::CordRep* Cord::InlineRep::tree() const {
+ if (is_tree()) {
+ return data_.as_tree.rep;
+ } else {
+ return nullptr;
+ }
+}
+
+inline bool Cord::InlineRep::empty() const { return tagged_size() == 0; }
+
+inline size_t Cord::InlineRep::size() const {
+ const char tag = tagged_size();
+ if (tag <= kMaxInline) return tag;
+ return static_cast<size_t>(tree()->length);
+}
+
+inline void Cord::InlineRep::set_tree(absl::cord_internal::CordRep* rep) {
+ if (rep == nullptr) {
+ ResetToEmpty();
+ } else {
+ bool was_tree = is_tree();
+ data_.as_tree = {rep, {}, tagged_size()};
+ if (!was_tree) {
+ // If we were not a tree already, set the tag.
+ // Otherwise, leave it alone because it might have the profile bit on.
+ set_tagged_size(kTreeFlag);
+ }
+ }
+}
+
+inline void Cord::InlineRep::replace_tree(absl::cord_internal::CordRep* rep) {
+ ABSL_ASSERT(is_tree());
+ if (ABSL_PREDICT_FALSE(rep == nullptr)) {
+ set_tree(rep);
+ return;
+ }
+ data_.as_tree = {rep, {}, tagged_size()};
+}
+
+inline absl::cord_internal::CordRep* Cord::InlineRep::clear() {
+ absl::cord_internal::CordRep* result = tree();
+ ResetToEmpty();
+ return result;
+}
+
+inline void Cord::InlineRep::CopyToArray(char* dst) const {
+ assert(!is_tree());
+ size_t n = tagged_size();
+ assert(n != 0);
+ cord_internal::SmallMemmove(dst, data_.as_chars, n);
+}
+
+constexpr inline Cord::Cord() noexcept {}
+
+template <typename T>
+constexpr Cord::Cord(strings_internal::StringConstant<T>)
+ : contents_(strings_internal::StringConstant<T>::value.size() <=
+ cord_internal::kMaxInline
+ ? cord_internal::InlineData(
+ strings_internal::StringConstant<T>::value)
+ : cord_internal::InlineData(cord_internal::AsTree{
+ &cord_internal::ConstInitExternalStorage<
+ strings_internal::StringConstant<T>>::value,
+ {},
+ cord_internal::kTreeFlag})) {}
+
+inline Cord& Cord::operator=(const Cord& x) {
+ contents_ = x.contents_;
+ return *this;
+}
+
+inline Cord::Cord(Cord&& src) noexcept : contents_(std::move(src.contents_)) {}
+
+inline void Cord::swap(Cord& other) noexcept {
+ contents_.Swap(&other.contents_);
+}
+
+inline Cord& Cord::operator=(Cord&& x) noexcept {
+ contents_ = std::move(x.contents_);
+ return *this;
+}
+
+extern template Cord::Cord(std::string&& src);
+extern template Cord& Cord::operator=(std::string&& src);
+
+inline size_t Cord::size() const {
+ // Length is 1st field in str.rep_
+ return contents_.size();
+}
+
+inline bool Cord::empty() const { return contents_.empty(); }
+
+inline size_t Cord::EstimatedMemoryUsage() const {
+ size_t result = sizeof(Cord);
+ if (const absl::cord_internal::CordRep* rep = contents_.tree()) {
+ result += MemoryUsageAux(rep);
+ }
+ return result;
+}
+
+inline absl::optional<absl::string_view> Cord::TryFlat() const {
+ absl::cord_internal::CordRep* rep = contents_.tree();
+ if (rep == nullptr) {
+ return absl::string_view(contents_.data(), contents_.size());
+ }
+ absl::string_view fragment;
+ if (GetFlatAux(rep, &fragment)) {
+ return fragment;
+ }
+ return absl::nullopt;
+}
+
+inline absl::string_view Cord::Flatten() {
+ absl::cord_internal::CordRep* rep = contents_.tree();
+ if (rep == nullptr) {
+ return absl::string_view(contents_.data(), contents_.size());
+ } else {
+ absl::string_view already_flat_contents;
+ if (GetFlatAux(rep, &already_flat_contents)) {
+ return already_flat_contents;
+ }
+ }
+ return FlattenSlowPath();
+}
+
+inline void Cord::Append(absl::string_view src) {
+ contents_.AppendArray(src.data(), src.size());
+}
+
+extern template void Cord::Append(std::string&& src);
+extern template void Cord::Prepend(std::string&& src);
+
+inline int Cord::Compare(const Cord& rhs) const {
+ if (!contents_.is_tree() && !rhs.contents_.is_tree()) {
+ return contents_.BitwiseCompare(rhs.contents_);
+ }
+
+ return CompareImpl(rhs);
+}
+
+// Does 'this' cord start/end with rhs
+inline bool Cord::StartsWith(const Cord& rhs) const {
+ if (contents_.IsSame(rhs.contents_)) return true;
+ size_t rhs_size = rhs.size();
+ if (size() < rhs_size) return false;
+ return EqualsImpl(rhs, rhs_size);
+}
+
+inline bool Cord::StartsWith(absl::string_view rhs) const {
+ size_t rhs_size = rhs.size();
+ if (size() < rhs_size) return false;
+ return EqualsImpl(rhs, rhs_size);
+}
+
+inline Cord::ChunkIterator::ChunkIterator(const Cord* cord)
+ : bytes_remaining_(cord->size()) {
+ if (cord->empty()) return;
+ if (cord->contents_.is_tree()) {
+ stack_of_right_children_.push_back(cord->contents_.tree());
+ operator++();
+ } else {
+ current_chunk_ = absl::string_view(cord->contents_.data(), cord->size());
+ }
+}
+
+inline Cord::ChunkIterator& Cord::ChunkIterator::operator++() {
+ ABSL_HARDENING_ASSERT(bytes_remaining_ > 0 &&
+ "Attempted to iterate past `end()`");
+ assert(bytes_remaining_ >= current_chunk_.size());
+ bytes_remaining_ -= current_chunk_.size();
+ if (bytes_remaining_ > 0) {
+ return AdvanceStack();
+ } else {
+ current_chunk_ = {};
+ }
+ return *this;
+}
+
+inline Cord::ChunkIterator Cord::ChunkIterator::operator++(int) {
+ ChunkIterator tmp(*this);
+ operator++();
+ return tmp;
+}
+
+inline bool Cord::ChunkIterator::operator==(const ChunkIterator& other) const {
+ return bytes_remaining_ == other.bytes_remaining_;
+}
+
+inline bool Cord::ChunkIterator::operator!=(const ChunkIterator& other) const {
+ return !(*this == other);
+}
+
+inline Cord::ChunkIterator::reference Cord::ChunkIterator::operator*() const {
+ ABSL_HARDENING_ASSERT(bytes_remaining_ != 0);
+ return current_chunk_;
+}
+
+inline Cord::ChunkIterator::pointer Cord::ChunkIterator::operator->() const {
+ ABSL_HARDENING_ASSERT(bytes_remaining_ != 0);
+ return ¤t_chunk_;
+}
+
+inline void Cord::ChunkIterator::RemoveChunkPrefix(size_t n) {
+ assert(n < current_chunk_.size());
+ current_chunk_.remove_prefix(n);
+ bytes_remaining_ -= n;
+}
+
+inline void Cord::ChunkIterator::AdvanceBytes(size_t n) {
+ if (ABSL_PREDICT_TRUE(n < current_chunk_.size())) {
+ RemoveChunkPrefix(n);
+ } else if (n != 0) {
+ AdvanceBytesSlowPath(n);
+ }
+}
+
+inline Cord::ChunkIterator Cord::chunk_begin() const {
+ return ChunkIterator(this);
+}
+
+inline Cord::ChunkIterator Cord::chunk_end() const { return ChunkIterator(); }
+
+inline Cord::ChunkIterator Cord::ChunkRange::begin() const {
+ return cord_->chunk_begin();
+}
+
+inline Cord::ChunkIterator Cord::ChunkRange::end() const {
+ return cord_->chunk_end();
+}
+
+inline Cord::ChunkRange Cord::Chunks() const { return ChunkRange(this); }
+
+inline Cord::CharIterator& Cord::CharIterator::operator++() {
+ if (ABSL_PREDICT_TRUE(chunk_iterator_->size() > 1)) {
+ chunk_iterator_.RemoveChunkPrefix(1);
+ } else {
+ ++chunk_iterator_;
+ }
+ return *this;
+}
+
+inline Cord::CharIterator Cord::CharIterator::operator++(int) {
+ CharIterator tmp(*this);
+ operator++();
+ return tmp;
+}
+
+inline bool Cord::CharIterator::operator==(const CharIterator& other) const {
+ return chunk_iterator_ == other.chunk_iterator_;
+}
+
+inline bool Cord::CharIterator::operator!=(const CharIterator& other) const {
+ return !(*this == other);
+}
+
+inline Cord::CharIterator::reference Cord::CharIterator::operator*() const {
+ return *chunk_iterator_->data();
+}
+
+inline Cord::CharIterator::pointer Cord::CharIterator::operator->() const {
+ return chunk_iterator_->data();
+}
+
+inline Cord Cord::AdvanceAndRead(CharIterator* it, size_t n_bytes) {
+ assert(it != nullptr);
+ return it->chunk_iterator_.AdvanceAndReadBytes(n_bytes);
+}
+
+inline void Cord::Advance(CharIterator* it, size_t n_bytes) {
+ assert(it != nullptr);
+ it->chunk_iterator_.AdvanceBytes(n_bytes);
+}
+
+inline absl::string_view Cord::ChunkRemaining(const CharIterator& it) {
+ return *it.chunk_iterator_;
+}
+
+inline Cord::CharIterator Cord::char_begin() const {
+ return CharIterator(this);
+}
+
+inline Cord::CharIterator Cord::char_end() const { return CharIterator(); }
+
+inline Cord::CharIterator Cord::CharRange::begin() const {
+ return cord_->char_begin();
+}
+
+inline Cord::CharIterator Cord::CharRange::end() const {
+ return cord_->char_end();
+}
+
+inline Cord::CharRange Cord::Chars() const { return CharRange(this); }
+
+inline void Cord::ForEachChunk(
+ absl::FunctionRef<void(absl::string_view)> callback) const {
+ absl::cord_internal::CordRep* rep = contents_.tree();
+ if (rep == nullptr) {
+ callback(absl::string_view(contents_.data(), contents_.size()));
+ } else {
+ return ForEachChunkAux(rep, callback);
+ }
+}
+
+// Nonmember Cord-to-Cord relational operarators.
+inline bool operator==(const Cord& lhs, const Cord& rhs) {
+ if (lhs.contents_.IsSame(rhs.contents_)) return true;
+ size_t rhs_size = rhs.size();
+ if (lhs.size() != rhs_size) return false;
+ return lhs.EqualsImpl(rhs, rhs_size);
+}
+
+inline bool operator!=(const Cord& x, const Cord& y) { return !(x == y); }
+inline bool operator<(const Cord& x, const Cord& y) {
+ return x.Compare(y) < 0;
+}
+inline bool operator>(const Cord& x, const Cord& y) {
+ return x.Compare(y) > 0;
+}
+inline bool operator<=(const Cord& x, const Cord& y) {
+ return x.Compare(y) <= 0;
+}
+inline bool operator>=(const Cord& x, const Cord& y) {
+ return x.Compare(y) >= 0;
+}
+
+// Nonmember Cord-to-absl::string_view relational operators.
+//
+// Due to implicit conversions, these also enable comparisons of Cord with
+// with std::string, ::string, and const char*.
+inline bool operator==(const Cord& lhs, absl::string_view rhs) {
+ size_t lhs_size = lhs.size();
+ size_t rhs_size = rhs.size();
+ if (lhs_size != rhs_size) return false;
+ return lhs.EqualsImpl(rhs, rhs_size);
+}
+
+inline bool operator==(absl::string_view x, const Cord& y) { return y == x; }
+inline bool operator!=(const Cord& x, absl::string_view y) { return !(x == y); }
+inline bool operator!=(absl::string_view x, const Cord& y) { return !(x == y); }
+inline bool operator<(const Cord& x, absl::string_view y) {
+ return x.Compare(y) < 0;
+}
+inline bool operator<(absl::string_view x, const Cord& y) {
+ return y.Compare(x) > 0;
+}
+inline bool operator>(const Cord& x, absl::string_view y) { return y < x; }
+inline bool operator>(absl::string_view x, const Cord& y) { return y < x; }
+inline bool operator<=(const Cord& x, absl::string_view y) { return !(y < x); }
+inline bool operator<=(absl::string_view x, const Cord& y) { return !(y < x); }
+inline bool operator>=(const Cord& x, absl::string_view y) { return !(x < y); }
+inline bool operator>=(absl::string_view x, const Cord& y) { return !(x < y); }
+
+// Some internals exposed to test code.
+namespace strings_internal {
+class CordTestAccess {
+ public:
+ static size_t FlatOverhead();
+ static size_t MaxFlatLength();
+ static size_t SizeofCordRepConcat();
+ static size_t SizeofCordRepExternal();
+ static size_t SizeofCordRepSubstring();
+ static size_t FlatTagToLength(uint8_t tag);
+ static uint8_t LengthToTag(size_t s);
+};
+} // namespace strings_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_STRINGS_CORD_H_
diff --git a/third_party/abseil/absl/strings/cord_test.cc b/third_party/abseil/absl/strings/cord_test.cc
new file mode 100644
index 0000000..7942bfc
--- /dev/null
+++ b/third_party/abseil/absl/strings/cord_test.cc
@@ -0,0 +1,1711 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/cord.h"
+
+#include <algorithm>
+#include <climits>
+#include <cstdio>
+#include <iterator>
+#include <map>
+#include <numeric>
+#include <random>
+#include <sstream>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/casts.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/endian.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
+#include "absl/container/fixed_array.h"
+#include "absl/strings/cord_test_helpers.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/string_view.h"
+
+typedef std::mt19937_64 RandomEngine;
+
+static std::string RandomLowercaseString(RandomEngine* rng);
+static std::string RandomLowercaseString(RandomEngine* rng, size_t length);
+
+static int GetUniformRandomUpTo(RandomEngine* rng, int upper_bound) {
+ if (upper_bound > 0) {
+ std::uniform_int_distribution<int> uniform(0, upper_bound - 1);
+ return uniform(*rng);
+ } else {
+ return 0;
+ }
+}
+
+static size_t GetUniformRandomUpTo(RandomEngine* rng, size_t upper_bound) {
+ if (upper_bound > 0) {
+ std::uniform_int_distribution<size_t> uniform(0, upper_bound - 1);
+ return uniform(*rng);
+ } else {
+ return 0;
+ }
+}
+
+static int32_t GenerateSkewedRandom(RandomEngine* rng, int max_log) {
+ const uint32_t base = (*rng)() % (max_log + 1);
+ const uint32_t mask = ((base < 32) ? (1u << base) : 0u) - 1u;
+ return (*rng)() & mask;
+}
+
+static std::string RandomLowercaseString(RandomEngine* rng) {
+ int length;
+ std::bernoulli_distribution one_in_1k(0.001);
+ std::bernoulli_distribution one_in_10k(0.0001);
+ // With low probability, make a large fragment
+ if (one_in_10k(*rng)) {
+ length = GetUniformRandomUpTo(rng, 1048576);
+ } else if (one_in_1k(*rng)) {
+ length = GetUniformRandomUpTo(rng, 10000);
+ } else {
+ length = GenerateSkewedRandom(rng, 10);
+ }
+ return RandomLowercaseString(rng, length);
+}
+
+static std::string RandomLowercaseString(RandomEngine* rng, size_t length) {
+ std::string result(length, '\0');
+ std::uniform_int_distribution<int> chars('a', 'z');
+ std::generate(result.begin(), result.end(),
+ [&]() { return static_cast<char>(chars(*rng)); });
+ return result;
+}
+
+static void DoNothing(absl::string_view /* data */, void* /* arg */) {}
+
+static void DeleteExternalString(absl::string_view data, void* arg) {
+ std::string* s = reinterpret_cast<std::string*>(arg);
+ EXPECT_EQ(data, *s);
+ delete s;
+}
+
+// Add "s" to *dst via `MakeCordFromExternal`
+static void AddExternalMemory(absl::string_view s, absl::Cord* dst) {
+ std::string* str = new std::string(s.data(), s.size());
+ dst->Append(absl::MakeCordFromExternal(*str, [str](absl::string_view data) {
+ DeleteExternalString(data, str);
+ }));
+}
+
+static void DumpGrowth() {
+ absl::Cord str;
+ for (int i = 0; i < 1000; i++) {
+ char c = 'a' + i % 26;
+ str.Append(absl::string_view(&c, 1));
+ }
+}
+
+// Make a Cord with some number of fragments. Return the size (in bytes)
+// of the smallest fragment.
+static size_t AppendWithFragments(const std::string& s, RandomEngine* rng,
+ absl::Cord* cord) {
+ size_t j = 0;
+ const size_t max_size = s.size() / 5; // Make approx. 10 fragments
+ size_t min_size = max_size; // size of smallest fragment
+ while (j < s.size()) {
+ size_t N = 1 + GetUniformRandomUpTo(rng, max_size);
+ if (N > (s.size() - j)) {
+ N = s.size() - j;
+ }
+ if (N < min_size) {
+ min_size = N;
+ }
+
+ std::bernoulli_distribution coin_flip(0.5);
+ if (coin_flip(*rng)) {
+ // Grow by adding an external-memory.
+ AddExternalMemory(absl::string_view(s.data() + j, N), cord);
+ } else {
+ cord->Append(absl::string_view(s.data() + j, N));
+ }
+ j += N;
+ }
+ return min_size;
+}
+
+// Add an external memory that contains the specified std::string to cord
+static void AddNewStringBlock(const std::string& str, absl::Cord* dst) {
+ char* data = new char[str.size()];
+ memcpy(data, str.data(), str.size());
+ dst->Append(absl::MakeCordFromExternal(
+ absl::string_view(data, str.size()),
+ [](absl::string_view s) { delete[] s.data(); }));
+}
+
+// Make a Cord out of many different types of nodes.
+static absl::Cord MakeComposite() {
+ absl::Cord cord;
+ cord.Append("the");
+ AddExternalMemory(" quick brown", &cord);
+ AddExternalMemory(" fox jumped", &cord);
+
+ absl::Cord full(" over");
+ AddExternalMemory(" the lazy", &full);
+ AddNewStringBlock(" dog slept the whole day away", &full);
+ absl::Cord substring = full.Subcord(0, 18);
+
+ // Make substring long enough to defeat the copying fast path in Append.
+ substring.Append(std::string(1000, '.'));
+ cord.Append(substring);
+ cord = cord.Subcord(0, cord.size() - 998); // Remove most of extra junk
+
+ return cord;
+}
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+class CordTestPeer {
+ public:
+ static void ForEachChunk(
+ const Cord& c, absl::FunctionRef<void(absl::string_view)> callback) {
+ c.ForEachChunk(callback);
+ }
+
+ static bool IsTree(const Cord& c) { return c.contents_.is_tree(); }
+};
+
+ABSL_NAMESPACE_END
+} // namespace absl
+
+TEST(Cord, AllFlatSizes) {
+ using absl::strings_internal::CordTestAccess;
+
+ for (size_t s = 0; s < CordTestAccess::MaxFlatLength(); s++) {
+ // Make a string of length s.
+ std::string src;
+ while (src.size() < s) {
+ src.push_back('a' + (src.size() % 26));
+ }
+
+ absl::Cord dst(src);
+ EXPECT_EQ(std::string(dst), src) << s;
+ }
+}
+
+// We create a Cord at least 128GB in size using the fact that Cords can
+// internally reference-count; thus the Cord is enormous without actually
+// consuming very much memory.
+TEST(GigabyteCord, FromExternal) {
+ const size_t one_gig = 1024U * 1024U * 1024U;
+ size_t max_size = 2 * one_gig;
+ if (sizeof(max_size) > 4) max_size = 128 * one_gig;
+
+ size_t length = 128 * 1024;
+ char* data = new char[length];
+ absl::Cord from = absl::MakeCordFromExternal(
+ absl::string_view(data, length),
+ [](absl::string_view sv) { delete[] sv.data(); });
+
+ // This loop may seem odd due to its combination of exponential doubling of
+ // size and incremental size increases. We do it incrementally to be sure the
+ // Cord will need rebalancing and will exercise code that, in the past, has
+ // caused crashes in production. We grow exponentially so that the code will
+ // execute in a reasonable amount of time.
+ absl::Cord c;
+ ABSL_RAW_LOG(INFO, "Made a Cord with %zu bytes!", c.size());
+ c.Append(from);
+ while (c.size() < max_size) {
+ c.Append(c);
+ c.Append(from);
+ c.Append(from);
+ c.Append(from);
+ c.Append(from);
+ }
+
+ for (int i = 0; i < 1024; ++i) {
+ c.Append(from);
+ }
+ ABSL_RAW_LOG(INFO, "Made a Cord with %zu bytes!", c.size());
+ // Note: on a 32-bit build, this comes out to 2,818,048,000 bytes.
+ // Note: on a 64-bit build, this comes out to 171,932,385,280 bytes.
+}
+
+static absl::Cord MakeExternalCord(int size) {
+ char* buffer = new char[size];
+ memset(buffer, 'x', size);
+ absl::Cord cord;
+ cord.Append(absl::MakeCordFromExternal(
+ absl::string_view(buffer, size),
+ [](absl::string_view s) { delete[] s.data(); }));
+ return cord;
+}
+
+// Extern to fool clang that this is not constant. Needed to suppress
+// a warning of unsafe code we want to test.
+extern bool my_unique_true_boolean;
+bool my_unique_true_boolean = true;
+
+TEST(Cord, Assignment) {
+ absl::Cord x(absl::string_view("hi there"));
+ absl::Cord y(x);
+ ASSERT_EQ(std::string(x), "hi there");
+ ASSERT_EQ(std::string(y), "hi there");
+ ASSERT_TRUE(x == y);
+ ASSERT_TRUE(x <= y);
+ ASSERT_TRUE(y <= x);
+
+ x = absl::string_view("foo");
+ ASSERT_EQ(std::string(x), "foo");
+ ASSERT_EQ(std::string(y), "hi there");
+ ASSERT_TRUE(x < y);
+ ASSERT_TRUE(y > x);
+ ASSERT_TRUE(x != y);
+ ASSERT_TRUE(x <= y);
+ ASSERT_TRUE(y >= x);
+
+ x = "foo";
+ ASSERT_EQ(x, "foo");
+
+ // Test that going from inline rep to tree we don't leak memory.
+ std::vector<std::pair<absl::string_view, absl::string_view>>
+ test_string_pairs = {{"hi there", "foo"},
+ {"loooooong coooooord", "short cord"},
+ {"short cord", "loooooong coooooord"},
+ {"loooooong coooooord1", "loooooong coooooord2"}};
+ for (std::pair<absl::string_view, absl::string_view> test_strings :
+ test_string_pairs) {
+ absl::Cord tmp(test_strings.first);
+ absl::Cord z(std::move(tmp));
+ ASSERT_EQ(std::string(z), test_strings.first);
+ tmp = test_strings.second;
+ z = std::move(tmp);
+ ASSERT_EQ(std::string(z), test_strings.second);
+ }
+ {
+ // Test that self-move assignment doesn't crash/leak.
+ // Do not write such code!
+ absl::Cord my_small_cord("foo");
+ absl::Cord my_big_cord("loooooong coooooord");
+ // Bypass clang's warning on self move-assignment.
+ absl::Cord* my_small_alias =
+ my_unique_true_boolean ? &my_small_cord : &my_big_cord;
+ absl::Cord* my_big_alias =
+ !my_unique_true_boolean ? &my_small_cord : &my_big_cord;
+
+ *my_small_alias = std::move(my_small_cord);
+ *my_big_alias = std::move(my_big_cord);
+ // my_small_cord and my_big_cord are in an unspecified but valid
+ // state, and will be correctly destroyed here.
+ }
+}
+
+TEST(Cord, StartsEndsWith) {
+ absl::Cord x(absl::string_view("abcde"));
+ absl::Cord empty("");
+
+ ASSERT_TRUE(x.StartsWith(absl::Cord("abcde")));
+ ASSERT_TRUE(x.StartsWith(absl::Cord("abc")));
+ ASSERT_TRUE(x.StartsWith(absl::Cord("")));
+ ASSERT_TRUE(empty.StartsWith(absl::Cord("")));
+ ASSERT_TRUE(x.EndsWith(absl::Cord("abcde")));
+ ASSERT_TRUE(x.EndsWith(absl::Cord("cde")));
+ ASSERT_TRUE(x.EndsWith(absl::Cord("")));
+ ASSERT_TRUE(empty.EndsWith(absl::Cord("")));
+
+ ASSERT_TRUE(!x.StartsWith(absl::Cord("xyz")));
+ ASSERT_TRUE(!empty.StartsWith(absl::Cord("xyz")));
+ ASSERT_TRUE(!x.EndsWith(absl::Cord("xyz")));
+ ASSERT_TRUE(!empty.EndsWith(absl::Cord("xyz")));
+
+ ASSERT_TRUE(x.StartsWith("abcde"));
+ ASSERT_TRUE(x.StartsWith("abc"));
+ ASSERT_TRUE(x.StartsWith(""));
+ ASSERT_TRUE(empty.StartsWith(""));
+ ASSERT_TRUE(x.EndsWith("abcde"));
+ ASSERT_TRUE(x.EndsWith("cde"));
+ ASSERT_TRUE(x.EndsWith(""));
+ ASSERT_TRUE(empty.EndsWith(""));
+
+ ASSERT_TRUE(!x.StartsWith("xyz"));
+ ASSERT_TRUE(!empty.StartsWith("xyz"));
+ ASSERT_TRUE(!x.EndsWith("xyz"));
+ ASSERT_TRUE(!empty.EndsWith("xyz"));
+}
+
+TEST(Cord, Subcord) {
+ RandomEngine rng(testing::GTEST_FLAG(random_seed));
+ const std::string s = RandomLowercaseString(&rng, 1024);
+
+ absl::Cord a;
+ AppendWithFragments(s, &rng, &a);
+ ASSERT_EQ(s.size(), a.size());
+
+ // Check subcords of a, from a variety of interesting points.
+ std::set<size_t> positions;
+ for (int i = 0; i <= 32; ++i) {
+ positions.insert(i);
+ positions.insert(i * 32 - 1);
+ positions.insert(i * 32);
+ positions.insert(i * 32 + 1);
+ positions.insert(a.size() - i);
+ }
+ positions.insert(237);
+ positions.insert(732);
+ for (size_t pos : positions) {
+ if (pos > a.size()) continue;
+ for (size_t end_pos : positions) {
+ if (end_pos < pos || end_pos > a.size()) continue;
+ absl::Cord sa = a.Subcord(pos, end_pos - pos);
+ EXPECT_EQ(absl::string_view(s).substr(pos, end_pos - pos),
+ std::string(sa))
+ << a;
+ }
+ }
+
+ // Do the same thing for an inline cord.
+ const std::string sh = "short";
+ absl::Cord c(sh);
+ for (size_t pos = 0; pos <= sh.size(); ++pos) {
+ for (size_t n = 0; n <= sh.size() - pos; ++n) {
+ absl::Cord sc = c.Subcord(pos, n);
+ EXPECT_EQ(sh.substr(pos, n), std::string(sc)) << c;
+ }
+ }
+
+ // Check subcords of subcords.
+ absl::Cord sa = a.Subcord(0, a.size());
+ std::string ss = s.substr(0, s.size());
+ while (sa.size() > 1) {
+ sa = sa.Subcord(1, sa.size() - 2);
+ ss = ss.substr(1, ss.size() - 2);
+ EXPECT_EQ(ss, std::string(sa)) << a;
+ if (HasFailure()) break; // halt cascade
+ }
+
+ // It is OK to ask for too much.
+ sa = a.Subcord(0, a.size() + 1);
+ EXPECT_EQ(s, std::string(sa));
+
+ // It is OK to ask for something beyond the end.
+ sa = a.Subcord(a.size() + 1, 0);
+ EXPECT_TRUE(sa.empty());
+ sa = a.Subcord(a.size() + 1, 1);
+ EXPECT_TRUE(sa.empty());
+}
+
+TEST(Cord, Swap) {
+ absl::string_view a("Dexter");
+ absl::string_view b("Mandark");
+ absl::Cord x(a);
+ absl::Cord y(b);
+ swap(x, y);
+ ASSERT_EQ(x, absl::Cord(b));
+ ASSERT_EQ(y, absl::Cord(a));
+ x.swap(y);
+ ASSERT_EQ(x, absl::Cord(a));
+ ASSERT_EQ(y, absl::Cord(b));
+}
+
+static void VerifyCopyToString(const absl::Cord& cord) {
+ std::string initially_empty;
+ absl::CopyCordToString(cord, &initially_empty);
+ EXPECT_EQ(initially_empty, cord);
+
+ constexpr size_t kInitialLength = 1024;
+ std::string has_initial_contents(kInitialLength, 'x');
+ const char* address_before_copy = has_initial_contents.data();
+ absl::CopyCordToString(cord, &has_initial_contents);
+ EXPECT_EQ(has_initial_contents, cord);
+
+ if (cord.size() <= kInitialLength) {
+ EXPECT_EQ(has_initial_contents.data(), address_before_copy)
+ << "CopyCordToString allocated new string storage; "
+ "has_initial_contents = \""
+ << has_initial_contents << "\"";
+ }
+}
+
+TEST(Cord, CopyToString) {
+ VerifyCopyToString(absl::Cord());
+ VerifyCopyToString(absl::Cord("small cord"));
+ VerifyCopyToString(
+ absl::MakeFragmentedCord({"fragmented ", "cord ", "to ", "test ",
+ "copying ", "to ", "a ", "string."}));
+}
+
+TEST(TryFlat, Empty) {
+ absl::Cord c;
+ EXPECT_EQ(c.TryFlat(), "");
+}
+
+TEST(TryFlat, Flat) {
+ absl::Cord c("hello");
+ EXPECT_EQ(c.TryFlat(), "hello");
+}
+
+TEST(TryFlat, SubstrInlined) {
+ absl::Cord c("hello");
+ c.RemovePrefix(1);
+ EXPECT_EQ(c.TryFlat(), "ello");
+}
+
+TEST(TryFlat, SubstrFlat) {
+ absl::Cord c("longer than 15 bytes");
+ c.RemovePrefix(1);
+ EXPECT_EQ(c.TryFlat(), "onger than 15 bytes");
+}
+
+TEST(TryFlat, Concat) {
+ absl::Cord c = absl::MakeFragmentedCord({"hel", "lo"});
+ EXPECT_EQ(c.TryFlat(), absl::nullopt);
+}
+
+TEST(TryFlat, External) {
+ absl::Cord c = absl::MakeCordFromExternal("hell", [](absl::string_view) {});
+ EXPECT_EQ(c.TryFlat(), "hell");
+}
+
+TEST(TryFlat, SubstrExternal) {
+ absl::Cord c = absl::MakeCordFromExternal("hell", [](absl::string_view) {});
+ c.RemovePrefix(1);
+ EXPECT_EQ(c.TryFlat(), "ell");
+}
+
+TEST(TryFlat, SubstrConcat) {
+ absl::Cord c = absl::MakeFragmentedCord({"hello", " world"});
+ c.RemovePrefix(1);
+ EXPECT_EQ(c.TryFlat(), absl::nullopt);
+}
+
+static bool IsFlat(const absl::Cord& c) {
+ return c.chunk_begin() == c.chunk_end() || ++c.chunk_begin() == c.chunk_end();
+}
+
+static void VerifyFlatten(absl::Cord c) {
+ std::string old_contents(c);
+ absl::string_view old_flat;
+ bool already_flat_and_non_empty = IsFlat(c) && !c.empty();
+ if (already_flat_and_non_empty) {
+ old_flat = *c.chunk_begin();
+ }
+ absl::string_view new_flat = c.Flatten();
+
+ // Verify that the contents of the flattened Cord are correct.
+ EXPECT_EQ(new_flat, old_contents);
+ EXPECT_EQ(std::string(c), old_contents);
+
+ // If the Cord contained data and was already flat, verify that the data
+ // wasn't copied.
+ if (already_flat_and_non_empty) {
+ EXPECT_EQ(old_flat.data(), new_flat.data())
+ << "Allocated new memory even though the Cord was already flat.";
+ }
+
+ // Verify that the flattened Cord is in fact flat.
+ EXPECT_TRUE(IsFlat(c));
+}
+
+TEST(Cord, Flatten) {
+ VerifyFlatten(absl::Cord());
+ VerifyFlatten(absl::Cord("small cord"));
+ VerifyFlatten(absl::Cord("larger than small buffer optimization"));
+ VerifyFlatten(absl::MakeFragmentedCord({"small ", "fragmented ", "cord"}));
+
+ // Test with a cord that is longer than the largest flat buffer
+ RandomEngine rng(testing::GTEST_FLAG(random_seed));
+ VerifyFlatten(absl::Cord(RandomLowercaseString(&rng, 8192)));
+}
+
+// Test data
+namespace {
+class TestData {
+ private:
+ std::vector<std::string> data_;
+
+ // Return a std::string of the specified length.
+ static std::string MakeString(int length) {
+ std::string result;
+ char buf[30];
+ snprintf(buf, sizeof(buf), "(%d)", length);
+ while (result.size() < length) {
+ result += buf;
+ }
+ result.resize(length);
+ return result;
+ }
+
+ public:
+ TestData() {
+ // short strings increasing in length by one
+ for (int i = 0; i < 30; i++) {
+ data_.push_back(MakeString(i));
+ }
+
+ // strings around half kMaxFlatLength
+ static const int kMaxFlatLength = 4096 - 9;
+ static const int kHalf = kMaxFlatLength / 2;
+
+ for (int i = -10; i <= +10; i++) {
+ data_.push_back(MakeString(kHalf + i));
+ }
+
+ for (int i = -10; i <= +10; i++) {
+ data_.push_back(MakeString(kMaxFlatLength + i));
+ }
+ }
+
+ size_t size() const { return data_.size(); }
+ const std::string& data(size_t i) const { return data_[i]; }
+};
+} // namespace
+
+TEST(Cord, MultipleLengths) {
+ TestData d;
+ for (size_t i = 0; i < d.size(); i++) {
+ std::string a = d.data(i);
+
+ { // Construct from Cord
+ absl::Cord tmp(a);
+ absl::Cord x(tmp);
+ EXPECT_EQ(a, std::string(x)) << "'" << a << "'";
+ }
+
+ { // Construct from absl::string_view
+ absl::Cord x(a);
+ EXPECT_EQ(a, std::string(x)) << "'" << a << "'";
+ }
+
+ { // Append cord to self
+ absl::Cord self(a);
+ self.Append(self);
+ EXPECT_EQ(a + a, std::string(self)) << "'" << a << "' + '" << a << "'";
+ }
+
+ { // Prepend cord to self
+ absl::Cord self(a);
+ self.Prepend(self);
+ EXPECT_EQ(a + a, std::string(self)) << "'" << a << "' + '" << a << "'";
+ }
+
+ // Try to append/prepend others
+ for (size_t j = 0; j < d.size(); j++) {
+ std::string b = d.data(j);
+
+ { // CopyFrom Cord
+ absl::Cord x(a);
+ absl::Cord y(b);
+ x = y;
+ EXPECT_EQ(b, std::string(x)) << "'" << a << "' + '" << b << "'";
+ }
+
+ { // CopyFrom absl::string_view
+ absl::Cord x(a);
+ x = b;
+ EXPECT_EQ(b, std::string(x)) << "'" << a << "' + '" << b << "'";
+ }
+
+ { // Cord::Append(Cord)
+ absl::Cord x(a);
+ absl::Cord y(b);
+ x.Append(y);
+ EXPECT_EQ(a + b, std::string(x)) << "'" << a << "' + '" << b << "'";
+ }
+
+ { // Cord::Append(absl::string_view)
+ absl::Cord x(a);
+ x.Append(b);
+ EXPECT_EQ(a + b, std::string(x)) << "'" << a << "' + '" << b << "'";
+ }
+
+ { // Cord::Prepend(Cord)
+ absl::Cord x(a);
+ absl::Cord y(b);
+ x.Prepend(y);
+ EXPECT_EQ(b + a, std::string(x)) << "'" << b << "' + '" << a << "'";
+ }
+
+ { // Cord::Prepend(absl::string_view)
+ absl::Cord x(a);
+ x.Prepend(b);
+ EXPECT_EQ(b + a, std::string(x)) << "'" << b << "' + '" << a << "'";
+ }
+ }
+ }
+}
+
+namespace {
+
+TEST(Cord, RemoveSuffixWithExternalOrSubstring) {
+ absl::Cord cord = absl::MakeCordFromExternal(
+ "foo bar baz", [](absl::string_view s) { DoNothing(s, nullptr); });
+
+ EXPECT_EQ("foo bar baz", std::string(cord));
+
+ // This RemoveSuffix() will wrap the EXTERNAL node in a SUBSTRING node.
+ cord.RemoveSuffix(4);
+ EXPECT_EQ("foo bar", std::string(cord));
+
+ // This RemoveSuffix() will adjust the SUBSTRING node in-place.
+ cord.RemoveSuffix(4);
+ EXPECT_EQ("foo", std::string(cord));
+}
+
+TEST(Cord, RemoveSuffixMakesZeroLengthNode) {
+ absl::Cord c;
+ c.Append(absl::Cord(std::string(100, 'x')));
+ absl::Cord other_ref = c; // Prevent inplace appends
+ c.Append(absl::Cord(std::string(200, 'y')));
+ c.RemoveSuffix(200);
+ EXPECT_EQ(std::string(100, 'x'), std::string(c));
+}
+
+} // namespace
+
+// CordSpliceTest contributed by hendrie.
+namespace {
+
+// Create a cord with an external memory block filled with 'z'
+absl::Cord CordWithZedBlock(size_t size) {
+ char* data = new char[size];
+ if (size > 0) {
+ memset(data, 'z', size);
+ }
+ absl::Cord cord = absl::MakeCordFromExternal(
+ absl::string_view(data, size),
+ [](absl::string_view s) { delete[] s.data(); });
+ return cord;
+}
+
+// Establish that ZedBlock does what we think it does.
+TEST(CordSpliceTest, ZedBlock) {
+ absl::Cord blob = CordWithZedBlock(10);
+ EXPECT_EQ(10, blob.size());
+ std::string s;
+ absl::CopyCordToString(blob, &s);
+ EXPECT_EQ("zzzzzzzzzz", s);
+}
+
+TEST(CordSpliceTest, ZedBlock0) {
+ absl::Cord blob = CordWithZedBlock(0);
+ EXPECT_EQ(0, blob.size());
+ std::string s;
+ absl::CopyCordToString(blob, &s);
+ EXPECT_EQ("", s);
+}
+
+TEST(CordSpliceTest, ZedBlockSuffix1) {
+ absl::Cord blob = CordWithZedBlock(10);
+ EXPECT_EQ(10, blob.size());
+ absl::Cord suffix(blob);
+ suffix.RemovePrefix(9);
+ EXPECT_EQ(1, suffix.size());
+ std::string s;
+ absl::CopyCordToString(suffix, &s);
+ EXPECT_EQ("z", s);
+}
+
+// Remove all of a prefix block
+TEST(CordSpliceTest, ZedBlockSuffix0) {
+ absl::Cord blob = CordWithZedBlock(10);
+ EXPECT_EQ(10, blob.size());
+ absl::Cord suffix(blob);
+ suffix.RemovePrefix(10);
+ EXPECT_EQ(0, suffix.size());
+ std::string s;
+ absl::CopyCordToString(suffix, &s);
+ EXPECT_EQ("", s);
+}
+
+absl::Cord BigCord(size_t len, char v) {
+ std::string s(len, v);
+ return absl::Cord(s);
+}
+
+// Splice block into cord.
+absl::Cord SpliceCord(const absl::Cord& blob, int64_t offset,
+ const absl::Cord& block) {
+ ABSL_RAW_CHECK(offset >= 0, "");
+ ABSL_RAW_CHECK(offset + block.size() <= blob.size(), "");
+ absl::Cord result(blob);
+ result.RemoveSuffix(blob.size() - offset);
+ result.Append(block);
+ absl::Cord suffix(blob);
+ suffix.RemovePrefix(offset + block.size());
+ result.Append(suffix);
+ ABSL_RAW_CHECK(blob.size() == result.size(), "");
+ return result;
+}
+
+// Taking an empty suffix of a block breaks appending.
+TEST(CordSpliceTest, RemoveEntireBlock1) {
+ absl::Cord zero = CordWithZedBlock(10);
+ absl::Cord suffix(zero);
+ suffix.RemovePrefix(10);
+ absl::Cord result;
+ result.Append(suffix);
+}
+
+TEST(CordSpliceTest, RemoveEntireBlock2) {
+ absl::Cord zero = CordWithZedBlock(10);
+ absl::Cord prefix(zero);
+ prefix.RemoveSuffix(10);
+ absl::Cord suffix(zero);
+ suffix.RemovePrefix(10);
+ absl::Cord result(prefix);
+ result.Append(suffix);
+}
+
+TEST(CordSpliceTest, RemoveEntireBlock3) {
+ absl::Cord blob = CordWithZedBlock(10);
+ absl::Cord block = BigCord(10, 'b');
+ blob = SpliceCord(blob, 0, block);
+}
+
+struct CordCompareTestCase {
+ template <typename LHS, typename RHS>
+ CordCompareTestCase(const LHS& lhs, const RHS& rhs)
+ : lhs_cord(lhs), rhs_cord(rhs) {}
+
+ absl::Cord lhs_cord;
+ absl::Cord rhs_cord;
+};
+
+const auto sign = [](int x) { return x == 0 ? 0 : (x > 0 ? 1 : -1); };
+
+void VerifyComparison(const CordCompareTestCase& test_case) {
+ std::string lhs_string(test_case.lhs_cord);
+ std::string rhs_string(test_case.rhs_cord);
+ int expected = sign(lhs_string.compare(rhs_string));
+ EXPECT_EQ(expected, test_case.lhs_cord.Compare(test_case.rhs_cord))
+ << "LHS=" << lhs_string << "; RHS=" << rhs_string;
+ EXPECT_EQ(expected, test_case.lhs_cord.Compare(rhs_string))
+ << "LHS=" << lhs_string << "; RHS=" << rhs_string;
+ EXPECT_EQ(-expected, test_case.rhs_cord.Compare(test_case.lhs_cord))
+ << "LHS=" << rhs_string << "; RHS=" << lhs_string;
+ EXPECT_EQ(-expected, test_case.rhs_cord.Compare(lhs_string))
+ << "LHS=" << rhs_string << "; RHS=" << lhs_string;
+}
+
+TEST(Cord, Compare) {
+ absl::Cord subcord("aaaaaBBBBBcccccDDDDD");
+ subcord = subcord.Subcord(3, 10);
+
+ absl::Cord tmp("aaaaaaaaaaaaaaaa");
+ tmp.Append("BBBBBBBBBBBBBBBB");
+ absl::Cord concat = absl::Cord("cccccccccccccccc");
+ concat.Append("DDDDDDDDDDDDDDDD");
+ concat.Prepend(tmp);
+
+ absl::Cord concat2("aaaaaaaaaaaaa");
+ concat2.Append("aaaBBBBBBBBBBBBBBBBccccc");
+ concat2.Append("cccccccccccDDDDDDDDDDDDDD");
+ concat2.Append("DD");
+
+ std::vector<CordCompareTestCase> test_cases = {{
+ // Inline cords
+ {"abcdef", "abcdef"},
+ {"abcdef", "abcdee"},
+ {"abcdef", "abcdeg"},
+ {"bbcdef", "abcdef"},
+ {"bbcdef", "abcdeg"},
+ {"abcdefa", "abcdef"},
+ {"abcdef", "abcdefa"},
+
+ // Small flat cords
+ {"aaaaaBBBBBcccccDDDDD", "aaaaaBBBBBcccccDDDDD"},
+ {"aaaaaBBBBBcccccDDDDD", "aaaaaBBBBBxccccDDDDD"},
+ {"aaaaaBBBBBcxcccDDDDD", "aaaaaBBBBBcccccDDDDD"},
+ {"aaaaaBBBBBxccccDDDDD", "aaaaaBBBBBcccccDDDDX"},
+ {"aaaaaBBBBBcccccDDDDDa", "aaaaaBBBBBcccccDDDDD"},
+ {"aaaaaBBBBBcccccDDDDD", "aaaaaBBBBBcccccDDDDDa"},
+
+ // Subcords
+ {subcord, subcord},
+ {subcord, "aaBBBBBccc"},
+ {subcord, "aaBBBBBccd"},
+ {subcord, "aaBBBBBccb"},
+ {subcord, "aaBBBBBxcb"},
+ {subcord, "aaBBBBBccca"},
+ {subcord, "aaBBBBBcc"},
+
+ // Concats
+ {concat, concat},
+ {concat,
+ "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBccccccccccccccccDDDDDDDDDDDDDDDD"},
+ {concat,
+ "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBcccccccccccccccxDDDDDDDDDDDDDDDD"},
+ {concat,
+ "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBacccccccccccccccDDDDDDDDDDDDDDDD"},
+ {concat,
+ "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBccccccccccccccccDDDDDDDDDDDDDDD"},
+ {concat,
+ "aaaaaaaaaaaaaaaaBBBBBBBBBBBBBBBBccccccccccccccccDDDDDDDDDDDDDDDDe"},
+
+ {concat, concat2},
+ }};
+
+ for (const auto& tc : test_cases) {
+ VerifyComparison(tc);
+ }
+}
+
+TEST(Cord, CompareAfterAssign) {
+ absl::Cord a("aaaaaa1111111");
+ absl::Cord b("aaaaaa2222222");
+ a = "cccccc";
+ b = "cccccc";
+ EXPECT_EQ(a, b);
+ EXPECT_FALSE(a < b);
+
+ a = "aaaa";
+ b = "bbbbb";
+ a = "";
+ b = "";
+ EXPECT_EQ(a, b);
+ EXPECT_FALSE(a < b);
+}
+
+// Test CompareTo() and ComparePrefix() against string and substring
+// comparison methods from basic_string.
+static void TestCompare(const absl::Cord& c, const absl::Cord& d,
+ RandomEngine* rng) {
+ typedef std::basic_string<uint8_t> ustring;
+ ustring cs(reinterpret_cast<const uint8_t*>(std::string(c).data()), c.size());
+ ustring ds(reinterpret_cast<const uint8_t*>(std::string(d).data()), d.size());
+ // ustring comparison is ideal because we expect Cord comparisons to be
+ // based on unsigned byte comparisons regardless of whether char is signed.
+ int expected = sign(cs.compare(ds));
+ EXPECT_EQ(expected, sign(c.Compare(d))) << c << ", " << d;
+}
+
+TEST(Compare, ComparisonIsUnsigned) {
+ RandomEngine rng(testing::GTEST_FLAG(random_seed));
+ std::uniform_int_distribution<uint32_t> uniform_uint8(0, 255);
+ char x = static_cast<char>(uniform_uint8(rng));
+ TestCompare(
+ absl::Cord(std::string(GetUniformRandomUpTo(&rng, 100), x)),
+ absl::Cord(std::string(GetUniformRandomUpTo(&rng, 100), x ^ 0x80)), &rng);
+}
+
+TEST(Compare, RandomComparisons) {
+ const int kIters = 5000;
+ RandomEngine rng(testing::GTEST_FLAG(random_seed));
+
+ int n = GetUniformRandomUpTo(&rng, 5000);
+ absl::Cord a[] = {MakeExternalCord(n),
+ absl::Cord("ant"),
+ absl::Cord("elephant"),
+ absl::Cord("giraffe"),
+ absl::Cord(std::string(GetUniformRandomUpTo(&rng, 100),
+ GetUniformRandomUpTo(&rng, 100))),
+ absl::Cord(""),
+ absl::Cord("x"),
+ absl::Cord("A"),
+ absl::Cord("B"),
+ absl::Cord("C")};
+ for (int i = 0; i < kIters; i++) {
+ absl::Cord c, d;
+ for (int j = 0; j < (i % 7) + 1; j++) {
+ c.Append(a[GetUniformRandomUpTo(&rng, ABSL_ARRAYSIZE(a))]);
+ d.Append(a[GetUniformRandomUpTo(&rng, ABSL_ARRAYSIZE(a))]);
+ }
+ std::bernoulli_distribution coin_flip(0.5);
+ TestCompare(coin_flip(rng) ? c : absl::Cord(std::string(c)),
+ coin_flip(rng) ? d : absl::Cord(std::string(d)), &rng);
+ }
+}
+
+template <typename T1, typename T2>
+void CompareOperators() {
+ const T1 a("a");
+ const T2 b("b");
+
+ EXPECT_TRUE(a == a);
+ // For pointer type (i.e. `const char*`), operator== compares the address
+ // instead of the string, so `a == const char*("a")` isn't necessarily true.
+ EXPECT_TRUE(std::is_pointer<T1>::value || a == T1("a"));
+ EXPECT_TRUE(std::is_pointer<T2>::value || a == T2("a"));
+ EXPECT_FALSE(a == b);
+
+ EXPECT_TRUE(a != b);
+ EXPECT_FALSE(a != a);
+
+ EXPECT_TRUE(a < b);
+ EXPECT_FALSE(b < a);
+
+ EXPECT_TRUE(b > a);
+ EXPECT_FALSE(a > b);
+
+ EXPECT_TRUE(a >= a);
+ EXPECT_TRUE(b >= a);
+ EXPECT_FALSE(a >= b);
+
+ EXPECT_TRUE(a <= a);
+ EXPECT_TRUE(a <= b);
+ EXPECT_FALSE(b <= a);
+}
+
+TEST(ComparisonOperators, Cord_Cord) {
+ CompareOperators<absl::Cord, absl::Cord>();
+}
+
+TEST(ComparisonOperators, Cord_StringPiece) {
+ CompareOperators<absl::Cord, absl::string_view>();
+}
+
+TEST(ComparisonOperators, StringPiece_Cord) {
+ CompareOperators<absl::string_view, absl::Cord>();
+}
+
+TEST(ComparisonOperators, Cord_string) {
+ CompareOperators<absl::Cord, std::string>();
+}
+
+TEST(ComparisonOperators, string_Cord) {
+ CompareOperators<std::string, absl::Cord>();
+}
+
+TEST(ComparisonOperators, stdstring_Cord) {
+ CompareOperators<std::string, absl::Cord>();
+}
+
+TEST(ComparisonOperators, Cord_stdstring) {
+ CompareOperators<absl::Cord, std::string>();
+}
+
+TEST(ComparisonOperators, charstar_Cord) {
+ CompareOperators<const char*, absl::Cord>();
+}
+
+TEST(ComparisonOperators, Cord_charstar) {
+ CompareOperators<absl::Cord, const char*>();
+}
+
+TEST(ConstructFromExternal, ReleaserInvoked) {
+ // Empty external memory means the releaser should be called immediately.
+ {
+ bool invoked = false;
+ auto releaser = [&invoked](absl::string_view) { invoked = true; };
+ {
+ auto c = absl::MakeCordFromExternal("", releaser);
+ EXPECT_TRUE(invoked);
+ }
+ }
+
+ // If the size of the data is small enough, a future constructor
+ // implementation may copy the bytes and immediately invoke the releaser
+ // instead of creating an external node. We make a large dummy std::string to
+ // make this test independent of such an optimization.
+ std::string large_dummy(2048, 'c');
+ {
+ bool invoked = false;
+ auto releaser = [&invoked](absl::string_view) { invoked = true; };
+ {
+ auto c = absl::MakeCordFromExternal(large_dummy, releaser);
+ EXPECT_FALSE(invoked);
+ }
+ EXPECT_TRUE(invoked);
+ }
+
+ {
+ bool invoked = false;
+ auto releaser = [&invoked](absl::string_view) { invoked = true; };
+ {
+ absl::Cord copy;
+ {
+ auto c = absl::MakeCordFromExternal(large_dummy, releaser);
+ copy = c;
+ EXPECT_FALSE(invoked);
+ }
+ EXPECT_FALSE(invoked);
+ }
+ EXPECT_TRUE(invoked);
+ }
+}
+
+TEST(ConstructFromExternal, CompareContents) {
+ RandomEngine rng(testing::GTEST_FLAG(random_seed));
+
+ for (int length = 1; length <= 2048; length *= 2) {
+ std::string data = RandomLowercaseString(&rng, length);
+ auto* external = new std::string(data);
+ auto cord =
+ absl::MakeCordFromExternal(*external, [external](absl::string_view sv) {
+ EXPECT_EQ(external->data(), sv.data());
+ EXPECT_EQ(external->size(), sv.size());
+ delete external;
+ });
+ EXPECT_EQ(data, cord);
+ }
+}
+
+TEST(ConstructFromExternal, LargeReleaser) {
+ RandomEngine rng(testing::GTEST_FLAG(random_seed));
+ constexpr size_t kLength = 256;
+ std::string data = RandomLowercaseString(&rng, kLength);
+ std::array<char, kLength> data_array;
+ for (size_t i = 0; i < kLength; ++i) data_array[i] = data[i];
+ bool invoked = false;
+ auto releaser = [data_array, &invoked](absl::string_view data) {
+ EXPECT_EQ(data, absl::string_view(data_array.data(), data_array.size()));
+ invoked = true;
+ };
+ (void)absl::MakeCordFromExternal(data, releaser);
+ EXPECT_TRUE(invoked);
+}
+
+TEST(ConstructFromExternal, FunctionPointerReleaser) {
+ static absl::string_view data("hello world");
+ static bool invoked;
+ auto* releaser =
+ static_cast<void (*)(absl::string_view)>([](absl::string_view sv) {
+ EXPECT_EQ(data, sv);
+ invoked = true;
+ });
+ invoked = false;
+ (void)absl::MakeCordFromExternal(data, releaser);
+ EXPECT_TRUE(invoked);
+
+ invoked = false;
+ (void)absl::MakeCordFromExternal(data, *releaser);
+ EXPECT_TRUE(invoked);
+}
+
+TEST(ConstructFromExternal, MoveOnlyReleaser) {
+ struct Releaser {
+ explicit Releaser(bool* invoked) : invoked(invoked) {}
+ Releaser(Releaser&& other) noexcept : invoked(other.invoked) {}
+ void operator()(absl::string_view) const { *invoked = true; }
+
+ bool* invoked;
+ };
+
+ bool invoked = false;
+ (void)absl::MakeCordFromExternal("dummy", Releaser(&invoked));
+ EXPECT_TRUE(invoked);
+}
+
+TEST(ConstructFromExternal, NoArgLambda) {
+ bool invoked = false;
+ (void)absl::MakeCordFromExternal("dummy", [&invoked]() { invoked = true; });
+ EXPECT_TRUE(invoked);
+}
+
+TEST(ConstructFromExternal, StringViewArgLambda) {
+ bool invoked = false;
+ (void)absl::MakeCordFromExternal(
+ "dummy", [&invoked](absl::string_view) { invoked = true; });
+ EXPECT_TRUE(invoked);
+}
+
+TEST(ConstructFromExternal, NonTrivialReleaserDestructor) {
+ struct Releaser {
+ explicit Releaser(bool* destroyed) : destroyed(destroyed) {}
+ ~Releaser() { *destroyed = true; }
+ void operator()(absl::string_view) const {}
+
+ bool* destroyed;
+ };
+
+ bool destroyed = false;
+ Releaser releaser(&destroyed);
+ (void)absl::MakeCordFromExternal("dummy", releaser);
+ EXPECT_TRUE(destroyed);
+}
+
+TEST(ConstructFromExternal, ReferenceQualifierOverloads) {
+ struct Releaser {
+ void operator()(absl::string_view) & { *lvalue_invoked = true; }
+ void operator()(absl::string_view) && { *rvalue_invoked = true; }
+
+ bool* lvalue_invoked;
+ bool* rvalue_invoked;
+ };
+
+ bool lvalue_invoked = false;
+ bool rvalue_invoked = false;
+ Releaser releaser = {&lvalue_invoked, &rvalue_invoked};
+ (void)absl::MakeCordFromExternal("", releaser);
+ EXPECT_FALSE(lvalue_invoked);
+ EXPECT_TRUE(rvalue_invoked);
+ rvalue_invoked = false;
+
+ (void)absl::MakeCordFromExternal("dummy", releaser);
+ EXPECT_FALSE(lvalue_invoked);
+ EXPECT_TRUE(rvalue_invoked);
+ rvalue_invoked = false;
+
+ // NOLINTNEXTLINE: suppress clang-tidy std::move on trivially copyable type.
+ (void)absl::MakeCordFromExternal("dummy", std::move(releaser));
+ EXPECT_FALSE(lvalue_invoked);
+ EXPECT_TRUE(rvalue_invoked);
+}
+
+TEST(ExternalMemory, BasicUsage) {
+ static const char* strings[] = {"", "hello", "there"};
+ for (const char* str : strings) {
+ absl::Cord dst("(prefix)");
+ AddExternalMemory(str, &dst);
+ dst.Append("(suffix)");
+ EXPECT_EQ((std::string("(prefix)") + str + std::string("(suffix)")),
+ std::string(dst));
+ }
+}
+
+TEST(ExternalMemory, RemovePrefixSuffix) {
+ // Exhaustively try all sub-strings.
+ absl::Cord cord = MakeComposite();
+ std::string s = std::string(cord);
+ for (int offset = 0; offset <= s.size(); offset++) {
+ for (int length = 0; length <= s.size() - offset; length++) {
+ absl::Cord result(cord);
+ result.RemovePrefix(offset);
+ result.RemoveSuffix(result.size() - length);
+ EXPECT_EQ(s.substr(offset, length), std::string(result))
+ << offset << " " << length;
+ }
+ }
+}
+
+TEST(ExternalMemory, Get) {
+ absl::Cord cord("hello");
+ AddExternalMemory(" world!", &cord);
+ AddExternalMemory(" how are ", &cord);
+ cord.Append(" you?");
+ std::string s = std::string(cord);
+ for (int i = 0; i < s.size(); i++) {
+ EXPECT_EQ(s[i], cord[i]);
+ }
+}
+
+// CordMemoryUsage tests verify the correctness of the EstimatedMemoryUsage()
+// These tests take into account that the reported memory usage is approximate
+// and non-deterministic. For all tests, We verify that the reported memory
+// usage is larger than `size()`, and less than `size() * 1.5` as a cord should
+// never reserve more 'extra' capacity than half of its size as it grows.
+// Additionally we have some whiteboxed expectations based on our knowledge of
+// the layout and size of empty and inlined cords, and flat nodes.
+
+TEST(CordMemoryUsage, Empty) {
+ EXPECT_EQ(sizeof(absl::Cord), absl::Cord().EstimatedMemoryUsage());
+}
+
+TEST(CordMemoryUsage, Embedded) {
+ absl::Cord a("hello");
+ EXPECT_EQ(a.EstimatedMemoryUsage(), sizeof(absl::Cord));
+}
+
+TEST(CordMemoryUsage, EmbeddedAppend) {
+ absl::Cord a("a");
+ absl::Cord b("bcd");
+ EXPECT_EQ(b.EstimatedMemoryUsage(), sizeof(absl::Cord));
+ a.Append(b);
+ EXPECT_EQ(a.EstimatedMemoryUsage(), sizeof(absl::Cord));
+}
+
+TEST(CordMemoryUsage, ExternalMemory) {
+ static const int kLength = 1000;
+ absl::Cord cord;
+ AddExternalMemory(std::string(kLength, 'x'), &cord);
+ EXPECT_GT(cord.EstimatedMemoryUsage(), kLength);
+ EXPECT_LE(cord.EstimatedMemoryUsage(), kLength * 1.5);
+}
+
+TEST(CordMemoryUsage, Flat) {
+ static const int kLength = 125;
+ absl::Cord a(std::string(kLength, 'a'));
+ EXPECT_GT(a.EstimatedMemoryUsage(), kLength);
+ EXPECT_LE(a.EstimatedMemoryUsage(), kLength * 1.5);
+}
+
+TEST(CordMemoryUsage, AppendFlat) {
+ using absl::strings_internal::CordTestAccess;
+ absl::Cord a(std::string(CordTestAccess::MaxFlatLength(), 'a'));
+ size_t length = a.EstimatedMemoryUsage();
+ a.Append(std::string(CordTestAccess::MaxFlatLength(), 'b'));
+ size_t delta = a.EstimatedMemoryUsage() - length;
+ EXPECT_GT(delta, CordTestAccess::MaxFlatLength());
+ EXPECT_LE(delta, CordTestAccess::MaxFlatLength() * 1.5);
+}
+
+// Regtest for a change that had to be rolled back because it expanded out
+// of the InlineRep too soon, which was observable through MemoryUsage().
+TEST(CordMemoryUsage, InlineRep) {
+ constexpr size_t kMaxInline = 15; // Cord::InlineRep::N
+ const std::string small_string(kMaxInline, 'x');
+ absl::Cord c1(small_string);
+
+ absl::Cord c2;
+ c2.Append(small_string);
+ EXPECT_EQ(c1, c2);
+ EXPECT_EQ(c1.EstimatedMemoryUsage(), c2.EstimatedMemoryUsage());
+}
+
+} // namespace
+
+// Regtest for 7510292 (fix a bug introduced by 7465150)
+TEST(Cord, Concat_Append) {
+ // Create a rep of type CONCAT
+ absl::Cord s1("foobarbarbarbarbar");
+ s1.Append("abcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefg");
+ size_t size = s1.size();
+
+ // Create a copy of s1 and append to it.
+ absl::Cord s2 = s1;
+ s2.Append("x");
+
+ // 7465150 modifies s1 when it shouldn't.
+ EXPECT_EQ(s1.size(), size);
+ EXPECT_EQ(s2.size(), size + 1);
+}
+
+TEST(MakeFragmentedCord, MakeFragmentedCordFromInitializerList) {
+ absl::Cord fragmented =
+ absl::MakeFragmentedCord({"A ", "fragmented ", "Cord"});
+
+ EXPECT_EQ("A fragmented Cord", fragmented);
+
+ auto chunk_it = fragmented.chunk_begin();
+
+ ASSERT_TRUE(chunk_it != fragmented.chunk_end());
+ EXPECT_EQ("A ", *chunk_it);
+
+ ASSERT_TRUE(++chunk_it != fragmented.chunk_end());
+ EXPECT_EQ("fragmented ", *chunk_it);
+
+ ASSERT_TRUE(++chunk_it != fragmented.chunk_end());
+ EXPECT_EQ("Cord", *chunk_it);
+
+ ASSERT_TRUE(++chunk_it == fragmented.chunk_end());
+}
+
+TEST(MakeFragmentedCord, MakeFragmentedCordFromVector) {
+ std::vector<absl::string_view> chunks = {"A ", "fragmented ", "Cord"};
+ absl::Cord fragmented = absl::MakeFragmentedCord(chunks);
+
+ EXPECT_EQ("A fragmented Cord", fragmented);
+
+ auto chunk_it = fragmented.chunk_begin();
+
+ ASSERT_TRUE(chunk_it != fragmented.chunk_end());
+ EXPECT_EQ("A ", *chunk_it);
+
+ ASSERT_TRUE(++chunk_it != fragmented.chunk_end());
+ EXPECT_EQ("fragmented ", *chunk_it);
+
+ ASSERT_TRUE(++chunk_it != fragmented.chunk_end());
+ EXPECT_EQ("Cord", *chunk_it);
+
+ ASSERT_TRUE(++chunk_it == fragmented.chunk_end());
+}
+
+TEST(CordChunkIterator, Traits) {
+ static_assert(std::is_copy_constructible<absl::Cord::ChunkIterator>::value,
+ "");
+ static_assert(std::is_copy_assignable<absl::Cord::ChunkIterator>::value, "");
+
+ // Move semantics to satisfy swappable via std::swap
+ static_assert(std::is_move_constructible<absl::Cord::ChunkIterator>::value,
+ "");
+ static_assert(std::is_move_assignable<absl::Cord::ChunkIterator>::value, "");
+
+ static_assert(
+ std::is_same<
+ std::iterator_traits<absl::Cord::ChunkIterator>::iterator_category,
+ std::input_iterator_tag>::value,
+ "");
+ static_assert(
+ std::is_same<std::iterator_traits<absl::Cord::ChunkIterator>::value_type,
+ absl::string_view>::value,
+ "");
+ static_assert(
+ std::is_same<
+ std::iterator_traits<absl::Cord::ChunkIterator>::difference_type,
+ ptrdiff_t>::value,
+ "");
+ static_assert(
+ std::is_same<std::iterator_traits<absl::Cord::ChunkIterator>::pointer,
+ const absl::string_view*>::value,
+ "");
+ static_assert(
+ std::is_same<std::iterator_traits<absl::Cord::ChunkIterator>::reference,
+ absl::string_view>::value,
+ "");
+}
+
+static void VerifyChunkIterator(const absl::Cord& cord,
+ size_t expected_chunks) {
+ EXPECT_EQ(cord.chunk_begin() == cord.chunk_end(), cord.empty()) << cord;
+ EXPECT_EQ(cord.chunk_begin() != cord.chunk_end(), !cord.empty());
+
+ absl::Cord::ChunkRange range = cord.Chunks();
+ EXPECT_EQ(range.begin() == range.end(), cord.empty());
+ EXPECT_EQ(range.begin() != range.end(), !cord.empty());
+
+ std::string content(cord);
+ size_t pos = 0;
+ auto pre_iter = cord.chunk_begin(), post_iter = cord.chunk_begin();
+ size_t n_chunks = 0;
+ while (pre_iter != cord.chunk_end() && post_iter != cord.chunk_end()) {
+ EXPECT_FALSE(pre_iter == cord.chunk_end()); // NOLINT: explicitly test ==
+ EXPECT_FALSE(post_iter == cord.chunk_end()); // NOLINT
+
+ EXPECT_EQ(pre_iter, post_iter);
+ EXPECT_EQ(*pre_iter, *post_iter);
+
+ EXPECT_EQ(pre_iter->data(), (*pre_iter).data());
+ EXPECT_EQ(pre_iter->size(), (*pre_iter).size());
+
+ absl::string_view chunk = *pre_iter;
+ EXPECT_FALSE(chunk.empty());
+ EXPECT_LE(pos + chunk.size(), content.size());
+ EXPECT_EQ(absl::string_view(content.c_str() + pos, chunk.size()), chunk);
+
+ int n_equal_iterators = 0;
+ for (absl::Cord::ChunkIterator it = range.begin(); it != range.end();
+ ++it) {
+ n_equal_iterators += static_cast<int>(it == pre_iter);
+ }
+ EXPECT_EQ(n_equal_iterators, 1);
+
+ ++pre_iter;
+ EXPECT_EQ(*post_iter++, chunk);
+
+ pos += chunk.size();
+ ++n_chunks;
+ }
+ EXPECT_EQ(expected_chunks, n_chunks);
+ EXPECT_EQ(pos, content.size());
+ EXPECT_TRUE(pre_iter == cord.chunk_end()); // NOLINT: explicitly test ==
+ EXPECT_TRUE(post_iter == cord.chunk_end()); // NOLINT
+}
+
+TEST(CordChunkIterator, Operations) {
+ absl::Cord empty_cord;
+ VerifyChunkIterator(empty_cord, 0);
+
+ absl::Cord small_buffer_cord("small cord");
+ VerifyChunkIterator(small_buffer_cord, 1);
+
+ absl::Cord flat_node_cord("larger than small buffer optimization");
+ VerifyChunkIterator(flat_node_cord, 1);
+
+ VerifyChunkIterator(
+ absl::MakeFragmentedCord({"a ", "small ", "fragmented ", "cord ", "for ",
+ "testing ", "chunk ", "iterations."}),
+ 8);
+
+ absl::Cord reused_nodes_cord(std::string(40, 'c'));
+ reused_nodes_cord.Prepend(absl::Cord(std::string(40, 'b')));
+ reused_nodes_cord.Prepend(absl::Cord(std::string(40, 'a')));
+ size_t expected_chunks = 3;
+ for (int i = 0; i < 8; ++i) {
+ reused_nodes_cord.Prepend(reused_nodes_cord);
+ expected_chunks *= 2;
+ VerifyChunkIterator(reused_nodes_cord, expected_chunks);
+ }
+
+ RandomEngine rng(testing::GTEST_FLAG(random_seed));
+ absl::Cord flat_cord(RandomLowercaseString(&rng, 256));
+ absl::Cord subcords;
+ for (int i = 0; i < 128; ++i) subcords.Prepend(flat_cord.Subcord(i, 128));
+ VerifyChunkIterator(subcords, 128);
+}
+
+TEST(CordCharIterator, Traits) {
+ static_assert(std::is_copy_constructible<absl::Cord::CharIterator>::value,
+ "");
+ static_assert(std::is_copy_assignable<absl::Cord::CharIterator>::value, "");
+
+ // Move semantics to satisfy swappable via std::swap
+ static_assert(std::is_move_constructible<absl::Cord::CharIterator>::value,
+ "");
+ static_assert(std::is_move_assignable<absl::Cord::CharIterator>::value, "");
+
+ static_assert(
+ std::is_same<
+ std::iterator_traits<absl::Cord::CharIterator>::iterator_category,
+ std::input_iterator_tag>::value,
+ "");
+ static_assert(
+ std::is_same<std::iterator_traits<absl::Cord::CharIterator>::value_type,
+ char>::value,
+ "");
+ static_assert(
+ std::is_same<
+ std::iterator_traits<absl::Cord::CharIterator>::difference_type,
+ ptrdiff_t>::value,
+ "");
+ static_assert(
+ std::is_same<std::iterator_traits<absl::Cord::CharIterator>::pointer,
+ const char*>::value,
+ "");
+ static_assert(
+ std::is_same<std::iterator_traits<absl::Cord::CharIterator>::reference,
+ const char&>::value,
+ "");
+}
+
+static void VerifyCharIterator(const absl::Cord& cord) {
+ EXPECT_EQ(cord.char_begin() == cord.char_end(), cord.empty());
+ EXPECT_EQ(cord.char_begin() != cord.char_end(), !cord.empty());
+
+ absl::Cord::CharRange range = cord.Chars();
+ EXPECT_EQ(range.begin() == range.end(), cord.empty());
+ EXPECT_EQ(range.begin() != range.end(), !cord.empty());
+
+ size_t i = 0;
+ absl::Cord::CharIterator pre_iter = cord.char_begin();
+ absl::Cord::CharIterator post_iter = cord.char_begin();
+ std::string content(cord);
+ while (pre_iter != cord.char_end() && post_iter != cord.char_end()) {
+ EXPECT_FALSE(pre_iter == cord.char_end()); // NOLINT: explicitly test ==
+ EXPECT_FALSE(post_iter == cord.char_end()); // NOLINT
+
+ EXPECT_LT(i, cord.size());
+ EXPECT_EQ(content[i], *pre_iter);
+
+ EXPECT_EQ(pre_iter, post_iter);
+ EXPECT_EQ(*pre_iter, *post_iter);
+ EXPECT_EQ(&*pre_iter, &*post_iter);
+
+ EXPECT_EQ(&*pre_iter, pre_iter.operator->());
+
+ const char* character_address = &*pre_iter;
+ absl::Cord::CharIterator copy = pre_iter;
+ ++copy;
+ EXPECT_EQ(character_address, &*pre_iter);
+
+ int n_equal_iterators = 0;
+ for (absl::Cord::CharIterator it = range.begin(); it != range.end(); ++it) {
+ n_equal_iterators += static_cast<int>(it == pre_iter);
+ }
+ EXPECT_EQ(n_equal_iterators, 1);
+
+ absl::Cord::CharIterator advance_iter = range.begin();
+ absl::Cord::Advance(&advance_iter, i);
+ EXPECT_EQ(pre_iter, advance_iter);
+
+ advance_iter = range.begin();
+ EXPECT_EQ(absl::Cord::AdvanceAndRead(&advance_iter, i), cord.Subcord(0, i));
+ EXPECT_EQ(pre_iter, advance_iter);
+
+ advance_iter = pre_iter;
+ absl::Cord::Advance(&advance_iter, cord.size() - i);
+ EXPECT_EQ(range.end(), advance_iter);
+
+ advance_iter = pre_iter;
+ EXPECT_EQ(absl::Cord::AdvanceAndRead(&advance_iter, cord.size() - i),
+ cord.Subcord(i, cord.size() - i));
+ EXPECT_EQ(range.end(), advance_iter);
+
+ ++i;
+ ++pre_iter;
+ post_iter++;
+ }
+ EXPECT_EQ(i, cord.size());
+ EXPECT_TRUE(pre_iter == cord.char_end()); // NOLINT: explicitly test ==
+ EXPECT_TRUE(post_iter == cord.char_end()); // NOLINT
+
+ absl::Cord::CharIterator zero_advanced_end = cord.char_end();
+ absl::Cord::Advance(&zero_advanced_end, 0);
+ EXPECT_EQ(zero_advanced_end, cord.char_end());
+
+ absl::Cord::CharIterator it = cord.char_begin();
+ for (absl::string_view chunk : cord.Chunks()) {
+ while (!chunk.empty()) {
+ EXPECT_EQ(absl::Cord::ChunkRemaining(it), chunk);
+ chunk.remove_prefix(1);
+ ++it;
+ }
+ }
+}
+
+TEST(CordCharIterator, Operations) {
+ absl::Cord empty_cord;
+ VerifyCharIterator(empty_cord);
+
+ absl::Cord small_buffer_cord("small cord");
+ VerifyCharIterator(small_buffer_cord);
+
+ absl::Cord flat_node_cord("larger than small buffer optimization");
+ VerifyCharIterator(flat_node_cord);
+
+ VerifyCharIterator(
+ absl::MakeFragmentedCord({"a ", "small ", "fragmented ", "cord ", "for ",
+ "testing ", "character ", "iteration."}));
+
+ absl::Cord reused_nodes_cord("ghi");
+ reused_nodes_cord.Prepend(absl::Cord("def"));
+ reused_nodes_cord.Prepend(absl::Cord("abc"));
+ for (int i = 0; i < 4; ++i) {
+ reused_nodes_cord.Prepend(reused_nodes_cord);
+ VerifyCharIterator(reused_nodes_cord);
+ }
+
+ RandomEngine rng(testing::GTEST_FLAG(random_seed));
+ absl::Cord flat_cord(RandomLowercaseString(&rng, 256));
+ absl::Cord subcords;
+ for (int i = 0; i < 4; ++i) subcords.Prepend(flat_cord.Subcord(16 * i, 128));
+ VerifyCharIterator(subcords);
+}
+
+TEST(Cord, StreamingOutput) {
+ absl::Cord c =
+ absl::MakeFragmentedCord({"A ", "small ", "fragmented ", "Cord", "."});
+ std::stringstream output;
+ output << c;
+ EXPECT_EQ("A small fragmented Cord.", output.str());
+}
+
+TEST(Cord, ForEachChunk) {
+ for (int num_elements : {1, 10, 200}) {
+ SCOPED_TRACE(num_elements);
+ std::vector<std::string> cord_chunks;
+ for (int i = 0; i < num_elements; ++i) {
+ cord_chunks.push_back(absl::StrCat("[", i, "]"));
+ }
+ absl::Cord c = absl::MakeFragmentedCord(cord_chunks);
+
+ std::vector<std::string> iterated_chunks;
+ absl::CordTestPeer::ForEachChunk(c,
+ [&iterated_chunks](absl::string_view sv) {
+ iterated_chunks.emplace_back(sv);
+ });
+ EXPECT_EQ(iterated_chunks, cord_chunks);
+ }
+}
+
+TEST(Cord, SmallBufferAssignFromOwnData) {
+ constexpr size_t kMaxInline = 15;
+ std::string contents = "small buff cord";
+ EXPECT_EQ(contents.size(), kMaxInline);
+ for (size_t pos = 0; pos < contents.size(); ++pos) {
+ for (size_t count = contents.size() - pos; count > 0; --count) {
+ absl::Cord c(contents);
+ absl::string_view flat = c.Flatten();
+ c = flat.substr(pos, count);
+ EXPECT_EQ(c, contents.substr(pos, count))
+ << "pos = " << pos << "; count = " << count;
+ }
+ }
+}
+
+TEST(Cord, Format) {
+ absl::Cord c;
+ absl::Format(&c, "There were %04d little %s.", 3, "pigs");
+ EXPECT_EQ(c, "There were 0003 little pigs.");
+ absl::Format(&c, "And %-3llx bad wolf!", 1);
+ EXPECT_EQ(c, "There were 0003 little pigs.And 1 bad wolf!");
+}
+
+TEST(CordDeathTest, Hardening) {
+ absl::Cord cord("hello");
+ // These statement should abort the program in all builds modes.
+ EXPECT_DEATH_IF_SUPPORTED(cord.RemovePrefix(6), "");
+ EXPECT_DEATH_IF_SUPPORTED(cord.RemoveSuffix(6), "");
+
+ bool test_hardening = false;
+ ABSL_HARDENING_ASSERT([&]() {
+ // This only runs when ABSL_HARDENING_ASSERT is active.
+ test_hardening = true;
+ return true;
+ }());
+ if (!test_hardening) return;
+
+ EXPECT_DEATH_IF_SUPPORTED(cord[5], "");
+ EXPECT_DEATH_IF_SUPPORTED(*cord.chunk_end(), "");
+ EXPECT_DEATH_IF_SUPPORTED(static_cast<void>(cord.chunk_end()->empty()), "");
+ EXPECT_DEATH_IF_SUPPORTED(++cord.chunk_end(), "");
+}
+
+class AfterExitCordTester {
+ public:
+ bool Set(absl::Cord* cord, absl::string_view expected) {
+ cord_ = cord;
+ expected_ = expected;
+ return true;
+ }
+
+ ~AfterExitCordTester() {
+ EXPECT_EQ(*cord_, expected_);
+ }
+ private:
+ absl::Cord* cord_;
+ absl::string_view expected_;
+};
+
+template <typename Str>
+void TestConstinitConstructor(Str) {
+ const auto expected = Str::value;
+ // Defined before `cord` to be destroyed after it.
+ static AfterExitCordTester exit_tester; // NOLINT
+ ABSL_CONST_INIT static absl::Cord cord(Str{}); // NOLINT
+ static bool init_exit_tester = exit_tester.Set(&cord, expected);
+ (void)init_exit_tester;
+
+ EXPECT_EQ(cord, expected);
+ // Copy the object and test the copy, and the original.
+ {
+ absl::Cord copy = cord;
+ EXPECT_EQ(copy, expected);
+ }
+ // The original still works
+ EXPECT_EQ(cord, expected);
+
+ // Try making adding more structure to the tree.
+ {
+ absl::Cord copy = cord;
+ std::string expected_copy(expected);
+ for (int i = 0; i < 10; ++i) {
+ copy.Append(cord);
+ absl::StrAppend(&expected_copy, expected);
+ EXPECT_EQ(copy, expected_copy);
+ }
+ }
+
+ // Make sure we are using the right branch during constant evaluation.
+ EXPECT_EQ(absl::CordTestPeer::IsTree(cord), cord.size() >= 16);
+
+ for (int i = 0; i < 10; ++i) {
+ // Make a few more Cords from the same global rep.
+ // This tests what happens when the refcount for it gets below 1.
+ EXPECT_EQ(expected, absl::Cord(Str{}));
+ }
+}
+
+constexpr int SimpleStrlen(const char* p) {
+ return *p ? 1 + SimpleStrlen(p + 1) : 0;
+}
+
+struct ShortView {
+ constexpr absl::string_view operator()() const {
+ return absl::string_view("SSO string", SimpleStrlen("SSO string"));
+ }
+};
+
+struct LongView {
+ constexpr absl::string_view operator()() const {
+ return absl::string_view("String that does not fit SSO.",
+ SimpleStrlen("String that does not fit SSO."));
+ }
+};
+
+
+TEST(Cord, ConstinitConstructor) {
+ TestConstinitConstructor(
+ absl::strings_internal::MakeStringConstant(ShortView{}));
+ TestConstinitConstructor(
+ absl::strings_internal::MakeStringConstant(LongView{}));
+}
diff --git a/third_party/abseil/absl/strings/cord_test_helpers.h b/third_party/abseil/absl/strings/cord_test_helpers.h
new file mode 100644
index 0000000..f1036e3
--- /dev/null
+++ b/third_party/abseil/absl/strings/cord_test_helpers.h
@@ -0,0 +1,60 @@
+//
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef ABSL_STRINGS_CORD_TEST_HELPERS_H_
+#define ABSL_STRINGS_CORD_TEST_HELPERS_H_
+
+#include "absl/strings/cord.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// Creates a multi-segment Cord from an iterable container of strings. The
+// resulting Cord is guaranteed to have one segment for every string in the
+// container. This allows code to be unit tested with multi-segment Cord
+// inputs.
+//
+// Example:
+//
+// absl::Cord c = absl::MakeFragmentedCord({"A ", "fragmented ", "Cord"});
+// EXPECT_FALSE(c.GetFlat(&unused));
+//
+// The mechanism by which this Cord is created is an implementation detail. Any
+// implementation that produces a multi-segment Cord may produce a flat Cord in
+// the future as new optimizations are added to the Cord class.
+// MakeFragmentedCord will, however, always be updated to return a multi-segment
+// Cord.
+template <typename Container>
+Cord MakeFragmentedCord(const Container& c) {
+ Cord result;
+ for (const auto& s : c) {
+ auto* external = new std::string(s);
+ Cord tmp = absl::MakeCordFromExternal(
+ *external, [external](absl::string_view) { delete external; });
+ tmp.Prepend(result);
+ result = tmp;
+ }
+ return result;
+}
+
+inline Cord MakeFragmentedCord(std::initializer_list<absl::string_view> list) {
+ return MakeFragmentedCord<std::initializer_list<absl::string_view>>(list);
+}
+
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_STRINGS_CORD_TEST_HELPERS_H_
diff --git a/third_party/abseil/absl/strings/escaping.cc b/third_party/abseil/absl/strings/escaping.cc
index 0d336e3..18b20b8 100644
--- a/third_party/abseil/absl/strings/escaping.cc
+++ b/third_party/abseil/absl/strings/escaping.cc
@@ -26,6 +26,7 @@
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/unaligned_access.h"
#include "absl/strings/internal/char_map.h"
+#include "absl/strings/internal/escaping.h"
#include "absl/strings/internal/resize_uninitialized.h"
#include "absl/strings/internal/utf8.h"
#include "absl/strings/str_cat.h"
@@ -33,29 +34,9 @@
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
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;
@@ -156,7 +137,7 @@
// Copy the escape sequence for the null character
const ptrdiff_t octal_size = p + 1 - octal_start;
*d++ = '\\';
- memcpy(d, octal_start, octal_size);
+ memmove(d, octal_start, octal_size);
d += octal_size;
break;
}
@@ -189,7 +170,7 @@
// Copy the escape sequence for the null character
const ptrdiff_t hex_size = p + 1 - hex_start;
*d++ = '\\';
- memcpy(d, hex_start, hex_size);
+ memmove(d, hex_start, hex_size);
d += hex_size;
break;
}
@@ -222,7 +203,7 @@
if ((rune == 0) && leave_nulls_escaped) {
// Copy the escape sequence for the null character
*d++ = '\\';
- memcpy(d, hex_start, 5); // u0000
+ memmove(d, hex_start, 5); // u0000
d += 5;
break;
}
@@ -270,7 +251,7 @@
if ((rune == 0) && leave_nulls_escaped) {
// Copy the escape sequence for the null character
*d++ = '\\';
- memcpy(d, hex_start, 9); // U00000000
+ memmove(d, hex_start, 9); // U00000000
d += 9;
break;
}
@@ -348,14 +329,14 @@
(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]);
+ dest.push_back(numbers_internal::kHexChar[c / 16]);
+ dest.push_back(numbers_internal::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]);
+ dest.push_back(numbers_internal::kHexChar[c / 64]);
+ dest.push_back(numbers_internal::kHexChar[(c % 64) / 8]);
+ dest.push_back(numbers_internal::kHexChar[c % 8]);
}
} else {
dest.push_back(c);
@@ -469,7 +450,7 @@
// 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
+ // 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.
@@ -492,18 +473,18 @@
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
+ // data left in the 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
+ // bytes of the 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).
+ // never read past a null in the string (no matter how long
+ // szsrc claims the string is).
if (!src[0] || !src[1] || !src[2] ||
((temp = ((unsigned(unbase64[src[0]]) << 18) |
@@ -528,7 +509,7 @@
temp = (temp << 6) | decode;
} else {
// We really did have four good data bytes, so advance four
- // characters in the std::string.
+ // characters in the string.
szsrc -= 4;
src += 4;
@@ -663,7 +644,7 @@
state);
}
- // The remainder of the std::string should be all whitespace, mixed with
+ // The remainder of the 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.)
@@ -784,180 +765,13 @@
};
/* 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 https://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 https://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 https://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 https://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) { // While 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-_";
template <typename String>
-void Base64EscapeInternal(const unsigned char* src, size_t szsrc, 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);
-}
-
-template <typename String>
bool Base64UnescapeInternal(const char* src, size_t slen, String* dest,
const signed char* unbase64) {
- // Determine the size of the output std::string. Base64 encodes every 3 bytes into
+ // Determine the size of the output 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);
@@ -965,7 +779,7 @@
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 *.
+ // string and converting it into a char *.
size_t len;
const bool ok =
Base64UnescapeInternal(src, slen, &(*dest)[0], dest_len, unbase64, &len);
@@ -982,7 +796,7 @@
}
/* clang-format off */
-constexpr char kHexValue[256] = {
+constexpr char kHexValueLenient[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,
@@ -998,8 +812,9 @@
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*
@@ -1008,8 +823,8 @@
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]);
+ to[i] = (kHexValueLenient[from[i * 2] & 0xFF] << 4) +
+ (kHexValueLenient[from[i * 2 + 1] & 0xFF]);
}
}
@@ -1019,7 +834,7 @@
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];
+ const char* hex_p = &numbers_internal::kHexTable[*src_ptr * 2];
std::copy(hex_p, hex_p + 2, dest_ptr);
}
}
@@ -1087,26 +902,30 @@
}
void Base64Escape(absl::string_view src, std::string* dest) {
- Base64EscapeInternal(reinterpret_cast<const unsigned char*>(src.data()),
- src.size(), dest, true, kBase64Chars);
+ strings_internal::Base64EscapeInternal(
+ reinterpret_cast<const unsigned char*>(src.data()), src.size(), dest,
+ true, strings_internal::kBase64Chars);
}
void WebSafeBase64Escape(absl::string_view src, std::string* dest) {
- Base64EscapeInternal(reinterpret_cast<const unsigned char*>(src.data()),
- src.size(), dest, false, kWebSafeBase64Chars);
+ strings_internal::Base64EscapeInternal(
+ reinterpret_cast<const unsigned char*>(src.data()), src.size(), dest,
+ false, kWebSafeBase64Chars);
}
std::string Base64Escape(absl::string_view src) {
std::string dest;
- Base64EscapeInternal(reinterpret_cast<const unsigned char*>(src.data()),
- src.size(), &dest, true, kBase64Chars);
+ strings_internal::Base64EscapeInternal(
+ reinterpret_cast<const unsigned char*>(src.data()), src.size(), &dest,
+ true, strings_internal::kBase64Chars);
return dest;
}
std::string WebSafeBase64Escape(absl::string_view src) {
std::string dest;
- Base64EscapeInternal(reinterpret_cast<const unsigned char*>(src.data()),
- src.size(), &dest, false, kWebSafeBase64Chars);
+ strings_internal::Base64EscapeInternal(
+ reinterpret_cast<const unsigned char*>(src.data()), src.size(), &dest,
+ false, kWebSafeBase64Chars);
return dest;
}
@@ -1126,4 +945,5 @@
return result;
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/escaping.h b/third_party/abseil/absl/strings/escaping.h
index 198b934..f5ca26c 100644
--- a/third_party/abseil/absl/strings/escaping.h
+++ b/third_party/abseil/absl/strings/escaping.h
@@ -33,6 +33,7 @@
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// CUnescape()
//
@@ -157,6 +158,7 @@
// `2*from.size()`.
std::string BytesToHexString(absl::string_view from);
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_ESCAPING_H_
diff --git a/third_party/abseil/absl/strings/escaping_test.cc b/third_party/abseil/absl/strings/escaping_test.cc
index 1967975..45671a0 100644
--- a/third_party/abseil/absl/strings/escaping_test.cc
+++ b/third_party/abseil/absl/strings/escaping_test.cc
@@ -300,7 +300,7 @@
absl::string_view plaintext;
absl::string_view cyphertext;
} const base64_tests[] = {
- // Empty std::string.
+ // Empty string.
{{"", 0}, {"", 0}},
{{nullptr, 0},
{"", 0}}, // if length is zero, plaintext ptr must be ignored!
@@ -586,7 +586,7 @@
EXPECT_EQ(encoded, websafe);
EXPECT_EQ(absl::WebSafeBase64Escape(tc.plaintext), websafe);
- // Let's try the std::string version of the decoder
+ // Let's try the string version of the decoder
decoded = "this junk should be ignored";
EXPECT_TRUE(absl::WebSafeBase64Unescape(websafe, &decoded));
EXPECT_EQ(decoded, tc.plaintext);
@@ -625,7 +625,7 @@
std::string escaped;
absl::Base64Escape(huge, &escaped);
- // Generates the std::string that should match a base64 encoded "xxx..." std::string.
+ // Generates the string that should match a base64 encoded "xxx..." string.
// "xxx" in base64 is "eHh4".
std::string expected_encoding;
expected_encoding.reserve(kSize / 3 * 4);
diff --git a/third_party/abseil/absl/strings/internal/char_map.h b/third_party/abseil/absl/strings/internal/char_map.h
index b9108b8..61484de 100644
--- a/third_party/abseil/absl/strings/internal/char_map.h
+++ b/third_party/abseil/absl/strings/internal/char_map.h
@@ -28,6 +28,7 @@
#include "absl/base/port.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
class Charmap {
@@ -71,7 +72,7 @@
CharMaskForWord(x, 2), CharMaskForWord(x, 3));
}
- // Containing all the chars in the C-std::string 's'.
+ // Containing all the chars in the C-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) {
@@ -149,6 +150,7 @@
constexpr Charmap PunctCharmap() { return GraphCharmap() & ~AlnumCharmap(); }
} // namespace strings_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_CHAR_MAP_H_
diff --git a/third_party/abseil/absl/strings/internal/charconv_bigint.cc b/third_party/abseil/absl/strings/internal/charconv_bigint.cc
index 95d471d..ebf8c07 100644
--- a/third_party/abseil/absl/strings/internal/charconv_bigint.cc
+++ b/third_party/abseil/absl/strings/internal/charconv_bigint.cc
@@ -19,6 +19,7 @@
#include <string>
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
namespace {
@@ -157,12 +158,12 @@
int LargePowerOfFiveSize(int i) { return 2 * i; }
} // namespace
-const uint32_t kFiveToNth[14] = {
+ABSL_DLL const uint32_t kFiveToNth[14] = {
1, 5, 25, 125, 625, 3125, 15625,
78125, 390625, 1953125, 9765625, 48828125, 244140625, 1220703125,
};
-const uint32_t kTenToNth[10] = {
+ABSL_DLL const uint32_t kTenToNth[10] = {
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000,
};
@@ -207,7 +208,7 @@
++dropped_digits;
}
if (begin < end && *std::prev(end) == '.') {
- // If the std::string ends in '.', either before or after dropping zeroes, then
+ // If the string ends in '.', either before or after dropping zeroes, then
// drop the decimal point and look for more digits to drop.
dropped_digits = 0;
--end;
@@ -354,4 +355,5 @@
template class BigUnsigned<84>;
} // namespace strings_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/internal/charconv_bigint.h b/third_party/abseil/absl/strings/internal/charconv_bigint.h
index 7da9a7e..8f70297 100644
--- a/third_party/abseil/absl/strings/internal/charconv_bigint.h
+++ b/third_party/abseil/absl/strings/internal/charconv_bigint.h
@@ -20,11 +20,13 @@
#include <iostream>
#include <string>
+#include "absl/base/config.h"
#include "absl/strings/ascii.h"
#include "absl/strings/internal/charconv_parse.h"
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
// The largest power that 5 that can be raised to, and still fit in a uint32_t.
@@ -32,8 +34,9 @@
// The largest power that 10 that can be raised to, and still fit in a uint32_t.
constexpr int kMaxSmallPowerOfTen = 9;
-extern const uint32_t kFiveToNth[kMaxSmallPowerOfFive + 1];
-extern const uint32_t kTenToNth[kMaxSmallPowerOfTen + 1];
+ABSL_DLL extern const uint32_t
+ kFiveToNth[kMaxSmallPowerOfFive + 1];
+ABSL_DLL extern const uint32_t kTenToNth[kMaxSmallPowerOfTen + 1];
// Large, fixed-width unsigned integer.
//
@@ -63,7 +66,7 @@
static_cast<uint32_t>(v >> 32)} {}
// Constructs a BigUnsigned from the given string_view containing a decimal
- // value. If the input std::string is not a decimal integer, constructs a 0
+ // value. If the input string is not a decimal integer, constructs a 0
// instead.
explicit BigUnsigned(absl::string_view sv) : size_(0), words_{} {
// Check for valid input, returning a 0 otherwise. This is reasonable
@@ -207,7 +210,7 @@
return words_[index];
}
- // Returns this integer as a decimal std::string. This is not used in the decimal-
+ // Returns this integer as a decimal string. This is not used in the decimal-
// to-binary conversion; it is intended to aid in testing.
std::string ToString() const;
@@ -414,6 +417,7 @@
extern template class BigUnsigned<84>;
} // namespace strings_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_
diff --git a/third_party/abseil/absl/strings/internal/charconv_bigint_test.cc b/third_party/abseil/absl/strings/internal/charconv_bigint_test.cc
index 745714a..a8b9945 100644
--- a/third_party/abseil/absl/strings/internal/charconv_bigint_test.cc
+++ b/third_party/abseil/absl/strings/internal/charconv_bigint_test.cc
@@ -19,6 +19,7 @@
#include "gtest/gtest.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
TEST(BigUnsigned, ShiftLeft) {
@@ -68,6 +69,61 @@
// And we should have fully rotated all bits off by now:
EXPECT_EQ(a, BigUnsigned<84>(0u));
}
+ {
+ // Bit shifting large and small numbers by large and small offsets.
+ // Intended to exercise bounds-checking corner on ShiftLeft() (directly
+ // and under asan).
+
+ // 2**(32*84)-1
+ const BigUnsigned<84> all_bits_one(
+ "1474444211396924248063325089479706787923460402125687709454567433186613"
+ "6228083464060749874845919674257665016359189106695900028098437021384227"
+ "3285029708032466536084583113729486015826557532750465299832071590813090"
+ "2011853039837649252477307070509704043541368002938784757296893793903797"
+ "8180292336310543540677175225040919704702800559606097685920595947397024"
+ "8303316808753252115729411497720357971050627997031988036134171378490368"
+ "6008000778741115399296162550786288457245180872759047016734959330367829"
+ "5235612397427686310674725251378116268607113017720538636924549612987647"
+ "5767411074510311386444547332882472126067840027882117834454260409440463"
+ "9345147252664893456053258463203120637089916304618696601333953616715125"
+ "2115882482473279040772264257431663818610405673876655957323083702713344"
+ "4201105427930770976052393421467136557055");
+ const BigUnsigned<84> zero(0u);
+ const BigUnsigned<84> one(1u);
+ // in bounds shifts
+ for (int i = 1; i < 84*32; ++i) {
+ // shifting all_bits_one to the left should result in a smaller number,
+ // since the high bits rotate off and the low bits are replaced with
+ // zeroes.
+ BigUnsigned<84> big_shifted = all_bits_one;
+ big_shifted.ShiftLeft(i);
+ EXPECT_GT(all_bits_one, big_shifted);
+ // Shifting 1 to the left should instead result in a larger number.
+ BigUnsigned<84> small_shifted = one;
+ small_shifted.ShiftLeft(i);
+ EXPECT_LT(one, small_shifted);
+ }
+ // Shifting by zero or a negative number has no effect
+ for (int no_op_shift : {0, -1, -84 * 32, std::numeric_limits<int>::min()}) {
+ BigUnsigned<84> big_shifted = all_bits_one;
+ big_shifted.ShiftLeft(no_op_shift);
+ EXPECT_EQ(all_bits_one, big_shifted);
+ BigUnsigned<84> small_shifted = one;
+ big_shifted.ShiftLeft(no_op_shift);
+ EXPECT_EQ(one, small_shifted);
+ }
+ // Shifting by an amount greater than the number of bits should result in
+ // zero.
+ for (int out_of_bounds_shift :
+ {84 * 32, 84 * 32 + 1, std::numeric_limits<int>::max()}) {
+ BigUnsigned<84> big_shifted = all_bits_one;
+ big_shifted.ShiftLeft(out_of_bounds_shift);
+ EXPECT_EQ(zero, big_shifted);
+ BigUnsigned<84> small_shifted = one;
+ small_shifted.ShiftLeft(out_of_bounds_shift);
+ EXPECT_EQ(zero, small_shifted);
+ }
+ }
}
TEST(BigUnsigned, MultiplyByUint32) {
@@ -200,4 +256,5 @@
} // namespace strings_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/internal/charconv_parse.cc b/third_party/abseil/absl/strings/internal/charconv_parse.cc
index f3c7232..8b11868 100644
--- a/third_party/abseil/absl/strings/internal/charconv_parse.cc
+++ b/third_party/abseil/absl/strings/internal/charconv_parse.cc
@@ -22,6 +22,7 @@
#include "absl/strings/internal/memutil.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
// ParseFloat<10> will read the first 19 significant digits of the mantissa.
@@ -245,14 +246,20 @@
// ConsumeDigits does not protect against overflow on *out; max_digits must
// be chosen with respect to type T to avoid the possibility of overflow.
template <int base, typename T>
-std::size_t ConsumeDigits(const char* begin, const char* end, int max_digits,
- T* out, bool* dropped_nonzero_digit) {
+int ConsumeDigits(const char* begin, const char* end, int max_digits, T* out,
+ bool* dropped_nonzero_digit) {
if (base == 10) {
assert(max_digits <= std::numeric_limits<T>::digits10);
} else if (base == 16) {
assert(max_digits * 4 <= std::numeric_limits<T>::digits);
}
const char* const original_begin = begin;
+
+ // Skip leading zeros, but only if *out is zero.
+ // They don't cause an overflow so we don't have to count them for
+ // `max_digits`.
+ while (!*out && end != begin && *begin == '0') ++begin;
+
T accumulator = *out;
const char* significant_digits_end =
(end - begin > max_digits) ? begin + max_digits : end;
@@ -275,7 +282,7 @@
*dropped_nonzero_digit = true;
}
*out = accumulator;
- return begin - original_begin;
+ return static_cast<int>(begin - original_begin);
}
// Returns true if `v` is one of the chars allowed inside parentheses following
@@ -295,7 +302,7 @@
switch (*begin) {
case 'i':
case 'I': {
- // An infinity std::string consists of the characters "inf" or "infinity",
+ // An infinity string consists of the characters "inf" or "infinity",
// case insensitive.
if (strings_internal::memcasecmp(begin + 1, "nf", 2) != 0) {
return false;
@@ -319,7 +326,7 @@
}
out->type = strings_internal::FloatType::kNan;
out->end = begin + 3;
- // NaN is allowed to be followed by a parenthesized std::string, consisting of
+ // NaN is allowed to be followed by a parenthesized string, consisting of
// only the characters [a-zA-Z0-9_]. Match that if it's present.
begin += 3;
if (begin < end && *begin == '(') {
@@ -365,7 +372,7 @@
int exponent_adjustment = 0;
bool mantissa_is_inexact = false;
- std::size_t pre_decimal_digits = ConsumeDigits<base>(
+ int pre_decimal_digits = ConsumeDigits<base>(
begin, end, MantissaDigitsMax<base>(), &mantissa, &mantissa_is_inexact);
begin += pre_decimal_digits;
int digits_left;
@@ -391,14 +398,14 @@
while (begin < end && *begin == '0') {
++begin;
}
- std::size_t zeros_skipped = begin - begin_zeros;
+ int zeros_skipped = static_cast<int>(begin - begin_zeros);
if (zeros_skipped >= DigitLimit<base>()) {
// refuse to parse pathological inputs
return result;
}
exponent_adjustment -= static_cast<int>(zeros_skipped);
}
- std::size_t post_decimal_digits = ConsumeDigits<base>(
+ int post_decimal_digits = ConsumeDigits<base>(
begin, end, digits_left, &mantissa, &mantissa_is_inexact);
begin += post_decimal_digits;
@@ -493,4 +500,5 @@
chars_format format_flags);
} // namespace strings_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/internal/charconv_parse.h b/third_party/abseil/absl/strings/internal/charconv_parse.h
index 44d06b2..505998b 100644
--- a/third_party/abseil/absl/strings/internal/charconv_parse.h
+++ b/third_party/abseil/absl/strings/internal/charconv_parse.h
@@ -17,9 +17,11 @@
#include <cstdint>
+#include "absl/base/config.h"
#include "absl/strings/charconv.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
// Enum indicating whether a parsed float is a number or special value.
@@ -92,5 +94,6 @@
absl::chars_format format_flags);
} // namespace strings_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_CHARCONV_PARSE_H_
diff --git a/third_party/abseil/absl/strings/internal/charconv_parse_test.cc b/third_party/abseil/absl/strings/internal/charconv_parse_test.cc
index 9511c98..bc2d111 100644
--- a/third_party/abseil/absl/strings/internal/charconv_parse_test.cc
+++ b/third_party/abseil/absl/strings/internal/charconv_parse_test.cc
@@ -63,7 +63,7 @@
}
const std::string::size_type expected_characters_matched = s.find('$');
ABSL_RAW_CHECK(expected_characters_matched != std::string::npos,
- "Input std::string must contain $");
+ "Input string must contain $");
s.replace(expected_characters_matched, 1, "");
ParsedFloat parsed =
diff --git a/third_party/abseil/absl/strings/internal/cord_internal.cc b/third_party/abseil/absl/strings/internal/cord_internal.cc
new file mode 100644
index 0000000..59f2e4d
--- /dev/null
+++ b/third_party/abseil/absl/strings/internal/cord_internal.cc
@@ -0,0 +1,79 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "absl/strings/internal/cord_internal.h"
+
+#include <atomic>
+#include <cassert>
+#include <memory>
+
+#include "absl/container/inlined_vector.h"
+#include "absl/strings/internal/cord_rep_flat.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+ABSL_CONST_INIT std::atomic<bool> cord_ring_buffer_enabled(
+ kCordEnableRingBufferDefault);
+ABSL_CONST_INIT std::atomic<bool> shallow_subcords_enabled(
+ kCordShallowSubcordsDefault);
+
+void CordRep::Destroy(CordRep* rep) {
+ assert(rep != nullptr);
+
+ absl::InlinedVector<CordRep*, Constants::kInlinedVectorSize> pending;
+ while (true) {
+ assert(!rep->refcount.IsImmortal());
+ if (rep->tag == CONCAT) {
+ CordRepConcat* rep_concat = rep->concat();
+ CordRep* right = rep_concat->right;
+ if (!right->refcount.Decrement()) {
+ pending.push_back(right);
+ }
+ CordRep* left = rep_concat->left;
+ delete rep_concat;
+ rep = nullptr;
+ if (!left->refcount.Decrement()) {
+ rep = left;
+ continue;
+ }
+ } else if (rep->tag == EXTERNAL) {
+ CordRepExternal::Delete(rep);
+ rep = nullptr;
+ } else if (rep->tag == SUBSTRING) {
+ CordRepSubstring* rep_substring = rep->substring();
+ CordRep* child = rep_substring->child;
+ delete rep_substring;
+ rep = nullptr;
+ if (!child->refcount.Decrement()) {
+ rep = child;
+ continue;
+ }
+ } else {
+ CordRepFlat::Delete(rep);
+ rep = nullptr;
+ }
+
+ if (!pending.empty()) {
+ rep = pending.back();
+ pending.pop_back();
+ } else {
+ break;
+ }
+ }
+}
+
+} // namespace cord_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/strings/internal/cord_internal.h b/third_party/abseil/absl/strings/internal/cord_internal.h
new file mode 100644
index 0000000..57e7046
--- /dev/null
+++ b/third_party/abseil/absl/strings/internal/cord_internal.h
@@ -0,0 +1,408 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_
+#define ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_
+
+#include <atomic>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <type_traits>
+
+#include "absl/base/internal/invoke.h"
+#include "absl/base/optimization.h"
+#include "absl/container/internal/compressed_tuple.h"
+#include "absl/meta/type_traits.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+// Default feature enable states for cord ring buffers
+enum CordFeatureDefaults {
+ kCordEnableRingBufferDefault = false,
+ kCordShallowSubcordsDefault = false
+};
+
+extern std::atomic<bool> cord_ring_buffer_enabled;
+extern std::atomic<bool> shallow_subcords_enabled;
+
+inline void enable_cord_ring_buffer(bool enable) {
+ cord_ring_buffer_enabled.store(enable, std::memory_order_relaxed);
+}
+
+inline void enable_shallow_subcords(bool enable) {
+ shallow_subcords_enabled.store(enable, std::memory_order_relaxed);
+}
+
+enum Constants {
+ // The inlined size to use with absl::InlinedVector.
+ //
+ // Note: The InlinedVectors in this file (and in cord.h) do not need to use
+ // the same value for their inlined size. The fact that they do is historical.
+ // It may be desirable for each to use a different inlined size optimized for
+ // that InlinedVector's usage.
+ //
+ // TODO(jgm): Benchmark to see if there's a more optimal value than 47 for
+ // the inlined vector size (47 exists for backward compatibility).
+ kInlinedVectorSize = 47,
+
+ // Prefer copying blocks of at most this size, otherwise reference count.
+ kMaxBytesToCopy = 511
+};
+
+// Wraps std::atomic for reference counting.
+class Refcount {
+ public:
+ constexpr Refcount() : count_{kRefIncrement} {}
+ struct Immortal {};
+ explicit constexpr Refcount(Immortal) : count_(kImmortalTag) {}
+
+ // Increments the reference count. Imposes no memory ordering.
+ inline void Increment() {
+ count_.fetch_add(kRefIncrement, std::memory_order_relaxed);
+ }
+
+ // Asserts that the current refcount is greater than 0. If the refcount is
+ // greater than 1, decrements the reference count.
+ //
+ // Returns false if there are no references outstanding; true otherwise.
+ // Inserts barriers to ensure that state written before this method returns
+ // false will be visible to a thread that just observed this method returning
+ // false.
+ inline bool Decrement() {
+ int32_t refcount = count_.load(std::memory_order_acquire);
+ assert(refcount > 0 || refcount & kImmortalTag);
+ return refcount != kRefIncrement &&
+ count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel) !=
+ kRefIncrement;
+ }
+
+ // Same as Decrement but expect that refcount is greater than 1.
+ inline bool DecrementExpectHighRefcount() {
+ int32_t refcount =
+ count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel);
+ assert(refcount > 0 || refcount & kImmortalTag);
+ return refcount != kRefIncrement;
+ }
+
+ // Returns the current reference count using acquire semantics.
+ inline int32_t Get() const {
+ return count_.load(std::memory_order_acquire) >> kImmortalShift;
+ }
+
+ // Returns whether the atomic integer is 1.
+ // If the reference count is used in the conventional way, a
+ // reference count of 1 implies that the current thread owns the
+ // reference and no other thread shares it.
+ // This call performs the test for a reference count of one, and
+ // performs the memory barrier needed for the owning thread
+ // to act on the object, knowing that it has exclusive access to the
+ // object.
+ inline bool IsOne() {
+ return count_.load(std::memory_order_acquire) == kRefIncrement;
+ }
+
+ bool IsImmortal() const {
+ return (count_.load(std::memory_order_relaxed) & kImmortalTag) != 0;
+ }
+
+ private:
+ // We reserve the bottom bit to tag a reference count as immortal.
+ // By making it `1` we ensure that we never reach `0` when adding/subtracting
+ // `2`, thus it never looks as if it should be destroyed.
+ // These are used for the StringConstant constructor where we do not increase
+ // the refcount at construction time (due to constinit requirements) but we
+ // will still decrease it at destruction time to avoid branching on Unref.
+ enum {
+ kImmortalShift = 1,
+ kRefIncrement = 1 << kImmortalShift,
+ kImmortalTag = kRefIncrement - 1
+ };
+
+ std::atomic<int32_t> count_;
+};
+
+// The overhead of a vtable is too much for Cord, so we roll our own subclasses
+// using only a single byte to differentiate classes from each other - the "tag"
+// byte. Define the subclasses first so we can provide downcasting helper
+// functions in the base class.
+
+struct CordRepConcat;
+struct CordRepExternal;
+struct CordRepFlat;
+struct CordRepSubstring;
+
+// Various representations that we allow
+enum CordRepKind {
+ CONCAT = 0,
+ EXTERNAL = 1,
+ SUBSTRING = 2,
+ RING = 3,
+
+ // We have different tags for different sized flat arrays,
+ // starting with FLAT, and limited to MAX_FLAT_TAG. The 224 value is based on
+ // the current 'size to tag' encoding of 8 / 32 bytes. If a new tag is needed
+ // in the future, then 'FLAT' and 'MAX_FLAT_TAG' should be adjusted as well
+ // as the Tag <---> Size logic so that FLAT stil represents the minimum flat
+ // allocation size. (32 bytes as of now).
+ FLAT = 4,
+ MAX_FLAT_TAG = 224,
+};
+
+struct CordRep {
+ CordRep() = default;
+ constexpr CordRep(Refcount::Immortal immortal, size_t l)
+ : length(l), refcount(immortal), tag(EXTERNAL), data{} {}
+
+ // The following three fields have to be less than 32 bytes since
+ // that is the smallest supported flat node size.
+ size_t length;
+ Refcount refcount;
+ // If tag < FLAT, it represents CordRepKind and indicates the type of node.
+ // Otherwise, the node type is CordRepFlat and the tag is the encoded size.
+ uint8_t tag;
+ char data[1]; // Starting point for flat array: MUST BE LAST FIELD of CordRep
+
+ inline CordRepConcat* concat();
+ inline const CordRepConcat* concat() const;
+ inline CordRepSubstring* substring();
+ inline const CordRepSubstring* substring() const;
+ inline CordRepExternal* external();
+ inline const CordRepExternal* external() const;
+ inline CordRepFlat* flat();
+ inline const CordRepFlat* flat() const;
+
+ // --------------------------------------------------------------------
+ // Memory management
+
+ // This internal routine is called from the cold path of Unref below. Keeping
+ // it in a separate routine allows good inlining of Unref into many profitable
+ // call sites. However, the call to this function can be highly disruptive to
+ // the register pressure in those callers. To minimize the cost to callers, we
+ // use a special LLVM calling convention that preserves most registers. This
+ // allows the call to this routine in cold paths to not disrupt the caller's
+ // register pressure. This calling convention is not available on all
+ // platforms; we intentionally allow LLVM to ignore the attribute rather than
+ // attempting to hardcode the list of supported platforms.
+#if defined(__clang__) && !defined(__i386__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wattributes"
+ __attribute__((preserve_most))
+#pragma clang diagnostic pop
+#endif
+ static void Destroy(CordRep* rep);
+
+ // Increments the reference count of `rep`.
+ // Requires `rep` to be a non-null pointer value.
+ static inline CordRep* Ref(CordRep* rep);
+
+ // Decrements the reference count of `rep`. Destroys rep if count reaches
+ // zero. Requires `rep` to be a non-null pointer value.
+ static inline void Unref(CordRep* rep);
+};
+
+struct CordRepConcat : public CordRep {
+ CordRep* left;
+ CordRep* right;
+
+ uint8_t depth() const { return static_cast<uint8_t>(data[0]); }
+ void set_depth(uint8_t depth) { data[0] = static_cast<char>(depth); }
+};
+
+struct CordRepSubstring : public CordRep {
+ size_t start; // Starting offset of substring in child
+ CordRep* child;
+};
+
+// Type for function pointer that will invoke the releaser function and also
+// delete the `CordRepExternalImpl` corresponding to the passed in
+// `CordRepExternal`.
+using ExternalReleaserInvoker = void (*)(CordRepExternal*);
+
+// External CordReps are allocated together with a type erased releaser. The
+// releaser is stored in the memory directly following the CordRepExternal.
+struct CordRepExternal : public CordRep {
+ CordRepExternal() = default;
+ explicit constexpr CordRepExternal(absl::string_view str)
+ : CordRep(Refcount::Immortal{}, str.size()),
+ base(str.data()),
+ releaser_invoker(nullptr) {}
+
+ const char* base;
+ // Pointer to function that knows how to call and destroy the releaser.
+ ExternalReleaserInvoker releaser_invoker;
+
+ // Deletes (releases) the external rep.
+ // Requires rep != nullptr and rep->tag == EXTERNAL
+ static void Delete(CordRep* rep);
+};
+
+struct Rank1 {};
+struct Rank0 : Rank1 {};
+
+template <typename Releaser, typename = ::absl::base_internal::invoke_result_t<
+ Releaser, absl::string_view>>
+void InvokeReleaser(Rank0, Releaser&& releaser, absl::string_view data) {
+ ::absl::base_internal::invoke(std::forward<Releaser>(releaser), data);
+}
+
+template <typename Releaser,
+ typename = ::absl::base_internal::invoke_result_t<Releaser>>
+void InvokeReleaser(Rank1, Releaser&& releaser, absl::string_view) {
+ ::absl::base_internal::invoke(std::forward<Releaser>(releaser));
+}
+
+// We use CompressedTuple so that we can benefit from EBCO.
+template <typename Releaser>
+struct CordRepExternalImpl
+ : public CordRepExternal,
+ public ::absl::container_internal::CompressedTuple<Releaser> {
+ // The extra int arg is so that we can avoid interfering with copy/move
+ // constructors while still benefitting from perfect forwarding.
+ template <typename T>
+ CordRepExternalImpl(T&& releaser, int)
+ : CordRepExternalImpl::CompressedTuple(std::forward<T>(releaser)) {
+ this->releaser_invoker = &Release;
+ }
+
+ ~CordRepExternalImpl() {
+ InvokeReleaser(Rank0{}, std::move(this->template get<0>()),
+ absl::string_view(base, length));
+ }
+
+ static void Release(CordRepExternal* rep) {
+ delete static_cast<CordRepExternalImpl*>(rep);
+ }
+};
+
+inline void CordRepExternal::Delete(CordRep* rep) {
+ assert(rep != nullptr && rep->tag == EXTERNAL);
+ auto* rep_external = static_cast<CordRepExternal*>(rep);
+ assert(rep_external->releaser_invoker != nullptr);
+ rep_external->releaser_invoker(rep_external);
+}
+
+template <typename Str>
+struct ConstInitExternalStorage {
+ ABSL_CONST_INIT static CordRepExternal value;
+};
+
+template <typename Str>
+CordRepExternal ConstInitExternalStorage<Str>::value(Str::value);
+
+enum {
+ kMaxInline = 15,
+ // Tag byte & kMaxInline means we are storing a pointer.
+ kTreeFlag = 1 << 4,
+ // Tag byte & kProfiledFlag means we are profiling the Cord.
+ kProfiledFlag = 1 << 5
+};
+
+// If the data has length <= kMaxInline, we store it in `as_chars`, and
+// store the size in `tagged_size`.
+// Else we store it in a tree and store a pointer to that tree in
+// `as_tree.rep` and store a tag in `tagged_size`.
+struct AsTree {
+ absl::cord_internal::CordRep* rep;
+ char padding[kMaxInline + 1 - sizeof(absl::cord_internal::CordRep*) - 1];
+ char tagged_size;
+};
+
+constexpr char GetOrNull(absl::string_view data, size_t pos) {
+ return pos < data.size() ? data[pos] : '\0';
+}
+
+union InlineData {
+ constexpr InlineData() : as_chars{} {}
+ explicit constexpr InlineData(AsTree tree) : as_tree(tree) {}
+ explicit constexpr InlineData(absl::string_view chars)
+ : as_chars{GetOrNull(chars, 0), GetOrNull(chars, 1),
+ GetOrNull(chars, 2), GetOrNull(chars, 3),
+ GetOrNull(chars, 4), GetOrNull(chars, 5),
+ GetOrNull(chars, 6), GetOrNull(chars, 7),
+ GetOrNull(chars, 8), GetOrNull(chars, 9),
+ GetOrNull(chars, 10), GetOrNull(chars, 11),
+ GetOrNull(chars, 12), GetOrNull(chars, 13),
+ GetOrNull(chars, 14), static_cast<char>(chars.size())} {}
+
+ AsTree as_tree;
+ char as_chars[kMaxInline + 1];
+};
+static_assert(sizeof(InlineData) == kMaxInline + 1, "");
+static_assert(sizeof(AsTree) == sizeof(InlineData), "");
+static_assert(offsetof(AsTree, tagged_size) == kMaxInline, "");
+
+inline CordRepConcat* CordRep::concat() {
+ assert(tag == CONCAT);
+ return static_cast<CordRepConcat*>(this);
+}
+
+inline const CordRepConcat* CordRep::concat() const {
+ assert(tag == CONCAT);
+ return static_cast<const CordRepConcat*>(this);
+}
+
+inline CordRepSubstring* CordRep::substring() {
+ assert(tag == SUBSTRING);
+ return static_cast<CordRepSubstring*>(this);
+}
+
+inline const CordRepSubstring* CordRep::substring() const {
+ assert(tag == SUBSTRING);
+ return static_cast<const CordRepSubstring*>(this);
+}
+
+inline CordRepExternal* CordRep::external() {
+ assert(tag == EXTERNAL);
+ return static_cast<CordRepExternal*>(this);
+}
+
+inline const CordRepExternal* CordRep::external() const {
+ assert(tag == EXTERNAL);
+ return static_cast<const CordRepExternal*>(this);
+}
+
+inline CordRepFlat* CordRep::flat() {
+ assert(tag >= FLAT && tag <= MAX_FLAT_TAG);
+ return reinterpret_cast<CordRepFlat*>(this);
+}
+
+inline const CordRepFlat* CordRep::flat() const {
+ assert(tag >= FLAT && tag <= MAX_FLAT_TAG);
+ return reinterpret_cast<const CordRepFlat*>(this);
+}
+
+inline CordRep* CordRep::Ref(CordRep* rep) {
+ assert(rep != nullptr);
+ rep->refcount.Increment();
+ return rep;
+}
+
+inline void CordRep::Unref(CordRep* rep) {
+ assert(rep != nullptr);
+ // Expect refcount to be 0. Avoiding the cost of an atomic decrement should
+ // typically outweigh the cost of an extra branch checking for ref == 1.
+ if (ABSL_PREDICT_FALSE(!rep->refcount.DecrementExpectHighRefcount())) {
+ Destroy(rep);
+ }
+}
+
+} // namespace cord_internal
+
+ABSL_NAMESPACE_END
+} // namespace absl
+#endif // ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_
diff --git a/third_party/abseil/absl/strings/internal/cord_rep_flat.h b/third_party/abseil/absl/strings/internal/cord_rep_flat.h
new file mode 100644
index 0000000..af3d961
--- /dev/null
+++ b/third_party/abseil/absl/strings/internal/cord_rep_flat.h
@@ -0,0 +1,129 @@
+// Copyright 2020 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_
+#define ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+
+#include "absl/strings/internal/cord_internal.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+// Note: all constants below are never ODR used and internal to cord, we define
+// these as static constexpr to avoid 'in struct' definition and usage clutter.
+
+// Largest and smallest flat node lengths we are willing to allocate
+// Flat allocation size is stored in tag, which currently can encode sizes up
+// to 4K, encoded as multiple of either 8 or 32 bytes.
+// If we allow for larger sizes, we need to change this to 8/64, 16/128, etc.
+// kMinFlatSize is bounded by tag needing to be at least FLAT * 8 bytes, and
+// ideally a 'nice' size aligning with allocation and cacheline sizes like 32.
+// kMaxFlatSize is bounded by the size resulting in a computed tag no greater
+// than MAX_FLAT_TAG. MAX_FLAT_TAG provides for additional 'high' tag values.
+static constexpr size_t kFlatOverhead = offsetof(CordRep, data);
+static constexpr size_t kMinFlatSize = 32;
+static constexpr size_t kMaxFlatSize = 4096;
+static constexpr size_t kMaxFlatLength = kMaxFlatSize - kFlatOverhead;
+static constexpr size_t kMinFlatLength = kMinFlatSize - kFlatOverhead;
+
+constexpr size_t AllocatedSizeToTagUnchecked(size_t size) {
+ return (size <= 1024) ? size / 8 : 128 + size / 32 - 1024 / 32;
+}
+
+static_assert(kMinFlatSize / 8 >= FLAT, "");
+static_assert(AllocatedSizeToTagUnchecked(kMaxFlatSize) <= MAX_FLAT_TAG, "");
+
+// Helper functions for rounded div, and rounding to exact sizes.
+constexpr size_t DivUp(size_t n, size_t m) { return (n + m - 1) / m; }
+constexpr size_t RoundUp(size_t n, size_t m) { return DivUp(n, m) * m; }
+
+// Returns the size to the nearest equal or larger value that can be
+// expressed exactly as a tag value.
+inline size_t RoundUpForTag(size_t size) {
+ return RoundUp(size, (size <= 1024) ? 8 : 32);
+}
+
+// Converts the allocated size to a tag, rounding down if the size
+// does not exactly match a 'tag expressible' size value. The result is
+// undefined if the size exceeds the maximum size that can be encoded in
+// a tag, i.e., if size is larger than TagToAllocatedSize(<max tag>).
+inline uint8_t AllocatedSizeToTag(size_t size) {
+ const size_t tag = AllocatedSizeToTagUnchecked(size);
+ assert(tag <= MAX_FLAT_TAG);
+ return static_cast<uint8_t>(tag);
+}
+
+// Converts the provided tag to the corresponding allocated size
+constexpr size_t TagToAllocatedSize(uint8_t tag) {
+ return (tag <= 128) ? (tag * 8) : (1024 + (tag - 128) * 32);
+}
+
+// Converts the provided tag to the corresponding available data length
+constexpr size_t TagToLength(uint8_t tag) {
+ return TagToAllocatedSize(tag) - kFlatOverhead;
+}
+
+// Enforce that kMaxFlatSize maps to a well-known exact tag value.
+static_assert(TagToAllocatedSize(224) == kMaxFlatSize, "Bad tag logic");
+
+struct CordRepFlat : public CordRep {
+ // Creates a new flat node.
+ static CordRepFlat* New(size_t len) {
+ if (len <= kMinFlatLength) {
+ len = kMinFlatLength;
+ } else if (len > kMaxFlatLength) {
+ len = kMaxFlatLength;
+ }
+
+ // Round size up so it matches a size we can exactly express in a tag.
+ const size_t size = RoundUpForTag(len + kFlatOverhead);
+ void* const raw_rep = ::operator new(size);
+ CordRepFlat* rep = new (raw_rep) CordRepFlat();
+ rep->tag = AllocatedSizeToTag(size);
+ return rep;
+ }
+
+ // Deletes a CordRepFlat instance created previously through a call to New().
+ // Flat CordReps are allocated and constructed with raw ::operator new and
+ // placement new, and must be destructed and deallocated accordingly.
+ static void Delete(CordRep*rep) {
+ assert(rep->tag >= FLAT);
+#if defined(__cpp_sized_deallocation)
+ size_t size = TagToAllocatedSize(rep->tag);
+ rep->~CordRep();
+ ::operator delete(rep, size);
+#else
+ rep->~CordRep();
+ ::operator delete(rep);
+#endif
+ }
+
+ // Returns the maximum capacity (payload size) of this instance.
+ size_t Capacity() const { return TagToLength(tag); }
+
+ // Returns the allocated size (payload + overhead) of this instance.
+ size_t AllocatedSize() const { return TagToAllocatedSize(tag); }
+};
+
+} // namespace cord_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_
diff --git a/third_party/abseil/absl/strings/internal/escaping.cc b/third_party/abseil/absl/strings/internal/escaping.cc
new file mode 100644
index 0000000..c527128
--- /dev/null
+++ b/third_party/abseil/absl/strings/internal/escaping.cc
@@ -0,0 +1,180 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/internal/escaping.h"
+
+#include "absl/base/internal/endian.h"
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+const char kBase64Chars[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+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 https://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 https://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 https://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 https://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) { // While 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);
+}
+
+} // namespace strings_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/third_party/abseil/absl/strings/internal/escaping.h b/third_party/abseil/absl/strings/internal/escaping.h
new file mode 100644
index 0000000..6a9ce60
--- /dev/null
+++ b/third_party/abseil/absl/strings/internal/escaping.h
@@ -0,0 +1,58 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_ESCAPING_H_
+#define ABSL_STRINGS_INTERNAL_ESCAPING_H_
+
+#include <cassert>
+
+#include "absl/strings/internal/resize_uninitialized.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+ABSL_CONST_INIT extern const char kBase64Chars[];
+
+// Calculates how long a string will be when it is base64 encoded given its
+// length and whether or not the result should be padded.
+size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding);
+
+// Base64-encodes `src` using the alphabet provided in `base64` and writes the
+// result to `dest`. If `do_padding` is true, `dest` is padded with '=' chars
+// until its length is a multiple of 3. Returns the length of `dest`.
+size_t Base64EscapeInternal(const unsigned char* src, size_t szsrc, char* dest,
+ size_t szdest, const char* base64, bool do_padding);
+
+// Base64-encodes `src` using the alphabet provided in `base64` and writes the
+// result to `dest`. If `do_padding` is true, `dest` is padded with '=' chars
+// until its length is a multiple of 3.
+template <typename String>
+void Base64EscapeInternal(const unsigned char* src, size_t szsrc, String* dest,
+ bool do_padding, const char* base64_chars) {
+ const size_t calc_escaped_size =
+ CalculateBase64EscapedLenInternal(szsrc, do_padding);
+ 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);
+}
+
+} // namespace strings_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_STRINGS_INTERNAL_ESCAPING_H_
diff --git a/third_party/abseil/absl/strings/internal/escaping_test_common.h b/third_party/abseil/absl/strings/internal/escaping_test_common.h
index bd80303..7b18017 100644
--- a/third_party/abseil/absl/strings/internal/escaping_test_common.h
+++ b/third_party/abseil/absl/strings/internal/escaping_test_common.h
@@ -22,6 +22,7 @@
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
struct base64_testcase {
@@ -126,6 +127,7 @@
}
} // namespace strings_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_ESCAPING_TEST_COMMON_H_
diff --git a/third_party/abseil/absl/strings/internal/memutil.cc b/third_party/abseil/absl/strings/internal/memutil.cc
index 77aa63c..2519c68 100644
--- a/third_party/abseil/absl/strings/internal/memutil.cc
+++ b/third_party/abseil/absl/strings/internal/memutil.cc
@@ -17,6 +17,7 @@
#include <cstdlib>
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
int memcasecmp(const char* s1, const char* s2, size_t len) {
@@ -107,4 +108,5 @@
}
} // namespace strings_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/internal/memutil.h b/third_party/abseil/absl/strings/internal/memutil.h
index 7c071a8..9ad0535 100644
--- a/third_party/abseil/absl/strings/internal/memutil.h
+++ b/third_party/abseil/absl/strings/internal/memutil.h
@@ -69,6 +69,7 @@
#include "absl/strings/ascii.h" // for absl::ascii_tolower
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
inline char* memcat(char* dest, size_t destlen, const char* src,
@@ -141,6 +142,7 @@
size_t neelen);
} // namespace strings_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_MEMUTIL_H_
diff --git a/third_party/abseil/absl/strings/internal/numbers_test_common.h b/third_party/abseil/absl/strings/internal/numbers_test_common.h
index 2824720..eaa88a8 100644
--- a/third_party/abseil/absl/strings/internal/numbers_test_common.h
+++ b/third_party/abseil/absl/strings/internal/numbers_test_common.h
@@ -23,7 +23,10 @@
#include <limits>
#include <string>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
template <typename IntType>
@@ -42,8 +45,9 @@
while (value != 0) {
const IntType next_value = value / base;
// Can't use std::abs here because of problems when IntType is unsigned.
- int remainder = value > next_value * base ? value - next_value * base
- : next_value * base - value;
+ int remainder =
+ static_cast<int>(value > next_value * base ? value - next_value * base
+ : next_value * base - value);
char c = remainder < 10 ? '0' + remainder : 'A' + remainder - 10;
destination->insert(0, 1, c);
value = next_value;
@@ -166,7 +170,7 @@
{"0x1234", true, 16, 0x1234},
- // Base-10 std::string version.
+ // Base-10 string version.
{"1234", true, 0, 1234},
{nullptr, false, 0, 0},
}};
@@ -174,6 +178,7 @@
}
} // namespace strings_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_
diff --git a/third_party/abseil/absl/strings/internal/ostringstream.cc b/third_party/abseil/absl/strings/internal/ostringstream.cc
index d0f0f84..05324c7 100644
--- a/third_party/abseil/absl/strings/internal/ostringstream.cc
+++ b/third_party/abseil/absl/strings/internal/ostringstream.cc
@@ -15,6 +15,7 @@
#include "absl/strings/internal/ostringstream.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
OStringStream::Buf::int_type OStringStream::overflow(int c) {
@@ -31,4 +32,5 @@
}
} // namespace strings_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/internal/ostringstream.h b/third_party/abseil/absl/strings/internal/ostringstream.h
index 2079201..d25d604 100644
--- a/third_party/abseil/absl/strings/internal/ostringstream.h
+++ b/third_party/abseil/absl/strings/internal/ostringstream.h
@@ -23,6 +23,7 @@
#include "absl/base/port.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
// The same as std::ostringstream but appends to a user-specified std::string,
@@ -82,6 +83,7 @@
};
} // namespace strings_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_OSTRINGSTREAM_H_
diff --git a/third_party/abseil/absl/strings/internal/pow10_helper.cc b/third_party/abseil/absl/strings/internal/pow10_helper.cc
index 03ed8d0..42e96c3 100644
--- a/third_party/abseil/absl/strings/internal/pow10_helper.cc
+++ b/third_party/abseil/absl/strings/internal/pow10_helper.cc
@@ -17,6 +17,7 @@
#include <cmath>
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
namespace {
@@ -117,4 +118,5 @@
}
} // namespace strings_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/internal/pow10_helper.h b/third_party/abseil/absl/strings/internal/pow10_helper.h
index 9d1aa71..c37c2c3 100644
--- a/third_party/abseil/absl/strings/internal/pow10_helper.h
+++ b/third_party/abseil/absl/strings/internal/pow10_helper.h
@@ -22,7 +22,10 @@
#include <vector>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
// Computes the precise value of 10^exp. (I.e. the nearest representable
@@ -31,6 +34,7 @@
double Pow10(int exp);
} // namespace strings_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_POW10_HELPER_H_
diff --git a/third_party/abseil/absl/strings/internal/pow10_helper_test.cc b/third_party/abseil/absl/strings/internal/pow10_helper_test.cc
index a4a68b5..a4ff76d 100644
--- a/third_party/abseil/absl/strings/internal/pow10_helper_test.cc
+++ b/third_party/abseil/absl/strings/internal/pow10_helper_test.cc
@@ -20,6 +20,7 @@
#include "absl/strings/str_format.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
namespace {
@@ -117,4 +118,5 @@
} // namespace
} // namespace strings_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/internal/resize_uninitialized.h b/third_party/abseil/absl/strings/internal/resize_uninitialized.h
index 469962b..e42628e 100644
--- a/third_party/abseil/absl/strings/internal/resize_uninitialized.h
+++ b/third_party/abseil/absl/strings/internal/resize_uninitialized.h
@@ -25,6 +25,7 @@
#include "absl/meta/type_traits.h" // for void_t
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
// Is a subclass of true_type or false_type, depending on whether or not
@@ -35,8 +36,7 @@
static void Resize(string_type* s, size_t new_size) { s->resize(new_size); }
};
-// __resize_default_init is provided by libc++ >= 8.0 and by Google's internal
-// ::string implementation.
+// __resize_default_init is provided by libc++ >= 8.0
template <typename string_type>
struct ResizeUninitializedTraits<
string_type, absl::void_t<decltype(std::declval<string_type&>()
@@ -67,6 +67,7 @@
}
} // namespace strings_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_
diff --git a/third_party/abseil/absl/strings/internal/resize_uninitialized_test.cc b/third_party/abseil/absl/strings/internal/resize_uninitialized_test.cc
index c5be0b1..0f8b3c2 100644
--- a/third_party/abseil/absl/strings/internal/resize_uninitialized_test.cc
+++ b/third_party/abseil/absl/strings/internal/resize_uninitialized_test.cc
@@ -20,13 +20,27 @@
int resize_call_count = 0;
+// A mock string class whose only purpose is to track how many times its
+// resize() method has been called.
struct resizable_string {
+ size_t size() const { return 0; }
+ char& operator[](size_t) {
+ static char c = '\0';
+ return c;
+ }
void resize(size_t) { resize_call_count += 1; }
};
int resize_default_init_call_count = 0;
+// A mock string class whose only purpose is to track how many times its
+// resize() and __resize_default_init() methods have been called.
struct resize_default_init_string {
+ size_t size() const { return 0; }
+ char& operator[](size_t) {
+ static char c = '\0';
+ return c;
+ }
void resize(size_t) { resize_call_count += 1; }
void __resize_default_init(size_t) { resize_default_init_call_count += 1; }
};
diff --git a/third_party/abseil/absl/strings/internal/stl_type_traits.h b/third_party/abseil/absl/strings/internal/stl_type_traits.h
index 202ab37..6035ca4 100644
--- a/third_party/abseil/absl/strings/internal/stl_type_traits.h
+++ b/third_party/abseil/absl/strings/internal/stl_type_traits.h
@@ -40,6 +40,7 @@
#include "absl/meta/type_traits.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
template <typename C, template <typename...> class T>
@@ -242,5 +243,6 @@
IsConvertibleToSTLContainer<C>> {};
} // namespace strings_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_
diff --git a/third_party/abseil/absl/strings/internal/str_format/arg.cc b/third_party/abseil/absl/strings/internal/str_format/arg.cc
index b40be8f..e28a29b 100644
--- a/third_party/abseil/absl/strings/internal/str_format/arg.cc
+++ b/third_party/abseil/absl/strings/internal/str_format/arg.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
//
// POSIX spec:
// http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html
@@ -12,13 +26,13 @@
#include "absl/base/port.h"
#include "absl/strings/internal/str_format/float_conversion.h"
+#include "absl/strings/numbers.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
namespace {
-const char kDigit[2][32] = { "0123456789abcdef", "0123456789ABCDEF" };
-
// Reduce *capacity by s.size(), clipped to a 0 minimum.
void ReducePadding(string_view s, size_t *capacity) {
*capacity = Excess(s.size(), *capacity);
@@ -32,6 +46,10 @@
template <typename T>
struct MakeUnsigned : std::make_unsigned<T> {};
template <>
+struct MakeUnsigned<absl::int128> {
+ using type = absl::uint128;
+};
+template <>
struct MakeUnsigned<absl::uint128> {
using type = absl::uint128;
};
@@ -39,128 +57,183 @@
template <typename T>
struct IsSigned : std::is_signed<T> {};
template <>
+struct IsSigned<absl::int128> : std::true_type {};
+template <>
struct IsSigned<absl::uint128> : std::false_type {};
-class ConvertedIntInfo {
+// Integral digit printer.
+// Call one of the PrintAs* routines after construction once.
+// Use with_neg_and_zero/without_neg_or_zero/is_negative to access the results.
+class IntDigits {
public:
+ // Print the unsigned integer as octal.
+ // Supports unsigned integral types and uint128.
template <typename T>
- ConvertedIntInfo(T v, ConversionChar conv) {
- using Unsigned = typename MakeUnsigned<T>::type;
- auto u = static_cast<Unsigned>(v);
- if (IsNeg(v)) {
- is_neg_ = true;
- u = Unsigned{} - u;
- } else {
- is_neg_ = false;
- }
- UnsignedToStringRight(u, conv);
+ void PrintAsOct(T v) {
+ static_assert(!IsSigned<T>::value, "");
+ char *p = storage_ + sizeof(storage_);
+ do {
+ *--p = static_cast<char>('0' + (static_cast<size_t>(v) & 7));
+ v >>= 3;
+ } while (v);
+ start_ = p;
+ size_ = storage_ + sizeof(storage_) - p;
}
- string_view digits() const {
- return {end() - size_, static_cast<size_t>(size_)};
+ // Print the signed or unsigned integer as decimal.
+ // Supports all integral types.
+ template <typename T>
+ void PrintAsDec(T v) {
+ static_assert(std::is_integral<T>::value, "");
+ start_ = storage_;
+ size_ = numbers_internal::FastIntToBuffer(v, storage_) - storage_;
}
- bool is_neg() const { return is_neg_; }
+
+ void PrintAsDec(int128 v) {
+ auto u = static_cast<uint128>(v);
+ bool add_neg = false;
+ if (v < 0) {
+ add_neg = true;
+ u = uint128{} - u;
+ }
+ PrintAsDec(u, add_neg);
+ }
+
+ void PrintAsDec(uint128 v, bool add_neg = false) {
+ // This function can be sped up if needed. We can call FastIntToBuffer
+ // twice, or fix FastIntToBuffer to support uint128.
+ char *p = storage_ + sizeof(storage_);
+ do {
+ p -= 2;
+ numbers_internal::PutTwoDigits(static_cast<size_t>(v % 100), p);
+ v /= 100;
+ } while (v);
+ if (p[0] == '0') {
+ // We printed one too many hexits.
+ ++p;
+ }
+ if (add_neg) {
+ *--p = '-';
+ }
+ size_ = storage_ + sizeof(storage_) - p;
+ start_ = p;
+ }
+
+ // Print the unsigned integer as hex using lowercase.
+ // Supports unsigned integral types and uint128.
+ template <typename T>
+ void PrintAsHexLower(T v) {
+ static_assert(!IsSigned<T>::value, "");
+ char *p = storage_ + sizeof(storage_);
+
+ do {
+ p -= 2;
+ constexpr const char* table = numbers_internal::kHexTable;
+ std::memcpy(p, table + 2 * (static_cast<size_t>(v) & 0xFF), 2);
+ if (sizeof(T) == 1) break;
+ v >>= 8;
+ } while (v);
+ if (p[0] == '0') {
+ // We printed one too many digits.
+ ++p;
+ }
+ start_ = p;
+ size_ = storage_ + sizeof(storage_) - p;
+ }
+
+ // Print the unsigned integer as hex using uppercase.
+ // Supports unsigned integral types and uint128.
+ template <typename T>
+ void PrintAsHexUpper(T v) {
+ static_assert(!IsSigned<T>::value, "");
+ char *p = storage_ + sizeof(storage_);
+
+ // kHexTable is only lowercase, so do it manually for uppercase.
+ do {
+ *--p = "0123456789ABCDEF"[static_cast<size_t>(v) & 15];
+ v >>= 4;
+ } while (v);
+ start_ = p;
+ size_ = storage_ + sizeof(storage_) - p;
+ }
+
+ // The printed value including the '-' sign if available.
+ // For inputs of value `0`, this will return "0"
+ string_view with_neg_and_zero() const { return {start_, size_}; }
+
+ // The printed value not including the '-' sign.
+ // For inputs of value `0`, this will return "".
+ string_view without_neg_or_zero() const {
+ static_assert('-' < '0', "The check below verifies both.");
+ size_t advance = start_[0] <= '0' ? 1 : 0;
+ return {start_ + advance, size_ - advance};
+ }
+
+ bool is_negative() const { return start_[0] == '-'; }
private:
- template <typename T, bool IsSigned>
- struct IsNegImpl {
- static bool Eval(T v) { return v < 0; }
- };
- template <typename T>
- struct IsNegImpl<T, false> {
- static bool Eval(T) {
- return false;
- }
- };
-
- template <typename T>
- bool IsNeg(T v) {
- return IsNegImpl<T, IsSigned<T>::value>::Eval(v);
- }
-
- template <typename T>
- void UnsignedToStringRight(T u, ConversionChar conv) {
- char *p = end();
- switch (conv.radix()) {
- default:
- case 10:
- for (; u; u /= 10)
- *--p = static_cast<char>('0' + static_cast<size_t>(u % 10));
- break;
- case 8:
- for (; u; u /= 8)
- *--p = static_cast<char>('0' + static_cast<size_t>(u % 8));
- break;
- case 16: {
- const char *digits = kDigit[conv.upper() ? 1 : 0];
- for (; u; u /= 16) *--p = digits[static_cast<size_t>(u % 16)];
- break;
- }
- }
- size_ = static_cast<int>(end() - p);
- }
-
- const char *end() const { return storage_ + sizeof(storage_); }
- char *end() { return storage_ + sizeof(storage_); }
-
- bool is_neg_;
- int size_;
- // Max size: 128 bit value as octal -> 43 digits
- char storage_[128 / 3 + 1];
+ const char *start_;
+ size_t size_;
+ // Max size: 128 bit value as octal -> 43 digits, plus sign char
+ char storage_[128 / 3 + 1 + 1];
};
// Note: 'o' conversions do not have a base indicator, it's just that
// the '#' flag is specified to modify the precision for 'o' conversions.
-string_view BaseIndicator(const ConvertedIntInfo &info,
- const ConversionSpec conv) {
- bool alt = conv.flags().alt;
- int radix = conv.conv().radix();
- if (conv.conv().id() == ConversionChar::p)
- alt = true; // always show 0x for %p.
+string_view BaseIndicator(const IntDigits &as_digits,
+ const FormatConversionSpecImpl conv) {
+ // always show 0x for %p.
+ bool alt = conv.has_alt_flag() ||
+ conv.conversion_char() == FormatConversionCharInternal::p;
+ bool hex = (conv.conversion_char() == FormatConversionCharInternal::x ||
+ conv.conversion_char() == FormatConversionCharInternal::X ||
+ conv.conversion_char() == FormatConversionCharInternal::p);
// From the POSIX description of '#' flag:
// "For x or X conversion specifiers, a non-zero result shall have
// 0x (or 0X) prefixed to it."
- if (alt && radix == 16 && !info.digits().empty()) {
- if (conv.conv().upper()) return "0X";
- return "0x";
+ if (alt && hex && !as_digits.without_neg_or_zero().empty()) {
+ return conv.conversion_char() == FormatConversionCharInternal::X ? "0X"
+ : "0x";
}
return {};
}
-string_view SignColumn(bool neg, const ConversionSpec conv) {
- if (conv.conv().is_signed()) {
+string_view SignColumn(bool neg, const FormatConversionSpecImpl conv) {
+ if (conv.conversion_char() == FormatConversionCharInternal::d ||
+ conv.conversion_char() == FormatConversionCharInternal::i) {
if (neg) return "-";
- if (conv.flags().show_pos) return "+";
- if (conv.flags().sign_col) return " ";
+ if (conv.has_show_pos_flag()) return "+";
+ if (conv.has_sign_col_flag()) return " ";
}
return {};
}
-bool ConvertCharImpl(unsigned char v, const ConversionSpec conv,
+bool ConvertCharImpl(unsigned char v, const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
size_t fill = 0;
if (conv.width() >= 0) fill = conv.width();
ReducePadding(1, &fill);
- if (!conv.flags().left) sink->Append(fill, ' ');
+ if (!conv.has_left_flag()) sink->Append(fill, ' ');
sink->Append(1, v);
- if (conv.flags().left) sink->Append(fill, ' ');
+ if (conv.has_left_flag()) sink->Append(fill, ' ');
return true;
}
-bool ConvertIntImplInner(const ConvertedIntInfo &info,
- const ConversionSpec conv, FormatSinkImpl *sink) {
+bool ConvertIntImplInnerSlow(const IntDigits &as_digits,
+ const FormatConversionSpecImpl conv,
+ FormatSinkImpl *sink) {
// Print as a sequence of Substrings:
// [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces]
size_t fill = 0;
if (conv.width() >= 0) fill = conv.width();
- string_view formatted = info.digits();
+ string_view formatted = as_digits.without_neg_or_zero();
ReducePadding(formatted, &fill);
- string_view sign = SignColumn(info.is_neg(), conv);
+ string_view sign = SignColumn(as_digits.is_negative(), conv);
ReducePadding(sign, &fill);
- string_view base_indicator = BaseIndicator(info, conv);
+ string_view base_indicator = BaseIndicator(as_digits, conv);
ReducePadding(base_indicator, &fill);
int precision = conv.precision();
@@ -168,7 +241,8 @@
if (!precision_specified)
precision = 1;
- if (conv.flags().alt && conv.conv().id() == ConversionChar::o) {
+ if (conv.has_alt_flag() &&
+ conv.conversion_char() == FormatConversionCharInternal::o) {
// From POSIX description of the '#' (alt) flag:
// "For o conversion, it increases the precision (if necessary) to
// force the first digit of the result to be zero."
@@ -181,13 +255,13 @@
size_t num_zeroes = Excess(formatted.size(), precision);
ReducePadding(num_zeroes, &fill);
- size_t num_left_spaces = !conv.flags().left ? fill : 0;
- size_t num_right_spaces = conv.flags().left ? fill : 0;
+ size_t num_left_spaces = !conv.has_left_flag() ? fill : 0;
+ size_t num_right_spaces = conv.has_left_flag() ? fill : 0;
// From POSIX description of the '0' (zero) flag:
// "For d, i, o, u, x, and X conversion specifiers, if a precision
// is specified, the '0' flag is ignored."
- if (!precision_specified && conv.flags().zero) {
+ if (!precision_specified && conv.has_zero_flag()) {
num_zeroes += num_left_spaces;
num_left_spaces = 0;
}
@@ -202,72 +276,97 @@
}
template <typename T>
-bool ConvertIntImplInner(T v, const ConversionSpec conv, FormatSinkImpl *sink) {
- ConvertedIntInfo info(v, conv.conv());
- if (conv.flags().basic && conv.conv().id() != ConversionChar::p) {
- if (info.is_neg()) sink->Append(1, '-');
- if (info.digits().empty()) {
- sink->Append(1, '0');
- } else {
- sink->Append(info.digits());
- }
+bool ConvertIntArg(T v, const FormatConversionSpecImpl conv,
+ FormatSinkImpl *sink) {
+ using U = typename MakeUnsigned<T>::type;
+ IntDigits as_digits;
+
+ // This odd casting is due to a bug in -Wswitch behavior in gcc49 which causes
+ // it to complain about a switch/case type mismatch, even though both are
+ // FormatConverionChar. Likely this is because at this point
+ // FormatConversionChar is declared, but not defined.
+ switch (static_cast<uint8_t>(conv.conversion_char())) {
+ case static_cast<uint8_t>(FormatConversionCharInternal::c):
+ return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink);
+
+ case static_cast<uint8_t>(FormatConversionCharInternal::o):
+ as_digits.PrintAsOct(static_cast<U>(v));
+ break;
+
+ case static_cast<uint8_t>(FormatConversionCharInternal::x):
+ as_digits.PrintAsHexLower(static_cast<U>(v));
+ break;
+ case static_cast<uint8_t>(FormatConversionCharInternal::X):
+ as_digits.PrintAsHexUpper(static_cast<U>(v));
+ break;
+
+ case static_cast<uint8_t>(FormatConversionCharInternal::u):
+ as_digits.PrintAsDec(static_cast<U>(v));
+ break;
+
+ case static_cast<uint8_t>(FormatConversionCharInternal::d):
+ case static_cast<uint8_t>(FormatConversionCharInternal::i):
+ as_digits.PrintAsDec(v);
+ break;
+
+ case static_cast<uint8_t>(FormatConversionCharInternal::a):
+ case static_cast<uint8_t>(FormatConversionCharInternal::e):
+ case static_cast<uint8_t>(FormatConversionCharInternal::f):
+ case static_cast<uint8_t>(FormatConversionCharInternal::g):
+ case static_cast<uint8_t>(FormatConversionCharInternal::A):
+ case static_cast<uint8_t>(FormatConversionCharInternal::E):
+ case static_cast<uint8_t>(FormatConversionCharInternal::F):
+ case static_cast<uint8_t>(FormatConversionCharInternal::G):
+ return ConvertFloatImpl(static_cast<double>(v), conv, sink);
+
+ default:
+ ABSL_INTERNAL_ASSUME(false);
+ }
+
+ if (conv.is_basic()) {
+ sink->Append(as_digits.with_neg_and_zero());
return true;
}
- return ConvertIntImplInner(info, conv, sink);
+ return ConvertIntImplInnerSlow(as_digits, conv, sink);
}
template <typename T>
-bool ConvertIntArg(T v, const ConversionSpec conv, FormatSinkImpl *sink) {
- if (conv.conv().is_float()) {
- return FormatConvertImpl(static_cast<double>(v), conv, sink).value;
- }
- if (conv.conv().id() == ConversionChar::c)
- return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink);
- if (!conv.conv().is_integral())
- return false;
- if (!conv.conv().is_signed() && IsSigned<T>::value) {
- using U = typename MakeUnsigned<T>::type;
- return FormatConvertImpl(static_cast<U>(v), conv, sink).value;
- }
- return ConvertIntImplInner(v, conv, sink);
+bool ConvertFloatArg(T v, const FormatConversionSpecImpl conv,
+ FormatSinkImpl *sink) {
+ return FormatConversionCharIsFloat(conv.conversion_char()) &&
+ ConvertFloatImpl(v, conv, sink);
}
-template <typename T>
-bool ConvertFloatArg(T v, const ConversionSpec conv, FormatSinkImpl *sink) {
- return conv.conv().is_float() && ConvertFloatImpl(v, conv, sink);
-}
-
-inline bool ConvertStringArg(string_view v, const ConversionSpec conv,
+inline bool ConvertStringArg(string_view v, const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
- if (conv.conv().id() != ConversionChar::s)
- return false;
- if (conv.flags().basic) {
+ if (conv.is_basic()) {
sink->Append(v);
return true;
}
return sink->PutPaddedString(v, conv.width(), conv.precision(),
- conv.flags().left);
+ conv.has_left_flag());
}
} // namespace
// ==================== Strings ====================
-ConvertResult<Conv::s> FormatConvertImpl(const std::string &v,
- const ConversionSpec conv,
- FormatSinkImpl *sink) {
+StringConvertResult FormatConvertImpl(const std::string &v,
+ const FormatConversionSpecImpl conv,
+ FormatSinkImpl *sink) {
return {ConvertStringArg(v, conv, sink)};
}
-ConvertResult<Conv::s> FormatConvertImpl(string_view v,
- const ConversionSpec conv,
- FormatSinkImpl *sink) {
+StringConvertResult FormatConvertImpl(string_view v,
+ const FormatConversionSpecImpl conv,
+ FormatSinkImpl *sink) {
return {ConvertStringArg(v, conv, sink)};
}
-ConvertResult<Conv::s | Conv::p> FormatConvertImpl(const char *v,
- const ConversionSpec conv,
- FormatSinkImpl *sink) {
- if (conv.conv().id() == ConversionChar::p)
+ArgConvertResult<FormatConversionCharSetUnion(
+ FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)>
+FormatConvertImpl(const char *v, const FormatConversionSpecImpl conv,
+ FormatSinkImpl *sink) {
+ if (conv.conversion_char() == FormatConversionCharInternal::p)
return {FormatConvertImpl(VoidPtr(v), conv, sink).value};
size_t len;
if (v == nullptr) {
@@ -275,96 +374,106 @@
} else if (conv.precision() < 0) {
len = std::strlen(v);
} else {
- // If precision is set, we look for the null terminator on the valid range.
+ // If precision is set, we look for the NUL-terminator on the valid range.
len = std::find(v, v + conv.precision(), '\0') - v;
}
return {ConvertStringArg(string_view(v, len), conv, sink)};
}
// ==================== Raw pointers ====================
-ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, const ConversionSpec conv,
- FormatSinkImpl *sink) {
- if (conv.conv().id() != ConversionChar::p)
- return {false};
+ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
+ VoidPtr v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
if (!v.value) {
sink->Append("(nil)");
return {true};
}
- return {ConvertIntImplInner(v.value, conv, sink)};
+ IntDigits as_digits;
+ as_digits.PrintAsHexLower(v.value);
+ return {ConvertIntImplInnerSlow(as_digits, conv, sink)};
}
// ==================== Floats ====================
-FloatingConvertResult FormatConvertImpl(float v, const ConversionSpec conv,
+FloatingConvertResult FormatConvertImpl(float v,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertFloatArg(v, conv, sink)};
}
-FloatingConvertResult FormatConvertImpl(double v, const ConversionSpec conv,
+FloatingConvertResult FormatConvertImpl(double v,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertFloatArg(v, conv, sink)};
}
FloatingConvertResult FormatConvertImpl(long double v,
- const ConversionSpec conv,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertFloatArg(v, conv, sink)};
}
// ==================== Chars ====================
-IntegralConvertResult FormatConvertImpl(char v, const ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(char v,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
IntegralConvertResult FormatConvertImpl(signed char v,
- const ConversionSpec conv,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
IntegralConvertResult FormatConvertImpl(unsigned char v,
- const ConversionSpec conv,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
// ==================== Ints ====================
IntegralConvertResult FormatConvertImpl(short v, // NOLINT
- const ConversionSpec conv,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT
- const ConversionSpec conv,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
-IntegralConvertResult FormatConvertImpl(int v, const ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(int v,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
-IntegralConvertResult FormatConvertImpl(unsigned v, const ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(unsigned v,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
IntegralConvertResult FormatConvertImpl(long v, // NOLINT
- const ConversionSpec conv,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT
- const ConversionSpec conv,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
IntegralConvertResult FormatConvertImpl(long long v, // NOLINT
- const ConversionSpec conv,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT
- const ConversionSpec conv,
+ const FormatConversionSpecImpl conv,
+ FormatSinkImpl *sink) {
+ return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(absl::int128 v,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
IntegralConvertResult FormatConvertImpl(absl::uint128 v,
- const ConversionSpec conv,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
@@ -372,6 +481,8 @@
ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_();
+
} // namespace str_format_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/internal/str_format/arg.h b/third_party/abseil/absl/strings/internal/str_format/arg.h
index 5cb3a14..7040c86 100644
--- a/third_party/abseil/absl/strings/internal/str_format/arg.h
+++ b/third_party/abseil/absl/strings/internal/str_format/arg.h
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
@@ -18,24 +32,44 @@
#include "absl/strings/internal/str_format/extension.h"
#include "absl/strings/string_view.h"
-class Cord;
-class CordReader;
-
namespace absl {
+ABSL_NAMESPACE_BEGIN
+class Cord;
class FormatCountCapture;
class FormatSink;
+template <absl::FormatConversionCharSet C>
+struct FormatConvertResult;
+class FormatConversionSpec;
+
namespace str_format_internal {
template <typename T, typename = void>
struct HasUserDefinedConvert : std::false_type {};
template <typename T>
-struct HasUserDefinedConvert<
- T, void_t<decltype(AbslFormatConvert(
- std::declval<const T&>(), std::declval<ConversionSpec>(),
- std::declval<FormatSink*>()))>> : std::true_type {};
+struct HasUserDefinedConvert<T, void_t<decltype(AbslFormatConvert(
+ std::declval<const T&>(),
+ std::declval<const FormatConversionSpec&>(),
+ std::declval<FormatSink*>()))>>
+ : std::true_type {};
+
+void AbslFormatConvert(); // Stops the lexical name lookup
+template <typename T>
+auto FormatConvertImpl(const T& v, FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink)
+ -> decltype(AbslFormatConvert(v,
+ std::declval<const FormatConversionSpec&>(),
+ std::declval<FormatSink*>())) {
+ using FormatConversionSpecT =
+ absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatConversionSpec>;
+ using FormatSinkT =
+ absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatSink>;
+ auto fcs = conv.Wrap<FormatConversionSpecT>();
+ auto fs = sink->Wrap<FormatSinkT>();
+ return AbslFormatConvert(v, fcs, &fs);
+}
template <typename T>
class StreamedWrapper;
@@ -44,6 +78,13 @@
// then convert it, appending to `sink` and return `true`.
// Otherwise fail and return `false`.
+// AbslFormatConvert(v, conv, sink) is intended to be found by ADL on 'v'
+// as an extension mechanism. These FormatConvertImpl functions are the default
+// implementations.
+// The ADL search is augmented via the 'Sink*' parameter, which also
+// serves as a disambiguator to reject possible unintended 'AbslFormatConvert'
+// functions in the namespaces associated with 'v'.
+
// Raw pointers.
struct VoidPtr {
VoidPtr() = default;
@@ -53,28 +94,45 @@
: value(ptr ? reinterpret_cast<uintptr_t>(ptr) : 0) {}
uintptr_t value;
};
-ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, ConversionSpec conv,
- FormatSinkImpl* sink);
+
+template <FormatConversionCharSet C>
+struct ArgConvertResult {
+ bool value;
+};
+
+template <FormatConversionCharSet C>
+constexpr FormatConversionCharSet ExtractCharSet(FormatConvertResult<C>) {
+ return C;
+}
+
+template <FormatConversionCharSet C>
+constexpr FormatConversionCharSet ExtractCharSet(ArgConvertResult<C>) {
+ return C;
+}
+
+using StringConvertResult =
+ ArgConvertResult<FormatConversionCharSetInternal::s>;
+ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
+ VoidPtr v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
// Strings.
-ConvertResult<Conv::s> FormatConvertImpl(const std::string& v,
- ConversionSpec conv,
- FormatSinkImpl* sink);
-ConvertResult<Conv::s> FormatConvertImpl(string_view v, ConversionSpec conv,
- FormatSinkImpl* sink);
-ConvertResult<Conv::s | Conv::p> FormatConvertImpl(const char* v,
- ConversionSpec conv,
- FormatSinkImpl* sink);
-template <class AbslCord,
- typename std::enable_if<
- std::is_same<AbslCord, ::Cord>::value>::type* = nullptr,
- class AbslCordReader = ::CordReader>
-ConvertResult<Conv::s> FormatConvertImpl(const AbslCord& value,
- ConversionSpec conv,
- FormatSinkImpl* sink) {
- if (conv.conv().id() != ConversionChar::s) return {false};
+StringConvertResult FormatConvertImpl(const std::string& v,
+ FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink);
+StringConvertResult FormatConvertImpl(string_view v,
+ FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink);
+ArgConvertResult<FormatConversionCharSetUnion(
+ FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)>
+FormatConvertImpl(const char* v, const FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink);
- bool is_left = conv.flags().left;
+template <class AbslCord, typename std::enable_if<std::is_same<
+ AbslCord, absl::Cord>::value>::type* = nullptr>
+StringConvertResult FormatConvertImpl(const AbslCord& value,
+ FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink) {
+ bool is_left = conv.has_left_flag();
size_t space_remaining = 0;
int width = conv.width();
@@ -90,64 +148,80 @@
if (space_remaining > 0 && !is_left) sink->Append(space_remaining, ' ');
- string_view piece;
- for (AbslCordReader reader(value);
- to_write > 0 && reader.ReadFragment(&piece); to_write -= piece.size()) {
- if (piece.size() > to_write) piece.remove_suffix(piece.size() - to_write);
+ for (string_view piece : value.Chunks()) {
+ if (piece.size() > to_write) {
+ piece.remove_suffix(piece.size() - to_write);
+ to_write = 0;
+ } else {
+ to_write -= piece.size();
+ }
sink->Append(piece);
+ if (to_write == 0) {
+ break;
+ }
}
if (space_remaining > 0 && is_left) sink->Append(space_remaining, ' ');
return {true};
}
-using IntegralConvertResult =
- ConvertResult<Conv::c | Conv::numeric | Conv::star>;
-using FloatingConvertResult = ConvertResult<Conv::floating>;
+using IntegralConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
+ FormatConversionCharSetInternal::c,
+ FormatConversionCharSetInternal::kNumeric,
+ FormatConversionCharSetInternal::kStar)>;
+using FloatingConvertResult =
+ ArgConvertResult<FormatConversionCharSetInternal::kFloating>;
// Floats.
-FloatingConvertResult FormatConvertImpl(float v, ConversionSpec conv,
+FloatingConvertResult FormatConvertImpl(float v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-FloatingConvertResult FormatConvertImpl(double v, ConversionSpec conv,
+FloatingConvertResult FormatConvertImpl(double v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-FloatingConvertResult FormatConvertImpl(long double v, ConversionSpec conv,
+FloatingConvertResult FormatConvertImpl(long double v,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
// Chars.
-IntegralConvertResult FormatConvertImpl(char v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(signed char v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(signed char v,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(unsigned char v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(unsigned char v,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
// Ints.
IntegralConvertResult FormatConvertImpl(short v, // NOLINT
- ConversionSpec conv,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT
- ConversionSpec conv,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(int v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(int v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(unsigned v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(unsigned v,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(long v, // NOLINT
- ConversionSpec conv,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT
- ConversionSpec conv,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(long long v, // NOLINT
- ConversionSpec conv,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT
- ConversionSpec conv,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(uint128 v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(int128 v, FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(uint128 v,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0>
-IntegralConvertResult FormatConvertImpl(T v, ConversionSpec conv,
+IntegralConvertResult FormatConvertImpl(T v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink) {
return FormatConvertImpl(static_cast<int>(v), conv, sink);
}
@@ -158,12 +232,12 @@
typename std::enable_if<std::is_enum<T>::value &&
!HasUserDefinedConvert<T>::value,
IntegralConvertResult>::type
-FormatConvertImpl(T v, ConversionSpec conv, FormatSinkImpl* sink);
+FormatConvertImpl(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
template <typename T>
-ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<T>& v,
- ConversionSpec conv,
- FormatSinkImpl* out) {
+StringConvertResult FormatConvertImpl(const StreamedWrapper<T>& v,
+ FormatConversionSpecImpl conv,
+ FormatSinkImpl* out) {
std::ostringstream oss;
oss << v.v_;
if (!oss) return {false};
@@ -174,22 +248,24 @@
// until after FormatCountCapture is fully defined.
struct FormatCountCaptureHelper {
template <class T = int>
- static ConvertResult<Conv::n> ConvertHelper(const FormatCountCapture& v,
- ConversionSpec conv,
- FormatSinkImpl* sink) {
+ static ArgConvertResult<FormatConversionCharSetInternal::n> ConvertHelper(
+ const FormatCountCapture& v, FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink) {
const absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v;
- if (conv.conv().id() != str_format_internal::ConversionChar::n)
+ if (conv.conversion_char() !=
+ str_format_internal::FormatConversionCharInternal::n) {
return {false};
+ }
*v2.p_ = static_cast<int>(sink->size());
return {true};
}
};
template <class T = int>
-ConvertResult<Conv::n> FormatConvertImpl(const FormatCountCapture& v,
- ConversionSpec conv,
- FormatSinkImpl* sink) {
+ArgConvertResult<FormatConversionCharSetInternal::n> FormatConvertImpl(
+ const FormatCountCapture& v, FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink) {
return FormatCountCaptureHelper::ConvertHelper(v, conv, sink);
}
@@ -198,13 +274,13 @@
struct FormatArgImplFriend {
template <typename Arg>
static bool ToInt(Arg arg, int* out) {
- // A value initialized ConversionSpec has a `none` conv, which tells the
- // dispatcher to run the `int` conversion.
+ // A value initialized FormatConversionSpecImpl has a `none` conv, which
+ // tells the dispatcher to run the `int` conversion.
return arg.dispatcher_(arg.data_, {}, out);
}
template <typename Arg>
- static bool Convert(Arg arg, str_format_internal::ConversionSpec conv,
+ static bool Convert(Arg arg, FormatConversionSpecImpl conv,
FormatSinkImpl* out) {
return arg.dispatcher_(arg.data_, conv, out);
}
@@ -215,6 +291,15 @@
}
};
+template <typename Arg>
+constexpr FormatConversionCharSet ArgumentToConv() {
+ return absl::str_format_internal::ExtractCharSet(
+ decltype(str_format_internal::FormatConvertImpl(
+ std::declval<const Arg&>(),
+ std::declval<const FormatConversionSpecImpl&>(),
+ std::declval<FormatSinkImpl*>())){});
+}
+
// A type-erased handle to a format argument.
class FormatArgImpl {
private:
@@ -228,7 +313,7 @@
char buf[kInlinedSpace];
};
- using Dispatcher = bool (*)(Data, ConversionSpec, void* out);
+ using Dispatcher = bool (*)(Data, FormatConversionSpecImpl, void* out);
template <typename T>
struct store_by_value
@@ -370,15 +455,20 @@
}
template <typename T>
- static bool Dispatch(Data arg, ConversionSpec spec, void* out) {
+ static bool Dispatch(Data arg, FormatConversionSpecImpl spec, void* out) {
// A `none` conv indicates that we want the `int` conversion.
- if (ABSL_PREDICT_FALSE(spec.conv().id() == ConversionChar::none)) {
+ if (ABSL_PREDICT_FALSE(spec.conversion_char() ==
+ FormatConversionCharInternal::kNone)) {
return ToInt<T>(arg, static_cast<int*>(out), std::is_integral<T>(),
std::is_enum<T>());
}
-
+ if (ABSL_PREDICT_FALSE(!Contains(ArgumentToConv<T>(),
+ spec.conversion_char()))) {
+ return false;
+ }
return str_format_internal::FormatConvertImpl(
- Manager<T>::Value(arg), spec, static_cast<FormatSinkImpl*>(out))
+ Manager<T>::Value(arg), spec,
+ static_cast<FormatSinkImpl*>(out))
.value;
}
@@ -386,8 +476,9 @@
Dispatcher dispatcher_;
};
-#define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E) \
- E template bool FormatArgImpl::Dispatch<T>(Data, ConversionSpec, void*)
+#define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E) \
+ E template bool FormatArgImpl::Dispatch<T>(Data, FormatConversionSpecImpl, \
+ void*)
#define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...) \
ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(str_format_internal::VoidPtr, \
@@ -408,6 +499,7 @@
__VA_ARGS__); \
ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long long, /* NOLINT */ \
__VA_ARGS__); \
+ ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(int128, __VA_ARGS__); \
ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(uint128, __VA_ARGS__); \
ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(float, __VA_ARGS__); \
ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(double, __VA_ARGS__); \
@@ -418,7 +510,9 @@
ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(extern);
+
} // namespace str_format_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
diff --git a/third_party/abseil/absl/strings/internal/str_format/arg_test.cc b/third_party/abseil/absl/strings/internal/str_format/arg_test.cc
index 3421fac..1261937 100644
--- a/third_party/abseil/absl/strings/internal/str_format/arg_test.cc
+++ b/third_party/abseil/absl/strings/internal/str_format/arg_test.cc
@@ -6,6 +6,12 @@
//
// https://www.apache.org/licenses/LICENSE-2.0
//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
#include "absl/strings/internal/str_format/arg.h"
#include <ostream>
@@ -14,6 +20,7 @@
#include "absl/strings/str_format.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
namespace {
@@ -22,8 +29,17 @@
enum Color { kRed, kGreen, kBlue };
static const char *hi() { return "hi"; }
+
+ struct X {};
+
+ X x_;
};
+inline FormatConvertResult<FormatConversionCharSet{}> AbslFormatConvert(
+ const FormatArgImplTest::X &, const FormatConversionSpec &, FormatSink *) {
+ return {false};
+}
+
TEST_F(FormatArgImplTest, ToInt) {
int out = 0;
EXPECT_TRUE(FormatArgImplFriend::ToInt(FormatArgImpl(1), &out));
@@ -58,6 +74,7 @@
FormatArgImpl(static_cast<int *>(nullptr)), &out));
EXPECT_FALSE(FormatArgImplFriend::ToInt(FormatArgImpl(hi()), &out));
EXPECT_FALSE(FormatArgImplFriend::ToInt(FormatArgImpl("hi"), &out));
+ EXPECT_FALSE(FormatArgImplFriend::ToInt(FormatArgImpl(x_), &out));
EXPECT_TRUE(FormatArgImplFriend::ToInt(FormatArgImpl(kBlue), &out));
EXPECT_EQ(2, out);
}
@@ -94,11 +111,12 @@
TEST_F(FormatArgImplTest, WorksWithCharArraysOfUnknownSize) {
std::string s;
FormatSinkImpl sink(&s);
- ConversionSpec conv;
- conv.set_conv(ConversionChar::FromChar('s'));
- conv.set_flags(Flags());
- conv.set_width(-1);
- conv.set_precision(-1);
+ FormatConversionSpecImpl conv;
+ FormatConversionSpecImplFriend::SetConversionChar(
+ FormatConversionCharInternal::s, &conv);
+ FormatConversionSpecImplFriend::SetFlags(Flags(), &conv);
+ FormatConversionSpecImplFriend::SetWidth(-1, &conv);
+ FormatConversionSpecImplFriend::SetPrecision(-1, &conv);
EXPECT_TRUE(
FormatArgImplFriend::Convert(FormatArgImpl(kMyArray), conv, &sink));
sink.Flush();
@@ -108,4 +126,5 @@
} // namespace
} // namespace str_format_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/internal/str_format/bind.cc b/third_party/abseil/absl/strings/internal/str_format/bind.cc
index a31859e..4e68b90 100644
--- a/third_party/abseil/absl/strings/internal/str_format/bind.cc
+++ b/third_party/abseil/absl/strings/internal/str_format/bind.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
#include "absl/strings/internal/str_format/bind.h"
#include <cerrno>
@@ -6,6 +20,7 @@
#include <string>
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
namespace {
@@ -65,19 +80,22 @@
return false;
}
- bound->set_width(width);
- bound->set_precision(precision);
- bound->set_flags(unbound->flags);
- if (force_left)
- bound->set_left(true);
- } else {
- bound->set_flags(unbound->flags);
- bound->set_width(-1);
- bound->set_precision(-1);
- }
+ FormatConversionSpecImplFriend::SetWidth(width, bound);
+ FormatConversionSpecImplFriend::SetPrecision(precision, bound);
- bound->set_length_mod(unbound->length_mod);
- bound->set_conv(unbound->conv);
+ if (force_left) {
+ Flags flags = unbound->flags;
+ flags.left = true;
+ FormatConversionSpecImplFriend::SetFlags(flags, bound);
+ } else {
+ FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound);
+ }
+ } else {
+ FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound);
+ FormatConversionSpecImplFriend::SetWidth(-1, bound);
+ FormatConversionSpecImplFriend::SetPrecision(-1, bound);
+ }
+ FormatConversionSpecImplFriend::SetConversionChar(unbound->conv, bound);
bound->set_arg(arg);
return true;
}
@@ -139,10 +157,11 @@
UntypedFormatSpecImpl spec("%d");
std::ostringstream ss;
- ss << "{" << Streamable(spec, {*bound.arg()}) << ":" << bound.flags();
+ ss << "{" << Streamable(spec, {*bound.arg()}) << ":"
+ << FormatConversionSpecImplFriend::FlagsToString(bound);
if (bound.width() >= 0) ss << bound.width();
if (bound.precision() >= 0) ss << "." << bound.precision();
- ss << bound.length_mod() << bound.conv() << "}";
+ ss << bound.conversion_char() << "}";
Append(ss.str());
return true;
}
@@ -196,6 +215,15 @@
return *out;
}
+std::string FormatPack(const UntypedFormatSpecImpl format,
+ absl::Span<const FormatArgImpl> args) {
+ std::string out;
+ if (ABSL_PREDICT_FALSE(!FormatUntyped(&out, format, args))) {
+ out.clear();
+ }
+ return out;
+}
+
int FprintF(std::FILE* output, const UntypedFormatSpecImpl format,
absl::Span<const FormatArgImpl> args) {
FILERawSink sink(output);
@@ -207,7 +235,7 @@
errno = sink.error();
return -1;
}
- if (sink.count() > std::numeric_limits<int>::max()) {
+ if (sink.count() > static_cast<size_t>(std::numeric_limits<int>::max())) {
errno = EFBIG;
return -1;
}
@@ -227,4 +255,5 @@
}
} // namespace str_format_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/internal/str_format/bind.h b/third_party/abseil/absl/strings/internal/str_format/bind.h
index 7df140a..267cc0e 100644
--- a/third_party/abseil/absl/strings/internal/str_format/bind.h
+++ b/third_party/abseil/absl/strings/internal/str_format/bind.h
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
@@ -13,12 +27,13 @@
#include "absl/types/span.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
class UntypedFormatSpec;
namespace str_format_internal {
-class BoundConversion : public ConversionSpec {
+class BoundConversion : public FormatConversionSpecImpl {
public:
const FormatArgImpl* arg() const { return arg_; }
void set_arg(const FormatArgImpl* a) { arg_ = a; }
@@ -59,7 +74,7 @@
size_t size_;
};
-template <typename T, typename...>
+template <typename T, FormatConversionCharSet...>
struct MakeDependent {
using type = T;
};
@@ -67,19 +82,19 @@
// Implicitly convertible from `const char*`, `string_view`, and the
// `ExtendedParsedFormat` type. This abstraction allows all format functions to
// operate on any without providing too many overloads.
-template <typename... Args>
+template <FormatConversionCharSet... Args>
class FormatSpecTemplate
: public MakeDependent<UntypedFormatSpec, Args...>::type {
using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type;
public:
-#if ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+#ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
- // Honeypot overload for when the std::string is not constexpr.
+ // Honeypot overload for when the string is not constexpr.
// We use the 'unavailable' attribute to give a better compiler error than
// just 'method is deleted'.
FormatSpecTemplate(...) // NOLINT
- __attribute__((unavailable("Format std::string is not constexpr.")));
+ __attribute__((unavailable("Format string is not constexpr.")));
// Honeypot overload for when the format is constexpr and invalid.
// We use the 'unavailable' attribute to give a better compiler error than
@@ -104,13 +119,11 @@
// Good format overload.
FormatSpecTemplate(const char* s) // NOLINT
- __attribute__((enable_if(ValidFormatImpl<ArgumentToConv<Args>()...>(s),
- "bad format trap")))
+ __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap")))
: Base(s) {}
FormatSpecTemplate(string_view s) // NOLINT
- __attribute__((enable_if(ValidFormatImpl<ArgumentToConv<Args>()...>(s),
- "bad format trap")))
+ __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap")))
: Base(s) {}
#else // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
@@ -120,19 +133,15 @@
#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
- template <Conv... C, typename = typename std::enable_if<
- sizeof...(C) == sizeof...(Args) &&
- AllOf(Contains(ArgumentToConv<Args>(),
- C)...)>::type>
+ template <
+ FormatConversionCharSet... C,
+ typename = typename std::enable_if<sizeof...(C) == sizeof...(Args)>::type,
+ typename = typename std::enable_if<AllOf(Contains(Args,
+ C)...)>::type>
FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc) // NOLINT
: Base(&pc) {}
};
-template <typename... Args>
-struct FormatSpecDeductionBarrier {
- using type = FormatSpecTemplate<Args...>;
-};
-
class Streamable {
public:
Streamable(const UntypedFormatSpecImpl& format,
@@ -178,12 +187,8 @@
std::string& AppendPack(std::string* out, UntypedFormatSpecImpl format,
absl::Span<const FormatArgImpl> args);
-inline std::string FormatPack(const UntypedFormatSpecImpl format,
- absl::Span<const FormatArgImpl> args) {
- std::string out;
- AppendPack(&out, format, args);
- return out;
-}
+std::string FormatPack(const UntypedFormatSpecImpl format,
+ absl::Span<const FormatArgImpl> args);
int FprintF(std::FILE* output, UntypedFormatSpecImpl format,
absl::Span<const FormatArgImpl> args);
@@ -199,13 +204,14 @@
private:
template <typename S>
- friend ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<S>& v,
- ConversionSpec conv,
- FormatSinkImpl* out);
+ friend ArgConvertResult<FormatConversionCharSetInternal::s> FormatConvertImpl(
+ const StreamedWrapper<S>& v, FormatConversionSpecImpl conv,
+ FormatSinkImpl* out);
const T& v_;
};
} // namespace str_format_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
diff --git a/third_party/abseil/absl/strings/internal/str_format/bind_test.cc b/third_party/abseil/absl/strings/internal/str_format/bind_test.cc
index 2574801..1eef9c4 100644
--- a/third_party/abseil/absl/strings/internal/str_format/bind_test.cc
+++ b/third_party/abseil/absl/strings/internal/str_format/bind_test.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
#include "absl/strings/internal/str_format/bind.h"
#include <string.h>
@@ -6,6 +20,7 @@
#include "gtest/gtest.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
namespace {
@@ -112,18 +127,18 @@
FormatArgImpl(ia[2]), FormatArgImpl(ia[3]),
FormatArgImpl(ia[4])};
const Expectation kExpect[] = {
- {__LINE__, "a%4db%dc", "a{10:4d}b{20:d}c"},
- {__LINE__, "a%.4db%dc", "a{10:.4d}b{20:d}c"},
- {__LINE__, "a%4.5db%dc", "a{10:4.5d}b{20:d}c"},
- {__LINE__, "a%db%4.5dc", "a{10:d}b{20:4.5d}c"},
- {__LINE__, "a%db%*.*dc", "a{10:d}b{40:20.30d}c"},
- {__LINE__, "a%.*fb", "a{20:.10f}b"},
- {__LINE__, "a%1$db%2$*3$.*4$dc", "a{10:d}b{20:30.40d}c"},
- {__LINE__, "a%4$db%3$*2$.*1$dc", "a{40:d}b{30:20.10d}c"},
- {__LINE__, "a%04ldb", "a{10:04ld}b"},
- {__LINE__, "a%-#04lldb", "a{10:-#04lld}b"},
- {__LINE__, "a%1$*5$db", "a{10:-10d}b"},
- {__LINE__, "a%1$.*5$db", "a{10:d}b"},
+ {__LINE__, "a%4db%dc", "a{10:4d}b{20:d}c"},
+ {__LINE__, "a%.4db%dc", "a{10:.4d}b{20:d}c"},
+ {__LINE__, "a%4.5db%dc", "a{10:4.5d}b{20:d}c"},
+ {__LINE__, "a%db%4.5dc", "a{10:d}b{20:4.5d}c"},
+ {__LINE__, "a%db%*.*dc", "a{10:d}b{40:20.30d}c"},
+ {__LINE__, "a%.*fb", "a{20:.10f}b"},
+ {__LINE__, "a%1$db%2$*3$.*4$dc", "a{10:d}b{20:30.40d}c"},
+ {__LINE__, "a%4$db%3$*2$.*1$dc", "a{40:d}b{30:20.10d}c"},
+ {__LINE__, "a%04ldb", "a{10:04d}b"},
+ {__LINE__, "a%-#04lldb", "a{10:-#04d}b"},
+ {__LINE__, "a%1$*5$db", "a{10:-10d}b"},
+ {__LINE__, "a%1$.*5$db", "a{10:d}b"},
};
for (const Expectation &e : kExpect) {
absl::string_view fmt = e.fmt;
@@ -138,4 +153,5 @@
} // namespace
} // namespace str_format_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/internal/str_format/checker.h b/third_party/abseil/absl/strings/internal/str_format/checker.h
index 8b594f2..2a2601e 100644
--- a/third_party/abseil/absl/strings/internal/str_format/checker.h
+++ b/third_party/abseil/absl/strings/internal/str_format/checker.h
@@ -1,20 +1,34 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
+#include "absl/base/attributes.h"
#include "absl/strings/internal/str_format/arg.h"
#include "absl/strings/internal/str_format/extension.h"
// Compile time check support for entry points.
#ifndef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
-#if defined(__clang__) && !defined(__native_client__)
-#if __has_attribute(enable_if)
+#if ABSL_HAVE_ATTRIBUTE(enable_if) && !defined(__native_client__)
#define ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 1
-#endif // __has_attribute(enable_if)
-#endif // defined(__clang__) && !defined(__native_client__)
+#endif // ABSL_HAVE_ATTRIBUTE(enable_if) && !defined(__native_client__)
#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
constexpr bool AllOf() { return true; }
@@ -24,14 +38,7 @@
return b && AllOf(t...);
}
-template <typename Arg>
-constexpr Conv ArgumentToConv() {
- return decltype(str_format_internal::FormatConvertImpl(
- std::declval<const Arg&>(), std::declval<const ConversionSpec&>(),
- std::declval<FormatSinkImpl*>()))::kConv;
-}
-
-#if ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+#ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
constexpr bool ContainsChar(const char* chars, char c) {
return *chars == c || (*chars && ContainsChar(chars + 1, c));
@@ -39,14 +46,14 @@
// A constexpr compatible list of Convs.
struct ConvList {
- const Conv* array;
+ const FormatConversionCharSet* array;
int count;
// We do the bound check here to avoid having to do it on the callers.
- // Returning an empty Conv has the same effect as short circuiting because it
- // will never match any conversion.
- constexpr Conv operator[](int i) const {
- return i < count ? array[i] : Conv{};
+ // Returning an empty FormatConversionCharSet has the same effect as
+ // short circuiting because it will never match any conversion.
+ constexpr FormatConversionCharSet operator[](int i) const {
+ return i < count ? array[i] : FormatConversionCharSet{};
}
constexpr ConvList without_front() const {
@@ -57,7 +64,7 @@
template <size_t count>
struct ConvListT {
// Make sure the array has size > 0.
- Conv list[count ? count : 1];
+ FormatConversionCharSet list[count ? count : 1];
};
constexpr char GetChar(string_view str, size_t index) {
@@ -310,7 +317,7 @@
ConvList args_;
};
-template <Conv... C>
+template <FormatConversionCharSet... C>
constexpr bool ValidFormatImpl(string_view format) {
return FormatParser(format,
{ConvListT<sizeof...(C)>{{C...}}.list, sizeof...(C)})
@@ -320,6 +327,7 @@
#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
} // namespace str_format_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
diff --git a/third_party/abseil/absl/strings/internal/str_format/checker_test.cc b/third_party/abseil/absl/strings/internal/str_format/checker_test.cc
index c1d8c76..7c70f47 100644
--- a/third_party/abseil/absl/strings/internal/str_format/checker_test.cc
+++ b/third_party/abseil/absl/strings/internal/str_format/checker_test.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
#include <string>
#include "gmock/gmock.h"
@@ -5,21 +19,26 @@
#include "absl/strings/str_format.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
namespace {
-std::string ConvToString(Conv conv) {
+std::string ConvToString(FormatConversionCharSet conv) {
std::string out;
-#define CONV_SET_CASE(c) \
- if (Contains(conv, Conv::c)) out += #c;
- ABSL_CONVERSION_CHARS_EXPAND_(CONV_SET_CASE, )
+#define CONV_SET_CASE(c) \
+ if (Contains(conv, FormatConversionCharSetInternal::c)) { \
+ out += #c; \
+ }
+ ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(CONV_SET_CASE, )
#undef CONV_SET_CASE
- if (Contains(conv, Conv::star)) out += "*";
+ if (Contains(conv, FormatConversionCharSetInternal::kStar)) {
+ out += "*";
+ }
return out;
}
TEST(StrFormatChecker, ArgumentToConv) {
- Conv conv = ArgumentToConv<std::string>();
+ FormatConversionCharSet conv = ArgumentToConv<std::string>();
EXPECT_EQ(ConvToString(conv), "s");
conv = ArgumentToConv<const char*>();
@@ -35,7 +54,7 @@
EXPECT_EQ(ConvToString(conv), "p");
}
-#if ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+#ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
struct Case {
bool result;
@@ -147,4 +166,5 @@
} // namespace
} // namespace str_format_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/internal/str_format/convert_test.cc b/third_party/abseil/absl/strings/internal/str_format/convert_test.cc
index 814ccf4..375db0a 100644
--- a/third_party/abseil/absl/strings/internal/str_format/convert_test.cc
+++ b/third_party/abseil/absl/strings/internal/str_format/convert_test.cc
@@ -1,17 +1,46 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
+
#include <cctype>
#include <cmath>
+#include <limits>
#include <string>
+#include <thread> // NOLINT
+#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
#include "absl/strings/internal/str_format/bind.h"
+#include "absl/strings/match.h"
+#include "absl/types/optional.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
namespace {
+struct NativePrintfTraits {
+ bool hex_float_has_glibc_rounding;
+ bool hex_float_prefers_denormal_repr;
+ bool hex_float_uses_minimal_precision_when_not_specified;
+ bool hex_float_optimizes_leading_digit_bit_count;
+};
+
template <typename T, size_t N>
size_t ArraySize(T (&)[N]) {
return N;
@@ -54,7 +83,7 @@
return oss.str();
}
-void StrAppend(std::string *dst, const char *format, va_list ap) {
+void StrAppendV(std::string *dst, const char *format, va_list ap) {
// First try with a small fixed size buffer
static const int kSpaceLength = 1024;
char space[kSpaceLength];
@@ -95,15 +124,79 @@
delete[] buf;
}
+void StrAppend(std::string *out, const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ StrAppendV(out, format, ap);
+ va_end(ap);
+}
+
std::string StrPrint(const char *format, ...) {
va_list ap;
va_start(ap, format);
std::string result;
- StrAppend(&result, format, ap);
+ StrAppendV(&result, format, ap);
va_end(ap);
return result;
}
+NativePrintfTraits VerifyNativeImplementationImpl() {
+ NativePrintfTraits result;
+
+ // >>> hex_float_has_glibc_rounding. To have glibc's rounding behavior we need
+ // to meet three requirements:
+ //
+ // - The threshold for rounding up is 8 (for e.g. MSVC uses 9).
+ // - If the digits lower than than the 8 are non-zero then we round up.
+ // - If the digits lower than the 8 are all zero then we round toward even.
+ //
+ // The numbers below represent all the cases covering {below,at,above} the
+ // threshold (8) with both {zero,non-zero} lower bits and both {even,odd}
+ // preceding digits.
+ const double d0079 = 65657.0; // 0x1.0079p+16
+ const double d0179 = 65913.0; // 0x1.0179p+16
+ const double d0080 = 65664.0; // 0x1.0080p+16
+ const double d0180 = 65920.0; // 0x1.0180p+16
+ const double d0081 = 65665.0; // 0x1.0081p+16
+ const double d0181 = 65921.0; // 0x1.0181p+16
+ result.hex_float_has_glibc_rounding =
+ StartsWith(StrPrint("%.2a", d0079), "0x1.00") &&
+ StartsWith(StrPrint("%.2a", d0179), "0x1.01") &&
+ StartsWith(StrPrint("%.2a", d0080), "0x1.00") &&
+ StartsWith(StrPrint("%.2a", d0180), "0x1.02") &&
+ StartsWith(StrPrint("%.2a", d0081), "0x1.01") &&
+ StartsWith(StrPrint("%.2a", d0181), "0x1.02");
+
+ // >>> hex_float_prefers_denormal_repr. Formatting `denormal` on glibc yields
+ // "0x0.0000000000001p-1022", whereas on std libs that don't use denormal
+ // representation it would either be 0x1p-1074 or 0x1.0000000000000-1074.
+ const double denormal = std::numeric_limits<double>::denorm_min();
+ result.hex_float_prefers_denormal_repr =
+ StartsWith(StrPrint("%a", denormal), "0x0.0000000000001");
+
+ // >>> hex_float_uses_minimal_precision_when_not_specified. Some (non-glibc)
+ // libs will format the following as "0x1.0079000000000p+16".
+ result.hex_float_uses_minimal_precision_when_not_specified =
+ (StrPrint("%a", d0079) == "0x1.0079p+16");
+
+ // >>> hex_float_optimizes_leading_digit_bit_count. The number 1.5, when
+ // formatted by glibc should yield "0x1.8p+0" for `double` and "0xcp-3" for
+ // `long double`, i.e., number of bits in the leading digit is adapted to the
+ // number of bits in the mantissa.
+ const double d_15 = 1.5;
+ const long double ld_15 = 1.5;
+ result.hex_float_optimizes_leading_digit_bit_count =
+ StartsWith(StrPrint("%a", d_15), "0x1.8") &&
+ StartsWith(StrPrint("%La", ld_15), "0xc");
+
+ return result;
+}
+
+const NativePrintfTraits &VerifyNativeImplementation() {
+ static NativePrintfTraits native_traits = VerifyNativeImplementationImpl();
+ return native_traits;
+}
+
class FormatConvertTest : public ::testing::Test { };
template <typename T>
@@ -151,18 +244,26 @@
UntypedFormatSpecImpl format("%.1s");
EXPECT_EQ("a", FormatPack(format, {FormatArgImpl(p)}));
- // We cap at the nul terminator.
+ // We cap at the NUL-terminator.
p = "ABC";
UntypedFormatSpecImpl format2("%.10s");
EXPECT_EQ("ABC", FormatPack(format2, {FormatArgImpl(p)}));
}
+// Pointer formatting is implementation defined. This checks that the argument
+// can be matched to `ptr`.
+MATCHER_P(MatchesPointerString, ptr, "") {
+ if (ptr == nullptr && arg == "(nil)") {
+ return true;
+ }
+ void* parsed = nullptr;
+ if (sscanf(arg.c_str(), "%p", &parsed) != 1) {
+ ABSL_RAW_LOG(FATAL, "Could not parse %s", arg.c_str());
+ }
+ return ptr == parsed;
+}
+
TEST_F(FormatConvertTest, Pointer) {
-#ifdef _MSC_VER
- // MSVC's printf implementation prints pointers differently. We can't easily
- // compare our implementation to theirs.
- return;
-#endif
static int x = 0;
const int *xp = &x;
char c = 'h';
@@ -173,48 +274,62 @@
using VoidF = void (*)();
VoidF fp = [] {}, fnil = nullptr;
volatile char vc;
- volatile char* vcp = &vc;
- volatile char* vcnil = nullptr;
- const FormatArgImpl args[] = {
+ volatile char *vcp = &vc;
+ volatile char *vcnil = nullptr;
+ const FormatArgImpl args_array[] = {
FormatArgImpl(xp), FormatArgImpl(cp), FormatArgImpl(inil),
FormatArgImpl(cnil), FormatArgImpl(mcp), FormatArgImpl(fp),
FormatArgImpl(fnil), FormatArgImpl(vcp), FormatArgImpl(vcnil),
};
- struct Expectation {
- std::string out;
- const char *fmt;
- };
- const Expectation kExpect[] = {
- {StrPrint("%p", &x), "%p"},
- {StrPrint("%20p", &x), "%20p"},
- {StrPrint("%.1p", &x), "%.1p"},
- {StrPrint("%.20p", &x), "%.20p"},
- {StrPrint("%30.20p", &x), "%30.20p"},
+ auto args = absl::MakeConstSpan(args_array);
- {StrPrint("%-p", &x), "%-p"},
- {StrPrint("%-20p", &x), "%-20p"},
- {StrPrint("%-.1p", &x), "%-.1p"},
- {StrPrint("%.20p", &x), "%.20p"},
- {StrPrint("%-30.20p", &x), "%-30.20p"},
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%p"), args),
+ MatchesPointerString(&x));
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%20p"), args),
+ MatchesPointerString(&x));
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%.1p"), args),
+ MatchesPointerString(&x));
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%.20p"), args),
+ MatchesPointerString(&x));
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%30.20p"), args),
+ MatchesPointerString(&x));
- {StrPrint("%p", cp), "%2$p"}, // const char*
- {"(nil)", "%3$p"}, // null const char *
- {"(nil)", "%4$p"}, // null const int *
- {StrPrint("%p", mcp), "%5$p"}, // nonconst char*
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%-p"), args),
+ MatchesPointerString(&x));
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%-20p"), args),
+ MatchesPointerString(&x));
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%-.1p"), args),
+ MatchesPointerString(&x));
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%.20p"), args),
+ MatchesPointerString(&x));
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%-30.20p"), args),
+ MatchesPointerString(&x));
- {StrPrint("%p", fp), "%6$p"}, // function pointer
- {StrPrint("%p", vcp), "%8$p"}, // function pointer
+ // const char*
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%2$p"), args),
+ MatchesPointerString(cp));
+ // null const int*
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%3$p"), args),
+ MatchesPointerString(nullptr));
+ // null const char*
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%4$p"), args),
+ MatchesPointerString(nullptr));
+ // nonconst char*
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%5$p"), args),
+ MatchesPointerString(mcp));
-#ifndef __APPLE__
- // Apple's printf differs here (0x0 vs. nil)
- {StrPrint("%p", fnil), "%7$p"}, // null function pointer
- {StrPrint("%p", vcnil), "%9$p"}, // null function pointer
-#endif
- };
- for (const Expectation &e : kExpect) {
- UntypedFormatSpecImpl format(e.fmt);
- EXPECT_EQ(e.out, FormatPack(format, absl::MakeSpan(args))) << e.fmt;
- }
+ // function pointers
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%6$p"), args),
+ MatchesPointerString(reinterpret_cast<const void*>(fp)));
+ EXPECT_THAT(
+ FormatPack(UntypedFormatSpecImpl("%8$p"), args),
+ MatchesPointerString(reinterpret_cast<volatile const void *>(vcp)));
+
+ // null function pointers
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%7$p"), args),
+ MatchesPointerString(nullptr));
+ EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%9$p"), args),
+ MatchesPointerString(nullptr));
}
struct Cardinal {
@@ -366,7 +481,6 @@
AllIntTypes;
INSTANTIATE_TYPED_TEST_CASE_P(TypedFormatConvertTestWithAllIntTypes,
TypedFormatConvertTest, AllIntTypes);
-
TEST_F(FormatConvertTest, VectorBool) {
// Make sure vector<bool>'s values behave as bools.
std::vector<bool> v = {true, false};
@@ -378,6 +492,42 @@
FormatArgImpl(cv[0]), FormatArgImpl(cv[1])})));
}
+
+TEST_F(FormatConvertTest, Int128) {
+ absl::int128 positive = static_cast<absl::int128>(0x1234567890abcdef) * 1979;
+ absl::int128 negative = -positive;
+ absl::int128 max = absl::Int128Max(), min = absl::Int128Min();
+ const FormatArgImpl args[] = {FormatArgImpl(positive),
+ FormatArgImpl(negative), FormatArgImpl(max),
+ FormatArgImpl(min)};
+
+ struct Case {
+ const char* format;
+ const char* expected;
+ } cases[] = {
+ {"%1$d", "2595989796776606496405"},
+ {"%1$30d", " 2595989796776606496405"},
+ {"%1$-30d", "2595989796776606496405 "},
+ {"%1$u", "2595989796776606496405"},
+ {"%1$x", "8cba9876066020f695"},
+ {"%2$d", "-2595989796776606496405"},
+ {"%2$30d", " -2595989796776606496405"},
+ {"%2$-30d", "-2595989796776606496405 "},
+ {"%2$u", "340282366920938460867384810655161715051"},
+ {"%2$x", "ffffffffffffff73456789f99fdf096b"},
+ {"%3$d", "170141183460469231731687303715884105727"},
+ {"%3$u", "170141183460469231731687303715884105727"},
+ {"%3$x", "7fffffffffffffffffffffffffffffff"},
+ {"%4$d", "-170141183460469231731687303715884105728"},
+ {"%4$x", "80000000000000000000000000000000"},
+ };
+
+ for (auto c : cases) {
+ UntypedFormatSpecImpl format(c.format);
+ EXPECT_EQ(c.expected, FormatPack(format, absl::MakeSpan(args)));
+ }
+}
+
TEST_F(FormatConvertTest, Uint128) {
absl::uint128 v = static_cast<absl::uint128>(0x1234567890abcdef) * 1979;
absl::uint128 max = absl::Uint128Max();
@@ -403,6 +553,68 @@
}
}
+template <typename Floating>
+void TestWithMultipleFormatsHelper(const std::vector<Floating> &floats) {
+ const NativePrintfTraits &native_traits = VerifyNativeImplementation();
+ // Reserve the space to ensure we don't allocate memory in the output itself.
+ std::string str_format_result;
+ str_format_result.reserve(1 << 20);
+ std::string string_printf_result;
+ string_printf_result.reserve(1 << 20);
+
+ const char *const kFormats[] = {
+ "%", "%.3", "%8.5", "%500", "%.5000", "%.60", "%.30", "%03",
+ "%+", "% ", "%-10", "%#15.3", "%#.0", "%.0", "%1$*2$", "%1$.*2$"};
+
+ for (const char *fmt : kFormats) {
+ for (char f : {'f', 'F', //
+ 'g', 'G', //
+ 'a', 'A', //
+ 'e', 'E'}) {
+ std::string fmt_str = std::string(fmt) + f;
+
+ if (fmt == absl::string_view("%.5000") && f != 'f' && f != 'F' &&
+ f != 'a' && f != 'A') {
+ // This particular test takes way too long with snprintf.
+ // Disable for the case we are not implementing natively.
+ continue;
+ }
+
+ if ((f == 'a' || f == 'A') &&
+ !native_traits.hex_float_has_glibc_rounding) {
+ continue;
+ }
+
+ for (Floating d : floats) {
+ if (!native_traits.hex_float_prefers_denormal_repr &&
+ (f == 'a' || f == 'A') && std::fpclassify(d) == FP_SUBNORMAL) {
+ continue;
+ }
+ int i = -10;
+ FormatArgImpl args[2] = {FormatArgImpl(d), FormatArgImpl(i)};
+ UntypedFormatSpecImpl format(fmt_str);
+
+ string_printf_result.clear();
+ StrAppend(&string_printf_result, fmt_str.c_str(), d, i);
+ str_format_result.clear();
+
+ {
+ AppendPack(&str_format_result, format, absl::MakeSpan(args));
+ }
+
+ if (string_printf_result != str_format_result) {
+ // We use ASSERT_EQ here because failures are usually correlated and a
+ // bug would print way too many failed expectations causing the test
+ // to time out.
+ ASSERT_EQ(string_printf_result, str_format_result)
+ << fmt_str << " " << StrPrint("%.18g", d) << " "
+ << StrPrint("%a", d) << " " << StrPrint("%.50f", d);
+ }
+ }
+ }
+ }
+}
+
TEST_F(FormatConvertTest, Float) {
#ifdef _MSC_VER
// MSVC has a different rounding policy than us so we can't test our
@@ -410,9 +622,62 @@
return;
#endif // _MSC_VER
- const char *const kFormats[] = {
- "%", "%.3", "%8.5", "%9", "%.60", "%.30", "%03", "%+",
- "% ", "%-10", "%#15.3", "%#.0", "%.0", "%1$*2$", "%1$.*2$"};
+ std::vector<float> floats = {0.0f,
+ -0.0f,
+ .9999999f,
+ 9999999.f,
+ std::numeric_limits<float>::max(),
+ -std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::min(),
+ -std::numeric_limits<float>::min(),
+ std::numeric_limits<float>::lowest(),
+ -std::numeric_limits<float>::lowest(),
+ std::numeric_limits<float>::epsilon(),
+ std::numeric_limits<float>::epsilon() + 1.0f,
+ std::numeric_limits<float>::infinity(),
+ -std::numeric_limits<float>::infinity()};
+
+ // Some regression tests.
+ floats.push_back(0.999999989f);
+
+ if (std::numeric_limits<float>::has_denorm != std::denorm_absent) {
+ floats.push_back(std::numeric_limits<float>::denorm_min());
+ floats.push_back(-std::numeric_limits<float>::denorm_min());
+ }
+
+ for (float base :
+ {1.f, 12.f, 123.f, 1234.f, 12345.f, 123456.f, 1234567.f, 12345678.f,
+ 123456789.f, 1234567890.f, 12345678901.f, 12345678.f, 12345678.f}) {
+ for (int exp = -123; exp <= 123; ++exp) {
+ for (int sign : {1, -1}) {
+ floats.push_back(sign * std::ldexp(base, exp));
+ }
+ }
+ }
+
+ for (int exp = -300; exp <= 300; ++exp) {
+ const float all_ones_mantissa = 0xffffff;
+ floats.push_back(std::ldexp(all_ones_mantissa, exp));
+ }
+
+ // Remove duplicates to speed up the logic below.
+ std::sort(floats.begin(), floats.end());
+ floats.erase(std::unique(floats.begin(), floats.end()), floats.end());
+
+#ifndef __APPLE__
+ // Apple formats NaN differently (+nan) vs. (nan)
+ floats.push_back(std::nan(""));
+#endif
+
+ TestWithMultipleFormatsHelper(floats);
+}
+
+TEST_F(FormatConvertTest, Double) {
+#ifdef _MSC_VER
+ // MSVC has a different rounding policy than us so we can't test our
+ // implementation against the native one there.
+ return;
+#endif // _MSC_VER
std::vector<double> doubles = {0.0,
-0.0,
@@ -429,11 +694,6 @@
std::numeric_limits<double>::infinity(),
-std::numeric_limits<double>::infinity()};
-#ifndef __APPLE__
- // Apple formats NaN differently (+nan) vs. (nan)
- doubles.push_back(std::nan(""));
-#endif
-
// Some regression tests.
doubles.push_back(0.99999999999999989);
@@ -452,43 +712,375 @@
}
}
- for (const char *fmt : kFormats) {
- for (char f : {'f', 'F', //
- 'g', 'G', //
- 'a', 'A', //
- 'e', 'E'}) {
- std::string fmt_str = std::string(fmt) + f;
- for (double d : doubles) {
- int i = -10;
- FormatArgImpl args[2] = {FormatArgImpl(d), FormatArgImpl(i)};
- UntypedFormatSpecImpl format(fmt_str);
- // We use ASSERT_EQ here because failures are usually correlated and a
- // bug would print way too many failed expectations causing the test to
- // time out.
- ASSERT_EQ(StrPrint(fmt_str.c_str(), d, i),
- FormatPack(format, absl::MakeSpan(args)))
- << fmt_str << " " << StrPrint("%.18g", d) << " "
- << StrPrint("%.999f", d);
+ // Workaround libc bug.
+ // https://sourceware.org/bugzilla/show_bug.cgi?id=22142
+ const bool gcc_bug_22142 =
+ StrPrint("%f", std::numeric_limits<double>::max()) !=
+ "1797693134862315708145274237317043567980705675258449965989174768031"
+ "5726078002853876058955863276687817154045895351438246423432132688946"
+ "4182768467546703537516986049910576551282076245490090389328944075868"
+ "5084551339423045832369032229481658085593321233482747978262041447231"
+ "68738177180919299881250404026184124858368.000000";
+
+ if (!gcc_bug_22142) {
+ for (int exp = -300; exp <= 300; ++exp) {
+ const double all_ones_mantissa = 0x1fffffffffffff;
+ doubles.push_back(std::ldexp(all_ones_mantissa, exp));
+ }
+ }
+
+ if (gcc_bug_22142) {
+ for (auto &d : doubles) {
+ using L = std::numeric_limits<double>;
+ double d2 = std::abs(d);
+ if (d2 == L::max() || d2 == L::min() || d2 == L::denorm_min()) {
+ d = 0;
}
}
}
+
+ // Remove duplicates to speed up the logic below.
+ std::sort(doubles.begin(), doubles.end());
+ doubles.erase(std::unique(doubles.begin(), doubles.end()), doubles.end());
+
+#ifndef __APPLE__
+ // Apple formats NaN differently (+nan) vs. (nan)
+ doubles.push_back(std::nan(""));
+#endif
+
+ TestWithMultipleFormatsHelper(doubles);
+}
+
+TEST_F(FormatConvertTest, DoubleRound) {
+ std::string s;
+ const auto format = [&](const char *fmt, double d) -> std::string & {
+ s.clear();
+ FormatArgImpl args[1] = {FormatArgImpl(d)};
+ AppendPack(&s, UntypedFormatSpecImpl(fmt), absl::MakeSpan(args));
+#if !defined(_MSC_VER)
+ // MSVC has a different rounding policy than us so we can't test our
+ // implementation against the native one there.
+ EXPECT_EQ(StrPrint(fmt, d), s);
+#endif // _MSC_VER
+
+ return s;
+ };
+ // All of these values have to be exactly represented.
+ // Otherwise we might not be testing what we think we are testing.
+
+ // These values can fit in a 64bit "fast" representation.
+ const double exact_value = 0.00000000000005684341886080801486968994140625;
+ assert(exact_value == std::pow(2, -44));
+ // Round up at a 5xx.
+ EXPECT_EQ(format("%.13f", exact_value), "0.0000000000001");
+ // Round up at a >5
+ EXPECT_EQ(format("%.14f", exact_value), "0.00000000000006");
+ // Round down at a <5
+ EXPECT_EQ(format("%.16f", exact_value), "0.0000000000000568");
+ // Nine handling
+ EXPECT_EQ(format("%.35f", exact_value),
+ "0.00000000000005684341886080801486969");
+ EXPECT_EQ(format("%.36f", exact_value),
+ "0.000000000000056843418860808014869690");
+ // Round down the last nine.
+ EXPECT_EQ(format("%.37f", exact_value),
+ "0.0000000000000568434188608080148696899");
+ EXPECT_EQ(format("%.10f", 0.000003814697265625), "0.0000038147");
+ // Round up the last nine
+ EXPECT_EQ(format("%.11f", 0.000003814697265625), "0.00000381470");
+ EXPECT_EQ(format("%.12f", 0.000003814697265625), "0.000003814697");
+
+ // Round to even (down)
+ EXPECT_EQ(format("%.43f", exact_value),
+ "0.0000000000000568434188608080148696899414062");
+ // Exact
+ EXPECT_EQ(format("%.44f", exact_value),
+ "0.00000000000005684341886080801486968994140625");
+ // Round to even (up), let make the last digits 75 instead of 25
+ EXPECT_EQ(format("%.43f", exact_value + std::pow(2, -43)),
+ "0.0000000000001705302565824240446090698242188");
+ // Exact, just to check.
+ EXPECT_EQ(format("%.44f", exact_value + std::pow(2, -43)),
+ "0.00000000000017053025658242404460906982421875");
+
+ // This value has to be small enough that it won't fit in the uint128
+ // representation for printing.
+ const double small_exact_value =
+ 0.000000000000000000000000000000000000752316384526264005099991383822237233803945956334136013765601092018187046051025390625; // NOLINT
+ assert(small_exact_value == std::pow(2, -120));
+ // Round up at a 5xx.
+ EXPECT_EQ(format("%.37f", small_exact_value),
+ "0.0000000000000000000000000000000000008");
+ // Round down at a <5
+ EXPECT_EQ(format("%.38f", small_exact_value),
+ "0.00000000000000000000000000000000000075");
+ // Round up at a >5
+ EXPECT_EQ(format("%.41f", small_exact_value),
+ "0.00000000000000000000000000000000000075232");
+ // Nine handling
+ EXPECT_EQ(format("%.55f", small_exact_value),
+ "0.0000000000000000000000000000000000007523163845262640051");
+ EXPECT_EQ(format("%.56f", small_exact_value),
+ "0.00000000000000000000000000000000000075231638452626400510");
+ EXPECT_EQ(format("%.57f", small_exact_value),
+ "0.000000000000000000000000000000000000752316384526264005100");
+ EXPECT_EQ(format("%.58f", small_exact_value),
+ "0.0000000000000000000000000000000000007523163845262640051000");
+ // Round down the last nine
+ EXPECT_EQ(format("%.59f", small_exact_value),
+ "0.00000000000000000000000000000000000075231638452626400509999");
+ // Round up the last nine
+ EXPECT_EQ(format("%.79f", small_exact_value),
+ "0.000000000000000000000000000000000000"
+ "7523163845262640050999913838222372338039460");
+
+ // Round to even (down)
+ EXPECT_EQ(format("%.119f", small_exact_value),
+ "0.000000000000000000000000000000000000"
+ "75231638452626400509999138382223723380"
+ "394595633413601376560109201818704605102539062");
+ // Exact
+ EXPECT_EQ(format("%.120f", small_exact_value),
+ "0.000000000000000000000000000000000000"
+ "75231638452626400509999138382223723380"
+ "3945956334136013765601092018187046051025390625");
+ // Round to even (up), let make the last digits 75 instead of 25
+ EXPECT_EQ(format("%.119f", small_exact_value + std::pow(2, -119)),
+ "0.000000000000000000000000000000000002"
+ "25694915357879201529997415146671170141"
+ "183786900240804129680327605456113815307617188");
+ // Exact, just to check.
+ EXPECT_EQ(format("%.120f", small_exact_value + std::pow(2, -119)),
+ "0.000000000000000000000000000000000002"
+ "25694915357879201529997415146671170141"
+ "1837869002408041296803276054561138153076171875");
+}
+
+TEST_F(FormatConvertTest, DoubleRoundA) {
+ const NativePrintfTraits &native_traits = VerifyNativeImplementation();
+ std::string s;
+ const auto format = [&](const char *fmt, double d) -> std::string & {
+ s.clear();
+ FormatArgImpl args[1] = {FormatArgImpl(d)};
+ AppendPack(&s, UntypedFormatSpecImpl(fmt), absl::MakeSpan(args));
+ if (native_traits.hex_float_has_glibc_rounding) {
+ EXPECT_EQ(StrPrint(fmt, d), s);
+ }
+ return s;
+ };
+
+ // 0x1.00018000p+100
+ const double on_boundary_odd = 1267679614447900152596896153600.0;
+ EXPECT_EQ(format("%.0a", on_boundary_odd), "0x1p+100");
+ EXPECT_EQ(format("%.1a", on_boundary_odd), "0x1.0p+100");
+ EXPECT_EQ(format("%.2a", on_boundary_odd), "0x1.00p+100");
+ EXPECT_EQ(format("%.3a", on_boundary_odd), "0x1.000p+100");
+ EXPECT_EQ(format("%.4a", on_boundary_odd), "0x1.0002p+100"); // round
+ EXPECT_EQ(format("%.5a", on_boundary_odd), "0x1.00018p+100");
+ EXPECT_EQ(format("%.6a", on_boundary_odd), "0x1.000180p+100");
+
+ // 0x1.00028000p-2
+ const double on_boundary_even = 0.250009536743164062500;
+ EXPECT_EQ(format("%.0a", on_boundary_even), "0x1p-2");
+ EXPECT_EQ(format("%.1a", on_boundary_even), "0x1.0p-2");
+ EXPECT_EQ(format("%.2a", on_boundary_even), "0x1.00p-2");
+ EXPECT_EQ(format("%.3a", on_boundary_even), "0x1.000p-2");
+ EXPECT_EQ(format("%.4a", on_boundary_even), "0x1.0002p-2"); // no round
+ EXPECT_EQ(format("%.5a", on_boundary_even), "0x1.00028p-2");
+ EXPECT_EQ(format("%.6a", on_boundary_even), "0x1.000280p-2");
+
+ // 0x1.00018001p+1
+ const double slightly_over = 2.00004577683284878730773925781250;
+ EXPECT_EQ(format("%.0a", slightly_over), "0x1p+1");
+ EXPECT_EQ(format("%.1a", slightly_over), "0x1.0p+1");
+ EXPECT_EQ(format("%.2a", slightly_over), "0x1.00p+1");
+ EXPECT_EQ(format("%.3a", slightly_over), "0x1.000p+1");
+ EXPECT_EQ(format("%.4a", slightly_over), "0x1.0002p+1");
+ EXPECT_EQ(format("%.5a", slightly_over), "0x1.00018p+1");
+ EXPECT_EQ(format("%.6a", slightly_over), "0x1.000180p+1");
+
+ // 0x1.00017fffp+0
+ const double slightly_under = 1.000022887950763106346130371093750;
+ EXPECT_EQ(format("%.0a", slightly_under), "0x1p+0");
+ EXPECT_EQ(format("%.1a", slightly_under), "0x1.0p+0");
+ EXPECT_EQ(format("%.2a", slightly_under), "0x1.00p+0");
+ EXPECT_EQ(format("%.3a", slightly_under), "0x1.000p+0");
+ EXPECT_EQ(format("%.4a", slightly_under), "0x1.0001p+0");
+ EXPECT_EQ(format("%.5a", slightly_under), "0x1.00018p+0");
+ EXPECT_EQ(format("%.6a", slightly_under), "0x1.000180p+0");
+ EXPECT_EQ(format("%.7a", slightly_under), "0x1.0001800p+0");
+
+ // 0x1.1b3829ac28058p+3
+ const double hex_value = 8.85060580848964661981881363317370414733886718750;
+ EXPECT_EQ(format("%.0a", hex_value), "0x1p+3");
+ EXPECT_EQ(format("%.1a", hex_value), "0x1.2p+3");
+ EXPECT_EQ(format("%.2a", hex_value), "0x1.1bp+3");
+ EXPECT_EQ(format("%.3a", hex_value), "0x1.1b4p+3");
+ EXPECT_EQ(format("%.4a", hex_value), "0x1.1b38p+3");
+ EXPECT_EQ(format("%.5a", hex_value), "0x1.1b383p+3");
+ EXPECT_EQ(format("%.6a", hex_value), "0x1.1b382ap+3");
+ EXPECT_EQ(format("%.7a", hex_value), "0x1.1b3829bp+3");
+ EXPECT_EQ(format("%.8a", hex_value), "0x1.1b3829acp+3");
+ EXPECT_EQ(format("%.9a", hex_value), "0x1.1b3829ac3p+3");
+ EXPECT_EQ(format("%.10a", hex_value), "0x1.1b3829ac28p+3");
+ EXPECT_EQ(format("%.11a", hex_value), "0x1.1b3829ac280p+3");
+ EXPECT_EQ(format("%.12a", hex_value), "0x1.1b3829ac2806p+3");
+ EXPECT_EQ(format("%.13a", hex_value), "0x1.1b3829ac28058p+3");
+ EXPECT_EQ(format("%.14a", hex_value), "0x1.1b3829ac280580p+3");
+ EXPECT_EQ(format("%.15a", hex_value), "0x1.1b3829ac2805800p+3");
+ EXPECT_EQ(format("%.16a", hex_value), "0x1.1b3829ac28058000p+3");
+ EXPECT_EQ(format("%.17a", hex_value), "0x1.1b3829ac280580000p+3");
+ EXPECT_EQ(format("%.18a", hex_value), "0x1.1b3829ac2805800000p+3");
+ EXPECT_EQ(format("%.19a", hex_value), "0x1.1b3829ac28058000000p+3");
+ EXPECT_EQ(format("%.20a", hex_value), "0x1.1b3829ac280580000000p+3");
+ EXPECT_EQ(format("%.21a", hex_value), "0x1.1b3829ac2805800000000p+3");
+
+ // 0x1.0818283848586p+3
+ const double hex_value2 = 8.2529488658208371987257123691961169242858886718750;
+ EXPECT_EQ(format("%.0a", hex_value2), "0x1p+3");
+ EXPECT_EQ(format("%.1a", hex_value2), "0x1.1p+3");
+ EXPECT_EQ(format("%.2a", hex_value2), "0x1.08p+3");
+ EXPECT_EQ(format("%.3a", hex_value2), "0x1.082p+3");
+ EXPECT_EQ(format("%.4a", hex_value2), "0x1.0818p+3");
+ EXPECT_EQ(format("%.5a", hex_value2), "0x1.08183p+3");
+ EXPECT_EQ(format("%.6a", hex_value2), "0x1.081828p+3");
+ EXPECT_EQ(format("%.7a", hex_value2), "0x1.0818284p+3");
+ EXPECT_EQ(format("%.8a", hex_value2), "0x1.08182838p+3");
+ EXPECT_EQ(format("%.9a", hex_value2), "0x1.081828385p+3");
+ EXPECT_EQ(format("%.10a", hex_value2), "0x1.0818283848p+3");
+ EXPECT_EQ(format("%.11a", hex_value2), "0x1.08182838486p+3");
+ EXPECT_EQ(format("%.12a", hex_value2), "0x1.081828384858p+3");
+ EXPECT_EQ(format("%.13a", hex_value2), "0x1.0818283848586p+3");
+ EXPECT_EQ(format("%.14a", hex_value2), "0x1.08182838485860p+3");
+ EXPECT_EQ(format("%.15a", hex_value2), "0x1.081828384858600p+3");
+ EXPECT_EQ(format("%.16a", hex_value2), "0x1.0818283848586000p+3");
+ EXPECT_EQ(format("%.17a", hex_value2), "0x1.08182838485860000p+3");
+ EXPECT_EQ(format("%.18a", hex_value2), "0x1.081828384858600000p+3");
+ EXPECT_EQ(format("%.19a", hex_value2), "0x1.0818283848586000000p+3");
+ EXPECT_EQ(format("%.20a", hex_value2), "0x1.08182838485860000000p+3");
+ EXPECT_EQ(format("%.21a", hex_value2), "0x1.081828384858600000000p+3");
+}
+
+TEST_F(FormatConvertTest, LongDoubleRoundA) {
+ if (std::numeric_limits<long double>::digits % 4 != 0) {
+ // This test doesn't really make sense to run on platforms where a long
+ // double has a different mantissa size (mod 4) than Prod, since then the
+ // leading digit will be formatted differently.
+ return;
+ }
+ const NativePrintfTraits &native_traits = VerifyNativeImplementation();
+ std::string s;
+ const auto format = [&](const char *fmt, long double d) -> std::string & {
+ s.clear();
+ FormatArgImpl args[1] = {FormatArgImpl(d)};
+ AppendPack(&s, UntypedFormatSpecImpl(fmt), absl::MakeSpan(args));
+ if (native_traits.hex_float_has_glibc_rounding &&
+ native_traits.hex_float_optimizes_leading_digit_bit_count) {
+ EXPECT_EQ(StrPrint(fmt, d), s);
+ }
+ return s;
+ };
+
+ // 0x8.8p+4
+ const long double on_boundary_even = 136.0;
+ EXPECT_EQ(format("%.0La", on_boundary_even), "0x8p+4");
+ EXPECT_EQ(format("%.1La", on_boundary_even), "0x8.8p+4");
+ EXPECT_EQ(format("%.2La", on_boundary_even), "0x8.80p+4");
+ EXPECT_EQ(format("%.3La", on_boundary_even), "0x8.800p+4");
+ EXPECT_EQ(format("%.4La", on_boundary_even), "0x8.8000p+4");
+ EXPECT_EQ(format("%.5La", on_boundary_even), "0x8.80000p+4");
+ EXPECT_EQ(format("%.6La", on_boundary_even), "0x8.800000p+4");
+
+ // 0x9.8p+4
+ const long double on_boundary_odd = 152.0;
+ EXPECT_EQ(format("%.0La", on_boundary_odd), "0xap+4");
+ EXPECT_EQ(format("%.1La", on_boundary_odd), "0x9.8p+4");
+ EXPECT_EQ(format("%.2La", on_boundary_odd), "0x9.80p+4");
+ EXPECT_EQ(format("%.3La", on_boundary_odd), "0x9.800p+4");
+ EXPECT_EQ(format("%.4La", on_boundary_odd), "0x9.8000p+4");
+ EXPECT_EQ(format("%.5La", on_boundary_odd), "0x9.80000p+4");
+ EXPECT_EQ(format("%.6La", on_boundary_odd), "0x9.800000p+4");
+
+ // 0x8.80001p+24
+ const long double slightly_over = 142606352.0;
+ EXPECT_EQ(format("%.0La", slightly_over), "0x9p+24");
+ EXPECT_EQ(format("%.1La", slightly_over), "0x8.8p+24");
+ EXPECT_EQ(format("%.2La", slightly_over), "0x8.80p+24");
+ EXPECT_EQ(format("%.3La", slightly_over), "0x8.800p+24");
+ EXPECT_EQ(format("%.4La", slightly_over), "0x8.8000p+24");
+ EXPECT_EQ(format("%.5La", slightly_over), "0x8.80001p+24");
+ EXPECT_EQ(format("%.6La", slightly_over), "0x8.800010p+24");
+
+ // 0x8.7ffffp+24
+ const long double slightly_under = 142606320.0;
+ EXPECT_EQ(format("%.0La", slightly_under), "0x8p+24");
+ EXPECT_EQ(format("%.1La", slightly_under), "0x8.8p+24");
+ EXPECT_EQ(format("%.2La", slightly_under), "0x8.80p+24");
+ EXPECT_EQ(format("%.3La", slightly_under), "0x8.800p+24");
+ EXPECT_EQ(format("%.4La", slightly_under), "0x8.8000p+24");
+ EXPECT_EQ(format("%.5La", slightly_under), "0x8.7ffffp+24");
+ EXPECT_EQ(format("%.6La", slightly_under), "0x8.7ffff0p+24");
+ EXPECT_EQ(format("%.7La", slightly_under), "0x8.7ffff00p+24");
+
+ // 0xc.0828384858688000p+128
+ const long double eights = 4094231060438608800781871108094404067328.0;
+ EXPECT_EQ(format("%.0La", eights), "0xcp+128");
+ EXPECT_EQ(format("%.1La", eights), "0xc.1p+128");
+ EXPECT_EQ(format("%.2La", eights), "0xc.08p+128");
+ EXPECT_EQ(format("%.3La", eights), "0xc.083p+128");
+ EXPECT_EQ(format("%.4La", eights), "0xc.0828p+128");
+ EXPECT_EQ(format("%.5La", eights), "0xc.08284p+128");
+ EXPECT_EQ(format("%.6La", eights), "0xc.082838p+128");
+ EXPECT_EQ(format("%.7La", eights), "0xc.0828385p+128");
+ EXPECT_EQ(format("%.8La", eights), "0xc.08283848p+128");
+ EXPECT_EQ(format("%.9La", eights), "0xc.082838486p+128");
+ EXPECT_EQ(format("%.10La", eights), "0xc.0828384858p+128");
+ EXPECT_EQ(format("%.11La", eights), "0xc.08283848587p+128");
+ EXPECT_EQ(format("%.12La", eights), "0xc.082838485868p+128");
+ EXPECT_EQ(format("%.13La", eights), "0xc.0828384858688p+128");
+ EXPECT_EQ(format("%.14La", eights), "0xc.08283848586880p+128");
+ EXPECT_EQ(format("%.15La", eights), "0xc.082838485868800p+128");
+ EXPECT_EQ(format("%.16La", eights), "0xc.0828384858688000p+128");
+}
+
+// We don't actually store the results. This is just to exercise the rest of the
+// machinery.
+struct NullSink {
+ friend void AbslFormatFlush(NullSink *sink, string_view str) {}
+};
+
+template <typename... T>
+bool FormatWithNullSink(absl::string_view fmt, const T &... a) {
+ NullSink sink;
+ FormatArgImpl args[] = {FormatArgImpl(a)...};
+ return FormatUntyped(&sink, UntypedFormatSpecImpl(fmt), absl::MakeSpan(args));
+}
+
+TEST_F(FormatConvertTest, ExtremeWidthPrecision) {
+ for (const char *fmt : {"f"}) {
+ for (double d : {1e-100, 1.0, 1e100}) {
+ constexpr int max = std::numeric_limits<int>::max();
+ EXPECT_TRUE(FormatWithNullSink(std::string("%.*") + fmt, max, d));
+ EXPECT_TRUE(FormatWithNullSink(std::string("%1.*") + fmt, max, d));
+ EXPECT_TRUE(FormatWithNullSink(std::string("%*") + fmt, max, d));
+ EXPECT_TRUE(FormatWithNullSink(std::string("%*.*") + fmt, max, max, d));
+ }
+ }
}
TEST_F(FormatConvertTest, LongDouble) {
- const char *const kFormats[] = {"%", "%.3", "%8.5", "%9",
+#ifdef _MSC_VER
+ // MSVC has a different rounding policy than us so we can't test our
+ // implementation against the native one there.
+ return;
+#endif // _MSC_VER
+ const NativePrintfTraits &native_traits = VerifyNativeImplementation();
+ const char *const kFormats[] = {"%", "%.3", "%8.5", "%9", "%.5000",
"%.60", "%+", "% ", "%-10"};
- // This value is not representable in double, but it is in long double that
- // uses the extended format.
- // This is to verify that we are not truncating the value mistakenly through a
- // double.
- long double very_precise = 10000000000000000.25L;
-
std::vector<long double> doubles = {
0.0,
-0.0,
- very_precise,
- 1 / very_precise,
std::numeric_limits<long double>::max(),
-std::numeric_limits<long double>::max(),
std::numeric_limits<long double>::min(),
@@ -496,28 +1088,65 @@
std::numeric_limits<long double>::infinity(),
-std::numeric_limits<long double>::infinity()};
+ for (long double base : {1.L, 12.L, 123.L, 1234.L, 12345.L, 123456.L,
+ 1234567.L, 12345678.L, 123456789.L, 1234567890.L,
+ 12345678901.L, 123456789012.L, 1234567890123.L,
+ // This value is not representable in double, but it
+ // is in long double that uses the extended format.
+ // This is to verify that we are not truncating the
+ // value mistakenly through a double.
+ 10000000000000000.25L}) {
+ for (int exp : {-1000, -500, 0, 500, 1000}) {
+ for (int sign : {1, -1}) {
+ doubles.push_back(sign * std::ldexp(base, exp));
+ doubles.push_back(sign / std::ldexp(base, exp));
+ }
+ }
+ }
+
+ // Regression tests
+ //
+ // Using a string literal because not all platforms support hex literals or it
+ // might be out of range.
+ doubles.push_back(std::strtold("-0xf.ffffffb5feafffbp-16324L", nullptr));
+
for (const char *fmt : kFormats) {
for (char f : {'f', 'F', //
'g', 'G', //
'a', 'A', //
'e', 'E'}) {
std::string fmt_str = std::string(fmt) + 'L' + f;
+
+ if (fmt == absl::string_view("%.5000") && f != 'f' && f != 'F' &&
+ f != 'a' && f != 'A') {
+ // This particular test takes way too long with snprintf.
+ // Disable for the case we are not implementing natively.
+ continue;
+ }
+
+ if (f == 'a' || f == 'A') {
+ if (!native_traits.hex_float_has_glibc_rounding ||
+ !native_traits.hex_float_optimizes_leading_digit_bit_count) {
+ continue;
+ }
+ }
+
for (auto d : doubles) {
FormatArgImpl arg(d);
UntypedFormatSpecImpl format(fmt_str);
// We use ASSERT_EQ here because failures are usually correlated and a
// bug would print way too many failed expectations causing the test to
// time out.
- ASSERT_EQ(StrPrint(fmt_str.c_str(), d),
- FormatPack(format, {&arg, 1}))
+ ASSERT_EQ(StrPrint(fmt_str.c_str(), d), FormatPack(format, {&arg, 1}))
<< fmt_str << " " << StrPrint("%.18Lg", d) << " "
- << StrPrint("%.999Lf", d);
+ << StrPrint("%La", d) << " " << StrPrint("%.1080Lf", d);
}
}
}
}
-TEST_F(FormatConvertTest, IntAsFloat) {
+TEST_F(FormatConvertTest, IntAsDouble) {
+ const NativePrintfTraits &native_traits = VerifyNativeImplementation();
const int kMin = std::numeric_limits<int>::min();
const int kMax = std::numeric_limits<int>::max();
const int ia[] = {
@@ -533,14 +1162,17 @@
const char *fmt;
};
const double dx = static_cast<double>(fx);
- const Expectation kExpect[] = {
- { __LINE__, StrPrint("%f", dx), "%f" },
- { __LINE__, StrPrint("%12f", dx), "%12f" },
- { __LINE__, StrPrint("%.12f", dx), "%.12f" },
- { __LINE__, StrPrint("%12a", dx), "%12a" },
- { __LINE__, StrPrint("%.12a", dx), "%.12a" },
+ std::vector<Expectation> expect = {
+ {__LINE__, StrPrint("%f", dx), "%f"},
+ {__LINE__, StrPrint("%12f", dx), "%12f"},
+ {__LINE__, StrPrint("%.12f", dx), "%.12f"},
+ {__LINE__, StrPrint("%.12a", dx), "%.12a"},
};
- for (const Expectation &e : kExpect) {
+ if (native_traits.hex_float_uses_minimal_precision_when_not_specified) {
+ Expectation ex = {__LINE__, StrPrint("%12a", dx), "%12a"};
+ expect.push_back(ex);
+ }
+ for (const Expectation &e : expect) {
SCOPED_TRACE(e.line);
SCOPED_TRACE(e.fmt);
UntypedFormatSpecImpl format(e.fmt);
@@ -585,6 +1217,26 @@
EXPECT_TRUE(FormatFails("%*d", ""));
}
+// Sanity check to make sure that we are testing what we think we're testing on
+// e.g. the x86_64+glibc platform.
+TEST_F(FormatConvertTest, GlibcHasCorrectTraits) {
+#if !defined(__GLIBC__) || !defined(__x86_64__)
+ return;
+#endif
+ const NativePrintfTraits &native_traits = VerifyNativeImplementation();
+ // If one of the following tests break then it is either because the above PP
+ // macro guards failed to exclude a new platform (likely) or because something
+ // has changed in the implemention of glibc sprintf float formatting behavior.
+ // If the latter, then the code that computes these flags needs to be
+ // revisited and/or possibly the StrFormat implementation.
+ EXPECT_TRUE(native_traits.hex_float_has_glibc_rounding);
+ EXPECT_TRUE(native_traits.hex_float_prefers_denormal_repr);
+ EXPECT_TRUE(
+ native_traits.hex_float_uses_minimal_precision_when_not_specified);
+ EXPECT_TRUE(native_traits.hex_float_optimizes_leading_digit_bit_count);
+}
+
} // namespace
} // namespace str_format_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/internal/str_format/extension.cc b/third_party/abseil/absl/strings/internal/str_format/extension.cc
index d7f5815..bb0d96c 100644
--- a/third_party/abseil/absl/strings/internal/str_format/extension.cc
+++ b/third_party/abseil/absl/strings/internal/str_format/extension.cc
@@ -20,38 +20,8 @@
#include <string>
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
-namespace {
-// clang-format off
-#define ABSL_LENGTH_MODS_EXPAND_ \
- X_VAL(h) X_SEP \
- X_VAL(hh) X_SEP \
- X_VAL(l) X_SEP \
- X_VAL(ll) X_SEP \
- X_VAL(L) X_SEP \
- X_VAL(j) X_SEP \
- X_VAL(z) X_SEP \
- X_VAL(t) X_SEP \
- X_VAL(q)
-// clang-format on
-} // namespace
-
-const LengthMod::Spec LengthMod::kSpecs[] = {
-#define X_VAL(id) { LengthMod::id, #id, strlen(#id) }
-#define X_SEP ,
- ABSL_LENGTH_MODS_EXPAND_, {LengthMod::none, "", 0}
-#undef X_VAL
-#undef X_SEP
-};
-
-const ConversionChar::Spec ConversionChar::kSpecs[] = {
-#define X_VAL(id) { ConversionChar::id, #id[0] }
-#define X_SEP ,
- ABSL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP),
- {ConversionChar::none, '\0'},
-#undef X_VAL
-#undef X_SEP
-};
std::string Flags::ToString() const {
std::string s;
@@ -63,22 +33,43 @@
return s;
}
-const size_t LengthMod::kNumValues;
+#define ABSL_INTERNAL_X_VAL(id) \
+ constexpr absl::FormatConversionChar FormatConversionCharInternal::id;
+ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
+#undef ABSL_INTERNAL_X_VAL
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr absl::FormatConversionChar FormatConversionCharInternal::kNone;
-const size_t ConversionChar::kNumValues;
+#define ABSL_INTERNAL_CHAR_SET_CASE(c) \
+ constexpr FormatConversionCharSet FormatConversionCharSetInternal::c;
+ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
+#undef ABSL_INTERNAL_CHAR_SET_CASE
-bool FormatSinkImpl::PutPaddedString(string_view v, int w, int p, bool l) {
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr FormatConversionCharSet FormatConversionCharSetInternal::kStar;
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr FormatConversionCharSet FormatConversionCharSetInternal::kIntegral;
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr FormatConversionCharSet FormatConversionCharSetInternal::kFloating;
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr FormatConversionCharSet FormatConversionCharSetInternal::kNumeric;
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr FormatConversionCharSet FormatConversionCharSetInternal::kPointer;
+
+bool FormatSinkImpl::PutPaddedString(string_view value, int width,
+ int precision, bool left) {
size_t space_remaining = 0;
- if (w >= 0) space_remaining = w;
- size_t n = v.size();
- if (p >= 0) n = std::min(n, static_cast<size_t>(p));
- string_view shown(v.data(), n);
+ if (width >= 0) space_remaining = width;
+ size_t n = value.size();
+ if (precision >= 0) n = std::min(n, static_cast<size_t>(precision));
+ string_view shown(value.data(), n);
space_remaining = Excess(shown.size(), space_remaining);
- if (!l) Append(space_remaining, ' ');
+ if (!left) Append(space_remaining, ' ');
Append(shown);
- if (l) Append(space_remaining, ' ');
+ if (left) Append(space_remaining, ' ');
return true;
}
} // namespace str_format_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/internal/str_format/extension.h b/third_party/abseil/absl/strings/internal/str_format/extension.h
index eb81f8a..a9b9e13 100644
--- a/third_party/abseil/absl/strings/internal/str_format/extension.h
+++ b/third_party/abseil/absl/strings/internal/str_format/extension.h
@@ -17,17 +17,22 @@
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
#include <limits.h>
+
#include <cstddef>
#include <cstring>
#include <ostream>
+#include "absl/base/config.h"
#include "absl/base/port.h"
+#include "absl/meta/type_traits.h"
#include "absl/strings/internal/str_format/output.h"
#include "absl/strings/string_view.h"
-class Cord;
-
namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+enum class FormatConversionChar : uint8_t;
+enum class FormatConversionCharSet : uint64_t;
namespace str_format_internal {
@@ -102,7 +107,7 @@
size_t size() const { return size_; }
// Put 'v' to 'sink' with specified width, precision, and left flag.
- bool PutPaddedString(string_view v, int w, int p, bool l);
+ bool PutPaddedString(string_view v, int width, int precision, bool left);
template <typename T>
T Wrap() {
@@ -136,58 +141,10 @@
}
};
-struct LengthMod {
- public:
- enum Id : uint8_t {
- h, hh, l, ll, L, j, z, t, q, none
- };
- static const size_t kNumValues = none + 1;
-
- LengthMod() : id_(none) {}
-
- // Index into the opaque array of LengthMod enums.
- // Requires: i < kNumValues
- static LengthMod FromIndex(size_t i) {
- return LengthMod(kSpecs[i].value);
- }
-
- static LengthMod FromId(Id id) { return LengthMod(id); }
-
- // The length modifier std::string associated with a specified LengthMod.
- string_view name() const {
- const Spec& spec = kSpecs[id_];
- return {spec.name, spec.name_length};
- }
-
- Id id() const { return id_; }
-
- friend bool operator==(const LengthMod& a, const LengthMod& b) {
- return a.id() == b.id();
- }
- friend bool operator!=(const LengthMod& a, const LengthMod& b) {
- return !(a == b);
- }
- friend std::ostream& operator<<(std::ostream& os, const LengthMod& v) {
- return os << v.name();
- }
-
- private:
- struct Spec {
- Id value;
- const char *name;
- size_t name_length;
- };
- static const Spec kSpecs[];
-
- explicit LengthMod(Id id) : id_(id) {}
-
- Id id_;
-};
-
// clang-format off
-#define ABSL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP) \
+#define ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP) \
/* text */ \
- X_VAL(c) X_SEP X_VAL(C) X_SEP X_VAL(s) X_SEP X_VAL(S) X_SEP \
+ X_VAL(c) X_SEP X_VAL(s) X_SEP \
/* ints */ \
X_VAL(d) X_SEP X_VAL(i) X_SEP X_VAL(o) X_SEP \
X_VAL(u) X_SEP X_VAL(x) X_SEP X_VAL(X) X_SEP \
@@ -198,119 +155,119 @@
X_VAL(n) X_SEP X_VAL(p)
// clang-format on
-struct ConversionChar {
- public:
- enum Id : uint8_t {
- c, C, s, S, // text
+// This type should not be referenced, it exists only to provide labels
+// internally that match the values declared in FormatConversionChar in
+// str_format.h. This is meant to allow internal libraries to use the same
+// declared interface type as the public interface
+// (absl::StrFormatConversionChar) while keeping the definition in a public
+// header.
+// Internal libraries should use the form
+// `FormatConversionCharInternal::c`, `FormatConversionCharInternal::kNone` for
+// comparisons. Use in switch statements is not recommended due to a bug in how
+// gcc 4.9 -Wswitch handles declared but undefined enums.
+struct FormatConversionCharInternal {
+ FormatConversionCharInternal() = delete;
+
+ private:
+ // clang-format off
+ enum class Enum : uint8_t {
+ c, s, // text
d, i, o, u, x, X, // int
f, F, e, E, g, G, a, A, // float
n, p, // misc
- none
+ kNone
};
- static const size_t kNumValues = none + 1;
-
- ConversionChar() : id_(none) {}
-
+ // clang-format on
public:
- // Index into the opaque array of ConversionChar enums.
- // Requires: i < kNumValues
- static ConversionChar FromIndex(size_t i) {
- return ConversionChar(kSpecs[i].value);
- }
-
- static ConversionChar FromChar(char c) {
- ConversionChar::Id out_id = ConversionChar::none;
- switch (c) {
-#define X_VAL(id) \
- case #id[0]: \
- out_id = ConversionChar::id; \
- break;
- ABSL_CONVERSION_CHARS_EXPAND_(X_VAL, )
-#undef X_VAL
- default:
- break;
- }
- return ConversionChar(out_id);
- }
-
- static ConversionChar FromId(Id id) { return ConversionChar(id); }
- Id id() const { return id_; }
-
- int radix() const {
- switch (id()) {
- case x: case X: case a: case A: case p: return 16;
- case o: return 8;
- default: return 10;
- }
- }
-
- bool upper() const {
- switch (id()) {
- case X: case F: case E: case G: case A: return true;
- default: return false;
- }
- }
-
- bool is_signed() const {
- switch (id()) {
- case d: case i: return true;
- default: return false;
- }
- }
-
- bool is_integral() const {
- switch (id()) {
- case d: case i: case u: case o: case x: case X:
- return true;
- default: return false;
- }
- }
-
- bool is_float() const {
- switch (id()) {
- case a: case e: case f: case g: case A: case E: case F: case G:
- return true;
- default: return false;
- }
- }
-
- bool IsValid() const { return id() != none; }
-
- // The associated char.
- char Char() const { return kSpecs[id_].name; }
-
- friend bool operator==(const ConversionChar& a, const ConversionChar& b) {
- return a.id() == b.id();
- }
- friend bool operator!=(const ConversionChar& a, const ConversionChar& b) {
- return !(a == b);
- }
- friend std::ostream& operator<<(std::ostream& os, const ConversionChar& v) {
- char c = v.Char();
- if (!c) c = '?';
- return os << c;
- }
-
- private:
- struct Spec {
- Id value;
- char name;
- };
- static const Spec kSpecs[];
-
- explicit ConversionChar(Id id) : id_(id) {}
-
- Id id_;
+#define ABSL_INTERNAL_X_VAL(id) \
+ static constexpr FormatConversionChar id = \
+ static_cast<FormatConversionChar>(Enum::id);
+ ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
+#undef ABSL_INTERNAL_X_VAL
+ static constexpr FormatConversionChar kNone =
+ static_cast<FormatConversionChar>(Enum::kNone);
};
+// clang-format on
-class ConversionSpec {
+inline FormatConversionChar FormatConversionCharFromChar(char c) {
+ switch (c) {
+#define ABSL_INTERNAL_X_VAL(id) \
+ case #id[0]: \
+ return FormatConversionCharInternal::id;
+ ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
+#undef ABSL_INTERNAL_X_VAL
+ }
+ return FormatConversionCharInternal::kNone;
+}
+
+inline bool FormatConversionCharIsUpper(FormatConversionChar c) {
+ if (c == FormatConversionCharInternal::X ||
+ c == FormatConversionCharInternal::F ||
+ c == FormatConversionCharInternal::E ||
+ c == FormatConversionCharInternal::G ||
+ c == FormatConversionCharInternal::A) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+inline bool FormatConversionCharIsFloat(FormatConversionChar c) {
+ if (c == FormatConversionCharInternal::a ||
+ c == FormatConversionCharInternal::e ||
+ c == FormatConversionCharInternal::f ||
+ c == FormatConversionCharInternal::g ||
+ c == FormatConversionCharInternal::A ||
+ c == FormatConversionCharInternal::E ||
+ c == FormatConversionCharInternal::F ||
+ c == FormatConversionCharInternal::G) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+inline char FormatConversionCharToChar(FormatConversionChar c) {
+ if (c == FormatConversionCharInternal::kNone) {
+ return '\0';
+
+#define ABSL_INTERNAL_X_VAL(e) \
+ } else if (c == FormatConversionCharInternal::e) { \
+ return #e[0];
+#define ABSL_INTERNAL_X_SEP
+ ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL,
+ ABSL_INTERNAL_X_SEP)
+ } else {
+ return '\0';
+ }
+
+#undef ABSL_INTERNAL_X_VAL
+#undef ABSL_INTERNAL_X_SEP
+}
+
+// The associated char.
+inline std::ostream& operator<<(std::ostream& os, FormatConversionChar v) {
+ char c = FormatConversionCharToChar(v);
+ if (!c) c = '?';
+ return os << c;
+}
+
+struct FormatConversionSpecImplFriend;
+
+class FormatConversionSpecImpl {
public:
- Flags flags() const { return flags_; }
- LengthMod length_mod() const { return length_mod_; }
- ConversionChar conv() const {
+ // Width and precison are not specified, no flags are set.
+ bool is_basic() const { return flags_.basic; }
+ bool has_left_flag() const { return flags_.left; }
+ bool has_show_pos_flag() const { return flags_.show_pos; }
+ bool has_sign_col_flag() const { return flags_.sign_col; }
+ bool has_alt_flag() const { return flags_.alt; }
+ bool has_zero_flag() const { return flags_.zero; }
+
+ FormatConversionChar conversion_char() const {
// Keep this field first in the struct . It generates better code when
// accessing it when ConversionSpec is passed by value in registers.
- static_assert(offsetof(ConversionSpec, conv_) == 0, "");
+ static_assert(offsetof(FormatConversionSpecImpl, conv_) == 0, "");
return conv_;
}
@@ -321,46 +278,36 @@
// negative value.
int precision() const { return precision_; }
- void set_flags(Flags f) { flags_ = f; }
- void set_length_mod(LengthMod lm) { length_mod_ = lm; }
- void set_conv(ConversionChar c) { conv_ = c; }
- void set_width(int w) { width_ = w; }
- void set_precision(int p) { precision_ = p; }
- void set_left(bool b) { flags_.left = b; }
+ template <typename T>
+ T Wrap() {
+ return T(*this);
+ }
private:
- ConversionChar conv_;
+ friend struct str_format_internal::FormatConversionSpecImplFriend;
+ FormatConversionChar conv_ = FormatConversionCharInternal::kNone;
Flags flags_;
- LengthMod length_mod_;
int width_;
int precision_;
};
-constexpr uint64_t ConversionCharToConvValue(char conv) {
- return
-#define CONV_SET_CASE(c) \
- conv == #c[0] ? (uint64_t{1} << (1 + ConversionChar::Id::c)):
- ABSL_CONVERSION_CHARS_EXPAND_(CONV_SET_CASE, )
-#undef CONV_SET_CASE
- conv == '*'
- ? 1
- : 0;
-}
-
-enum class Conv : uint64_t {
-#define CONV_SET_CASE(c) c = ConversionCharToConvValue(#c[0]),
- ABSL_CONVERSION_CHARS_EXPAND_(CONV_SET_CASE, )
-#undef CONV_SET_CASE
-
- // Used for width/precision '*' specification.
- star = ConversionCharToConvValue('*'),
-
- // Some predefined values:
- integral = d | i | u | o | x | X,
- floating = a | e | f | g | A | E | F | G,
- numeric = integral | floating,
- string = s,
- pointer = p
+struct FormatConversionSpecImplFriend final {
+ static void SetFlags(Flags f, FormatConversionSpecImpl* conv) {
+ conv->flags_ = f;
+ }
+ static void SetConversionChar(FormatConversionChar c,
+ FormatConversionSpecImpl* conv) {
+ conv->conv_ = c;
+ }
+ static void SetWidth(int w, FormatConversionSpecImpl* conv) {
+ conv->width_ = w;
+ }
+ static void SetPrecision(int p, FormatConversionSpecImpl* conv) {
+ conv->precision_ = p;
+ }
+ static std::string FlagsToString(const FormatConversionSpecImpl& spec) {
+ return spec.flags_.ToString();
+ }
};
// Type safe OR operator.
@@ -368,36 +315,104 @@
// 1. operator| on enums makes them decay to integers and the result is an
// integer. We need the result to stay as an enum.
// 2. We use "enum class" which would not work even if we accepted the decay.
-constexpr Conv operator|(Conv a, Conv b) {
- return Conv(static_cast<uint64_t>(a) | static_cast<uint64_t>(b));
+constexpr FormatConversionCharSet FormatConversionCharSetUnion(
+ FormatConversionCharSet a) {
+ return a;
+}
+
+template <typename... CharSet>
+constexpr FormatConversionCharSet FormatConversionCharSetUnion(
+ FormatConversionCharSet a, CharSet... rest) {
+ return static_cast<FormatConversionCharSet>(
+ static_cast<uint64_t>(a) |
+ static_cast<uint64_t>(FormatConversionCharSetUnion(rest...)));
+}
+
+constexpr uint64_t FormatConversionCharToConvInt(FormatConversionChar c) {
+ return uint64_t{1} << (1 + static_cast<uint8_t>(c));
+}
+
+constexpr uint64_t FormatConversionCharToConvInt(char conv) {
+ return
+#define ABSL_INTERNAL_CHAR_SET_CASE(c) \
+ conv == #c[0] \
+ ? FormatConversionCharToConvInt(FormatConversionCharInternal::c) \
+ :
+ ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
+#undef ABSL_INTERNAL_CHAR_SET_CASE
+ conv == '*'
+ ? 1
+ : 0;
+}
+
+constexpr FormatConversionCharSet FormatConversionCharToConvValue(char conv) {
+ return static_cast<FormatConversionCharSet>(
+ FormatConversionCharToConvInt(conv));
+}
+
+struct FormatConversionCharSetInternal {
+#define ABSL_INTERNAL_CHAR_SET_CASE(c) \
+ static constexpr FormatConversionCharSet c = \
+ FormatConversionCharToConvValue(#c[0]);
+ ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
+#undef ABSL_INTERNAL_CHAR_SET_CASE
+
+ // Used for width/precision '*' specification.
+ static constexpr FormatConversionCharSet kStar =
+ FormatConversionCharToConvValue('*');
+
+ static constexpr FormatConversionCharSet kIntegral =
+ FormatConversionCharSetUnion(d, i, u, o, x, X);
+ static constexpr FormatConversionCharSet kFloating =
+ FormatConversionCharSetUnion(a, e, f, g, A, E, F, G);
+ static constexpr FormatConversionCharSet kNumeric =
+ FormatConversionCharSetUnion(kIntegral, kFloating);
+ static constexpr FormatConversionCharSet kPointer = p;
+};
+
+// Type safe OR operator.
+// We need this for two reasons:
+// 1. operator| on enums makes them decay to integers and the result is an
+// integer. We need the result to stay as an enum.
+// 2. We use "enum class" which would not work even if we accepted the decay.
+constexpr FormatConversionCharSet operator|(FormatConversionCharSet a,
+ FormatConversionCharSet b) {
+ return FormatConversionCharSetUnion(a, b);
+}
+
+// Overloaded conversion functions to support absl::ParsedFormat.
+// Get a conversion with a single character in it.
+constexpr FormatConversionCharSet ToFormatConversionCharSet(char c) {
+ return static_cast<FormatConversionCharSet>(
+ FormatConversionCharToConvValue(c));
}
// Get a conversion with a single character in it.
-constexpr Conv ConversionCharToConv(char c) {
- return Conv(ConversionCharToConvValue(c));
+constexpr FormatConversionCharSet ToFormatConversionCharSet(
+ FormatConversionCharSet c) {
+ return c;
}
+template <typename T>
+void ToFormatConversionCharSet(T) = delete;
+
// Checks whether `c` exists in `set`.
-constexpr bool Contains(Conv set, char c) {
- return (static_cast<uint64_t>(set) & ConversionCharToConvValue(c)) != 0;
+constexpr bool Contains(FormatConversionCharSet set, char c) {
+ return (static_cast<uint64_t>(set) &
+ static_cast<uint64_t>(FormatConversionCharToConvValue(c))) != 0;
}
// Checks whether all the characters in `c` are contained in `set`
-constexpr bool Contains(Conv set, Conv c) {
+constexpr bool Contains(FormatConversionCharSet set,
+ FormatConversionCharSet c) {
return (static_cast<uint64_t>(set) & static_cast<uint64_t>(c)) ==
static_cast<uint64_t>(c);
}
-// Return type of the AbslFormatConvert() functions.
-// The Conv template parameter is used to inform the framework of what
-// conversion characters are supported by that AbslFormatConvert routine.
-template <Conv C>
-struct ConvertResult {
- static constexpr Conv kConv = C;
- bool value;
-};
-template <Conv C>
-constexpr Conv ConvertResult<C>::kConv;
+// Checks whether all the characters in `c` are contained in `set`
+constexpr bool Contains(FormatConversionCharSet set, FormatConversionChar c) {
+ return (static_cast<uint64_t>(set) & FormatConversionCharToConvInt(c)) != 0;
+}
// Return capacity - used, clipped to a minimum of 0.
inline size_t Excess(size_t used, size_t capacity) {
@@ -406,6 +421,7 @@
} // namespace str_format_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
diff --git a/third_party/abseil/absl/strings/internal/str_format/extension_test.cc b/third_party/abseil/absl/strings/internal/str_format/extension_test.cc
index 4e23fef..1c93fdb 100644
--- a/third_party/abseil/absl/strings/internal/str_format/extension_test.cc
+++ b/third_party/abseil/absl/strings/internal/str_format/extension_test.cc
@@ -19,9 +19,26 @@
#include <random>
#include <string>
-#include "absl/strings/str_format.h"
-
#include "gtest/gtest.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/string_view.h"
+
+namespace my_namespace {
+class UserDefinedType {
+ public:
+ UserDefinedType() = default;
+
+ void Append(absl::string_view str) { value_.append(str.data(), str.size()); }
+ const std::string& Value() const { return value_; }
+
+ friend void AbslFormatFlush(UserDefinedType* x, absl::string_view str) {
+ x->Append(str);
+ }
+
+ private:
+ std::string value_;
+};
+} // namespace my_namespace
namespace {
@@ -63,4 +80,19 @@
EXPECT_EQ(actual, expected);
}
}
+
+TEST(FormatExtensionTest, VerifyEnumEquality) {
+#define X_VAL(id) \
+ EXPECT_EQ(absl::FormatConversionChar::id, \
+ absl::str_format_internal::FormatConversionCharInternal::id);
+ ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(X_VAL, );
+#undef X_VAL
+
+#define X_VAL(id) \
+ EXPECT_EQ(absl::FormatConversionCharSet::id, \
+ absl::str_format_internal::FormatConversionCharSetInternal::id);
+ ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(X_VAL, );
+#undef X_VAL
+}
+
} // namespace
diff --git a/third_party/abseil/absl/strings/internal/str_format/float_conversion.cc b/third_party/abseil/absl/strings/internal/str_format/float_conversion.cc
index 9236acd..2aa41aa 100644
--- a/third_party/abseil/absl/strings/internal/str_format/float_conversion.cc
+++ b/third_party/abseil/absl/strings/internal/str_format/float_conversion.cc
@@ -1,25 +1,938 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
#include "absl/strings/internal/str_format/float_conversion.h"
#include <string.h>
+
#include <algorithm>
#include <cassert>
#include <cmath>
+#include <limits>
#include <string>
+#include "absl/base/attributes.h"
#include "absl/base/config.h"
+#include "absl/base/optimization.h"
+#include "absl/functional/function_ref.h"
+#include "absl/meta/type_traits.h"
+#include "absl/numeric/bits.h"
+#include "absl/numeric/int128.h"
+#include "absl/strings/numbers.h"
+#include "absl/types/optional.h"
+#include "absl/types/span.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
namespace {
-char *CopyStringTo(string_view v, char *out) {
+// The code below wants to avoid heap allocations.
+// To do so it needs to allocate memory on the stack.
+// `StackArray` will allocate memory on the stack in the form of a uint32_t
+// array and call the provided callback with said memory.
+// It will allocate memory in increments of 512 bytes. We could allocate the
+// largest needed unconditionally, but that is more than we need in most of
+// cases. This way we use less stack in the common cases.
+class StackArray {
+ using Func = absl::FunctionRef<void(absl::Span<uint32_t>)>;
+ static constexpr size_t kStep = 512 / sizeof(uint32_t);
+ // 5 steps is 2560 bytes, which is enough to hold a long double with the
+ // largest/smallest exponents.
+ // The operations below will static_assert their particular maximum.
+ static constexpr size_t kNumSteps = 5;
+
+ // We do not want this function to be inlined.
+ // Otherwise the caller will allocate the stack space unnecessarily for all
+ // the variants even though it only calls one.
+ template <size_t steps>
+ ABSL_ATTRIBUTE_NOINLINE static void RunWithCapacityImpl(Func f) {
+ uint32_t values[steps * kStep]{};
+ f(absl::MakeSpan(values));
+ }
+
+ public:
+ static constexpr size_t kMaxCapacity = kStep * kNumSteps;
+
+ static void RunWithCapacity(size_t capacity, Func f) {
+ assert(capacity <= kMaxCapacity);
+ const size_t step = (capacity + kStep - 1) / kStep;
+ assert(step <= kNumSteps);
+ switch (step) {
+ case 1:
+ return RunWithCapacityImpl<1>(f);
+ case 2:
+ return RunWithCapacityImpl<2>(f);
+ case 3:
+ return RunWithCapacityImpl<3>(f);
+ case 4:
+ return RunWithCapacityImpl<4>(f);
+ case 5:
+ return RunWithCapacityImpl<5>(f);
+ }
+
+ assert(false && "Invalid capacity");
+ }
+};
+
+// Calculates `10 * (*v) + carry` and stores the result in `*v` and returns
+// the carry.
+template <typename Int>
+inline Int MultiplyBy10WithCarry(Int *v, Int carry) {
+ using BiggerInt = absl::conditional_t<sizeof(Int) == 4, uint64_t, uint128>;
+ BiggerInt tmp = 10 * static_cast<BiggerInt>(*v) + carry;
+ *v = static_cast<Int>(tmp);
+ return static_cast<Int>(tmp >> (sizeof(Int) * 8));
+}
+
+// Calculates `(2^64 * carry + *v) / 10`.
+// Stores the quotient in `*v` and returns the remainder.
+// Requires: `0 <= carry <= 9`
+inline uint64_t DivideBy10WithCarry(uint64_t *v, uint64_t carry) {
+ constexpr uint64_t divisor = 10;
+ // 2^64 / divisor = chunk_quotient + chunk_remainder / divisor
+ constexpr uint64_t chunk_quotient = (uint64_t{1} << 63) / (divisor / 2);
+ constexpr uint64_t chunk_remainder = uint64_t{} - chunk_quotient * divisor;
+
+ const uint64_t mod = *v % divisor;
+ const uint64_t next_carry = chunk_remainder * carry + mod;
+ *v = *v / divisor + carry * chunk_quotient + next_carry / divisor;
+ return next_carry % divisor;
+}
+
+// Generates the decimal representation for an integer of the form `v * 2^exp`,
+// where `v` and `exp` are both positive integers.
+// It generates the digits from the left (ie the most significant digit first)
+// to allow for direct printing into the sink.
+//
+// Requires `0 <= exp` and `exp <= numeric_limits<long double>::max_exponent`.
+class BinaryToDecimal {
+ static constexpr int ChunksNeeded(int exp) {
+ // We will left shift a uint128 by `exp` bits, so we need `128+exp` total
+ // bits. Round up to 32.
+ // See constructor for details about adding `10%` to the value.
+ return (128 + exp + 31) / 32 * 11 / 10;
+ }
+
+ public:
+ // Run the conversion for `v * 2^exp` and call `f(binary_to_decimal)`.
+ // This function will allocate enough stack space to perform the conversion.
+ static void RunConversion(uint128 v, int exp,
+ absl::FunctionRef<void(BinaryToDecimal)> f) {
+ assert(exp > 0);
+ assert(exp <= std::numeric_limits<long double>::max_exponent);
+ static_assert(
+ static_cast<int>(StackArray::kMaxCapacity) >=
+ ChunksNeeded(std::numeric_limits<long double>::max_exponent),
+ "");
+
+ StackArray::RunWithCapacity(
+ ChunksNeeded(exp),
+ [=](absl::Span<uint32_t> input) { f(BinaryToDecimal(input, v, exp)); });
+ }
+
+ int TotalDigits() const {
+ return static_cast<int>((decimal_end_ - decimal_start_) * kDigitsPerChunk +
+ CurrentDigits().size());
+ }
+
+ // See the current block of digits.
+ absl::string_view CurrentDigits() const {
+ return absl::string_view(digits_ + kDigitsPerChunk - size_, size_);
+ }
+
+ // Advance the current view of digits.
+ // Returns `false` when no more digits are available.
+ bool AdvanceDigits() {
+ if (decimal_start_ >= decimal_end_) return false;
+
+ uint32_t w = data_[decimal_start_++];
+ for (size_ = 0; size_ < kDigitsPerChunk; w /= 10) {
+ digits_[kDigitsPerChunk - ++size_] = w % 10 + '0';
+ }
+ return true;
+ }
+
+ private:
+ BinaryToDecimal(absl::Span<uint32_t> data, uint128 v, int exp) : data_(data) {
+ // We need to print the digits directly into the sink object without
+ // buffering them all first. To do this we need two things:
+ // - to know the total number of digits to do padding when necessary
+ // - to generate the decimal digits from the left.
+ //
+ // In order to do this, we do a two pass conversion.
+ // On the first pass we convert the binary representation of the value into
+ // a decimal representation in which each uint32_t chunk holds up to 9
+ // decimal digits. In the second pass we take each decimal-holding-uint32_t
+ // value and generate the ascii decimal digits into `digits_`.
+ //
+ // The binary and decimal representations actually share the same memory
+ // region. As we go converting the chunks from binary to decimal we free
+ // them up and reuse them for the decimal representation. One caveat is that
+ // the decimal representation is around 7% less efficient in space than the
+ // binary one. We allocate an extra 10% memory to account for this. See
+ // ChunksNeeded for this calculation.
+ int chunk_index = exp / 32;
+ decimal_start_ = decimal_end_ = ChunksNeeded(exp);
+ const int offset = exp % 32;
+ // Left shift v by exp bits.
+ data_[chunk_index] = static_cast<uint32_t>(v << offset);
+ for (v >>= (32 - offset); v; v >>= 32)
+ data_[++chunk_index] = static_cast<uint32_t>(v);
+
+ while (chunk_index >= 0) {
+ // While we have more than one chunk available, go in steps of 1e9.
+ // `data_[chunk_index]` holds the highest non-zero binary chunk, so keep
+ // the variable updated.
+ uint32_t carry = 0;
+ for (int i = chunk_index; i >= 0; --i) {
+ uint64_t tmp = uint64_t{data_[i]} + (uint64_t{carry} << 32);
+ data_[i] = static_cast<uint32_t>(tmp / uint64_t{1000000000});
+ carry = static_cast<uint32_t>(tmp % uint64_t{1000000000});
+ }
+
+ // If the highest chunk is now empty, remove it from view.
+ if (data_[chunk_index] == 0) --chunk_index;
+
+ --decimal_start_;
+ assert(decimal_start_ != chunk_index);
+ data_[decimal_start_] = carry;
+ }
+
+ // Fill the first set of digits. The first chunk might not be complete, so
+ // handle differently.
+ for (uint32_t first = data_[decimal_start_++]; first != 0; first /= 10) {
+ digits_[kDigitsPerChunk - ++size_] = first % 10 + '0';
+ }
+ }
+
+ private:
+ static constexpr int kDigitsPerChunk = 9;
+
+ int decimal_start_;
+ int decimal_end_;
+
+ char digits_[kDigitsPerChunk];
+ int size_ = 0;
+
+ absl::Span<uint32_t> data_;
+};
+
+// Converts a value of the form `x * 2^-exp` into a sequence of decimal digits.
+// Requires `-exp < 0` and
+// `-exp >= limits<long double>::min_exponent - limits<long double>::digits`.
+class FractionalDigitGenerator {
+ public:
+ // Run the conversion for `v * 2^exp` and call `f(generator)`.
+ // This function will allocate enough stack space to perform the conversion.
+ static void RunConversion(
+ uint128 v, int exp, absl::FunctionRef<void(FractionalDigitGenerator)> f) {
+ using Limits = std::numeric_limits<long double>;
+ assert(-exp < 0);
+ assert(-exp >= Limits::min_exponent - 128);
+ static_assert(StackArray::kMaxCapacity >=
+ (Limits::digits + 128 - Limits::min_exponent + 31) / 32,
+ "");
+ StackArray::RunWithCapacity((Limits::digits + exp + 31) / 32,
+ [=](absl::Span<uint32_t> input) {
+ f(FractionalDigitGenerator(input, v, exp));
+ });
+ }
+
+ // Returns true if there are any more non-zero digits left.
+ bool HasMoreDigits() const { return next_digit_ != 0 || chunk_index_ >= 0; }
+
+ // Returns true if the remainder digits are greater than 5000...
+ bool IsGreaterThanHalf() const {
+ return next_digit_ > 5 || (next_digit_ == 5 && chunk_index_ >= 0);
+ }
+ // Returns true if the remainder digits are exactly 5000...
+ bool IsExactlyHalf() const { return next_digit_ == 5 && chunk_index_ < 0; }
+
+ struct Digits {
+ int digit_before_nine;
+ int num_nines;
+ };
+
+ // Get the next set of digits.
+ // They are composed by a non-9 digit followed by a runs of zero or more 9s.
+ Digits GetDigits() {
+ Digits digits{next_digit_, 0};
+
+ next_digit_ = GetOneDigit();
+ while (next_digit_ == 9) {
+ ++digits.num_nines;
+ next_digit_ = GetOneDigit();
+ }
+
+ return digits;
+ }
+
+ private:
+ // Return the next digit.
+ int GetOneDigit() {
+ if (chunk_index_ < 0) return 0;
+
+ uint32_t carry = 0;
+ for (int i = chunk_index_; i >= 0; --i) {
+ carry = MultiplyBy10WithCarry(&data_[i], carry);
+ }
+ // If the lowest chunk is now empty, remove it from view.
+ if (data_[chunk_index_] == 0) --chunk_index_;
+ return carry;
+ }
+
+ FractionalDigitGenerator(absl::Span<uint32_t> data, uint128 v, int exp)
+ : chunk_index_(exp / 32), data_(data) {
+ const int offset = exp % 32;
+ // Right shift `v` by `exp` bits.
+ data_[chunk_index_] = static_cast<uint32_t>(v << (32 - offset));
+ v >>= offset;
+ // Make sure we don't overflow the data. We already calculated that
+ // non-zero bits fit, so we might not have space for leading zero bits.
+ for (int pos = chunk_index_; v; v >>= 32)
+ data_[--pos] = static_cast<uint32_t>(v);
+
+ // Fill next_digit_, as GetDigits expects it to be populated always.
+ next_digit_ = GetOneDigit();
+ }
+
+ int next_digit_;
+ int chunk_index_;
+ absl::Span<uint32_t> data_;
+};
+
+// Count the number of leading zero bits.
+int LeadingZeros(uint64_t v) { return countl_zero(v); }
+int LeadingZeros(uint128 v) {
+ auto high = static_cast<uint64_t>(v >> 64);
+ auto low = static_cast<uint64_t>(v);
+ return high != 0 ? countl_zero(high) : 64 + countl_zero(low);
+}
+
+// Round up the text digits starting at `p`.
+// The buffer must have an extra digit that is known to not need rounding.
+// This is done below by having an extra '0' digit on the left.
+void RoundUp(char *p) {
+ while (*p == '9' || *p == '.') {
+ if (*p == '9') *p = '0';
+ --p;
+ }
+ ++*p;
+}
+
+// Check the previous digit and round up or down to follow the round-to-even
+// policy.
+void RoundToEven(char *p) {
+ if (*p == '.') --p;
+ if (*p % 2 == 1) RoundUp(p);
+}
+
+// Simple integral decimal digit printing for values that fit in 64-bits.
+// Returns the pointer to the last written digit.
+char *PrintIntegralDigitsFromRightFast(uint64_t v, char *p) {
+ do {
+ *--p = DivideBy10WithCarry(&v, 0) + '0';
+ } while (v != 0);
+ return p;
+}
+
+// Simple integral decimal digit printing for values that fit in 128-bits.
+// Returns the pointer to the last written digit.
+char *PrintIntegralDigitsFromRightFast(uint128 v, char *p) {
+ auto high = static_cast<uint64_t>(v >> 64);
+ auto low = static_cast<uint64_t>(v);
+
+ while (high != 0) {
+ uint64_t carry = DivideBy10WithCarry(&high, 0);
+ carry = DivideBy10WithCarry(&low, carry);
+ *--p = carry + '0';
+ }
+ return PrintIntegralDigitsFromRightFast(low, p);
+}
+
+// Simple fractional decimal digit printing for values that fir in 64-bits after
+// shifting.
+// Performs rounding if necessary to fit within `precision`.
+// Returns the pointer to one after the last character written.
+char *PrintFractionalDigitsFast(uint64_t v, char *start, int exp,
+ int precision) {
+ char *p = start;
+ v <<= (64 - exp);
+ while (precision > 0) {
+ if (!v) return p;
+ *p++ = MultiplyBy10WithCarry(&v, uint64_t{0}) + '0';
+ --precision;
+ }
+
+ // We need to round.
+ if (v < 0x8000000000000000) {
+ // We round down, so nothing to do.
+ } else if (v > 0x8000000000000000) {
+ // We round up.
+ RoundUp(p - 1);
+ } else {
+ RoundToEven(p - 1);
+ }
+
+ assert(precision == 0);
+ // Precision can only be zero here.
+ return p;
+}
+
+// Simple fractional decimal digit printing for values that fir in 128-bits
+// after shifting.
+// Performs rounding if necessary to fit within `precision`.
+// Returns the pointer to one after the last character written.
+char *PrintFractionalDigitsFast(uint128 v, char *start, int exp,
+ int precision) {
+ char *p = start;
+ v <<= (128 - exp);
+ auto high = static_cast<uint64_t>(v >> 64);
+ auto low = static_cast<uint64_t>(v);
+
+ // While we have digits to print and `low` is not empty, do the long
+ // multiplication.
+ while (precision > 0 && low != 0) {
+ uint64_t carry = MultiplyBy10WithCarry(&low, uint64_t{0});
+ carry = MultiplyBy10WithCarry(&high, carry);
+
+ *p++ = carry + '0';
+ --precision;
+ }
+
+ // Now `low` is empty, so use a faster approach for the rest of the digits.
+ // This block is pretty much the same as the main loop for the 64-bit case
+ // above.
+ while (precision > 0) {
+ if (!high) return p;
+ *p++ = MultiplyBy10WithCarry(&high, uint64_t{0}) + '0';
+ --precision;
+ }
+
+ // We need to round.
+ if (high < 0x8000000000000000) {
+ // We round down, so nothing to do.
+ } else if (high > 0x8000000000000000 || low != 0) {
+ // We round up.
+ RoundUp(p - 1);
+ } else {
+ RoundToEven(p - 1);
+ }
+
+ assert(precision == 0);
+ // Precision can only be zero here.
+ return p;
+}
+
+struct FormatState {
+ char sign_char;
+ int precision;
+ const FormatConversionSpecImpl &conv;
+ FormatSinkImpl *sink;
+
+ // In `alt` mode (flag #) we keep the `.` even if there are no fractional
+ // digits. In non-alt mode, we strip it.
+ bool ShouldPrintDot() const { return precision != 0 || conv.has_alt_flag(); }
+};
+
+struct Padding {
+ int left_spaces;
+ int zeros;
+ int right_spaces;
+};
+
+Padding ExtraWidthToPadding(size_t total_size, const FormatState &state) {
+ if (state.conv.width() < 0 ||
+ static_cast<size_t>(state.conv.width()) <= total_size) {
+ return {0, 0, 0};
+ }
+ int missing_chars = state.conv.width() - total_size;
+ if (state.conv.has_left_flag()) {
+ return {0, 0, missing_chars};
+ } else if (state.conv.has_zero_flag()) {
+ return {0, missing_chars, 0};
+ } else {
+ return {missing_chars, 0, 0};
+ }
+}
+
+void FinalPrint(const FormatState &state, absl::string_view data,
+ int padding_offset, int trailing_zeros,
+ absl::string_view data_postfix) {
+ if (state.conv.width() < 0) {
+ // No width specified. Fast-path.
+ if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
+ state.sink->Append(data);
+ state.sink->Append(trailing_zeros, '0');
+ state.sink->Append(data_postfix);
+ return;
+ }
+
+ auto padding = ExtraWidthToPadding((state.sign_char != '\0' ? 1 : 0) +
+ data.size() + data_postfix.size() +
+ static_cast<size_t>(trailing_zeros),
+ state);
+
+ state.sink->Append(padding.left_spaces, ' ');
+ if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
+ // Padding in general needs to be inserted somewhere in the middle of `data`.
+ state.sink->Append(data.substr(0, padding_offset));
+ state.sink->Append(padding.zeros, '0');
+ state.sink->Append(data.substr(padding_offset));
+ state.sink->Append(trailing_zeros, '0');
+ state.sink->Append(data_postfix);
+ state.sink->Append(padding.right_spaces, ' ');
+}
+
+// Fastpath %f formatter for when the shifted value fits in a simple integral
+// type.
+// Prints `v*2^exp` with the options from `state`.
+template <typename Int>
+void FormatFFast(Int v, int exp, const FormatState &state) {
+ constexpr int input_bits = sizeof(Int) * 8;
+
+ static constexpr size_t integral_size =
+ /* in case we need to round up an extra digit */ 1 +
+ /* decimal digits for uint128 */ 40 + 1;
+ char buffer[integral_size + /* . */ 1 + /* max digits uint128 */ 128];
+ buffer[integral_size] = '.';
+ char *const integral_digits_end = buffer + integral_size;
+ char *integral_digits_start;
+ char *const fractional_digits_start = buffer + integral_size + 1;
+ char *fractional_digits_end = fractional_digits_start;
+
+ if (exp >= 0) {
+ const int total_bits = input_bits - LeadingZeros(v) + exp;
+ integral_digits_start =
+ total_bits <= 64
+ ? PrintIntegralDigitsFromRightFast(static_cast<uint64_t>(v) << exp,
+ integral_digits_end)
+ : PrintIntegralDigitsFromRightFast(static_cast<uint128>(v) << exp,
+ integral_digits_end);
+ } else {
+ exp = -exp;
+
+ integral_digits_start = PrintIntegralDigitsFromRightFast(
+ exp < input_bits ? v >> exp : 0, integral_digits_end);
+ // PrintFractionalDigits may pull a carried 1 all the way up through the
+ // integral portion.
+ integral_digits_start[-1] = '0';
+
+ fractional_digits_end =
+ exp <= 64 ? PrintFractionalDigitsFast(v, fractional_digits_start, exp,
+ state.precision)
+ : PrintFractionalDigitsFast(static_cast<uint128>(v),
+ fractional_digits_start, exp,
+ state.precision);
+ // There was a carry, so include the first digit too.
+ if (integral_digits_start[-1] != '0') --integral_digits_start;
+ }
+
+ size_t size = fractional_digits_end - integral_digits_start;
+
+ // In `alt` mode (flag #) we keep the `.` even if there are no fractional
+ // digits. In non-alt mode, we strip it.
+ if (!state.ShouldPrintDot()) --size;
+ FinalPrint(state, absl::string_view(integral_digits_start, size),
+ /*padding_offset=*/0,
+ static_cast<int>(state.precision - (fractional_digits_end -
+ fractional_digits_start)),
+ /*data_postfix=*/"");
+}
+
+// Slow %f formatter for when the shifted value does not fit in a uint128, and
+// `exp > 0`.
+// Prints `v*2^exp` with the options from `state`.
+// This one is guaranteed to not have fractional digits, so we don't have to
+// worry about anything after the `.`.
+void FormatFPositiveExpSlow(uint128 v, int exp, const FormatState &state) {
+ BinaryToDecimal::RunConversion(v, exp, [&](BinaryToDecimal btd) {
+ const size_t total_digits =
+ btd.TotalDigits() +
+ (state.ShouldPrintDot() ? static_cast<size_t>(state.precision) + 1 : 0);
+
+ const auto padding = ExtraWidthToPadding(
+ total_digits + (state.sign_char != '\0' ? 1 : 0), state);
+
+ state.sink->Append(padding.left_spaces, ' ');
+ if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
+ state.sink->Append(padding.zeros, '0');
+
+ do {
+ state.sink->Append(btd.CurrentDigits());
+ } while (btd.AdvanceDigits());
+
+ if (state.ShouldPrintDot()) state.sink->Append(1, '.');
+ state.sink->Append(state.precision, '0');
+ state.sink->Append(padding.right_spaces, ' ');
+ });
+}
+
+// Slow %f formatter for when the shifted value does not fit in a uint128, and
+// `exp < 0`.
+// Prints `v*2^exp` with the options from `state`.
+// This one is guaranteed to be < 1.0, so we don't have to worry about integral
+// digits.
+void FormatFNegativeExpSlow(uint128 v, int exp, const FormatState &state) {
+ const size_t total_digits =
+ /* 0 */ 1 +
+ (state.ShouldPrintDot() ? static_cast<size_t>(state.precision) + 1 : 0);
+ auto padding =
+ ExtraWidthToPadding(total_digits + (state.sign_char ? 1 : 0), state);
+ padding.zeros += 1;
+ state.sink->Append(padding.left_spaces, ' ');
+ if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
+ state.sink->Append(padding.zeros, '0');
+
+ if (state.ShouldPrintDot()) state.sink->Append(1, '.');
+
+ // Print digits
+ int digits_to_go = state.precision;
+
+ FractionalDigitGenerator::RunConversion(
+ v, exp, [&](FractionalDigitGenerator digit_gen) {
+ // There are no digits to print here.
+ if (state.precision == 0) return;
+
+ // We go one digit at a time, while keeping track of runs of nines.
+ // The runs of nines are used to perform rounding when necessary.
+
+ while (digits_to_go > 0 && digit_gen.HasMoreDigits()) {
+ auto digits = digit_gen.GetDigits();
+
+ // Now we have a digit and a run of nines.
+ // See if we can print them all.
+ if (digits.num_nines + 1 < digits_to_go) {
+ // We don't have to round yet, so print them.
+ state.sink->Append(1, digits.digit_before_nine + '0');
+ state.sink->Append(digits.num_nines, '9');
+ digits_to_go -= digits.num_nines + 1;
+
+ } else {
+ // We can't print all the nines, see where we have to truncate.
+
+ bool round_up = false;
+ if (digits.num_nines + 1 > digits_to_go) {
+ // We round up at a nine. No need to print them.
+ round_up = true;
+ } else {
+ // We can fit all the nines, but truncate just after it.
+ if (digit_gen.IsGreaterThanHalf()) {
+ round_up = true;
+ } else if (digit_gen.IsExactlyHalf()) {
+ // Round to even
+ round_up =
+ digits.num_nines != 0 || digits.digit_before_nine % 2 == 1;
+ }
+ }
+
+ if (round_up) {
+ state.sink->Append(1, digits.digit_before_nine + '1');
+ --digits_to_go;
+ // The rest will be zeros.
+ } else {
+ state.sink->Append(1, digits.digit_before_nine + '0');
+ state.sink->Append(digits_to_go - 1, '9');
+ digits_to_go = 0;
+ }
+ return;
+ }
+ }
+ });
+
+ state.sink->Append(digits_to_go, '0');
+ state.sink->Append(padding.right_spaces, ' ');
+}
+
+template <typename Int>
+void FormatF(Int mantissa, int exp, const FormatState &state) {
+ if (exp >= 0) {
+ const int total_bits = sizeof(Int) * 8 - LeadingZeros(mantissa) + exp;
+
+ // Fallback to the slow stack-based approach if we can't do it in a 64 or
+ // 128 bit state.
+ if (ABSL_PREDICT_FALSE(total_bits > 128)) {
+ return FormatFPositiveExpSlow(mantissa, exp, state);
+ }
+ } else {
+ // Fallback to the slow stack-based approach if we can't do it in a 64 or
+ // 128 bit state.
+ if (ABSL_PREDICT_FALSE(exp < -128)) {
+ return FormatFNegativeExpSlow(mantissa, -exp, state);
+ }
+ }
+ return FormatFFast(mantissa, exp, state);
+}
+
+// Grab the group of four bits (nibble) from `n`. E.g., nibble 1 corresponds to
+// bits 4-7.
+template <typename Int>
+uint8_t GetNibble(Int n, int nibble_index) {
+ constexpr Int mask_low_nibble = Int{0xf};
+ int shift = nibble_index * 4;
+ n &= mask_low_nibble << shift;
+ return static_cast<uint8_t>((n >> shift) & 0xf);
+}
+
+// Add one to the given nibble, applying carry to higher nibbles. Returns true
+// if overflow, false otherwise.
+template <typename Int>
+bool IncrementNibble(int nibble_index, Int *n) {
+ constexpr int kShift = sizeof(Int) * 8 - 1;
+ constexpr int kNumNibbles = sizeof(Int) * 8 / 4;
+ Int before = *n >> kShift;
+ // Here we essentially want to take the number 1 and move it into the requsted
+ // nibble, then add it to *n to effectively increment the nibble. However,
+ // ASan will complain if we try to shift the 1 beyond the limits of the Int,
+ // i.e., if the nibble_index is out of range. So therefore we check for this
+ // and if we are out of range we just add 0 which leaves *n unchanged, which
+ // seems like the reasonable thing to do in that case.
+ *n += ((nibble_index >= kNumNibbles) ? 0 : (Int{1} << (nibble_index * 4)));
+ Int after = *n >> kShift;
+ return (before && !after) || (nibble_index >= kNumNibbles);
+}
+
+// Return a mask with 1's in the given nibble and all lower nibbles.
+template <typename Int>
+Int MaskUpToNibbleInclusive(int nibble_index) {
+ constexpr int kNumNibbles = sizeof(Int) * 8 / 4;
+ static const Int ones = ~Int{0};
+ return ones >> std::max(0, 4 * (kNumNibbles - nibble_index - 1));
+}
+
+// Return a mask with 1's below the given nibble.
+template <typename Int>
+Int MaskUpToNibbleExclusive(int nibble_index) {
+ return nibble_index <= 0 ? 0 : MaskUpToNibbleInclusive<Int>(nibble_index - 1);
+}
+
+template <typename Int>
+Int MoveToNibble(uint8_t nibble, int nibble_index) {
+ return Int{nibble} << (4 * nibble_index);
+}
+
+// Given mantissa size, find optimal # of mantissa bits to put in initial digit.
+//
+// In the hex representation we keep a single hex digit to the left of the dot.
+// However, the question as to how many bits of the mantissa should be put into
+// that hex digit in theory is arbitrary, but in practice it is optimal to
+// choose based on the size of the mantissa. E.g., for a `double`, there are 53
+// mantissa bits, so that means that we should put 1 bit to the left of the dot,
+// thereby leaving 52 bits to the right, which is evenly divisible by four and
+// thus all fractional digits represent actual precision. For a `long double`,
+// on the other hand, there are 64 bits of mantissa, thus we can use all four
+// bits for the initial hex digit and still have a number left over (60) that is
+// a multiple of four. Once again, the goal is to have all fractional digits
+// represent real precision.
+template <typename Float>
+constexpr int HexFloatLeadingDigitSizeInBits() {
+ return std::numeric_limits<Float>::digits % 4 > 0
+ ? std::numeric_limits<Float>::digits % 4
+ : 4;
+}
+
+// This function captures the rounding behavior of glibc for hex float
+// representations. E.g. when rounding 0x1.ab800000 to a precision of .2
+// ("%.2a") glibc will round up because it rounds toward the even number (since
+// 0xb is an odd number, it will round up to 0xc). However, when rounding at a
+// point that is not followed by 800000..., it disregards the parity and rounds
+// up if > 8 and rounds down if < 8.
+template <typename Int>
+bool HexFloatNeedsRoundUp(Int mantissa, int final_nibble_displayed,
+ uint8_t leading) {
+ // If the last nibble (hex digit) to be displayed is the lowest on in the
+ // mantissa then that means that we don't have any further nibbles to inform
+ // rounding, so don't round.
+ if (final_nibble_displayed <= 0) {
+ return false;
+ }
+ int rounding_nibble_idx = final_nibble_displayed - 1;
+ constexpr int kTotalNibbles = sizeof(Int) * 8 / 4;
+ assert(final_nibble_displayed <= kTotalNibbles);
+ Int mantissa_up_to_rounding_nibble_inclusive =
+ mantissa & MaskUpToNibbleInclusive<Int>(rounding_nibble_idx);
+ Int eight = MoveToNibble<Int>(8, rounding_nibble_idx);
+ if (mantissa_up_to_rounding_nibble_inclusive != eight) {
+ return mantissa_up_to_rounding_nibble_inclusive > eight;
+ }
+ // Nibble in question == 8.
+ uint8_t round_if_odd = (final_nibble_displayed == kTotalNibbles)
+ ? leading
+ : GetNibble(mantissa, final_nibble_displayed);
+ return round_if_odd % 2 == 1;
+}
+
+// Stores values associated with a Float type needed by the FormatA
+// implementation in order to avoid templatizing that function by the Float
+// type.
+struct HexFloatTypeParams {
+ template <typename Float>
+ explicit HexFloatTypeParams(Float)
+ : min_exponent(std::numeric_limits<Float>::min_exponent - 1),
+ leading_digit_size_bits(HexFloatLeadingDigitSizeInBits<Float>()) {
+ assert(leading_digit_size_bits >= 1 && leading_digit_size_bits <= 4);
+ }
+
+ int min_exponent;
+ int leading_digit_size_bits;
+};
+
+// Hex Float Rounding. First check if we need to round; if so, then we do that
+// by manipulating (incrementing) the mantissa, that way we can later print the
+// mantissa digits by iterating through them in the same way regardless of
+// whether a rounding happened.
+template <typename Int>
+void FormatARound(bool precision_specified, const FormatState &state,
+ uint8_t *leading, Int *mantissa, int *exp) {
+ constexpr int kTotalNibbles = sizeof(Int) * 8 / 4;
+ // Index of the last nibble that we could display given precision.
+ int final_nibble_displayed =
+ precision_specified ? std::max(0, (kTotalNibbles - state.precision)) : 0;
+ if (HexFloatNeedsRoundUp(*mantissa, final_nibble_displayed, *leading)) {
+ // Need to round up.
+ bool overflow = IncrementNibble(final_nibble_displayed, mantissa);
+ *leading += (overflow ? 1 : 0);
+ if (ABSL_PREDICT_FALSE(*leading > 15)) {
+ // We have overflowed the leading digit. This would mean that we would
+ // need two hex digits to the left of the dot, which is not allowed. So
+ // adjust the mantissa and exponent so that the result is always 1.0eXXX.
+ *leading = 1;
+ *mantissa = 0;
+ *exp += 4;
+ }
+ }
+ // Now that we have handled a possible round-up we can go ahead and zero out
+ // all the nibbles of the mantissa that we won't need.
+ if (precision_specified) {
+ *mantissa &= ~MaskUpToNibbleExclusive<Int>(final_nibble_displayed);
+ }
+}
+
+template <typename Int>
+void FormatANormalize(const HexFloatTypeParams float_traits, uint8_t *leading,
+ Int *mantissa, int *exp) {
+ constexpr int kIntBits = sizeof(Int) * 8;
+ static const Int kHighIntBit = Int{1} << (kIntBits - 1);
+ const int kLeadDigitBitsCount = float_traits.leading_digit_size_bits;
+ // Normalize mantissa so that highest bit set is in MSB position, unless we
+ // get interrupted by the exponent threshold.
+ while (*mantissa && !(*mantissa & kHighIntBit)) {
+ if (ABSL_PREDICT_FALSE(*exp - 1 < float_traits.min_exponent)) {
+ *mantissa >>= (float_traits.min_exponent - *exp);
+ *exp = float_traits.min_exponent;
+ return;
+ }
+ *mantissa <<= 1;
+ --*exp;
+ }
+ // Extract bits for leading digit then shift them away leaving the
+ // fractional part.
+ *leading =
+ static_cast<uint8_t>(*mantissa >> (kIntBits - kLeadDigitBitsCount));
+ *exp -= (*mantissa != 0) ? kLeadDigitBitsCount : *exp;
+ *mantissa <<= kLeadDigitBitsCount;
+}
+
+template <typename Int>
+void FormatA(const HexFloatTypeParams float_traits, Int mantissa, int exp,
+ bool uppercase, const FormatState &state) {
+ // Int properties.
+ constexpr int kIntBits = sizeof(Int) * 8;
+ constexpr int kTotalNibbles = sizeof(Int) * 8 / 4;
+ // Did the user specify a precision explicitly?
+ const bool precision_specified = state.conv.precision() >= 0;
+
+ // ========== Normalize/Denormalize ==========
+ exp += kIntBits; // make all digits fractional digits.
+ // This holds the (up to four) bits of leading digit, i.e., the '1' in the
+ // number 0x1.e6fp+2. It's always > 0 unless number is zero or denormal.
+ uint8_t leading = 0;
+ FormatANormalize(float_traits, &leading, &mantissa, &exp);
+
+ // =============== Rounding ==================
+ // Check if we need to round; if so, then we do that by manipulating
+ // (incrementing) the mantissa before beginning to print characters.
+ FormatARound(precision_specified, state, &leading, &mantissa, &exp);
+
+ // ============= Format Result ===============
+ // This buffer holds the "0x1.ab1de3" portion of "0x1.ab1de3pe+2". Compute the
+ // size with long double which is the largest of the floats.
+ constexpr size_t kBufSizeForHexFloatRepr =
+ 2 // 0x
+ + std::numeric_limits<long double>::digits / 4 // number of hex digits
+ + 1 // round up
+ + 1; // "." (dot)
+ char digits_buffer[kBufSizeForHexFloatRepr];
+ char *digits_iter = digits_buffer;
+ const char *const digits =
+ static_cast<const char *>("0123456789ABCDEF0123456789abcdef") +
+ (uppercase ? 0 : 16);
+
+ // =============== Hex Prefix ================
+ *digits_iter++ = '0';
+ *digits_iter++ = uppercase ? 'X' : 'x';
+
+ // ========== Non-Fractional Digit ===========
+ *digits_iter++ = digits[leading];
+
+ // ================== Dot ====================
+ // There are three reasons we might need a dot. Keep in mind that, at this
+ // point, the mantissa holds only the fractional part.
+ if ((precision_specified && state.precision > 0) ||
+ (!precision_specified && mantissa > 0) || state.conv.has_alt_flag()) {
+ *digits_iter++ = '.';
+ }
+
+ // ============ Fractional Digits ============
+ int digits_emitted = 0;
+ while (mantissa > 0) {
+ *digits_iter++ = digits[GetNibble(mantissa, kTotalNibbles - 1)];
+ mantissa <<= 4;
+ ++digits_emitted;
+ }
+ int trailing_zeros =
+ precision_specified ? state.precision - digits_emitted : 0;
+ assert(trailing_zeros >= 0);
+ auto digits_result = string_view(digits_buffer, digits_iter - digits_buffer);
+
+ // =============== Exponent ==================
+ constexpr size_t kBufSizeForExpDecRepr =
+ numbers_internal::kFastToBufferSize // requred for FastIntToBuffer
+ + 1 // 'p' or 'P'
+ + 1; // '+' or '-'
+ char exp_buffer[kBufSizeForExpDecRepr];
+ exp_buffer[0] = uppercase ? 'P' : 'p';
+ exp_buffer[1] = exp >= 0 ? '+' : '-';
+ numbers_internal::FastIntToBuffer(exp < 0 ? -exp : exp, exp_buffer + 2);
+
+ // ============ Assemble Result ==============
+ FinalPrint(state, //
+ digits_result, // 0xN.NNN...
+ 2, // offset in `data` to start padding if needed.
+ trailing_zeros, // num remaining mantissa padding zeros
+ exp_buffer); // exponent
+}
+
+char *CopyStringTo(absl::string_view v, char *out) {
std::memcpy(out, v.data(), v.size());
return out + v.size();
}
template <typename Float>
-bool FallbackToSnprintf(const Float v, const ConversionSpec &conv,
+bool FallbackToSnprintf(const Float v, const FormatConversionSpecImpl &conv,
FormatSinkImpl *sink) {
int w = conv.width() >= 0 ? conv.width() : 0;
int p = conv.precision() >= 0 ? conv.precision() : -1;
@@ -27,22 +940,22 @@
{
char *fp = fmt;
*fp++ = '%';
- fp = CopyStringTo(conv.flags().ToString(), fp);
+ fp = CopyStringTo(FormatConversionSpecImplFriend::FlagsToString(conv), fp);
fp = CopyStringTo("*.*", fp);
if (std::is_same<long double, Float>()) {
*fp++ = 'L';
}
- *fp++ = conv.conv().Char();
+ *fp++ = FormatConversionCharToChar(conv.conversion_char());
*fp = 0;
assert(fp < fmt + sizeof(fmt));
}
std::string space(512, '\0');
- string_view result;
+ absl::string_view result;
while (true) {
int n = snprintf(&space[0], space.size(), fmt, w, p, v);
if (n < 0) return false;
if (static_cast<size_t>(n) < space.size()) {
- result = string_view(space.data(), n);
+ result = absl::string_view(space.data(), n);
break;
}
space.resize(n + 1);
@@ -95,19 +1008,24 @@
// Otherwise, return false.
template <typename Float>
bool ConvertNonNumericFloats(char sign_char, Float v,
- const ConversionSpec &conv, FormatSinkImpl *sink) {
+ const FormatConversionSpecImpl &conv,
+ FormatSinkImpl *sink) {
char text[4], *ptr = text;
- if (sign_char) *ptr++ = sign_char;
+ if (sign_char != '\0') *ptr++ = sign_char;
if (std::isnan(v)) {
- ptr = std::copy_n(conv.conv().upper() ? "NAN" : "nan", 3, ptr);
+ ptr = std::copy_n(
+ FormatConversionCharIsUpper(conv.conversion_char()) ? "NAN" : "nan", 3,
+ ptr);
} else if (std::isinf(v)) {
- ptr = std::copy_n(conv.conv().upper() ? "INF" : "inf", 3, ptr);
+ ptr = std::copy_n(
+ FormatConversionCharIsUpper(conv.conversion_char()) ? "INF" : "inf", 3,
+ ptr);
} else {
return false;
}
return sink->PutPaddedString(string_view(text, ptr - text), conv.width(), -1,
- conv.flags().left);
+ conv.has_left_flag());
}
// Round up the last digit of the value.
@@ -167,7 +1085,12 @@
template <typename Float>
struct Decomposed {
- Float mantissa;
+ using MantissaType =
+ absl::conditional_t<std::is_same<long double, Float>::value, uint128,
+ uint64_t>;
+ static_assert(std::numeric_limits<Float>::digits <= sizeof(MantissaType) * 8,
+ "");
+ MantissaType mantissa;
int exponent;
};
@@ -178,7 +1101,8 @@
Float m = std::frexp(v, &exp);
m = std::ldexp(m, std::numeric_limits<Float>::digits);
exp -= std::numeric_limits<Float>::digits;
- return {m, exp};
+
+ return {static_cast<typename Decomposed<Float>::MantissaType>(m), exp};
}
// Print 'digits' as decimal.
@@ -347,31 +1271,32 @@
return false;
}
-void WriteBufferToSink(char sign_char, string_view str,
- const ConversionSpec &conv, FormatSinkImpl *sink) {
+void WriteBufferToSink(char sign_char, absl::string_view str,
+ const FormatConversionSpecImpl &conv,
+ FormatSinkImpl *sink) {
int left_spaces = 0, zeros = 0, right_spaces = 0;
int missing_chars =
conv.width() >= 0 ? std::max(conv.width() - static_cast<int>(str.size()) -
static_cast<int>(sign_char != 0),
0)
: 0;
- if (conv.flags().left) {
+ if (conv.has_left_flag()) {
right_spaces = missing_chars;
- } else if (conv.flags().zero) {
+ } else if (conv.has_zero_flag()) {
zeros = missing_chars;
} else {
left_spaces = missing_chars;
}
sink->Append(left_spaces, ' ');
- if (sign_char) sink->Append(1, sign_char);
+ if (sign_char != '\0') sink->Append(1, sign_char);
sink->Append(zeros, '0');
sink->Append(str);
sink->Append(right_spaces, ' ');
}
template <typename Float>
-bool FloatToSink(const Float v, const ConversionSpec &conv,
+bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv,
FormatSinkImpl *sink) {
// Print the sign or the sign column.
Float abs_v = v;
@@ -379,9 +1304,9 @@
if (std::signbit(abs_v)) {
sign_char = '-';
abs_v = -abs_v;
- } else if (conv.flags().show_pos) {
+ } else if (conv.has_show_pos_flag()) {
sign_char = '+';
- } else if (conv.flags().sign_col) {
+ } else if (conv.has_sign_col_flag()) {
sign_char = ' ';
}
@@ -398,88 +1323,96 @@
Buffer buffer;
- switch (conv.conv().id()) {
- case ConversionChar::f:
- case ConversionChar::F:
- if (!FloatToBuffer<FormatStyle::Fixed>(decomposed, precision, &buffer,
- nullptr)) {
- return FallbackToSnprintf(v, conv, sink);
- }
- if (!conv.flags().alt && buffer.back() == '.') buffer.pop_back();
- break;
+ FormatConversionChar c = conv.conversion_char();
- case ConversionChar::e:
- case ConversionChar::E:
- if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
- &exp)) {
- return FallbackToSnprintf(v, conv, sink);
- }
- if (!conv.flags().alt && buffer.back() == '.') buffer.pop_back();
- PrintExponent(exp, conv.conv().upper() ? 'E' : 'e', &buffer);
- break;
-
- case ConversionChar::g:
- case ConversionChar::G:
- precision = std::max(0, precision - 1);
- if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
- &exp)) {
- return FallbackToSnprintf(v, conv, sink);
- }
- if (precision + 1 > exp && exp >= -4) {
- if (exp < 0) {
- // Have 1.23456, needs 0.00123456
- // Move the first digit
- buffer.begin[1] = *buffer.begin;
- // Add some zeros
- for (; exp < -1; ++exp) *buffer.begin-- = '0';
- *buffer.begin-- = '.';
- *buffer.begin = '0';
- } else if (exp > 0) {
- // Have 1.23456, needs 1234.56
- // Move the '.' exp positions to the right.
- std::rotate(buffer.begin + 1, buffer.begin + 2,
- buffer.begin + exp + 2);
- }
- exp = 0;
- }
- if (!conv.flags().alt) {
- while (buffer.back() == '0') buffer.pop_back();
- if (buffer.back() == '.') buffer.pop_back();
- }
- if (exp) PrintExponent(exp, conv.conv().upper() ? 'E' : 'e', &buffer);
- break;
-
- case ConversionChar::a:
- case ConversionChar::A:
+ if (c == FormatConversionCharInternal::f ||
+ c == FormatConversionCharInternal::F) {
+ FormatF(decomposed.mantissa, decomposed.exponent,
+ {sign_char, precision, conv, sink});
+ return true;
+ } else if (c == FormatConversionCharInternal::e ||
+ c == FormatConversionCharInternal::E) {
+ if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
+ &exp)) {
return FallbackToSnprintf(v, conv, sink);
-
- default:
- return false;
+ }
+ if (!conv.has_alt_flag() && buffer.back() == '.') buffer.pop_back();
+ PrintExponent(
+ exp, FormatConversionCharIsUpper(conv.conversion_char()) ? 'E' : 'e',
+ &buffer);
+ } else if (c == FormatConversionCharInternal::g ||
+ c == FormatConversionCharInternal::G) {
+ precision = std::max(0, precision - 1);
+ if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
+ &exp)) {
+ return FallbackToSnprintf(v, conv, sink);
+ }
+ if (precision + 1 > exp && exp >= -4) {
+ if (exp < 0) {
+ // Have 1.23456, needs 0.00123456
+ // Move the first digit
+ buffer.begin[1] = *buffer.begin;
+ // Add some zeros
+ for (; exp < -1; ++exp) *buffer.begin-- = '0';
+ *buffer.begin-- = '.';
+ *buffer.begin = '0';
+ } else if (exp > 0) {
+ // Have 1.23456, needs 1234.56
+ // Move the '.' exp positions to the right.
+ std::rotate(buffer.begin + 1, buffer.begin + 2, buffer.begin + exp + 2);
+ }
+ exp = 0;
+ }
+ if (!conv.has_alt_flag()) {
+ while (buffer.back() == '0') buffer.pop_back();
+ if (buffer.back() == '.') buffer.pop_back();
+ }
+ if (exp) {
+ PrintExponent(
+ exp, FormatConversionCharIsUpper(conv.conversion_char()) ? 'E' : 'e',
+ &buffer);
+ }
+ } else if (c == FormatConversionCharInternal::a ||
+ c == FormatConversionCharInternal::A) {
+ bool uppercase = (c == FormatConversionCharInternal::A);
+ FormatA(HexFloatTypeParams(Float{}), decomposed.mantissa,
+ decomposed.exponent, uppercase, {sign_char, precision, conv, sink});
+ return true;
+ } else {
+ return false;
}
WriteBufferToSink(sign_char,
- string_view(buffer.begin, buffer.end - buffer.begin), conv,
- sink);
+ absl::string_view(buffer.begin, buffer.end - buffer.begin),
+ conv, sink);
return true;
}
} // namespace
-bool ConvertFloatImpl(long double v, const ConversionSpec &conv,
+bool ConvertFloatImpl(long double v, const FormatConversionSpecImpl &conv,
FormatSinkImpl *sink) {
+ if (std::numeric_limits<long double>::digits ==
+ 2 * std::numeric_limits<double>::digits) {
+ // This is the `double-double` representation of `long double`.
+ // We do not handle it natively. Fallback to snprintf.
+ return FallbackToSnprintf(v, conv, sink);
+ }
+
return FloatToSink(v, conv, sink);
}
-bool ConvertFloatImpl(float v, const ConversionSpec &conv,
+bool ConvertFloatImpl(float v, const FormatConversionSpecImpl &conv,
FormatSinkImpl *sink) {
- return FloatToSink(v, conv, sink);
+ return FloatToSink(static_cast<double>(v), conv, sink);
}
-bool ConvertFloatImpl(double v, const ConversionSpec &conv,
+bool ConvertFloatImpl(double v, const FormatConversionSpecImpl &conv,
FormatSinkImpl *sink) {
return FloatToSink(v, conv, sink);
}
} // namespace str_format_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/internal/str_format/float_conversion.h b/third_party/abseil/absl/strings/internal/str_format/float_conversion.h
index 8ba5566..71100e7 100644
--- a/third_party/abseil/absl/strings/internal/str_format/float_conversion.h
+++ b/third_party/abseil/absl/strings/internal/str_format/float_conversion.h
@@ -1,21 +1,37 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
#include "absl/strings/internal/str_format/extension.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
-bool ConvertFloatImpl(float v, const ConversionSpec &conv,
+bool ConvertFloatImpl(float v, const FormatConversionSpecImpl &conv,
FormatSinkImpl *sink);
-bool ConvertFloatImpl(double v, const ConversionSpec &conv,
+bool ConvertFloatImpl(double v, const FormatConversionSpecImpl &conv,
FormatSinkImpl *sink);
-bool ConvertFloatImpl(long double v, const ConversionSpec &conv,
+bool ConvertFloatImpl(long double v, const FormatConversionSpecImpl &conv,
FormatSinkImpl *sink);
} // namespace str_format_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
diff --git a/third_party/abseil/absl/strings/internal/str_format/output.cc b/third_party/abseil/absl/strings/internal/str_format/output.cc
index 38987b6..c4b2470 100644
--- a/third_party/abseil/absl/strings/internal/str_format/output.cc
+++ b/third_party/abseil/absl/strings/internal/str_format/output.cc
@@ -18,6 +18,7 @@
#include <cstring>
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
namespace {
@@ -67,4 +68,5 @@
}
} // namespace str_format_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/internal/str_format/output.h b/third_party/abseil/absl/strings/internal/str_format/output.h
index 42da641..8030dae 100644
--- a/third_party/abseil/absl/strings/internal/str_format/output.h
+++ b/third_party/abseil/absl/strings/internal/str_format/output.h
@@ -28,9 +28,8 @@
#include "absl/base/port.h"
#include "absl/strings/string_view.h"
-class Cord;
-
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
// RawSink implementation that writes into a char* buffer.
@@ -75,12 +74,6 @@
out->write(s.data(), s.size());
}
-template <class AbslCord, typename = typename std::enable_if<
- std::is_same<AbslCord, ::Cord>::value>::type>
-inline void AbslFormatFlush(AbslCord* out, string_view s) {
- out->Append(s);
-}
-
inline void AbslFormatFlush(FILERawSink* sink, string_view v) {
sink->Write(v);
}
@@ -89,13 +82,15 @@
sink->Write(v);
}
+// This is a SFINAE to get a better compiler error message when the type
+// is not supported.
template <typename T>
-auto InvokeFlush(T* out, string_view s)
- -> decltype(str_format_internal::AbslFormatFlush(out, s)) {
- str_format_internal::AbslFormatFlush(out, s);
+auto InvokeFlush(T* out, string_view s) -> decltype(AbslFormatFlush(out, s)) {
+ AbslFormatFlush(out, s);
}
} // namespace str_format_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_
diff --git a/third_party/abseil/absl/strings/internal/str_format/output_test.cc b/third_party/abseil/absl/strings/internal/str_format/output_test.cc
index 6e04abe..ce2e91a 100644
--- a/third_party/abseil/absl/strings/internal/str_format/output_test.cc
+++ b/third_party/abseil/absl/strings/internal/str_format/output_test.cc
@@ -19,8 +19,10 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/strings/cord.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
TEST(InvokeFlush, String) {
@@ -36,6 +38,12 @@
EXPECT_EQ(str.str(), "ABCDEF");
}
+TEST(InvokeFlush, Cord) {
+ absl::Cord str("ABC");
+ str_format_internal::InvokeFlush(&str, "DEF");
+ EXPECT_EQ(str, "ABCDEF");
+}
+
TEST(BufferRawSink, Limits) {
char buf[16];
{
@@ -67,5 +75,5 @@
}
} // namespace
+ABSL_NAMESPACE_END
} // namespace absl
-
diff --git a/third_party/abseil/absl/strings/internal/str_format/parser.cc b/third_party/abseil/absl/strings/internal/str_format/parser.cc
index 9ef5615..f308d02 100644
--- a/third_party/abseil/absl/strings/internal/str_format/parser.cc
+++ b/third_party/abseil/absl/strings/internal/str_format/parser.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
#include "absl/strings/internal/str_format/parser.h"
#include <assert.h>
@@ -14,10 +28,12 @@
#include <unordered_set>
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
-using CC = ConversionChar::Id;
-using LM = LengthMod::Id;
+using CC = FormatConversionCharInternal;
+using LM = LengthMod;
+
ABSL_CONST_INIT const ConvTag kTags[256] = {
{}, {}, {}, {}, {}, {}, {}, {}, // 00-07
{}, {}, {}, {}, {}, {}, {}, {}, // 08-0f
@@ -27,9 +43,9 @@
{}, {}, {}, {}, {}, {}, {}, {}, // 28-2f
{}, {}, {}, {}, {}, {}, {}, {}, // 30-37
{}, {}, {}, {}, {}, {}, {}, {}, // 38-3f
- {}, CC::A, {}, CC::C, {}, CC::E, CC::F, CC::G, // @ABCDEFG
+ {}, CC::A, {}, {}, {}, CC::E, CC::F, CC::G, // @ABCDEFG
{}, {}, {}, {}, LM::L, {}, {}, {}, // HIJKLMNO
- {}, {}, {}, CC::S, {}, {}, {}, {}, // PQRSTUVW
+ {}, {}, {}, {}, {}, {}, {}, {}, // PQRSTUVW
CC::X, {}, {}, {}, {}, {}, {}, {}, // XYZ[\]^_
{}, CC::a, {}, CC::c, CC::d, CC::e, CC::f, CC::g, // `abcdefg
LM::h, CC::i, LM::j, {}, LM::l, {}, CC::n, CC::o, // hijklmno
@@ -204,11 +220,11 @@
using str_format_internal::LengthMod;
LengthMod length_mod = tag.as_length();
ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
- if (c == 'h' && length_mod.id() == LengthMod::h) {
- conv->length_mod = LengthMod::FromId(LengthMod::hh);
+ if (c == 'h' && length_mod == LengthMod::h) {
+ conv->length_mod = LengthMod::hh;
ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
- } else if (c == 'l' && length_mod.id() == LengthMod::l) {
- conv->length_mod = LengthMod::FromId(LengthMod::ll);
+ } else if (c == 'l' && length_mod == LengthMod::l) {
+ conv->length_mod = LengthMod::ll;
ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
} else {
conv->length_mod = length_mod;
@@ -227,6 +243,32 @@
} // namespace
+std::string LengthModToString(LengthMod v) {
+ switch (v) {
+ case LengthMod::h:
+ return "h";
+ case LengthMod::hh:
+ return "hh";
+ case LengthMod::l:
+ return "l";
+ case LengthMod::ll:
+ return "ll";
+ case LengthMod::L:
+ return "L";
+ case LengthMod::j:
+ return "j";
+ case LengthMod::z:
+ return "z";
+ case LengthMod::t:
+ return "t";
+ case LengthMod::q:
+ return "q";
+ case LengthMod::none:
+ return "";
+ }
+ return "";
+}
+
const char *ConsumeUnboundConversion(const char *p, const char *end,
UnboundConversion *conv, int *next_arg) {
if (*next_arg < 0) return ConsumeConversion<true>(p, end, conv, next_arg);
@@ -268,15 +310,17 @@
char* data_pos;
};
-ParsedFormatBase::ParsedFormatBase(string_view format, bool allow_ignored,
- std::initializer_list<Conv> convs)
+ParsedFormatBase::ParsedFormatBase(
+ string_view format, bool allow_ignored,
+ std::initializer_list<FormatConversionCharSet> convs)
: data_(format.empty() ? nullptr : new char[format.size()]) {
has_error_ = !ParseFormatString(format, ParsedFormatConsumer(this)) ||
!MatchesConversions(allow_ignored, convs);
}
bool ParsedFormatBase::MatchesConversions(
- bool allow_ignored, std::initializer_list<Conv> convs) const {
+ bool allow_ignored,
+ std::initializer_list<FormatConversionCharSet> convs) const {
std::unordered_set<int> used;
auto add_if_valid_conv = [&](int pos, char c) {
if (static_cast<size_t>(pos) > convs.size() ||
@@ -294,10 +338,13 @@
if (conv.width.is_from_arg() &&
!add_if_valid_conv(conv.width.get_from_arg(), '*'))
return false;
- if (!add_if_valid_conv(conv.arg_position, conv.conv.Char())) return false;
+ if (!add_if_valid_conv(conv.arg_position,
+ FormatConversionCharToChar(conv.conv)))
+ return false;
}
return used.size() == convs.size() || allow_ignored;
}
} // namespace str_format_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/internal/str_format/parser.h b/third_party/abseil/absl/strings/internal/str_format/parser.h
index b7614a0..6504dd3 100644
--- a/third_party/abseil/absl/strings/internal/str_format/parser.h
+++ b/third_party/abseil/absl/strings/internal/str_format/parser.h
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
@@ -6,18 +20,25 @@
#include <stdlib.h>
#include <cassert>
+#include <cstdint>
#include <initializer_list>
#include <iosfwd>
#include <iterator>
#include <memory>
+#include <string>
#include <vector>
#include "absl/strings/internal/str_format/checker.h"
#include "absl/strings/internal/str_format/extension.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
+enum class LengthMod : std::uint8_t { h, hh, l, ll, L, j, z, t, q, none };
+
+std::string LengthModToString(LengthMod v);
+
// The analyzed properties of a single specified conversion.
struct UnboundConversion {
UnboundConversion()
@@ -59,8 +80,8 @@
InputValue precision;
Flags flags;
- LengthMod length_mod;
- ConversionChar conv;
+ LengthMod length_mod = LengthMod::none;
+ FormatConversionChar conv = FormatConversionCharInternal::kNone;
};
// Consume conversion spec prefix (not including '%') of [p, end) if valid.
@@ -72,25 +93,28 @@
UnboundConversion* conv, int* next_arg);
// Helper tag class for the table below.
-// It allows fast `char -> ConversionChar/LengthMod` checking and conversions.
+// It allows fast `char -> ConversionChar/LengthMod` checking and
+// conversions.
class ConvTag {
public:
- constexpr ConvTag(ConversionChar::Id id) : tag_(id) {} // NOLINT
+ constexpr ConvTag(FormatConversionChar conversion_char) // NOLINT
+ : tag_(static_cast<int8_t>(conversion_char)) {}
// We invert the length modifiers to make them negative so that we can easily
// test for them.
- constexpr ConvTag(LengthMod::Id id) : tag_(~id) {} // NOLINT
+ constexpr ConvTag(LengthMod length_mod) // NOLINT
+ : tag_(~static_cast<std::int8_t>(length_mod)) {}
// Everything else is -128, which is negative to make is_conv() simpler.
constexpr ConvTag() : tag_(-128) {}
bool is_conv() const { return tag_ >= 0; }
bool is_length() const { return tag_ < 0 && tag_ != -128; }
- ConversionChar as_conv() const {
+ FormatConversionChar as_conv() const {
assert(is_conv());
- return ConversionChar::FromId(static_cast<ConversionChar::Id>(tag_));
+ return static_cast<FormatConversionChar>(tag_);
}
LengthMod as_length() const {
assert(is_length());
- return LengthMod::FromId(static_cast<LengthMod::Id>(~tag_));
+ return static_cast<LengthMod>(~tag_);
}
private:
@@ -133,7 +157,7 @@
auto tag = GetTagForChar(percent[1]);
if (tag.is_conv()) {
if (ABSL_PREDICT_FALSE(next_arg < 0)) {
- // This indicates an error in the format std::string.
+ // This indicates an error in the format string.
// The only way to get `next_arg < 0` here is to have a positional
// argument first which sets next_arg to -1 and then a non-positional
// argument.
@@ -176,8 +200,9 @@
class ParsedFormatBase {
public:
- explicit ParsedFormatBase(string_view format, bool allow_ignored,
- std::initializer_list<Conv> convs);
+ explicit ParsedFormatBase(
+ string_view format, bool allow_ignored,
+ std::initializer_list<FormatConversionCharSet> convs);
ParsedFormatBase(const ParsedFormatBase& other) { *this = other; }
@@ -224,8 +249,9 @@
private:
// Returns whether the conversions match and if !allow_ignored it verifies
// that all conversions are used by the format.
- bool MatchesConversions(bool allow_ignored,
- std::initializer_list<Conv> convs) const;
+ bool MatchesConversions(
+ bool allow_ignored,
+ std::initializer_list<FormatConversionCharSet> convs) const;
struct ParsedFormatConsumer;
@@ -270,14 +296,14 @@
// This is the only API that allows the user to pass a runtime specified format
// string. These factory functions will return NULL if the format does not match
// the conversions requested by the user.
-template <str_format_internal::Conv... C>
+template <FormatConversionCharSet... C>
class ExtendedParsedFormat : public str_format_internal::ParsedFormatBase {
public:
explicit ExtendedParsedFormat(string_view format)
-#if ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+#ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
__attribute__((
enable_if(str_format_internal::EnsureConstexpr(format),
- "Format std::string is not constexpr."),
+ "Format string is not constexpr."),
enable_if(str_format_internal::ValidFormatImpl<C...>(format),
"Format specified does not match the template arguments.")))
#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
@@ -317,6 +343,7 @@
: ParsedFormatBase(s, allow_ignored, {C...}) {}
};
} // namespace str_format_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
diff --git a/third_party/abseil/absl/strings/internal/str_format/parser_test.cc b/third_party/abseil/absl/strings/internal/str_format/parser_test.cc
index 6d356093..a5fa1c7 100644
--- a/third_party/abseil/absl/strings/internal/str_format/parser_test.cc
+++ b/third_party/abseil/absl/strings/internal/str_format/parser_test.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
#include "absl/strings/internal/str_format/parser.h"
#include <string.h>
@@ -7,6 +21,7 @@
#include "absl/base/macros.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
namespace {
@@ -16,7 +31,7 @@
TEST(LengthModTest, Names) {
struct Expectation {
int line;
- LengthMod::Id id;
+ LengthMod mod;
const char *name;
};
const Expectation kExpect[] = {
@@ -31,37 +46,33 @@
{__LINE__, LengthMod::t, "t" },
{__LINE__, LengthMod::q, "q" },
};
- EXPECT_EQ(ABSL_ARRAYSIZE(kExpect), LengthMod::kNumValues);
+ EXPECT_EQ(ABSL_ARRAYSIZE(kExpect), 10);
for (auto e : kExpect) {
SCOPED_TRACE(e.line);
- LengthMod mod = LengthMod::FromId(e.id);
- EXPECT_EQ(e.id, mod.id());
- EXPECT_EQ(e.name, mod.name());
+ EXPECT_EQ(e.name, LengthModToString(e.mod));
}
}
TEST(ConversionCharTest, Names) {
struct Expectation {
- ConversionChar::Id id;
+ FormatConversionChar id;
char name;
};
// clang-format off
const Expectation kExpect[] = {
-#define X(c) {ConversionChar::c, #c[0]}
- X(c), X(C), X(s), X(S), // text
+#define X(c) {FormatConversionCharInternal::c, #c[0]}
+ X(c), X(s), // text
X(d), X(i), X(o), X(u), X(x), X(X), // int
X(f), X(F), X(e), X(E), X(g), X(G), X(a), X(A), // float
X(n), X(p), // misc
#undef X
- {ConversionChar::none, '\0'},
+ {FormatConversionCharInternal::kNone, '\0'},
};
// clang-format on
- EXPECT_EQ(ABSL_ARRAYSIZE(kExpect), ConversionChar::kNumValues);
for (auto e : kExpect) {
SCOPED_TRACE(e.name);
- ConversionChar v = ConversionChar::FromId(e.id);
- EXPECT_EQ(e.id, v.id());
- EXPECT_EQ(e.name, v.Char());
+ FormatConversionChar v = e.id;
+ EXPECT_EQ(e.name, FormatConversionCharToChar(v));
}
}
@@ -120,13 +131,12 @@
EXPECT_FALSE(Run("dd")); // no excess allowed
EXPECT_TRUE(Run("d"));
- EXPECT_EQ('d', o.conv.Char());
+ EXPECT_EQ('d', FormatConversionCharToChar(o.conv));
EXPECT_FALSE(o.width.is_from_arg());
EXPECT_LT(o.width.value(), 0);
EXPECT_FALSE(o.precision.is_from_arg());
EXPECT_LT(o.precision.value(), 0);
EXPECT_EQ(1, o.arg_position);
- EXPECT_EQ(LengthMod::none, o.length_mod.id());
}
TEST_F(ConsumeUnboundConversionTest, ArgPosition) {
@@ -162,7 +172,7 @@
TEST_F(ConsumeUnboundConversionTest, WidthAndPrecision) {
EXPECT_TRUE(Run("14d"));
- EXPECT_EQ('d', o.conv.Char());
+ EXPECT_EQ('d', FormatConversionCharToChar(o.conv));
EXPECT_FALSE(o.width.is_from_arg());
EXPECT_EQ(14, o.width.value());
EXPECT_FALSE(o.precision.is_from_arg());
@@ -289,6 +299,29 @@
}
}
+TEST_F(ConsumeUnboundConversionTest, LengthMod) {
+ EXPECT_TRUE(Run("d"));
+ EXPECT_EQ(LengthMod::none, o.length_mod);
+ EXPECT_TRUE(Run("hd"));
+ EXPECT_EQ(LengthMod::h, o.length_mod);
+ EXPECT_TRUE(Run("hhd"));
+ EXPECT_EQ(LengthMod::hh, o.length_mod);
+ EXPECT_TRUE(Run("ld"));
+ EXPECT_EQ(LengthMod::l, o.length_mod);
+ EXPECT_TRUE(Run("lld"));
+ EXPECT_EQ(LengthMod::ll, o.length_mod);
+ EXPECT_TRUE(Run("Lf"));
+ EXPECT_EQ(LengthMod::L, o.length_mod);
+ EXPECT_TRUE(Run("qf"));
+ EXPECT_EQ(LengthMod::q, o.length_mod);
+ EXPECT_TRUE(Run("jd"));
+ EXPECT_EQ(LengthMod::j, o.length_mod);
+ EXPECT_TRUE(Run("zd"));
+ EXPECT_EQ(LengthMod::z, o.length_mod);
+ EXPECT_TRUE(Run("td"));
+ EXPECT_EQ(LengthMod::t, o.length_mod);
+}
+
struct SummarizeConsumer {
std::string* out;
explicit SummarizeConsumer(std::string* out) : out(out) {}
@@ -309,7 +342,7 @@
if (conv.precision.is_from_arg()) {
*out += "." + std::to_string(conv.precision.get_from_arg()) + "$*";
}
- *out += conv.conv.Char();
+ *out += FormatConversionCharToChar(conv.conv);
*out += "}";
return true;
}
@@ -330,7 +363,8 @@
ParsedFormatBase p2 = p1; // copy construct (empty)
EXPECT_EQ(SummarizeParsedFormat(p1), SummarizeParsedFormat(p2));
- p1 = ParsedFormatBase("hello%s", true, {Conv::s}); // move assign
+ p1 = ParsedFormatBase("hello%s", true,
+ {FormatConversionCharSetInternal::s}); // move assign
EXPECT_EQ("[hello]{s:1$s}", SummarizeParsedFormat(p1));
ParsedFormatBase p3 = p1; // copy construct (nonempty)
@@ -348,7 +382,7 @@
struct ExpectParse {
const char* in;
- std::initializer_list<Conv> conv_set;
+ std::initializer_list<FormatConversionCharSet> conv_set;
const char* out;
};
@@ -358,9 +392,9 @@
const ExpectParse kExpect[] = {
{"", {}, ""},
{"ab", {}, "[ab]"},
- {"a%d", {Conv::d}, "[a]{d:1$d}"},
- {"a%+d", {Conv::d}, "[a]{+d:1$d}"},
- {"a% d", {Conv::d}, "[a]{ d:1$d}"},
+ {"a%d", {FormatConversionCharSetInternal::d}, "[a]{d:1$d}"},
+ {"a%+d", {FormatConversionCharSetInternal::d}, "[a]{+d:1$d}"},
+ {"a% d", {FormatConversionCharSetInternal::d}, "[a]{ d:1$d}"},
{"a%b %d", {}, "[a]!"}, // stop after error
};
for (const auto& e : kExpect) {
@@ -372,13 +406,13 @@
TEST_F(ParsedFormatTest, ParsingFlagOrder) {
const ExpectParse kExpect[] = {
- {"a%+ 0d", {Conv::d}, "[a]{+ 0d:1$d}"},
- {"a%+0 d", {Conv::d}, "[a]{+0 d:1$d}"},
- {"a%0+ d", {Conv::d}, "[a]{0+ d:1$d}"},
- {"a% +0d", {Conv::d}, "[a]{ +0d:1$d}"},
- {"a%0 +d", {Conv::d}, "[a]{0 +d:1$d}"},
- {"a% 0+d", {Conv::d}, "[a]{ 0+d:1$d}"},
- {"a%+ 0+d", {Conv::d}, "[a]{+ 0+d:1$d}"},
+ {"a%+ 0d", {FormatConversionCharSetInternal::d}, "[a]{+ 0d:1$d}"},
+ {"a%+0 d", {FormatConversionCharSetInternal::d}, "[a]{+0 d:1$d}"},
+ {"a%0+ d", {FormatConversionCharSetInternal::d}, "[a]{0+ d:1$d}"},
+ {"a% +0d", {FormatConversionCharSetInternal::d}, "[a]{ +0d:1$d}"},
+ {"a%0 +d", {FormatConversionCharSetInternal::d}, "[a]{0 +d:1$d}"},
+ {"a% 0+d", {FormatConversionCharSetInternal::d}, "[a]{ 0+d:1$d}"},
+ {"a%+ 0+d", {FormatConversionCharSetInternal::d}, "[a]{+ 0+d:1$d}"},
};
for (const auto& e : kExpect) {
SCOPED_TRACE(e.in);
@@ -389,4 +423,5 @@
} // namespace
} // namespace str_format_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/internal/str_join_internal.h b/third_party/abseil/absl/strings/internal/str_join_internal.h
index 7c35f4d..31dbf67 100644
--- a/third_party/abseil/absl/strings/internal/str_join_internal.h
+++ b/third_party/abseil/absl/strings/internal/str_join_internal.h
@@ -43,6 +43,7 @@
#include "absl/strings/str_cat.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
//
@@ -307,6 +308,7 @@
}
} // namespace strings_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_
diff --git a/third_party/abseil/absl/strings/internal/str_split_internal.h b/third_party/abseil/absl/strings/internal/str_split_internal.h
index 52f6222..a2f41c1 100644
--- a/third_party/abseil/absl/strings/internal/str_split_internal.h
+++ b/third_party/abseil/absl/strings/internal/str_split_internal.h
@@ -47,12 +47,13 @@
#endif // _GLIBCXX_DEBUG
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
// This class is implicitly constructible from everything that absl::string_view
-// is implicitly constructible from. If it's constructed from a temporary
-// string, the data is moved into a data member so its lifetime matches that of
-// the ConvertibleToStringView instance.
+// is implicitly constructible from, except for rvalue strings. This means it
+// can be used as a function parameter in places where passing a temporary
+// string might cause memory lifetime issues.
class ConvertibleToStringView {
public:
ConvertibleToStringView(const char* s) // NOLINT(runtime/explicit)
@@ -64,41 +65,12 @@
: 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;
- }
+ ConvertibleToStringView(std::string&& s) = delete;
+ ConvertibleToStringView(const std::string&& s) = delete;
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_;
};
@@ -272,7 +244,11 @@
// 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>
+//
+// The StringType parameter can be either string_view or string, depending on
+// whether the Splitter refers to a string stored elsewhere, or if the string
+// resides inside the Splitter itself.
+template <typename Delimiter, typename Predicate, typename StringType>
class Splitter {
public:
using DelimiterType = Delimiter;
@@ -280,12 +256,12 @@
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)
+ Splitter(StringType 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(); }
+ absl::string_view text() const { return text_; }
const Delimiter& delimiter() const { return delimiter_; }
const Predicate& predicate() const { return predicate_; }
@@ -335,7 +311,7 @@
Container operator()(const Splitter& splitter) const {
Container c;
auto it = std::inserter(c, c.end());
- for (const auto sp : splitter) {
+ for (const auto& sp : splitter) {
*it++ = ValueType(sp);
}
return c;
@@ -400,7 +376,7 @@
Container m;
typename Container::iterator it;
bool insert = true;
- for (const auto sp : splitter) {
+ for (const auto& sp : splitter) {
if (insert) {
it = Inserter<Container>::Insert(&m, First(sp), Second());
} else {
@@ -442,12 +418,13 @@
};
};
- ConvertibleToStringView text_;
+ StringType text_;
Delimiter delimiter_;
Predicate predicate_;
};
} // namespace strings_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_
diff --git a/third_party/abseil/absl/strings/internal/string_constant.h b/third_party/abseil/absl/strings/internal/string_constant.h
new file mode 100644
index 0000000..a11336b
--- /dev/null
+++ b/third_party/abseil/absl/strings/internal/string_constant.h
@@ -0,0 +1,64 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_
+#define ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_
+
+#include "absl/meta/type_traits.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+// StringConstant<T> represents a compile time string constant.
+// It can be accessed via its `absl::string_view value` static member.
+// It is guaranteed that the `string_view` returned has constant `.data()`,
+// constant `.size()` and constant `value[i]` for all `0 <= i < .size()`
+//
+// The `T` is an opaque type. It is guaranteed that different string constants
+// will have different values of `T`. This allows users to associate the string
+// constant with other static state at compile time.
+//
+// Instances should be made using the `MakeStringConstant()` factory function
+// below.
+template <typename T>
+struct StringConstant {
+ static constexpr absl::string_view value = T{}();
+ constexpr absl::string_view operator()() const { return value; }
+
+ // Check to be sure `view` points to constant data.
+ // Otherwise, it can't be constant evaluated.
+ static_assert(value.empty() || 2 * value[0] != 1,
+ "The input string_view must point to constant data.");
+};
+
+template <typename T>
+constexpr absl::string_view StringConstant<T>::value; // NOLINT
+
+// Factory function for `StringConstant` instances.
+// It supports callables that have a constexpr default constructor and a
+// constexpr operator().
+// It must return an `absl::string_view` or `const char*` pointing to constant
+// data. This is validated at compile time.
+template <typename T>
+constexpr StringConstant<T> MakeStringConstant(T) {
+ return {};
+}
+
+} // namespace strings_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_
diff --git a/third_party/abseil/absl/strings/internal/string_constant_test.cc b/third_party/abseil/absl/strings/internal/string_constant_test.cc
new file mode 100644
index 0000000..392833c
--- /dev/null
+++ b/third_party/abseil/absl/strings/internal/string_constant_test.cc
@@ -0,0 +1,60 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/internal/string_constant.h"
+
+#include "absl/meta/type_traits.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace {
+
+using absl::strings_internal::MakeStringConstant;
+
+struct Callable {
+ constexpr absl::string_view operator()() const {
+ return absl::string_view("Callable", 8);
+ }
+};
+
+TEST(StringConstant, Traits) {
+ constexpr auto str = MakeStringConstant(Callable{});
+ using T = decltype(str);
+
+ EXPECT_TRUE(std::is_empty<T>::value);
+ EXPECT_TRUE(std::is_trivial<T>::value);
+ EXPECT_TRUE(absl::is_trivially_default_constructible<T>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<T>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<T>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<T>::value);
+}
+
+TEST(StringConstant, MakeFromCallable) {
+ constexpr auto str = MakeStringConstant(Callable{});
+ using T = decltype(str);
+ EXPECT_EQ(Callable{}(), T::value);
+ EXPECT_EQ(Callable{}(), str());
+}
+
+TEST(StringConstant, MakeFromStringConstant) {
+ // We want to make sure the StringConstant itself is a valid input to the
+ // factory function.
+ constexpr auto str = MakeStringConstant(Callable{});
+ constexpr auto str2 = MakeStringConstant(str);
+ using T = decltype(str2);
+ EXPECT_EQ(Callable{}(), T::value);
+ EXPECT_EQ(Callable{}(), str2());
+}
+
+} // namespace
diff --git a/third_party/abseil/absl/strings/internal/utf8.cc b/third_party/abseil/absl/strings/internal/utf8.cc
index 82d36c2..8fd8edc 100644
--- a/third_party/abseil/absl/strings/internal/utf8.cc
+++ b/third_party/abseil/absl/strings/internal/utf8.cc
@@ -17,6 +17,7 @@
#include "absl/strings/internal/utf8.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
size_t EncodeUTF8Char(char *buffer, char32_t utf8_char) {
@@ -48,4 +49,5 @@
}
} // namespace strings_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/internal/utf8.h b/third_party/abseil/absl/strings/internal/utf8.h
index 0423630..32fb109 100644
--- a/third_party/abseil/absl/strings/internal/utf8.h
+++ b/third_party/abseil/absl/strings/internal/utf8.h
@@ -20,7 +20,10 @@
#include <cstddef>
#include <cstdint>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
// For Unicode code points 0 through 0x10FFFF, EncodeUTF8Char writes
@@ -41,6 +44,7 @@
size_t EncodeUTF8Char(char *buffer, char32_t utf8_char);
} // namespace strings_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_UTF8_H_
diff --git a/third_party/abseil/absl/strings/match.cc b/third_party/abseil/absl/strings/match.cc
index 7b24241..2d67250 100644
--- a/third_party/abseil/absl/strings/match.cc
+++ b/third_party/abseil/absl/strings/match.cc
@@ -17,22 +17,27 @@
#include "absl/strings/internal/memutil.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
-bool EqualsIgnoreCase(absl::string_view piece1, absl::string_view piece2) {
+bool EqualsIgnoreCase(absl::string_view piece1,
+ absl::string_view piece2) noexcept {
return (piece1.size() == piece2.size() &&
0 == absl::strings_internal::memcasecmp(piece1.data(), piece2.data(),
piece1.size()));
// memcasecmp uses absl::ascii_tolower().
}
-bool StartsWithIgnoreCase(absl::string_view text, absl::string_view prefix) {
+bool StartsWithIgnoreCase(absl::string_view text,
+ absl::string_view prefix) noexcept {
return (text.size() >= prefix.size()) &&
EqualsIgnoreCase(text.substr(0, prefix.size()), prefix);
}
-bool EndsWithIgnoreCase(absl::string_view text, absl::string_view suffix) {
+bool EndsWithIgnoreCase(absl::string_view text,
+ absl::string_view suffix) noexcept {
return (text.size() >= suffix.size()) &&
EqualsIgnoreCase(text.substr(text.size() - suffix.size()), suffix);
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/match.h b/third_party/abseil/absl/strings/match.h
index 762f359..038cbb3 100644
--- a/third_party/abseil/absl/strings/match.h
+++ b/third_party/abseil/absl/strings/match.h
@@ -20,7 +20,7 @@
// This file contains simple utilities for performing 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.
+// NUL-terminated C-style strings.
//
// Examples:
// std::string s = "foo";
@@ -38,18 +38,25 @@
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// StrContains()
//
// Returns whether a given string `haystack` contains the substring `needle`.
-inline bool StrContains(absl::string_view haystack, absl::string_view needle) {
+inline bool StrContains(absl::string_view haystack,
+ absl::string_view needle) noexcept {
return haystack.find(needle, 0) != haystack.npos;
}
+inline bool StrContains(absl::string_view haystack, char needle) noexcept {
+ return haystack.find(needle) != haystack.npos;
+}
+
// StartsWith()
//
// Returns whether a given string `text` begins with `prefix`.
-inline bool StartsWith(absl::string_view text, absl::string_view prefix) {
+inline bool StartsWith(absl::string_view text,
+ absl::string_view prefix) noexcept {
return prefix.empty() ||
(text.size() >= prefix.size() &&
memcmp(text.data(), prefix.data(), prefix.size()) == 0);
@@ -58,7 +65,8 @@
// EndsWith()
//
// Returns whether a given string `text` ends with `suffix`.
-inline bool EndsWith(absl::string_view text, absl::string_view suffix) {
+inline bool EndsWith(absl::string_view text,
+ absl::string_view suffix) noexcept {
return suffix.empty() ||
(text.size() >= suffix.size() &&
memcmp(text.data() + (text.size() - suffix.size()), suffix.data(),
@@ -69,20 +77,24 @@
//
// Returns whether given ASCII strings `piece1` and `piece2` are equal, ignoring
// case in the comparison.
-bool EqualsIgnoreCase(absl::string_view piece1, absl::string_view piece2);
+bool EqualsIgnoreCase(absl::string_view piece1,
+ absl::string_view piece2) noexcept;
// StartsWithIgnoreCase()
//
// Returns whether a given ASCII string `text` starts with `prefix`,
// ignoring case in the comparison.
-bool StartsWithIgnoreCase(absl::string_view text, absl::string_view prefix);
+bool StartsWithIgnoreCase(absl::string_view text,
+ absl::string_view prefix) noexcept;
// EndsWithIgnoreCase()
//
// Returns whether a given ASCII string `text` ends with `suffix`, ignoring
// case in the comparison.
-bool EndsWithIgnoreCase(absl::string_view text, absl::string_view suffix);
+bool EndsWithIgnoreCase(absl::string_view text,
+ absl::string_view suffix) noexcept;
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_MATCH_H_
diff --git a/third_party/abseil/absl/strings/match_test.cc b/third_party/abseil/absl/strings/match_test.cc
index 4c313dd..5841bc1 100644
--- a/third_party/abseil/absl/strings/match_test.cc
+++ b/third_party/abseil/absl/strings/match_test.cc
@@ -66,6 +66,23 @@
EXPECT_FALSE(absl::StrContains("", "a"));
}
+TEST(MatchTest, ContainsChar) {
+ absl::string_view a("abcdefg");
+ absl::string_view b("abcd");
+ EXPECT_TRUE(absl::StrContains(a, 'a'));
+ EXPECT_TRUE(absl::StrContains(a, 'b'));
+ EXPECT_TRUE(absl::StrContains(a, 'e'));
+ EXPECT_FALSE(absl::StrContains(a, 'h'));
+
+ EXPECT_TRUE(absl::StrContains(b, 'a'));
+ EXPECT_TRUE(absl::StrContains(b, 'b'));
+ EXPECT_FALSE(absl::StrContains(b, 'e'));
+ EXPECT_FALSE(absl::StrContains(b, 'h'));
+
+ EXPECT_FALSE(absl::StrContains("", 'a'));
+ EXPECT_FALSE(absl::StrContains("", 'a'));
+}
+
TEST(MatchTest, ContainsNull) {
const std::string s = "foo";
const char* cs = "foo";
diff --git a/third_party/abseil/absl/strings/numbers.cc b/third_party/abseil/absl/strings/numbers.cc
index 38d1486..e6bf44c 100644
--- a/third_party/abseil/absl/strings/numbers.cc
+++ b/third_party/abseil/absl/strings/numbers.cc
@@ -19,8 +19,8 @@
#include <algorithm>
#include <cassert>
-#include <cfloat> // for DBL_DIG and FLT_DIG
-#include <cmath> // for HUGE_VAL
+#include <cfloat> // for DBL_DIG and FLT_DIG
+#include <cmath> // for HUGE_VAL
#include <cstdint>
#include <cstdio>
#include <cstdlib>
@@ -30,15 +30,18 @@
#include <memory>
#include <utility>
-#include "absl/base/internal/bits.h"
+#include "absl/base/attributes.h"
#include "absl/base/internal/raw_logging.h"
+#include "absl/numeric/bits.h"
#include "absl/strings/ascii.h"
#include "absl/strings/charconv.h"
+#include "absl/strings/escaping.h"
#include "absl/strings/internal/memutil.h"
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
bool SimpleAtof(absl::string_view str, float* out) {
*out = 0.0;
@@ -92,43 +95,6 @@
return true;
}
-namespace {
-
-// Writes a two-character representation of 'i' to 'buf'. 'i' must be in the
-// range 0 <= i < 100, and buf must have space for two characters. Example:
-// char buf[2];
-// PutTwoDigits(42, buf);
-// // buf[0] == '4'
-// // buf[1] == '2'
-inline void PutTwoDigits(size_t i, char* buf) {
- static const char two_ASCII_digits[100][2] = {
- {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'},
- {'0', '5'}, {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'},
- {'1', '0'}, {'1', '1'}, {'1', '2'}, {'1', '3'}, {'1', '4'},
- {'1', '5'}, {'1', '6'}, {'1', '7'}, {'1', '8'}, {'1', '9'},
- {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'}, {'2', '4'},
- {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'},
- {'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'},
- {'3', '5'}, {'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'},
- {'4', '0'}, {'4', '1'}, {'4', '2'}, {'4', '3'}, {'4', '4'},
- {'4', '5'}, {'4', '6'}, {'4', '7'}, {'4', '8'}, {'4', '9'},
- {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'}, {'5', '4'},
- {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'},
- {'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'},
- {'6', '5'}, {'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'},
- {'7', '0'}, {'7', '1'}, {'7', '2'}, {'7', '3'}, {'7', '4'},
- {'7', '5'}, {'7', '6'}, {'7', '7'}, {'7', '8'}, {'7', '9'},
- {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'}, {'8', '4'},
- {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'},
- {'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'},
- {'9', '5'}, {'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}
- };
- assert(i < 100);
- memcpy(buf, two_ASCII_digits[i], 2);
-}
-
-} // namespace
-
bool SimpleAtob(absl::string_view str, bool* out) {
ABSL_RAW_CHECK(out != nullptr, "Output pointer must not be nullptr.");
if (EqualsIgnoreCase(str, "true") || EqualsIgnoreCase(str, "t") ||
@@ -337,7 +303,7 @@
uint64_t bits128_up = (bits96_127 >> 32) + (bits64_127 < bits64_95);
if (bits128_up == 0) return {bits64_127, bits0_63};
- int shift = 64 - base_internal::CountLeadingZeros64(bits128_up);
+ auto shift = static_cast<unsigned>(bit_width(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};
@@ -368,7 +334,7 @@
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 = base_internal::CountLeadingZeros64(result.first);
+ int shift = countl_zero(result.first);
if (shift != 0) {
result.first = (result.first << shift) + (result.second >> (64 - shift));
result.second = (result.second << shift);
@@ -495,13 +461,13 @@
int two_digits = dddddd / 10000;
dddddd -= two_digits * 10000;
- PutTwoDigits(two_digits, &exp_dig.digits[0]);
+ numbers_internal::PutTwoDigits(two_digits, &exp_dig.digits[0]);
two_digits = dddddd / 100;
dddddd -= two_digits * 100;
- PutTwoDigits(two_digits, &exp_dig.digits[2]);
+ numbers_internal::PutTwoDigits(two_digits, &exp_dig.digits[2]);
- PutTwoDigits(dddddd, &exp_dig.digits[4]);
+ numbers_internal::PutTwoDigits(dddddd, &exp_dig.digits[4]);
return exp_dig;
}
@@ -754,8 +720,8 @@
// commonly used bases.
template <typename IntType>
struct LookupTables {
- static const IntType kVmaxOverBase[];
- static const IntType kVminOverBase[];
+ ABSL_CONST_INIT static const IntType kVmaxOverBase[];
+ ABSL_CONST_INIT static const IntType kVminOverBase[];
};
// An array initializer macro for X/base where base in [0, 36].
@@ -770,6 +736,163 @@
X / 35, X / 36, \
}
+// This kVmaxOverBase is generated with
+// for (int base = 2; base < 37; ++base) {
+// absl::uint128 max = std::numeric_limits<absl::uint128>::max();
+// auto result = max / base;
+// std::cout << " MakeUint128(" << absl::Uint128High64(result) << "u, "
+// << absl::Uint128Low64(result) << "u),\n";
+// }
+// See https://godbolt.org/z/aneYsb
+//
+// uint128& operator/=(uint128) is not constexpr, so hardcode the resulting
+// array to avoid a static initializer.
+template<>
+const uint128 LookupTables<uint128>::kVmaxOverBase[] = {
+ 0,
+ 0,
+ MakeUint128(9223372036854775807u, 18446744073709551615u),
+ MakeUint128(6148914691236517205u, 6148914691236517205u),
+ MakeUint128(4611686018427387903u, 18446744073709551615u),
+ MakeUint128(3689348814741910323u, 3689348814741910323u),
+ MakeUint128(3074457345618258602u, 12297829382473034410u),
+ MakeUint128(2635249153387078802u, 5270498306774157604u),
+ MakeUint128(2305843009213693951u, 18446744073709551615u),
+ MakeUint128(2049638230412172401u, 14347467612885206812u),
+ MakeUint128(1844674407370955161u, 11068046444225730969u),
+ MakeUint128(1676976733973595601u, 8384883669867978007u),
+ MakeUint128(1537228672809129301u, 6148914691236517205u),
+ MakeUint128(1418980313362273201u, 4256940940086819603u),
+ MakeUint128(1317624576693539401u, 2635249153387078802u),
+ MakeUint128(1229782938247303441u, 1229782938247303441u),
+ MakeUint128(1152921504606846975u, 18446744073709551615u),
+ MakeUint128(1085102592571150095u, 1085102592571150095u),
+ MakeUint128(1024819115206086200u, 16397105843297379214u),
+ MakeUint128(970881267037344821u, 16504981539634861972u),
+ MakeUint128(922337203685477580u, 14757395258967641292u),
+ MakeUint128(878416384462359600u, 14054662151397753612u),
+ MakeUint128(838488366986797800u, 13415813871788764811u),
+ MakeUint128(802032351030850070u, 4812194106185100421u),
+ MakeUint128(768614336404564650u, 12297829382473034410u),
+ MakeUint128(737869762948382064u, 11805916207174113034u),
+ MakeUint128(709490156681136600u, 11351842506898185609u),
+ MakeUint128(683212743470724133u, 17080318586768103348u),
+ MakeUint128(658812288346769700u, 10540996613548315209u),
+ MakeUint128(636094623231363848u, 15266270957552732371u),
+ MakeUint128(614891469123651720u, 9838263505978427528u),
+ MakeUint128(595056260442243600u, 9520900167075897608u),
+ MakeUint128(576460752303423487u, 18446744073709551615u),
+ MakeUint128(558992244657865200u, 8943875914525843207u),
+ MakeUint128(542551296285575047u, 9765923333140350855u),
+ MakeUint128(527049830677415760u, 8432797290838652167u),
+ MakeUint128(512409557603043100u, 8198552921648689607u),
+};
+
+// This kVmaxOverBase generated with
+// for (int base = 2; base < 37; ++base) {
+// absl::int128 max = std::numeric_limits<absl::int128>::max();
+// auto result = max / base;
+// std::cout << "\tMakeInt128(" << absl::Int128High64(result) << ", "
+// << absl::Int128Low64(result) << "u),\n";
+// }
+// See https://godbolt.org/z/7djYWz
+//
+// int128& operator/=(int128) is not constexpr, so hardcode the resulting array
+// to avoid a static initializer.
+template<>
+const int128 LookupTables<int128>::kVmaxOverBase[] = {
+ 0,
+ 0,
+ MakeInt128(4611686018427387903, 18446744073709551615u),
+ MakeInt128(3074457345618258602, 12297829382473034410u),
+ MakeInt128(2305843009213693951, 18446744073709551615u),
+ MakeInt128(1844674407370955161, 11068046444225730969u),
+ MakeInt128(1537228672809129301, 6148914691236517205u),
+ MakeInt128(1317624576693539401, 2635249153387078802u),
+ MakeInt128(1152921504606846975, 18446744073709551615u),
+ MakeInt128(1024819115206086200, 16397105843297379214u),
+ MakeInt128(922337203685477580, 14757395258967641292u),
+ MakeInt128(838488366986797800, 13415813871788764811u),
+ MakeInt128(768614336404564650, 12297829382473034410u),
+ MakeInt128(709490156681136600, 11351842506898185609u),
+ MakeInt128(658812288346769700, 10540996613548315209u),
+ MakeInt128(614891469123651720, 9838263505978427528u),
+ MakeInt128(576460752303423487, 18446744073709551615u),
+ MakeInt128(542551296285575047, 9765923333140350855u),
+ MakeInt128(512409557603043100, 8198552921648689607u),
+ MakeInt128(485440633518672410, 17475862806672206794u),
+ MakeInt128(461168601842738790, 7378697629483820646u),
+ MakeInt128(439208192231179800, 7027331075698876806u),
+ MakeInt128(419244183493398900, 6707906935894382405u),
+ MakeInt128(401016175515425035, 2406097053092550210u),
+ MakeInt128(384307168202282325, 6148914691236517205u),
+ MakeInt128(368934881474191032, 5902958103587056517u),
+ MakeInt128(354745078340568300, 5675921253449092804u),
+ MakeInt128(341606371735362066, 17763531330238827482u),
+ MakeInt128(329406144173384850, 5270498306774157604u),
+ MakeInt128(318047311615681924, 7633135478776366185u),
+ MakeInt128(307445734561825860, 4919131752989213764u),
+ MakeInt128(297528130221121800, 4760450083537948804u),
+ MakeInt128(288230376151711743, 18446744073709551615u),
+ MakeInt128(279496122328932600, 4471937957262921603u),
+ MakeInt128(271275648142787523, 14106333703424951235u),
+ MakeInt128(263524915338707880, 4216398645419326083u),
+ MakeInt128(256204778801521550, 4099276460824344803u),
+};
+
+// This kVminOverBase generated with
+// for (int base = 2; base < 37; ++base) {
+// absl::int128 min = std::numeric_limits<absl::int128>::min();
+// auto result = min / base;
+// std::cout << "\tMakeInt128(" << absl::Int128High64(result) << ", "
+// << absl::Int128Low64(result) << "u),\n";
+// }
+//
+// See https://godbolt.org/z/7djYWz
+//
+// int128& operator/=(int128) is not constexpr, so hardcode the resulting array
+// to avoid a static initializer.
+template<>
+const int128 LookupTables<int128>::kVminOverBase[] = {
+ 0,
+ 0,
+ MakeInt128(-4611686018427387904, 0u),
+ MakeInt128(-3074457345618258603, 6148914691236517206u),
+ MakeInt128(-2305843009213693952, 0u),
+ MakeInt128(-1844674407370955162, 7378697629483820647u),
+ MakeInt128(-1537228672809129302, 12297829382473034411u),
+ MakeInt128(-1317624576693539402, 15811494920322472814u),
+ MakeInt128(-1152921504606846976, 0u),
+ MakeInt128(-1024819115206086201, 2049638230412172402u),
+ MakeInt128(-922337203685477581, 3689348814741910324u),
+ MakeInt128(-838488366986797801, 5030930201920786805u),
+ MakeInt128(-768614336404564651, 6148914691236517206u),
+ MakeInt128(-709490156681136601, 7094901566811366007u),
+ MakeInt128(-658812288346769701, 7905747460161236407u),
+ MakeInt128(-614891469123651721, 8608480567731124088u),
+ MakeInt128(-576460752303423488, 0u),
+ MakeInt128(-542551296285575048, 8680820740569200761u),
+ MakeInt128(-512409557603043101, 10248191152060862009u),
+ MakeInt128(-485440633518672411, 970881267037344822u),
+ MakeInt128(-461168601842738791, 11068046444225730970u),
+ MakeInt128(-439208192231179801, 11419412998010674810u),
+ MakeInt128(-419244183493398901, 11738837137815169211u),
+ MakeInt128(-401016175515425036, 16040647020617001406u),
+ MakeInt128(-384307168202282326, 12297829382473034411u),
+ MakeInt128(-368934881474191033, 12543785970122495099u),
+ MakeInt128(-354745078340568301, 12770822820260458812u),
+ MakeInt128(-341606371735362067, 683212743470724134u),
+ MakeInt128(-329406144173384851, 13176245766935394012u),
+ MakeInt128(-318047311615681925, 10813608594933185431u),
+ MakeInt128(-307445734561825861, 13527612320720337852u),
+ MakeInt128(-297528130221121801, 13686293990171602812u),
+ MakeInt128(-288230376151711744, 0u),
+ MakeInt128(-279496122328932601, 13974806116446630013u),
+ MakeInt128(-271275648142787524, 4340410370284600381u),
+ MakeInt128(-263524915338707881, 14230345428290225533u),
+ MakeInt128(-256204778801521551, 14347467612885206813u),
+};
+
template <typename IntType>
const IntType LookupTables<IntType>::kVmaxOverBase[] =
X_OVER_BASE_INITIALIZER(std::numeric_limits<IntType>::max());
@@ -789,6 +912,8 @@
assert(base >= 0);
assert(vmax >= static_cast<IntType>(base));
const IntType vmax_over_base = LookupTables<IntType>::kVmaxOverBase[base];
+ assert(base < 2 ||
+ std::numeric_limits<IntType>::max() / base == vmax_over_base);
const char* start = text.data();
const char* end = start + text.size();
// loop over digits
@@ -822,6 +947,8 @@
assert(vmin < 0);
assert(vmin <= 0 - base);
IntType vmin_over_base = LookupTables<IntType>::kVminOverBase[base];
+ assert(base < 2 ||
+ std::numeric_limits<IntType>::min() / base == vmin_over_base);
// 2003 c++ standard [expr.mul]
// "... the sign of the remainder is implementation-defined."
// Although (vmin/base)*base + vmin%base is always vmin.
@@ -885,6 +1012,48 @@
} // anonymous namespace
namespace numbers_internal {
+
+// Digit conversion.
+ABSL_CONST_INIT ABSL_DLL const char kHexChar[] =
+ "0123456789abcdef";
+
+ABSL_CONST_INIT ABSL_DLL const char kHexTable[513] =
+ "000102030405060708090a0b0c0d0e0f"
+ "101112131415161718191a1b1c1d1e1f"
+ "202122232425262728292a2b2c2d2e2f"
+ "303132333435363738393a3b3c3d3e3f"
+ "404142434445464748494a4b4c4d4e4f"
+ "505152535455565758595a5b5c5d5e5f"
+ "606162636465666768696a6b6c6d6e6f"
+ "707172737475767778797a7b7c7d7e7f"
+ "808182838485868788898a8b8c8d8e8f"
+ "909192939495969798999a9b9c9d9e9f"
+ "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
+ "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
+ "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
+ "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
+ "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
+ "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
+
+ABSL_CONST_INIT ABSL_DLL const char two_ASCII_digits[100][2] = {
+ {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'},
+ {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, {'1', '0'}, {'1', '1'},
+ {'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'},
+ {'1', '8'}, {'1', '9'}, {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'},
+ {'2', '4'}, {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'},
+ {'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, {'3', '5'},
+ {'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'}, {'4', '0'}, {'4', '1'},
+ {'4', '2'}, {'4', '3'}, {'4', '4'}, {'4', '5'}, {'4', '6'}, {'4', '7'},
+ {'4', '8'}, {'4', '9'}, {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'},
+ {'5', '4'}, {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'},
+ {'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, {'6', '5'},
+ {'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'}, {'7', '0'}, {'7', '1'},
+ {'7', '2'}, {'7', '3'}, {'7', '4'}, {'7', '5'}, {'7', '6'}, {'7', '7'},
+ {'7', '8'}, {'7', '9'}, {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'},
+ {'8', '4'}, {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'},
+ {'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'},
+ {'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}};
+
bool safe_strto32_base(absl::string_view text, int32_t* value, int base) {
return safe_int_internal<int32_t>(text, value, base);
}
@@ -893,6 +1062,10 @@
return safe_int_internal<int64_t>(text, value, base);
}
+bool safe_strto128_base(absl::string_view text, int128* value, int base) {
+ return safe_int_internal<absl::int128>(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);
}
@@ -900,6 +1073,11 @@
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
+bool safe_strtou128_base(absl::string_view text, uint128* value, int base) {
+ return safe_uint_internal<absl::uint128>(text, value, base);
+}
+
+} // namespace numbers_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/numbers.h b/third_party/abseil/absl/strings/numbers.h
index 100839b..ffc738f 100644
--- a/third_party/abseil/absl/strings/numbers.h
+++ b/third_party/abseil/absl/strings/numbers.h
@@ -1,4 +1,3 @@
-//
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,6 +23,10 @@
#ifndef ABSL_STRINGS_NUMBERS_H_
#define ABSL_STRINGS_NUMBERS_H_
+#ifdef __SSE4_2__
+#include <x86intrin.h>
+#endif
+
#include <cstddef>
#include <cstdlib>
#include <cstring>
@@ -32,38 +35,54 @@
#include <string>
#include <type_traits>
+#include "absl/base/config.h"
+#ifdef __SSE4_2__
+// TODO(jorg): Remove this when we figure out the right way
+// to swap bytes on SSE 4.2 that works with the compilers
+// we claim to support. Also, add tests for the compiler
+// that doesn't support the Intel _bswap64 intrinsic but
+// does support all the SSE 4.2 intrinsics
+#include "absl/base/internal/endian.h"
+#endif
#include "absl/base/macros.h"
#include "absl/base/port.h"
+#include "absl/numeric/bits.h"
#include "absl/numeric/int128.h"
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// SimpleAtoi()
//
-// Converts the given string into an integer value, returning `true` if
-// successful. The string must reflect a base-10 integer (optionally followed or
-// preceded by ASCII whitespace) whose value falls within the range of the
-// integer type. If any errors are encountered, this function returns `false`,
-// leaving `out` in an unspecified state.
+// Converts the given string (optionally followed or preceded by ASCII
+// whitespace) into an integer value, returning `true` if successful. The string
+// must reflect a base-10 integer whose value falls within the range of the
+// integer type (optionally preceded by a `+` or `-`). If any errors are
+// encountered, this function returns `false`, leaving `out` in an unspecified
+// state.
template <typename int_type>
ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, int_type* out);
// SimpleAtof()
//
// Converts the given string (optionally followed or preceded by ASCII
-// whitespace) into a float, which may be rounded on overflow or underflow.
+// whitespace) into a float, which may be rounded on overflow or underflow,
+// returning `true` if successful.
// See https://en.cppreference.com/w/c/string/byte/strtof for details about the
-// allowed formats for `str`. If any errors are encountered, this function
+// allowed formats for `str`, except SimpleAtof() is locale-independent and will
+// always use the "C" locale. If any errors are encountered, this function
// returns `false`, leaving `out` in an unspecified state.
ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str, float* out);
// SimpleAtod()
//
// Converts the given string (optionally followed or preceded by ASCII
-// whitespace) into a double, which may be rounded on overflow or underflow.
+// whitespace) into a double, which may be rounded on overflow or underflow,
+// returning `true` if successful.
// See https://en.cppreference.com/w/c/string/byte/strtof for details about the
-// allowed formats for `str`. If any errors are encountered, this function
+// allowed formats for `str`, except SimpleAtod is locale-independent and will
+// always use the "C" locale. If any errors are encountered, this function
// returns `false`, leaving `out` in an unspecified state.
ABSL_MUST_USE_RESULT bool SimpleAtod(absl::string_view str, double* out);
@@ -77,18 +96,42 @@
// unspecified state.
ABSL_MUST_USE_RESULT bool SimpleAtob(absl::string_view str, bool* out);
+ABSL_NAMESPACE_END
} // namespace absl
// End of public API. Implementation details follow.
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace numbers_internal {
+// Digit conversion.
+ABSL_DLL extern const char kHexChar[17]; // 0123456789abcdef
+ABSL_DLL extern const char
+ kHexTable[513]; // 000102030405060708090a0b0c0d0e0f1011...
+ABSL_DLL extern const char
+ two_ASCII_digits[100][2]; // 00, 01, 02, 03...
+
+// Writes a two-character representation of 'i' to 'buf'. 'i' must be in the
+// range 0 <= i < 100, and buf must have space for two characters. Example:
+// char buf[2];
+// PutTwoDigits(42, buf);
+// // buf[0] == '4'
+// // buf[1] == '2'
+inline void PutTwoDigits(size_t i, char* buf) {
+ assert(i < 100);
+ memcpy(buf, two_ASCII_digits[i], 2);
+}
+
// safe_strto?() functions for implementing SimpleAtoi()
bool safe_strto32_base(absl::string_view text, int32_t* value, int base);
bool safe_strto64_base(absl::string_view text, int64_t* value, int base);
+bool safe_strto128_base(absl::string_view text, absl::int128* value,
+ int base);
bool safe_strtou32_base(absl::string_view text, uint32_t* value, int base);
bool safe_strtou64_base(absl::string_view text, uint64_t* value, int base);
+bool safe_strtou128_base(absl::string_view text, absl::uint128* value,
+ int base);
static const int kFastToBufferSize = 32;
static const int kSixDigitsToBufferSize = 16;
@@ -170,20 +213,53 @@
return parsed;
}
+// FastHexToBufferZeroPad16()
+//
+// Outputs `val` into `out` as if by `snprintf(out, 17, "%016x", val)` but
+// without the terminating null character. Thus `out` must be of length >= 16.
+// Returns the number of non-pad digits of the output (it can never be zero
+// since 0 has one digit).
+inline size_t FastHexToBufferZeroPad16(uint64_t val, char* out) {
+#ifdef __SSE4_2__
+ uint64_t be = absl::big_endian::FromHost64(val);
+ const auto kNibbleMask = _mm_set1_epi8(0xf);
+ const auto kHexDigits = _mm_setr_epi8('0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f');
+ auto v = _mm_loadl_epi64(reinterpret_cast<__m128i*>(&be)); // load lo dword
+ auto v4 = _mm_srli_epi64(v, 4); // shift 4 right
+ auto il = _mm_unpacklo_epi8(v4, v); // interleave bytes
+ auto m = _mm_and_si128(il, kNibbleMask); // mask out nibbles
+ auto hexchars = _mm_shuffle_epi8(kHexDigits, m); // hex chars
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(out), hexchars);
+#else
+ for (int i = 0; i < 8; ++i) {
+ auto byte = (val >> (56 - 8 * i)) & 0xFF;
+ auto* hex = &absl::numbers_internal::kHexTable[byte * 2];
+ std::memcpy(out + 2 * i, hex, 2);
+ }
+#endif
+ // | 0x1 so that even 0 has 1 digit.
+ return 16 - countl_zero(val | 0x1) / 4;
+}
+
} // namespace numbers_internal
-// SimpleAtoi()
-//
-// Converts a string to an integer, using `safe_strto?()` functions for actual
-// parsing, returning `true` if successful. The `safe_strto?()` functions apply
-// strict checking; the 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 str, int_type* out) {
return numbers_internal::safe_strtoi_base(str, out, 10);
}
+ABSL_MUST_USE_RESULT inline bool SimpleAtoi(absl::string_view str,
+ absl::int128* out) {
+ return numbers_internal::safe_strto128_base(str, out, 10);
+}
+
+ABSL_MUST_USE_RESULT inline bool SimpleAtoi(absl::string_view str,
+ absl::uint128* out) {
+ return numbers_internal::safe_strtou128_base(str, out, 10);
+}
+
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_NUMBERS_H_
diff --git a/third_party/abseil/absl/strings/numbers_benchmark.cc b/third_party/abseil/absl/strings/numbers_benchmark.cc
index 54dbedd..6e79b3e 100644
--- a/third_party/abseil/absl/strings/numbers_benchmark.cc
+++ b/third_party/abseil/absl/strings/numbers_benchmark.cc
@@ -20,6 +20,8 @@
#include "benchmark/benchmark.h"
#include "absl/base/internal/raw_logging.h"
+#include "absl/random/distributions.h"
+#include "absl/random/random.h"
#include "absl/strings/numbers.h"
namespace {
@@ -260,4 +262,25 @@
->ArgPair(10, 4)
->ArgPair(10, 8);
+void BM_FastHexToBufferZeroPad16(benchmark::State& state) {
+ absl::BitGen rng;
+ std::vector<uint64_t> nums;
+ nums.resize(1000);
+ auto min = std::numeric_limits<uint64_t>::min();
+ auto max = std::numeric_limits<uint64_t>::max();
+ for (auto& num : nums) {
+ num = absl::LogUniform(rng, min, max);
+ }
+
+ char buf[16];
+ while (state.KeepRunningBatch(nums.size())) {
+ for (auto num : nums) {
+ auto digits = absl::numbers_internal::FastHexToBufferZeroPad16(num, buf);
+ benchmark::DoNotOptimize(digits);
+ benchmark::DoNotOptimize(buf);
+ }
+ }
+}
+BENCHMARK(BM_FastHexToBufferZeroPad16);
+
} // namespace
diff --git a/third_party/abseil/absl/strings/numbers_test.cc b/third_party/abseil/absl/strings/numbers_test.cc
index 77d7e78..27616bf 100644
--- a/third_party/abseil/absl/strings/numbers_test.cc
+++ b/third_party/abseil/absl/strings/numbers_test.cc
@@ -17,6 +17,7 @@
#include "absl/strings/numbers.h"
#include <sys/types.h>
+
#include <cfenv> // NOLINT(build/c++11)
#include <cinttypes>
#include <climits>
@@ -36,13 +37,16 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/internal/raw_logging.h"
-#include "absl/strings/str_cat.h"
-
+#include "absl/random/distributions.h"
+#include "absl/random/random.h"
#include "absl/strings/internal/numbers_test_common.h"
+#include "absl/strings/internal/ostringstream.h"
#include "absl/strings/internal/pow10_helper.h"
+#include "absl/strings/str_cat.h"
namespace {
+using absl::SimpleAtoi;
using absl::numbers_internal::kSixDigitsToBufferSize;
using absl::numbers_internal::safe_strto32_base;
using absl::numbers_internal::safe_strto64_base;
@@ -52,7 +56,6 @@
using absl::strings_internal::Itoa;
using absl::strings_internal::strtouint32_test_cases;
using absl::strings_internal::strtouint64_test_cases;
-using absl::SimpleAtoi;
using testing::Eq;
using testing::MatchesRegex;
@@ -204,6 +207,9 @@
std::string actual = absl::StrCat(absl::Hex(v, absl::kZeroPad16));
snprintf(expected, sizeof(expected), "%016" PRIx64, static_cast<uint64_t>(v));
EXPECT_EQ(expected, actual) << " Input " << v;
+ actual = absl::StrCat(absl::Hex(v, absl::kSpacePad16));
+ snprintf(expected, sizeof(expected), "%16" PRIx64, static_cast<uint64_t>(v));
+ EXPECT_EQ(expected, actual) << " Input " << v;
}
TEST(Numbers, TestFastPrints) {
@@ -244,7 +250,9 @@
template <typename int_type, typename in_val_type>
void VerifySimpleAtoiGood(in_val_type in_value, int_type exp_value) {
- std::string s = absl::StrCat(in_value);
+ std::string s;
+ // (u)int128 can be streamed but not StrCat'd.
+ absl::strings_internal::OStringStream(&s) << in_value;
int_type x = static_cast<int_type>(~exp_value);
EXPECT_TRUE(SimpleAtoi(s, &x))
<< "in_value=" << in_value << " s=" << s << " x=" << x;
@@ -256,7 +264,9 @@
template <typename int_type, typename in_val_type>
void VerifySimpleAtoiBad(in_val_type in_value) {
- std::string s = absl::StrCat(in_value);
+ std::string s;
+ // (u)int128 can be streamed but not StrCat'd.
+ absl::strings_internal::OStringStream(&s) << in_value;
int_type x;
EXPECT_FALSE(SimpleAtoi(s, &x));
EXPECT_FALSE(SimpleAtoi(s.c_str(), &x));
@@ -320,18 +330,68 @@
VerifySimpleAtoiGood<uint64_t>(std::numeric_limits<uint64_t>::max(),
std::numeric_limits<uint64_t>::max());
+ // SimpleAtoi(absl::string_view, absl::uint128)
+ VerifySimpleAtoiGood<absl::uint128>(0, 0);
+ VerifySimpleAtoiGood<absl::uint128>(42, 42);
+ VerifySimpleAtoiBad<absl::uint128>(-42);
+
+ VerifySimpleAtoiBad<absl::uint128>(std::numeric_limits<int32_t>::min());
+ VerifySimpleAtoiGood<absl::uint128>(std::numeric_limits<int32_t>::max(),
+ std::numeric_limits<int32_t>::max());
+ VerifySimpleAtoiGood<absl::uint128>(std::numeric_limits<uint32_t>::max(),
+ std::numeric_limits<uint32_t>::max());
+ VerifySimpleAtoiBad<absl::uint128>(std::numeric_limits<int64_t>::min());
+ VerifySimpleAtoiGood<absl::uint128>(std::numeric_limits<int64_t>::max(),
+ std::numeric_limits<int64_t>::max());
+ VerifySimpleAtoiGood<absl::uint128>(std::numeric_limits<uint64_t>::max(),
+ std::numeric_limits<uint64_t>::max());
+ VerifySimpleAtoiGood<absl::uint128>(
+ std::numeric_limits<absl::uint128>::max(),
+ std::numeric_limits<absl::uint128>::max());
+
+ // SimpleAtoi(absl::string_view, absl::int128)
+ VerifySimpleAtoiGood<absl::int128>(0, 0);
+ VerifySimpleAtoiGood<absl::int128>(42, 42);
+ VerifySimpleAtoiGood<absl::int128>(-42, -42);
+
+ VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<int32_t>::min(),
+ std::numeric_limits<int32_t>::min());
+ VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<int32_t>::max(),
+ std::numeric_limits<int32_t>::max());
+ VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<uint32_t>::max(),
+ std::numeric_limits<uint32_t>::max());
+ VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<int64_t>::min(),
+ std::numeric_limits<int64_t>::min());
+ VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<int64_t>::max(),
+ std::numeric_limits<int64_t>::max());
+ VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<uint64_t>::max(),
+ std::numeric_limits<uint64_t>::max());
+ VerifySimpleAtoiGood<absl::int128>(
+ std::numeric_limits<absl::int128>::min(),
+ std::numeric_limits<absl::int128>::min());
+ VerifySimpleAtoiGood<absl::int128>(
+ std::numeric_limits<absl::int128>::max(),
+ std::numeric_limits<absl::int128>::max());
+ VerifySimpleAtoiBad<absl::int128>(std::numeric_limits<absl::uint128>::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<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, Atod) {
+ double d;
+ EXPECT_TRUE(absl::SimpleAtod("nan", &d));
+ EXPECT_TRUE(std::isnan(d));
+}
+
TEST(NumbersTest, Atoenum) {
enum E01 {
E01_zero = 0,
@@ -455,7 +515,7 @@
EXPECT_TRUE(safe_strto32_base(std::string("0x1234"), &value, 16));
EXPECT_EQ(0x1234, value);
- // Base-10 std::string version.
+ // Base-10 string version.
EXPECT_TRUE(safe_strto32_base("1234", &value, 10));
EXPECT_EQ(1234, value);
}
@@ -596,7 +656,7 @@
EXPECT_TRUE(safe_strto64_base(std::string("0x1234"), &value, 16));
EXPECT_EQ(0x1234, value);
- // Base-10 std::string version.
+ // Base-10 string version.
EXPECT_TRUE(safe_strto64_base("1234", &value, 10));
EXPECT_EQ(1234, value);
}
@@ -652,6 +712,91 @@
TEST(stringtest, safe_strtou64_random) {
test_random_integer_parse_base<uint64_t>(&safe_strtou64_base);
}
+TEST(stringtest, safe_strtou128_random) {
+ // random number generators don't work for uint128, and
+ // uint128 can be streamed but not StrCat'd, so this code must be custom
+ // implemented for uint128, but is generally the same as what's above.
+ // test_random_integer_parse_base<absl::uint128>(
+ // &absl::numbers_internal::safe_strtou128_base);
+ using RandomEngine = std::minstd_rand0;
+ using IntType = absl::uint128;
+ constexpr auto parse_func = &absl::numbers_internal::safe_strtou128_base;
+
+ std::random_device rd;
+ RandomEngine rng(rd());
+ std::uniform_int_distribution<uint64_t> random_uint64(
+ std::numeric_limits<uint64_t>::min());
+ std::uniform_int_distribution<int> random_base(2, 35);
+
+ for (size_t i = 0; i < kNumRandomTests; i++) {
+ IntType value = random_uint64(rng);
+ value = (value << 64) + random_uint64(rng);
+ int base = random_base(rng);
+ std::string str_value;
+ EXPECT_TRUE(Itoa<IntType>(value, base, &str_value));
+ IntType parsed_value;
+
+ // Test successful parse
+ EXPECT_TRUE(parse_func(str_value, &parsed_value, base));
+ EXPECT_EQ(parsed_value, value);
+
+ // Test overflow
+ std::string s;
+ absl::strings_internal::OStringStream(&s)
+ << std::numeric_limits<IntType>::max() << value;
+ EXPECT_FALSE(parse_func(s, &parsed_value, base));
+
+ // Test underflow
+ s.clear();
+ absl::strings_internal::OStringStream(&s) << "-" << value;
+ EXPECT_FALSE(parse_func(s, &parsed_value, base));
+ }
+}
+TEST(stringtest, safe_strto128_random) {
+ // random number generators don't work for int128, and
+ // int128 can be streamed but not StrCat'd, so this code must be custom
+ // implemented for int128, but is generally the same as what's above.
+ // test_random_integer_parse_base<absl::int128>(
+ // &absl::numbers_internal::safe_strto128_base);
+ using RandomEngine = std::minstd_rand0;
+ using IntType = absl::int128;
+ constexpr auto parse_func = &absl::numbers_internal::safe_strto128_base;
+
+ std::random_device rd;
+ RandomEngine rng(rd());
+ std::uniform_int_distribution<int64_t> random_int64(
+ std::numeric_limits<int64_t>::min());
+ std::uniform_int_distribution<uint64_t> random_uint64(
+ std::numeric_limits<uint64_t>::min());
+ std::uniform_int_distribution<int> random_base(2, 35);
+
+ for (size_t i = 0; i < kNumRandomTests; ++i) {
+ int64_t high = random_int64(rng);
+ uint64_t low = random_uint64(rng);
+ IntType value = absl::MakeInt128(high, low);
+
+ int base = random_base(rng);
+ std::string str_value;
+ EXPECT_TRUE(Itoa<IntType>(value, base, &str_value));
+ IntType parsed_value;
+
+ // Test successful parse
+ EXPECT_TRUE(parse_func(str_value, &parsed_value, base));
+ EXPECT_EQ(parsed_value, value);
+
+ // Test overflow
+ std::string s;
+ absl::strings_internal::OStringStream(&s)
+ << std::numeric_limits<IntType>::max() << value;
+ EXPECT_FALSE(parse_func(s, &parsed_value, base));
+
+ // Test underflow
+ s.clear();
+ absl::strings_internal::OStringStream(&s)
+ << std::numeric_limits<IntType>::min() << value;
+ EXPECT_FALSE(parse_func(s, &parsed_value, base));
+ }
+}
TEST(stringtest, safe_strtou32_base) {
for (int i = 0; strtouint32_test_cases()[i].str != nullptr; ++i) {
@@ -713,11 +858,11 @@
}
}
-// feenableexcept() and fedisableexcept() are missing on macOS, MSVC,
-// and WebAssembly.
-#if defined(_MSC_VER) || defined(__APPLE__) || defined(__EMSCRIPTEN__)
-#define ABSL_MISSING_FEENABLEEXCEPT 1
-#define ABSL_MISSING_FEDISABLEEXCEPT 1
+// feenableexcept() and fedisableexcept() are extensions supported by some libc
+// implementations.
+#if defined(__GLIBC__) || defined(__BIONIC__)
+#define ABSL_HAVE_FEENABLEEXCEPT 1
+#define ABSL_HAVE_FEDISABLEEXCEPT 1
#endif
class SimpleDtoaTest : public testing::Test {
@@ -725,7 +870,7 @@
void SetUp() override {
// Store the current floating point env & clear away any pending exceptions.
feholdexcept(&fp_env_);
-#ifndef ABSL_MISSING_FEENABLEEXCEPT
+#ifdef ABSL_HAVE_FEENABLEEXCEPT
// Turn on floating point exceptions.
feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
#endif
@@ -735,7 +880,7 @@
// 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
+#ifdef ABSL_HAVE_FEDISABLEEXCEPT
fedisableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
#endif
fesetenv(&fp_env_);
@@ -1184,4 +1329,28 @@
}
}
+void TestFastHexToBufferZeroPad16(uint64_t v) {
+ char buf[16];
+ auto digits = absl::numbers_internal::FastHexToBufferZeroPad16(v, buf);
+ absl::string_view res(buf, 16);
+ char buf2[17];
+ snprintf(buf2, sizeof(buf2), "%016" PRIx64, v);
+ EXPECT_EQ(res, buf2) << v;
+ size_t expected_digits = snprintf(buf2, sizeof(buf2), "%" PRIx64, v);
+ EXPECT_EQ(digits, expected_digits) << v;
+}
+
+TEST(FastHexToBufferZeroPad16, Smoke) {
+ TestFastHexToBufferZeroPad16(std::numeric_limits<uint64_t>::min());
+ TestFastHexToBufferZeroPad16(std::numeric_limits<uint64_t>::max());
+ TestFastHexToBufferZeroPad16(std::numeric_limits<int64_t>::min());
+ TestFastHexToBufferZeroPad16(std::numeric_limits<int64_t>::max());
+ absl::BitGen rng;
+ for (int i = 0; i < 100000; ++i) {
+ TestFastHexToBufferZeroPad16(
+ absl::LogUniform(rng, std::numeric_limits<uint64_t>::min(),
+ std::numeric_limits<uint64_t>::max()));
+ }
+}
+
} // namespace
diff --git a/third_party/abseil/absl/strings/str_cat.cc b/third_party/abseil/absl/strings/str_cat.cc
index 9961944..dd5d25b 100644
--- a/third_party/abseil/absl/strings/str_cat.cc
+++ b/third_party/abseil/absl/strings/str_cat.cc
@@ -15,34 +15,34 @@
#include "absl/strings/str_cat.h"
#include <assert.h>
+
#include <algorithm>
#include <cstdint>
#include <cstring>
#include "absl/strings/ascii.h"
#include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/numbers.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
AlphaNum::AlphaNum(Hex hex) {
+ static_assert(numbers_internal::kFastToBufferSize >= 32,
+ "This function only works when output buffer >= 32 bytes long");
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);
+ auto real_width =
+ absl::numbers_internal::FastHexToBufferZeroPad16(hex.value, end - 16);
+ if (real_width >= hex.width) {
+ piece_ = absl::string_view(end - real_width, real_width);
} else {
- beg = writer;
+ // Pad first 16 chars because FastHexToBufferZeroPad16 pads only to 16 and
+ // max pad width can be up to 20.
+ std::memset(end - 32, hex.fill, 16);
+ // Patch up everything else up to the real_width.
+ std::memset(end - real_width - 16, hex.fill, 16);
+ piece_ = absl::string_view(end - hex.width, hex.width);
}
-
- piece_ = absl::string_view(beg, end - beg);
}
AlphaNum::AlphaNum(Dec dec) {
@@ -141,12 +141,12 @@
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();
+ for (const absl::string_view& piece : pieces) total_size += piece.size();
strings_internal::STLStringResizeUninitialized(&result, total_size);
char* const begin = &result[0];
char* out = begin;
- for (const absl::string_view piece : pieces) {
+ for (const absl::string_view& piece : pieces) {
const size_t this_size = piece.size();
if (this_size != 0) {
memcpy(out, piece.data(), this_size);
@@ -170,7 +170,7 @@
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) {
+ for (const absl::string_view& piece : pieces) {
ASSERT_NO_OVERLAP(*dest, piece);
total_size += piece.size();
}
@@ -178,7 +178,7 @@
char* const begin = &(*dest)[0];
char* out = begin + old_size;
- for (const absl::string_view piece : pieces) {
+ for (const absl::string_view& piece : pieces) {
const size_t this_size = piece.size();
if (this_size != 0) {
memcpy(out, piece.data(), this_size);
@@ -242,4 +242,5 @@
assert(out == begin + dest->size());
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/str_cat.h b/third_party/abseil/absl/strings/str_cat.h
index a99aac0..a8a85c7 100644
--- a/third_party/abseil/absl/strings/str_cat.h
+++ b/third_party/abseil/absl/strings/str_cat.h
@@ -64,6 +64,7 @@
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
// AlphaNumBuffer allows a way to pass a string to StrCat without having to do
@@ -252,7 +253,7 @@
const std::basic_string<char, std::char_traits<char>, Allocator>& str)
: piece_(str) {}
- // Use std::string literals ":" instead of character literals ':'.
+ // Use string literals ":" instead of character literals ':'.
AlphaNum(char c) = delete; // NOLINT(runtime/explicit)
AlphaNum(const AlphaNum&) = delete;
@@ -290,7 +291,8 @@
// StrCat()
// -----------------------------------------------------------------------------
//
-// Merges given strings or numbers, using no delimiter(s).
+// Merges given strings or numbers, using no delimiter(s), returning the merged
+// result as a string.
//
// `StrCat()` is designed to be the fastest possible way to construct a string
// out of a mix of raw C strings, string_views, strings, bool values,
@@ -400,6 +402,7 @@
return result;
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_STR_CAT_H_
diff --git a/third_party/abseil/absl/strings/str_cat_benchmark.cc b/third_party/abseil/absl/strings/str_cat_benchmark.cc
index 14c63b3..02c4dbe 100644
--- a/third_party/abseil/absl/strings/str_cat_benchmark.cc
+++ b/third_party/abseil/absl/strings/str_cat_benchmark.cc
@@ -23,7 +23,7 @@
namespace {
const char kStringOne[] = "Once Upon A Time, ";
-const char kStringTwo[] = "There was a std::string benchmark";
+const char kStringTwo[] = "There was a string benchmark";
// We want to include negative numbers in the benchmark, so this function
// is used to count 0, 1, -1, 2, -2, 3, -3, ...
@@ -137,4 +137,51 @@
}
BENCHMARK(BM_DoubleToString_By_SixDigits);
+template <typename... Chunks>
+void BM_StrAppendImpl(benchmark::State& state, size_t total_bytes,
+ Chunks... chunks) {
+ for (auto s : state) {
+ std::string result;
+ while (result.size() < total_bytes) {
+ absl::StrAppend(&result, chunks...);
+ benchmark::DoNotOptimize(result);
+ }
+ }
+}
+
+void BM_StrAppend(benchmark::State& state) {
+ const int total_bytes = state.range(0);
+ const int chunks_at_a_time = state.range(1);
+ const absl::string_view kChunk = "0123456789";
+
+ switch (chunks_at_a_time) {
+ case 1:
+ return BM_StrAppendImpl(state, total_bytes, kChunk);
+ case 2:
+ return BM_StrAppendImpl(state, total_bytes, kChunk, kChunk);
+ case 4:
+ return BM_StrAppendImpl(state, total_bytes, kChunk, kChunk, kChunk,
+ kChunk);
+ case 8:
+ return BM_StrAppendImpl(state, total_bytes, kChunk, kChunk, kChunk,
+ kChunk, kChunk, kChunk, kChunk, kChunk);
+ default:
+ std::abort();
+ }
+}
+
+template <typename B>
+void StrAppendConfig(B* benchmark) {
+ for (int bytes : {10, 100, 1000, 10000}) {
+ for (int chunks : {1, 2, 4, 8}) {
+ // Only add the ones that divide properly. Otherwise we are over counting.
+ if (bytes % (10 * chunks) == 0) {
+ benchmark->Args({bytes, chunks});
+ }
+ }
+ }
+}
+
+BENCHMARK(BM_StrAppend)->Apply(StrAppendConfig);
+
} // namespace
diff --git a/third_party/abseil/absl/strings/str_cat_test.cc b/third_party/abseil/absl/strings/str_cat_test.cc
index be39880..f3770dc 100644
--- a/third_party/abseil/absl/strings/str_cat_test.cc
+++ b/third_party/abseil/absl/strings/str_cat_test.cc
@@ -162,7 +162,7 @@
EXPECT_EQ(result, "12345678910, 10987654321!");
std::string one =
- "1"; // Actually, it's the size of this std::string that we want; a
+ "1"; // Actually, it's the size of this 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 ",
@@ -375,7 +375,7 @@
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
+ "1"; // Actually, it's the size of this 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();
@@ -463,7 +463,7 @@
}
TEST(StrAppend, CornerCasesNonEmptyAppend) {
- for (std::string result : {"hello", "a std::string too long to fit in the SSO"}) {
+ for (std::string result : {"hello", "a string too long to fit in the SSO"}) {
const std::string expected = result;
absl::StrAppend(&result, "");
EXPECT_EQ(result, expected);
diff --git a/third_party/abseil/absl/strings/str_format.h b/third_party/abseil/absl/strings/str_format.h
index 607e2bc..0146510 100644
--- a/third_party/abseil/absl/strings/str_format.h
+++ b/third_party/abseil/absl/strings/str_format.h
@@ -19,7 +19,7 @@
//
// The `str_format` library is a typesafe replacement for the family of
// `printf()` string formatting routines within the `<cstdio>` standard library
-// header. Like the `printf` family, the `str_format` uses a "format string" to
+// header. Like the `printf` family, `str_format` uses a "format string" to
// perform argument substitutions based on types. See the `FormatSpec` section
// below for format string documentation.
//
@@ -57,8 +57,7 @@
// arbitrary sink types:
//
// * A generic `Format()` function to write outputs to arbitrary sink types,
-// which must implement a `RawSinkFormat` interface. (See
-// `str_format_sink.h` for more information.)
+// which must implement a `FormatRawSink` interface.
//
// * A `FormatUntyped()` function that is similar to `Format()` except it is
// loosely typed. `FormatUntyped()` is not a template and does not perform
@@ -66,8 +65,7 @@
// boolean from a runtime check.
//
// In addition, the `str_format` library provides extension points for
-// augmenting formatting to new types. These extensions are fully documented
-// within the `str_format_extension.h` header file.
+// augmenting formatting to new types. See "StrFormat Extensions" below.
#ifndef ABSL_STRINGS_STR_FORMAT_H_
#define ABSL_STRINGS_STR_FORMAT_H_
@@ -82,6 +80,7 @@
#include "absl/strings/internal/str_format/parser.h" // IWYU pragma: export
namespace absl {
+ABSL_NAMESPACE_BEGIN
// UntypedFormatSpec
//
@@ -254,8 +253,8 @@
// argument, etc.
template <typename... Args>
-using FormatSpec =
- typename str_format_internal::FormatSpecDeductionBarrier<Args...>::type;
+using FormatSpec = str_format_internal::FormatSpecTemplate<
+ str_format_internal::ArgumentToConv<Args>()...>;
// ParsedFormat
//
@@ -282,9 +281,36 @@
// } else {
// ... error case ...
// }
+
+#if defined(__cpp_nontype_template_parameter_auto)
+// If C++17 is available, an 'extended' format is also allowed that can specify
+// multiple conversion characters per format argument, using a combination of
+// `absl::FormatConversionCharSet` enum values (logically a set union)
+// via the `|` operator. (Single character-based arguments are still accepted,
+// but cannot be combined). Some common conversions also have predefined enum
+// values, such as `absl::FormatConversionCharSet::kIntegral`.
+//
+// Example:
+// // Extended format supports multiple conversion characters per argument,
+// // specified via a combination of `FormatConversionCharSet` enums.
+// using MyFormat = absl::ParsedFormat<absl::FormatConversionCharSet::d |
+// absl::FormatConversionCharSet::x>;
+// MyFormat GetFormat(bool use_hex) {
+// if (use_hex) return MyFormat("foo %x bar");
+// return MyFormat("foo %d bar");
+// }
+// // `format` can be used with any value that supports 'd' and 'x',
+// // like `int`.
+// auto format = GetFormat(use_hex);
+// value = StringF(format, i);
+template <auto... Conv>
+using ParsedFormat = absl::str_format_internal::ExtendedParsedFormat<
+ absl::str_format_internal::ToFormatConversionCharSet(Conv)...>;
+#else
template <char... Conv>
using ParsedFormat = str_format_internal::ExtendedParsedFormat<
- str_format_internal::ConversionCharToConv(Conv)...>;
+ absl::str_format_internal::ToFormatConversionCharSet(Conv)...>;
+#endif // defined(__cpp_nontype_template_parameter_auto)
// StrFormat()
//
@@ -400,6 +426,12 @@
// This function is functionally equivalent to `std::snprintf()` (and
// type-safe); prefer `absl::SNPrintF()` over `std::snprintf()`.
//
+// In particular, a successful call to `absl::SNPrintF()` writes at most `size`
+// bytes of the formatted output to `output`, including a NUL-terminator, and
+// returns the number of bytes that would have been written if truncation did
+// not occur. In the event of an error, a negative value is returned and `errno`
+// is set.
+//
// Example:
//
// std::string_view s = "Ulaanbaatar";
@@ -425,6 +457,16 @@
//
// FormatRawSink is a type erased wrapper around arbitrary sink objects
// specifically used as an argument to `Format()`.
+//
+// All the object has to do define an overload of `AbslFormatFlush()` for the
+// sink, usually by adding a ADL-based free function in the same namespace as
+// the sink:
+//
+// void AbslFormatFlush(MySink* dest, absl::string_view part);
+//
+// where `dest` is the pointer passed to `absl::Format()`. The function should
+// append `part` to `dest`.
+//
// FormatRawSink does not own the passed sink object. The passed object must
// outlive the FormatRawSink.
class FormatRawSink {
@@ -448,12 +490,13 @@
// `absl::FormatRawSink` interface), using a format string and zero or more
// additional arguments.
//
-// By default, `std::string` and `std::ostream` are supported as destination
-// objects. If a `std::string` is used the formatted string is appended to it.
+// By default, `std::string`, `std::ostream`, and `absl::Cord` are supported as
+// destination objects. If a `std::string` is used the formatted string is
+// appended to it.
//
-// `absl::Format()` is a generic version of `absl::StrFormat(), for custom
-// sinks. The format string, like format strings for `StrFormat()`, is checked
-// at compile-time.
+// `absl::Format()` is a generic version of `absl::StrAppendFormat()`, for
+// custom sinks. The format string, like format strings for `StrFormat()`, is
+// checked at compile-time.
//
// On failure, this function returns `false` and the state of the sink is
// unspecified.
@@ -524,6 +567,247 @@
str_format_internal::UntypedFormatSpecImpl::Extract(format), args);
}
+//------------------------------------------------------------------------------
+// StrFormat Extensions
+//------------------------------------------------------------------------------
+//
+// AbslFormatConvert()
+//
+// The StrFormat library provides a customization API for formatting
+// user-defined types using absl::StrFormat(). The API relies on detecting an
+// overload in the user-defined type's namespace of a free (non-member)
+// `AbslFormatConvert()` function, usually as a friend definition with the
+// following signature:
+//
+// absl::FormatConvertResult<...> AbslFormatConvert(
+// const X& value,
+// const absl::FormatConversionSpec& spec,
+// absl::FormatSink *sink);
+//
+// An `AbslFormatConvert()` overload for a type should only be declared in the
+// same file and namespace as said type.
+//
+// The abstractions within this definition include:
+//
+// * An `absl::FormatConversionSpec` to specify the fields to pull from a
+// user-defined type's format string
+// * An `absl::FormatSink` to hold the converted string data during the
+// conversion process.
+// * An `absl::FormatConvertResult` to hold the status of the returned
+// formatting operation
+//
+// The return type encodes all the conversion characters that your
+// AbslFormatConvert() routine accepts. The return value should be {true}.
+// A return value of {false} will result in `StrFormat()` returning
+// an empty string. This result will be propagated to the result of
+// `FormatUntyped`.
+//
+// Example:
+//
+// struct Point {
+// // To add formatting support to `Point`, we simply need to add a free
+// // (non-member) function `AbslFormatConvert()`. This method interprets
+// // `spec` to print in the request format. The allowed conversion characters
+// // can be restricted via the type of the result, in this example
+// // string and integral formatting are allowed (but not, for instance
+// // floating point characters like "%f"). You can add such a free function
+// // using a friend declaration within the body of the class:
+// friend absl::FormatConvertResult<absl::FormatConversionCharSet::kString |
+// absl::FormatConversionCharSet::kIntegral>
+// AbslFormatConvert(const Point& p, const absl::FormatConversionSpec& spec,
+// absl::FormatSink* s) {
+// if (spec.conversion_char() == absl::FormatConversionChar::s) {
+// s->Append(absl::StrCat("x=", p.x, " y=", p.y));
+// } else {
+// s->Append(absl::StrCat(p.x, ",", p.y));
+// }
+// return {true};
+// }
+//
+// int x;
+// int y;
+// };
+
+// clang-format off
+
+// FormatConversionChar
+//
+// Specifies the formatting character provided in the format string
+// passed to `StrFormat()`.
+enum class FormatConversionChar : uint8_t {
+ c, s, // text
+ d, i, o, u, x, X, // int
+ f, F, e, E, g, G, a, A, // float
+ n, p // misc
+};
+// clang-format on
+
+// FormatConversionSpec
+//
+// Specifies modifications to the conversion of the format string, through use
+// of one or more format flags in the source format string.
+class FormatConversionSpec {
+ public:
+ // FormatConversionSpec::is_basic()
+ //
+ // Indicates that width and precision are not specified, and no additional
+ // flags are set for this conversion character in the format string.
+ bool is_basic() const { return impl_.is_basic(); }
+
+ // FormatConversionSpec::has_left_flag()
+ //
+ // Indicates whether the result should be left justified for this conversion
+ // character in the format string. This flag is set through use of a '-'
+ // character in the format string. E.g. "%-s"
+ bool has_left_flag() const { return impl_.has_left_flag(); }
+
+ // FormatConversionSpec::has_show_pos_flag()
+ //
+ // Indicates whether a sign column is prepended to the result for this
+ // conversion character in the format string, even if the result is positive.
+ // This flag is set through use of a '+' character in the format string.
+ // E.g. "%+d"
+ bool has_show_pos_flag() const { return impl_.has_show_pos_flag(); }
+
+ // FormatConversionSpec::has_sign_col_flag()
+ //
+ // Indicates whether a mandatory sign column is added to the result for this
+ // conversion character. This flag is set through use of a space character
+ // (' ') in the format string. E.g. "% i"
+ bool has_sign_col_flag() const { return impl_.has_sign_col_flag(); }
+
+ // FormatConversionSpec::has_alt_flag()
+ //
+ // Indicates whether an "alternate" format is applied to the result for this
+ // conversion character. Alternative forms depend on the type of conversion
+ // character, and unallowed alternatives are undefined. This flag is set
+ // through use of a '#' character in the format string. E.g. "%#h"
+ bool has_alt_flag() const { return impl_.has_alt_flag(); }
+
+ // FormatConversionSpec::has_zero_flag()
+ //
+ // Indicates whether zeroes should be prepended to the result for this
+ // conversion character instead of spaces. This flag is set through use of the
+ // '0' character in the format string. E.g. "%0f"
+ bool has_zero_flag() const { return impl_.has_zero_flag(); }
+
+ // FormatConversionSpec::conversion_char()
+ //
+ // Returns the underlying conversion character.
+ FormatConversionChar conversion_char() const {
+ return impl_.conversion_char();
+ }
+
+ // FormatConversionSpec::width()
+ //
+ // Returns the specified width (indicated through use of a non-zero integer
+ // value or '*' character) of the conversion character. If width is
+ // unspecified, it returns a negative value.
+ int width() const { return impl_.width(); }
+
+ // FormatConversionSpec::precision()
+ //
+ // Returns the specified precision (through use of the '.' character followed
+ // by a non-zero integer value or '*' character) of the conversion character.
+ // If precision is unspecified, it returns a negative value.
+ int precision() const { return impl_.precision(); }
+
+ private:
+ explicit FormatConversionSpec(
+ str_format_internal::FormatConversionSpecImpl impl)
+ : impl_(impl) {}
+
+ friend str_format_internal::FormatConversionSpecImpl;
+
+ absl::str_format_internal::FormatConversionSpecImpl impl_;
+};
+
+// Type safe OR operator for FormatConversionCharSet to allow accepting multiple
+// conversion chars in custom format converters.
+constexpr FormatConversionCharSet operator|(FormatConversionCharSet a,
+ FormatConversionCharSet b) {
+ return static_cast<FormatConversionCharSet>(static_cast<uint64_t>(a) |
+ static_cast<uint64_t>(b));
+}
+
+// FormatConversionCharSet
+//
+// Specifies the _accepted_ conversion types as a template parameter to
+// FormatConvertResult for custom implementations of `AbslFormatConvert`.
+// Note the helper predefined alias definitions (kIntegral, etc.) below.
+enum class FormatConversionCharSet : uint64_t {
+ // text
+ c = str_format_internal::FormatConversionCharToConvInt('c'),
+ s = str_format_internal::FormatConversionCharToConvInt('s'),
+ // integer
+ d = str_format_internal::FormatConversionCharToConvInt('d'),
+ i = str_format_internal::FormatConversionCharToConvInt('i'),
+ o = str_format_internal::FormatConversionCharToConvInt('o'),
+ u = str_format_internal::FormatConversionCharToConvInt('u'),
+ x = str_format_internal::FormatConversionCharToConvInt('x'),
+ X = str_format_internal::FormatConversionCharToConvInt('X'),
+ // Float
+ f = str_format_internal::FormatConversionCharToConvInt('f'),
+ F = str_format_internal::FormatConversionCharToConvInt('F'),
+ e = str_format_internal::FormatConversionCharToConvInt('e'),
+ E = str_format_internal::FormatConversionCharToConvInt('E'),
+ g = str_format_internal::FormatConversionCharToConvInt('g'),
+ G = str_format_internal::FormatConversionCharToConvInt('G'),
+ a = str_format_internal::FormatConversionCharToConvInt('a'),
+ A = str_format_internal::FormatConversionCharToConvInt('A'),
+ // misc
+ n = str_format_internal::FormatConversionCharToConvInt('n'),
+ p = str_format_internal::FormatConversionCharToConvInt('p'),
+
+ // Used for width/precision '*' specification.
+ kStar = static_cast<uint64_t>(
+ absl::str_format_internal::FormatConversionCharSetInternal::kStar),
+ // Some predefined values:
+ kIntegral = d | i | u | o | x | X,
+ kFloating = a | e | f | g | A | E | F | G,
+ kNumeric = kIntegral | kFloating,
+ kString = s,
+ kPointer = p,
+};
+
+// FormatSink
+//
+// An abstraction to which conversions write their string data.
+//
+class FormatSink {
+ public:
+ // Appends `count` copies of `ch`.
+ void Append(size_t count, char ch) { sink_->Append(count, ch); }
+
+ void Append(string_view v) { sink_->Append(v); }
+
+ // Appends the first `precision` bytes of `v`. If this is less than
+ // `width`, spaces will be appended first (if `left` is false), or
+ // after (if `left` is true) to ensure the total amount appended is
+ // at least `width`.
+ bool PutPaddedString(string_view v, int width, int precision, bool left) {
+ return sink_->PutPaddedString(v, width, precision, left);
+ }
+
+ private:
+ friend str_format_internal::FormatSinkImpl;
+ explicit FormatSink(str_format_internal::FormatSinkImpl* s) : sink_(s) {}
+ str_format_internal::FormatSinkImpl* sink_;
+};
+
+// FormatConvertResult
+//
+// Indicates whether a call to AbslFormatConvert() was successful.
+// This return type informs the StrFormat extension framework (through
+// ADL but using the return type) of what conversion characters are supported.
+// It is strongly discouraged to return {false}, as this will result in an
+// empty string in StrFormat.
+template <FormatConversionCharSet C>
+struct FormatConvertResult {
+ bool value;
+};
+
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_STR_FORMAT_H_
diff --git a/third_party/abseil/absl/strings/str_format_test.cc b/third_party/abseil/absl/strings/str_format_test.cc
index cfd81bb..c60027a 100644
--- a/third_party/abseil/absl/strings/str_format_test.cc
+++ b/third_party/abseil/absl/strings/str_format_test.cc
@@ -1,3 +1,18 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/str_format.h"
#include <cstdarg>
#include <cstdint>
@@ -6,10 +21,12 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
-#include "absl/strings/str_format.h"
+#include "absl/strings/cord.h"
+#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
using str_format_internal::FormatArgImpl;
@@ -241,7 +258,7 @@
std::FILE* file() const { return file_; }
- // Read the file into a std::string.
+ // Read the file into a string.
std::string ReadFile() {
std::fseek(file_, 0, SEEK_END);
int size = std::ftell(file_);
@@ -344,11 +361,12 @@
EXPECT_EQ(StrFormat("%c", int{'a'}), "a");
EXPECT_EQ(StrFormat("%c", long{'a'}), "a"); // NOLINT
EXPECT_EQ(StrFormat("%c", uint64_t{'a'}), "a");
- // "s" - std::string Eg: "C" -> "C", std::string("C++") -> "C++"
+ // "s" - string Eg: "C" -> "C", std::string("C++") -> "C++"
// Formats std::string, char*, string_view, and Cord.
EXPECT_EQ(StrFormat("%s", "C"), "C");
EXPECT_EQ(StrFormat("%s", std::string("C++")), "C++");
EXPECT_EQ(StrFormat("%s", string_view("view")), "view");
+ EXPECT_EQ(StrFormat("%s", absl::Cord("cord")), "cord");
// Integral Conversion
// These format integral types: char, int, long, uint64_t, etc.
EXPECT_EQ(StrFormat("%d", char{10}), "10");
@@ -449,7 +467,7 @@
if (conv.precision.is_from_arg()) {
*out += "." + std::to_string(conv.precision.get_from_arg()) + "$*";
}
- *out += conv.conv.Char();
+ *out += str_format_internal::FormatConversionCharToChar(conv.conv);
*out += "}";
return true;
}
@@ -531,76 +549,152 @@
EXPECT_FALSE((ParsedFormat<'s', 'd', 'g'>::New(format)));
}
-using str_format_internal::Conv;
+#if defined(__cpp_nontype_template_parameter_auto)
+
+template <auto T>
+std::true_type IsValidParsedFormatArgTest(ParsedFormat<T>*);
+
+template <auto T>
+std::false_type IsValidParsedFormatArgTest(...);
+
+template <auto T>
+using IsValidParsedFormatArg = decltype(IsValidParsedFormatArgTest<T>(nullptr));
+
+TEST_F(ParsedFormatTest, OnlyValidTypesAllowed) {
+ ASSERT_TRUE(IsValidParsedFormatArg<'c'>::value);
+
+ ASSERT_TRUE(IsValidParsedFormatArg<FormatConversionCharSet::d>::value);
+
+ ASSERT_TRUE(IsValidParsedFormatArg<absl::FormatConversionCharSet::d |
+ absl::FormatConversionCharSet::x>::value);
+ ASSERT_TRUE(
+ IsValidParsedFormatArg<absl::FormatConversionCharSet::kIntegral>::value);
+
+ // This is an easy mistake to make, however, this will reduce to an integer
+ // which has no meaning, so we need to ensure it doesn't compile.
+ ASSERT_FALSE(IsValidParsedFormatArg<'x' | 'd'>::value);
+
+ // For now, we disallow construction based on ConversionChar (rather than
+ // CharSet)
+ ASSERT_FALSE(IsValidParsedFormatArg<absl::FormatConversionChar::d>::value);
+}
+
+TEST_F(ParsedFormatTest, ExtendedTyping) {
+ EXPECT_FALSE(ParsedFormat<FormatConversionCharSet::d>::New(""));
+ ASSERT_TRUE(ParsedFormat<absl::FormatConversionCharSet::d>::New("%d"));
+ auto v1 = ParsedFormat<'d', absl::FormatConversionCharSet::s>::New("%d%s");
+ ASSERT_TRUE(v1);
+ auto v2 = ParsedFormat<absl::FormatConversionCharSet::d, 's'>::New("%d%s");
+ ASSERT_TRUE(v2);
+ auto v3 = ParsedFormat<absl::FormatConversionCharSet::d |
+ absl::FormatConversionCharSet::s,
+ 's'>::New("%d%s");
+ ASSERT_TRUE(v3);
+ auto v4 = ParsedFormat<absl::FormatConversionCharSet::d |
+ absl::FormatConversionCharSet::s,
+ 's'>::New("%s%s");
+ ASSERT_TRUE(v4);
+}
+#endif
TEST_F(ParsedFormatTest, UncheckedCorrect) {
- auto f = ExtendedParsedFormat<Conv::d>::New("ABC%dDEF");
+ auto f =
+ ExtendedParsedFormat<absl::FormatConversionCharSet::d>::New("ABC%dDEF");
ASSERT_TRUE(f);
EXPECT_EQ("[ABC]{d:1$d}[DEF]", SummarizeParsedFormat(*f));
std::string format = "%sFFF%dZZZ%f";
- auto f2 =
- ExtendedParsedFormat<Conv::string, Conv::d, Conv::floating>::New(format);
+ auto f2 = ExtendedParsedFormat<
+ absl::FormatConversionCharSet::kString, absl::FormatConversionCharSet::d,
+ absl::FormatConversionCharSet::kFloating>::New(format);
ASSERT_TRUE(f2);
EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
- f2 = ExtendedParsedFormat<Conv::string, Conv::d, Conv::floating>::New(
- "%s %d %f");
+ f2 = ExtendedParsedFormat<
+ absl::FormatConversionCharSet::kString, absl::FormatConversionCharSet::d,
+ absl::FormatConversionCharSet::kFloating>::New("%s %d %f");
ASSERT_TRUE(f2);
EXPECT_EQ("{s:1$s}[ ]{d:2$d}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
- auto star = ExtendedParsedFormat<Conv::star, Conv::d>::New("%*d");
+ auto star =
+ ExtendedParsedFormat<absl::FormatConversionCharSet::kStar,
+ absl::FormatConversionCharSet::d>::New("%*d");
ASSERT_TRUE(star);
EXPECT_EQ("{*d:2$1$*d}", SummarizeParsedFormat(*star));
- auto dollar = ExtendedParsedFormat<Conv::d, Conv::s>::New("%2$s %1$d");
+ auto dollar =
+ ExtendedParsedFormat<absl::FormatConversionCharSet::d,
+ absl::FormatConversionCharSet::s>::New("%2$s %1$d");
ASSERT_TRUE(dollar);
EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}", SummarizeParsedFormat(*dollar));
// with reuse
- dollar = ExtendedParsedFormat<Conv::d, Conv::s>::New("%2$s %1$d %1$d");
+ dollar = ExtendedParsedFormat<
+ absl::FormatConversionCharSet::d,
+ absl::FormatConversionCharSet::s>::New("%2$s %1$d %1$d");
ASSERT_TRUE(dollar);
EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}[ ]{1$d:1$d}",
SummarizeParsedFormat(*dollar));
}
TEST_F(ParsedFormatTest, UncheckedIgnoredArgs) {
- EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::s>::New("ABC")));
- EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::s>::New("%dABC")));
- EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::s>::New("ABC%2$s")));
- auto f = ExtendedParsedFormat<Conv::d, Conv::s>::NewAllowIgnored("ABC");
+ EXPECT_FALSE(
+ (ExtendedParsedFormat<absl::FormatConversionCharSet::d,
+ absl::FormatConversionCharSet::s>::New("ABC")));
+ EXPECT_FALSE(
+ (ExtendedParsedFormat<absl::FormatConversionCharSet::d,
+ absl::FormatConversionCharSet::s>::New("%dABC")));
+ EXPECT_FALSE(
+ (ExtendedParsedFormat<absl::FormatConversionCharSet::d,
+ absl::FormatConversionCharSet::s>::New("ABC%2$s")));
+ auto f = ExtendedParsedFormat<
+ absl::FormatConversionCharSet::d,
+ absl::FormatConversionCharSet::s>::NewAllowIgnored("ABC");
ASSERT_TRUE(f);
EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f));
- f = ExtendedParsedFormat<Conv::d, Conv::s>::NewAllowIgnored("%dABC");
+ f = ExtendedParsedFormat<
+ absl::FormatConversionCharSet::d,
+ absl::FormatConversionCharSet::s>::NewAllowIgnored("%dABC");
ASSERT_TRUE(f);
EXPECT_EQ("{d:1$d}[ABC]", SummarizeParsedFormat(*f));
- f = ExtendedParsedFormat<Conv::d, Conv::s>::NewAllowIgnored("ABC%2$s");
+ f = ExtendedParsedFormat<
+ absl::FormatConversionCharSet::d,
+ absl::FormatConversionCharSet::s>::NewAllowIgnored("ABC%2$s");
ASSERT_TRUE(f);
EXPECT_EQ("[ABC]{2$s:2$s}", SummarizeParsedFormat(*f));
}
TEST_F(ParsedFormatTest, UncheckedMultipleTypes) {
- auto dx = ExtendedParsedFormat<Conv::d | Conv::x>::New("%1$d %1$x");
+ auto dx =
+ ExtendedParsedFormat<absl::FormatConversionCharSet::d |
+ absl::FormatConversionCharSet::x>::New("%1$d %1$x");
EXPECT_TRUE(dx);
EXPECT_EQ("{1$d:1$d}[ ]{1$x:1$x}", SummarizeParsedFormat(*dx));
- dx = ExtendedParsedFormat<Conv::d | Conv::x>::New("%1$d");
+ dx = ExtendedParsedFormat<absl::FormatConversionCharSet::d |
+ absl::FormatConversionCharSet::x>::New("%1$d");
EXPECT_TRUE(dx);
EXPECT_EQ("{1$d:1$d}", SummarizeParsedFormat(*dx));
}
TEST_F(ParsedFormatTest, UncheckedIncorrect) {
- EXPECT_FALSE(ExtendedParsedFormat<Conv::d>::New(""));
+ EXPECT_FALSE(ExtendedParsedFormat<absl::FormatConversionCharSet::d>::New(""));
- EXPECT_FALSE(ExtendedParsedFormat<Conv::d>::New("ABC%dDEF%d"));
+ EXPECT_FALSE(ExtendedParsedFormat<absl::FormatConversionCharSet::d>::New(
+ "ABC%dDEF%d"));
std::string format = "%sFFF%dZZZ%f";
- EXPECT_FALSE((ExtendedParsedFormat<Conv::s, Conv::d, Conv::g>::New(format)));
+ EXPECT_FALSE(
+ (ExtendedParsedFormat<absl::FormatConversionCharSet::s,
+ absl::FormatConversionCharSet::d,
+ absl::FormatConversionCharSet::g>::New(format)));
}
TEST_F(ParsedFormatTest, RegressionMixPositional) {
- EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::o>::New("%1$d %o")));
+ EXPECT_FALSE(
+ (ExtendedParsedFormat<absl::FormatConversionCharSet::d,
+ absl::FormatConversionCharSet::o>::New("%1$d %o")));
}
using FormatWrapperTest = ::testing::Test;
@@ -622,8 +716,41 @@
}
} // namespace
+ABSL_NAMESPACE_END
} // namespace absl
+using FormatExtensionTest = ::testing::Test;
+
+struct Point {
+ friend absl::FormatConvertResult<absl::FormatConversionCharSet::kString |
+ absl::FormatConversionCharSet::kIntegral>
+ AbslFormatConvert(const Point& p, const absl::FormatConversionSpec& spec,
+ absl::FormatSink* s) {
+ if (spec.conversion_char() == absl::FormatConversionChar::s) {
+ s->Append(absl::StrCat("x=", p.x, " y=", p.y));
+ } else {
+ s->Append(absl::StrCat(p.x, ",", p.y));
+ }
+ return {true};
+ }
+
+ int x = 10;
+ int y = 20;
+};
+
+TEST_F(FormatExtensionTest, AbslFormatConvertExample) {
+ Point p;
+ EXPECT_EQ(absl::StrFormat("a %s z", p), "a x=10 y=20 z");
+ EXPECT_EQ(absl::StrFormat("a %d z", p), "a 10,20 z");
+
+ // Typed formatting will fail to compile an invalid format.
+ // StrFormat("%f", p); // Does not compile.
+ std::string actual;
+ absl::UntypedFormatSpec f1("%f");
+ // FormatUntyped will return false for bad character.
+ EXPECT_FALSE(absl::FormatUntyped(&actual, f1, {absl::FormatArg(p)}));
+}
+
// Some codegen thunks that we can use to easily dump the generated assembly for
// different StrFormat calls.
diff --git a/third_party/abseil/absl/strings/str_join.h b/third_party/abseil/absl/strings/str_join.h
index 4772f5d..ae5731a 100644
--- a/third_party/abseil/absl/strings/str_join.h
+++ b/third_party/abseil/absl/strings/str_join.h
@@ -60,6 +60,7 @@
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// -----------------------------------------------------------------------------
// Concept: Formatter
@@ -286,6 +287,7 @@
return strings_internal::JoinAlgorithm(value, separator, AlphaNumFormatter());
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_STR_JOIN_H_
diff --git a/third_party/abseil/absl/strings/str_join_test.cc b/third_party/abseil/absl/strings/str_join_test.cc
index 921d9c2..2be6256 100644
--- a/third_party/abseil/absl/strings/str_join_test.cc
+++ b/third_party/abseil/absl/strings/str_join_test.cc
@@ -134,26 +134,26 @@
//
{
- // Empty range yields an empty std::string.
+ // Empty range yields an empty 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
+ // A range of 1 element gives a 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
+ // A range with a single empty 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
+ // A range with 2 elements, one of which is an empty string
std::vector<std::string> v = {"a", ""};
EXPECT_EQ("a-", absl::StrJoin(v, "-"));
}
diff --git a/third_party/abseil/absl/strings/str_replace.cc b/third_party/abseil/absl/strings/str_replace.cc
index 280f63d..2bd5fa9 100644
--- a/third_party/abseil/absl/strings/str_replace.cc
+++ b/third_party/abseil/absl/strings/str_replace.cc
@@ -17,6 +17,7 @@
#include "absl/strings/str_cat.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace strings_internal {
using FixedMapping =
@@ -77,4 +78,5 @@
return StrReplaceAll<strings_internal::FixedMapping>(replacements, target);
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/str_replace.h b/third_party/abseil/absl/strings/str_replace.h
index 30540d0..273c707 100644
--- a/third_party/abseil/absl/strings/str_replace.h
+++ b/third_party/abseil/absl/strings/str_replace.h
@@ -46,6 +46,7 @@
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// StrReplaceAll()
//
@@ -212,6 +213,7 @@
return substitutions;
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_STR_REPLACE_H_
diff --git a/third_party/abseil/absl/strings/str_replace_benchmark.cc b/third_party/abseil/absl/strings/str_replace_benchmark.cc
index 95b2dc1..01331da 100644
--- a/third_party/abseil/absl/strings/str_replace_benchmark.cc
+++ b/third_party/abseil/absl/strings/str_replace_benchmark.cc
@@ -62,7 +62,7 @@
}
}
// big_string->resize(50);
- // OK, we've set up the std::string, now let's set up expectations - first by
+ // OK, we've set up the string, now let's set up expectations - first by
// just replacing "the" with "box"
after_replacing_the = new std::string(*big_string);
for (size_t pos = 0;
diff --git a/third_party/abseil/absl/strings/str_replace_test.cc b/third_party/abseil/absl/strings/str_replace_test.cc
index 1ca23af..9d8c7f7 100644
--- a/third_party/abseil/absl/strings/str_replace_test.cc
+++ b/third_party/abseil/absl/strings/str_replace_test.cc
@@ -25,7 +25,7 @@
TEST(StrReplaceAll, OneReplacement) {
std::string s;
- // Empty std::string.
+ // Empty string.
s = absl::StrReplaceAll(s, {{"", ""}});
EXPECT_EQ(s, "");
s = absl::StrReplaceAll(s, {{"x", ""}});
@@ -47,7 +47,7 @@
s = absl::StrReplaceAll("abc", {{"xyz", "123"}});
EXPECT_EQ(s, "abc");
- // Replace entire std::string.
+ // Replace entire string.
s = absl::StrReplaceAll("abc", {{"abc", "xyz"}});
EXPECT_EQ(s, "xyz");
@@ -88,7 +88,7 @@
TEST(StrReplaceAll, ManyReplacements) {
std::string s;
- // Empty std::string.
+ // Empty string.
s = absl::StrReplaceAll("", {{"", ""}, {"x", ""}, {"", "y"}, {"x", "y"}});
EXPECT_EQ(s, "");
@@ -96,7 +96,7 @@
s = absl::StrReplaceAll("abc", {{"", ""}, {"", "y"}, {"x", ""}});
EXPECT_EQ(s, "abc");
- // Replace entire std::string, one char at a time
+ // Replace entire 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"}});
@@ -264,7 +264,7 @@
std::string s;
int reps;
- // Empty std::string.
+ // Empty string.
s = "";
reps = absl::StrReplaceAll({{"", ""}, {"x", ""}, {"", "y"}, {"x", "y"}}, &s);
EXPECT_EQ(reps, 0);
@@ -276,7 +276,7 @@
EXPECT_EQ(reps, 0);
EXPECT_EQ(s, "abc");
- // Replace entire std::string, one char at a time
+ // Replace entire string, one char at a time
s = "abc";
reps = absl::StrReplaceAll({{"a", "x"}, {"b", "y"}, {"c", "z"}}, &s);
EXPECT_EQ(reps, 3);
diff --git a/third_party/abseil/absl/strings/str_split.cc b/third_party/abseil/absl/strings/str_split.cc
index 2593130..e08c26b 100644
--- a/third_party/abseil/absl/strings/str_split.cc
+++ b/third_party/abseil/absl/strings/str_split.cc
@@ -27,6 +27,7 @@
#include "absl/strings/ascii.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
@@ -41,7 +42,7 @@
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
+ // Special case for empty string delimiters: always return a zero-length
// absl::string_view referring to the item at position 1 past pos.
return absl::string_view(text.data() + pos + 1, 0);
}
@@ -126,7 +127,7 @@
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
+ // If the 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.data() + text.size(), 0);
@@ -134,4 +135,5 @@
return absl::string_view(substr.data() + length_, 0);
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/str_split.h b/third_party/abseil/absl/strings/str_split.h
index 7333078..bfbca42 100644
--- a/third_party/abseil/absl/strings/str_split.h
+++ b/third_party/abseil/absl/strings/str_split.h
@@ -44,11 +44,13 @@
#include <vector>
#include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
#include "absl/strings/internal/str_split_internal.h"
#include "absl/strings/string_view.h"
#include "absl/strings/strip.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
//------------------------------------------------------------------------------
// Delimiters
@@ -367,6 +369,12 @@
}
};
+template <typename T>
+using EnableSplitIfString =
+ typename std::enable_if<std::is_same<T, std::string>::value ||
+ std::is_same<T, const std::string>::value,
+ int>::type;
+
//------------------------------------------------------------------------------
// StrSplit()
//------------------------------------------------------------------------------
@@ -487,25 +495,54 @@
// 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>
+ typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty,
+ absl::string_view>
StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d) {
using DelimiterType =
typename strings_internal::SelectDelimiter<Delimiter>::type;
- return strings_internal::Splitter<DelimiterType, AllowEmpty>(
+ return strings_internal::Splitter<DelimiterType, AllowEmpty,
+ absl::string_view>(
+ text.value(), DelimiterType(d), AllowEmpty());
+}
+
+template <typename Delimiter, typename StringType,
+ EnableSplitIfString<StringType> = 0>
+strings_internal::Splitter<
+ typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty,
+ std::string>
+StrSplit(StringType&& text, Delimiter d) {
+ using DelimiterType =
+ typename strings_internal::SelectDelimiter<Delimiter>::type;
+ return strings_internal::Splitter<DelimiterType, AllowEmpty, std::string>(
std::move(text), DelimiterType(d), AllowEmpty());
}
template <typename Delimiter, typename Predicate>
strings_internal::Splitter<
- typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate>
+ typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate,
+ absl::string_view>
StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d,
Predicate p) {
using DelimiterType =
typename strings_internal::SelectDelimiter<Delimiter>::type;
- return strings_internal::Splitter<DelimiterType, Predicate>(
+ return strings_internal::Splitter<DelimiterType, Predicate,
+ absl::string_view>(
+ text.value(), DelimiterType(d), std::move(p));
+}
+
+template <typename Delimiter, typename Predicate, typename StringType,
+ EnableSplitIfString<StringType> = 0>
+strings_internal::Splitter<
+ typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate,
+ std::string>
+StrSplit(StringType&& text, Delimiter d, Predicate p) {
+ using DelimiterType =
+ typename strings_internal::SelectDelimiter<Delimiter>::type;
+ return strings_internal::Splitter<DelimiterType, Predicate, std::string>(
std::move(text), DelimiterType(d), std::move(p));
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_STR_SPLIT_H_
diff --git a/third_party/abseil/absl/strings/str_split_test.cc b/third_party/abseil/absl/strings/str_split_test.cc
index 02f27bc..7f7c097 100644
--- a/third_party/abseil/absl/strings/str_split_test.cc
+++ b/third_party/abseil/absl/strings/str_split_test.cc
@@ -27,8 +27,10 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
-#include "absl/base/dynamic_annotations.h" // for RunningOnValgrind
+#include "absl/base/dynamic_annotations.h"
#include "absl/base/macros.h"
+#include "absl/container/flat_hash_map.h"
+#include "absl/container/node_hash_map.h"
#include "absl/strings/numbers.h"
namespace {
@@ -71,7 +73,7 @@
// namespaces just like callers will need to use.
TEST(Split, APIExamples) {
{
- // Passes std::string delimiter. Assumes the default of ByString.
+ // Passes string delimiter. Assumes the default of ByString.
std::vector<std::string> v = absl::StrSplit("a,b,c", ","); // NOLINT
EXPECT_THAT(v, ElementsAre("a", "b", "c"));
@@ -97,7 +99,7 @@
}
{
- // Uses the Literal std::string "=>" as the delimiter.
+ // Uses the Literal string "=>" as the delimiter.
const std::vector<std::string> v = absl::StrSplit("a=>b=>c", "=>");
EXPECT_THAT(v, ElementsAre("a", "b", "c"));
}
@@ -121,17 +123,17 @@
}
{
- // Splits the input std::string into individual characters by using an empty
- // std::string as the delimiter.
+ // Splits the input string into individual characters by using an empty
+ // 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
+ // Splits 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
+ // say that's the empty string when constructing the absl::string_view
+ // delimiter. Instead, a non-empty string containing NUL can be used as the
// delimiter.
std::string embedded_nulls("a\0b\0c", 5);
std::string null_delim("\0", 1);
@@ -365,7 +367,7 @@
TEST(Splitter, RangeIterators) {
auto splitter = absl::StrSplit("a,b,c", ',');
std::vector<absl::string_view> output;
- for (const absl::string_view p : splitter) {
+ for (const absl::string_view& p : splitter) {
output.push_back(p);
}
EXPECT_THAT(output, ElementsAre("a", "b", "c"));
@@ -421,6 +423,18 @@
TestMapConversionOperator<std::multimap<std::string, std::string>>(splitter);
TestMapConversionOperator<std::unordered_map<std::string, std::string>>(
splitter);
+ TestMapConversionOperator<
+ absl::node_hash_map<absl::string_view, absl::string_view>>(splitter);
+ TestMapConversionOperator<
+ absl::node_hash_map<absl::string_view, std::string>>(splitter);
+ TestMapConversionOperator<
+ absl::node_hash_map<std::string, absl::string_view>>(splitter);
+ TestMapConversionOperator<
+ absl::flat_hash_map<absl::string_view, absl::string_view>>(splitter);
+ TestMapConversionOperator<
+ absl::flat_hash_map<absl::string_view, std::string>>(splitter);
+ TestMapConversionOperator<
+ absl::flat_hash_map<std::string, absl::string_view>>(splitter);
// Tests conversion to std::pair
@@ -436,7 +450,7 @@
// less-than, equal-to, and more-than 2 strings.
TEST(Splitter, ToPair) {
{
- // Empty std::string
+ // Empty string
std::pair<std::string, std::string> p = absl::StrSplit("", ',');
EXPECT_EQ("", p.first);
EXPECT_EQ("", p.second);
@@ -565,7 +579,7 @@
TEST(Split, Temporary) {
// Use a std::string longer than the SSO length, so that when the temporary is
- // destroyed, if the splitter keeps a reference to the std::string's contents,
+ // destroyed, if the splitter keeps a reference to the 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))
@@ -651,14 +665,14 @@
// Tests splitting utf8 strings and utf8 delimiters.
std::string utf8_string = u8"\u03BA\u1F79\u03C3\u03BC\u03B5";
{
- // A utf8 input std::string with an ascii delimiter.
+ // A utf8 input string with an ascii delimiter.
std::string to_split = "a," + utf8_string;
std::vector<absl::string_view> v = absl::StrSplit(to_split, ',');
EXPECT_THAT(v, ElementsAre("a", utf8_string));
}
{
- // A utf8 input std::string and a utf8 delimiter.
+ // A utf8 input string and a utf8 delimiter.
std::string to_split = "a," + utf8_string + ",b";
std::string unicode_delimiter = "," + utf8_string + ",";
std::vector<absl::string_view> v =
@@ -667,7 +681,7 @@
}
{
- // A utf8 input std::string and ByAnyChar with ascii chars.
+ // A utf8 input string and ByAnyChar with ascii chars.
std::vector<absl::string_view> v =
absl::StrSplit(u8"Foo h\u00E4llo th\u4E1Ere", absl::ByAnyChar(" \t"));
EXPECT_THAT(v, ElementsAre("Foo", u8"h\u00E4llo", u8"th\u4E1Ere"));
@@ -814,10 +828,10 @@
ByString comma_string(",");
TestComma(comma_string);
- // The first occurrence of empty std::string ("") in a std::string is at position 0.
+ // The first occurrence of empty string ("") in a 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
+ // be an infinite loop in the SplitIterator code. To avoid this, empty 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
@@ -876,7 +890,7 @@
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
+ // 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));
@@ -913,7 +927,7 @@
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.
+ // testing::StartsWith is too slow with a 2G string.
EXPECT_EQ('x', v[0][0]);
EXPECT_EQ('x', v[0][1]);
EXPECT_EQ('x', v[0][3]);
diff --git a/third_party/abseil/absl/strings/string_view.cc b/third_party/abseil/absl/strings/string_view.cc
index dc034a8..c5f5de9 100644
--- a/third_party/abseil/absl/strings/string_view.cc
+++ b/third_party/abseil/absl/strings/string_view.cc
@@ -14,7 +14,7 @@
#include "absl/strings/string_view.h"
-#ifndef ABSL_HAVE_STD_STRING_VIEW
+#ifndef ABSL_USES_STD_STRING_VIEW
#include <algorithm>
#include <climits>
@@ -24,6 +24,7 @@
#include "absl/strings/internal/memutil.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
void WritePadding(std::ostream& o, size_t pad) {
@@ -228,6 +229,7 @@
ABSL_STRING_VIEW_SELECTANY
constexpr string_view::size_type string_view::kMaxSize;
+ABSL_NAMESPACE_END
} // namespace absl
-#endif // ABSL_HAVE_STD_STRING_VIEW
+#endif // ABSL_USES_STD_STRING_VIEW
diff --git a/third_party/abseil/absl/strings/string_view.h b/third_party/abseil/absl/strings/string_view.h
index 68b90aa..5260b5b 100644
--- a/third_party/abseil/absl/strings/string_view.h
+++ b/third_party/abseil/absl/strings/string_view.h
@@ -28,18 +28,6 @@
#define ABSL_STRINGS_STRING_VIEW_H_
#include <algorithm>
-#include "absl/base/config.h"
-
-#ifdef ABSL_HAVE_STD_STRING_VIEW
-
-#include <string_view> // IWYU pragma: export
-
-namespace absl {
-using std::string_view;
-} // namespace absl
-
-#else // ABSL_HAVE_STD_STRING_VIEW
-
#include <cassert>
#include <cstddef>
#include <cstring>
@@ -48,12 +36,33 @@
#include <limits>
#include <string>
+#include "absl/base/config.h"
#include "absl/base/internal/throw_delegate.h"
#include "absl/base/macros.h"
#include "absl/base/optimization.h"
#include "absl/base/port.h"
+#ifdef ABSL_USES_STD_STRING_VIEW
+
+#include <string_view> // IWYU pragma: export
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
+using string_view = std::string_view;
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#else // ABSL_USES_STD_STRING_VIEW
+
+#if ABSL_HAVE_BUILTIN(__builtin_memcmp) || \
+ (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_INTERNAL_STRING_VIEW_MEMCMP __builtin_memcmp
+#else // ABSL_HAVE_BUILTIN(__builtin_memcmp)
+#define ABSL_INTERNAL_STRING_VIEW_MEMCMP memcmp
+#endif // ABSL_HAVE_BUILTIN(__builtin_memcmp)
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
// absl::string_view
//
@@ -102,17 +111,22 @@
// example, when splitting a 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
+// For another example, a Cord is a non-contiguous, potentially very
+// long string-like object. The Cord class has an interface that iteratively
+// provides string_view objects that point to the successive pieces of a Cord
+// object.
+//
+// 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;
// absl::string_view sv(nullptr, 0);
//
// For the above, `sv.data() == nullptr`, `sv.length() == 0`, and
@@ -168,9 +182,11 @@
string_view( // NOLINT(runtime/explicit)
const std::basic_string<char, std::char_traits<char>, Allocator>&
str) noexcept
- : ptr_(str.data()), length_(CheckLengthInternal(str.size())) {}
+ // This is implemented in terms of `string_view(p, n)` so `str.size()`
+ // doesn't need to be reevaluated after `ptr_` is set.
+ : string_view(str.data(), str.size()) {}
- // Implicit constructor of a `string_view` from nul-terminated `str`. When
+ // 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)
@@ -271,7 +287,9 @@
//
// Returns the ith element of the `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]; }
+ constexpr const_reference operator[](size_type i) const {
+ return ABSL_HARDENING_ASSERT(i < size()), ptr_[i];
+ }
// string_view::at()
//
@@ -281,27 +299,32 @@
constexpr const_reference at(size_type i) const {
return ABSL_PREDICT_TRUE(i < size())
? ptr_[i]
- : (base_internal::ThrowStdOutOfRange("absl::string_view::at"),
+ : ((void)base_internal::ThrowStdOutOfRange(
+ "absl::string_view::at"),
ptr_[i]);
}
// string_view::front()
//
// Returns the first element of a `string_view`.
- constexpr const_reference front() const { return ptr_[0]; }
+ constexpr const_reference front() const {
+ return ABSL_HARDENING_ASSERT(!empty()), ptr_[0];
+ }
// string_view::back()
//
// Returns the last element of a `string_view`.
- constexpr const_reference back() const { return ptr_[size() - 1]; }
+ constexpr const_reference back() const {
+ return ABSL_HARDENING_ASSERT(!empty()), 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.
+ // 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
+ // string.
constexpr const_pointer data() const noexcept { return ptr_; }
// Modifiers
@@ -309,9 +332,9 @@
// string_view::remove_prefix()
//
// Removes the first `n` characters from the `string_view`. Note that the
- // underlying std::string is not changed, only the view.
+ // underlying string is not changed, only the view.
void remove_prefix(size_type n) {
- assert(n <= length_);
+ ABSL_HARDENING_ASSERT(n <= length_);
ptr_ += n;
length_ -= n;
}
@@ -319,9 +342,9 @@
// 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.
+ // underlying string is not changed, only the view.
void remove_suffix(size_type n) {
- assert(n <= length_);
+ ABSL_HARDENING_ASSERT(n <= length_);
length_ -= n;
}
@@ -364,31 +387,29 @@
// Returns a "substring" of the `string_view` (at offset `pos` and length
// `n`) as another string_view. 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);
+ // Use absl::ClippedSubstr if you need a truncating substr operation.
+ constexpr string_view substr(size_type pos, size_type n = npos) const {
+ return ABSL_PREDICT_FALSE(pos > length_)
+ ? (base_internal::ThrowStdOutOfRange(
+ "absl::string_view::substr"),
+ string_view())
+ : string_view(ptr_ + pos, Min(n, length_ - pos));
}
// 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
+ // `this` is equal to, and 1 if `this` is greater than the passed 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;
+ constexpr int compare(string_view x) const noexcept {
+ return CompareImpl(length_, x.length_,
+ Min(length_, x.length_) == 0
+ ? 0
+ : ABSL_INTERNAL_STRING_VIEW_MEMCMP(
+ ptr_, x.ptr_, Min(length_, x.length_)));
}
// Overload of `string_view::compare()` for comparing a substring of the
@@ -405,17 +426,17 @@
}
// Overload of `string_view::compare()` for comparing a `string_view` and a
- // a different C-style std::string `s`.
+ // a different C-style 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`.
+ // `string_view` and a different string C-style 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`.
+ // `string_view` and a substring of a different C-style 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));
@@ -505,7 +526,7 @@
(std::numeric_limits<difference_type>::max)();
static constexpr size_type CheckLengthInternal(size_type len) {
- return ABSL_ASSERT(len <= kMaxSize), len;
+ return ABSL_HARDENING_ASSERT(len <= kMaxSize), len;
}
static constexpr size_type StrlenInternal(const char* str) {
@@ -526,6 +547,17 @@
#endif
}
+ static constexpr size_t Min(size_type length_a, size_type length_b) {
+ return length_a < length_b ? length_a : length_b;
+ }
+
+ static constexpr int CompareImpl(size_type length_a, size_type length_b,
+ int compare_result) {
+ return compare_result == 0 ? static_cast<int>(length_a > length_b) -
+ static_cast<int>(length_a < length_b)
+ : (compare_result < 0 ? -1 : 1);
+ }
+
const char* ptr_;
size_type length_;
};
@@ -533,44 +565,44 @@
// 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;
+constexpr bool operator==(string_view x, string_view y) noexcept {
+ return x.size() == y.size() &&
+ (x.empty() ||
+ ABSL_INTERNAL_STRING_VIEW_MEMCMP(x.data(), y.data(), x.size()) == 0);
}
-inline bool operator!=(string_view x, string_view y) noexcept {
+constexpr 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());
+constexpr bool operator<(string_view x, string_view y) noexcept {
+ return x.compare(y) < 0;
}
-inline bool operator>(string_view x, string_view y) noexcept { return y < x; }
+constexpr bool operator>(string_view x, string_view y) noexcept {
+ return y < x;
+}
-inline bool operator<=(string_view x, string_view y) noexcept {
+constexpr bool operator<=(string_view x, string_view y) noexcept {
return !(y < x);
}
-inline bool operator>=(string_view x, string_view y) noexcept {
+constexpr bool operator>=(string_view x, string_view y) noexcept {
return !(x < y);
}
// IO Insertion Operator
std::ostream& operator<<(std::ostream& o, string_view piece);
+ABSL_NAMESPACE_END
} // namespace absl
-#endif // ABSL_HAVE_STD_STRING_VIEW
+#undef ABSL_INTERNAL_STRING_VIEW_MEMCMP
+
+#endif // ABSL_USES_STD_STRING_VIEW
namespace absl {
+ABSL_NAMESPACE_BEGIN
// ClippedSubstr()
//
@@ -587,10 +619,11 @@
// 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) {
+constexpr string_view NullSafeStringView(const char* p) {
return p ? string_view(p) : string_view();
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_STRING_VIEW_H_
diff --git a/third_party/abseil/absl/strings/string_view_benchmark.cc b/third_party/abseil/absl/strings/string_view_benchmark.cc
index 46909cb..0d74e23 100644
--- a/third_party/abseil/absl/strings/string_view_benchmark.cc
+++ b/third_party/abseil/absl/strings/string_view_benchmark.cc
@@ -30,6 +30,24 @@
namespace {
+void BM_StringViewFromString(benchmark::State& state) {
+ std::string s(state.range(0), 'x');
+ std::string* ps = &s;
+ struct SV {
+ SV() = default;
+ explicit SV(const std::string& s) : sv(s) {}
+ absl::string_view sv;
+ } sv;
+ SV* psv = &sv;
+ benchmark::DoNotOptimize(ps);
+ benchmark::DoNotOptimize(psv);
+ for (auto _ : state) {
+ new (psv) SV(*ps);
+ benchmark::DoNotOptimize(sv);
+ }
+}
+BENCHMARK(BM_StringViewFromString)->Arg(12)->Arg(128);
+
// Provide a forcibly out-of-line wrapper for operator== that can be used in
// benchmarks to measure the impact of inlining.
ABSL_ATTRIBUTE_NOINLINE
@@ -142,11 +160,45 @@
absl::string_view b = y;
for (auto _ : state) {
+ benchmark::DoNotOptimize(a);
+ benchmark::DoNotOptimize(b);
benchmark::DoNotOptimize(a.compare(b));
}
}
BENCHMARK(BM_CompareSame)->DenseRange(0, 3)->Range(4, 1 << 10);
+void BM_CompareFirstOneLess(benchmark::State& state) {
+ const int len = state.range(0);
+ std::string x(len, 'a');
+ std::string y = x;
+ y.back() = 'b';
+ absl::string_view a = x;
+ absl::string_view b = y;
+
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(a);
+ benchmark::DoNotOptimize(b);
+ benchmark::DoNotOptimize(a.compare(b));
+ }
+}
+BENCHMARK(BM_CompareFirstOneLess)->DenseRange(1, 3)->Range(4, 1 << 10);
+
+void BM_CompareSecondOneLess(benchmark::State& state) {
+ const int len = state.range(0);
+ std::string x(len, 'a');
+ std::string y = x;
+ x.back() = 'b';
+ absl::string_view a = x;
+ absl::string_view b = y;
+
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(a);
+ benchmark::DoNotOptimize(b);
+ benchmark::DoNotOptimize(a.compare(b));
+ }
+}
+BENCHMARK(BM_CompareSecondOneLess)->DenseRange(1, 3)->Range(4, 1 << 10);
+
void BM_find_string_view_len_one(benchmark::State& state) {
std::string haystack(state.range(0), '0');
absl::string_view s(haystack);
diff --git a/third_party/abseil/absl/strings/string_view_test.cc b/third_party/abseil/absl/strings/string_view_test.cc
index eb8b170..643af8f 100644
--- a/third_party/abseil/absl/strings/string_view_test.cc
+++ b/third_party/abseil/absl/strings/string_view_test.cc
@@ -28,6 +28,7 @@
#include "gtest/gtest.h"
#include "absl/base/config.h"
#include "absl/base/dynamic_annotations.h"
+#include "absl/base/options.h"
#if defined(ABSL_HAVE_STD_STRING_VIEW) || defined(__ANDROID__)
// We don't control the death messaging when using std::string_view.
@@ -410,7 +411,7 @@
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
+ // empty 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);
@@ -438,7 +439,7 @@
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
+ // empty 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);
@@ -465,7 +466,7 @@
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
+ // empty 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()));
@@ -484,7 +485,7 @@
EXPECT_EQ(f.rfind('\0', 12), 3);
EXPECT_EQ(f.rfind('3'), 2);
EXPECT_EQ(f.rfind('5'), 5);
- // empty std::string nonsense
+ // empty 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);
@@ -520,7 +521,7 @@
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
+ // empty 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);
@@ -538,7 +539,7 @@
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
+ // empty 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);
@@ -566,7 +567,7 @@
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
+ // empty 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);
@@ -606,7 +607,7 @@
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
+ // empty 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);
@@ -632,7 +633,7 @@
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
+ // empty 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);
@@ -656,7 +657,7 @@
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
+ // empty 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);
@@ -678,7 +679,7 @@
EXPECT_EQ(a.substr(23, 99), c);
EXPECT_EQ(a.substr(0), a);
EXPECT_EQ(a.substr(3, 2), "de");
- // empty std::string nonsense
+ // empty string nonsense
EXPECT_EQ(d.substr(0, 99), e);
// use of npos
EXPECT_EQ(a.substr(0, absl::string_view::npos), a);
@@ -818,6 +819,18 @@
EXPECT_EQ(&c, &csp.back());
}
+TEST(StringViewTest, FrontBackEmpty) {
+#ifndef ABSL_USES_STD_STRING_VIEW
+#if !defined(NDEBUG) || ABSL_OPTION_HARDENED
+ // Abseil's string_view implementation has debug assertions that check that
+ // front() and back() are not called on an empty string_view.
+ absl::string_view sv;
+ ABSL_EXPECT_DEATH_IF_SUPPORTED(sv.front(), "");
+ ABSL_EXPECT_DEATH_IF_SUPPORTED(sv.back(), "");
+#endif
+#endif
+}
+
// `std::string_view::string_view(const char*)` calls
// `std::char_traits<char>::length(const char*)` to get the string length. In
// libc++, it doesn't allow `nullptr` in the constexpr context, with the error
@@ -830,7 +843,7 @@
// to the standard, but `absl::string_view` implements a different
// behavior for historical reasons. We work around tests that construct
// `string_view` from `nullptr` when using libc++.
-#if !defined(ABSL_HAVE_STD_STRING_VIEW) || \
+#if !defined(ABSL_USES_STD_STRING_VIEW) || \
(!(defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE >= 9) && \
!defined(_LIBCPP_VERSION) && !defined(_MSC_VER))
#define ABSL_HAVE_STRING_VIEW_FROM_NULLPTR 1
@@ -847,7 +860,7 @@
EXPECT_EQ(s.size(), 0);
// .ToString() on a absl::string_view with nullptr should produce the empty
- // std::string.
+ // string.
EXPECT_EQ("", std::string(s));
#endif // ABSL_HAVE_STRING_VIEW_FROM_NULLPTR
}
@@ -902,9 +915,9 @@
EXPECT_EQ(abc.at(1), 'b');
EXPECT_EQ(abc.at(2), 'c');
#ifdef ABSL_HAVE_EXCEPTIONS
- EXPECT_THROW(abc.at(3), std::out_of_range);
+ EXPECT_THROW((void)abc.at(3), std::out_of_range);
#else
- ABSL_EXPECT_DEATH_IF_SUPPORTED(abc.at(3), "absl::string_view::at");
+ ABSL_EXPECT_DEATH_IF_SUPPORTED((void)abc.at(3), "absl::string_view::at");
#endif
}
@@ -931,6 +944,31 @@
}
}
+TEST(StringViewTest, ConstexprNullSafeStringView) {
+ {
+ constexpr absl::string_view s = absl::NullSafeStringView(nullptr);
+ EXPECT_EQ(nullptr, s.data());
+ EXPECT_EQ(0, s.size());
+ EXPECT_EQ(absl::string_view(), s);
+ }
+#if !defined(_MSC_VER) || _MSC_VER >= 1910
+ // MSVC 2017+ is required for good constexpr string_view support.
+ // See the implementation of `absl::string_view::StrlenInternal()`.
+ {
+ static constexpr 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);
+ }
+ {
+ constexpr absl::string_view s = absl::NullSafeStringView("hello");
+ EXPECT_EQ(s.size(), 5);
+ EXPECT_EQ("hello", s);
+ }
+#endif
+}
+
TEST(StringViewTest, ConstexprCompiles) {
constexpr absl::string_view sp;
#ifdef ABSL_HAVE_STRING_VIEW_FROM_NULLPTR
@@ -938,9 +976,9 @@
#endif
constexpr absl::string_view cstr_len("cstr", 4);
-#if defined(ABSL_HAVE_STD_STRING_VIEW)
+#if defined(ABSL_USES_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
+ // calls `std::char_traits<char>::length(const char*)` to get the 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
@@ -952,7 +990,7 @@
#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR 1
#endif // !__GLIBCXX__
-#else // ABSL_HAVE_STD_STRING_VIEW
+#else // ABSL_USES_STD_STRING_VIEW
// This duplicates the check for __builtin_strlen in the header.
#if ABSL_HAVE_BUILTIN(__builtin_strlen) || \
@@ -967,13 +1005,36 @@
#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR 1
#endif
-#endif // ABSL_HAVE_STD_STRING_VIEW
+#endif // ABSL_USES_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");
+
+#if ABSL_HAVE_BUILTIN(__builtin_memcmp) || \
+ (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_COMPARISON 1
+#endif
+#ifdef ABSL_HAVE_CONSTEXPR_STRING_VIEW_COMPARISON
+ constexpr absl::string_view foo = "foo";
+ constexpr absl::string_view bar = "bar";
+ constexpr bool foo_eq_bar = foo == bar;
+ constexpr bool foo_ne_bar = foo != bar;
+ constexpr bool foo_lt_bar = foo < bar;
+ constexpr bool foo_le_bar = foo <= bar;
+ constexpr bool foo_gt_bar = foo > bar;
+ constexpr bool foo_ge_bar = foo >= bar;
+ constexpr int foo_compare_bar = foo.compare(bar);
+ EXPECT_FALSE(foo_eq_bar);
+ EXPECT_TRUE(foo_ne_bar);
+ EXPECT_FALSE(foo_lt_bar);
+ EXPECT_FALSE(foo_le_bar);
+ EXPECT_TRUE(foo_gt_bar);
+ EXPECT_TRUE(foo_ge_bar);
+ EXPECT_GT(foo_compare_bar, 0);
+#endif
#endif
#if !defined(__clang__) || 3 < __clang_major__ || \
@@ -1026,6 +1087,14 @@
EXPECT_EQ(sp_npos, -1);
}
+TEST(StringViewTest, ConstexprSubstr) {
+ constexpr absl::string_view foobar("foobar", 6);
+ constexpr absl::string_view foo = foobar.substr(0, 3);
+ constexpr absl::string_view bar = foobar.substr(3);
+ EXPECT_EQ(foo, "foo");
+ EXPECT_EQ(bar, "bar");
+}
+
TEST(StringViewTest, Noexcept) {
EXPECT_TRUE((std::is_nothrow_constructible<absl::string_view,
const std::string&>::value));
@@ -1060,6 +1129,17 @@
EXPECT_TRUE(noexcept(sp.find_last_not_of('f')));
}
+TEST(StringViewTest, BoundsCheck) {
+#ifndef ABSL_USES_STD_STRING_VIEW
+#if !defined(NDEBUG) || ABSL_OPTION_HARDENED
+ // Abseil's string_view implementation has bounds-checking in debug mode.
+ absl::string_view h = "hello";
+ ABSL_EXPECT_DEATH_IF_SUPPORTED(h[5], "");
+ ABSL_EXPECT_DEATH_IF_SUPPORTED(h[-1], "");
+#endif
+#endif
+}
+
TEST(ComparisonOpsTest, StringCompareNotAmbiguous) {
EXPECT_EQ("hello", std::string("hello"));
EXPECT_LT("hello", std::string("world"));
@@ -1097,11 +1177,11 @@
EXPECT_EQ(absl::string_view::npos, a.rfind('x'));
}
-#ifndef THREAD_SANITIZER // Allocates too much memory for tsan.
+#ifndef ABSL_HAVE_THREAD_SANITIZER // Allocates too much memory for tsan.
TEST(HugeStringView, TwoPointTwoGB) {
- if (sizeof(size_t) <= 4 || RunningOnValgrind())
+ if (sizeof(size_t) <= 4)
return;
- // Try a huge std::string piece.
+ // Try a huge string piece.
const size_t size = size_t{2200} * 1000 * 1000;
std::string s(size, 'a');
absl::string_view sp(s);
@@ -1111,9 +1191,9 @@
sp.remove_suffix(2);
EXPECT_EQ(size - 1 - 2, sp.length());
}
-#endif // THREAD_SANITIZER
+#endif // ABSL_HAVE_THREAD_SANITIZER
-#if !defined(NDEBUG) && !defined(ABSL_HAVE_STD_STRING_VIEW)
+#if !defined(NDEBUG) && !defined(ABSL_USES_STD_STRING_VIEW)
TEST(NonNegativeLenTest, NonNegativeLen) {
ABSL_EXPECT_DEATH_IF_SUPPORTED(absl::string_view("xyz", -1),
"len <= kMaxSize");
@@ -1129,7 +1209,7 @@
ABSL_EXPECT_DEATH_IF_SUPPORTED(absl::string_view("", max_size + 1),
"len <= kMaxSize");
}
-#endif // !defined(NDEBUG) && !defined(ABSL_HAVE_STD_STRING_VIEW)
+#endif // !defined(NDEBUG) && !defined(ABSL_USES_STD_STRING_VIEW)
class StringViewStreamTest : public ::testing::Test {
public:
diff --git a/third_party/abseil/absl/strings/strip.h b/third_party/abseil/absl/strings/strip.h
index e1341e0..111872c 100644
--- a/third_party/abseil/absl/strings/strip.h
+++ b/third_party/abseil/absl/strings/strip.h
@@ -30,6 +30,7 @@
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// ConsumePrefix()
//
@@ -84,6 +85,7 @@
return str;
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_STRIP_H_
diff --git a/third_party/abseil/absl/strings/substitute.cc b/third_party/abseil/absl/strings/substitute.cc
index bc17695..1f3c740 100644
--- a/third_party/abseil/absl/strings/substitute.cc
+++ b/third_party/abseil/absl/strings/substitute.cc
@@ -23,6 +23,7 @@
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace substitute_internal {
void SubstituteAndAppendArray(std::string* output, absl::string_view format,
@@ -35,7 +36,7 @@
if (i + 1 >= format.size()) {
#ifndef NDEBUG
ABSL_RAW_LOG(FATAL,
- "Invalid strings::Substitute() format std::string: \"%s\".",
+ "Invalid absl::Substitute() format string: \"%s\".",
absl::CEscape(format).c_str());
#endif
return;
@@ -45,8 +46,8 @@
#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: "
+ "Invalid absl::Substitute() format string: asked for \"$"
+ "%d\", but only %d args were given. Full format string was: "
"\"%s\".",
index, static_cast<int>(num_args), absl::CEscape(format).c_str());
#endif
@@ -60,7 +61,7 @@
} else {
#ifndef NDEBUG
ABSL_RAW_LOG(FATAL,
- "Invalid strings::Substitute() format std::string: \"%s\".",
+ "Invalid absl::Substitute() format string: \"%s\".",
absl::CEscape(format).c_str());
#endif
return;
@@ -72,7 +73,7 @@
if (size == 0) return;
- // Build the std::string.
+ // Build the string.
size_t original_size = output->size();
strings_internal::STLStringResizeUninitialized(output, original_size + size);
char* target = &(*output)[original_size];
@@ -94,7 +95,6 @@
assert(target == output->data() + output->size());
}
-static const char kHexDigits[] = "0123456789abcdef";
Arg::Arg(const void* value) {
static_assert(sizeof(scratch_) >= sizeof(value) * 2 + 2,
"fix sizeof(scratch_)");
@@ -104,7 +104,7 @@
char* ptr = scratch_ + sizeof(scratch_);
uintptr_t num = reinterpret_cast<uintptr_t>(value);
do {
- *--ptr = kHexDigits[num & 0xf];
+ *--ptr = absl::numbers_internal::kHexChar[num & 0xf];
num >>= 4;
} while (num != 0);
*--ptr = 'x';
@@ -119,7 +119,7 @@
char* writer = end;
uint64_t value = hex.value;
do {
- *--writer = kHexDigits[value & 0xF];
+ *--writer = absl::numbers_internal::kHexChar[value & 0xF];
value >>= 4;
} while (value != 0);
@@ -167,4 +167,5 @@
}
} // namespace substitute_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/strings/substitute.h b/third_party/abseil/absl/strings/substitute.h
index 233e9dc..c6da4dc 100644
--- a/third_party/abseil/absl/strings/substitute.h
+++ b/third_party/abseil/absl/strings/substitute.h
@@ -50,7 +50,7 @@
//
// Supported types:
// * absl::string_view, std::string, const char* (null is equivalent to "")
-// * int32_t, int64_t, uint32_t, uint64
+// * int32_t, int64_t, uint32_t, uint64_t
// * float, double
// * bool (Printed as "true" or "false")
// * pointer types other than char* (Printed as "0x<lower case hex string>",
@@ -86,6 +86,7 @@
#include "absl/strings/strip.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace substitute_internal {
// Arg
@@ -98,7 +99,7 @@
// This class has implicit constructors.
class Arg {
public:
- // Overloads for std::string-y things
+ // Overloads for string-y things
//
// Explicitly overload `const char*` so the compiler doesn't cast to `bool`.
Arg(const char* value) // NOLINT(runtime/explicit)
@@ -119,7 +120,9 @@
// 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; }
+ : piece_(scratch_, 1) {
+ scratch_[0] = value;
+ }
Arg(short value) // NOLINT(*)
: piece_(scratch_,
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
@@ -189,7 +192,12 @@
#if defined(ABSL_BAD_CALL_IF)
constexpr int CalculateOneBit(const char* format) {
- return (*format < '0' || *format > '9') ? 0 : (1 << (*format - '0'));
+ // Returns:
+ // * 2^N for '$N' when N is in [0-9]
+ // * 0 for correct '$' escaping: '$$'.
+ // * -1 otherwise.
+ return (*format < '0' || *format > '9') ? (*format == '$' ? 0 : -1)
+ : (1 << (*format - '0'));
}
constexpr const char* SkipNumber(const char* format) {
@@ -197,10 +205,11 @@
}
constexpr int PlaceholderBitmask(const char* format) {
- return !*format ? 0 : *format != '$'
- ? PlaceholderBitmask(format + 1)
- : (CalculateOneBit(format + 1) |
- PlaceholderBitmask(SkipNumber(format + 1)));
+ return !*format
+ ? 0
+ : *format != '$' ? PlaceholderBitmask(format + 1)
+ : (CalculateOneBit(format + 1) |
+ PlaceholderBitmask(SkipNumber(format + 1)));
}
#endif // ABSL_BAD_CALL_IF
@@ -354,13 +363,13 @@
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");
+ "but this format 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 "
+ "this format string is either missing its $0, or "
"contains one of $1-$9");
void SubstituteAndAppend(std::string* output, const char* format,
@@ -368,7 +377,7 @@
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 "
+ "this format string is either missing its $0/$1, or "
"contains one of $2-$9");
void SubstituteAndAppend(std::string* output, const char* format,
@@ -377,7 +386,7 @@
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 "
+ "this format string is either missing its $0/$1/$2, or "
"contains one of $3-$9");
void SubstituteAndAppend(std::string* output, const char* format,
@@ -387,7 +396,7 @@
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 "
+ "this format string is either missing its $0-$3, or "
"contains one of $4-$9");
void SubstituteAndAppend(std::string* output, const char* format,
@@ -398,7 +407,7 @@
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 "
+ "this format string is either missing its $0-$4, or "
"contains one of $5-$9");
void SubstituteAndAppend(std::string* output, const char* format,
@@ -410,7 +419,7 @@
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 "
+ "this format string is either missing its $0-$5, or "
"contains one of $6-$9");
void SubstituteAndAppend(
@@ -420,7 +429,7 @@
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 "
+ "this format string is either missing its $0-$6, or "
"contains one of $7-$9");
void SubstituteAndAppend(
@@ -431,7 +440,7 @@
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 "
+ "this format string is either missing its $0-$7, or "
"contains one of $8-$9");
void SubstituteAndAppend(
@@ -443,7 +452,7 @@
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");
+ "this format string is either missing its $0-$8, or contains a $9");
void SubstituteAndAppend(
std::string* output, const char* format, const substitute_internal::Arg& a0,
@@ -454,7 +463,7 @@
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");
+ "format string doesn't contain all of $0 through $9");
#endif // ABSL_BAD_CALL_IF
// Substitute()
@@ -580,19 +589,19 @@
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");
+ "but this format 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 "
+ "this format 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 "
+ "this format string is either missing its $0/$1, or "
"contains one of $2-$9");
std::string Substitute(const char* format, const substitute_internal::Arg& a0,
@@ -600,7 +609,7 @@
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 "
+ "this format 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,
@@ -609,7 +618,7 @@
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 "
+ "this format string is either missing its $0-$3, or "
"contains one of $4-$9");
std::string Substitute(const char* format, const substitute_internal::Arg& a0,
@@ -619,7 +628,7 @@
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 "
+ "this format string is either missing its $0-$4, or "
"contains one of $5-$9");
std::string Substitute(const char* format, const substitute_internal::Arg& a0,
@@ -630,7 +639,7 @@
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 "
+ "this format string is either missing its $0-$5, or "
"contains one of $6-$9");
std::string Substitute(const char* format, const substitute_internal::Arg& a0,
@@ -642,7 +651,7 @@
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 "
+ "this format string is either missing its $0-$6, or "
"contains one of $7-$9");
std::string Substitute(const char* format, const substitute_internal::Arg& a0,
@@ -655,7 +664,7 @@
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 "
+ "this format string is either missing its $0-$7, or "
"contains one of $8-$9");
std::string Substitute(
@@ -667,7 +676,7 @@
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");
+ "this format string is either missing its $0-$8, or contains a $9");
std::string Substitute(
const char* format, const substitute_internal::Arg& a0,
@@ -678,9 +687,10 @@
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");
+ "format string doesn't contain all of $0 through $9");
#endif // ABSL_BAD_CALL_IF
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_SUBSTITUTE_H_
diff --git a/third_party/abseil/absl/strings/substitute_test.cc b/third_party/abseil/absl/strings/substitute_test.cc
index e27abb1..442c921 100644
--- a/third_party/abseil/absl/strings/substitute_test.cc
+++ b/third_party/abseil/absl/strings/substitute_test.cc
@@ -89,7 +89,7 @@
str = absl::Substitute("$0", char_buf);
EXPECT_EQ("print me too", str);
- // null char* is "doubly" special. Represented as the empty std::string.
+ // null char* is "doubly" special. Represented as the empty string.
char_p = nullptr;
str = absl::Substitute("$0", char_p);
EXPECT_EQ("", str);
@@ -189,14 +189,14 @@
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\", "
+ "Invalid absl::Substitute\\(\\) format 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-\"");
+ static_cast<void>(absl::Substitute(absl::string_view("-$z-"))),
+ "Invalid absl::Substitute\\(\\) format string: \"-\\$z-\"");
EXPECT_DEBUG_DEATH(
- static_cast<void>(absl::Substitute("-$")),
- "Invalid strings::Substitute\\(\\) format std::string: \"-\\$\"");
+ static_cast<void>(absl::Substitute(absl::string_view("-$"))),
+ "Invalid absl::Substitute\\(\\) format string: \"-\\$\"");
}
#endif // GTEST_HAS_DEATH_TEST
diff --git a/third_party/abseil/absl/strings/testdata/getline-1.txt b/third_party/abseil/absl/strings/testdata/getline-1.txt
deleted file mode 100644
index 19b9097..0000000
--- a/third_party/abseil/absl/strings/testdata/getline-1.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-alpha
-
-beta gamma
diff --git a/third_party/abseil/absl/strings/testdata/getline-2.txt b/third_party/abseil/absl/strings/testdata/getline-2.txt
deleted file mode 100644
index d6842d8..0000000
--- a/third_party/abseil/absl/strings/testdata/getline-2.txt
+++ /dev/null
@@ -1 +0,0 @@
-one.two.three
diff --git a/third_party/abseil/absl/synchronization/BUILD.bazel b/third_party/abseil/absl/synchronization/BUILD.bazel
index 6d640ae..cd4009a 100644
--- a/third_party/abseil/absl/synchronization/BUILD.bazel
+++ b/third_party/abseil/absl/synchronization/BUILD.bazel
@@ -14,7 +14,7 @@
# limitations under the License.
#
-#load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
+load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
load(
"//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
@@ -24,7 +24,7 @@
package(default_visibility = ["//visibility:public"])
-licenses(["notice"]) # Apache 2.0
+licenses(["notice"])
# Internal data structure for efficiently detecting mutex dependency cycles
cc_library(
@@ -43,6 +43,7 @@
deps = [
"//absl/base",
"//absl/base:base_internal",
+ "//absl/base:config",
"//absl/base:core_headers",
"//absl/base:malloc_internal",
"//absl/base:raw_logging_internal",
@@ -72,22 +73,25 @@
"internal/create_thread_identity.cc",
"internal/per_thread_sem.cc",
"internal/waiter.cc",
+ "mutex.cc",
"notification.cc",
- ] + select({
- "//conditions:default": ["mutex.cc"],
- }),
+ ],
hdrs = [
"barrier.h",
"blocking_counter.h",
"internal/create_thread_identity.h",
- "internal/mutex_nonprod.inc",
+ "internal/futex.h",
"internal/per_thread_sem.h",
"internal/waiter.h",
"mutex.h",
"notification.h",
],
copts = ABSL_DEFAULT_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
+ linkopts = select({
+ "//absl:windows": [],
+ "//absl:wasm": [],
+ "//conditions:default": ["-pthread"],
+ }) + ABSL_DEFAULT_LINKOPTS,
deps = [
":graphcycles_internal",
":kernel_timeout_internal",
@@ -185,6 +189,7 @@
":synchronization",
":thread_pool",
"//absl/base",
+ "//absl/base:config",
"//absl/base:core_headers",
"//absl/base:raw_logging_internal",
"//absl/memory",
@@ -206,6 +211,7 @@
":synchronization",
":thread_pool",
"//absl/base",
+ "//absl/base:config",
"@com_github_google_benchmark//:benchmark_main",
],
alwayslink = 1,
@@ -244,6 +250,7 @@
deps = [
":synchronization",
"//absl/base",
+ "//absl/base:config",
"//absl/strings",
"//absl/time",
"@com_google_googletest//:gtest",
diff --git a/third_party/abseil/absl/synchronization/CMakeLists.txt b/third_party/abseil/absl/synchronization/CMakeLists.txt
index 3c47a1b..e633d0b 100644
--- a/third_party/abseil/absl/synchronization/CMakeLists.txt
+++ b/third_party/abseil/absl/synchronization/CMakeLists.txt
@@ -26,6 +26,7 @@
DEPS
absl::base
absl::base_internal
+ absl::config
absl::core_headers
absl::malloc_internal
absl::raw_logging_internal
@@ -51,7 +52,7 @@
"barrier.h"
"blocking_counter.h"
"internal/create_thread_identity.h"
- "internal/mutex_nonprod.inc"
+ "internal/futex.h"
"internal/per_thread_sem.h"
"internal/waiter.h"
"mutex.h"
@@ -148,6 +149,7 @@
absl::synchronization
absl::thread_pool
absl::base
+ absl::config
absl::core_headers
absl::memory
absl::raw_logging_internal
@@ -178,6 +180,7 @@
DEPS
absl::synchronization
absl::base
+ absl::config
absl::strings
absl::time
gmock
diff --git a/third_party/abseil/absl/synchronization/barrier.cc b/third_party/abseil/absl/synchronization/barrier.cc
index c2c539a..0dfd795 100644
--- a/third_party/abseil/absl/synchronization/barrier.cc
+++ b/third_party/abseil/absl/synchronization/barrier.cc
@@ -18,6 +18,7 @@
#include "absl/synchronization/mutex.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// Return whether int *arg is zero.
static bool IsZero(void *arg) {
@@ -47,4 +48,5 @@
return this->num_to_exit_ == 0;
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/synchronization/barrier.h b/third_party/abseil/absl/synchronization/barrier.h
index cb5d821..d8e7544 100644
--- a/third_party/abseil/absl/synchronization/barrier.h
+++ b/third_party/abseil/absl/synchronization/barrier.h
@@ -23,6 +23,7 @@
#include "absl/synchronization/mutex.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// Barrier
//
@@ -73,5 +74,6 @@
int num_to_exit_ ABSL_GUARDED_BY(lock_);
};
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_SYNCHRONIZATION_BARRIER_H_
diff --git a/third_party/abseil/absl/synchronization/blocking_counter.cc b/third_party/abseil/absl/synchronization/blocking_counter.cc
index 481a06b..3cea7ae 100644
--- a/third_party/abseil/absl/synchronization/blocking_counter.cc
+++ b/third_party/abseil/absl/synchronization/blocking_counter.cc
@@ -17,6 +17,7 @@
#include "absl/base/internal/raw_logging.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// Return whether int *arg is zero.
static bool IsZero(void *arg) {
@@ -52,4 +53,5 @@
// after we return from this method.
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/synchronization/blocking_counter.h b/third_party/abseil/absl/synchronization/blocking_counter.h
index 77560fc..1f53f9f 100644
--- a/third_party/abseil/absl/synchronization/blocking_counter.h
+++ b/third_party/abseil/absl/synchronization/blocking_counter.h
@@ -24,6 +24,7 @@
#include "absl/synchronization/mutex.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// BlockingCounter
//
@@ -92,6 +93,7 @@
int num_waiting_ ABSL_GUARDED_BY(lock_);
};
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_
diff --git a/third_party/abseil/absl/synchronization/blocking_counter_test.cc b/third_party/abseil/absl/synchronization/blocking_counter_test.cc
index c63e339..2926224 100644
--- a/third_party/abseil/absl/synchronization/blocking_counter_test.cc
+++ b/third_party/abseil/absl/synchronization/blocking_counter_test.cc
@@ -22,6 +22,7 @@
#include "absl/time/time.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
void PauseAndDecreaseCounter(BlockingCounter* counter, int* done) {
@@ -63,4 +64,5 @@
}
} // namespace
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/synchronization/internal/create_thread_identity.cc b/third_party/abseil/absl/synchronization/internal/create_thread_identity.cc
index ce3676a..53a71b3 100644
--- a/third_party/abseil/absl/synchronization/internal/create_thread_identity.cc
+++ b/third_party/abseil/absl/synchronization/internal/create_thread_identity.cc
@@ -27,17 +27,18 @@
#include "absl/synchronization/internal/per_thread_sem.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
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;
+ABSL_CONST_INIT static base_internal::SpinLock freelist_lock(
+ absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
+ABSL_CONST_INIT 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) {
+void ReclaimThreadIdentity(void* v) {
base_internal::ThreadIdentity* identity =
static_cast<base_internal::ThreadIdentity*>(v);
@@ -47,6 +48,8 @@
base_internal::LowLevelAlloc::Free(identity->per_thread_synch.all_locks);
}
+ PerThreadSem::Destroy(identity);
+
// 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
@@ -84,7 +87,6 @@
pts->wake = false;
pts->cond_waiter = false;
pts->all_locks = nullptr;
- identity->waiter_state = {};
identity->blocked_count_ptr = nullptr;
identity->ticker.store(0, std::memory_order_relaxed);
identity->wait_start.store(0, std::memory_order_relaxed);
@@ -132,6 +134,7 @@
}
} // namespace synchronization_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_LOW_LEVEL_ALLOC_MISSING
diff --git a/third_party/abseil/absl/synchronization/internal/create_thread_identity.h b/third_party/abseil/absl/synchronization/internal/create_thread_identity.h
index ebb16c5..e121f68 100644
--- a/third_party/abseil/absl/synchronization/internal/create_thread_identity.h
+++ b/third_party/abseil/absl/synchronization/internal/create_thread_identity.h
@@ -29,12 +29,17 @@
#include "absl/base/port.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace synchronization_internal {
// Allocates and attaches a ThreadIdentity object for the calling thread.
// For private use only.
base_internal::ThreadIdentity* CreateThreadIdentity();
+// A per-thread destructor for reclaiming associated ThreadIdentity objects.
+// For private use only.
+void ReclaimThreadIdentity(void* v);
+
// 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.
@@ -49,6 +54,7 @@
}
} // namespace synchronization_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_SYNCHRONIZATION_INTERNAL_CREATE_THREAD_IDENTITY_H_
diff --git a/third_party/abseil/absl/synchronization/internal/futex.h b/third_party/abseil/absl/synchronization/internal/futex.h
new file mode 100644
index 0000000..06fbd6d
--- /dev/null
+++ b/third_party/abseil/absl/synchronization/internal/futex.h
@@ -0,0 +1,154 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_
+
+#include "absl/base/config.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+#ifdef __linux__
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <atomic>
+#include <cstdint>
+
+#include "absl/base/optimization.h"
+#include "absl/synchronization/internal/kernel_timeout.h"
+
+#ifdef ABSL_INTERNAL_HAVE_FUTEX
+#error ABSL_INTERNAL_HAVE_FUTEX may not be set on the command line
+#elif defined(__BIONIC__)
+// Bionic supports all the futex operations we need even when some of the futex
+// definitions are missing.
+#define ABSL_INTERNAL_HAVE_FUTEX
+#elif defined(__linux__) && defined(FUTEX_CLOCK_REALTIME)
+// FUTEX_CLOCK_REALTIME requires Linux >= 2.6.28.
+#define ABSL_INTERNAL_HAVE_FUTEX
+#endif
+
+#ifdef ABSL_INTERNAL_HAVE_FUTEX
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace synchronization_internal {
+
+// 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
+
+#if defined(__NR_futex_time64) && !defined(SYS_futex_time64)
+#define SYS_futex_time64 __NR_futex_time64
+#endif
+
+#if defined(SYS_futex_time64) && !defined(SYS_futex)
+#define SYS_futex SYS_futex_time64
+#endif
+
+class FutexImpl {
+ public:
+ static int WaitUntil(std::atomic<int32_t> *v, int32_t val,
+ KernelTimeout t) {
+ 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<int32_t *>(v),
+ FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, val,
+ &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<int32_t *>(v),
+ FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, nullptr);
+ }
+ if (ABSL_PREDICT_FALSE(err != 0)) {
+ err = -errno;
+ }
+ return err;
+ }
+
+ static int WaitBitsetAbsoluteTimeout(std::atomic<int32_t> *v, int32_t val,
+ int32_t bits,
+ const struct timespec *abstime) {
+ int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+ FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG, val, abstime,
+ nullptr, bits);
+ if (ABSL_PREDICT_FALSE(err != 0)) {
+ err = -errno;
+ }
+ return err;
+ }
+
+ static int Wake(std::atomic<int32_t> *v, int32_t count) {
+ int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+ FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count);
+ if (ABSL_PREDICT_FALSE(err < 0)) {
+ err = -errno;
+ }
+ return err;
+ }
+
+ // FUTEX_WAKE_BITSET
+ static int WakeBitset(std::atomic<int32_t> *v, int32_t count, int32_t bits) {
+ int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+ FUTEX_WAKE_BITSET | FUTEX_PRIVATE_FLAG, count, nullptr,
+ nullptr, bits);
+ if (ABSL_PREDICT_FALSE(err < 0)) {
+ err = -errno;
+ }
+ return err;
+ }
+};
+
+class Futex : public FutexImpl {};
+
+} // namespace synchronization_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_INTERNAL_HAVE_FUTEX
+
+#endif // ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_
diff --git a/third_party/abseil/absl/synchronization/internal/graphcycles.cc b/third_party/abseil/absl/synchronization/internal/graphcycles.cc
index 0c8c756..27fec21 100644
--- a/third_party/abseil/absl/synchronization/internal/graphcycles.cc
+++ b/third_party/abseil/absl/synchronization/internal/graphcycles.cc
@@ -37,6 +37,7 @@
#include <algorithm>
#include <array>
+#include <limits>
#include "absl/base/internal/hide_ptr.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/spinlock.h"
@@ -44,15 +45,16 @@
// Do not use STL. This module does not use standard memory allocation.
namespace absl {
+ABSL_NAMESPACE_BEGIN
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;
+ABSL_CONST_INIT static absl::base_internal::SpinLock arena_mu(
+ absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
+ABSL_CONST_INIT static base_internal::LowLevelAlloc::Arena* arena;
static void InitArenaIfNecessary() {
arena_mu.Lock();
@@ -690,6 +692,7 @@
}
} // namespace synchronization_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_LOW_LEVEL_ALLOC_MISSING
diff --git a/third_party/abseil/absl/synchronization/internal/graphcycles.h b/third_party/abseil/absl/synchronization/internal/graphcycles.h
index e5bde00..ceba33e 100644
--- a/third_party/abseil/absl/synchronization/internal/graphcycles.h
+++ b/third_party/abseil/absl/synchronization/internal/graphcycles.h
@@ -36,11 +36,14 @@
// 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.
+// The current implementation uses O(|V|+|E|) space.
#include <cstdint>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace synchronization_internal {
// Opaque identifier for a graph node.
@@ -132,6 +135,7 @@
};
} // namespace synchronization_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif
diff --git a/third_party/abseil/absl/synchronization/internal/graphcycles_test.cc b/third_party/abseil/absl/synchronization/internal/graphcycles_test.cc
index 58e8477..74eaffe 100644
--- a/third_party/abseil/absl/synchronization/internal/graphcycles_test.cc
+++ b/third_party/abseil/absl/synchronization/internal/graphcycles_test.cc
@@ -25,6 +25,7 @@
#include "absl/base/macros.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace synchronization_internal {
// We emulate a GraphCycles object with a node vector and an edge vector.
@@ -459,4 +460,5 @@
}
} // namespace synchronization_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/synchronization/internal/kernel_timeout.h b/third_party/abseil/absl/synchronization/internal/kernel_timeout.h
index 61c72e7..bbd4d2d 100644
--- a/third_party/abseil/absl/synchronization/internal/kernel_timeout.h
+++ b/third_party/abseil/absl/synchronization/internal/kernel_timeout.h
@@ -26,6 +26,7 @@
#define ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
#include <time.h>
+
#include <algorithm>
#include <limits>
@@ -34,6 +35,7 @@
#include "absl/time/time.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace synchronization_internal {
class Futex;
@@ -56,6 +58,10 @@
bool has_timeout() const { return ns_ != 0; }
+ // Convert to parameter for sem_timedwait/futex/similar. Only for approved
+ // users. Do not call if !has_timeout.
+ struct timespec MakeAbsTimespec();
+
private:
// internal rep, not user visible: ns after unix epoch.
// zero = no timeout.
@@ -81,34 +87,6 @@
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
@@ -147,7 +125,32 @@
friend class Waiter;
};
+inline struct timespec KernelTimeout::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;
+}
+
} // namespace synchronization_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
diff --git a/third_party/abseil/absl/synchronization/internal/mutex_nonprod.cc b/third_party/abseil/absl/synchronization/internal/mutex_nonprod.cc
deleted file mode 100644
index 267deaf..0000000
--- a/third_party/abseil/absl/synchronization/internal/mutex_nonprod.cc
+++ /dev/null
@@ -1,318 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// 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));
-}
-
-void Mutex::ReaderLockWhen(const Condition& cond) {
- ReaderLock();
- Await(cond);
-}
-
-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);
-}
-
-void RegisterSymbolizer(bool (*)(const void*, char*, int)) {}
-
-} // namespace absl
diff --git a/third_party/abseil/absl/synchronization/internal/mutex_nonprod.inc b/third_party/abseil/absl/synchronization/internal/mutex_nonprod.inc
deleted file mode 100644
index b8d5af7..0000000
--- a/third_party/abseil/absl/synchronization/internal/mutex_nonprod.inc
+++ /dev/null
@@ -1,259 +0,0 @@
-// 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 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 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 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 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, 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 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 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
-// 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 LinkerInitialized constructor is a NOP, and immaterial to
-// even to concurrent calls to get().
-//
-// c) the destructor being a NOP for 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_internal::LinkerInitialized) {}
-
- constexpr explicit SynchronizationStorage(absl::ConstInitType)
- : is_dynamic_(false), once_(), space_{{0}} {}
-
- 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
- // 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 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/third_party/abseil/absl/synchronization/internal/per_thread_sem.cc b/third_party/abseil/absl/synchronization/internal/per_thread_sem.cc
index b7014fb..821ca9b 100644
--- a/third_party/abseil/absl/synchronization/internal/per_thread_sem.cc
+++ b/third_party/abseil/absl/synchronization/internal/per_thread_sem.cc
@@ -25,6 +25,7 @@
#include "absl/synchronization/internal/waiter.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace synchronization_internal {
void PerThreadSem::SetThreadBlockedCounter(std::atomic<int> *counter) {
@@ -40,12 +41,16 @@
}
void PerThreadSem::Init(base_internal::ThreadIdentity *identity) {
- Waiter::GetWaiter(identity)->Init();
+ new (Waiter::GetWaiter(identity)) Waiter();
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::Destroy(base_internal::ThreadIdentity *identity) {
+ Waiter::GetWaiter(identity)->~Waiter();
+}
+
void PerThreadSem::Tick(base_internal::ThreadIdentity *identity) {
const int ticker =
identity->ticker.fetch_add(1, std::memory_order_relaxed) + 1;
@@ -58,6 +63,7 @@
}
} // namespace synchronization_internal
+ABSL_NAMESPACE_END
} // namespace absl
extern "C" {
diff --git a/third_party/abseil/absl/synchronization/internal/per_thread_sem.h b/third_party/abseil/absl/synchronization/internal/per_thread_sem.h
index e7da070..2228b6e 100644
--- a/third_party/abseil/absl/synchronization/internal/per_thread_sem.h
+++ b/third_party/abseil/absl/synchronization/internal/per_thread_sem.h
@@ -32,6 +32,7 @@
#include "absl/synchronization/internal/kernel_timeout.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
class Mutex;
@@ -65,6 +66,10 @@
// REQUIRES: May only be called by ThreadIdentity.
static void Init(base_internal::ThreadIdentity* identity);
+ // Destroy the PerThreadSem associated with "identity".
+ // REQUIRES: May only be called by ThreadIdentity.
+ static void Destroy(base_internal::ThreadIdentity* identity);
+
// Increments "identity"'s count.
static inline void Post(base_internal::ThreadIdentity* identity);
@@ -73,13 +78,15 @@
// !t.has_timeout() => Wait(t) will return true.
static inline bool Wait(KernelTimeout t);
- // White-listed callers.
+ // Permitted callers.
friend class PerThreadSemTest;
friend class absl::Mutex;
friend absl::base_internal::ThreadIdentity* CreateThreadIdentity();
+ friend void ReclaimThreadIdentity(void* v);
};
} // namespace synchronization_internal
+ABSL_NAMESPACE_END
} // namespace absl
// In some build configurations we pass --detect-odr-violations to the
diff --git a/third_party/abseil/absl/synchronization/internal/per_thread_sem_test.cc b/third_party/abseil/absl/synchronization/internal/per_thread_sem_test.cc
index dba7239..8cf59e6 100644
--- a/third_party/abseil/absl/synchronization/internal/per_thread_sem_test.cc
+++ b/third_party/abseil/absl/synchronization/internal/per_thread_sem_test.cc
@@ -23,6 +23,7 @@
#include <thread> // NOLINT(build/c++11)
#include "gtest/gtest.h"
+#include "absl/base/config.h"
#include "absl/base/internal/cycleclock.h"
#include "absl/base/internal/thread_identity.h"
#include "absl/strings/str_cat.h"
@@ -33,6 +34,7 @@
// primitives which might use PerThreadSem, most notably absl::Mutex.
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace synchronization_internal {
class SimpleSemaphore {
@@ -175,4 +177,5 @@
} // namespace
} // namespace synchronization_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/synchronization/internal/thread_pool.h b/third_party/abseil/absl/synchronization/internal/thread_pool.h
index a00f2be..0cb96da 100644
--- a/third_party/abseil/absl/synchronization/internal/thread_pool.h
+++ b/third_party/abseil/absl/synchronization/internal/thread_pool.h
@@ -26,6 +26,7 @@
#include "absl/synchronization/mutex.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace synchronization_internal {
// A simple ThreadPool implementation for tests.
@@ -86,6 +87,7 @@
};
} // namespace synchronization_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_SYNCHRONIZATION_INTERNAL_THREAD_POOL_H_
diff --git a/third_party/abseil/absl/synchronization/internal/waiter.cc b/third_party/abseil/absl/synchronization/internal/waiter.cc
index f17ea56..2123be6 100644
--- a/third_party/abseil/absl/synchronization/internal/waiter.cc
+++ b/third_party/abseil/absl/synchronization/internal/waiter.cc
@@ -48,7 +48,9 @@
#include "absl/base/optimization.h"
#include "absl/synchronization/internal/kernel_timeout.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace synchronization_internal {
static void MaybeBecomeIdle() {
@@ -65,73 +67,21 @@
#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
-
-class Futex {
- public:
- static int WaitUntil(std::atomic<int32_t> *v, int32_t val,
- KernelTimeout t) {
- 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<int32_t *>(v),
- FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, val,
- &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<int32_t *>(v),
- FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, nullptr);
- }
- if (err != 0) {
- err = -errno;
- }
- return err;
- }
-
- static int Wake(std::atomic<int32_t> *v, int32_t count) {
- int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
- FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count);
- if (ABSL_PREDICT_FALSE(err < 0)) {
- err = -errno;
- }
- return err;
- }
-};
-
-void Waiter::Init() {
+Waiter::Waiter() {
futex_.store(0, std::memory_order_relaxed);
}
+Waiter::~Waiter() = default;
+
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.
+ // Note that, since the thread ticker is just reset, we don't need to check
+ // whether the thread is idle on the very first pass of the loop.
+ bool first_pass = true;
while (true) {
int32_t x = futex_.load(std::memory_order_relaxed);
- if (x != 0) {
+ while (x != 0) {
if (!futex_.compare_exchange_weak(x, x - 1,
std::memory_order_acquire,
std::memory_order_relaxed)) {
@@ -140,6 +90,8 @@
return true; // Consumed a wakeup, we are done.
}
+
+ if (!first_pass) MaybeBecomeIdle();
const int err = Futex::WaitUntil(&futex_, 0, t);
if (err != 0) {
if (err == -EINTR || err == -EWOULDBLOCK) {
@@ -150,14 +102,13 @@
ABSL_RAW_LOG(FATAL, "Futex operation failed with error %d\n", err);
}
}
-
- MaybeBecomeIdle();
+ first_pass = false;
}
}
void Waiter::Post() {
if (futex_.fetch_add(1, std::memory_order_release) == 0) {
- // We incremented from 0, need to wake a potential waker.
+ // We incremented from 0, need to wake a potential waiter.
Poke();
}
}
@@ -195,7 +146,7 @@
pthread_mutex_t *mu_;
};
-void Waiter::Init() {
+Waiter::Waiter() {
const int err = pthread_mutex_init(&mu_, 0);
if (err != 0) {
ABSL_RAW_LOG(FATAL, "pthread_mutex_init failed: %d", err);
@@ -206,8 +157,20 @@
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);
+ waiter_count_ = 0;
+ wakeup_count_ = 0;
+}
+
+Waiter::~Waiter() {
+ const int err = pthread_mutex_destroy(&mu_);
+ if (err != 0) {
+ ABSL_RAW_LOG(FATAL, "pthread_mutex_destroy failed: %d", err);
+ }
+
+ const int err2 = pthread_cond_destroy(&cv_);
+ if (err2 != 0) {
+ ABSL_RAW_LOG(FATAL, "pthread_cond_destroy failed: %d", err2);
+ }
}
bool Waiter::Wait(KernelTimeout t) {
@@ -217,21 +180,13 @@
}
PthreadMutexHolder h(&mu_);
- waiter_count_.fetch_add(1, std::memory_order_relaxed);
+ ++waiter_count_;
// 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;
- }
-
+ // Note that, since the thread ticker is just reset, we don't need to check
+ // whether the thread is idle on the very first pass of the loop.
+ bool first_pass = true;
+ while (wakeup_count_ == 0) {
+ if (!first_pass) MaybeBecomeIdle();
// No wakeups available, time to wait.
if (!t.has_timeout()) {
const int err = pthread_cond_wait(&cv_, &mu_);
@@ -241,46 +196,56 @@
} else {
const int err = pthread_cond_timedwait(&cv_, &mu_, &abs_timeout);
if (err == ETIMEDOUT) {
- waiter_count_.fetch_sub(1, std::memory_order_relaxed);
+ --waiter_count_;
return false;
}
if (err != 0) {
- ABSL_RAW_LOG(FATAL, "pthread_cond_wait failed: %d", err);
+ ABSL_RAW_LOG(FATAL, "pthread_cond_timedwait failed: %d", err);
}
}
- MaybeBecomeIdle();
+ first_pass = false;
}
+ // Consume a wakeup and we're done.
+ --wakeup_count_;
+ --waiter_count_;
+ return true;
}
void Waiter::Post() {
- wakeup_count_.fetch_add(1, std::memory_order_release);
- Poke();
+ PthreadMutexHolder h(&mu_);
+ ++wakeup_count_;
+ InternalCondVarPoke();
}
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);
+ InternalCondVarPoke();
+}
+
+void Waiter::InternalCondVarPoke() {
+ if (waiter_count_ != 0) {
+ const int err = pthread_cond_signal(&cv_);
+ if (ABSL_PREDICT_FALSE(err != 0)) {
+ ABSL_RAW_LOG(FATAL, "pthread_cond_signal failed: %d", err);
+ }
}
}
#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_SEM
-void Waiter::Init() {
+Waiter::Waiter() {
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);
}
+Waiter::~Waiter() {
+ if (sem_destroy(&sem_) != 0) {
+ ABSL_RAW_LOG(FATAL, "sem_destroy failed with errno %d\n", errno);
+ }
+}
+
bool Waiter::Wait(KernelTimeout t) {
struct timespec abs_timeout;
if (t.has_timeout()) {
@@ -288,9 +253,12 @@
}
// Loop until we timeout or consume a wakeup.
+ // Note that, since the thread ticker is just reset, we don't need to check
+ // whether the thread is idle on the very first pass of the loop.
+ bool first_pass = true;
while (true) {
int x = wakeups_.load(std::memory_order_relaxed);
- if (x != 0) {
+ while (x != 0) {
if (!wakeups_.compare_exchange_weak(x, x - 1,
std::memory_order_acquire,
std::memory_order_relaxed)) {
@@ -300,6 +268,7 @@
return true;
}
+ if (!first_pass) MaybeBecomeIdle();
// Nothing to consume, wait (looping on EINTR).
while (true) {
if (!t.has_timeout()) {
@@ -313,13 +282,16 @@
ABSL_RAW_LOG(FATAL, "sem_timedwait failed: %d", errno);
}
}
- MaybeBecomeIdle();
+ first_pass = false;
}
}
void Waiter::Post() {
- wakeups_.fetch_add(1, std::memory_order_release); // Post a wakeup.
- Poke();
+ // Post a wakeup.
+ if (wakeups_.fetch_add(1, std::memory_order_release) == 0) {
+ // We incremented from 0, need to wake a potential waiter.
+ Poke();
+ }
}
void Waiter::Poke() {
@@ -340,31 +312,29 @@
return reinterpret_cast<CONDITION_VARIABLE *>(&w->cv_storage_);
}
- static_assert(sizeof(SRWLOCK) == sizeof(Waiter::SRWLockStorage),
- "SRWLockStorage does not have the same size as SRWLOCK");
+ static_assert(sizeof(SRWLOCK) == sizeof(void *),
+ "`mu_storage_` does not have the same size as SRWLOCK");
+ static_assert(alignof(SRWLOCK) == alignof(void *),
+ "`mu_storage_` does not have the same alignment as SRWLOCK");
+
+ static_assert(sizeof(CONDITION_VARIABLE) == sizeof(void *),
+ "`ABSL_CONDITION_VARIABLE_STORAGE` does not have the same size "
+ "as `CONDITION_VARIABLE`");
static_assert(
- alignof(SRWLOCK) == alignof(Waiter::SRWLockStorage),
- "SRWLockStorage does not have the same alignment as SRWLOCK");
+ alignof(CONDITION_VARIABLE) == alignof(void *),
+ "`cv_storage_` does not have the same alignment as `CONDITION_VARIABLE`");
- static_assert(sizeof(CONDITION_VARIABLE) ==
- sizeof(Waiter::ConditionVariableStorage),
- "ABSL_CONDITION_VARIABLE_STORAGE does not have the same size "
- "as CONDITION_VARIABLE");
- static_assert(alignof(CONDITION_VARIABLE) ==
- alignof(Waiter::ConditionVariableStorage),
- "ConditionVariableStorage does not have the same "
- "alignment as CONDITION_VARIABLE");
-
- // The SRWLOCK and CONDITION_VARIABLE types must be trivially constuctible
+ // The SRWLOCK and CONDITION_VARIABLE types must be trivially constructible
// and destructible because we never call their constructors or destructors.
static_assert(std::is_trivially_constructible<SRWLOCK>::value,
- "The SRWLOCK type must be trivially constructible");
- static_assert(std::is_trivially_constructible<CONDITION_VARIABLE>::value,
- "The CONDITION_VARIABLE type must be trivially constructible");
+ "The `SRWLOCK` type must be trivially constructible");
+ static_assert(
+ std::is_trivially_constructible<CONDITION_VARIABLE>::value,
+ "The `CONDITION_VARIABLE` type must be trivially constructible");
static_assert(std::is_trivially_destructible<SRWLOCK>::value,
- "The SRWLOCK type must be trivially destructible");
+ "The `SRWLOCK` type must be trivially destructible");
static_assert(std::is_trivially_destructible<CONDITION_VARIABLE>::value,
- "The CONDITION_VARIABLE type must be trivially destructible");
+ "The `CONDITION_VARIABLE` type must be trivially destructible");
};
class LockHolder {
@@ -384,36 +354,33 @@
SRWLOCK* mu_;
};
-void Waiter::Init() {
+Waiter::Waiter() {
auto *mu = ::new (static_cast<void *>(&mu_storage_)) SRWLOCK;
auto *cv = ::new (static_cast<void *>(&cv_storage_)) CONDITION_VARIABLE;
InitializeSRWLock(mu);
InitializeConditionVariable(cv);
- waiter_count_.store(0, std::memory_order_relaxed);
- wakeup_count_.store(0, std::memory_order_relaxed);
+ waiter_count_ = 0;
+ wakeup_count_ = 0;
}
+// SRW locks and condition variables do not need to be explicitly destroyed.
+// https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-initializesrwlock
+// https://stackoverflow.com/questions/28975958/why-does-windows-have-no-deleteconditionvariable-function-to-go-together-with
+Waiter::~Waiter() = default;
+
bool Waiter::Wait(KernelTimeout t) {
SRWLOCK *mu = WinHelper::GetLock(this);
CONDITION_VARIABLE *cv = WinHelper::GetCond(this);
LockHolder h(mu);
- waiter_count_.fetch_add(1, std::memory_order_relaxed);
+ ++waiter_count_;
// 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;
- }
-
+ // Note that, since the thread ticker is just reset, we don't need to check
+ // whether the thread is idle on the very first pass of the loop.
+ bool first_pass = true;
+ while (wakeup_count_ == 0) {
+ if (!first_pass) MaybeBecomeIdle();
// No wakeups available, time to wait.
if (!SleepConditionVariableSRW(cv, mu, t.InMillisecondsFromNow(), 0)) {
// GetLastError() returns a Win32 DWORD, but we assign to
@@ -421,32 +388,35 @@
// 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);
+ --waiter_count_;
return false;
} else {
ABSL_RAW_LOG(FATAL, "SleepConditionVariableSRW failed: %lu", err);
}
}
-
- MaybeBecomeIdle();
+ first_pass = false;
}
+ // Consume a wakeup and we're done.
+ --wakeup_count_;
+ --waiter_count_;
+ return true;
}
void Waiter::Post() {
- wakeup_count_.fetch_add(1, std::memory_order_release);
- Poke();
+ LockHolder h(WinHelper::GetLock(this));
+ ++wakeup_count_;
+ InternalCondVarPoke();
}
void Waiter::Poke() {
- if (waiter_count_.load(std::memory_order_relaxed) == 0) {
- return;
- }
- // Potentially a waker. Take the lock and check again.
LockHolder h(WinHelper::GetLock(this));
- if (waiter_count_.load(std::memory_order_relaxed) == 0) {
- return;
+ InternalCondVarPoke();
+}
+
+void Waiter::InternalCondVarPoke() {
+ if (waiter_count_ != 0) {
+ WakeConditionVariable(WinHelper::GetCond(this));
}
- WakeConditionVariable(WinHelper::GetCond(this));
}
#else
@@ -454,4 +424,5 @@
#endif
} // namespace synchronization_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/synchronization/internal/waiter.h b/third_party/abseil/absl/synchronization/internal/waiter.h
index a3e3124..be3df18 100644
--- a/third_party/abseil/absl/synchronization/internal/waiter.h
+++ b/third_party/abseil/absl/synchronization/internal/waiter.h
@@ -18,10 +18,16 @@
#include "absl/base/config.h"
-#ifndef _WIN32
+#ifdef _WIN32
+#include <sdkddkver.h>
+#else
#include <pthread.h>
#endif
+#ifdef __linux__
+#include <linux/futex.h>
+#endif
+
#ifdef ABSL_HAVE_SEMAPHORE_H
#include <semaphore.h>
#endif
@@ -30,6 +36,7 @@
#include <cstdint>
#include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/futex.h"
#include "absl/synchronization/internal/kernel_timeout.h"
// May be chosen at compile time via -DABSL_FORCE_WAITER_MODE=<index>
@@ -40,9 +47,9 @@
#if defined(ABSL_FORCE_WAITER_MODE)
#define ABSL_WAITER_MODE ABSL_FORCE_WAITER_MODE
-#elif defined(_WIN32)
+#elif defined(_WIN32) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
#define ABSL_WAITER_MODE ABSL_WAITER_MODE_WIN32
-#elif defined(__linux__)
+#elif defined(ABSL_INTERNAL_HAVE_FUTEX)
#define ABSL_WAITER_MODE ABSL_WAITER_MODE_FUTEX
#elif defined(ABSL_HAVE_SEMAPHORE_H)
#define ABSL_WAITER_MODE ABSL_WAITER_MODE_SEM
@@ -51,19 +58,21 @@
#endif
namespace absl {
+ABSL_NAMESPACE_BEGIN
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;
+ // Prepare any data to track waits.
+ Waiter();
+
+ // Not copyable or movable
Waiter(const Waiter&) = delete;
Waiter& operator=(const Waiter&) = delete;
- // Prepare any data to track waits.
- void Init();
+ // Destroy any data to track waits.
+ ~Waiter();
// Blocks the calling thread until a matching call to `Post()` or
// `t` has passed. Returns `true` if woken (`Post()` called),
@@ -87,8 +96,8 @@
}
// How many periods to remain idle before releasing resources
-#ifndef THREAD_SANITIZER
- static const int kIdlePeriods = 60;
+#ifndef ABSL_HAVE_THREAD_SANITIZER
+ static constexpr 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
@@ -104,10 +113,13 @@
static_assert(sizeof(int32_t) == sizeof(futex_), "Wrong size for futex");
#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_CONDVAR
+ // REQUIRES: mu_ must be held.
+ void InternalCondVarPoke();
+
pthread_mutex_t mu_;
pthread_cond_t cv_;
- std::atomic<int> waiter_count_;
- std::atomic<int> wakeup_count_; // Unclaimed wakeups, written under lock.
+ int waiter_count_;
+ int wakeup_count_; // Unclaimed wakeups.
#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_SEM
sem_t sem_;
@@ -117,26 +129,19 @@
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.
- //
- // However, we can't include Windows.h in our headers, so we use aligned
- // storage buffers to define the storage.
- using SRWLockStorage =
- typename std::aligned_storage<sizeof(void*), alignof(void*)>::type;
- using ConditionVariableStorage =
- typename std::aligned_storage<sizeof(void*), alignof(void*)>::type;
-
// WinHelper - Used to define utilities for accessing the lock and
// condition variable storage once the types are complete.
class WinHelper;
- SRWLockStorage mu_storage_;
- ConditionVariableStorage cv_storage_;
- std::atomic<int> waiter_count_;
- std::atomic<int> wakeup_count_;
+ // REQUIRES: WinHelper::GetLock(this) must be held.
+ void InternalCondVarPoke();
+
+ // We can't include Windows.h in our headers, so we use aligned charachter
+ // buffers to define the storage of SRWLOCK and CONDITION_VARIABLE.
+ alignas(void*) unsigned char mu_storage_[sizeof(void*)];
+ alignas(void*) unsigned char cv_storage_[sizeof(void*)];
+ int waiter_count_;
+ int wakeup_count_;
#else
#error Unknown ABSL_WAITER_MODE
@@ -144,6 +149,7 @@
};
} // namespace synchronization_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_SYNCHRONIZATION_INTERNAL_WAITER_H_
diff --git a/third_party/abseil/absl/synchronization/lifetime_test.cc b/third_party/abseil/absl/synchronization/lifetime_test.cc
index 34b8875..cc973a3 100644
--- a/third_party/abseil/absl/synchronization/lifetime_test.cc
+++ b/third_party/abseil/absl/synchronization/lifetime_test.cc
@@ -122,6 +122,11 @@
Function fn_;
};
+// These tests require that the compiler correctly supports C++11 constant
+// initialization... but MSVC has a known regression since v19.10:
+// https://developercommunity.visualstudio.com/content/problem/336946/class-with-constexpr-constructor-not-using-static.html
+// TODO(epastor): Limit the affected range once MSVC fixes this bug.
+#if defined(__clang__) || !(defined(_MSC_VER) && _MSC_VER > 1900)
// kConstInit
// Test early usage. (Declaration comes first; definitions must appear after
// the test runner.)
@@ -151,6 +156,7 @@
const_init_sanity_mutex.AssertHeld();
const_init_sanity_mutex.Unlock();
});
+#endif // defined(__clang__) || !(defined(_MSC_VER) && _MSC_VER > 1900)
// Test shutdown usage. (Declarations come first; definitions must appear after
// the test runner.)
diff --git a/third_party/abseil/absl/synchronization/mutex.cc b/third_party/abseil/absl/synchronization/mutex.cc
index 100def2..9e01393 100644
--- a/third_party/abseil/absl/synchronization/mutex.cc
+++ b/third_party/abseil/absl/synchronization/mutex.cc
@@ -39,6 +39,7 @@
#include <thread> // NOLINT(build/c++11)
#include "absl/base/attributes.h"
+#include "absl/base/call_once.h"
#include "absl/base/config.h"
#include "absl/base/dynamic_annotations.h"
#include "absl/base/internal/atomic_hook.h"
@@ -49,6 +50,7 @@
#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/debugging/symbolize.h"
@@ -58,6 +60,7 @@
using absl::base_internal::CurrentThreadIdentityIfPresent;
using absl::base_internal::PerThreadSynch;
+using absl::base_internal::SchedulingGuard;
using absl::base_internal::ThreadIdentity;
using absl::synchronization_internal::GetOrCreateCurrentThreadIdentity;
using absl::synchronization_internal::GraphCycles;
@@ -71,10 +74,11 @@
} // extern "C"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
-#if defined(THREAD_SANITIZER)
+#if defined(ABSL_HAVE_THREAD_SANITIZER)
constexpr OnDeadlockCycle kDeadlockDetectionDefault = OnDeadlockCycle::kIgnore;
#else
constexpr OnDeadlockCycle kDeadlockDetectionDefault = OnDeadlockCycle::kAbort;
@@ -84,35 +88,16 @@
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)>
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
+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<
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES absl::base_internal::AtomicHook<void (*)(
+ const char *msg, const void *obj, int64_t wait_cycles)>
+ mutex_tracer;
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
+ absl::base_internal::AtomicHook<void (*)(const char *msg, const void *cv)>
+ cond_var_tracer;
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES absl::base_internal::AtomicHook<
bool (*)(const void *pc, char *out, int out_size)>
symbolizer(absl::Symbolize);
@@ -139,33 +124,55 @@
symbolizer.Store(fn);
}
-// spinlock delay on iteration c. Returns new c.
+struct ABSL_CACHELINE_ALIGNED MutexGlobals {
+ absl::once_flag once;
+ int num_cpus = 0;
+ int spinloop_iterations = 0;
+};
+
+static const MutexGlobals& GetMutexGlobals() {
+ ABSL_CONST_INIT static MutexGlobals data;
+ absl::base_internal::LowLevelCallOnce(&data.once, [&]() {
+ data.num_cpus = absl::base_internal::NumCPUs();
+ data.spinloop_iterations = data.num_cpus > 1 ? 1500 : 0;
+ });
+ return data;
+}
+
+// Spinlock delay on iteration c. Returns new c.
namespace {
enum DelayMode { AGGRESSIVE, GENTLE };
};
-static int Delay(int32_t c, DelayMode mode) {
+
+namespace synchronization_internal {
+int MutexDelay(int32_t c, int 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;
+ const int32_t limit =
+ GetMutexGlobals().num_cpus > 1 ? (mode == AGGRESSIVE ? 5000 : 250) : 0;
if (c < limit) {
- c++; // spin
+ // Spin.
+ c++;
} else {
+ SchedulingGuard::ScopedEnable enable_rescheduling;
ABSL_TSAN_MUTEX_PRE_DIVERT(nullptr, 0);
- if (c == limit) { // yield once
+ if (c == limit) {
+ // Yield once.
AbslInternalMutexYield();
c++;
- } else { // then wait
+ } else {
+ // Then wait.
absl::SleepFor(absl::Microseconds(10));
c = 0;
}
ABSL_TSAN_MUTEX_POST_DIVERT(nullptr, 0);
}
- return (c);
+ return c;
}
+} // namespace synchronization_internal
// --------------------------Generic atomic ops
// Ensure that "(*pv & bits) == bits" by doing an atomic update of "*pv" to
@@ -203,12 +210,12 @@
//------------------------------------------------------------------
// Data for doing deadlock detection.
-static absl::base_internal::SpinLock deadlock_graph_mu(
- absl::base_internal::kLinkerInitialized);
+ABSL_CONST_INIT static absl::base_internal::SpinLock deadlock_graph_mu(
+ absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
-// graph used to detect deadlocks.
-static GraphCycles *deadlock_graph ABSL_GUARDED_BY(deadlock_graph_mu)
- ABSL_PT_GUARDED_BY(deadlock_graph_mu);
+// Graph used to detect deadlocks.
+ABSL_CONST_INIT static GraphCycles *deadlock_graph
+ ABSL_GUARDED_BY(deadlock_graph_mu) ABSL_PT_GUARDED_BY(deadlock_graph_mu);
//------------------------------------------------------------------
// An event mechanism for debugging mutex use.
@@ -269,13 +276,12 @@
{0, "SignalAll on "},
};
-static absl::base_internal::SpinLock synch_event_mu(
- absl::base_internal::kLinkerInitialized);
-// protects synch_event
+ABSL_CONST_INIT static absl::base_internal::SpinLock synch_event_mu(
+ absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
// 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;
+static constexpr uint32_t kNSynchEvent = 1031;
static struct SynchEvent { // this is a trivial hash table for the events
// struct is freed when refcount reaches 0
@@ -295,7 +301,7 @@
bool log; // logging turned on
// Constant after initialization
- char name[1]; // actually longer---null-terminated std::string
+ char name[1]; // actually longer---NUL-terminated string
} * synch_event[kNSynchEvent] ABSL_GUARDED_BY(synch_event_mu);
// Ensure that the object at "addr" has a SynchEvent struct associated with it,
@@ -486,7 +492,7 @@
std::atomic<intptr_t> *cv_word;
int64_t contention_start_cycles; // Time (in cycles) when this thread started
- // to contend for the mutex.
+ // to contend for the mutex.
};
struct SynchLocksHeld {
@@ -700,7 +706,7 @@
static constexpr bool kDebugMode = true;
#endif
-#ifdef THREAD_SANITIZER
+#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
static unsigned TsanFlags(Mutex::MuHow how) {
return how == kShared ? __tsan_mutex_read_lock : 0;
}
@@ -1051,6 +1057,7 @@
// 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) {
+ SchedulingGuard::ScopedDisable disable_rescheduling;
intptr_t v = mu_.load(std::memory_order_relaxed);
// acquire spinlock & lock
if ((v & (kMuWait | kMuSpin | kMuWriter | kMuReader)) == kMuWait &&
@@ -1115,7 +1122,7 @@
this->TryRemove(s);
int c = 0;
while (s->next != nullptr) {
- c = Delay(c, GENTLE);
+ c = synchronization_internal::MutexDelay(c, GENTLE);
this->TryRemove(s);
}
if (kDebugMode) {
@@ -1434,21 +1441,19 @@
// 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
-
+ int c = GetMutexGlobals().spinloop_iterations;
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;
+ if ((v & (kMuReader|kMuEvent)) != 0) {
+ return false; // a reader or tracing -> give up
} 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;
+ return true;
}
- } while (result == -1 && --c > 0);
- return result == 1;
+ } while (--c > 0);
+ return false;
}
ABSL_XRAY_LOG_ARGS(1) void Mutex::Lock() {
@@ -1747,7 +1752,8 @@
};
// Internal version of LockWhen(). See LockSlowWithDeadline()
-void Mutex::LockSlow(MuHow how, const Condition *cond, int flags) {
+ABSL_ATTRIBUTE_NOINLINE 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");
@@ -1762,7 +1768,7 @@
// All memory accesses are ignored inside of mutex operations + for unlock
// operation tsan considers that we've already released the mutex.
bool res = false;
-#ifdef THREAD_SANITIZER
+#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
const int flags = read_lock ? __tsan_mutex_read_lock : 0;
const int tryflags = flags | (trylock ? __tsan_mutex_try_lock : 0);
#endif
@@ -1812,9 +1818,9 @@
// 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();
+ ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
bool res = cond->Eval();
- ANNOTATE_IGNORE_READS_AND_WRITES_END();
+ ABSL_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;
@@ -1895,6 +1901,7 @@
}
void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) {
+ SchedulingGuard::ScopedDisable disable_rescheduling;
int c = 0;
intptr_t v = mu_.load(std::memory_order_relaxed);
if ((v & kMuEvent) != 0) {
@@ -1996,7 +2003,8 @@
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
+ // delay, then try again
+ c = synchronization_internal::MutexDelay(c, GENTLE);
}
ABSL_RAW_CHECK(
waitp->thread->waitp == nullptr || waitp->thread->suppress_fatal_errors,
@@ -2013,7 +2021,8 @@
// which holds the lock but is not runnable because its condition is false
// or it is in 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) {
+ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) {
+ SchedulingGuard::ScopedDisable disable_rescheduling;
intptr_t v = mu_.load(std::memory_order_relaxed);
this->AssertReaderHeld();
CheckForMutexCorruption(v, "Unlock");
@@ -2290,7 +2299,8 @@
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
+ // aggressive here; no one can proceed till we do
+ c = synchronization_internal::MutexDelay(c, AGGRESSIVE);
} // end of for(;;)-loop
if (wake_list != kPerThreadSynchNull) {
@@ -2302,7 +2312,8 @@
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;
+ 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);
@@ -2329,6 +2340,7 @@
// It will later acquire the mutex with high probability. Otherwise, we
// enqueue thread w on this mutex.
void Mutex::Fer(PerThreadSynch *w) {
+ SchedulingGuard::ScopedDisable disable_rescheduling;
int c = 0;
ABSL_RAW_CHECK(w->waitp->cond == nullptr,
"Mutex::Fer while waiting on Condition");
@@ -2378,7 +2390,7 @@
return;
}
}
- c = Delay(c, GENTLE);
+ c = synchronization_internal::MutexDelay(c, GENTLE);
}
}
@@ -2427,6 +2439,7 @@
// Remove thread s from the list of waiters on this condition variable.
void CondVar::Remove(PerThreadSynch *s) {
+ SchedulingGuard::ScopedDisable disable_rescheduling;
intptr_t v;
int c = 0;
for (v = cv_.load(std::memory_order_relaxed);;
@@ -2455,7 +2468,8 @@
std::memory_order_release);
return;
} else {
- c = Delay(c, GENTLE); // try again after a delay
+ // try again after a delay
+ c = synchronization_internal::MutexDelay(c, GENTLE);
}
}
}
@@ -2488,7 +2502,7 @@
!cv_word->compare_exchange_weak(v, v | kCvSpin,
std::memory_order_acquire,
std::memory_order_relaxed)) {
- c = Delay(c, GENTLE);
+ c = synchronization_internal::MutexDelay(c, GENTLE);
v = cv_word->load(std::memory_order_relaxed);
}
ABSL_RAW_CHECK(waitp->thread->waitp == nullptr, "waiting when shouldn't be");
@@ -2587,6 +2601,7 @@
}
void CondVar::Signal() {
+ SchedulingGuard::ScopedDisable disable_rescheduling;
ABSL_TSAN_MUTEX_PRE_SIGNAL(nullptr, 0);
intptr_t v;
int c = 0;
@@ -2619,7 +2634,7 @@
ABSL_TSAN_MUTEX_POST_SIGNAL(nullptr, 0);
return;
} else {
- c = Delay(c, GENTLE);
+ c = synchronization_internal::MutexDelay(c, GENTLE);
}
}
ABSL_TSAN_MUTEX_POST_SIGNAL(nullptr, 0);
@@ -2656,7 +2671,8 @@
ABSL_TSAN_MUTEX_POST_SIGNAL(nullptr, 0);
return;
} else {
- c = Delay(c, GENTLE); // try again after a delay
+ // try again after a delay
+ c = synchronization_internal::MutexDelay(c, GENTLE);
}
}
ABSL_TSAN_MUTEX_POST_SIGNAL(nullptr, 0);
@@ -2669,7 +2685,7 @@
this->mu_ = nullptr;
}
-#ifdef THREAD_SANITIZER
+#ifdef ABSL_HAVE_THREAD_SANITIZER
extern "C" void __tsan_read1(void *addr);
#else
#define __tsan_read1(addr) // do nothing if TSan not enabled
@@ -2720,4 +2736,5 @@
a->arg_ == b->arg_ && a->method_ == b->method_;
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/synchronization/mutex.h b/third_party/abseil/absl/synchronization/mutex.h
index d33318d..598d1e0 100644
--- a/third_party/abseil/absl/synchronization/mutex.h
+++ b/third_party/abseil/absl/synchronization/mutex.h
@@ -31,22 +31,23 @@
//
// 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.
+// - Effectively an 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.
+// 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`.
//
@@ -72,16 +73,8 @@
#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 {
+ABSL_NAMESPACE_BEGIN
class Condition;
struct SynchWaitParams;
@@ -330,17 +323,16 @@
// 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:
+ // Unlocks this `Mutex` and blocks 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.
//
+ // If the condition is initially `true`, the implementation *may* skip the
+ // release/re-acquire step and return immediately.
+ //
// Deadlines in the past are equivalent to an immediate deadline.
// Negative timeouts are equivalent to a zero timeout.
//
@@ -461,15 +453,6 @@
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
@@ -504,7 +487,6 @@
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)
@@ -525,22 +507,36 @@
// Example:
//
// Class Foo {
-//
+// public:
// Foo::Bar* Baz() {
-// MutexLock l(&lock_);
+// MutexLock lock(&mu_);
// ...
// return bar;
// }
//
// private:
-// Mutex lock_;
+// Mutex mu_;
// };
class ABSL_SCOPED_LOCKABLE MutexLock {
public:
+ // Constructors
+
+ // Calls `mu->Lock()` and returns when that call returns. That is, `*mu` is
+ // guaranteed to be locked when this object is constructed. Requires that
+ // `mu` be dereferenceable.
explicit MutexLock(Mutex *mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
this->mu_->Lock();
}
+ // Like above, but calls `mu->LockWhen(cond)` instead. That is, in addition to
+ // the above, the condition given by `cond` is also guaranteed to hold when
+ // this object is constructed.
+ explicit MutexLock(Mutex *mu, const Condition &cond)
+ ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+ : mu_(mu) {
+ this->mu_->LockWhen(cond);
+ }
+
MutexLock(const MutexLock &) = delete; // NOLINT(runtime/mutex)
MutexLock(MutexLock&&) = delete; // NOLINT(runtime/mutex)
MutexLock& operator=(const MutexLock&) = delete;
@@ -562,6 +558,12 @@
mu->ReaderLock();
}
+ explicit ReaderMutexLock(Mutex *mu, const Condition &cond)
+ ABSL_SHARED_LOCK_FUNCTION(mu)
+ : mu_(mu) {
+ mu->ReaderLockWhen(cond);
+ }
+
ReaderMutexLock(const ReaderMutexLock&) = delete;
ReaderMutexLock(ReaderMutexLock&&) = delete;
ReaderMutexLock& operator=(const ReaderMutexLock&) = delete;
@@ -584,6 +586,12 @@
mu->WriterLock();
}
+ explicit WriterMutexLock(Mutex *mu, const Condition &cond)
+ ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+ : mu_(mu) {
+ mu->WriterLockWhen(cond);
+ }
+
WriterMutexLock(const WriterMutexLock&) = delete;
WriterMutexLock(WriterMutexLock&&) = delete;
WriterMutexLock& operator=(const WriterMutexLock&) = delete;
@@ -622,16 +630,26 @@
// `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()`.
+// Note: to use a `Condition`, you need only construct it and pass it to a
+// suitable `Mutex' member function, such as `Mutex::Await()`, or to the
+// constructor of one of the scope guard classes.
//
-// Example:
+// Example using LockWhen/Unlock:
//
// // assume count_ is not internal reference count
-// int count_ GUARDED_BY(mu_);
+// int count_ ABSL_GUARDED_BY(mu_);
+// Condition count_is_zero(+[](int *count) { return *count == 0; }, &count_);
//
-// mu_.LockWhen(Condition(+[](int* count) { return *count == 0; },
-// &count_));
+// mu_.LockWhen(count_is_zero);
+// // ...
+// mu_.Unlock();
+//
+// Example using a scope guard:
+//
+// {
+// MutexLock lock(&mu_, count_is_zero);
+// // ...
+// }
//
// When multiple threads are waiting on exactly the same condition, make sure
// that they are constructed with the same parameters (same pointer to function
@@ -685,6 +703,11 @@
// return processed_ >= current;
// };
// mu_.Await(Condition(&reached));
+ //
+ // NOTE: never use "mu_.AssertHeld()" instead of "mu_.AssertReaderHeld()" in
+ // the lambda as it may be called when the mutex is being unlocked from a
+ // scope holding only a reader lock, which will make the assertion not
+ // fulfilled and crash the binary.
// See class comment for performance advice. In particular, if there
// might be more than one waiter for the same condition, make sure
@@ -769,6 +792,8 @@
//
class CondVar {
public:
+ // A `CondVar` allocated on the heap or on the stack can use the this
+ // constructor.
CondVar();
~CondVar();
@@ -831,17 +856,10 @@
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;
};
@@ -863,6 +881,15 @@
this->mu_->Lock();
}
}
+
+ explicit MutexLockMaybe(Mutex *mu, const Condition &cond)
+ ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+ : mu_(mu) {
+ if (this->mu_ != nullptr) {
+ this->mu_->LockWhen(cond);
+ }
+ }
+
~MutexLockMaybe() ABSL_UNLOCK_FUNCTION() {
if (this->mu_ != nullptr) { this->mu_->Unlock(); }
}
@@ -885,6 +912,13 @@
: mu_(mu) {
this->mu_->Lock();
}
+
+ explicit ReleasableMutexLock(Mutex *mu, const Condition &cond)
+ ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+ : mu_(mu) {
+ this->mu_->LockWhen(cond);
+ }
+
~ReleasableMutexLock() ABSL_UNLOCK_FUNCTION() {
if (this->mu_ != nullptr) { this->mu_->Unlock(); }
}
@@ -899,10 +933,6 @@
ReleasableMutexLock& operator=(ReleasableMutexLock&&) = delete;
};
-#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX
-inline constexpr Mutex::Mutex(absl::ConstInitType) : impl_(absl::kConstInit) {}
-
-#else
inline Mutex::Mutex() : mu_(0) {
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
}
@@ -910,7 +940,6 @@
inline constexpr Mutex::Mutex(absl::ConstInitType) : mu_(0) {}
inline CondVar::CondVar() : cv_(0) {}
-#endif
// static
template <typename T>
@@ -978,7 +1007,7 @@
//
// This has the same memory ordering concerns as RegisterMutexProfiler() above.
void RegisterMutexTracer(void (*fn)(const char *msg, const void *obj,
- int64_t wait_cycles));
+ int64_t wait_cycles));
// TODO(gfalcon): Combine RegisterMutexProfiler() and RegisterMutexTracer()
// into a single interface, since they are only ever called in pairs.
@@ -1000,7 +1029,7 @@
//
// '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
+// false if symbolizing failed, or true if a NUL-terminated symbol was written
// to 'out.'
//
// This has the same memory ordering concerns as RegisterMutexProfiler() above.
@@ -1039,6 +1068,7 @@
// the manner chosen here.
void SetMutexDeadlockDetectionMode(OnDeadlockCycle mode);
+ABSL_NAMESPACE_END
} // namespace absl
// In some build configurations we pass --detect-odr-violations to the
diff --git a/third_party/abseil/absl/synchronization/mutex_benchmark.cc b/third_party/abseil/absl/synchronization/mutex_benchmark.cc
index ab18800..933ea14 100644
--- a/third_party/abseil/absl/synchronization/mutex_benchmark.cc
+++ b/third_party/abseil/absl/synchronization/mutex_benchmark.cc
@@ -16,6 +16,7 @@
#include <mutex> // NOLINT(build/c++11)
#include <vector>
+#include "absl/base/config.h"
#include "absl/base/internal/cycleclock.h"
#include "absl/base/internal/spinlock.h"
#include "absl/synchronization/blocking_counter.h"
@@ -213,7 +214,7 @@
}
// Some configurations have higher thread limits than others.
-#if defined(__linux__) && !defined(THREAD_SANITIZER)
+#if defined(__linux__) && !defined(ABSL_HAVE_THREAD_SANITIZER)
constexpr int kMaxConditionWaiters = 8192;
#else
constexpr int kMaxConditionWaiters = 1024;
diff --git a/third_party/abseil/absl/synchronization/mutex_test.cc b/third_party/abseil/absl/synchronization/mutex_test.cc
index afb363a..058f757 100644
--- a/third_party/abseil/absl/synchronization/mutex_test.cc
+++ b/third_party/abseil/absl/synchronization/mutex_test.cc
@@ -30,6 +30,7 @@
#include "gtest/gtest.h"
#include "absl/base/attributes.h"
+#include "absl/base/config.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/sysinfo.h"
#include "absl/memory/memory.h"
@@ -706,6 +707,40 @@
t.join();
}
+TEST(Mutex, LockWhenGuard) {
+ absl::Mutex mu;
+ int n = 30;
+ bool done = false;
+
+ // We don't inline the lambda because the conversion is ambiguous in MSVC.
+ bool (*cond_eq_10)(int *) = [](int *p) { return *p == 10; };
+ bool (*cond_lt_10)(int *) = [](int *p) { return *p < 10; };
+
+ std::thread t1([&mu, &n, &done, cond_eq_10]() {
+ absl::ReaderMutexLock lock(&mu, absl::Condition(cond_eq_10, &n));
+ done = true;
+ });
+
+ std::thread t2[10];
+ for (std::thread &t : t2) {
+ t = std::thread([&mu, &n, cond_lt_10]() {
+ absl::WriterMutexLock lock(&mu, absl::Condition(cond_lt_10, &n));
+ ++n;
+ });
+ }
+
+ {
+ absl::MutexLock lock(&mu);
+ n = 0;
+ }
+
+ for (std::thread &t : t2) t.join();
+ t1.join();
+
+ EXPECT_TRUE(done);
+ EXPECT_EQ(n, 10);
+}
+
// --------------------------------------------------------
// The following test requires Mutex::ReaderLock to be a real shared
// lock, which is not the case in all builds.
@@ -815,7 +850,7 @@
// Test that we correctly handle the situation when a lock is
// held and then destroyed (w/o unlocking).
-#ifdef THREAD_SANITIZER
+#ifdef ABSL_HAVE_THREAD_SANITIZER
// TSAN reports errors when locked Mutexes are destroyed.
TEST(Mutex, DISABLED_LockedMutexDestructionBug) NO_THREAD_SAFETY_ANALYSIS {
#else
@@ -1001,9 +1036,6 @@
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);
@@ -1067,7 +1099,7 @@
const char ScopedDisableBazelTestWarnings::kVarName[] =
"TEST_WARNINGS_OUTPUT_FILE";
-#ifdef THREAD_SANITIZER
+#ifdef ABSL_HAVE_THREAD_SANITIZER
// This test intentionally creates deadlocks to test the deadlock detector.
TEST(Mutex, DISABLED_DeadlockDetectorBazelWarning) {
#else
@@ -1101,7 +1133,7 @@
// 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) ABSL_NO_THREAD_SAFETY_ANALYSIS {
+TEST(Mutex, DeadlockDetectorStressTest) ABSL_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.
@@ -1119,7 +1151,7 @@
}
}
-#ifdef THREAD_SANITIZER
+#ifdef ABSL_HAVE_THREAD_SANITIZER
// TSAN reports errors when locked Mutexes are destroyed.
TEST(Mutex, DISABLED_DeadlockIdBug) NO_THREAD_SAFETY_ANALYSIS {
#else
@@ -1157,7 +1189,6 @@
c.Lock();
c.Unlock();
}
-#endif // !defined(ABSL_INTERNAL_USE_NONPROD_MUTEX)
// --------------------------------------------------------
// Test for timeouts/deadlines on condition waits that are specified using
diff --git a/third_party/abseil/absl/synchronization/notification.cc b/third_party/abseil/absl/synchronization/notification.cc
index 53ace00..e91b903 100644
--- a/third_party/abseil/absl/synchronization/notification.cc
+++ b/third_party/abseil/absl/synchronization/notification.cc
@@ -22,6 +22,7 @@
#include "absl/time/time.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
void Notification::Notify() {
MutexLock l(&this->mutex_);
@@ -44,15 +45,6 @@
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,
@@ -82,4 +74,5 @@
return notified;
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/synchronization/notification.h b/third_party/abseil/absl/synchronization/notification.h
index 82d111a..9a354ca 100644
--- a/third_party/abseil/absl/synchronization/notification.h
+++ b/third_party/abseil/absl/synchronization/notification.h
@@ -57,6 +57,7 @@
#include "absl/time/time.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// -----------------------------------------------------------------------------
// Notification
@@ -73,7 +74,9 @@
// Notification::HasBeenNotified()
//
// Returns the value of the notification's internal "notified" state.
- bool HasBeenNotified() const;
+ bool HasBeenNotified() const {
+ return HasBeenNotifiedInternal(&this->notified_yet_);
+ }
// Notification::WaitForNotification()
//
@@ -105,10 +108,16 @@
void Notify();
private:
+ static inline bool HasBeenNotifiedInternal(
+ const std::atomic<bool>* notified_yet) {
+ return notified_yet->load(std::memory_order_acquire);
+ }
+
mutable Mutex mutex_;
std::atomic<bool> notified_yet_; // written under mutex_
};
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_SYNCHRONIZATION_NOTIFICATION_H_
diff --git a/third_party/abseil/absl/synchronization/notification_test.cc b/third_party/abseil/absl/synchronization/notification_test.cc
index 059d4cd..100ea76 100644
--- a/third_party/abseil/absl/synchronization/notification_test.cc
+++ b/third_party/abseil/absl/synchronization/notification_test.cc
@@ -21,6 +21,7 @@
#include "absl/synchronization/mutex.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// A thread-safe class that holds a counter.
class ThreadSafeCounter {
@@ -128,4 +129,5 @@
BasicTests(true, &local_notification2);
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/time/BUILD.bazel b/third_party/abseil/absl/time/BUILD.bazel
index 02e18a6..3e25ca2 100644
--- a/third_party/abseil/absl/time/BUILD.bazel
+++ b/third_party/abseil/absl/time/BUILD.bazel
@@ -14,7 +14,7 @@
# limitations under the License.
#
-#load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load(
"//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
@@ -24,7 +24,7 @@
package(default_visibility = ["//visibility:public"])
-licenses(["notice"]) # Apache 2.0
+licenses(["notice"])
cc_library(
name = "time",
@@ -70,6 +70,7 @@
],
deps = [
":time",
+ "//absl/base:config",
"//absl/base:raw_logging_internal",
"//absl/time/internal/cctz:time_zone",
"@com_google_googletest//:gtest",
@@ -93,6 +94,7 @@
":time",
"//absl/base:config",
"//absl/base:core_headers",
+ "//absl/numeric:int128",
"//absl/time/internal/cctz:time_zone",
"@com_google_googletest//:gtest_main",
],
@@ -117,6 +119,7 @@
":time",
"//absl/base",
"//absl/base:core_headers",
+ "//absl/flags:flag",
"//absl/hash",
"@com_github_google_benchmark//:benchmark_main",
],
diff --git a/third_party/abseil/absl/time/CMakeLists.txt b/third_party/abseil/absl/time/CMakeLists.txt
index 853563e..00bdd49 100644
--- a/third_party/abseil/absl/time/CMakeLists.txt
+++ b/third_party/abseil/absl/time/CMakeLists.txt
@@ -99,6 +99,7 @@
${ABSL_DEFAULT_COPTS}
DEPS
absl::time
+ absl::config
absl::raw_logging_internal
absl::time_zone
gmock
diff --git a/third_party/abseil/absl/time/civil_time.cc b/third_party/abseil/absl/time/civil_time.cc
index 7527fc1..bdfe9ce 100644
--- a/third_party/abseil/absl/time/civil_time.cc
+++ b/third_party/abseil/absl/time/civil_time.cc
@@ -21,6 +21,7 @@
#include "absl/time/time.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
@@ -37,26 +38,116 @@
const CivilSecond ncs(NormalizeYear(cs.year()), cs.month(), cs.day(),
cs.hour(), cs.minute(), cs.second());
const TimeZone utc = UTCTimeZone();
- // TODO(absl-team): Avoid conversion of fmt std::string.
+ // TODO(absl-team): Avoid conversion of fmt string.
return StrCat(cs.year(),
FormatTime(std::string(fmt), FromCivil(ncs, utc), utc));
}
+template <typename CivilT>
+bool ParseYearAnd(string_view fmt, string_view s, CivilT* c) {
+ // Civil times support a larger year range than absl::Time, so we need to
+ // parse the year separately, normalize it, then use absl::ParseTime on the
+ // normalized string.
+ const std::string ss = std::string(s); // TODO(absl-team): Avoid conversion.
+ const char* const np = ss.c_str();
+ char* endp;
+ errno = 0;
+ const civil_year_t y =
+ std::strtoll(np, &endp, 10); // NOLINT(runtime/deprecated_fn)
+ if (endp == np || errno == ERANGE) return false;
+ const std::string norm = StrCat(NormalizeYear(y), endp);
+
+ const TimeZone utc = UTCTimeZone();
+ Time t;
+ if (ParseTime(StrCat("%Y", fmt), norm, utc, &t, nullptr)) {
+ const auto cs = ToCivilSecond(t, utc);
+ *c = CivilT(y, cs.month(), cs.day(), cs.hour(), cs.minute(), cs.second());
+ return true;
+ }
+
+ return false;
+}
+
+// Tries to parse the type as a CivilT1, but then assigns the result to the
+// argument of type CivilT2.
+template <typename CivilT1, typename CivilT2>
+bool ParseAs(string_view s, CivilT2* c) {
+ CivilT1 t1;
+ if (ParseCivilTime(s, &t1)) {
+ *c = CivilT2(t1);
+ return true;
+ }
+ return false;
+}
+
+template <typename CivilT>
+bool ParseLenient(string_view s, CivilT* c) {
+ // A fastpath for when the given string data parses exactly into the given
+ // type T (e.g., s="YYYY-MM-DD" and CivilT=CivilDay).
+ if (ParseCivilTime(s, c)) return true;
+ // Try parsing as each of the 6 types, trying the most common types first
+ // (based on csearch results).
+ if (ParseAs<CivilDay>(s, c)) return true;
+ if (ParseAs<CivilSecond>(s, c)) return true;
+ if (ParseAs<CivilHour>(s, c)) return true;
+ if (ParseAs<CivilMonth>(s, c)) return true;
+ if (ParseAs<CivilMinute>(s, c)) return true;
+ if (ParseAs<CivilYear>(s, c)) return true;
+ return false;
+}
} // namespace
std::string FormatCivilTime(CivilSecond c) {
- return FormatYearAnd("-%m-%dT%H:%M:%S", c);
+ return FormatYearAnd("-%m-%d%ET%H:%M:%S", c);
}
std::string FormatCivilTime(CivilMinute c) {
- return FormatYearAnd("-%m-%dT%H:%M", c);
+ return FormatYearAnd("-%m-%d%ET%H:%M", c);
}
std::string FormatCivilTime(CivilHour c) {
- return FormatYearAnd("-%m-%dT%H", c);
+ return FormatYearAnd("-%m-%d%ET%H", c);
}
std::string FormatCivilTime(CivilDay c) { return FormatYearAnd("-%m-%d", c); }
std::string FormatCivilTime(CivilMonth c) { return FormatYearAnd("-%m", c); }
std::string FormatCivilTime(CivilYear c) { return FormatYearAnd("", c); }
+bool ParseCivilTime(string_view s, CivilSecond* c) {
+ return ParseYearAnd("-%m-%d%ET%H:%M:%S", s, c);
+}
+bool ParseCivilTime(string_view s, CivilMinute* c) {
+ return ParseYearAnd("-%m-%d%ET%H:%M", s, c);
+}
+bool ParseCivilTime(string_view s, CivilHour* c) {
+ return ParseYearAnd("-%m-%d%ET%H", s, c);
+}
+bool ParseCivilTime(string_view s, CivilDay* c) {
+ return ParseYearAnd("-%m-%d", s, c);
+}
+bool ParseCivilTime(string_view s, CivilMonth* c) {
+ return ParseYearAnd("-%m", s, c);
+}
+bool ParseCivilTime(string_view s, CivilYear* c) {
+ return ParseYearAnd("", s, c);
+}
+
+bool ParseLenientCivilTime(string_view s, CivilSecond* c) {
+ return ParseLenient(s, c);
+}
+bool ParseLenientCivilTime(string_view s, CivilMinute* c) {
+ return ParseLenient(s, c);
+}
+bool ParseLenientCivilTime(string_view s, CivilHour* c) {
+ return ParseLenient(s, c);
+}
+bool ParseLenientCivilTime(string_view s, CivilDay* c) {
+ return ParseLenient(s, c);
+}
+bool ParseLenientCivilTime(string_view s, CivilMonth* c) {
+ return ParseLenient(s, c);
+}
+bool ParseLenientCivilTime(string_view s, CivilYear* c) {
+ return ParseLenient(s, c);
+}
+
namespace time_internal {
std::ostream& operator<<(std::ostream& os, CivilYear y) {
@@ -80,4 +171,5 @@
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/time/civil_time.h b/third_party/abseil/absl/time/civil_time.h
index beaf7d8..bb46004 100644
--- a/third_party/abseil/absl/time/civil_time.h
+++ b/third_party/abseil/absl/time/civil_time.h
@@ -76,6 +76,7 @@
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
struct second_tag : cctz::detail::second_tag {};
@@ -247,7 +248,7 @@
// int minute()
// int second()
//
-// Recall that fields inferior to the type's aligment will be set to their
+// Recall that fields inferior to the type's alignment will be set to their
// minimum valid value.
//
// Example:
@@ -459,6 +460,57 @@
std::string FormatCivilTime(CivilMonth c);
std::string FormatCivilTime(CivilYear c);
+// absl::ParseCivilTime()
+//
+// Parses a civil-time value from the specified `absl::string_view` into the
+// passed output parameter. Returns `true` upon successful parsing.
+//
+// The expected form of the input string is as follows:
+//
+// Type | Format
+// ---------------------------------
+// CivilSecond | YYYY-MM-DDTHH:MM:SS
+// CivilMinute | YYYY-MM-DDTHH:MM
+// CivilHour | YYYY-MM-DDTHH
+// CivilDay | YYYY-MM-DD
+// CivilMonth | YYYY-MM
+// CivilYear | YYYY
+//
+// Example:
+//
+// absl::CivilDay d;
+// bool ok = absl::ParseCivilTime("2018-01-02", &d); // OK
+//
+// Note that parsing will fail if the string's format does not match the
+// expected type exactly. `ParseLenientCivilTime()` below is more lenient.
+//
+bool ParseCivilTime(absl::string_view s, CivilSecond* c);
+bool ParseCivilTime(absl::string_view s, CivilMinute* c);
+bool ParseCivilTime(absl::string_view s, CivilHour* c);
+bool ParseCivilTime(absl::string_view s, CivilDay* c);
+bool ParseCivilTime(absl::string_view s, CivilMonth* c);
+bool ParseCivilTime(absl::string_view s, CivilYear* c);
+
+// ParseLenientCivilTime()
+//
+// Parses any of the formats accepted by `absl::ParseCivilTime()`, but is more
+// lenient if the format of the string does not exactly match the associated
+// type.
+//
+// Example:
+//
+// absl::CivilDay d;
+// bool ok = absl::ParseLenientCivilTime("1969-07-20", &d); // OK
+// ok = absl::ParseLenientCivilTime("1969-07-20T10", &d); // OK: T10 floored
+// ok = absl::ParseLenientCivilTime("1969-07", &d); // OK: day defaults to 1
+//
+bool ParseLenientCivilTime(absl::string_view s, CivilSecond* c);
+bool ParseLenientCivilTime(absl::string_view s, CivilMinute* c);
+bool ParseLenientCivilTime(absl::string_view s, CivilHour* c);
+bool ParseLenientCivilTime(absl::string_view s, CivilDay* c);
+bool ParseLenientCivilTime(absl::string_view s, CivilMonth* c);
+bool ParseLenientCivilTime(absl::string_view s, CivilYear* c);
+
namespace time_internal { // For functions found via ADL on civil-time tags.
// Streaming Operators
@@ -468,7 +520,7 @@
//
// Example:
//
-// absl::CivilDay d = absl::CivilDay("1969-07-20");
+// absl::CivilDay d = absl::CivilDay(1969, 7, 20);
// std::cout << "Date is: " << d << "\n";
//
std::ostream& operator<<(std::ostream& os, CivilYear y);
@@ -480,6 +532,7 @@
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_TIME_CIVIL_TIME_H_
diff --git a/third_party/abseil/absl/time/civil_time_benchmark.cc b/third_party/abseil/absl/time/civil_time_benchmark.cc
index 4086983..f04dbe2 100644
--- a/third_party/abseil/absl/time/civil_time_benchmark.cc
+++ b/third_party/abseil/absl/time/civil_time_benchmark.cc
@@ -66,6 +66,26 @@
}
BENCHMARK(BM_Format);
+void BM_Parse(benchmark::State& state) {
+ const std::string f = "2014-01-02T03:04:05";
+ absl::CivilSecond c;
+ while (state.KeepRunning()) {
+ const bool b = absl::ParseCivilTime(f, &c);
+ benchmark::DoNotOptimize(b);
+ }
+}
+BENCHMARK(BM_Parse);
+
+void BM_RoundTripFormatParse(benchmark::State& state) {
+ const absl::CivilSecond c(2014, 1, 2, 3, 4, 5);
+ absl::CivilSecond out;
+ while (state.KeepRunning()) {
+ const bool b = absl::ParseCivilTime(absl::FormatCivilTime(c), &out);
+ benchmark::DoNotOptimize(b);
+ }
+}
+BENCHMARK(BM_RoundTripFormatParse);
+
template <typename T>
void BM_CivilTimeAbslHash(benchmark::State& state) {
const int kSize = 100000;
diff --git a/third_party/abseil/absl/time/civil_time_test.cc b/third_party/abseil/absl/time/civil_time_test.cc
index 03cd1f1..0ebd97a 100644
--- a/third_party/abseil/absl/time/civil_time_test.cc
+++ b/third_party/abseil/absl/time/civil_time_test.cc
@@ -690,6 +690,69 @@
EXPECT_EQ("1970", absl::FormatCivilTime(y));
}
+TEST(CivilTime, Parse) {
+ absl::CivilSecond ss;
+ absl::CivilMinute mm;
+ absl::CivilHour hh;
+ absl::CivilDay d;
+ absl::CivilMonth m;
+ absl::CivilYear y;
+
+ // CivilSecond OK; others fail
+ EXPECT_TRUE(absl::ParseCivilTime("2015-01-02T03:04:05", &ss));
+ EXPECT_EQ("2015-01-02T03:04:05", absl::FormatCivilTime(ss));
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03:04:05", &mm));
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03:04:05", &hh));
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03:04:05", &d));
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03:04:05", &m));
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03:04:05", &y));
+
+ // CivilMinute OK; others fail
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03:04", &ss));
+ EXPECT_TRUE(absl::ParseCivilTime("2015-01-02T03:04", &mm));
+ EXPECT_EQ("2015-01-02T03:04", absl::FormatCivilTime(mm));
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03:04", &hh));
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03:04", &d));
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03:04", &m));
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03:04", &y));
+
+ // CivilHour OK; others fail
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03", &ss));
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03", &mm));
+ EXPECT_TRUE(absl::ParseCivilTime("2015-01-02T03", &hh));
+ EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(hh));
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03", &d));
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03", &m));
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03", &y));
+
+ // CivilDay OK; others fail
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01-02", &ss));
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01-02", &mm));
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01-02", &hh));
+ EXPECT_TRUE(absl::ParseCivilTime("2015-01-02", &d));
+ EXPECT_EQ("2015-01-02", absl::FormatCivilTime(d));
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01-02", &m));
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01-02", &y));
+
+ // CivilMonth OK; others fail
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01", &ss));
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01", &mm));
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01", &hh));
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01", &d));
+ EXPECT_TRUE(absl::ParseCivilTime("2015-01", &m));
+ EXPECT_EQ("2015-01", absl::FormatCivilTime(m));
+ EXPECT_FALSE(absl::ParseCivilTime("2015-01", &y));
+
+ // CivilYear OK; others fail
+ EXPECT_FALSE(absl::ParseCivilTime("2015", &ss));
+ EXPECT_FALSE(absl::ParseCivilTime("2015", &mm));
+ EXPECT_FALSE(absl::ParseCivilTime("2015", &hh));
+ EXPECT_FALSE(absl::ParseCivilTime("2015", &d));
+ EXPECT_FALSE(absl::ParseCivilTime("2015", &m));
+ EXPECT_TRUE(absl::ParseCivilTime("2015", &y));
+ EXPECT_EQ("2015", absl::FormatCivilTime(y));
+}
+
TEST(CivilTime, FormatAndParseLenient) {
absl::CivilSecond ss;
EXPECT_EQ("1970-01-01T00:00:00", absl::FormatCivilTime(ss));
@@ -708,6 +771,101 @@
absl::CivilYear y;
EXPECT_EQ("1970", absl::FormatCivilTime(y));
+
+ EXPECT_TRUE(absl::ParseLenientCivilTime("2015-01-02T03:04:05", &ss));
+ EXPECT_EQ("2015-01-02T03:04:05", absl::FormatCivilTime(ss));
+
+ EXPECT_TRUE(absl::ParseLenientCivilTime("2015-01-02T03:04:05", &mm));
+ EXPECT_EQ("2015-01-02T03:04", absl::FormatCivilTime(mm));
+
+ EXPECT_TRUE(absl::ParseLenientCivilTime("2015-01-02T03:04:05", &hh));
+ EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(hh));
+
+ EXPECT_TRUE(absl::ParseLenientCivilTime("2015-01-02T03:04:05", &d));
+ EXPECT_EQ("2015-01-02", absl::FormatCivilTime(d));
+
+ EXPECT_TRUE(absl::ParseLenientCivilTime("2015-01-02T03:04:05", &m));
+ EXPECT_EQ("2015-01", absl::FormatCivilTime(m));
+
+ EXPECT_TRUE(absl::ParseLenientCivilTime("2015-01-02T03:04:05", &y));
+ EXPECT_EQ("2015", absl::FormatCivilTime(y));
+}
+
+TEST(CivilTime, ParseEdgeCases) {
+ absl::CivilSecond ss;
+ EXPECT_TRUE(
+ absl::ParseLenientCivilTime("9223372036854775807-12-31T23:59:59", &ss));
+ EXPECT_EQ("9223372036854775807-12-31T23:59:59", absl::FormatCivilTime(ss));
+ EXPECT_TRUE(
+ absl::ParseLenientCivilTime("-9223372036854775808-01-01T00:00:00", &ss));
+ EXPECT_EQ("-9223372036854775808-01-01T00:00:00", absl::FormatCivilTime(ss));
+
+ absl::CivilMinute mm;
+ EXPECT_TRUE(
+ absl::ParseLenientCivilTime("9223372036854775807-12-31T23:59", &mm));
+ EXPECT_EQ("9223372036854775807-12-31T23:59", absl::FormatCivilTime(mm));
+ EXPECT_TRUE(
+ absl::ParseLenientCivilTime("-9223372036854775808-01-01T00:00", &mm));
+ EXPECT_EQ("-9223372036854775808-01-01T00:00", absl::FormatCivilTime(mm));
+
+ absl::CivilHour hh;
+ EXPECT_TRUE(
+ absl::ParseLenientCivilTime("9223372036854775807-12-31T23", &hh));
+ EXPECT_EQ("9223372036854775807-12-31T23", absl::FormatCivilTime(hh));
+ EXPECT_TRUE(
+ absl::ParseLenientCivilTime("-9223372036854775808-01-01T00", &hh));
+ EXPECT_EQ("-9223372036854775808-01-01T00", absl::FormatCivilTime(hh));
+
+ absl::CivilDay d;
+ EXPECT_TRUE(absl::ParseLenientCivilTime("9223372036854775807-12-31", &d));
+ EXPECT_EQ("9223372036854775807-12-31", absl::FormatCivilTime(d));
+ EXPECT_TRUE(absl::ParseLenientCivilTime("-9223372036854775808-01-01", &d));
+ EXPECT_EQ("-9223372036854775808-01-01", absl::FormatCivilTime(d));
+
+ absl::CivilMonth m;
+ EXPECT_TRUE(absl::ParseLenientCivilTime("9223372036854775807-12", &m));
+ EXPECT_EQ("9223372036854775807-12", absl::FormatCivilTime(m));
+ EXPECT_TRUE(absl::ParseLenientCivilTime("-9223372036854775808-01", &m));
+ EXPECT_EQ("-9223372036854775808-01", absl::FormatCivilTime(m));
+
+ absl::CivilYear y;
+ EXPECT_TRUE(absl::ParseLenientCivilTime("9223372036854775807", &y));
+ EXPECT_EQ("9223372036854775807", absl::FormatCivilTime(y));
+ EXPECT_TRUE(absl::ParseLenientCivilTime("-9223372036854775808", &y));
+ EXPECT_EQ("-9223372036854775808", absl::FormatCivilTime(y));
+
+ // Tests some valid, but interesting, cases
+ EXPECT_TRUE(absl::ParseLenientCivilTime("0", &ss)) << ss;
+ EXPECT_EQ(absl::CivilYear(0), ss);
+ EXPECT_TRUE(absl::ParseLenientCivilTime("0-1", &ss)) << ss;
+ EXPECT_EQ(absl::CivilMonth(0, 1), ss);
+ EXPECT_TRUE(absl::ParseLenientCivilTime(" 2015 ", &ss)) << ss;
+ EXPECT_EQ(absl::CivilYear(2015), ss);
+ EXPECT_TRUE(absl::ParseLenientCivilTime(" 2015-6 ", &ss)) << ss;
+ EXPECT_EQ(absl::CivilMonth(2015, 6), ss);
+ EXPECT_TRUE(absl::ParseLenientCivilTime("2015-6-7", &ss)) << ss;
+ EXPECT_EQ(absl::CivilDay(2015, 6, 7), ss);
+ EXPECT_TRUE(absl::ParseLenientCivilTime(" 2015-6-7 ", &ss)) << ss;
+ EXPECT_EQ(absl::CivilDay(2015, 6, 7), ss);
+ EXPECT_TRUE(absl::ParseLenientCivilTime("2015-06-07T10:11:12 ", &ss)) << ss;
+ EXPECT_EQ(absl::CivilSecond(2015, 6, 7, 10, 11, 12), ss);
+ EXPECT_TRUE(absl::ParseLenientCivilTime(" 2015-06-07T10:11:12 ", &ss)) << ss;
+ EXPECT_EQ(absl::CivilSecond(2015, 6, 7, 10, 11, 12), ss);
+ EXPECT_TRUE(absl::ParseLenientCivilTime("-01-01", &ss)) << ss;
+ EXPECT_EQ(absl::CivilMonth(-1, 1), ss);
+
+ // Tests some invalid cases
+ EXPECT_FALSE(absl::ParseLenientCivilTime("01-01-2015", &ss)) << ss;
+ EXPECT_FALSE(absl::ParseLenientCivilTime("2015-", &ss)) << ss;
+ EXPECT_FALSE(absl::ParseLenientCivilTime("0xff-01", &ss)) << ss;
+ EXPECT_FALSE(absl::ParseLenientCivilTime("2015-02-30T04:05:06", &ss)) << ss;
+ EXPECT_FALSE(absl::ParseLenientCivilTime("2015-02-03T04:05:96", &ss)) << ss;
+ EXPECT_FALSE(absl::ParseLenientCivilTime("X2015-02-03T04:05:06", &ss)) << ss;
+ EXPECT_FALSE(absl::ParseLenientCivilTime("2015-02-03T04:05:003", &ss)) << ss;
+ EXPECT_FALSE(absl::ParseLenientCivilTime("2015 -02-03T04:05:06", &ss)) << ss;
+ EXPECT_FALSE(absl::ParseLenientCivilTime("2015-02-03-04:05:06", &ss)) << ss;
+ EXPECT_FALSE(absl::ParseLenientCivilTime("2015:02:03T04-05-06", &ss)) << ss;
+ EXPECT_FALSE(absl::ParseLenientCivilTime("9223372036854775808", &y)) << y;
}
TEST(CivilTime, OutputStream) {
diff --git a/third_party/abseil/absl/time/clock.cc b/third_party/abseil/absl/time/clock.cc
index fa0ed34..6862e01 100644
--- a/third_party/abseil/absl/time/clock.cc
+++ b/third_party/abseil/absl/time/clock.cc
@@ -34,6 +34,7 @@
#include "absl/base/thread_annotations.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
Time Now() {
// TODO(bww): Get a timespec instead so we don't have to divide.
int64_t n = absl::GetCurrentTimeNanos();
@@ -43,6 +44,7 @@
}
return time_internal::FromUnixDuration(absl::Nanoseconds(n));
}
+ABSL_NAMESPACE_END
} // namespace absl
// Decide if we should use the fast GetCurrentTimeNanos() algorithm
@@ -71,9 +73,9 @@
#if !ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
namespace absl {
-int64_t GetCurrentTimeNanos() {
- return GET_CURRENT_TIME_NANOS_FROM_SYSTEM();
-}
+ABSL_NAMESPACE_BEGIN
+int64_t GetCurrentTimeNanos() { return GET_CURRENT_TIME_NANOS_FROM_SYSTEM(); }
+ABSL_NAMESPACE_END
} // namespace absl
#else // Use the cyclecounter-based implementation below.
@@ -91,6 +93,7 @@
static int64_t stats_fast_slow_paths;
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
// This is a friend wrapper around UnscaledCycleClock::Now()
// (needed to access UnscaledCycleClock).
@@ -221,9 +224,9 @@
// 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);
+ABSL_CONST_INIT static absl::base_internal::SpinLock lock(
+ absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
+ABSL_CONST_INIT static std::atomic<uint64_t> seq(0);
// data from a sample of the kernel's time value
struct TimeSampleAtomic {
@@ -385,7 +388,7 @@
// TODO(absl-team): Remove this attribute when our compiler is smart enough
// to do the right thing.
ABSL_ATTRIBUTE_NOINLINE
-static int64_t GetCurrentTimeNanosSlowPath() LOCKS_EXCLUDED(lock) {
+static int64_t GetCurrentTimeNanosSlowPath() ABSL_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();
@@ -430,7 +433,7 @@
static uint64_t UpdateLastSample(uint64_t now_cycles, uint64_t now_ns,
uint64_t delta_cycles,
const struct TimeSample *sample)
- EXCLUSIVE_LOCKS_REQUIRED(lock) {
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(lock) {
uint64_t estimated_base_ns = now_ns;
uint64_t lock_value = SeqAcquire(&seq); // acquire seqlock to block readers
@@ -449,7 +452,7 @@
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) {
+ sample->base_cycles + 50 < 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
@@ -515,10 +518,12 @@
return estimated_base_ns;
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
// Returns the maximum duration that SleepOnce() can sleep for.
@@ -546,6 +551,7 @@
}
} // namespace
+ABSL_NAMESPACE_END
} // namespace absl
extern "C" {
diff --git a/third_party/abseil/absl/time/clock.h b/third_party/abseil/absl/time/clock.h
index bb52e4f..27764a9 100644
--- a/third_party/abseil/absl/time/clock.h
+++ b/third_party/abseil/absl/time/clock.h
@@ -26,6 +26,7 @@
#include "absl/time/time.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// Now()
//
@@ -49,6 +50,7 @@
// * Returns immediately when passed a nonpositive duration.
void SleepFor(absl::Duration duration);
+ABSL_NAMESPACE_END
} // namespace absl
// -----------------------------------------------------------------------------
diff --git a/third_party/abseil/absl/time/duration.cc b/third_party/abseil/absl/time/duration.cc
index a3ac61a..4443109 100644
--- a/third_party/abseil/absl/time/duration.cc
+++ b/third_party/abseil/absl/time/duration.cc
@@ -67,10 +67,14 @@
#include <string>
#include "absl/base/casts.h"
+#include "absl/base/macros.h"
#include "absl/numeric/int128.h"
+#include "absl/strings/string_view.h"
+#include "absl/strings/strip.h"
#include "absl/time/time.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
@@ -197,11 +201,11 @@
// double as overflow cases.
inline bool SafeAddRepHi(double a_hi, double b_hi, Duration* d) {
double c = a_hi + b_hi;
- if (c >= kint64max) {
+ if (c >= static_cast<double>(kint64max)) {
*d = InfiniteDuration();
return false;
}
- if (c <= kint64min) {
+ if (c <= static_cast<double>(kint64min)) {
*d = -InfiniteDuration();
return false;
}
@@ -352,7 +356,7 @@
// 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) {
+ Duration* rem) {
int64_t q = 0;
if (IDivFastPath(num, den, &q, rem)) {
return q;
@@ -707,16 +711,17 @@
// fractional digits, because it is in the noise of what a Duration can
// represent.
struct DisplayUnit {
- const char* abbr;
+ absl::string_view 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
+ABSL_CONST_INIT const DisplayUnit kDisplayNano = {"ns", 2, 1e2};
+ABSL_CONST_INIT const DisplayUnit kDisplayMicro = {"us", 5, 1e5};
+ABSL_CONST_INIT const DisplayUnit kDisplayMilli = {"ms", 8, 1e8};
+ABSL_CONST_INIT const DisplayUnit kDisplaySec = {"s", 11, 1e11};
+ABSL_CONST_INIT const DisplayUnit kDisplayMin = {"m", -1, 0.0}; // prec ignored
+ABSL_CONST_INIT 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
@@ -724,16 +729,16 @@
char* bp = Format64(ep, 0, n);
if (*bp != '0' || bp + 1 != ep) {
out->append(bp, ep - bp);
- out->append(unit.abbr);
+ out->append(unit.abbr.data(), unit.abbr.size());
}
}
// 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
+ constexpr int kBufferSize = std::numeric_limits<double>::digits10;
+ const int prec = std::min(kBufferSize, unit.prec);
+ char buf[kBufferSize]; // 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);
@@ -747,7 +752,7 @@
while (ep[-1] == '0') --ep;
out->append(bp, ep - bp);
}
- out->append(unit.abbr);
+ out->append(unit.abbr.data(), unit.abbr.size());
}
}
@@ -758,7 +763,8 @@
// 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.
+// is non-zero.
+// Unlike Go, we format the zero duration as 0, with no unit.
std::string FormatDuration(Duration d) {
const Duration min_duration = Seconds(kint64min);
if (d == min_duration) {
@@ -799,23 +805,27 @@
// A helper for ParseDuration() that parses a leading number from the given
// string and stores the result in *int_part/*frac_part/*frac_scale. The
// given string pointer is modified to point to the first unconsumed char.
-bool ConsumeDurationNumber(const char** dpp, int64_t* int_part,
+bool ConsumeDurationNumber(const char** dpp, const char* ep, int64_t* int_part,
int64_t* frac_part, int64_t* frac_scale) {
*int_part = 0;
*frac_part = 0;
*frac_scale = 1; // invariant: *frac_part < *frac_scale
const char* start = *dpp;
- for (; std::isdigit(**dpp); *dpp += 1) {
+ for (; *dpp != ep; *dpp += 1) {
const int d = **dpp - '0'; // contiguous digits
+ if (d < 0 || 10 <= d) break;
+
if (*int_part > kint64max / 10) return false;
*int_part *= 10;
if (*int_part > kint64max - d) return false;
*int_part += d;
}
const bool int_part_empty = (*dpp == start);
- if (**dpp != '.') return !int_part_empty;
- for (*dpp += 1; std::isdigit(**dpp); *dpp += 1) {
+ if (*dpp == ep || **dpp != '.') return !int_part_empty;
+
+ for (*dpp += 1; *dpp != ep; *dpp += 1) {
const int d = **dpp - '0'; // contiguous digits
+ if (d < 0 || 10 <= d) break;
if (*frac_scale <= kint64max / 10) {
*frac_part *= 10;
*frac_part += d;
@@ -829,32 +839,56 @@
// ns, us, ms, s, m, h) from the given string and stores the resulting unit
// in "*unit". The given 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;
+bool ConsumeDurationUnit(const char** start, const char* end, Duration* unit) {
+ size_t size = end - *start;
+ switch (size) {
+ case 0:
+ return false;
+ default:
+ switch (**start) {
+ case 'n':
+ if (*(*start + 1) == 's') {
+ *start += 2;
+ *unit = Nanoseconds(1);
+ return true;
+ }
+ break;
+ case 'u':
+ if (*(*start + 1) == 's') {
+ *start += 2;
+ *unit = Microseconds(1);
+ return true;
+ }
+ break;
+ case 'm':
+ if (*(*start + 1) == 's') {
+ *start += 2;
+ *unit = Milliseconds(1);
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ ABSL_FALLTHROUGH_INTENDED;
+ case 1:
+ switch (**start) {
+ case 's':
+ *unit = Seconds(1);
+ *start += 1;
+ return true;
+ case 'm':
+ *unit = Minutes(1);
+ *start += 1;
+ return true;
+ case 'h':
+ *unit = Hours(1);
+ *start += 1;
+ return true;
+ default:
+ return false;
+ }
}
- *start = s;
- return ok;
}
} // namespace
@@ -864,39 +898,38 @@
// 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();
+bool ParseDuration(absl::string_view dur_sv, Duration* d) {
int sign = 1;
-
- if (*start == '-' || *start == '+') {
- sign = *start == '-' ? -1 : 1;
- ++start;
+ if (absl::ConsumePrefix(&dur_sv, "-")) {
+ sign = -1;
+ } else {
+ absl::ConsumePrefix(&dur_sv, "+");
}
+ if (dur_sv.empty()) return false;
- // 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') {
+ // Special case for a string of "0".
+ if (dur_sv == "0") {
*d = ZeroDuration();
return true;
}
- if (strcmp(start, "inf") == 0) {
+ if (dur_sv == "inf") {
*d = sign * InfiniteDuration();
return true;
}
+ const char* start = dur_sv.data();
+ const char* end = start + dur_sv.size();
+
Duration dur;
- while (*start != '\0') {
+ while (start != end) {
int64_t int_part;
int64_t frac_part;
int64_t frac_scale;
Duration unit;
- if (!ConsumeDurationNumber(&start, &int_part, &frac_part, &frac_scale) ||
- !ConsumeDurationUnit(&start, &unit)) {
+ if (!ConsumeDurationNumber(&start, end, &int_part, &frac_part,
+ &frac_scale) ||
+ !ConsumeDurationUnit(&start, end, &unit)) {
return false;
}
if (int_part != 0) dur += sign * int_part * unit;
@@ -906,10 +939,16 @@
return true;
}
+bool AbslParseFlag(absl::string_view text, Duration* dst, std::string*) {
+ return ParseDuration(text, dst);
+}
+
+std::string AbslUnparseFlag(Duration d) { return FormatDuration(d); }
bool ParseFlag(const std::string& text, Duration* dst, std::string* ) {
return ParseDuration(text, dst);
}
std::string UnparseFlag(Duration d) { return FormatDuration(d); }
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/time/duration_benchmark.cc b/third_party/abseil/absl/time/duration_benchmark.cc
index 83a836c..56820f3 100644
--- a/third_party/abseil/absl/time/duration_benchmark.cc
+++ b/third_party/abseil/absl/time/duration_benchmark.cc
@@ -18,9 +18,14 @@
#include <string>
#include "absl/base/attributes.h"
+#include "absl/flags/flag.h"
#include "absl/time/time.h"
#include "benchmark/benchmark.h"
+ABSL_FLAG(absl::Duration, absl_duration_flag_for_benchmark,
+ absl::Milliseconds(1),
+ "Flag to use for benchmarking duration flag access speed.");
+
namespace {
//
@@ -425,4 +430,15 @@
}
BENCHMARK(BM_Duration_ParseDuration)->DenseRange(0, kNumDurations - 1);
+//
+// Flag access
+//
+void BM_Duration_GetFlag(benchmark::State& state) {
+ while (state.KeepRunning()) {
+ benchmark::DoNotOptimize(
+ absl::GetFlag(FLAGS_absl_duration_flag_for_benchmark));
+ }
+}
+BENCHMARK(BM_Duration_GetFlag);
+
} // namespace
diff --git a/third_party/abseil/absl/time/duration_test.cc b/third_party/abseil/absl/time/duration_test.cc
index 5dce9ac..4d85a2c 100644
--- a/third_party/abseil/absl/time/duration_test.cc
+++ b/third_party/abseil/absl/time/duration_test.cc
@@ -762,11 +762,6 @@
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(std::isinf(two / z));
- EXPECT_TRUE(std::isnan(z / z)); // We'll return inf
-
// Operator/(Duration, double)
EXPECT_EQ(inf, zero / 0.0);
EXPECT_EQ(-inf, zero / -0.0);
@@ -1050,7 +1045,7 @@
EXPECT_EQ(absl::Seconds(666666666) + absl::Nanoseconds(666666667) +
absl::Nanoseconds(1) / 2,
sigfigs / 3);
- sigfigs = absl::Seconds(7000000000LL);
+ sigfigs = absl::Seconds(int64_t{7000000000});
EXPECT_EQ(absl::Seconds(2333333333) + absl::Nanoseconds(333333333) +
absl::Nanoseconds(1) / 4,
sigfigs / 3);
diff --git a/third_party/abseil/absl/time/format.cc b/third_party/abseil/absl/time/format.cc
index d6ca860..4005fb7 100644
--- a/third_party/abseil/absl/time/format.cc
+++ b/third_party/abseil/absl/time/format.cc
@@ -13,21 +13,25 @@
// limitations under the License.
#include <string.h>
+
#include <cctype>
#include <cstdint>
+#include "absl/strings/match.h"
+#include "absl/strings/string_view.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
#include "absl/time/time.h"
namespace cctz = absl::time_internal::cctz;
namespace absl {
+ABSL_NAMESPACE_BEGIN
-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";
+ABSL_DLL extern const char RFC3339_full[] = "%Y-%m-%d%ET%H:%M:%E*S%Ez";
+ABSL_DLL extern const char RFC3339_sec[] = "%Y-%m-%d%ET%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";
+ABSL_DLL extern const char RFC1123_full[] = "%a, %d %b %E4Y %H:%M:%S %z";
+ABSL_DLL extern const char RFC1123_no_wday[] = "%d %b %E4Y %H:%M:%S %z";
namespace {
@@ -67,12 +71,12 @@
} // namespace
-std::string FormatTime(const std::string& format, absl::Time t,
+std::string FormatTime(absl::string_view format, absl::Time t,
absl::TimeZone tz) {
- if (t == absl::InfiniteFuture()) return kInfiniteFutureStr;
- if (t == absl::InfinitePast()) return kInfinitePastStr;
+ if (t == absl::InfiniteFuture()) return std::string(kInfiniteFutureStr);
+ if (t == absl::InfinitePast()) return std::string(kInfinitePastStr);
const auto parts = Split(t);
- return cctz::detail::format(format, parts.sec, parts.fem,
+ return cctz::detail::format(std::string(format), parts.sec, parts.fem,
cctz::time_zone(tz));
}
@@ -84,42 +88,50 @@
return absl::FormatTime(RFC3339_full, t, absl::LocalTimeZone());
}
-bool ParseTime(const std::string& format, const std::string& input,
+bool ParseTime(absl::string_view format, absl::string_view input,
absl::Time* time, std::string* err) {
return absl::ParseTime(format, input, absl::UTCTimeZone(), time, err);
}
// If the input 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,
+bool ParseTime(absl::string_view format, absl::string_view 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;
+ auto strip_leading_space = [](absl::string_view* sv) {
+ while (!sv->empty()) {
+ if (!std::isspace(sv->front())) return;
+ sv->remove_prefix(1);
}
- }
+ };
- 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;
+ // Portable toolchains means we don't get nice constexpr here.
+ struct Literal {
+ const char* name;
+ size_t size;
+ absl::Time value;
+ };
+ static Literal literals[] = {
+ {kInfiniteFutureStr, strlen(kInfiniteFutureStr), InfiniteFuture()},
+ {kInfinitePastStr, strlen(kInfinitePastStr), InfinitePast()},
+ };
+ strip_leading_space(&input);
+ for (const auto& lit : literals) {
+ if (absl::StartsWith(input, absl::string_view(lit.name, lit.size))) {
+ absl::string_view tail = input;
+ tail.remove_prefix(lit.size);
+ strip_leading_space(&tail);
+ if (tail.empty()) {
+ *time = lit.value;
+ 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);
+ const bool b =
+ cctz::detail::parse(std::string(format), std::string(input),
+ cctz::time_zone(tz), &parts.sec, &parts.fem, &error);
if (b) {
*time = Join(parts);
} else if (err != nullptr) {
@@ -129,6 +141,13 @@
}
// Functions required to support absl::Time flags.
+bool AbslParseFlag(absl::string_view text, absl::Time* t, std::string* error) {
+ return absl::ParseTime(RFC3339_full, text, absl::UTCTimeZone(), t, error);
+}
+
+std::string AbslUnparseFlag(absl::Time t) {
+ return absl::FormatTime(RFC3339_full, t, absl::UTCTimeZone());
+}
bool ParseFlag(const std::string& text, absl::Time* t, std::string* error) {
return absl::ParseTime(RFC3339_full, text, absl::UTCTimeZone(), t, error);
}
@@ -137,4 +156,5 @@
return absl::FormatTime(RFC3339_full, t, absl::UTCTimeZone());
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/time/format_benchmark.cc b/third_party/abseil/absl/time/format_benchmark.cc
index 249c51d..19e481d 100644
--- a/third_party/abseil/absl/time/format_benchmark.cc
+++ b/third_party/abseil/absl/time/format_benchmark.cc
@@ -26,7 +26,7 @@
absl::RFC1123_no_wday, // 1
absl::RFC3339_full, // 2
absl::RFC3339_sec, // 3
- "%Y-%m-%dT%H:%M:%S", // 4
+ "%Y-%m-%d%ET%H:%M:%S", // 4
"%Y-%m-%d", // 5
};
const int kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
diff --git a/third_party/abseil/absl/time/format_test.cc b/third_party/abseil/absl/time/format_test.cc
index ab1f305..a9a1eb8 100644
--- a/third_party/abseil/absl/time/format_test.cc
+++ b/third_party/abseil/absl/time/format_test.cc
@@ -173,7 +173,7 @@
absl::Time t;
std::string e;
- // We can parse a std::string without a UTC offset if we supply a timezone.
+ // We can parse a 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;
@@ -327,7 +327,7 @@
EXPECT_TRUE(absl::ParseTime("%H:%M blah", " infinite-past ", &t, &err));
EXPECT_EQ(absl::InfinitePast(), t);
- // "infinite-future" as literal std::string
+ // "infinite-future" as literal string
absl::TimeZone tz = absl::UTCTimeZone();
EXPECT_TRUE(absl::ParseTime("infinite-future %H:%M", "infinite-future 03:04",
&t, &err));
@@ -335,7 +335,7 @@
EXPECT_EQ(3, tz.At(t).cs.hour());
EXPECT_EQ(4, tz.At(t).cs.minute());
- // "infinite-past" as literal std::string
+ // "infinite-past" as literal string
EXPECT_TRUE(
absl::ParseTime("infinite-past %H:%M", "infinite-past 03:04", &t, &err));
EXPECT_NE(absl::InfinitePast(), t);
diff --git a/third_party/abseil/absl/time/internal/cctz/BUILD.bazel b/third_party/abseil/absl/time/internal/cctz/BUILD.bazel
index e3c4609..45a9529 100644
--- a/third_party/abseil/absl/time/internal/cctz/BUILD.bazel
+++ b/third_party/abseil/absl/time/internal/cctz/BUILD.bazel
@@ -12,11 +12,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-#load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
package(features = ["-parse_headers"])
-licenses(["notice"]) # Apache License
+licenses(["notice"])
+
+filegroup(
+ name = "zoneinfo",
+ srcs = glob(["testdata/zoneinfo/**"]),
+)
config_setting(
name = "osx",
@@ -42,6 +47,7 @@
],
textual_hdrs = ["include/cctz/civil_time_detail.h"],
visibility = ["//visibility:public"],
+ deps = ["//absl/base:config"],
)
cc_library(
@@ -78,17 +84,26 @@
"//conditions:default": [],
}),
visibility = ["//visibility:public"],
- deps = [":civil_time"],
+ deps = [
+ ":civil_time",
+ "//absl/base:config",
+ ],
)
### tests
+test_suite(
+ name = "all_tests",
+ visibility = ["//visibility:public"],
+)
+
cc_test(
name = "civil_time_test",
size = "small",
srcs = ["src/civil_time_test.cc"],
deps = [
":civil_time",
+ "//absl/base:config",
"@com_google_googletest//:gtest_main",
],
)
@@ -106,6 +121,7 @@
deps = [
":civil_time",
":time_zone",
+ "//absl/base:config",
"@com_google_googletest//:gtest_main",
],
)
@@ -124,6 +140,7 @@
deps = [
":civil_time",
":time_zone",
+ "//absl/base:config",
"@com_google_googletest//:gtest_main",
],
)
@@ -144,6 +161,7 @@
deps = [
":civil_time",
":time_zone",
+ "//absl/base:config",
"@com_github_google_benchmark//:benchmark_main",
],
)
@@ -151,8 +169,3 @@
### examples
### binaries
-
-filegroup(
- name = "zoneinfo",
- srcs = glob(["testdata/zoneinfo/**"]),
-)
diff --git a/third_party/abseil/absl/time/internal/cctz/include/cctz/civil_time.h b/third_party/abseil/absl/time/internal/cctz/include/cctz/civil_time.h
index 85d0d3f..d47ff86 100644
--- a/third_party/abseil/absl/time/internal/cctz/include/cctz/civil_time.h
+++ b/third_party/abseil/absl/time/internal/cctz/include/cctz/civil_time.h
@@ -15,9 +15,11 @@
#ifndef ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_
#define ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_
+#include "absl/base/config.h"
#include "absl/time/internal/cctz/include/cctz/civil_time_detail.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
@@ -150,7 +152,7 @@
//
// All civil-time types have accessors for all six of the civil-time fields:
// year, month, day, hour, minute, and second. Recall that fields inferior to
-// the type's aligment will be set to their minimum valid value.
+// the type's alignment will be set to their minimum valid value.
//
// civil_day d(2015, 6, 28);
// // d.year() == 2015
@@ -324,6 +326,7 @@
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_
diff --git a/third_party/abseil/absl/time/internal/cctz/include/cctz/civil_time_detail.h b/third_party/abseil/absl/time/internal/cctz/include/cctz/civil_time_detail.h
index 433078a..8aadde5 100644
--- a/third_party/abseil/absl/time/internal/cctz/include/cctz/civil_time_detail.h
+++ b/third_party/abseil/absl/time/internal/cctz/include/cctz/civil_time_detail.h
@@ -20,6 +20,8 @@
#include <ostream>
#include <type_traits>
+#include "absl/base/config.h"
+
// Disable constexpr support unless we are in C++14 mode.
#if __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910)
#define CONSTEXPR_D constexpr // data
@@ -32,6 +34,7 @@
#endif
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
@@ -53,8 +56,8 @@
// Normalized civil-time fields: Y-M-D HH:MM:SS.
struct fields {
- CONSTEXPR_M fields(year_t year, month_t month, day_t day,
- hour_t hour, minute_t minute, second_t second)
+ CONSTEXPR_M fields(year_t year, month_t month, day_t day, hour_t hour,
+ minute_t minute, second_t second)
: y(year), m(month), d(day), hh(hour), mm(minute), ss(second) {}
std::int_least64_t y;
std::int_least8_t m;
@@ -101,59 +104,69 @@
return k_days_per_month[m] + (m == 2 && is_leap_year(y));
}
-CONSTEXPR_F fields n_day(year_t y, month_t m, diff_t d, diff_t cd,
- hour_t hh, minute_t mm, second_t ss) noexcept {
- y += (cd / 146097) * 400;
+CONSTEXPR_F fields n_day(year_t y, month_t m, diff_t d, diff_t cd, hour_t hh,
+ minute_t mm, second_t ss) noexcept {
+ year_t ey = y % 400;
+ const year_t oey = ey;
+ ey += (cd / 146097) * 400;
cd %= 146097;
if (cd < 0) {
- y -= 400;
+ ey -= 400;
cd += 146097;
}
- y += (d / 146097) * 400;
+ ey += (d / 146097) * 400;
d = d % 146097 + cd;
if (d > 0) {
if (d > 146097) {
- y += 400;
+ ey += 400;
d -= 146097;
}
} else {
if (d > -365) {
// We often hit the previous year when stepping a civil time backwards,
// so special case it to avoid counting up by 100/4/1-year chunks.
- y -= 1;
- d += days_per_year(y, m);
+ ey -= 1;
+ d += days_per_year(ey, m);
} else {
- y -= 400;
+ ey -= 400;
d += 146097;
}
}
if (d > 365) {
- for (int n = days_per_century(y, m); d > n; n = days_per_century(y, m)) {
+ for (;;) {
+ int n = days_per_century(ey, m);
+ if (d <= n) break;
d -= n;
- y += 100;
+ ey += 100;
}
- for (int n = days_per_4years(y, m); d > n; n = days_per_4years(y, m)) {
+ for (;;) {
+ int n = days_per_4years(ey, m);
+ if (d <= n) break;
d -= n;
- y += 4;
+ ey += 4;
}
- for (int n = days_per_year(y, m); d > n; n = days_per_year(y, m)) {
+ for (;;) {
+ int n = days_per_year(ey, m);
+ if (d <= n) break;
d -= n;
- ++y;
+ ++ey;
}
}
if (d > 28) {
- for (int n = days_per_month(y, m); d > n; n = days_per_month(y, m)) {
+ for (;;) {
+ int n = days_per_month(ey, m);
+ if (d <= n) break;
d -= n;
if (++m > 12) {
- ++y;
+ ++ey;
m = 1;
}
}
}
- return fields(y, m, static_cast<day_t>(d), hh, mm, ss);
+ return fields(y + (ey - oey), m, static_cast<day_t>(d), hh, mm, ss);
}
-CONSTEXPR_F fields n_mon(year_t y, diff_t m, diff_t d, diff_t cd,
- hour_t hh, minute_t mm, second_t ss) noexcept {
+CONSTEXPR_F fields n_mon(year_t y, diff_t m, diff_t d, diff_t cd, hour_t hh,
+ minute_t mm, second_t ss) noexcept {
if (m != 12) {
y += m / 12;
m %= 12;
@@ -164,8 +177,8 @@
}
return n_day(y, static_cast<month_t>(m), d, cd, hh, mm, ss);
}
-CONSTEXPR_F fields n_hour(year_t y, diff_t m, diff_t d, diff_t cd,
- diff_t hh, minute_t mm, second_t ss) noexcept {
+CONSTEXPR_F fields n_hour(year_t y, diff_t m, diff_t d, diff_t cd, diff_t hh,
+ minute_t mm, second_t ss) noexcept {
cd += hh / 24;
hh %= 24;
if (hh < 0) {
@@ -264,8 +277,8 @@
// yet the difference between two such extreme values may actually be
// small, so we take a little care to avoid overflow when possible by
// exploiting the 146097-day cycle.
-CONSTEXPR_F diff_t day_difference(year_t y1, month_t m1, day_t d1,
- year_t y2, month_t m2, day_t d2) noexcept {
+CONSTEXPR_F diff_t day_difference(year_t y1, month_t m1, day_t d1, year_t y2,
+ month_t m2, day_t d2) noexcept {
const diff_t a_c4_off = y1 % 400;
const diff_t b_c4_off = y2 % 400;
diff_t c4_diff = (y1 - a_c4_off) - (y2 - b_c4_off);
@@ -305,9 +318,7 @@
////////////////////////////////////////////////////////////////////////
// Aligns the (normalized) fields struct to the indicated field.
-CONSTEXPR_F fields align(second_tag, fields f) noexcept {
- return f;
-}
+CONSTEXPR_F fields align(second_tag, fields f) noexcept { return f; }
CONSTEXPR_F fields align(minute_tag, fields f) noexcept {
return fields{f.y, f.m, f.d, f.hh, f.mm, 0};
}
@@ -386,11 +397,11 @@
: civil_time(ct.f_) {}
// Factories for the maximum/minimum representable civil_time.
- static CONSTEXPR_F civil_time (max)() {
+ static CONSTEXPR_F civil_time(max)() {
const auto max_year = (std::numeric_limits<std::int_least64_t>::max)();
return civil_time(max_year, 12, 31, 23, 59, 59);
}
- static CONSTEXPR_F civil_time (min)() {
+ static CONSTEXPR_F civil_time(min)() {
const auto min_year = (std::numeric_limits<std::int_least64_t>::min)();
return civil_time(min_year, 1, 1, 0, 0, 0);
}
@@ -405,28 +416,18 @@
// Assigning arithmetic.
CONSTEXPR_M civil_time& operator+=(diff_t n) noexcept {
- f_ = step(T{}, f_, n);
- return *this;
+ return *this = *this + n;
}
CONSTEXPR_M civil_time& operator-=(diff_t n) noexcept {
- if (n != (std::numeric_limits<diff_t>::min)()) {
- f_ = step(T{}, f_, -n);
- } else {
- f_ = step(T{}, step(T{}, f_, -(n + 1)), 1);
- }
- return *this;
+ return *this = *this - n;
}
- CONSTEXPR_M civil_time& operator++() noexcept {
- return *this += 1;
- }
+ CONSTEXPR_M civil_time& operator++() noexcept { return *this += 1; }
CONSTEXPR_M civil_time operator++(int) noexcept {
const civil_time a = *this;
++*this;
return a;
}
- CONSTEXPR_M civil_time& operator--() noexcept {
- return *this -= 1;
- }
+ CONSTEXPR_M civil_time& operator--() noexcept { return *this -= 1; }
CONSTEXPR_M civil_time operator--(int) noexcept {
const civil_time a = *this;
--*this;
@@ -435,13 +436,15 @@
// Binary arithmetic operators.
friend CONSTEXPR_F civil_time operator+(civil_time a, diff_t n) noexcept {
- return a += n;
+ return civil_time(step(T{}, a.f_, n));
}
friend CONSTEXPR_F civil_time operator+(diff_t n, civil_time a) noexcept {
- return a += n;
+ return a + n;
}
friend CONSTEXPR_F civil_time operator-(civil_time a, diff_t n) noexcept {
- return a -= n;
+ return n != (std::numeric_limits<diff_t>::min)()
+ ? civil_time(step(T{}, a.f_, -n))
+ : civil_time(step(T{}, step(T{}, a.f_, -(n + 1)), 1));
}
friend CONSTEXPR_F diff_t operator-(civil_time lhs, civil_time rhs) noexcept {
return difference(T{}, lhs.f_, rhs.f_);
@@ -483,17 +486,17 @@
template <typename T1, typename T2>
CONSTEXPR_F bool operator<(const civil_time<T1>& lhs,
const civil_time<T2>& rhs) noexcept {
- return (lhs.year() < rhs.year() ||
- (lhs.year() == rhs.year() &&
- (lhs.month() < rhs.month() ||
- (lhs.month() == rhs.month() &&
- (lhs.day() < rhs.day() ||
- (lhs.day() == rhs.day() &&
- (lhs.hour() < rhs.hour() ||
- (lhs.hour() == rhs.hour() &&
- (lhs.minute() < rhs.minute() ||
- (lhs.minute() == rhs.minute() &&
- (lhs.second() < rhs.second())))))))))));
+ return (
+ lhs.year() < rhs.year() ||
+ (lhs.year() == rhs.year() &&
+ (lhs.month() < rhs.month() ||
+ (lhs.month() == rhs.month() &&
+ (lhs.day() < rhs.day() || (lhs.day() == rhs.day() &&
+ (lhs.hour() < rhs.hour() ||
+ (lhs.hour() == rhs.hour() &&
+ (lhs.minute() < rhs.minute() ||
+ (lhs.minute() == rhs.minute() &&
+ (lhs.second() < rhs.second())))))))))));
}
template <typename T1, typename T2>
CONSTEXPR_F bool operator<=(const civil_time<T1>& lhs,
@@ -615,6 +618,7 @@
} // namespace detail
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
#undef CONSTEXPR_M
diff --git a/third_party/abseil/absl/time/internal/cctz/include/cctz/time_zone.h b/third_party/abseil/absl/time/internal/cctz/include/cctz/time_zone.h
index ef6c4ba..5562a37 100644
--- a/third_party/abseil/absl/time/internal/cctz/include/cctz/time_zone.h
+++ b/third_party/abseil/absl/time/internal/cctz/include/cctz/time_zone.h
@@ -25,9 +25,11 @@
#include <string>
#include <utility>
+#include "absl/base/config.h"
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
@@ -39,8 +41,8 @@
namespace detail {
template <typename D>
-inline std::pair<time_point<seconds>, D>
-split_seconds(const time_point<D>& tp) {
+inline std::pair<time_point<seconds>, D> split_seconds(
+ const time_point<D>& tp) {
auto sec = std::chrono::time_point_cast<seconds>(tp);
auto sub = tp - sec;
if (sub.count() < 0) {
@@ -49,8 +51,8 @@
}
return {sec, std::chrono::duration_cast<D>(sub)};
}
-inline std::pair<time_point<seconds>, seconds>
-split_seconds(const time_point<seconds>& tp) {
+inline std::pair<time_point<seconds>, seconds> split_seconds(
+ const time_point<seconds>& tp) {
return {tp, seconds::zero()};
}
} // namespace detail
@@ -194,22 +196,20 @@
bool next_transition(const time_point<seconds>& tp,
civil_transition* trans) const;
template <typename D>
- bool next_transition(const time_point<D>& tp,
- civil_transition* trans) const {
+ bool next_transition(const time_point<D>& tp, civil_transition* trans) const {
return next_transition(detail::split_seconds(tp).first, trans);
}
bool prev_transition(const time_point<seconds>& tp,
civil_transition* trans) const;
template <typename D>
- bool prev_transition(const time_point<D>& tp,
- civil_transition* trans) const {
+ bool prev_transition(const time_point<D>& tp, civil_transition* trans) const {
return prev_transition(detail::split_seconds(tp).first, trans);
}
// version() and description() provide additional information about the
// time zone. The content of each of the returned strings is unspecified,
// however, when the IANA Time Zone Database is the underlying data source
- // the version() std::string will be in the familar form (e.g, "2018e") or
+ // the version() string will be in the familar form (e.g, "2018e") or
// empty when unavailable.
//
// Note: These functions are for informational or testing purposes only.
@@ -220,9 +220,7 @@
friend bool operator==(time_zone lhs, time_zone rhs) {
return &lhs.effective_impl() == &rhs.effective_impl();
}
- friend bool operator!=(time_zone lhs, time_zone rhs) {
- return !(lhs == rhs);
- }
+ friend bool operator!=(time_zone lhs, time_zone rhs) { return !(lhs == rhs); }
template <typename H>
friend H AbslHashValue(H h, time_zone tz) {
@@ -294,6 +292,7 @@
// - %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)
+// - %ET - The RFC3339 "date-time" separator "T"
//
// 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'.
@@ -323,7 +322,8 @@
// returns the corresponding time_point. Uses strftime()-like formatting
// options, with the same extensions as cctz::format(), but with the
// exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez
-// and %E*z also accept the same inputs.
+// and %E*z also accept the same inputs, which (along with %z) includes
+// 'z' and 'Z' as synonyms for +00:00. %ET accepts either 'T' or 't'.
//
// %Y consumes as many numeric characters as it can, so the matching data
// should always be terminated with a non-numeric. %E4Y always consumes
@@ -380,6 +380,7 @@
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_
diff --git a/third_party/abseil/absl/time/internal/cctz/include/cctz/zone_info_source.h b/third_party/abseil/absl/time/internal/cctz/include/cctz/zone_info_source.h
index 2b898d1..012eb4e 100644
--- a/third_party/abseil/absl/time/internal/cctz/include/cctz/zone_info_source.h
+++ b/third_party/abseil/absl/time/internal/cctz/include/cctz/zone_info_source.h
@@ -20,7 +20,10 @@
#include <memory>
#include <string>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
@@ -30,19 +33,21 @@
virtual ~ZoneInfoSource();
virtual std::size_t Read(void* ptr, std::size_t size) = 0; // like fread()
- virtual int Skip(std::size_t offset) = 0; // like fseek()
+ virtual int Skip(std::size_t offset) = 0; // like fseek()
// Until the zoneinfo data supports versioning information, we provide
// a way for a ZoneInfoSource to indicate it out-of-band. The default
- // implementation returns an empty std::string.
+ // implementation returns an empty string.
virtual std::string Version() const;
};
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz_extension {
@@ -52,8 +57,8 @@
using ZoneInfoSourceFactory =
std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource> (*)(
const std::string&,
- const std::function<std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource>(
- const std::string&)>&);
+ const std::function<std::unique_ptr<
+ absl::time_internal::cctz::ZoneInfoSource>(const std::string&)>&);
// The user can control the mapping of zone names to zoneinfo data by
// providing a definition for cctz_extension::zone_info_source_factory.
@@ -91,6 +96,7 @@
} // namespace cctz_extension
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_ZONE_INFO_SOURCE_H_
diff --git a/third_party/abseil/absl/time/internal/cctz/src/cctz_benchmark.cc b/third_party/abseil/absl/time/internal/cctz/src/cctz_benchmark.cc
index a40f504..4e39188 100644
--- a/third_party/abseil/absl/time/internal/cctz/src/cctz_benchmark.cc
+++ b/third_party/abseil/absl/time/internal/cctz/src/cctz_benchmark.cc
@@ -97,609 +97,608 @@
}
BENCHMARK(BM_PrevWeekday);
-const char RFC3339_full[] = "%Y-%m-%dT%H:%M:%E*S%Ez";
-const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez";
+const char RFC3339_full[] = "%Y-%m-%d%ET%H:%M:%E*S%Ez";
+const char RFC3339_sec[] = "%Y-%m-%d%ET%H:%M:%S%Ez";
const char RFC1123_full[] = "%a, %d %b %Y %H:%M:%S %z";
const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z";
// A list of known time-zone names.
// TODO: Refactor with src/time_zone_lookup_test.cc.
-const char* const kTimeZoneNames[] = {
- "Africa/Abidjan",
- "Africa/Accra",
- "Africa/Addis_Ababa",
- "Africa/Algiers",
- "Africa/Asmara",
- "Africa/Asmera",
- "Africa/Bamako",
- "Africa/Bangui",
- "Africa/Banjul",
- "Africa/Bissau",
- "Africa/Blantyre",
- "Africa/Brazzaville",
- "Africa/Bujumbura",
- "Africa/Cairo",
- "Africa/Casablanca",
- "Africa/Ceuta",
- "Africa/Conakry",
- "Africa/Dakar",
- "Africa/Dar_es_Salaam",
- "Africa/Djibouti",
- "Africa/Douala",
- "Africa/El_Aaiun",
- "Africa/Freetown",
- "Africa/Gaborone",
- "Africa/Harare",
- "Africa/Johannesburg",
- "Africa/Juba",
- "Africa/Kampala",
- "Africa/Khartoum",
- "Africa/Kigali",
- "Africa/Kinshasa",
- "Africa/Lagos",
- "Africa/Libreville",
- "Africa/Lome",
- "Africa/Luanda",
- "Africa/Lubumbashi",
- "Africa/Lusaka",
- "Africa/Malabo",
- "Africa/Maputo",
- "Africa/Maseru",
- "Africa/Mbabane",
- "Africa/Mogadishu",
- "Africa/Monrovia",
- "Africa/Nairobi",
- "Africa/Ndjamena",
- "Africa/Niamey",
- "Africa/Nouakchott",
- "Africa/Ouagadougou",
- "Africa/Porto-Novo",
- "Africa/Sao_Tome",
- "Africa/Timbuktu",
- "Africa/Tripoli",
- "Africa/Tunis",
- "Africa/Windhoek",
- "America/Adak",
- "America/Anchorage",
- "America/Anguilla",
- "America/Antigua",
- "America/Araguaina",
- "America/Argentina/Buenos_Aires",
- "America/Argentina/Catamarca",
- "America/Argentina/ComodRivadavia",
- "America/Argentina/Cordoba",
- "America/Argentina/Jujuy",
- "America/Argentina/La_Rioja",
- "America/Argentina/Mendoza",
- "America/Argentina/Rio_Gallegos",
- "America/Argentina/Salta",
- "America/Argentina/San_Juan",
- "America/Argentina/San_Luis",
- "America/Argentina/Tucuman",
- "America/Argentina/Ushuaia",
- "America/Aruba",
- "America/Asuncion",
- "America/Atikokan",
- "America/Atka",
- "America/Bahia",
- "America/Bahia_Banderas",
- "America/Barbados",
- "America/Belem",
- "America/Belize",
- "America/Blanc-Sablon",
- "America/Boa_Vista",
- "America/Bogota",
- "America/Boise",
- "America/Buenos_Aires",
- "America/Cambridge_Bay",
- "America/Campo_Grande",
- "America/Cancun",
- "America/Caracas",
- "America/Catamarca",
- "America/Cayenne",
- "America/Cayman",
- "America/Chicago",
- "America/Chihuahua",
- "America/Coral_Harbour",
- "America/Cordoba",
- "America/Costa_Rica",
- "America/Creston",
- "America/Cuiaba",
- "America/Curacao",
- "America/Danmarkshavn",
- "America/Dawson",
- "America/Dawson_Creek",
- "America/Denver",
- "America/Detroit",
- "America/Dominica",
- "America/Edmonton",
- "America/Eirunepe",
- "America/El_Salvador",
- "America/Ensenada",
- "America/Fort_Nelson",
- "America/Fort_Wayne",
- "America/Fortaleza",
- "America/Glace_Bay",
- "America/Godthab",
- "America/Goose_Bay",
- "America/Grand_Turk",
- "America/Grenada",
- "America/Guadeloupe",
- "America/Guatemala",
- "America/Guayaquil",
- "America/Guyana",
- "America/Halifax",
- "America/Havana",
- "America/Hermosillo",
- "America/Indiana/Indianapolis",
- "America/Indiana/Knox",
- "America/Indiana/Marengo",
- "America/Indiana/Petersburg",
- "America/Indiana/Tell_City",
- "America/Indiana/Vevay",
- "America/Indiana/Vincennes",
- "America/Indiana/Winamac",
- "America/Indianapolis",
- "America/Inuvik",
- "America/Iqaluit",
- "America/Jamaica",
- "America/Jujuy",
- "America/Juneau",
- "America/Kentucky/Louisville",
- "America/Kentucky/Monticello",
- "America/Knox_IN",
- "America/Kralendijk",
- "America/La_Paz",
- "America/Lima",
- "America/Los_Angeles",
- "America/Louisville",
- "America/Lower_Princes",
- "America/Maceio",
- "America/Managua",
- "America/Manaus",
- "America/Marigot",
- "America/Martinique",
- "America/Matamoros",
- "America/Mazatlan",
- "America/Mendoza",
- "America/Menominee",
- "America/Merida",
- "America/Metlakatla",
- "America/Mexico_City",
- "America/Miquelon",
- "America/Moncton",
- "America/Monterrey",
- "America/Montevideo",
- "America/Montreal",
- "America/Montserrat",
- "America/Nassau",
- "America/New_York",
- "America/Nipigon",
- "America/Nome",
- "America/Noronha",
- "America/North_Dakota/Beulah",
- "America/North_Dakota/Center",
- "America/North_Dakota/New_Salem",
- "America/Ojinaga",
- "America/Panama",
- "America/Pangnirtung",
- "America/Paramaribo",
- "America/Phoenix",
- "America/Port-au-Prince",
- "America/Port_of_Spain",
- "America/Porto_Acre",
- "America/Porto_Velho",
- "America/Puerto_Rico",
- "America/Punta_Arenas",
- "America/Rainy_River",
- "America/Rankin_Inlet",
- "America/Recife",
- "America/Regina",
- "America/Resolute",
- "America/Rio_Branco",
- "America/Rosario",
- "America/Santa_Isabel",
- "America/Santarem",
- "America/Santiago",
- "America/Santo_Domingo",
- "America/Sao_Paulo",
- "America/Scoresbysund",
- "America/Shiprock",
- "America/Sitka",
- "America/St_Barthelemy",
- "America/St_Johns",
- "America/St_Kitts",
- "America/St_Lucia",
- "America/St_Thomas",
- "America/St_Vincent",
- "America/Swift_Current",
- "America/Tegucigalpa",
- "America/Thule",
- "America/Thunder_Bay",
- "America/Tijuana",
- "America/Toronto",
- "America/Tortola",
- "America/Vancouver",
- "America/Virgin",
- "America/Whitehorse",
- "America/Winnipeg",
- "America/Yakutat",
- "America/Yellowknife",
- "Antarctica/Casey",
- "Antarctica/Davis",
- "Antarctica/DumontDUrville",
- "Antarctica/Macquarie",
- "Antarctica/Mawson",
- "Antarctica/McMurdo",
- "Antarctica/Palmer",
- "Antarctica/Rothera",
- "Antarctica/South_Pole",
- "Antarctica/Syowa",
- "Antarctica/Troll",
- "Antarctica/Vostok",
- "Arctic/Longyearbyen",
- "Asia/Aden",
- "Asia/Almaty",
- "Asia/Amman",
- "Asia/Anadyr",
- "Asia/Aqtau",
- "Asia/Aqtobe",
- "Asia/Ashgabat",
- "Asia/Ashkhabad",
- "Asia/Atyrau",
- "Asia/Baghdad",
- "Asia/Bahrain",
- "Asia/Baku",
- "Asia/Bangkok",
- "Asia/Barnaul",
- "Asia/Beirut",
- "Asia/Bishkek",
- "Asia/Brunei",
- "Asia/Calcutta",
- "Asia/Chita",
- "Asia/Choibalsan",
- "Asia/Chongqing",
- "Asia/Chungking",
- "Asia/Colombo",
- "Asia/Dacca",
- "Asia/Damascus",
- "Asia/Dhaka",
- "Asia/Dili",
- "Asia/Dubai",
- "Asia/Dushanbe",
- "Asia/Famagusta",
- "Asia/Gaza",
- "Asia/Harbin",
- "Asia/Hebron",
- "Asia/Ho_Chi_Minh",
- "Asia/Hong_Kong",
- "Asia/Hovd",
- "Asia/Irkutsk",
- "Asia/Istanbul",
- "Asia/Jakarta",
- "Asia/Jayapura",
- "Asia/Jerusalem",
- "Asia/Kabul",
- "Asia/Kamchatka",
- "Asia/Karachi",
- "Asia/Kashgar",
- "Asia/Kathmandu",
- "Asia/Katmandu",
- "Asia/Khandyga",
- "Asia/Kolkata",
- "Asia/Krasnoyarsk",
- "Asia/Kuala_Lumpur",
- "Asia/Kuching",
- "Asia/Kuwait",
- "Asia/Macao",
- "Asia/Macau",
- "Asia/Magadan",
- "Asia/Makassar",
- "Asia/Manila",
- "Asia/Muscat",
- "Asia/Nicosia",
- "Asia/Novokuznetsk",
- "Asia/Novosibirsk",
- "Asia/Omsk",
- "Asia/Oral",
- "Asia/Phnom_Penh",
- "Asia/Pontianak",
- "Asia/Pyongyang",
- "Asia/Qatar",
- "Asia/Qostanay",
- "Asia/Qyzylorda",
- "Asia/Rangoon",
- "Asia/Riyadh",
- "Asia/Saigon",
- "Asia/Sakhalin",
- "Asia/Samarkand",
- "Asia/Seoul",
- "Asia/Shanghai",
- "Asia/Singapore",
- "Asia/Srednekolymsk",
- "Asia/Taipei",
- "Asia/Tashkent",
- "Asia/Tbilisi",
- "Asia/Tehran",
- "Asia/Tel_Aviv",
- "Asia/Thimbu",
- "Asia/Thimphu",
- "Asia/Tokyo",
- "Asia/Tomsk",
- "Asia/Ujung_Pandang",
- "Asia/Ulaanbaatar",
- "Asia/Ulan_Bator",
- "Asia/Urumqi",
- "Asia/Ust-Nera",
- "Asia/Vientiane",
- "Asia/Vladivostok",
- "Asia/Yakutsk",
- "Asia/Yangon",
- "Asia/Yekaterinburg",
- "Asia/Yerevan",
- "Atlantic/Azores",
- "Atlantic/Bermuda",
- "Atlantic/Canary",
- "Atlantic/Cape_Verde",
- "Atlantic/Faeroe",
- "Atlantic/Faroe",
- "Atlantic/Jan_Mayen",
- "Atlantic/Madeira",
- "Atlantic/Reykjavik",
- "Atlantic/South_Georgia",
- "Atlantic/St_Helena",
- "Atlantic/Stanley",
- "Australia/ACT",
- "Australia/Adelaide",
- "Australia/Brisbane",
- "Australia/Broken_Hill",
- "Australia/Canberra",
- "Australia/Currie",
- "Australia/Darwin",
- "Australia/Eucla",
- "Australia/Hobart",
- "Australia/LHI",
- "Australia/Lindeman",
- "Australia/Lord_Howe",
- "Australia/Melbourne",
- "Australia/NSW",
- "Australia/North",
- "Australia/Perth",
- "Australia/Queensland",
- "Australia/South",
- "Australia/Sydney",
- "Australia/Tasmania",
- "Australia/Victoria",
- "Australia/West",
- "Australia/Yancowinna",
- "Brazil/Acre",
- "Brazil/DeNoronha",
- "Brazil/East",
- "Brazil/West",
- "CET",
- "CST6CDT",
- "Canada/Atlantic",
- "Canada/Central",
- "Canada/Eastern",
- "Canada/Mountain",
- "Canada/Newfoundland",
- "Canada/Pacific",
- "Canada/Saskatchewan",
- "Canada/Yukon",
- "Chile/Continental",
- "Chile/EasterIsland",
- "Cuba",
- "EET",
- "EST",
- "EST5EDT",
- "Egypt",
- "Eire",
- "Etc/GMT",
- "Etc/GMT+0",
- "Etc/GMT+1",
- "Etc/GMT+10",
- "Etc/GMT+11",
- "Etc/GMT+12",
- "Etc/GMT+2",
- "Etc/GMT+3",
- "Etc/GMT+4",
- "Etc/GMT+5",
- "Etc/GMT+6",
- "Etc/GMT+7",
- "Etc/GMT+8",
- "Etc/GMT+9",
- "Etc/GMT-0",
- "Etc/GMT-1",
- "Etc/GMT-10",
- "Etc/GMT-11",
- "Etc/GMT-12",
- "Etc/GMT-13",
- "Etc/GMT-14",
- "Etc/GMT-2",
- "Etc/GMT-3",
- "Etc/GMT-4",
- "Etc/GMT-5",
- "Etc/GMT-6",
- "Etc/GMT-7",
- "Etc/GMT-8",
- "Etc/GMT-9",
- "Etc/GMT0",
- "Etc/Greenwich",
- "Etc/UCT",
- "Etc/UTC",
- "Etc/Universal",
- "Etc/Zulu",
- "Europe/Amsterdam",
- "Europe/Andorra",
- "Europe/Astrakhan",
- "Europe/Athens",
- "Europe/Belfast",
- "Europe/Belgrade",
- "Europe/Berlin",
- "Europe/Bratislava",
- "Europe/Brussels",
- "Europe/Bucharest",
- "Europe/Budapest",
- "Europe/Busingen",
- "Europe/Chisinau",
- "Europe/Copenhagen",
- "Europe/Dublin",
- "Europe/Gibraltar",
- "Europe/Guernsey",
- "Europe/Helsinki",
- "Europe/Isle_of_Man",
- "Europe/Istanbul",
- "Europe/Jersey",
- "Europe/Kaliningrad",
- "Europe/Kiev",
- "Europe/Kirov",
- "Europe/Lisbon",
- "Europe/Ljubljana",
- "Europe/London",
- "Europe/Luxembourg",
- "Europe/Madrid",
- "Europe/Malta",
- "Europe/Mariehamn",
- "Europe/Minsk",
- "Europe/Monaco",
- "Europe/Moscow",
- "Europe/Nicosia",
- "Europe/Oslo",
- "Europe/Paris",
- "Europe/Podgorica",
- "Europe/Prague",
- "Europe/Riga",
- "Europe/Rome",
- "Europe/Samara",
- "Europe/San_Marino",
- "Europe/Sarajevo",
- "Europe/Saratov",
- "Europe/Simferopol",
- "Europe/Skopje",
- "Europe/Sofia",
- "Europe/Stockholm",
- "Europe/Tallinn",
- "Europe/Tirane",
- "Europe/Tiraspol",
- "Europe/Ulyanovsk",
- "Europe/Uzhgorod",
- "Europe/Vaduz",
- "Europe/Vatican",
- "Europe/Vienna",
- "Europe/Vilnius",
- "Europe/Volgograd",
- "Europe/Warsaw",
- "Europe/Zagreb",
- "Europe/Zaporozhye",
- "Europe/Zurich",
- "GB",
- "GB-Eire",
- "GMT",
- "GMT+0",
- "GMT-0",
- "GMT0",
- "Greenwich",
- "HST",
- "Hongkong",
- "Iceland",
- "Indian/Antananarivo",
- "Indian/Chagos",
- "Indian/Christmas",
- "Indian/Cocos",
- "Indian/Comoro",
- "Indian/Kerguelen",
- "Indian/Mahe",
- "Indian/Maldives",
- "Indian/Mauritius",
- "Indian/Mayotte",
- "Indian/Reunion",
- "Iran",
- "Israel",
- "Jamaica",
- "Japan",
- "Kwajalein",
- "Libya",
- "MET",
- "MST",
- "MST7MDT",
- "Mexico/BajaNorte",
- "Mexico/BajaSur",
- "Mexico/General",
- "NZ",
- "NZ-CHAT",
- "Navajo",
- "PRC",
- "PST8PDT",
- "Pacific/Apia",
- "Pacific/Auckland",
- "Pacific/Bougainville",
- "Pacific/Chatham",
- "Pacific/Chuuk",
- "Pacific/Easter",
- "Pacific/Efate",
- "Pacific/Enderbury",
- "Pacific/Fakaofo",
- "Pacific/Fiji",
- "Pacific/Funafuti",
- "Pacific/Galapagos",
- "Pacific/Gambier",
- "Pacific/Guadalcanal",
- "Pacific/Guam",
- "Pacific/Honolulu",
- "Pacific/Johnston",
- "Pacific/Kiritimati",
- "Pacific/Kosrae",
- "Pacific/Kwajalein",
- "Pacific/Majuro",
- "Pacific/Marquesas",
- "Pacific/Midway",
- "Pacific/Nauru",
- "Pacific/Niue",
- "Pacific/Norfolk",
- "Pacific/Noumea",
- "Pacific/Pago_Pago",
- "Pacific/Palau",
- "Pacific/Pitcairn",
- "Pacific/Pohnpei",
- "Pacific/Ponape",
- "Pacific/Port_Moresby",
- "Pacific/Rarotonga",
- "Pacific/Saipan",
- "Pacific/Samoa",
- "Pacific/Tahiti",
- "Pacific/Tarawa",
- "Pacific/Tongatapu",
- "Pacific/Truk",
- "Pacific/Wake",
- "Pacific/Wallis",
- "Pacific/Yap",
- "Poland",
- "Portugal",
- "ROC",
- "ROK",
- "Singapore",
- "Turkey",
- "UCT",
- "US/Alaska",
- "US/Aleutian",
- "US/Arizona",
- "US/Central",
- "US/East-Indiana",
- "US/Eastern",
- "US/Hawaii",
- "US/Indiana-Starke",
- "US/Michigan",
- "US/Mountain",
- "US/Pacific",
- "US/Samoa",
- "UTC",
- "Universal",
- "W-SU",
- "WET",
- "Zulu",
- nullptr
-};
+const char* const kTimeZoneNames[] = {"Africa/Abidjan",
+ "Africa/Accra",
+ "Africa/Addis_Ababa",
+ "Africa/Algiers",
+ "Africa/Asmara",
+ "Africa/Asmera",
+ "Africa/Bamako",
+ "Africa/Bangui",
+ "Africa/Banjul",
+ "Africa/Bissau",
+ "Africa/Blantyre",
+ "Africa/Brazzaville",
+ "Africa/Bujumbura",
+ "Africa/Cairo",
+ "Africa/Casablanca",
+ "Africa/Ceuta",
+ "Africa/Conakry",
+ "Africa/Dakar",
+ "Africa/Dar_es_Salaam",
+ "Africa/Djibouti",
+ "Africa/Douala",
+ "Africa/El_Aaiun",
+ "Africa/Freetown",
+ "Africa/Gaborone",
+ "Africa/Harare",
+ "Africa/Johannesburg",
+ "Africa/Juba",
+ "Africa/Kampala",
+ "Africa/Khartoum",
+ "Africa/Kigali",
+ "Africa/Kinshasa",
+ "Africa/Lagos",
+ "Africa/Libreville",
+ "Africa/Lome",
+ "Africa/Luanda",
+ "Africa/Lubumbashi",
+ "Africa/Lusaka",
+ "Africa/Malabo",
+ "Africa/Maputo",
+ "Africa/Maseru",
+ "Africa/Mbabane",
+ "Africa/Mogadishu",
+ "Africa/Monrovia",
+ "Africa/Nairobi",
+ "Africa/Ndjamena",
+ "Africa/Niamey",
+ "Africa/Nouakchott",
+ "Africa/Ouagadougou",
+ "Africa/Porto-Novo",
+ "Africa/Sao_Tome",
+ "Africa/Timbuktu",
+ "Africa/Tripoli",
+ "Africa/Tunis",
+ "Africa/Windhoek",
+ "America/Adak",
+ "America/Anchorage",
+ "America/Anguilla",
+ "America/Antigua",
+ "America/Araguaina",
+ "America/Argentina/Buenos_Aires",
+ "America/Argentina/Catamarca",
+ "America/Argentina/ComodRivadavia",
+ "America/Argentina/Cordoba",
+ "America/Argentina/Jujuy",
+ "America/Argentina/La_Rioja",
+ "America/Argentina/Mendoza",
+ "America/Argentina/Rio_Gallegos",
+ "America/Argentina/Salta",
+ "America/Argentina/San_Juan",
+ "America/Argentina/San_Luis",
+ "America/Argentina/Tucuman",
+ "America/Argentina/Ushuaia",
+ "America/Aruba",
+ "America/Asuncion",
+ "America/Atikokan",
+ "America/Atka",
+ "America/Bahia",
+ "America/Bahia_Banderas",
+ "America/Barbados",
+ "America/Belem",
+ "America/Belize",
+ "America/Blanc-Sablon",
+ "America/Boa_Vista",
+ "America/Bogota",
+ "America/Boise",
+ "America/Buenos_Aires",
+ "America/Cambridge_Bay",
+ "America/Campo_Grande",
+ "America/Cancun",
+ "America/Caracas",
+ "America/Catamarca",
+ "America/Cayenne",
+ "America/Cayman",
+ "America/Chicago",
+ "America/Chihuahua",
+ "America/Coral_Harbour",
+ "America/Cordoba",
+ "America/Costa_Rica",
+ "America/Creston",
+ "America/Cuiaba",
+ "America/Curacao",
+ "America/Danmarkshavn",
+ "America/Dawson",
+ "America/Dawson_Creek",
+ "America/Denver",
+ "America/Detroit",
+ "America/Dominica",
+ "America/Edmonton",
+ "America/Eirunepe",
+ "America/El_Salvador",
+ "America/Ensenada",
+ "America/Fort_Nelson",
+ "America/Fort_Wayne",
+ "America/Fortaleza",
+ "America/Glace_Bay",
+ "America/Godthab",
+ "America/Goose_Bay",
+ "America/Grand_Turk",
+ "America/Grenada",
+ "America/Guadeloupe",
+ "America/Guatemala",
+ "America/Guayaquil",
+ "America/Guyana",
+ "America/Halifax",
+ "America/Havana",
+ "America/Hermosillo",
+ "America/Indiana/Indianapolis",
+ "America/Indiana/Knox",
+ "America/Indiana/Marengo",
+ "America/Indiana/Petersburg",
+ "America/Indiana/Tell_City",
+ "America/Indiana/Vevay",
+ "America/Indiana/Vincennes",
+ "America/Indiana/Winamac",
+ "America/Indianapolis",
+ "America/Inuvik",
+ "America/Iqaluit",
+ "America/Jamaica",
+ "America/Jujuy",
+ "America/Juneau",
+ "America/Kentucky/Louisville",
+ "America/Kentucky/Monticello",
+ "America/Knox_IN",
+ "America/Kralendijk",
+ "America/La_Paz",
+ "America/Lima",
+ "America/Los_Angeles",
+ "America/Louisville",
+ "America/Lower_Princes",
+ "America/Maceio",
+ "America/Managua",
+ "America/Manaus",
+ "America/Marigot",
+ "America/Martinique",
+ "America/Matamoros",
+ "America/Mazatlan",
+ "America/Mendoza",
+ "America/Menominee",
+ "America/Merida",
+ "America/Metlakatla",
+ "America/Mexico_City",
+ "America/Miquelon",
+ "America/Moncton",
+ "America/Monterrey",
+ "America/Montevideo",
+ "America/Montreal",
+ "America/Montserrat",
+ "America/Nassau",
+ "America/New_York",
+ "America/Nipigon",
+ "America/Nome",
+ "America/Noronha",
+ "America/North_Dakota/Beulah",
+ "America/North_Dakota/Center",
+ "America/North_Dakota/New_Salem",
+ "America/Nuuk",
+ "America/Ojinaga",
+ "America/Panama",
+ "America/Pangnirtung",
+ "America/Paramaribo",
+ "America/Phoenix",
+ "America/Port-au-Prince",
+ "America/Port_of_Spain",
+ "America/Porto_Acre",
+ "America/Porto_Velho",
+ "America/Puerto_Rico",
+ "America/Punta_Arenas",
+ "America/Rainy_River",
+ "America/Rankin_Inlet",
+ "America/Recife",
+ "America/Regina",
+ "America/Resolute",
+ "America/Rio_Branco",
+ "America/Rosario",
+ "America/Santa_Isabel",
+ "America/Santarem",
+ "America/Santiago",
+ "America/Santo_Domingo",
+ "America/Sao_Paulo",
+ "America/Scoresbysund",
+ "America/Shiprock",
+ "America/Sitka",
+ "America/St_Barthelemy",
+ "America/St_Johns",
+ "America/St_Kitts",
+ "America/St_Lucia",
+ "America/St_Thomas",
+ "America/St_Vincent",
+ "America/Swift_Current",
+ "America/Tegucigalpa",
+ "America/Thule",
+ "America/Thunder_Bay",
+ "America/Tijuana",
+ "America/Toronto",
+ "America/Tortola",
+ "America/Vancouver",
+ "America/Virgin",
+ "America/Whitehorse",
+ "America/Winnipeg",
+ "America/Yakutat",
+ "America/Yellowknife",
+ "Antarctica/Casey",
+ "Antarctica/Davis",
+ "Antarctica/DumontDUrville",
+ "Antarctica/Macquarie",
+ "Antarctica/Mawson",
+ "Antarctica/McMurdo",
+ "Antarctica/Palmer",
+ "Antarctica/Rothera",
+ "Antarctica/South_Pole",
+ "Antarctica/Syowa",
+ "Antarctica/Troll",
+ "Antarctica/Vostok",
+ "Arctic/Longyearbyen",
+ "Asia/Aden",
+ "Asia/Almaty",
+ "Asia/Amman",
+ "Asia/Anadyr",
+ "Asia/Aqtau",
+ "Asia/Aqtobe",
+ "Asia/Ashgabat",
+ "Asia/Ashkhabad",
+ "Asia/Atyrau",
+ "Asia/Baghdad",
+ "Asia/Bahrain",
+ "Asia/Baku",
+ "Asia/Bangkok",
+ "Asia/Barnaul",
+ "Asia/Beirut",
+ "Asia/Bishkek",
+ "Asia/Brunei",
+ "Asia/Calcutta",
+ "Asia/Chita",
+ "Asia/Choibalsan",
+ "Asia/Chongqing",
+ "Asia/Chungking",
+ "Asia/Colombo",
+ "Asia/Dacca",
+ "Asia/Damascus",
+ "Asia/Dhaka",
+ "Asia/Dili",
+ "Asia/Dubai",
+ "Asia/Dushanbe",
+ "Asia/Famagusta",
+ "Asia/Gaza",
+ "Asia/Harbin",
+ "Asia/Hebron",
+ "Asia/Ho_Chi_Minh",
+ "Asia/Hong_Kong",
+ "Asia/Hovd",
+ "Asia/Irkutsk",
+ "Asia/Istanbul",
+ "Asia/Jakarta",
+ "Asia/Jayapura",
+ "Asia/Jerusalem",
+ "Asia/Kabul",
+ "Asia/Kamchatka",
+ "Asia/Karachi",
+ "Asia/Kashgar",
+ "Asia/Kathmandu",
+ "Asia/Katmandu",
+ "Asia/Khandyga",
+ "Asia/Kolkata",
+ "Asia/Krasnoyarsk",
+ "Asia/Kuala_Lumpur",
+ "Asia/Kuching",
+ "Asia/Kuwait",
+ "Asia/Macao",
+ "Asia/Macau",
+ "Asia/Magadan",
+ "Asia/Makassar",
+ "Asia/Manila",
+ "Asia/Muscat",
+ "Asia/Nicosia",
+ "Asia/Novokuznetsk",
+ "Asia/Novosibirsk",
+ "Asia/Omsk",
+ "Asia/Oral",
+ "Asia/Phnom_Penh",
+ "Asia/Pontianak",
+ "Asia/Pyongyang",
+ "Asia/Qatar",
+ "Asia/Qostanay",
+ "Asia/Qyzylorda",
+ "Asia/Rangoon",
+ "Asia/Riyadh",
+ "Asia/Saigon",
+ "Asia/Sakhalin",
+ "Asia/Samarkand",
+ "Asia/Seoul",
+ "Asia/Shanghai",
+ "Asia/Singapore",
+ "Asia/Srednekolymsk",
+ "Asia/Taipei",
+ "Asia/Tashkent",
+ "Asia/Tbilisi",
+ "Asia/Tehran",
+ "Asia/Tel_Aviv",
+ "Asia/Thimbu",
+ "Asia/Thimphu",
+ "Asia/Tokyo",
+ "Asia/Tomsk",
+ "Asia/Ujung_Pandang",
+ "Asia/Ulaanbaatar",
+ "Asia/Ulan_Bator",
+ "Asia/Urumqi",
+ "Asia/Ust-Nera",
+ "Asia/Vientiane",
+ "Asia/Vladivostok",
+ "Asia/Yakutsk",
+ "Asia/Yangon",
+ "Asia/Yekaterinburg",
+ "Asia/Yerevan",
+ "Atlantic/Azores",
+ "Atlantic/Bermuda",
+ "Atlantic/Canary",
+ "Atlantic/Cape_Verde",
+ "Atlantic/Faeroe",
+ "Atlantic/Faroe",
+ "Atlantic/Jan_Mayen",
+ "Atlantic/Madeira",
+ "Atlantic/Reykjavik",
+ "Atlantic/South_Georgia",
+ "Atlantic/St_Helena",
+ "Atlantic/Stanley",
+ "Australia/ACT",
+ "Australia/Adelaide",
+ "Australia/Brisbane",
+ "Australia/Broken_Hill",
+ "Australia/Canberra",
+ "Australia/Currie",
+ "Australia/Darwin",
+ "Australia/Eucla",
+ "Australia/Hobart",
+ "Australia/LHI",
+ "Australia/Lindeman",
+ "Australia/Lord_Howe",
+ "Australia/Melbourne",
+ "Australia/NSW",
+ "Australia/North",
+ "Australia/Perth",
+ "Australia/Queensland",
+ "Australia/South",
+ "Australia/Sydney",
+ "Australia/Tasmania",
+ "Australia/Victoria",
+ "Australia/West",
+ "Australia/Yancowinna",
+ "Brazil/Acre",
+ "Brazil/DeNoronha",
+ "Brazil/East",
+ "Brazil/West",
+ "CET",
+ "CST6CDT",
+ "Canada/Atlantic",
+ "Canada/Central",
+ "Canada/Eastern",
+ "Canada/Mountain",
+ "Canada/Newfoundland",
+ "Canada/Pacific",
+ "Canada/Saskatchewan",
+ "Canada/Yukon",
+ "Chile/Continental",
+ "Chile/EasterIsland",
+ "Cuba",
+ "EET",
+ "EST",
+ "EST5EDT",
+ "Egypt",
+ "Eire",
+ "Etc/GMT",
+ "Etc/GMT+0",
+ "Etc/GMT+1",
+ "Etc/GMT+10",
+ "Etc/GMT+11",
+ "Etc/GMT+12",
+ "Etc/GMT+2",
+ "Etc/GMT+3",
+ "Etc/GMT+4",
+ "Etc/GMT+5",
+ "Etc/GMT+6",
+ "Etc/GMT+7",
+ "Etc/GMT+8",
+ "Etc/GMT+9",
+ "Etc/GMT-0",
+ "Etc/GMT-1",
+ "Etc/GMT-10",
+ "Etc/GMT-11",
+ "Etc/GMT-12",
+ "Etc/GMT-13",
+ "Etc/GMT-14",
+ "Etc/GMT-2",
+ "Etc/GMT-3",
+ "Etc/GMT-4",
+ "Etc/GMT-5",
+ "Etc/GMT-6",
+ "Etc/GMT-7",
+ "Etc/GMT-8",
+ "Etc/GMT-9",
+ "Etc/GMT0",
+ "Etc/Greenwich",
+ "Etc/UCT",
+ "Etc/UTC",
+ "Etc/Universal",
+ "Etc/Zulu",
+ "Europe/Amsterdam",
+ "Europe/Andorra",
+ "Europe/Astrakhan",
+ "Europe/Athens",
+ "Europe/Belfast",
+ "Europe/Belgrade",
+ "Europe/Berlin",
+ "Europe/Bratislava",
+ "Europe/Brussels",
+ "Europe/Bucharest",
+ "Europe/Budapest",
+ "Europe/Busingen",
+ "Europe/Chisinau",
+ "Europe/Copenhagen",
+ "Europe/Dublin",
+ "Europe/Gibraltar",
+ "Europe/Guernsey",
+ "Europe/Helsinki",
+ "Europe/Isle_of_Man",
+ "Europe/Istanbul",
+ "Europe/Jersey",
+ "Europe/Kaliningrad",
+ "Europe/Kiev",
+ "Europe/Kirov",
+ "Europe/Lisbon",
+ "Europe/Ljubljana",
+ "Europe/London",
+ "Europe/Luxembourg",
+ "Europe/Madrid",
+ "Europe/Malta",
+ "Europe/Mariehamn",
+ "Europe/Minsk",
+ "Europe/Monaco",
+ "Europe/Moscow",
+ "Europe/Nicosia",
+ "Europe/Oslo",
+ "Europe/Paris",
+ "Europe/Podgorica",
+ "Europe/Prague",
+ "Europe/Riga",
+ "Europe/Rome",
+ "Europe/Samara",
+ "Europe/San_Marino",
+ "Europe/Sarajevo",
+ "Europe/Saratov",
+ "Europe/Simferopol",
+ "Europe/Skopje",
+ "Europe/Sofia",
+ "Europe/Stockholm",
+ "Europe/Tallinn",
+ "Europe/Tirane",
+ "Europe/Tiraspol",
+ "Europe/Ulyanovsk",
+ "Europe/Uzhgorod",
+ "Europe/Vaduz",
+ "Europe/Vatican",
+ "Europe/Vienna",
+ "Europe/Vilnius",
+ "Europe/Volgograd",
+ "Europe/Warsaw",
+ "Europe/Zagreb",
+ "Europe/Zaporozhye",
+ "Europe/Zurich",
+ "GB",
+ "GB-Eire",
+ "GMT",
+ "GMT+0",
+ "GMT-0",
+ "GMT0",
+ "Greenwich",
+ "HST",
+ "Hongkong",
+ "Iceland",
+ "Indian/Antananarivo",
+ "Indian/Chagos",
+ "Indian/Christmas",
+ "Indian/Cocos",
+ "Indian/Comoro",
+ "Indian/Kerguelen",
+ "Indian/Mahe",
+ "Indian/Maldives",
+ "Indian/Mauritius",
+ "Indian/Mayotte",
+ "Indian/Reunion",
+ "Iran",
+ "Israel",
+ "Jamaica",
+ "Japan",
+ "Kwajalein",
+ "Libya",
+ "MET",
+ "MST",
+ "MST7MDT",
+ "Mexico/BajaNorte",
+ "Mexico/BajaSur",
+ "Mexico/General",
+ "NZ",
+ "NZ-CHAT",
+ "Navajo",
+ "PRC",
+ "PST8PDT",
+ "Pacific/Apia",
+ "Pacific/Auckland",
+ "Pacific/Bougainville",
+ "Pacific/Chatham",
+ "Pacific/Chuuk",
+ "Pacific/Easter",
+ "Pacific/Efate",
+ "Pacific/Enderbury",
+ "Pacific/Fakaofo",
+ "Pacific/Fiji",
+ "Pacific/Funafuti",
+ "Pacific/Galapagos",
+ "Pacific/Gambier",
+ "Pacific/Guadalcanal",
+ "Pacific/Guam",
+ "Pacific/Honolulu",
+ "Pacific/Johnston",
+ "Pacific/Kiritimati",
+ "Pacific/Kosrae",
+ "Pacific/Kwajalein",
+ "Pacific/Majuro",
+ "Pacific/Marquesas",
+ "Pacific/Midway",
+ "Pacific/Nauru",
+ "Pacific/Niue",
+ "Pacific/Norfolk",
+ "Pacific/Noumea",
+ "Pacific/Pago_Pago",
+ "Pacific/Palau",
+ "Pacific/Pitcairn",
+ "Pacific/Pohnpei",
+ "Pacific/Ponape",
+ "Pacific/Port_Moresby",
+ "Pacific/Rarotonga",
+ "Pacific/Saipan",
+ "Pacific/Samoa",
+ "Pacific/Tahiti",
+ "Pacific/Tarawa",
+ "Pacific/Tongatapu",
+ "Pacific/Truk",
+ "Pacific/Wake",
+ "Pacific/Wallis",
+ "Pacific/Yap",
+ "Poland",
+ "Portugal",
+ "ROC",
+ "ROK",
+ "Singapore",
+ "Turkey",
+ "UCT",
+ "US/Alaska",
+ "US/Aleutian",
+ "US/Arizona",
+ "US/Central",
+ "US/East-Indiana",
+ "US/Eastern",
+ "US/Hawaii",
+ "US/Indiana-Starke",
+ "US/Michigan",
+ "US/Mountain",
+ "US/Pacific",
+ "US/Samoa",
+ "UTC",
+ "Universal",
+ "W-SU",
+ "WET",
+ "Zulu",
+ nullptr};
std::vector<std::string> AllTimeZoneNames() {
std::vector<std::string> names;
@@ -992,12 +991,12 @@
BENCHMARK(BM_Time_FromCivilDay0_Libc);
const char* const kFormats[] = {
- RFC1123_full, // 0
- RFC1123_no_wday, // 1
- RFC3339_full, // 2
- RFC3339_sec, // 3
- "%Y-%m-%dT%H:%M:%S", // 4
- "%Y-%m-%d", // 5
+ RFC1123_full, // 0
+ RFC1123_no_wday, // 1
+ RFC3339_full, // 2
+ RFC3339_sec, // 3
+ "%Y-%m-%d%ET%H:%M:%S", // 4
+ "%Y-%m-%d", // 5
};
const int kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
diff --git a/third_party/abseil/absl/time/internal/cctz/src/civil_time_detail.cc b/third_party/abseil/absl/time/internal/cctz/src/civil_time_detail.cc
index cb40b6b..0b07e39 100644
--- a/third_party/abseil/absl/time/internal/cctz/src/civil_time_detail.cc
+++ b/third_party/abseil/absl/time/internal/cctz/src/civil_time_detail.cc
@@ -18,7 +18,10 @@
#include <ostream>
#include <sstream>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
namespace detail {
@@ -87,4 +90,5 @@
} // namespace detail
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/time/internal/cctz/src/civil_time_test.cc b/third_party/abseil/absl/time/internal/cctz/src/civil_time_test.cc
index 10a5ffe..a5a7123 100644
--- a/third_party/abseil/absl/time/internal/cctz/src/civil_time_test.cc
+++ b/third_party/abseil/absl/time/internal/cctz/src/civil_time_test.cc
@@ -21,8 +21,10 @@
#include <type_traits>
#include "gtest/gtest.h"
+#include "absl/base/config.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
@@ -233,6 +235,16 @@
}
// NOTE: Run this with --copt=-ftrapv to detect overflow problems.
+TEST(CivilTime, ConstructionWithHugeYear) {
+ constexpr civil_hour h(-9223372036854775807, 1, 1, -1);
+ static_assert(h.year() == -9223372036854775807 - 1,
+ "ConstructionWithHugeYear");
+ static_assert(h.month() == 12, "ConstructionWithHugeYear");
+ static_assert(h.day() == 31, "ConstructionWithHugeYear");
+ static_assert(h.hour() == 23, "ConstructionWithHugeYear");
+}
+
+// NOTE: Run this with --copt=-ftrapv to detect overflow problems.
TEST(CivilTime, DifferenceWithHugeYear) {
{
constexpr civil_day d1(9223372036854775807, 1, 1);
@@ -1014,19 +1026,13 @@
int day;
} leap_day; // The date of the day after Feb 28.
} kLeapYearTable[]{
- {1900, 365, {3, 1}},
- {1999, 365, {3, 1}},
+ {1900, 365, {3, 1}}, {1999, 365, {3, 1}},
{2000, 366, {2, 29}}, // leap year
- {2001, 365, {3, 1}},
- {2002, 365, {3, 1}},
- {2003, 365, {3, 1}},
- {2004, 366, {2, 29}}, // leap year
- {2005, 365, {3, 1}},
- {2006, 365, {3, 1}},
- {2007, 365, {3, 1}},
- {2008, 366, {2, 29}}, // leap year
- {2009, 365, {3, 1}},
- {2100, 365, {3, 1}},
+ {2001, 365, {3, 1}}, {2002, 365, {3, 1}},
+ {2003, 365, {3, 1}}, {2004, 366, {2, 29}}, // leap year
+ {2005, 365, {3, 1}}, {2006, 365, {3, 1}},
+ {2007, 365, {3, 1}}, {2008, 366, {2, 29}}, // leap year
+ {2009, 365, {3, 1}}, {2100, 365, {3, 1}},
};
for (const auto& e : kLeapYearTable) {
@@ -1056,4 +1062,5 @@
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/time/internal/cctz/src/time_zone_fixed.cc b/third_party/abseil/absl/time/internal/cctz/src/time_zone_fixed.cc
index b0d159a..303c024 100644
--- a/third_party/abseil/absl/time/internal/cctz/src/time_zone_fixed.cc
+++ b/third_party/abseil/absl/time/internal/cctz/src/time_zone_fixed.cc
@@ -20,7 +20,10 @@
#include <cstring>
#include <string>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
@@ -59,11 +62,9 @@
const char* const ep = kFixedZonePrefix + prefix_len;
if (name.size() != prefix_len + 9) // <prefix>+99:99:99
return false;
- if (!std::equal(kFixedZonePrefix, ep, name.begin()))
- return false;
+ if (!std::equal(kFixedZonePrefix, ep, name.begin())) return false;
const char* np = name.data() + prefix_len;
- if (np[0] != '+' && np[0] != '-')
- return false;
+ if (np[0] != '+' && np[0] != '-') return false;
if (np[3] != ':' || np[6] != ':') // see note below about large offsets
return false;
@@ -88,29 +89,29 @@
// offsets and to (somewhat) limit the total number of zones.
return "UTC";
}
- int seconds = static_cast<int>(offset.count());
- const char sign = (seconds < 0 ? '-' : '+');
- int minutes = seconds / 60;
- seconds %= 60;
+ int offset_seconds = static_cast<int>(offset.count());
+ const char sign = (offset_seconds < 0 ? '-' : '+');
+ int offset_minutes = offset_seconds / 60;
+ offset_seconds %= 60;
if (sign == '-') {
- if (seconds > 0) {
- seconds -= 60;
- minutes += 1;
+ if (offset_seconds > 0) {
+ offset_seconds -= 60;
+ offset_minutes += 1;
}
- seconds = -seconds;
- minutes = -minutes;
+ offset_seconds = -offset_seconds;
+ offset_minutes = -offset_minutes;
}
- int hours = minutes / 60;
- minutes %= 60;
+ int offset_hours = offset_minutes / 60;
+ offset_minutes %= 60;
const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1;
char buf[prefix_len + sizeof("-24:00:00")];
char* ep = std::copy(kFixedZonePrefix, kFixedZonePrefix + prefix_len, buf);
*ep++ = sign;
- ep = Format02d(ep, hours);
+ ep = Format02d(ep, offset_hours);
*ep++ = ':';
- ep = Format02d(ep, minutes);
+ ep = Format02d(ep, offset_minutes);
*ep++ = ':';
- ep = Format02d(ep, seconds);
+ ep = Format02d(ep, offset_seconds);
*ep++ = '\0';
assert(ep == buf + sizeof(buf));
return buf;
@@ -135,4 +136,5 @@
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/time/internal/cctz/src/time_zone_fixed.h b/third_party/abseil/absl/time/internal/cctz/src/time_zone_fixed.h
index 9c1f5e7..e74a0bb 100644
--- a/third_party/abseil/absl/time/internal/cctz/src/time_zone_fixed.h
+++ b/third_party/abseil/absl/time/internal/cctz/src/time_zone_fixed.h
@@ -17,9 +17,11 @@
#include <string>
+#include "absl/base/config.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
@@ -44,6 +46,7 @@
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_
diff --git a/third_party/abseil/absl/time/internal/cctz/src/time_zone_format.cc b/third_party/abseil/absl/time/internal/cctz/src/time_zone_format.cc
index 84e280b..d8cb047 100644
--- a/third_party/abseil/absl/time/internal/cctz/src/time_zone_format.cc
+++ b/third_party/abseil/absl/time/internal/cctz/src/time_zone_format.cc
@@ -13,17 +13,18 @@
// limitations under the License.
#if !defined(HAS_STRPTIME)
-# if !defined(_MSC_VER) && !defined(__MINGW32__)
-# define HAS_STRPTIME 1 // assume everyone has strptime() except windows
-# endif
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+#define HAS_STRPTIME 1 // assume everyone has strptime() except windows
+#endif
#endif
#if defined(HAS_STRPTIME) && HAS_STRPTIME
-# if !defined(_XOPEN_SOURCE)
-# define _XOPEN_SOURCE // Definedness suffices for strptime.
-# endif
+#if !defined(_XOPEN_SOURCE)
+#define _XOPEN_SOURCE // Definedness suffices for strptime.
+#endif
#endif
+#include "absl/base/config.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
// Include time.h directly since, by C++ standards, ctime doesn't have to
@@ -48,6 +49,7 @@
#include "time_zone_if.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
namespace detail {
@@ -65,6 +67,48 @@
}
#endif
+// Convert a cctz::weekday to a tm_wday value (0-6, Sunday = 0).
+int ToTmWday(weekday wd) {
+ switch (wd) {
+ case weekday::sunday:
+ return 0;
+ case weekday::monday:
+ return 1;
+ case weekday::tuesday:
+ return 2;
+ case weekday::wednesday:
+ return 3;
+ case weekday::thursday:
+ return 4;
+ case weekday::friday:
+ return 5;
+ case weekday::saturday:
+ return 6;
+ }
+ return 0; /*NOTREACHED*/
+}
+
+// Convert a tm_wday value (0-6, Sunday = 0) to a cctz::weekday.
+weekday FromTmWday(int tm_wday) {
+ switch (tm_wday) {
+ case 0:
+ return weekday::sunday;
+ case 1:
+ return weekday::monday;
+ case 2:
+ return weekday::tuesday;
+ case 3:
+ return weekday::wednesday;
+ case 4:
+ return weekday::thursday;
+ case 5:
+ return weekday::friday;
+ case 6:
+ return weekday::saturday;
+ }
+ return weekday::sunday; /*NOTREACHED*/
+}
+
std::tm ToTM(const time_zone::absolute_lookup& al) {
std::tm tm{};
tm.tm_sec = al.cs.second();
@@ -82,34 +126,19 @@
tm.tm_year = static_cast<int>(al.cs.year() - 1900);
}
- switch (get_weekday(al.cs)) {
- case weekday::sunday:
- tm.tm_wday = 0;
- break;
- case weekday::monday:
- tm.tm_wday = 1;
- break;
- case weekday::tuesday:
- tm.tm_wday = 2;
- break;
- case weekday::wednesday:
- tm.tm_wday = 3;
- break;
- case weekday::thursday:
- tm.tm_wday = 4;
- break;
- case weekday::friday:
- tm.tm_wday = 5;
- break;
- case weekday::saturday:
- tm.tm_wday = 6;
- break;
- }
+ tm.tm_wday = ToTmWday(get_weekday(al.cs));
tm.tm_yday = get_yearday(al.cs) - 1;
tm.tm_isdst = al.is_dst ? 1 : 0;
return tm;
}
+// Returns the week of the year [0:53] given a civil day and the day on
+// which weeks are defined to start.
+int ToWeek(const civil_day& cd, weekday week_start) {
+ const civil_day d(cd.year() % 400, cd.month(), cd.day());
+ return static_cast<int>((d - prev_weekday(civil_year(d), week_start)) / 7);
+}
+
const char kDigits[] = "0123456789";
// Formats a 64-bit integer in the given field width. Note that it is up
@@ -187,7 +216,7 @@
// strftime(3) returns the number of characters placed in the output
// array (which may be 0 characters). It also returns 0 to indicate
// an error, like the array wasn't large enough. To accommodate this,
- // the following code grows the buffer size from 2x the format std::string
+ // the following code grows the buffer size from 2x the format string
// length up to 32x.
for (std::size_t i = 2; i != 32; i *= 2) {
std::size_t buf_size = fmt.size() * i;
@@ -288,6 +317,7 @@
// - %E#S - Seconds with # digits of fractional precision
// - %E*S - Seconds with full fractional precision (a literal '*')
// - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
+// - %ET - The RFC3339 "date-time" separator "T"
//
// The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are
// handled internally for performance reasons. strftime(3) is slow due to
@@ -352,7 +382,7 @@
if (cur == end || (cur - percent) % 2 == 0) continue;
// Simple specifiers that we handle ourselves.
- if (strchr("YmdeHMSzZs%", *cur)) {
+ if (strchr("YmdeUuWwHMSzZs%", *cur)) {
if (cur - 1 != pending) {
FormatTM(&result, std::string(pending, cur - 1), tm);
}
@@ -373,6 +403,22 @@
if (*cur == 'e' && *bp == '0') *bp = ' '; // for Windows
result.append(bp, static_cast<std::size_t>(ep - bp));
break;
+ case 'U':
+ bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::sunday));
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ break;
+ case 'u':
+ bp = Format64(ep, 0, tm.tm_wday ? tm.tm_wday : 7);
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ break;
+ case 'W':
+ bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::monday));
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ break;
+ case 'w':
+ bp = Format64(ep, 0, tm.tm_wday);
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ break;
case 'H':
bp = Format02d(ep, al.cs.hour());
result.append(bp, static_cast<std::size_t>(ep - bp));
@@ -446,7 +492,14 @@
if (*cur != 'E' || ++cur == end) continue;
// Format our extensions.
- if (*cur == 'z') {
+ if (*cur == 'T') {
+ // Formats %ET.
+ if (cur - 2 != pending) {
+ FormatTM(&result, std::string(pending, cur - 2), tm);
+ }
+ result.append("T");
+ pending = ++cur;
+ } else if (*cur == 'z') {
// Formats %Ez.
if (cur - 2 != pending) {
FormatTM(&result, std::string(pending, cur - 2), tm);
@@ -502,8 +555,9 @@
bp = ep;
if (n > 0) {
if (n > kDigits10_64) n = kDigits10_64;
- bp = Format64(bp, n, (n > 15) ? fs.count() * kExp10[n - 15]
- : fs.count() / kExp10[15 - n]);
+ bp = Format64(bp, n,
+ (n > 15) ? fs.count() * kExp10[n - 15]
+ : fs.count() / kExp10[15 - n]);
if (*np == 'S') *--bp = '.';
}
if (*np == 'S') bp = Format02d(bp, al.cs.second());
@@ -548,7 +602,7 @@
} else {
dp = nullptr;
}
- } else if (first == 'Z') { // Zulu
+ } else if (first == 'Z' || first == 'z') { // Zulu
*offset = 0;
} else {
dp = nullptr;
@@ -599,12 +653,32 @@
return dp;
}
+// Sets year, tm_mon and tm_mday given the year, week_num, and tm_wday,
+// and the day on which weeks are defined to start. Returns false if year
+// would need to move outside its bounds.
+bool FromWeek(int week_num, weekday week_start, year_t* year, std::tm* tm) {
+ const civil_year y(*year % 400);
+ civil_day cd = prev_weekday(y, week_start); // week 0
+ cd = next_weekday(cd - 1, FromTmWday(tm->tm_wday)) + (week_num * 7);
+ if (const year_t shift = cd.year() - y.year()) {
+ if (shift > 0) {
+ if (*year > std::numeric_limits<year_t>::max() - shift) return false;
+ } else {
+ if (*year < std::numeric_limits<year_t>::min() - shift) return false;
+ }
+ *year += shift;
+ }
+ tm->tm_mon = cd.month() - 1;
+ tm->tm_mday = cd.day();
+ return true;
+}
+
} // namespace
// Uses strptime(3) to parse the given input. Supports the same extended
// format specifiers as format(), although %E#S and %E*S are treated
// identically (and similarly for %E#f and %E*f). %Ez and %E*z also accept
-// the same inputs.
+// the same inputs. %ET accepts either 'T' or 't'.
//
// The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are
// handled internally so that we can normally avoid strptime() altogether
@@ -648,6 +722,8 @@
const char* fmt = format.c_str(); // NUL terminated
bool twelve_hour = false;
bool afternoon = false;
+ int week_num = -1;
+ weekday week_start = weekday::sunday;
bool saw_percent_s = false;
std::int_fast64_t percent_s = 0;
@@ -686,10 +762,27 @@
case 'm':
data = ParseInt(data, 2, 1, 12, &tm.tm_mon);
if (data != nullptr) tm.tm_mon -= 1;
+ week_num = -1;
continue;
case 'd':
case 'e':
data = ParseInt(data, 2, 1, 31, &tm.tm_mday);
+ week_num = -1;
+ continue;
+ case 'U':
+ data = ParseInt(data, 0, 0, 53, &week_num);
+ week_start = weekday::sunday;
+ continue;
+ case 'W':
+ data = ParseInt(data, 0, 0, 53, &week_num);
+ week_start = weekday::monday;
+ continue;
+ case 'u':
+ data = ParseInt(data, 0, 1, 7, &tm.tm_wday);
+ if (data != nullptr) tm.tm_wday %= 7;
+ continue;
+ case 'w':
+ data = ParseInt(data, 0, 0, 6, &tm.tm_wday);
continue;
case 'H':
data = ParseInt(data, 2, 0, 23, &tm.tm_hour);
@@ -720,10 +813,9 @@
data = ParseZone(data, &zone);
continue;
case 's':
- data = ParseInt(data, 0,
- std::numeric_limits<std::int_fast64_t>::min(),
- std::numeric_limits<std::int_fast64_t>::max(),
- &percent_s);
+ data =
+ ParseInt(data, 0, std::numeric_limits<std::int_fast64_t>::min(),
+ std::numeric_limits<std::int_fast64_t>::max(), &percent_s);
if (data != nullptr) saw_percent_s = true;
continue;
case ':':
@@ -740,6 +832,15 @@
data = (*data == '%' ? data + 1 : nullptr);
continue;
case 'E':
+ if (fmt[0] == 'T') {
+ if (*data == 'T' || *data == 't') {
+ ++data;
+ ++fmt;
+ } else {
+ data = nullptr;
+ }
+ continue;
+ }
if (fmt[0] == 'z' || (fmt[0] == '*' && fmt[1] == 'z')) {
data = ParseOffset(data, ":", &offset);
if (data != nullptr) saw_offset = true;
@@ -837,7 +938,7 @@
// Skip any remaining whitespace.
while (std::isspace(*data)) ++data;
- // parse() must consume the entire input std::string.
+ // parse() must consume the entire input string.
if (*data != '\0') {
if (err != nullptr) *err = "Illegal trailing data in input string";
return false;
@@ -872,6 +973,14 @@
year += 1900;
}
+ // Compute year, tm.tm_mon and tm.tm_mday if we parsed a week number.
+ if (week_num != -1) {
+ if (!FromWeek(week_num, week_start, &year, &tm)) {
+ if (err != nullptr) *err = "Out-of-range field";
+ return false;
+ }
+ }
+
const int month = tm.tm_mon + 1;
civil_second cs(year, month, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
@@ -916,4 +1025,5 @@
} // namespace detail
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/time/internal/cctz/src/time_zone_format_test.cc b/third_party/abseil/absl/time/internal/cctz/src/time_zone_format_test.cc
index 705ccdc..a11f93e 100644
--- a/third_party/abseil/absl/time/internal/cctz/src/time_zone_format_test.cc
+++ b/third_party/abseil/absl/time/internal/cctz/src/time_zone_format_test.cc
@@ -12,20 +12,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "absl/time/internal/cctz/include/cctz/time_zone.h"
-
#include <chrono>
#include <iomanip>
#include <sstream>
#include <string>
-#include "absl/time/internal/cctz/include/cctz/civil_time.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
namespace chrono = std::chrono;
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
@@ -47,11 +48,11 @@
EXPECT_STREQ(zone, al.abbr); \
} while (0)
-const char RFC3339_full[] = "%Y-%m-%dT%H:%M:%E*S%Ez";
-const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez";
+const char RFC3339_full[] = "%Y-%m-%d%ET%H:%M:%E*S%Ez";
+const char RFC3339_sec[] = "%Y-%m-%d%ET%H:%M:%S%Ez";
const char RFC1123_full[] = "%a, %d %b %Y %H:%M:%S %z";
-const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z";
+const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z";
// A helper that tests the given format specifier by itself, and with leading
// and trailing characters. For example: TestFormatSpecifier(tp, "%a", "Thu").
@@ -88,8 +89,11 @@
format(kFmt, chrono::time_point_cast<chrono::milliseconds>(t0), utc));
EXPECT_EQ("03:04:05",
format(kFmt, chrono::time_point_cast<chrono::seconds>(t0), utc));
- EXPECT_EQ("03:04:05",
- format(kFmt, chrono::time_point_cast<absl::time_internal::cctz::seconds>(t0), utc));
+ EXPECT_EQ(
+ "03:04:05",
+ format(kFmt,
+ chrono::time_point_cast<absl::time_internal::cctz::seconds>(t0),
+ utc));
EXPECT_EQ("03:04:00",
format(kFmt, chrono::time_point_cast<chrono::minutes>(t0), utc));
EXPECT_EQ("03:00:00",
@@ -110,12 +114,10 @@
EXPECT_EQ(
"12:34:56.012345678901234",
detail::format(kFmt, tp, detail::femtoseconds(12345678901234), utc));
- EXPECT_EQ(
- "12:34:56.001234567890123",
- detail::format(kFmt, tp, detail::femtoseconds(1234567890123), utc));
- EXPECT_EQ(
- "12:34:56.000123456789012",
- detail::format(kFmt, tp, detail::femtoseconds(123456789012), utc));
+ EXPECT_EQ("12:34:56.001234567890123",
+ detail::format(kFmt, tp, detail::femtoseconds(1234567890123), utc));
+ EXPECT_EQ("12:34:56.000123456789012",
+ detail::format(kFmt, tp, detail::femtoseconds(123456789012), utc));
EXPECT_EQ("12:34:56.000000000000123",
detail::format(kFmt, tp, detail::femtoseconds(123), utc));
@@ -677,6 +679,34 @@
EXPECT_EQ("28 Jun 1977 09:08:07 -0700", format(RFC1123_no_wday, tp, tz));
}
+TEST(Format, Week) {
+ const time_zone utc = utc_time_zone();
+
+ auto tp = convert(civil_second(2017, 1, 1, 0, 0, 0), utc);
+ EXPECT_EQ("2017-01-7", format("%Y-%U-%u", tp, utc));
+ EXPECT_EQ("2017-00-0", format("%Y-%W-%w", tp, utc));
+
+ tp = convert(civil_second(2017, 12, 31, 0, 0, 0), utc);
+ EXPECT_EQ("2017-53-7", format("%Y-%U-%u", tp, utc));
+ EXPECT_EQ("2017-52-0", format("%Y-%W-%w", tp, utc));
+
+ tp = convert(civil_second(2018, 1, 1, 0, 0, 0), utc);
+ EXPECT_EQ("2018-00-1", format("%Y-%U-%u", tp, utc));
+ EXPECT_EQ("2018-01-1", format("%Y-%W-%w", tp, utc));
+
+ tp = convert(civil_second(2018, 12, 31, 0, 0, 0), utc);
+ EXPECT_EQ("2018-52-1", format("%Y-%U-%u", tp, utc));
+ EXPECT_EQ("2018-53-1", format("%Y-%W-%w", tp, utc));
+
+ tp = convert(civil_second(2019, 1, 1, 0, 0, 0), utc);
+ EXPECT_EQ("2019-00-2", format("%Y-%U-%u", tp, utc));
+ EXPECT_EQ("2019-00-2", format("%Y-%W-%w", tp, utc));
+
+ tp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
+ EXPECT_EQ("2019-52-2", format("%Y-%U-%u", tp, utc));
+ EXPECT_EQ("2019-52-2", format("%Y-%W-%w", tp, utc));
+}
+
//
// Testing parse()
//
@@ -765,7 +795,7 @@
EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
time_point<chrono::nanoseconds> tp;
- // We can parse a std::string without a UTC offset if we supply a timezone.
+ // We can parse a string without a UTC offset if we supply a timezone.
EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &tp));
ExpectTime(tp, tz, 2013, 6, 28, 19, 8, 9, -7 * 60 * 60, true, "PDT");
@@ -1250,9 +1280,9 @@
const auto expected = chrono::system_clock::from_time_t(0) +
chrono::nanoseconds(micros * 1000 + ns);
for (int ps = 0; ps < 1000; ps += 250) {
- std::ostringstream oss;
+ std::ostringstream ps_oss;
oss << std::setfill('0') << std::setw(3) << ps;
- const std::string input = nanos + oss.str() + "999";
+ const std::string input = nanos + ps_oss.str() + "999";
EXPECT_TRUE(parse("%E*f", input, tz, &tp));
EXPECT_EQ(expected + chrono::nanoseconds(ps) / 1000, tp) << input;
}
@@ -1377,10 +1407,85 @@
EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00+00:00", tz, &tp));
ExpectTime(tp, tz, 2014, 2, 12, 20, 21, 0, 0, false, "UTC");
- // Check that %Ez also accepts "Z" as a synonym for "+00:00".
+ // Check that %ET also accepts "t".
time_point<chrono::nanoseconds> tp2;
- EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00Z", tz, &tp2));
+ EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12t20:21:00+00:00", tz, &tp2));
EXPECT_EQ(tp, tp2);
+
+ // Check that %Ez also accepts "Z" as a synonym for "+00:00".
+ time_point<chrono::nanoseconds> tp3;
+ EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00Z", tz, &tp3));
+ EXPECT_EQ(tp, tp3);
+
+ // Check that %Ez also accepts "z" as a synonym for "+00:00".
+ time_point<chrono::nanoseconds> tp4;
+ EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00z", tz, &tp4));
+ EXPECT_EQ(tp, tp4);
+}
+
+TEST(Parse, Week) {
+ const time_zone utc = utc_time_zone();
+ time_point<absl::time_internal::cctz::seconds> tp;
+
+ auto exp = convert(civil_second(2017, 1, 1, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2017-01-7", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2017-00-0", utc, &tp));
+ EXPECT_EQ(exp, tp);
+
+ exp = convert(civil_second(2017, 12, 31, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2017-53-7", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2017-52-0", utc, &tp));
+ EXPECT_EQ(exp, tp);
+
+ exp = convert(civil_second(2018, 1, 1, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2018-00-1", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2018-01-1", utc, &tp));
+ EXPECT_EQ(exp, tp);
+
+ exp = convert(civil_second(2018, 12, 31, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2018-52-1", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2018-53-1", utc, &tp));
+ EXPECT_EQ(exp, tp);
+
+ exp = convert(civil_second(2019, 1, 1, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2019-00-2", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2019-00-2", utc, &tp));
+ EXPECT_EQ(exp, tp);
+
+ exp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2019-52-2", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2019-52-2", utc, &tp));
+ EXPECT_EQ(exp, tp);
+}
+
+TEST(Parse, WeekYearShift) {
+ // %U/%W conversions with week values in {0, 52, 53} can slip
+ // into the previous/following calendar years.
+ const time_zone utc = utc_time_zone();
+ time_point<absl::time_internal::cctz::seconds> tp;
+
+ auto exp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2020-00-2", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2020-00-2", utc, &tp));
+ EXPECT_EQ(exp, tp);
+
+ exp = convert(civil_second(2021, 1, 1, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2020-52-5", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2020-52-5", utc, &tp));
+ EXPECT_EQ(exp, tp);
+
+ // Slipping into the previous/following calendar years should fail when
+ // we're already at the extremes.
+ EXPECT_FALSE(parse("%Y-%U-%u", "-9223372036854775808-0-7", utc, &tp));
+ EXPECT_FALSE(parse("%Y-%U-%u", "9223372036854775807-53-7", utc, &tp));
}
TEST(Parse, MaxRange) {
@@ -1416,8 +1521,8 @@
parse(RFC3339_sec, "-292277022657-01-27T08:29:51+01:00", utc, &tp));
// tests max/min civil-second overflow
- EXPECT_FALSE(parse(RFC3339_sec, "9223372036854775807-12-31T23:59:59-00:01",
- utc, &tp));
+ EXPECT_FALSE(
+ parse(RFC3339_sec, "9223372036854775807-12-31T23:59:59-00:01", utc, &tp));
EXPECT_FALSE(parse(RFC3339_sec, "-9223372036854775808-01-01T00:00:00+00:01",
utc, &tp));
@@ -1474,7 +1579,8 @@
TEST(FormatParse, RoundTripDistantFuture) {
const time_zone utc = utc_time_zone();
- const time_point<absl::time_internal::cctz::seconds> in = time_point<absl::time_internal::cctz::seconds>::max();
+ const time_point<absl::time_internal::cctz::seconds> in =
+ time_point<absl::time_internal::cctz::seconds>::max();
const std::string s = format(RFC3339_full, in, utc);
time_point<absl::time_internal::cctz::seconds> out;
EXPECT_TRUE(parse(RFC3339_full, s, utc, &out)) << s;
@@ -1483,7 +1589,8 @@
TEST(FormatParse, RoundTripDistantPast) {
const time_zone utc = utc_time_zone();
- const time_point<absl::time_internal::cctz::seconds> in = time_point<absl::time_internal::cctz::seconds>::min();
+ const time_point<absl::time_internal::cctz::seconds> in =
+ time_point<absl::time_internal::cctz::seconds>::min();
const std::string s = format(RFC3339_full, in, utc);
time_point<absl::time_internal::cctz::seconds> out;
EXPECT_TRUE(parse(RFC3339_full, s, utc, &out)) << s;
@@ -1492,4 +1599,5 @@
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/time/internal/cctz/src/time_zone_if.cc b/third_party/abseil/absl/time/internal/cctz/src/time_zone_if.cc
index 09aaee5..0319b2f 100644
--- a/third_party/abseil/absl/time/internal/cctz/src/time_zone_if.cc
+++ b/third_party/abseil/absl/time/internal/cctz/src/time_zone_if.cc
@@ -13,10 +13,13 @@
// limitations under the License.
#include "time_zone_if.h"
+
+#include "absl/base/config.h"
#include "time_zone_info.h"
#include "time_zone_libc.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
@@ -38,4 +41,5 @@
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/time/internal/cctz/src/time_zone_if.h b/third_party/abseil/absl/time/internal/cctz/src/time_zone_if.h
index d000b7a..32c0891 100644
--- a/third_party/abseil/absl/time/internal/cctz/src/time_zone_if.h
+++ b/third_party/abseil/absl/time/internal/cctz/src/time_zone_if.h
@@ -20,10 +20,12 @@
#include <memory>
#include <string>
+#include "absl/base/config.h"
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
@@ -38,8 +40,7 @@
virtual time_zone::absolute_lookup BreakTime(
const time_point<seconds>& tp) const = 0;
- virtual time_zone::civil_lookup MakeTime(
- const civil_second& cs) const = 0;
+ virtual time_zone::civil_lookup MakeTime(const civil_second& cs) const = 0;
virtual bool NextTransition(const time_point<seconds>& tp,
time_zone::civil_transition* trans) const = 0;
@@ -58,15 +59,18 @@
// Unix clock are second aligned, but not that they share an epoch.
inline std::int_fast64_t ToUnixSeconds(const time_point<seconds>& tp) {
return (tp - std::chrono::time_point_cast<seconds>(
- std::chrono::system_clock::from_time_t(0))).count();
+ std::chrono::system_clock::from_time_t(0)))
+ .count();
}
inline time_point<seconds> FromUnixSeconds(std::int_fast64_t t) {
return std::chrono::time_point_cast<seconds>(
- std::chrono::system_clock::from_time_t(0)) + seconds(t);
+ std::chrono::system_clock::from_time_t(0)) +
+ seconds(t);
}
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IF_H_
diff --git a/third_party/abseil/absl/time/internal/cctz/src/time_zone_impl.cc b/third_party/abseil/absl/time/internal/cctz/src/time_zone_impl.cc
index a26151d..f34e3ae 100644
--- a/third_party/abseil/absl/time/internal/cctz/src/time_zone_impl.cc
+++ b/third_party/abseil/absl/time/internal/cctz/src/time_zone_impl.cc
@@ -14,14 +14,18 @@
#include "time_zone_impl.h"
+#include <deque>
+#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <utility>
+#include "absl/base/config.h"
#include "time_zone_fixed.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
@@ -42,22 +46,19 @@
} // namespace
-time_zone time_zone::Impl::UTC() {
- return time_zone(UTCImpl());
-}
+time_zone time_zone::Impl::UTC() { return time_zone(UTCImpl()); }
bool time_zone::Impl::LoadTimeZone(const std::string& name, time_zone* tz) {
- const time_zone::Impl* const utc_impl = UTCImpl();
+ const Impl* const utc_impl = UTCImpl();
- // First check for UTC (which is never a key in time_zone_map).
+ // Check for UTC (which is never a key in time_zone_map).
auto offset = seconds::zero();
if (FixedOffsetFromName(name, &offset) && offset == seconds::zero()) {
*tz = time_zone(utc_impl);
return true;
}
- // Then check, under a shared lock, whether the time zone has already
- // been loaded. This is the common path. TODO: Move to shared_mutex.
+ // Check whether the time zone has already been loaded.
{
std::lock_guard<std::mutex> lock(TimeZoneMutex());
if (time_zone_map != nullptr) {
@@ -69,20 +70,15 @@
}
}
- // Now check again, under an exclusive lock.
+ // Load the new time zone (outside the lock).
+ std::unique_ptr<const Impl> new_impl(new Impl(name));
+
+ // Add the new time zone to the map.
std::lock_guard<std::mutex> lock(TimeZoneMutex());
if (time_zone_map == nullptr) time_zone_map = new TimeZoneImplByName;
const Impl*& impl = (*time_zone_map)[name];
- if (impl == nullptr) {
- // The first thread in loads the new time zone.
- Impl* new_impl = new Impl(name);
- new_impl->zone_ = TimeZoneIf::Load(new_impl->name_);
- if (new_impl->zone_ == nullptr) {
- delete new_impl; // free the nascent Impl
- impl = utc_impl; // and fallback to UTC
- } else {
- impl = new_impl; // install new time zone
- }
+ if (impl == nullptr) { // this thread won any load race
+ impl = new_impl->zone_ ? new_impl.release() : utc_impl;
}
*tz = time_zone(impl);
return impl != utc_impl;
@@ -91,23 +87,27 @@
void time_zone::Impl::ClearTimeZoneMapTestOnly() {
std::lock_guard<std::mutex> lock(TimeZoneMutex());
if (time_zone_map != nullptr) {
- // Existing time_zone::Impl* entries are in the wild, so we simply
- // leak them. Future requests will result in reloading the data.
+ // Existing time_zone::Impl* entries are in the wild, so we can't delete
+ // them. Instead, we move them to a private container, where they are
+ // logically unreachable but not "leaked". Future requests will result
+ // in reloading the data.
+ static auto* cleared = new std::deque<const time_zone::Impl*>;
+ for (const auto& element : *time_zone_map) {
+ cleared->push_back(element.second);
+ }
time_zone_map->clear();
}
}
-time_zone::Impl::Impl(const std::string& name) : name_(name) {}
+time_zone::Impl::Impl(const std::string& name)
+ : name_(name), zone_(TimeZoneIf::Load(name_)) {}
const time_zone::Impl* time_zone::Impl::UTCImpl() {
- static Impl* utc_impl = [] {
- Impl* impl = new Impl("UTC");
- impl->zone_ = TimeZoneIf::Load(impl->name_); // never fails
- return impl;
- }();
+ static const Impl* utc_impl = new Impl("UTC"); // never fails
return utc_impl;
}
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/time/internal/cctz/src/time_zone_impl.h b/third_party/abseil/absl/time/internal/cctz/src/time_zone_impl.h
index b73fad9..7d747ba 100644
--- a/third_party/abseil/absl/time/internal/cctz/src/time_zone_impl.h
+++ b/third_party/abseil/absl/time/internal/cctz/src/time_zone_impl.h
@@ -18,12 +18,14 @@
#include <memory>
#include <string>
+#include "absl/base/config.h"
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
#include "time_zone_if.h"
#include "time_zone_info.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
@@ -69,7 +71,7 @@
return zone_->PrevTransition(tp, trans);
}
- // Returns an implementation-defined version std::string for this time zone.
+ // Returns an implementation-defined version string for this time zone.
std::string Version() const { return zone_->Version(); }
// Returns an implementation-defined description of this time zone.
@@ -85,6 +87,7 @@
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IMPL_H_
diff --git a/third_party/abseil/absl/time/internal/cctz/src/time_zone_info.cc b/third_party/abseil/absl/time/internal/cctz/src/time_zone_info.cc
index 9db72e0..8039353 100644
--- a/third_party/abseil/absl/time/internal/cctz/src/time_zone_info.cc
+++ b/third_party/abseil/absl/time/internal/cctz/src/time_zone_info.cc
@@ -40,16 +40,17 @@
#include <cstdlib>
#include <cstring>
#include <functional>
-#include <iostream>
#include <memory>
#include <sstream>
#include <string>
+#include "absl/base/config.h"
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
#include "time_zone_fixed.h"
#include "time_zone_posix.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
@@ -65,8 +66,8 @@
// The day offsets of the beginning of each (1-based) month in non-leap and
// leap years respectively (e.g., 335 days before December in a leap year).
const std::int_least16_t kMonthOffsets[2][1 + 12 + 1] = {
- {-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
- {-1, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366},
+ {-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
+ {-1, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366},
};
// We reject leap-second encoded zoneinfo and so assume 60-second minutes.
@@ -77,10 +78,31 @@
// Like kDaysPerYear[] but scaled up by a factor of kSecsPerDay.
const std::int_least32_t kSecsPerYear[2] = {
- 365 * kSecsPerDay,
- 366 * kSecsPerDay,
+ 365 * kSecsPerDay,
+ 366 * kSecsPerDay,
};
+// Convert a cctz::weekday to a POSIX TZ weekday number (0==Sun, ..., 6=Sat).
+inline int ToPosixWeekday(weekday wd) {
+ switch (wd) {
+ case weekday::sunday:
+ return 0;
+ case weekday::monday:
+ return 1;
+ case weekday::tuesday:
+ return 2;
+ case weekday::wednesday:
+ return 3;
+ case weekday::thursday:
+ return 4;
+ case weekday::friday:
+ return 5;
+ case weekday::saturday:
+ return 6;
+ }
+ return 0; /*NOTREACHED*/
+}
+
// Single-byte, unsigned numeric values are encoded directly.
inline std::uint_fast8_t Decode8(const char* cp) {
return static_cast<std::uint_fast8_t>(*cp) & 0xff;
@@ -172,8 +194,8 @@
}
inline civil_second YearShift(const civil_second& cs, year_t shift) {
- return civil_second(cs.year() + shift, cs.month(), cs.day(),
- cs.hour(), cs.minute(), cs.second());
+ return civil_second(cs.year() + shift, cs.month(), cs.day(), cs.hour(),
+ cs.minute(), cs.second());
}
} // namespace
@@ -186,15 +208,13 @@
tt.is_dst = false;
tt.abbr_index = 0;
- // We temporarily add some redundant, contemporary (2013 through 2023)
+ // We temporarily add some redundant, contemporary (2015 through 2025)
// transitions for performance reasons. See TimeZoneInfo::LocalTime().
// TODO: Fix the performance issue and remove the extra transitions.
transitions_.clear();
transitions_.reserve(12);
for (const std::int_fast64_t unix_time : {
- -(1LL << 59), // BIG_BANG
- 1356998400LL, // 2013-01-01T00:00:00+00:00
- 1388534400LL, // 2014-01-01T00:00:00+00:00
+ -(1LL << 59), // a "first half" transition
1420070400LL, // 2015-01-01T00:00:00+00:00
1451606400LL, // 2016-01-01T00:00:00+00:00
1483228800LL, // 2017-01-01T00:00:00+00:00
@@ -204,7 +224,8 @@
1609459200LL, // 2021-01-01T00:00:00+00:00
1640995200LL, // 2022-01-01T00:00:00+00:00
1672531200LL, // 2023-01-01T00:00:00+00:00
- 2147483647LL, // 2^31 - 1
+ 1704067200LL, // 2024-01-01T00:00:00+00:00
+ 1735689600LL, // 2025-01-01T00:00:00+00:00
}) {
Transition& tr(*transitions_.emplace(transitions_.end()));
tr.unix_time = unix_time;
@@ -215,7 +236,7 @@
default_transition_type_ = 0;
abbreviations_ = FixedOffsetToAbbr(offset);
- abbreviations_.append(1, '\0'); // add NUL
+ abbreviations_.append(1, '\0');
future_spec_.clear(); // never needed for a fixed-offset zone
extended_ = false;
@@ -257,21 +278,6 @@
return len;
}
-// Check that the TransitionType has the expected offset/is_dst/abbreviation.
-void TimeZoneInfo::CheckTransition(const std::string& name,
- const TransitionType& tt,
- std::int_fast32_t offset, bool is_dst,
- const std::string& abbr) const {
- if (tt.utc_offset != offset || tt.is_dst != is_dst ||
- &abbreviations_[tt.abbr_index] != abbr) {
- std::clog << name << ": Transition"
- << " offset=" << tt.utc_offset << "/"
- << (tt.is_dst ? "DST" : "STD")
- << "/abbr=" << &abbreviations_[tt.abbr_index]
- << " does not match POSIX spec '" << future_spec_ << "'\n";
- }
-}
-
// zic(8) can generate no-op transitions when a zone changes rules at an
// instant when there is actually no discontinuity. So we check whether
// two transitions have equivalent types (same offset/is_dst/abbr).
@@ -280,144 +286,128 @@
if (tt1_index == tt2_index) return true;
const TransitionType& tt1(transition_types_[tt1_index]);
const TransitionType& tt2(transition_types_[tt2_index]);
- if (tt1.is_dst != tt2.is_dst) return false;
if (tt1.utc_offset != tt2.utc_offset) return false;
+ if (tt1.is_dst != tt2.is_dst) return false;
if (tt1.abbr_index != tt2.abbr_index) return false;
return true;
}
+// Find/make a transition type with these attributes.
+bool TimeZoneInfo::GetTransitionType(std::int_fast32_t utc_offset, bool is_dst,
+ const std::string& abbr,
+ std::uint_least8_t* index) {
+ std::size_t type_index = 0;
+ std::size_t abbr_index = abbreviations_.size();
+ for (; type_index != transition_types_.size(); ++type_index) {
+ const TransitionType& tt(transition_types_[type_index]);
+ const char* tt_abbr = &abbreviations_[tt.abbr_index];
+ if (tt_abbr == abbr) abbr_index = tt.abbr_index;
+ if (tt.utc_offset == utc_offset && tt.is_dst == is_dst) {
+ if (abbr_index == tt.abbr_index) break; // reuse
+ }
+ }
+ if (type_index > 255 || abbr_index > 255) {
+ // No index space (8 bits) available for a new type or abbreviation.
+ return false;
+ }
+ if (type_index == transition_types_.size()) {
+ TransitionType& tt(*transition_types_.emplace(transition_types_.end()));
+ tt.utc_offset = static_cast<std::int_least32_t>(utc_offset);
+ tt.is_dst = is_dst;
+ if (abbr_index == abbreviations_.size()) {
+ abbreviations_.append(abbr);
+ abbreviations_.append(1, '\0');
+ }
+ tt.abbr_index = static_cast<std::uint_least8_t>(abbr_index);
+ }
+ *index = static_cast<std::uint_least8_t>(type_index);
+ return true;
+}
+
// Use the POSIX-TZ-environment-variable-style string to handle times
// in years after the last transition stored in the zoneinfo data.
-void TimeZoneInfo::ExtendTransitions(const std::string& name,
- const Header& hdr) {
+bool TimeZoneInfo::ExtendTransitions() {
extended_ = false;
- bool extending = !future_spec_.empty();
+ if (future_spec_.empty()) return true; // last transition prevails
PosixTimeZone posix;
- if (extending && !ParsePosixSpec(future_spec_, &posix)) {
- std::clog << name << ": Failed to parse '" << future_spec_ << "'\n";
- extending = false;
+ if (!ParsePosixSpec(future_spec_, &posix)) return false;
+
+ // Find transition type for the future std specification.
+ std::uint_least8_t std_ti;
+ if (!GetTransitionType(posix.std_offset, false, posix.std_abbr, &std_ti))
+ return false;
+
+ if (posix.dst_abbr.empty()) { // std only
+ // The future specification should match the last transition, and
+ // that means that handling the future will fall out naturally.
+ return EquivTransitions(transitions_.back().type_index, std_ti);
}
- if (extending && posix.dst_abbr.empty()) { // std only
- // The future specification should match the last/default transition,
- // and that means that handling the future will fall out naturally.
- std::uint_fast8_t index = default_transition_type_;
- if (hdr.timecnt != 0) index = transitions_[hdr.timecnt - 1].type_index;
- const TransitionType& tt(transition_types_[index]);
- CheckTransition(name, tt, posix.std_offset, false, posix.std_abbr);
- extending = false;
- }
-
- if (extending && hdr.timecnt < 2) {
- std::clog << name << ": Too few transitions for POSIX spec\n";
- extending = false;
- }
-
- if (!extending) {
- // Ensure that there is always a transition in the second half of the
- // time line (the BIG_BANG transition is in the first half) so that the
- // signed difference between a civil_second and the civil_second of its
- // previous transition is always representable, without overflow.
- const Transition& last(transitions_.back());
- if (last.unix_time < 0) {
- const std::uint_fast8_t type_index = last.type_index;
- Transition& tr(*transitions_.emplace(transitions_.end()));
- tr.unix_time = 2147483647; // 2038-01-19T03:14:07+00:00
- tr.type_index = type_index;
- }
- return; // last transition wins
- }
+ // Find transition type for the future dst specification.
+ std::uint_least8_t dst_ti;
+ if (!GetTransitionType(posix.dst_offset, true, posix.dst_abbr, &dst_ti))
+ return false;
// Extend the transitions for an additional 400 years using the
// future specification. Years beyond those can be handled by
// mapping back to a cycle-equivalent year within that range.
- // zic(8) should probably do this so that we don't have to.
- // TODO: Reduce the extension by the number of compatible
- // transitions already in place.
- transitions_.reserve(hdr.timecnt + 400 * 2 + 1);
- transitions_.resize(hdr.timecnt + 400 * 2);
+ // We may need two additional transitions for the current year.
+ transitions_.reserve(transitions_.size() + 400 * 2 + 2);
extended_ = true;
- // The future specification should match the last two transitions,
- // and those transitions should have different is_dst flags. Note
- // that nothing says the UTC offset used by the is_dst transition
- // must be greater than that used by the !is_dst transition. (See
- // Europe/Dublin, for example.)
- const Transition* tr0 = &transitions_[hdr.timecnt - 1];
- const Transition* tr1 = &transitions_[hdr.timecnt - 2];
- const TransitionType* tt0 = &transition_types_[tr0->type_index];
- const TransitionType* tt1 = &transition_types_[tr1->type_index];
- const TransitionType& dst(tt0->is_dst ? *tt0 : *tt1);
- const TransitionType& std(tt0->is_dst ? *tt1 : *tt0);
- CheckTransition(name, dst, posix.dst_offset, true, posix.dst_abbr);
- CheckTransition(name, std, posix.std_offset, false, posix.std_abbr);
-
- // Add the transitions to tr1 and back to tr0 for each extra year.
- last_year_ = LocalTime(tr0->unix_time, *tt0).cs.year();
+ const Transition& last(transitions_.back());
+ const std::int_fast64_t last_time = last.unix_time;
+ const TransitionType& last_tt(transition_types_[last.type_index]);
+ last_year_ = LocalTime(last_time, last_tt).cs.year();
bool leap_year = IsLeap(last_year_);
- const civil_day jan1(last_year_, 1, 1);
- std::int_fast64_t jan1_time = civil_second(jan1) - civil_second();
- int jan1_weekday = (static_cast<int>(get_weekday(jan1)) + 1) % 7;
- Transition* tr = &transitions_[hdr.timecnt]; // next trans to fill
- if (LocalTime(tr1->unix_time, *tt1).cs.year() != last_year_) {
- // Add a single extra transition to align to a calendar year.
- transitions_.resize(transitions_.size() + 1);
- assert(tr == &transitions_[hdr.timecnt]); // no reallocation
- const PosixTransition& pt1(tt0->is_dst ? posix.dst_end : posix.dst_start);
- std::int_fast64_t tr1_offset = TransOffset(leap_year, jan1_weekday, pt1);
- tr->unix_time = jan1_time + tr1_offset - tt0->utc_offset;
- tr++->type_index = tr1->type_index;
- tr0 = &transitions_[hdr.timecnt];
- tr1 = &transitions_[hdr.timecnt - 1];
- tt0 = &transition_types_[tr0->type_index];
- tt1 = &transition_types_[tr1->type_index];
- }
- const PosixTransition& pt1(tt0->is_dst ? posix.dst_end : posix.dst_start);
- const PosixTransition& pt0(tt0->is_dst ? posix.dst_start : posix.dst_end);
- for (const year_t limit = last_year_ + 400; last_year_ < limit;) {
- last_year_ += 1; // an additional year of generated transitions
+ const civil_second jan1(last_year_);
+ std::int_fast64_t jan1_time = jan1 - civil_second();
+ int jan1_weekday = ToPosixWeekday(get_weekday(jan1));
+
+ Transition dst = {0, dst_ti, civil_second(), civil_second()};
+ Transition std = {0, std_ti, civil_second(), civil_second()};
+ for (const year_t limit = last_year_ + 400;; ++last_year_) {
+ auto dst_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_start);
+ auto std_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_end);
+ dst.unix_time = jan1_time + dst_trans_off - posix.std_offset;
+ std.unix_time = jan1_time + std_trans_off - posix.dst_offset;
+ const auto* ta = dst.unix_time < std.unix_time ? &dst : &std;
+ const auto* tb = dst.unix_time < std.unix_time ? &std : &dst;
+ if (last_time < tb->unix_time) {
+ if (last_time < ta->unix_time) transitions_.push_back(*ta);
+ transitions_.push_back(*tb);
+ }
+ if (last_year_ == limit) break;
jan1_time += kSecsPerYear[leap_year];
jan1_weekday = (jan1_weekday + kDaysPerYear[leap_year]) % 7;
- leap_year = !leap_year && IsLeap(last_year_);
- std::int_fast64_t tr1_offset = TransOffset(leap_year, jan1_weekday, pt1);
- tr->unix_time = jan1_time + tr1_offset - tt0->utc_offset;
- tr++->type_index = tr1->type_index;
- std::int_fast64_t tr0_offset = TransOffset(leap_year, jan1_weekday, pt0);
- tr->unix_time = jan1_time + tr0_offset - tt1->utc_offset;
- tr++->type_index = tr0->type_index;
+ leap_year = !leap_year && IsLeap(last_year_ + 1);
}
- assert(tr == &transitions_[0] + transitions_.size());
+
+ return true;
}
-bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
+bool TimeZoneInfo::Load(ZoneInfoSource* zip) {
// Read and validate the header.
tzhead tzh;
- if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh))
- return false;
+ if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false;
if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0)
return false;
Header hdr;
- if (!hdr.Build(tzh))
- return false;
+ if (!hdr.Build(tzh)) return false;
std::size_t time_len = 4;
if (tzh.tzh_version[0] != '\0') {
// Skip the 4-byte data.
- if (zip->Skip(hdr.DataLength(time_len)) != 0)
- return false;
+ if (zip->Skip(hdr.DataLength(time_len)) != 0) return false;
// Read and validate the header for the 8-byte data.
- if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh))
- return false;
+ if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false;
if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0)
return false;
- if (tzh.tzh_version[0] == '\0')
- return false;
- if (!hdr.Build(tzh))
- return false;
+ if (tzh.tzh_version[0] == '\0') return false;
+ if (!hdr.Build(tzh)) return false;
time_len = 8;
}
- if (hdr.typecnt == 0)
- return false;
+ if (hdr.typecnt == 0) return false;
if (hdr.leapcnt != 0) {
// This code assumes 60-second minutes so we do not want
// the leap-second encoded zoneinfo. We could reverse the
@@ -425,20 +415,17 @@
// so currently we simply reject such data.
return false;
}
- if (hdr.ttisstdcnt != 0 && hdr.ttisstdcnt != hdr.typecnt)
- return false;
- if (hdr.ttisutcnt != 0 && hdr.ttisutcnt != hdr.typecnt)
- return false;
+ if (hdr.ttisstdcnt != 0 && hdr.ttisstdcnt != hdr.typecnt) return false;
+ if (hdr.ttisutcnt != 0 && hdr.ttisutcnt != hdr.typecnt) return false;
// Read the data into a local buffer.
std::size_t len = hdr.DataLength(time_len);
std::vector<char> tbuf(len);
- if (zip->Read(tbuf.data(), len) != len)
- return false;
+ if (zip->Read(tbuf.data(), len) != len) return false;
const char* bp = tbuf.data();
// Decode and validate the transitions.
- transitions_.reserve(hdr.timecnt + 2); // We might add a couple.
+ transitions_.reserve(hdr.timecnt + 2);
transitions_.resize(hdr.timecnt);
for (std::size_t i = 0; i != hdr.timecnt; ++i) {
transitions_[i].unix_time = (time_len == 4) ? Decode32(bp) : Decode64(bp);
@@ -452,13 +439,12 @@
bool seen_type_0 = false;
for (std::size_t i = 0; i != hdr.timecnt; ++i) {
transitions_[i].type_index = Decode8(bp++);
- if (transitions_[i].type_index >= hdr.typecnt)
- return false;
- if (transitions_[i].type_index == 0)
- seen_type_0 = true;
+ if (transitions_[i].type_index >= hdr.typecnt) return false;
+ if (transitions_[i].type_index == 0) seen_type_0 = true;
}
// Decode and validate the transition types.
+ transition_types_.reserve(hdr.typecnt + 2);
transition_types_.resize(hdr.typecnt);
for (std::size_t i = 0; i != hdr.typecnt; ++i) {
transition_types_[i].utc_offset =
@@ -469,8 +455,7 @@
bp += 4;
transition_types_[i].is_dst = (Decode8(bp++) != 0);
transition_types_[i].abbr_index = Decode8(bp++);
- if (transition_types_[i].abbr_index >= hdr.charcnt)
- return false;
+ if (transition_types_[i].abbr_index >= hdr.charcnt) return false;
}
// Determine the before-first-transition type.
@@ -479,16 +464,14 @@
std::uint_fast8_t index = 0;
if (transition_types_[0].is_dst) {
index = transitions_[0].type_index;
- while (index != 0 && transition_types_[index].is_dst)
- --index;
+ while (index != 0 && transition_types_[index].is_dst) --index;
}
- while (index != hdr.typecnt && transition_types_[index].is_dst)
- ++index;
- if (index != hdr.typecnt)
- default_transition_type_ = index;
+ while (index != hdr.typecnt && transition_types_[index].is_dst) ++index;
+ if (index != hdr.typecnt) default_transition_type_ = index;
}
// Copy all the abbreviations.
+ abbreviations_.reserve(hdr.charcnt + 10);
abbreviations_.assign(bp, hdr.charcnt);
bp += hdr.charcnt;
@@ -509,11 +492,9 @@
unsigned char ch; // all non-EOF results are positive
return (azip->Read(&ch, 1) == 1) ? ch : EOF;
};
- if (get_char(zip) != '\n')
- return false;
+ if (get_char(zip) != '\n') return false;
for (int c = get_char(zip); c != '\n'; c = get_char(zip)) {
- if (c == EOF)
- return false;
+ if (c == EOF) return false;
future_spec_.push_back(static_cast<char>(c));
}
}
@@ -522,7 +503,7 @@
// If we did not find version information during the standard loading
// process (as of tzh_version '3' that is unsupported), then ask the
- // ZoneInfoSource for any out-of-bound version std::string it may be privy to.
+ // ZoneInfoSource for any out-of-bound version string it may be privy to.
if (version_.empty()) {
version_ = zip->Version();
}
@@ -541,19 +522,29 @@
transitions_.resize(hdr.timecnt);
// Ensure that there is always a transition in the first half of the
- // time line (the second half is handled in ExtendTransitions()) so that
- // the signed difference between a civil_second and the civil_second of
- // its previous transition is always representable, without overflow.
- // A contemporary zic will usually have already done this for us.
+ // time line (the second half is handled below) so that the signed
+ // difference between a civil_second and the civil_second of its
+ // previous transition is always representable, without overflow.
if (transitions_.empty() || transitions_.front().unix_time >= 0) {
Transition& tr(*transitions_.emplace(transitions_.begin()));
- tr.unix_time = -(1LL << 59); // see tz/zic.c "BIG_BANG"
+ tr.unix_time = -(1LL << 59); // -18267312070-10-26T17:01:52+00:00
tr.type_index = default_transition_type_;
- hdr.timecnt += 1;
}
// Extend the transitions using the future specification.
- ExtendTransitions(name, hdr);
+ if (!ExtendTransitions()) return false;
+
+ // Ensure that there is always a transition in the second half of the
+ // time line (the first half is handled above) so that the signed
+ // difference between a civil_second and the civil_second of its
+ // previous transition is always representable, without overflow.
+ const Transition& last(transitions_.back());
+ if (last.unix_time < 0) {
+ const std::uint_fast8_t type_index = last.type_index;
+ Transition& tr(*transitions_.emplace(transitions_.end()));
+ tr.unix_time = 2147483647; // 2038-01-19T03:14:07+00:00
+ tr.type_index = type_index;
+ }
// Compute the local civil time for each transition and the preceding
// second. These will be used for reverse conversions in MakeTime().
@@ -624,18 +615,18 @@
: fp_(fp, fclose), len_(len) {}
private:
- std::unique_ptr<FILE, int(*)(FILE*)> fp_;
+ std::unique_ptr<FILE, int (*)(FILE*)> fp_;
std::size_t len_;
};
std::unique_ptr<ZoneInfoSource> FileZoneInfoSource::Open(
const std::string& name) {
// Use of the "file:" prefix is intended for testing purposes only.
- if (name.compare(0, 5, "file:") == 0) return Open(name.substr(5));
+ const std::size_t pos = (name.compare(0, 5, "file:") == 0) ? 5 : 0;
// Map the time-zone name to a path name.
std::string path;
- if (name.empty() || name[0] != '/') {
+ if (pos == name.size() || name[pos] != '/') {
const char* tzdir = "/usr/share/zoneinfo";
char* tzdir_env = nullptr;
#if defined(_MSC_VER)
@@ -650,16 +641,16 @@
free(tzdir_env);
#endif
}
- path += name;
+ path.append(name, pos, std::string::npos);
// Open the zoneinfo file.
FILE* fp = FOpen(path.c_str(), "rb");
if (fp == nullptr) return nullptr;
std::size_t length = 0;
if (fseek(fp, 0, SEEK_END) == 0) {
- long pos = ftell(fp);
- if (pos >= 0) {
- length = static_cast<std::size_t>(pos);
+ long offset = ftell(fp);
+ if (offset >= 0) {
+ length = static_cast<std::size_t>(offset);
}
rewind(fp);
}
@@ -680,7 +671,7 @@
std::unique_ptr<ZoneInfoSource> AndroidZoneInfoSource::Open(
const std::string& name) {
// Use of the "file:" prefix is intended for testing purposes only.
- if (name.compare(0, 5, "file:") == 0) return Open(name.substr(5));
+ const std::size_t pos = (name.compare(0, 5, "file:") == 0) ? 5 : 0;
// See Android's libc/tzcode/bionic.cpp for additional information.
for (const char* tzdata : {"/data/misc/zoneinfo/current/tzdata",
@@ -709,7 +700,7 @@
const std::int_fast32_t length = Decode32(ebuf + 44);
if (start < 0 || length < 0) break;
ebuf[40] = '\0'; // ensure zone name is NUL terminated
- if (strcmp(name.c_str(), ebuf) == 0) {
+ if (strcmp(name.c_str() + pos, ebuf) == 0) {
if (fseek(fp.get(), static_cast<long>(start), SEEK_SET) != 0) break;
return std::unique_ptr<ZoneInfoSource>(new AndroidZoneInfoSource(
fp.release(), static_cast<std::size_t>(length), vers));
@@ -734,12 +725,12 @@
// Find and use a ZoneInfoSource to load the named zone.
auto zip = cctz_extension::zone_info_source_factory(
- name, [](const std::string& name) -> std::unique_ptr<ZoneInfoSource> {
- if (auto zip = FileZoneInfoSource::Open(name)) return zip;
- if (auto zip = AndroidZoneInfoSource::Open(name)) return zip;
+ name, [](const std::string& n) -> std::unique_ptr<ZoneInfoSource> {
+ if (auto z = FileZoneInfoSource::Open(n)) return z;
+ if (auto z = AndroidZoneInfoSource::Open(n)) return z;
return nullptr;
});
- return zip != nullptr && Load(name, zip.get());
+ return zip != nullptr && Load(zip.get());
}
// BreakTime() translation for a particular transition type.
@@ -748,13 +739,13 @@
// A civil time in "+offset" looks like (time+offset) in UTC.
// Note: We perform two additions in the civil_second domain to
// sidestep the chance of overflow in (unix_time + tt.utc_offset).
- return {(civil_second() + unix_time) + tt.utc_offset,
- tt.utc_offset, tt.is_dst, &abbreviations_[tt.abbr_index]};
+ return {(civil_second() + unix_time) + tt.utc_offset, tt.utc_offset,
+ tt.is_dst, &abbreviations_[tt.abbr_index]};
}
// BreakTime() translation for a particular transition.
-time_zone::absolute_lookup TimeZoneInfo::LocalTime(
- std::int_fast64_t unix_time, const Transition& tr) const {
+time_zone::absolute_lookup TimeZoneInfo::LocalTime(std::int_fast64_t unix_time,
+ const Transition& tr) const {
const TransitionType& tt = transition_types_[tr.type_index];
// Note: (unix_time - tr.unix_time) will never overflow as we
// have ensured that there is always a "nearby" transition.
@@ -897,9 +888,7 @@
return MakeUnique(tr->unix_time + (cs - tr->civil_sec));
}
-std::string TimeZoneInfo::Version() const {
- return version_;
-}
+std::string TimeZoneInfo::Version() const { return version_; }
std::string TimeZoneInfo::Description() const {
std::ostringstream oss;
@@ -915,14 +904,14 @@
const Transition* begin = &transitions_[0];
const Transition* end = begin + transitions_.size();
if (begin->unix_time <= -(1LL << 59)) {
- // Do not report the BIG_BANG found in recent zoneinfo data as it is
- // really a sentinel, not a transition. See tz/zic.c.
+ // Do not report the BIG_BANG found in some zoneinfo data as it is
+ // really a sentinel, not a transition. See pre-2018f tz/zic.c.
++begin;
}
std::int_fast64_t unix_time = ToUnixSeconds(tp);
const Transition target = {unix_time, 0, civil_second(), civil_second()};
- const Transition* tr = std::upper_bound(begin, end, target,
- Transition::ByUnixTime());
+ const Transition* tr =
+ std::upper_bound(begin, end, target, Transition::ByUnixTime());
for (; tr != end; ++tr) { // skip no-op transitions
std::uint_fast8_t prev_type_index =
(tr == begin) ? default_transition_type_ : tr[-1].type_index;
@@ -941,8 +930,8 @@
const Transition* begin = &transitions_[0];
const Transition* end = begin + transitions_.size();
if (begin->unix_time <= -(1LL << 59)) {
- // Do not report the BIG_BANG found in recent zoneinfo data as it is
- // really a sentinel, not a transition. See tz/zic.c.
+ // Do not report the BIG_BANG found in some zoneinfo data as it is
+ // really a sentinel, not a transition. See pre-2018f tz/zic.c.
++begin;
}
std::int_fast64_t unix_time = ToUnixSeconds(tp);
@@ -956,8 +945,8 @@
unix_time += 1; // ceils
}
const Transition target = {unix_time, 0, civil_second(), civil_second()};
- const Transition* tr = std::lower_bound(begin, end, target,
- Transition::ByUnixTime());
+ const Transition* tr =
+ std::lower_bound(begin, end, target, Transition::ByUnixTime());
for (; tr != begin; --tr) { // skip no-op transitions
std::uint_fast8_t prev_type_index =
(tr - 1 == begin) ? default_transition_type_ : tr[-2].type_index;
@@ -972,4 +961,5 @@
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/time/internal/cctz/src/time_zone_info.h b/third_party/abseil/absl/time/internal/cctz/src/time_zone_info.h
index 81cd402..2467ff5 100644
--- a/third_party/abseil/absl/time/internal/cctz/src/time_zone_info.h
+++ b/third_party/abseil/absl/time/internal/cctz/src/time_zone_info.h
@@ -21,6 +21,7 @@
#include <string>
#include <vector>
+#include "absl/base/config.h"
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
#include "absl/time/internal/cctz/include/cctz/zone_info_source.h"
@@ -28,6 +29,7 @@
#include "tzfile.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
@@ -72,8 +74,7 @@
// TimeZoneIf implementations.
time_zone::absolute_lookup BreakTime(
const time_point<seconds>& tp) const override;
- time_zone::civil_lookup MakeTime(
- const civil_second& cs) const override;
+ time_zone::civil_lookup MakeTime(const civil_second& cs) const override;
bool NextTransition(const time_point<seconds>& tp,
time_zone::civil_transition* trans) const override;
bool PrevTransition(const time_point<seconds>& tp,
@@ -82,7 +83,7 @@
std::string Description() const override;
private:
- struct Header { // counts of:
+ struct Header { // counts of:
std::size_t timecnt; // transition times
std::size_t typecnt; // transition types
std::size_t charcnt; // zone abbreviation characters
@@ -94,15 +95,14 @@
std::size_t DataLength(std::size_t time_len) const;
};
- void CheckTransition(const std::string& name, const TransitionType& tt,
- std::int_fast32_t offset, bool is_dst,
- const std::string& abbr) const;
+ bool GetTransitionType(std::int_fast32_t utc_offset, bool is_dst,
+ const std::string& abbr, std::uint_least8_t* index);
bool EquivTransitions(std::uint_fast8_t tt1_index,
std::uint_fast8_t tt2_index) const;
- void ExtendTransitions(const std::string& name, const Header& hdr);
+ bool ExtendTransitions();
bool ResetToBuiltinUTC(const seconds& offset);
- bool Load(const std::string& name, ZoneInfoSource* zip);
+ bool Load(ZoneInfoSource* zip);
// Helpers for BreakTime() and MakeTime().
time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time,
@@ -114,7 +114,7 @@
std::vector<Transition> transitions_; // ordered by unix_time and civil_sec
std::vector<TransitionType> transition_types_; // distinct transition types
- std::uint_fast8_t default_transition_type_; // for before first transition
+ std::uint_fast8_t default_transition_type_; // for before first transition
std::string abbreviations_; // all the NUL-terminated abbreviations
std::string version_; // the tzdata version if available
@@ -131,6 +131,7 @@
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_
diff --git a/third_party/abseil/absl/time/internal/cctz/src/time_zone_libc.cc b/third_party/abseil/absl/time/internal/cctz/src/time_zone_libc.cc
index 6095e76..887dd09 100644
--- a/third_party/abseil/absl/time/internal/cctz/src/time_zone_libc.cc
+++ b/third_party/abseil/absl/time/internal/cctz/src/time_zone_libc.cc
@@ -23,10 +23,18 @@
#include <limits>
#include <utility>
+#include "absl/base/config.h"
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+#if defined(_AIX)
+extern "C" {
+extern long altzone;
+}
+#endif
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
@@ -42,7 +50,7 @@
const bool is_dst = tm.tm_isdst > 0;
return _tzname[is_dst];
}
-#elif defined(__sun)
+#elif defined(__sun) || defined(_AIX)
// Uses the globals: 'timezone', 'altzone' and 'tzname'.
auto tm_gmtoff(const std::tm& tm) -> decltype(timezone) {
const bool is_dst = tm.tm_isdst > 0;
@@ -84,9 +92,7 @@
}
#endif // tm_gmtoff
#if defined(tm_zone)
-auto tm_zone(const std::tm& tm) -> decltype(tm.tm_zone) {
- return tm.tm_zone;
-}
+auto tm_zone(const std::tm& tm) -> decltype(tm.tm_zone) { return tm.tm_zone; }
#elif defined(__tm_zone)
auto tm_zone(const std::tm& tm) -> decltype(tm.__tm_zone) {
return tm.__tm_zone;
@@ -103,19 +109,19 @@
#endif // tm_zone
#endif
-inline std::tm* gm_time(const std::time_t *timep, std::tm *result) {
+inline std::tm* gm_time(const std::time_t* timep, std::tm* result) {
#if defined(_WIN32) || defined(_WIN64)
- return gmtime_s(result, timep) ? nullptr : result;
+ return gmtime_s(result, timep) ? nullptr : result;
#else
- return gmtime_r(timep, result);
+ return gmtime_r(timep, result);
#endif
}
-inline std::tm* local_time(const std::time_t *timep, std::tm *result) {
+inline std::tm* local_time(const std::time_t* timep, std::tm* result) {
#if defined(_WIN32) || defined(_WIN64)
- return localtime_s(result, timep) ? nullptr : result;
+ return localtime_s(result, timep) ? nullptr : result;
#else
- return localtime_r(timep, result);
+ return localtime_r(timep, result);
#endif
}
@@ -153,7 +159,8 @@
std::tm tm;
while (lo + 1 != hi) {
const std::time_t mid = lo + (hi - lo) / 2;
- if (std::tm* tmp = local_time(&mid, &tm)) {
+ std::tm* tmp = local_time(&mid, &tm);
+ if (tmp != nullptr) {
if (tm_gmtoff(*tmp) == offset) {
hi = mid;
} else {
@@ -163,7 +170,8 @@
// If std::tm cannot hold some result we resort to a linear search,
// ignoring all failed conversions. Slow, but never really happens.
while (++lo != hi) {
- if (std::tm* tmp = local_time(&lo, &tm)) {
+ tmp = local_time(&lo, &tm);
+ if (tmp != nullptr) {
if (tm_gmtoff(*tmp) == offset) break;
}
}
@@ -208,8 +216,8 @@
}
const year_t year = tmp->tm_year + year_t{1900};
- al.cs = civil_second(year, tmp->tm_mon + 1, tmp->tm_mday,
- tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+ al.cs = civil_second(year, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour,
+ tmp->tm_min, tmp->tm_sec);
al.offset = static_cast<int>(tm_gmtoff(*tmp));
al.abbr = local_ ? tm_zone(*tmp) : "UTC"; // as expected by cctz
al.is_dst = tmp->tm_isdst > 0;
@@ -223,11 +231,10 @@
civil_second() + ToUnixSeconds(time_point<seconds>::min());
static const civil_second max_tp_cs =
civil_second() + ToUnixSeconds(time_point<seconds>::max());
- const time_point<seconds> tp =
- (cs < min_tp_cs)
- ? time_point<seconds>::min()
- : (cs > max_tp_cs) ? time_point<seconds>::max()
- : FromUnixSeconds(cs - civil_second());
+ const time_point<seconds> tp = (cs < min_tp_cs) ? time_point<seconds>::min()
+ : (cs > max_tp_cs)
+ ? time_point<seconds>::max()
+ : FromUnixSeconds(cs - civil_second());
return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
}
@@ -304,4 +311,5 @@
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/time/internal/cctz/src/time_zone_libc.h b/third_party/abseil/absl/time/internal/cctz/src/time_zone_libc.h
index 0d18e9a..1da9039 100644
--- a/third_party/abseil/absl/time/internal/cctz/src/time_zone_libc.h
+++ b/third_party/abseil/absl/time/internal/cctz/src/time_zone_libc.h
@@ -17,9 +17,11 @@
#include <string>
+#include "absl/base/config.h"
#include "time_zone_if.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
@@ -33,8 +35,7 @@
// TimeZoneIf implementations.
time_zone::absolute_lookup BreakTime(
const time_point<seconds>& tp) const override;
- time_zone::civil_lookup MakeTime(
- const civil_second& cs) const override;
+ time_zone::civil_lookup MakeTime(const civil_second& cs) const override;
bool NextTransition(const time_point<seconds>& tp,
time_zone::civil_transition* trans) const override;
bool PrevTransition(const time_point<seconds>& tp,
@@ -48,6 +49,7 @@
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_
diff --git a/third_party/abseil/absl/time/internal/cctz/src/time_zone_lookup.cc b/third_party/abseil/absl/time/internal/cctz/src/time_zone_lookup.cc
index 3c53dd1..efdea64 100644
--- a/third_party/abseil/absl/time/internal/cctz/src/time_zone_lookup.cc
+++ b/third_party/abseil/absl/time/internal/cctz/src/time_zone_lookup.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "absl/base/config.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
#if defined(__ANDROID__)
@@ -23,6 +24,7 @@
#if defined(__APPLE__)
#include <CoreFoundation/CFTimeZone.h>
+
#include <vector>
#endif
@@ -34,6 +36,7 @@
#include "time_zone_impl.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
@@ -66,9 +69,7 @@
} // namespace
#endif
-std::string time_zone::name() const {
- return effective_impl().Name();
-}
+std::string time_zone::name() const { return effective_impl().Name(); }
time_zone::absolute_lookup time_zone::lookup(
const time_point<seconds>& tp) const {
@@ -89,9 +90,7 @@
return effective_impl().PrevTransition(tp, trans);
}
-std::string time_zone::version() const {
- return effective_impl().Version();
-}
+std::string time_zone::version() const { return effective_impl().Version(); }
std::string time_zone::description() const {
return effective_impl().Description();
@@ -184,4 +183,5 @@
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/third_party/abseil/absl/time/internal/cctz/src/time_zone_lookup_test.cc
index 42dd6d5..9a1a8d6 100644
--- a/third_party/abseil/absl/time/internal/cctz/src/time_zone_lookup_test.cc
+++ b/third_party/abseil/absl/time/internal/cctz/src/time_zone_lookup_test.cc
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "absl/time/internal/cctz/include/cctz/time_zone.h"
-
#include <chrono>
#include <cstddef>
#include <cstdlib>
@@ -23,613 +21,615 @@
#include <thread>
#include <vector>
-#include "absl/time/internal/cctz/include/cctz/civil_time.h"
#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
namespace chrono = std::chrono;
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
namespace {
// A list of known time-zone names.
-const char* const kTimeZoneNames[] = {
- "Africa/Abidjan",
- "Africa/Accra",
- "Africa/Addis_Ababa",
- "Africa/Algiers",
- "Africa/Asmara",
- "Africa/Asmera",
- "Africa/Bamako",
- "Africa/Bangui",
- "Africa/Banjul",
- "Africa/Bissau",
- "Africa/Blantyre",
- "Africa/Brazzaville",
- "Africa/Bujumbura",
- "Africa/Cairo",
- "Africa/Casablanca",
- "Africa/Ceuta",
- "Africa/Conakry",
- "Africa/Dakar",
- "Africa/Dar_es_Salaam",
- "Africa/Djibouti",
- "Africa/Douala",
- "Africa/El_Aaiun",
- "Africa/Freetown",
- "Africa/Gaborone",
- "Africa/Harare",
- "Africa/Johannesburg",
- "Africa/Juba",
- "Africa/Kampala",
- "Africa/Khartoum",
- "Africa/Kigali",
- "Africa/Kinshasa",
- "Africa/Lagos",
- "Africa/Libreville",
- "Africa/Lome",
- "Africa/Luanda",
- "Africa/Lubumbashi",
- "Africa/Lusaka",
- "Africa/Malabo",
- "Africa/Maputo",
- "Africa/Maseru",
- "Africa/Mbabane",
- "Africa/Mogadishu",
- "Africa/Monrovia",
- "Africa/Nairobi",
- "Africa/Ndjamena",
- "Africa/Niamey",
- "Africa/Nouakchott",
- "Africa/Ouagadougou",
- "Africa/Porto-Novo",
- "Africa/Sao_Tome",
- "Africa/Timbuktu",
- "Africa/Tripoli",
- "Africa/Tunis",
- "Africa/Windhoek",
- "America/Adak",
- "America/Anchorage",
- "America/Anguilla",
- "America/Antigua",
- "America/Araguaina",
- "America/Argentina/Buenos_Aires",
- "America/Argentina/Catamarca",
- "America/Argentina/ComodRivadavia",
- "America/Argentina/Cordoba",
- "America/Argentina/Jujuy",
- "America/Argentina/La_Rioja",
- "America/Argentina/Mendoza",
- "America/Argentina/Rio_Gallegos",
- "America/Argentina/Salta",
- "America/Argentina/San_Juan",
- "America/Argentina/San_Luis",
- "America/Argentina/Tucuman",
- "America/Argentina/Ushuaia",
- "America/Aruba",
- "America/Asuncion",
- "America/Atikokan",
- "America/Atka",
- "America/Bahia",
- "America/Bahia_Banderas",
- "America/Barbados",
- "America/Belem",
- "America/Belize",
- "America/Blanc-Sablon",
- "America/Boa_Vista",
- "America/Bogota",
- "America/Boise",
- "America/Buenos_Aires",
- "America/Cambridge_Bay",
- "America/Campo_Grande",
- "America/Cancun",
- "America/Caracas",
- "America/Catamarca",
- "America/Cayenne",
- "America/Cayman",
- "America/Chicago",
- "America/Chihuahua",
- "America/Coral_Harbour",
- "America/Cordoba",
- "America/Costa_Rica",
- "America/Creston",
- "America/Cuiaba",
- "America/Curacao",
- "America/Danmarkshavn",
- "America/Dawson",
- "America/Dawson_Creek",
- "America/Denver",
- "America/Detroit",
- "America/Dominica",
- "America/Edmonton",
- "America/Eirunepe",
- "America/El_Salvador",
- "America/Ensenada",
- "America/Fort_Nelson",
- "America/Fort_Wayne",
- "America/Fortaleza",
- "America/Glace_Bay",
- "America/Godthab",
- "America/Goose_Bay",
- "America/Grand_Turk",
- "America/Grenada",
- "America/Guadeloupe",
- "America/Guatemala",
- "America/Guayaquil",
- "America/Guyana",
- "America/Halifax",
- "America/Havana",
- "America/Hermosillo",
- "America/Indiana/Indianapolis",
- "America/Indiana/Knox",
- "America/Indiana/Marengo",
- "America/Indiana/Petersburg",
- "America/Indiana/Tell_City",
- "America/Indiana/Vevay",
- "America/Indiana/Vincennes",
- "America/Indiana/Winamac",
- "America/Indianapolis",
- "America/Inuvik",
- "America/Iqaluit",
- "America/Jamaica",
- "America/Jujuy",
- "America/Juneau",
- "America/Kentucky/Louisville",
- "America/Kentucky/Monticello",
- "America/Knox_IN",
- "America/Kralendijk",
- "America/La_Paz",
- "America/Lima",
- "America/Los_Angeles",
- "America/Louisville",
- "America/Lower_Princes",
- "America/Maceio",
- "America/Managua",
- "America/Manaus",
- "America/Marigot",
- "America/Martinique",
- "America/Matamoros",
- "America/Mazatlan",
- "America/Mendoza",
- "America/Menominee",
- "America/Merida",
- "America/Metlakatla",
- "America/Mexico_City",
- "America/Miquelon",
- "America/Moncton",
- "America/Monterrey",
- "America/Montevideo",
- "America/Montreal",
- "America/Montserrat",
- "America/Nassau",
- "America/New_York",
- "America/Nipigon",
- "America/Nome",
- "America/Noronha",
- "America/North_Dakota/Beulah",
- "America/North_Dakota/Center",
- "America/North_Dakota/New_Salem",
- "America/Ojinaga",
- "America/Panama",
- "America/Pangnirtung",
- "America/Paramaribo",
- "America/Phoenix",
- "America/Port-au-Prince",
- "America/Port_of_Spain",
- "America/Porto_Acre",
- "America/Porto_Velho",
- "America/Puerto_Rico",
- "America/Punta_Arenas",
- "America/Rainy_River",
- "America/Rankin_Inlet",
- "America/Recife",
- "America/Regina",
- "America/Resolute",
- "America/Rio_Branco",
- "America/Rosario",
- "America/Santa_Isabel",
- "America/Santarem",
- "America/Santiago",
- "America/Santo_Domingo",
- "America/Sao_Paulo",
- "America/Scoresbysund",
- "America/Shiprock",
- "America/Sitka",
- "America/St_Barthelemy",
- "America/St_Johns",
- "America/St_Kitts",
- "America/St_Lucia",
- "America/St_Thomas",
- "America/St_Vincent",
- "America/Swift_Current",
- "America/Tegucigalpa",
- "America/Thule",
- "America/Thunder_Bay",
- "America/Tijuana",
- "America/Toronto",
- "America/Tortola",
- "America/Vancouver",
- "America/Virgin",
- "America/Whitehorse",
- "America/Winnipeg",
- "America/Yakutat",
- "America/Yellowknife",
- "Antarctica/Casey",
- "Antarctica/Davis",
- "Antarctica/DumontDUrville",
- "Antarctica/Macquarie",
- "Antarctica/Mawson",
- "Antarctica/McMurdo",
- "Antarctica/Palmer",
- "Antarctica/Rothera",
- "Antarctica/South_Pole",
- "Antarctica/Syowa",
- "Antarctica/Troll",
- "Antarctica/Vostok",
- "Arctic/Longyearbyen",
- "Asia/Aden",
- "Asia/Almaty",
- "Asia/Amman",
- "Asia/Anadyr",
- "Asia/Aqtau",
- "Asia/Aqtobe",
- "Asia/Ashgabat",
- "Asia/Ashkhabad",
- "Asia/Atyrau",
- "Asia/Baghdad",
- "Asia/Bahrain",
- "Asia/Baku",
- "Asia/Bangkok",
- "Asia/Barnaul",
- "Asia/Beirut",
- "Asia/Bishkek",
- "Asia/Brunei",
- "Asia/Calcutta",
- "Asia/Chita",
- "Asia/Choibalsan",
- "Asia/Chongqing",
- "Asia/Chungking",
- "Asia/Colombo",
- "Asia/Dacca",
- "Asia/Damascus",
- "Asia/Dhaka",
- "Asia/Dili",
- "Asia/Dubai",
- "Asia/Dushanbe",
- "Asia/Famagusta",
- "Asia/Gaza",
- "Asia/Harbin",
- "Asia/Hebron",
- "Asia/Ho_Chi_Minh",
- "Asia/Hong_Kong",
- "Asia/Hovd",
- "Asia/Irkutsk",
- "Asia/Istanbul",
- "Asia/Jakarta",
- "Asia/Jayapura",
- "Asia/Jerusalem",
- "Asia/Kabul",
- "Asia/Kamchatka",
- "Asia/Karachi",
- "Asia/Kashgar",
- "Asia/Kathmandu",
- "Asia/Katmandu",
- "Asia/Khandyga",
- "Asia/Kolkata",
- "Asia/Krasnoyarsk",
- "Asia/Kuala_Lumpur",
- "Asia/Kuching",
- "Asia/Kuwait",
- "Asia/Macao",
- "Asia/Macau",
- "Asia/Magadan",
- "Asia/Makassar",
- "Asia/Manila",
- "Asia/Muscat",
- "Asia/Nicosia",
- "Asia/Novokuznetsk",
- "Asia/Novosibirsk",
- "Asia/Omsk",
- "Asia/Oral",
- "Asia/Phnom_Penh",
- "Asia/Pontianak",
- "Asia/Pyongyang",
- "Asia/Qatar",
- "Asia/Qostanay",
- "Asia/Qyzylorda",
- "Asia/Rangoon",
- "Asia/Riyadh",
- "Asia/Saigon",
- "Asia/Sakhalin",
- "Asia/Samarkand",
- "Asia/Seoul",
- "Asia/Shanghai",
- "Asia/Singapore",
- "Asia/Srednekolymsk",
- "Asia/Taipei",
- "Asia/Tashkent",
- "Asia/Tbilisi",
- "Asia/Tehran",
- "Asia/Tel_Aviv",
- "Asia/Thimbu",
- "Asia/Thimphu",
- "Asia/Tokyo",
- "Asia/Tomsk",
- "Asia/Ujung_Pandang",
- "Asia/Ulaanbaatar",
- "Asia/Ulan_Bator",
- "Asia/Urumqi",
- "Asia/Ust-Nera",
- "Asia/Vientiane",
- "Asia/Vladivostok",
- "Asia/Yakutsk",
- "Asia/Yangon",
- "Asia/Yekaterinburg",
- "Asia/Yerevan",
- "Atlantic/Azores",
- "Atlantic/Bermuda",
- "Atlantic/Canary",
- "Atlantic/Cape_Verde",
- "Atlantic/Faeroe",
- "Atlantic/Faroe",
- "Atlantic/Jan_Mayen",
- "Atlantic/Madeira",
- "Atlantic/Reykjavik",
- "Atlantic/South_Georgia",
- "Atlantic/St_Helena",
- "Atlantic/Stanley",
- "Australia/ACT",
- "Australia/Adelaide",
- "Australia/Brisbane",
- "Australia/Broken_Hill",
- "Australia/Canberra",
- "Australia/Currie",
- "Australia/Darwin",
- "Australia/Eucla",
- "Australia/Hobart",
- "Australia/LHI",
- "Australia/Lindeman",
- "Australia/Lord_Howe",
- "Australia/Melbourne",
- "Australia/NSW",
- "Australia/North",
- "Australia/Perth",
- "Australia/Queensland",
- "Australia/South",
- "Australia/Sydney",
- "Australia/Tasmania",
- "Australia/Victoria",
- "Australia/West",
- "Australia/Yancowinna",
- "Brazil/Acre",
- "Brazil/DeNoronha",
- "Brazil/East",
- "Brazil/West",
- "CET",
- "CST6CDT",
- "Canada/Atlantic",
- "Canada/Central",
- "Canada/Eastern",
- "Canada/Mountain",
- "Canada/Newfoundland",
- "Canada/Pacific",
- "Canada/Saskatchewan",
- "Canada/Yukon",
- "Chile/Continental",
- "Chile/EasterIsland",
- "Cuba",
- "EET",
- "EST",
- "EST5EDT",
- "Egypt",
- "Eire",
- "Etc/GMT",
- "Etc/GMT+0",
- "Etc/GMT+1",
- "Etc/GMT+10",
- "Etc/GMT+11",
- "Etc/GMT+12",
- "Etc/GMT+2",
- "Etc/GMT+3",
- "Etc/GMT+4",
- "Etc/GMT+5",
- "Etc/GMT+6",
- "Etc/GMT+7",
- "Etc/GMT+8",
- "Etc/GMT+9",
- "Etc/GMT-0",
- "Etc/GMT-1",
- "Etc/GMT-10",
- "Etc/GMT-11",
- "Etc/GMT-12",
- "Etc/GMT-13",
- "Etc/GMT-14",
- "Etc/GMT-2",
- "Etc/GMT-3",
- "Etc/GMT-4",
- "Etc/GMT-5",
- "Etc/GMT-6",
- "Etc/GMT-7",
- "Etc/GMT-8",
- "Etc/GMT-9",
- "Etc/GMT0",
- "Etc/Greenwich",
- "Etc/UCT",
- "Etc/UTC",
- "Etc/Universal",
- "Etc/Zulu",
- "Europe/Amsterdam",
- "Europe/Andorra",
- "Europe/Astrakhan",
- "Europe/Athens",
- "Europe/Belfast",
- "Europe/Belgrade",
- "Europe/Berlin",
- "Europe/Bratislava",
- "Europe/Brussels",
- "Europe/Bucharest",
- "Europe/Budapest",
- "Europe/Busingen",
- "Europe/Chisinau",
- "Europe/Copenhagen",
- "Europe/Dublin",
- "Europe/Gibraltar",
- "Europe/Guernsey",
- "Europe/Helsinki",
- "Europe/Isle_of_Man",
- "Europe/Istanbul",
- "Europe/Jersey",
- "Europe/Kaliningrad",
- "Europe/Kiev",
- "Europe/Kirov",
- "Europe/Lisbon",
- "Europe/Ljubljana",
- "Europe/London",
- "Europe/Luxembourg",
- "Europe/Madrid",
- "Europe/Malta",
- "Europe/Mariehamn",
- "Europe/Minsk",
- "Europe/Monaco",
- "Europe/Moscow",
- "Europe/Nicosia",
- "Europe/Oslo",
- "Europe/Paris",
- "Europe/Podgorica",
- "Europe/Prague",
- "Europe/Riga",
- "Europe/Rome",
- "Europe/Samara",
- "Europe/San_Marino",
- "Europe/Sarajevo",
- "Europe/Saratov",
- "Europe/Simferopol",
- "Europe/Skopje",
- "Europe/Sofia",
- "Europe/Stockholm",
- "Europe/Tallinn",
- "Europe/Tirane",
- "Europe/Tiraspol",
- "Europe/Ulyanovsk",
- "Europe/Uzhgorod",
- "Europe/Vaduz",
- "Europe/Vatican",
- "Europe/Vienna",
- "Europe/Vilnius",
- "Europe/Volgograd",
- "Europe/Warsaw",
- "Europe/Zagreb",
- "Europe/Zaporozhye",
- "Europe/Zurich",
- "GB",
- "GB-Eire",
- "GMT",
- "GMT+0",
- "GMT-0",
- "GMT0",
- "Greenwich",
- "HST",
- "Hongkong",
- "Iceland",
- "Indian/Antananarivo",
- "Indian/Chagos",
- "Indian/Christmas",
- "Indian/Cocos",
- "Indian/Comoro",
- "Indian/Kerguelen",
- "Indian/Mahe",
- "Indian/Maldives",
- "Indian/Mauritius",
- "Indian/Mayotte",
- "Indian/Reunion",
- "Iran",
- "Israel",
- "Jamaica",
- "Japan",
- "Kwajalein",
- "Libya",
- "MET",
- "MST",
- "MST7MDT",
- "Mexico/BajaNorte",
- "Mexico/BajaSur",
- "Mexico/General",
- "NZ",
- "NZ-CHAT",
- "Navajo",
- "PRC",
- "PST8PDT",
- "Pacific/Apia",
- "Pacific/Auckland",
- "Pacific/Bougainville",
- "Pacific/Chatham",
- "Pacific/Chuuk",
- "Pacific/Easter",
- "Pacific/Efate",
- "Pacific/Enderbury",
- "Pacific/Fakaofo",
- "Pacific/Fiji",
- "Pacific/Funafuti",
- "Pacific/Galapagos",
- "Pacific/Gambier",
- "Pacific/Guadalcanal",
- "Pacific/Guam",
- "Pacific/Honolulu",
- "Pacific/Johnston",
- "Pacific/Kiritimati",
- "Pacific/Kosrae",
- "Pacific/Kwajalein",
- "Pacific/Majuro",
- "Pacific/Marquesas",
- "Pacific/Midway",
- "Pacific/Nauru",
- "Pacific/Niue",
- "Pacific/Norfolk",
- "Pacific/Noumea",
- "Pacific/Pago_Pago",
- "Pacific/Palau",
- "Pacific/Pitcairn",
- "Pacific/Pohnpei",
- "Pacific/Ponape",
- "Pacific/Port_Moresby",
- "Pacific/Rarotonga",
- "Pacific/Saipan",
- "Pacific/Samoa",
- "Pacific/Tahiti",
- "Pacific/Tarawa",
- "Pacific/Tongatapu",
- "Pacific/Truk",
- "Pacific/Wake",
- "Pacific/Wallis",
- "Pacific/Yap",
- "Poland",
- "Portugal",
- "ROC",
- "ROK",
- "Singapore",
- "Turkey",
- "UCT",
- "US/Alaska",
- "US/Aleutian",
- "US/Arizona",
- "US/Central",
- "US/East-Indiana",
- "US/Eastern",
- "US/Hawaii",
- "US/Indiana-Starke",
- "US/Michigan",
- "US/Mountain",
- "US/Pacific",
- "US/Samoa",
- "UTC",
- "Universal",
- "W-SU",
- "WET",
- "Zulu",
- nullptr
-};
+const char* const kTimeZoneNames[] = {"Africa/Abidjan",
+ "Africa/Accra",
+ "Africa/Addis_Ababa",
+ "Africa/Algiers",
+ "Africa/Asmara",
+ "Africa/Asmera",
+ "Africa/Bamako",
+ "Africa/Bangui",
+ "Africa/Banjul",
+ "Africa/Bissau",
+ "Africa/Blantyre",
+ "Africa/Brazzaville",
+ "Africa/Bujumbura",
+ "Africa/Cairo",
+ "Africa/Casablanca",
+ "Africa/Ceuta",
+ "Africa/Conakry",
+ "Africa/Dakar",
+ "Africa/Dar_es_Salaam",
+ "Africa/Djibouti",
+ "Africa/Douala",
+ "Africa/El_Aaiun",
+ "Africa/Freetown",
+ "Africa/Gaborone",
+ "Africa/Harare",
+ "Africa/Johannesburg",
+ "Africa/Juba",
+ "Africa/Kampala",
+ "Africa/Khartoum",
+ "Africa/Kigali",
+ "Africa/Kinshasa",
+ "Africa/Lagos",
+ "Africa/Libreville",
+ "Africa/Lome",
+ "Africa/Luanda",
+ "Africa/Lubumbashi",
+ "Africa/Lusaka",
+ "Africa/Malabo",
+ "Africa/Maputo",
+ "Africa/Maseru",
+ "Africa/Mbabane",
+ "Africa/Mogadishu",
+ "Africa/Monrovia",
+ "Africa/Nairobi",
+ "Africa/Ndjamena",
+ "Africa/Niamey",
+ "Africa/Nouakchott",
+ "Africa/Ouagadougou",
+ "Africa/Porto-Novo",
+ "Africa/Sao_Tome",
+ "Africa/Timbuktu",
+ "Africa/Tripoli",
+ "Africa/Tunis",
+ "Africa/Windhoek",
+ "America/Adak",
+ "America/Anchorage",
+ "America/Anguilla",
+ "America/Antigua",
+ "America/Araguaina",
+ "America/Argentina/Buenos_Aires",
+ "America/Argentina/Catamarca",
+ "America/Argentina/ComodRivadavia",
+ "America/Argentina/Cordoba",
+ "America/Argentina/Jujuy",
+ "America/Argentina/La_Rioja",
+ "America/Argentina/Mendoza",
+ "America/Argentina/Rio_Gallegos",
+ "America/Argentina/Salta",
+ "America/Argentina/San_Juan",
+ "America/Argentina/San_Luis",
+ "America/Argentina/Tucuman",
+ "America/Argentina/Ushuaia",
+ "America/Aruba",
+ "America/Asuncion",
+ "America/Atikokan",
+ "America/Atka",
+ "America/Bahia",
+ "America/Bahia_Banderas",
+ "America/Barbados",
+ "America/Belem",
+ "America/Belize",
+ "America/Blanc-Sablon",
+ "America/Boa_Vista",
+ "America/Bogota",
+ "America/Boise",
+ "America/Buenos_Aires",
+ "America/Cambridge_Bay",
+ "America/Campo_Grande",
+ "America/Cancun",
+ "America/Caracas",
+ "America/Catamarca",
+ "America/Cayenne",
+ "America/Cayman",
+ "America/Chicago",
+ "America/Chihuahua",
+ "America/Coral_Harbour",
+ "America/Cordoba",
+ "America/Costa_Rica",
+ "America/Creston",
+ "America/Cuiaba",
+ "America/Curacao",
+ "America/Danmarkshavn",
+ "America/Dawson",
+ "America/Dawson_Creek",
+ "America/Denver",
+ "America/Detroit",
+ "America/Dominica",
+ "America/Edmonton",
+ "America/Eirunepe",
+ "America/El_Salvador",
+ "America/Ensenada",
+ "America/Fort_Nelson",
+ "America/Fort_Wayne",
+ "America/Fortaleza",
+ "America/Glace_Bay",
+ "America/Godthab",
+ "America/Goose_Bay",
+ "America/Grand_Turk",
+ "America/Grenada",
+ "America/Guadeloupe",
+ "America/Guatemala",
+ "America/Guayaquil",
+ "America/Guyana",
+ "America/Halifax",
+ "America/Havana",
+ "America/Hermosillo",
+ "America/Indiana/Indianapolis",
+ "America/Indiana/Knox",
+ "America/Indiana/Marengo",
+ "America/Indiana/Petersburg",
+ "America/Indiana/Tell_City",
+ "America/Indiana/Vevay",
+ "America/Indiana/Vincennes",
+ "America/Indiana/Winamac",
+ "America/Indianapolis",
+ "America/Inuvik",
+ "America/Iqaluit",
+ "America/Jamaica",
+ "America/Jujuy",
+ "America/Juneau",
+ "America/Kentucky/Louisville",
+ "America/Kentucky/Monticello",
+ "America/Knox_IN",
+ "America/Kralendijk",
+ "America/La_Paz",
+ "America/Lima",
+ "America/Los_Angeles",
+ "America/Louisville",
+ "America/Lower_Princes",
+ "America/Maceio",
+ "America/Managua",
+ "America/Manaus",
+ "America/Marigot",
+ "America/Martinique",
+ "America/Matamoros",
+ "America/Mazatlan",
+ "America/Mendoza",
+ "America/Menominee",
+ "America/Merida",
+ "America/Metlakatla",
+ "America/Mexico_City",
+ "America/Miquelon",
+ "America/Moncton",
+ "America/Monterrey",
+ "America/Montevideo",
+ "America/Montreal",
+ "America/Montserrat",
+ "America/Nassau",
+ "America/New_York",
+ "America/Nipigon",
+ "America/Nome",
+ "America/Noronha",
+ "America/North_Dakota/Beulah",
+ "America/North_Dakota/Center",
+ "America/North_Dakota/New_Salem",
+ "America/Nuuk",
+ "America/Ojinaga",
+ "America/Panama",
+ "America/Pangnirtung",
+ "America/Paramaribo",
+ "America/Phoenix",
+ "America/Port-au-Prince",
+ "America/Port_of_Spain",
+ "America/Porto_Acre",
+ "America/Porto_Velho",
+ "America/Puerto_Rico",
+ "America/Punta_Arenas",
+ "America/Rainy_River",
+ "America/Rankin_Inlet",
+ "America/Recife",
+ "America/Regina",
+ "America/Resolute",
+ "America/Rio_Branco",
+ "America/Rosario",
+ "America/Santa_Isabel",
+ "America/Santarem",
+ "America/Santiago",
+ "America/Santo_Domingo",
+ "America/Sao_Paulo",
+ "America/Scoresbysund",
+ "America/Shiprock",
+ "America/Sitka",
+ "America/St_Barthelemy",
+ "America/St_Johns",
+ "America/St_Kitts",
+ "America/St_Lucia",
+ "America/St_Thomas",
+ "America/St_Vincent",
+ "America/Swift_Current",
+ "America/Tegucigalpa",
+ "America/Thule",
+ "America/Thunder_Bay",
+ "America/Tijuana",
+ "America/Toronto",
+ "America/Tortola",
+ "America/Vancouver",
+ "America/Virgin",
+ "America/Whitehorse",
+ "America/Winnipeg",
+ "America/Yakutat",
+ "America/Yellowknife",
+ "Antarctica/Casey",
+ "Antarctica/Davis",
+ "Antarctica/DumontDUrville",
+ "Antarctica/Macquarie",
+ "Antarctica/Mawson",
+ "Antarctica/McMurdo",
+ "Antarctica/Palmer",
+ "Antarctica/Rothera",
+ "Antarctica/South_Pole",
+ "Antarctica/Syowa",
+ "Antarctica/Troll",
+ "Antarctica/Vostok",
+ "Arctic/Longyearbyen",
+ "Asia/Aden",
+ "Asia/Almaty",
+ "Asia/Amman",
+ "Asia/Anadyr",
+ "Asia/Aqtau",
+ "Asia/Aqtobe",
+ "Asia/Ashgabat",
+ "Asia/Ashkhabad",
+ "Asia/Atyrau",
+ "Asia/Baghdad",
+ "Asia/Bahrain",
+ "Asia/Baku",
+ "Asia/Bangkok",
+ "Asia/Barnaul",
+ "Asia/Beirut",
+ "Asia/Bishkek",
+ "Asia/Brunei",
+ "Asia/Calcutta",
+ "Asia/Chita",
+ "Asia/Choibalsan",
+ "Asia/Chongqing",
+ "Asia/Chungking",
+ "Asia/Colombo",
+ "Asia/Dacca",
+ "Asia/Damascus",
+ "Asia/Dhaka",
+ "Asia/Dili",
+ "Asia/Dubai",
+ "Asia/Dushanbe",
+ "Asia/Famagusta",
+ "Asia/Gaza",
+ "Asia/Harbin",
+ "Asia/Hebron",
+ "Asia/Ho_Chi_Minh",
+ "Asia/Hong_Kong",
+ "Asia/Hovd",
+ "Asia/Irkutsk",
+ "Asia/Istanbul",
+ "Asia/Jakarta",
+ "Asia/Jayapura",
+ "Asia/Jerusalem",
+ "Asia/Kabul",
+ "Asia/Kamchatka",
+ "Asia/Karachi",
+ "Asia/Kashgar",
+ "Asia/Kathmandu",
+ "Asia/Katmandu",
+ "Asia/Khandyga",
+ "Asia/Kolkata",
+ "Asia/Krasnoyarsk",
+ "Asia/Kuala_Lumpur",
+ "Asia/Kuching",
+ "Asia/Kuwait",
+ "Asia/Macao",
+ "Asia/Macau",
+ "Asia/Magadan",
+ "Asia/Makassar",
+ "Asia/Manila",
+ "Asia/Muscat",
+ "Asia/Nicosia",
+ "Asia/Novokuznetsk",
+ "Asia/Novosibirsk",
+ "Asia/Omsk",
+ "Asia/Oral",
+ "Asia/Phnom_Penh",
+ "Asia/Pontianak",
+ "Asia/Pyongyang",
+ "Asia/Qatar",
+ "Asia/Qostanay",
+ "Asia/Qyzylorda",
+ "Asia/Rangoon",
+ "Asia/Riyadh",
+ "Asia/Saigon",
+ "Asia/Sakhalin",
+ "Asia/Samarkand",
+ "Asia/Seoul",
+ "Asia/Shanghai",
+ "Asia/Singapore",
+ "Asia/Srednekolymsk",
+ "Asia/Taipei",
+ "Asia/Tashkent",
+ "Asia/Tbilisi",
+ "Asia/Tehran",
+ "Asia/Tel_Aviv",
+ "Asia/Thimbu",
+ "Asia/Thimphu",
+ "Asia/Tokyo",
+ "Asia/Tomsk",
+ "Asia/Ujung_Pandang",
+ "Asia/Ulaanbaatar",
+ "Asia/Ulan_Bator",
+ "Asia/Urumqi",
+ "Asia/Ust-Nera",
+ "Asia/Vientiane",
+ "Asia/Vladivostok",
+ "Asia/Yakutsk",
+ "Asia/Yangon",
+ "Asia/Yekaterinburg",
+ "Asia/Yerevan",
+ "Atlantic/Azores",
+ "Atlantic/Bermuda",
+ "Atlantic/Canary",
+ "Atlantic/Cape_Verde",
+ "Atlantic/Faeroe",
+ "Atlantic/Faroe",
+ "Atlantic/Jan_Mayen",
+ "Atlantic/Madeira",
+ "Atlantic/Reykjavik",
+ "Atlantic/South_Georgia",
+ "Atlantic/St_Helena",
+ "Atlantic/Stanley",
+ "Australia/ACT",
+ "Australia/Adelaide",
+ "Australia/Brisbane",
+ "Australia/Broken_Hill",
+ "Australia/Canberra",
+ "Australia/Currie",
+ "Australia/Darwin",
+ "Australia/Eucla",
+ "Australia/Hobart",
+ "Australia/LHI",
+ "Australia/Lindeman",
+ "Australia/Lord_Howe",
+ "Australia/Melbourne",
+ "Australia/NSW",
+ "Australia/North",
+ "Australia/Perth",
+ "Australia/Queensland",
+ "Australia/South",
+ "Australia/Sydney",
+ "Australia/Tasmania",
+ "Australia/Victoria",
+ "Australia/West",
+ "Australia/Yancowinna",
+ "Brazil/Acre",
+ "Brazil/DeNoronha",
+ "Brazil/East",
+ "Brazil/West",
+ "CET",
+ "CST6CDT",
+ "Canada/Atlantic",
+ "Canada/Central",
+ "Canada/Eastern",
+ "Canada/Mountain",
+ "Canada/Newfoundland",
+ "Canada/Pacific",
+ "Canada/Saskatchewan",
+ "Canada/Yukon",
+ "Chile/Continental",
+ "Chile/EasterIsland",
+ "Cuba",
+ "EET",
+ "EST",
+ "EST5EDT",
+ "Egypt",
+ "Eire",
+ "Etc/GMT",
+ "Etc/GMT+0",
+ "Etc/GMT+1",
+ "Etc/GMT+10",
+ "Etc/GMT+11",
+ "Etc/GMT+12",
+ "Etc/GMT+2",
+ "Etc/GMT+3",
+ "Etc/GMT+4",
+ "Etc/GMT+5",
+ "Etc/GMT+6",
+ "Etc/GMT+7",
+ "Etc/GMT+8",
+ "Etc/GMT+9",
+ "Etc/GMT-0",
+ "Etc/GMT-1",
+ "Etc/GMT-10",
+ "Etc/GMT-11",
+ "Etc/GMT-12",
+ "Etc/GMT-13",
+ "Etc/GMT-14",
+ "Etc/GMT-2",
+ "Etc/GMT-3",
+ "Etc/GMT-4",
+ "Etc/GMT-5",
+ "Etc/GMT-6",
+ "Etc/GMT-7",
+ "Etc/GMT-8",
+ "Etc/GMT-9",
+ "Etc/GMT0",
+ "Etc/Greenwich",
+ "Etc/UCT",
+ "Etc/UTC",
+ "Etc/Universal",
+ "Etc/Zulu",
+ "Europe/Amsterdam",
+ "Europe/Andorra",
+ "Europe/Astrakhan",
+ "Europe/Athens",
+ "Europe/Belfast",
+ "Europe/Belgrade",
+ "Europe/Berlin",
+ "Europe/Bratislava",
+ "Europe/Brussels",
+ "Europe/Bucharest",
+ "Europe/Budapest",
+ "Europe/Busingen",
+ "Europe/Chisinau",
+ "Europe/Copenhagen",
+ "Europe/Dublin",
+ "Europe/Gibraltar",
+ "Europe/Guernsey",
+ "Europe/Helsinki",
+ "Europe/Isle_of_Man",
+ "Europe/Istanbul",
+ "Europe/Jersey",
+ "Europe/Kaliningrad",
+ "Europe/Kiev",
+ "Europe/Kirov",
+ "Europe/Lisbon",
+ "Europe/Ljubljana",
+ "Europe/London",
+ "Europe/Luxembourg",
+ "Europe/Madrid",
+ "Europe/Malta",
+ "Europe/Mariehamn",
+ "Europe/Minsk",
+ "Europe/Monaco",
+ "Europe/Moscow",
+ "Europe/Nicosia",
+ "Europe/Oslo",
+ "Europe/Paris",
+ "Europe/Podgorica",
+ "Europe/Prague",
+ "Europe/Riga",
+ "Europe/Rome",
+ "Europe/Samara",
+ "Europe/San_Marino",
+ "Europe/Sarajevo",
+ "Europe/Saratov",
+ "Europe/Simferopol",
+ "Europe/Skopje",
+ "Europe/Sofia",
+ "Europe/Stockholm",
+ "Europe/Tallinn",
+ "Europe/Tirane",
+ "Europe/Tiraspol",
+ "Europe/Ulyanovsk",
+ "Europe/Uzhgorod",
+ "Europe/Vaduz",
+ "Europe/Vatican",
+ "Europe/Vienna",
+ "Europe/Vilnius",
+ "Europe/Volgograd",
+ "Europe/Warsaw",
+ "Europe/Zagreb",
+ "Europe/Zaporozhye",
+ "Europe/Zurich",
+ "GB",
+ "GB-Eire",
+ "GMT",
+ "GMT+0",
+ "GMT-0",
+ "GMT0",
+ "Greenwich",
+ "HST",
+ "Hongkong",
+ "Iceland",
+ "Indian/Antananarivo",
+ "Indian/Chagos",
+ "Indian/Christmas",
+ "Indian/Cocos",
+ "Indian/Comoro",
+ "Indian/Kerguelen",
+ "Indian/Mahe",
+ "Indian/Maldives",
+ "Indian/Mauritius",
+ "Indian/Mayotte",
+ "Indian/Reunion",
+ "Iran",
+ "Israel",
+ "Jamaica",
+ "Japan",
+ "Kwajalein",
+ "Libya",
+ "MET",
+ "MST",
+ "MST7MDT",
+ "Mexico/BajaNorte",
+ "Mexico/BajaSur",
+ "Mexico/General",
+ "NZ",
+ "NZ-CHAT",
+ "Navajo",
+ "PRC",
+ "PST8PDT",
+ "Pacific/Apia",
+ "Pacific/Auckland",
+ "Pacific/Bougainville",
+ "Pacific/Chatham",
+ "Pacific/Chuuk",
+ "Pacific/Easter",
+ "Pacific/Efate",
+ "Pacific/Enderbury",
+ "Pacific/Fakaofo",
+ "Pacific/Fiji",
+ "Pacific/Funafuti",
+ "Pacific/Galapagos",
+ "Pacific/Gambier",
+ "Pacific/Guadalcanal",
+ "Pacific/Guam",
+ "Pacific/Honolulu",
+ "Pacific/Johnston",
+ "Pacific/Kiritimati",
+ "Pacific/Kosrae",
+ "Pacific/Kwajalein",
+ "Pacific/Majuro",
+ "Pacific/Marquesas",
+ "Pacific/Midway",
+ "Pacific/Nauru",
+ "Pacific/Niue",
+ "Pacific/Norfolk",
+ "Pacific/Noumea",
+ "Pacific/Pago_Pago",
+ "Pacific/Palau",
+ "Pacific/Pitcairn",
+ "Pacific/Pohnpei",
+ "Pacific/Ponape",
+ "Pacific/Port_Moresby",
+ "Pacific/Rarotonga",
+ "Pacific/Saipan",
+ "Pacific/Samoa",
+ "Pacific/Tahiti",
+ "Pacific/Tarawa",
+ "Pacific/Tongatapu",
+ "Pacific/Truk",
+ "Pacific/Wake",
+ "Pacific/Wallis",
+ "Pacific/Yap",
+ "Poland",
+ "Portugal",
+ "ROC",
+ "ROK",
+ "Singapore",
+ "Turkey",
+ "UCT",
+ "US/Alaska",
+ "US/Aleutian",
+ "US/Arizona",
+ "US/Central",
+ "US/East-Indiana",
+ "US/Eastern",
+ "US/Hawaii",
+ "US/Indiana-Starke",
+ "US/Michigan",
+ "US/Mountain",
+ "US/Pacific",
+ "US/Samoa",
+ "UTC",
+ "Universal",
+ "W-SU",
+ "WET",
+ "Zulu",
+ nullptr};
// Helper to return a loaded time zone by value (UTC on error).
time_zone LoadZone(const std::string& name) {
@@ -724,7 +724,8 @@
EXPECT_EQ("America/New_York", nyc.name());
const time_zone syd = LoadZone("Australia/Sydney");
EXPECT_EQ("Australia/Sydney", syd.name());
- const time_zone fixed0 = fixed_time_zone(absl::time_internal::cctz::seconds::zero());
+ const time_zone fixed0 =
+ fixed_time_zone(absl::time_internal::cctz::seconds::zero());
EXPECT_EQ("UTC", fixed0.name());
const time_zone fixed_pos = fixed_time_zone(
chrono::hours(3) + chrono::minutes(25) + chrono::seconds(45));
@@ -749,7 +750,7 @@
EXPECT_EQ(chrono::system_clock::from_time_t(0),
convert(civil_second(1970, 1, 1, 0, 0, 0), tz)); // UTC
- // Loading an empty std::string timezone should fail.
+ // Loading an empty string timezone should fail.
tz = LoadZone("America/Los_Angeles");
EXPECT_FALSE(load_time_zone("", &tz));
EXPECT_EQ(chrono::system_clock::from_time_t(0),
@@ -767,7 +768,8 @@
EXPECT_EQ(implicit_utc, explicit_utc);
EXPECT_EQ(implicit_utc.name(), explicit_utc.name());
- const time_zone fixed_zero = fixed_time_zone(absl::time_internal::cctz::seconds::zero());
+ const time_zone fixed_zero =
+ fixed_time_zone(absl::time_internal::cctz::seconds::zero());
EXPECT_EQ(fixed_zero, LoadZone(fixed_zero.name()));
EXPECT_EQ(fixed_zero, explicit_utc);
@@ -806,8 +808,8 @@
TEST(StdChronoTimePoint, TimeTAlignment) {
// Ensures that the Unix epoch and the system clock epoch are an integral
// number of seconds apart. This simplifies conversions to/from time_t.
- auto diff = chrono::system_clock::time_point() -
- chrono::system_clock::from_time_t(0);
+ auto diff =
+ chrono::system_clock::time_point() - chrono::system_clock::from_time_t(0);
EXPECT_EQ(chrono::system_clock::time_point::duration::zero(),
diff % chrono::seconds(1));
}
@@ -816,20 +818,20 @@
const time_zone utc = utc_time_zone();
const auto t0 = chrono::system_clock::from_time_t(0);
- ExpectTime(chrono::time_point_cast<chrono::nanoseconds>(t0), utc,
- 1970, 1, 1, 0, 0, 0, 0, false, "UTC");
- ExpectTime(chrono::time_point_cast<chrono::microseconds>(t0), utc,
- 1970, 1, 1, 0, 0, 0, 0, false, "UTC");
- ExpectTime(chrono::time_point_cast<chrono::milliseconds>(t0), utc,
- 1970, 1, 1, 0, 0, 0, 0, false, "UTC");
- ExpectTime(chrono::time_point_cast<chrono::seconds>(t0), utc,
- 1970, 1, 1, 0, 0, 0, 0, false, "UTC");
- ExpectTime(chrono::time_point_cast<absl::time_internal::cctz::seconds>(t0), utc,
- 1970, 1, 1, 0, 0, 0, 0, false, "UTC");
- ExpectTime(chrono::time_point_cast<chrono::minutes>(t0), utc,
- 1970, 1, 1, 0, 0, 0, 0, false, "UTC");
- ExpectTime(chrono::time_point_cast<chrono::hours>(t0), utc,
- 1970, 1, 1, 0, 0, 0, 0, false, "UTC");
+ ExpectTime(chrono::time_point_cast<chrono::nanoseconds>(t0), utc, 1970, 1, 1,
+ 0, 0, 0, 0, false, "UTC");
+ ExpectTime(chrono::time_point_cast<chrono::microseconds>(t0), utc, 1970, 1, 1,
+ 0, 0, 0, 0, false, "UTC");
+ ExpectTime(chrono::time_point_cast<chrono::milliseconds>(t0), utc, 1970, 1, 1,
+ 0, 0, 0, 0, false, "UTC");
+ ExpectTime(chrono::time_point_cast<chrono::seconds>(t0), utc, 1970, 1, 1, 0,
+ 0, 0, 0, false, "UTC");
+ ExpectTime(chrono::time_point_cast<absl::time_internal::cctz::seconds>(t0),
+ utc, 1970, 1, 1, 0, 0, 0, 0, false, "UTC");
+ ExpectTime(chrono::time_point_cast<chrono::minutes>(t0), utc, 1970, 1, 1, 0,
+ 0, 0, 0, false, "UTC");
+ ExpectTime(chrono::time_point_cast<chrono::hours>(t0), utc, 1970, 1, 1, 0, 0,
+ 0, 0, false, "UTC");
}
TEST(BreakTime, LocalTimeInUTC) {
@@ -911,9 +913,8 @@
chrono::time_point_cast<chrono::minutes>(
convert(civil_second(2015, 1, 2, 3, 4, 5), utc));
EXPECT_EQ("04:00", format("%M:%E*S", tp_m, utc));
- const time_point<chrono::hours> tp_h =
- chrono::time_point_cast<chrono::hours>(
- convert(civil_second(2015, 1, 2, 3, 4, 5), utc));
+ const time_point<chrono::hours> tp_h = chrono::time_point_cast<chrono::hours>(
+ convert(civil_second(2015, 1, 2, 3, 4, 5), utc));
EXPECT_EQ("00:00", format("%M:%E*S", tp_h, utc));
}
@@ -932,7 +933,7 @@
// NOTE: Run this with -ftrapv to detect overflow problems.
TEST(MakeTime, SysSecondsLimits) {
- const char RFC3339[] = "%Y-%m-%dT%H:%M:%S%Ez";
+ const char RFC3339[] = "%Y-%m-%d%ET%H:%M:%S%Ez";
const time_zone utc = utc_time_zone();
const time_zone east = fixed_time_zone(chrono::hours(14));
const time_zone west = fixed_time_zone(-chrono::hours(14));
@@ -1003,13 +1004,17 @@
#if defined(_WIN32) || defined(_WIN64)
// localtime_s() and gmtime_s() don't believe in years outside [1970:3000].
#else
- const time_zone utc = LoadZone("libc:UTC");
+ const time_zone cut = LoadZone("libc:UTC");
const year_t max_tm_year = year_t{std::numeric_limits<int>::max()} + 1900;
- tp = convert(civil_second(max_tm_year, 12, 31, 23, 59, 59), utc);
- EXPECT_EQ("2147485547-12-31T23:59:59+00:00", format(RFC3339, tp, utc));
+ tp = convert(civil_second(max_tm_year, 12, 31, 23, 59, 59), cut);
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+ // The BSD gmtime_r() fails on extreme positive tm_year values.
+#else
+ EXPECT_EQ("2147485547-12-31T23:59:59+00:00", format(RFC3339, tp, cut));
+#endif
const year_t min_tm_year = year_t{std::numeric_limits<int>::min()} + 1900;
- tp = convert(civil_second(min_tm_year, 1, 1, 0, 0, 0), utc);
- EXPECT_EQ("-2147481748-01-01T00:00:00+00:00", format(RFC3339, tp, utc));
+ tp = convert(civil_second(min_tm_year, 1, 1, 0, 0, 0), cut);
+ EXPECT_EQ("-2147481748-01-01T00:00:00+00:00", format(RFC3339, tp, cut));
#endif
}
}
@@ -1028,17 +1033,17 @@
ASSERT_EQ(0, setenv("TZ", *np, 1)); // change what "localtime" means
const auto zi = local_time_zone();
const auto lc = LoadZone("libc:localtime");
- time_zone::civil_transition trans;
+ time_zone::civil_transition transition;
for (auto tp = zi.lookup(civil_second()).trans;
- zi.next_transition(tp, &trans);
- tp = zi.lookup(trans.to).trans) {
- const auto fcl = zi.lookup(trans.from);
- const auto tcl = zi.lookup(trans.to);
+ zi.next_transition(tp, &transition);
+ tp = zi.lookup(transition.to).trans) {
+ const auto fcl = zi.lookup(transition.from);
+ const auto tcl = zi.lookup(transition.to);
civil_second cs; // compare cs in zi and lc
if (fcl.kind == time_zone::civil_lookup::UNIQUE) {
if (tcl.kind == time_zone::civil_lookup::UNIQUE) {
// Both unique; must be an is_dst or abbr change.
- ASSERT_EQ(trans.from, trans.to);
+ ASSERT_EQ(transition.from, transition.to);
const auto trans = fcl.trans;
const auto tal = zi.lookup(trans);
const auto tprev = trans - absl::time_internal::cctz::seconds(1);
@@ -1049,11 +1054,11 @@
continue;
}
ASSERT_EQ(time_zone::civil_lookup::REPEATED, tcl.kind);
- cs = trans.to;
+ cs = transition.to;
} else {
ASSERT_EQ(time_zone::civil_lookup::UNIQUE, tcl.kind);
ASSERT_EQ(time_zone::civil_lookup::SKIPPED, fcl.kind);
- cs = trans.from;
+ cs = transition.from;
}
if (cs.year() > 2037) break; // limit test time (and to 32-bit time_t)
const auto cl_zi = zi.lookup(cs);
@@ -1433,4 +1438,5 @@
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/time/internal/cctz/src/time_zone_posix.cc b/third_party/abseil/absl/time/internal/cctz/src/time_zone_posix.cc
index 038740e..5cdd09e 100644
--- a/third_party/abseil/absl/time/internal/cctz/src/time_zone_posix.cc
+++ b/third_party/abseil/absl/time/internal/cctz/src/time_zone_posix.cc
@@ -19,7 +19,10 @@
#include <limits>
#include <string>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
@@ -152,4 +155,5 @@
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/time/internal/cctz/src/time_zone_posix.h b/third_party/abseil/absl/time/internal/cctz/src/time_zone_posix.h
index 6a60022..0cf2905 100644
--- a/third_party/abseil/absl/time/internal/cctz/src/time_zone_posix.h
+++ b/third_party/abseil/absl/time/internal/cctz/src/time_zone_posix.h
@@ -55,7 +55,10 @@
#include <cstdint>
#include <string>
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
@@ -123,6 +126,7 @@
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_POSIX_H_
diff --git a/third_party/abseil/absl/time/internal/cctz/src/tzfile.h b/third_party/abseil/absl/time/internal/cctz/src/tzfile.h
index 51b1f1f..269fa36 100644
--- a/third_party/abseil/absl/time/internal/cctz/src/tzfile.h
+++ b/third_party/abseil/absl/time/internal/cctz/src/tzfile.h
@@ -22,36 +22,35 @@
*/
#ifndef TZDIR
-#define TZDIR "/usr/share/zoneinfo" /* Time zone object file directory */
-#endif /* !defined TZDIR */
+#define TZDIR "/usr/share/zoneinfo" /* Time zone object file directory */
+#endif /* !defined TZDIR */
#ifndef TZDEFAULT
-#define TZDEFAULT "/etc/localtime"
+#define TZDEFAULT "/etc/localtime"
#endif /* !defined TZDEFAULT */
#ifndef TZDEFRULES
-#define TZDEFRULES "posixrules"
+#define TZDEFRULES "posixrules"
#endif /* !defined TZDEFRULES */
-
/* See Internet RFC 8536 for more details about the following format. */
/*
** Each file begins with. . .
*/
-#define TZ_MAGIC "TZif"
+#define TZ_MAGIC "TZif"
struct tzhead {
- char tzh_magic[4]; /* TZ_MAGIC */
- char tzh_version[1]; /* '\0' or '2' or '3' as of 2013 */
- char tzh_reserved[15]; /* reserved; must be zero */
- char tzh_ttisutcnt[4]; /* coded number of trans. time flags */
- char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
- char tzh_leapcnt[4]; /* coded number of leap seconds */
- char tzh_timecnt[4]; /* coded number of transition times */
- char tzh_typecnt[4]; /* coded number of local time types */
- char tzh_charcnt[4]; /* coded number of abbr. chars */
+ char tzh_magic[4]; /* TZ_MAGIC */
+ char tzh_version[1]; /* '\0' or '2' or '3' as of 2013 */
+ char tzh_reserved[15]; /* reserved; must be zero */
+ char tzh_ttisutcnt[4]; /* coded number of trans. time flags */
+ char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
+ char tzh_leapcnt[4]; /* coded number of leap seconds */
+ char tzh_timecnt[4]; /* coded number of transition times */
+ char tzh_typecnt[4]; /* coded number of local time types */
+ char tzh_charcnt[4]; /* coded number of abbr. chars */
};
/*
@@ -84,13 +83,13 @@
** If tzh_version is '2' or greater, the above is followed by a second instance
** of tzhead and a second instance of the data in which each coded transition
** time uses 8 rather than 4 chars,
-** then a POSIX-TZ-environment-variable-style std::string for use in handling
+** then a POSIX-TZ-environment-variable-style string for use in handling
** instants after the last transition time stored in the file
** (with nothing between the newlines if there is no POSIX representation for
** such instants).
**
** If tz_version is '3' or greater, the above is extended as follows.
-** First, the POSIX TZ std::string's hour offset may range from -167
+** First, the POSIX TZ string's hour offset may range from -167
** through 167 as compared to the POSIX-required 0 through 24.
** Second, its DST start time may be January 1 at 00:00 and its stop
** time December 31 at 24:00 plus the difference between DST and
@@ -103,21 +102,21 @@
*/
#ifndef TZ_MAX_TIMES
-#define TZ_MAX_TIMES 2000
+#define TZ_MAX_TIMES 2000
#endif /* !defined TZ_MAX_TIMES */
#ifndef TZ_MAX_TYPES
/* This must be at least 17 for Europe/Samara and Europe/Vilnius. */
-#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
-#endif /* !defined TZ_MAX_TYPES */
+#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
+#endif /* !defined TZ_MAX_TYPES */
#ifndef TZ_MAX_CHARS
-#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
- /* (limited by what unsigned chars can hold) */
-#endif /* !defined TZ_MAX_CHARS */
+#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
+ /* (limited by what unsigned chars can hold) */
+#endif /* !defined TZ_MAX_CHARS */
#ifndef TZ_MAX_LEAPS
-#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
-#endif /* !defined TZ_MAX_LEAPS */
+#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
+#endif /* !defined TZ_MAX_LEAPS */
#endif /* !defined TZFILE_H */
diff --git a/third_party/abseil/absl/time/internal/cctz/src/zone_info_source.cc b/third_party/abseil/absl/time/internal/cctz/src/zone_info_source.cc
index 42f50c5..7209533 100644
--- a/third_party/abseil/absl/time/internal/cctz/src/zone_info_source.cc
+++ b/third_party/abseil/absl/time/internal/cctz/src/zone_info_source.cc
@@ -14,7 +14,10 @@
#include "absl/time/internal/cctz/include/cctz/zone_info_source.h"
+#include "absl/base/config.h"
+
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz {
@@ -24,9 +27,11 @@
} // namespace cctz
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz_extension {
@@ -36,8 +41,9 @@
// defers to the fallback factory.
std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource> DefaultFactory(
const std::string& name,
- const std::function<std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource>(
- const std::string& name)>& fallback_factory) {
+ const std::function<
+ std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource>(
+ const std::string& name)>& fallback_factory) {
return fallback_factory(name);
}
@@ -49,21 +55,53 @@
#if !defined(__has_attribute)
#define __has_attribute(x) 0
#endif
-#if __has_attribute(weak) || defined(__GNUC__)
-ZoneInfoSourceFactory zone_info_source_factory
- __attribute__((weak)) = DefaultFactory;
-#elif defined(_MSC_VER) && !defined(_LIBCPP_VERSION)
+// MinGW is GCC on Windows, so while it asserts __has_attribute(weak), the
+// Windows linker cannot handle that. Nor does the MinGW compiler know how to
+// pass "#pragma comment(linker, ...)" to the Windows linker.
+#if (__has_attribute(weak) || defined(__GNUC__)) && !defined(__MINGW32__)
+ZoneInfoSourceFactory zone_info_source_factory __attribute__((weak)) =
+ DefaultFactory;
+#elif defined(_MSC_VER) && !defined(__MINGW32__) && !defined(_LIBCPP_VERSION)
extern ZoneInfoSourceFactory zone_info_source_factory;
extern ZoneInfoSourceFactory default_factory;
ZoneInfoSourceFactory default_factory = DefaultFactory;
#if defined(_M_IX86)
-#pragma comment( \
- linker, \
- "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZA=?default_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZA")
-#elif defined(_M_IA_64) || defined(_M_AMD64) || defined(_M_ARM64)
-#pragma comment( \
- linker, \
- "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZEA=?default_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZEA")
+#pragma comment( \
+ linker, \
+ "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@" ABSL_INTERNAL_MANGLED_NS \
+ "@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
+ "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
+ "@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
+ "@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
+ "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
+ "@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
+ "@@ZA=?default_factory@cctz_extension@time_internal@" ABSL_INTERNAL_MANGLED_NS \
+ "@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
+ "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
+ "@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
+ "@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
+ "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
+ "@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
+ "@@ZA")
+#elif defined(_M_IA_64) || defined(_M_AMD64) || defined(_M_ARM) || \
+ defined(_M_ARM64)
+#pragma comment( \
+ linker, \
+ "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@" ABSL_INTERNAL_MANGLED_NS \
+ "@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
+ "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
+ "@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
+ "@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
+ "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
+ "@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
+ "@@ZEA=?default_factory@cctz_extension@time_internal@" ABSL_INTERNAL_MANGLED_NS \
+ "@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
+ "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
+ "@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
+ "@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
+ "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
+ "@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
+ "@@ZEA")
#else
#error Unsupported MSVC platform
#endif // _M_<PLATFORM>
@@ -74,4 +112,5 @@
} // namespace cctz_extension
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/version b/third_party/abseil/absl/time/internal/cctz/testdata/version
index db18f83..b4410dc 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/version
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/version
@@ -1 +1 @@
-2019c
+2020d
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan
index 28b32ab..8906e88 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra
index 697b993..9ca907b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa
index 9a2918f..d3c0bb3 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers
index ae04342..56a4dd2 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara
index 9a2918f..d3c0bb3 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera
index 9a2918f..d3c0bb3 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako
index 28b32ab..8906e88 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui
index 0c80137..2f2ce2f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul
index 28b32ab..8906e88 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau
index 82ea5aa..0da1d1e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre
index 52753c0..651e5cf 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville
index 0c80137..2f2ce2f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura
index 52753c0..651e5cf 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo
index d3f8196..ea38c97 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca
index 245f4eb..0263c90 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta
index 850c8f0..a461dce 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry
index 28b32ab..8906e88 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar
index 28b32ab..8906e88 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam
index 9a2918f..d3c0bb3 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti
index 9a2918f..d3c0bb3 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala
index 0c80137..2f2ce2f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun
index a91f65f..772e23c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown
index 28b32ab..8906e88 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone
index 52753c0..651e5cf 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare
index 52753c0..651e5cf 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg
index b1c425d..bada063 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba
index 625b1ac..36b0522 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala
index 9a2918f..d3c0bb3 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum
index 8ee8cb9..3f8e44b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali
index 52753c0..651e5cf 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa
index 0c80137..2f2ce2f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos
index 0c80137..2f2ce2f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville
index 0c80137..2f2ce2f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome
index 28b32ab..8906e88 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda
index 0c80137..2f2ce2f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi
index 52753c0..651e5cf 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka
index 52753c0..651e5cf 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo
index 0c80137..2f2ce2f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo
index 52753c0..651e5cf 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru
index b1c425d..bada063 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane
index b1c425d..bada063 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu
index 9a2918f..d3c0bb3 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia
index 6d68850..8377809 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi
index 9a2918f..d3c0bb3 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena
index a968845..ecbc096 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey
index 0c80137..2f2ce2f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott
index 28b32ab..8906e88 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou
index 28b32ab..8906e88 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo
index 0c80137..2f2ce2f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome
index 59f3759..425ad3f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu
index 28b32ab..8906e88 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli
index 07b393b..e0c8997 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis
index 427fa56..ca324cb 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek
index abecd13..0edc52b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Adak b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Adak
index 4323649..b1497bd 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Adak
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Adak
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage
index 9bbb2fd..cdf0572 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla
index 697cf5b..f4fe590 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua
index 697cf5b..f4fe590 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina
index 49381b4..f66c9f7 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires
index 260f86a..d6f999b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca
index 0ae222a..1dcc8d8 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia
index 0ae222a..1dcc8d8 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba
index da4c23a..35a52e5 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy
index 604b856..b275f27 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja
index 2218e36..23fca12 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza
index f9e677f..691c569 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos
index c36587e..991d1fa 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta
index 0e797f2..58863e0 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan
index 2698495..7eba33c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis
index fe50f62..0a81cbd 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman
index c954000..10556d5 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia
index 3643628..e031750 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba
index f7ab6ef..d6ddf7d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion
index 2f3bbda..6225036 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan
index 629ed42..c828715 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Atka b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Atka
index 4323649..b1497bd 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Atka
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Atka
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia
index 15808d3..7969e30 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas
index 896af3f..cbe22a7 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados
index 9b90e30..9d3afa6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Belem b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Belem
index 60b5924..e0d7653 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Belem
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Belem
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Belize b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Belize
index 851051a..de99b84 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Belize
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Belize
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon
index f9f13a1..7096b69 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista
index 978c331..fca9720 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota
index b2647d7a..6cb53d4 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Boise b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Boise
index f8d54e2..72fec9e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Boise
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Boise
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires
index 260f86a..d6f999b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay
index f8db4b6..0a22252 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande
index 8120624..6855e4e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun
index f907f0a..640b259 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas
index eedf725..8dbe6ff 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca
index 0ae222a..1dcc8d8 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne
index e5bc06f..cd49f05 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman
index 9964b9a..9154643 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago
index a5b1617..b016880 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua
index 8ed5f93..e1780a5 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour
index 629ed42..c828715 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba
index da4c23a..35a52e5 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica
index 37cb85e..08f0128 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Creston b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Creston
index ca64857..9d69a0a 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Creston
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Creston
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba
index 9bea3d4..c09a875 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao
index f7ab6ef..d6ddf7d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn
index 9549adc..8718efc 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson
index db9cead..07e4c5f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek
index db9e339..761d1d9 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Denver b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Denver
index 5fbe26b..09e54e5 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Denver
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Denver
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit
index e104faa..6eb3ac4 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica
index 697cf5b..f4fe590 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton
index cd78a6f..645ee94 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe
index 39d6dae..7da4b98 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador
index e2f2230..4348411 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada
index ada6bf7..19ccd35 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Nelson b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Nelson
index 5a0b7f1..2a49c6c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Nelson
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Nelson
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne
index 09511cc..6b08d15 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza
index be57dc2..092e40d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay
index 48412a4..f85eb34 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab
index 0160308..4ddc99d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay
index a3f2990..820e0dd 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk
index b9bb063..062fcae 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada
index 697cf5b..f4fe590 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe
index 697cf5b..f4fe590 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala
index 407138c..8aa8e58 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil
index 0559a7a..381ae6c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana
index d5dab14..ebd85d0 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax
index 756099a..9fa850a 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Havana b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Havana
index b69ac45..e06629d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Havana
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Havana
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo
index 791a9fa..8283239 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis
index 09511cc..6b08d15 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox
index fcd408d..b187d5f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo
index 1abf75e..a730fe6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg
index 0133548..341a023 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City
index 7bbb653..76e1f62 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay
index d236b7c..f2acf6c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes
index c818929..c255f89 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac
index 630935c..8700ed9 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis
index 09511cc..6b08d15 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik
index 87bb355..af3107d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit
index c8138bd..eb2c99c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica
index 2a9b7fd..be6b1b6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy
index 604b856..b275f27 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau
index 451f349..e347b36 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville
index 177836e..f2136d6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello
index 438e3ea..d9f54a1 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN
index fcd408d..b187d5f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk
index f7ab6ef..d6ddf7d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz
index a101372..68ddaae 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Lima b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Lima
index 3c6529b..b643c55 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Lima
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Lima
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles
index 9dad4f4..aaf0778 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville
index 177836e..f2136d6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes
index f7ab6ef..d6ddf7d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio
index bc8b951..dbb8d57 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Managua b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Managua
index e0242bf..86ef76b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Managua
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Managua
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus
index 63d58f8..59c952e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot
index 697cf5b..f4fe590 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique
index 8df43dc..25c0232 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros
index 047968d..722751b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan
index e4a7857..4c819fa 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza
index f9e677f..691c569 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee
index 3146138..28d2c56 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Merida b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Merida
index ea852da..d3b0ca1 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Merida
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Merida
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla
index 1e94be3..9fefee3 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City
index e7fb6f2..ffcf8be 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon
index b924b71..3b62585 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton
index 9df8d0f..ecb69ef 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey
index a8928c8..dea9e3f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo
index 2f357bc..4b2fb3e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal
index 6752c5b..fe6be8e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat
index 697cf5b..f4fe590 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau
index 33cc6c6..cf1e92d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/New_York b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/New_York
index 2f75480..2b6c2ee 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/New_York
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/New_York
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon
index f6a856e..b9f67a9 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Nome b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Nome
index 10998df..23ead1c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Nome
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Nome
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha
index f140726..9e74745 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah
index 246345d..becf438 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center
index 1fa0703..d03bda0 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem
index 123f2ae..ecefc15 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Nuuk b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Nuuk
new file mode 100644
index 0000000..4ddc99d
--- /dev/null
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Nuuk
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga
index fc4a03e..da0909c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Panama b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Panama
index 9964b9a..9154643 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Panama
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Panama
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung
index 3e4e0db..5be6f9b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo
index bc8a6ed..24f925a 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix
index ac6bb0c..c2bd2f9 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince
index 287f143..3e75731 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain
index 697cf5b..f4fe590 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre
index a374cb4..fb5185c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho
index 2e873a5..7f8047d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico
index a662a57..47b4dc3 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas
index a5a8af5..5c9a20b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River
index ea66099..d6ddda4 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet
index 3a70587..92e2ed2 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Recife b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Recife
index d7abb16..305abcb 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Recife
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Recife
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Regina b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Regina
index 20c9c84..a3f8217 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Regina
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Regina
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute
index 0a73b75..a84d1df 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco
index a374cb4..fb5185c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario
index da4c23a..35a52e5 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel
index ada6bf7..19ccd35 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem
index c28f360..f81d144 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago
index 816a042..8d60322 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo
index 4fe36fd..3e07850 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo
index 13ff083..a16da2c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund
index e20e9e1..6db4912 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock
index 5fbe26b..09e54e5 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka
index 31f7061..36681ed 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy
index 697cf5b..f4fe590 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns
index 65a5b0c..e5f2aec 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts
index 697cf5b..f4fe590 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia
index 697cf5b..f4fe590 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas
index 697cf5b..f4fe590 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent
index 697cf5b..f4fe590 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current
index 8e9ef25..bdbb494 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa
index 2adacb2..38036a3 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Thule b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Thule
index 6f802f1..f38dc56 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Thule
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Thule
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay
index e504c9a..fcb0328 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana
index ada6bf7..19ccd35 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Toronto b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Toronto
index 6752c5b..fe6be8e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Toronto
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Toronto
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola
index 697cf5b..f4fe590 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver
index bb60cbc..c998491 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin
index 697cf5b..f4fe590 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse
index fb3cd71..878b6a9 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg
index ac40299..7e646d1 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat
index da209f9..773feba 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife
index e6afa39..c779cef 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey
index f100f47..30315cc 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis
index 916f2c2..3ec3222 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville
index a71b39c..c0cfc85 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie
index 616afd9..232717b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson
index b32e7fd..05e4c6c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo
index 6575fdc..afb3929 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer
index 3dd85f8..32c1941 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera
index 8b2430a..ea49c00 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole
index 6575fdc..afb3929 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa
index 254af7d..97d80d7 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll
index 5e565da..4e31aff 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok
index 7283053..6e32907 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen
index 15a34c3..dfc5095 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden
index 2aea25f..01c47cc 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty
index a4b0077..3ec4fc8 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman
index c9e8707..1bd09fe 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr
index 6ed8b7c..551884d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau
index e2d0f91..3a40d11 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe
index 06f0a13..62c5840 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat
index 73891af..8482167 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad
index 73891af..8482167 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau
index 8b5153e..cb2c82f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad
index f7162ed..a3ce975 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain
index 63188b2..7409d74 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku
index a0de74b..96203d7 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok
index c292ac5..ed687d2 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul
index 759592a..ff976dd 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut
index fb266ed..55dce57 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek
index f6e20dd..fe7832c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei
index 3dab0ab..e67b411 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta
index 0014046..00bc80a 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita
index c4149c0..9d49cd3 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan
index e48daa8..0a948c2 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing
index 3c0bef2..d6b6698 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking
index 3c0bef2..d6b6698 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo
index 62c64d8..3eeb1b7 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca
index b11c928..2813680 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus
index d9104a7..168ef9b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka
index b11c928..2813680 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili
index 30943bb..bb7be9f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai
index fc0a589..58d75bc 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe
index 82d85b8..d83fb07 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta
index 653b146..cc44179 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza
index 592b632..4278ffa 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin
index 3c0bef2..d6b6698 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron
index ae82f9b..e55318a 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh
index e2934e3..7ca9972 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong
index 23d0375..c80e364 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd
index 4cb800a..6e08a26 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk
index 4dcbbb7..550e2a0 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul
index 508446b..c891866 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta
index 5baa3a8..c9752d2 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura
index 3002c82..7c22f53 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem
index 440ef06..e6e6cc6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul
index d19b9bd..660ce4c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka
index 3e80b4e..c651554 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi
index ba65c0e..e56d5af 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar
index faa14d9..69ff7f6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu
index a5d5107..3a0d330 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu
index a5d5107..3a0d330 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga
index 72bea64..aeb7332 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata
index 0014046..00bc80a 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk
index 30c6f16..e0d4fcb 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur
index 612b01e..e93dd51 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching
index c86750c..59bc6e4 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait
index 2aea25f..01c47cc 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao
index cac6506..c22f75e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau
index cac6506..c22f75e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan
index b4fcac1..16bac84 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar
index 556ba86..5990010 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila
index f4f4b04..3c3584e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat
index fc0a589..58d75bc 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia
index f7f10ab..c210d0a 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk
index d983276..9378d50 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk
index e0ee5fc..65a9fa2 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk
index b29b769..dc0ed42 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral
index ad1f9ca..25a63ec 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh
index c292ac5..ed687d2 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak
index 12ce24c..285bed2 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang
index 7ad7e0b..57240cf 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar
index 63188b2..7409d74 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qostanay b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qostanay
index 73b9d96..ff6fe61 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qostanay
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qostanay
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda
index c2fe4c1..fe4d6c6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon
index dd77395..14b2ad0 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh
index 2aea25f..01c47cc 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon
index e2934e3..7ca9972 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin
index 485459c..69f0faa 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand
index 030d47c..c43e27c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul
index 96199e7..1755147 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai
index 3c0bef2..d6b6698 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore
index 2364b21..350d77e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk
index 261a983..7fdee5c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei
index 24c4344..35d89d0 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent
index 32a9d7d..65ee428 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi
index b608d79..166e434 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran
index 8cec5ad..f1555f0 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv
index 440ef06..e6e6cc6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu
index fe409c7..0edc72c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu
index fe409c7..0edc72c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo
index 26f4d34..1aa066c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk
index 670e2ad..c3c307d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang
index 556ba86..5990010 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar
index 2e20cc3..6f5d3a1 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator
index 2e20cc3..6f5d3a1 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi
index faa14d9..69ff7f6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera
index 9e4a78f..c39331e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane
index c292ac5..ed687d2 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok
index 8ab253c..72a3d4e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk
index c815e99..336f932 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon
index dd77395..14b2ad0 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg
index 6958d7e..a3bf7f2 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan
index 250bfe0..6dd927c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores
index 56593db..b7f75a9 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda
index 419c660..aa33014 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary
index f319215..5ab3243 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde
index e2a49d2..8f7de1c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe
index 4dab7ef..9558bf7 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe
index 4dab7ef..9558bf7 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen
index 15a34c3..dfc5095 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira
index 5213761..7c3a49c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik
index 10e0fc8..2451aca 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia
index 4466608..7fa5f46 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena
index 28b32ab..8906e88 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley
index 88077f1..1a4c8ea 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT
index 7636592..f235d0d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide
index 0b1252a..f397b3b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane
index 3021bdb..c7915db 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill
index 1ac3fc8..ed0d17a 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra
index 7636592..f235d0d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie
index f65a990..55ceaef 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin
index 1cf5029..7114153 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla
index 98ae557..9fbc01f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart
index 02b07ca..21ef2d3 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI
index 9e04a80..4d4ec8c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman
index eab0fb9..e271d5b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe
index 9e04a80..4d4ec8c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne
index ba45733..c7160da 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW
index 7636592..f235d0d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/North b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/North
index 1cf5029..7114153 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/North
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/North
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth
index a876b9e..e449b03 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland
index 3021bdb..c7915db 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/South b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/South
index 0b1252a..f397b3b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/South
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/South
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney
index 7636592..f235d0d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania
index 02b07ca..21ef2d3 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria
index ba45733..c7160da 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/West b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/West
index a876b9e..e449b03 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/West
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/West
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna
index 1ac3fc8..ed0d17a 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre
index a374cb4..fb5185c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha
index f140726..9e74745 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East
index 13ff083..a16da2c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West
index 63d58f8..59c952e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/CET b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/CET
index 122e934..546748d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/CET
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/CET
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT
index ca67929..d931558 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic
index 756099a..9fa850a 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central
index ac40299..7e646d1 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern
index 6752c5b..fe6be8e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain
index cd78a6f..645ee94 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland
index 65a5b0c..e5f2aec 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific
index bb60cbc..c998491 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan
index 20c9c84..a3f8217 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon
index fb3cd71..878b6a9 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental
index 816a042..8d60322 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland
index cae3744..d29bcd6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Cuba b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Cuba
index b69ac45..e06629d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Cuba
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Cuba
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/EET b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/EET
index cbdb71d..378919e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/EET
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/EET
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/EST b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/EST
index 21ebc00..3ae9691 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/EST
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/EST
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT
index 9bce500..50c95e0 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Egypt b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Egypt
index d3f8196..ea38c97 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Egypt
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Egypt
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Eire b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Eire
index 1d99490..4a45ea8 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Eire
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Eire
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT
index c634746..157573b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0
index c634746..157573b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1
index 4dab6f9..98d5dcf 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10
index c749290..ecb287e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11
index d969982..e941412 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12
index cdeec90..9c95bd0 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2
index fbd2a94..6d5ce3d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3
index ee246ef..5ef7be7 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4
index 5a25ff2..75f1621 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5
index c0b745f..589990a 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6
index 06e777d..fcb60ca 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7
index 4e0b53a..c0427a4 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8
index 714b0c5..9bdc228 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9
index 78b9daa..ca7a81f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0
index c634746..157573b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1
index a838beb..cb45601 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10
index 68ff77d..11d988e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11
index 66af5a4..f4c5d5c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12
index 17ba505..cd397b0 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13
index 5f3706c..8fad7c6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14
index 7e9f9c4..a595e60 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2
index fcef6d9..97b44a9 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3
index 27973bc..4eb17ff 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4
index 1efd841..13aef80 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5
index 1f76184..83a2816 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6
index 952681e..79a983e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7
index cefc912..e136690 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8
index afb093d..bc70fe4 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9
index 9265fb7..d18cedd 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0
index c634746..157573b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich
index c634746..157573b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT
index 91558be..00841a6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC
index 91558be..00841a6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal
index 91558be..00841a6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu
index 91558be..00841a6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam
index c3ff07b..4a6fa1d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra
index 5962550..38685d4 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan
index 73a4d01..aff8d82 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens
index 9f3a067..231bf9c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast
index ac02a81..323cd38 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade
index 27de456..a1bf928 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin
index 7f6d958..465546b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava
index ce8f433..fb7c145 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels
index 40d7124..3197327 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest
index 4303b90..efa689b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest
index 6b94a4f..940be46 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen
index ad6cf59..388df29 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau
index 5ee23fe..6970b14 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen
index 776be6e..45984a7 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin
index 1d99490..4a45ea8 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar
index 117aadb..017bb2e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey
index ac02a81..323cd38 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki
index b4f8f9c..ff5e565 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man
index ac02a81..323cd38 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul
index 508446b..c891866 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey
index ac02a81..323cd38 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad
index cc99bea..0ec4756 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev
index 9337c9e..8f83cef 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov
index a3b5320..d1c93c5 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon
index 355817b..6484166 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana
index 27de456..a1bf928 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/London b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/London
index ac02a81..323cd38 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/London
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/London
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg
index c4ca733..682bcbf 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid
index 16f6420..60bdf4d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta
index bf2452d..27539c2 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn
index b4f8f9c..ff5e565 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk
index 453306c..30d3a67 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco
index 686ae88..f30dfc7 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow
index ddb3f4e..5e6b6de 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia
index f7f10ab..c210d0a 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo
index 15a34c3..dfc5095 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris
index ca85435..00a2726 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica
index 27de456..a1bf928 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague
index ce8f433..fb7c145 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga
index 8db477d..26af4c9 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome
index ac4c163..639ca3b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara
index 97d5dd9..8d0c26e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino
index ac4c163..639ca3b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo
index 27de456..a1bf928 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov
index 8fd5f6d..2684d8f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol
index 432e831..88a6f3b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje
index 27de456..a1bf928 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia
index 0e4d879..eabc972 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm
index f3e0c7f..dd3eb32 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn
index b5acca3..5321bbd 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane
index 0b86017..743a733 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol
index 5ee23fe..6970b14 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk
index 7b61bdc..bb842cb 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod
index 66ae8d6..a575568 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz
index ad6cf59..388df29 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican
index ac4c163..639ca3b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna
index 3582bb1..75339e9 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius
index 7abd63f..75b2eeb 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd
index d1cfac0..a486ad4 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw
index e33cf67..efe1a40 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb
index 27de456..a1bf928 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye
index e42edfc..4ea8dae 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich
index ad6cf59..388df29 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Factory b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Factory
index 60aa2a0..b4dd773 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Factory
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Factory
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GB b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GB
index ac02a81..323cd38 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GB
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GB
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire
index ac02a81..323cd38 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GMT b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GMT
index c634746..157573b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GMT
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GMT
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GMT+0 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GMT+0
index c634746..157573b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GMT+0
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GMT+0
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GMT-0 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GMT-0
index c634746..157573b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GMT-0
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GMT-0
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GMT0 b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GMT0
index c634746..157573b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GMT0
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/GMT0
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Greenwich b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Greenwich
index c634746..157573b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Greenwich
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Greenwich
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/HST b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/HST
index cccd45e..160a53e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/HST
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/HST
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Hongkong b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Hongkong
index 23d0375..c80e364 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Hongkong
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Hongkong
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Iceland b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Iceland
index 10e0fc8..2451aca 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Iceland
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Iceland
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo
index 9a2918f..d3c0bb3 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos
index 93d6dda..8b8ce22 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas
index d18c381..766024b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos
index f8116e7..1175034 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro
index 9a2918f..d3c0bb3 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen
index cde4cf7..8ce93e0 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe
index cba7dfe..75362bb 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives
index 7c839cf..58a82e4 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius
index 17f2616..7c11134 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte
index 9a2918f..d3c0bb3 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion
index dfe0831..248a7c9 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Iran b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Iran
index 8cec5ad..f1555f0 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Iran
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Iran
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Israel b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Israel
index 440ef06..e6e6cc6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Israel
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Israel
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Jamaica b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Jamaica
index 2a9b7fd..be6b1b6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Jamaica
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Jamaica
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Japan b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Japan
index 26f4d34..1aa066c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Japan
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Japan
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein
index 1a7975f..9416d52 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Libya b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Libya
index 07b393b..e0c8997 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Libya
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Libya
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/MET b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/MET
index 4a826bb..6f0558c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/MET
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/MET
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/MST b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/MST
index c93a58e..a0953d1 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/MST
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/MST
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT
index 4506a6e..137867c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte
index ada6bf7..19ccd35 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur
index e4a7857..4c819fa 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General
index e7fb6f2..ffcf8be 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/NZ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/NZ
index 6575fdc..afb3929 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/NZ
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/NZ
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT
index c004109..f06065e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Navajo b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Navajo
index 5fbe26b..09e54e5 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Navajo
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Navajo
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/PRC b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/PRC
index 3c0bef2..d6b6698 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/PRC
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/PRC
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT
index 99d246b..fde4833 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia
index dab1f3f..244af26 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland
index 6575fdc..afb3929 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville
index 2892d26..7c66709 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham
index c004109..f06065e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk
index 07c84b7..ea3fb5c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter
index cae3744..d29bcd6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate
index 6015017..906971e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury
index f0b8252..b22ab14 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo
index e40307f..b7b3021 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji
index d39bf53..e3934e4 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti
index ea72863..78ab35b 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos
index 31f0921..a9403ec 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier
index e1fc3da..ddfc34f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal
index 7e9d10a..720c679 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam
index 66490d2..bf9a2d9 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu
index c7cd060..40e3d49 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston
index c7cd060..40e3d49 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati
index 7cae0cb..2f676d3 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae
index a584aae..f5d5824 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein
index 1a7975f..9416d52 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro
index 9ef8374..9228ee0 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas
index 74d6792..6ea24b7 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway
index cb56709..001289c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru
index acec042..ae13aac 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue
index 684b010..7b35793 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk
index 53c1aad..79e2a94 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea
index 931a1a3..824f814 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago
index cb56709..001289c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau
index 146b351..bc8eb7a 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn
index ef91b06..8a4ba4d 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei
index c298ddd..b92b254 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape
index c298ddd..b92b254 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby
index 920ad27..5d8fc3a 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga
index da6b0fa..143a188 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan
index 66490d2..bf9a2d9 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa
index cb56709..001289c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti
index 442b8eb..50a064f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa
index 3db6c75..6bc2168 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu
index 5553c60..54aeb0f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk
index 07c84b7..ea3fb5c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake
index c9e3106..71cca88 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis
index b35344b..4bce893 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap
index 07c84b7..ea3fb5c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Poland b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Poland
index e33cf67..efe1a40 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Poland
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Poland
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Portugal b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Portugal
index 355817b..6484166 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Portugal
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Portugal
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/ROC b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/ROC
index 24c4344..35d89d0 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/ROC
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/ROC
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/ROK b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/ROK
index 96199e7..1755147 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/ROK
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/ROK
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Singapore b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Singapore
index 2364b21..350d77e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Singapore
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Singapore
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Turkey b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Turkey
index 508446b..c891866 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Turkey
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Turkey
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/UCT b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/UCT
index 91558be..00841a6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/UCT
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/UCT
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska
index 9bbb2fd..cdf0572 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian
index 4323649..b1497bd 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona
index ac6bb0c..c2bd2f9 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Central b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Central
index a5b1617..b016880 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Central
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Central
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana
index 09511cc..6b08d15 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern
index 2f75480..2b6c2ee 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii
index c7cd060..40e3d49 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke
index fcd408d..b187d5f 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan
index e104faa..6eb3ac4 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain
index 5fbe26b..09e54e5 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific
index 9dad4f4..aaf0778 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa
index cb56709..001289c 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/UTC b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/UTC
index 91558be..00841a6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/UTC
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/UTC
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Universal b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Universal
index 91558be..00841a6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Universal
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Universal
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/W-SU b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/W-SU
index ddb3f4e..5e6b6de 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/W-SU
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/W-SU
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/WET b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/WET
index c27390b..423c6c2 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/WET
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/WET
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Zulu b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Zulu
index 91558be..00841a6 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Zulu
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/Zulu
Binary files differ
diff --git a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
index 822ffa1..53ee77e 100644
--- a/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
+++ b/third_party/abseil/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
@@ -128,8 +128,8 @@
CA +5946-12014 America/Dawson_Creek MST - BC (Dawson Cr, Ft St John)
CA +5848-12242 America/Fort_Nelson MST - BC (Ft Nelson)
CA +4916-12307 America/Vancouver Pacific - BC (most areas)
-CA +6043-13503 America/Whitehorse Pacific - Yukon (south)
-CA +6404-13925 America/Dawson Pacific - Yukon (north)
+CA +6043-13503 America/Whitehorse Pacific - Yukon (east)
+CA +6404-13925 America/Dawson Pacific - Yukon (west)
CC -1210+09655 Indian/Cocos
CH,DE,LI +4723+00832 Europe/Zurich Swiss time
CI,BF,GM,GN,ML,MR,SH,SL,SN,TG +0519-00402 Africa/Abidjan
@@ -173,7 +173,7 @@
GF +0456-05220 America/Cayenne
GH +0533-00013 Africa/Accra
GI +3608-00521 Europe/Gibraltar
-GL +6411-05144 America/Godthab Greenland (most areas)
+GL +6411-05144 America/Nuuk Greenland (most areas)
GL +7646-01840 America/Danmarkshavn National Park (east coast)
GL +7029-02158 America/Scoresbysund Scoresbysund/Ittoqqortoormiit
GL +7634-06847 America/Thule Thule/Pituffik
@@ -290,7 +290,7 @@
RU +5443+02030 Europe/Kaliningrad MSK-01 - Kaliningrad
RU +554521+0373704 Europe/Moscow MSK+00 - Moscow area
# Mention RU and UA alphabetically. See "territorial claims" above.
-RU,UA +4457+03406 Europe/Simferopol MSK+00 - Crimea
+RU,UA +4457+03406 Europe/Simferopol Crimea
RU +5836+04939 Europe/Kirov MSK+00 - Kirov
RU +4621+04803 Europe/Astrakhan MSK+01 - Astrakhan
RU +4844+04425 Europe/Volgograd MSK+01 - Volgograd
@@ -341,8 +341,8 @@
TV -0831+17913 Pacific/Funafuti
TW +2503+12130 Asia/Taipei
UA +5026+03031 Europe/Kiev Ukraine (most areas)
-UA +4837+02218 Europe/Uzhgorod Ruthenia
-UA +4750+03510 Europe/Zaporozhye Zaporozh'ye/Zaporizhia; Lugansk/Luhansk (east)
+UA +4837+02218 Europe/Uzhgorod Transcarpathia
+UA +4750+03510 Europe/Zaporozhye Zaporozhye and east Lugansk
UM +1917+16637 Pacific/Wake Wake Island
US +404251-0740023 America/New_York Eastern (most areas)
US +421953-0830245 America/Detroit Eastern - MI (most areas)
diff --git a/third_party/abseil/absl/time/internal/get_current_time_chrono.inc b/third_party/abseil/absl/time/internal/get_current_time_chrono.inc
index 5180230..5eeb640 100644
--- a/third_party/abseil/absl/time/internal/get_current_time_chrono.inc
+++ b/third_party/abseil/absl/time/internal/get_current_time_chrono.inc
@@ -16,6 +16,7 @@
#include <cstdint>
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
static int64_t GetCurrentTimeNanosFromSystem() {
@@ -26,4 +27,5 @@
}
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/time/internal/get_current_time_posix.inc b/third_party/abseil/absl/time/internal/get_current_time_posix.inc
index 65474ca..4207200 100644
--- a/third_party/abseil/absl/time/internal/get_current_time_posix.inc
+++ b/third_party/abseil/absl/time/internal/get_current_time_posix.inc
@@ -7,6 +7,7 @@
#include "absl/base/internal/raw_logging.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
static int64_t GetCurrentTimeNanosFromSystem() {
@@ -19,4 +20,5 @@
}
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/time/internal/test_util.cc b/third_party/abseil/absl/time/internal/test_util.cc
index 59166a7..9a485a0 100644
--- a/third_party/abseil/absl/time/internal/test_util.cc
+++ b/third_party/abseil/absl/time/internal/test_util.cc
@@ -18,12 +18,14 @@
#include <cstddef>
#include <cstring>
+#include "absl/base/config.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/time/internal/cctz/include/cctz/zone_info_source.h"
namespace cctz = absl::time_internal::cctz;
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
TimeZone LoadTimeZone(const std::string& name) {
@@ -33,9 +35,11 @@
}
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
namespace cctz_extension {
namespace {
@@ -116,8 +120,12 @@
} // namespace
+#if !defined(__MINGW32__)
+// MinGW does not support the weak symbol extension mechanism.
ZoneInfoSourceFactory zone_info_source_factory = TestFactory;
+#endif
} // namespace cctz_extension
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/time/internal/test_util.h b/third_party/abseil/absl/time/internal/test_util.h
index d7319ea..5c4bf1f 100644
--- a/third_party/abseil/absl/time/internal/test_util.h
+++ b/third_party/abseil/absl/time/internal/test_util.h
@@ -20,12 +20,14 @@
#include "absl/time/time.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace time_internal {
// Loads the named timezone, but dies on any failure.
absl::TimeZone LoadTimeZone(const std::string& name);
} // namespace time_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_TIME_INTERNAL_TEST_UTIL_H_
diff --git a/third_party/abseil/absl/time/time.cc b/third_party/abseil/absl/time/time.cc
index 6a387bc..1ec2026 100644
--- a/third_party/abseil/absl/time/time.cc
+++ b/third_party/abseil/absl/time/time.cc
@@ -47,6 +47,7 @@
namespace cctz = absl::time_internal::cctz;
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
@@ -59,9 +60,10 @@
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;
+ return (q > 0 || rem >= ZeroDuration() ||
+ q == std::numeric_limits<int64_t>::min())
+ ? q
+ : q - 1;
}
inline absl::Time::Breakdown InfiniteFutureBreakdown() {
@@ -430,9 +432,17 @@
}
absl::Time FromTM(const struct tm& tm, absl::TimeZone tz) {
- const CivilSecond cs(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec);
- const auto ti = tz.At(cs);
+ civil_year_t tm_year = tm.tm_year;
+ // Avoids years that are too extreme for CivilSecond to normalize.
+ if (tm_year > 300000000000ll) return InfiniteFuture();
+ if (tm_year < -300000000000ll) return InfinitePast();
+ int tm_mon = tm.tm_mon;
+ if (tm_mon == std::numeric_limits<int>::max()) {
+ tm_mon -= 12;
+ tm_year += 1;
+ }
+ const auto ti = tz.At(CivilSecond(tm_year + 1900, tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec));
return tm.tm_isdst == 0 ? ti.post : ti.pre;
}
@@ -486,4 +496,5 @@
return tm;
}
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/time/time.h b/third_party/abseil/absl/time/time.h
index 9c8f317..7250803 100644
--- a/third_party/abseil/absl/time/time.h
+++ b/third_party/abseil/absl/time/time.h
@@ -83,11 +83,13 @@
#include <type_traits>
#include <utility>
+#include "absl/base/macros.h"
#include "absl/strings/string_view.h"
#include "absl/time/civil_time.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
class Duration; // Defined below
class Time; // Defined below
@@ -421,7 +423,9 @@
template <typename T, time_internal::EnableIfFloat<T> = 0>
Duration Seconds(T n) {
if (n >= 0) { // Note: `NaN >= 0` is false.
- if (n >= (std::numeric_limits<int64_t>::max)()) return InfiniteDuration();
+ if (n >= static_cast<T>((std::numeric_limits<int64_t>::max)())) {
+ return InfiniteDuration();
+ }
return time_internal::MakePosDoubleDuration(n);
} else {
if (std::isnan(n))
@@ -541,11 +545,15 @@
// suffix. The valid suffixes are "ns", "us" "ms", "s", "m", and "h".
// Simple examples include "300ms", "-1.5h", and "2h45m". Parses "0" as
// `ZeroDuration()`. Parses "inf" and "-inf" as +/- `InfiniteDuration()`.
-bool ParseDuration(const std::string& dur_string, Duration* d);
+bool ParseDuration(absl::string_view dur_string, Duration* d);
// Support for flag values of type Duration. Duration flags must be specified
// in a format that is valid input for absl::ParseDuration().
+bool AbslParseFlag(absl::string_view text, Duration* dst, std::string* error);
+std::string AbslUnparseFlag(Duration d);
+ABSL_DEPRECATED("Use AbslParseFlag() instead.")
bool ParseFlag(const std::string& text, Duration* dst, std::string* error);
+ABSL_DEPRECATED("Use AbslUnparseFlag() instead.")
std::string UnparseFlag(Duration d);
// Time
@@ -631,7 +639,7 @@
// Deprecated. Use `absl::TimeZone::CivilInfo`.
struct
Breakdown {
- int64_t year; // year (e.g., 2013)
+ 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]
@@ -815,7 +823,11 @@
// Additionally, if you'd like to specify a time as a count of
// seconds/milliseconds/etc from the Unix epoch, use an absl::Duration flag
// and add that duration to absl::UnixEpoch() to get an absl::Time.
+bool AbslParseFlag(absl::string_view text, Time* t, std::string* error);
+std::string AbslUnparseFlag(Time t);
+ABSL_DEPRECATED("Use AbslParseFlag() instead.")
bool ParseFlag(const std::string& text, Time* t, std::string* error);
+ABSL_DEPRECATED("Use AbslUnparseFlag() instead.")
std::string UnparseFlag(Time t);
// TimeZone
@@ -1009,13 +1021,13 @@
// 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) {
+inline bool LoadTimeZone(absl::string_view name, TimeZone* tz) {
if (name == "localtime") {
*tz = TimeZone(time_internal::cctz::local_time_zone());
return true;
}
time_internal::cctz::time_zone cz;
- const bool b = time_internal::cctz::load_time_zone(name, &cz);
+ const bool b = time_internal::cctz::load_time_zone(std::string(name), &cz);
*tz = TimeZone(cz);
return b;
}
@@ -1191,15 +1203,15 @@
// time with UTC offset. Also note the use of "%Y": RFC3339 mandates that
// years have exactly four digits, but we allow them to take their natural
// width.
-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
+ABSL_DLL extern const char RFC3339_full[]; // %Y-%m-%d%ET%H:%M:%E*S%Ez
+ABSL_DLL extern const char RFC3339_sec[]; // %Y-%m-%d%ET%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
+ABSL_DLL extern const char RFC1123_full[]; // %a, %d %b %E4Y %H:%M:%S %z
+ABSL_DLL extern const char RFC1123_no_wday[]; // %d %b %E4Y %H:%M:%S %z
// FormatTime()
//
@@ -1214,6 +1226,7 @@
// - %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)
+// - %ET - The RFC3339 "date-time" separator "T"
//
// 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'.
@@ -1237,7 +1250,7 @@
// `absl::InfinitePast()`, the returned string will be exactly "infinite-past".
// In both cases the given format string and `absl::TimeZone` are ignored.
//
-std::string FormatTime(const std::string& format, Time t, TimeZone tz);
+std::string FormatTime(absl::string_view 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
@@ -1256,7 +1269,8 @@
// 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. %Ez
-// and %E*z also accept the same inputs.
+// and %E*z also accept the same inputs, which (along with %z) includes
+// 'z' and 'Z' as synonyms for +00:00. %ET accepts either 'T' or 't'.
//
// %Y consumes as many numeric characters as it can, so the matching data
// should always be terminated with a non-numeric. %E4Y always consumes
@@ -1298,7 +1312,7 @@
// If the input 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,
+bool ParseTime(absl::string_view format, absl::string_view input, Time* time,
std::string* err);
// Like ParseTime() above, but if the format string does not contain a UTC
@@ -1308,7 +1322,7 @@
// of ambiguity or non-existence, in which case the "pre" time (as defined
// by TimeZone::TimeInfo) 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,
+bool ParseTime(absl::string_view format, absl::string_view input, TimeZone tz,
Time* time, std::string* err);
// ============================================================================
@@ -1333,8 +1347,8 @@
// it's positive and can be converted to int64_t without risk of UB.
inline Duration MakePosDoubleDuration(double n) {
const int64_t int_secs = static_cast<int64_t>(n);
- const uint32_t ticks =
- static_cast<uint32_t>((n - int_secs) * kTicksPerSecond + 0.5);
+ const uint32_t ticks = static_cast<uint32_t>(
+ (n - static_cast<double>(int_secs)) * kTicksPerSecond + 0.5);
return ticks < kTicksPerSecond
? MakeDuration(int_secs, ticks)
: MakeDuration(int_secs + 1, ticks - kTicksPerSecond);
@@ -1401,8 +1415,7 @@
// IsValidRep64<T>(0) is true if the expression `int64_t{std::declval<T>()}` is
// valid. That is, if a T can be assigned to an int64_t without narrowing.
template <typename T>
-constexpr auto IsValidRep64(int)
- -> decltype(int64_t{std::declval<T>()}, bool()) {
+constexpr auto IsValidRep64(int) -> decltype(int64_t{std::declval<T>()} == 0) {
return true;
}
template <typename T>
@@ -1481,12 +1494,10 @@
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);
+ : 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) {
@@ -1564,6 +1575,7 @@
return time_internal::FromUnixDuration(Seconds(t));
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_TIME_TIME_H_
diff --git a/third_party/abseil/absl/time/time_test.cc b/third_party/abseil/absl/time/time_test.cc
index 37af39d..cde9423 100644
--- a/third_party/abseil/absl/time/time_test.cc
+++ b/third_party/abseil/absl/time/time_test.cc
@@ -27,6 +27,7 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/numeric/int128.h"
#include "absl/time/clock.h"
#include "absl/time/internal/test_util.h"
@@ -57,8 +58,7 @@
// 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;
+ 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;
@@ -68,8 +68,7 @@
// 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;
+ 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;
@@ -102,7 +101,7 @@
EXPECT_EQ(a, b);
EXPECT_EQ(a, c);
EXPECT_EQ(b, c);
- b = c; // Assignment
+ b = c; // Assignment
EXPECT_EQ(a, b);
EXPECT_EQ(a, c);
EXPECT_EQ(b, c);
@@ -227,6 +226,9 @@
constexpr absl::Time t = absl::UnixEpoch(); // Any finite time.
static_assert(t < ifuture, "");
static_assert(t > ipast, "");
+
+ EXPECT_EQ(ifuture, t + absl::InfiniteDuration());
+ EXPECT_EQ(ipast, t - absl::InfiniteDuration());
}
TEST(Time, FloorConversion) {
@@ -357,19 +359,21 @@
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));
+ 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));
+ 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));
+ absl::ToUnixSeconds(
+ absl::FromUnixSeconds(std::numeric_limits<int64_t>::max()) -
+ absl::Nanoseconds(1) / 2));
}
TEST(Time, RoundtripConversion) {
@@ -575,6 +579,50 @@
absl::ToChronoTime(absl::UnixEpoch() - tick));
}
+// Check that absl::int128 works as a std::chrono::duration representation.
+TEST(Time, Chrono128) {
+ // Define a std::chrono::time_point type whose time[sic]_since_epoch() is
+ // a signed 128-bit count of attoseconds. This has a range and resolution
+ // (currently) beyond those of absl::Time, and undoubtedly also beyond those
+ // of std::chrono::system_clock::time_point.
+ //
+ // Note: The to/from-chrono support should probably be updated to handle
+ // such wide representations.
+ using Timestamp =
+ std::chrono::time_point<std::chrono::system_clock,
+ std::chrono::duration<absl::int128, std::atto>>;
+
+ // Expect that we can round-trip the std::chrono::system_clock::time_point
+ // extremes through both absl::Time and Timestamp, and that Timestamp can
+ // handle the (current) absl::Time extremes.
+ //
+ // Note: We should use std::chrono::floor() instead of time_point_cast(),
+ // but floor() is only available since c++17.
+ for (const auto tp : {std::chrono::system_clock::time_point::min(),
+ std::chrono::system_clock::time_point::max()}) {
+ EXPECT_EQ(tp, absl::ToChronoTime(absl::FromChrono(tp)));
+ EXPECT_EQ(tp, std::chrono::time_point_cast<
+ std::chrono::system_clock::time_point::duration>(
+ std::chrono::time_point_cast<Timestamp::duration>(tp)));
+ }
+ Timestamp::duration::rep v = std::numeric_limits<int64_t>::min();
+ v *= Timestamp::duration::period::den;
+ auto ts = Timestamp(Timestamp::duration(v));
+ ts += std::chrono::duration<int64_t, std::atto>(0);
+ EXPECT_EQ(std::numeric_limits<int64_t>::min(),
+ ts.time_since_epoch().count() / Timestamp::duration::period::den);
+ EXPECT_EQ(0,
+ ts.time_since_epoch().count() % Timestamp::duration::period::den);
+ v = std::numeric_limits<int64_t>::max();
+ v *= Timestamp::duration::period::den;
+ ts = Timestamp(Timestamp::duration(v));
+ ts += std::chrono::duration<int64_t, std::atto>(999999999750000000);
+ EXPECT_EQ(std::numeric_limits<int64_t>::max(),
+ ts.time_since_epoch().count() / Timestamp::duration::period::den);
+ EXPECT_EQ(999999999750000000,
+ ts.time_since_epoch().count() % Timestamp::duration::period::den);
+}
+
TEST(Time, TimeZoneAt) {
const absl::TimeZone nyc =
absl::time_internal::LoadTimeZone("America/New_York");
@@ -795,6 +843,30 @@
tm.tm_isdst = 1;
t = FromTM(tm, nyc);
EXPECT_EQ("2014-03-09T03:30:42-04:00", absl::FormatTime(t, nyc)); // DST
+
+ // Adjusts tm to refer to a time with a year larger than 2147483647.
+ tm.tm_year = 2147483647 - 1900 + 1;
+ 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;
+ t = FromTM(tm, absl::UTCTimeZone());
+ EXPECT_EQ("2147483648-06-28T01:02:03+00:00",
+ absl::FormatTime(t, absl::UTCTimeZone()));
+
+ // Adjusts tm to refer to a time with a very large month.
+ tm.tm_year = 2019 - 1900;
+ tm.tm_mon = 2147483647;
+ tm.tm_mday = 28;
+ tm.tm_hour = 1;
+ tm.tm_min = 2;
+ tm.tm_sec = 3;
+ tm.tm_isdst = -1;
+ t = FromTM(tm, absl::UTCTimeZone());
+ EXPECT_EQ("178958989-08-28T01:02:03+00:00",
+ absl::FormatTime(t, absl::UTCTimeZone()));
}
TEST(Time, TMRoundTrip) {
@@ -976,15 +1048,15 @@
// Checks how TimeZone::At() saturates on infinities.
auto ci = utc.At(absl::InfiniteFuture());
- EXPECT_CIVIL_INFO(ci, std::numeric_limits<int64_t>::max(), 12, 31, 23,
- 59, 59, 0, false);
+ EXPECT_CIVIL_INFO(ci, std::numeric_limits<int64_t>::max(), 12, 31, 23, 59, 59,
+ 0, false);
EXPECT_EQ(absl::InfiniteDuration(), ci.subsecond);
EXPECT_EQ(absl::Weekday::thursday, absl::GetWeekday(ci.cs));
EXPECT_EQ(365, absl::GetYearDay(ci.cs));
EXPECT_STREQ("-00", ci.zone_abbr); // artifact of TimeZone::At()
ci = utc.At(absl::InfinitePast());
- EXPECT_CIVIL_INFO(ci, std::numeric_limits<int64_t>::min(), 1, 1, 0, 0,
- 0, 0, false);
+ EXPECT_CIVIL_INFO(ci, std::numeric_limits<int64_t>::min(), 1, 1, 0, 0, 0, 0,
+ false);
EXPECT_EQ(-absl::InfiniteDuration(), ci.subsecond);
EXPECT_EQ(absl::Weekday::sunday, absl::GetWeekday(ci.cs));
EXPECT_EQ(1, absl::GetYearDay(ci.cs));
@@ -998,7 +1070,8 @@
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);
+ 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);
@@ -1006,7 +1079,8 @@
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);
+ absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()),
+ t);
// One second later should push us to infinity.
t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 15, 30, 8), utc);
@@ -1020,7 +1094,8 @@
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);
+ 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);
@@ -1029,7 +1104,8 @@
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);
+ absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()),
+ t);
// One second before should push us to -infinity.
t = absl::FromCivil(absl::CivilSecond(-292277022657, 1, 27, 8, 29, 51), utc);
@@ -1102,14 +1178,13 @@
const int kMin = std::numeric_limits<int>::min();
absl::Time t;
- t = absl::FromDateTime(std::numeric_limits<absl::civil_year_t>::max(),
- kMax, kMax, kMax, kMax, kMax, utc);
+ t = absl::FromDateTime(std::numeric_limits<absl::civil_year_t>::max(), kMax,
+ kMax, kMax, kMax, kMax, utc);
EXPECT_EQ("infinite-future",
absl::FormatTime(ymdhms, t, utc)); // no overflow
- t = absl::FromDateTime(std::numeric_limits<absl::civil_year_t>::min(),
- kMin, kMin, kMin, kMin, kMin, utc);
- EXPECT_EQ("infinite-past",
- absl::FormatTime(ymdhms, t, utc)); // no overflow
+ t = absl::FromDateTime(std::numeric_limits<absl::civil_year_t>::min(), kMin,
+ kMin, kMin, kMin, kMin, utc);
+ EXPECT_EQ("infinite-past", absl::FormatTime(ymdhms, t, utc)); // no overflow
// Check normalization.
EXPECT_TRUE(absl::ConvertDateTime(2013, 10, 32, 8, 30, 0, utc).normalized);
diff --git a/third_party/abseil/absl/time/time_zone_test.cc b/third_party/abseil/absl/time/time_zone_test.cc
index 8f1e74a..229fcfc 100644
--- a/third_party/abseil/absl/time/time_zone_test.cc
+++ b/third_party/abseil/absl/time/time_zone_test.cc
@@ -88,7 +88,7 @@
EXPECT_FALSE(LoadTimeZone("Invalid/TimeZone", &tz));
EXPECT_EQ(absl::UTCTimeZone(), tz); // guaranteed fallback to UTC
- // Loading an empty std::string timezone should fail.
+ // Loading an empty 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
diff --git a/third_party/abseil/absl/types/BUILD.bazel b/third_party/abseil/absl/types/BUILD.bazel
index 18b90db..83be936 100644
--- a/third_party/abseil/absl/types/BUILD.bazel
+++ b/third_party/abseil/absl/types/BUILD.bazel
@@ -12,9 +12,8 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-#
-#load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load(
"//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
@@ -24,7 +23,7 @@
package(default_visibility = ["//visibility:public"])
-licenses(["notice"]) # Apache 2.0
+licenses(["notice"])
cc_library(
name = "any",
@@ -35,6 +34,7 @@
":bad_any_cast",
"//absl/base:config",
"//absl/base:core_headers",
+ "//absl/base:fast_type_id",
"//absl/meta:type_traits",
"//absl/utility",
],
@@ -209,6 +209,44 @@
)
cc_library(
+ name = "conformance_testing",
+ testonly = 1,
+ hdrs = [
+ "internal/conformance_aliases.h",
+ "internal/conformance_archetype.h",
+ "internal/conformance_profile.h",
+ "internal/conformance_testing.h",
+ "internal/conformance_testing_helpers.h",
+ "internal/parentheses.h",
+ "internal/transform_args.h",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ "//absl/algorithm:container",
+ "//absl/meta:type_traits",
+ "//absl/strings",
+ "//absl/utility",
+ "@com_google_googletest//:gtest",
+ ],
+)
+
+cc_test(
+ name = "conformance_testing_test",
+ size = "small",
+ srcs = [
+ "internal/conformance_testing_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":conformance_testing",
+ "//absl/meta:type_traits",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_library(
name = "variant",
srcs = ["internal/variant.h"],
hdrs = ["variant.h"],
diff --git a/third_party/abseil/absl/types/CMakeLists.txt b/third_party/abseil/absl/types/CMakeLists.txt
index 952efc3..3f99ad8 100644
--- a/third_party/abseil/absl/types/CMakeLists.txt
+++ b/third_party/abseil/absl/types/CMakeLists.txt
@@ -24,6 +24,7 @@
absl::bad_any_cast
absl::config
absl::core_headers
+ absl::fast_type_id
absl::type_traits
absl::utility
PUBLIC
@@ -240,6 +241,58 @@
absl_cc_library(
NAME
+ conformance_testing
+ HDRS
+ "internal/conformance_aliases.h"
+ "internal/conformance_archetype.h"
+ "internal/conformance_profile.h"
+ "internal/conformance_testing.h"
+ "internal/conformance_testing_helpers.h"
+ "internal/parentheses.h"
+ "internal/transform_args.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::algorithm
+ absl::debugging
+ absl::type_traits
+ absl::strings
+ absl::utility
+ gmock_main
+ TESTONLY
+)
+
+absl_cc_test(
+ NAME
+ conformance_testing_test
+ SRCS
+ "internal/conformance_testing_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ ${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::conformance_testing
+ absl::type_traits
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ conformance_testing_test_no_exceptions
+ SRCS
+ "internal/conformance_testing_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::conformance_testing
+ absl::type_traits
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
variant
HDRS
"variant.h"
diff --git a/third_party/abseil/absl/types/any.h b/third_party/abseil/absl/types/any.h
index d2e2533..fc5a074 100644
--- a/third_party/abseil/absl/types/any.h
+++ b/third_party/abseil/absl/types/any.h
@@ -47,27 +47,29 @@
// 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`.
+// Abseil has also released an `absl::variant` type (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
+#ifdef ABSL_USES_STD_ANY
#include <any> // IWYU pragma: export
namespace absl {
+ABSL_NAMESPACE_BEGIN
using std::any;
using std::any_cast;
using std::bad_any_cast;
using std::make_any;
+ABSL_NAMESPACE_END
} // namespace absl
-#else // ABSL_HAVE_STD_ANY
+#else // ABSL_USES_STD_ANY
#include <algorithm>
#include <cstddef>
@@ -78,6 +80,7 @@
#include <typeinfo>
#include <utility>
+#include "absl/base/internal/fast_type_id.h"
#include "absl/base/macros.h"
#include "absl/meta/type_traits.h"
#include "absl/types/bad_any_cast.h"
@@ -91,26 +94,7 @@
#endif // !defined(__GNUC__) || defined(__GXX_RTTI)
namespace absl {
-
-namespace any_internal {
-
-template <typename Type>
-struct TypeTag {
- constexpr static char dummy_var = 0;
-};
-
-template <typename Type>
-constexpr char TypeTag<Type>::dummy_var;
-
-// FastTypeId<Type>() evaluates at compile/link-time to a unique pointer for the
-// passed in type. These are meant to be good match for keys into maps or
-// straight up comparisons.
-template<typename Type>
-constexpr inline const void* FastTypeId() {
- return &TypeTag<Type>::dummy_var;
-}
-
-} // namespace any_internal
+ABSL_NAMESPACE_BEGIN
class any;
@@ -182,7 +166,7 @@
// 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
+// An `absl::any` can only store a type that is copy-constructible; move-only
// types are not allowed within an `any` object.
//
// Example:
@@ -190,7 +174,7 @@
// 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
+// auto c = absl::any(std::move(my_foo)); // Error, not copy-constructible
//
// Note that `absl::any` makes use of decayed types (`absl::decay_t` in this
// context) to remove const-volatile qualifiers (known as "cv qualifiers"),
@@ -420,11 +404,11 @@
using NormalizedType =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
- return any_internal::FastTypeId<NormalizedType>();
+ return base_internal::FastTypeId<NormalizedType>();
}
const void* GetObjTypeId() const {
- return obj_ ? obj_->ObjTypeId() : any_internal::FastTypeId<void>();
+ return obj_ ? obj_->ObjTypeId() : base_internal::FastTypeId<void>();
}
// `absl::any` nonmember functions //
@@ -534,10 +518,11 @@
: nullptr;
}
+ABSL_NAMESPACE_END
} // namespace absl
#undef ABSL_ANY_DETAIL_HAS_RTTI
-#endif // ABSL_HAVE_STD_ANY
+#endif // ABSL_USES_STD_ANY
#endif // ABSL_TYPES_ANY_H_
diff --git a/third_party/abseil/absl/types/any_exception_safety_test.cc b/third_party/abseil/absl/types/any_exception_safety_test.cc
index 17d7f5d..31c1140 100644
--- a/third_party/abseil/absl/types/any_exception_safety_test.cc
+++ b/third_party/abseil/absl/types/any_exception_safety_test.cc
@@ -18,7 +18,7 @@
// This test is a no-op when absl::any is an alias for std::any and when
// exceptions are not enabled.
-#if !defined(ABSL_HAVE_STD_ANY) && defined(ABSL_HAVE_EXCEPTIONS)
+#if !defined(ABSL_USES_STD_ANY) && defined(ABSL_HAVE_EXCEPTIONS)
#include <typeinfo>
#include <vector>
@@ -170,4 +170,4 @@
} // namespace
-#endif // #if !defined(ABSL_HAVE_STD_ANY) && defined(ABSL_HAVE_EXCEPTIONS)
+#endif // #if !defined(ABSL_USES_STD_ANY) && defined(ABSL_HAVE_EXCEPTIONS)
diff --git a/third_party/abseil/absl/types/any_test.cc b/third_party/abseil/absl/types/any_test.cc
index 4a848ae..70e4ba2 100644
--- a/third_party/abseil/absl/types/any_test.cc
+++ b/third_party/abseil/absl/types/any_test.cc
@@ -15,7 +15,7 @@
#include "absl/types/any.h"
// This test is a no-op when absl::any is an alias for std::any.
-#if !defined(ABSL_HAVE_STD_ANY)
+#if !defined(ABSL_USES_STD_ANY)
#include <initializer_list>
#include <type_traits>
@@ -642,7 +642,7 @@
// Tests for Exception Behavior //
//////////////////////////////////
-#if defined(ABSL_HAVE_STD_ANY)
+#if defined(ABSL_USES_STD_ANY)
// If using a std `any` implementation, we can't check for a specific message.
#define ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(...) \
@@ -656,7 +656,7 @@
ABSL_BASE_INTERNAL_EXPECT_FAIL((__VA_ARGS__), absl::bad_any_cast, \
"Bad any cast")
-#endif // defined(ABSL_HAVE_STD_ANY)
+#endif // defined(ABSL_USES_STD_ANY)
TEST(AnyTest, ThrowBadAlloc) {
{
@@ -764,7 +764,7 @@
BadCopyable bad;
absl::any target(absl::in_place_type<int>);
ABSL_ANY_TEST_EXPECT_BAD_COPY(target.emplace<BadCopyable>(bad));
-#if defined(ABSL_HAVE_STD_ANY) && defined(__GLIBCXX__)
+#if defined(ABSL_USES_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
@@ -778,4 +778,4 @@
} // namespace
-#endif // #if !defined(ABSL_HAVE_STD_ANY)
+#endif // #if !defined(ABSL_USES_STD_ANY)
diff --git a/third_party/abseil/absl/types/bad_any_cast.cc b/third_party/abseil/absl/types/bad_any_cast.cc
index 505919a..b0592cc 100644
--- a/third_party/abseil/absl/types/bad_any_cast.cc
+++ b/third_party/abseil/absl/types/bad_any_cast.cc
@@ -14,7 +14,7 @@
#include "absl/types/bad_any_cast.h"
-#ifndef ABSL_HAVE_STD_ANY
+#ifndef ABSL_USES_STD_ANY
#include <cstdlib>
@@ -22,6 +22,7 @@
#include "absl/base/internal/raw_logging.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
bad_any_cast::~bad_any_cast() = default;
@@ -39,6 +40,7 @@
}
} // namespace any_internal
+ABSL_NAMESPACE_END
} // namespace absl
-#endif // ABSL_HAVE_STD_ANY
+#endif // ABSL_USES_STD_ANY
diff --git a/third_party/abseil/absl/types/bad_any_cast.h b/third_party/abseil/absl/types/bad_any_cast.h
index 8d020ed..114cef8 100644
--- a/third_party/abseil/absl/types/bad_any_cast.h
+++ b/third_party/abseil/absl/types/bad_any_cast.h
@@ -25,17 +25,20 @@
#include "absl/base/config.h"
-#ifdef ABSL_HAVE_STD_ANY
+#ifdef ABSL_USES_STD_ANY
#include <any>
namespace absl {
+ABSL_NAMESPACE_BEGIN
using std::bad_any_cast;
+ABSL_NAMESPACE_END
} // namespace absl
-#else // ABSL_HAVE_STD_ANY
+#else // ABSL_USES_STD_ANY
namespace absl {
+ABSL_NAMESPACE_BEGIN
// -----------------------------------------------------------------------------
// bad_any_cast
@@ -64,8 +67,9 @@
[[noreturn]] void ThrowBadAnyCast();
} // namespace any_internal
+ABSL_NAMESPACE_END
} // namespace absl
-#endif // ABSL_HAVE_STD_ANY
+#endif // ABSL_USES_STD_ANY
#endif // ABSL_TYPES_BAD_ANY_CAST_H_
diff --git a/third_party/abseil/absl/types/bad_optional_access.cc b/third_party/abseil/absl/types/bad_optional_access.cc
index a791c7c..26aca70 100644
--- a/third_party/abseil/absl/types/bad_optional_access.cc
+++ b/third_party/abseil/absl/types/bad_optional_access.cc
@@ -14,7 +14,7 @@
#include "absl/types/bad_optional_access.h"
-#ifndef ABSL_HAVE_STD_OPTIONAL
+#ifndef ABSL_USES_STD_OPTIONAL
#include <cstdlib>
@@ -22,6 +22,7 @@
#include "absl/base/internal/raw_logging.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
bad_optional_access::~bad_optional_access() = default;
@@ -41,6 +42,7 @@
}
} // namespace optional_internal
+ABSL_NAMESPACE_END
} // namespace absl
-#endif // ABSL_HAVE_STD_OPTIONAL
+#endif // ABSL_USES_STD_OPTIONAL
diff --git a/third_party/abseil/absl/types/bad_optional_access.h b/third_party/abseil/absl/types/bad_optional_access.h
index add5c45..a500286 100644
--- a/third_party/abseil/absl/types/bad_optional_access.h
+++ b/third_party/abseil/absl/types/bad_optional_access.h
@@ -25,17 +25,20 @@
#include "absl/base/config.h"
-#ifdef ABSL_HAVE_STD_OPTIONAL
+#ifdef ABSL_USES_STD_OPTIONAL
#include <optional>
namespace absl {
+ABSL_NAMESPACE_BEGIN
using std::bad_optional_access;
+ABSL_NAMESPACE_END
} // namespace absl
-#else // ABSL_HAVE_STD_OPTIONAL
+#else // ABSL_USES_STD_OPTIONAL
namespace absl {
+ABSL_NAMESPACE_BEGIN
// -----------------------------------------------------------------------------
// bad_optional_access
@@ -67,8 +70,9 @@
[[noreturn]] void throw_bad_optional_access();
} // namespace optional_internal
+ABSL_NAMESPACE_END
} // namespace absl
-#endif // ABSL_HAVE_STD_OPTIONAL
+#endif // ABSL_USES_STD_OPTIONAL
#endif // ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_
diff --git a/third_party/abseil/absl/types/bad_variant_access.cc b/third_party/abseil/absl/types/bad_variant_access.cc
index a4325c8..3dc88cc 100644
--- a/third_party/abseil/absl/types/bad_variant_access.cc
+++ b/third_party/abseil/absl/types/bad_variant_access.cc
@@ -14,7 +14,7 @@
#include "absl/types/bad_variant_access.h"
-#ifndef ABSL_HAVE_STD_VARIANT
+#ifndef ABSL_USES_STD_VARIANT
#include <cstdlib>
#include <stdexcept>
@@ -23,6 +23,7 @@
#include "absl/base/internal/raw_logging.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
//////////////////////////
// [variant.bad.access] //
@@ -57,6 +58,7 @@
}
} // namespace variant_internal
+ABSL_NAMESPACE_END
} // namespace absl
-#endif // ABSL_HAVE_STD_VARIANT
+#endif // ABSL_USES_STD_VARIANT
diff --git a/third_party/abseil/absl/types/bad_variant_access.h b/third_party/abseil/absl/types/bad_variant_access.h
index 637db43..095969f 100644
--- a/third_party/abseil/absl/types/bad_variant_access.h
+++ b/third_party/abseil/absl/types/bad_variant_access.h
@@ -25,17 +25,20 @@
#include "absl/base/config.h"
-#ifdef ABSL_HAVE_STD_VARIANT
+#ifdef ABSL_USES_STD_VARIANT
#include <variant>
namespace absl {
+ABSL_NAMESPACE_BEGIN
using std::bad_variant_access;
+ABSL_NAMESPACE_END
} // namespace absl
-#else // ABSL_HAVE_STD_VARIANT
+#else // ABSL_USES_STD_VARIANT
namespace absl {
+ABSL_NAMESPACE_BEGIN
// -----------------------------------------------------------------------------
// bad_variant_access
@@ -71,8 +74,9 @@
[[noreturn]] void Rethrow();
} // namespace variant_internal
+ABSL_NAMESPACE_END
} // namespace absl
-#endif // ABSL_HAVE_STD_VARIANT
+#endif // ABSL_USES_STD_VARIANT
#endif // ABSL_TYPES_BAD_VARIANT_ACCESS_H_
diff --git a/third_party/abseil/absl/types/compare.h b/third_party/abseil/absl/types/compare.h
index a213e0b..19b076e 100644
--- a/third_party/abseil/absl/types/compare.h
+++ b/third_party/abseil/absl/types/compare.h
@@ -39,6 +39,7 @@
#include "absl/meta/type_traits.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace compare_internal {
using value_type = int8_t;
@@ -85,7 +86,8 @@
// incomplete types so they need to be defined after the types are complete.
#ifdef __cpp_inline_variables
-#define ABSL_COMPARE_INLINE_BASECLASS_DECL(name)
+// A no-op expansion that can be followed by a semicolon at class level.
+#define ABSL_COMPARE_INLINE_BASECLASS_DECL(name) static_assert(true, "")
#define ABSL_COMPARE_INLINE_SUBCLASS_DECL(type, name) \
static const type name
@@ -98,7 +100,8 @@
#define ABSL_COMPARE_INLINE_BASECLASS_DECL(name) \
ABSL_CONST_INIT static const T name
-#define ABSL_COMPARE_INLINE_SUBCLASS_DECL(type, name)
+// A no-op expansion that can be followed by a semicolon at class level.
+#define ABSL_COMPARE_INLINE_SUBCLASS_DECL(type, name) static_assert(true, "")
#define ABSL_COMPARE_INLINE_INIT(type, name, init) \
template <typename T> \
@@ -175,6 +178,14 @@
weak_equality v) noexcept {
return 0 != v.value_;
}
+ friend constexpr bool operator==(weak_equality v1,
+ weak_equality v2) noexcept {
+ return v1.value_ == v2.value_;
+ }
+ friend constexpr bool operator!=(weak_equality v1,
+ weak_equality v2) noexcept {
+ return v1.value_ != v2.value_;
+ }
private:
compare_internal::value_type value_;
@@ -218,6 +229,14 @@
strong_equality v) noexcept {
return 0 != v.value_;
}
+ friend constexpr bool operator==(strong_equality v1,
+ strong_equality v2) noexcept {
+ return v1.value_ == v2.value_;
+ }
+ friend constexpr bool operator!=(strong_equality v1,
+ strong_equality v2) noexcept {
+ return v1.value_ != v2.value_;
+ }
private:
compare_internal::value_type value_;
@@ -305,6 +324,14 @@
partial_ordering v) noexcept {
return v.is_ordered() && 0 >= v.value_;
}
+ friend constexpr bool operator==(partial_ordering v1,
+ partial_ordering v2) noexcept {
+ return v1.value_ == v2.value_;
+ }
+ friend constexpr bool operator!=(partial_ordering v1,
+ partial_ordering v2) noexcept {
+ return v1.value_ != v2.value_;
+ }
private:
compare_internal::value_type value_;
@@ -389,6 +416,14 @@
weak_ordering v) noexcept {
return 0 >= v.value_;
}
+ friend constexpr bool operator==(weak_ordering v1,
+ weak_ordering v2) noexcept {
+ return v1.value_ == v2.value_;
+ }
+ friend constexpr bool operator!=(weak_ordering v1,
+ weak_ordering v2) noexcept {
+ return v1.value_ != v2.value_;
+ }
private:
compare_internal::value_type value_;
@@ -480,6 +515,14 @@
strong_ordering v) noexcept {
return 0 >= v.value_;
}
+ friend constexpr bool operator==(strong_ordering v1,
+ strong_ordering v2) noexcept {
+ return v1.value_ == v2.value_;
+ }
+ friend constexpr bool operator!=(strong_ordering v1,
+ strong_ordering v2) noexcept {
+ return v1.value_ != v2.value_;
+ }
private:
compare_internal::value_type value_;
@@ -551,6 +594,7 @@
}
} // namespace compare_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_TYPES_COMPARE_H_
diff --git a/third_party/abseil/absl/types/compare_test.cc b/third_party/abseil/absl/types/compare_test.cc
index ee396fc..8095baf 100644
--- a/third_party/abseil/absl/types/compare_test.cc
+++ b/third_party/abseil/absl/types/compare_test.cc
@@ -18,6 +18,7 @@
#include "absl/base/casts.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
// This is necessary to avoid a bunch of lint warnings suggesting that we use
@@ -30,6 +31,15 @@
EXPECT_TRUE(Identity(0 == weak_equality::equivalent));
EXPECT_TRUE(Identity(weak_equality::nonequivalent != 0));
EXPECT_TRUE(Identity(0 != weak_equality::nonequivalent));
+ const weak_equality values[] = {weak_equality::equivalent,
+ weak_equality::nonequivalent};
+ for (const auto& lhs : values) {
+ for (const auto& rhs : values) {
+ const bool are_equal = &lhs == &rhs;
+ EXPECT_EQ(lhs == rhs, are_equal);
+ EXPECT_EQ(lhs != rhs, !are_equal);
+ }
+ }
}
TEST(Compare, StrongEquality) {
@@ -41,6 +51,18 @@
EXPECT_TRUE(Identity(0 == strong_equality::equivalent));
EXPECT_TRUE(Identity(strong_equality::nonequivalent != 0));
EXPECT_TRUE(Identity(0 != strong_equality::nonequivalent));
+ const strong_equality values[] = {strong_equality::equal,
+ strong_equality::nonequal};
+ for (const auto& lhs : values) {
+ for (const auto& rhs : values) {
+ const bool are_equal = &lhs == &rhs;
+ EXPECT_EQ(lhs == rhs, are_equal);
+ EXPECT_EQ(lhs != rhs, !are_equal);
+ }
+ }
+ EXPECT_TRUE(Identity(strong_equality::equivalent == strong_equality::equal));
+ EXPECT_TRUE(
+ Identity(strong_equality::nonequivalent == strong_equality::nonequal));
}
TEST(Compare, PartialOrdering) {
@@ -64,6 +86,16 @@
EXPECT_FALSE(Identity(0 > partial_ordering::unordered));
EXPECT_FALSE(Identity(partial_ordering::unordered >= 0));
EXPECT_FALSE(Identity(0 >= partial_ordering::unordered));
+ const partial_ordering values[] = {
+ partial_ordering::less, partial_ordering::equivalent,
+ partial_ordering::greater, partial_ordering::unordered};
+ for (const auto& lhs : values) {
+ for (const auto& rhs : values) {
+ const bool are_equal = &lhs == &rhs;
+ EXPECT_EQ(lhs == rhs, are_equal);
+ EXPECT_EQ(lhs != rhs, !are_equal);
+ }
+ }
}
TEST(Compare, WeakOrdering) {
@@ -77,6 +109,15 @@
EXPECT_TRUE(Identity(0 < weak_ordering::greater));
EXPECT_TRUE(Identity(weak_ordering::greater >= 0));
EXPECT_TRUE(Identity(0 <= weak_ordering::greater));
+ const weak_ordering values[] = {
+ weak_ordering::less, weak_ordering::equivalent, weak_ordering::greater};
+ for (const auto& lhs : values) {
+ for (const auto& rhs : values) {
+ const bool are_equal = &lhs == &rhs;
+ EXPECT_EQ(lhs == rhs, are_equal);
+ EXPECT_EQ(lhs != rhs, !are_equal);
+ }
+ }
}
TEST(Compare, StrongOrdering) {
@@ -92,6 +133,16 @@
EXPECT_TRUE(Identity(0 < strong_ordering::greater));
EXPECT_TRUE(Identity(strong_ordering::greater >= 0));
EXPECT_TRUE(Identity(0 <= strong_ordering::greater));
+ const strong_ordering values[] = {
+ strong_ordering::less, strong_ordering::equal, strong_ordering::greater};
+ for (const auto& lhs : values) {
+ for (const auto& rhs : values) {
+ const bool are_equal = &lhs == &rhs;
+ EXPECT_EQ(lhs == rhs, are_equal);
+ EXPECT_EQ(lhs != rhs, !are_equal);
+ }
+ }
+ EXPECT_TRUE(Identity(strong_ordering::equivalent == strong_ordering::equal));
}
TEST(Compare, Conversions) {
@@ -189,7 +240,7 @@
struct WeakOrderingLess {
template <typename T>
- absl::weak_ordering operator()(const T &a, const T &b) const {
+ absl::weak_ordering operator()(const T& a, const T& b) const {
return a < b ? absl::weak_ordering::less
: a == b ? absl::weak_ordering::equivalent
: absl::weak_ordering::greater;
@@ -223,10 +274,10 @@
}
TEST(CompareResultAsOrdering, SanityTest) {
- EXPECT_TRUE(Identity(
- absl::compare_internal::compare_result_as_ordering(-1) < 0));
- EXPECT_FALSE(Identity(
- absl::compare_internal::compare_result_as_ordering(-1) == 0));
+ EXPECT_TRUE(
+ Identity(absl::compare_internal::compare_result_as_ordering(-1) < 0));
+ EXPECT_FALSE(
+ Identity(absl::compare_internal::compare_result_as_ordering(-1) == 0));
EXPECT_FALSE(
Identity(absl::compare_internal::compare_result_as_ordering(-1) > 0));
EXPECT_TRUE(Identity(absl::compare_internal::compare_result_as_ordering(
@@ -236,31 +287,31 @@
EXPECT_FALSE(Identity(absl::compare_internal::compare_result_as_ordering(
weak_ordering::less) > 0));
- EXPECT_FALSE(Identity(
- absl::compare_internal::compare_result_as_ordering(0) < 0));
- EXPECT_TRUE(Identity(
- absl::compare_internal::compare_result_as_ordering(0) == 0));
- EXPECT_FALSE(Identity(
- absl::compare_internal::compare_result_as_ordering(0) > 0));
+ EXPECT_FALSE(
+ Identity(absl::compare_internal::compare_result_as_ordering(0) < 0));
+ EXPECT_TRUE(
+ Identity(absl::compare_internal::compare_result_as_ordering(0) == 0));
+ EXPECT_FALSE(
+ Identity(absl::compare_internal::compare_result_as_ordering(0) > 0));
EXPECT_FALSE(Identity(absl::compare_internal::compare_result_as_ordering(
- weak_ordering::equivalent) < 0));
+ weak_ordering::equivalent) < 0));
EXPECT_TRUE(Identity(absl::compare_internal::compare_result_as_ordering(
- weak_ordering::equivalent) == 0));
+ weak_ordering::equivalent) == 0));
EXPECT_FALSE(Identity(absl::compare_internal::compare_result_as_ordering(
weak_ordering::equivalent) > 0));
- EXPECT_FALSE(Identity(
- absl::compare_internal::compare_result_as_ordering(1) < 0));
- EXPECT_FALSE(Identity(
- absl::compare_internal::compare_result_as_ordering(1) == 0));
- EXPECT_TRUE(Identity(
- absl::compare_internal::compare_result_as_ordering(1) > 0));
+ EXPECT_FALSE(
+ Identity(absl::compare_internal::compare_result_as_ordering(1) < 0));
+ EXPECT_FALSE(
+ Identity(absl::compare_internal::compare_result_as_ordering(1) == 0));
+ EXPECT_TRUE(
+ Identity(absl::compare_internal::compare_result_as_ordering(1) > 0));
EXPECT_FALSE(Identity(absl::compare_internal::compare_result_as_ordering(
- weak_ordering::greater) < 0));
+ weak_ordering::greater) < 0));
EXPECT_FALSE(Identity(absl::compare_internal::compare_result_as_ordering(
weak_ordering::greater) == 0));
EXPECT_TRUE(Identity(absl::compare_internal::compare_result_as_ordering(
- weak_ordering::greater) > 0));
+ weak_ordering::greater) > 0));
}
TEST(DoThreeWayComparison, SanityTest) {
@@ -334,4 +385,5 @@
#endif // __cpp_inline_variables
} // namespace
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/types/internal/conformance_aliases.h b/third_party/abseil/absl/types/internal/conformance_aliases.h
new file mode 100644
index 0000000..0cc6884
--- /dev/null
+++ b/third_party/abseil/absl/types/internal/conformance_aliases.h
@@ -0,0 +1,447 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// regularity_aliases.h
+// -----------------------------------------------------------------------------
+//
+// This file contains type aliases of common ConformanceProfiles and Archetypes
+// so that they can be directly used by name without creating them from scratch.
+
+#ifndef ABSL_TYPES_INTERNAL_CONFORMANCE_ALIASES_H_
+#define ABSL_TYPES_INTERNAL_CONFORMANCE_ALIASES_H_
+
+#include "absl/types/internal/conformance_archetype.h"
+#include "absl/types/internal/conformance_profile.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace types_internal {
+
+// Creates both a Profile and a corresponding Archetype with root name "name".
+#define ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(name, ...) \
+ struct name##Profile : __VA_ARGS__ {}; \
+ \
+ using name##Archetype = ::absl::types_internal::Archetype<name##Profile>; \
+ \
+ template <class AbslInternalProfileTag> \
+ using name##Archetype##_ = ::absl::types_internal::Archetype< \
+ ::absl::types_internal::StrongProfileTypedef<name##Profile, \
+ AbslInternalProfileTag>>
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasTrivialDefaultConstructor,
+ ConformanceProfile<default_constructible::trivial>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasNothrowDefaultConstructor,
+ ConformanceProfile<default_constructible::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasDefaultConstructor, ConformanceProfile<default_constructible::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasTrivialMoveConstructor, ConformanceProfile<default_constructible::maybe,
+ move_constructible::trivial>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasNothrowMoveConstructor, ConformanceProfile<default_constructible::maybe,
+ move_constructible::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasMoveConstructor,
+ ConformanceProfile<default_constructible::maybe, move_constructible::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasTrivialCopyConstructor,
+ ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::trivial>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasNothrowCopyConstructor,
+ ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasCopyConstructor,
+ ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasTrivialMoveAssign,
+ ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::trivial>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasNothrowMoveAssign,
+ ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasMoveAssign,
+ ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasTrivialCopyAssign,
+ ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::maybe,
+ copy_assignable::trivial>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasNothrowCopyAssign,
+ ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::maybe,
+ copy_assignable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasCopyAssign,
+ ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::maybe,
+ copy_assignable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasTrivialDestructor,
+ ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::maybe,
+ copy_assignable::maybe, destructible::trivial>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasNothrowDestructor,
+ ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::maybe,
+ copy_assignable::maybe, destructible::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasDestructor,
+ ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::maybe,
+ copy_assignable::maybe, destructible::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasNothrowEquality,
+ ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::maybe,
+ copy_assignable::maybe, destructible::maybe,
+ equality_comparable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasEquality,
+ ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::maybe,
+ copy_assignable::maybe, destructible::maybe,
+ equality_comparable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasNothrowInequality,
+ ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::maybe,
+ copy_assignable::maybe, destructible::maybe,
+ equality_comparable::maybe,
+ inequality_comparable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasInequality,
+ ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::maybe,
+ copy_assignable::maybe, destructible::maybe,
+ equality_comparable::maybe, inequality_comparable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasNothrowLessThan,
+ ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::maybe,
+ copy_assignable::maybe, destructible::maybe,
+ equality_comparable::maybe, inequality_comparable::maybe,
+ less_than_comparable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasLessThan,
+ ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::maybe,
+ copy_assignable::maybe, destructible::maybe,
+ equality_comparable::maybe, inequality_comparable::maybe,
+ less_than_comparable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasNothrowLessEqual,
+ ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::maybe,
+ copy_assignable::maybe, destructible::maybe,
+ equality_comparable::maybe, inequality_comparable::maybe,
+ less_than_comparable::maybe,
+ less_equal_comparable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasLessEqual,
+ ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::maybe,
+ copy_assignable::maybe, destructible::maybe,
+ equality_comparable::maybe, inequality_comparable::maybe,
+ less_than_comparable::maybe,
+ less_equal_comparable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasNothrowGreaterEqual,
+ ConformanceProfile<
+ default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::maybe,
+ copy_assignable::maybe, destructible::maybe, equality_comparable::maybe,
+ inequality_comparable::maybe, less_than_comparable::maybe,
+ less_equal_comparable::maybe, greater_equal_comparable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasGreaterEqual,
+ ConformanceProfile<
+ default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::maybe,
+ copy_assignable::maybe, destructible::maybe, equality_comparable::maybe,
+ inequality_comparable::maybe, less_than_comparable::maybe,
+ less_equal_comparable::maybe, greater_equal_comparable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasNothrowGreaterThan,
+ ConformanceProfile<
+ default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::maybe,
+ copy_assignable::maybe, destructible::maybe, equality_comparable::maybe,
+ inequality_comparable::maybe, less_than_comparable::maybe,
+ less_equal_comparable::maybe, greater_equal_comparable::maybe,
+ greater_than_comparable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasGreaterThan,
+ ConformanceProfile<
+ default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::maybe,
+ copy_assignable::maybe, destructible::maybe, equality_comparable::maybe,
+ inequality_comparable::maybe, less_than_comparable::maybe,
+ less_equal_comparable::maybe, greater_equal_comparable::maybe,
+ greater_than_comparable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasNothrowSwap,
+ ConformanceProfile<
+ default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::maybe,
+ copy_assignable::maybe, destructible::maybe, equality_comparable::maybe,
+ inequality_comparable::maybe, less_than_comparable::maybe,
+ less_equal_comparable::maybe, greater_equal_comparable::maybe,
+ greater_than_comparable::maybe, swappable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasSwap,
+ ConformanceProfile<
+ default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::maybe,
+ copy_assignable::maybe, destructible::maybe, equality_comparable::maybe,
+ inequality_comparable::maybe, less_than_comparable::maybe,
+ less_equal_comparable::maybe, greater_equal_comparable::maybe,
+ greater_than_comparable::maybe, swappable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HasStdHashSpecialization,
+ ConformanceProfile<
+ default_constructible::maybe, move_constructible::maybe,
+ copy_constructible::maybe, move_assignable::maybe,
+ copy_assignable::maybe, destructible::maybe, equality_comparable::maybe,
+ inequality_comparable::maybe, less_than_comparable::maybe,
+ less_equal_comparable::maybe, greater_equal_comparable::maybe,
+ greater_than_comparable::maybe, swappable::maybe, hashable::yes>);
+
+////////////////////////////////////////////////////////////////////////////////
+//// The remaining aliases are combinations of the previous aliases. ////
+////////////////////////////////////////////////////////////////////////////////
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ Equatable, CombineProfiles<HasEqualityProfile, HasInequalityProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ Comparable,
+ CombineProfiles<EquatableProfile, HasLessThanProfile, HasLessEqualProfile,
+ HasGreaterEqualProfile, HasGreaterThanProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ NothrowEquatable,
+ CombineProfiles<HasNothrowEqualityProfile, HasNothrowInequalityProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ NothrowComparable,
+ CombineProfiles<NothrowEquatableProfile, HasNothrowLessThanProfile,
+ HasNothrowLessEqualProfile, HasNothrowGreaterEqualProfile,
+ HasNothrowGreaterThanProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ Value,
+ CombineProfiles<HasNothrowMoveConstructorProfile, HasCopyConstructorProfile,
+ HasNothrowMoveAssignProfile, HasCopyAssignProfile,
+ HasNothrowDestructorProfile, HasNothrowSwapProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ EquatableValue, CombineProfiles<EquatableProfile, ValueProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ ComparableValue, CombineProfiles<ComparableProfile, ValueProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ DefaultConstructibleValue,
+ CombineProfiles<HasDefaultConstructorProfile, ValueProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ NothrowMoveConstructible, CombineProfiles<HasNothrowMoveConstructorProfile,
+ HasNothrowDestructorProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ EquatableNothrowMoveConstructible,
+ CombineProfiles<EquatableProfile, NothrowMoveConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ ComparableNothrowMoveConstructible,
+ CombineProfiles<ComparableProfile, NothrowMoveConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ DefaultConstructibleNothrowMoveConstructible,
+ CombineProfiles<HasDefaultConstructorProfile,
+ NothrowMoveConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ CopyConstructible,
+ CombineProfiles<HasNothrowMoveConstructorProfile, HasCopyConstructorProfile,
+ HasNothrowDestructorProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ EquatableCopyConstructible,
+ CombineProfiles<EquatableProfile, CopyConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ ComparableCopyConstructible,
+ CombineProfiles<ComparableProfile, CopyConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ DefaultConstructibleCopyConstructible,
+ CombineProfiles<HasDefaultConstructorProfile, CopyConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ NothrowMovable,
+ CombineProfiles<HasNothrowMoveConstructorProfile,
+ HasNothrowMoveAssignProfile, HasNothrowDestructorProfile,
+ HasNothrowSwapProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ EquatableNothrowMovable,
+ CombineProfiles<EquatableProfile, NothrowMovableProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ ComparableNothrowMovable,
+ CombineProfiles<ComparableProfile, NothrowMovableProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ DefaultConstructibleNothrowMovable,
+ CombineProfiles<HasDefaultConstructorProfile, NothrowMovableProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ TrivialSpecialMemberFunctions,
+ CombineProfiles<HasTrivialDefaultConstructorProfile,
+ HasTrivialMoveConstructorProfile,
+ HasTrivialCopyConstructorProfile,
+ HasTrivialMoveAssignProfile, HasTrivialCopyAssignProfile,
+ HasTrivialDestructorProfile, HasNothrowSwapProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ TriviallyComplete,
+ CombineProfiles<TrivialSpecialMemberFunctionsProfile, ComparableProfile,
+ HasStdHashSpecializationProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HashableNothrowMoveConstructible,
+ CombineProfiles<HasStdHashSpecializationProfile,
+ NothrowMoveConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HashableCopyConstructible,
+ CombineProfiles<HasStdHashSpecializationProfile, CopyConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HashableNothrowMovable,
+ CombineProfiles<HasStdHashSpecializationProfile, NothrowMovableProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ HashableValue,
+ CombineProfiles<HasStdHashSpecializationProfile, ValueProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+ ComparableHashableValue,
+ CombineProfiles<HashableValueProfile, ComparableProfile>);
+
+// The "preferred" profiles that we support in Abseil.
+template <template <class...> class Receiver>
+using ExpandBasicProfiles =
+ Receiver<NothrowMoveConstructibleProfile, CopyConstructibleProfile,
+ NothrowMovableProfile, ValueProfile>;
+
+// The basic profiles except that they are also all Equatable.
+template <template <class...> class Receiver>
+using ExpandBasicEquatableProfiles =
+ Receiver<EquatableNothrowMoveConstructibleProfile,
+ EquatableCopyConstructibleProfile, EquatableNothrowMovableProfile,
+ EquatableValueProfile>;
+
+// The basic profiles except that they are also all Comparable.
+template <template <class...> class Receiver>
+using ExpandBasicComparableProfiles =
+ Receiver<ComparableNothrowMoveConstructibleProfile,
+ ComparableCopyConstructibleProfile,
+ ComparableNothrowMovableProfile, ComparableValueProfile>;
+
+// The basic profiles except that they are also all Hashable.
+template <template <class...> class Receiver>
+using ExpandBasicHashableProfiles =
+ Receiver<HashableNothrowMoveConstructibleProfile,
+ HashableCopyConstructibleProfile, HashableNothrowMovableProfile,
+ HashableValueProfile>;
+
+// The basic profiles except that they are also all DefaultConstructible.
+template <template <class...> class Receiver>
+using ExpandBasicDefaultConstructibleProfiles =
+ Receiver<DefaultConstructibleNothrowMoveConstructibleProfile,
+ DefaultConstructibleCopyConstructibleProfile,
+ DefaultConstructibleNothrowMovableProfile,
+ DefaultConstructibleValueProfile>;
+
+// The type profiles that we support in Abseil (all of the previous lists).
+template <template <class...> class Receiver>
+using ExpandSupportedProfiles = Receiver<
+ NothrowMoveConstructibleProfile, CopyConstructibleProfile,
+ NothrowMovableProfile, ValueProfile,
+ EquatableNothrowMoveConstructibleProfile, EquatableCopyConstructibleProfile,
+ EquatableNothrowMovableProfile, EquatableValueProfile,
+ ComparableNothrowMoveConstructibleProfile,
+ ComparableCopyConstructibleProfile, ComparableNothrowMovableProfile,
+ ComparableValueProfile, DefaultConstructibleNothrowMoveConstructibleProfile,
+ DefaultConstructibleCopyConstructibleProfile,
+ DefaultConstructibleNothrowMovableProfile, DefaultConstructibleValueProfile,
+ HashableNothrowMoveConstructibleProfile, HashableCopyConstructibleProfile,
+ HashableNothrowMovableProfile, HashableValueProfile>;
+
+// TODO(calabrese) Include types that have throwing move constructors, since in
+// practice we still need to support them because of standard library types with
+// (potentially) non-noexcept moves.
+
+} // namespace types_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#undef ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS
+
+#endif // ABSL_TYPES_INTERNAL_CONFORMANCE_ALIASES_H_
diff --git a/third_party/abseil/absl/types/internal/conformance_archetype.h b/third_party/abseil/absl/types/internal/conformance_archetype.h
new file mode 100644
index 0000000..2349e0f
--- /dev/null
+++ b/third_party/abseil/absl/types/internal/conformance_archetype.h
@@ -0,0 +1,978 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// conformance_archetype.h
+// -----------------------------------------------------------------------------
+//
+// This file contains a facility for generating "archetypes" of out of
+// "Conformance Profiles" (see "conformance_profiles.h" for more information
+// about Conformance Profiles). An archetype is a type that aims to support the
+// bare minimum requirements of a given Conformance Profile. For instance, an
+// archetype that corresponds to an ImmutableProfile has exactly a nothrow
+// move-constructor, a potentially-throwing copy constructor, a nothrow
+// destructor, with all other special-member-functions deleted. These archetypes
+// are useful for testing to make sure that templates are able to work with the
+// kinds of types that they claim to support (i.e. that they do not accidentally
+// under-constrain),
+//
+// The main type template in this file is the Archetype template, which takes
+// a Conformance Profile as a template argument and its instantiations are a
+// minimum-conforming model of that profile.
+
+#ifndef ABSL_TYPES_INTERNAL_CONFORMANCE_ARCHETYPE_H_
+#define ABSL_TYPES_INTERNAL_CONFORMANCE_ARCHETYPE_H_
+
+#include <cstddef>
+#include <functional>
+#include <type_traits>
+#include <utility>
+
+#include "absl/meta/type_traits.h"
+#include "absl/types/internal/conformance_profile.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace types_internal {
+
+// A minimum-conforming implementation of a type with properties specified in
+// `Prof`, where `Prof` is a valid Conformance Profile.
+template <class Prof, class /*Enabler*/ = void>
+class Archetype;
+
+// Given an Archetype, obtain the properties of the profile associated with that
+// archetype.
+template <class Archetype>
+struct PropertiesOfArchetype;
+
+template <class Prof>
+struct PropertiesOfArchetype<Archetype<Prof>> {
+ using type = PropertiesOfT<Prof>;
+};
+
+template <class Archetype>
+using PropertiesOfArchetypeT = typename PropertiesOfArchetype<Archetype>::type;
+
+// A metafunction to determine if a type is an `Archetype`.
+template <class T>
+struct IsArchetype : std::false_type {};
+
+template <class Prof>
+struct IsArchetype<Archetype<Prof>> : std::true_type {};
+
+// A constructor tag type used when creating an Archetype with internal state.
+struct MakeArchetypeState {};
+
+// Data stored within an archetype that is copied/compared/hashed when the
+// corresponding operations are used.
+using ArchetypeState = std::size_t;
+
+////////////////////////////////////////////////////////////////////////////////
+// This section of the file defines a chain of base classes for Archetype, //
+// where each base defines a specific special member function with the //
+// appropriate properties (deleted, noexcept(false), noexcept, or trivial). //
+////////////////////////////////////////////////////////////////////////////////
+
+// The bottom-most base, which contains the state and the default constructor.
+template <default_constructible DefaultConstructibleValue>
+struct ArchetypeStateBase {
+ static_assert(DefaultConstructibleValue == default_constructible::yes ||
+ DefaultConstructibleValue == default_constructible::nothrow,
+ "");
+
+ ArchetypeStateBase() noexcept(
+ DefaultConstructibleValue ==
+ default_constructible::
+ nothrow) /*Vacuous archetype_state initialization*/ {}
+ explicit ArchetypeStateBase(MakeArchetypeState, ArchetypeState state) noexcept
+ : archetype_state(state) {}
+
+ ArchetypeState archetype_state;
+};
+
+template <>
+struct ArchetypeStateBase<default_constructible::maybe> {
+ explicit ArchetypeStateBase() = delete;
+ explicit ArchetypeStateBase(MakeArchetypeState, ArchetypeState state) noexcept
+ : archetype_state(state) {}
+
+ ArchetypeState archetype_state;
+};
+
+template <>
+struct ArchetypeStateBase<default_constructible::trivial> {
+ ArchetypeStateBase() = default;
+ explicit ArchetypeStateBase(MakeArchetypeState, ArchetypeState state) noexcept
+ : archetype_state(state) {}
+
+ ArchetypeState archetype_state;
+};
+
+// The move-constructor base
+template <default_constructible DefaultConstructibleValue,
+ move_constructible MoveConstructibleValue>
+struct ArchetypeMoveConstructor
+ : ArchetypeStateBase<DefaultConstructibleValue> {
+ static_assert(MoveConstructibleValue == move_constructible::yes ||
+ MoveConstructibleValue == move_constructible::nothrow,
+ "");
+
+ explicit ArchetypeMoveConstructor(MakeArchetypeState,
+ ArchetypeState state) noexcept
+ : ArchetypeStateBase<DefaultConstructibleValue>(MakeArchetypeState(),
+ state) {}
+
+ ArchetypeMoveConstructor() = default;
+ ArchetypeMoveConstructor(ArchetypeMoveConstructor&& other) noexcept(
+ MoveConstructibleValue == move_constructible::nothrow)
+ : ArchetypeStateBase<DefaultConstructibleValue>(MakeArchetypeState(),
+ other.archetype_state) {}
+ ArchetypeMoveConstructor(const ArchetypeMoveConstructor&) = default;
+ ArchetypeMoveConstructor& operator=(ArchetypeMoveConstructor&&) = default;
+ ArchetypeMoveConstructor& operator=(const ArchetypeMoveConstructor&) =
+ default;
+};
+
+template <default_constructible DefaultConstructibleValue>
+struct ArchetypeMoveConstructor<DefaultConstructibleValue,
+ move_constructible::trivial>
+ : ArchetypeStateBase<DefaultConstructibleValue> {
+ explicit ArchetypeMoveConstructor(MakeArchetypeState,
+ ArchetypeState state) noexcept
+ : ArchetypeStateBase<DefaultConstructibleValue>(MakeArchetypeState(),
+ state) {}
+
+ ArchetypeMoveConstructor() = default;
+};
+
+// The copy-constructor base
+template <default_constructible DefaultConstructibleValue,
+ move_constructible MoveConstructibleValue,
+ copy_constructible CopyConstructibleValue>
+struct ArchetypeCopyConstructor
+ : ArchetypeMoveConstructor<DefaultConstructibleValue,
+ MoveConstructibleValue> {
+ static_assert(CopyConstructibleValue == copy_constructible::yes ||
+ CopyConstructibleValue == copy_constructible::nothrow,
+ "");
+ explicit ArchetypeCopyConstructor(MakeArchetypeState,
+ ArchetypeState state) noexcept
+ : ArchetypeMoveConstructor<DefaultConstructibleValue,
+ MoveConstructibleValue>(MakeArchetypeState(),
+ state) {}
+
+ ArchetypeCopyConstructor() = default;
+ ArchetypeCopyConstructor(ArchetypeCopyConstructor&&) = default;
+ ArchetypeCopyConstructor(const ArchetypeCopyConstructor& other) noexcept(
+ CopyConstructibleValue == copy_constructible::nothrow)
+ : ArchetypeMoveConstructor<DefaultConstructibleValue,
+ MoveConstructibleValue>(
+ MakeArchetypeState(), other.archetype_state) {}
+ ArchetypeCopyConstructor& operator=(ArchetypeCopyConstructor&&) = default;
+ ArchetypeCopyConstructor& operator=(const ArchetypeCopyConstructor&) =
+ default;
+};
+
+template <default_constructible DefaultConstructibleValue,
+ move_constructible MoveConstructibleValue>
+struct ArchetypeCopyConstructor<DefaultConstructibleValue,
+ MoveConstructibleValue,
+ copy_constructible::maybe>
+ : ArchetypeMoveConstructor<DefaultConstructibleValue,
+ MoveConstructibleValue> {
+ explicit ArchetypeCopyConstructor(MakeArchetypeState,
+ ArchetypeState state) noexcept
+ : ArchetypeMoveConstructor<DefaultConstructibleValue,
+ MoveConstructibleValue>(MakeArchetypeState(),
+ state) {}
+
+ ArchetypeCopyConstructor() = default;
+ ArchetypeCopyConstructor(ArchetypeCopyConstructor&&) = default;
+ ArchetypeCopyConstructor(const ArchetypeCopyConstructor&) = delete;
+ ArchetypeCopyConstructor& operator=(ArchetypeCopyConstructor&&) = default;
+ ArchetypeCopyConstructor& operator=(const ArchetypeCopyConstructor&) =
+ default;
+};
+
+template <default_constructible DefaultConstructibleValue,
+ move_constructible MoveConstructibleValue>
+struct ArchetypeCopyConstructor<DefaultConstructibleValue,
+ MoveConstructibleValue,
+ copy_constructible::trivial>
+ : ArchetypeMoveConstructor<DefaultConstructibleValue,
+ MoveConstructibleValue> {
+ explicit ArchetypeCopyConstructor(MakeArchetypeState,
+ ArchetypeState state) noexcept
+ : ArchetypeMoveConstructor<DefaultConstructibleValue,
+ MoveConstructibleValue>(MakeArchetypeState(),
+ state) {}
+
+ ArchetypeCopyConstructor() = default;
+};
+
+// The move-assign base
+template <default_constructible DefaultConstructibleValue,
+ move_constructible MoveConstructibleValue,
+ copy_constructible CopyConstructibleValue,
+ move_assignable MoveAssignableValue>
+struct ArchetypeMoveAssign
+ : ArchetypeCopyConstructor<DefaultConstructibleValue,
+ MoveConstructibleValue, CopyConstructibleValue> {
+ static_assert(MoveAssignableValue == move_assignable::yes ||
+ MoveAssignableValue == move_assignable::nothrow,
+ "");
+ explicit ArchetypeMoveAssign(MakeArchetypeState,
+ ArchetypeState state) noexcept
+ : ArchetypeCopyConstructor<DefaultConstructibleValue,
+ MoveConstructibleValue,
+ CopyConstructibleValue>(MakeArchetypeState(),
+ state) {}
+
+ ArchetypeMoveAssign() = default;
+ ArchetypeMoveAssign(ArchetypeMoveAssign&&) = default;
+ ArchetypeMoveAssign(const ArchetypeMoveAssign&) = default;
+ ArchetypeMoveAssign& operator=(ArchetypeMoveAssign&& other) noexcept(
+ MoveAssignableValue == move_assignable::nothrow) {
+ this->archetype_state = other.archetype_state;
+ return *this;
+ }
+
+ ArchetypeMoveAssign& operator=(const ArchetypeMoveAssign&) = default;
+};
+
+template <default_constructible DefaultConstructibleValue,
+ move_constructible MoveConstructibleValue,
+ copy_constructible CopyConstructibleValue>
+struct ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue,
+ CopyConstructibleValue, move_assignable::trivial>
+ : ArchetypeCopyConstructor<DefaultConstructibleValue,
+ MoveConstructibleValue, CopyConstructibleValue> {
+ explicit ArchetypeMoveAssign(MakeArchetypeState,
+ ArchetypeState state) noexcept
+ : ArchetypeCopyConstructor<DefaultConstructibleValue,
+ MoveConstructibleValue,
+ CopyConstructibleValue>(MakeArchetypeState(),
+ state) {}
+
+ ArchetypeMoveAssign() = default;
+};
+
+// The copy-assign base
+template <default_constructible DefaultConstructibleValue,
+ move_constructible MoveConstructibleValue,
+ copy_constructible CopyConstructibleValue,
+ move_assignable MoveAssignableValue,
+ copy_assignable CopyAssignableValue>
+struct ArchetypeCopyAssign
+ : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue,
+ CopyConstructibleValue, MoveAssignableValue> {
+ static_assert(CopyAssignableValue == copy_assignable::yes ||
+ CopyAssignableValue == copy_assignable::nothrow,
+ "");
+ explicit ArchetypeCopyAssign(MakeArchetypeState,
+ ArchetypeState state) noexcept
+ : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue,
+ CopyConstructibleValue, MoveAssignableValue>(
+ MakeArchetypeState(), state) {}
+
+ ArchetypeCopyAssign() = default;
+ ArchetypeCopyAssign(ArchetypeCopyAssign&&) = default;
+ ArchetypeCopyAssign(const ArchetypeCopyAssign&) = default;
+ ArchetypeCopyAssign& operator=(ArchetypeCopyAssign&&) = default;
+
+ ArchetypeCopyAssign& operator=(const ArchetypeCopyAssign& other) noexcept(
+ CopyAssignableValue == copy_assignable::nothrow) {
+ this->archetype_state = other.archetype_state;
+ return *this;
+ }
+};
+
+template <default_constructible DefaultConstructibleValue,
+ move_constructible MoveConstructibleValue,
+ copy_constructible CopyConstructibleValue,
+ move_assignable MoveAssignableValue>
+struct ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue,
+ CopyConstructibleValue, MoveAssignableValue,
+ copy_assignable::maybe>
+ : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue,
+ CopyConstructibleValue, MoveAssignableValue> {
+ explicit ArchetypeCopyAssign(MakeArchetypeState,
+ ArchetypeState state) noexcept
+ : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue,
+ CopyConstructibleValue, MoveAssignableValue>(
+ MakeArchetypeState(), state) {}
+
+ ArchetypeCopyAssign() = default;
+ ArchetypeCopyAssign(ArchetypeCopyAssign&&) = default;
+ ArchetypeCopyAssign(const ArchetypeCopyAssign&) = default;
+ ArchetypeCopyAssign& operator=(ArchetypeCopyAssign&&) = default;
+ ArchetypeCopyAssign& operator=(const ArchetypeCopyAssign&) = delete;
+};
+
+template <default_constructible DefaultConstructibleValue,
+ move_constructible MoveConstructibleValue,
+ copy_constructible CopyConstructibleValue,
+ move_assignable MoveAssignableValue>
+struct ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue,
+ CopyConstructibleValue, MoveAssignableValue,
+ copy_assignable::trivial>
+ : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue,
+ CopyConstructibleValue, MoveAssignableValue> {
+ explicit ArchetypeCopyAssign(MakeArchetypeState,
+ ArchetypeState state) noexcept
+ : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue,
+ CopyConstructibleValue, MoveAssignableValue>(
+ MakeArchetypeState(), state) {}
+
+ ArchetypeCopyAssign() = default;
+};
+
+// The destructor base
+template <default_constructible DefaultConstructibleValue,
+ move_constructible MoveConstructibleValue,
+ copy_constructible CopyConstructibleValue,
+ move_assignable MoveAssignableValue,
+ copy_assignable CopyAssignableValue, destructible DestructibleValue>
+struct ArchetypeDestructor
+ : ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue,
+ CopyConstructibleValue, MoveAssignableValue,
+ CopyAssignableValue> {
+ static_assert(DestructibleValue == destructible::yes ||
+ DestructibleValue == destructible::nothrow,
+ "");
+
+ explicit ArchetypeDestructor(MakeArchetypeState,
+ ArchetypeState state) noexcept
+ : ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue,
+ CopyConstructibleValue, MoveAssignableValue,
+ CopyAssignableValue>(MakeArchetypeState(), state) {}
+
+ ArchetypeDestructor() = default;
+ ArchetypeDestructor(ArchetypeDestructor&&) = default;
+ ArchetypeDestructor(const ArchetypeDestructor&) = default;
+ ArchetypeDestructor& operator=(ArchetypeDestructor&&) = default;
+ ArchetypeDestructor& operator=(const ArchetypeDestructor&) = default;
+ ~ArchetypeDestructor() noexcept(DestructibleValue == destructible::nothrow) {}
+};
+
+template <default_constructible DefaultConstructibleValue,
+ move_constructible MoveConstructibleValue,
+ copy_constructible CopyConstructibleValue,
+ move_assignable MoveAssignableValue,
+ copy_assignable CopyAssignableValue>
+struct ArchetypeDestructor<DefaultConstructibleValue, MoveConstructibleValue,
+ CopyConstructibleValue, MoveAssignableValue,
+ CopyAssignableValue, destructible::trivial>
+ : ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue,
+ CopyConstructibleValue, MoveAssignableValue,
+ CopyAssignableValue> {
+ explicit ArchetypeDestructor(MakeArchetypeState,
+ ArchetypeState state) noexcept
+ : ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue,
+ CopyConstructibleValue, MoveAssignableValue,
+ CopyAssignableValue>(MakeArchetypeState(), state) {}
+
+ ArchetypeDestructor() = default;
+};
+
+// An alias to the top of the chain of bases for special-member functions.
+// NOTE: move_constructible::maybe, move_assignable::maybe, and
+// destructible::maybe are handled in the top-level type by way of SFINAE.
+// Because of this, we never instantiate the base classes with
+// move_constructible::maybe, move_assignable::maybe, or destructible::maybe so
+// that we minimize the number of different possible type-template
+// instantiations.
+template <default_constructible DefaultConstructibleValue,
+ move_constructible MoveConstructibleValue,
+ copy_constructible CopyConstructibleValue,
+ move_assignable MoveAssignableValue,
+ copy_assignable CopyAssignableValue, destructible DestructibleValue>
+using ArchetypeSpecialMembersBase = ArchetypeDestructor<
+ DefaultConstructibleValue,
+ MoveConstructibleValue != move_constructible::maybe
+ ? MoveConstructibleValue
+ : move_constructible::nothrow,
+ CopyConstructibleValue,
+ MoveAssignableValue != move_assignable::maybe ? MoveAssignableValue
+ : move_assignable::nothrow,
+ CopyAssignableValue,
+ DestructibleValue != destructible::maybe ? DestructibleValue
+ : destructible::nothrow>;
+
+// A function that is used to create an archetype with some associated state.
+template <class Arch>
+Arch MakeArchetype(ArchetypeState state) noexcept {
+ static_assert(IsArchetype<Arch>::value,
+ "The explicit template argument to MakeArchetype is required "
+ "to be an Archetype.");
+ return Arch(MakeArchetypeState(), state);
+}
+
+// This is used to conditionally delete "copy" and "move" constructors in a way
+// that is consistent with what the ConformanceProfile requires and that also
+// strictly enforces the arguments to the copy/move to not come from implicit
+// conversions when dealing with the Archetype.
+template <class Prof, class T>
+constexpr bool ShouldDeleteConstructor() {
+ return !((PropertiesOfT<Prof>::move_constructible_support !=
+ move_constructible::maybe &&
+ std::is_same<T, Archetype<Prof>>::value) ||
+ (PropertiesOfT<Prof>::copy_constructible_support !=
+ copy_constructible::maybe &&
+ (std::is_same<T, const Archetype<Prof>&>::value ||
+ std::is_same<T, Archetype<Prof>&>::value ||
+ std::is_same<T, const Archetype<Prof>>::value)));
+}
+
+// This is used to conditionally delete "copy" and "move" assigns in a way
+// that is consistent with what the ConformanceProfile requires and that also
+// strictly enforces the arguments to the copy/move to not come from implicit
+// conversions when dealing with the Archetype.
+template <class Prof, class T>
+constexpr bool ShouldDeleteAssign() {
+ return !(
+ (PropertiesOfT<Prof>::move_assignable_support != move_assignable::maybe &&
+ std::is_same<T, Archetype<Prof>>::value) ||
+ (PropertiesOfT<Prof>::copy_assignable_support != copy_assignable::maybe &&
+ (std::is_same<T, const Archetype<Prof>&>::value ||
+ std::is_same<T, Archetype<Prof>&>::value ||
+ std::is_same<T, const Archetype<Prof>>::value)));
+}
+
+// TODO(calabrese) Inherit from a chain of secondary bases to pull in the
+// associated functions of other concepts.
+template <class Prof, class Enabler>
+class Archetype : ArchetypeSpecialMembersBase<
+ PropertiesOfT<Prof>::default_constructible_support,
+ PropertiesOfT<Prof>::move_constructible_support,
+ PropertiesOfT<Prof>::copy_constructible_support,
+ PropertiesOfT<Prof>::move_assignable_support,
+ PropertiesOfT<Prof>::copy_assignable_support,
+ PropertiesOfT<Prof>::destructible_support> {
+ static_assert(std::is_same<Enabler, void>::value,
+ "An explicit type must not be passed as the second template "
+ "argument to 'Archetype`.");
+
+ // The cases mentioned in these static_asserts are expected to be handled in
+ // the partial template specializations of Archetype that follow this
+ // definition.
+ static_assert(PropertiesOfT<Prof>::destructible_support !=
+ destructible::maybe,
+ "");
+ static_assert(PropertiesOfT<Prof>::move_constructible_support !=
+ move_constructible::maybe ||
+ PropertiesOfT<Prof>::copy_constructible_support ==
+ copy_constructible::maybe,
+ "");
+ static_assert(PropertiesOfT<Prof>::move_assignable_support !=
+ move_assignable::maybe ||
+ PropertiesOfT<Prof>::copy_assignable_support ==
+ copy_assignable::maybe,
+ "");
+
+ public:
+ Archetype() = default;
+
+ // Disallow moves when requested, and disallow implicit conversions.
+ template <class T, typename std::enable_if<
+ ShouldDeleteConstructor<Prof, T>()>::type* = nullptr>
+ Archetype(T&&) = delete;
+
+ // Disallow moves when requested, and disallow implicit conversions.
+ template <class T, typename std::enable_if<
+ ShouldDeleteAssign<Prof, T>()>::type* = nullptr>
+ Archetype& operator=(T&&) = delete;
+
+ using ArchetypeSpecialMembersBase<
+ PropertiesOfT<Prof>::default_constructible_support,
+ PropertiesOfT<Prof>::move_constructible_support,
+ PropertiesOfT<Prof>::copy_constructible_support,
+ PropertiesOfT<Prof>::move_assignable_support,
+ PropertiesOfT<Prof>::copy_assignable_support,
+ PropertiesOfT<Prof>::destructible_support>::archetype_state;
+
+ private:
+ explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept
+ : ArchetypeSpecialMembersBase<
+ PropertiesOfT<Prof>::default_constructible_support,
+ PropertiesOfT<Prof>::move_constructible_support,
+ PropertiesOfT<Prof>::copy_constructible_support,
+ PropertiesOfT<Prof>::move_assignable_support,
+ PropertiesOfT<Prof>::copy_assignable_support,
+ PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(),
+ state) {}
+
+ friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept;
+};
+
+template <class Prof>
+class Archetype<Prof, typename std::enable_if<
+ PropertiesOfT<Prof>::move_constructible_support !=
+ move_constructible::maybe &&
+ PropertiesOfT<Prof>::move_assignable_support ==
+ move_assignable::maybe &&
+ PropertiesOfT<Prof>::destructible_support !=
+ destructible::maybe>::type>
+ : ArchetypeSpecialMembersBase<
+ PropertiesOfT<Prof>::default_constructible_support,
+ PropertiesOfT<Prof>::move_constructible_support,
+ PropertiesOfT<Prof>::copy_constructible_support,
+ PropertiesOfT<Prof>::move_assignable_support,
+ PropertiesOfT<Prof>::copy_assignable_support,
+ PropertiesOfT<Prof>::destructible_support> {
+ public:
+ Archetype() = default;
+ Archetype(Archetype&&) = default;
+ Archetype(const Archetype&) = default;
+ Archetype& operator=(Archetype&&) = delete;
+ Archetype& operator=(const Archetype&) = default;
+
+ // Disallow moves when requested, and disallow implicit conversions.
+ template <class T, typename std::enable_if<
+ ShouldDeleteConstructor<Prof, T>()>::type* = nullptr>
+ Archetype(T&&) = delete;
+
+ // Disallow moves when requested, and disallow implicit conversions.
+ template <class T, typename std::enable_if<
+ ShouldDeleteAssign<Prof, T>()>::type* = nullptr>
+ Archetype& operator=(T&&) = delete;
+
+ using ArchetypeSpecialMembersBase<
+ PropertiesOfT<Prof>::default_constructible_support,
+ PropertiesOfT<Prof>::move_constructible_support,
+ PropertiesOfT<Prof>::copy_constructible_support,
+ PropertiesOfT<Prof>::move_assignable_support,
+ PropertiesOfT<Prof>::copy_assignable_support,
+ PropertiesOfT<Prof>::destructible_support>::archetype_state;
+
+ private:
+ explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept
+ : ArchetypeSpecialMembersBase<
+ PropertiesOfT<Prof>::default_constructible_support,
+ PropertiesOfT<Prof>::move_constructible_support,
+ PropertiesOfT<Prof>::copy_constructible_support,
+ PropertiesOfT<Prof>::move_assignable_support,
+ PropertiesOfT<Prof>::copy_assignable_support,
+ PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(),
+ state) {}
+
+ friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept;
+};
+
+template <class Prof>
+class Archetype<Prof, typename std::enable_if<
+ PropertiesOfT<Prof>::move_constructible_support ==
+ move_constructible::maybe &&
+ PropertiesOfT<Prof>::move_assignable_support ==
+ move_assignable::maybe &&
+ PropertiesOfT<Prof>::destructible_support !=
+ destructible::maybe>::type>
+ : ArchetypeSpecialMembersBase<
+ PropertiesOfT<Prof>::default_constructible_support,
+ PropertiesOfT<Prof>::move_constructible_support,
+ PropertiesOfT<Prof>::copy_constructible_support,
+ PropertiesOfT<Prof>::move_assignable_support,
+ PropertiesOfT<Prof>::copy_assignable_support,
+ PropertiesOfT<Prof>::destructible_support> {
+ public:
+ Archetype() = default;
+ Archetype(Archetype&&) = delete;
+ Archetype(const Archetype&) = default;
+ Archetype& operator=(Archetype&&) = delete;
+ Archetype& operator=(const Archetype&) = default;
+
+ // Disallow moves when requested, and disallow implicit conversions.
+ template <class T, typename std::enable_if<
+ ShouldDeleteConstructor<Prof, T>()>::type* = nullptr>
+ Archetype(T&&) = delete;
+
+ // Disallow moves when requested, and disallow implicit conversions.
+ template <class T, typename std::enable_if<
+ ShouldDeleteAssign<Prof, T>()>::type* = nullptr>
+ Archetype& operator=(T&&) = delete;
+
+ using ArchetypeSpecialMembersBase<
+ PropertiesOfT<Prof>::default_constructible_support,
+ PropertiesOfT<Prof>::move_constructible_support,
+ PropertiesOfT<Prof>::copy_constructible_support,
+ PropertiesOfT<Prof>::move_assignable_support,
+ PropertiesOfT<Prof>::copy_assignable_support,
+ PropertiesOfT<Prof>::destructible_support>::archetype_state;
+
+ private:
+ explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept
+ : ArchetypeSpecialMembersBase<
+ PropertiesOfT<Prof>::default_constructible_support,
+ PropertiesOfT<Prof>::move_constructible_support,
+ PropertiesOfT<Prof>::copy_constructible_support,
+ PropertiesOfT<Prof>::move_assignable_support,
+ PropertiesOfT<Prof>::copy_assignable_support,
+ PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(),
+ state) {}
+
+ friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept;
+};
+
+template <class Prof>
+class Archetype<Prof, typename std::enable_if<
+ PropertiesOfT<Prof>::move_constructible_support ==
+ move_constructible::maybe &&
+ PropertiesOfT<Prof>::move_assignable_support !=
+ move_assignable::maybe &&
+ PropertiesOfT<Prof>::destructible_support !=
+ destructible::maybe>::type>
+ : ArchetypeSpecialMembersBase<
+ PropertiesOfT<Prof>::default_constructible_support,
+ PropertiesOfT<Prof>::move_constructible_support,
+ PropertiesOfT<Prof>::copy_constructible_support,
+ PropertiesOfT<Prof>::move_assignable_support,
+ PropertiesOfT<Prof>::copy_assignable_support,
+ PropertiesOfT<Prof>::destructible_support> {
+ public:
+ Archetype() = default;
+ Archetype(Archetype&&) = delete;
+ Archetype(const Archetype&) = default;
+ Archetype& operator=(Archetype&&) = default;
+ Archetype& operator=(const Archetype&) = default;
+
+ // Disallow moves when requested, and disallow implicit conversions.
+ template <class T, typename std::enable_if<
+ ShouldDeleteConstructor<Prof, T>()>::type* = nullptr>
+ Archetype(T&&) = delete;
+
+ // Disallow moves when requested, and disallow implicit conversions.
+ template <class T, typename std::enable_if<
+ ShouldDeleteAssign<Prof, T>()>::type* = nullptr>
+ Archetype& operator=(T&&) = delete;
+
+ using ArchetypeSpecialMembersBase<
+ PropertiesOfT<Prof>::default_constructible_support,
+ PropertiesOfT<Prof>::move_constructible_support,
+ PropertiesOfT<Prof>::copy_constructible_support,
+ PropertiesOfT<Prof>::move_assignable_support,
+ PropertiesOfT<Prof>::copy_assignable_support,
+ PropertiesOfT<Prof>::destructible_support>::archetype_state;
+
+ private:
+ explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept
+ : ArchetypeSpecialMembersBase<
+ PropertiesOfT<Prof>::default_constructible_support,
+ PropertiesOfT<Prof>::move_constructible_support,
+ PropertiesOfT<Prof>::copy_constructible_support,
+ PropertiesOfT<Prof>::move_assignable_support,
+ PropertiesOfT<Prof>::copy_assignable_support,
+ PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(),
+ state) {}
+
+ friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept;
+};
+
+template <class Prof>
+class Archetype<Prof, typename std::enable_if<
+ PropertiesOfT<Prof>::move_constructible_support !=
+ move_constructible::maybe &&
+ PropertiesOfT<Prof>::move_assignable_support ==
+ move_assignable::maybe &&
+ PropertiesOfT<Prof>::destructible_support ==
+ destructible::maybe>::type>
+ : ArchetypeSpecialMembersBase<
+ PropertiesOfT<Prof>::default_constructible_support,
+ PropertiesOfT<Prof>::move_constructible_support,
+ PropertiesOfT<Prof>::copy_constructible_support,
+ PropertiesOfT<Prof>::move_assignable_support,
+ PropertiesOfT<Prof>::copy_assignable_support,
+ PropertiesOfT<Prof>::destructible_support> {
+ public:
+ Archetype() = default;
+ Archetype(Archetype&&) = default;
+ Archetype(const Archetype&) = default;
+ Archetype& operator=(Archetype&&) = delete;
+ Archetype& operator=(const Archetype&) = default;
+ ~Archetype() = delete;
+
+ // Disallow moves when requested, and disallow implicit conversions.
+ template <class T, typename std::enable_if<
+ ShouldDeleteConstructor<Prof, T>()>::type* = nullptr>
+ Archetype(T&&) = delete;
+
+ // Disallow moves when requested, and disallow implicit conversions.
+ template <class T, typename std::enable_if<
+ ShouldDeleteAssign<Prof, T>()>::type* = nullptr>
+ Archetype& operator=(T&&) = delete;
+
+ using ArchetypeSpecialMembersBase<
+ PropertiesOfT<Prof>::default_constructible_support,
+ PropertiesOfT<Prof>::move_constructible_support,
+ PropertiesOfT<Prof>::copy_constructible_support,
+ PropertiesOfT<Prof>::move_assignable_support,
+ PropertiesOfT<Prof>::copy_assignable_support,
+ PropertiesOfT<Prof>::destructible_support>::archetype_state;
+
+ private:
+ explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept
+ : ArchetypeSpecialMembersBase<
+ PropertiesOfT<Prof>::default_constructible_support,
+ PropertiesOfT<Prof>::move_constructible_support,
+ PropertiesOfT<Prof>::copy_constructible_support,
+ PropertiesOfT<Prof>::move_assignable_support,
+ PropertiesOfT<Prof>::copy_assignable_support,
+ PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(),
+ state) {}
+
+ friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept;
+};
+
+template <class Prof>
+class Archetype<Prof, typename std::enable_if<
+ PropertiesOfT<Prof>::move_constructible_support ==
+ move_constructible::maybe &&
+ PropertiesOfT<Prof>::move_assignable_support ==
+ move_assignable::maybe &&
+ PropertiesOfT<Prof>::destructible_support ==
+ destructible::maybe>::type>
+ : ArchetypeSpecialMembersBase<
+ PropertiesOfT<Prof>::default_constructible_support,
+ PropertiesOfT<Prof>::move_constructible_support,
+ PropertiesOfT<Prof>::copy_constructible_support,
+ PropertiesOfT<Prof>::move_assignable_support,
+ PropertiesOfT<Prof>::copy_assignable_support,
+ PropertiesOfT<Prof>::destructible_support> {
+ public:
+ Archetype() = default;
+ Archetype(Archetype&&) = delete;
+ Archetype(const Archetype&) = default;
+ Archetype& operator=(Archetype&&) = delete;
+ Archetype& operator=(const Archetype&) = default;
+ ~Archetype() = delete;
+
+ // Disallow moves when requested, and disallow implicit conversions.
+ template <class T, typename std::enable_if<
+ ShouldDeleteConstructor<Prof, T>()>::type* = nullptr>
+ Archetype(T&&) = delete;
+
+ // Disallow moves when requested, and disallow implicit conversions.
+ template <class T, typename std::enable_if<
+ ShouldDeleteAssign<Prof, T>()>::type* = nullptr>
+ Archetype& operator=(T&&) = delete;
+
+ using ArchetypeSpecialMembersBase<
+ PropertiesOfT<Prof>::default_constructible_support,
+ PropertiesOfT<Prof>::move_constructible_support,
+ PropertiesOfT<Prof>::copy_constructible_support,
+ PropertiesOfT<Prof>::move_assignable_support,
+ PropertiesOfT<Prof>::copy_assignable_support,
+ PropertiesOfT<Prof>::destructible_support>::archetype_state;
+
+ private:
+ explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept
+ : ArchetypeSpecialMembersBase<
+ PropertiesOfT<Prof>::default_constructible_support,
+ PropertiesOfT<Prof>::move_constructible_support,
+ PropertiesOfT<Prof>::copy_constructible_support,
+ PropertiesOfT<Prof>::move_assignable_support,
+ PropertiesOfT<Prof>::copy_assignable_support,
+ PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(),
+ state) {}
+
+ friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept;
+};
+
+template <class Prof>
+class Archetype<Prof, typename std::enable_if<
+ PropertiesOfT<Prof>::move_constructible_support ==
+ move_constructible::maybe &&
+ PropertiesOfT<Prof>::move_assignable_support !=
+ move_assignable::maybe &&
+ PropertiesOfT<Prof>::destructible_support ==
+ destructible::maybe>::type>
+ : ArchetypeSpecialMembersBase<
+ PropertiesOfT<Prof>::default_constructible_support,
+ PropertiesOfT<Prof>::move_constructible_support,
+ PropertiesOfT<Prof>::copy_constructible_support,
+ PropertiesOfT<Prof>::move_assignable_support,
+ PropertiesOfT<Prof>::copy_assignable_support,
+ PropertiesOfT<Prof>::destructible_support> {
+ public:
+ Archetype() = default;
+ Archetype(Archetype&&) = delete;
+ Archetype(const Archetype&) = default;
+ Archetype& operator=(Archetype&&) = default;
+ Archetype& operator=(const Archetype&) = default;
+ ~Archetype() = delete;
+
+ // Disallow moves when requested, and disallow implicit conversions.
+ template <class T, typename std::enable_if<
+ ShouldDeleteConstructor<Prof, T>()>::type* = nullptr>
+ Archetype(T&&) = delete;
+
+ // Disallow moves when requested, and disallow implicit conversions.
+ template <class T, typename std::enable_if<
+ ShouldDeleteAssign<Prof, T>()>::type* = nullptr>
+ Archetype& operator=(T&&) = delete;
+
+ using ArchetypeSpecialMembersBase<
+ PropertiesOfT<Prof>::default_constructible_support,
+ PropertiesOfT<Prof>::move_constructible_support,
+ PropertiesOfT<Prof>::copy_constructible_support,
+ PropertiesOfT<Prof>::move_assignable_support,
+ PropertiesOfT<Prof>::copy_assignable_support,
+ PropertiesOfT<Prof>::destructible_support>::archetype_state;
+
+ private:
+ explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept
+ : ArchetypeSpecialMembersBase<
+ PropertiesOfT<Prof>::default_constructible_support,
+ PropertiesOfT<Prof>::move_constructible_support,
+ PropertiesOfT<Prof>::copy_constructible_support,
+ PropertiesOfT<Prof>::move_assignable_support,
+ PropertiesOfT<Prof>::copy_assignable_support,
+ PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(),
+ state) {}
+
+ friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept;
+};
+
+// Explicitly deleted swap for Archetype if the profile does not require swap.
+// It is important to delete it rather than simply leave it out so that the
+// "using std::swap;" idiom will result in this deleted overload being picked.
+template <class Prof,
+ absl::enable_if_t<!PropertiesOfT<Prof>::is_swappable, int> = 0>
+void swap(Archetype<Prof>&, Archetype<Prof>&) = delete; // NOLINT
+
+// A conditionally-noexcept swap implementation for Archetype when the profile
+// supports swap.
+template <class Prof,
+ absl::enable_if_t<PropertiesOfT<Prof>::is_swappable, int> = 0>
+void swap(Archetype<Prof>& lhs, Archetype<Prof>& rhs) // NOLINT
+ noexcept(PropertiesOfT<Prof>::swappable_support != swappable::yes) {
+ std::swap(lhs.archetype_state, rhs.archetype_state);
+}
+
+// A convertible-to-bool type that is used as the return type of comparison
+// operators since the standard doesn't always require exactly bool.
+struct NothrowBool {
+ explicit NothrowBool() = delete;
+ ~NothrowBool() = default;
+
+ // TODO(calabrese) Delete the copy constructor in C++17 mode since guaranteed
+ // elision makes it not required when returning from a function.
+ // NothrowBool(NothrowBool const&) = delete;
+
+ NothrowBool& operator=(NothrowBool const&) = delete;
+
+ explicit operator bool() const noexcept { return value; }
+
+ static NothrowBool make(bool const value) noexcept {
+ return NothrowBool(value);
+ }
+
+ private:
+ explicit NothrowBool(bool const value) noexcept : value(value) {}
+
+ bool value;
+};
+
+// A convertible-to-bool type that is used as the return type of comparison
+// operators since the standard doesn't always require exactly bool.
+// Note: ExceptionalBool has a conversion operator that is not noexcept, so
+// that even when a comparison operator is noexcept, that operation may still
+// potentially throw when converted to bool.
+struct ExceptionalBool {
+ explicit ExceptionalBool() = delete;
+ ~ExceptionalBool() = default;
+
+ // TODO(calabrese) Delete the copy constructor in C++17 mode since guaranteed
+ // elision makes it not required when returning from a function.
+ // ExceptionalBool(ExceptionalBool const&) = delete;
+
+ ExceptionalBool& operator=(ExceptionalBool const&) = delete;
+
+ explicit operator bool() const { return value; } // NOLINT
+
+ static ExceptionalBool make(bool const value) noexcept {
+ return ExceptionalBool(value);
+ }
+
+ private:
+ explicit ExceptionalBool(bool const value) noexcept : value(value) {}
+
+ bool value;
+};
+
+// The following macro is only used as a helper in this file to stamp out
+// comparison operator definitions. It is undefined after usage.
+//
+// NOTE: Non-nothrow operators throw via their result's conversion to bool even
+// though the operation itself is noexcept.
+#define ABSL_TYPES_INTERNAL_OP(enum_name, op) \
+ template <class Prof> \
+ absl::enable_if_t<!PropertiesOfT<Prof>::is_##enum_name, bool> operator op( \
+ const Archetype<Prof>&, const Archetype<Prof>&) = delete; \
+ \
+ template <class Prof> \
+ typename absl::enable_if_t< \
+ PropertiesOfT<Prof>::is_##enum_name, \
+ std::conditional<PropertiesOfT<Prof>::enum_name##_support == \
+ enum_name::nothrow, \
+ NothrowBool, ExceptionalBool>>::type \
+ operator op(const Archetype<Prof>& lhs, \
+ const Archetype<Prof>& rhs) noexcept { \
+ return absl::conditional_t< \
+ PropertiesOfT<Prof>::enum_name##_support == enum_name::nothrow, \
+ NothrowBool, ExceptionalBool>::make(lhs.archetype_state op \
+ rhs.archetype_state); \
+ }
+
+ABSL_TYPES_INTERNAL_OP(equality_comparable, ==);
+ABSL_TYPES_INTERNAL_OP(inequality_comparable, !=);
+ABSL_TYPES_INTERNAL_OP(less_than_comparable, <);
+ABSL_TYPES_INTERNAL_OP(less_equal_comparable, <=);
+ABSL_TYPES_INTERNAL_OP(greater_equal_comparable, >=);
+ABSL_TYPES_INTERNAL_OP(greater_than_comparable, >);
+
+#undef ABSL_TYPES_INTERNAL_OP
+
+// Base class for std::hash specializations when an Archetype doesn't support
+// hashing.
+struct PoisonedHash {
+ PoisonedHash() = delete;
+ PoisonedHash(const PoisonedHash&) = delete;
+ PoisonedHash& operator=(const PoisonedHash&) = delete;
+};
+
+// Base class for std::hash specializations when an Archetype supports hashing.
+template <class Prof>
+struct EnabledHash {
+ using argument_type = Archetype<Prof>;
+ using result_type = std::size_t;
+ result_type operator()(const argument_type& arg) const {
+ return std::hash<ArchetypeState>()(arg.archetype_state);
+ }
+};
+
+} // namespace types_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+namespace std {
+
+template <class Prof> // NOLINT
+struct hash<::absl::types_internal::Archetype<Prof>>
+ : conditional<::absl::types_internal::PropertiesOfT<Prof>::is_hashable,
+ ::absl::types_internal::EnabledHash<Prof>,
+ ::absl::types_internal::PoisonedHash>::type {};
+
+} // namespace std
+
+#endif // ABSL_TYPES_INTERNAL_CONFORMANCE_ARCHETYPE_H_
diff --git a/third_party/abseil/absl/types/internal/conformance_profile.h b/third_party/abseil/absl/types/internal/conformance_profile.h
new file mode 100644
index 0000000..cf64ff4
--- /dev/null
+++ b/third_party/abseil/absl/types/internal/conformance_profile.h
@@ -0,0 +1,931 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// conformance_profiles.h
+// -----------------------------------------------------------------------------
+//
+// This file contains templates for representing "Regularity Profiles" and
+// concisely-named versions of commonly used Regularity Profiles.
+//
+// A Regularity Profile is a compile-time description of the types of operations
+// that a given type supports, along with properties of those operations when
+// they do exist. For instance, a Regularity Profile may describe a type that
+// has a move-constructor that is noexcept and a copy constructor that is not
+// noexcept. This description can then be examined and passed around to other
+// templates for the purposes of asserting expectations on user-defined types
+// via a series trait checks, or for determining what kinds of run-time tests
+// are able to be performed.
+//
+// Regularity Profiles are also used when creating "archetypes," which are
+// minimum-conforming types that meet all of the requirements of a given
+// Regularity Profile. For more information regarding archetypes, see
+// "conformance_archetypes.h".
+
+#ifndef ABSL_TYPES_INTERNAL_CONFORMANCE_PROFILE_H_
+#define ABSL_TYPES_INTERNAL_CONFORMANCE_PROFILE_H_
+
+#include <set>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/algorithm/container.h"
+#include "absl/meta/type_traits.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/internal/conformance_testing_helpers.h"
+#include "absl/utility/utility.h"
+
+// TODO(calabrese) Add support for extending profiles.
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace types_internal {
+
+// Converts an enum to its underlying integral value.
+template <typename Enum>
+constexpr absl::underlying_type_t<Enum> UnderlyingValue(Enum value) {
+ return static_cast<absl::underlying_type_t<Enum>>(value);
+}
+
+// A tag type used in place of a matcher when checking that an assertion result
+// does not actually contain any errors.
+struct NoError {};
+
+// -----------------------------------------------------------------------------
+// ConformanceErrors
+// -----------------------------------------------------------------------------
+class ConformanceErrors {
+ public:
+ // Setup the error reporting mechanism by seeding it with the name of the type
+ // that is being tested.
+ explicit ConformanceErrors(std::string type_name)
+ : assertion_result_(false), type_name_(std::move(type_name)) {
+ assertion_result_ << "\n\n"
+ "Assuming the following type alias:\n"
+ "\n"
+ " using _T = "
+ << type_name_ << ";\n\n";
+ outputDivider();
+ }
+
+ // Adds the test name to the list of successfully run tests iff it was not
+ // previously reported as failing. This behavior is useful for tests that
+ // have multiple parts, where failures and successes are reported individually
+ // with the same test name.
+ void addTestSuccess(absl::string_view test_name) {
+ auto normalized_test_name = absl::AsciiStrToLower(test_name);
+
+ // If the test is already reported as failing, do not add it to the list of
+ // successes.
+ if (test_failures_.find(normalized_test_name) == test_failures_.end()) {
+ test_successes_.insert(std::move(normalized_test_name));
+ }
+ }
+
+ // Streams a single error description into the internal buffer (a visual
+ // divider is automatically inserted after the error so that multiple errors
+ // are visibly distinct).
+ //
+ // This function increases the error count by 1.
+ //
+ // TODO(calabrese) Determine desired behavior when if this function throws.
+ template <class... P>
+ void addTestFailure(absl::string_view test_name, const P&... args) {
+ // Output a message related to the test failure.
+ assertion_result_ << "\n\n"
+ "Failed test: "
+ << test_name << "\n\n";
+ addTestFailureImpl(args...);
+ assertion_result_ << "\n\n";
+ outputDivider();
+
+ auto normalized_test_name = absl::AsciiStrToLower(test_name);
+
+ // If previous parts of this test succeeded, remove it from that set.
+ test_successes_.erase(normalized_test_name);
+
+ // Add the test name to the list of failed tests.
+ test_failures_.insert(std::move(normalized_test_name));
+
+ has_error_ = true;
+ }
+
+ // Convert this object into a testing::AssertionResult instance such that it
+ // can be used with gtest.
+ ::testing::AssertionResult assertionResult() const {
+ return has_error_ ? assertion_result_ : ::testing::AssertionSuccess();
+ }
+
+ // Convert this object into a testing::AssertionResult instance such that it
+ // can be used with gtest. This overload expects errors, using the specified
+ // matcher.
+ ::testing::AssertionResult expectFailedTests(
+ const std::set<std::string>& test_names) const {
+ // Since we are expecting nonconformance, output an error message when the
+ // type actually conformed to the specified profile.
+ if (!has_error_) {
+ return ::testing::AssertionFailure()
+ << "Unexpected conformance of type:\n"
+ " "
+ << type_name_ << "\n\n";
+ }
+
+ // Get a list of all expected failures that did not actually fail
+ // (or that were not run).
+ std::vector<std::string> nonfailing_tests;
+ absl::c_set_difference(test_names, test_failures_,
+ std::back_inserter(nonfailing_tests));
+
+ // Get a list of all "expected failures" that were never actually run.
+ std::vector<std::string> unrun_tests;
+ absl::c_set_difference(nonfailing_tests, test_successes_,
+ std::back_inserter(unrun_tests));
+
+ // Report when the user specified tests that were not run.
+ if (!unrun_tests.empty()) {
+ const bool tests_were_run =
+ !(test_failures_.empty() && test_successes_.empty());
+
+ // Prepare an assertion result used in the case that tests pass that were
+ // expected to fail.
+ ::testing::AssertionResult result = ::testing::AssertionFailure();
+ result << "When testing type:\n " << type_name_
+ << "\n\nThe following tests were expected to fail but were not "
+ "run";
+
+ if (tests_were_run) result << " (was the test name spelled correctly?)";
+
+ result << ":\n\n";
+
+ // List all of the tests that unexpectedly passed.
+ for (const auto& test_name : unrun_tests) {
+ result << " " << test_name << "\n";
+ }
+
+ if (!tests_were_run) result << "\nNo tests were run.";
+
+ if (!test_failures_.empty()) {
+ // List test failures
+ result << "\nThe tests that were run and failed are:\n\n";
+ for (const auto& test_name : test_failures_) {
+ result << " " << test_name << "\n";
+ }
+ }
+
+ if (!test_successes_.empty()) {
+ // List test successes
+ result << "\nThe tests that were run and succeeded are:\n\n";
+ for (const auto& test_name : test_successes_) {
+ result << " " << test_name << "\n";
+ }
+ }
+
+ return result;
+ }
+
+ // If some tests passed when they were expected to fail, alert the caller.
+ if (nonfailing_tests.empty()) return ::testing::AssertionSuccess();
+
+ // Prepare an assertion result used in the case that tests pass that were
+ // expected to fail.
+ ::testing::AssertionResult unexpected_successes =
+ ::testing::AssertionFailure();
+ unexpected_successes << "When testing type:\n " << type_name_
+ << "\n\nThe following tests passed when they were "
+ "expected to fail:\n\n";
+
+ // List all of the tests that unexpectedly passed.
+ for (const auto& test_name : nonfailing_tests) {
+ unexpected_successes << " " << test_name << "\n";
+ }
+
+ return unexpected_successes;
+ }
+
+ private:
+ void outputDivider() {
+ assertion_result_ << "========================================";
+ }
+
+ void addTestFailureImpl() {}
+
+ template <class H, class... T>
+ void addTestFailureImpl(const H& head, const T&... tail) {
+ assertion_result_ << head;
+ addTestFailureImpl(tail...);
+ }
+
+ ::testing::AssertionResult assertion_result_;
+ std::set<std::string> test_failures_;
+ std::set<std::string> test_successes_;
+ std::string type_name_;
+ bool has_error_ = false;
+};
+
+template <class T, class /*Enabler*/ = void>
+struct PropertiesOfImpl {};
+
+template <class T>
+struct PropertiesOfImpl<T, absl::void_t<typename T::properties>> {
+ using type = typename T::properties;
+};
+
+template <class T>
+struct PropertiesOfImpl<T, absl::void_t<typename T::profile_alias_of>> {
+ using type = typename PropertiesOfImpl<typename T::profile_alias_of>::type;
+};
+
+template <class T>
+struct PropertiesOf : PropertiesOfImpl<T> {};
+
+template <class T>
+using PropertiesOfT = typename PropertiesOf<T>::type;
+
+// NOTE: These enums use this naming convention to be consistent with the
+// standard trait names, which is useful since it allows us to match up each
+// enum name with a corresponding trait name in macro definitions.
+
+// An enum that describes the various expectations on an operations existence.
+enum class function_support { maybe, yes, nothrow, trivial };
+
+constexpr const char* PessimisticPropertyDescription(function_support v) {
+ return v == function_support::maybe
+ ? "no"
+ : v == function_support::yes
+ ? "yes, potentially throwing"
+ : v == function_support::nothrow ? "yes, nothrow"
+ : "yes, trivial";
+}
+
+// Return a string that describes the kind of property support that was
+// expected.
+inline std::string ExpectedFunctionKindList(function_support min,
+ function_support max) {
+ if (min == max) {
+ std::string result =
+ absl::StrCat("Expected:\n ",
+ PessimisticPropertyDescription(
+ static_cast<function_support>(UnderlyingValue(min))),
+ "\n");
+ return result;
+ }
+
+ std::string result = "Expected one of:\n";
+ for (auto curr_support = UnderlyingValue(min);
+ curr_support <= UnderlyingValue(max); ++curr_support) {
+ absl::StrAppend(&result, " ",
+ PessimisticPropertyDescription(
+ static_cast<function_support>(curr_support)),
+ "\n");
+ }
+
+ return result;
+}
+
+template <class Enum>
+void ExpectModelOfImpl(ConformanceErrors* errors, Enum min_support,
+ Enum max_support, Enum kind) {
+ const auto kind_value = UnderlyingValue(kind);
+ const auto min_support_value = UnderlyingValue(min_support);
+ const auto max_support_value = UnderlyingValue(max_support);
+
+ if (!(kind_value >= min_support_value && kind_value <= max_support_value)) {
+ errors->addTestFailure(
+ PropertyName(kind), "**Failed property expectation**\n\n",
+ ExpectedFunctionKindList(
+ static_cast<function_support>(min_support_value),
+ static_cast<function_support>(max_support_value)),
+ '\n', "Actual:\n ",
+ PessimisticPropertyDescription(
+ static_cast<function_support>(kind_value)));
+ } else {
+ errors->addTestSuccess(PropertyName(kind));
+ }
+}
+
+#define ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(description, name) \
+ enum class name { maybe, yes, nothrow, trivial }; \
+ \
+ constexpr const char* PropertyName(name v) { return description; } \
+ static_assert(true, "") // Force a semicolon when using this macro.
+
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM("support for default construction",
+ default_constructible);
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM("support for move construction",
+ move_constructible);
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM("support for copy construction",
+ copy_constructible);
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM("support for move assignment",
+ move_assignable);
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM("support for copy assignment",
+ copy_assignable);
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM("support for destruction",
+ destructible);
+
+#undef ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM
+
+#define ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(description, name) \
+ enum class name { maybe, yes, nothrow }; \
+ \
+ constexpr const char* PropertyName(name v) { return description; } \
+ static_assert(true, "") // Force a semicolon when using this macro.
+
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM("support for ==", equality_comparable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM("support for !=", inequality_comparable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM("support for <", less_than_comparable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM("support for <=", less_equal_comparable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM("support for >=",
+ greater_equal_comparable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM("support for >", greater_than_comparable);
+
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM("support for swap", swappable);
+
+#undef ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM
+
+enum class hashable { maybe, yes };
+
+constexpr const char* PropertyName(hashable v) {
+ return "support for std::hash";
+}
+
+template <class T>
+using AlwaysFalse = std::false_type;
+
+#define ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER(name, property) \
+ template <class T> \
+ constexpr property property##_support_of() { \
+ return std::is_##property<T>::value \
+ ? std::is_nothrow_##property<T>::value \
+ ? absl::is_trivially_##property<T>::value \
+ ? property::trivial \
+ : property::nothrow \
+ : property::yes \
+ : property::maybe; \
+ } \
+ \
+ template <class T, class MinProf, class MaxProf> \
+ void ExpectModelOf##name(ConformanceErrors* errors) { \
+ (ExpectModelOfImpl)(errors, PropertiesOfT<MinProf>::property##_support, \
+ PropertiesOfT<MaxProf>::property##_support, \
+ property##_support_of<T>()); \
+ }
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER(DefaultConstructible,
+ default_constructible);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER(MoveConstructible,
+ move_constructible);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER(CopyConstructible,
+ copy_constructible);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER(MoveAssignable,
+ move_assignable);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER(CopyAssignable,
+ copy_assignable);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER(Destructible, destructible);
+
+#undef ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER
+
+void BoolFunction(bool) noexcept;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A metafunction for checking if an operation exists through SFINAE.
+//
+// `T` is the type to test and Op is an alias containing the expression to test.
+template <class T, template <class...> class Op, class = void>
+struct IsOpableImpl : std::false_type {};
+
+template <class T, template <class...> class Op>
+struct IsOpableImpl<T, Op, absl::void_t<Op<T>>> : std::true_type {};
+
+template <template <class...> class Op>
+struct IsOpable {
+ template <class T>
+ using apply = typename IsOpableImpl<T, Op>::type;
+};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A metafunction for checking if an operation exists and is also noexcept
+// through SFINAE and the noexcept operator.
+///
+// `T` is the type to test and Op is an alias containing the expression to test.
+template <class T, template <class...> class Op, class = void>
+struct IsNothrowOpableImpl : std::false_type {};
+
+template <class T, template <class...> class Op>
+struct IsNothrowOpableImpl<T, Op, absl::enable_if_t<Op<T>::value>>
+ : std::true_type {};
+
+template <template <class...> class Op>
+struct IsNothrowOpable {
+ template <class T>
+ using apply = typename IsNothrowOpableImpl<T, Op>::type;
+};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A macro that produces the necessary function for reporting what kind of
+// support a specific comparison operation has and a function for reporting an
+// error if a given type's support for that operation does not meet the expected
+// requirements.
+#define ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON(name, property, op) \
+ template <class T, \
+ class Result = std::integral_constant< \
+ bool, noexcept((BoolFunction)(std::declval<const T&>() op \
+ std::declval<const T&>()))>> \
+ using name = Result; \
+ \
+ template <class T> \
+ constexpr property property##_support_of() { \
+ return IsOpable<name>::apply<T>::value \
+ ? IsNothrowOpable<name>::apply<T>::value ? property::nothrow \
+ : property::yes \
+ : property::maybe; \
+ } \
+ \
+ template <class T, class MinProf, class MaxProf> \
+ void ExpectModelOf##name(ConformanceErrors* errors) { \
+ (ExpectModelOfImpl)(errors, PropertiesOfT<MinProf>::property##_support, \
+ PropertiesOfT<MaxProf>::property##_support, \
+ property##_support_of<T>()); \
+ }
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Generate the necessary support-checking and error reporting functions for
+// each of the comparison operators.
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON(EqualityComparable,
+ equality_comparable, ==);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON(InequalityComparable,
+ inequality_comparable, !=);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON(LessThanComparable,
+ less_than_comparable, <);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON(LessEqualComparable,
+ less_equal_comparable, <=);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON(GreaterEqualComparable,
+ greater_equal_comparable, >=);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON(GreaterThanComparable,
+ greater_than_comparable, >);
+
+#undef ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// The necessary support-checking and error-reporting functions for swap.
+template <class T>
+constexpr swappable swappable_support_of() {
+ return type_traits_internal::IsSwappable<T>::value
+ ? type_traits_internal::IsNothrowSwappable<T>::value
+ ? swappable::nothrow
+ : swappable::yes
+ : swappable::maybe;
+}
+
+template <class T, class MinProf, class MaxProf>
+void ExpectModelOfSwappable(ConformanceErrors* errors) {
+ (ExpectModelOfImpl)(errors, PropertiesOfT<MinProf>::swappable_support,
+ PropertiesOfT<MaxProf>::swappable_support,
+ swappable_support_of<T>());
+}
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// The necessary support-checking and error-reporting functions for std::hash.
+template <class T>
+constexpr hashable hashable_support_of() {
+ return type_traits_internal::IsHashable<T>::value ? hashable::yes
+ : hashable::maybe;
+}
+
+template <class T, class MinProf, class MaxProf>
+void ExpectModelOfHashable(ConformanceErrors* errors) {
+ (ExpectModelOfImpl)(errors, PropertiesOfT<MinProf>::hashable_support,
+ PropertiesOfT<MaxProf>::hashable_support,
+ hashable_support_of<T>());
+}
+//
+////////////////////////////////////////////////////////////////////////////////
+
+template <
+ default_constructible DefaultConstructibleValue =
+ default_constructible::maybe,
+ move_constructible MoveConstructibleValue = move_constructible::maybe,
+ copy_constructible CopyConstructibleValue = copy_constructible::maybe,
+ move_assignable MoveAssignableValue = move_assignable::maybe,
+ copy_assignable CopyAssignableValue = copy_assignable::maybe,
+ destructible DestructibleValue = destructible::maybe,
+ equality_comparable EqualityComparableValue = equality_comparable::maybe,
+ inequality_comparable InequalityComparableValue =
+ inequality_comparable::maybe,
+ less_than_comparable LessThanComparableValue = less_than_comparable::maybe,
+ less_equal_comparable LessEqualComparableValue =
+ less_equal_comparable::maybe,
+ greater_equal_comparable GreaterEqualComparableValue =
+ greater_equal_comparable::maybe,
+ greater_than_comparable GreaterThanComparableValue =
+ greater_than_comparable::maybe,
+ swappable SwappableValue = swappable::maybe,
+ hashable HashableValue = hashable::maybe>
+struct ConformanceProfile {
+ using properties = ConformanceProfile;
+
+ static constexpr default_constructible
+ default_constructible_support = // NOLINT
+ DefaultConstructibleValue;
+
+ static constexpr move_constructible move_constructible_support = // NOLINT
+ MoveConstructibleValue;
+
+ static constexpr copy_constructible copy_constructible_support = // NOLINT
+ CopyConstructibleValue;
+
+ static constexpr move_assignable move_assignable_support = // NOLINT
+ MoveAssignableValue;
+
+ static constexpr copy_assignable copy_assignable_support = // NOLINT
+ CopyAssignableValue;
+
+ static constexpr destructible destructible_support = // NOLINT
+ DestructibleValue;
+
+ static constexpr equality_comparable equality_comparable_support = // NOLINT
+ EqualityComparableValue;
+
+ static constexpr inequality_comparable
+ inequality_comparable_support = // NOLINT
+ InequalityComparableValue;
+
+ static constexpr less_than_comparable
+ less_than_comparable_support = // NOLINT
+ LessThanComparableValue;
+
+ static constexpr less_equal_comparable
+ less_equal_comparable_support = // NOLINT
+ LessEqualComparableValue;
+
+ static constexpr greater_equal_comparable
+ greater_equal_comparable_support = // NOLINT
+ GreaterEqualComparableValue;
+
+ static constexpr greater_than_comparable
+ greater_than_comparable_support = // NOLINT
+ GreaterThanComparableValue;
+
+ static constexpr swappable swappable_support = SwappableValue; // NOLINT
+
+ static constexpr hashable hashable_support = HashableValue; // NOLINT
+
+ static constexpr bool is_default_constructible = // NOLINT
+ DefaultConstructibleValue != default_constructible::maybe;
+
+ static constexpr bool is_move_constructible = // NOLINT
+ MoveConstructibleValue != move_constructible::maybe;
+
+ static constexpr bool is_copy_constructible = // NOLINT
+ CopyConstructibleValue != copy_constructible::maybe;
+
+ static constexpr bool is_move_assignable = // NOLINT
+ MoveAssignableValue != move_assignable::maybe;
+
+ static constexpr bool is_copy_assignable = // NOLINT
+ CopyAssignableValue != copy_assignable::maybe;
+
+ static constexpr bool is_destructible = // NOLINT
+ DestructibleValue != destructible::maybe;
+
+ static constexpr bool is_equality_comparable = // NOLINT
+ EqualityComparableValue != equality_comparable::maybe;
+
+ static constexpr bool is_inequality_comparable = // NOLINT
+ InequalityComparableValue != inequality_comparable::maybe;
+
+ static constexpr bool is_less_than_comparable = // NOLINT
+ LessThanComparableValue != less_than_comparable::maybe;
+
+ static constexpr bool is_less_equal_comparable = // NOLINT
+ LessEqualComparableValue != less_equal_comparable::maybe;
+
+ static constexpr bool is_greater_equal_comparable = // NOLINT
+ GreaterEqualComparableValue != greater_equal_comparable::maybe;
+
+ static constexpr bool is_greater_than_comparable = // NOLINT
+ GreaterThanComparableValue != greater_than_comparable::maybe;
+
+ static constexpr bool is_swappable = // NOLINT
+ SwappableValue != swappable::maybe;
+
+ static constexpr bool is_hashable = // NOLINT
+ HashableValue != hashable::maybe;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Compliant SFINAE-friendliness is not always present on the standard library
+// implementations that we support. This helper-struct (and associated enum) is
+// used as a means to conditionally check the hashability support of a type.
+enum class CheckHashability { no, yes };
+
+template <class T, CheckHashability ShouldCheckHashability>
+struct conservative_hashable_support_of;
+
+template <class T>
+struct conservative_hashable_support_of<T, CheckHashability::no> {
+ static constexpr hashable Invoke() { return hashable::maybe; }
+};
+
+template <class T>
+struct conservative_hashable_support_of<T, CheckHashability::yes> {
+ static constexpr hashable Invoke() { return hashable_support_of<T>(); }
+};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// The ConformanceProfile that is expected based on introspection into the type
+// by way of trait checks.
+template <class T, CheckHashability ShouldCheckHashability>
+struct SyntacticConformanceProfileOf {
+ using properties = ConformanceProfile<
+ default_constructible_support_of<T>(), move_constructible_support_of<T>(),
+ copy_constructible_support_of<T>(), move_assignable_support_of<T>(),
+ copy_assignable_support_of<T>(), destructible_support_of<T>(),
+ equality_comparable_support_of<T>(),
+ inequality_comparable_support_of<T>(),
+ less_than_comparable_support_of<T>(),
+ less_equal_comparable_support_of<T>(),
+ greater_equal_comparable_support_of<T>(),
+ greater_than_comparable_support_of<T>(), swappable_support_of<T>(),
+ conservative_hashable_support_of<T, ShouldCheckHashability>::Invoke()>;
+};
+
+#define ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL(type, name) \
+ template <default_constructible DefaultConstructibleValue, \
+ move_constructible MoveConstructibleValue, \
+ copy_constructible CopyConstructibleValue, \
+ move_assignable MoveAssignableValue, \
+ copy_assignable CopyAssignableValue, \
+ destructible DestructibleValue, \
+ equality_comparable EqualityComparableValue, \
+ inequality_comparable InequalityComparableValue, \
+ less_than_comparable LessThanComparableValue, \
+ less_equal_comparable LessEqualComparableValue, \
+ greater_equal_comparable GreaterEqualComparableValue, \
+ greater_than_comparable GreaterThanComparableValue, \
+ swappable SwappableValue, hashable HashableValue> \
+ constexpr type ConformanceProfile< \
+ DefaultConstructibleValue, MoveConstructibleValue, \
+ CopyConstructibleValue, MoveAssignableValue, CopyAssignableValue, \
+ DestructibleValue, EqualityComparableValue, InequalityComparableValue, \
+ LessThanComparableValue, LessEqualComparableValue, \
+ GreaterEqualComparableValue, GreaterThanComparableValue, SwappableValue, \
+ HashableValue>::name
+
+#define ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(type) \
+ ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL(type, \
+ type##_support); \
+ ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL(bool, is_##type)
+
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(default_constructible);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(move_constructible);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(copy_constructible);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(move_assignable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(copy_assignable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(destructible);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(equality_comparable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(inequality_comparable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(less_than_comparable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(less_equal_comparable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(greater_equal_comparable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(greater_than_comparable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(swappable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(hashable);
+
+#undef ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF
+#undef ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL
+
+// Retrieve the enum with the minimum underlying value.
+// Note: std::min is not constexpr in C++11, which is why this is necessary.
+template <class H>
+constexpr H MinEnum(H head) {
+ return head;
+}
+
+template <class H, class N, class... T>
+constexpr H MinEnum(H head, N next, T... tail) {
+ return (UnderlyingValue)(head) < (UnderlyingValue)(next)
+ ? (MinEnum)(head, tail...)
+ : (MinEnum)(next, tail...);
+}
+
+template <class... Profs>
+struct MinimalProfiles {
+ static constexpr default_constructible
+ default_constructible_support = // NOLINT
+ (MinEnum)(PropertiesOfT<Profs>::default_constructible_support...);
+
+ static constexpr move_constructible move_constructible_support = // NOLINT
+ (MinEnum)(PropertiesOfT<Profs>::move_constructible_support...);
+
+ static constexpr copy_constructible copy_constructible_support = // NOLINT
+ (MinEnum)(PropertiesOfT<Profs>::copy_constructible_support...);
+
+ static constexpr move_assignable move_assignable_support = // NOLINT
+ (MinEnum)(PropertiesOfT<Profs>::move_assignable_support...);
+
+ static constexpr copy_assignable copy_assignable_support = // NOLINT
+ (MinEnum)(PropertiesOfT<Profs>::copy_assignable_support...);
+
+ static constexpr destructible destructible_support = // NOLINT
+ (MinEnum)(PropertiesOfT<Profs>::destructible_support...);
+
+ static constexpr equality_comparable equality_comparable_support = // NOLINT
+ (MinEnum)(PropertiesOfT<Profs>::equality_comparable_support...);
+
+ static constexpr inequality_comparable
+ inequality_comparable_support = // NOLINT
+ (MinEnum)(PropertiesOfT<Profs>::inequality_comparable_support...);
+
+ static constexpr less_than_comparable
+ less_than_comparable_support = // NOLINT
+ (MinEnum)(PropertiesOfT<Profs>::less_than_comparable_support...);
+
+ static constexpr less_equal_comparable
+ less_equal_comparable_support = // NOLINT
+ (MinEnum)(PropertiesOfT<Profs>::less_equal_comparable_support...);
+
+ static constexpr greater_equal_comparable
+ greater_equal_comparable_support = // NOLINT
+ (MinEnum)(PropertiesOfT<Profs>::greater_equal_comparable_support...);
+
+ static constexpr greater_than_comparable
+ greater_than_comparable_support = // NOLINT
+ (MinEnum)(PropertiesOfT<Profs>::greater_than_comparable_support...);
+
+ static constexpr swappable swappable_support = // NOLINT
+ (MinEnum)(PropertiesOfT<Profs>::swappable_support...);
+
+ static constexpr hashable hashable_support = // NOLINT
+ (MinEnum)(PropertiesOfT<Profs>::hashable_support...);
+
+ using properties = ConformanceProfile<
+ default_constructible_support, move_constructible_support,
+ copy_constructible_support, move_assignable_support,
+ copy_assignable_support, destructible_support,
+ equality_comparable_support, inequality_comparable_support,
+ less_than_comparable_support, less_equal_comparable_support,
+ greater_equal_comparable_support, greater_than_comparable_support,
+ swappable_support, hashable_support>;
+};
+
+// Retrieve the enum with the greatest underlying value.
+// Note: std::max is not constexpr in C++11, which is why this is necessary.
+template <class H>
+constexpr H MaxEnum(H head) {
+ return head;
+}
+
+template <class H, class N, class... T>
+constexpr H MaxEnum(H head, N next, T... tail) {
+ return (UnderlyingValue)(next) < (UnderlyingValue)(head)
+ ? (MaxEnum)(head, tail...)
+ : (MaxEnum)(next, tail...);
+}
+
+template <class... Profs>
+struct CombineProfilesImpl {
+ static constexpr default_constructible
+ default_constructible_support = // NOLINT
+ (MaxEnum)(PropertiesOfT<Profs>::default_constructible_support...);
+
+ static constexpr move_constructible move_constructible_support = // NOLINT
+ (MaxEnum)(PropertiesOfT<Profs>::move_constructible_support...);
+
+ static constexpr copy_constructible copy_constructible_support = // NOLINT
+ (MaxEnum)(PropertiesOfT<Profs>::copy_constructible_support...);
+
+ static constexpr move_assignable move_assignable_support = // NOLINT
+ (MaxEnum)(PropertiesOfT<Profs>::move_assignable_support...);
+
+ static constexpr copy_assignable copy_assignable_support = // NOLINT
+ (MaxEnum)(PropertiesOfT<Profs>::copy_assignable_support...);
+
+ static constexpr destructible destructible_support = // NOLINT
+ (MaxEnum)(PropertiesOfT<Profs>::destructible_support...);
+
+ static constexpr equality_comparable equality_comparable_support = // NOLINT
+ (MaxEnum)(PropertiesOfT<Profs>::equality_comparable_support...);
+
+ static constexpr inequality_comparable
+ inequality_comparable_support = // NOLINT
+ (MaxEnum)(PropertiesOfT<Profs>::inequality_comparable_support...);
+
+ static constexpr less_than_comparable
+ less_than_comparable_support = // NOLINT
+ (MaxEnum)(PropertiesOfT<Profs>::less_than_comparable_support...);
+
+ static constexpr less_equal_comparable
+ less_equal_comparable_support = // NOLINT
+ (MaxEnum)(PropertiesOfT<Profs>::less_equal_comparable_support...);
+
+ static constexpr greater_equal_comparable
+ greater_equal_comparable_support = // NOLINT
+ (MaxEnum)(PropertiesOfT<Profs>::greater_equal_comparable_support...);
+
+ static constexpr greater_than_comparable
+ greater_than_comparable_support = // NOLINT
+ (MaxEnum)(PropertiesOfT<Profs>::greater_than_comparable_support...);
+
+ static constexpr swappable swappable_support = // NOLINT
+ (MaxEnum)(PropertiesOfT<Profs>::swappable_support...);
+
+ static constexpr hashable hashable_support = // NOLINT
+ (MaxEnum)(PropertiesOfT<Profs>::hashable_support...);
+
+ using properties = ConformanceProfile<
+ default_constructible_support, move_constructible_support,
+ copy_constructible_support, move_assignable_support,
+ copy_assignable_support, destructible_support,
+ equality_comparable_support, inequality_comparable_support,
+ less_than_comparable_support, less_equal_comparable_support,
+ greater_equal_comparable_support, greater_than_comparable_support,
+ swappable_support, hashable_support>;
+};
+
+// NOTE: We use this as opposed to a direct alias of CombineProfilesImpl so that
+// when named aliases of CombineProfiles are created (such as in
+// conformance_aliases.h), we only pay for the combination algorithm on the
+// profiles that are actually used.
+template <class... Profs>
+struct CombineProfiles {
+ using profile_alias_of = CombineProfilesImpl<Profs...>;
+};
+
+template <>
+struct CombineProfiles<> {
+ using properties = ConformanceProfile<>;
+};
+
+template <class Profile, class Tag>
+struct StrongProfileTypedef {
+ using properties = PropertiesOfT<Profile>;
+};
+
+template <class T, class /*Enabler*/ = void>
+struct IsProfileImpl : std::false_type {};
+
+template <class T>
+struct IsProfileImpl<T, absl::void_t<PropertiesOfT<T>>> : std::true_type {};
+
+template <class T>
+struct IsProfile : IsProfileImpl<T>::type {};
+
+// A tag that describes which set of properties we will check when the user
+// requires a strict match in conformance (as opposed to a loose match which
+// allows more-refined support of any given operation).
+//
+// Currently only the RegularityDomain exists and it includes all operations
+// that the conformance testing suite knows about. The intent is that if the
+// suite is expanded to support extension, such as for checking conformance of
+// concepts like Iterators or Containers, additional corresponding domains can
+// be created.
+struct RegularityDomain {};
+
+} // namespace types_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_TYPES_INTERNAL_CONFORMANCE_PROFILE_H_
diff --git a/third_party/abseil/absl/types/internal/conformance_testing.h b/third_party/abseil/absl/types/internal/conformance_testing.h
new file mode 100644
index 0000000..487b0f7
--- /dev/null
+++ b/third_party/abseil/absl/types/internal/conformance_testing.h
@@ -0,0 +1,1386 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// conformance_testing.h
+// -----------------------------------------------------------------------------
+//
+
+#ifndef ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_H_
+#define ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_H_
+
+////////////////////////////////////////////////////////////////////////////////
+// //
+// Many templates in this file take a `T` and a `Prof` type as explicit //
+// template arguments. These are a type to be checked and a //
+// "Regularity Profile" that describes what operations that type `T` is //
+// expected to support. See "regularity_profiles.h" for more details //
+// regarding Regularity Profiles. //
+// //
+////////////////////////////////////////////////////////////////////////////////
+
+#include <cstddef>
+#include <set>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "absl/meta/type_traits.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/internal/conformance_aliases.h"
+#include "absl/types/internal/conformance_archetype.h"
+#include "absl/types/internal/conformance_profile.h"
+#include "absl/types/internal/conformance_testing_helpers.h"
+#include "absl/types/internal/parentheses.h"
+#include "absl/types/internal/transform_args.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace types_internal {
+
+// Returns true if the compiler incorrectly greedily instantiates constexpr
+// templates in any unevaluated context.
+constexpr bool constexpr_instantiation_when_unevaluated() {
+#if defined(__apple_build_version__) // TODO(calabrese) Make more specific
+ return true;
+#elif defined(__clang__)
+ return __clang_major__ < 4;
+#elif defined(__GNUC__)
+ // TODO(calabrese) Figure out why gcc 7 fails (seems like a different bug)
+ return __GNUC__ < 5 || (__GNUC__ == 5 && __GNUC_MINOR__ < 2) || __GNUC__ >= 7;
+#else
+ return false;
+#endif
+}
+
+// Returns true if the standard library being used incorrectly produces an error
+// when instantiating the definition of a poisoned std::hash specialization.
+constexpr bool poisoned_hash_fails_instantiation() {
+#if defined(_MSC_VER) && !defined(_LIBCPP_VERSION)
+ return _MSC_VER < 1914;
+#else
+ return false;
+#endif
+}
+
+template <class Fun>
+struct GeneratorType {
+ decltype(std::declval<const Fun&>()()) operator()() const
+ noexcept(noexcept(std::declval<const Fun&>()())) {
+ return fun();
+ }
+
+ Fun fun;
+ const char* description;
+};
+
+// A "make" function for the GeneratorType template that deduces the function
+// object type.
+template <class Fun,
+ absl::enable_if_t<IsNullaryCallable<Fun>::value>** = nullptr>
+GeneratorType<Fun> Generator(Fun fun, const char* description) {
+ return GeneratorType<Fun>{absl::move(fun), description};
+}
+
+// A type that contains a set of nullary function objects that each return an
+// instance of the same type and value (though possibly different
+// representations, such as +0 and -0 or two vectors with the same elements but
+// with different capacities).
+template <class... Funs>
+struct EquivalenceClassType {
+ std::tuple<GeneratorType<Funs>...> generators;
+};
+
+// A "make" function for the EquivalenceClassType template that deduces the
+// function object types and is constrained such that a user can only pass in
+// function objects that all have the same return type.
+template <class... Funs, absl::enable_if_t<AreGeneratorsWithTheSameReturnType<
+ Funs...>::value>** = nullptr>
+EquivalenceClassType<Funs...> EquivalenceClass(GeneratorType<Funs>... funs) {
+ return {std::make_tuple(absl::move(funs)...)};
+}
+
+// A type that contains an ordered series of EquivalenceClassTypes, from
+// smallest value to largest value.
+template <class... EqClasses>
+struct OrderedEquivalenceClasses {
+ std::tuple<EqClasses...> eq_classes;
+};
+
+// An object containing the parts of a given (name, initialization expression),
+// and is capable of generating a string that describes the given.
+struct GivenDeclaration {
+ std::string outputDeclaration(std::size_t width) const {
+ const std::size_t indent_size = 2;
+ std::string result = absl::StrCat(" ", name);
+
+ if (!expression.empty()) {
+ // Indent
+ result.resize(indent_size + width, ' ');
+ absl::StrAppend(&result, " = ", expression, ";\n");
+ } else {
+ absl::StrAppend(&result, ";\n");
+ }
+
+ return result;
+ }
+
+ std::string name;
+ std::string expression;
+};
+
+// Produce a string that contains all of the givens of an error report.
+template <class... Decls>
+std::string PrepareGivenContext(const Decls&... decls) {
+ const std::size_t width = (std::max)({decls.name.size()...});
+ return absl::StrCat("Given:\n", decls.outputDeclaration(width)..., "\n");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Function objects that perform a check for each comparison operator //
+////////////////////////////////////////////////////////////////////////////////
+
+#define ABSL_INTERNAL_EXPECT_OP(name, op) \
+ struct Expect##name { \
+ template <class T> \
+ void operator()(absl::string_view test_name, absl::string_view context, \
+ const T& lhs, const T& rhs, absl::string_view lhs_name, \
+ absl::string_view rhs_name) const { \
+ if (!static_cast<bool>(lhs op rhs)) { \
+ errors->addTestFailure( \
+ test_name, absl::StrCat(context, \
+ "**Unexpected comparison result**\n" \
+ "\n" \
+ "Expression:\n" \
+ " ", \
+ lhs_name, " " #op " ", rhs_name, \
+ "\n" \
+ "\n" \
+ "Expected: true\n" \
+ " Actual: false")); \
+ } else { \
+ errors->addTestSuccess(test_name); \
+ } \
+ } \
+ \
+ ConformanceErrors* errors; \
+ }; \
+ \
+ struct ExpectNot##name { \
+ template <class T> \
+ void operator()(absl::string_view test_name, absl::string_view context, \
+ const T& lhs, const T& rhs, absl::string_view lhs_name, \
+ absl::string_view rhs_name) const { \
+ if (lhs op rhs) { \
+ errors->addTestFailure( \
+ test_name, absl::StrCat(context, \
+ "**Unexpected comparison result**\n" \
+ "\n" \
+ "Expression:\n" \
+ " ", \
+ lhs_name, " " #op " ", rhs_name, \
+ "\n" \
+ "\n" \
+ "Expected: false\n" \
+ " Actual: true")); \
+ } else { \
+ errors->addTestSuccess(test_name); \
+ } \
+ } \
+ \
+ ConformanceErrors* errors; \
+ }
+
+ABSL_INTERNAL_EXPECT_OP(Eq, ==);
+ABSL_INTERNAL_EXPECT_OP(Ne, !=);
+ABSL_INTERNAL_EXPECT_OP(Lt, <);
+ABSL_INTERNAL_EXPECT_OP(Le, <=);
+ABSL_INTERNAL_EXPECT_OP(Ge, >=);
+ABSL_INTERNAL_EXPECT_OP(Gt, >);
+
+#undef ABSL_INTERNAL_EXPECT_OP
+
+// A function object that verifies that two objects hash to the same value by
+// way of the std::hash specialization.
+struct ExpectSameHash {
+ template <class T>
+ void operator()(absl::string_view test_name, absl::string_view context,
+ const T& lhs, const T& rhs, absl::string_view lhs_name,
+ absl::string_view rhs_name) const {
+ if (std::hash<T>()(lhs) != std::hash<T>()(rhs)) {
+ errors->addTestFailure(
+ test_name, absl::StrCat(context,
+ "**Unexpected hash result**\n"
+ "\n"
+ "Expression:\n"
+ " std::hash<T>()(",
+ lhs_name, ") == std::hash<T>()(", rhs_name,
+ ")\n"
+ "\n"
+ "Expected: true\n"
+ " Actual: false"));
+ } else {
+ errors->addTestSuccess(test_name);
+ }
+ }
+
+ ConformanceErrors* errors;
+};
+
+// A function template that takes two objects and verifies that each comparison
+// operator behaves in a way that is consistent with equality. It has "OneWay"
+// in the name because the first argument will always be the left-hand operand
+// of the corresponding comparison operator and the second argument will
+// always be the right-hand operand. It will never switch that order.
+// At a higher level in the test suite, the one-way form is called once for each
+// of the two possible orders whenever lhs and rhs are not the same initializer.
+template <class T, class Prof>
+void ExpectOneWayEquality(ConformanceErrors* errors,
+ absl::string_view test_name,
+ absl::string_view context, const T& lhs, const T& rhs,
+ absl::string_view lhs_name,
+ absl::string_view rhs_name) {
+ If<PropertiesOfT<Prof>::is_equality_comparable>::Invoke(
+ ExpectEq{errors}, test_name, context, lhs, rhs, lhs_name, rhs_name);
+
+ If<PropertiesOfT<Prof>::is_inequality_comparable>::Invoke(
+ ExpectNotNe{errors}, test_name, context, lhs, rhs, lhs_name, rhs_name);
+
+ If<PropertiesOfT<Prof>::is_less_than_comparable>::Invoke(
+ ExpectNotLt{errors}, test_name, context, lhs, rhs, lhs_name, rhs_name);
+
+ If<PropertiesOfT<Prof>::is_less_equal_comparable>::Invoke(
+ ExpectLe{errors}, test_name, context, lhs, rhs, lhs_name, rhs_name);
+
+ If<PropertiesOfT<Prof>::is_greater_equal_comparable>::Invoke(
+ ExpectGe{errors}, test_name, context, lhs, rhs, lhs_name, rhs_name);
+
+ If<PropertiesOfT<Prof>::is_greater_than_comparable>::Invoke(
+ ExpectNotGt{errors}, test_name, context, lhs, rhs, lhs_name, rhs_name);
+
+ If<PropertiesOfT<Prof>::is_hashable>::Invoke(
+ ExpectSameHash{errors}, test_name, context, lhs, rhs, lhs_name, rhs_name);
+}
+
+// A function template that takes two objects and verifies that each comparison
+// operator behaves in a way that is consistent with equality. This function
+// differs from ExpectOneWayEquality in that this will do checks with argument
+// order reversed in addition to in-order.
+template <class T, class Prof>
+void ExpectEquality(ConformanceErrors* errors, absl::string_view test_name,
+ absl::string_view context, const T& lhs, const T& rhs,
+ absl::string_view lhs_name, absl::string_view rhs_name) {
+ (ExpectOneWayEquality<T, Prof>)(errors, test_name, context, lhs, rhs,
+ lhs_name, rhs_name);
+ (ExpectOneWayEquality<T, Prof>)(errors, test_name, context, rhs, lhs,
+ rhs_name, lhs_name);
+}
+
+// Given a generator, makes sure that a generated value and a moved-from
+// generated value are equal.
+template <class T, class Prof>
+struct ExpectMoveConstructOneGenerator {
+ template <class Fun>
+ void operator()(const Fun& generator) const {
+ const T object = generator();
+ const T moved_object = absl::move(generator()); // Force no elision.
+
+ (ExpectEquality<T, Prof>)(errors, "Move construction",
+ PrepareGivenContext(
+ GivenDeclaration{"const _T object",
+ generator.description},
+ GivenDeclaration{"const _T moved_object",
+ std::string("std::move(") +
+ generator.description +
+ ")"}),
+ object, moved_object, "object", "moved_object");
+ }
+
+ ConformanceErrors* errors;
+};
+
+// Given a generator, makes sure that a generated value and a copied-from
+// generated value are equal.
+template <class T, class Prof>
+struct ExpectCopyConstructOneGenerator {
+ template <class Fun>
+ void operator()(const Fun& generator) const {
+ const T object = generator();
+ const T copied_object = static_cast<const T&>(generator());
+
+ (ExpectEquality<T, Prof>)(errors, "Copy construction",
+ PrepareGivenContext(
+ GivenDeclaration{"const _T object",
+ generator.description},
+ GivenDeclaration{
+ "const _T copied_object",
+ std::string("static_cast<const _T&>(") +
+ generator.description + ")"}),
+ object, copied_object, "object", "copied_object");
+ }
+
+ ConformanceErrors* errors;
+};
+
+// Default-construct and do nothing before destruction.
+//
+// This is useful in exercising the codepath of default construction followed by
+// destruction, but does not explicitly test anything. An example of where this
+// might fail is a default destructor that default-initializes a scalar and a
+// destructor reads the value of that member. Sanitizers can catch this as long
+// as our test attempts to execute such a case.
+template <class T>
+struct ExpectDefaultConstructWithDestruct {
+ void operator()() const {
+ // Scoped so that destructor gets called before reporting success.
+ {
+ T object;
+ static_cast<void>(object);
+ }
+
+ errors->addTestSuccess("Default construction");
+ }
+
+ ConformanceErrors* errors;
+};
+
+// Check move-assign into a default-constructed object.
+template <class T, class Prof>
+struct ExpectDefaultConstructWithMoveAssign {
+ template <class Fun>
+ void operator()(const Fun& generator) const {
+ const T source_of_truth = generator();
+ T object;
+ object = generator();
+
+ (ExpectEquality<T, Prof>)(errors, "Move assignment",
+ PrepareGivenContext(
+ GivenDeclaration{"const _T object",
+ generator.description},
+ GivenDeclaration{"_T object", ""},
+ GivenDeclaration{"object",
+ generator.description}),
+ object, source_of_truth, "std::as_const(object)",
+ "source_of_truth");
+ }
+
+ ConformanceErrors* errors;
+};
+
+// Check copy-assign into a default-constructed object.
+template <class T, class Prof>
+struct ExpectDefaultConstructWithCopyAssign {
+ template <class Fun>
+ void operator()(const Fun& generator) const {
+ const T source_of_truth = generator();
+ T object;
+ object = static_cast<const T&>(generator());
+
+ (ExpectEquality<T, Prof>)(errors, "Copy assignment",
+ PrepareGivenContext(
+ GivenDeclaration{"const _T source_of_truth",
+ generator.description},
+ GivenDeclaration{"_T object", ""},
+ GivenDeclaration{
+ "object",
+ std::string("static_cast<const _T&>(") +
+ generator.description + ")"}),
+ object, source_of_truth, "std::as_const(object)",
+ "source_of_truth");
+ }
+
+ ConformanceErrors* errors;
+};
+
+// Perform a self move-assign.
+template <class T, class Prof>
+struct ExpectSelfMoveAssign {
+ template <class Fun>
+ void operator()(const Fun& generator) const {
+ T object = generator();
+ object = absl::move(object);
+
+ // NOTE: Self move-assign results in a valid-but-unspecified state.
+
+ (ExpectEquality<T, Prof>)(errors, "Move assignment",
+ PrepareGivenContext(
+ GivenDeclaration{"_T object",
+ generator.description},
+ GivenDeclaration{"object",
+ "std::move(object)"}),
+ object, object, "object", "object");
+ }
+
+ ConformanceErrors* errors;
+};
+
+// Perform a self copy-assign.
+template <class T, class Prof>
+struct ExpectSelfCopyAssign {
+ template <class Fun>
+ void operator()(const Fun& generator) const {
+ const T source_of_truth = generator();
+ T object = generator();
+ const T& const_object = object;
+ object = const_object;
+
+ (ExpectEquality<T, Prof>)(errors, "Copy assignment",
+ PrepareGivenContext(
+ GivenDeclaration{"const _T source_of_truth",
+ generator.description},
+ GivenDeclaration{"_T object",
+ generator.description},
+ GivenDeclaration{"object",
+ "std::as_const(object)"}),
+ const_object, source_of_truth,
+ "std::as_const(object)", "source_of_truth");
+ }
+
+ ConformanceErrors* errors;
+};
+
+// Perform a self-swap.
+template <class T, class Prof>
+struct ExpectSelfSwap {
+ template <class Fun>
+ void operator()(const Fun& generator) const {
+ const T source_of_truth = generator();
+ T object = generator();
+
+ type_traits_internal::Swap(object, object);
+
+ std::string preliminary_info = absl::StrCat(
+ PrepareGivenContext(
+ GivenDeclaration{"const _T source_of_truth", generator.description},
+ GivenDeclaration{"_T object", generator.description}),
+ "After performing a self-swap:\n"
+ " using std::swap;\n"
+ " swap(object, object);\n"
+ "\n");
+
+ (ExpectEquality<T, Prof>)(errors, "Swap", std::move(preliminary_info),
+ object, source_of_truth, "std::as_const(object)",
+ "source_of_truth");
+ }
+
+ ConformanceErrors* errors;
+};
+
+// Perform each of the single-generator checks when necessary operations are
+// supported.
+template <class T, class Prof>
+struct ExpectSelfComparison {
+ template <class Fun>
+ void operator()(const Fun& generator) const {
+ const T object = generator();
+ (ExpectOneWayEquality<T, Prof>)(errors, "Comparison",
+ PrepareGivenContext(GivenDeclaration{
+ "const _T object",
+ generator.description}),
+ object, object, "object", "object");
+ }
+
+ ConformanceErrors* errors;
+};
+
+// Perform each of the single-generator checks when necessary operations are
+// supported.
+template <class T, class Prof>
+struct ExpectConsistency {
+ template <class Fun>
+ void operator()(const Fun& generator) const {
+ If<PropertiesOfT<Prof>::is_move_constructible>::Invoke(
+ ExpectMoveConstructOneGenerator<T, Prof>{errors}, generator);
+
+ If<PropertiesOfT<Prof>::is_copy_constructible>::Invoke(
+ ExpectCopyConstructOneGenerator<T, Prof>{errors}, generator);
+
+ If<PropertiesOfT<Prof>::is_default_constructible &&
+ PropertiesOfT<Prof>::is_move_assignable>::
+ Invoke(ExpectDefaultConstructWithMoveAssign<T, Prof>{errors},
+ generator);
+
+ If<PropertiesOfT<Prof>::is_default_constructible &&
+ PropertiesOfT<Prof>::is_copy_assignable>::
+ Invoke(ExpectDefaultConstructWithCopyAssign<T, Prof>{errors},
+ generator);
+
+ If<PropertiesOfT<Prof>::is_move_assignable>::Invoke(
+ ExpectSelfMoveAssign<T, Prof>{errors}, generator);
+
+ If<PropertiesOfT<Prof>::is_copy_assignable>::Invoke(
+ ExpectSelfCopyAssign<T, Prof>{errors}, generator);
+
+ If<PropertiesOfT<Prof>::is_swappable>::Invoke(
+ ExpectSelfSwap<T, Prof>{errors}, generator);
+ }
+
+ ConformanceErrors* errors;
+};
+
+// Check move-assign with two different values.
+template <class T, class Prof>
+struct ExpectMoveAssign {
+ template <class Fun0, class Fun1>
+ void operator()(const Fun0& generator0, const Fun1& generator1) const {
+ const T source_of_truth1 = generator1();
+ T object = generator0();
+ object = generator1();
+
+ (ExpectEquality<T, Prof>)(errors, "Move assignment",
+ PrepareGivenContext(
+ GivenDeclaration{"const _T source_of_truth1",
+ generator1.description},
+ GivenDeclaration{"_T object",
+ generator0.description},
+ GivenDeclaration{"object",
+ generator1.description}),
+ object, source_of_truth1, "std::as_const(object)",
+ "source_of_truth1");
+ }
+
+ ConformanceErrors* errors;
+};
+
+// Check copy-assign with two different values.
+template <class T, class Prof>
+struct ExpectCopyAssign {
+ template <class Fun0, class Fun1>
+ void operator()(const Fun0& generator0, const Fun1& generator1) const {
+ const T source_of_truth1 = generator1();
+ T object = generator0();
+ object = static_cast<const T&>(generator1());
+
+ (ExpectEquality<T, Prof>)(errors, "Copy assignment",
+ PrepareGivenContext(
+ GivenDeclaration{"const _T source_of_truth1",
+ generator1.description},
+ GivenDeclaration{"_T object",
+ generator0.description},
+ GivenDeclaration{
+ "object",
+ std::string("static_cast<const _T&>(") +
+ generator1.description + ")"}),
+ object, source_of_truth1, "std::as_const(object)",
+ "source_of_truth1");
+ }
+
+ ConformanceErrors* errors;
+};
+
+// Check swap with two different values.
+template <class T, class Prof>
+struct ExpectSwap {
+ template <class Fun0, class Fun1>
+ void operator()(const Fun0& generator0, const Fun1& generator1) const {
+ const T source_of_truth0 = generator0();
+ const T source_of_truth1 = generator1();
+ T object0 = generator0();
+ T object1 = generator1();
+
+ type_traits_internal::Swap(object0, object1);
+
+ const std::string context =
+ PrepareGivenContext(
+ GivenDeclaration{"const _T source_of_truth0",
+ generator0.description},
+ GivenDeclaration{"const _T source_of_truth1",
+ generator1.description},
+ GivenDeclaration{"_T object0", generator0.description},
+ GivenDeclaration{"_T object1", generator1.description}) +
+ "After performing a swap:\n"
+ " using std::swap;\n"
+ " swap(object0, object1);\n"
+ "\n";
+
+ (ExpectEquality<T, Prof>)(errors, "Swap", context, object0,
+ source_of_truth1, "std::as_const(object0)",
+ "source_of_truth1");
+ (ExpectEquality<T, Prof>)(errors, "Swap", context, object1,
+ source_of_truth0, "std::as_const(object1)",
+ "source_of_truth0");
+ }
+
+ ConformanceErrors* errors;
+};
+
+// Validate that `generator0` and `generator1` produce values that are equal.
+template <class T, class Prof>
+struct ExpectEquivalenceClassComparison {
+ template <class Fun0, class Fun1>
+ void operator()(const Fun0& generator0, const Fun1& generator1) const {
+ const T object0 = generator0();
+ const T object1 = generator1();
+
+ (ExpectEquality<T, Prof>)(errors, "Comparison",
+ PrepareGivenContext(
+ GivenDeclaration{"const _T object0",
+ generator0.description},
+ GivenDeclaration{"const _T object1",
+ generator1.description}),
+ object0, object1, "object0", "object1");
+ }
+
+ ConformanceErrors* errors;
+};
+
+// Validate that all objects in the same equivalence-class have the same value.
+template <class T, class Prof>
+struct ExpectEquivalenceClassConsistency {
+ template <class Fun0, class Fun1>
+ void operator()(const Fun0& generator0, const Fun1& generator1) const {
+ If<PropertiesOfT<Prof>::is_move_assignable>::Invoke(
+ ExpectMoveAssign<T, Prof>{errors}, generator0, generator1);
+
+ If<PropertiesOfT<Prof>::is_copy_assignable>::Invoke(
+ ExpectCopyAssign<T, Prof>{errors}, generator0, generator1);
+
+ If<PropertiesOfT<Prof>::is_swappable>::Invoke(ExpectSwap<T, Prof>{errors},
+ generator0, generator1);
+ }
+
+ ConformanceErrors* errors;
+};
+
+// Given a "lesser" object and a "greater" object, perform every combination of
+// comparison operators supported for the type, expecting consistent results.
+template <class T, class Prof>
+void ExpectOrdered(ConformanceErrors* errors, absl::string_view context,
+ const T& small, const T& big, absl::string_view small_name,
+ absl::string_view big_name) {
+ const absl::string_view test_name = "Comparison";
+
+ If<PropertiesOfT<Prof>::is_equality_comparable>::Invoke(
+ ExpectNotEq{errors}, test_name, context, small, big, small_name,
+ big_name);
+ If<PropertiesOfT<Prof>::is_equality_comparable>::Invoke(
+ ExpectNotEq{errors}, test_name, context, big, small, big_name,
+ small_name);
+
+ If<PropertiesOfT<Prof>::is_inequality_comparable>::Invoke(
+ ExpectNe{errors}, test_name, context, small, big, small_name, big_name);
+ If<PropertiesOfT<Prof>::is_inequality_comparable>::Invoke(
+ ExpectNe{errors}, test_name, context, big, small, big_name, small_name);
+
+ If<PropertiesOfT<Prof>::is_less_than_comparable>::Invoke(
+ ExpectLt{errors}, test_name, context, small, big, small_name, big_name);
+ If<PropertiesOfT<Prof>::is_less_than_comparable>::Invoke(
+ ExpectNotLt{errors}, test_name, context, big, small, big_name,
+ small_name);
+
+ If<PropertiesOfT<Prof>::is_less_equal_comparable>::Invoke(
+ ExpectLe{errors}, test_name, context, small, big, small_name, big_name);
+ If<PropertiesOfT<Prof>::is_less_equal_comparable>::Invoke(
+ ExpectNotLe{errors}, test_name, context, big, small, big_name,
+ small_name);
+
+ If<PropertiesOfT<Prof>::is_greater_equal_comparable>::Invoke(
+ ExpectNotGe{errors}, test_name, context, small, big, small_name,
+ big_name);
+ If<PropertiesOfT<Prof>::is_greater_equal_comparable>::Invoke(
+ ExpectGe{errors}, test_name, context, big, small, big_name, small_name);
+
+ If<PropertiesOfT<Prof>::is_greater_than_comparable>::Invoke(
+ ExpectNotGt{errors}, test_name, context, small, big, small_name,
+ big_name);
+ If<PropertiesOfT<Prof>::is_greater_than_comparable>::Invoke(
+ ExpectGt{errors}, test_name, context, big, small, big_name, small_name);
+}
+
+// For every two elements of an equivalence class, makes sure that those two
+// elements compare equal, including checks with the same argument passed as
+// both operands.
+template <class T, class Prof>
+struct ExpectEquivalenceClassComparisons {
+ template <class... Funs>
+ void operator()(EquivalenceClassType<Funs...> eq_class) const {
+ (ForEachTupleElement)(ExpectSelfComparison<T, Prof>{errors},
+ eq_class.generators);
+
+ (ForEveryTwo)(ExpectEquivalenceClassComparison<T, Prof>{errors},
+ eq_class.generators);
+ }
+
+ ConformanceErrors* errors;
+};
+
+// For every element of an equivalence class, makes sure that the element is
+// self-consistent (in other words, if any of move/copy/swap are defined,
+// perform those operations and make such that results and operands still
+// compare equal to known values whenever it is required for that operation.
+template <class T, class Prof>
+struct ExpectEquivalenceClass {
+ template <class... Funs>
+ void operator()(EquivalenceClassType<Funs...> eq_class) const {
+ (ForEachTupleElement)(ExpectConsistency<T, Prof>{errors},
+ eq_class.generators);
+
+ (ForEveryTwo)(ExpectEquivalenceClassConsistency<T, Prof>{errors},
+ eq_class.generators);
+ }
+
+ ConformanceErrors* errors;
+};
+
+// Validate that the passed-in argument is a generator of a greater value than
+// the one produced by the "small_gen" datamember with respect to all of the
+// comparison operators that Prof requires, with both argument orders to test.
+template <class T, class Prof, class SmallGenerator>
+struct ExpectBiggerGeneratorThanComparisons {
+ template <class BigGenerator>
+ void operator()(BigGenerator big_gen) const {
+ const T small = small_gen();
+ const T big = big_gen();
+
+ (ExpectOrdered<T, Prof>)(errors,
+ PrepareGivenContext(
+ GivenDeclaration{"const _T small",
+ small_gen.description},
+ GivenDeclaration{"const _T big",
+ big_gen.description}),
+ small, big, "small", "big");
+ }
+
+ SmallGenerator small_gen;
+ ConformanceErrors* errors;
+};
+
+// Perform all of the move, copy, and swap checks on the value generated by
+// `small_gen` and the value generated by `big_gen`.
+template <class T, class Prof, class SmallGenerator>
+struct ExpectBiggerGeneratorThan {
+ template <class BigGenerator>
+ void operator()(BigGenerator big_gen) const {
+ If<PropertiesOfT<Prof>::is_move_assignable>::Invoke(
+ ExpectMoveAssign<T, Prof>{errors}, small_gen, big_gen);
+ If<PropertiesOfT<Prof>::is_move_assignable>::Invoke(
+ ExpectMoveAssign<T, Prof>{errors}, big_gen, small_gen);
+
+ If<PropertiesOfT<Prof>::is_copy_assignable>::Invoke(
+ ExpectCopyAssign<T, Prof>{errors}, small_gen, big_gen);
+ If<PropertiesOfT<Prof>::is_copy_assignable>::Invoke(
+ ExpectCopyAssign<T, Prof>{errors}, big_gen, small_gen);
+
+ If<PropertiesOfT<Prof>::is_swappable>::Invoke(ExpectSwap<T, Prof>{errors},
+ small_gen, big_gen);
+ }
+
+ SmallGenerator small_gen;
+ ConformanceErrors* errors;
+};
+
+// Validate that the result of a generator is greater than the results of all
+// generators in an equivalence class with respect to comparisons.
+template <class T, class Prof, class SmallGenerator>
+struct ExpectBiggerGeneratorThanEqClassesComparisons {
+ template <class BigEqClass>
+ void operator()(BigEqClass big_eq_class) const {
+ (ForEachTupleElement)(
+ ExpectBiggerGeneratorThanComparisons<T, Prof, SmallGenerator>{small_gen,
+ errors},
+ big_eq_class.generators);
+ }
+
+ SmallGenerator small_gen;
+ ConformanceErrors* errors;
+};
+
+// Validate that the non-comparison binary operations required by Prof are
+// correct for the result of each generator of big_eq_class and a generator of
+// the logically smaller value returned by small_gen.
+template <class T, class Prof, class SmallGenerator>
+struct ExpectBiggerGeneratorThanEqClasses {
+ template <class BigEqClass>
+ void operator()(BigEqClass big_eq_class) const {
+ (ForEachTupleElement)(
+ ExpectBiggerGeneratorThan<T, Prof, SmallGenerator>{small_gen, errors},
+ big_eq_class.generators);
+ }
+
+ SmallGenerator small_gen;
+ ConformanceErrors* errors;
+};
+
+// Validate that each equivalence class that is passed is logically less than
+// the equivalence classes that comes later on in the argument list.
+template <class T, class Prof>
+struct ExpectOrderedEquivalenceClassesComparisons {
+ template <class... BigEqClasses>
+ struct Impl {
+ // Validate that the value produced by `small_gen` is less than all of the
+ // values generated by those of the logically larger equivalence classes.
+ template <class SmallGenerator>
+ void operator()(SmallGenerator small_gen) const {
+ (ForEachTupleElement)(ExpectBiggerGeneratorThanEqClassesComparisons<
+ T, Prof, SmallGenerator>{small_gen, errors},
+ big_eq_classes);
+ }
+
+ std::tuple<BigEqClasses...> big_eq_classes;
+ ConformanceErrors* errors;
+ };
+
+ // When given no equivalence classes, no validation is necessary.
+ void operator()() const {}
+
+ template <class SmallEqClass, class... BigEqClasses>
+ void operator()(SmallEqClass small_eq_class,
+ BigEqClasses... big_eq_classes) const {
+ // For each generator in the first equivalence class, make sure that it is
+ // less than each of those in the logically greater equivalence classes.
+ (ForEachTupleElement)(
+ Impl<BigEqClasses...>{std::make_tuple(absl::move(big_eq_classes)...),
+ errors},
+ small_eq_class.generators);
+
+ // Recurse so that all equivalence class combinations are checked.
+ (*this)(absl::move(big_eq_classes)...);
+ }
+
+ ConformanceErrors* errors;
+};
+
+// Validate that the non-comparison binary operations required by Prof are
+// correct for the result of each generator of big_eq_classes and a generator of
+// the logically smaller value returned by small_gen.
+template <class T, class Prof>
+struct ExpectOrderedEquivalenceClasses {
+ template <class... BigEqClasses>
+ struct Impl {
+ template <class SmallGenerator>
+ void operator()(SmallGenerator small_gen) const {
+ (ForEachTupleElement)(
+ ExpectBiggerGeneratorThanEqClasses<T, Prof, SmallGenerator>{small_gen,
+ errors},
+ big_eq_classes);
+ }
+
+ std::tuple<BigEqClasses...> big_eq_classes;
+ ConformanceErrors* errors;
+ };
+
+ // Check that small_eq_class is logically consistent and also is logically
+ // less than all values in big_eq_classes.
+ template <class SmallEqClass, class... BigEqClasses>
+ void operator()(SmallEqClass small_eq_class,
+ BigEqClasses... big_eq_classes) const {
+ (ForEachTupleElement)(
+ Impl<BigEqClasses...>{std::make_tuple(absl::move(big_eq_classes)...),
+ errors},
+ small_eq_class.generators);
+
+ (*this)(absl::move(big_eq_classes)...);
+ }
+
+ // Terminating case of operator().
+ void operator()() const {}
+
+ ConformanceErrors* errors;
+};
+
+// Validate that a type meets the syntactic requirements of std::hash if the
+// range of profiles requires it.
+template <class T, class MinProf, class MaxProf>
+struct ExpectHashable {
+ void operator()() const {
+ ExpectModelOfHashable<T, MinProf, MaxProf>(errors);
+ }
+
+ ConformanceErrors* errors;
+};
+
+// Validate that the type `T` meets all of the requirements associated with
+// `MinProf` and without going beyond the syntactic properties of `MaxProf`.
+template <class T, class MinProf, class MaxProf>
+struct ExpectModels {
+ void operator()(ConformanceErrors* errors) const {
+ ExpectModelOfDefaultConstructible<T, MinProf, MaxProf>(errors);
+ ExpectModelOfMoveConstructible<T, MinProf, MaxProf>(errors);
+ ExpectModelOfCopyConstructible<T, MinProf, MaxProf>(errors);
+ ExpectModelOfMoveAssignable<T, MinProf, MaxProf>(errors);
+ ExpectModelOfCopyAssignable<T, MinProf, MaxProf>(errors);
+ ExpectModelOfDestructible<T, MinProf, MaxProf>(errors);
+ ExpectModelOfEqualityComparable<T, MinProf, MaxProf>(errors);
+ ExpectModelOfInequalityComparable<T, MinProf, MaxProf>(errors);
+ ExpectModelOfLessThanComparable<T, MinProf, MaxProf>(errors);
+ ExpectModelOfLessEqualComparable<T, MinProf, MaxProf>(errors);
+ ExpectModelOfGreaterEqualComparable<T, MinProf, MaxProf>(errors);
+ ExpectModelOfGreaterThanComparable<T, MinProf, MaxProf>(errors);
+ ExpectModelOfSwappable<T, MinProf, MaxProf>(errors);
+
+ // Only check hashability on compilers that have a compliant default-hash.
+ If<!poisoned_hash_fails_instantiation()>::Invoke(
+ ExpectHashable<T, MinProf, MaxProf>{errors});
+ }
+};
+
+// A metafunction that yields a Profile matching the set of properties that are
+// safe to be checked (lack-of-hashability is only checked on standard library
+// implementations that are standards compliant in that they provide a std::hash
+// primary template that is SFINAE-friendly)
+template <class LogicalProf, class T>
+struct MinimalCheckableProfile {
+ using type =
+ MinimalProfiles<PropertiesOfT<LogicalProf>,
+ PropertiesOfT<SyntacticConformanceProfileOf<
+ T, !PropertiesOfT<LogicalProf>::is_hashable &&
+ poisoned_hash_fails_instantiation()
+ ? CheckHashability::no
+ : CheckHashability::yes>>>;
+};
+
+// An identity metafunction
+template <class T>
+struct Always {
+ using type = T;
+};
+
+// Validate the T meets all of the necessary requirements of LogicalProf, with
+// syntactic requirements defined by the profile range [MinProf, MaxProf].
+template <class T, class LogicalProf, class MinProf, class MaxProf,
+ class... EqClasses>
+ConformanceErrors ExpectRegularityImpl(
+ OrderedEquivalenceClasses<EqClasses...> vals) {
+ ConformanceErrors errors((NameOf<T>()));
+
+ If<!constexpr_instantiation_when_unevaluated()>::Invoke(
+ ExpectModels<T, MinProf, MaxProf>(), &errors);
+
+ using minimal_profile = typename absl::conditional_t<
+ constexpr_instantiation_when_unevaluated(), Always<LogicalProf>,
+ MinimalCheckableProfile<LogicalProf, T>>::type;
+
+ If<PropertiesOfT<minimal_profile>::is_default_constructible>::Invoke(
+ ExpectDefaultConstructWithDestruct<T>{&errors});
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Perform all comparison checks first, since later checks depend on their
+ // correctness.
+ //
+ // Check all of the comparisons for all values in the same equivalence
+ // class (equal with respect to comparison operators and hash the same).
+ (ForEachTupleElement)(
+ ExpectEquivalenceClassComparisons<T, minimal_profile>{&errors},
+ vals.eq_classes);
+
+ // Check all of the comparisons for each combination of values that are in
+ // different equivalence classes (not equal with respect to comparison
+ // operators).
+ absl::apply(
+ ExpectOrderedEquivalenceClassesComparisons<T, minimal_profile>{&errors},
+ vals.eq_classes);
+ //
+ //////////////////////////////////////////////////////////////////////////////
+
+ // Perform remaining checks, relying on comparisons.
+ // TODO(calabrese) short circuit if any comparisons above failed.
+ (ForEachTupleElement)(ExpectEquivalenceClass<T, minimal_profile>{&errors},
+ vals.eq_classes);
+
+ absl::apply(ExpectOrderedEquivalenceClasses<T, minimal_profile>{&errors},
+ vals.eq_classes);
+
+ return errors;
+}
+
+// A type that represents a range of profiles that are acceptable to be matched.
+//
+// `MinProf` is the minimum set of syntactic requirements that must be met.
+//
+// `MaxProf` is the maximum set of syntactic requirements that must be met.
+// This maximum is particularly useful for certain "strictness" checking. Some
+// examples for when this is useful:
+//
+// * Making sure that a type is move-only (rather than simply movable)
+//
+// * Making sure that a member function is *not* noexcept in cases where it
+// cannot be noexcept, such as if a dependent datamember has certain
+// operations that are not noexcept.
+//
+// * Making sure that a type tightly matches a spec, such as the standard.
+//
+// `LogicalProf` is the Profile for which run-time testing is to take place.
+//
+// Note: The reason for `LogicalProf` is because it is often the case, when
+// dealing with templates, that a declaration of a given operation is specified,
+// but whose body would fail to instantiate. Examples include the
+// copy-constructor of a standard container when the element-type is move-only,
+// or the comparison operators of a standard container when the element-type
+// does not have the necessary comparison operations defined. The `LogicalProf`
+// parameter allows us to capture the intent of what should be tested at
+// run-time, even in the cases where syntactically it might otherwise appear as
+// though the type undergoing testing supports more than it actually does.
+template <class LogicalProf, class MinProf = LogicalProf,
+ class MaxProf = MinProf>
+struct ProfileRange {
+ using logical_profile = LogicalProf;
+ using min_profile = MinProf;
+ using max_profile = MaxProf;
+};
+
+// Similar to ProfileRange except that it creates a profile range that is
+// coupled with a Domain and is used when testing that a type matches exactly
+// the "minimum" requirements of LogicalProf.
+template <class StrictnessDomain, class LogicalProf,
+ class MinProf = LogicalProf, class MaxProf = MinProf>
+struct StrictProfileRange {
+ // We do not yet support extension.
+ static_assert(
+ std::is_same<StrictnessDomain, RegularityDomain>::value,
+ "Currently, the only valid StrictnessDomain is RegularityDomain.");
+ using strictness_domain = StrictnessDomain;
+ using logical_profile = LogicalProf;
+ using min_profile = MinProf;
+ using max_profile = MaxProf;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A metafunction that creates a StrictProfileRange from a Domain and either a
+// Profile or ProfileRange.
+template <class StrictnessDomain, class ProfOrRange>
+struct MakeStrictProfileRange;
+
+template <class StrictnessDomain, class LogicalProf>
+struct MakeStrictProfileRange {
+ using type = StrictProfileRange<StrictnessDomain, LogicalProf>;
+};
+
+template <class StrictnessDomain, class LogicalProf, class MinProf,
+ class MaxProf>
+struct MakeStrictProfileRange<StrictnessDomain,
+ ProfileRange<LogicalProf, MinProf, MaxProf>> {
+ using type =
+ StrictProfileRange<StrictnessDomain, LogicalProf, MinProf, MaxProf>;
+};
+
+template <class StrictnessDomain, class ProfOrRange>
+using MakeStrictProfileRangeT =
+ typename MakeStrictProfileRange<StrictnessDomain, ProfOrRange>::type;
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// A profile in the RegularityDomain with the strongest possible requirements.
+using MostStrictProfile =
+ CombineProfiles<TriviallyCompleteProfile, NothrowComparableProfile>;
+
+// Forms a ProfileRange that treats the Profile as the bare minimum requirements
+// of a type.
+template <class LogicalProf, class MinProf = LogicalProf>
+using LooseProfileRange = StrictProfileRange<RegularityDomain, LogicalProf,
+ MinProf, MostStrictProfile>;
+
+template <class Prof>
+using MakeLooseProfileRangeT = Prof;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// The following classes implement the metafunction ProfileRangeOfT<T> that
+// takes either a Profile or ProfileRange and yields the ProfileRange to be
+// used during testing.
+//
+template <class T, class /*Enabler*/ = void>
+struct ProfileRangeOfImpl;
+
+template <class T>
+struct ProfileRangeOfImpl<T, absl::void_t<PropertiesOfT<T>>> {
+ using type = LooseProfileRange<T>;
+};
+
+template <class T>
+struct ProfileRangeOf : ProfileRangeOfImpl<T> {};
+
+template <class StrictnessDomain, class LogicalProf, class MinProf,
+ class MaxProf>
+struct ProfileRangeOf<
+ StrictProfileRange<StrictnessDomain, LogicalProf, MinProf, MaxProf>> {
+ using type =
+ StrictProfileRange<StrictnessDomain, LogicalProf, MinProf, MaxProf>;
+};
+
+template <class T>
+using ProfileRangeOfT = typename ProfileRangeOf<T>::type;
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// Extract the logical profile of a range (what will be runtime tested).
+template <class T>
+using LogicalProfileOfT = typename ProfileRangeOfT<T>::logical_profile;
+
+// Extract the minimal syntactic profile of a range (error if not at least).
+template <class T>
+using MinProfileOfT = typename ProfileRangeOfT<T>::min_profile;
+
+// Extract the maximum syntactic profile of a range (error if more than).
+template <class T>
+using MaxProfileOfT = typename ProfileRangeOfT<T>::max_profile;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+template <class T>
+struct IsProfileOrProfileRange : IsProfile<T>::type {};
+
+template <class StrictnessDomain, class LogicalProf, class MinProf,
+ class MaxProf>
+struct IsProfileOrProfileRange<
+ StrictProfileRange<StrictnessDomain, LogicalProf, MinProf, MaxProf>>
+ : std::true_type {};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// TODO(calabrese): Consider naming the functions in this class the same as
+// the macros (defined later on) so that auto-complete leads to the correct name
+// and so that a user cannot accidentally call a function rather than the macro
+// form.
+template <bool ExpectSuccess, class T, class... EqClasses>
+struct ExpectConformanceOf {
+ // Add a value to be tested. Subsequent calls to this function on the same
+ // object must specify logically "larger" values with respect to the
+ // comparison operators of the type, if any.
+ //
+ // NOTE: This function should not be called directly. A stateless lambda is
+ // implicitly formed and passed when using the INITIALIZER macro at the bottom
+ // of this file.
+ template <class Fun,
+ absl::enable_if_t<std::is_same<
+ ResultOfGeneratorT<GeneratorType<Fun>>, T>::value>** = nullptr>
+ ABSL_MUST_USE_RESULT ExpectConformanceOf<ExpectSuccess, T, EqClasses...,
+ EquivalenceClassType<Fun>>
+ initializer(GeneratorType<Fun> fun) && {
+ return {
+ {std::tuple_cat(absl::move(ordered_vals.eq_classes),
+ std::make_tuple((EquivalenceClass)(absl::move(fun))))},
+ std::move(expected_failed_tests)};
+ }
+
+ template <class... TestNames,
+ absl::enable_if_t<!ExpectSuccess && sizeof...(EqClasses) == 0 &&
+ absl::conjunction<std::is_convertible<
+ TestNames, absl::string_view>...>::value>** =
+ nullptr>
+ ABSL_MUST_USE_RESULT ExpectConformanceOf<ExpectSuccess, T, EqClasses...>
+ due_to(TestNames&&... test_names) && {
+ (InsertEach)(&expected_failed_tests,
+ absl::AsciiStrToLower(absl::string_view(test_names))...);
+
+ return {absl::move(ordered_vals), std::move(expected_failed_tests)};
+ }
+
+ template <class... TestNames, int = 0, // MSVC disambiguator
+ absl::enable_if_t<ExpectSuccess && sizeof...(EqClasses) == 0 &&
+ absl::conjunction<std::is_convertible<
+ TestNames, absl::string_view>...>::value>** =
+ nullptr>
+ ABSL_MUST_USE_RESULT ExpectConformanceOf<ExpectSuccess, T, EqClasses...>
+ due_to(TestNames&&... test_names) && {
+ // TODO(calabrese) Instead have DUE_TO only exist via a CRTP base.
+ // This would produce better errors messages than the static_assert.
+ static_assert(!ExpectSuccess,
+ "DUE_TO cannot be called when conformance is expected -- did "
+ "you mean to use ASSERT_NONCONFORMANCE_OF?");
+ }
+
+ // Add a value to be tested. Subsequent calls to this function on the same
+ // object must specify logically "larger" values with respect to the
+ // comparison operators of the type, if any.
+ //
+ // NOTE: This function should not be called directly. A stateful lambda is
+ // implicitly formed and passed when using the INITIALIZER macro at the bottom
+ // of this file.
+ template <class Fun,
+ absl::enable_if_t<std::is_same<
+ ResultOfGeneratorT<GeneratorType<Fun>>, T>::value>** = nullptr>
+ ABSL_MUST_USE_RESULT ExpectConformanceOf<ExpectSuccess, T, EqClasses...,
+ EquivalenceClassType<Fun>>
+ dont_class_directly_stateful_initializer(GeneratorType<Fun> fun) && {
+ return {
+ {std::tuple_cat(absl::move(ordered_vals.eq_classes),
+ std::make_tuple((EquivalenceClass)(absl::move(fun))))},
+ std::move(expected_failed_tests)};
+ }
+
+ // Add a set of value to be tested, where each value is equal with respect to
+ // the comparison operators and std::hash specialization, if defined.
+ template <
+ class... Funs,
+ absl::void_t<absl::enable_if_t<std::is_same<
+ ResultOfGeneratorT<GeneratorType<Funs>>, T>::value>...>** = nullptr>
+ ABSL_MUST_USE_RESULT ExpectConformanceOf<ExpectSuccess, T, EqClasses...,
+ EquivalenceClassType<Funs...>>
+ equivalence_class(GeneratorType<Funs>... funs) && {
+ return {{std::tuple_cat(
+ absl::move(ordered_vals.eq_classes),
+ std::make_tuple((EquivalenceClass)(absl::move(funs)...)))},
+ std::move(expected_failed_tests)};
+ }
+
+ // Execute the tests for the captured set of values, strictly matching a range
+ // of expected profiles in a given domain.
+ template <
+ class ProfRange,
+ absl::enable_if_t<IsProfileOrProfileRange<ProfRange>::value>** = nullptr>
+ ABSL_MUST_USE_RESULT ::testing::AssertionResult with_strict_profile(
+ ProfRange /*profile*/) {
+ ConformanceErrors test_result =
+ (ExpectRegularityImpl<
+ T, LogicalProfileOfT<ProfRange>, MinProfileOfT<ProfRange>,
+ MaxProfileOfT<ProfRange>>)(absl::move(ordered_vals));
+
+ return ExpectSuccess ? test_result.assertionResult()
+ : test_result.expectFailedTests(expected_failed_tests);
+ }
+
+ // Execute the tests for the captured set of values, loosely matching a range
+ // of expected profiles (loose in that an interface is allowed to be more
+ // refined that a profile suggests, such as a type having a noexcept copy
+ // constructor when all that is required is that the copy constructor exists).
+ template <class Prof, absl::enable_if_t<IsProfile<Prof>::value>** = nullptr>
+ ABSL_MUST_USE_RESULT ::testing::AssertionResult with_loose_profile(
+ Prof /*profile*/) {
+ ConformanceErrors test_result =
+ (ExpectRegularityImpl<
+ T, Prof, Prof,
+ CombineProfiles<TriviallyCompleteProfile,
+ NothrowComparableProfile>>)(absl::
+ move(ordered_vals));
+
+ return ExpectSuccess ? test_result.assertionResult()
+ : test_result.expectFailedTests(expected_failed_tests);
+ }
+
+ OrderedEquivalenceClasses<EqClasses...> ordered_vals;
+ std::set<std::string> expected_failed_tests;
+};
+
+template <class T>
+using ExpectConformanceOfType = ExpectConformanceOf</*ExpectSuccess=*/true, T>;
+
+template <class T>
+using ExpectNonconformanceOfType =
+ ExpectConformanceOf</*ExpectSuccess=*/false, T>;
+
+struct EquivalenceClassMaker {
+ // TODO(calabrese) Constrain to callable
+ template <class Fun>
+ static GeneratorType<Fun> initializer(GeneratorType<Fun> fun) {
+ return fun;
+ }
+};
+
+// A top-level macro that begins the builder pattern.
+//
+// The argument here takes the datatype to be tested.
+#define ABSL_INTERNAL_ASSERT_CONFORMANCE_OF(...) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if ABSL_INTERNAL_LPAREN \
+ const ::testing::AssertionResult gtest_ar = \
+ ABSL_INTERNAL_LPAREN ::absl::types_internal::ExpectConformanceOfType< \
+ __VA_ARGS__>()
+
+// Akin to ASSERT_CONFORMANCE_OF except that it expects failure and tries to
+// match text.
+#define ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(...) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if ABSL_INTERNAL_LPAREN \
+ const ::testing::AssertionResult gtest_ar = \
+ ABSL_INTERNAL_LPAREN ::absl::types_internal::ExpectNonconformanceOfType< \
+ __VA_ARGS__>()
+
+////////////////////////////////////////////////////////////////////////////////
+// NOTE: The following macros look like they are recursive, but are not (macros
+// cannot recurse). These actually refer to member functions of the same name.
+// This is done intentionally so that a user cannot accidentally invoke a
+// member function of the conformance-testing suite without going through the
+// macro.
+////////////////////////////////////////////////////////////////////////////////
+
+// Specify expected test failures as comma-separated strings.
+#define DUE_TO(...) due_to(__VA_ARGS__)
+
+// Specify a value to be tested.
+//
+// Note: Internally, this takes an expression and turns it into the return value
+// of lambda that captures no data. The expression is stringized during
+// preprocessing so that it can be used in error reports.
+#define INITIALIZER(...) \
+ initializer(::absl::types_internal::Generator( \
+ [] { return __VA_ARGS__; }, ABSL_INTERNAL_STRINGIZE(__VA_ARGS__)))
+
+// Specify a value to be tested.
+//
+// Note: Internally, this takes an expression and turns it into the return value
+// of lambda that captures data by reference. The expression is stringized
+// during preprocessing so that it can be used in error reports.
+#define STATEFUL_INITIALIZER(...) \
+ stateful_initializer(::absl::types_internal::Generator( \
+ [&] { return __VA_ARGS__; }, ABSL_INTERNAL_STRINGIZE(__VA_ARGS__)))
+
+// Used in the builder-pattern.
+//
+// Takes a series of INITIALIZER and/or STATEFUL_INITIALIZER invocations and
+// forwards them along to be tested, grouping them such that the testing suite
+// knows that they are supposed to represent the same logical value (the values
+// compare the same, hash the same, etc.).
+#define EQUIVALENCE_CLASS(...) \
+ equivalence_class(ABSL_INTERNAL_TRANSFORM_ARGS( \
+ ABSL_INTERNAL_PREPEND_EQ_MAKER, __VA_ARGS__))
+
+// An invocation of this or WITH_STRICT_PROFILE must end the builder-pattern.
+// It takes a Profile as its argument.
+//
+// This executes the tests and allows types that are "more referined" than the
+// profile specifies, but not less. For instance, if the Profile specifies
+// noexcept copy-constructiblity, the test will fail if the copy-constructor is
+// not noexcept, however, it will succeed if the copy constructor is trivial.
+//
+// This is useful for testing that a type meets some minimum set of
+// requirements.
+#define WITH_LOOSE_PROFILE(...) \
+ with_loose_profile( \
+ ::absl::types_internal::MakeLooseProfileRangeT<__VA_ARGS__>()) \
+ ABSL_INTERNAL_RPAREN ABSL_INTERNAL_RPAREN; \
+ else GTEST_FATAL_FAILURE_(gtest_ar.failure_message()) // NOLINT
+
+// An invocation of this or WITH_STRICT_PROFILE must end the builder-pattern.
+// It takes a Domain and a Profile as its arguments.
+//
+// This executes the tests and disallows types that differ at all from the
+// properties of the Profile. For instance, if the Profile specifies noexcept
+// copy-constructiblity, the test will fail if the copy constructor is trivial.
+//
+// This is useful for testing that a type does not do anything more than a
+// specification requires, such as to minimize things like Hyrum's Law, or more
+// commonly, to prevent a type from being "accidentally" copy-constructible in
+// a way that may produce incorrect results, simply because the user forget to
+// delete that operation.
+#define WITH_STRICT_PROFILE(...) \
+ with_strict_profile( \
+ ::absl::types_internal::MakeStrictProfileRangeT<__VA_ARGS__>()) \
+ ABSL_INTERNAL_RPAREN ABSL_INTERNAL_RPAREN; \
+ else GTEST_FATAL_FAILURE_(gtest_ar.failure_message()) // NOLINT
+
+// Internal macro that is used in the internals of the EDSL when forming
+// equivalence classes.
+#define ABSL_INTERNAL_PREPEND_EQ_MAKER(arg) \
+ ::absl::types_internal::EquivalenceClassMaker().arg
+
+} // namespace types_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_H_
diff --git a/third_party/abseil/absl/types/internal/conformance_testing_helpers.h b/third_party/abseil/absl/types/internal/conformance_testing_helpers.h
new file mode 100644
index 0000000..00775f9
--- /dev/null
+++ b/third_party/abseil/absl/types/internal/conformance_testing_helpers.h
@@ -0,0 +1,391 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_HELPERS_H_
+#define ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_HELPERS_H_
+
+// Checks to determine whether or not we can use abi::__cxa_demangle
+#if (defined(__ANDROID__) || defined(ANDROID)) && !defined(OS_ANDROID)
+#define ABSL_INTERNAL_OS_ANDROID
+#endif
+
+// We support certain compilers only. See demangle.h for details.
+#if defined(OS_ANDROID) && (defined(__i386__) || defined(__x86_64__))
+#define ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE 0
+#elif (__GNUC__ >= 4 || (__GNUC__ >= 3 && __GNUC_MINOR__ >= 4)) && \
+ !defined(__mips__)
+#define ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE 1
+#elif defined(__clang__) && !defined(_MSC_VER)
+#define ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE 1
+#else
+#define ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE 0
+#endif
+
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "absl/meta/type_traits.h"
+#include "absl/strings/string_view.h"
+#include "absl/utility/utility.h"
+
+#if ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE
+#include <cxxabi.h>
+
+#include <cstdlib>
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace types_internal {
+
+// Return a readable name for type T.
+template <class T>
+absl::string_view NameOfImpl() {
+// TODO(calabrese) Investigate using debugging:internal_demangle as a fallback.
+#if ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE
+ int status = 0;
+ char* demangled_name = nullptr;
+
+ demangled_name =
+ abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, &status);
+
+ if (status == 0 && demangled_name != nullptr) {
+ return demangled_name;
+ } else {
+ return typeid(T).name();
+ }
+#else
+ return typeid(T).name();
+#endif
+ // NOTE: We intentionally leak demangled_name so that it remains valid
+ // throughout the remainder of the program.
+}
+
+// Given a type, returns as nice of a type name as we can produce (demangled).
+//
+// Note: This currently strips cv-qualifiers and references, but that is okay
+// because we only use this internally with unqualified object types.
+template <class T>
+std::string NameOf() {
+ static const absl::string_view result = NameOfImpl<T>();
+ return std::string(result);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Metafunction to check if a type is callable with no explicit arguments
+template <class Fun, class /*Enabler*/ = void>
+struct IsNullaryCallableImpl : std::false_type {};
+
+template <class Fun>
+struct IsNullaryCallableImpl<
+ Fun, absl::void_t<decltype(std::declval<const Fun&>()())>>
+ : std::true_type {
+ using result_type = decltype(std::declval<const Fun&>()());
+
+ template <class ValueType>
+ using for_type = std::is_same<ValueType, result_type>;
+
+ using void_if_true = void;
+};
+
+template <class Fun>
+struct IsNullaryCallable : IsNullaryCallableImpl<Fun> {};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// A type that contains a function object that returns an instance of a type
+// that is undergoing conformance testing. This function is required to always
+// return the same value upon invocation.
+template <class Fun>
+struct GeneratorType;
+
+// A type that contains a tuple of GeneratorType<Fun> where each Fun has the
+// same return type. The result of each of the different generators should all
+// be equal values, though the underlying object representation may differ (such
+// as if one returns 0.0 and another return -0.0, or if one returns an empty
+// vector and another returns an empty vector with a different capacity.
+template <class... Funs>
+struct EquivalenceClassType;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A metafunction to check if a type is a specialization of EquivalenceClassType
+template <class T>
+struct IsEquivalenceClass : std::false_type {};
+
+template <>
+struct IsEquivalenceClass<EquivalenceClassType<>> : std::true_type {
+ using self = IsEquivalenceClass;
+
+ // A metafunction to check if this EquivalenceClassType is a valid
+ // EquivalenceClassType for a type `ValueType` that is undergoing testing
+ template <class ValueType>
+ using for_type = std::true_type;
+};
+
+template <class Head, class... Tail>
+struct IsEquivalenceClass<EquivalenceClassType<Head, Tail...>>
+ : std::true_type {
+ using self = IsEquivalenceClass;
+
+ // The type undergoing conformance testing that this EquivalenceClass
+ // corresponds to
+ using result_type = typename IsNullaryCallable<Head>::result_type;
+
+ // A metafunction to check if this EquivalenceClassType is a valid
+ // EquivalenceClassType for a type `ValueType` that is undergoing testing
+ template <class ValueType>
+ using for_type = std::is_same<ValueType, result_type>;
+};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// A type that contains an ordered series of EquivalenceClassTypes, where the
+// the function object of each underlying GeneratorType has the same return type
+//
+// These equivalence classes are required to be in a logical ascending order
+// that is consistent with comparison operators that are defined for the return
+// type of each GeneratorType, if any.
+template <class... EqClasses>
+struct OrderedEquivalenceClasses;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A metafunction to determine the return type of the function object contained
+// in a GeneratorType specialization.
+template <class T>
+struct ResultOfGenerator {};
+
+template <class Fun>
+struct ResultOfGenerator<GeneratorType<Fun>> {
+ using type = decltype(std::declval<const Fun&>()());
+};
+
+template <class Fun>
+using ResultOfGeneratorT = typename ResultOfGenerator<GeneratorType<Fun>>::type;
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A metafunction that yields true iff each of Funs is a GeneratorType
+// specialization and they all contain functions with the same return type
+template <class /*Enabler*/, class... Funs>
+struct AreGeneratorsWithTheSameReturnTypeImpl : std::false_type {};
+
+template <>
+struct AreGeneratorsWithTheSameReturnTypeImpl<void> : std::true_type {};
+
+template <class Head, class... Tail>
+struct AreGeneratorsWithTheSameReturnTypeImpl<
+ typename std::enable_if<absl::conjunction<std::is_same<
+ ResultOfGeneratorT<Head>, ResultOfGeneratorT<Tail>>...>::value>::type,
+ Head, Tail...> : std::true_type {};
+
+template <class... Funs>
+struct AreGeneratorsWithTheSameReturnType
+ : AreGeneratorsWithTheSameReturnTypeImpl<void, Funs...>::type {};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A metafunction that yields true iff each of Funs is an EquivalenceClassType
+// specialization and they all contain GeneratorType specializations that have
+// the same return type
+template <class... EqClasses>
+struct AreEquivalenceClassesOfTheSameType {
+ static_assert(sizeof...(EqClasses) != sizeof...(EqClasses), "");
+};
+
+template <>
+struct AreEquivalenceClassesOfTheSameType<> : std::true_type {
+ using self = AreEquivalenceClassesOfTheSameType;
+
+ // Metafunction to check that a type is the same as all of the equivalence
+ // classes, if any.
+ // Note: In this specialization there are no equivalence classes, so the
+ // value type is always compatible.
+ template <class /*ValueType*/>
+ using for_type = std::true_type;
+};
+
+template <class... Funs>
+struct AreEquivalenceClassesOfTheSameType<EquivalenceClassType<Funs...>>
+ : std::true_type {
+ using self = AreEquivalenceClassesOfTheSameType;
+
+ // Metafunction to check that a type is the same as all of the equivalence
+ // classes, if any.
+ template <class ValueType>
+ using for_type = typename IsEquivalenceClass<
+ EquivalenceClassType<Funs...>>::template for_type<ValueType>;
+};
+
+template <class... TailEqClasses>
+struct AreEquivalenceClassesOfTheSameType<
+ EquivalenceClassType<>, EquivalenceClassType<>, TailEqClasses...>
+ : AreEquivalenceClassesOfTheSameType<TailEqClasses...>::self {};
+
+template <class HeadNextFun, class... TailNextFuns, class... TailEqClasses>
+struct AreEquivalenceClassesOfTheSameType<
+ EquivalenceClassType<>, EquivalenceClassType<HeadNextFun, TailNextFuns...>,
+ TailEqClasses...>
+ : AreEquivalenceClassesOfTheSameType<
+ EquivalenceClassType<HeadNextFun, TailNextFuns...>,
+ TailEqClasses...>::self {};
+
+template <class HeadHeadFun, class... TailHeadFuns, class... TailEqClasses>
+struct AreEquivalenceClassesOfTheSameType<
+ EquivalenceClassType<HeadHeadFun, TailHeadFuns...>, EquivalenceClassType<>,
+ TailEqClasses...>
+ : AreEquivalenceClassesOfTheSameType<
+ EquivalenceClassType<HeadHeadFun, TailHeadFuns...>,
+ TailEqClasses...>::self {};
+
+template <class HeadHeadFun, class... TailHeadFuns, class HeadNextFun,
+ class... TailNextFuns, class... TailEqClasses>
+struct AreEquivalenceClassesOfTheSameType<
+ EquivalenceClassType<HeadHeadFun, TailHeadFuns...>,
+ EquivalenceClassType<HeadNextFun, TailNextFuns...>, TailEqClasses...>
+ : absl::conditional_t<
+ IsNullaryCallable<HeadNextFun>::template for_type<
+ typename IsNullaryCallable<HeadHeadFun>::result_type>::value,
+ AreEquivalenceClassesOfTheSameType<
+ EquivalenceClassType<HeadHeadFun, TailHeadFuns...>,
+ TailEqClasses...>,
+ std::false_type> {};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// Execute a function for each passed-in parameter.
+template <class Fun, class... Cases>
+void ForEachParameter(const Fun& fun, const Cases&... cases) {
+ const std::initializer_list<bool> results = {
+ (static_cast<void>(fun(cases)), true)...};
+
+ (void)results;
+}
+
+// Execute a function on each passed-in parameter (using a bound function).
+template <class Fun>
+struct ForEachParameterFun {
+ template <class... T>
+ void operator()(const T&... cases) const {
+ (ForEachParameter)(fun, cases...);
+ }
+
+ Fun fun;
+};
+
+// Execute a function on each element of a tuple.
+template <class Fun, class Tup>
+void ForEachTupleElement(const Fun& fun, const Tup& tup) {
+ absl::apply(ForEachParameterFun<Fun>{fun}, tup);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Execute a function for each combination of two elements of a tuple, including
+// combinations of an element with itself.
+template <class Fun, class... T>
+struct ForEveryTwoImpl {
+ template <class Lhs>
+ struct WithBoundLhs {
+ template <class Rhs>
+ void operator()(const Rhs& rhs) const {
+ fun(lhs, rhs);
+ }
+
+ Fun fun;
+ Lhs lhs;
+ };
+
+ template <class Lhs>
+ void operator()(const Lhs& lhs) const {
+ (ForEachTupleElement)(WithBoundLhs<Lhs>{fun, lhs}, args);
+ }
+
+ Fun fun;
+ std::tuple<T...> args;
+};
+
+template <class Fun, class... T>
+void ForEveryTwo(const Fun& fun, std::tuple<T...> args) {
+ (ForEachTupleElement)(ForEveryTwoImpl<Fun, T...>{fun, args}, args);
+}
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Insert all values into an associative container
+template<class Container>
+void InsertEach(Container* cont) {
+}
+
+template<class Container, class H, class... T>
+void InsertEach(Container* cont, H&& head, T&&... tail) {
+ cont->insert(head);
+ (InsertEach)(cont, tail...);
+}
+//
+////////////////////////////////////////////////////////////////////////////////
+// A template with a nested "Invoke" static-member-function that executes a
+// passed-in Callable when `Condition` is true, otherwise it ignores the
+// Callable. This is useful for executing a function object with a condition
+// that corresponds to whether or not the Callable can be safely instantiated.
+// It has some overlapping uses with C++17 `if constexpr`.
+template <bool Condition>
+struct If;
+
+template <>
+struct If</*Condition =*/false> {
+ template <class Fun, class... P>
+ static void Invoke(const Fun& /*fun*/, P&&... /*args*/) {}
+};
+
+template <>
+struct If</*Condition =*/true> {
+ template <class Fun, class... P>
+ static void Invoke(const Fun& fun, P&&... args) {
+ // TODO(calabrese) Use std::invoke equivalent instead of function-call.
+ fun(absl::forward<P>(args)...);
+ }
+};
+
+//
+// ABSL_INTERNAL_STRINGIZE(...)
+//
+// This variadic macro transforms its arguments into a c-string literal after
+// expansion.
+//
+// Example:
+//
+// ABSL_INTERNAL_STRINGIZE(std::array<int, 10>)
+//
+// Results in:
+//
+// "std::array<int, 10>"
+#define ABSL_INTERNAL_STRINGIZE(...) ABSL_INTERNAL_STRINGIZE_IMPL((__VA_ARGS__))
+#define ABSL_INTERNAL_STRINGIZE_IMPL(arg) ABSL_INTERNAL_STRINGIZE_IMPL2 arg
+#define ABSL_INTERNAL_STRINGIZE_IMPL2(...) #__VA_ARGS__
+
+} // namespace types_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_HELPERS_H_
diff --git a/third_party/abseil/absl/types/internal/conformance_testing_test.cc b/third_party/abseil/absl/types/internal/conformance_testing_test.cc
new file mode 100644
index 0000000..cf262fa
--- /dev/null
+++ b/third_party/abseil/absl/types/internal/conformance_testing_test.cc
@@ -0,0 +1,1556 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/types/internal/conformance_testing.h"
+
+#include <new>
+#include <type_traits>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "absl/meta/type_traits.h"
+#include "absl/types/internal/conformance_aliases.h"
+#include "absl/types/internal/conformance_profile.h"
+
+namespace {
+
+namespace ti = absl::types_internal;
+
+template <class T>
+using DefaultConstructibleWithNewImpl = decltype(::new (std::nothrow) T);
+
+template <class T>
+using DefaultConstructibleWithNew =
+ absl::type_traits_internal::is_detected<DefaultConstructibleWithNewImpl, T>;
+
+template <class T>
+using MoveConstructibleWithNewImpl =
+ decltype(::new (std::nothrow) T(std::declval<T>()));
+
+template <class T>
+using MoveConstructibleWithNew =
+ absl::type_traits_internal::is_detected<MoveConstructibleWithNewImpl, T>;
+
+template <class T>
+using CopyConstructibleWithNewImpl =
+ decltype(::new (std::nothrow) T(std::declval<const T&>()));
+
+template <class T>
+using CopyConstructibleWithNew =
+ absl::type_traits_internal::is_detected<CopyConstructibleWithNewImpl, T>;
+
+template <class T,
+ class Result =
+ std::integral_constant<bool, noexcept(::new (std::nothrow) T)>>
+using NothrowDefaultConstructibleWithNewImpl =
+ typename std::enable_if<Result::value>::type;
+
+template <class T>
+using NothrowDefaultConstructibleWithNew =
+ absl::type_traits_internal::is_detected<
+ NothrowDefaultConstructibleWithNewImpl, T>;
+
+template <class T,
+ class Result = std::integral_constant<
+ bool, noexcept(::new (std::nothrow) T(std::declval<T>()))>>
+using NothrowMoveConstructibleWithNewImpl =
+ typename std::enable_if<Result::value>::type;
+
+template <class T>
+using NothrowMoveConstructibleWithNew =
+ absl::type_traits_internal::is_detected<NothrowMoveConstructibleWithNewImpl,
+ T>;
+
+template <class T,
+ class Result = std::integral_constant<
+ bool, noexcept(::new (std::nothrow) T(std::declval<const T&>()))>>
+using NothrowCopyConstructibleWithNewImpl =
+ typename std::enable_if<Result::value>::type;
+
+template <class T>
+using NothrowCopyConstructibleWithNew =
+ absl::type_traits_internal::is_detected<NothrowCopyConstructibleWithNewImpl,
+ T>;
+
+// NOTE: ?: is used to verify contextually-convertible to bool and not simply
+// implicit or explicit convertibility.
+#define ABSL_INTERNAL_COMPARISON_OP_EXPR(op) \
+ ((std::declval<const T&>() op std::declval<const T&>()) ? true : true)
+
+#define ABSL_INTERNAL_COMPARISON_OP_TRAIT(name, op) \
+ template <class T> \
+ using name##Impl = decltype(ABSL_INTERNAL_COMPARISON_OP_EXPR(op)); \
+ \
+ template <class T> \
+ using name = absl::type_traits_internal::is_detected<name##Impl, T>; \
+ \
+ template <class T, \
+ class Result = std::integral_constant< \
+ bool, noexcept(ABSL_INTERNAL_COMPARISON_OP_EXPR(op))>> \
+ using Nothrow##name##Impl = typename std::enable_if<Result::value>::type; \
+ \
+ template <class T> \
+ using Nothrow##name = \
+ absl::type_traits_internal::is_detected<Nothrow##name##Impl, T>
+
+ABSL_INTERNAL_COMPARISON_OP_TRAIT(EqualityComparable, ==);
+ABSL_INTERNAL_COMPARISON_OP_TRAIT(InequalityComparable, !=);
+ABSL_INTERNAL_COMPARISON_OP_TRAIT(LessThanComparable, <);
+ABSL_INTERNAL_COMPARISON_OP_TRAIT(LessEqualComparable, <=);
+ABSL_INTERNAL_COMPARISON_OP_TRAIT(GreaterEqualComparable, >=);
+ABSL_INTERNAL_COMPARISON_OP_TRAIT(GreaterThanComparable, >);
+
+#undef ABSL_INTERNAL_COMPARISON_OP_TRAIT
+
+template <class T>
+class ProfileTest : public ::testing::Test {};
+
+TYPED_TEST_SUITE_P(ProfileTest);
+
+TYPED_TEST_P(ProfileTest, HasAppropriateConstructionProperties) {
+ using profile = typename TypeParam::profile;
+ using arch = typename TypeParam::arch;
+ using expected_profile = typename TypeParam::expected_profile;
+
+ using props = ti::PropertiesOfT<profile>;
+ using arch_props = ti::PropertiesOfArchetypeT<arch>;
+ using expected_props = ti::PropertiesOfT<expected_profile>;
+
+ // Make sure all of the properties are as expected.
+ // There are seemingly redundant tests here to make it easier to diagnose
+ // the specifics of the failure if something were to go wrong.
+ EXPECT_TRUE((std::is_same<props, arch_props>::value));
+ EXPECT_TRUE((std::is_same<props, expected_props>::value));
+ EXPECT_TRUE((std::is_same<arch_props, expected_props>::value));
+
+ EXPECT_EQ(props::default_constructible_support,
+ expected_props::default_constructible_support);
+
+ EXPECT_EQ(props::move_constructible_support,
+ expected_props::move_constructible_support);
+
+ EXPECT_EQ(props::copy_constructible_support,
+ expected_props::copy_constructible_support);
+
+ EXPECT_EQ(props::destructible_support, expected_props::destructible_support);
+
+ // Avoid additional error message noise when profile and archetype match with
+ // each other but were not what was expected.
+ if (!std::is_same<props, arch_props>::value) {
+ EXPECT_EQ(arch_props::default_constructible_support,
+ expected_props::default_constructible_support);
+
+ EXPECT_EQ(arch_props::move_constructible_support,
+ expected_props::move_constructible_support);
+
+ EXPECT_EQ(arch_props::copy_constructible_support,
+ expected_props::copy_constructible_support);
+
+ EXPECT_EQ(arch_props::destructible_support,
+ expected_props::destructible_support);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Default constructor checks //
+ //////////////////////////////////////////////////////////////////////////////
+ EXPECT_EQ(props::default_constructible_support,
+ expected_props::default_constructible_support);
+
+ switch (expected_props::default_constructible_support) {
+ case ti::default_constructible::maybe:
+ EXPECT_FALSE(DefaultConstructibleWithNew<arch>::value);
+ EXPECT_FALSE(NothrowDefaultConstructibleWithNew<arch>::value);
+
+ // Standard constructible traits depend on the destructor.
+ if (std::is_destructible<arch>::value) {
+ EXPECT_FALSE(std::is_default_constructible<arch>::value);
+ EXPECT_FALSE(std::is_nothrow_default_constructible<arch>::value);
+ EXPECT_FALSE(absl::is_trivially_default_constructible<arch>::value);
+ }
+ break;
+ case ti::default_constructible::yes:
+ EXPECT_TRUE(DefaultConstructibleWithNew<arch>::value);
+ EXPECT_FALSE(NothrowDefaultConstructibleWithNew<arch>::value);
+
+ // Standard constructible traits depend on the destructor.
+ if (std::is_destructible<arch>::value) {
+ EXPECT_TRUE(std::is_default_constructible<arch>::value);
+ EXPECT_FALSE(std::is_nothrow_default_constructible<arch>::value);
+ EXPECT_FALSE(absl::is_trivially_default_constructible<arch>::value);
+ }
+ break;
+ case ti::default_constructible::nothrow:
+ EXPECT_TRUE(DefaultConstructibleWithNew<arch>::value);
+ EXPECT_TRUE(NothrowDefaultConstructibleWithNew<arch>::value);
+
+ // Standard constructible traits depend on the destructor.
+ if (std::is_destructible<arch>::value) {
+ EXPECT_TRUE(std::is_default_constructible<arch>::value);
+ EXPECT_TRUE(std::is_nothrow_default_constructible<arch>::value);
+ EXPECT_FALSE(absl::is_trivially_default_constructible<arch>::value);
+
+ // Constructor traits also check the destructor.
+ if (std::is_nothrow_destructible<arch>::value) {
+ EXPECT_TRUE(std::is_nothrow_default_constructible<arch>::value);
+ }
+ }
+ break;
+ case ti::default_constructible::trivial:
+ EXPECT_TRUE(DefaultConstructibleWithNew<arch>::value);
+ EXPECT_TRUE(NothrowDefaultConstructibleWithNew<arch>::value);
+
+ // Standard constructible traits depend on the destructor.
+ if (std::is_destructible<arch>::value) {
+ EXPECT_TRUE(std::is_default_constructible<arch>::value);
+ EXPECT_TRUE(std::is_nothrow_default_constructible<arch>::value);
+
+ // Constructor triviality traits require trivially destructible types.
+ if (absl::is_trivially_destructible<arch>::value) {
+ EXPECT_TRUE(absl::is_trivially_default_constructible<arch>::value);
+ }
+ }
+ break;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Move constructor checks //
+ //////////////////////////////////////////////////////////////////////////////
+ EXPECT_EQ(props::move_constructible_support,
+ expected_props::move_constructible_support);
+
+ switch (expected_props::move_constructible_support) {
+ case ti::move_constructible::maybe:
+ EXPECT_FALSE(MoveConstructibleWithNew<arch>::value);
+ EXPECT_FALSE(NothrowMoveConstructibleWithNew<arch>::value);
+
+ // Standard constructible traits depend on the destructor.
+ if (std::is_destructible<arch>::value) {
+ EXPECT_FALSE(std::is_move_constructible<arch>::value);
+ EXPECT_FALSE(std::is_nothrow_move_constructible<arch>::value);
+ EXPECT_FALSE(absl::is_trivially_move_constructible<arch>::value);
+ }
+ break;
+ case ti::move_constructible::yes:
+ EXPECT_TRUE(MoveConstructibleWithNew<arch>::value);
+ EXPECT_FALSE(NothrowMoveConstructibleWithNew<arch>::value);
+
+ // Standard constructible traits depend on the destructor.
+ if (std::is_destructible<arch>::value) {
+ EXPECT_TRUE(std::is_move_constructible<arch>::value);
+ EXPECT_FALSE(std::is_nothrow_move_constructible<arch>::value);
+ EXPECT_FALSE(absl::is_trivially_move_constructible<arch>::value);
+ }
+ break;
+ case ti::move_constructible::nothrow:
+ EXPECT_TRUE(MoveConstructibleWithNew<arch>::value);
+ EXPECT_TRUE(NothrowMoveConstructibleWithNew<arch>::value);
+
+ // Standard constructible traits depend on the destructor.
+ if (std::is_destructible<arch>::value) {
+ EXPECT_TRUE(std::is_move_constructible<arch>::value);
+ EXPECT_TRUE(std::is_nothrow_move_constructible<arch>::value);
+ EXPECT_FALSE(absl::is_trivially_move_constructible<arch>::value);
+
+ // Constructor traits also check the destructor.
+ if (std::is_nothrow_destructible<arch>::value) {
+ EXPECT_TRUE(std::is_nothrow_move_constructible<arch>::value);
+ }
+ }
+ break;
+ case ti::move_constructible::trivial:
+ EXPECT_TRUE(MoveConstructibleWithNew<arch>::value);
+ EXPECT_TRUE(NothrowMoveConstructibleWithNew<arch>::value);
+
+ // Standard constructible traits depend on the destructor.
+ if (std::is_destructible<arch>::value) {
+ EXPECT_TRUE(std::is_move_constructible<arch>::value);
+ EXPECT_TRUE(std::is_nothrow_move_constructible<arch>::value);
+
+ // Constructor triviality traits require trivially destructible types.
+ if (absl::is_trivially_destructible<arch>::value) {
+ EXPECT_TRUE(absl::is_trivially_move_constructible<arch>::value);
+ }
+ }
+ break;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Copy constructor checks //
+ //////////////////////////////////////////////////////////////////////////////
+ EXPECT_EQ(props::copy_constructible_support,
+ expected_props::copy_constructible_support);
+
+ switch (expected_props::copy_constructible_support) {
+ case ti::copy_constructible::maybe:
+ EXPECT_FALSE(CopyConstructibleWithNew<arch>::value);
+ EXPECT_FALSE(NothrowCopyConstructibleWithNew<arch>::value);
+
+ // Standard constructible traits depend on the destructor.
+ if (std::is_destructible<arch>::value) {
+ EXPECT_FALSE(std::is_copy_constructible<arch>::value);
+ EXPECT_FALSE(std::is_nothrow_copy_constructible<arch>::value);
+ EXPECT_FALSE(absl::is_trivially_copy_constructible<arch>::value);
+ }
+ break;
+ case ti::copy_constructible::yes:
+ EXPECT_TRUE(CopyConstructibleWithNew<arch>::value);
+ EXPECT_FALSE(NothrowCopyConstructibleWithNew<arch>::value);
+
+ // Standard constructible traits depend on the destructor.
+ if (std::is_destructible<arch>::value) {
+ EXPECT_TRUE(std::is_copy_constructible<arch>::value);
+ EXPECT_FALSE(std::is_nothrow_copy_constructible<arch>::value);
+ EXPECT_FALSE(absl::is_trivially_copy_constructible<arch>::value);
+ }
+ break;
+ case ti::copy_constructible::nothrow:
+ EXPECT_TRUE(CopyConstructibleWithNew<arch>::value);
+ EXPECT_TRUE(NothrowCopyConstructibleWithNew<arch>::value);
+
+ // Standard constructible traits depend on the destructor.
+ if (std::is_destructible<arch>::value) {
+ EXPECT_TRUE(std::is_copy_constructible<arch>::value);
+ EXPECT_TRUE(std::is_nothrow_copy_constructible<arch>::value);
+ EXPECT_FALSE(absl::is_trivially_copy_constructible<arch>::value);
+
+ // Constructor traits also check the destructor.
+ if (std::is_nothrow_destructible<arch>::value) {
+ EXPECT_TRUE(std::is_nothrow_copy_constructible<arch>::value);
+ }
+ }
+ break;
+ case ti::copy_constructible::trivial:
+ EXPECT_TRUE(CopyConstructibleWithNew<arch>::value);
+ EXPECT_TRUE(NothrowCopyConstructibleWithNew<arch>::value);
+
+ // Standard constructible traits depend on the destructor.
+ if (std::is_destructible<arch>::value) {
+ EXPECT_TRUE(std::is_copy_constructible<arch>::value);
+ EXPECT_TRUE(std::is_nothrow_copy_constructible<arch>::value);
+
+ // Constructor triviality traits require trivially destructible types.
+ if (absl::is_trivially_destructible<arch>::value) {
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<arch>::value);
+ }
+ }
+ break;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Destructible checks //
+ //////////////////////////////////////////////////////////////////////////////
+ EXPECT_EQ(props::destructible_support, expected_props::destructible_support);
+
+ switch (expected_props::destructible_support) {
+ case ti::destructible::maybe:
+ EXPECT_FALSE(std::is_destructible<arch>::value);
+ EXPECT_FALSE(std::is_nothrow_destructible<arch>::value);
+ EXPECT_FALSE(absl::is_trivially_destructible<arch>::value);
+ break;
+ case ti::destructible::yes:
+ EXPECT_TRUE(std::is_destructible<arch>::value);
+ EXPECT_FALSE(std::is_nothrow_destructible<arch>::value);
+ EXPECT_FALSE(absl::is_trivially_destructible<arch>::value);
+ break;
+ case ti::destructible::nothrow:
+ EXPECT_TRUE(std::is_destructible<arch>::value);
+ EXPECT_TRUE(std::is_nothrow_destructible<arch>::value);
+ EXPECT_FALSE(absl::is_trivially_destructible<arch>::value);
+ break;
+ case ti::destructible::trivial:
+ EXPECT_TRUE(std::is_destructible<arch>::value);
+ EXPECT_TRUE(std::is_nothrow_destructible<arch>::value);
+ EXPECT_TRUE(absl::is_trivially_destructible<arch>::value);
+ break;
+ }
+}
+
+TYPED_TEST_P(ProfileTest, HasAppropriateAssignmentProperties) {
+ using profile = typename TypeParam::profile;
+ using arch = typename TypeParam::arch;
+ using expected_profile = typename TypeParam::expected_profile;
+
+ using props = ti::PropertiesOfT<profile>;
+ using arch_props = ti::PropertiesOfArchetypeT<arch>;
+ using expected_props = ti::PropertiesOfT<expected_profile>;
+
+ // Make sure all of the properties are as expected.
+ // There are seemingly redundant tests here to make it easier to diagnose
+ // the specifics of the failure if something were to go wrong.
+ EXPECT_TRUE((std::is_same<props, arch_props>::value));
+ EXPECT_TRUE((std::is_same<props, expected_props>::value));
+ EXPECT_TRUE((std::is_same<arch_props, expected_props>::value));
+
+ EXPECT_EQ(props::move_assignable_support,
+ expected_props::move_assignable_support);
+
+ EXPECT_EQ(props::copy_assignable_support,
+ expected_props::copy_assignable_support);
+
+ // Avoid additional error message noise when profile and archetype match with
+ // each other but were not what was expected.
+ if (!std::is_same<props, arch_props>::value) {
+ EXPECT_EQ(arch_props::move_assignable_support,
+ expected_props::move_assignable_support);
+
+ EXPECT_EQ(arch_props::copy_assignable_support,
+ expected_props::copy_assignable_support);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Move assignment checks //
+ //////////////////////////////////////////////////////////////////////////////
+ EXPECT_EQ(props::move_assignable_support,
+ expected_props::move_assignable_support);
+
+ switch (expected_props::move_assignable_support) {
+ case ti::move_assignable::maybe:
+ EXPECT_FALSE(std::is_move_assignable<arch>::value);
+ EXPECT_FALSE(std::is_nothrow_move_assignable<arch>::value);
+ EXPECT_FALSE(absl::is_trivially_move_assignable<arch>::value);
+ break;
+ case ti::move_assignable::yes:
+ EXPECT_TRUE(std::is_move_assignable<arch>::value);
+ EXPECT_FALSE(std::is_nothrow_move_assignable<arch>::value);
+ EXPECT_FALSE(absl::is_trivially_move_assignable<arch>::value);
+ break;
+ case ti::move_assignable::nothrow:
+ EXPECT_TRUE(std::is_move_assignable<arch>::value);
+ EXPECT_TRUE(std::is_nothrow_move_assignable<arch>::value);
+ EXPECT_FALSE(absl::is_trivially_move_assignable<arch>::value);
+ break;
+ case ti::move_assignable::trivial:
+ EXPECT_TRUE(std::is_move_assignable<arch>::value);
+ EXPECT_TRUE(std::is_nothrow_move_assignable<arch>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<arch>::value);
+ break;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Copy assignment checks //
+ //////////////////////////////////////////////////////////////////////////////
+ EXPECT_EQ(props::copy_assignable_support,
+ expected_props::copy_assignable_support);
+
+ switch (expected_props::copy_assignable_support) {
+ case ti::copy_assignable::maybe:
+ EXPECT_FALSE(std::is_copy_assignable<arch>::value);
+ EXPECT_FALSE(std::is_nothrow_copy_assignable<arch>::value);
+ EXPECT_FALSE(absl::is_trivially_copy_assignable<arch>::value);
+ break;
+ case ti::copy_assignable::yes:
+ EXPECT_TRUE(std::is_copy_assignable<arch>::value);
+ EXPECT_FALSE(std::is_nothrow_copy_assignable<arch>::value);
+ EXPECT_FALSE(absl::is_trivially_copy_assignable<arch>::value);
+ break;
+ case ti::copy_assignable::nothrow:
+ EXPECT_TRUE(std::is_copy_assignable<arch>::value);
+ EXPECT_TRUE(std::is_nothrow_copy_assignable<arch>::value);
+ EXPECT_FALSE(absl::is_trivially_copy_assignable<arch>::value);
+ break;
+ case ti::copy_assignable::trivial:
+ EXPECT_TRUE(std::is_copy_assignable<arch>::value);
+ EXPECT_TRUE(std::is_nothrow_copy_assignable<arch>::value);
+ EXPECT_TRUE(absl::is_trivially_copy_assignable<arch>::value);
+ break;
+ }
+}
+
+TYPED_TEST_P(ProfileTest, HasAppropriateComparisonProperties) {
+ using profile = typename TypeParam::profile;
+ using arch = typename TypeParam::arch;
+ using expected_profile = typename TypeParam::expected_profile;
+
+ using props = ti::PropertiesOfT<profile>;
+ using arch_props = ti::PropertiesOfArchetypeT<arch>;
+ using expected_props = ti::PropertiesOfT<expected_profile>;
+
+ // Make sure all of the properties are as expected.
+ // There are seemingly redundant tests here to make it easier to diagnose
+ // the specifics of the failure if something were to go wrong.
+ EXPECT_TRUE((std::is_same<props, arch_props>::value));
+ EXPECT_TRUE((std::is_same<props, expected_props>::value));
+ EXPECT_TRUE((std::is_same<arch_props, expected_props>::value));
+
+ EXPECT_EQ(props::equality_comparable_support,
+ expected_props::equality_comparable_support);
+
+ EXPECT_EQ(props::inequality_comparable_support,
+ expected_props::inequality_comparable_support);
+
+ EXPECT_EQ(props::less_than_comparable_support,
+ expected_props::less_than_comparable_support);
+
+ EXPECT_EQ(props::less_equal_comparable_support,
+ expected_props::less_equal_comparable_support);
+
+ EXPECT_EQ(props::greater_equal_comparable_support,
+ expected_props::greater_equal_comparable_support);
+
+ EXPECT_EQ(props::greater_than_comparable_support,
+ expected_props::greater_than_comparable_support);
+
+ // Avoid additional error message noise when profile and archetype match with
+ // each other but were not what was expected.
+ if (!std::is_same<props, arch_props>::value) {
+ EXPECT_EQ(arch_props::equality_comparable_support,
+ expected_props::equality_comparable_support);
+
+ EXPECT_EQ(arch_props::inequality_comparable_support,
+ expected_props::inequality_comparable_support);
+
+ EXPECT_EQ(arch_props::less_than_comparable_support,
+ expected_props::less_than_comparable_support);
+
+ EXPECT_EQ(arch_props::less_equal_comparable_support,
+ expected_props::less_equal_comparable_support);
+
+ EXPECT_EQ(arch_props::greater_equal_comparable_support,
+ expected_props::greater_equal_comparable_support);
+
+ EXPECT_EQ(arch_props::greater_than_comparable_support,
+ expected_props::greater_than_comparable_support);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Equality comparable checks //
+ //////////////////////////////////////////////////////////////////////////////
+ switch (expected_props::equality_comparable_support) {
+ case ti::equality_comparable::maybe:
+ EXPECT_FALSE(EqualityComparable<arch>::value);
+ EXPECT_FALSE(NothrowEqualityComparable<arch>::value);
+ break;
+ case ti::equality_comparable::yes:
+ EXPECT_TRUE(EqualityComparable<arch>::value);
+ EXPECT_FALSE(NothrowEqualityComparable<arch>::value);
+ break;
+ case ti::equality_comparable::nothrow:
+ EXPECT_TRUE(EqualityComparable<arch>::value);
+ EXPECT_TRUE(NothrowEqualityComparable<arch>::value);
+ break;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Inequality comparable checks //
+ //////////////////////////////////////////////////////////////////////////////
+ switch (expected_props::inequality_comparable_support) {
+ case ti::inequality_comparable::maybe:
+ EXPECT_FALSE(InequalityComparable<arch>::value);
+ EXPECT_FALSE(NothrowInequalityComparable<arch>::value);
+ break;
+ case ti::inequality_comparable::yes:
+ EXPECT_TRUE(InequalityComparable<arch>::value);
+ EXPECT_FALSE(NothrowInequalityComparable<arch>::value);
+ break;
+ case ti::inequality_comparable::nothrow:
+ EXPECT_TRUE(InequalityComparable<arch>::value);
+ EXPECT_TRUE(NothrowInequalityComparable<arch>::value);
+ break;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Less than comparable checks //
+ //////////////////////////////////////////////////////////////////////////////
+ switch (expected_props::less_than_comparable_support) {
+ case ti::less_than_comparable::maybe:
+ EXPECT_FALSE(LessThanComparable<arch>::value);
+ EXPECT_FALSE(NothrowLessThanComparable<arch>::value);
+ break;
+ case ti::less_than_comparable::yes:
+ EXPECT_TRUE(LessThanComparable<arch>::value);
+ EXPECT_FALSE(NothrowLessThanComparable<arch>::value);
+ break;
+ case ti::less_than_comparable::nothrow:
+ EXPECT_TRUE(LessThanComparable<arch>::value);
+ EXPECT_TRUE(NothrowLessThanComparable<arch>::value);
+ break;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Less equal comparable checks //
+ //////////////////////////////////////////////////////////////////////////////
+ switch (expected_props::less_equal_comparable_support) {
+ case ti::less_equal_comparable::maybe:
+ EXPECT_FALSE(LessEqualComparable<arch>::value);
+ EXPECT_FALSE(NothrowLessEqualComparable<arch>::value);
+ break;
+ case ti::less_equal_comparable::yes:
+ EXPECT_TRUE(LessEqualComparable<arch>::value);
+ EXPECT_FALSE(NothrowLessEqualComparable<arch>::value);
+ break;
+ case ti::less_equal_comparable::nothrow:
+ EXPECT_TRUE(LessEqualComparable<arch>::value);
+ EXPECT_TRUE(NothrowLessEqualComparable<arch>::value);
+ break;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Greater equal comparable checks //
+ //////////////////////////////////////////////////////////////////////////////
+ switch (expected_props::greater_equal_comparable_support) {
+ case ti::greater_equal_comparable::maybe:
+ EXPECT_FALSE(GreaterEqualComparable<arch>::value);
+ EXPECT_FALSE(NothrowGreaterEqualComparable<arch>::value);
+ break;
+ case ti::greater_equal_comparable::yes:
+ EXPECT_TRUE(GreaterEqualComparable<arch>::value);
+ EXPECT_FALSE(NothrowGreaterEqualComparable<arch>::value);
+ break;
+ case ti::greater_equal_comparable::nothrow:
+ EXPECT_TRUE(GreaterEqualComparable<arch>::value);
+ EXPECT_TRUE(NothrowGreaterEqualComparable<arch>::value);
+ break;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Greater than comparable checks //
+ //////////////////////////////////////////////////////////////////////////////
+ switch (expected_props::greater_than_comparable_support) {
+ case ti::greater_than_comparable::maybe:
+ EXPECT_FALSE(GreaterThanComparable<arch>::value);
+ EXPECT_FALSE(NothrowGreaterThanComparable<arch>::value);
+ break;
+ case ti::greater_than_comparable::yes:
+ EXPECT_TRUE(GreaterThanComparable<arch>::value);
+ EXPECT_FALSE(NothrowGreaterThanComparable<arch>::value);
+ break;
+ case ti::greater_than_comparable::nothrow:
+ EXPECT_TRUE(GreaterThanComparable<arch>::value);
+ EXPECT_TRUE(NothrowGreaterThanComparable<arch>::value);
+ break;
+ }
+}
+
+TYPED_TEST_P(ProfileTest, HasAppropriateAuxilliaryProperties) {
+ using profile = typename TypeParam::profile;
+ using arch = typename TypeParam::arch;
+ using expected_profile = typename TypeParam::expected_profile;
+
+ using props = ti::PropertiesOfT<profile>;
+ using arch_props = ti::PropertiesOfArchetypeT<arch>;
+ using expected_props = ti::PropertiesOfT<expected_profile>;
+
+ // Make sure all of the properties are as expected.
+ // There are seemingly redundant tests here to make it easier to diagnose
+ // the specifics of the failure if something were to go wrong.
+ EXPECT_TRUE((std::is_same<props, arch_props>::value));
+ EXPECT_TRUE((std::is_same<props, expected_props>::value));
+ EXPECT_TRUE((std::is_same<arch_props, expected_props>::value));
+
+ EXPECT_EQ(props::swappable_support, expected_props::swappable_support);
+
+ EXPECT_EQ(props::hashable_support, expected_props::hashable_support);
+
+ // Avoid additional error message noise when profile and archetype match with
+ // each other but were not what was expected.
+ if (!std::is_same<props, arch_props>::value) {
+ EXPECT_EQ(arch_props::swappable_support, expected_props::swappable_support);
+
+ EXPECT_EQ(arch_props::hashable_support, expected_props::hashable_support);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Swappable checks //
+ //////////////////////////////////////////////////////////////////////////////
+ switch (expected_props::swappable_support) {
+ case ti::swappable::maybe:
+ EXPECT_FALSE(absl::type_traits_internal::IsSwappable<arch>::value);
+ EXPECT_FALSE(absl::type_traits_internal::IsNothrowSwappable<arch>::value);
+ break;
+ case ti::swappable::yes:
+ EXPECT_TRUE(absl::type_traits_internal::IsSwappable<arch>::value);
+ EXPECT_FALSE(absl::type_traits_internal::IsNothrowSwappable<arch>::value);
+ break;
+ case ti::swappable::nothrow:
+ EXPECT_TRUE(absl::type_traits_internal::IsSwappable<arch>::value);
+ EXPECT_TRUE(absl::type_traits_internal::IsNothrowSwappable<arch>::value);
+ break;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Hashable checks //
+ //////////////////////////////////////////////////////////////////////////////
+ switch (expected_props::hashable_support) {
+ case ti::hashable::maybe:
+#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
+ EXPECT_FALSE(absl::type_traits_internal::IsHashable<arch>::value);
+#endif // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
+ break;
+ case ti::hashable::yes:
+ EXPECT_TRUE(absl::type_traits_internal::IsHashable<arch>::value);
+ break;
+ }
+}
+
+REGISTER_TYPED_TEST_SUITE_P(ProfileTest, HasAppropriateConstructionProperties,
+ HasAppropriateAssignmentProperties,
+ HasAppropriateComparisonProperties,
+ HasAppropriateAuxilliaryProperties);
+
+template <class Profile, class Arch, class ExpectedProfile>
+struct ProfileAndExpectation {
+ using profile = Profile;
+ using arch = Arch;
+ using expected_profile = ExpectedProfile;
+};
+
+using CoreProfilesToTest = ::testing::Types<
+ // The terminating case of combine (all properties are "maybe").
+ ProfileAndExpectation<ti::CombineProfiles<>,
+ ti::Archetype<ti::CombineProfiles<>>,
+ ti::ConformanceProfile<>>,
+
+ // Core default constructor profiles
+ ProfileAndExpectation<
+ ti::HasDefaultConstructorProfile, ti::HasDefaultConstructorArchetype,
+ ti::ConformanceProfile<ti::default_constructible::yes>>,
+ ProfileAndExpectation<
+ ti::HasNothrowDefaultConstructorProfile,
+ ti::HasNothrowDefaultConstructorArchetype,
+ ti::ConformanceProfile<ti::default_constructible::nothrow>>,
+ ProfileAndExpectation<
+ ti::HasTrivialDefaultConstructorProfile,
+ ti::HasTrivialDefaultConstructorArchetype,
+ ti::ConformanceProfile<ti::default_constructible::trivial>>,
+
+ // Core move constructor profiles
+ ProfileAndExpectation<
+ ti::HasMoveConstructorProfile, ti::HasMoveConstructorArchetype,
+ ti::ConformanceProfile<ti::default_constructible::maybe,
+ ti::move_constructible::yes>>,
+ ProfileAndExpectation<
+ ti::HasNothrowMoveConstructorProfile,
+ ti::HasNothrowMoveConstructorArchetype,
+ ti::ConformanceProfile<ti::default_constructible::maybe,
+ ti::move_constructible::nothrow>>,
+ ProfileAndExpectation<
+ ti::HasTrivialMoveConstructorProfile,
+ ti::HasTrivialMoveConstructorArchetype,
+ ti::ConformanceProfile<ti::default_constructible::maybe,
+ ti::move_constructible::trivial>>,
+
+ // Core copy constructor profiles
+ ProfileAndExpectation<
+ ti::HasCopyConstructorProfile, ti::HasCopyConstructorArchetype,
+ ti::ConformanceProfile<ti::default_constructible::maybe,
+ ti::move_constructible::maybe,
+ ti::copy_constructible::yes>>,
+ ProfileAndExpectation<
+ ti::HasNothrowCopyConstructorProfile,
+ ti::HasNothrowCopyConstructorArchetype,
+ ti::ConformanceProfile<ti::default_constructible::maybe,
+ ti::move_constructible::maybe,
+ ti::copy_constructible::nothrow>>,
+ ProfileAndExpectation<
+ ti::HasTrivialCopyConstructorProfile,
+ ti::HasTrivialCopyConstructorArchetype,
+ ti::ConformanceProfile<ti::default_constructible::maybe,
+ ti::move_constructible::maybe,
+ ti::copy_constructible::trivial>>,
+
+ // Core move assignment profiles
+ ProfileAndExpectation<
+ ti::HasMoveAssignProfile, ti::HasMoveAssignArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::yes>>,
+ ProfileAndExpectation<
+ ti::HasNothrowMoveAssignProfile, ti::HasNothrowMoveAssignArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::nothrow>>,
+ ProfileAndExpectation<
+ ti::HasTrivialMoveAssignProfile, ti::HasTrivialMoveAssignArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::trivial>>,
+
+ // Core copy assignment profiles
+ ProfileAndExpectation<
+ ti::HasCopyAssignProfile, ti::HasCopyAssignArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::yes>>,
+ ProfileAndExpectation<
+ ti::HasNothrowCopyAssignProfile, ti::HasNothrowCopyAssignArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::nothrow>>,
+ ProfileAndExpectation<
+ ti::HasTrivialCopyAssignProfile, ti::HasTrivialCopyAssignArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::trivial>>,
+
+ // Core destructor profiles
+ ProfileAndExpectation<
+ ti::HasDestructorProfile, ti::HasDestructorArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::yes>>,
+ ProfileAndExpectation<
+ ti::HasNothrowDestructorProfile, ti::HasNothrowDestructorArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::nothrow>>,
+ ProfileAndExpectation<
+ ti::HasTrivialDestructorProfile, ti::HasTrivialDestructorArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::trivial>>,
+
+ // Core equality comparable profiles
+ ProfileAndExpectation<
+ ti::HasEqualityProfile, ti::HasEqualityArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::maybe,
+ ti::equality_comparable::yes>>,
+ ProfileAndExpectation<
+ ti::HasNothrowEqualityProfile, ti::HasNothrowEqualityArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::maybe,
+ ti::equality_comparable::nothrow>>,
+
+ // Core inequality comparable profiles
+ ProfileAndExpectation<
+ ti::HasInequalityProfile, ti::HasInequalityArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::maybe,
+ ti::equality_comparable::maybe, ti::inequality_comparable::yes>>,
+ ProfileAndExpectation<
+ ti::HasNothrowInequalityProfile, ti::HasNothrowInequalityArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::maybe,
+ ti::equality_comparable::maybe,
+ ti::inequality_comparable::nothrow>>,
+
+ // Core less than comparable profiles
+ ProfileAndExpectation<
+ ti::HasLessThanProfile, ti::HasLessThanArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::maybe,
+ ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+ ti::less_than_comparable::yes>>,
+ ProfileAndExpectation<
+ ti::HasNothrowLessThanProfile, ti::HasNothrowLessThanArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::maybe,
+ ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+ ti::less_than_comparable::nothrow>>,
+
+ // Core less equal comparable profiles
+ ProfileAndExpectation<
+ ti::HasLessEqualProfile, ti::HasLessEqualArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::maybe,
+ ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+ ti::less_than_comparable::maybe, ti::less_equal_comparable::yes>>,
+ ProfileAndExpectation<
+ ti::HasNothrowLessEqualProfile, ti::HasNothrowLessEqualArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::maybe,
+ ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+ ti::less_than_comparable::maybe,
+ ti::less_equal_comparable::nothrow>>,
+
+ // Core greater equal comparable profiles
+ ProfileAndExpectation<
+ ti::HasGreaterEqualProfile, ti::HasGreaterEqualArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::maybe,
+ ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+ ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+ ti::greater_equal_comparable::yes>>,
+ ProfileAndExpectation<
+ ti::HasNothrowGreaterEqualProfile, ti::HasNothrowGreaterEqualArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::maybe,
+ ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+ ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+ ti::greater_equal_comparable::nothrow>>,
+
+ // Core greater than comparable profiles
+ ProfileAndExpectation<
+ ti::HasGreaterThanProfile, ti::HasGreaterThanArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::maybe,
+ ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+ ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+ ti::greater_equal_comparable::maybe,
+ ti::greater_than_comparable::yes>>,
+ ProfileAndExpectation<
+ ti::HasNothrowGreaterThanProfile, ti::HasNothrowGreaterThanArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::maybe,
+ ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+ ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+ ti::greater_equal_comparable::maybe,
+ ti::greater_than_comparable::nothrow>>,
+
+ // Core swappable profiles
+ ProfileAndExpectation<
+ ti::HasSwapProfile, ti::HasSwapArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::maybe,
+ ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+ ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+ ti::greater_equal_comparable::maybe,
+ ti::greater_than_comparable::maybe, ti::swappable::yes>>,
+ ProfileAndExpectation<
+ ti::HasNothrowSwapProfile, ti::HasNothrowSwapArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::maybe,
+ ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+ ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+ ti::greater_equal_comparable::maybe,
+ ti::greater_than_comparable::maybe, ti::swappable::nothrow>>,
+
+ // Core hashable profiles
+ ProfileAndExpectation<
+ ti::HasStdHashSpecializationProfile,
+ ti::HasStdHashSpecializationArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::maybe,
+ ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+ ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+ ti::greater_equal_comparable::maybe,
+ ti::greater_than_comparable::maybe, ti::swappable::maybe,
+ ti::hashable::yes>>>;
+
+using CommonProfilesToTest = ::testing::Types<
+ // NothrowMoveConstructible
+ ProfileAndExpectation<
+ ti::NothrowMoveConstructibleProfile,
+ ti::NothrowMoveConstructibleArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::nothrow,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::nothrow>>,
+
+ // CopyConstructible
+ ProfileAndExpectation<
+ ti::CopyConstructibleProfile, ti::CopyConstructibleArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::nothrow,
+ ti::copy_constructible::yes, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::nothrow>>,
+
+ // NothrowMovable
+ ProfileAndExpectation<
+ ti::NothrowMovableProfile, ti::NothrowMovableArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::nothrow,
+ ti::copy_constructible::maybe, ti::move_assignable::nothrow,
+ ti::copy_assignable::maybe, ti::destructible::nothrow,
+ ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+ ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+ ti::greater_equal_comparable::maybe,
+ ti::greater_than_comparable::maybe, ti::swappable::nothrow>>,
+
+ // Value
+ ProfileAndExpectation<
+ ti::ValueProfile, ti::ValueArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::nothrow,
+ ti::copy_constructible::yes, ti::move_assignable::nothrow,
+ ti::copy_assignable::yes, ti::destructible::nothrow,
+ ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+ ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+ ti::greater_equal_comparable::maybe,
+ ti::greater_than_comparable::maybe, ti::swappable::nothrow>>,
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Common but also DefaultConstructible //
+ ////////////////////////////////////////////////////////////////////////////
+
+ // DefaultConstructibleNothrowMoveConstructible
+ ProfileAndExpectation<
+ ti::DefaultConstructibleNothrowMoveConstructibleProfile,
+ ti::DefaultConstructibleNothrowMoveConstructibleArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::yes, ti::move_constructible::nothrow,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::nothrow>>,
+
+ // DefaultConstructibleCopyConstructible
+ ProfileAndExpectation<
+ ti::DefaultConstructibleCopyConstructibleProfile,
+ ti::DefaultConstructibleCopyConstructibleArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::yes, ti::move_constructible::nothrow,
+ ti::copy_constructible::yes, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::nothrow>>,
+
+ // DefaultConstructibleNothrowMovable
+ ProfileAndExpectation<
+ ti::DefaultConstructibleNothrowMovableProfile,
+ ti::DefaultConstructibleNothrowMovableArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::yes, ti::move_constructible::nothrow,
+ ti::copy_constructible::maybe, ti::move_assignable::nothrow,
+ ti::copy_assignable::maybe, ti::destructible::nothrow,
+ ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+ ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+ ti::greater_equal_comparable::maybe,
+ ti::greater_than_comparable::maybe, ti::swappable::nothrow>>,
+
+ // DefaultConstructibleValue
+ ProfileAndExpectation<
+ ti::DefaultConstructibleValueProfile,
+ ti::DefaultConstructibleValueArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::yes, ti::move_constructible::nothrow,
+ ti::copy_constructible::yes, ti::move_assignable::nothrow,
+ ti::copy_assignable::yes, ti::destructible::nothrow,
+ ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+ ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+ ti::greater_equal_comparable::maybe,
+ ti::greater_than_comparable::maybe, ti::swappable::nothrow>>>;
+
+using ComparableHelpersProfilesToTest = ::testing::Types<
+ // Equatable
+ ProfileAndExpectation<
+ ti::EquatableProfile, ti::EquatableArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::maybe,
+ ti::equality_comparable::yes, ti::inequality_comparable::yes>>,
+
+ // Comparable
+ ProfileAndExpectation<
+ ti::ComparableProfile, ti::ComparableArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::maybe,
+ ti::equality_comparable::yes, ti::inequality_comparable::yes,
+ ti::less_than_comparable::yes, ti::less_equal_comparable::yes,
+ ti::greater_equal_comparable::yes,
+ ti::greater_than_comparable::yes>>,
+
+ // NothrowEquatable
+ ProfileAndExpectation<
+ ti::NothrowEquatableProfile, ti::NothrowEquatableArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::maybe,
+ ti::equality_comparable::nothrow,
+ ti::inequality_comparable::nothrow>>,
+
+ // NothrowComparable
+ ProfileAndExpectation<
+ ti::NothrowComparableProfile, ti::NothrowComparableArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::maybe,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::maybe,
+ ti::equality_comparable::nothrow,
+ ti::inequality_comparable::nothrow,
+ ti::less_than_comparable::nothrow,
+ ti::less_equal_comparable::nothrow,
+ ti::greater_equal_comparable::nothrow,
+ ti::greater_than_comparable::nothrow>>>;
+
+using CommonComparableProfilesToTest = ::testing::Types<
+ // ComparableNothrowMoveConstructible
+ ProfileAndExpectation<
+ ti::ComparableNothrowMoveConstructibleProfile,
+ ti::ComparableNothrowMoveConstructibleArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::nothrow,
+ ti::copy_constructible::maybe, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::nothrow,
+ ti::equality_comparable::yes, ti::inequality_comparable::yes,
+ ti::less_than_comparable::yes, ti::less_equal_comparable::yes,
+ ti::greater_equal_comparable::yes,
+ ti::greater_than_comparable::yes>>,
+
+ // ComparableCopyConstructible
+ ProfileAndExpectation<
+ ti::ComparableCopyConstructibleProfile,
+ ti::ComparableCopyConstructibleArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::nothrow,
+ ti::copy_constructible::yes, ti::move_assignable::maybe,
+ ti::copy_assignable::maybe, ti::destructible::nothrow,
+ ti::equality_comparable::yes, ti::inequality_comparable::yes,
+ ti::less_than_comparable::yes, ti::less_equal_comparable::yes,
+ ti::greater_equal_comparable::yes,
+ ti::greater_than_comparable::yes>>,
+
+ // ComparableNothrowMovable
+ ProfileAndExpectation<
+ ti::ComparableNothrowMovableProfile,
+ ti::ComparableNothrowMovableArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::nothrow,
+ ti::copy_constructible::maybe, ti::move_assignable::nothrow,
+ ti::copy_assignable::maybe, ti::destructible::nothrow,
+ ti::equality_comparable::yes, ti::inequality_comparable::yes,
+ ti::less_than_comparable::yes, ti::less_equal_comparable::yes,
+ ti::greater_equal_comparable::yes, ti::greater_than_comparable::yes,
+ ti::swappable::nothrow>>,
+
+ // ComparableValue
+ ProfileAndExpectation<
+ ti::ComparableValueProfile, ti::ComparableValueArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::maybe, ti::move_constructible::nothrow,
+ ti::copy_constructible::yes, ti::move_assignable::nothrow,
+ ti::copy_assignable::yes, ti::destructible::nothrow,
+ ti::equality_comparable::yes, ti::inequality_comparable::yes,
+ ti::less_than_comparable::yes, ti::less_equal_comparable::yes,
+ ti::greater_equal_comparable::yes, ti::greater_than_comparable::yes,
+ ti::swappable::nothrow>>>;
+
+using TrivialProfilesToTest = ::testing::Types<
+ ProfileAndExpectation<
+ ti::TrivialSpecialMemberFunctionsProfile,
+ ti::TrivialSpecialMemberFunctionsArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::trivial, ti::move_constructible::trivial,
+ ti::copy_constructible::trivial, ti::move_assignable::trivial,
+ ti::copy_assignable::trivial, ti::destructible::trivial,
+ ti::equality_comparable::maybe, ti::inequality_comparable::maybe,
+ ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe,
+ ti::greater_equal_comparable::maybe,
+ ti::greater_than_comparable::maybe, ti::swappable::nothrow>>,
+
+ ProfileAndExpectation<
+ ti::TriviallyCompleteProfile, ti::TriviallyCompleteArchetype,
+ ti::ConformanceProfile<
+ ti::default_constructible::trivial, ti::move_constructible::trivial,
+ ti::copy_constructible::trivial, ti::move_assignable::trivial,
+ ti::copy_assignable::trivial, ti::destructible::trivial,
+ ti::equality_comparable::yes, ti::inequality_comparable::yes,
+ ti::less_than_comparable::yes, ti::less_equal_comparable::yes,
+ ti::greater_equal_comparable::yes, ti::greater_than_comparable::yes,
+ ti::swappable::nothrow, ti::hashable::yes>>>;
+
+INSTANTIATE_TYPED_TEST_SUITE_P(Core, ProfileTest, CoreProfilesToTest);
+INSTANTIATE_TYPED_TEST_SUITE_P(Common, ProfileTest, CommonProfilesToTest);
+INSTANTIATE_TYPED_TEST_SUITE_P(ComparableHelpers, ProfileTest,
+ ComparableHelpersProfilesToTest);
+INSTANTIATE_TYPED_TEST_SUITE_P(CommonComparable, ProfileTest,
+ CommonComparableProfilesToTest);
+INSTANTIATE_TYPED_TEST_SUITE_P(Trivial, ProfileTest, TrivialProfilesToTest);
+
+TEST(ConformanceTestingTest, Basic) {
+ using profile = ti::CombineProfiles<ti::TriviallyCompleteProfile,
+ ti::NothrowComparableProfile>;
+
+ using lim = std::numeric_limits<float>;
+
+ ABSL_INTERNAL_ASSERT_CONFORMANCE_OF(float)
+ .INITIALIZER(-lim::infinity())
+ .INITIALIZER(lim::lowest())
+ .INITIALIZER(-1.f)
+ .INITIALIZER(-lim::min())
+ .EQUIVALENCE_CLASS(INITIALIZER(-0.f), INITIALIZER(0.f))
+ .INITIALIZER(lim::min())
+ .INITIALIZER(1.f)
+ .INITIALIZER(lim::max())
+ .INITIALIZER(lim::infinity())
+ .WITH_STRICT_PROFILE(absl::types_internal::RegularityDomain, profile);
+}
+
+struct BadMoveConstruct {
+ BadMoveConstruct() = default;
+ BadMoveConstruct(BadMoveConstruct&& other) noexcept
+ : value(other.value + 1) {}
+ BadMoveConstruct& operator=(BadMoveConstruct&& other) noexcept = default;
+ int value = 0;
+
+ friend bool operator==(BadMoveConstruct const& lhs,
+ BadMoveConstruct const& rhs) {
+ return lhs.value == rhs.value;
+ }
+ friend bool operator!=(BadMoveConstruct const& lhs,
+ BadMoveConstruct const& rhs) {
+ return lhs.value != rhs.value;
+ }
+};
+
+struct BadMoveAssign {
+ BadMoveAssign() = default;
+ BadMoveAssign(BadMoveAssign&& other) noexcept = default;
+ BadMoveAssign& operator=(BadMoveAssign&& other) noexcept {
+ int new_value = other.value + 1;
+ value = new_value;
+ return *this;
+ }
+ int value = 0;
+
+ friend bool operator==(BadMoveAssign const& lhs, BadMoveAssign const& rhs) {
+ return lhs.value == rhs.value;
+ }
+ friend bool operator!=(BadMoveAssign const& lhs, BadMoveAssign const& rhs) {
+ return lhs.value != rhs.value;
+ }
+};
+
+enum class WhichCompIsBad { eq, ne, lt, le, ge, gt };
+
+template <WhichCompIsBad Which>
+struct BadCompare {
+ int value;
+
+ friend bool operator==(BadCompare const& lhs, BadCompare const& rhs) {
+ return Which == WhichCompIsBad::eq ? lhs.value != rhs.value
+ : lhs.value == rhs.value;
+ }
+
+ friend bool operator!=(BadCompare const& lhs, BadCompare const& rhs) {
+ return Which == WhichCompIsBad::ne ? lhs.value == rhs.value
+ : lhs.value != rhs.value;
+ }
+
+ friend bool operator<(BadCompare const& lhs, BadCompare const& rhs) {
+ return Which == WhichCompIsBad::lt ? lhs.value >= rhs.value
+ : lhs.value < rhs.value;
+ }
+
+ friend bool operator<=(BadCompare const& lhs, BadCompare const& rhs) {
+ return Which == WhichCompIsBad::le ? lhs.value > rhs.value
+ : lhs.value <= rhs.value;
+ }
+
+ friend bool operator>=(BadCompare const& lhs, BadCompare const& rhs) {
+ return Which == WhichCompIsBad::ge ? lhs.value < rhs.value
+ : lhs.value >= rhs.value;
+ }
+
+ friend bool operator>(BadCompare const& lhs, BadCompare const& rhs) {
+ return Which == WhichCompIsBad::gt ? lhs.value <= rhs.value
+ : lhs.value > rhs.value;
+ }
+};
+
+TEST(ConformanceTestingDeathTest, Failures) {
+ {
+ using profile = ti::CombineProfiles<ti::TriviallyCompleteProfile,
+ ti::NothrowComparableProfile>;
+
+ // Note: The initializers are intentionally in the wrong order.
+ ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(float)
+ .INITIALIZER(1.f)
+ .INITIALIZER(0.f)
+ .WITH_LOOSE_PROFILE(profile);
+ }
+
+ {
+ using profile =
+ ti::CombineProfiles<ti::NothrowMovableProfile, ti::EquatableProfile>;
+
+ ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadMoveConstruct)
+ .DUE_TO("Move construction")
+ .INITIALIZER(BadMoveConstruct())
+ .WITH_LOOSE_PROFILE(profile);
+ }
+
+ {
+ using profile =
+ ti::CombineProfiles<ti::NothrowMovableProfile, ti::EquatableProfile>;
+
+ ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadMoveAssign)
+ .DUE_TO("Move assignment")
+ .INITIALIZER(BadMoveAssign())
+ .WITH_LOOSE_PROFILE(profile);
+ }
+}
+
+TEST(ConformanceTestingDeathTest, CompFailures) {
+ using profile = ti::ComparableProfile;
+
+ {
+ using BadComp = BadCompare<WhichCompIsBad::eq>;
+
+ ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadComp)
+ .DUE_TO("Comparison")
+ .INITIALIZER(BadComp{0})
+ .INITIALIZER(BadComp{1})
+ .WITH_LOOSE_PROFILE(profile);
+ }
+
+ {
+ using BadComp = BadCompare<WhichCompIsBad::ne>;
+
+ ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadComp)
+ .DUE_TO("Comparison")
+ .INITIALIZER(BadComp{0})
+ .INITIALIZER(BadComp{1})
+ .WITH_LOOSE_PROFILE(profile);
+ }
+
+ {
+ using BadComp = BadCompare<WhichCompIsBad::lt>;
+
+ ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadComp)
+ .DUE_TO("Comparison")
+ .INITIALIZER(BadComp{0})
+ .INITIALIZER(BadComp{1})
+ .WITH_LOOSE_PROFILE(profile);
+ }
+
+ {
+ using BadComp = BadCompare<WhichCompIsBad::le>;
+
+ ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadComp)
+ .DUE_TO("Comparison")
+ .INITIALIZER(BadComp{0})
+ .INITIALIZER(BadComp{1})
+ .WITH_LOOSE_PROFILE(profile);
+ }
+
+ {
+ using BadComp = BadCompare<WhichCompIsBad::ge>;
+
+ ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadComp)
+ .DUE_TO("Comparison")
+ .INITIALIZER(BadComp{0})
+ .INITIALIZER(BadComp{1})
+ .WITH_LOOSE_PROFILE(profile);
+ }
+
+ {
+ using BadComp = BadCompare<WhichCompIsBad::gt>;
+
+ ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadComp)
+ .DUE_TO("Comparison")
+ .INITIALIZER(BadComp{0})
+ .INITIALIZER(BadComp{1})
+ .WITH_LOOSE_PROFILE(profile);
+ }
+}
+
+struct BadSelfMove {
+ BadSelfMove() = default;
+ BadSelfMove(BadSelfMove&&) = default;
+ BadSelfMove& operator=(BadSelfMove&& other) noexcept {
+ if (this == &other) {
+ broken_state = true;
+ }
+ return *this;
+ }
+
+ friend bool operator==(const BadSelfMove& lhs, const BadSelfMove& rhs) {
+ return !(lhs.broken_state || rhs.broken_state);
+ }
+
+ friend bool operator!=(const BadSelfMove& lhs, const BadSelfMove& rhs) {
+ return lhs.broken_state || rhs.broken_state;
+ }
+
+ bool broken_state = false;
+};
+
+TEST(ConformanceTestingDeathTest, SelfMoveFailure) {
+ using profile = ti::EquatableNothrowMovableProfile;
+
+ {
+ ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadSelfMove)
+ .DUE_TO("Move assignment")
+ .INITIALIZER(BadSelfMove())
+ .WITH_LOOSE_PROFILE(profile);
+ }
+}
+
+struct BadSelfCopy {
+ BadSelfCopy() = default;
+ BadSelfCopy(BadSelfCopy&&) = default;
+ BadSelfCopy(const BadSelfCopy&) = default;
+ BadSelfCopy& operator=(BadSelfCopy&&) = default;
+ BadSelfCopy& operator=(BadSelfCopy const& other) {
+ if (this == &other) {
+ broken_state = true;
+ }
+ return *this;
+ }
+
+ friend bool operator==(const BadSelfCopy& lhs, const BadSelfCopy& rhs) {
+ return !(lhs.broken_state || rhs.broken_state);
+ }
+
+ friend bool operator!=(const BadSelfCopy& lhs, const BadSelfCopy& rhs) {
+ return lhs.broken_state || rhs.broken_state;
+ }
+
+ bool broken_state = false;
+};
+
+TEST(ConformanceTestingDeathTest, SelfCopyFailure) {
+ using profile = ti::EquatableValueProfile;
+
+ {
+ ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadSelfCopy)
+ .DUE_TO("Copy assignment")
+ .INITIALIZER(BadSelfCopy())
+ .WITH_LOOSE_PROFILE(profile);
+ }
+}
+
+struct BadSelfSwap {
+ friend void swap(BadSelfSwap& lhs, BadSelfSwap& rhs) noexcept {
+ if (&lhs == &rhs) lhs.broken_state = true;
+ }
+
+ friend bool operator==(const BadSelfSwap& lhs, const BadSelfSwap& rhs) {
+ return !(lhs.broken_state || rhs.broken_state);
+ }
+
+ friend bool operator!=(const BadSelfSwap& lhs, const BadSelfSwap& rhs) {
+ return lhs.broken_state || rhs.broken_state;
+ }
+
+ bool broken_state = false;
+};
+
+TEST(ConformanceTestingDeathTest, SelfSwapFailure) {
+ using profile = ti::EquatableNothrowMovableProfile;
+
+ {
+ ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadSelfSwap)
+ .DUE_TO("Swap")
+ .INITIALIZER(BadSelfSwap())
+ .WITH_LOOSE_PROFILE(profile);
+ }
+}
+
+struct BadDefaultInitializedMoveAssign {
+ BadDefaultInitializedMoveAssign() : default_initialized(true) {}
+ explicit BadDefaultInitializedMoveAssign(int v) : value(v) {}
+ BadDefaultInitializedMoveAssign(
+ BadDefaultInitializedMoveAssign&& other) noexcept
+ : value(other.value) {}
+ BadDefaultInitializedMoveAssign& operator=(
+ BadDefaultInitializedMoveAssign&& other) noexcept {
+ value = other.value;
+ if (default_initialized) ++value; // Bad move if lhs is default initialized
+ return *this;
+ }
+
+ friend bool operator==(const BadDefaultInitializedMoveAssign& lhs,
+ const BadDefaultInitializedMoveAssign& rhs) {
+ return lhs.value == rhs.value;
+ }
+
+ friend bool operator!=(const BadDefaultInitializedMoveAssign& lhs,
+ const BadDefaultInitializedMoveAssign& rhs) {
+ return lhs.value != rhs.value;
+ }
+
+ bool default_initialized = false;
+ int value = 0;
+};
+
+TEST(ConformanceTestingDeathTest, DefaultInitializedMoveAssignFailure) {
+ using profile =
+ ti::CombineProfiles<ti::DefaultConstructibleNothrowMovableProfile,
+ ti::EquatableProfile>;
+
+ {
+ ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadDefaultInitializedMoveAssign)
+ .DUE_TO("move assignment")
+ .INITIALIZER(BadDefaultInitializedMoveAssign(0))
+ .WITH_LOOSE_PROFILE(profile);
+ }
+}
+
+struct BadDefaultInitializedCopyAssign {
+ BadDefaultInitializedCopyAssign() : default_initialized(true) {}
+ explicit BadDefaultInitializedCopyAssign(int v) : value(v) {}
+ BadDefaultInitializedCopyAssign(
+ BadDefaultInitializedCopyAssign&& other) noexcept
+ : value(other.value) {}
+ BadDefaultInitializedCopyAssign(const BadDefaultInitializedCopyAssign& other)
+ : value(other.value) {}
+
+ BadDefaultInitializedCopyAssign& operator=(
+ BadDefaultInitializedCopyAssign&& other) noexcept {
+ value = other.value;
+ return *this;
+ }
+
+ BadDefaultInitializedCopyAssign& operator=(
+ const BadDefaultInitializedCopyAssign& other) {
+ value = other.value;
+ if (default_initialized) ++value; // Bad move if lhs is default initialized
+ return *this;
+ }
+
+ friend bool operator==(const BadDefaultInitializedCopyAssign& lhs,
+ const BadDefaultInitializedCopyAssign& rhs) {
+ return lhs.value == rhs.value;
+ }
+
+ friend bool operator!=(const BadDefaultInitializedCopyAssign& lhs,
+ const BadDefaultInitializedCopyAssign& rhs) {
+ return lhs.value != rhs.value;
+ }
+
+ bool default_initialized = false;
+ int value = 0;
+};
+
+TEST(ConformanceTestingDeathTest, DefaultInitializedAssignFailure) {
+ using profile = ti::CombineProfiles<ti::DefaultConstructibleValueProfile,
+ ti::EquatableProfile>;
+
+ {
+ ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadDefaultInitializedCopyAssign)
+ .DUE_TO("copy assignment")
+ .INITIALIZER(BadDefaultInitializedCopyAssign(0))
+ .WITH_LOOSE_PROFILE(profile);
+ }
+}
+
+} // namespace
diff --git a/third_party/abseil/absl/types/internal/optional.h b/third_party/abseil/absl/types/internal/optional.h
index 8acbda2..92932b6 100644
--- a/third_party/abseil/absl/types/internal/optional.h
+++ b/third_party/abseil/absl/types/internal/optional.h
@@ -54,6 +54,7 @@
#endif
namespace absl {
+ABSL_NAMESPACE_BEGIN
// Forward declaration
template <typename T>
@@ -84,8 +85,8 @@
bool engaged_;
// Data storage
union {
- dummy_type dummy_;
T data_;
+ dummy_type dummy_;
};
void destruct() noexcept {
@@ -119,8 +120,8 @@
bool engaged_;
// Data storage
union {
- dummy_type dummy_;
T data_;
+ dummy_type dummy_;
};
void destruct() noexcept { engaged_ = false; }
@@ -387,6 +388,7 @@
};
} // namespace optional_internal
+ABSL_NAMESPACE_END
} // namespace absl
#undef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
diff --git a/third_party/abseil/absl/types/internal/parentheses.h b/third_party/abseil/absl/types/internal/parentheses.h
new file mode 100644
index 0000000..5aebee8
--- /dev/null
+++ b/third_party/abseil/absl/types/internal/parentheses.h
@@ -0,0 +1,34 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// parentheses.h
+// -----------------------------------------------------------------------------
+//
+// This file contains macros that expand to a left parenthesis and a right
+// parenthesis. These are in their own file and are generated from macros
+// because otherwise clang-format gets confused and clang-format off directives
+// do not help.
+//
+// The parentheses macros are used when wanting to require a rescan before
+// expansion of parenthesized text appearing after a function-style macro name.
+
+#ifndef ABSL_TYPES_INTERNAL_PARENTHESES_H_
+#define ABSL_TYPES_INTERNAL_PARENTHESES_H_
+
+#define ABSL_INTERNAL_LPAREN (
+
+#define ABSL_INTERNAL_RPAREN )
+
+#endif // ABSL_TYPES_INTERNAL_PARENTHESES_H_
diff --git a/third_party/abseil/absl/types/internal/span.h b/third_party/abseil/absl/types/internal/span.h
index d203aad..112612f 100644
--- a/third_party/abseil/absl/types/internal/span.h
+++ b/third_party/abseil/absl/types/internal/span.h
@@ -26,6 +26,7 @@
#include "absl/meta/type_traits.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace span_internal {
// A constexpr min function
@@ -121,6 +122,7 @@
using EnableIfConvertibleTo =
typename std::enable_if<IsConvertible<From, To>::value>::type;
} // namespace span_internal
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_TYPES_INTERNAL_SPAN_H_
diff --git a/third_party/abseil/absl/types/internal/transform_args.h b/third_party/abseil/absl/types/internal/transform_args.h
new file mode 100644
index 0000000..4a0ab42
--- /dev/null
+++ b/third_party/abseil/absl/types/internal/transform_args.h
@@ -0,0 +1,246 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// transform_args.h
+// -----------------------------------------------------------------------------
+//
+// This file contains a higher-order macro that "transforms" each element of a
+// a variadic argument by a provided secondary macro.
+
+#ifndef ABSL_TYPES_INTERNAL_TRANSFORM_ARGS_H_
+#define ABSL_TYPES_INTERNAL_TRANSFORM_ARGS_H_
+
+//
+// ABSL_INTERNAL_CAT(a, b)
+//
+// This macro takes two arguments and concatenates them together via ## after
+// expansion.
+//
+// Example:
+//
+// ABSL_INTERNAL_CAT(foo_, bar)
+//
+// Results in:
+//
+// foo_bar
+#define ABSL_INTERNAL_CAT(a, b) ABSL_INTERNAL_CAT_IMPL(a, b)
+#define ABSL_INTERNAL_CAT_IMPL(a, b) a##b
+
+//
+// ABSL_INTERNAL_TRANSFORM_ARGS(m, ...)
+//
+// This macro takes another macro as an argument followed by a trailing series
+// of additional parameters (up to 32 additional arguments). It invokes the
+// passed-in macro once for each of the additional arguments, with the
+// expansions separated by commas.
+//
+// Example:
+//
+// ABSL_INTERNAL_TRANSFORM_ARGS(MY_MACRO, a, b, c)
+//
+// Results in:
+//
+// MY_MACRO(a), MY_MACRO(b), MY_MACRO(c)
+//
+// TODO(calabrese) Handle no arguments as a special case.
+#define ABSL_INTERNAL_TRANSFORM_ARGS(m, ...) \
+ ABSL_INTERNAL_CAT(ABSL_INTERNAL_TRANSFORM_ARGS, \
+ ABSL_INTERNAL_NUM_ARGS(__VA_ARGS__)) \
+ (m, __VA_ARGS__)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS1(m, a0) m(a0)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS2(m, a0, a1) m(a0), m(a1)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS3(m, a0, a1, a2) m(a0), m(a1), m(a2)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS4(m, a0, a1, a2, a3) \
+ m(a0), m(a1), m(a2), m(a3)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS5(m, a0, a1, a2, a3, a4) \
+ m(a0), m(a1), m(a2), m(a3), m(a4)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS6(m, a0, a1, a2, a3, a4, a5) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS7(m, a0, a1, a2, a3, a4, a5, a6) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS8(m, a0, a1, a2, a3, a4, a5, a6, a7) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS9(m, a0, a1, a2, a3, a4, a5, a6, a7, a8) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS10(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+ a9) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS11(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+ a9, a10) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), m(a10)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS12(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+ a9, a10, a11) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), \
+ m(a10), m(a11)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS13(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+ a9, a10, a11, a12) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), \
+ m(a10), m(a11), m(a12)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS14(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+ a9, a10, a11, a12, a13) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), \
+ m(a10), m(a11), m(a12), m(a13)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS15(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+ a9, a10, a11, a12, a13, a14) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), \
+ m(a10), m(a11), m(a12), m(a13), m(a14)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS16(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+ a9, a10, a11, a12, a13, a14, a15) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), \
+ m(a10), m(a11), m(a12), m(a13), m(a14), m(a15)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS17(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+ a9, a10, a11, a12, a13, a14, a15, a16) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), \
+ m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS18(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+ a9, a10, a11, a12, a13, a14, a15, a16, \
+ a17) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), \
+ m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS19(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+ a9, a10, a11, a12, a13, a14, a15, a16, \
+ a17, a18) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), \
+ m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS20(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+ a9, a10, a11, a12, a13, a14, a15, a16, \
+ a17, a18, a19) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), \
+ m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+ m(a19)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS21(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+ a9, a10, a11, a12, a13, a14, a15, a16, \
+ a17, a18, a19, a20) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), \
+ m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+ m(a19), m(a20)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS22(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+ a9, a10, a11, a12, a13, a14, a15, a16, \
+ a17, a18, a19, a20, a21) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), \
+ m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+ m(a19), m(a20), m(a21)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS23(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+ a9, a10, a11, a12, a13, a14, a15, a16, \
+ a17, a18, a19, a20, a21, a22) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), \
+ m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+ m(a19), m(a20), m(a21), m(a22)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS24(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+ a9, a10, a11, a12, a13, a14, a15, a16, \
+ a17, a18, a19, a20, a21, a22, a23) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), \
+ m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+ m(a19), m(a20), m(a21), m(a22), m(a23)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS25(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+ a9, a10, a11, a12, a13, a14, a15, a16, \
+ a17, a18, a19, a20, a21, a22, a23, a24) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), \
+ m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+ m(a19), m(a20), m(a21), m(a22), m(a23), m(a24)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS26( \
+ m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, \
+ a16, a17, a18, a19, a20, a21, a22, a23, a24, a25) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), \
+ m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+ m(a19), m(a20), m(a21), m(a22), m(a23), m(a24), m(a25)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS27( \
+ m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, \
+ a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), \
+ m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+ m(a19), m(a20), m(a21), m(a22), m(a23), m(a24), m(a25), m(a26)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS28( \
+ m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, \
+ a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), \
+ m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+ m(a19), m(a20), m(a21), m(a22), m(a23), m(a24), m(a25), m(a26), m(a27)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS29( \
+ m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, \
+ a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), \
+ m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+ m(a19), m(a20), m(a21), m(a22), m(a23), m(a24), m(a25), m(a26), m(a27), \
+ m(a28)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS30( \
+ m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, \
+ a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), \
+ m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+ m(a19), m(a20), m(a21), m(a22), m(a23), m(a24), m(a25), m(a26), m(a27), \
+ m(a28), m(a29)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS31( \
+ m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, \
+ a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), \
+ m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+ m(a19), m(a20), m(a21), m(a22), m(a23), m(a24), m(a25), m(a26), m(a27), \
+ m(a28), m(a29), m(a30)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS32(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+ a9, a10, a11, a12, a13, a14, a15, a16, \
+ a17, a18, a19, a20, a21, a22, a23, a24, \
+ a25, a26, a27, a28, a29, a30, a31) \
+ m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), \
+ m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+ m(a19), m(a20), m(a21), m(a22), m(a23), m(a24), m(a25), m(a26), m(a27), \
+ m(a28), m(a29), m(a30), m(a31)
+
+#define ABSL_INTERNAL_NUM_ARGS_IMPL(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, \
+ a10, a11, a12, a13, a14, a15, a16, a17, \
+ a18, a19, a20, a21, a22, a23, a24, a25, \
+ a26, a27, a28, a29, a30, a31, result, ...) \
+ result
+
+#define ABSL_INTERNAL_FORCE_EXPANSION(...) __VA_ARGS__
+
+#define ABSL_INTERNAL_NUM_ARGS(...) \
+ ABSL_INTERNAL_FORCE_EXPANSION(ABSL_INTERNAL_NUM_ARGS_IMPL( \
+ __VA_ARGS__, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, \
+ 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, ))
+
+#endif // ABSL_TYPES_INTERNAL_TRANSFORM_ARGS_H_
diff --git a/third_party/abseil/absl/types/internal/variant.h b/third_party/abseil/absl/types/internal/variant.h
index 19de2e1..772008c 100644
--- a/third_party/abseil/absl/types/internal/variant.h
+++ b/third_party/abseil/absl/types/internal/variant.h
@@ -37,14 +37,15 @@
#include "absl/types/bad_variant_access.h"
#include "absl/utility/utility.h"
-#if !defined(ABSL_HAVE_STD_VARIANT)
+#if !defined(ABSL_USES_STD_VARIANT)
namespace absl {
+ABSL_NAMESPACE_BEGIN
template <class... Types>
class variant;
-ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, -1);
+ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, static_cast<size_t>(-1));
template <class T>
struct variant_size;
@@ -291,7 +292,7 @@
template <class Op, std::size_t I>
struct ReachableSwitchCase {
static VisitIndicesResultT<Op, std::size_t> Run(Op&& op) {
- return absl::base_internal::Invoke(absl::forward<Op>(op), SizeT<I>());
+ return absl::base_internal::invoke(absl::forward<Op>(op), SizeT<I>());
}
};
@@ -423,7 +424,7 @@
return PickCase<Op, 32, EndIndex>::Run(absl::forward<Op>(op));
default:
ABSL_ASSERT(i == variant_npos);
- return absl::base_internal::Invoke(absl::forward<Op>(op), NPos());
+ return absl::base_internal::invoke(absl::forward<Op>(op), NPos());
}
}
};
@@ -487,7 +488,7 @@
template <std::size_t I>
VisitIndicesResultT<Op, decltype(EndIndices)...> operator()(
SizeT<I> /*index*/) && {
- return base_internal::Invoke(
+ return base_internal::invoke(
absl::forward<Op>(op),
SizeT<UnflattenIndex<I, N, (EndIndices + 1)...>::value -
std::size_t{1}>()...);
@@ -929,7 +930,7 @@
absl::result_of_t<Op(VariantAccessResult<
Is, QualifiedVariants>...)>>::value,
"All visitation overloads must have the same return type.");
- return absl::base_internal::Invoke(
+ return absl::base_internal::invoke(
absl::forward<Op>(op),
VariantCoreAccess::Access<Is>(
absl::forward<QualifiedVariants>(std::get<TupIs>(variant_tup)))...);
@@ -1638,7 +1639,8 @@
};
} // namespace variant_internal
+ABSL_NAMESPACE_END
} // namespace absl
-#endif // !defined(ABSL_HAVE_STD_VARIANT)
+#endif // !defined(ABSL_USES_STD_VARIANT)
#endif // ABSL_TYPES_variant_internal_H_
diff --git a/third_party/abseil/absl/types/optional.h b/third_party/abseil/absl/types/optional.h
index ed8faf9..61540cf 100644
--- a/third_party/abseil/absl/types/optional.h
+++ b/third_party/abseil/absl/types/optional.h
@@ -38,19 +38,21 @@
#include "absl/base/config.h" // TODO(calabrese) IWYU removal?
#include "absl/utility/utility.h"
-#ifdef ABSL_HAVE_STD_OPTIONAL
+#ifdef ABSL_USES_STD_OPTIONAL
#include <optional> // IWYU pragma: export
namespace absl {
+ABSL_NAMESPACE_BEGIN
using std::bad_optional_access;
using std::optional;
using std::make_optional;
using std::nullopt_t;
using std::nullopt;
+ABSL_NAMESPACE_END
} // namespace absl
-#else // ABSL_HAVE_STD_OPTIONAL
+#else // ABSL_USES_STD_OPTIONAL
#include <cassert>
#include <functional>
@@ -65,6 +67,7 @@
#include "absl/types/internal/optional.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// nullopt_t
//
@@ -133,10 +136,10 @@
constexpr optional(nullopt_t) noexcept {} // NOLINT(runtime/explicit)
// Copy constructor, standard semantics
- optional(const optional& src) = default;
+ optional(const optional&) = default;
// Move constructor, standard semantics
- optional(optional&& src) = default;
+ optional(optional&&) = default;
// Constructs a non-empty `optional` direct-initialized value of type `T` from
// the arguments `std::forward<Args>(args)...` within the `optional`.
@@ -409,11 +412,11 @@
//
// If you need myOpt->foo in constexpr, use (*myOpt).foo instead.
const T* operator->() const {
- assert(this->engaged_);
+ ABSL_HARDENING_ASSERT(this->engaged_);
return std::addressof(this->data_);
}
T* operator->() {
- assert(this->engaged_);
+ ABSL_HARDENING_ASSERT(this->engaged_);
return std::addressof(this->data_);
}
@@ -422,17 +425,17 @@
// Accesses the underlying `T` value of an `optional`. If the `optional` is
// empty, behavior is undefined.
constexpr const T& operator*() const& {
- return ABSL_ASSERT(this->engaged_), reference();
+ return ABSL_HARDENING_ASSERT(this->engaged_), reference();
}
T& operator*() & {
- assert(this->engaged_);
+ ABSL_HARDENING_ASSERT(this->engaged_);
return reference();
}
constexpr const T&& operator*() const && {
- return absl::move(reference());
+ return ABSL_HARDENING_ASSERT(this->engaged_), absl::move(reference());
}
T&& operator*() && {
- assert(this->engaged_);
+ ABSL_HARDENING_ASSERT(this->engaged_);
return std::move(reference());
}
@@ -441,7 +444,7 @@
// Returns false if and only if the `optional` is empty.
//
// if (opt) {
- // // do something with opt.value();
+ // // do something with *opt or opt->;
// } else {
// // opt is empty.
// }
@@ -754,6 +757,7 @@
return static_cast<bool>(x) ? static_cast<bool>(v >= *x) : true;
}
+ABSL_NAMESPACE_END
} // namespace absl
namespace std {
@@ -767,6 +771,6 @@
#undef ABSL_MSVC_CONSTEXPR_BUG_IN_UNION_LIKE_CLASS
-#endif // ABSL_HAVE_STD_OPTIONAL
+#endif // ABSL_USES_STD_OPTIONAL
#endif // ABSL_TYPES_OPTIONAL_H_
diff --git a/third_party/abseil/absl/types/optional_exception_safety_test.cc b/third_party/abseil/absl/types/optional_exception_safety_test.cc
index f99e35c..8e5fe85 100644
--- a/third_party/abseil/absl/types/optional_exception_safety_test.cc
+++ b/third_party/abseil/absl/types/optional_exception_safety_test.cc
@@ -18,12 +18,13 @@
// This test is a no-op when absl::optional is an alias for std::optional and
// when exceptions are not enabled.
-#if !defined(ABSL_HAVE_STD_OPTIONAL) && defined(ABSL_HAVE_EXCEPTIONS)
+#if !defined(ABSL_USES_STD_OPTIONAL) && defined(ABSL_HAVE_EXCEPTIONS)
#include "gtest/gtest.h"
#include "absl/base/internal/exception_safety_testing.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
@@ -285,6 +286,7 @@
} // namespace
+ABSL_NAMESPACE_END
} // namespace absl
-#endif // #if !defined(ABSL_HAVE_STD_OPTIONAL) && defined(ABSL_HAVE_EXCEPTIONS)
+#endif // #if !defined(ABSL_USES_STD_OPTIONAL) && defined(ABSL_HAVE_EXCEPTIONS)
diff --git a/third_party/abseil/absl/types/optional_test.cc b/third_party/abseil/absl/types/optional_test.cc
index e005aff..7ef142c 100644
--- a/third_party/abseil/absl/types/optional_test.cc
+++ b/third_party/abseil/absl/types/optional_test.cc
@@ -15,7 +15,7 @@
#include "absl/types/optional.h"
// This test is a no-op when absl::optional is an alias for std::optional.
-#if !defined(ABSL_HAVE_STD_OPTIONAL)
+#if !defined(ABSL_USES_STD_OPTIONAL)
#include <string>
#include <type_traits>
@@ -224,7 +224,7 @@
EXPECT_FALSE(
absl::is_trivially_copy_constructible<absl::optional<Copyable>>::value);
-#if defined(ABSL_HAVE_STD_OPTIONAL) && defined(__GLIBCXX__)
+#if defined(ABSL_USES_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).
@@ -279,7 +279,7 @@
// std::optional when T is volatile-qualified. So skipping this test.
// Bug report:
// https://connect.microsoft.com/VisualStudio/feedback/details/3142534
-#if defined(ABSL_HAVE_STD_OPTIONAL) && defined(_MSC_VER) && _MSC_VER >= 1911
+#if defined(ABSL_USES_STD_OPTIONAL) && defined(_MSC_VER) && _MSC_VER >= 1911
#define ABSL_MSVC_OPTIONAL_VOLATILE_COPY_BUG 1
#endif
#ifndef ABSL_MSVC_OPTIONAL_VOLATILE_COPY_BUG
@@ -305,7 +305,7 @@
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
+#ifndef ABSL_USES_STD_OPTIONAL
EXPECT_EQ(
absl::default_allocator_is_nothrow::value,
std::is_nothrow_move_constructible<absl::optional<MoveableThrow>>::value);
@@ -639,7 +639,7 @@
EXPECT_FALSE(absl::is_trivially_copy_assignable<NonTrivial>::value);
// std::optional doesn't support volatile nontrivial types.
-#ifndef ABSL_HAVE_STD_OPTIONAL
+#ifndef ABSL_USES_STD_OPTIONAL
{
StructorListener listener;
Listenable::listener = &listener;
@@ -658,7 +658,7 @@
EXPECT_EQ(1, listener.destruct);
EXPECT_EQ(1, listener.volatile_copy_assign);
}
-#endif // ABSL_HAVE_STD_OPTIONAL
+#endif // ABSL_USES_STD_OPTIONAL
}
TEST(optionalTest, MoveAssignment) {
@@ -682,7 +682,7 @@
EXPECT_EQ(1, listener.move_assign);
}
// std::optional doesn't support volatile nontrivial types.
-#ifndef ABSL_HAVE_STD_OPTIONAL
+#ifndef ABSL_USES_STD_OPTIONAL
{
StructorListener listener;
Listenable::listener = &listener;
@@ -702,7 +702,7 @@
EXPECT_EQ(1, listener.destruct);
EXPECT_EQ(1, listener.volatile_move_assign);
}
-#endif // ABSL_HAVE_STD_OPTIONAL
+#endif // ABSL_USES_STD_OPTIONAL
EXPECT_FALSE(absl::is_move_assignable<absl::optional<const int>>::value);
EXPECT_TRUE(absl::is_move_assignable<absl::optional<Copyable>>::value);
EXPECT_TRUE(absl::is_move_assignable<absl::optional<MoveableThrow>>::value);
@@ -944,7 +944,7 @@
template <int v>
struct DeletedOpAddr {
- constexpr static const int value = v;
+ int value = v;
constexpr DeletedOpAddr() = default;
constexpr const DeletedOpAddr<v>* operator&() const = delete; // NOLINT
DeletedOpAddr<v>* operator&() = delete; // NOLINT
@@ -954,9 +954,9 @@
// to document the fact that the current implementation of absl::optional<T>
// expects such usecases to be malformed and not compile.
TEST(optionalTest, OperatorAddr) {
- constexpr const int v = -1;
+ constexpr int v = -1;
{ // constexpr
- constexpr const absl::optional<DeletedOpAddr<v>> opt(absl::in_place_t{});
+ constexpr absl::optional<DeletedOpAddr<v>> opt(absl::in_place_t{});
static_assert(opt.has_value(), "");
// static_assert(opt->value == v, "");
static_assert((*opt).value == v, "");
@@ -1051,14 +1051,13 @@
#ifdef ABSL_HAVE_EXCEPTIONS
EXPECT_THROW((void)empty.value(), absl::bad_optional_access);
#else
- EXPECT_DEATH((void)empty.value(), "Bad optional access");
+ EXPECT_DEATH_IF_SUPPORTED((void)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)
+#if !defined(_MSC_VER) && !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG)
using COI = const absl::optional<int>;
static_assert(2 == COI(2).value(), ""); // const &&
#endif
@@ -1098,8 +1097,7 @@
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)
+#if !defined(_MSC_VER) && !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG)
using COI = const absl::optional<int>;
static_assert(*COI(2) == 2, "");
#endif
@@ -1560,7 +1558,7 @@
static_assert(
std::is_nothrow_move_constructible<absl::optional<MoveMeNoThrow>>::value,
"");
-#ifndef ABSL_HAVE_STD_OPTIONAL
+#ifndef ABSL_USES_STD_OPTIONAL
static_assert(absl::default_allocator_is_nothrow::value ==
std::is_nothrow_move_constructible<
absl::optional<MoveMeThrow>>::value,
@@ -1658,4 +1656,4 @@
} // namespace
-#endif // #if !defined(ABSL_HAVE_STD_OPTIONAL)
+#endif // #if !defined(ABSL_USES_STD_OPTIONAL)
diff --git a/third_party/abseil/absl/types/span.h b/third_party/abseil/absl/types/span.h
index b007fc1..95fe792 100644
--- a/third_party/abseil/absl/types/span.h
+++ b/third_party/abseil/absl/types/span.h
@@ -17,32 +17,30 @@
// 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.
+// This header file defines a `Span<T>` type for holding a reference to existing
+// array data. The `Span` object, much like the `absl::string_view` object,
+// does not own such data itself, and the data being referenced by the span must
+// outlive the span itself. Unlike `view` type references, a span can hold a
+// reference to mutable data (and can mutate it for underlying types of
+// non-const T.) A span provides a lightweight way to pass a reference to 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`
+// The C++20 draft standard includes a `std::span` type. As of June 2020, the
+// differences between `absl::Span` and `std::span` are:
+// * `absl::Span` has `operator==` (which is likely a design bug,
+// per https://abseil.io/blog/20180531-regular-types)
// * `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
+// * `absl::Span` has no `element_type` typedef
// * 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
@@ -71,14 +69,15 @@
#include "absl/types/internal/span.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
//------------------------------------------------------------------------------
// 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
+// A `Span` is an "array reference" type for holding a reference of contiguous
+// array data; 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.
@@ -96,7 +95,8 @@
// 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
+// of elements of type `T`, and unlike an `absl::string_view`, a span can hold a
+// reference to mutable data. 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:
@@ -126,7 +126,7 @@
// 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
+// associated spans should not invoke operations that may reallocate memory
// (such as resizing) or invalidate iterators into the container.
//
// One common use for a `Span` is when passing arguments to a routine that can
@@ -275,7 +275,7 @@
// 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);
+ return ABSL_HARDENING_ASSERT(i < size()), *(data() + i);
}
// Span::at()
@@ -291,60 +291,74 @@
// Span::front()
//
- // Returns a reference to the first element of this span.
+ // Returns a reference to the first element of this span. The span must not
+ // be empty.
constexpr reference front() const noexcept {
- return ABSL_ASSERT(size() > 0), *data();
+ return ABSL_HARDENING_ASSERT(size() > 0), *data();
}
// Span::back()
//
- // Returns a reference to the last element of this span.
+ // Returns a reference to the last element of this span. The span must not
+ // be empty.
constexpr reference back() const noexcept {
- return ABSL_ASSERT(size() > 0), *(data() + size() - 1);
+ return ABSL_HARDENING_ASSERT(size() > 0), *(data() + size() - 1);
}
// Span::begin()
//
- // Returns an iterator to the first element of this span.
+ // Returns an iterator pointing to the first element of this span, or `end()`
+ // if the span is empty.
constexpr iterator begin() const noexcept { return data(); }
// Span::cbegin()
//
- // Returns a const iterator to the first element of this span.
+ // Returns a const iterator pointing to the first element of this span, or
+ // `end()` if the span is empty.
constexpr const_iterator cbegin() const noexcept { return begin(); }
// Span::end()
//
- // Returns an iterator to the last element of this span.
+ // Returns an iterator pointing just beyond the last element at the
+ // end of this span. This iterator acts as a placeholder; attempting to
+ // access it results in undefined behavior.
constexpr iterator end() const noexcept { return data() + size(); }
// Span::cend()
//
- // Returns a const iterator to the last element of this span.
+ // Returns a const iterator pointing just beyond the last element at the
+ // end of this span. This iterator acts as a placeholder; attempting to
+ // access it results in undefined behavior.
constexpr const_iterator cend() const noexcept { return end(); }
// Span::rbegin()
//
- // Returns a reverse iterator starting at the last element of this span.
+ // Returns a reverse iterator pointing to the last element at the end of this
+ // span, or `rend()` if the span is empty.
constexpr reverse_iterator rbegin() const noexcept {
return reverse_iterator(end());
}
// Span::crbegin()
//
- // Returns a reverse const iterator starting at the last element of this span.
+ // Returns a const reverse iterator pointing to the last element at the end of
+ // this span, or `crend()` if the span is empty.
constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); }
// Span::rend()
//
- // Returns a reverse iterator starting at the first element of this span.
+ // Returns a reverse iterator pointing just before the first element
+ // at the beginning of this span. This pointer acts as a placeholder;
+ // attempting to access its element results in undefined behavior.
constexpr reverse_iterator rend() const noexcept {
return reverse_iterator(begin());
}
// Span::crend()
//
- // Returns a reverse iterator starting at the first element of this span.
+ // Returns a reverse const iterator pointing just before the first element
+ // at the beginning of this span. This pointer acts as a placeholder;
+ // attempting to access its element results in undefined behavior.
constexpr const_reverse_iterator crend() const noexcept { return rend(); }
// Span mutations
@@ -353,7 +367,7 @@
//
// Removes the first `n` elements from the span.
void remove_prefix(size_type n) noexcept {
- assert(size() >= n);
+ ABSL_HARDENING_ASSERT(size() >= n);
ptr_ += n;
len_ -= n;
}
@@ -362,7 +376,7 @@
//
// Removes the last `n` elements from the span.
void remove_suffix(size_type n) noexcept {
- assert(size() >= n);
+ ABSL_HARDENING_ASSERT(size() >= n);
len_ -= n;
}
@@ -650,7 +664,7 @@
template <int&... ExplicitArgumentBarrier, typename T>
Span<T> MakeSpan(T* begin, T* end) noexcept {
- return ABSL_ASSERT(begin <= end), Span<T>(begin, end - begin);
+ return ABSL_HARDENING_ASSERT(begin <= end), Span<T>(begin, end - begin);
}
template <int&... ExplicitArgumentBarrier, typename C>
@@ -695,7 +709,7 @@
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);
+ return ABSL_HARDENING_ASSERT(begin <= end), Span<const T>(begin, end - begin);
}
template <int&... ExplicitArgumentBarrier, typename C>
@@ -707,5 +721,6 @@
constexpr Span<const T> MakeConstSpan(const T (&array)[N]) noexcept {
return Span<const T>(array, N);
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_TYPES_SPAN_H_
diff --git a/third_party/abseil/absl/types/span_test.cc b/third_party/abseil/absl/types/span_test.cc
index 22467a0..2584339 100644
--- a/third_party/abseil/absl/types/span_test.cc
+++ b/third_party/abseil/absl/types/span_test.cc
@@ -27,6 +27,7 @@
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/internal/exception_testing.h"
+#include "absl/base/options.h"
#include "absl/container/fixed_array.h"
#include "absl/container/inlined_vector.h"
#include "absl/hash/hash_testing.h"
@@ -232,6 +233,11 @@
EXPECT_EQ(s.front(), s[0]);
EXPECT_EQ(s.back(), s[9]);
+
+#if !defined(NDEBUG) || ABSL_OPTION_HARDENED
+ EXPECT_DEATH_IF_SUPPORTED(s[-1], "");
+ EXPECT_DEATH_IF_SUPPORTED(s[10], "");
+#endif
}
TEST(IntSpan, AtThrows) {
@@ -268,6 +274,13 @@
EXPECT_EQ(s.size(), 0);
EXPECT_EQ(v, MakeRamp(20, 1));
+
+#if !defined(NDEBUG) || ABSL_OPTION_HARDENED
+ absl::Span<int> prefix_death(v);
+ EXPECT_DEATH_IF_SUPPORTED(prefix_death.remove_prefix(21), "");
+ absl::Span<int> suffix_death(v);
+ EXPECT_DEATH_IF_SUPPORTED(suffix_death.remove_suffix(21), "");
+#endif
}
TEST(IntSpan, Subspan) {
diff --git a/third_party/abseil/absl/types/variant.h b/third_party/abseil/absl/types/variant.h
index ebd52d2..ac93464 100644
--- a/third_party/abseil/absl/types/variant.h
+++ b/third_party/abseil/absl/types/variant.h
@@ -24,7 +24,7 @@
// should always hold a value of one of its alternative types (except in the
// "valueless by exception state" -- see below). A default-constructed
// `absl::variant` will hold the value of its first alternative type, provided
-// it is default-constructable.
+// it is default-constructible.
//
// In exceptional cases due to error, an `absl::variant` can hold no
// value (known as a "valueless by exception" state), though this is not the
@@ -45,11 +45,12 @@
#include "absl/base/config.h"
#include "absl/utility/utility.h"
-#ifdef ABSL_HAVE_STD_VARIANT
+#ifdef ABSL_USES_STD_VARIANT
#include <variant> // IWYU pragma: export
namespace absl {
+ABSL_NAMESPACE_BEGIN
using std::bad_variant_access;
using std::get;
using std::get_if;
@@ -62,9 +63,10 @@
using std::variant_size;
using std::variant_size_v;
using std::visit;
+ABSL_NAMESPACE_END
} // namespace absl
-#else // ABSL_HAVE_STD_VARIANT
+#else // ABSL_USES_STD_VARIANT
#include <functional>
#include <new>
@@ -77,6 +79,7 @@
#include "absl/types/internal/variant.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// -----------------------------------------------------------------------------
// absl::variant
@@ -92,7 +95,7 @@
// // assign it to a std::string.
// absl::variant<int, std::string> v = std::string("abc");
//
-// // A default-contructed variant will hold a value-initialized value of
+// // A default-constructed variant will hold a value-initialized value of
// // the first alternative type.
// auto a = absl::variant<int, std::string>(); // Holds an int of value '0'.
//
@@ -601,7 +604,10 @@
// emplace() Functions
- // Constructs a value of the given alternative type T within the variant.
+ // Constructs a value of the given alternative type T within the variant. The
+ // existing value of the variant is destroyed first (provided that
+ // `absl::valueless_by_exception()` is false). Requires that T is unambiguous
+ // in the variant.
//
// Example:
//
@@ -621,7 +627,9 @@
}
// Constructs a value of the given alternative type T within the variant using
- // an initializer list.
+ // an initializer list. The existing value of the variant is destroyed first
+ // (provided that `absl::valueless_by_exception()` is false). Requires that T
+ // is unambiguous in the variant.
//
// Example:
//
@@ -640,7 +648,7 @@
}
// Destroys the current value of the variant (provided that
- // `absl::valueless_by_exception()` is false, and constructs a new value at
+ // `absl::valueless_by_exception()` is false) and constructs a new value at
// the given index.
//
// Example:
@@ -659,7 +667,7 @@
}
// Destroys the current value of the variant (provided that
- // `absl::valueless_by_exception()` is false, and constructs a new value at
+ // `absl::valueless_by_exception()` is false) and constructs a new value at
// the given index using an initializer list and the provided arguments.
//
// Example:
@@ -795,6 +803,7 @@
a.index());
}
+ABSL_NAMESPACE_END
} // namespace absl
namespace std {
@@ -812,9 +821,10 @@
} // namespace std
-#endif // ABSL_HAVE_STD_VARIANT
+#endif // ABSL_USES_STD_VARIANT
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace variant_internal {
// Helper visitor for converting a variant<Ts...>` into another type (mostly
@@ -850,6 +860,7 @@
std::forward<Variant>(variant));
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_TYPES_VARIANT_H_
diff --git a/third_party/abseil/absl/types/variant_benchmark.cc b/third_party/abseil/absl/types/variant_benchmark.cc
index a5f5216..350b175 100644
--- a/third_party/abseil/absl/types/variant_benchmark.cc
+++ b/third_party/abseil/absl/types/variant_benchmark.cc
@@ -28,6 +28,7 @@
#include "absl/utility/utility.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
template <std::size_t I>
@@ -217,4 +218,5 @@
->DenseRange(0, integral_pow(4, 2) - 1);
} // namespace
+ABSL_NAMESPACE_END
} // namespace absl
diff --git a/third_party/abseil/absl/types/variant_exception_safety_test.cc b/third_party/abseil/absl/types/variant_exception_safety_test.cc
index fd7e6c7..439c6e1 100644
--- a/third_party/abseil/absl/types/variant_exception_safety_test.cc
+++ b/third_party/abseil/absl/types/variant_exception_safety_test.cc
@@ -18,7 +18,7 @@
// This test is a no-op when absl::variant is an alias for std::variant and when
// exceptions are not enabled.
-#if !defined(ABSL_HAVE_STD_VARIANT) && defined(ABSL_HAVE_EXCEPTIONS)
+#if !defined(ABSL_USES_STD_VARIANT) && defined(ABSL_HAVE_EXCEPTIONS)
#include <iostream>
#include <memory>
@@ -34,6 +34,7 @@
#if !defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE)
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
using ::testing::MakeExceptionSafetyTester;
@@ -237,7 +238,7 @@
}
// libstdc++ std::variant has bugs on copy assignment regarding exception
// safety.
-#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+#if !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__))
// index() != j
// if is_nothrow_copy_constructible_v<Tj> or
// !is_nothrow_move_constructible<Tj> is true, equivalent to
@@ -268,7 +269,7 @@
.Test());
EXPECT_FALSE(tester.WithContracts(strong_guarantee).Test());
}
-#endif // !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+#endif // !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__))
{
// is_nothrow_copy_constructible_v<Tj> == false &&
// is_nothrow_move_constructible_v<Tj> == true
@@ -325,7 +326,7 @@
// The fix is targeted for gcc-9.
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87431#c7
// https://gcc.gnu.org/viewcvs/gcc?view=revision&revision=267614
-#if !(defined(ABSL_HAVE_STD_VARIANT) && \
+#if !(defined(ABSL_USES_STD_VARIANT) && \
defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 8)
// - otherwise (index() != j), equivalent to
// emplace<j>(get<j>(std::move(rhs)))
@@ -342,7 +343,7 @@
auto copy = rhs;
*lhs = std::move(copy);
}));
-#endif // !(defined(ABSL_HAVE_STD_VARIANT) &&
+#endif // !(defined(ABSL_USES_STD_VARIANT) &&
// defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 8)
}
}
@@ -445,7 +446,7 @@
// and operator=(variant&&) invokes Tj's move ctor which doesn't throw.
// libstdc++ std::variant has bugs on conversion assignment regarding
// exception safety.
-#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+#if !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__))
{
MoveNothrow rhs;
EXPECT_TRUE(MakeExceptionSafetyTester()
@@ -453,7 +454,7 @@
.WithContracts(VariantInvariants, strong_guarantee)
.Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
}
-#endif // !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+#endif // !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__))
}
TEST(VariantExceptionSafetyTest, Emplace) {
@@ -523,8 +524,9 @@
}
} // namespace
+ABSL_NAMESPACE_END
} // namespace absl
#endif // !defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE)
-#endif // #if !defined(ABSL_HAVE_STD_VARIANT) && defined(ABSL_HAVE_EXCEPTIONS)
+#endif // #if !defined(ABSL_USES_STD_VARIANT) && defined(ABSL_HAVE_EXCEPTIONS)
diff --git a/third_party/abseil/absl/types/variant_test.cc b/third_party/abseil/absl/types/variant_test.cc
index b591274..cf23733 100644
--- a/third_party/abseil/absl/types/variant_test.cc
+++ b/third_party/abseil/absl/types/variant_test.cc
@@ -20,7 +20,7 @@
#include "absl/types/variant.h"
// This test is a no-op when absl::variant is an alias for std::variant.
-#if !defined(ABSL_HAVE_STD_VARIANT)
+#if !defined(ABSL_USES_STD_VARIANT)
#include <algorithm>
#include <cstddef>
@@ -50,7 +50,7 @@
#else
#define ABSL_VARIANT_TEST_EXPECT_FAIL(expr, exception_t, text) \
- EXPECT_DEATH(expr, text)
+ EXPECT_DEATH_IF_SUPPORTED(expr, text)
#endif // ABSL_HAVE_EXCEPTIONS
@@ -70,6 +70,7 @@
struct NonHashable {};
namespace absl {
+ABSL_NAMESPACE_BEGIN
namespace {
using ::testing::DoubleEq;
@@ -678,7 +679,7 @@
object.operator=(object);
EXPECT_EQ(0, counter);
- // A std::string long enough that it's likely to defeat any inline representation
+ // A string long enough that it's likely to defeat any inline representation
// optimization.
const std::string long_str(128, 'a');
@@ -842,7 +843,7 @@
}
// libstdc++ doesn't pass this test
-#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+#if !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__))
EXPECT_EQ(3, counter[0]);
EXPECT_EQ(2, counter[1]);
EXPECT_EQ(2, counter[2]);
@@ -1933,7 +1934,7 @@
}
// libstdc++ std::variant doesn't support the INVOKE semantics.
-#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+#if !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__))
TEST(VariantTest, VisitMemberFunction) {
absl::variant<std::unique_ptr<Class>> p(absl::make_unique<Class>());
absl::variant<std::unique_ptr<const Class>> cp(
@@ -1957,7 +1958,7 @@
EXPECT_EQ(42, absl::visit(&Class::member, cp));
}
-#endif // !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+#endif // !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__))
/////////////////////////
// [variant.monostate] //
@@ -2035,7 +2036,7 @@
std::swap(a, b);
EXPECT_THAT(a, VariantWith<SpecialSwap>(v2));
EXPECT_THAT(b, VariantWith<SpecialSwap>(v1));
-#ifndef ABSL_HAVE_STD_VARIANT
+#ifndef ABSL_USES_STD_VARIANT
EXPECT_FALSE(absl::get<SpecialSwap>(a).special_swap);
#endif
@@ -2083,7 +2084,7 @@
// MSVC std::hash<std::variant> does not use the index, thus produce the same
// result on the same value as different alternative.
-#if !(defined(_MSC_VER) && defined(ABSL_HAVE_STD_VARIANT))
+#if !(defined(_MSC_VER) && defined(ABSL_USES_STD_VARIANT))
{
// same value as different alternative
variant<int, int> v0(in_place_index<0>, 42);
@@ -2091,7 +2092,7 @@
std::hash<variant<int, int>> hash;
EXPECT_NE(hash(v0), hash(v1));
}
-#endif // !(defined(_MSC_VER) && defined(ABSL_HAVE_STD_VARIANT))
+#endif // !(defined(_MSC_VER) && defined(ABSL_USES_STD_VARIANT))
{
std::hash<variant<int>> hash;
@@ -2118,7 +2119,7 @@
////////////////////////////////////////
// Test that a set requiring a basic type conversion works correctly
-#if !defined(ABSL_HAVE_STD_VARIANT)
+#if !defined(ABSL_USES_STD_VARIANT)
TEST(VariantTest, TestConvertingSet) {
typedef variant<double> Variant;
Variant v(1.0);
@@ -2128,7 +2129,7 @@
ASSERT_TRUE(nullptr != absl::get_if<double>(&v));
EXPECT_DOUBLE_EQ(2, absl::get<double>(v));
}
-#endif // ABSL_HAVE_STD_VARIANT
+#endif // ABSL_USES_STD_VARIANT
// Test that a vector of variants behaves reasonably.
TEST(VariantTest, Container) {
@@ -2280,7 +2281,7 @@
};
TEST(VariantTest, TestRvalueConversion) {
-#if !defined(ABSL_HAVE_STD_VARIANT)
+#if !defined(ABSL_USES_STD_VARIANT)
variant<double, std::string> var(
ConvertVariantTo<variant<double, std::string>>(
variant<std::string, int>(0)));
@@ -2310,10 +2311,11 @@
ASSERT_TRUE(absl::holds_alternative<int32_t>(variant2));
EXPECT_EQ(42, absl::get<int32_t>(variant2));
- variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
+ variant2 =
+ ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2));
EXPECT_EQ(42, absl::get<uint32_t>(variant2));
-#endif // !ABSL_HAVE_STD_VARIANT
+#endif // !ABSL_USES_STD_VARIANT
variant<Convertible1, Convertible2> variant3(
ConvertVariantTo<variant<Convertible1, Convertible2>>(
@@ -2326,7 +2328,7 @@
}
TEST(VariantTest, TestLvalueConversion) {
-#if !defined(ABSL_HAVE_STD_VARIANT)
+#if !defined(ABSL_USES_STD_VARIANT)
variant<std::string, int> source1 = 0;
variant<double, std::string> destination(
ConvertVariantTo<variant<double, std::string>>(source1));
@@ -2428,7 +2430,7 @@
}
TEST(VariantTest, TestRvalueConversionViaConvertVariantTo) {
-#if !defined(ABSL_HAVE_STD_VARIANT)
+#if !defined(ABSL_USES_STD_VARIANT)
variant<double, std::string> var(
ConvertVariantTo<variant<double, std::string>>(
variant<std::string, int>(3)));
@@ -2452,7 +2454,8 @@
ConvertVariantTo<variant<int32_t, uint32_t>>(variant<int32_t>(42)));
EXPECT_THAT(absl::get_if<int32_t>(&variant2), Pointee(42));
- variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
+ variant2 =
+ ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42));
#endif
@@ -2467,7 +2470,7 @@
}
TEST(VariantTest, TestLvalueConversionViaConvertVariantTo) {
-#if !defined(ABSL_HAVE_STD_VARIANT)
+#if !defined(ABSL_USES_STD_VARIANT)
variant<std::string, int> source1 = 3;
variant<double, std::string> destination(
ConvertVariantTo<variant<double, std::string>>(source1));
@@ -2499,7 +2502,7 @@
variant<uint32_t> source6(42);
variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(source6);
EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42));
-#endif // !ABSL_HAVE_STD_VARIANT
+#endif // !ABSL_USES_STD_VARIANT
variant<Convertible2, Convertible1> source7((Convertible1()));
variant<Convertible1, Convertible2> variant3(
@@ -2533,7 +2536,7 @@
// standard and we know that libstdc++ variant doesn't have this feature.
// For more details see the paper:
// http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0602r0.html
-#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
+#if !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__))
#define ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY 1
#endif
@@ -2709,6 +2712,7 @@
}
} // namespace
+ABSL_NAMESPACE_END
} // namespace absl
-#endif // #if !defined(ABSL_HAVE_STD_VARIANT)
+#endif // #if !defined(ABSL_USES_STD_VARIANT)
diff --git a/third_party/abseil/absl/utility/BUILD.bazel b/third_party/abseil/absl/utility/BUILD.bazel
index ce437f7..02b2c40 100644
--- a/third_party/abseil/absl/utility/BUILD.bazel
+++ b/third_party/abseil/absl/utility/BUILD.bazel
@@ -14,7 +14,7 @@
# limitations under the License.
#
-#load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load(
"//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
@@ -24,7 +24,7 @@
package(default_visibility = ["//visibility:public"])
-licenses(["notice"]) # Apache 2.0
+licenses(["notice"])
cc_library(
name = "utility",
diff --git a/third_party/abseil/absl/utility/utility.h b/third_party/abseil/absl/utility/utility.h
index eef8fb4..bf92322 100644
--- a/third_party/abseil/absl/utility/utility.h
+++ b/third_party/abseil/absl/utility/utility.h
@@ -51,6 +51,7 @@
#include "absl/meta/type_traits.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
// integer_sequence
//
@@ -158,12 +159,12 @@
// Tag types
-#ifdef ABSL_HAVE_STD_OPTIONAL
+#ifdef ABSL_USES_STD_OPTIONAL
using std::in_place_t;
using std::in_place;
-#else // ABSL_HAVE_STD_OPTIONAL
+#else // ABSL_USES_STD_OPTIONAL
// in_place_t
//
@@ -174,9 +175,9 @@
ABSL_INTERNAL_INLINE_CONSTEXPR(in_place_t, in_place, {});
-#endif // ABSL_HAVE_STD_OPTIONAL
+#endif // ABSL_USES_STD_OPTIONAL
-#if defined(ABSL_HAVE_STD_ANY) || defined(ABSL_HAVE_STD_VARIANT)
+#if defined(ABSL_USES_STD_ANY) || defined(ABSL_USES_STD_VARIANT)
using std::in_place_type;
using std::in_place_type_t;
#else
@@ -191,9 +192,9 @@
template <typename T>
void in_place_type(utility_internal::InPlaceTypeTag<T>) {}
-#endif // ABSL_HAVE_STD_ANY || ABSL_HAVE_STD_VARIANT
+#endif // ABSL_USES_STD_ANY || ABSL_USES_STD_VARIANT
-#ifdef ABSL_HAVE_STD_VARIANT
+#ifdef ABSL_USES_STD_VARIANT
using std::in_place_index;
using std::in_place_index_t;
#else
@@ -208,7 +209,7 @@
template <size_t I>
void in_place_index(utility_internal::InPlaceIndexTag<I>) {}
-#endif // ABSL_HAVE_STD_VARIANT
+#endif // ABSL_USES_STD_VARIANT
// Constexpr move and forward
@@ -235,10 +236,10 @@
// Helper method for expanding tuple into a called method.
template <typename Functor, typename Tuple, std::size_t... Indexes>
auto apply_helper(Functor&& functor, Tuple&& t, index_sequence<Indexes...>)
- -> decltype(absl::base_internal::Invoke(
+ -> decltype(absl::base_internal::invoke(
absl::forward<Functor>(functor),
std::get<Indexes>(absl::forward<Tuple>(t))...)) {
- return absl::base_internal::Invoke(
+ return absl::base_internal::invoke(
absl::forward<Functor>(functor),
std::get<Indexes>(absl::forward<Tuple>(t))...);
}
@@ -343,6 +344,7 @@
std::tuple_size<absl::decay_t<Tuple>>::value>{});
}
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_UTILITY_UTILITY_H_
diff --git a/third_party/abseil/ci/absl_alternate_options.h b/third_party/abseil/ci/absl_alternate_options.h
new file mode 100644
index 0000000..29b020d
--- /dev/null
+++ b/third_party/abseil/ci/absl_alternate_options.h
@@ -0,0 +1,29 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Alternate options.h file, used in continuous integration testing to exercise
+// option settings not used by default.
+
+#ifndef ABSL_BASE_OPTIONS_H_
+#define ABSL_BASE_OPTIONS_H_
+
+#define ABSL_OPTION_USE_STD_ANY 0
+#define ABSL_OPTION_USE_STD_OPTIONAL 0
+#define ABSL_OPTION_USE_STD_STRING_VIEW 0
+#define ABSL_OPTION_USE_STD_VARIANT 0
+#define ABSL_OPTION_USE_INLINE_NAMESPACE 1
+#define ABSL_OPTION_INLINE_NAMESPACE_NAME ns
+#define ABSL_OPTION_HARDENED 1
+
+#endif // ABSL_BASE_OPTIONS_H_
diff --git a/third_party/abseil/ci/cmake_common.sh b/third_party/abseil/ci/cmake_common.sh
new file mode 100644
index 0000000..aec8a11
--- /dev/null
+++ b/third_party/abseil/ci/cmake_common.sh
@@ -0,0 +1,25 @@
+# Copyright 2020 The Abseil Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# The commit of GoogleTest to be used in the CMake tests in this directory.
+# Keep this in sync with the commit in the WORKSPACE file.
+readonly ABSL_GOOGLETEST_COMMIT="8567b09290fe402cf01923e2131c5635b8ed851b"
+
+# Avoid depending on GitHub by looking for a cached copy of the commit first.
+if [[ -r "${KOKORO_GFILE_DIR:-}/distdir/${ABSL_GOOGLETEST_COMMIT}.zip" ]]; then
+ DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
+ ABSL_GOOGLETEST_DOWNLOAD_URL="file:///distdir/${ABSL_GOOGLETEST_COMMIT}.zip"
+else
+ ABSL_GOOGLETEST_DOWNLOAD_URL="https://github.com/google/googletest/archive/${ABSL_GOOGLETEST_COMMIT}.zip"
+fi
diff --git a/third_party/abseil/ci/cmake_install_test.sh b/third_party/abseil/ci/cmake_install_test.sh
index 03eb043..5bf540c 100755
--- a/third_party/abseil/ci/cmake_install_test.sh
+++ b/third_party/abseil/ci/cmake_install_test.sh
@@ -16,18 +16,22 @@
set -euox pipefail
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
fi
+source "${ABSEIL_ROOT}/ci/cmake_common.sh"
+
+source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
+readonly DOCKER_CONTAINER=${LINUX_GCC_LATEST_CONTAINER}
+
time docker run \
- --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
+ --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
--workdir=/abseil-cpp \
--tmpfs=/buildfs:exec \
--cap-add=SYS_PTRACE \
--rm \
-e CFLAGS="-Werror" \
-e CXXFLAGS="-Werror" \
- gcr.io/google.com/absl-177019/linux_gcc-latest:20190703 \
+ ${DOCKER_CONTAINER} \
/bin/bash CMake/install_test_project/test.sh $@
-
diff --git a/third_party/abseil/ci/linux_clang-latest_libcxx_asan_bazel.sh b/third_party/abseil/ci/linux_clang-latest_libcxx_asan_bazel.sh
index cc8c695..ffbb832 100755
--- a/third_party/abseil/ci/linux_clang-latest_libcxx_asan_bazel.sh
+++ b/third_party/abseil/ci/linux_clang-latest_libcxx_asan_bazel.sh
@@ -20,28 +20,29 @@
set -euox pipefail
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
fi
-if [ -z ${STD:-} ]; then
- STD="c++11 c++14 c++17"
+if [[ -z ${STD:-} ]]; then
+ STD="c++11 c++14 c++17 c++20"
fi
-if [ -z ${COMPILATION_MODE:-} ]; then
+if [[ -z ${COMPILATION_MODE:-} ]]; then
COMPILATION_MODE="fastbuild opt"
fi
-if [ -z ${EXCEPTIONS_MODE:-} ]; then
+if [[ -z ${EXCEPTIONS_MODE:-} ]]; then
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
fi
-readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20190813"
+source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
+readonly DOCKER_CONTAINER=${LINUX_CLANG_LATEST_CONTAINER}
# USE_BAZEL_CACHE=1 only works on Kokoro.
# Without access to the credentials this won't work.
-if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
- DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
+if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
+ DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
# Bazel doesn't track changes to tools outside of the workspace
# (e.g. /usr/bin/gcc), so by appending the docker container to the
# remote_http_cache url, we make changes to the container part of
@@ -50,17 +51,24 @@
BAZEL_EXTRA_ARGS="--remote_http_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}"
fi
+# Avoid depending on external sites like GitHub by checking --distdir for
+# external dependencies first.
+# https://docs.bazel.build/versions/master/guide.html#distdir
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
+ DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
+ BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
+fi
+
for std in ${STD}; do
for compilation_mode in ${COMPILATION_MODE}; do
for exceptions_mode in ${EXCEPTIONS_MODE}; do
echo "--------------------------------------------------------------------"
time docker run \
- --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
+ --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
--workdir=/abseil-cpp \
--cap-add=SYS_PTRACE \
--rm \
-e CC="/opt/llvm/clang/bin/clang" \
- -e BAZEL_COMPILER="llvm" \
-e BAZEL_CXXOPTS="-std=${std}:-nostdinc++" \
-e BAZEL_LINKOPTS="-L/opt/llvm/libcxx/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx/lib" \
-e CPLUS_INCLUDE_PATH="/opt/llvm/libcxx/include/c++/v1" \
@@ -69,13 +77,11 @@
/usr/local/bin/bazel test ... \
--compilation_mode="${compilation_mode}" \
--copt="${exceptions_mode}" \
- --copt="-DDYNAMIC_ANNOTATIONS_ENABLED=1" \
- --copt="-DADDRESS_SANITIZER" \
- --copt="-DUNDEFINED_BEHAVIOR_SANITIZER" \
--copt="-fsanitize=address" \
--copt="-fsanitize=float-divide-by-zero" \
--copt="-fsanitize=nullability" \
--copt="-fsanitize=undefined" \
+ --copt="-fno-sanitize-blacklist" \
--copt=-Werror \
--keep_going \
--linkopt="-fsanitize=address" \
diff --git a/third_party/abseil/ci/linux_clang-latest_libcxx_bazel.sh b/third_party/abseil/ci/linux_clang-latest_libcxx_bazel.sh
index 5849a84..f6a2221 100755
--- a/third_party/abseil/ci/linux_clang-latest_libcxx_bazel.sh
+++ b/third_party/abseil/ci/linux_clang-latest_libcxx_bazel.sh
@@ -20,28 +20,29 @@
set -euox pipefail
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
fi
-if [ -z ${STD:-} ]; then
- STD="c++11 c++14 c++17"
+if [[ -z ${STD:-} ]]; then
+ STD="c++11 c++14 c++17 c++20"
fi
-if [ -z ${COMPILATION_MODE:-} ]; then
+if [[ -z ${COMPILATION_MODE:-} ]]; then
COMPILATION_MODE="fastbuild opt"
fi
-if [ -z ${EXCEPTIONS_MODE:-} ]; then
+if [[ -z ${EXCEPTIONS_MODE:-} ]]; then
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
fi
-readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20190813"
+source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
+readonly DOCKER_CONTAINER=${LINUX_CLANG_LATEST_CONTAINER}
# USE_BAZEL_CACHE=1 only works on Kokoro.
# Without access to the credentials this won't work.
-if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
- DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
+if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
+ DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
# Bazel doesn't track changes to tools outside of the workspace
# (e.g. /usr/bin/gcc), so by appending the docker container to the
# remote_http_cache url, we make changes to the container part of
@@ -50,34 +51,47 @@
BAZEL_EXTRA_ARGS="--remote_http_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}"
fi
+# Avoid depending on external sites like GitHub by checking --distdir for
+# external dependencies first.
+# https://docs.bazel.build/versions/master/guide.html#distdir
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
+ DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
+ BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
+fi
+
for std in ${STD}; do
for compilation_mode in ${COMPILATION_MODE}; do
for exceptions_mode in ${EXCEPTIONS_MODE}; do
echo "--------------------------------------------------------------------"
time docker run \
- --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
+ --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp-ro,readonly \
+ --tmpfs=/abseil-cpp \
--workdir=/abseil-cpp \
--cap-add=SYS_PTRACE \
--rm \
-e CC="/opt/llvm/clang/bin/clang" \
- -e BAZEL_COMPILER="llvm" \
-e BAZEL_CXXOPTS="-std=${std}:-nostdinc++" \
-e BAZEL_LINKOPTS="-L/opt/llvm/libcxx/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx/lib" \
-e CPLUS_INCLUDE_PATH="/opt/llvm/libcxx/include/c++/v1" \
${DOCKER_EXTRA_ARGS:-} \
${DOCKER_CONTAINER} \
- /usr/local/bin/bazel test ... \
- --compilation_mode="${compilation_mode}" \
- --copt="${exceptions_mode}" \
- --copt=-Werror \
- --define="absl=1" \
- --keep_going \
- --show_timestamps \
- --test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1" \
- --test_env="TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo" \
- --test_output=errors \
- --test_tag_filters=-benchmark \
- ${BAZEL_EXTRA_ARGS:-}
+ /bin/sh -c "
+ cp -r /abseil-cpp-ro/* /abseil-cpp/
+ if [ -n \"${ALTERNATE_OPTIONS:-}\" ]; then
+ cp ${ALTERNATE_OPTIONS:-} absl/base/options.h || exit 1
+ fi
+ /usr/local/bin/bazel test ... \
+ --compilation_mode=\"${compilation_mode}\" \
+ --copt=\"${exceptions_mode}\" \
+ --copt=-Werror \
+ --define=\"absl=1\" \
+ --keep_going \
+ --show_timestamps \
+ --test_env=\"GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1\" \
+ --test_env=\"TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo\" \
+ --test_output=errors \
+ --test_tag_filters=-benchmark \
+ ${BAZEL_EXTRA_ARGS:-}"
done
done
done
diff --git a/third_party/abseil/ci/linux_clang-latest_libcxx_tsan_bazel.sh b/third_party/abseil/ci/linux_clang-latest_libcxx_tsan_bazel.sh
index 8721ada..e70e821 100755
--- a/third_party/abseil/ci/linux_clang-latest_libcxx_tsan_bazel.sh
+++ b/third_party/abseil/ci/linux_clang-latest_libcxx_tsan_bazel.sh
@@ -20,28 +20,29 @@
set -euox pipefail
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
fi
-if [ -z ${STD:-} ]; then
- STD="c++11 c++14 c++17"
+if [[ -z ${STD:-} ]]; then
+ STD="c++11 c++14 c++17 c++20"
fi
-if [ -z ${COMPILATION_MODE:-} ]; then
+if [[ -z ${COMPILATION_MODE:-} ]]; then
COMPILATION_MODE="fastbuild opt"
fi
-if [ -z ${EXCEPTIONS_MODE:-} ]; then
+if [[ -z ${EXCEPTIONS_MODE:-} ]]; then
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
fi
-readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20190813"
+source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
+readonly DOCKER_CONTAINER=${LINUX_CLANG_LATEST_CONTAINER}
# USE_BAZEL_CACHE=1 only works on Kokoro.
# Without access to the credentials this won't work.
-if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
- DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
+if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
+ DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
# Bazel doesn't track changes to tools outside of the workspace
# (e.g. /usr/bin/gcc), so by appending the docker container to the
# remote_http_cache url, we make changes to the container part of
@@ -50,17 +51,24 @@
BAZEL_EXTRA_ARGS="--remote_http_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}"
fi
+# Avoid depending on external sites like GitHub by checking --distdir for
+# external dependencies first.
+# https://docs.bazel.build/versions/master/guide.html#distdir
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
+ DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
+ BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
+fi
+
for std in ${STD}; do
for compilation_mode in ${COMPILATION_MODE}; do
for exceptions_mode in ${EXCEPTIONS_MODE}; do
echo "--------------------------------------------------------------------"
time docker run \
- --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
+ --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
--workdir=/abseil-cpp \
--cap-add=SYS_PTRACE \
--rm \
-e CC="/opt/llvm/clang/bin/clang" \
- -e BAZEL_COMPILER="llvm" \
-e BAZEL_CXXOPTS="-std=${std}:-nostdinc++" \
-e BAZEL_LINKOPTS="-L/opt/llvm/libcxx-tsan/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx-tsan/lib" \
-e CPLUS_INCLUDE_PATH="/opt/llvm/libcxx-tsan/include/c++/v1" \
@@ -70,9 +78,8 @@
--build_tag_filters="-notsan" \
--compilation_mode="${compilation_mode}" \
--copt="${exceptions_mode}" \
- --copt="-DDYNAMIC_ANNOTATIONS_ENABLED=1" \
- --copt="-DTHREAD_SANITIZER" \
--copt="-fsanitize=thread" \
+ --copt="-fno-sanitize-blacklist" \
--copt=-Werror \
--keep_going \
--linkopt="-fsanitize=thread" \
diff --git a/third_party/abseil/ci/linux_clang-latest_libstdcxx_bazel.sh b/third_party/abseil/ci/linux_clang-latest_libstdcxx_bazel.sh
index 78ce0b3..0986ff4 100755
--- a/third_party/abseil/ci/linux_clang-latest_libstdcxx_bazel.sh
+++ b/third_party/abseil/ci/linux_clang-latest_libstdcxx_bazel.sh
@@ -20,28 +20,29 @@
set -euox pipefail
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
fi
-if [ -z ${STD:-} ]; then
- STD="c++11 c++14 c++17"
+if [[ -z ${STD:-} ]]; then
+ STD="c++11 c++14 c++17 c++20"
fi
-if [ -z ${COMPILATION_MODE:-} ]; then
+if [[ -z ${COMPILATION_MODE:-} ]]; then
COMPILATION_MODE="fastbuild opt"
fi
-if [ -z ${EXCEPTIONS_MODE:-} ]; then
+if [[ -z ${EXCEPTIONS_MODE:-} ]]; then
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
fi
-readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20190813"
+source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
+readonly DOCKER_CONTAINER=${LINUX_CLANG_LATEST_CONTAINER}
# USE_BAZEL_CACHE=1 only works on Kokoro.
# Without access to the credentials this won't work.
-if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
- DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
+if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
+ DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
# Bazel doesn't track changes to tools outside of the workspace
# (e.g. /usr/bin/gcc), so by appending the docker container to the
# remote_http_cache url, we make changes to the container part of
@@ -50,27 +51,35 @@
BAZEL_EXTRA_ARGS="--remote_http_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}"
fi
+# Avoid depending on external sites like GitHub by checking --distdir for
+# external dependencies first.
+# https://docs.bazel.build/versions/master/guide.html#distdir
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
+ DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
+ BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
+fi
+
for std in ${STD}; do
for compilation_mode in ${COMPILATION_MODE}; do
for exceptions_mode in ${EXCEPTIONS_MODE}; do
echo "--------------------------------------------------------------------"
time docker run \
- --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
+ --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
--workdir=/abseil-cpp \
--cap-add=SYS_PTRACE \
--rm \
-e CC="/opt/llvm/clang/bin/clang" \
- -e BAZEL_COMPILER="llvm" \
-e BAZEL_CXXOPTS="-std=${std}" \
- -e CPLUS_INCLUDE_PATH="/usr/include/c++/6" \
${DOCKER_EXTRA_ARGS:-} \
${DOCKER_CONTAINER} \
/usr/local/bin/bazel test ... \
--compilation_mode="${compilation_mode}" \
+ --copt="--gcc-toolchain=/usr/local" \
--copt="${exceptions_mode}" \
--copt=-Werror \
--define="absl=1" \
--keep_going \
+ --linkopt="--gcc-toolchain=/usr/local" \
--show_timestamps \
--test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1" \
--test_env="TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo" \
diff --git a/third_party/abseil/ci/linux_docker_containers.sh b/third_party/abseil/ci/linux_docker_containers.sh
new file mode 100644
index 0000000..1c29d9a
--- /dev/null
+++ b/third_party/abseil/ci/linux_docker_containers.sh
@@ -0,0 +1,21 @@
+# Copyright 2019 The Abseil Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# The file contains Docker container identifiers currently used by test scripts.
+# Test scripts should source this file to get the identifiers.
+
+readonly LINUX_ALPINE_CONTAINER="gcr.io/google.com/absl-177019/alpine:20201026"
+readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20201008"
+readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20201008"
+readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20201015"
diff --git a/third_party/abseil/ci/linux_gcc-4.9_libstdcxx_bazel.sh b/third_party/abseil/ci/linux_gcc-floor_libstdcxx_bazel.sh
similarity index 77%
rename from third_party/abseil/ci/linux_gcc-4.9_libstdcxx_bazel.sh
rename to third_party/abseil/ci/linux_gcc-floor_libstdcxx_bazel.sh
index c3b936b..224aef8 100755
--- a/third_party/abseil/ci/linux_gcc-4.9_libstdcxx_bazel.sh
+++ b/third_party/abseil/ci/linux_gcc-floor_libstdcxx_bazel.sh
@@ -1,6 +1,6 @@
#!/bin/bash
#
-# Copyright 2019 The Abseil Authors.
+# Copyright 2020 The Abseil Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -20,27 +20,28 @@
set -euox pipefail
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
fi
-if [ -z ${STD:-} ]; then
+if [[ -z ${STD:-} ]]; then
STD="c++11 c++14"
fi
-if [ -z ${COMPILATION_MODE:-} ]; then
+if [[ -z ${COMPILATION_MODE:-} ]]; then
COMPILATION_MODE="fastbuild opt"
fi
-if [ -z ${EXCEPTIONS_MODE:-} ]; then
+if [[ -z ${EXCEPTIONS_MODE:-} ]]; then
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
fi
-readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-4.9:20190702"
+source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
+readonly DOCKER_CONTAINER=${LINUX_GCC_FLOOR_CONTAINER}
# USE_BAZEL_CACHE=1 only works on Kokoro.
# Without access to the credentials this won't work.
-if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
+if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
# Bazel doesn't track changes to tools outside of the workspace
# (e.g. /usr/bin/gcc), so by appending the docker container to the
@@ -50,6 +51,14 @@
BAZEL_EXTRA_ARGS="--remote_http_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}"
fi
+# Avoid depending on external sites like GitHub by checking --distdir for
+# external dependencies first.
+# https://docs.bazel.build/versions/master/guide.html#distdir
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
+ DOCKER_EXTRA_ARGS="--volume=${KOKORO_GFILE_DIR}/distdir:/distdir:ro ${DOCKER_EXTRA_ARGS:-}"
+ BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
+fi
+
for std in ${STD}; do
for compilation_mode in ${COMPILATION_MODE}; do
for exceptions_mode in ${EXCEPTIONS_MODE}; do
@@ -59,7 +68,7 @@
--workdir=/abseil-cpp \
--cap-add=SYS_PTRACE \
--rm \
- -e CC="/usr/bin/gcc-4.9" \
+ -e CC="/usr/local/bin/gcc" \
-e BAZEL_CXXOPTS="-std=${std}" \
${DOCKER_EXTRA_ARGS:-} \
${DOCKER_CONTAINER} \
diff --git a/third_party/abseil/ci/linux_gcc-latest_libstdcxx_bazel.sh b/third_party/abseil/ci/linux_gcc-latest_libstdcxx_bazel.sh
index 10f6be2..37d89d9 100755
--- a/third_party/abseil/ci/linux_gcc-latest_libstdcxx_bazel.sh
+++ b/third_party/abseil/ci/linux_gcc-latest_libstdcxx_bazel.sh
@@ -20,28 +20,29 @@
set -euox pipefail
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
fi
-if [ -z ${STD:-} ]; then
- STD="c++11 c++14 c++17"
+if [[ -z ${STD:-} ]]; then
+ STD="c++11 c++14 c++17 c++20"
fi
-if [ -z ${COMPILATION_MODE:-} ]; then
+if [[ -z ${COMPILATION_MODE:-} ]]; then
COMPILATION_MODE="fastbuild opt"
fi
-if [ -z ${EXCEPTIONS_MODE:-} ]; then
+if [[ -z ${EXCEPTIONS_MODE:-} ]]; then
EXCEPTIONS_MODE="-fno-exceptions -fexceptions"
fi
-readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-latest:20190703"
+source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
+readonly DOCKER_CONTAINER=${LINUX_GCC_LATEST_CONTAINER}
# USE_BAZEL_CACHE=1 only works on Kokoro.
# Without access to the credentials this won't work.
-if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
- DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
+if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
+ DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
# Bazel doesn't track changes to tools outside of the workspace
# (e.g. /usr/bin/gcc), so by appending the docker container to the
# remote_http_cache url, we make changes to the container part of
@@ -50,12 +51,21 @@
BAZEL_EXTRA_ARGS="--remote_http_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}"
fi
+# Avoid depending on external sites like GitHub by checking --distdir for
+# external dependencies first.
+# https://docs.bazel.build/versions/master/guide.html#distdir
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
+ DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
+ BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
+fi
+
for std in ${STD}; do
for compilation_mode in ${COMPILATION_MODE}; do
for exceptions_mode in ${EXCEPTIONS_MODE}; do
echo "--------------------------------------------------------------------"
time docker run \
- --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
+ --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp-ro,readonly \
+ --tmpfs=/abseil-cpp \
--workdir=/abseil-cpp \
--cap-add=SYS_PTRACE \
--rm \
@@ -63,18 +73,23 @@
-e BAZEL_CXXOPTS="-std=${std}" \
${DOCKER_EXTRA_ARGS:-} \
${DOCKER_CONTAINER} \
- /usr/local/bin/bazel test ... \
- --compilation_mode="${compilation_mode}" \
- --copt="${exceptions_mode}" \
- --copt=-Werror \
- --define="absl=1" \
- --keep_going \
- --show_timestamps \
- --test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1" \
- --test_env="TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo" \
- --test_output=errors \
- --test_tag_filters=-benchmark \
- ${BAZEL_EXTRA_ARGS:-}
+ /bin/sh -c "
+ cp -r /abseil-cpp-ro/* /abseil-cpp/
+ if [ -n \"${ALTERNATE_OPTIONS:-}\" ]; then
+ cp ${ALTERNATE_OPTIONS:-} absl/base/options.h || exit 1
+ fi
+ /usr/local/bin/bazel test ... \
+ --compilation_mode=\"${compilation_mode}\" \
+ --copt=\"${exceptions_mode}\" \
+ --copt=-Werror \
+ --define=\"absl=1\" \
+ --keep_going \
+ --show_timestamps \
+ --test_env=\"GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1\" \
+ --test_env=\"TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo\" \
+ --test_output=errors \
+ --test_tag_filters=-benchmark \
+ ${BAZEL_EXTRA_ARGS:-}"
done
done
done
diff --git a/third_party/abseil/ci/linux_gcc-latest_libstdcxx_cmake.sh b/third_party/abseil/ci/linux_gcc-latest_libstdcxx_cmake.sh
index 3e831c1..ed9cfa3 100755
--- a/third_party/abseil/ci/linux_gcc-latest_libstdcxx_cmake.sh
+++ b/third_party/abseil/ci/linux_gcc-latest_libstdcxx_cmake.sh
@@ -14,48 +14,52 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# TODO(absl-team): This script isn't fully hermetic because
-# -DABSL_USE_GOOGLETEST_HEAD=ON means that this script isn't pinned to a fixed
-# version of GoogleTest. This means that an upstream change to GoogleTest could
-# break this test. Fix this by allowing this script to pin to a known-good
-# version of GoogleTest.
-
set -euox pipefail
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
fi
-if [ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]; then
- ABSL_CMAKE_CXX_STANDARDS="11 14 17"
+source "${ABSEIL_ROOT}/ci/cmake_common.sh"
+
+if [[ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]]; then
+ ABSL_CMAKE_CXX_STANDARDS="11 14 17 20"
fi
-if [ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]; then
+if [[ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]]; then
ABSL_CMAKE_BUILD_TYPES="Debug Release"
fi
+if [[ -z ${ABSL_CMAKE_BUILD_SHARED:-} ]]; then
+ ABSL_CMAKE_BUILD_SHARED="OFF ON"
+fi
+
+source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
+readonly DOCKER_CONTAINER=${LINUX_GCC_LATEST_CONTAINER}
+
for std in ${ABSL_CMAKE_CXX_STANDARDS}; do
for compilation_mode in ${ABSL_CMAKE_BUILD_TYPES}; do
- echo "--------------------------------------------------------------------"
- echo "Testing with CMAKE_BUILD_TYPE=${compilation_mode} and -std=c++${std}"
-
- time docker run \
- --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
- --workdir=/abseil-cpp \
- --tmpfs=/buildfs:exec \
- --cap-add=SYS_PTRACE \
- --rm \
- -e CFLAGS="-Werror" \
- -e CXXFLAGS="-Werror" \
- gcr.io/google.com/absl-177019/linux_gcc-latest:20190703 \
- /bin/bash -c "
- cd /buildfs && \
- cmake /abseil-cpp \
- -DABSL_USE_GOOGLETEST_HEAD=ON \
- -DABSL_RUN_TESTS=ON \
- -DCMAKE_BUILD_TYPE=${compilation_mode} \
- -DCMAKE_CXX_STANDARD=${std} && \
- make -j$(nproc) && \
- ctest -j$(nproc) --output-on-failure"
+ for build_shared in ${ABSL_CMAKE_BUILD_SHARED}; do
+ time docker run \
+ --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
+ --tmpfs=/buildfs:exec \
+ --workdir=/buildfs \
+ --cap-add=SYS_PTRACE \
+ --rm \
+ -e CFLAGS="-Werror" \
+ -e CXXFLAGS="-Werror" \
+ ${DOCKER_EXTRA_ARGS:-} \
+ "${DOCKER_CONTAINER}" \
+ /bin/bash -c "
+ cmake /abseil-cpp \
+ -DABSL_GOOGLETEST_DOWNLOAD_URL=${ABSL_GOOGLETEST_DOWNLOAD_URL} \
+ -DABSL_RUN_TESTS=ON \
+ -DBUILD_SHARED_LIBS=${build_shared} \
+ -DCMAKE_BUILD_TYPE=${compilation_mode} \
+ -DCMAKE_CXX_STANDARD=${std} \
+ -DCMAKE_MODULE_LINKER_FLAGS=\"-Wl,--no-undefined\" && \
+ make -j$(nproc) && \
+ ctest -j$(nproc) --output-on-failure"
+ done
done
done
diff --git a/third_party/abseil/ci/linux_gcc_alpine_cmake.sh b/third_party/abseil/ci/linux_gcc_alpine_cmake.sh
new file mode 100755
index 0000000..31310ac
--- /dev/null
+++ b/third_party/abseil/ci/linux_gcc_alpine_cmake.sh
@@ -0,0 +1,64 @@
+#!/bin/bash
+#
+# Copyright 2019 The Abseil Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -euox pipefail
+
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
+ ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
+fi
+
+source "${ABSEIL_ROOT}/ci/cmake_common.sh"
+
+if [[ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]]; then
+ ABSL_CMAKE_CXX_STANDARDS="11 14 17"
+fi
+
+if [[ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]]; then
+ ABSL_CMAKE_BUILD_TYPES="Debug Release"
+fi
+
+if [[ -z ${ABSL_CMAKE_BUILD_SHARED:-} ]]; then
+ ABSL_CMAKE_BUILD_SHARED="OFF ON"
+fi
+
+source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
+readonly DOCKER_CONTAINER=${LINUX_ALPINE_CONTAINER}
+
+for std in ${ABSL_CMAKE_CXX_STANDARDS}; do
+ for compilation_mode in ${ABSL_CMAKE_BUILD_TYPES}; do
+ for build_shared in ${ABSL_CMAKE_BUILD_SHARED}; do
+ time docker run \
+ --mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
+ --tmpfs=/buildfs:exec \
+ --workdir=/buildfs \
+ --cap-add=SYS_PTRACE \
+ --rm \
+ -e CFLAGS="-Werror" \
+ -e CXXFLAGS="-Werror" \
+ ${DOCKER_EXTRA_ARGS:-} \
+ "${DOCKER_CONTAINER}" \
+ /bin/sh -c "
+ cmake /abseil-cpp \
+ -DABSL_GOOGLETEST_DOWNLOAD_URL=${ABSL_GOOGLETEST_DOWNLOAD_URL} \
+ -DABSL_RUN_TESTS=ON \
+ -DCMAKE_BUILD_TYPE=${compilation_mode} \
+ -DCMAKE_CXX_STANDARD=${std} \
+ -DCMAKE_MODULE_LINKER_FLAGS=\"-Wl,--no-undefined\" && \
+ make -j$(nproc) && \
+ ctest -j$(nproc) --output-on-failure"
+ done
+ done
+done
diff --git a/third_party/abseil/ci/macos_xcode_bazel.sh b/third_party/abseil/ci/macos_xcode_bazel.sh
index 3e13b15..738adf9 100755
--- a/third_party/abseil/ci/macos_xcode_bazel.sh
+++ b/third_party/abseil/ci/macos_xcode_bazel.sh
@@ -19,13 +19,13 @@
set -euox pipefail
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
fi
# If we are running on Kokoro, check for a versioned Bazel binary.
-KOKORO_GFILE_BAZEL_BIN="bazel-0.28.1-darwin-x86_64"
-if [ ${KOKORO_GFILE_DIR:-} ] && [ -f ${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN} ]; then
+KOKORO_GFILE_BAZEL_BIN="bazel-2.0.0-darwin-x86_64"
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f ${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN} ]]; then
BAZEL_BIN="${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN}"
chmod +x ${BAZEL_BIN}
else
@@ -41,6 +41,10 @@
cd ${ABSEIL_ROOT}
+if [[ -n "${ALTERNATE_OPTIONS:-}" ]]; then
+ cp ${ALTERNATE_OPTIONS:-} absl/base/options.h || exit 1
+fi
+
${BAZEL_BIN} test ... \
--copt=-Werror \
--keep_going \
diff --git a/third_party/abseil/ci/macos_xcode_cmake.sh b/third_party/abseil/ci/macos_xcode_cmake.sh
index 75b0f2d..0847b3e 100755
--- a/third_party/abseil/ci/macos_xcode_cmake.sh
+++ b/third_party/abseil/ci/macos_xcode_cmake.sh
@@ -14,30 +14,43 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# This script is invoked on Kokoro to test Abseil on macOS.
-# It is not hermetic and may break when Kokoro is updated.
-
set -euox pipefail
-if [ -z ${ABSEIL_ROOT:-} ]; then
+if [[ -z ${ABSEIL_ROOT:-} ]]; then
ABSEIL_ROOT="$(dirname ${0})/.."
fi
ABSEIL_ROOT=$(realpath ${ABSEIL_ROOT})
-if [ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]; then
+source "${ABSEIL_ROOT}/ci/cmake_common.sh"
+
+# The MacOS build doesn't run in a docker container, so we have to override ABSL_GOOGLETEST_DOWNLOAD_URL.
+if [[ -r "${KOKORO_GFILE_DIR}/distdir/${ABSL_GOOGLETEST_COMMIT}.zip" ]]; then
+ ABSL_GOOGLETEST_DOWNLOAD_URL="file://${KOKORO_GFILE_DIR}/distdir/${ABSL_GOOGLETEST_COMMIT}.zip"
+fi
+
+if [[ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]]; then
ABSL_CMAKE_BUILD_TYPES="Debug"
fi
-for compilation_mode in ${ABSL_CMAKE_BUILD_TYPES}; do
- BUILD_DIR=$(mktemp -d ${compilation_mode}.XXXXXXXX)
- cd ${BUILD_DIR}
+if [[ -z ${ABSL_CMAKE_BUILD_SHARED:-} ]]; then
+ ABSL_CMAKE_BUILD_SHARED="OFF ON"
+fi
- # TODO(absl-team): Enable -Werror once all warnings are fixed.
- time cmake ${ABSEIL_ROOT} \
- -GXcode \
- -DCMAKE_BUILD_TYPE=${compilation_mode} \
- -DABSL_USE_GOOGLETEST_HEAD=ON \
- -DABSL_RUN_TESTS=ON
- time cmake --build .
- time ctest -C ${compilation_mode} --output-on-failure
+for compilation_mode in ${ABSL_CMAKE_BUILD_TYPES}; do
+ for build_shared in ${ABSL_CMAKE_BUILD_SHARED}; do
+ BUILD_DIR=$(mktemp -d ${compilation_mode}.XXXXXXXX)
+ cd ${BUILD_DIR}
+
+ # TODO(absl-team): Enable -Werror once all warnings are fixed.
+ time cmake ${ABSEIL_ROOT} \
+ -GXcode \
+ -DBUILD_SHARED_LIBS=${build_shared} \
+ -DCMAKE_BUILD_TYPE=${compilation_mode} \
+ -DCMAKE_CXX_STANDARD=11 \
+ -DCMAKE_MODULE_LINKER_FLAGS="-Wl,--no-undefined" \
+ -DABSL_GOOGLETEST_DOWNLOAD_URL="${ABSL_GOOGLETEST_DOWNLOAD_URL}" \
+ -DABSL_RUN_TESTS=ON
+ time cmake --build .
+ time ctest -C ${compilation_mode} --output-on-failure
+ done
done
diff --git a/third_party/abseil/conanfile.py b/third_party/abseil/conanfile.py
old mode 100644
new mode 100755
index cd124aa..926ec5c
--- a/third_party/abseil/conanfile.py
+++ b/third_party/abseil/conanfile.py
@@ -30,7 +30,7 @@
raise ConanInvalidConfiguration("Abseil does not support MSVC < 14")
def build(self):
- tools.replace_in_file("CMakeLists.txt", "project(absl)", "project(absl)\ninclude(conanbuildinfo.cmake)\nconan_basic_setup()")
+ tools.replace_in_file("CMakeLists.txt", "project(absl CXX)", "project(absl CXX)\ninclude(conanbuildinfo.cmake)\nconan_basic_setup()")
cmake = CMake(self)
cmake.definitions["BUILD_TESTING"] = False
cmake.configure()